Further modules included.
[yaffs-website] / web / modules / contrib / drupalmoduleupgrader / src / Plugin / DMU / Converter / Tests.php
diff --git a/web/modules/contrib/drupalmoduleupgrader/src/Plugin/DMU/Converter/Tests.php b/web/modules/contrib/drupalmoduleupgrader/src/Plugin/DMU/Converter/Tests.php
new file mode 100644 (file)
index 0000000..d3e8b66
--- /dev/null
@@ -0,0 +1,201 @@
+<?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);
+  }
+
+}