Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

vfsstream paths and realpath

I'm experimenting with vfsStream for unit testing filesystem interactions and have very quickly run into a major hurdle. One of the validation checks the code under test does is execute realpath() on a supplied input path to test that it's an actual path and not nonsense. However, realpath always fails on a vfsstream path.

The following code demonstrates the problem outside of any particular class.

$content    = "It rubs the lotion on its skin or else it gets the hose again";
$url        = vfsStream::url ('test/text.txt');
file_put_contents ($url, $content);
var_dump ($url);
var_dump (realpath ($url));
var_dump (file_get_contents ($url));

The output is as follows:

string(27) "vfs://FileClassMap/text.txt"
bool(false)
string(61) "It rubs the lotion on its skin or else it gets the hose again"

Obviously the vfsStream created the file and wrote the given content to it, but I can't verify that the path to it is correct with realpath. As realpath is being used inside the actual code I need a way of working about this.

I really don't think removing realpath is a sensible approach because it performs an important function inside the code, and eliminating an important check just to make the code testable seems a pretty poor solution. I could also put an if around the test to make it possible to disable it for testing purposes, but again I don't think that's a good idea either. Also I'd hate to have to do that at every point in the code where I might make a call to realpath (). The third option would be to set up a RAM disk for filesystem unit tests, but that's not ideal either. You have to clean up after yourself (which is what vfsstream is supposed to help you avoid the need for) and how to actually do it will differ from OS to OS, so the unit tests would cease to be OS agnostic.

So is there a way to get a vfsstream path in a format that actually works with realpath?

For completeness, the following is the code fragment from the class I'm trying to actually test.

if (($fullPath = realpath ($unvalidatedPath))
&& (is_file ($fullPath))
&& (is_writable ($fullPath))) {

A refactoring to the following (as per potential solution 2) allows me to test with vfsStream, but I think it could be problematic in production:

// If we can get a canonical path then do so (realpath can fail on URLs, stream wrappers, etc)
$fullPath   = realpath ($unvalidatedPath);
if (false === $fullPath) {
    $fullPath   = $unvalidatedPath;
}

if ((is_file ($fullPath))
&& (is_writable ($fullPath))) {
like image 256
GordonM Avatar asked Mar 12 '14 22:03

GordonM


1 Answers

If you use namespaces you can override the realpath function only in the test class. I always use canonical paths in my vfsStream testcases, beause i don't want to test the realpath() function itself.

namespace my\namespace;

/**
 * Override realpath() in current namespace for testing
 *
 * @param string $path     the file path
 *
 * @return string
 */
function realpath($path)
{
    return $path;
}

Good described here: http://www.schmengler-se.de/en/2011/03/php-mocking-built-in-functions-like-time-in-unit-tests/

like image 61
sebkrueger Avatar answered Sep 27 '22 20:09

sebkrueger