<?php
/*
* This file is part of Chevere.
*
* (c) Rodolfo Berrios < [email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Chevere\Tests;
use BadMethodCallException;
use Chevere\Parameter\Exceptions\ParameterException;
use Chevere\Parameter\Exceptions\ReturnException;
use InvalidArgumentException;
use LogicException;
use OutOfBoundsException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
use stdClass;
use TypeError;
use function Chevere\Parameter\arguments;
use function Chevere\Parameter\arrayFrom;
use function Chevere\Parameter\arrayp;
use function Chevere\Parameter\assertArray;
use function Chevere\Parameter\assertNamedArgument;
use function Chevere\Parameter\bool;
use function Chevere\Parameter\cast;
use function Chevere\Parameter\float;
use function Chevere\Parameter\getType;
use function Chevere\Parameter\int;
use function Chevere\Parameter\iterable;
use function Chevere\Parameter\null;
use function Chevere\Parameter\object;
use function Chevere\Parameter\parameterAttr;
use function Chevere\Parameter\parameters;
use function Chevere\Parameter\parametersFrom;
use function Chevere\Parameter\string;
use function Chevere\Parameter\takeFrom;
use function Chevere\Parameter\takeKeys;
use function Chevere\Parameter\validated;
use function Chevere\Parameter\valMd;
final class FunctionsTest extends TestCase
{
public function testParameters(): void
{
$parameters = parameters();
$this->assertCount(0, $parameters);
$parameters = parameters(
foo: string()
);
$this->assertCount(1, $parameters);
$this->assertTrue($parameters->requiredKeys()->contains('foo'));
}
public function testArguments(): void
{
$parameters = parameters(
foo: string()
);
$args = [
'foo' => 'bar',
];
$arguments = arguments($parameters, $args);
$this->assertSame($args, $arguments->toArray());
}
public function testArrayParameter(): void
{
$parameter = arrayp();
$this->assertSame('', $parameter->description());
$this->assertSame(null, $parameter->default());
$parameter([]);
}
public function testBoolParameter(): void
{
$parameter = bool();
$parameter(true);
$this->assertSame('', $parameter->description());
$this->assertSame(null, $parameter->default());
$parameter = bool(
description: 'name',
default: true
);
$this->assertSame('name', $parameter->description());
$this->assertSame(true, $parameter->default());
$this->expectException(TypeError::class);
$parameter(null);
}
public function testNullParameter(): void
{
$parameter = null();
$parameter(null);
$this->assertSame('', $parameter->description());
$this->assertSame(null, $parameter->default());
$this->expectException(TypeError::class);
$parameter(1);
}
public function testIntParameter(): void
{
$parameter = int();
$parameter(1);
$this->assertSame('', $parameter->description());
$this->assertSame(null, $parameter->default());
$parameter = int(
default: 10
);
$this->assertSame(10, $parameter->default());
$this->expectException(TypeError::class);
$parameter('');
}
public function testFunctionObjectParameter(): void
{
$parameter = object(stdClass::class);
$parameter(new stdClass());
$this->assertSame('', $parameter->description());
$this->assertSame(stdClass::class, $parameter->className());
$parameter = object(stdClass::class, 'foo');
$this->assertSame('foo', $parameter->description());
$this->expectException(TypeError::class);
$parameter(parameters());
}
public function testFunctionStringParameter(): void
{
$description = 'some description';
$default = 'abcd';
$regex = '/^[a-z]+$/';
$parameter = string(
description: $description,
default: $default,
regex: $regex,
);
$parameter($default);
$this->assertSame($description, $parameter->description());
$this->assertSame($default, $parameter->default());
$this->assertSame($regex, $parameter->regex()->__toString());
$this->expectException(TypeError::class);
$parameter(123);
}
public function testFunctionArrayParameter(): void
{
$parameter = arrayp(
one: string(),
two: int(default: 222)
);
$array = [
'one' => 'foo',
];
$expected = array_merge($array, [
'two' => 222,
]);
$assert = assertArray($parameter, $array);
$this->assertSame($assert, $expected);
$this->assertCount(2, $parameter->parameters());
$this->expectException(TypeError::class);
$parameter(1);
}
public function testFunctionArrayParameterNested(): void
{
$parameter = arrayp(
one: string(),
two: int(default: 222),
nest: arrayp(
nestOne: int(default: 1),
nestTwo: int(default: 2),
)
);
$array = [
'one' => 'foo',
'nest' => [],
];
$expected = [
'one' => 'foo',
'nest' => [
'nestOne' => 1,
'nestTwo' => 2,
],
'two' => 222,
];
$assert = assertArray($parameter, $array);
$this->assertSame($assert, $expected);
$this->assertCount(3, $parameter->parameters());
$this->expectException(TypeError::class);
$parameter(1);
}
public function testFunctionAssertArgument(): void
{
assertNamedArgument('test', int(), 123);
$this->expectException(InvalidArgumentException::class);
assertNamedArgument('fail', string(), 13.13);
}
public function testFunctionIterableParameter(): void
{
$parameter = iterable(
V: string()
);
$this->assertSame('', $parameter->description());
$parameter = iterable(
K: string(),
V: string(),
description: 'foo'
);
$this->assertSame('foo', $parameter->description());
}
public function testAssertArrayIgnoreExtraArguments(): void
{
$parameter = arrayp(
OK: string(),
);
$this->expectNotToPerformAssertions();
assertArray($parameter, [
'OK' => 'abc',
'ERROR' => 123,
]);
}
public function testAssertArrayErrorType(): void
{
$parameter = arrayp(
OK: string(),
);
$this->expectException(InvalidArgumentException::class);
assertArray($parameter, [
'OK' => 123,
]);
}
public function testAssertArrayErrorNull(): void
{
$parameter = arrayp(
OK: string(),
);
$this->expectException(InvalidArgumentException::class);
assertArray($parameter, [
'OK' => null,
]);
}
public function testWithParametersFrom(): void
{
$foo = string(default: 'foo');
$bar = int(default: 1);
$parameters = parameters()
->withRequired('foo', $foo)
->withOptional('bar', $bar);
$from = parametersFrom($parameters, 'foo', 'bar');
$array = arrayp()
->withRequired(foo: $foo)
->withOptional(bar: $bar);
$fromArray = parametersFrom($array, 'foo', 'bar');
$this->assertEquals($from, $fromArray);
$this->assertNotEquals($parameters, $from);
$this->assertTrue($from->has('foo', 'bar'));
$this->assertTrue($from->requiredKeys()->contains('foo', 'bar'));
$this->assertFalse($from->optionalKeys()->contains('foo', 'bar'));
$from = parametersFrom($parameters, 'bar');
$this->assertNotEquals($parameters, $from);
$this->assertTrue($from->has('bar'));
$this->assertFalse($from->has('foo'));
$this->assertTrue($from->requiredKeys()->contains('bar'));
}
public function testTakeKeys(): void
{
$parameters = parameters(foo: string())
->withOptional('bar', int());
$this->assertSame(['foo', 'bar'], takeKeys($parameters));
}
public function testTakeFrom(): void
{
$foo = string(default: 'foo');
$bar = int(default: 1);
$parameters = parameters()
->withRequired('foo', $foo)
->withOptional('bar', $bar);
$take = takeFrom($parameters, 'foo', 'bar');
$takeArray = iterator_to_array($take);
$this->assertSame(
iterator_to_array($parameters),
$takeArray
);
$this->assertSame(
[
'foo' => $foo,
'bar' => $bar,
],
$takeArray
);
$take = takeFrom($parameters, 'foo');
$this->assertSame(
[
'foo' => $foo,
],
iterator_to_array($take)
);
$take = takeFrom($parameters, 'bar');
$this->assertSame(
[
'bar' => $bar,
],
iterator_to_array($take)
);
$take = takeFrom($parameters, 'bar', 'foo');
$this->assertSame(
[
'bar' => $bar,
'foo' => $foo,
],
iterator_to_array($take)
);
$this->expectException(OutOfBoundsException::class);
iterator_to_array(takeFrom($parameters, '404'));
}
public function testArrayFrom(): void
{
$foo = int();
$bar = string();
$baz = float();
$parameter = arrayp(
foo: $foo,
bar: $bar,
baz: $baz,
);
$arrayFrom = arrayFrom($parameter, 'foo', 'baz');
$this->assertSame(
[
'foo' => $foo,
'baz' => $baz,
],
iterator_to_array(
$arrayFrom->parameters()
)
);
}
public function testGetType(): void
{
$table = [
'object' => $this,
'float' => 10.10,
'null' => null,
'int' => 1,
'string' => 'foo',
'array' => [],
'bool' => true,
];
foreach ($table as $type => $value) {
$this->assertSame($type, getType($value));
}
}
public function testCast(): void
{
$value = 'string';
$cast = cast($value);
$this->assertSame($value, $cast->string());
}
public function testCastArray(): void
{
$value = [
'foo' => 'bar',
];
$cast = cast($value, 'foo');
$this->assertSame('bar', $cast->string());
}
public function testCastNested(): void
{
$value = [
'super' => [
'taldo' => null,
],
3 => 'co',
'agac',
];
$cast = cast($value);
$this->assertSame($value, $cast->array());
$cast = cast($value, 'super');
$this->assertSame([
'taldo' => null,
], $cast->array());
$cast = cast($value, 'super', 'taldo');
$this->assertSame(null, $cast->mixed());
$cast = cast($value, 3);
$this->assertSame('co', $cast->string());
$cast = cast($value, 4);
$this->assertSame('agac', $cast->string());
}
public static function dataProviderCastNestedError(): array
{
return [
[1, BadMethodCallException::class],
[[], InvalidArgumentException::class],
];
}
#[DataProvider('dataProviderCastNestedError')]
public function testCastNestedError(mixed $value, string $exception): void
{
$this->expectException($exception);
$cast = cast($value, 'foo');
}
public function testParameterAttr(): void
{
$caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];
$this->expectException(LogicException::class);
$this->expectExceptionMessage("Parameter `foo` doesn't exists");
parameterAttr('foo', $caller['function'], $caller['class'] ?? '');
}
public function testValidatedParameterError(): void
{
$function = 'Chevere\Tests\src\validates';
$base = 0;
$times = 1;
$name = 'Test';
$this->expectException(ParameterException::class);
$this->expectExceptionMessage("`{$function}` InvalidArgumentException ? [base]: Argument value provided `0` is less than `1`");
validated($function, $base, $times, $name);
}
public function testValidatedReturnError(): void
{
$function = 'Chevere\Tests\src\validates';
$base = 99;
$times = 1;
$name = 'Test';
$this->expectException(ReturnException::class);
$this->expectExceptionMessage("`{$function}` InvalidArgumentException ? Argument value provided `99` is less than `100`");
validated($function, $base, $times, $name);
}
public function testValidatedFunction(): void
{
$function = 'Chevere\Tests\src\validates';
$base = 100;
$times = 1;
$name = 'Test';
$this->expectNotToPerformAssertions();
validated($function, $base, $times, $name);
}
#[DataProvider('dataProviderValMd')]
public function testValMd(mixed $value, string $expects): void
{
$this->assertSame($expects, valMd($value));
}
public static function dataProviderValMd(): array
{
return [
[null, ' `null`'],
[1, ' `1`'],
['foo', ' `foo`'],
['', ''],
];
}
}
|