MigrateTestCase.php

Same filename in other branches
  1. 9 core/modules/migrate/tests/src/Unit/MigrateTestCase.php
  2. 8.9.x core/modules/migrate/tests/src/Unit/MigrateTestCase.php
  3. 10 core/modules/migrate/tests/src/Unit/MigrateTestCase.php

Namespace

Drupal\Tests\migrate\Unit

File

core/modules/migrate/tests/src/Unit/MigrateTestCase.php

View source
<?php

declare (strict_types=1);
namespace Drupal\Tests\migrate\Unit;

use Drupal\sqlite\Driver\Database\sqlite\Connection;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\migrate\Plugin\MigrateIdMapInterface;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\Tests\UnitTestCase;

/**
 * Provides setup and helper methods for Migrate module tests.
 */
abstract class MigrateTestCase extends UnitTestCase {
    
    /**
     * An array of migration configuration values.
     *
     * @var array
     */
    protected $migrationConfiguration = [];
    
    /**
     * The migration ID map.
     *
     * @var \Drupal\migrate\Plugin\MigrateIdMapInterface|\PHPUnit\Framework\MockObject\MockObject
     */
    protected $idMap;
    
    /**
     * Local store for mocking setStatus()/getStatus().
     *
     * @var int
     */
    protected $migrationStatus = MigrationInterface::STATUS_IDLE;
    
    /**
     * Retrieves a mocked migration.
     *
     * @param \Drupal\migrate\Plugin\MigrateIdMapInterface|\PHPUnit\Framework\MockObject\MockObject|null $id_map
     *   An ID map plugin to use, or NULL for using a mocked one. Optional,
     *   defaults to NULL.
     *
     * @return \Drupal\migrate\Plugin\MigrationInterface|\PHPUnit\Framework\MockObject\MockObject
     *   The mocked migration.
     */
    protected function getMigration($id_map = NULL) {
        $this->migrationConfiguration += [
            'migrationClass' => 'Drupal\\migrate\\Plugin\\Migration',
        ];
        $this->idMap = $id_map;
        if (is_null($id_map)) {
            $this->idMap = $this->createMock(MigrateIdMapInterface::class);
            $this->idMap
                ->method('getQualifiedMapTableName')
                ->willReturn('test_map');
        }
        $migration = $this->getMockBuilder($this->migrationConfiguration['migrationClass'])
            ->disableOriginalConstructor()
            ->getMock();
        $migration->method('checkRequirements')
            ->willReturn(TRUE);
        $migration->method('getIdMap')
            ->willReturn($this->idMap);
        // We need the state to be toggled throughout the test so we store the value
        // on the test class and use a return callback.
        $migration->expects($this->any())
            ->method('getStatus')
            ->willReturnCallback(function () {
            return $this->migrationStatus;
        });
        $migration->expects($this->any())
            ->method('setStatus')
            ->willReturnCallback(function ($status) {
            $this->migrationStatus = $status;
        });
        $migration->method('getMigrationDependencies')
            ->willReturn([
            'required' => [],
            'optional' => [],
        ]);
        $configuration =& $this->migrationConfiguration;
        $migration->method('set')
            ->willReturnCallback(function ($argument, $value) use (&$configuration) {
            $configuration[$argument] = $value;
        });
        $migration->method('id')
            ->willReturn($configuration['id']);
        return $migration;
    }
    
    /**
     * Gets an SQLite database connection object for use in tests.
     *
     * @param array $database_contents
     *   The database contents faked as an array. Each key is a table name, each
     *   value is a list of table rows, an associative array of field => value.
     * @param array $connection_options
     *   (optional) Options for the database connection. Defaults to an empty
     *   array.
     *
     * @return \Drupal\sqlite\Driver\Database\sqlite\Connection
     *   The database connection.
     */
    protected function getDatabase(array $database_contents, $connection_options = []) {
        if (extension_loaded('pdo_sqlite')) {
            $connection_options['database'] = ':memory:';
            $pdo = Connection::open($connection_options);
            $connection = new Connection($pdo, $connection_options);
        }
        else {
            $this->markTestSkipped('The pdo_sqlite extension is not available.');
        }
        // Initialize the DIC with a fake module handler for alterable queries.
        $container = new ContainerBuilder();
        $container->set('module_handler', $this->createMock('\\Drupal\\Core\\Extension\\ModuleHandlerInterface'));
        \Drupal::setContainer($container);
        // Create the tables and load them up with data, skipping empty ones.
        foreach (array_filter($database_contents) as $table => $rows) {
            $pilot_row = reset($rows);
            $connection->schema()
                ->createTable($table, $this->createSchemaFromRow($pilot_row));
            $insert = $connection->insert($table)
                ->fields(array_keys($pilot_row));
            array_walk($rows, [
                $insert,
                'values',
            ]);
            $insert->execute();
        }
        return $connection;
    }
    
    /**
     * Generates a table schema from a row.
     *
     * @param array $row
     *   The reference row on which to base the schema.
     *
     * @return array
     *   The Schema API-ready table schema.
     */
    protected function createSchemaFromRow(array $row) {
        // SQLite uses loose ("affinity") typing, so it is OK for every column to be
        // a text field.
        $fields = array_map(function () {
            return [
                'type' => 'text',
            ];
        }, $row);
        return [
            'fields' => $fields,
        ];
    }
    
    /**
     * Tests a query.
     *
     * @param array|\Traversable $iter
     *   The countable. foreach-able actual results if a query is being run.
     * @param array $expected_results
     *   An array of expected results.
     */
    public function queryResultTest($iter, $expected_results) {
        $this->assertSameSize($expected_results, $iter, 'Number of results match');
        $count = 0;
        foreach ($iter as $data_row) {
            $expected_row = $expected_results[$count];
            $count++;
            foreach ($expected_row as $key => $expected_value) {
                $this->retrievalAssertHelper($expected_value, $this->getValue($data_row, $key), sprintf('Value matches for key "%s"', $key));
            }
        }
        $this->assertSame(count($expected_results), $count);
    }
    
    /**
     * Gets the value on a row for a given key.
     *
     * @param array $row
     *   The row information.
     * @param string $key
     *   The key identifier.
     *
     * @return mixed
     *   The value on a row for a given key.
     */
    protected function getValue($row, $key) {
        return $row[$key];
    }
    
    /**
     * Asserts tested values during test retrieval.
     *
     * @param mixed $expected_value
     *   The incoming expected value to test.
     * @param mixed $actual_value
     *   The incoming value itself.
     * @param string $message
     *   The tested result as a formatted string.
     */
    protected function retrievalAssertHelper($expected_value, $actual_value, $message) {
        if (is_array($expected_value)) {
            // If the expected and actual values are empty, no need to array compare.
            if (empty($expected_value && $actual_value)) {
                return;
            }
            $this->assertEquals($expected_value, $actual_value, $message);
        }
        else {
            $this->assertSame((string) $expected_value, (string) $actual_value, $message);
        }
    }

}

Classes

Title Deprecated Summary
MigrateTestCase Provides setup and helper methods for Migrate module tests.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.