diff --git a/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceRestTestCoverageTest.php b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceRestTestCoverageTest.php new file mode 100644 index 0000000000..afe111943c --- /dev/null +++ b/core/modules/rest/tests/src/Functional/EntityResource/EntityResourceRestTestCoverageTest.php @@ -0,0 +1,163 @@ +origin === 'core' && + empty($module->info['hidden']) && + !$module->status && + $module->info['package'] !== 'Testing' && + $module->info['package'] !== 'Core (Experimental)'; + }); + + $this->container->get('module_installer')->install(array_keys($stable_core_modules)); + $this->rebuildContainer(); + + $this->definitions = $this->container->get('entity_type.manager')->getDefinitions(); + + // Remove definitions for which the REST resource plugin definition was + // removed via hook_rest_resource_alter(). Entity types which are never + // exposed via REST also don't need test coverage. + $resource_plugin_ids = array_keys($this->container->get('plugin.manager.rest')->getDefinitions()); + foreach (array_keys($this->definitions) as $entity_type_id) { + if (!in_array("entity:$entity_type_id", $resource_plugin_ids, TRUE)) { + unset($this->definitions[$entity_type_id]); + } + } + } + + /** + * Tests that all core content/config entity types have REST test coverage. + */ + public function testEntityTypeRestTestCoverage() { + $default_test_locations = [ + // Test coverage for formats provided by the 'serialization' module. + 'serialization' => [ + 'possible paths' => [ + '\Drupal\Tests\rest\Functional\EntityResource\CLASS\CLASS', + ], + 'class suffix' => [ + 'JsonAnonTest', + 'JsonBasicAuthTest', + 'JsonCookieTest', + ], + ], + // Test coverage for formats provided by the 'hal' module. + 'hal' => [ + 'possible paths' => [ + '\Drupal\Tests\hal\Functional\EntityResource\CLASS\CLASS', + ], + 'class suffix' => [ + 'HalJsonAnonTest', + 'HalJsonBasicAuthTest', + 'HalJsonCookieTest', + ], + ], + ]; + + $problems = []; + foreach ($this->definitions as $entity_type_id => $info) { + $class_name_full = $info->getClass(); + $parts = explode('\\', $class_name_full); + $class_name = end($parts); + $module_name = $parts[1]; + + // The test class can live either in the REST/HAL module, or in the module + // providing the entity type. + $tests = $default_test_locations; + $tests['serialization']['possible paths'][] = '\Drupal\Tests\\' . $module_name . '\Functional\Rest\CLASS'; + $tests['hal']['possible paths'][] = '\Drupal\Tests\\' . $module_name . '\Functional\Hal\CLASS'; + + foreach ($tests as $module => $info) { + $possible_paths = $info['possible paths']; + foreach ($info['class suffix'] as $postfix) { + do { + $path = array_shift($possible_paths); + $class = str_replace('CLASS', $class_name, $path . $postfix); + if (class_exists($class)) { + continue 3; + } + } while (!empty($possible_paths)); + $problems[] = "$entity_type_id: $class_name ($class_name_full)"; + break 2; + } + } + } + $all = count($this->definitions); + $good = $all - count($problems); + // @todo Remove this in https://www.drupal.org/node/2843139. Having this + // work-around in here until then means we can ensure we don't add more + // entity types without adding REST test coverage. + if ($problems === ['file: File (Drupal\file\Entity\File)']) { + $problems = []; + } + elseif ($problems === []) { + $this->fail('Drupal\file\Entity\File now supports REST test coverage. We need remove @todo with work-around for pass it.'); + } + $this->assertSame([], $problems, $this->getLlamaMessage($good, $all)); + } + + /** + * Message from Llama. + * + * @param int $g + * A count of entities with test coverage. + * @param int $a + * A count of all entities. + * + * @return string + * An information about progress of REST test coverage. + */ + protected function getLlamaMessage($g, $a) { + return " +☼ + ________________________ + / Hi! \\ + | It's llame to not have | + | complete REST tests! | + | | + | Progress: $g/$a. | + | ________________________/ + |/ +// o +l'> +ll +llama +|| || +'' '' +"; + } + +}