Commit 2e22e03f authored by heddn's avatar heddn Committed by heddn

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

parent eb3336f0
......@@ -17,7 +17,15 @@
"source": "https://cgit.drupalcode.org/migrate_source_csv"
},
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"drupal/core": "~8.1"
},
"require-dev": {
"mikey179/vfsStream": "~1",
"phpunit/phpunit": "~4"
},
"config": {
"preferred-install": "dist"
}
}
......@@ -17,3 +17,6 @@ migrate.source.csv:
column_names:
type: sequence
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 {
*/
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}
*/
......@@ -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.');
}
$this->fileClass = empty($configuration['file_class']) ? CSVFileObject::class : $configuration['file_class'];
}
/**
......@@ -73,36 +88,36 @@ class CSV extends SourcePluginBase {
*/
public function initializeIterator() {
// 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.
$delimiter = !empty($this->configuration['delimiter']) ? $this->configuration['delimiter'] : ',';
$enclosure = !empty($this->configuration['enclosure']) ? $this->configuration['enclosure'] : '"';
$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
// explicitly provided column name(s).
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.
$file->rewind();
$file->seek($file->getHeaderRowCount() - 1);
$this->file->rewind();
$this->file->seek($this->file->getHeaderRowCount() - 1);
$row = $file->current();
$row = $this->file->current();
foreach ($row as $header) {
$header = trim($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).
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 {
/**
* Tests that the construction appropriately creates a CSVFileObject.
*
* @test
*
* @covers ::__construct
*/
public function create() {
public function testCreate() {
$this->assertInstanceOf(CSVFileObject::class, $this->csvFileObject);
$flags = CSVFileObject::READ_CSV | CSVFileObject::READ_AHEAD | CSVFileObject::DROP_NEW_LINE | CSVFileObject::SKIP_EMPTY;
$this->assertSame($flags, $this->csvFileObject->getFlags());
......@@ -46,11 +44,9 @@ class CSVFileObjectTest extends CSVUnitTestCase {
/**
* Tests that the header row count is correctly set.
*
* @test
*
* @covers ::setHeaderRowCount
*/
public function setHeaderRowCount() {
public function testSetHeaderRowCount() {
$expected = 2;
$this->csvFileObject->setHeaderRowCount($expected);
......@@ -60,13 +56,11 @@ class CSVFileObjectTest extends CSVUnitTestCase {
/**
* Tests that the header row count is correctly returned.
*
* @test
*
* @depends setHeaderRowCount
*
* @covers ::getHeaderRowCount
*/
public function getHeaderRowCount($actual) {
public function testGetHeaderRowCount($actual) {
$expected = 2;
$this->assertEquals($expected, $actual);
}
......@@ -74,11 +68,9 @@ class CSVFileObjectTest extends CSVUnitTestCase {
/**
* Tests that line count is correct.
*
* @test
*
* @covers ::count
*/
public function countLines() {
public function testCountLines() {
$expected = 15;
$this->csvFileObject->setHeaderRowCount(1);
$actual = $this->csvFileObject->count();
......@@ -89,14 +81,12 @@ class CSVFileObjectTest extends CSVUnitTestCase {
/**
* Tests that the current row is correctly returned.
*
* @test
*
* @covers ::current
* @covers ::rewind
* @covers ::getColumnNames
* @covers ::setColumnNames
*/
public function current() {
public function testCurrent() {
$column_names = [
['id' => 'Identifier'],
['first_name' => 'First Name'],
......
......@@ -34,6 +34,8 @@ abstract class CSVUnitTestCase extends UnitTestCase {
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$root_dir = vfsStream::setup('root');
$happy = <<<'EOD'
id,first_name,last_name,email,country,ip_address
......
......@@ -7,9 +7,9 @@
namespace Drupal\Tests\migrate_source_csv\Unit\Plugin\migrate\source;
use Drupal\migrate\Plugin\MigrationInterface;
use Drupal\migrate_source_csv\CSVFileObject;
use Drupal\migrate_source_csv\Plugin\migrate\source\CSV;
use Drupal\Tests\migrate_source_csv\Unit\CSVUnitTestCase;
use Prophecy\Argument;
/**
* @coversDefaultClass \Drupal\migrate_source_csv\Plugin\migrate\source\CSV
......@@ -52,9 +52,6 @@ class CSVTest extends CSVUnitTestCase {
$plugin = $this->prophesize(MigrationInterface::class);
$plugin->getIdMap()
->willReturn(NULL);
// @topo Swap it out for getHighWaterProperty after https://www.drupal.org/node/2694009
$plugin->getHighWaterProperty()
->willReturn(NULL);
$this->plugin = $plugin->reveal();
}
......@@ -62,11 +59,9 @@ class CSVTest extends CSVUnitTestCase {
/**
* Tests the construction of CSV.
*
* @test
*
* @covers ::__construct
*/
public function create() {
public function testCreate() {
$configuration = [
'path' => $this->happyPath,
'keys' => ['id'],
......@@ -81,26 +76,22 @@ class CSVTest extends CSVUnitTestCase {
/**
* Tests that a missing path will throw an exception.
*
* @test
*
* @expectedException \Drupal\migrate\MigrateException
*
* @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);
}
/**
* Tests that missing keys will throw an exception.
*
* @test
*
* @expectedException \Drupal\migrate\MigrateException
*
* @expectedExceptionMessage You must declare "keys" as a unique array of fields in your source settings.
*/
public function migrateExceptionKeysMissing() {
public function testMigrateExceptionKeysMissing() {
$configuration = [
'path' => $this->happyPath,
];
......@@ -111,11 +102,9 @@ class CSVTest extends CSVUnitTestCase {
/**
* Tests that toString functions as expected.
*
* @test
*
* @covers ::__toString
*/
public function toString() {
public function testToString() {
$configuration = [
'path' => $this->happyPath,
'keys' => ['id'],
......@@ -130,11 +119,9 @@ class CSVTest extends CSVUnitTestCase {
/**
* Tests initialization of the iterator.
*
* @test
*
* @covers ::initializeIterator
*/
public function initializeIterator() {
public function testInitializeIterator() {
$configuration = [
'path' => $this->happyPath,
'keys' => ['id'],
......@@ -227,11 +214,9 @@ class CSVTest extends CSVUnitTestCase {
/**
* Tests that the key is properly identified.
*
* @test
*
* @covers ::getIds
*/
public function getIds() {
public function testGetIds() {
$configuration = [
'path' => $this->happyPath,
'keys' => ['id'],
......@@ -247,11 +232,9 @@ class CSVTest extends CSVUnitTestCase {
/**
* Tests that fields have a machine name and description.
*
* @test
*
* @covers ::fields
*/
public function fields() {
public function testFields() {
$configuration = [
'path' => $this->happyPath,
'keys' => ['id'],
......@@ -263,11 +246,11 @@ class CSVTest extends CSVUnitTestCase {
];
$expected = $fields + [
'last_name' => 'last_name',
'email' => 'email',
'country' => 'country',
'ip_address' => 'ip_address',
];
'last_name' => 'last_name',
'email' => 'email',
'country' => 'country',
'ip_address' => 'ip_address',
];
$csv = new CSV($configuration, $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 {
2 => ['first_name' => 'User first name'],
];
$csv = new CSV($configuration + [
'fields' => $fields,
'column_names' => $column_names,
], $this->pluginId, $this->pluginDefinition, $this->plugin);
'fields' => $fields,
'column_names' => $column_names,
], $this->pluginId, $this->pluginDefinition, $this->plugin);
$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 { }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment