endtoend-test-psl/tests/Psl/Collection/AbstractVectorTest.php
2020-03-01 21:52:25 +01:00

549 lines
16 KiB
PHP

<?php
declare(strict_types=1);
namespace Psl\Tests\Collection;
use PHPUnit\Framework\TestCase;
use Psl\Collection\IVector;
use Psl\Exception\InvariantViolationException;
use Psl\Str;
/**
* @covers \Psl\Collection\AbstractVector
* @covers \Psl\Collection\AbstractAccessibleCollection
*/
abstract class AbstractVectorTest extends TestCase
{
/**
* The Vector class used for values, keys .. etc.
*
* @psalm-var class-string<IVector>
*/
protected string $vectorClass = IVector::class;
public function testIsEmpty(): void
{
$this->assertTrue($this->create([])->isEmpty());
$this->assertFalse($this->create(['foo', 'bar'])->isEmpty());
$this->assertEmpty($this->create([null])->isEmpty());
}
public function testCount(): void
{
$this->assertCount(0, $this->create([]));
$this->assertCount(2, $this->create(['foo', 'bar']));
$this->assertSame(5, $this->create([
'foo',
'bar',
'baz',
'qux',
'hax' // ??
])->count());
}
public function testValues(): void
{
$vector = $this->create([1, 2, 3]);
$values = $vector->values();
$this->assertInstanceOf($this->vectorClass, $values);
$this->assertCount(3, $values);
$this->assertSame(1, $values->at(0));
$this->assertSame(2, $values->at(1));
$this->assertSame(3, $values->at(2));
$vector = $this->create([]);
$values = $vector->values();
$this->assertInstanceOf($this->vectorClass, $values);
$this->assertCount(0, $values);
}
public function testKeys(): void
{
$vector = $this->create([
'foo',
'bar',
'baz',
]);
$keys = $vector->keys();
$this->assertInstanceOf($this->vectorClass, $keys);
$this->assertCount(3, $keys);
$this->assertSame(0, $keys->at(0));
$this->assertSame(1, $keys->at(1));
$this->assertSame(2, $keys->at(2));
$vector = $this->create([]);
$keys = $vector->keys();
$this->assertInstanceOf($this->vectorClass, $keys);
$this->assertCount(0, $keys);
}
public function testFilter(): void
{
$vector = $this->create([
'foo',
'bar',
'baz',
'qux',
]);
$filtered = $vector->filter(fn (string $item) => Str\contains($item, 'b'));
$this->assertInstanceOf($this->vectorClass, $filtered);
$this->assertNotSame($vector, $filtered);
$this->assertContains('bar', $filtered);
$this->assertContains('baz', $filtered);
$this->assertNotContains('foo', $filtered);
$this->assertNotContains('qux', $filtered);
$this->assertCount(2, $filtered);
$vector = $this->create([
'foo',
'bar',
'baz',
'qux',
]);
$filtered = $vector->filter(fn (string $item) => Str\contains($item, 'hello'));
$this->assertInstanceOf($this->vectorClass, $filtered);
$this->assertNotContains('bar', $filtered);
$this->assertNotContains('baz', $filtered);
$this->assertNotContains('foo', $filtered);
$this->assertNotContains('qux', $filtered);
$this->assertCount(0, $filtered);
}
public function testFilterWithKey(): void
{
$vector = $this->create([
'foo',
'bar',
'baz',
'qux',
]);
$filtered = $vector->filterWithKey(fn (int $k, string $v) => 'foo' === $v || 3 === $k);
$this->assertInstanceOf($this->vectorClass, $filtered);
$this->assertNotSame($vector, $filtered);
$this->assertContains('foo', $filtered);
$this->assertContains('qux', $filtered);
$this->assertNotContains('bar', $filtered);
$this->assertNotContains('baz', $filtered);
$this->assertCount(2, $filtered);
$vector = $this->create([
'foo',
'bar',
'baz',
'qux',
]);
$filtered = $vector->filterWithKey(fn (int $k, string $v) => 4 === $k);
$this->assertInstanceOf($this->vectorClass, $filtered);
$this->assertNotContains('bar', $filtered);
$this->assertNotContains('baz', $filtered);
$this->assertNotContains('foo', $filtered);
$this->assertNotContains('qux', $filtered);
$this->assertCount(0, $filtered);
}
public function testMap(): void
{
$vector = $this->create([
'foo',
'bar',
'baz',
'qux',
]);
$mapped = $vector->map(fn (string $item) => Str\uppercase($item));
$this->assertInstanceOf($this->vectorClass, $mapped);
$this->assertSame([
'FOO',
'BAR',
'BAZ',
'QUX',
], $mapped->toArray());
$this->assertNotSame($vector, $mapped);
$this->assertCount(4, $mapped);
$vector = $this->create([
'foo',
'bar',
'baz',
'qux',
]);
$mapped = $vector->map(fn (string $item) => $item);
$this->assertInstanceOf($this->vectorClass, $mapped);
$this->assertNotSame($vector, $mapped);
$this->assertSame($vector->toArray(), $mapped->toArray());
$this->assertCount(4, $mapped);
}
public function testMapWithKey(): void
{
$vector = $this->create([
0 => 'foo',
1 => 'bar',
2 => 'baz',
3 => 'qux',
]);
$mapped = $vector->mapWithKey(fn (int $k, string $v) => Str\format('%s ( %d )', $v, $k));
$this->assertInstanceOf($this->vectorClass, $mapped);
$this->assertSame([
'foo ( 0 )',
'bar ( 1 )',
'baz ( 2 )',
'qux ( 3 )',
], $mapped->toArray());
$this->assertNotSame($vector, $mapped);
$this->assertCount(4, $mapped);
$vector = $this->create([
'foo',
'bar',
'baz',
'qux',
]);
$mapped = $vector->mapWithKey(fn (int $k, string $v) => $k);
$this->assertInstanceOf($this->vectorClass, $mapped);
$this->assertNotSame($vector, $mapped);
$this->assertSame($vector->keys()->toArray(), $mapped->toArray());
$this->assertCount(4, $mapped);
$mapped = $vector->mapWithKey(fn (int $k, string $v) => $v);
$this->assertInstanceOf($this->vectorClass, $mapped);
$this->assertNotSame($vector, $mapped);
$this->assertSame($vector->toArray(), $mapped->toArray());
$this->assertCount(4, $mapped);
}
public function testFirst(): void
{
$vector = $this->create([]);
$this->assertNull($vector->first());
$vector = $this->create([null]);
$this->assertNull($vector->first());
$vector = $this->create(['foo']);
$this->assertSame('foo', $vector->first());
$vector = $this->create(['bar', 'qux']);
$this->assertSame('bar', $vector->first());
}
public function testFirstKey(): void
{
$vector = $this->create([]);
$this->assertNull($vector->firstKey());
$vector = $this->create([null]);
$this->assertSame(0, $vector->firstKey());
$vector = $this->create(['foo']);
$this->assertSame(0, $vector->firstKey());
$vector = $this->create(['bar', 'qux']);
$this->assertSame(0, $vector->firstKey());
}
public function testLast(): void
{
$vector = $this->create([]);
$this->assertNull($vector->last());
$vector = $this->create([null]);
$this->assertNull($vector->last());
$vector = $this->create(['foo']);
$this->assertSame('foo', $vector->last());
$vector = $this->create(['bar', 'qux']);
$this->assertSame('qux', $vector->last());
}
public function testLastKey(): void
{
$vector = $this->create([]);
$this->assertNull($vector->lastKey());
$vector = $this->create([null]);
$this->assertSame(0, $vector->lastKey());
$vector = $this->create(['foo']);
$this->assertSame(0, $vector->lastKey());
$vector = $this->create(['bar', 'qux']);
$this->assertSame(1, $vector->lastKey());
}
public function testLinearSearch(): void
{
$vector = $this->create([]);
$this->assertNull($vector->linearSearch('foo'));
$vector = $this->create([
'foo',
'bar',
]);
$this->assertSame(0, $vector->linearSearch('foo'));
$this->assertSame(1, $vector->linearSearch('bar'));
$this->assertNull($vector->linearSearch('baz'));
$this->assertNull($vector->linearSearch('qux'));
}
public function testZip(): void
{
$vector = $this->create([]);
$zipped = $vector->zip([]);
$this->assertInstanceOf($this->vectorClass, $zipped);
$this->assertCount(0, $zipped);
$vector = $this->create([]);
$zipped = $vector->zip([1, 2]);
$this->assertInstanceOf($this->vectorClass, $zipped);
$this->assertCount(0, $zipped);
$vector = $this->create(['foo', 'bar']);
$zipped = $vector->zip([]);
$this->assertInstanceOf($this->vectorClass, $zipped);
$this->assertCount(0, $zipped);
$vector = $this->create(['foo', 'bar']);
$zipped = $vector->zip(['baz', 'qux']);
$this->assertInstanceOf($this->vectorClass, $zipped);
$this->assertCount(2, $zipped);
$this->assertSame(['foo', 'baz'], $zipped->at(0));
$this->assertSame(['bar', 'qux'], $zipped->at(1));
$vector = $this->create(['foo', 'bar', 'baz', 'qux']);
$zipped = $vector->zip(['hello', 'world']);
$this->assertInstanceOf($this->vectorClass, $zipped);
$this->assertCount(2, $zipped);
$this->assertSame(['foo', 'hello'], $zipped->at(0));
$this->assertSame(['bar', 'world'], $zipped->at(1));
$vector = $this->create(['hello', 'world']);
$zipped = $vector->zip(['foo', 'bar', 'baz', 'qux']);
$this->assertInstanceOf($this->vectorClass, $zipped);
$this->assertCount(2, $zipped);
$this->assertSame(['hello', 'foo'], $zipped->at(0));
$this->assertSame(['world', 'bar'], $zipped->at(1));
}
public function testTake(): void
{
$vector = $this->create([]);
$rest = $vector->take(2);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(0, $rest);
$vector = $this->create(['bar', 'qux']);
$rest = $vector->take(4);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(2, $rest);
$this->assertSame($vector->toArray(), $rest->toArray());
$vector = $this->create(['bar', 'qux']);
$rest = $vector->take(1);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(1, $rest);
$this->assertSame('bar', $rest->at(0));
}
public function testTakeWhile(): void
{
$vector = $this->create([]);
$rest = $vector->takeWhile(fn ($v) => false);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(0, $rest);
$vector = $this->create([]);
$rest = $vector->takeWhile(fn ($v) => true);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(0, $rest);
$vector = $this->create(['bar', 'qux']);
$rest = $vector->takeWhile(fn ($v) => true);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(2, $rest);
$this->assertSame($vector->toArray(), $rest->toArray());
$vector = $this->create(['bar', 'qux']);
$rest = $vector->takeWhile(fn ($v) => 'bar' === $v);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(1, $rest);
$this->assertSame('bar', $rest->at(0));
}
public function testDrop(): void
{
$vector = $this->create([]);
$rest = $vector->drop(2);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(0, $rest);
$vector = $this->create(['bar', 'qux']);
$rest = $vector->drop(4);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(0, $rest);
$vector = $this->create(['bar', 'qux']);
$rest = $vector->drop(1);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(1, $rest);
$this->assertSame('qux', $rest->at(0));
$vector = $this->create(['bar', 'qux']);
$rest = $vector->drop(0);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(2, $rest);
$this->assertSame($vector->toArray(), $rest->toArray());
}
public function testDropWhile(): void
{
$vector = $this->create([]);
$rest = $vector->dropWhile(fn ($v) => true);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(0, $rest);
$vector = $this->create([]);
$rest = $vector->dropWhile(fn ($v) => false);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(0, $rest);
$vector = $this->create(['bar', 'qux']);
$rest = $vector->dropWhile(fn ($v) => true);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(0, $rest);
$vector = $this->create(['bar', 'qux']);
$rest = $vector->dropWhile(fn ($v) => false);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(2, $rest);
$this->assertSame($vector->toArray(), $rest->toArray());
$vector = $this->create(['bar', 'qux']);
$rest = $vector->dropWhile(fn ($v) => 'bar' === $v);
$this->assertInstanceOf($this->vectorClass, $rest);
$this->assertNotSame($vector, $rest);
$this->assertCount(1, $rest);
$this->assertSame('qux', $rest->at(0));
}
public function testSlice(): void
{
$vector = $this->create([
'foo',
'foo',
'bar',
'bar',
'baz',
'baz',
'qux',
'qux',
]);
$slice1 = $vector->slice(0, 1);
$this->assertInstanceOf($this->vectorClass, $slice1);
$this->assertNotSame($slice1, $vector);
$this->assertCount(1, $slice1);
$this->assertSame('foo', $slice1->at(0));
$slice2 = $vector->slice(2, 4);
$this->assertInstanceOf($this->vectorClass, $slice1);
$this->assertNotSame($slice2, $vector);
$this->assertCount(4, $slice2);
$this->assertSame([
'bar',
'bar',
'baz',
'baz',
], $slice2->toArray());
}
public function testAt(): void
{
$vector = $this->create([
'hello',
'world',
]);
$this->assertSame('hello', $vector->at(0));
$this->assertSame('world', $vector->at(1));
$this->expectException(InvariantViolationException::class);
$this->expectExceptionMessage('Key (2) is out-of-bound.');
$vector->at(2);
}
public function testContains(): void
{
$vector = $this->create([
'hello',
'world',
]);
$this->assertTrue($vector->contains(0));
$this->assertTrue($vector->contains(1));
$this->assertFalse($vector->contains(2));
}
public function testGet(): void
{
$vector = $this->create([
'hello',
'world',
]);
$this->assertSame('hello', $vector->get(0));
$this->assertSame('world', $vector->get(1));
$this->assertNull($vector->get(2));
}
/**
* @template T
*
* @psalm-param iterable<T> $items
*
* @psalm-return IVector<T>
*/
abstract protected function create(iterable $items): IVector;
}