[Collection] add tests

This commit is contained in:
azjezz 2019-12-25 22:45:52 +01:00
parent cae7166abb
commit f789bcd982
18 changed files with 1546 additions and 496 deletions

View File

@ -19,6 +19,9 @@
<testsuite name="Psl Random">
<directory>tests/Psl/Random</directory>
</testsuite>
<testsuite name="Psl Collection">
<directory>tests/Psl/Collection</directory>
</testsuite>
</testsuites>
<logging>

View File

@ -22,7 +22,7 @@ use Psl;
*/
function at(array $array, $key)
{
Psl\invariant(contains_key($array, $key), 'key (%s) was out-of-bound', (string) $key);
Psl\invariant(contains_key($array, $key), 'Key (%s) is out-of-bound.', (string) $key);
/** @psalm-var Tv */
return $array[$key];

View File

@ -13,7 +13,7 @@ namespace Psl\Collection;
* @psalm-template Tk
* @psalm-template Tv
*
* @template-extends ConstSetAccess<Tk, Tv>
* @template-extends ConstSetAccess<Tk>
* @template-extends ConstIndexAccess<Tk, Tv>
*/
interface ConstMapAccess extends ConstSetAccess, ConstIndexAccess

View File

@ -35,8 +35,9 @@ final class ImmMap implements ConstMap
* Get access to the items in the collection.
*
* @psalm-return iterable<int, Pair<Tk, Tv>>
* @return Pair[]
*/
public function items(): iterable
public function items(): Vector
{
return $this->mapWithKey(
/**
@ -345,7 +346,7 @@ final class ImmMap implements ConstMap
$other = new ImmVector($iterable);
$i = 0;
foreach ($this->elements as [$k, $v]) {
if ($other->containsKey($i)) {
if (!$other->containsKey($i)) {
break;
}

View File

@ -31,9 +31,9 @@ final class ImmVector implements ConstVector
/**
* Get access to the items in the collection.
*
* @psalm-return iterable<int, Tv>
* @psalm-return array<int, Tv>
*/
public function items(): iterable
public function items(): array
{
return $this->items;
}
@ -112,7 +112,7 @@ final class ImmVector implements ConstVector
*/
public function filterWithKey(callable $fn): ImmVector
{
return new ImmVector(Iter\filter_keys($this->items, $fn));
return new ImmVector(Iter\filter_with_key($this->items, $fn));
}
/**
@ -428,4 +428,14 @@ final class ImmVector implements ConstVector
/** @psalm-var array<int, Tv> $items */
return $this->items;
}
/**
* Returns a deep, mutable copy (`Vector`) of this `ImmVector`.
*
* @psalm-return Vector<Tv> - a `Vector` that is a deep copy of this `ImmVector`
*/
public function mutable(): Vector
{
return new Vector($this->toArray());
}
}

View File

@ -24,8 +24,8 @@ use Psl\Iter;
* are being removed. When a new key is added or an element is removed, all
* iterators that point to the `Map` shall be considered invalid.
*
* @psalm-template Tk as array-key
* @psalm-template Tv
* @psalm-template Tk as array-key
* @psalm-template Tv
*
* @template-implements MutableMap<Tk, Tv>
*/
@ -55,6 +55,7 @@ final class Map implements MutableMap
*/
public function add($value): Map
{
Psl\invariant($value instanceof Pair, 'Expected $value to be instance of %s, %s given.', Pair::class, gettype($value));
$this->elements[] = [$value->first(), $value->last()];
/** @var Map<Tk, Tv> */
@ -64,13 +65,14 @@ final class Map implements MutableMap
/**
* For every element in the provided iterable, append a value into the current map.
*
* @psalm-param iterable<Pair<Tk, Tv>> $values
* @psalm-param iterable<Pair<Tk, Tv>> $values
*
* @psalm-return Map<Tk, Tv>
*/
public function addAll(iterable $values): Map
{
foreach ($values as $pair) {
Psl\invariant($pair instanceof Pair, 'Expected $iterable to only contain instances of %s, %s given.', Pair::class, gettype($pair));
$this->elements[] = [$pair->first(), $pair->last()];
}
@ -95,16 +97,17 @@ final class Map implements MutableMap
* Get access to the items in the collection.
*
* @psalm-return iterable<int, Pair<Tk, Tv>>
* @return Pair[]
*/
public function items(): iterable
public function items(): Vector
{
return $this->mapWithKey(
/**
* @psalm-param Tk $k
* @psalm-param Tv $v
*
* @psalm-return Pair<Tk, Tv>
*/
/**
* @psalm-param Tk $k
* @psalm-param Tv $v
*
* @psalm-return Pair<Tk, Tv>
*/
fn ($k, $v) => new Pair($k, $v),
)->values();
}
@ -143,7 +146,7 @@ final class Map implements MutableMap
/**
* Returns the value at the specified key in the current collection.
*
* @psalm-param Tk $k
* @psalm-param Tk $k
*
* @psalm-return Tv
*/
@ -196,7 +199,7 @@ final class Map implements MutableMap
*
* This function is interchangeable with `containsKey()`.
*
* @psalm-param Tk $m
* @psalm-param Tk $m
*
* @psalm-return bool - `true` if the value is in the current `Map`; `false` otherwise
*/
@ -256,7 +259,7 @@ final class Map implements MutableMap
* @psalm-param (callable(Tv): Tu) $fn - The callback containing the operation to apply to the current
* `Map` values
*
* @psalm-return Map<Tk, Tu> - a `Map` containing key/value pairs after a user-specified
* @psalm-return Map<Tk, Tu> - a `Map` containing key/value pairs after a user-specified
* operation is applied
*/
public function map(callable $fn): Map
@ -290,7 +293,7 @@ final class Map implements MutableMap
* @psalm-param (callable(Tk, Tv): Tu) $fn - The callback containing the operation to apply to the current
* `Map` keys and values
*
* @psalm-return Map<Tk, Tu> - a `Map` containing the values after a user-specified
* @psalm-return Map<Tk, Tu> - a `Map` containing the values after a user-specified
* operation on the current `Map`'s keys and values is
* applied
*/
@ -379,10 +382,10 @@ final class Map implements MutableMap
*
* @psalm-template Tu
*
* @psalm-param iterable<Tu> $iterable - The `iterable` to use to combine with the
* @psalm-param iterable<Tu> $iterable - The `iterable` to use to combine with the
* elements of the current `Map`
*
* @psalm-return Map<Tk, Pair<Tv, Tu>> - The `Map` that combines the values of the current
* @psalm-return Map<Tk, Pair<Tv, Tu>> - The `Map` that combines the values of the current
* `Map` with the provided `iterable`
*/
public function zip(iterable $iterable): Map
@ -393,7 +396,7 @@ final class Map implements MutableMap
$other = new ImmVector($iterable);
$i = 0;
foreach ($this->elements as [$k, $v]) {
if ($other->containsKey($i)) {
if (!$other->containsKey($i)) {
break;
}
@ -413,7 +416,7 @@ final class Map implements MutableMap
*
* `$n` is 1-based. So the first element is 1, the second 2, etc.
*
* @psalm-param int $n - The last element that will be included in the `Map`
* @psalm-param int $n - The last element that will be included in the `Map`
*
* @psalm-return Map<Tk, Tv> - A `Map` that is a proper subset of the current
* `Map` up to `n` elements
@ -460,7 +463,7 @@ final class Map implements MutableMap
*
* `$n` is 1-based. So the first element is 1, the second 2, etc.
*
* @psalm-param int $n - The last element to be skipped; the `$n+1` element will be the
* @psalm-param int $n - The last element to be skipped; the `$n+1` element will be the
* first one in the returned `Map`
*
* @psalm-return Map<Tk, Tv> - A `Map` that is a proper subset of the current
@ -515,9 +518,9 @@ final class Map implements MutableMap
* The returned `Map` will always be a proper subset of the current
* `Map`.
*
* @psalm-param int $start - The starting key location of the current `Map` for
* @psalm-param int $start - The starting key location of the current `Map` for
* the featured `Map`
* @psalm-param int $len - The length of the returned `Map`
* @psalm-param int $len - The length of the returned `Map`
*
* @psalm-return Map<Tk, Tv> - A `Map` that is a proper subset of the current
* `Map` starting at `$start` up to but not including the
@ -558,10 +561,10 @@ final class Map implements MutableMap
*
* @psalm-template Tu of Tv
*
* @psalm-param iterable<Tu> $iterable - The `iterable` to concatenate to the current
* @psalm-param iterable<Tu> $iterable - The `iterable` to concatenate to the current
* `Map`
*
* @psalm-return Vector<Tv>
* @psalm-return Vector<Tv>
*
* @return Vector - The integer-indexed concatenated `Vector`
*/
@ -639,7 +642,7 @@ final class Map implements MutableMap
* Future changes made to the current `Map` ARE reflected in the returned
* `Map`, and vice-versa.
*
* @psalm-param Tk $k - The key to remove
* @psalm-param Tk $k - The key to remove
*
* @psalm-return Map<Tk, Tv> - Returns itself
*/
@ -664,7 +667,7 @@ final class Map implements MutableMap
* Returns a new `Map` with the keys that are in the current `Map`, but not
* in the provided `iterable`.
*
* @psalm-param iterable<Tk, Tv> $iterable - The `iterable` on which to compare the keys
* @psalm-param iterable<Tk, Tv> $iterable - The `iterable` on which to compare the keys
*
* @psalm-return Map<Tk, Tv> - A `Map` containing the keys (and associated values) of the
* current `Map` that are not in the `iterable`
@ -700,13 +703,17 @@ final class Map implements MutableMap
* Future changes made to the current `Map` ARE reflected in the returned
* `Map`, and vice-versa.
*
* @psalm-param Tk $k - The key to which we will set the value
* @psalm-param Tv $v - The value to set
* @psalm-param Tk $k - The key to which we will set the value
* @psalm-param Tv $v - The value to set
*
* @psalm-return Map<Tk, Tv> - Returns itself
*/
public function set($k, $v): Map
{
if ($this->contains($k)) {
$this->remove($k);
}
$this->elements[] = [$k, $v];
/** @var Map<Tk, Tv> */
@ -726,7 +733,7 @@ final class Map implements MutableMap
* Future changes made to the current `Map` ARE reflected in the returned
* `Map`, and vice-versa.
*
* @psalm-param iterable<Tk, Tv> $iterable - The `iterable` with the new values to set
* @psalm-param iterable<Tk, Tv> $iterable - The `iterable` with the new values to set
*
* @psalm-return Map<Tk, Tv> - Returns itself
*/
@ -748,7 +755,7 @@ final class Map implements MutableMap
* Future changes made to the current `Map` ARE reflected in the returned
* `Map`, and vice-versa.
*
* @psalm-param Tk $k - The key to remove
* @psalm-param Tk $k - The key to remove
*
* @psalm-return Map<Tk, Tv> - Returns itself
*/

View File

@ -90,7 +90,7 @@ final class Pair implements ConstVector
*/
public function containsKey($k): bool
{
return 1 === $k || 2 === $k;
return 0 === $k || 1 === $k;
}
/**

View File

@ -31,9 +31,9 @@ final class Vector implements MutableVector
/**
* Get access to the items in the collection.
*
* @psalm-return iterable<int, Tv>
* @psalm-return array<int, Tv>
*/
public function items(): iterable
public function items(): array
{
return $this->immutable->items();
}
@ -475,7 +475,7 @@ final class Vector implements MutableVector
{
/** @var array<int, Tv> $arr */
$arr = $this->toArray();
Psl\invariant(Arr\contains_key($arr, $k), 'Key (%d) is out-of-bound. If you want to add a value even if a key is not present, use `addAll()`', $k);
Psl\invariant(Arr\contains_key($arr, $k), 'Key (%d) is out-of-bound. If you want to add a value even if a key is not present, use `add()`.', $k);
$arr[$k] = $v;
$this->immutable = new ImmVector($arr);
@ -502,7 +502,7 @@ final class Vector implements MutableVector
/** @var array<int, Tv> $arr */
$arr = $this->toArray();
foreach ($iterable as $k => $v) {
Psl\invariant(Arr\contains_key($arr, $k), 'Key (%d) is out-of-bound. If you want to add a value even if a key is not present, use `addAll()`', $k);
Psl\invariant(Arr\contains_key($arr, $k), 'Key (%d) is out-of-bound. If you want to add a value even if a key is not present, use `addAll()`.', $k);
$arr[$k] = $v;
}
@ -536,4 +536,14 @@ final class Vector implements MutableVector
return $this;
}
/**
* Returns a deep, immutable copy (`ImmVector`) of this `Vector`.
*
* @psalm-return ImmVector<Tv> - an `ImmVector` that is a deep copy of this `Vector`
*/
public function immutable(): ImmVector
{
return clone $this->immutable;
}
}

View File

@ -16,7 +16,7 @@ use Psl;
*
* @template-implements \SeekableIterator<TKey, TValue>
*/
class Iterator implements \SeekableIterator, \Countable
final class Iterator implements \SeekableIterator, \Countable
{
/**
* @psalm-var array{0: array<int, TKey>, 1: array<int, TValue>}

View File

@ -21,5 +21,5 @@ use Psl\Arr;
*/
function contains_key(iterable $iterable, $key): bool
{
return Arr\contains_key(to_array($iterable), $key);
return Arr\contains_key(to_array_with_keys($iterable), $key);
}

View File

@ -7,15 +7,14 @@ namespace Psl\Iter;
use Psl\Arr;
/**
* @psalm-template Tk1 as array-key
* @psalm-template Tk2 as array-key
* @psalm-template Tk as array-key
* @psalm-template Tv
*
* @psalm-param iterable<Tk1, Tv> $first
* @psalm-param iterable<Tk2, mixed> $second
* @psalm-param iterable<Tk2, mixed> ...$rest
* @psalm-param iterable<Tk, Tv> $first
* @psalm-param iterable<Tk, mixed> $second
* @psalm-param iterable<Tk, mixed> ...$rest
*
* @psalm-return iterable<Tk1, Tv>
* @psalm-return iterable<Tk, Tv>
*/
function diff_by_key(iterable $first, iterable $second, iterable ...$rest): iterable
{
@ -27,13 +26,11 @@ function diff_by_key(iterable $first, iterable $second, iterable ...$rest): iter
return $first;
}
$union = Arr\merge($second, ...$rest);
/** @psalm-var iterable<Tk1, Tv> $result */
$result = filter_keys(
$first,
/** @psalm-param Tk1 $key */
fn ($key) => !contains_key($union, $key)
);
return $result;
$other = Arr\flatten([$second, ...$rest]);
/** @psalm-var iterable<Tk1, Tv> */
foreach ($first as $k => $v) {
if (!contains_key($other, $k)) {
yield $k => $v;
}
}
}

View File

@ -16,6 +16,8 @@ const ALPHABET_BASE64_URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy
/**
* Verifies that the `$offset` is within plus/minus `$length`. Returns the
* offset as a positive integer.
*
* @codeCoverageIgnore
*/
function validate_offset(int $offset, int $length): int
{
@ -33,6 +35,8 @@ function validate_offset(int $offset, int $length): int
/**
* Verifies that the `$offset` is not less than minus `$length`. Returns the
* offset as a positive integer.
*
* @codeCoverageIgnore
*/
function validate_offset_lower_bound(int $offset, int $length): int
{
@ -49,6 +53,8 @@ function validate_offset_lower_bound(int $offset, int $length): int
/**
* @param mixed $val
*
* @codeCoverageIgnore
*/
function boolean($val): bool
{

View File

@ -31,7 +31,7 @@ class AtTest extends TestCase
public function testAtThrowsForOutOfBoundKey(): void
{
$this->expectException(Exception\InvariantViolationException::class);
$this->expectExceptionMessage('key (5) was out-of-bound');
$this->expectExceptionMessage('Key (5) is out-of-bound.');
Arr\at([], 5);
}

View File

@ -5,146 +5,347 @@ declare(strict_types=1);
namespace Psl\Tests\Collection;
use PHPUnit\Framework\TestCase;
use Psl\Collection;
use Psl\Exception;
use Psl\Iter;
use Psl\Str;
class ImmMapTest extends TestCase
{
public function testItems(): void
{
// TODO: write tests for ImmMap::items
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2]);
$items = $map->items();
self::assertSame(2, $items->count());
self::assertSame('foo', $items->at(0)->first());
self::assertSame(1, $items->at(0)->last());
self::assertSame('bar', $items->at(1)->first());
self::assertSame(2, $items->at(1)->last());
}
public function testIsEmpty(): void
{
// TODO: write tests for ImmMap::isEmpty
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2]);
self::assertFalse($map->isEmpty());
$map = $map->filter(fn ($v) => false);
self::assertTrue($map->isEmpty());
}
public function testCount(): void
{
// TODO: write tests for ImmMap::count
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2]);
self::assertCount(2, $map);
$map = $map->filter(fn ($v) => 1 === $v);
self::assertCount(1, $map);
$map = $map->filter(fn ($v) => false);
self::assertCount(0, $map);
}
public function testToArray(): void
{
// TODO: write tests for ImmMap::toArray
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2]);
$array = $map->toArray();
self::assertArrayHasKey('foo', $array);
self::assertArrayHasKey('bar', $array);
self::assertSame(1, $array['foo']);
self::assertSame(2, $array['bar']);
$map = $map->filter(fn ($v) => false);
$array = $map->toArray();
self::assertEmpty($array);
}
public function testAt(): void
{
// TODO: write tests for ImmMap::at
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2]);
self::assertSame(1, $map->at('foo'));
self::assertSame(2, $map->at('bar'));
$this->expectException(Exception\InvariantViolationException::class);
$this->expectExceptionMessage('Key (baz) is out-of-bound.');
$map->at('baz');
}
public function testContainsKey(): void
{
// TODO: write tests for ImmMap::containsKey
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => null]);
self::assertTrue($map->containsKey('foo'));
self::assertTrue($map->containsKey('bar'));
self::assertTrue($map->containsKey('baz'));
self::assertFalse($map->containsKey('qux'));
}
public function testGet(): void
{
// TODO: write tests for ImmMap::get
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2]);
self::assertSame(1, $map->get('foo'));
self::assertSame(2, $map->get('bar'));
self::assertNull($map->get('baz'));
}
public function testContains(): void
{
// TODO: write tests for ImmMap::contains
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => null]);
self::assertTrue($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertTrue($map->contains('baz'));
self::assertFalse($map->contains('qux'));
}
public function testValues(): void
{
// TODO: write tests for ImmMap::values
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => null]);
$values = $map->values();
self::assertCount(3, $values);
self::assertSame(1, $values->at(0));
self::assertSame(2, $values->at(1));
self::assertNull($values->at(2));
}
public function testKeys(): void
{
// TODO: write tests for ImmMap::keys
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => null]);
$keys = $map->keys();
self::assertCount(3, $keys);
self::assertSame('foo', $keys->at(0));
self::assertSame('bar', $keys->at(1));
self::assertSame('baz', $keys->at(2));
}
public function testMap(): void
{
// TODO: write tests for ImmMap::map
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->map(fn ($value) => $value * 2);
self::assertSame(2, $map->at('foo'));
self::assertSame(4, $map->at('bar'));
self::assertSame(6, $map->at('baz'));
}
public function testMapWithKey(): void
{
// TODO: write tests for ImmMap::mapWithKey
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->mapWithKey(fn ($key, $value) => Str\format('%s (%d)', $key, $value));
self::assertSame('foo (1)', $map->at('foo'));
self::assertSame('bar (2)', $map->at('bar'));
self::assertSame('baz (3)', $map->at('baz'));
}
public function testFilter(): void
{
// TODO: write tests for ImmMap::filter
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->filter(fn ($value) => $value >= 2);
self::assertCount(2, $map);
self::assertFalse($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertTrue($map->contains('baz'));
}
public function testFilterWithKey(): void
{
// TODO: write tests for ImmMap::filterWithKey
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->filterWithKey(fn ($key, $value) => $value >= 2 && 'baz' !== $key);
self::assertCount(1, $map);
self::assertFalse($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertFalse($map->contains('baz'));
}
public function testZip(): void
{
// TODO: write tests for ImmMap::zip
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$map = $map->zip(['one', 'two', 'three']);
/** @var Collection\Pair $foo */
$foo = $map->at('foo');
self::assertInstanceOf(Collection\Pair::class, $foo);
self::assertSame(1, $foo->first());
self::assertSame('one', $foo->last());
/** @var Collection\Pair $bar */
$bar = $map->at('bar');
self::assertInstanceOf(Collection\Pair::class, $bar);
self::assertSame(2, $bar->first());
self::assertSame('two', $bar->last());
/** @var Collection\Pair $baz */
$baz = $map->at('baz');
self::assertInstanceOf(Collection\Pair::class, $baz);
self::assertSame(3, $baz->first());
self::assertSame('three', $baz->last());
}
public function testTake(): void
{
// TODO: write tests for ImmMap::take
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->take(2);
self::assertCount(2, $map);
self::assertTrue($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertFalse($map->contains('baz'));
}
public function testTakeWhile(): void
{
// TODO: write tests for ImmMap::takeWhile
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->takeWhile(fn ($v) => 2 !== $v);
self::assertCount(1, $map);
self::assertTrue($map->contains('foo'));
self::assertFalse($map->contains('bar'));
self::assertFalse($map->contains('baz'));
}
public function testDrop(): void
{
// TODO: write tests for ImmMap::drop
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->drop(1);
self::assertCount(2, $map);
self::assertFalse($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertTrue($map->contains('baz'));
}
public function testDropWhile(): void
{
// TODO: write tests for ImmMap::dropWhile
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->dropWhile(fn ($value) => 3 !== $value);
self::assertCount(1, $map);
self::assertFalse($map->contains('foo'));
self::assertFalse($map->contains('bar'));
self::assertTrue($map->contains('baz'));
}
public function testSlice(): void
{
// TODO: write tests for ImmMap::slice
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$map = $map->slice(2, 1);
self::assertCount(1, $map);
self::assertFalse($map->contains('foo'));
self::assertFalse($map->contains('bar'));
self::assertTrue($map->contains('baz'));
self::assertFalse($map->contains('qux'));
$map = $map->slice(0, 0);
self::assertCount(0, $map);
}
public function testConcat(): void
{
// TODO: write tests for ImmMap::concat
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$vector = $map->concat([5, 6, 7, 8, 9, 10]);
self::assertCount(10, $vector);
self::assertSame([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], $vector->toArray());
}
public function testFirst(): void
{
// TODO: write tests for ImmMap::first
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
self::assertSame(1, $map->first());
$map = new Collection\ImmMap([]);
self::assertNull($map->first());
}
public function testFirstKey(): void
{
// TODO: write tests for ImmMap::firstKey
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
self::assertSame('foo', $map->firstKey());
$map = new Collection\ImmMap([]);
self::assertNull($map->firstKey());
}
public function testLast(): void
{
// TODO: write tests for ImmMap::last
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
self::assertSame(4, $map->last());
$map = new Collection\ImmMap([]);
self::assertNull($map->last());
}
public function testLastKey(): void
{
// TODO: write tests for ImmMap::lastKey
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
self::assertSame('qux', $map->lastKey());
$map = new Collection\ImmMap([]);
self::assertNull($map->lastKey());
}
public function testDifferenceByKey(): void
{
// TODO: write tests for ImmMap::differenceByKey
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$map = $map->differenceByKey(['foo' => 5, 'baz' => 6]);
self::assertFalse($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertFalse($map->contains('baz'));
self::assertTrue($map->contains('qux'));
}
public function testMutable(): void
{
// TODO: write tests for ImmMap::mutable
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$mutable = $map->mutable();
self::assertSame($map->toArray(), $mutable->toArray());
}
public function testGetIterator(): void
{
// TODO: write tests for ImmMap::getIterator
$map = new Collection\ImmMap(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$iterator = $map->getIterator();
self::assertInstanceOf(Iter\Iterator::class, $iterator);
$array = \iterator_to_array($iterator);
self::assertSame(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4], $array);
}
}

View File

@ -5,136 +5,322 @@ declare(strict_types=1);
namespace Psl\Tests\Collection;
use PHPUnit\Framework\TestCase;
use Psl\Arr;
use Psl\Collection;
use Psl\Exception;
use Psl\Iter;
use Psl\Str;
class ImmVectorTest extends TestCase
{
public function testItems(): void
{
// TODO: write tests for ImmVector::items
$vector = new Collection\ImmVector(['foo', 'bar']);
$items = $vector->items();
self::assertCount(2, $items);
self::assertSame('foo', $items[0]);
self::assertSame('bar', $items[1]);
}
public function testIsEmpty(): void
{
// TODO: write tests for ImmVector::isEmpty
$vector = new Collection\ImmVector(['foo', 'bar']);
self::assertFalse($vector->isEmpty());
$vector = new Collection\ImmVector([]);
self::assertTrue($vector->isEmpty());
}
public function testCount(): void
{
// TODO: write tests for ImmVector::count
}
$vector = new Collection\ImmVector(['foo', 'bar']);
self::assertCount(2, $vector);
public function testAt(): void
{
// TODO: write tests for ImmVector::at
}
$vector = $vector->filter(fn ($v) => 'foo' === $v);
self::assertCount(1, $vector);
public function testContainsKey(): void
{
// TODO: write tests for ImmVector::containsKey
}
public function testGet(): void
{
// TODO: write tests for ImmVector::get
}
public function testFilter(): void
{
// TODO: write tests for ImmVector::filter
}
public function testFilterWithKey(): void
{
// TODO: write tests for ImmVector::filterWithKey
}
public function testValues(): void
{
// TODO: write tests for ImmVector::values
}
public function testKeys(): void
{
// TODO: write tests for ImmVector::keys
}
public function testMap(): void
{
// TODO: write tests for ImmVector::map
}
public function testMapWithKey(): void
{
// TODO: write tests for ImmVector::mapWithKey
}
public function testZip(): void
{
// TODO: write tests for ImmVector::zip
}
public function testTake(): void
{
// TODO: write tests for ImmVector::take
}
public function testTakeWhile(): void
{
// TODO: write tests for ImmVector::takeWhile
}
public function testDrop(): void
{
// TODO: write tests for ImmVector::drop
}
public function testDropWhile(): void
{
// TODO: write tests for ImmVector::dropWhile
}
public function testSlice(): void
{
// TODO: write tests for ImmVector::slice
}
public function testConcat(): void
{
// TODO: write tests for ImmVector::concat
}
public function testFirst(): void
{
// TODO: write tests for ImmVector::first
}
public function testFirstKey(): void
{
// TODO: write tests for ImmVector::firstKey
}
public function testLast(): void
{
// TODO: write tests for ImmVector::last
}
public function testLastKey(): void
{
// TODO: write tests for ImmVector::lastKey
}
public function testLinearSearch(): void
{
// TODO: write tests for ImmVector::linearSearch
}
public function testGetIterator(): void
{
// TODO: write tests for ImmVector::getIterator
$vector = $vector->filter(fn ($v) => false);
self::assertCount(0, $vector);
}
public function testToArray(): void
{
// TODO: write tests for ImmVector::toArray
$vector = new Collection\ImmVector(['foo', 'bar']);
$array = $vector->toArray();
self::assertTrue(Arr\contains($array, 'foo'));
self::assertTrue(Arr\contains($array, 'bar'));
$vector = $vector->filter(fn ($v) => false);
$array = $vector->toArray();
self::assertEmpty($array);
}
public function testAt(): void
{
$vector = new Collection\ImmVector(['foo', 'bar']);
self::assertSame('foo', $vector->at(0));
self::assertSame('bar', $vector->at(1));
$this->expectException(Exception\InvariantViolationException::class);
$this->expectExceptionMessage('Key (2) is out-of-bound.');
$vector->at(2);
}
public function testContainsKey(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', null]);
self::assertTrue($vector->containsKey(0));
self::assertTrue($vector->containsKey(1));
self::assertTrue($vector->containsKey(2));
self::assertFalse($vector->containsKey(3));
}
public function testGet(): void
{
$vector = new Collection\ImmVector(['foo', 'bar']);
self::assertSame('foo', $vector->get(0));
self::assertSame('bar', $vector->get(1));
self::assertNull($vector->get(3));
}
public function testValues(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', null]);
$values = $vector->values();
self::assertCount(3, $values);
self::assertSame('foo', $values->at(0));
self::assertSame('bar', $values->at(1));
self::assertNull($values->at(2));
}
public function testKeys(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', 'baz']);
$keys = $vector->keys();
self::assertCount(3, $keys);
self::assertSame(0, $keys->at(0));
self::assertSame(1, $keys->at(1));
self::assertSame(2, $keys->at(2));
}
public function testMap(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', 'baz']);
$vector = $vector->map(fn ($value) => Str\uppercase($value));
self::assertSame('FOO', $vector->at(0));
self::assertSame('BAR', $vector->at(1));
self::assertSame('BAZ', $vector->at(2));
}
public function testMapWithKey(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', 'baz']);
$vector = $vector->mapWithKey(fn ($key, $value) => Str\format('%s (%d)', $value, $key));
self::assertSame('foo (0)', $vector->at(0));
self::assertSame('bar (1)', $vector->at(1));
self::assertSame('baz (2)', $vector->at(2));
}
public function testFilter(): void
{
$vector = new Collection\ImmVector(Iter\range(1, 3));
$vector = $vector->filter(fn ($value) => $value >= 2);
self::assertCount(2, $vector);
$array = $vector->toArray();
self::assertFalse(Arr\contains($array, 1));
self::assertTrue(Arr\contains($array, 2));
self::assertTrue(Arr\contains($array, 3));
}
public function testFilterWithKey(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', 'baz']);
$vector = $vector->filterWithKey(fn ($key, $value) => 0 === $key || 'baz' === $value);
self::assertCount(2, $vector);
$array = $vector->toArray();
self::assertTrue(Arr\contains($array, 'foo'));
self::assertFalse(Arr\contains($array, 'bar'));
self::assertTrue(Arr\contains($array, 'baz'));
}
public function testZip(): void
{
$vector = new Collection\ImmVector(Iter\range(1, 3));
$vector = $vector->zip(Iter\range(4, 8));
self::assertCount(3, $vector);
/** @var Collection\Pair $first */
$first = $vector->at(0);
self::assertInstanceOf(Collection\Pair::class, $first);
self::assertSame(1, $first->first());
self::assertSame(4, $first->last());
/** @var Collection\Pair $second */
$second = $vector->at(1);
self::assertInstanceOf(Collection\Pair::class, $second);
self::assertSame(2, $second->first());
self::assertSame(5, $second->last());
/** @var Collection\Pair $third */
$third = $vector->at(2);
self::assertInstanceOf(Collection\Pair::class, $third);
self::assertSame(3, $third->first());
self::assertSame(6, $third->last());
}
public function testTake(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', 'baz', 'qux']);
$vector = $vector->take(2);
self::assertCount(2, $vector);
self::assertSame(['foo', 'bar'], $vector->toArray());
}
public function testTakeWhile(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', 'baz', 'qux']);
$vector = $vector->takeWhile(fn ($value) => 'baz' !== $value);
self::assertCount(2, $vector);
self::assertSame(['foo', 'bar'], $vector->toArray());
}
public function testDrop(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', 'baz', 'qux']);
$vector = $vector->drop(2);
self::assertCount(2, $vector);
self::assertSame(['baz', 'qux'], $vector->toArray());
}
public function testDropWhile(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', 'baz', 'qux']);
$vector = $vector->dropWhile(fn ($value) => 'baz' !== $value);
self::assertCount(2, $vector);
self::assertSame(['baz', 'qux'], $vector->toArray());
}
public function testSlice(): void
{
$vector = new Collection\ImmVector(['foo', 'bar', 'baz', 'qux']);
$vector = $vector->slice(2, 1);
self::assertCount(1, $vector);
self::assertSame(['baz'], $vector->toArray());
}
public function testConcat(): void
{
$vector = new Collection\ImmVector(Iter\range(1, 5));
$vector = $vector->concat(Iter\range(6, 10));
self::assertCount(10, $vector);
self::assertSame([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], $vector->toArray());
}
public function testFirst(): void
{
$vector = new Collection\ImmVector(Iter\range(1, 5));
self::assertSame(1, $vector->first());
$vector = new Collection\ImmVector([]);
self::assertNull($vector->first());
}
public function testFirstKey(): void
{
$vector = new Collection\ImmVector(Iter\range(1, 5));
self::assertSame(0, $vector->firstKey());
$vector = new Collection\ImmVector([]);
self::assertNull($vector->firstKey());
}
public function testLast(): void
{
$vector = new Collection\ImmVector(Iter\range(1, 5));
self::assertSame(5, $vector->last());
$vector = new Collection\ImmVector([]);
self::assertNull($vector->last());
}
public function testLastKey(): void
{
$vector = new Collection\ImmVector(Iter\range(1, 5));
self::assertSame(4, $vector->lastKey());
$vector = new Collection\ImmVector([]);
self::assertNull($vector->lastKey());
}
public function testImmutable(): void
{
$vector = new Collection\ImmVector(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$mutable = $vector->mutable();
self::assertSame($vector->toArray(), $mutable->toArray());
}
public function testGetIterator(): void
{
$vector = new Collection\ImmVector(Iter\range(1, 10));
$iterator = $vector->getIterator();
self::assertInstanceOf(Iter\Iterator::class, $iterator);
$array = \iterator_to_array($iterator);
self::assertSame([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], $array);
}
public function testLinearSearch(): void
{
$vector = new Collection\ImmVector(Iter\range(1, 4));
self::assertSame(0, $vector->linearSearch(1));
self::assertSame(1, $vector->linearSearch(2));
self::assertSame(2, $vector->linearSearch(3));
self::assertSame(3, $vector->linearSearch(4));
self::assertNull($vector->linearSearch(5));
}
}

View File

@ -5,181 +5,430 @@ declare(strict_types=1);
namespace Psl\Tests\Collection;
use PHPUnit\Framework\TestCase;
use Psl\Collection;
use Psl\Exception;
use Psl\Iter;
use Psl\Str;
class MapTest extends TestCase
{
public function testAdd(): void
{
// TODO: write tests for Map::add
$map = new Collection\Map(['foo' => 1, 'bar' => 2]);
self::assertCount(2, $map);
$map->add(new Collection\Pair('baz', 3));
self::assertCount(3, $map);
self::assertTrue($map->contains('baz'));
$map->add(new Collection\Pair('qux', 4));
self::assertCount(4, $map);
self::assertTrue($map->contains('qux'));
}
public function testAddAll(): void
{
// TODO: write tests for Map::addAll
$map = new Collection\Map(['foo' => 1, 'bar' => 2]);
self::assertCount(2, $map);
$map->addAll([
new Collection\Pair('baz', 3),
new Collection\Pair('qux', 4)
]);
self::assertCount(4, $map);
self::assertTrue($map->contains('baz'));
self::assertTrue($map->contains('qux'));
}
public function testClear(): void
{
// TODO: write tests for Map::clear
$map = new Collection\Map(['foo' => 1, 'bar' => 2]);
$map->clear();
self::assertCount(0, $map);
$map = new Collection\Map([]);
$map->clear();
self::assertCount(0, $map);
}
public function testItems(): void
{
// TODO: write tests for Map::items
$map = new Collection\Map(['foo' => 1, 'bar' => 2]);
$items = $map->items();
self::assertSame(2, $items->count());
self::assertSame('foo', $items->at(0)->first());
self::assertSame(1, $items->at(0)->last());
self::assertSame('bar', $items->at(1)->first());
self::assertSame(2, $items->at(1)->last());
}
public function testIsEmpty(): void
{
// TODO: write tests for Map::isEmpty
$map = new Collection\Map(['foo' => 1, 'bar' => 2]);
self::assertFalse($map->isEmpty());
$map = $map->filter(fn ($v) => false);
self::assertTrue($map->isEmpty());
}
public function testCount(): void
{
// TODO: write tests for Map::count
$map = new Collection\Map(['foo' => 1, 'bar' => 2]);
self::assertCount(2, $map);
$map = $map->filter(fn ($v) => 1 === $v);
self::assertCount(1, $map);
$map = $map->filter(fn ($v) => false);
self::assertCount(0, $map);
}
public function testToArray(): void
{
// TODO: write tests for Map::toArray
$map = new Collection\Map(['foo' => 1, 'bar' => 2]);
$array = $map->toArray();
self::assertArrayHasKey('foo', $array);
self::assertArrayHasKey('bar', $array);
self::assertSame(1, $array['foo']);
self::assertSame(2, $array['bar']);
$map = $map->filter(fn ($v) => false);
$array = $map->toArray();
self::assertEmpty($array);
}
public function testAt(): void
{
// TODO: write tests for Map::at
$map = new Collection\Map(['foo' => 1, 'bar' => 2]);
self::assertSame(1, $map->at('foo'));
self::assertSame(2, $map->at('bar'));
$this->expectException(Exception\InvariantViolationException::class);
$this->expectExceptionMessage('Key (baz) is out-of-bound.');
$map->at('baz');
}
public function testContainsKey(): void
{
// TODO: write tests for Map::containsKey
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => null]);
self::assertTrue($map->containsKey('foo'));
self::assertTrue($map->containsKey('bar'));
self::assertTrue($map->containsKey('baz'));
self::assertFalse($map->containsKey('qux'));
}
public function testGet(): void
{
// TODO: write tests for Map::get
$map = new Collection\Map(['foo' => 1, 'bar' => 2]);
self::assertSame(1, $map->get('foo'));
self::assertSame(2, $map->get('bar'));
self::assertNull($map->get('baz'));
}
public function testContains(): void
{
// TODO: write tests for Map::contains
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => null]);
self::assertTrue($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertTrue($map->contains('baz'));
self::assertFalse($map->contains('qux'));
}
public function testValues(): void
{
// TODO: write tests for Map::values
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => null]);
$values = $map->values();
self::assertCount(3, $values);
self::assertSame(1, $values->at(0));
self::assertSame(2, $values->at(1));
self::assertNull($values->at(2));
}
public function testKeys(): void
{
// TODO: write tests for Map::keys
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => null]);
$keys = $map->keys();
self::assertCount(3, $keys);
self::assertSame('foo', $keys->at(0));
self::assertSame('bar', $keys->at(1));
self::assertSame('baz', $keys->at(2));
}
public function testMap(): void
{
// TODO: write tests for Map::map
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->map(fn ($value) => $value * 2);
self::assertSame(2, $map->at('foo'));
self::assertSame(4, $map->at('bar'));
self::assertSame(6, $map->at('baz'));
}
public function testMapWithKey(): void
{
// TODO: write tests for Map::mapWithKey
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->mapWithKey(fn ($key, $value) => Str\format('%s (%d)', $key, $value));
self::assertSame('foo (1)', $map->at('foo'));
self::assertSame('bar (2)', $map->at('bar'));
self::assertSame('baz (3)', $map->at('baz'));
}
public function testFilter(): void
{
// TODO: write tests for Map::filter
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->filter(fn ($value) => $value >= 2);
self::assertCount(2, $map);
self::assertFalse($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertTrue($map->contains('baz'));
}
public function testFilterWithKey(): void
{
// TODO: write tests for Map::filterWithKey
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->filterWithKey(fn ($key, $value) => $value >= 2 && 'baz' !== $key);
self::assertCount(1, $map);
self::assertFalse($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertFalse($map->contains('baz'));
}
public function testZip(): void
{
// TODO: write tests for Map::zip
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$map = $map->zip(['one', 'two', 'three']);
/** @var Collection\Pair $foo */
$foo = $map->at('foo');
self::assertInstanceOf(Collection\Pair::class, $foo);
self::assertSame(1, $foo->first());
self::assertSame('one', $foo->last());
/** @var Collection\Pair $bar */
$bar = $map->at('bar');
self::assertInstanceOf(Collection\Pair::class, $bar);
self::assertSame(2, $bar->first());
self::assertSame('two', $bar->last());
/** @var Collection\Pair $baz */
$baz = $map->at('baz');
self::assertInstanceOf(Collection\Pair::class, $baz);
self::assertSame(3, $baz->first());
self::assertSame('three', $baz->last());
}
public function testTake(): void
{
// TODO: write tests for Map::take
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->take(2);
self::assertCount(2, $map);
self::assertTrue($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertFalse($map->contains('baz'));
}
public function testTakeWhile(): void
{
// TODO: write tests for Map::takeWhile
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->takeWhile(fn ($v) => 2 !== $v);
self::assertCount(1, $map);
self::assertTrue($map->contains('foo'));
self::assertFalse($map->contains('bar'));
self::assertFalse($map->contains('baz'));
}
public function testDrop(): void
{
// TODO: write tests for Map::drop
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->drop(1);
self::assertCount(2, $map);
self::assertFalse($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertTrue($map->contains('baz'));
}
public function testDropWhile(): void
{
// TODO: write tests for Map::dropWhile
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map = $map->dropWhile(fn ($value) => 3 !== $value);
self::assertCount(1, $map);
self::assertFalse($map->contains('foo'));
self::assertFalse($map->contains('bar'));
self::assertTrue($map->contains('baz'));
}
public function testSlice(): void
{
// TODO: write tests for Map::slice
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$map = $map->slice(2, 1);
self::assertCount(1, $map);
self::assertFalse($map->contains('foo'));
self::assertFalse($map->contains('bar'));
self::assertTrue($map->contains('baz'));
self::assertFalse($map->contains('qux'));
$map = $map->slice(0, 0);
self::assertCount(0, $map);
}
public function testConcat(): void
{
// TODO: write tests for Map::concat
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$vector = $map->concat([5, 6, 7, 8, 9, 10]);
self::assertCount(10, $vector);
self::assertSame([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], $vector->toArray());
}
public function testFirst(): void
{
// TODO: write tests for Map::first
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
self::assertSame(1, $map->first());
$map = new Collection\Map([]);
self::assertNull($map->first());
}
public function testFirstKey(): void
{
// TODO: write tests for Map::firstKey
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
self::assertSame('foo', $map->firstKey());
$map = new Collection\Map([]);
self::assertNull($map->firstKey());
}
public function testLast(): void
{
// TODO: write tests for Map::last
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
self::assertSame(4, $map->last());
$map = new Collection\Map([]);
self::assertNull($map->last());
}
public function testLastKey(): void
{
// TODO: write tests for Map::lastKey
}
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
public function testRemove(): void
{
// TODO: write tests for Map::remove
self::assertSame('qux', $map->lastKey());
$map = new Collection\Map([]);
self::assertNull($map->lastKey());
}
public function testDifferenceByKey(): void
{
// TODO: write tests for Map::differenceByKey
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$map = $map->differenceByKey(['foo' => 5, 'baz' => 6]);
self::assertFalse($map->contains('foo'));
self::assertTrue($map->contains('bar'));
self::assertFalse($map->contains('baz'));
self::assertTrue($map->contains('qux'));
}
public function testImmutable(): void
{
// TODO: write tests for Map::immutable
}
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$immutable = $map->immutable();
public function testSet(): void
{
// TODO: write tests for Map::set
}
public function testSetAll(): void
{
// TODO: write tests for Map::setAll
}
public function testRemoveKey(): void
{
// TODO: write tests for Map::removeKey
self::assertSame($map->toArray(), $immutable->toArray());
}
public function testGetIterator(): void
{
// TODO: write tests for Map::getIterator
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$iterator = $map->getIterator();
self::assertInstanceOf(Iter\Iterator::class, $iterator);
$array = \iterator_to_array($iterator);
self::assertSame(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4], $array);
}
public function testRemove(): void
{
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$map->remove('foo');
self::assertFalse($map->contains('foo'));
}
public function testSet(): void
{
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map->set('foo', 5);
self::assertSame(5, $map->get('foo'));
$map->set('qux', 4);
self::assertTrue($map->contains('qux'));
self::assertSame(4, $map->get('qux'));
}
public function testSetAll(): void
{
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3]);
$map->setAll(['foo' => 5, 'qux' => 4]);
self::assertSame(5, $map->get('foo'));
self::assertTrue($map->contains('qux'));
self::assertSame(4, $map->get('qux'));
}
public function testRemoveKey(): void
{
$map = new Collection\Map(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$map->removeKey('foo');
self::assertFalse($map->contains('foo'));
}
}

View File

@ -5,136 +5,282 @@ declare(strict_types=1);
namespace Psl\Tests\Collection;
use PHPUnit\Framework\TestCase;
use Psl\Arr;
use Psl\Collection;
use Psl\Exception;
use Psl\Iter;
use Psl\Str;
class PairTest extends TestCase
{
public function testItems(): void
{
// TODO: write tests for Pair::items
$pair = new Collection\Pair('foo', 'bar');
$items = $pair->items();
self::assertCount(2, $items);
self::assertSame('foo', $items[0]);
self::assertSame('bar', $items[1]);
}
public function testIsEmpty(): void
{
// TODO: write tests for Pair::isEmpty
$pair = new Collection\Pair('foo', 'bar');
self::assertFalse($pair->isEmpty());
}
public function testCount(): void
{
// TODO: write tests for Pair::count
}
$pair = new Collection\Pair('foo', 'bar');
self::assertCount(2, $pair);
public function testAt(): void
{
// TODO: write tests for Pair::at
}
$vector = $pair->filter(fn ($v) => 'foo' === $v);
self::assertInstanceOf(Collection\ImmVector::class, $vector);
self::assertCount(1, $vector);
public function testContainsKey(): void
{
// TODO: write tests for Pair::containsKey
}
public function testGet(): void
{
// TODO: write tests for Pair::get
}
public function testFilter(): void
{
// TODO: write tests for Pair::filter
}
public function testFilterWithKey(): void
{
// TODO: write tests for Pair::filterWithKey
}
public function testValues(): void
{
// TODO: write tests for Pair::values
}
public function testKeys(): void
{
// TODO: write tests for Pair::keys
}
public function testMap(): void
{
// TODO: write tests for Pair::map
}
public function testMapWithKey(): void
{
// TODO: write tests for Pair::mapWithKey
}
public function testZip(): void
{
// TODO: write tests for Pair::zip
}
public function testTake(): void
{
// TODO: write tests for Pair::take
}
public function testTakeWhile(): void
{
// TODO: write tests for Pair::takeWhile
}
public function testDrop(): void
{
// TODO: write tests for Pair::drop
}
public function testDropWhile(): void
{
// TODO: write tests for Pair::dropWhile
}
public function testSlice(): void
{
// TODO: write tests for Pair::slice
}
public function testConcat(): void
{
// TODO: write tests for Pair::concat
}
public function testFirst(): void
{
// TODO: write tests for Pair::first
}
public function testFirstKey(): void
{
// TODO: write tests for Pair::firstKey
}
public function testLast(): void
{
// TODO: write tests for Pair::last
}
public function testLastKey(): void
{
// TODO: write tests for Pair::lastKey
}
public function testLinearSearch(): void
{
// TODO: write tests for Pair::linearSearch
}
public function testGetIterator(): void
{
// TODO: write tests for Pair::getIterator
$vector = $pair->filter(fn ($v) => false);
self::assertInstanceOf(Collection\ImmVector::class, $vector);
self::assertCount(0, $vector);
}
public function testToArray(): void
{
// TODO: write tests for Pair::toArray
$pair = new Collection\Pair('foo', 'bar');
$array = $pair->toArray();
self::assertTrue(Arr\contains($array, 'foo'));
self::assertTrue(Arr\contains($array, 'bar'));
$vector = $pair->filter(fn ($v) => false);
$array = $vector->toArray();
self::assertEmpty($array);
}
public function testAt(): void
{
$pair = new Collection\Pair('foo', 'bar');
self::assertSame('foo', $pair->at(0));
self::assertSame('bar', $pair->at(1));
$this->expectException(Exception\InvariantViolationException::class);
$this->expectExceptionMessage('Key (2) is out-of-bound.');
$pair->at(2);
}
public function testContainsKey(): void
{
$pair = new Collection\Pair('foo', 'bar');
self::assertTrue($pair->containsKey(0));
self::assertTrue($pair->containsKey(1));
self::assertFalse($pair->containsKey(2));
self::assertFalse($pair->containsKey(3));
}
public function testGet(): void
{
$pair = new Collection\Pair('foo', 'bar');
self::assertSame('foo', $pair->get(0));
self::assertSame('bar', $pair->get(1));
self::assertNull($pair->get(3));
}
public function testValues(): void
{
$pair = new Collection\Pair('foo', 'bar');
$values = $pair->values();
self::assertCount(2, $values);
self::assertSame('foo', $values->at(0));
self::assertSame('bar', $values->at(1));
}
public function testKeys(): void
{
$pair = new Collection\Pair('foo', 'bar');
$keys = $pair->keys();
self::assertCount(2, $keys);
self::assertSame(0, $keys->at(0));
self::assertSame(1, $keys->at(1));
}
public function testMap(): void
{
$pair = new Collection\Pair('foo', 'bar');
$vector = $pair->map(fn ($value) => Str\uppercase($value));
self::assertSame('FOO', $vector->at(0));
self::assertSame('BAR', $vector->at(1));
}
public function testMapWithKey(): void
{
$pair = new Collection\Pair('foo', 'bar');
$vector = $pair->mapWithKey(fn ($key, $value) => Str\format('%s (%d)', $value, $key));
self::assertSame('foo (0)', $vector->at(0));
self::assertSame('bar (1)', $vector->at(1));
}
public function testFilter(): void
{
$pair = new Collection\Pair(1, 2);
$pair = $pair->filter(fn ($value) => $value >= 2);
self::assertCount(1, $pair);
$array = $pair->toArray();
self::assertFalse(Arr\contains($array, 1));
self::assertTrue(Arr\contains($array, 2));
}
public function testFilterWithKey(): void
{
$pair = new Collection\Pair('foo', 'bar');
$vector = $pair->filterWithKey(fn ($key, $value) => 0 === $key);
self::assertCount(1, $vector);
$array = $vector->toArray();
self::assertTrue(Arr\contains($array, 'foo'));
self::assertFalse(Arr\contains($array, 'bar'));
}
public function testZip(): void
{
$pair = new Collection\Pair(1, 2);
$vector = $pair->zip(Iter\range(4, 8));
self::assertCount(2, $vector);
/** @var Collection\Pair $first */
$first = $vector->at(0);
self::assertInstanceOf(Collection\Pair::class, $first);
self::assertSame(1, $first->first());
self::assertSame(4, $first->last());
/** @var Collection\Pair $second */
$second = $vector->at(1);
self::assertInstanceOf(Collection\Pair::class, $second);
self::assertSame(2, $second->first());
self::assertSame(5, $second->last());
}
public function testTake(): void
{
$pair = new Collection\Pair('foo', 'bar');
$vector = $pair->take(1);
self::assertCount(1, $vector);
self::assertSame(['foo'], $vector->toArray());
}
public function testTakeWhile(): void
{
$pair = new Collection\Pair('foo', 'bar');
$vector = $pair->takeWhile(fn ($value) => 'bar' !== $value);
self::assertCount(1, $vector);
self::assertSame(['foo'], $vector->toArray());
}
public function testDrop(): void
{
$pair = new Collection\Pair('foo', 'bar');
$vector = $pair->drop(1);
self::assertCount(1, $vector);
self::assertSame(['bar'], $vector->toArray());
}
public function testDropWhile(): void
{
$pair = new Collection\Pair('foo', 'bar');
$vector = $pair->dropWhile(fn ($value) => 'bar' !== $value);
self::assertCount(1, $vector);
self::assertSame(['bar'], $vector->toArray());
}
public function testSlice(): void
{
$pair = new Collection\Pair('foo', 'bar');
$pair = $pair->slice(0, 1);
self::assertCount(1, $pair);
self::assertSame(['foo'], $pair->toArray());
}
public function testConcat(): void
{
$pair = new Collection\Pair(1, 2);
$vector = $pair->concat(Iter\range(3, 10));
self::assertCount(10, $vector);
self::assertSame([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], $vector->toArray());
}
public function testFirst(): void
{
$pair = new Collection\Pair(1, 2);
self::assertSame(1, $pair->first());
}
public function testFirstKey(): void
{
$pair = new Collection\Pair(1, 2);
self::assertSame(0, $pair->firstKey());
}
public function testLast(): void
{
$pair = new Collection\Pair(1, 2);
self::assertSame(2, $pair->last());
}
public function testLastKey(): void
{
$pair = new Collection\Pair(1, 2);
self::assertSame(1, $pair->lastKey());
}
public function testGetIterator(): void
{
$pair = new Collection\Pair(1, 2);
$iterator = $pair->getIterator();
self::assertInstanceOf(Iter\Iterator::class, $iterator);
$array = \iterator_to_array($iterator);
self::assertSame([1, 2], $array);
}
public function testLinearSearch(): void
{
$pair = new Collection\Pair(1, 2);
self::assertSame(0, $pair->linearSearch(1));
self::assertSame(1, $pair->linearSearch(2));
self::assertNull($pair->linearSearch(5));
}
}

View File

@ -5,166 +5,400 @@ declare(strict_types=1);
namespace Psl\Tests\Collection;
use PHPUnit\Framework\TestCase;
use Psl\Arr;
use Psl\Collection;
use Psl\Exception;
use Psl\Iter;
use Psl\Str;
class VectorTest extends TestCase
{
public function testItems(): void
{
// TODO: write tests for Vector::items
}
public function testIsEmpty(): void
{
// TODO: write tests for Vector::isEmpty
}
public function testCount(): void
{
// TODO: write tests for Vector::count
}
public function testAt(): void
{
// TODO: write tests for Vector::at
}
public function testContainsKey(): void
{
// TODO: write tests for Vector::containsKey
}
public function testGet(): void
{
// TODO: write tests for Vector::get
}
public function testFilter(): void
{
// TODO: write tests for Vector::filter
}
public function testFilterWithKey(): void
{
// TODO: write tests for Vector::filterWithKey
}
public function testValues(): void
{
// TODO: write tests for Vector::values
}
public function testKeys(): void
{
// TODO: write tests for Vector::keys
}
public function testMap(): void
{
// TODO: write tests for Vector::map
}
public function testMapWithKey(): void
{
// TODO: write tests for Vector::mapWithKey
}
public function testZip(): void
{
// TODO: write tests for Vector::zip
}
public function testTake(): void
{
// TODO: write tests for Vector::take
}
public function testTakeWhile(): void
{
// TODO: write tests for Vector::takeWhile
}
public function testDrop(): void
{
// TODO: write tests for Vector::drop
}
public function testDropWhile(): void
{
// TODO: write tests for Vector::dropWhile
}
public function testSlice(): void
{
// TODO: write tests for Vector::slice
}
public function testConcat(): void
{
// TODO: write tests for Vector::concat
}
public function testFirst(): void
{
// TODO: write tests for Vector::first
}
public function testFirstKey(): void
{
// TODO: write tests for Vector::firstKey
}
public function testLast(): void
{
// TODO: write tests for Vector::last
}
public function testLastKey(): void
{
// TODO: write tests for Vector::lastKey
}
public function testLinearSearch(): void
{
// TODO: write tests for Vector::linearSearch
}
public function testGetIterator(): void
{
// TODO: write tests for Vector::getIterator
}
public function testToArray(): void
{
// TODO: write tests for Vector::toArray
}
public function testAdd(): void
{
// TODO: write tests for Vector::add
$vector = new Collection\Vector(['foo', 'bar']);
self::assertCount(2, $vector);
$vector->add('baz');
self::assertCount(3, $vector);
self::assertSame('baz', $vector->at(2));
$vector->add('qux');
self::assertCount(4, $vector);
self::assertSame('qux', $vector->at(3));
}
public function testAddAll(): void
{
// TODO: write tests for Vector::addAll
$vector = new Collection\Vector(['foo', 'bar']);
self::assertCount(2, $vector);
$vector->addAll(['baz', 'qux']);
self::assertCount(4, $vector);
self::assertSame('baz', $vector->at(2));
self::assertSame('qux', $vector->at(3));
}
public function testClear(): void
{
// TODO: write tests for Vector::clear
$vector = new Collection\Vector(['foo', 'bar']);
$vector->clear();
self::assertCount(0, $vector);
$vector = new Collection\Vector([]);
$vector->clear();
self::assertCount(0, $vector);
}
public function testItems(): void
{
$vector = new Collection\Vector(['foo', 'bar']);
$items = $vector->items();
self::assertCount(2, $items);
self::assertSame('foo', $items[0]);
self::assertSame('bar', $items[1]);
}
public function testIsEmpty(): void
{
$vector = new Collection\Vector(['foo', 'bar']);
self::assertFalse($vector->isEmpty());
$vector->clear();
self::assertTrue($vector->isEmpty());
}
public function testCount(): void
{
$vector = new Collection\Vector(['foo', 'bar']);
self::assertCount(2, $vector);
$vector = $vector->filter(fn ($v) => 'foo' === $v);
self::assertCount(1, $vector);
$vector = $vector->filter(fn ($v) => false);
self::assertCount(0, $vector);
}
public function testToArray(): void
{
$vector = new Collection\Vector(['foo', 'bar']);
$array = $vector->toArray();
self::assertTrue(Arr\contains($array, 'foo'));
self::assertTrue(Arr\contains($array, 'bar'));
$vector = $vector->filter(fn ($v) => false);
$array = $vector->toArray();
self::assertEmpty($array);
}
public function testAt(): void
{
$vector = new Collection\Vector(['foo', 'bar']);
self::assertSame('foo', $vector->at(0));
self::assertSame('bar', $vector->at(1));
$this->expectException(Exception\InvariantViolationException::class);
$this->expectExceptionMessage('Key (2) is out-of-bound.');
$vector->at(2);
}
public function testContainsKey(): void
{
$vector = new Collection\Vector(['foo', 'bar', null]);
self::assertTrue($vector->containsKey(0));
self::assertTrue($vector->containsKey(1));
self::assertTrue($vector->containsKey(2));
self::assertFalse($vector->containsKey(3));
}
public function testGet(): void
{
$vector = new Collection\Vector(['foo', 'bar']);
self::assertSame('foo', $vector->get(0));
self::assertSame('bar', $vector->get(1));
self::assertNull($vector->get(3));
}
public function testValues(): void
{
$vector = new Collection\Vector(['foo', 'bar', null]);
$values = $vector->values();
self::assertCount(3, $values);
self::assertSame('foo', $values->at(0));
self::assertSame('bar', $values->at(1));
self::assertNull($values->at(2));
}
public function testKeys(): void
{
$vector = new Collection\Vector(['foo', 'bar', 'baz']);
$keys = $vector->keys();
self::assertCount(3, $keys);
self::assertSame(0, $keys->at(0));
self::assertSame(1, $keys->at(1));
self::assertSame(2, $keys->at(2));
}
public function testMap(): void
{
$vector = new Collection\Vector(['foo', 'bar', 'baz']);
$vector = $vector->map(fn ($value) => Str\uppercase($value));
self::assertSame('FOO', $vector->at(0));
self::assertSame('BAR', $vector->at(1));
self::assertSame('BAZ', $vector->at(2));
}
public function testMapWithKey(): void
{
$vector = new Collection\Vector(['foo', 'bar', 'baz']);
$vector = $vector->mapWithKey(fn ($key, $value) => Str\format('%s (%d)', $value, $key));
self::assertSame('foo (0)', $vector->at(0));
self::assertSame('bar (1)', $vector->at(1));
self::assertSame('baz (2)', $vector->at(2));
}
public function testFilter(): void
{
$vector = new Collection\Vector(Iter\range(1, 3));
$vector = $vector->filter(fn ($value) => $value >= 2);
self::assertCount(2, $vector);
$array = $vector->toArray();
self::assertFalse(Arr\contains($array, 1));
self::assertTrue(Arr\contains($array, 2));
self::assertTrue(Arr\contains($array, 3));
}
public function testFilterWithKey(): void
{
$vector = new Collection\Vector(['foo', 'bar', 'baz']);
$vector = $vector->filterWithKey(fn ($key, $value) => 0 === $key || 'baz' === $value);
self::assertCount(2, $vector);
$array = $vector->toArray();
self::assertTrue(Arr\contains($array, 'foo'));
self::assertFalse(Arr\contains($array, 'bar'));
self::assertTrue(Arr\contains($array, 'baz'));
}
public function testZip(): void
{
$vector = new Collection\Vector(Iter\range(1, 3));
$vector = $vector->zip(Iter\range(4, 8));
self::assertCount(3, $vector);
/** @var Collection\Pair $first */
$first = $vector->at(0);
self::assertInstanceOf(Collection\Pair::class, $first);
self::assertSame(1, $first->first());
self::assertSame(4, $first->last());
/** @var Collection\Pair $second */
$second = $vector->at(1);
self::assertInstanceOf(Collection\Pair::class, $second);
self::assertSame(2, $second->first());
self::assertSame(5, $second->last());
/** @var Collection\Pair $third */
$third = $vector->at(2);
self::assertInstanceOf(Collection\Pair::class, $third);
self::assertSame(3, $third->first());
self::assertSame(6, $third->last());
}
public function testTake(): void
{
$vector = new Collection\Vector(['foo', 'bar', 'baz', 'qux']);
$vector = $vector->take(2);
self::assertCount(2, $vector);
self::assertSame(['foo', 'bar'], $vector->toArray());
}
public function testTakeWhile(): void
{
$vector = new Collection\Vector(['foo', 'bar', 'baz', 'qux']);
$vector = $vector->takeWhile(fn ($value) => 'baz' !== $value);
self::assertCount(2, $vector);
self::assertSame(['foo', 'bar'], $vector->toArray());
}
public function testDrop(): void
{
$vector = new Collection\Vector(['foo', 'bar', 'baz', 'qux']);
$vector = $vector->drop(2);
self::assertCount(2, $vector);
self::assertSame(['baz', 'qux'], $vector->toArray());
}
public function testDropWhile(): void
{
$vector = new Collection\Vector(['foo', 'bar', 'baz', 'qux']);
$vector = $vector->dropWhile(fn ($value) => 'baz' !== $value);
self::assertCount(2, $vector);
self::assertSame(['baz', 'qux'], $vector->toArray());
}
public function testSlice(): void
{
$vector = new Collection\Vector(['foo', 'bar', 'baz', 'qux']);
$vector = $vector->slice(2, 1);
self::assertCount(1, $vector);
self::assertSame(['baz'], $vector->toArray());
}
public function testConcat(): void
{
$vector = new Collection\Vector(Iter\range(1, 5));
$vector = $vector->concat(Iter\range(6, 10));
self::assertCount(10, $vector);
self::assertSame([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], $vector->toArray());
}
public function testFirst(): void
{
$vector = new Collection\Vector(Iter\range(1, 5));
self::assertSame(1, $vector->first());
$vector = new Collection\Vector([]);
self::assertNull($vector->first());
}
public function testFirstKey(): void
{
$vector = new Collection\Vector(Iter\range(1, 5));
self::assertSame(0, $vector->firstKey());
$vector = new Collection\Vector([]);
self::assertNull($vector->firstKey());
}
public function testLast(): void
{
$vector = new Collection\Vector(Iter\range(1, 5));
self::assertSame(5, $vector->last());
$vector = new Collection\Vector([]);
self::assertNull($vector->last());
}
public function testLastKey(): void
{
$vector = new Collection\Vector(Iter\range(1, 5));
self::assertSame(4, $vector->lastKey());
$vector = new Collection\Vector([]);
self::assertNull($vector->lastKey());
}
public function testImmutable(): void
{
$vector = new Collection\Vector(['foo' => 1, 'bar' => 2, 'baz' => 3, 'qux' => 4]);
$immutable = $vector->immutable();
self::assertSame($vector->toArray(), $immutable->toArray());
}
public function testGetIterator(): void
{
$vector = new Collection\Vector(Iter\range(1, 10));
$iterator = $vector->getIterator();
self::assertInstanceOf(Iter\Iterator::class, $iterator);
$array = \iterator_to_array($iterator);
self::assertSame([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], $array);
}
public function testSet(): void
{
// TODO: write tests for Vector::set
$vector = new Collection\Vector(Iter\range(1, 10));
$vector->set(0, 5);
self::assertSame(5, $vector->get(0));
$this->expectException(Exception\InvariantViolationException::class);
$this->expectExceptionMessage('Key (20) is out-of-bound. If you want to add a value even if a key is not present, use `add()`.');
$vector->set(20, 5);
}
public function testSetAll(): void
{
// TODO: write tests for Vector::setAll
$vector = new Collection\Vector(Iter\range(1, 10));
$vector->setAll(Iter\range(10, 12));
self::assertSame(10, $vector->get(0));
self::assertSame(11, $vector->get(1));
self::assertSame(12, $vector->get(2));
$this->expectException(Exception\InvariantViolationException::class);
$this->expectExceptionMessage('Key (15) is out-of-bound. If you want to add a value even if a key is not present, use `addAll()`.');
$vector->setAll([15 => 5]);
}
public function testRemoveKey(): void
{
// TODO: write tests for Vector::removeKey
$vector = new Collection\Vector(Iter\range(0, 4));
self::assertCount(5, $vector);
$vector->removeKey(2);
self::assertCount(4, $vector);
}
public function testLinearSearch(): void
{
$vector = new Collection\Vector(Iter\range(1, 4));
self::assertSame(0, $vector->linearSearch(1));
self::assertSame(1, $vector->linearSearch(2));
self::assertSame(2, $vector->linearSearch(3));
self::assertSame(3, $vector->linearSearch(4));
self::assertNull($vector->linearSearch(5));
}
}