Loading core/tests/Drupal/BuildTests/Command/GenerateThemeTest.php +126 −55 Original line number Diff line number Diff line Loading @@ -30,6 +30,16 @@ class GenerateThemeTest extends QuickStartTestBase { */ protected $php; /** * The unaltered starterkit.info.yml contents. */ protected array $originalInfo; /** * The location of the starter kit .info.yml file. */ protected string $starterKitInfoYamlLocation; /** * {@inheritdoc} */ Loading @@ -44,6 +54,8 @@ protected function setUp(): void { $this->copyCodebase(); $this->executeCommand('COMPOSER_DISCARD_CHANGES=true composer install --no-dev --no-interaction'); chdir($this->getWorkingPath()); $this->starterKitInfoYamlLocation = $this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/starterkit_theme.info.yml'; $this->originalInfo = yaml::decode(file_get_contents($this->starterKitInfoYamlLocation)); } /** Loading Loading @@ -189,16 +201,39 @@ private function assertThemeExists(string $theme_path_relative): array { } /** * Tests the generate-theme command. * Delete the generated theme. */ protected function deleteGeneratedTheme(string $theme_name): void { $this->fileUnmanagedDeleteRecursive('themes/' . $theme_name); } /** * Set a version in the .info.yml. */ public function test(): void { protected function setVersion(string $version): void { // Do not rely on \Drupal::VERSION: change the version to a concrete version // number, to simulate using a tagged core release. $starterkit_info_yml = $this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/starterkit_theme.info.yml'; $info = Yaml::decode(file_get_contents($starterkit_info_yml)); $info['version'] = '9.4.0'; file_put_contents($starterkit_info_yml, Yaml::encode($info)); $info = $this->originalInfo; $info['version'] = $version; file_put_contents($this->starterKitInfoYamlLocation, Yaml::encode($info)); } /** * Tests the generate-theme command. */ public function testGenerateTheme(): void { $this->doTestGenerateTheme(); $this->deleteGeneratedTheme('test_custom_theme'); $this->doTestGeneratingFromAnotherTheme(); $this->deleteGeneratedTheme('test_custom_theme'); $this->doTestDevSnapshot(); $this->deleteGeneratedTheme('test_custom_theme'); $this->doTestContribStarterkit(); $this->deleteGeneratedTheme('test_custom_theme'); } protected function doTestGenerateTheme(): void { $this->setVersion('9.4.0'); $process = $this->generateThemeFromStarterkit(); $result = $process->run(); $this->assertStringContainsString('Theme generated successfully to themes/test_custom_theme', trim($process->getOutput()), $process->getErrorOutput()); Loading Loading @@ -239,13 +274,8 @@ public function test(): void { /** * Tests generating a theme from another Starterkit enabled theme. */ public function testGeneratingFromAnotherTheme(): void { // Do not rely on \Drupal::VERSION: change the version to a concrete version // number, to simulate using a tagged core release. $starterkit_info_yml = $this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/starterkit_theme.info.yml'; $info = Yaml::decode(file_get_contents($starterkit_info_yml)); $info['version'] = '9.4.0'; file_put_contents($starterkit_info_yml, Yaml::encode($info)); protected function doTestGeneratingFromAnotherTheme(): void { $this->setVersion('9.4.0'); $process = $this->generateThemeFromStarterkit(); $exit_code = $process->run(); Loading Loading @@ -278,18 +308,14 @@ public function testGeneratingFromAnotherTheme(): void { // Confirm new .theme file. $dot_theme_file = $this->getWorkspaceDirectory() . '/themes/generated_from_another_theme/src/Hook/GeneratedFromAnotherThemeHooks.php'; $this->assertStringContainsString('public function preprocessImageWidget(array &$variables): void {', file_get_contents($dot_theme_file)); $this->deleteGeneratedTheme('generated_from_another_theme'); } /** * Tests the generate-theme command on a dev snapshot of Drupal core. */ public function testDevSnapshot(): void { // Do not rely on \Drupal::VERSION: change the version to a development // snapshot version number, to simulate using a branch snapshot of core. $starterkit_info_yml = $this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/starterkit_theme.info.yml'; $info = Yaml::decode(file_get_contents($starterkit_info_yml)); $info['version'] = '9.4.0-dev'; file_put_contents($starterkit_info_yml, Yaml::encode($info)); protected function doTestDevSnapshot(): void { $this->setVersion('9.4.0-dev'); $process = $this->generateThemeFromStarterkit(); $result = $process->run(); Loading @@ -306,13 +332,8 @@ public function testDevSnapshot(): void { /** * Tests the generate-theme command on a theme with a release version number. */ public function testContribStarterkit(): void { // Change the version to a concrete version number, to simulate using a // contrib theme as the starterkit. $starterkit_info_yml = $this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/starterkit_theme.info.yml'; $info = Yaml::decode(file_get_contents($starterkit_info_yml)); $info['version'] = '1.20'; file_put_contents($starterkit_info_yml, Yaml::encode($info)); protected function doTestContribStarterkit(): void { $this->setVersion('1.20'); $process = $this->generateThemeFromStarterkit(); $result = $process->run(); Loading Loading @@ -419,10 +440,41 @@ public function testCustomStarterkit(): void { self::assertEquals('starterkit_theme:unknown-version', $info['generator']); } public function testDeleteDirectory(): void { $this->writeStarterkitConfig([ 'ignore' => [ '/src/*', '/starterkit_theme.starterkit.yml', ], ]); $tester = $this->runCommand( [ 'machine-name' => 'test_custom_theme', '--name' => 'Test custom starterkit theme', '--description' => 'Custom theme generated from a starterkit theme', ] ); $tester->assertCommandIsSuccessful($tester->getErrorOutput()); $this->assertThemeExists('themes/test_custom_theme'); $theme_path_absolute = $this->getWorkspaceDirectory() . '/themes/test_custom_theme'; self::assertDirectoryExists($theme_path_absolute); self::assertFileDoesNotExist($theme_path_absolute . '/src/StarterKit.php'); } public function testInvalidThemesAndWarnings(): void { $this->doTestThemeDoesNotExist(); $this->doTestStarterKitFlag(); $this->doTestNoEditMissingFilesWarning(); $this->doTestNoRenameMissingFilesWarning(); $this->doTestNoRename(); } /** * Tests themes that do not exist return an error. */ public function testThemeDoesNotExist(): void { protected function doTestThemeDoesNotExist(): void { $install_command = [ $this->php, 'core/scripts/drupal', Loading @@ -443,7 +495,7 @@ public function testThemeDoesNotExist(): void { /** * Tests that only themes with `starterkit` flag can be used. */ public function testStarterKitFlag(): void { protected function doTestStarterKitFlag(): void { // Explicitly not a starter theme. $install_command = [ $this->php, Loading Loading @@ -479,34 +531,12 @@ public function testStarterKitFlag(): void { $this->assertSame(1, $result); } public function testDeleteDirectory(): void { $this->writeStarterkitConfig([ 'ignore' => [ '/src/*', '/starterkit_theme.starterkit.yml', ], ]); $tester = $this->runCommand( [ 'machine-name' => 'test_custom_theme', '--name' => 'Test custom starterkit theme', '--description' => 'Custom theme generated from a starterkit theme', ] ); $tester->assertCommandIsSuccessful($tester->getErrorOutput()); $this->assertThemeExists('themes/test_custom_theme'); $theme_path_absolute = $this->getWorkspaceDirectory() . '/themes/test_custom_theme'; self::assertDirectoryExists($theme_path_absolute); self::assertFileDoesNotExist($theme_path_absolute . '/src/StarterKit.php'); } public function testNoEditMissingFilesWarning(): void { protected function doTestNoEditMissingFilesWarning(): void { $this->writeStarterkitConfig([ 'no_edit' => [ '/js/starterkit_theme.js', ], 'no_rename' => NULL, ]); $tester = $this->runCommand( Loading @@ -523,11 +553,12 @@ public function testNoEditMissingFilesWarning(): void { self::assertDirectoryDoesNotExist($theme_path_absolute); } public function testNoRenameMissingFilesWarning(): void { protected function doTestNoRenameMissingFilesWarning(): void { $this->writeStarterkitConfig([ 'no_rename' => [ '/js/starterkit_theme.js', ], 'no_edit' => NULL, ]); $tester = $this->runCommand( Loading @@ -544,13 +575,14 @@ public function testNoRenameMissingFilesWarning(): void { self::assertDirectoryDoesNotExist($theme_path_absolute); } public function testNoRename(): void { protected function doTestNoRename(): void { $this->writeStarterkitConfig([ 'no_rename' => [ 'js/starterkit_theme.js', '**/js/*.js', 'js/**/*.js', ], 'no_edit' => NULL, ]); mkdir($this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/js'); Loading Loading @@ -763,4 +795,43 @@ private function runCommand(array $input): CommandTester { return $tester; } /** * Deletes all files and directories in the specified path recursively. * * Note this method has no dependencies on Drupal core to ensure that the * test site can be torn down even if something in the test site is broken. * * @param string $path * A string containing either a URI or a file or directory path. * @param callable $callback * (optional) Callback function to run on each file prior to deleting it and * on each directory prior to traversing it. For example, can be used to * modify permissions. * * @return bool * TRUE for success or if path does not exist, FALSE in the event of an * error. * * @see \Drupal\Core\File\FileSystemInterface::deleteRecursive() */ protected function fileUnmanagedDeleteRecursive($path, $callback = NULL): bool { if (isset($callback)) { call_user_func($callback, $path); } if (is_dir($path)) { $dir = dir($path); while (($entry = $dir->read()) !== FALSE) { if ($entry == '.' || $entry == '..') { continue; } $entry_path = $path . '/' . $entry; $this->fileUnmanagedDeleteRecursive($entry_path, $callback); } $dir->close(); return rmdir($path); } return unlink($path); } } Loading
core/tests/Drupal/BuildTests/Command/GenerateThemeTest.php +126 −55 Original line number Diff line number Diff line Loading @@ -30,6 +30,16 @@ class GenerateThemeTest extends QuickStartTestBase { */ protected $php; /** * The unaltered starterkit.info.yml contents. */ protected array $originalInfo; /** * The location of the starter kit .info.yml file. */ protected string $starterKitInfoYamlLocation; /** * {@inheritdoc} */ Loading @@ -44,6 +54,8 @@ protected function setUp(): void { $this->copyCodebase(); $this->executeCommand('COMPOSER_DISCARD_CHANGES=true composer install --no-dev --no-interaction'); chdir($this->getWorkingPath()); $this->starterKitInfoYamlLocation = $this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/starterkit_theme.info.yml'; $this->originalInfo = yaml::decode(file_get_contents($this->starterKitInfoYamlLocation)); } /** Loading Loading @@ -189,16 +201,39 @@ private function assertThemeExists(string $theme_path_relative): array { } /** * Tests the generate-theme command. * Delete the generated theme. */ protected function deleteGeneratedTheme(string $theme_name): void { $this->fileUnmanagedDeleteRecursive('themes/' . $theme_name); } /** * Set a version in the .info.yml. */ public function test(): void { protected function setVersion(string $version): void { // Do not rely on \Drupal::VERSION: change the version to a concrete version // number, to simulate using a tagged core release. $starterkit_info_yml = $this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/starterkit_theme.info.yml'; $info = Yaml::decode(file_get_contents($starterkit_info_yml)); $info['version'] = '9.4.0'; file_put_contents($starterkit_info_yml, Yaml::encode($info)); $info = $this->originalInfo; $info['version'] = $version; file_put_contents($this->starterKitInfoYamlLocation, Yaml::encode($info)); } /** * Tests the generate-theme command. */ public function testGenerateTheme(): void { $this->doTestGenerateTheme(); $this->deleteGeneratedTheme('test_custom_theme'); $this->doTestGeneratingFromAnotherTheme(); $this->deleteGeneratedTheme('test_custom_theme'); $this->doTestDevSnapshot(); $this->deleteGeneratedTheme('test_custom_theme'); $this->doTestContribStarterkit(); $this->deleteGeneratedTheme('test_custom_theme'); } protected function doTestGenerateTheme(): void { $this->setVersion('9.4.0'); $process = $this->generateThemeFromStarterkit(); $result = $process->run(); $this->assertStringContainsString('Theme generated successfully to themes/test_custom_theme', trim($process->getOutput()), $process->getErrorOutput()); Loading Loading @@ -239,13 +274,8 @@ public function test(): void { /** * Tests generating a theme from another Starterkit enabled theme. */ public function testGeneratingFromAnotherTheme(): void { // Do not rely on \Drupal::VERSION: change the version to a concrete version // number, to simulate using a tagged core release. $starterkit_info_yml = $this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/starterkit_theme.info.yml'; $info = Yaml::decode(file_get_contents($starterkit_info_yml)); $info['version'] = '9.4.0'; file_put_contents($starterkit_info_yml, Yaml::encode($info)); protected function doTestGeneratingFromAnotherTheme(): void { $this->setVersion('9.4.0'); $process = $this->generateThemeFromStarterkit(); $exit_code = $process->run(); Loading Loading @@ -278,18 +308,14 @@ public function testGeneratingFromAnotherTheme(): void { // Confirm new .theme file. $dot_theme_file = $this->getWorkspaceDirectory() . '/themes/generated_from_another_theme/src/Hook/GeneratedFromAnotherThemeHooks.php'; $this->assertStringContainsString('public function preprocessImageWidget(array &$variables): void {', file_get_contents($dot_theme_file)); $this->deleteGeneratedTheme('generated_from_another_theme'); } /** * Tests the generate-theme command on a dev snapshot of Drupal core. */ public function testDevSnapshot(): void { // Do not rely on \Drupal::VERSION: change the version to a development // snapshot version number, to simulate using a branch snapshot of core. $starterkit_info_yml = $this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/starterkit_theme.info.yml'; $info = Yaml::decode(file_get_contents($starterkit_info_yml)); $info['version'] = '9.4.0-dev'; file_put_contents($starterkit_info_yml, Yaml::encode($info)); protected function doTestDevSnapshot(): void { $this->setVersion('9.4.0-dev'); $process = $this->generateThemeFromStarterkit(); $result = $process->run(); Loading @@ -306,13 +332,8 @@ public function testDevSnapshot(): void { /** * Tests the generate-theme command on a theme with a release version number. */ public function testContribStarterkit(): void { // Change the version to a concrete version number, to simulate using a // contrib theme as the starterkit. $starterkit_info_yml = $this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/starterkit_theme.info.yml'; $info = Yaml::decode(file_get_contents($starterkit_info_yml)); $info['version'] = '1.20'; file_put_contents($starterkit_info_yml, Yaml::encode($info)); protected function doTestContribStarterkit(): void { $this->setVersion('1.20'); $process = $this->generateThemeFromStarterkit(); $result = $process->run(); Loading Loading @@ -419,10 +440,41 @@ public function testCustomStarterkit(): void { self::assertEquals('starterkit_theme:unknown-version', $info['generator']); } public function testDeleteDirectory(): void { $this->writeStarterkitConfig([ 'ignore' => [ '/src/*', '/starterkit_theme.starterkit.yml', ], ]); $tester = $this->runCommand( [ 'machine-name' => 'test_custom_theme', '--name' => 'Test custom starterkit theme', '--description' => 'Custom theme generated from a starterkit theme', ] ); $tester->assertCommandIsSuccessful($tester->getErrorOutput()); $this->assertThemeExists('themes/test_custom_theme'); $theme_path_absolute = $this->getWorkspaceDirectory() . '/themes/test_custom_theme'; self::assertDirectoryExists($theme_path_absolute); self::assertFileDoesNotExist($theme_path_absolute . '/src/StarterKit.php'); } public function testInvalidThemesAndWarnings(): void { $this->doTestThemeDoesNotExist(); $this->doTestStarterKitFlag(); $this->doTestNoEditMissingFilesWarning(); $this->doTestNoRenameMissingFilesWarning(); $this->doTestNoRename(); } /** * Tests themes that do not exist return an error. */ public function testThemeDoesNotExist(): void { protected function doTestThemeDoesNotExist(): void { $install_command = [ $this->php, 'core/scripts/drupal', Loading @@ -443,7 +495,7 @@ public function testThemeDoesNotExist(): void { /** * Tests that only themes with `starterkit` flag can be used. */ public function testStarterKitFlag(): void { protected function doTestStarterKitFlag(): void { // Explicitly not a starter theme. $install_command = [ $this->php, Loading Loading @@ -479,34 +531,12 @@ public function testStarterKitFlag(): void { $this->assertSame(1, $result); } public function testDeleteDirectory(): void { $this->writeStarterkitConfig([ 'ignore' => [ '/src/*', '/starterkit_theme.starterkit.yml', ], ]); $tester = $this->runCommand( [ 'machine-name' => 'test_custom_theme', '--name' => 'Test custom starterkit theme', '--description' => 'Custom theme generated from a starterkit theme', ] ); $tester->assertCommandIsSuccessful($tester->getErrorOutput()); $this->assertThemeExists('themes/test_custom_theme'); $theme_path_absolute = $this->getWorkspaceDirectory() . '/themes/test_custom_theme'; self::assertDirectoryExists($theme_path_absolute); self::assertFileDoesNotExist($theme_path_absolute . '/src/StarterKit.php'); } public function testNoEditMissingFilesWarning(): void { protected function doTestNoEditMissingFilesWarning(): void { $this->writeStarterkitConfig([ 'no_edit' => [ '/js/starterkit_theme.js', ], 'no_rename' => NULL, ]); $tester = $this->runCommand( Loading @@ -523,11 +553,12 @@ public function testNoEditMissingFilesWarning(): void { self::assertDirectoryDoesNotExist($theme_path_absolute); } public function testNoRenameMissingFilesWarning(): void { protected function doTestNoRenameMissingFilesWarning(): void { $this->writeStarterkitConfig([ 'no_rename' => [ '/js/starterkit_theme.js', ], 'no_edit' => NULL, ]); $tester = $this->runCommand( Loading @@ -544,13 +575,14 @@ public function testNoRenameMissingFilesWarning(): void { self::assertDirectoryDoesNotExist($theme_path_absolute); } public function testNoRename(): void { protected function doTestNoRename(): void { $this->writeStarterkitConfig([ 'no_rename' => [ 'js/starterkit_theme.js', '**/js/*.js', 'js/**/*.js', ], 'no_edit' => NULL, ]); mkdir($this->getWorkspaceDirectory() . '/core/themes/starterkit_theme/js'); Loading Loading @@ -763,4 +795,43 @@ private function runCommand(array $input): CommandTester { return $tester; } /** * Deletes all files and directories in the specified path recursively. * * Note this method has no dependencies on Drupal core to ensure that the * test site can be torn down even if something in the test site is broken. * * @param string $path * A string containing either a URI or a file or directory path. * @param callable $callback * (optional) Callback function to run on each file prior to deleting it and * on each directory prior to traversing it. For example, can be used to * modify permissions. * * @return bool * TRUE for success or if path does not exist, FALSE in the event of an * error. * * @see \Drupal\Core\File\FileSystemInterface::deleteRecursive() */ protected function fileUnmanagedDeleteRecursive($path, $callback = NULL): bool { if (isset($callback)) { call_user_func($callback, $path); } if (is_dir($path)) { $dir = dir($path); while (($entry = $dir->read()) !== FALSE) { if ($entry == '.' || $entry == '..') { continue; } $entry_path = $path . '/' . $entry; $this->fileUnmanagedDeleteRecursive($entry_path, $callback); } $dir->close(); return rmdir($path); } return unlink($path); } }