Skip to content

feature: getTypedArray closes #59 #63

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 102 additions & 2 deletions src/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,112 @@ public function getDateTime(string $name, callable $callback):DateTimeInterface
public function getArray(string $name, callable $callback):array {
$value = $this->get($name, $callback);
if(!is_array($value)) {
throw new TypeError("Value with key '$name' is not an array");
throw new TypeError("Data '$name' is not an array");
}

return $value;
}

/**
* @template T
* @param class-string<T> $className
* @return array<T>
*/
public function getTypedArray(string $name, string $className, callable $callback):array {
$array = $this->get($name, $callback);
if(!is_array($array)) {
throw new TypeError("Data '$name' is not an array");
}

foreach($array as $key => $value) {
$array[$key] = $this->validateAndConvertValue($value, $className, $key);
}

return $array;
}

/**
* @template T
* @param mixed $value
* @param class-string<T> $className
* @param string|int $key
* @return T
*/
private function validateAndConvertValue(mixed $value, string $className, string|int $key): mixed {
return match(strtolower($className)) {
"int", "integer" => $this->validateAndConvertInt($value, $key),
"float", "double" => $this->validateAndConvertFloat($value, $key),
"string" => $this->convertToString($value),
"bool", "boolean" => $this->convertToBool($value),
default => $this->validateInstance($value, $className, $key),
};
}

/**
* @param mixed $value
* @param string|int $key
* @return int
*/
private function validateAndConvertInt(mixed $value, string|int $key): int {
if(is_int($value)) {
return $value;
}

if(is_numeric($value)) {
return (int)$value;
}

throw new TypeError("Array value at key '$key' is not an integer");
}

/**
* @param mixed $value
* @param string|int $key
* @return float
*/
private function validateAndConvertFloat(mixed $value, string|int $key): float {
if(is_float($value)) {
return $value;
}

if(is_numeric($value)) {
return (float)$value;
}

throw new TypeError("Array value at key '$key' is not a float");
}

/**
* @param mixed $value
* @return string
*/
private function convertToString(mixed $value): string {
return (string)$value;
}

/**
* @param mixed $value
* @return bool
*/
private function convertToBool(mixed $value): bool {
return (bool)$value;
}

/**
* @template T
* @param mixed $value
* @param class-string<T> $className
* @param string|int $key
* @return T
*/
private function validateInstance(mixed $value, string $className, string|int $key): object {
if($value instanceof $className) {
return $value;
}

throw new TypeError("Array value at key '$key' is not an instance of $className");
}

/**
* @template T
* @param class-string<T> $className
Expand All @@ -81,7 +181,7 @@ public function getArray(string $name, callable $callback):array {
public function getInstance(string $name, string $className, callable $callback):object {
$value = $this->get($name, $callback);
if(get_class($value) !== $className) {
throw new TypeError("Value is not of type $className");
throw new TypeError("Value is not an instance of $className");
}

return $value;
Expand Down
9 changes: 9 additions & 0 deletions src/FileAccess.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,13 @@ public function checkValidity(string $name, int $secondsValidity):void {
throw new CacheInvalidException($filePath);
}
}

public function invalidate(string $name):void {
$filePath = "$this->dirPath/$name";
if(!is_file($filePath)) {
return;
}

unlink($filePath);
}
}
112 changes: 110 additions & 2 deletions test/phpunit/CacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
use Gt\FileCache\Cache;
use Gt\FileCache\FileAccess;
use PHPUnit\Framework\TestCase;
use SplFileInfo;
use SplFixedArray;
use stdClass;
use TypeError;

class CacheTest extends TestCase {
public function tearDown():void {
Expand Down Expand Up @@ -97,6 +100,18 @@ public function testGetInstance():void {
self::assertSame($value->name, $class->name);
}

public function testGetInstance_error():void {
$value = new StdClass();
$value->name = uniqid();

$sut = $this->getSut([
"test" => $value,
]);
self::expectException(TypeError::class);
self::expectExceptionMessage("Value is not an instance of SplFileInfo");
$sut->getInstance("test", SplFileInfo::class, fn() => false);
}

public function testGetArray():void {
$value = [1, 2, 3];
$sut = $this->getSut([
Expand All @@ -110,11 +125,104 @@ public function testGetArray_notArray():void {
$sut = $this->getSut([
"numbers" => $value,
]);
self::expectException(\TypeError::class);
self::expectExceptionMessage("Value with key 'numbers' is not an array");
self::expectException(TypeError::class);
self::expectExceptionMessage("Data 'numbers' is not an array");
$sut->getArray("numbers", fn() => []);
}

public function testGetTypedArray_notArray():void {
$value = (object)[1, 2, 3];
$sut = $this->getSut([
"numbers" => $value,
]);
self::expectException(TypeError::class);
self::expectExceptionMessage("Data 'numbers' is not an array");
$sut->getTypedArray("numbers", "int", fn() => []);
}

public function testGetTypedArray_int():void {
$value = [1, "2", 3.000];
$sut = $this->getSut([
"numbers" => $value,
]);
$typedArray = $sut->getTypedArray("numbers", "int", fn() => []);
foreach($typedArray as $value) {
self::assertIsInt($value);
}
}

public function testGetTypedArray_intFailure():void {
$value = [1, "2", 3.000, "four"];
$sut = $this->getSut([
"numbers" => $value,
]);
self::expectException(TypeError::class);
$sut->getTypedArray("numbers", "int", fn() => []);
}

public function testGetTypedArray_float():void {
$value = [1, "2", 3.000];
$sut = $this->getSut([
"numbers" => $value,
]);
$typedArray = $sut->getTypedArray("numbers", "float", fn() => []);
foreach($typedArray as $value) {
self::assertIsFloat($value);
}
}

public function testGetTypedArray_floatFailure():void {
$value = [1, "2", 3.000, "four"];
$sut = $this->getSut([
"numbers" => $value,
]);
self::expectException(TypeError::class);
$sut->getTypedArray("numbers", "float", fn() => []);
}

public function testGetTypedArray_string():void {
$value = [1, "2", 3.000, "four"];
$sut = $this->getSut([
"numbers" => $value,
]);
$typedArray= $sut->getTypedArray("numbers", "string", fn() => []);
foreach($typedArray as $value) {
self::assertIsString($value);
}
}

public function testGetTypedArray_bool():void {
$value = [0, "1", false, true, [], new StdClass()];
$sut = $this->getSut([
"booleans" => $value,
]);
$typedArray= $sut->getTypedArray("booleans", "bool", fn() => []);
foreach($typedArray as $i => $value) {
self::assertSame((bool)($i % 2), $value, $i);
}
}

public function testGetTypedArray_class():void {
$value = [new SplFileInfo(__FILE__), new SplFileInfo(__DIR__)];
$sut = $this->getSut([
"files" => $value,
]);
$typedArray= $sut->getTypedArray("files", SplFileInfo::class, fn() => []);
foreach($typedArray as $value) {
self::assertInstanceOf(SplFileInfo::class, $value);
}
}

public function testGetTypedArray_classError():void {
$value = [new SplFileInfo(__FILE__), new SplFixedArray(), new SplFileInfo(__DIR__)];
$sut = $this->getSut([
"files" => $value,
]);
self::expectExceptionMessage("Array value at key '1' is not an instance of SplFileInfo");
self::expectException(TypeError::class);
$sut->getTypedArray("files", SplFileInfo::class, fn() => []);
}

private function getSut(array $mockFiles = []):Cache {
$mockFileAccess = null;
if(!empty($mockFiles)) {
Expand Down