3 namespace Drupal\drupalmoduleupgrader\Plugin\DMU\Converter;
5 use Drupal\drupalmoduleupgrader\ConverterBase;
6 use Drupal\drupalmoduleupgrader\TargetInterface;
7 use Drupal\drupalmoduleupgrader\Utility\Filter\ContainsLogicFilter;
8 use Pharborist\DocCommentNode;
10 use Pharborist\Objects\ClassMemberNode;
11 use Pharborist\Objects\ClassMethodCallNode;
12 use Pharborist\Objects\ClassNode;
13 use Pharborist\Parser;
14 use Pharborist\RootNode;
15 use Pharborist\Types\StringNode;
16 use Pharborist\WhitespaceNode;
21 * description = @Translation("Modifies test classes.")
24 class Tests extends ConverterBase {
31 public function isExecutable(TargetInterface $target) {
32 foreach (['DrupalTestCase', 'DrupalWebTestCase'] as $parent_class) {
33 if ($target->getIndexer('class')->getQuery()->condition('parent', $parent_class)->countQuery()->execute()) {
43 public function convert(TargetInterface $target) {
44 $this->target = $target;
47 'DrupalWebTestCase' => 'convertWeb',
48 'AJAXTestCase' => 'convertAjax',
50 foreach ($mapping as $parent_class => $convert_method) {
51 $test_files = $target->getIndexer('class')->getQuery(['file'])->condition('parent', $parent_class)->execute()->fetchCol();
52 foreach ($test_files as $test_file) {
53 /** @var \Pharborist\Objects\Classnode[] $tests */
54 $tests = $target->open($test_file)->find(Filter::isInstanceOf('\Pharborist\Objects\SingleInheritanceNode'))->toArray();
55 foreach ($tests as $test) {
56 if ((string) $test->getExtends() === $parent_class) {
57 $this->$convert_method($test);
65 * Converts a single web test.
67 * @param \Pharborist\Objects\ClassNode $test
69 public function convertWeb(ClassNode $test) {
70 $test->setExtends('\Drupal\simpletest\WebTestBase');
71 $this->convertInfo($test);
72 $this->setModules($test);
73 $this->setProfile($test);
78 * Converts the test's getInfo() method to an annotation.
80 * @param \Pharborist\Objects\ClassNode $test
82 private function convertInfo(ClassNode $test) {
83 $info = $this->extractInfo($test);
87 $comment .= $info['description'] . "\n\n";
88 $comment .= '@group ' . $this->target->id();
90 if (isset($info['dependencies'])) {
92 foreach ($info['dependencies'] as $module) {
93 $comment .= '@requires module . ' . $module . "\n";
97 $test->setDocComment(DocCommentNode::create($comment));
100 $this->log->error('Could not get info for test {class}.', [
101 'class' => $test->getName(),
107 * Extracts the return value of the test's getInfo() method, if there's no
108 * logic in the method.
110 * @param \Pharborist\Objects\ClassNode $test
114 private function extractInfo(ClassNode $test) {
115 if ($test->hasMethod('getInfo')) {
116 $info = $test->getMethod('getInfo');
118 if (! $info->is(new ContainsLogicFilter())) {
119 return eval($info->getBody()->getText());
125 * Sets the test's $modules property.
127 * @param \Pharborist\Objects\ClassNode $test
129 private function setModules(ClassNode $test) {
130 $modules = $this->extractModules($test);
132 // @todo Use ClassNode::createProperty() when #124 lands in Pharborist
133 $property = Parser::parseSnippet('class Foo { public static $modules = ["' . implode('", "', $modules) . '"]; }')
137 $test->appendProperty($property);
142 * Extracts every module required by a web test by scanning its calls
143 * to parent::setUp().
145 * @param \Pharborist\Objects\ClassNode $test
148 * Array of modules set up by this module.
150 private function extractModules(ClassNode $test) {
154 ->find(Filter::isClassMethodCall('parent', 'setUp'))
155 ->filter(function(ClassMethodCallNode $call) {
156 return (sizeof($call->getArguments()) > 0);
158 ->each(function(ClassMethodCallNode $call) use (&$modules) {
159 foreach ($call->getArguments() as $argument) {
160 if ($argument instanceof StringNode) {
161 $modules[] = $argument->toValue();
165 $call->clearArguments();
168 return array_unique($modules);
172 * Sets the test's $profile property.
174 * @param \Pharborist\Objects\ClassNode $test
176 private function setProfile(ClassNode $test) {
177 if (! $test->hasProperty('profile')) {
178 $test->appendProperty(ClassMemberNode::create('profile', StringNode::create("'standard'"), 'protected'));
182 public function move(ClassNode $test) {
183 $ns = 'Drupal\\' . $this->target->id() . '\\Tests';
184 RootNode::create($ns)->getNamespace($ns)->append($test->remove());
185 WhitespaceNode::create("\n\n")->insertBefore($test);
187 $this->writeClass($this->target, $test);
191 * Converts a single Ajax test.
193 * @param \Pharborist\Objects\ClassNode $test
195 public function convertAjax(ClassNode $test) {
196 $test->setExtends('\Drupal\system\Tests\Ajax\AjaxTestBase');
197 $this->setModules($test);