You are here

MigrateTestCase.php in Drupal 10

File

core/modules/migrate/tests/src/Unit/MigrateTestCase.php
View source
<?php

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

Namesort descending Description
MigrateTestCase Provides setup and helper methods for Migrate module tests.