Page MenuHomeDevCentral

No OneTemporary

diff --git a/omnitools/src/Collections/BaseCollection.php b/omnitools/src/Collections/BaseCollection.php
index 69b1901..eb373fd 100644
--- a/omnitools/src/Collections/BaseCollection.php
+++ b/omnitools/src/Collections/BaseCollection.php
@@ -1,34 +1,36 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Collections;
abstract class BaseCollection {
+ use WithCollection;
+
///
/// Constructors
///
public static abstract function from (iterable $items) : static;
///
/// Constants
///
const CB_ZERO_ARG = "Callback function should have at least one argument";
///
/// Getters
///
public abstract function toArray () : array;
///
/// Properties
///
public abstract function count () : int;
public abstract function isEmpty () : bool;
}
diff --git a/omnitools/src/Collections/WithCollection.php b/omnitools/src/Collections/WithCollection.php
new file mode 100644
index 0000000..3b7c3ee
--- /dev/null
+++ b/omnitools/src/Collections/WithCollection.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Keruald\OmniTools\Collections;
+
+use OutOfRangeException;
+
+trait WithCollection {
+
+ abstract function count () : int;
+ abstract function toArray() : array;
+
+ public function first () : mixed {
+ foreach ($this->toArray() as $item) {
+ return $item;
+ }
+
+ throw new OutOfRangeException("The collection is empty.");
+ }
+
+ public function firstOr (mixed $default) : mixed {
+ return match ($this->count()) {
+ 0 => $default,
+ default => $this->first(),
+ };
+ }
+
+}
diff --git a/omnitools/tests/Collections/BitsVectorTest.php b/omnitools/tests/Collections/BitsVectorTest.php
index cc5d1bb..d6064ce 100644
--- a/omnitools/tests/Collections/BitsVectorTest.php
+++ b/omnitools/tests/Collections/BitsVectorTest.php
@@ -1,233 +1,265 @@
<?php
namespace Keruald\OmniTools\Tests\Collections;
use InvalidArgumentException;
+use OutOfRangeException;
use Keruald\OmniTools\Collections\BitsVector;
use PHPUnit\Framework\TestCase;
class BitsVectorTest extends TestCase {
///
/// Constructors
///
public function testConstructorWithInvalidIterable () : void {
$this->expectException(InvalidArgumentException::class);
new BitsVector([1, 2, 3, 4]);
}
public function testNew () : void {
$bits = BitsVector::new(8);
$this->assertEquals(8, $bits->count());
}
public function testNewWhenCapacityIsEmpty () : void {
$bits = BitsVector::new(0);
$this->assertEquals(0, $bits->count());
}
public function testNewWhenCapacityIsNegative () : void {
$this->expectException(InvalidArgumentException::class);
BitsVector::new(-8);
}
public function testFromInteger () : void {
$bits = BitsVector::fromInteger(4);
$this->assertEquals([1, 0, 0], $bits->toArray());
}
public function testFromIntegerWhenValueIsNegative () : void {
$bits = BitsVector::fromInteger(-1);
$expected = array_fill(0, 64, 1);
$this->assertEquals($expected, $bits->toArray());
}
public function testFromBinString () : void {
$bits = BitsVector::fromBinaryString("1001");
$this->assertEquals([1, 0, 0, 1], $bits->toArray());
}
public function testFromHexString () : void {
$bits = BitsVector::fromHexString("337362ea");
$this->assertEquals("337362ea", $bits->toHexString());
}
public function testFromDecoratedHexString () : void {
$bits = BitsVector::fromDecoratedHexString("cc4eca23-b825-11ec-ab20-a81e84f35d9c");
$this->assertEquals("cc4eca23b82511ecab20a81e84f35d9c", $bits->toHexString());
}
public function testFromString () : void {
// Exemple based on pack() documentation
$binaryData = pack("nvc*", 0x1234, 0x5678, 65, 66);
$bits = BitsVector::fromString($binaryData);
$this->assertEquals(
[0x12, 0x34, 0x78, 0x56, 0x41, 0x42],
$bits->toBytesArray(),
);
}
public function testBytesArray () : void {
$bits = BitsVector::new(16)
->copyInteger(1, 0, 4)
->copyInteger(2, 4, 4)
->copyInteger(3, 8, 4)
->copyInteger(4, 12, 4);
$this->assertEquals(
[0x12, 0x34],
$bits->toBytesArray(),
);
}
public function provideLengths () : iterable {
yield [1];
yield [2];
yield [8];
yield [500];
yield [5000];
yield [0];
}
/**
* @dataProvider provideLengths
*/
public function testRandom($length) : void {
$bits = BitsVector::random($length);
$this->assertEquals($length, $bits->count());
}
public function testRandomWithNegativeLength() : void {
$this->expectException(InvalidArgumentException::class);
BitsVector::random(-1);
}
public function testBytesArrayWithBadLength () : void {
$this->expectException(InvalidArgumentException::class);
$bits = new BitsVector([1, 1, 1]); // 3 bits isn't a byte
$bits->toBytesArray();
}
public function testToBinaryString () : void {
$bits = new BitsVector([1, 0, 0, 1]);
$this->assertEquals("1001", $bits->toBinaryString());
}
public function testToInteger () : void {
$bits = new BitsVector([1, 0, 0, 1]);
$this->assertEquals(9, $bits->toInteger());
}
public function testToIntegerWhenThereIsTooMuchBits () : void {
$this->expectException(InvalidArgumentException::class);
BitsVector::new(66)->toInteger();
}
public function testPad () : void {
$bits = new BitsVector([1, 0, 0, 1]);
$bits->pad(8);
$this->assertEquals([0, 0, 0, 0, 1, 0, 0, 1], $bits->toArray());
}
public function testPadWithLargeEnoughCount () : void {
$bits = new BitsVector([1, 0, 0, 1]);
$bits->pad(4);
$this->assertEquals([1, 0, 0, 1], $bits->toArray());
}
public function testTruncate () : void {
$bits = new BitsVector([1, 0, 0, 1, 0, 0, 0, 0]);
$bits->truncate(4);
$this->assertEquals([1, 0, 0, 1], $bits->toArray());
}
public function testTruncateWithSmallEnoughCount () : void {
$bits = new BitsVector([1, 0, 0, 1]);
$bits->truncate(4);
$this->assertEquals([1, 0, 0, 1], $bits->toArray());
}
public function provideShapeArrays () : iterable {
yield [[1, 0, 0, 1, 0, 0, 0, 0], 4, [1, 0, 0, 1]];
yield [[1, 0, 0, 1], 4, [1, 0, 0, 1]];
yield [[1, 0, 0, 1], 3, [1, 0, 0]];
yield [[1, 0, 0, 1], 0, []];
yield [[], 0, []];
yield [[], 4, [0, 0, 0, 0]];
}
/**
* @dataProvider provideShapeArrays
*/
public function testShapeCapacity (array $initial, int $length, array $final) : void {
$bits = new BitsVector($initial);
$bits->shapeCapacity($length);
$this->assertEquals($final, $bits->toArray());
}
public function testCopyInteger() : void {
$bits = BitsVector::new(8);
$bits->copyInteger(5, 2, 3);
$this->assertEquals([0, 0, 1, 0, 1, 0, 0, 0], $bits->toArray());
}
///
/// BaseVector overrides
///
public function testSet () : void {
$bits = BitsVector::new(4);
$bits->set(2, 1);
$this->assertEquals([0, 0, 1, 0], $bits->toArray());
}
public function testContains () : void {
$bits = BitsVector::new(4);
$this->assertFalse($bits->contains(1));
}
public function testPush () : void {
$bits = BitsVector::new(4);
$bits->push(1);
$this->assertEquals([0, 0, 0, 0, 1], $bits->toArray());
}
public function testAppend () : void {
$bits = BitsVector::new(4);
$bits->append([1, 1]);
$this->assertEquals([0, 0, 0, 0, 1, 1], $bits->toArray());
}
public function testUpdate () : void {
$bits = BitsVector::new(4);
$bits->update([1, 0, 1, 0]); // 0 already exists, we'll add ONE 1
$this->assertEquals([0, 0, 0, 0, 1], $bits->toArray());
}
public function testOffsetSet () : void {
$bits = BitsVector::new(4);
$bits[2] = 1;
$this->assertEquals([0, 0, 1, 0], $bits->toArray());
}
+ ///
+ /// WithCollection trait
+ ///
+
+ public function testFirst () : void {
+ $bits = BitsVector::new(4);
+ $bits[2] = 1;
+
+ $this->assertEquals(0, $bits->first());
+ }
+
+ public function testFirstWhenEmpty () : void {
+ $bits = BitsVector::new(0);
+
+ $this->expectException(OutOfRangeException::class);
+ $bits->first();
+ }
+
+ public function testFirstOr () : void {
+ $bits = BitsVector::new(4);
+ $bits[2] = 1;
+
+ $this->assertEquals(0, $bits->firstOr(2));
+ }
+
+ public function testFirstOrWhenEmpty () : void {
+ $bits = BitsVector::new(0);
+
+ $this->assertEquals(2, $bits->firstOr(2));
+ }
+
}
diff --git a/omnitools/tests/Collections/HashMapTest.php b/omnitools/tests/Collections/HashMapTest.php
index c3c1fca..273813b 100644
--- a/omnitools/tests/Collections/HashMapTest.php
+++ b/omnitools/tests/Collections/HashMapTest.php
@@ -1,465 +1,495 @@
<?php
namespace Keruald\OmniTools\Tests\Collections;
+use Keruald\OmniTools\Collections\BitsVector;
use Keruald\OmniTools\Collections\HashMap;
use PHPUnit\Framework\TestCase;
use InvalidArgumentException;
use IteratorAggregate;
+use OutOfRangeException;
use Traversable;
class HashMapTest extends TestCase {
///
/// Test set up
///
private HashMap $map;
const MAP_CONTENT = [
// Some sci-fi civilizations and author
"The Culture" => "Iain Banks",
"Radchaai Empire" => "Ann Leckie",
"Barrayar" => "Lois McMaster Bujold",
"Hainish" => "Ursula K. Le Guin",
];
protected function setUp () : void {
$this->map = new HashMap(self::MAP_CONTENT);
}
///
/// Constructors
///
public function testConstructorWithArray () {
$this->assertSame(self::MAP_CONTENT, $this->map->toArray());
}
public function testConstructorWithTraversable () {
$expected = [
"color" => "blue",
"material" => "glass",
"shape" => "sphere",
];
$iterable = new class implements IteratorAggregate {
function getIterator () : Traversable {
yield "color" => "blue";
yield "material" => "glass";
yield "shape" => "sphere";
}
};
$map = new HashMap($iterable);
$this->assertSame($expected, $map->toArray());
}
private function provideDeepArrays() : iterable {
yield [self::MAP_CONTENT, self::MAP_CONTENT];
yield [[], []];
yield [null, []];
$caps = new \stdClass;
$caps->color = "red";
$caps->logo = "HCKR";
yield [$caps, [
"color" => "red",
"logo" => "HCKR",
]];
$sizedCaps = clone $caps;
$sizedCaps->size = new \stdClass;
$sizedCaps->size->h = 8;
$sizedCaps->size->r = 20;
yield [$sizedCaps, [
"color" => "red",
"logo" => "HCKR",
"size" => ["h" => 8, "r" => 20],
]];
}
/**
* @dataProvider provideDeepArrays
*/
public function testFrom($from, array $expected) : void {
$map = HashMap::from($from);
$this->assertEquals($expected, $map->toArray());
}
///
/// Getters and setters
///
public function testGet () {
$this->assertSame("Iain Banks", $this->map->get("The Culture"));
}
public function testGetWhenKeyIsNotFound () {
$this->expectException(InvalidArgumentException::class);
$this->map->get("Quuxians");
}
public function testGetOr () {
$actual = $this->map
->getOr("The Culture", "Another author");
$this->assertSame("Iain Banks", $actual);
}
public function testGetOrWhenKeyIsNotFound () {
$actual = $this->map
->getOr("Quuxians", "Another author");
$this->assertSame("Another author", $actual);
}
public function testSetWithNewKey () {
$this->map->set("Thélème", "François Rabelais");
$this->assertSame("François Rabelais",
$this->map->get("Thélème"));
}
public function testSetWithExistingKey () {
$this->map->set("The Culture", "Iain M. Banks");
$this->assertSame("Iain M. Banks",
$this->map->get("The Culture"));
}
public function testUnset() {
$this->map->unset("The Culture");
$this->assertFalse($this->map->contains("Iain Banks"));
}
public function testUnsetNotExistingKey() {
$this->map->unset("Not existing");
$this->assertEquals(4, $this->map->count());
}
public function testHas () {
$this->assertTrue($this->map->has("The Culture"));
$this->assertFalse($this->map->has("Not existing key"));
}
public function testContains () {
$this->assertTrue($this->map->contains("Iain Banks"));
$this->assertFalse($this->map->contains("Not existing value"));
}
///
/// Collection method
///
public function testCount () {
$this->assertSame(4, $this->map->count());
}
public function testClear () {
$this->map->clear();
$this->assertSame(0, $this->map->count());
}
public function testIsEmpty () : void {
$this->map->clear();
$this->assertTrue($this->map->isEmpty());
}
public function testMerge () {
$iterable = [
"The Culture" => "Iain M. Banks", // existing key
"Thélème" => "François Rabelais", // new key
];
$expected = [
// The original map
"The Culture" => "Iain Banks", // Old value should be kept
"Radchaai Empire" => "Ann Leckie",
"Barrayar" => "Lois McMaster Bujold",
"Hainish" => "Ursula K. Le Guin",
// The entries with a new key
"Thélème" => "François Rabelais",
];
$this->map->merge($iterable);
$this->assertSame($expected, $this->map->toArray());
}
public function testUpdate () {
$iterable = [
"The Culture" => "Iain M. Banks", // existing key
"Thélème" => "François Rabelais", // new key
];
$expected = [
// The original map
"The Culture" => "Iain M. Banks", // Old value should be updated
"Radchaai Empire" => "Ann Leckie",
"Barrayar" => "Lois McMaster Bujold",
"Hainish" => "Ursula K. Le Guin",
// The entries with a new key
"Thélème" => "François Rabelais",
];
$this->map->update($iterable);
$this->assertSame($expected, $this->map->toArray());
}
public function testToArray () {
$this->assertEquals(self::MAP_CONTENT, $this->map->toArray());
}
///
/// High order functions
///
public function testMap () {
$callback = function ($value) {
return "author='" . $value . "'";
};
$expected = [
"The Culture" => "author='Iain Banks'",
"Radchaai Empire" => "author='Ann Leckie'",
"Barrayar" => "author='Lois McMaster Bujold'",
"Hainish" => "author='Ursula K. Le Guin'",
];
$actual = $this->map->map($callback)->toArray();
$this->assertEquals($expected, $actual);
}
public function testMapKeys () {
$callback = function ($key) {
return "civ::" . $key;
};
$expected = [
// Some sci-fi civilizations and author
"civ::The Culture" => "Iain Banks",
"civ::Radchaai Empire" => "Ann Leckie",
"civ::Barrayar" => "Lois McMaster Bujold",
"civ::Hainish" => "Ursula K. Le Guin",
];
$actual = $this->map->mapKeys($callback)->toArray();
$this->assertEquals($expected, $actual);
}
public function testMapKeysAndValues () : void {
$callback = function ($civilization, $author) {
return [$author[0], "$author, $civilization"];
};
$expected = [
// Some sci-fi civilizations and author
"I" => "Iain Banks, The Culture",
"A" => "Ann Leckie, Radchaai Empire",
"L" => "Lois McMaster Bujold, Barrayar",
"U"=> "Ursula K. Le Guin, Hainish",
];
$actual = $this->map->mapValuesAndKeys($callback)->toArray();
$this->assertEquals($expected, $actual);
}
public function testMapKeysAndValuesForVectors () : void {
$callback = function ($author) {
return [$author[0], "author:" . $author];
};
$expected = [
// Some sci-fi civilizations and author
"I" => "author:Iain Banks",
"A" => "author:Ann Leckie",
"L" => "author:Lois McMaster Bujold",
"U" => "author:Ursula K. Le Guin",
];
$actual = $this->map->mapValuesAndKeys($callback)->toArray();
$this->assertEquals($expected, $actual);
}
public function testMapKeysAndValuesWithCallbackWithoutArgument() : void {
$this->expectException(InvalidArgumentException::class);
$callback = function () {};
$this->map->mapValuesAndKeys($callback);
}
public function testFlatMap(): void {
$callback = function ($key, $value) {
$items = explode(" ", $value);
foreach ($items as $item) {
yield $item => $key;
}
};
$expected = [
"Iain" => "The Culture",
"Banks" => "The Culture",
"Ann" => "Radchaai Empire",
"Leckie" => "Radchaai Empire",
"Lois" => "Barrayar",
"McMaster" => "Barrayar",
"Bujold" => "Barrayar",
"Ursula"=> "Hainish",
"K."=> "Hainish",
"Le"=> "Hainish",
"Guin"=> "Hainish",
];
$actual = $this->map->flatMap($callback)->toArray();
$this->assertEquals($expected, $actual);
}
public function testFlatMapForVectors() : void {
$callback = function ($value) {
$items = explode(" ", $value);
foreach ($items as $item) {
yield $item => $value;
}
};
$expected = [
"Iain" => "Iain Banks",
"Banks" => "Iain Banks",
"Ann" => "Ann Leckie",
"Leckie" => "Ann Leckie",
"Lois" => "Lois McMaster Bujold",
"McMaster" => "Lois McMaster Bujold",
"Bujold" => "Lois McMaster Bujold",
"Ursula"=> "Ursula K. Le Guin",
"K."=> "Ursula K. Le Guin",
"Le"=> "Ursula K. Le Guin",
"Guin"=> "Ursula K. Le Guin",
];
$actual = $this->map->flatMap($callback)->toArray();
$this->assertEquals($expected, $actual);
}
public function testFlatMapWithCallbackWithoutArgument() : void {
$this->expectException(InvalidArgumentException::class);
$callback = function () {};
$this->map->flatMap($callback);
}
public function testFilter () {
// Let's filter to keep names with 3 parts or more
$callback = function ($value) : bool {
return str_word_count($value) > 2;
};
$expected = [
// Some sci-fi civilizations and author
"Barrayar" => "Lois McMaster Bujold",
"Hainish" => "Ursula K. Le Guin",
];
$actual = $this->map->filter($callback)->toArray();
$this->assertEquals($expected, $actual);
}
public function testFilterWithKeyValueCallback () {
// Let's find civilization AND author with e inside
$expected = [
// Some sci-fi civilizations and author
"Radchaai Empire" => "Ann Leckie",
];
$callback = function ($key, $value) : bool {
return str_contains($key, "e") && str_contains($value, "e");
};
$actual = $this->map->filter($callback)->toArray();
$this->assertEquals($expected, $actual);
}
public function testFilterWithCallbackWithoutArgument() {
$this->expectException(InvalidArgumentException::class);
$callback = function () : bool { // No argument
return true;
};
$this->map->filter($callback);
}
public function testFilterKeys () {
// Let's filter to keep short civilization names
$callback = function ($key) : bool {
return str_word_count($key) == 1;
};
$expected = [
// Some sci-fi civilizations and author
"Barrayar" => "Lois McMaster Bujold",
"Hainish" => "Ursula K. Le Guin",
];
$actual = $this->map->filterKeys($callback)->toArray();
$this->assertEquals($expected, $actual);
}
///
/// ArrayAccess
///
public function testOffsetExists () : void {
$this->assertTrue(isset($this->map["The Culture"]));
$this->assertFalse(isset($this->map["Not existing"]));
}
public function testOffsetSetWithoutOffset () : void {
$this->expectException(InvalidArgumentException::class);
$this->map[] = "Another Author";
}
public function testOffsetSet () : void {
$this->map["The Culture"] = "Iain M. Banks";
$this->assertEquals("Iain M. Banks", $this->map["The Culture"]);
}
public function testOffsetUnset () : void {
unset($this->map["Barrayar"]);
$expected = [
"The Culture" => "Iain Banks",
"Radchaai Empire" => "Ann Leckie",
// "Barrayar" => "Lois McMaster Bujold", UNSET ENTRY
"Hainish" => "Ursula K. Le Guin",
];
$this->assertEquals($expected, $this->map->toArray());
}
///
/// IteratorAggregate
///
public function testGetIterator () : void {
$this->assertEquals(self::MAP_CONTENT, iterator_to_array($this->map));
}
+ ///
+ /// WithCollection trait
+ ///
+
+ public function testFirst () : void {
+ $this->assertEquals("Iain Banks", $this->map->first());
+ }
+
+ public function testFirstWhenEmpty () : void {
+ $map = new HashMap();
+
+ $this->expectException(OutOfRangeException::class);
+ $map->first();
+ }
+
+ public function testFirstOr () : void {
+ $bits = BitsVector::new(4);
+ $bits[2] = 1;
+
+ $this->assertEquals("Iain Banks", $this->map->firstOr("Anonymous"));
+ }
+
+ public function testFirstOrWhenEmpty () : void {
+ $map = new HashMap();
+
+ $this->assertEquals("Anonymous", $map->firstOr("Anonymous"));
+ }
+
}
diff --git a/omnitools/tests/Collections/VectorTest.php b/omnitools/tests/Collections/VectorTest.php
index 4874717..4dcdce2 100644
--- a/omnitools/tests/Collections/VectorTest.php
+++ b/omnitools/tests/Collections/VectorTest.php
@@ -1,376 +1,402 @@
<?php
declare(strict_types=1);
namespace Keruald\OmniTools\Tests\Collections;
use Keruald\OmniTools\Collections\Vector;
use PHPUnit\Framework\TestCase;
use InvalidArgumentException;
use IteratorAggregate;
+use OutOfRangeException;
use Traversable;
/**
* @covers \Keruald\OmniTools\Collections\Vector
* @covers \Keruald\OmniTools\Collections\BaseVector
*/
class VectorTest extends TestCase {
private Vector $vector;
protected function setUp () : void {
$this->vector = new Vector([1, 2, 3, 4, 5]);
}
public function testConstructorWithIterable () : void {
$iterable = new class implements IteratorAggregate {
public function getIterator () : Traversable {
yield 42;
yield 100;
}
};
$vector = new Vector($iterable);
$this->assertEquals([42, 100], $vector->toArray());
}
public function testFrom () : void {
$this->assertEquals([42, 100], Vector::from([42, 100])->toArray());
}
public function testGet () : void {
$vector = new Vector(["a", "b", "c"]);
$this->assertEquals("b", $vector->get(1));
}
public function testGetOverflow () : void {
$this->expectException(InvalidArgumentException::class);
$this->vector->get(800);
}
public function testGetOr () : void {
$vector = new Vector(["a", "b", "c"]);
$this->assertEquals("X", $vector->getOr(800, "X"));
}
public function testSet () : void {
$vector = new Vector(["a", "b", "c"]);
$vector->set(1, "x"); // should replace "b"
$this->assertEquals(["a", "x", "c"], $vector->toArray());
}
public function testContains () : void {
$this->assertTrue($this->vector->contains(2));
$this->assertFalse($this->vector->contains(666));
}
public function testCount () : void {
$this->assertEquals(5, $this->vector->count());
$this->assertEquals(0, (new Vector)->count());
}
public function testClear () : void {
$this->vector->clear();
$this->assertEquals(0, $this->vector->count());
}
public function testIsEmpty () : void {
$this->vector->clear();
$this->assertTrue($this->vector->isEmpty());
}
public function testPush () : void {
$this->vector->push(6);
$this->assertEquals([1, 2, 3, 4, 5, 6], $this->vector->toArray());
}
public function testAppend () : void {
$this->vector->append([6, 7, 8]);
$this->assertEquals([1, 2, 3, 4, 5, 6, 7 ,8], $this->vector->toArray());
}
public function testUpdate () : void {
$this->vector->update([5, 5, 5, 6, 7, 8]); // 5 already exists
$this->assertEquals([1, 2, 3, 4, 5, 6, 7 ,8], $this->vector->toArray());
}
public function testMap () : void {
$actual = $this->vector
->map(function ($x) { return $x * $x; })
->toArray();
$this->assertEquals([1, 4, 9, 16, 25], $actual);
}
public function testMapKeys () : void {
$vector = new Vector(["foo", "bar", "quux", "xizzy"]);
$filter = function ($key) {
return 0; // Let's collapse our array
};
$actual = $vector->mapKeys($filter)->toArray();
$this->assertEquals(["xizzy"], $actual);
}
public function testFlatMap () : void {
$expected = [
// Squares and cubes
1, 1,
4, 8,
9, 27,
16, 64,
25, 125
];
$callback = function ($n) {
yield $n * $n;
yield $n * $n * $n;
};
$actual = $this->vector->flatMap($callback)->toArray();
$this->assertEquals($expected, $actual);
}
public function testFlatMapWithKeyValueCallback() : void {
$vector = new Vector(["foo", "bar", "quux", "xizzy"]);
$callback = function (int $key, string $value) {
yield "$key::$value";
yield "$value ($key)";
};
$expected = [
"0::foo",
"foo (0)",
"1::bar",
"bar (1)",
"2::quux",
"quux (2)",
"3::xizzy",
"xizzy (3)",
];
$actual = $vector->flatMap($callback)->toArray();
$this->assertEquals($expected, $actual);
}
public function testFlatMapWithCallbackWithoutArgument() : void {
$this->expectException(InvalidArgumentException::class);
$callback = function () {};
$this->vector->flatMap($callback);
}
public function testFilter () : void {
$vector = new Vector(["foo", "bar", "quux", "xizzy"]);
$filter = function ($item) {
return strlen($item) === 3; // Let's keep 3-letters words
};
$actual = $vector->filter($filter)->toArray();
$this->assertEquals(["foo", "bar"], $actual);
}
public function testFilterWithBadCallback () : void {
$this->expectException(InvalidArgumentException::class);
$badFilter = function () {};
$this->vector->filter($badFilter);
}
public function testFilterKeys () : void {
$filter = function ($key) {
return $key % 2 === 0; // Let's keep even indices
};
$actual = $this->vector
->filterKeys($filter)
->toArray();
$this->assertEquals([0, 2, 4], array_keys($actual));
}
public function testChunk () : void {
$vector = new Vector([1, 2, 3, 4, 5, 6]);
$this->assertEquals(
[[1, 2], [3, 4], [5, 6]],
$vector->chunk(2)->toArray()
);
}
public function testSlice () : void {
$actual = $this->vector->slice(2, 3);
$this->assertEquals([3, 4, 5], $actual->toArray());
}
public function testImplode() : void {
$actual = (new Vector(["a", "b", "c"]))
->implode(".")
->__toString();
$this->assertEquals("a.b.c", $actual);
}
public function testImplodeWithoutDelimiter() : void {
$actual = (new Vector(["a", "b", "c"]))
->implode("")
->__toString();
$this->assertEquals("abc", $actual);
}
public function testExplode() : void {
$actual = Vector::explode(".", "a.b.c");
$this->assertEquals(["a", "b", "c"], $actual->toArray());
}
public function testExplodeWithoutDelimiter() : void {
$actual = Vector::explode("", "a.b.c");
$this->assertEquals(["a.b.c"], $actual->toArray());
}
///
/// n-grams
///
public function testBigrams() : void {
$expected = Vector::from([
[1, 2],
[2, 3],
[3, 4],
[4, 5],
]);
$this->assertEquals($expected, $this->vector->bigrams());
}
public function testTrigrams() : void {
$expected = Vector::from([
[1, 2, 3],
[2, 3, 4],
[3, 4, 5],
]);
$this->assertEquals($expected, $this->vector->trigrams());
}
public function testNgrams() : void {
$expected = Vector::from([
[1, 2, 3, 4],
[2, 3, 4, 5],
]);
$this->assertEquals($expected, $this->vector->ngrams(4));
}
public function testNgramsWithN1 () : void {
$expected = Vector::from([
[1],
[2],
[3],
[4],
[5],
]);
$this->assertEquals($expected, $this->vector->ngrams(1));
}
private function provideLowN () : iterable {
yield [0];
yield [-1];
yield [PHP_INT_MIN];
}
/**
* @dataProvider provideLowN
*/
public function testNgramsWithTooLowN ($n) : void {
$this->expectException(InvalidArgumentException::class);
$this->vector->ngrams($n);
}
private function provideLargeN () : iterable {
yield [5];
yield [6];
yield [PHP_INT_MAX];
}
/**
* @dataProvider provideLargeN
*/
public function testNgramsWithTooLargeN ($n) : void {
$expected = Vector::from([
[1, 2, 3, 4, 5],
]);
$this->assertEquals($expected, $this->vector->ngrams($n));
}
///
/// ArrayAccess
///
public function testArrayAccessFailsWithStringKey () : void {
$this->expectException(InvalidArgumentException::class);
$this->vector["foo"];
}
public function testOffsetExists () : void {
$this->assertTrue(isset($this->vector[0]));
$this->assertFalse(isset($this->vector[8]));
}
public function testOffsetSetWithoutOffset () : void {
$this->vector[] = 6;
$this->assertEquals(6, $this->vector[5]);
}
public function testOffsetSet () : void {
$this->vector[0] = 9;
$this->assertEquals(9, $this->vector[0]);
}
public function testOffsetUnset () : void {
unset($this->vector[2]);
$expected = [
0 => 1,
1 => 2,
// vector[2] has been unset
3 => 4,
4 => 5,
];
$this->assertEquals($expected, $this->vector->toArray());
}
///
/// IteratorAggregate
///
public function testGetIterator () : void {
$this->assertEquals([1, 2, 3, 4, 5], iterator_to_array($this->vector));
}
+ ///
+ /// WithCollection trait
+ ///
+
+ public function testFirst () : void {
+ $this->assertEquals(1, $this->vector->first());
+ }
+
+ public function testFirstWhenEmpty () : void {
+ $vector = new Vector;
+
+ $this->expectException(OutOfRangeException::class);
+ $vector->first();
+ }
+
+ public function testFirstOr () : void {
+ $this->assertEquals(1, $this->vector->firstOr(2));
+ }
+
+ public function testFirstOrWhenEmpty () : void {
+ $vector = new Vector;
+
+ $this->assertEquals(2, $vector->firstOr(2));
+ }
+
}

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 13:34 (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2258317
Default Alt Text
(33 KB)

Event Timeline