Skip to content

Commit

Permalink
add Assert::snapshot() and make Snapshot an instantiable representati…
Browse files Browse the repository at this point in the history
…on of a single snapshot
  • Loading branch information
jiripudil committed Dec 3, 2018
1 parent 1f9d613 commit f5d9644
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 106 deletions.
34 changes: 34 additions & 0 deletions src/Framework/Assert.php
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,40 @@ public static function matchFile(string $file, $actual, string $description = nu
}


/**
* Compares value with a previously created snapshot.
*/
public static function snapshot(string $snapshotName, $actual, string $description = null): void
{
self::$counter++;

$snapshot = new Snapshot($snapshotName);
if (!$snapshot->exists()) {
if (!$snapshot->canUpdate()) {
self::fail("Missing snapshot '$snapshotName', use --update-snapshots option to generate it.");
}

$snapshot->update($actual);
}

$expected = $snapshot->read();
if ($expected !== $actual) {
if (!$snapshot->canUpdate()) {
self::fail(
self::describe(
"%1 should be %2 in snapshot '$snapshotName'",
$description
),
$actual,
$expected
);
}

$snapshot->update($actual);
}
}


/**
* Failed assertion
*/
Expand Down
86 changes: 48 additions & 38 deletions src/Framework/Snapshot.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,71 +11,70 @@


/**
* Snapshot testing helper.
* Snapshot of a tested value.
*/
class Snapshot
{
/** @var string */
public static $snapshotDir = 'snapshots';

/** @var string[] */
public static $updatedSnapshots = [];

/** @var string[] */
private static $usedNames = [];

/**
* Compares value with a previously created snapshot.
*/
public static function match($value, string $snapshotName): void
{
$updateSnapshots = (bool) getenv(Environment::UPDATE_SNAPSHOTS);

$testFile = $_SERVER['argv'][0];
$snapshotFile = self::getSnapshotFile($testFile, $snapshotName);
/** @var string */
private $name;

if (!file_exists($snapshotFile)) {
if (!$updateSnapshots) {
Assert::fail("Missing snapshot file '$snapshotFile', use --update-snapshots option to generate it.");
}

self::write($snapshotFile, $value);
public function __construct(string $name)
{
if (!preg_match('/^[a-zA-Z0-9-_]+$/', $name)) {
throw new \Exception("Invalid snapshot name '$name'. Only alphanumeric characters, dash and underscore are allowed.");
}

$snapshot = self::read($snapshotFile);
if (in_array($name, self::$usedNames, true)) {
throw new \Exception("Snapshot '$name' was already asserted, please use a different name.");
}

try {
Assert::equal($snapshot, $value, "Snapshot $snapshotName");
$this->name = self::$usedNames[] = $name;
}

} catch (AssertException $e) {
if (!$updateSnapshots) {
throw $e;
}

self::write($snapshotFile, $value);
}
public function exists(): bool
{
return file_exists($this->getSnapshotFile());
}


private static function getSnapshotFile(string $testFile, string $snapshotName): string
public function read()
{
$path = self::$snapshotDir . DIRECTORY_SEPARATOR . pathinfo($testFile, PATHINFO_FILENAME) . '.' . $snapshotName . '.phps';
if (!preg_match('#/|\w:#A', self::$snapshotDir)) {
$path = dirname($testFile) . DIRECTORY_SEPARATOR . $path;
}
return $path;
$snapshotFile = $this->getSnapshotFile();
set_error_handler(function ($errno, $errstr) use ($snapshotFile) {
throw new \Exception("Unable to read snapshot file '$snapshotFile': $errstr");
});

$snapshotContents = include $snapshotFile;

restore_error_handler();
return $snapshotContents;
}


private static function read(string $snapshotFile)
public function canUpdate(): bool
{
$snapshotContents = @file_get_contents($snapshotFile);
if ($snapshotContents === false) {
throw new \Exception("Unable to read snapshot file '$snapshotFile'.");
}

return eval(substr($snapshotContents, strlen('<?php ')));
return (bool) getenv(Environment::UPDATE_SNAPSHOTS);
}


private static function write(string $snapshotFile, $value): void
public function update($value): void
{
if (!$this->canUpdate()) {
throw new \Exception('Cannot update snapshot. Please run tests again with --update-snapshots.');
}

$snapshotFile = $this->getSnapshotFile();
$snapshotDirectory = dirname($snapshotFile);
if (!is_dir($snapshotDirectory) && !mkdir($snapshotDirectory)) {
throw new \Exception("Unable to create snapshot directory '$snapshotDirectory'.");
Expand All @@ -88,4 +87,15 @@ private static function write(string $snapshotFile, $value): void

self::$updatedSnapshots[] = $snapshotFile;
}


private function getSnapshotFile(): string
{
$testFile = $_SERVER['argv'][0];
$path = self::$snapshotDir . DIRECTORY_SEPARATOR . pathinfo($testFile, PATHINFO_FILENAME) . '.' . $this->name . '.phps';
if (!preg_match('#/|\w:#A', self::$snapshotDir)) {
$path = dirname($testFile) . DIRECTORY_SEPARATOR . $path;
}
return $path;
}
}
29 changes: 29 additions & 0 deletions tests/Framework/Assert.snapshot.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

use Tester\Assert;
use Tester\AssertException;
use Tester\Snapshot;

require __DIR__ . '/../bootstrap.php';

Snapshot::$snapshotDir = __DIR__ . '/fixtures';

Assert::snapshot('existingSnapshot', ['answer' => 42]);

Assert::exception(function () {
Assert::snapshot('invalid / name', ['answer' => 42]);
}, \Exception::class, "Invalid snapshot name 'invalid / name'. Only alphanumeric characters, dash and underscore are allowed.");

Assert::exception(function () {
Assert::snapshot('existingSnapshot', ['answer' => 42]);
}, \Exception::class, "Snapshot 'existingSnapshot' was already asserted, please use a different name.");

Assert::exception(function () {
Assert::snapshot('anotherSnapshot', ['answer' => 43]);
}, AssertException::class, "%a% should be %a% in snapshot 'anotherSnapshot'");

Assert::exception(function () {
Assert::snapshot('nonExistingSnapshot', 'value');
}, AssertException::class, "Missing snapshot 'nonExistingSnapshot', use --update-snapshots option to generate it.");
43 changes: 43 additions & 0 deletions tests/Framework/Assert.snapshot.update.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

use Tester\Assert;
use Tester\Environment;
use Tester\Helpers;
use Tester\Snapshot;

require __DIR__ . '/../bootstrap.php';

putenv(Environment::UPDATE_SNAPSHOTS . '=1');
Snapshot::$snapshotDir = __DIR__ . '/snapshots';
Helpers::purge(Snapshot::$snapshotDir);

// newly created

Assert::false(file_exists(Snapshot::$snapshotDir . '/Assert.snapshot.update.newSnapshot.phps'));
Assert::snapshot('newSnapshot', ['answer' => 42]);
Assert::true(file_exists(Snapshot::$snapshotDir . '/Assert.snapshot.update.newSnapshot.phps'));
Assert::contains('42', file_get_contents(Snapshot::$snapshotDir . '/Assert.snapshot.update.newSnapshot.phps'));

// existing

file_put_contents(
Snapshot::$snapshotDir . '/Assert.snapshot.update.updatedSnapshot.phps',
'<?php return array(\'answer\' => 43);' . PHP_EOL
);

Assert::true(file_exists(Snapshot::$snapshotDir . '/Assert.snapshot.update.updatedSnapshot.phps'));
Assert::snapshot('updatedSnapshot', ['answer' => 42]);
Assert::true(file_exists(Snapshot::$snapshotDir . '/Assert.snapshot.update.updatedSnapshot.phps'));
Assert::contains('42', file_get_contents(Snapshot::$snapshotDir . '/Assert.snapshot.update.updatedSnapshot.phps'));

// Snapshot::$updatedSnapshots

Assert::same([
Snapshot::$snapshotDir . DIRECTORY_SEPARATOR . 'Assert.snapshot.update.newSnapshot.phps',
Snapshot::$snapshotDir . DIRECTORY_SEPARATOR . 'Assert.snapshot.update.updatedSnapshot.phps',
], Snapshot::$updatedSnapshots);

// reset the env variable so that the test does not fail due to updated snapshots
putenv(Environment::UPDATE_SNAPSHOTS . '=0');
21 changes: 0 additions & 21 deletions tests/Framework/Snapshot.match.phpt

This file was deleted.

43 changes: 0 additions & 43 deletions tests/Framework/Snapshot.update.phpt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<?php return ['answer' => 42];
4 changes: 2 additions & 2 deletions tests/Runner/Runner.snapshots.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ $runner->run();

Assert::same(Test::FAILED, $logger->results['update-snapshots.phptx'][0]);
Assert::match(
"Failed: Missing snapshot file '%a%', use --update-snapshots option to generate it.\n%A%",
"Failed: Missing snapshot '%a%', use --update-snapshots option to generate it.\n%A%",
trim(Dumper::removeColors($logger->results['update-snapshots.phptx'][1]))
);

// second run, with update -> skipped
// second run, with update -> fail

$runner = new Tester\Runner\Runner(createInterpreter());
$runner->paths[] = __DIR__ . '/snapshots/*.phptx';
Expand Down
4 changes: 2 additions & 2 deletions tests/Runner/snapshots/update-snapshots.phptx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php

use Tester\Snapshot;
use Tester\Assert;

require __DIR__ . '/../../bootstrap.php';

Snapshot::match('snapshot value', 'snapshot');
Assert::snapshot('snapshot', 'snapshot value');

0 comments on commit f5d9644

Please sign in to comment.