annotate core/modules/migrate/tests/src/Kernel/MigrateSourceTestBase.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Tests\migrate\Kernel;
Chris@0 4
Chris@0 5 use Drupal\KernelTests\KernelTestBase;
Chris@0 6 use Drupal\migrate\Plugin\MigrateIdMapInterface;
Chris@0 7 use Drupal\migrate\Plugin\MigrationInterface;
Chris@0 8 use Drupal\migrate\Row;
Chris@0 9
Chris@0 10 /**
Chris@0 11 * Base class for tests of Migrate source plugins.
Chris@0 12 */
Chris@0 13 abstract class MigrateSourceTestBase extends KernelTestBase {
Chris@0 14
Chris@0 15 /**
Chris@0 16 * {@inheritdoc}
Chris@0 17 */
Chris@0 18 public static $modules = ['migrate'];
Chris@0 19
Chris@0 20 /**
Chris@0 21 * The mocked migration.
Chris@0 22 *
Chris@12 23 * @var \Drupal\migrate\Plugin\MigrationInterface|\Prophecy\Prophecy\ObjectProphecy
Chris@0 24 */
Chris@0 25 protected $migration;
Chris@0 26
Chris@0 27 /**
Chris@0 28 * The source plugin under test.
Chris@0 29 *
Chris@0 30 * @var \Drupal\migrate\Plugin\MigrateSourceInterface
Chris@0 31 */
Chris@0 32 protected $plugin;
Chris@0 33
Chris@0 34 /**
Chris@0 35 * The data provider.
Chris@0 36 *
Chris@0 37 * @see \Drupal\Tests\migrate\Kernel\MigrateSourceTestBase::testSource
Chris@0 38 *
Chris@0 39 * @return array
Chris@0 40 * Array of data sets to test, each of which is a numerically indexed array
Chris@0 41 * with the following elements:
Chris@0 42 * - An array of source data, which can be optionally processed and set up
Chris@0 43 * by subclasses.
Chris@0 44 * - An array of expected result rows.
Chris@0 45 * - (optional) The number of result rows the plugin under test is expected
Chris@0 46 * to return. If this is not a numeric value, the plugin will not be
Chris@0 47 * counted.
Chris@0 48 * - (optional) Array of configuration options for the plugin under test.
Chris@0 49 */
Chris@0 50 abstract public function providerSource();
Chris@0 51
Chris@0 52 /**
Chris@0 53 * {@inheritdoc}
Chris@0 54 */
Chris@0 55 protected function setUp() {
Chris@0 56 parent::setUp();
Chris@0 57
Chris@0 58 // Create a mock migration. This will be injected into the source plugin
Chris@0 59 // under test.
Chris@0 60 $this->migration = $this->prophesize(MigrationInterface::class);
Chris@0 61
Chris@0 62 $this->migration->id()->willReturn(
Chris@0 63 $this->randomMachineName(16)
Chris@0 64 );
Chris@0 65 // Prophesize a useless ID map plugin and an empty set of destination IDs.
Chris@0 66 // Calling code can override these prophecies later and set up different
Chris@0 67 // behaviors.
Chris@0 68 $this->migration->getIdMap()->willReturn(
Chris@0 69 $this->prophesize(MigrateIdMapInterface::class)->reveal()
Chris@0 70 );
Chris@0 71 $this->migration->getDestinationIds()->willReturn([]);
Chris@0 72 }
Chris@0 73
Chris@0 74 /**
Chris@0 75 * Determines the plugin to be tested by reading the class @covers annotation.
Chris@0 76 *
Chris@0 77 * @return string
Chris@0 78 */
Chris@0 79 protected function getPluginClass() {
Chris@0 80 $annotations = $this->getAnnotations();
Chris@0 81
Chris@0 82 if (isset($annotations['class']['covers'])) {
Chris@0 83 return $annotations['class']['covers'][0];
Chris@0 84 }
Chris@0 85 else {
Chris@0 86 $this->fail('No plugin class was specified');
Chris@0 87 }
Chris@0 88 }
Chris@0 89
Chris@0 90 /**
Chris@0 91 * Instantiates the source plugin under test.
Chris@0 92 *
Chris@0 93 * @param array $configuration
Chris@0 94 * The source plugin configuration.
Chris@0 95 *
Chris@0 96 * @return \Drupal\migrate\Plugin\MigrateSourceInterface|object
Chris@0 97 * The fully configured source plugin.
Chris@0 98 */
Chris@0 99 protected function getPlugin(array $configuration) {
Chris@0 100 // Only create the plugin once per test.
Chris@0 101 if ($this->plugin) {
Chris@0 102 return $this->plugin;
Chris@0 103 }
Chris@0 104
Chris@0 105 $class = ltrim($this->getPluginClass(), '\\');
Chris@0 106
Chris@0 107 /** @var \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager */
Chris@0 108 $plugin_manager = $this->container->get('plugin.manager.migrate.source');
Chris@0 109
Chris@0 110 foreach ($plugin_manager->getDefinitions() as $id => $definition) {
Chris@0 111 if (ltrim($definition['class'], '\\') == $class) {
Chris@0 112 $this->plugin = $plugin_manager
Chris@0 113 ->createInstance($id, $configuration, $this->migration->reveal());
Chris@0 114
Chris@0 115 $this->migration
Chris@0 116 ->getSourcePlugin()
Chris@0 117 ->willReturn($this->plugin);
Chris@0 118
Chris@0 119 return $this->plugin;
Chris@0 120 }
Chris@0 121 }
Chris@0 122 $this->fail('No plugin found for class ' . $class);
Chris@0 123 }
Chris@0 124
Chris@0 125 /**
Chris@0 126 * Tests the source plugin against a particular data set.
Chris@0 127 *
Chris@0 128 * @param array $source_data
Chris@0 129 * The source data that the source plugin will read.
Chris@0 130 * @param array $expected_data
Chris@0 131 * The result rows the source plugin is expected to return.
Chris@0 132 * @param mixed $expected_count
Chris@0 133 * (optional) How many rows the source plugin is expected to return.
Chris@0 134 * Defaults to count($expected_data). If set to a non-null, non-numeric
Chris@0 135 * value (like FALSE or 'nope'), the source plugin will not be counted.
Chris@0 136 * @param array $configuration
Chris@0 137 * (optional) Configuration for the source plugin.
Chris@0 138 * @param mixed $high_water
Chris@0 139 * (optional) The value of the high water field.
Chris@0 140 *
Chris@0 141 * @dataProvider providerSource
Chris@0 142 */
Chris@0 143 public function testSource(array $source_data, array $expected_data, $expected_count = NULL, array $configuration = [], $high_water = NULL) {
Chris@0 144 $plugin = $this->getPlugin($configuration);
Chris@0 145
Chris@0 146 // All source plugins must define IDs.
Chris@0 147 $this->assertNotEmpty($plugin->getIds());
Chris@0 148
Chris@0 149 // If there is a high water mark, set it in the high water storage.
Chris@0 150 if (isset($high_water)) {
Chris@0 151 $this->container
Chris@0 152 ->get('keyvalue')
Chris@0 153 ->get('migrate:high_water')
Chris@0 154 ->set($this->migration->reveal()->id(), $high_water);
Chris@0 155 }
Chris@0 156
Chris@0 157 if (is_null($expected_count)) {
Chris@0 158 $expected_count = count($expected_data);
Chris@0 159 }
Chris@0 160 // If an expected count was given, assert it only if the plugin is
Chris@0 161 // countable.
Chris@0 162 if (is_numeric($expected_count)) {
Chris@0 163 $this->assertInstanceOf('\Countable', $plugin);
Chris@0 164 $this->assertCount($expected_count, $plugin);
Chris@0 165 }
Chris@0 166
Chris@0 167 $i = 0;
Chris@0 168 /** @var \Drupal\migrate\Row $row */
Chris@0 169 foreach ($plugin as $row) {
Chris@0 170 $this->assertInstanceOf(Row::class, $row);
Chris@0 171
Chris@0 172 $expected = $expected_data[$i++];
Chris@0 173 $actual = $row->getSource();
Chris@0 174
Chris@0 175 foreach ($expected as $key => $value) {
Chris@0 176 $this->assertArrayHasKey($key, $actual);
Chris@0 177
Chris@17 178 $msg = sprintf("Value at 'array[%s][%s]' is not correct.", $i - 1, $key);
Chris@0 179 if (is_array($value)) {
Chris@0 180 ksort($value);
Chris@0 181 ksort($actual[$key]);
Chris@17 182 $this->assertEquals($value, $actual[$key], $msg);
Chris@0 183 }
Chris@0 184 else {
Chris@17 185 $this->assertEquals((string) $value, (string) $actual[$key], $msg);
Chris@0 186 }
Chris@0 187 }
Chris@0 188 }
Chris@0 189 // False positives occur if the foreach is not entered. So, confirm the
Chris@0 190 // foreach loop was entered if the expected count is greater than 0.
Chris@0 191 if ($expected_count > 0) {
Chris@0 192 $this->assertGreaterThan(0, $i);
Chris@0 193 }
Chris@0 194 }
Chris@0 195
Chris@0 196 }