<?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 Chevere\Parameter\IterableParameter; 
use InvalidArgumentException; 
use PHPUnit\Framework\TestCase; 
use function Chevere\Parameter\arguments; 
use function Chevere\Parameter\int; 
use function Chevere\Parameter\iterable; 
use function Chevere\Parameter\string; 
use function Chevere\Parameter\union; 
 
final class IterableParameterTest extends TestCase 
{ 
    public function testConstruct(): void 
    { 
        $value = string(); 
        $key = string(); 
        $description = 'test'; 
        $parameter = new IterableParameter( 
            $value, 
            $key, 
            $description 
        ); 
        $this->assertSame($value, $parameter->value()); 
        $this->assertSame($key, $parameter->key()); 
        $this->assertSame(null, $parameter->default()); 
        $this->assertSame($description, $parameter->description()); 
        $this->assertSame([ 
            'type' => 'iterable', 
            'description' => $description, 
            'default' => null, 
            'parameters' => [ 
                'K' => [ 
                    'required' => true, 
                ] + $key->schema(), 
                'V' => [ 
                    'required' => true, 
                ] + $value->schema(), 
            ], 
        ], $parameter->schema()); 
        $parameters = $parameter->parameters(); 
        $this->assertSame($parameters, $parameter->parameters()); 
        $this->assertEquals($value, $parameters->get('V')); 
        $this->assertEquals($key, $parameters->get('K')); 
    } 
 
    public function testAssertCompatible(): void 
    { 
        $this->expectNotToPerformAssertions(); 
        $key = string(); 
        $value = int(description: 'compatible'); 
        $keyAlt = string(description: 'compatible'); 
        $valueAlt = int(); 
        $parameter = new IterableParameter($value, $key); 
        $compatible = new IterableParameter($valueAlt, $keyAlt, 'compatible'); 
        $parameter->assertCompatible($compatible); 
    } 
 
    public function testAssertCompatibleConflictValue(): void 
    { 
        $key = string(); 
        $value = int(); 
        $valueAlt = int(min: 1); 
        $parameter = new IterableParameter($value, $key); 
        $notCompatible = new IterableParameter($valueAlt, $key); 
        $this->expectException(InvalidArgumentException::class); 
        $parameter->assertCompatible($notCompatible); 
    } 
 
    public function testAssertCompatibleConflictKey(): void 
    { 
        $key = string(); 
        $value = int(); 
        $keyAlt = string('/^[a-z]+&/'); 
        $parameter = new IterableParameter($value, $key); 
        $notCompatible = new IterableParameter($value, $keyAlt); 
        $this->expectException(InvalidArgumentException::class); 
        $parameter->assertCompatible($notCompatible); 
    } 
 
    public function testNestedIterable(): void 
    { 
        $this->expectNotToPerformAssertions(); 
        $parameter = iterable( 
            V: string(), 
            K: string() 
        ); 
        $argument = [ 
            'a' => 'A', 
        ]; 
        $parameter($argument); 
        $parameter = iterable( 
            V: $parameter, 
        ); 
        $argument = [ 
            [ 
                'b' => 'B', 
            ], 
            [ 
                'c' => 'C', 
            ], 
        ]; 
        $parameter($argument); 
    } 
 
    public function testIterableArguments(): void 
    { 
        $parameter = iterable( 
            V: string(), 
            K: int() 
        ); 
        $array = [ 
            0 => 'foo', 
            1 => 'bar', 
            2 => 'baz', 
        ]; 
        $arguments = arguments($parameter, $array); 
        $this->assertSame($array['0'], $arguments->required('0')->string()); 
        $parameter = iterable( 
            V: iterable( 
                string() 
            ), 
            K: string() 
        ); 
        $array = [ 
            '0' => ['foo', 'oof'], 
            '1' => ['bar'], 
            '2' => ['baz', 'bar'], 
        ]; 
        $arguments = arguments($parameter, $array); 
        $this->assertSame($array['0'], $arguments->required('0')->array()); 
    } 
 
    public function testInvoke(): void 
    { 
        $value = [10, '10']; 
        $parameter = iterable(union(int(), string())); 
        $parameter($value); 
        $this->expectException(InvalidArgumentException::class); 
        $parameter([]); 
    } 
 
    public function testKeyError(): void 
    { 
        $parameter = iterable(K: int(), V: string()); 
        $this->expectException(InvalidArgumentException::class); 
        $this->expectExceptionMessage( 
            <<<PLAIN 
            [K *iterable]: Argument must be of type int, string given 
            PLAIN 
        ); 
        $parameter([ 
            'key' => 'foo', 
        ]); 
    } 
 
    public function testValueError(): void 
    { 
        $parameter = iterable(K: int(), V: string()); 
        $this->expectException(InvalidArgumentException::class); 
        $this->expectExceptionMessage( 
            <<<PLAIN 
            [V *iterable]: Argument must be of type Stringable|string, int given 
            PLAIN 
        ); 
        $parameter([ 
            100 => 100, 
        ]); 
    } 
 
    public function testWithDefault(): void 
    { 
        $value = [10, '10']; 
        $parameter = iterable(union(int(), string())); 
        $with = $parameter->withDefault($value); 
        $this->assertNotSame($parameter, $with); 
        $this->assertSame($value, $with->default()); 
        $this->expectException(InvalidArgumentException::class); 
        $parameter->withDefault([null, false]); 
    } 
} 
 
 |