drupalmoduleupgrader-8.x-1.5/src/Plugin/DMU/Converter/Tests.php
src/Plugin/DMU/Converter/Tests.php
<?php namespace Drupal\drupalmoduleupgrader\Plugin\DMU\Converter; use Drupal\drupalmoduleupgrader\ConverterBase; use Drupal\drupalmoduleupgrader\TargetInterface; use Drupal\drupalmoduleupgrader\Utility\Filter\ContainsLogicFilter; use Pharborist\DocCommentNode; use Pharborist\Filter; use Pharborist\Objects\ClassMemberNode; use Pharborist\Objects\ClassMethodCallNode; use Pharborist\Objects\ClassNode; use Pharborist\Parser; use Pharborist\RootNode; use Pharborist\Types\StringNode; use Pharborist\WhitespaceNode; /** * @Converter( * id = "tests", * description = @Translation("Modifies test classes.") * ) */ class Tests extends ConverterBase { private $target; /** * {@inheritdoc} */ public function isExecutable(TargetInterface $target) { foreach (['DrupalTestCase', 'DrupalWebTestCase'] as $parent_class) { if ($target->getIndexer('class')->getQuery()->condition('parent', $parent_class)->countQuery()->execute()) { return TRUE; } } return FALSE; } /** * {@inheritdoc} */ public function convert(TargetInterface $target) { $this->target = $target; $mapping = [ 'DrupalWebTestCase' => 'convertWeb', 'AJAXTestCase' => 'convertAjax', ]; foreach ($mapping as $parent_class => $convert_method) { $test_files = $target->getIndexer('class')->getQuery(['file'])->condition('parent', $parent_class)->execute()->fetchCol(); foreach ($test_files as $test_file) { /** @var \Pharborist\Objects\Classnode[] $tests */ $tests = $target->open($test_file)->find(Filter::isInstanceOf('\Pharborist\Objects\SingleInheritanceNode'))->toArray(); foreach ($tests as $test) { if ((string) $test->getExtends() === $parent_class) { $this->$convert_method($test); } } } } } /** * Converts a single web test. * * @param \Pharborist\Objects\ClassNode $test */ public function convertWeb(ClassNode $test) { $test->setExtends('\Drupal\simpletest\WebTestBase'); $this->convertInfo($test); $this->setModules($test); $this->setProfile($test); $this->move($test); } /** * Converts the test's getInfo() method to an annotation. * * @param \Pharborist\Objects\ClassNode $test */ private function convertInfo(ClassNode $test) { $info = $this->extractInfo($test); if ($info) { $comment = ''; $comment .= $info['description'] . "\n\n"; $comment .= '@group ' . $this->target->id(); if (isset($info['dependencies'])) { $comment .= "\n"; foreach ($info['dependencies'] as $module) { $comment .= '@requires module . ' . $module . "\n"; } } $test->setDocComment(DocCommentNode::create($comment)); } else { $this->log->error('Could not get info for test {class}.', [ 'class' => $test->getName(), ]); } } /** * Extracts the return value of the test's getInfo() method, if there's no * logic in the method. * * @param \Pharborist\Objects\ClassNode $test * * @return array|null */ private function extractInfo(ClassNode $test) { if ($test->hasMethod('getInfo')) { $info = $test->getMethod('getInfo'); if (!$info->is(new ContainsLogicFilter())) { return eval($info->getBody()->getText()); } } } /** * Sets the test's $modules property. * * @param \Pharborist\Objects\ClassNode $test */ private function setModules(ClassNode $test) { $modules = $this->extractModules($test); if ($modules) { // @todo Use ClassNode::createProperty() when #124 lands in Pharborist $property = Parser::parseSnippet('class Foo { public static $modules = ["' . implode('", "', $modules) . '"]; }') ->getBody() ->firstChild() ->remove(); $test->appendProperty($property); } } /** * Extracts every module required by a web test by scanning its calls * to parent::setUp(). * * @param \Pharborist\Objects\ClassNode $test * * @return string[] * Array of modules set up by this module. */ private function extractModules(ClassNode $test) { $modules = []; $test ->find(Filter::isClassMethodCall('parent', 'setUp')) ->filter(function (ClassMethodCallNode $call) { return (sizeof($call->getArguments()) > 0); }) ->each(function (ClassMethodCallNode $call) use (&$modules) { foreach ($call->getArguments() as $argument) { if ($argument instanceof StringNode) { $modules[] = $argument->toValue(); } } $call->clearArguments(); }); return array_unique($modules); } /** * Sets the test's $profile property. * * @param \Pharborist\Objects\ClassNode $test */ private function setProfile(ClassNode $test) { if (!$test->hasProperty('profile')) { $test->appendProperty(ClassMemberNode::create('profile', StringNode::create("'standard'"), 'protected')); } } public function move(ClassNode $test) { $ns = 'Drupal\\' . $this->target->id() . '\\Tests'; RootNode::create($ns)->getNamespace($ns)->append($test->remove()); WhitespaceNode::create("\n\n")->insertBefore($test); $this->writeClass($this->target, $test); } /** * Converts a single Ajax test. * * @param \Pharborist\Objects\ClassNode $test */ public function convertAjax(ClassNode $test) { $test->setExtends('\Drupal\system\Tests\Ajax\AjaxTestBase'); $this->setModules($test); $this->move($test); } }