schneespur/vendor/league/csv/src/StatementTest.php
Michael ee3dbba6cc Initial release v1.0.0
Schneespur — Open-source winter service documentation software (PWA + Admin).
GPS tracking via OwnTracks, weather data, photo evidence, and legally
compliant service records for winter maintenance operators.

License: AGPL-3.0-or-later
2026-05-17 13:33:51 +00:00

281 lines
7.9 KiB
PHP

<?php
/**
* League.Csv (https://csv.thephpleague.com)
*
* (c) Ignace Nyamagana Butera <nyamsprod@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace League\Csv;
use League\Csv\Query\Constraint\Comparison;
use League\Csv\Query\QueryException;
use OutOfBoundsException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;
use PHPUnit\Framework\TestCase;
use SplTempFileObject;
use function array_reverse;
use function in_array;
use function strcmp;
use function strlen;
#[Group('reader')]
final class StatementTest extends TestCase
{
private Reader $csv;
private Statement $stmt;
private array $expected = [
['john', 'doe', 'john.doe@example.com'],
['jane', 'doe', 'jane.doe@example.com'],
];
protected function setUp(): void
{
$tmp = new SplTempFileObject();
$tmp->setCsvControl(escape: '\\');
foreach ($this->expected as $row) {
$tmp->fputcsv($row, escape: '\\');
}
$this->csv = Reader::from($tmp);
$this->stmt = (new Statement());
}
protected function tearDown(): void
{
unset($this->csv, $this->stmt);
}
public function testSetLimit(): void
{
self::assertCount(1, $this->stmt->limit(1)->process($this->csv));
}
public function testSetLimitThrowException(): void
{
$this->expectException(InvalidArgument::class);
$this->stmt->limit(-2);
}
public function testSetOffset(): void
{
self::assertContains(
['jane', 'doe', 'jane.doe@example.com'],
[...$this->stmt->offset(1)->process($this->csv)]
);
}
public function testSetOffsetThrowsException(): void
{
$this->expectException(InvalidArgument::class);
$this->stmt->offset(-1);
}
public function testStatementSameInstance(): void
{
self::assertSame($this->stmt, $this->stmt->limit(-1)->offset(0));
}
#[DataProvider('intervalTest')]
public function testInterval(int $offset, int $limit): void
{
self::assertContains(
['jane', 'doe', 'jane.doe@example.com'],
[...$this->stmt
->offset($offset)
->limit($limit)
->where(fn (array $record): bool => true)
->where(fn (array $record): bool => [] !== $record)
->process($this->csv)]
);
}
public static function intervalTest(): array
{
return [
'tooHigh' => [1, 10],
'normal' => [1, 1],
];
}
public function testIntervalThrowException(): void
{
$this->expectException(OutOfBoundsException::class);
[...$this->stmt->offset(1)->limit(0)->process($this->csv)];
}
public function testFilter(): void
{
$func2 = fn (array $row): bool => !in_array('john', $row, true);
$stmt = (new Statement())->where(fn (array $row): bool => !in_array('jane', $row, true));
$result1 = $stmt->process($this->csv);
$result2 = $stmt->where($func2)->process($result1, ['foo', 'bar']);
$result3 = $stmt->where($func2)->process($result2, ['foo', 'bar']);
self::assertNotContains(['jane', 'doe', 'jane.doe@example.com'], [...$result1]);
self::assertCount(0, $result2);
self::assertEquals($result3, $result2);
}
public function testAddWhere(): void
{
$stmt1 = (new Statement())->andWhere(0, '=', 'jane');
$result1 = $stmt1->process($this->csv);
self::assertCount(1, $result1);
self::assertEquals('jane', $result1->first()[0]);
$stmt2 = (new Statement())->andWhere(0, 'starts_with', 'j');
$result2 = $stmt2->process($this->csv);
self::assertCount(2, $result2);
self::assertEquals('jane', $result2->nth(1)[0]);
$stmt3 = (new Statement())->andWhere(2, 'starts_with', 'blablabla');
$result3 = $stmt3->process($this->csv);
self::assertCount(0, $result3);
}
public function testOrWhere(): void
{
$stmt1 = (new Statement())
->orWhere(0, 'starts_with', 'ja')
->orWhere(0, 'ends_with', 'hn');
$result1 = $stmt1->process($this->csv);
self::assertCount(2, $result1);
self::assertEquals('john', $result1->first()[0]);
$stmt3 = (new Statement())->orWhere(2, 'starts_with', 'blablabla');
$result3 = $stmt3->process($this->csv);
self::assertCount(0, $result3);
}
public function testOrderBy(): void
{
$calculated = $this->stmt
->orderBy(fn (array $rowA, array $rowB): int => strcmp($rowA[0], $rowB[0])) /* @phpstan-ignore-line */
->process($this->csv);
self::assertSame(array_reverse($this->expected), array_values([...$calculated]));
}
public function testOrderByColumn(): void
{
$calculated = $this->stmt
->orderByAsc(0)
->process($this->csv);
self::assertSame(array_reverse($this->expected), array_values([...$calculated]));
$calculated = $this->stmt
->orderByDesc(0)
->process($this->csv);
self::assertSame($this->expected, array_values([...$calculated]));
}
public function testOrderByColumnThrowsExceptionIfTheOffsetDoesNotExists(): void
{
$this->expectException(QueryException::class);
$this->stmt->orderByDesc(-42)->process($this->csv);
}
public function testOrderByWithEquity(): void
{
$calculated = $this->stmt
->orderBy(fn (array $rowA, array $rowB): int => strlen($rowA[0]) <=> strlen($rowB[0])) /* @phpstan-ignore-line */
->process($this->csv);
self::assertSame($this->expected, array_values([...$calculated]));
}
public function testHeaderMapperOnStatement(): void
{
$results = (new Statement())
->process($this->csv, [2 => 'e-mail', 1 => 'lastname', 33 => 'does not exists']);
self::assertSame(['e-mail', 'lastname', 'does not exists'], $results->getHeader());
self::assertSame([
'e-mail' => 'john.doe@example.com',
'lastname' => 'doe',
'does not exists' => null,
], $results->first());
}
public function testOrderByDoesNotThrowOnInvalidOffsetOrLimit(): void
{
$document = <<<CSV
Integer,Float,Text,Multiline Text,Date and Time
1,1.11,Foo,"Foo
Bar",2020-01-01 01:01:01
2,1.22,Bar,"Bar
Baz",2020-02-02 02:02:02
3,1.33,Baz,"Baz
Foo",2020-03-03 03:03:03
CSV;
$csv = Reader::fromString($document);
$csv->setHeaderOffset(0);
$constraints = (new Statement())
->select('Integer', 'Text', 'Date and Time')
->where(fn (array $record): bool => (float) $record['Float'] < 1.3)
->orderBy(fn (array $record1, array $record2): int => (int) $record2['Integer'] <=> (int) $record1['Integer']) /* @phpstan-ignore-line */
->limit(5)
->offset(2);
self::assertSame([], $constraints->process($csv)->nth(42));
}
public function testItCanCompareNullValue(): void
{
$document = <<<CSV
Title,Name,Number
Commander,Fred,104
Officer,John,117
Major,Avery
CSV;
$csv = Reader::fromString($document);
$csv->setHeaderOffset(0);
$statement = (new Statement())
->andWhere('Number', Comparison::Contains, '117');
self::assertCount(1, $statement->process($csv));
}
public function testselectAllExcept(): void
{
$document = <<<CSV
Title,Name,Number
Commander,Fred,104
Officer,John,117
Major,Avery
CSV;
$csv = Reader::fromString($document);
$csv->setHeaderOffset(0);
$statement = (new Statement())
->limit(1)
->selectAllExcept('Number');
self::assertSame(['Title' => 'Commander', 'Name' => 'Fred'], $statement->process($csv)->first());
}
}