diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6c33240..b770e76 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -105,4 +105,4 @@ jobs:
run: "./tools/composer update --no-ansi --no-interaction --no-progress"
- name: "Run mutation tests with Infection"
- run: "./tools/infection"
+ run: "./tools/infection --only-covered"
diff --git a/.psalm/baseline.xml b/.psalm/baseline.xml
index 2a811d0..68fc820 100644
--- a/.psalm/baseline.xml
+++ b/.psalm/baseline.xml
@@ -1,2 +1,8 @@
-
+
+
+
+ $line
+
+
+
diff --git a/src/Parser.php b/src/Parser.php
index c19a41a..235fea0 100644
--- a/src/Parser.php
+++ b/src/Parser.php
@@ -9,10 +9,10 @@
*/
namespace SebastianBergmann\CsvParser;
-use function array_shift;
-use function file;
-use function str_getcsv;
+use function is_array;
use Generator;
+use RuntimeException;
+use SplFileObject;
/**
* @no-named-arguments Parameter names are not covered by the backward compatibility promise for this library
@@ -27,31 +27,39 @@ final class Parser
*/
public function parse(string $filename, Schema $schema, bool $ignoreFirstLine = true): Generator
{
- $lines = @file($filename);
-
- if ($lines === false) {
- throw CannotReadCsvFileException::from($filename);
+ try {
+ $file = new SplFileObject($filename);
+ } catch (RuntimeException $e) {
+ throw new CannotReadCsvFileException($e->getMessage());
}
- if ($ignoreFirstLine) {
- array_shift($lines);
- }
+ $file->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE);
- return $this->generator($lines, $schema);
+ return $this->generator($file, $schema, $ignoreFirstLine);
}
/**
- * @psalm-param list $lines
- *
* @psalm-return Generator>
*/
- private function generator(array $lines, Schema $schema): Generator
+ private function generator(SplFileObject $file, Schema $schema, bool $ignoreFirstLine): Generator
{
- foreach ($lines as $line) {
+ $firstLine = true;
+
+ foreach ($file as $line) {
+ if ($ignoreFirstLine && $firstLine) {
+ $firstLine = false;
+
+ continue;
+ }
+
+ if (!is_array($line)) {
+ continue;
+ }
+
$data = [];
foreach ($schema->columnDefinitions() as $columnDefinition) {
- $columnDefinition->parse(str_getcsv($line), $data);
+ $columnDefinition->parse($line, $data);
}
yield $data;
diff --git a/src/exception/CannotReadCsvFileException.php b/src/exception/CannotReadCsvFileException.php
index c2e9074..d7975ad 100644
--- a/src/exception/CannotReadCsvFileException.php
+++ b/src/exception/CannotReadCsvFileException.php
@@ -9,18 +9,8 @@
*/
namespace SebastianBergmann\CsvParser;
-use function sprintf;
use RuntimeException;
final class CannotReadCsvFileException extends RuntimeException implements Exception
{
- public static function from(string $filename): self
- {
- return new self(
- sprintf(
- 'Reading from CSV file %s failed',
- $filename
- )
- );
- }
}
diff --git a/src/exception/InvalidValueException.php b/src/exception/InvalidValueException.php
deleted file mode 100644
index 7f261c0..0000000
--- a/src/exception/InvalidValueException.php
+++ /dev/null
@@ -1,16 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-namespace SebastianBergmann\CsvParser;
-
-use RuntimeException;
-
-final class InvalidValueException extends RuntimeException implements Exception
-{
-}
diff --git a/src/schema/ColumnDefinition.php b/src/schema/ColumnDefinition.php
index e1397d9..466e496 100644
--- a/src/schema/ColumnDefinition.php
+++ b/src/schema/ColumnDefinition.php
@@ -50,7 +50,7 @@ private function __construct(int $position, string $name, Type $type)
}
/**
- * @psalm-param list $input
+ * @psalm-param list $input
* @psalm-param array $output
*
* @throws OutOfBoundsException
@@ -65,10 +65,6 @@ public function parse(array $input, array &$output): void
$value = $input[$this->position - 1];
- if ($value === null) {
- throw new InvalidValueException('Input array has element with invalid value at position ' . $this->position);
- }
-
$output[$this->name] = $this->type->cast($value);
}
diff --git a/tests/unit/ParserTest.php b/tests/unit/ParserTest.php
index e863a3b..0fb44f1 100644
--- a/tests/unit/ParserTest.php
+++ b/tests/unit/ParserTest.php
@@ -17,7 +17,6 @@
use PHPUnit\Framework\TestCase;
#[CoversClass(Parser::class)]
-#[CoversClass(CannotReadCsvFileException::class)]
#[UsesClass(Schema::class)]
#[UsesClass(ColumnDefinition::class)]
#[UsesClass(Type::class)]
@@ -88,7 +87,6 @@ public function test_Parses_CSV_file_according_to_schema(array $expected, Schema
public function test_Cannot_read_from_CSV_file_that_does_not_exist(): void
{
$this->expectException(CannotReadCsvFileException::class);
- $this->expectExceptionMessage('Reading from CSV file does_not_exist.csv failed');
(new Parser)->parse('does_not_exist.csv', Schema::from([]));
}
diff --git a/tests/unit/schema/ColumnDefinitionTest.php b/tests/unit/schema/ColumnDefinitionTest.php
index 5c071c9..d627cf7 100644
--- a/tests/unit/schema/ColumnDefinitionTest.php
+++ b/tests/unit/schema/ColumnDefinitionTest.php
@@ -56,17 +56,6 @@ public function testCannotParseColumnFromInputArrayThatDoesNotExist(): void
$this->column()->parse($input, $output);
}
- public function testCannotParseColumnWithInvalidValue(): void
- {
- $input = [null];
- $output = [];
-
- $this->expectException(InvalidValueException::class);
- $this->expectExceptionMessage('Input array has element with invalid value at position 1');
-
- $this->column()->parse($input, $output);
- }
-
private function column(): ColumnDefinition
{
return ColumnDefinition::from(1, 'name', Type::integer());