From 01b647e8eaf1ab2ff24913df1f5055b18d4bbe05 Mon Sep 17 00:00:00 2001 From: Timo Tijhof Date: Thu, 29 Feb 2024 03:06:14 +0000 Subject: [PATCH] test: Support child fixtures and enable for lessjs-2.5.3 Refactor the way we run fixtures to also consider child fixtures. We can't simply extend the glob() as-is, because the reason child fixtures exist is to separate input files that excercise non-default Parser options. For example, "compression/" tests the output of the `compress => true` option. * Move array of fixture groups from FixtureTest.php to fixtures.php, so that compare.php can easily re-use it. * Make the cssDir and lessDir explicit instead of automatic, so that we can easily set it to a subdirectory. * Add optional 'options' key for custom Parser options. * Define "strict-units/", and enable in PHPUnit. We pass this! * Define "compression/", and enable in PHPUnit. Add an override because our output is slightly less optimised than upstream (we output "0.5px" and "0px", instead of the shorter zeroless ".5px" and unitless "0"). To test live and compare against upstream output, run: `test compare.php test/Fixtures/lessjs-2.5.3/css/compression/` * Define "lessjs-2.5.3/include-path/", and disable in PHPUnit. We haven't implemented data-uri() yet. Change-Id: Iade37bae1728202926026289f3bc7acdfd1ab078 --- .../override/compression/compression.css | 3 + test/compare.php | 78 ++++++++++++------- test/fixtures.php | 51 ++++++++++++ test/phpunit/FixturesTest.php | 54 +++++++------ 4 files changed, 135 insertions(+), 51 deletions(-) create mode 100644 test/Fixtures/lessjs-2.5.3/override/compression/compression.css create mode 100644 test/fixtures.php diff --git a/test/Fixtures/lessjs-2.5.3/override/compression/compression.css b/test/Fixtures/lessjs-2.5.3/override/compression/compression.css new file mode 100644 index 00000000..e93e3d97 --- /dev/null +++ b/test/Fixtures/lessjs-2.5.3/override/compression/compression.css @@ -0,0 +1,3 @@ +#colours{color1:#fea;color2:#ffeeaa;color3:rgba(255,238,170,0.1);string:"#fea";/*! but not this type + Note preserved whitespace + */}dimensions{val:0.1px;val:0em;val:4cm;val:0.2;val:5;angles-must-have-unit:0deg;durations-must-have-unit:0s;length-doesnt-have-unit:0px;width:auto\9}@page{marks:none;@top-left-corner{vertical-align:top}@top-left{vertical-align:top}}.shadow^.dom,body^^.shadow{display:done} diff --git a/test/compare.php b/test/compare.php index a08eaef6..201f14c8 100644 --- a/test/compare.php +++ b/test/compare.php @@ -12,6 +12,8 @@ subdirectory, and compare it to an eponymous file in the "css/" subdirectory. + - {{FIXTURE_DIR}} + Default: test/Fixtures/lessjs-2.5.3/ --override By default, the compare tool validates the full upstream @@ -32,6 +34,8 @@ TEXT; +define( 'FIXTURES', require __DIR__ . '/fixtures.php' ); + class LessFixtureDiff { private int $summaryOK = 0; private array $summaryFail = []; @@ -44,15 +48,12 @@ public function cli( $args ) { if ( $arg === '--override' ) { $useOverride = true; } elseif ( strpos( $arg, '--' ) === 0 ) { - print "Error: Invalid option $arg\n\n"; - print USAGE; - exit( 1 ); + $this->error( "Invalid option $arg" ); } elseif ( $fixtureDir === null ) { // First non-option argument $fixtureDir = $arg; } else { - print "Error: Unexpected argument $arg\n\n"; - print USAGE; + $this->error( "Unexpected argument $arg" ); } } @@ -62,32 +63,55 @@ public function cli( $args ) { ); } - public function compare( string $fixtureDir, bool $useOverride ): void { - $fixtureDir = rtrim( $fixtureDir, '/' ); - $cssDir = "$fixtureDir/css"; - $overrideDir = "$fixtureDir/override"; - if ( !is_dir( $cssDir ) ) { - // Check because glob() tolerances non-existence - print "Error: Missing directory $cssDir\n\n"; - print USAGE; - exit( 1 ); + private function error( $message ) { + print "Error: $message\n\n"; + print preg_replace_callback( + '/^(.*){{FIXTURE_DIR}}$/m', + static function ( $matches ) { + $prefix = $matches[1]; + return $prefix . implode( "\n$prefix", array_keys( FIXTURES ) ); + }, + USAGE + ); + exit( 1 ); + } + + /** + * @param string $fixtureDir Fixture group name as defined in test/fixtures.php, + * or path to a fixture directory, + * or path to a fixture css/less subdirectory. + * @return array|null + */ + private function getFixture( string $fixtureDir ): ?array { + foreach ( FIXTURES as $group => $fixture ) { + if ( $fixtureDir === $group + || realpath( $fixtureDir ) === realpath( $fixture['cssDir'] ) + || realpath( $fixtureDir ) === realpath( $fixture['lessDir'] ) + || realpath( $fixtureDir ) === realpath( $fixture['cssDir'] . "/.." ) + ) { + return $fixture; + } } - if ( $useOverride && !is_dir( $overrideDir ) ) { - print "Error: Missing directory $overrideDir\n\n"; - print USAGE; - exit( 1 ); + return null; + } + + public function compare( string $fixtureDir, bool $useOverride ): void { + $fixture = $this->getFixture( $fixtureDir ); + if ( !$fixture ) { + $this->error( "Undefined fixture $fixtureDir" ); } - $group = basename( $fixtureDir ); + $cssDir = $fixture['cssDir']; + $lessDir = $fixture['lessDir']; + $overrideDir = $useOverride ? ( $fixture['overrideDir'] ?? null ) : null; + $options = $fixture['options'] ?? []; foreach ( glob( "$cssDir/*.css" ) as $cssFile ) { - // From /Fixtures/lessjs/css/something.css - // into /Fixtures/lessjs/less/name.less $name = basename( $cssFile, '.css' ); - $lessFile = dirname( dirname( $cssFile ) ) . '/less/' . $name . '.less'; - $overrideFile = dirname( dirname( $cssFile ) ) . '/override/' . $name . '.css'; - if ( $useOverride && file_exists( $overrideFile ) ) { + $lessFile = "$lessDir/$name.less"; + $overrideFile = $overrideDir ? "$overrideDir/$name.css" : null; + if ( $overrideFile && file_exists( $overrideFile ) ) { $cssFile = $overrideFile; } - $this->handleFixture( $cssFile, $lessFile ); + $this->handleFixture( $cssFile, $lessFile, $options ); } // Create a simple to understand summary at the end, @@ -105,11 +129,11 @@ private function addToSummary( string $line ) { $this->summary .= $line . "\n"; } - public function handleFixture( $cssFile, $lessFile ) { + public function handleFixture( $cssFile, $lessFile, $options ) { $expectedCSS = trim( file_get_contents( $cssFile ) ); // Check with standard parser - $parser = new Less_Parser(); + $parser = new Less_Parser( $options ); try { $parser->parseFile( $lessFile ); $css = $parser->getCss(); diff --git a/test/fixtures.php b/test/fixtures.php new file mode 100644 index 00000000..a88abe3d --- /dev/null +++ b/test/fixtures.php @@ -0,0 +1,51 @@ + [ + 'lessDir' => "$fixtureDir/less.php/less", + 'cssDir' => "$fixtureDir/less.php/css", + ], + 'bug-reports' => [ + 'lessDir' => "$fixtureDir/bug-reports/less", + 'cssDir' => "$fixtureDir/bug-reports/css", + ], + + // Upstream fixtures and parser options are declared + // at https://github.com/less/less.js/blob/v2.5.3/test/index.js#L17 + + 'lessjs-2.5.3' => [ + 'lessDir' => "$fixtureDir/lessjs-2.5.3/less", + 'cssDir' => "$fixtureDir/lessjs-2.5.3/css", + 'overrideDir' => "$fixtureDir/lessjs-2.5.3/override", + ], + 'lessjs-2.5.3/compression' => [ + 'lessDir' => "$fixtureDir/lessjs-2.5.3/less/compression", + 'cssDir' => "$fixtureDir/lessjs-2.5.3/css/compression", + 'overrideDir' => "$fixtureDir/lessjs-2.5.3/override/compression", + 'options' => [ + 'compress' => true, + ], + ], + 'lessjs-2.5.3/strict-units' => [ + 'lessDir' => "$fixtureDir/lessjs-2.5.3/less/strict-units", + 'cssDir' => "$fixtureDir/lessjs-2.5.3/css/strict-units", + 'options' => [ + 'strictUnits' => true, + ], + ], + 'lessjs-2.5.3/include-path' => [ + 'lessDir' => "$fixtureDir/lessjs-2.5.3/less/include-path", + 'cssDir' => "$fixtureDir/lessjs-2.5.3/css/include-path", + 'overrideDir' => "$fixtureDir/lessjs-2.5.3/override/include-path", + 'options' => [ + 'import_dirs' => [ + "$fixtureDir/lessjs-2.5.3/data" => '', + "$fixtureDir/lessjs-2.5.3/less/import" => '', + ], + ], + ], +]; diff --git a/test/phpunit/FixturesTest.php b/test/phpunit/FixturesTest.php index 5037a9bf..102b0793 100644 --- a/test/phpunit/FixturesTest.php +++ b/test/phpunit/FixturesTest.php @@ -39,27 +39,29 @@ class phpunit_FixturesTest extends phpunit_bootstrap { 'mixins-guards' => true, // T352867 'urls' => true, // T353147 'variables' => true, // T352830, T352866 - ] + ], + 'lessjs-2.5.3/include-path' => [ + 'include-path' => true, // T353147, data-uri() + ], ]; public static function provideFixtures() { - foreach ( [ - 'less.php', - 'bug-reports', - 'lessjs-2.5.3', - ] as $group ) { - $outputDir = self::getFixtureDir() . "/$group/css"; - if ( !is_dir( $outputDir ) ) { + foreach ( ( + require __DIR__ . '/../fixtures.php' + ) as $group => $fixture ) { + $cssDir = $fixture['cssDir']; + $lessDir = $fixture['lessDir']; + $overrideDir = $fixture['overrideDir'] ?? null; + $options = $fixture['options'] ?? []; + if ( !is_dir( $cssDir ) ) { // Check because glob() tolerances non-existence - throw new RuntimeException( "Directory missing: $outputDir" ); + throw new RuntimeException( "Directory missing: $cssDir" ); } - foreach ( glob( "$outputDir/*.css" ) as $cssFile ) { + foreach ( glob( "$cssDir/*.css" ) as $cssFile ) { $name = basename( $cssFile, '.css' ); - // From /Fixtures/lessjs/css/something.css - // into /Fixtures/lessjs/less/name.less - $lessFile = dirname( dirname( $cssFile ) ) . '/less/' . $name . '.less'; - $overrideFile = dirname( dirname( $cssFile ) ) . '/override/' . $name . '.css'; - if ( file_exists( $overrideFile ) ) { + $lessFile = "$lessDir/$name.less"; + $overrideFile = $overrideDir ? "$overrideDir/$name.css" : null; + if ( $overrideFile && file_exists( $overrideFile ) ) { if ( file_get_contents( $overrideFile ) === file_get_contents( $cssFile ) ) { print "WARNING: Redundant override for $overrideFile\n"; } @@ -68,7 +70,7 @@ public static function provideFixtures() { if ( self::KNOWN_FAILURE[ $group ][ $name ] ?? false ) { continue; } - yield "Fixtures/$group $name" => [ $cssFile, $lessFile ]; + yield "Fixtures/$group $name" => [ $cssFile, $lessFile, $options ]; } } } @@ -76,11 +78,11 @@ public static function provideFixtures() { /** * @dataProvider provideFixtures */ - public function testFixture( $cssFile, $lessFile ) { + public function testFixture( $cssFile, $lessFile, $options ) { $expectedCSS = trim( file_get_contents( $cssFile ) ); // Check with standard parser - $parser = new Less_Parser(); + $parser = new Less_Parser( $options ); try { $parser->registerFunction( '_color', [ __CLASS__, 'FnColor' ] ); $parser->registerFunction( 'add', [ __CLASS__, 'FnAdd' ] ); @@ -94,13 +96,17 @@ public function testFixture( $cssFile, $lessFile ) { $this->assertSame( $expectedCSS, $css, "Standard compiler" ); // Check with cache - $options = [ 'cache_dir' => $this->cache_dir, - 'functions' => [ '_color' => [ __CLASS__, 'FnColor' ], - 'add' => [ __CLASS__, 'FnAdd' ], - 'increment' => [ __CLASS__, 'FnIncrement' ] ] ]; + $optionsWithCache = $options + [ + 'cache_dir' => $this->cache_dir, + 'functions' => [ + '_color' => [ __CLASS__, 'FnColor' ], + 'add' => [ __CLASS__, 'FnAdd' ], + 'increment' => [ __CLASS__, 'FnIncrement' ], + ], + ]; $files = [ $lessFile => '' ]; try { - $cacheFile = Less_Cache::Regen( $files, $options ); + $cacheFile = Less_Cache::Regen( $files, $optionsWithCache ); $css = file_get_contents( $this->cache_dir . '/' . $cacheFile ); } catch ( Less_Exception_Parser $e ) { $css = $e->getMessage(); @@ -110,7 +116,7 @@ public function testFixture( $cssFile, $lessFile ) { // Check using the cached data try { - $cacheFile = Less_Cache::Get( $files, $options ); + $cacheFile = Less_Cache::Get( $files, $optionsWithCache ); $css = file_get_contents( $this->cache_dir . '/' . $cacheFile ); } catch ( Less_Exception_Parser $e ) { $css = $e->getMessage();