diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ea85285..f2a0eb1 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,11 +19,13 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: 8.3 - extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo - coverage: none + extensions: dom, curl, libxml, mbstring, zip, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo, xdebug + coverage: xdebug - name: Install dependencies run: composer install --no-interaction - name: Test - run: composer run test \ No newline at end of file + run: composer run test + - name: TestCoverage + run: composer run coverage \ No newline at end of file diff --git a/Tests/JsonlTest.php b/Tests/JsonlTest.php index bbf6706..2e7c350 100644 --- a/Tests/JsonlTest.php +++ b/Tests/JsonlTest.php @@ -1,7 +1,6 @@ assertEquals($expected, iterator_to_array(Jsonl::encode($data))); } + public function testJsonlEncodeSkipsEmptyLines() + { + $data = [[], ['key' => 'value'], null, ['key2' => 'value2']]; + $expected = ['{"key":"value"}' . "\n", '{"key2":"value2"}' . "\n"]; + + $this->assertEquals($expected, iterator_to_array(Jsonl::encode($data))); + } + public function testJsonlDecode() { $jsonlString = '{"key":"value"}' . "\n" . '{"key2":"value2"}' . "\n"; @@ -21,6 +28,13 @@ public function testJsonlDecode() $this->assertEquals($expected, iterator_to_array(Jsonl::decode($jsonlString, true))); } + public function testJsonlDecodeSkipsEmptyLines() + { + $jsonlString = '{"key":"value"}' . "\n" . '{"key2":"value2"}' . "\n\n \n"; + $expected = [['key' => 'value'], ['key2' => 'value2']]; + $this->assertEquals($expected, iterator_to_array(Jsonl::decode($jsonlString, true))); + } + public function testJsonlEncodeToFile() { $data = [['key' => 'value'], ['key2' => 'value2']]; @@ -42,6 +56,18 @@ public function testJsonlEncodeIncorrectResource() Jsonl::encodeToResource('', $data); } + public function testJsonlEncodeToReadOnlyResourceThrowsException() + { + $file = fopen(__DIR__ . '/data/test_decode.jsonl', 'r'); + + try { + $this->expectException(\RuntimeException::class); + Jsonl::encodeToResource($file, [['key' => 'value']]); + } finally { + fclose($file); + } + } + public function testJsonlDecodeFromFile() { $expected = [['key' => 'value'], ['key2' => 'value2']]; diff --git a/composer.json b/composer.json index 0cf84f9..0aa15ad 100644 --- a/composer.json +++ b/composer.json @@ -49,6 +49,7 @@ "scripts": { "analyse": "phpstan --memory-limit=256M", "test": "phpunit", + "coverage": "XDEBUG_MODE=coverage phpunit --coverage-text --only-summary-for-coverage-text | grep -c \"100.00%\" | grep -q \"^3$\" && exit 0 || exit 1", "phpcs": "vendor/bin/phpcs --standard=PSR12 --colors --exclude=Generic.Files.LineLength --extensions=php,phtml src", "phpcbf": "vendor/bin/phpcbf --standard=PSR12 --colors --exclude=Generic.Files.LineLength --extensions=php src || exit 0", "codestyle": [ diff --git a/phpunit.xml b/phpunit.xml index 9795e2a..7bea184 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,4 +1,5 @@ - + + @@ -7,4 +8,10 @@ ./Tests + + + + ./src + + \ No newline at end of file diff --git a/src/Jsonl.php b/src/Jsonl.php index 99aa187..558c3f2 100644 --- a/src/Jsonl.php +++ b/src/Jsonl.php @@ -32,7 +32,8 @@ class Jsonl public static function decode( Traversable|array|string $jsonl, ?bool $associative = null, - int $depth = 512 + int $depth = 512, + int $flags = JSON_THROW_ON_ERROR ): Generator { if (is_string($jsonl)) { $jsonl = explode("\n", $jsonl); @@ -43,11 +44,16 @@ public static function decode( continue; } + $line = trim($line); + if ($line === '') { + continue; + } + yield json_decode( - trim($line), + $line, $associative, $depth, - JSON_THROW_ON_ERROR + $flags ); } } @@ -65,14 +71,15 @@ public static function decode( public static function decodeFromResource( $resource, ?bool $associative = null, - int $depth = 512 + int $depth = 512, + int $flags = JSON_THROW_ON_ERROR ): Generator { if (!is_resource($resource)) { throw new InvalidArgumentException('decodeFromResource expects a resource "' . gettype($resource) . '" was passed'); } while (($line = fgets($resource)) !== false) { - foreach (static::decode($line, $associative, $depth) as $item) { + foreach (static::decode($line, $associative, $depth, $flags) as $item) { yield $item; } }