Version 1
[yaffs-website] / web / core / tests / Drupal / KernelTests / Core / Theme / RegistryTest.php
diff --git a/web/core/tests/Drupal/KernelTests/Core/Theme/RegistryTest.php b/web/core/tests/Drupal/KernelTests/Core/Theme/RegistryTest.php
new file mode 100644 (file)
index 0000000..a962fec
--- /dev/null
@@ -0,0 +1,195 @@
+<?php
+
+namespace Drupal\KernelTests\Core\Theme;
+
+use Drupal\Core\Path\CurrentPathStack;
+use Drupal\Core\Path\PathMatcherInterface;
+use Drupal\Core\Theme\Registry;
+use Drupal\Core\Utility\ThemeRegistry;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests the behavior of the ThemeRegistry class.
+ *
+ * @group Theme
+ */
+class RegistryTest extends KernelTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = ['theme_test', 'system'];
+
+  protected $profile = 'testing';
+
+  /**
+   * Tests the behavior of the theme registry class.
+   */
+  public function testRaceCondition() {
+    // The theme registry is not marked as persistable in case we don't have a
+    // proper request.
+    \Drupal::request()->setMethod('GET');
+    $cid = 'test_theme_registry';
+
+    // Directly instantiate the theme registry, this will cause a base cache
+    // entry to be written in __construct().
+    $cache = \Drupal::cache();
+    $lock_backend = \Drupal::lock();
+    $registry = new ThemeRegistry($cid, $cache, $lock_backend, ['theme_registry'], $this->container->get('module_handler')->isLoaded());
+
+    $this->assertTrue(\Drupal::cache()->get($cid), 'Cache entry was created.');
+
+    // Trigger a cache miss for an offset.
+    $this->assertTrue($registry->get('theme_test_template_test'), 'Offset was returned correctly from the theme registry.');
+    // This will cause the ThemeRegistry class to write an updated version of
+    // the cache entry when it is destroyed, usually at the end of the request.
+    // Before that happens, manually delete the cache entry we created earlier
+    // so that the new entry is written from scratch.
+    \Drupal::cache()->delete($cid);
+
+    // Destroy the class so that it triggers a cache write for the offset.
+    $registry->destruct();
+
+    $this->assertTrue(\Drupal::cache()->get($cid), 'Cache entry was created.');
+
+    // Create a new instance of the class. Confirm that both the offset
+    // requested previously, and one that has not yet been requested are both
+    // available.
+    $registry = new ThemeRegistry($cid, $cache, $lock_backend, ['theme_registry'], $this->container->get('module_handler')->isLoaded());
+    $this->assertTrue($registry->get('theme_test_template_test'), 'Offset was returned correctly from the theme registry');
+    $this->assertTrue($registry->get('theme_test_template_test_2'), 'Offset was returned correctly from the theme registry');
+  }
+
+  /**
+   * Tests the theme registry with multiple subthemes.
+   */
+  public function testMultipleSubThemes() {
+    $theme_handler = \Drupal::service('theme_handler');
+    $theme_handler->install(['test_basetheme', 'test_subtheme', 'test_subsubtheme']);
+
+    $registry_subsub_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_subsubtheme');
+    $registry_subsub_theme->setThemeManager(\Drupal::theme());
+    $registry_sub_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_subtheme');
+    $registry_sub_theme->setThemeManager(\Drupal::theme());
+    $registry_base_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_basetheme');
+    $registry_base_theme->setThemeManager(\Drupal::theme());
+
+    $preprocess_functions = $registry_subsub_theme->get()['theme_test_template_test']['preprocess functions'];
+    $this->assertIdentical([
+      'template_preprocess',
+      'test_basetheme_preprocess_theme_test_template_test',
+      'test_subtheme_preprocess_theme_test_template_test',
+      'test_subsubtheme_preprocess_theme_test_template_test',
+    ], $preprocess_functions);
+
+    $preprocess_functions = $registry_sub_theme->get()['theme_test_template_test']['preprocess functions'];
+    $this->assertIdentical([
+      'template_preprocess',
+      'test_basetheme_preprocess_theme_test_template_test',
+      'test_subtheme_preprocess_theme_test_template_test',
+    ], $preprocess_functions);
+
+    $preprocess_functions = $registry_base_theme->get()['theme_test_template_test']['preprocess functions'];
+    $this->assertIdentical([
+      'template_preprocess',
+      'test_basetheme_preprocess_theme_test_template_test',
+    ], $preprocess_functions);
+
+    $preprocess_functions = $registry_base_theme->get()['theme_test_function_suggestions']['preprocess functions'];
+    $this->assertIdentical([
+       'template_preprocess_theme_test_function_suggestions',
+       'test_basetheme_preprocess_theme_test_function_suggestions',
+    ], $preprocess_functions, "Theme functions don't have template_preprocess but do have template_preprocess_HOOK");
+  }
+
+  /**
+   * Tests the theme registry with suggestions.
+   */
+  public function testSuggestionPreprocessFunctions() {
+    $theme_handler = \Drupal::service('theme_handler');
+    $theme_handler->install(['test_theme']);
+
+    $registry_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_theme');
+    $registry_theme->setThemeManager(\Drupal::theme());
+
+    $suggestions = ['__kitten', '__flamingo'];
+    $expected_preprocess_functions = [
+      'template_preprocess',
+      'theme_test_preprocess_theme_test_preprocess_suggestions',
+    ];
+    $suggestion = '';
+    $hook = 'theme_test_preprocess_suggestions';
+    do {
+      $hook .= "$suggestion";
+      $expected_preprocess_functions[] = "test_theme_preprocess_$hook";
+      $preprocess_functions = $registry_theme->get()[$hook]['preprocess functions'];
+      $this->assertIdentical($expected_preprocess_functions, $preprocess_functions, "$hook has correct preprocess functions.");
+    } while ($suggestion = array_shift($suggestions));
+
+    $expected_preprocess_functions = [
+      'template_preprocess',
+      'theme_test_preprocess_theme_test_preprocess_suggestions',
+      'test_theme_preprocess_theme_test_preprocess_suggestions',
+      'test_theme_preprocess_theme_test_preprocess_suggestions__kitten',
+    ];
+
+    $preprocess_functions = $registry_theme->get()['theme_test_preprocess_suggestions__kitten__meerkat']['preprocess functions'];
+    $this->assertIdentical($expected_preprocess_functions, $preprocess_functions, 'Suggestion implemented as a function correctly inherits preprocess functions.');
+
+    $preprocess_functions = $registry_theme->get()['theme_test_preprocess_suggestions__kitten__bearcat']['preprocess functions'];
+    $this->assertIdentical($expected_preprocess_functions, $preprocess_functions, 'Suggestion implemented as a template correctly inherits preprocess functions.');
+
+    $this->assertTrue(isset($registry_theme->get()['theme_test_preprocess_suggestions__kitten__meerkat__tarsier__moose']), 'Preprocess function with an unimplemented lower-level suggestion is added to the registry.');
+  }
+
+  /**
+   * Tests that the theme registry can be altered by themes.
+   */
+  public function testThemeRegistryAlterByTheme() {
+
+    /** @var \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler */
+    $theme_handler = \Drupal::service('theme_handler');
+    $theme_handler->install(['test_theme']);
+    $this->config('system.theme')->set('default', 'test_theme')->save();
+
+    $registry = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_theme');
+    $registry->setThemeManager(\Drupal::theme());
+    $this->assertEqual('value', $registry->get()['theme_test_template_test']['variables']['additional']);
+  }
+
+  /**
+   * Tests front node theme suggestion generation.
+   */
+  public function testThemeSuggestions() {
+    // Mock the current page as the front page.
+    /** @var PathMatcherInterface $path_matcher */
+    $path_matcher = $this->prophesize(PathMatcherInterface::class);
+    $path_matcher->isFrontPage()->willReturn(TRUE);
+    $this->container->set('path.matcher', $path_matcher->reveal());
+    /** @var CurrentPathStack $path_matcher */
+    $path_current = $this->prophesize(CurrentPathStack::class);
+    $path_current->getPath()->willReturn('/node/1');
+    $this->container->set('path.current', $path_current->reveal());
+
+    // Check suggestions provided through hook_theme_suggestions_html().
+    $suggestions = \Drupal::moduleHandler()->invokeAll('theme_suggestions_html', [[]]);
+    $this->assertSame([
+      'html__node',
+      'html__node__%',
+      'html__node__1',
+      'html__front',
+    ], $suggestions, 'Found expected html node suggestions.');
+
+    // Check suggestions provided through hook_theme_suggestions_page().
+    $suggestions = \Drupal::moduleHandler()->invokeAll('theme_suggestions_page', [[]]);
+    $this->assertSame([
+      'page__node',
+      'page__node__%',
+      'page__node__1',
+      'page__front',
+    ], $suggestions, 'Found expected page node suggestions.');
+  }
+
+}