Skip to content
Snippets Groups Projects
Commit 2e22e03f authored by Lucas Hedding's avatar Lucas Hedding Committed by Lucas Hedding
Browse files

Issue #2781573 by sgurlt, heddn: Method for CSV File Object creation

parent eb3336f0
Branches
Tags
No related merge requests found
...@@ -17,7 +17,15 @@ ...@@ -17,7 +17,15 @@
"source": "https://cgit.drupalcode.org/migrate_source_csv" "source": "https://cgit.drupalcode.org/migrate_source_csv"
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true,
"require": { "require": {
"drupal/core": "~8.1" "drupal/core": "~8.1"
},
"require-dev": {
"mikey179/vfsStream": "~1",
"phpunit/phpunit": "~4"
},
"config": {
"preferred-install": "dist"
} }
} }
...@@ -17,3 +17,6 @@ migrate.source.csv: ...@@ -17,3 +17,6 @@ migrate.source.csv:
column_names: column_names:
type: sequence type: sequence
label: 'Numeric key 0-based index of the columns in source CSV file' label: 'Numeric key 0-based index of the columns in source CSV file'
file_class:
type: string
label: 'Full class name that includes namespace for an alternative CSV reader'
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="tests/bootstrap.php" colors="true">
<php>
<!-- Set error reporting to E_ALL. -->
<ini name="error_reporting" value="32767"/>
<!-- Do not limit the amount of memory tests take to run. -->
<ini name="memory_limit" value="-1"/>
</php>
<testsuites>
<testsuite name="Migrate CSV Test Suite">
<directory>./tests/src/Unit</directory>
</testsuite>
</testsuites>
<!-- Filter for coverage reports. -->
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory>./src</directory>
</whitelist>
</filter>
</phpunit>
...@@ -40,6 +40,20 @@ class CSV extends SourcePluginBase { ...@@ -40,6 +40,20 @@ class CSV extends SourcePluginBase {
*/ */
protected $keys = []; protected $keys = [];
/**
* The file class to read the file.
*
* @var string
*/
protected $fileClass = '';
/**
* The file object that reads the CSV file.
*
* @var \SplFileObject
*/
protected $file = NULL;
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
...@@ -56,6 +70,7 @@ class CSV extends SourcePluginBase { ...@@ -56,6 +70,7 @@ class CSV extends SourcePluginBase {
throw new MigrateException('You must declare "keys" as a unique array of fields in your source settings.'); throw new MigrateException('You must declare "keys" as a unique array of fields in your source settings.');
} }
$this->fileClass = empty($configuration['file_class']) ? CSVFileObject::class : $configuration['file_class'];
} }
/** /**
...@@ -73,36 +88,36 @@ class CSV extends SourcePluginBase { ...@@ -73,36 +88,36 @@ class CSV extends SourcePluginBase {
*/ */
public function initializeIterator() { public function initializeIterator() {
// File handler using header-rows-respecting extension of SPLFileObject. // File handler using header-rows-respecting extension of SPLFileObject.
$file = new CSVFileObject($this->configuration['path']); $this->file = new $this->fileClass($this->configuration['path']);
// Set basics of CSV behavior based on configuration. // Set basics of CSV behavior based on configuration.
$delimiter = !empty($this->configuration['delimiter']) ? $this->configuration['delimiter'] : ','; $delimiter = !empty($this->configuration['delimiter']) ? $this->configuration['delimiter'] : ',';
$enclosure = !empty($this->configuration['enclosure']) ? $this->configuration['enclosure'] : '"'; $enclosure = !empty($this->configuration['enclosure']) ? $this->configuration['enclosure'] : '"';
$escape = !empty($this->configuration['escape']) ? $this->configuration['escape'] : '\\'; $escape = !empty($this->configuration['escape']) ? $this->configuration['escape'] : '\\';
$file->setCsvControl($delimiter, $enclosure, $escape); $this->file->setCsvControl($delimiter, $enclosure, $escape);
// Figure out what CSV column(s) to use. Use either the header row(s) or // Figure out what CSV column(s) to use. Use either the header row(s) or
// explicitly provided column name(s). // explicitly provided column name(s).
if (!empty($this->configuration['header_row_count'])) { if (!empty($this->configuration['header_row_count'])) {
$file->setHeaderRowCount($this->configuration['header_row_count']); $this->file->setHeaderRowCount($this->configuration['header_row_count']);
// Find the last header line. // Find the last header line.
$file->rewind(); $this->file->rewind();
$file->seek($file->getHeaderRowCount() - 1); $this->file->seek($this->file->getHeaderRowCount() - 1);
$row = $file->current(); $row = $this->file->current();
foreach ($row as $header) { foreach ($row as $header) {
$header = trim($header); $header = trim($header);
$column_names[] = [$header => $header]; $column_names[] = [$header => $header];
} }
$file->setColumnNames($column_names); $this->file->setColumnNames($column_names);
} }
// An explicit list of column name(s) will override any header row(s). // An explicit list of column name(s) will override any header row(s).
if (!empty($this->configuration['column_names'])) { if (!empty($this->configuration['column_names'])) {
$file->setColumnNames($this->configuration['column_names']); $this->file->setColumnNames($this->configuration['column_names']);
} }
return $file; return $this->file;
} }
/** /**
......
<?php
/**
* @file
* Searches for the core bootstrap file.
*/
$dir = __DIR__;
// Match against previous dir for Windows.
$previous_dir = '';
while ($dir = dirname($dir)) {
// We've reached the root.
if ($dir === $previous_dir) {
break;
}
$previous_dir = $dir;
if (is_file($dir . '/core/tests/bootstrap.php')) {
require_once $dir . '/core/tests/bootstrap.php';
return;
}
}
throw new RuntimeException('Unable to load core bootstrap.php.');
...@@ -33,11 +33,9 @@ class CSVFileObjectTest extends CSVUnitTestCase { ...@@ -33,11 +33,9 @@ class CSVFileObjectTest extends CSVUnitTestCase {
/** /**
* Tests that the construction appropriately creates a CSVFileObject. * Tests that the construction appropriately creates a CSVFileObject.
* *
* @test
*
* @covers ::__construct * @covers ::__construct
*/ */
public function create() { public function testCreate() {
$this->assertInstanceOf(CSVFileObject::class, $this->csvFileObject); $this->assertInstanceOf(CSVFileObject::class, $this->csvFileObject);
$flags = CSVFileObject::READ_CSV | CSVFileObject::READ_AHEAD | CSVFileObject::DROP_NEW_LINE | CSVFileObject::SKIP_EMPTY; $flags = CSVFileObject::READ_CSV | CSVFileObject::READ_AHEAD | CSVFileObject::DROP_NEW_LINE | CSVFileObject::SKIP_EMPTY;
$this->assertSame($flags, $this->csvFileObject->getFlags()); $this->assertSame($flags, $this->csvFileObject->getFlags());
...@@ -46,11 +44,9 @@ class CSVFileObjectTest extends CSVUnitTestCase { ...@@ -46,11 +44,9 @@ class CSVFileObjectTest extends CSVUnitTestCase {
/** /**
* Tests that the header row count is correctly set. * Tests that the header row count is correctly set.
* *
* @test
*
* @covers ::setHeaderRowCount * @covers ::setHeaderRowCount
*/ */
public function setHeaderRowCount() { public function testSetHeaderRowCount() {
$expected = 2; $expected = 2;
$this->csvFileObject->setHeaderRowCount($expected); $this->csvFileObject->setHeaderRowCount($expected);
...@@ -60,13 +56,11 @@ class CSVFileObjectTest extends CSVUnitTestCase { ...@@ -60,13 +56,11 @@ class CSVFileObjectTest extends CSVUnitTestCase {
/** /**
* Tests that the header row count is correctly returned. * Tests that the header row count is correctly returned.
* *
* @test
*
* @depends setHeaderRowCount * @depends setHeaderRowCount
* *
* @covers ::getHeaderRowCount * @covers ::getHeaderRowCount
*/ */
public function getHeaderRowCount($actual) { public function testGetHeaderRowCount($actual) {
$expected = 2; $expected = 2;
$this->assertEquals($expected, $actual); $this->assertEquals($expected, $actual);
} }
...@@ -74,11 +68,9 @@ class CSVFileObjectTest extends CSVUnitTestCase { ...@@ -74,11 +68,9 @@ class CSVFileObjectTest extends CSVUnitTestCase {
/** /**
* Tests that line count is correct. * Tests that line count is correct.
* *
* @test
*
* @covers ::count * @covers ::count
*/ */
public function countLines() { public function testCountLines() {
$expected = 15; $expected = 15;
$this->csvFileObject->setHeaderRowCount(1); $this->csvFileObject->setHeaderRowCount(1);
$actual = $this->csvFileObject->count(); $actual = $this->csvFileObject->count();
...@@ -89,14 +81,12 @@ class CSVFileObjectTest extends CSVUnitTestCase { ...@@ -89,14 +81,12 @@ class CSVFileObjectTest extends CSVUnitTestCase {
/** /**
* Tests that the current row is correctly returned. * Tests that the current row is correctly returned.
* *
* @test
*
* @covers ::current * @covers ::current
* @covers ::rewind * @covers ::rewind
* @covers ::getColumnNames * @covers ::getColumnNames
* @covers ::setColumnNames * @covers ::setColumnNames
*/ */
public function current() { public function testCurrent() {
$column_names = [ $column_names = [
['id' => 'Identifier'], ['id' => 'Identifier'],
['first_name' => 'First Name'], ['first_name' => 'First Name'],
......
...@@ -34,6 +34,8 @@ abstract class CSVUnitTestCase extends UnitTestCase { ...@@ -34,6 +34,8 @@ abstract class CSVUnitTestCase extends UnitTestCase {
* {@inheritdoc} * {@inheritdoc}
*/ */
protected function setUp() { protected function setUp() {
parent::setUp();
$root_dir = vfsStream::setup('root'); $root_dir = vfsStream::setup('root');
$happy = <<<'EOD' $happy = <<<'EOD'
id,first_name,last_name,email,country,ip_address id,first_name,last_name,email,country,ip_address
......
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
namespace Drupal\Tests\migrate_source_csv\Unit\Plugin\migrate\source; namespace Drupal\Tests\migrate_source_csv\Unit\Plugin\migrate\source;
use Drupal\migrate\Plugin\MigrationInterface; use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate_source_csv\CSVFileObject;
use Drupal\migrate_source_csv\Plugin\migrate\source\CSV; use Drupal\migrate_source_csv\Plugin\migrate\source\CSV;
use Drupal\Tests\migrate_source_csv\Unit\CSVUnitTestCase; use Drupal\Tests\migrate_source_csv\Unit\CSVUnitTestCase;
use Prophecy\Argument;
/** /**
* @coversDefaultClass \Drupal\migrate_source_csv\Plugin\migrate\source\CSV * @coversDefaultClass \Drupal\migrate_source_csv\Plugin\migrate\source\CSV
...@@ -52,9 +52,6 @@ class CSVTest extends CSVUnitTestCase { ...@@ -52,9 +52,6 @@ class CSVTest extends CSVUnitTestCase {
$plugin = $this->prophesize(MigrationInterface::class); $plugin = $this->prophesize(MigrationInterface::class);
$plugin->getIdMap() $plugin->getIdMap()
->willReturn(NULL); ->willReturn(NULL);
// @topo Swap it out for getHighWaterProperty after https://www.drupal.org/node/2694009
$plugin->getHighWaterProperty()
->willReturn(NULL);
$this->plugin = $plugin->reveal(); $this->plugin = $plugin->reveal();
} }
...@@ -62,11 +59,9 @@ class CSVTest extends CSVUnitTestCase { ...@@ -62,11 +59,9 @@ class CSVTest extends CSVUnitTestCase {
/** /**
* Tests the construction of CSV. * Tests the construction of CSV.
* *
* @test
*
* @covers ::__construct * @covers ::__construct
*/ */
public function create() { public function testCreate() {
$configuration = [ $configuration = [
'path' => $this->happyPath, 'path' => $this->happyPath,
'keys' => ['id'], 'keys' => ['id'],
...@@ -81,26 +76,22 @@ class CSVTest extends CSVUnitTestCase { ...@@ -81,26 +76,22 @@ class CSVTest extends CSVUnitTestCase {
/** /**
* Tests that a missing path will throw an exception. * Tests that a missing path will throw an exception.
* *
* @test
*
* @expectedException \Drupal\migrate\MigrateException * @expectedException \Drupal\migrate\MigrateException
* *
* @expectedExceptionMessage You must declare the "path" to the source CSV file in your source settings. * @expectedExceptionMessage You must declare the "path" to the source CSV file in your source settings.
*/ */
public function migrateExceptionPathMissing() { public function testMigrateExceptionPathMissing() {
new CSV([], $this->pluginId, $this->pluginDefinition, $this->plugin); new CSV([], $this->pluginId, $this->pluginDefinition, $this->plugin);
} }
/** /**
* Tests that missing keys will throw an exception. * Tests that missing keys will throw an exception.
* *
* @test
*
* @expectedException \Drupal\migrate\MigrateException * @expectedException \Drupal\migrate\MigrateException
* *
* @expectedExceptionMessage You must declare "keys" as a unique array of fields in your source settings. * @expectedExceptionMessage You must declare "keys" as a unique array of fields in your source settings.
*/ */
public function migrateExceptionKeysMissing() { public function testMigrateExceptionKeysMissing() {
$configuration = [ $configuration = [
'path' => $this->happyPath, 'path' => $this->happyPath,
]; ];
...@@ -111,11 +102,9 @@ class CSVTest extends CSVUnitTestCase { ...@@ -111,11 +102,9 @@ class CSVTest extends CSVUnitTestCase {
/** /**
* Tests that toString functions as expected. * Tests that toString functions as expected.
* *
* @test
*
* @covers ::__toString * @covers ::__toString
*/ */
public function toString() { public function testToString() {
$configuration = [ $configuration = [
'path' => $this->happyPath, 'path' => $this->happyPath,
'keys' => ['id'], 'keys' => ['id'],
...@@ -130,11 +119,9 @@ class CSVTest extends CSVUnitTestCase { ...@@ -130,11 +119,9 @@ class CSVTest extends CSVUnitTestCase {
/** /**
* Tests initialization of the iterator. * Tests initialization of the iterator.
* *
* @test
*
* @covers ::initializeIterator * @covers ::initializeIterator
*/ */
public function initializeIterator() { public function testInitializeIterator() {
$configuration = [ $configuration = [
'path' => $this->happyPath, 'path' => $this->happyPath,
'keys' => ['id'], 'keys' => ['id'],
...@@ -227,11 +214,9 @@ class CSVTest extends CSVUnitTestCase { ...@@ -227,11 +214,9 @@ class CSVTest extends CSVUnitTestCase {
/** /**
* Tests that the key is properly identified. * Tests that the key is properly identified.
* *
* @test
*
* @covers ::getIds * @covers ::getIds
*/ */
public function getIds() { public function testGetIds() {
$configuration = [ $configuration = [
'path' => $this->happyPath, 'path' => $this->happyPath,
'keys' => ['id'], 'keys' => ['id'],
...@@ -247,11 +232,9 @@ class CSVTest extends CSVUnitTestCase { ...@@ -247,11 +232,9 @@ class CSVTest extends CSVUnitTestCase {
/** /**
* Tests that fields have a machine name and description. * Tests that fields have a machine name and description.
* *
* @test
*
* @covers ::fields * @covers ::fields
*/ */
public function fields() { public function testFields() {
$configuration = [ $configuration = [
'path' => $this->happyPath, 'path' => $this->happyPath,
'keys' => ['id'], 'keys' => ['id'],
...@@ -263,11 +246,11 @@ class CSVTest extends CSVUnitTestCase { ...@@ -263,11 +246,11 @@ class CSVTest extends CSVUnitTestCase {
]; ];
$expected = $fields + [ $expected = $fields + [
'last_name' => 'last_name', 'last_name' => 'last_name',
'email' => 'email', 'email' => 'email',
'country' => 'country', 'country' => 'country',
'ip_address' => 'ip_address', 'ip_address' => 'ip_address',
]; ];
$csv = new CSV($configuration, $this->pluginId, $this->pluginDefinition, $this->plugin); $csv = new CSV($configuration, $this->pluginId, $this->pluginDefinition, $this->plugin);
$csv = new CSV($configuration + ['fields' => $fields], $this->pluginId, $this->pluginDefinition, $this->plugin); $csv = new CSV($configuration + ['fields' => $fields], $this->pluginId, $this->pluginDefinition, $this->plugin);
...@@ -278,10 +261,39 @@ class CSVTest extends CSVUnitTestCase { ...@@ -278,10 +261,39 @@ class CSVTest extends CSVUnitTestCase {
2 => ['first_name' => 'User first name'], 2 => ['first_name' => 'User first name'],
]; ];
$csv = new CSV($configuration + [ $csv = new CSV($configuration + [
'fields' => $fields, 'fields' => $fields,
'column_names' => $column_names, 'column_names' => $column_names,
], $this->pluginId, $this->pluginDefinition, $this->plugin); ], $this->pluginId, $this->pluginDefinition, $this->plugin);
$this->assertArrayEquals($fields, $csv->fields()); $this->assertArrayEquals($fields, $csv->fields());
} }
/**
* Tests configurable CSV file object.
*
* @covers ::__construct
*/
public function testConfigurableCSVFileObject() {
$configuration = [
'path' => $this->happyPath,
'keys' => ['id'],
'header_row_count' => 1,
'file_class' => FooCSVFileObject::class ,
];
$csv = new CSV($configuration, $this->pluginId, $this->pluginDefinition, $this->plugin);
$csv->initializeIterator();
$fileObject = $this->readAttribute($csv, 'file');
$this->assertInstanceOf(FooCSVFileObject::class, $fileObject);
}
} }
/**
* Class FooCSVFileObject
*
* Test file object class.
*
* @package Drupal\Tests\migrate_source_csv\Unit\Plugin\migrate\source
*/
class FooCSVFileObject extends CSVFileObject { }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment