Chris@0: migration = $this->prophesize(MigrationInterface::class); Chris@0: Chris@0: $this->migration->id()->willReturn( Chris@0: $this->randomMachineName(16) Chris@0: ); Chris@0: // Prophesize a useless ID map plugin and an empty set of destination IDs. Chris@0: // Calling code can override these prophecies later and set up different Chris@0: // behaviors. Chris@0: $this->migration->getIdMap()->willReturn( Chris@0: $this->prophesize(MigrateIdMapInterface::class)->reveal() Chris@0: ); Chris@0: $this->migration->getDestinationIds()->willReturn([]); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Determines the plugin to be tested by reading the class @covers annotation. Chris@0: * Chris@0: * @return string Chris@0: */ Chris@0: protected function getPluginClass() { Chris@0: $annotations = $this->getAnnotations(); Chris@0: Chris@0: if (isset($annotations['class']['covers'])) { Chris@0: return $annotations['class']['covers'][0]; Chris@0: } Chris@0: else { Chris@0: $this->fail('No plugin class was specified'); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Instantiates the source plugin under test. Chris@0: * Chris@0: * @param array $configuration Chris@0: * The source plugin configuration. Chris@0: * Chris@0: * @return \Drupal\migrate\Plugin\MigrateSourceInterface|object Chris@0: * The fully configured source plugin. Chris@0: */ Chris@0: protected function getPlugin(array $configuration) { Chris@0: // Only create the plugin once per test. Chris@0: if ($this->plugin) { Chris@0: return $this->plugin; Chris@0: } Chris@0: Chris@0: $class = ltrim($this->getPluginClass(), '\\'); Chris@0: Chris@0: /** @var \Drupal\migrate\Plugin\MigratePluginManager $plugin_manager */ Chris@0: $plugin_manager = $this->container->get('plugin.manager.migrate.source'); Chris@0: Chris@0: foreach ($plugin_manager->getDefinitions() as $id => $definition) { Chris@0: if (ltrim($definition['class'], '\\') == $class) { Chris@0: $this->plugin = $plugin_manager Chris@0: ->createInstance($id, $configuration, $this->migration->reveal()); Chris@0: Chris@0: $this->migration Chris@0: ->getSourcePlugin() Chris@0: ->willReturn($this->plugin); Chris@0: Chris@0: return $this->plugin; Chris@0: } Chris@0: } Chris@0: $this->fail('No plugin found for class ' . $class); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Tests the source plugin against a particular data set. Chris@0: * Chris@0: * @param array $source_data Chris@0: * The source data that the source plugin will read. Chris@0: * @param array $expected_data Chris@0: * The result rows the source plugin is expected to return. Chris@0: * @param mixed $expected_count Chris@0: * (optional) How many rows the source plugin is expected to return. Chris@0: * Defaults to count($expected_data). If set to a non-null, non-numeric Chris@0: * value (like FALSE or 'nope'), the source plugin will not be counted. Chris@0: * @param array $configuration Chris@0: * (optional) Configuration for the source plugin. Chris@0: * @param mixed $high_water Chris@0: * (optional) The value of the high water field. Chris@0: * Chris@0: * @dataProvider providerSource Chris@0: */ Chris@0: public function testSource(array $source_data, array $expected_data, $expected_count = NULL, array $configuration = [], $high_water = NULL) { Chris@0: $plugin = $this->getPlugin($configuration); Chris@0: Chris@0: // All source plugins must define IDs. Chris@0: $this->assertNotEmpty($plugin->getIds()); Chris@0: Chris@0: // If there is a high water mark, set it in the high water storage. Chris@0: if (isset($high_water)) { Chris@0: $this->container Chris@0: ->get('keyvalue') Chris@0: ->get('migrate:high_water') Chris@0: ->set($this->migration->reveal()->id(), $high_water); Chris@0: } Chris@0: Chris@0: if (is_null($expected_count)) { Chris@0: $expected_count = count($expected_data); Chris@0: } Chris@0: // If an expected count was given, assert it only if the plugin is Chris@0: // countable. Chris@0: if (is_numeric($expected_count)) { Chris@0: $this->assertInstanceOf('\Countable', $plugin); Chris@0: $this->assertCount($expected_count, $plugin); Chris@0: } Chris@0: Chris@0: $i = 0; Chris@0: /** @var \Drupal\migrate\Row $row */ Chris@0: foreach ($plugin as $row) { Chris@0: $this->assertInstanceOf(Row::class, $row); Chris@0: Chris@0: $expected = $expected_data[$i++]; Chris@0: $actual = $row->getSource(); Chris@0: Chris@0: foreach ($expected as $key => $value) { Chris@0: $this->assertArrayHasKey($key, $actual); Chris@0: Chris@17: $msg = sprintf("Value at 'array[%s][%s]' is not correct.", $i - 1, $key); Chris@0: if (is_array($value)) { Chris@0: ksort($value); Chris@0: ksort($actual[$key]); Chris@17: $this->assertEquals($value, $actual[$key], $msg); Chris@0: } Chris@0: else { Chris@17: $this->assertEquals((string) $value, (string) $actual[$key], $msg); Chris@0: } Chris@0: } Chris@0: } Chris@0: // False positives occur if the foreach is not entered. So, confirm the Chris@0: // foreach loop was entered if the expected count is greater than 0. Chris@0: if ($expected_count > 0) { Chris@0: $this->assertGreaterThan(0, $i); Chris@0: } Chris@0: } Chris@0: Chris@0: }