Skip to content

Commit

Permalink
add tests for Set
Browse files Browse the repository at this point in the history
  • Loading branch information
ericfortmeyer committed Aug 8, 2021
1 parent 2e01118 commit 577a9c2
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/Pair.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public static function fromTuple(array $tuple): self

2 => new self($tuple[0], $tuple[1]),

default => new InvalidArgumentException(self::TOO_MANY_VALUES_MSG)
default => throw new InvalidArgumentException(self::TOO_MANY_VALUES_MSG)
};
}

Expand Down
64 changes: 42 additions & 22 deletions src/Set.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,73 @@

namespace PhpDs;

final class Set
use Countable;

final class Set implements Countable
{
private array $internalMap = [];

/**
* @var array<string, string> $keyMap
* @var array<string|int|float,string|int|float> $keyMap
*/
private array $keyMap = [];
private array $hashMap = [];

public function add(string $key, object $item): void
public function add(string|int|float|bool|null|object $member): void
{
$this->internalMap[$key] = $item;
$this->keyMap[$key] = $key;
$hash = $this->hash($member);
$this->internalMap[$hash] = $member;
$this->hashMap[$hash] = $hash;
}

public function get(string $key): object
private function hash(string|int|float|bool|null|object $member): string|int
{
return $this->internalMap[$key];
return match (true) {
is_object($member) => spl_object_hash($member),

is_string($member) => md5($member),

is_null($member) => sha1("NULL"),

is_integer($member) => $member,

is_float($member) => number_format($member, 300),

is_bool($member) => $member === true ? sha1("TRUE") : sha1("FALSE")
};
}

private function keyOfMax(): string
/**
* Uses the given key to get a member of the set.
*
* ```?
* Time complexity: O1
* ```
*/
public function get(string|int|float|bool|null|object $member): string|int|float|bool|null|object
{
$counts = array_map("count", $this->internalMap);
return array_flip($counts)[max($counts)];
return $this->internalMap[$this->hash($member)];
}

public function max()
public function cardinality(): int
{
return $this->internalMap[$this->keyOfMax()];
return count($this->internalMap);
}

public function keys(): array
public function count(): int
{
return $this->keyMap;
return count($this->internalMap);
}

public function has(string $key): bool
public function max()
{
return key_exists($key, $this->internalMap);
return max($this->internalMap);
}

/**
* Transforms the set into a standard array.
*/
public function toArray(): array
{
$arr = [];
foreach ($this->internalMap as $v) {
$arr[] = $v;
}
return $arr;
return array_values($this->internalMap);
}
}
155 changes: 155 additions & 0 deletions tests/SetTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?php

use PhpDs\Set;
use PHPUnit\Framework\TestCase;

class SetTest extends TestCase
{
public function valueProvider()
{
return [
[ array_merge(range(1,100), range(10e2, 10e3, 10e2), array_fill(0, 5, (object)""), [true, false]) ]
];
}

public function testShouldBeAbleToAddDistinctFalsyValues()
{
$falsyValues = ["", false, 0, 0.0, null];

$sut = new Set();

array_walk($falsyValues, [$sut, "add"]);

$this->assertCount(count($falsyValues), $sut);
}

public function testShouldBeAbleToAddStringIntegersAndLiteralIntegers()
{
$integers = range(1, 300);
$stringIntegers = array_map("strval", $integers);
$bothKinds = array_merge($integers, $stringIntegers);

$sut = new Set();

array_walk($bothKinds, [$sut, "add"]);

$this->assertCount(count($integers) + count($stringIntegers), $sut);
}

public function testShouldBeAbleToAddStringFloatsAndLiteralFloats()
{
$floats = range(10e-3, 10e-2, 10e-3);
$stringFloats = array_map("strval", $floats);
$bothKinds = array_merge($floats, $stringFloats);

$sut = new Set();

array_walk($bothKinds, [$sut, "add"]);

$this->assertCount(count($floats) + count($stringFloats), $sut);
}

public function testShouldBeAbleToAddDistinctObjects()
{
$a = (object)"";
$b = (object)"";
$c = (object)"";
$objects = [$a, $b, $c];

$sut = new Set();

array_walk($objects, [$sut, "add"]);

$this->assertCount(count($objects), $sut);
}

public function testShouldNotAddTheSameObjectMoreThanOnce()
{
$object = (object)"";
$ref = $object;

$sut = new Set();

$sut->add($object);
$sut->add($ref);

$this->assertCount(1, $sut);
}

public function testShouldBeAbleToGetTheMaxNumericValue()
{
$max = random_int(42, 98);
$values = range(1, $max);

$sut = new Set();

array_walk($values, [$sut, "add"]);

$this->assertEquals($max, $sut->max());
}

public function testShouldBeAbleToGetCardinality()
{
$sut = new Set();

$arr = range(10, 220);

array_walk($arr, [$sut, "add"]);

$this->assertEquals(count($arr), $sut->cardinality());
}

public function testShouldOnlyContainDistinctValues()
{
$sut = new Set();

$arr = range(1, 10);
$duplicates = $arr;

$arrayWithDuplicates = array_merge($arr, $duplicates);

array_walk($arrayWithDuplicates, [$sut, "add"]);

$this->assertNotEquals(count($sut), count($arrayWithDuplicates));
}

/**
* @dataProvider valueProvider
*/
public function testShouldBeAbleToLocateAValue(array $values)
{
$sut = new Set();

array_walk_recursive($values, [$sut, "add"]);

array_walk_recursive(
$values,
function ($value) use ($sut) {
$this->assertEquals($value, $sut->get($value));
}
);
}

/**
* @dataProvider valueProvider
*/
public function testToArrayShouldHaveTheSameCardinalityAsTheSet(array $values)
{
$sut = new Set();

array_walk_recursive($values, [$sut, "add"]);

$this->assertEquals(count($sut), count($sut->toArray()));
}

public function testCountAndCardinalityAreTheSame()
{
$sut = new Set();

$sut->add(1);
$sut->add(2);
$sut->add(3);

$this->assertEquals($sut->count(), $sut->cardinality());
}
}

0 comments on commit 577a9c2

Please sign in to comment.