Further modules included.
[yaffs-website] / web / modules / contrib / drupalmoduleupgrader / src / Plugin / DMU / Converter / Tests.php
1 <?php
2
3 namespace Drupal\drupalmoduleupgrader\Plugin\DMU\Converter;
4
5 use Drupal\drupalmoduleupgrader\ConverterBase;
6 use Drupal\drupalmoduleupgrader\TargetInterface;
7 use Drupal\drupalmoduleupgrader\Utility\Filter\ContainsLogicFilter;
8 use Pharborist\DocCommentNode;
9 use Pharborist\Filter;
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;
17
18 /**
19  * @Converter(
20  *  id = "tests",
21  *  description = @Translation("Modifies test classes.")
22  * )
23  */
24 class Tests extends ConverterBase {
25
26   private $target;
27
28   /**
29    * {@inheritdoc}
30    */
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()) {
34         return TRUE;
35       }
36     }
37     return FALSE;
38   }
39
40   /**
41    * {@inheritdoc}
42    */
43   public function convert(TargetInterface $target) {
44     $this->target = $target;
45
46     $mapping = [
47       'DrupalWebTestCase' => 'convertWeb',
48       'AJAXTestCase' => 'convertAjax',
49     ];
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);
58           }
59         }
60       }
61     }
62   }
63
64   /**
65    * Converts a single web test.
66    *
67    * @param \Pharborist\Objects\ClassNode $test
68    */
69   public function convertWeb(ClassNode $test) {
70     $test->setExtends('\Drupal\simpletest\WebTestBase');
71     $this->convertInfo($test);
72     $this->setModules($test);
73     $this->setProfile($test);
74     $this->move($test);
75   }
76
77   /**
78    * Converts the test's getInfo() method to an annotation.
79    *
80    * @param \Pharborist\Objects\ClassNode $test
81    */
82   private function convertInfo(ClassNode $test) {
83     $info = $this->extractInfo($test);
84
85     if ($info) {
86       $comment = '';
87       $comment .= $info['description'] . "\n\n";
88       $comment .= '@group ' . $this->target->id();
89
90       if (isset($info['dependencies'])) {
91         $comment .= "\n";
92         foreach ($info['dependencies'] as $module) {
93           $comment .= '@requires module . ' . $module . "\n";
94         }
95       }
96
97       $test->setDocComment(DocCommentNode::create($comment));
98     }
99     else {
100       $this->log->error('Could not get info for test {class}.', [
101         'class' => $test->getName(),
102       ]);
103     }
104   }
105
106   /**
107    * Extracts the return value of the test's getInfo() method, if there's no
108    * logic in the method.
109    *
110    * @param \Pharborist\Objects\ClassNode $test
111    *
112    * @return array|NULL
113    */
114   private function extractInfo(ClassNode $test) {
115     if ($test->hasMethod('getInfo')) {
116       $info = $test->getMethod('getInfo');
117
118       if (! $info->is(new ContainsLogicFilter())) {
119         return eval($info->getBody()->getText());
120       }
121     }
122   }
123
124   /**
125    * Sets the test's $modules property.
126    *
127    * @param \Pharborist\Objects\ClassNode $test
128    */
129   private function setModules(ClassNode $test) {
130     $modules = $this->extractModules($test);
131     if ($modules) {
132       // @todo Use ClassNode::createProperty() when #124 lands in Pharborist
133       $property = Parser::parseSnippet('class Foo { public static $modules = ["' . implode('", "', $modules) . '"]; }')
134         ->getBody()
135         ->firstChild()
136         ->remove();
137       $test->appendProperty($property);
138     }
139   }
140
141   /**
142    * Extracts every module required by a web test by scanning its calls
143    * to parent::setUp().
144    *
145    * @param \Pharborist\Objects\ClassNode $test
146    *
147    * @return string[]
148    *  Array of modules set up by this module.
149    */
150   private function extractModules(ClassNode $test) {
151     $modules = [];
152
153     $test
154       ->find(Filter::isClassMethodCall('parent', 'setUp'))
155       ->filter(function(ClassMethodCallNode $call) {
156         return (sizeof($call->getArguments()) > 0);
157       })
158       ->each(function(ClassMethodCallNode $call) use (&$modules) {
159         foreach ($call->getArguments() as $argument) {
160           if ($argument instanceof StringNode) {
161             $modules[] = $argument->toValue();
162           }
163         }
164
165         $call->clearArguments();
166       });
167
168     return array_unique($modules);
169   }
170
171   /**
172    * Sets the test's $profile property.
173    *
174    * @param \Pharborist\Objects\ClassNode $test
175    */
176   private function setProfile(ClassNode $test) {
177     if (! $test->hasProperty('profile')) {
178       $test->appendProperty(ClassMemberNode::create('profile', StringNode::create("'standard'"), 'protected'));
179     }
180   }
181
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);
186
187     $this->writeClass($this->target, $test);
188   }
189
190   /**
191    * Converts a single Ajax test.
192    *
193    * @param \Pharborist\Objects\ClassNode $test
194    */
195   public function convertAjax(ClassNode $test) {
196     $test->setExtends('\Drupal\system\Tests\Ajax\AjaxTestBase');
197     $this->setModules($test);
198     $this->move($test);
199   }
200
201 }