| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 | <?phpnamespace Guzzle\Tests\Service\Description;use GuzzleHttp\Command\Guzzle\Parameter;use GuzzleHttp\Command\Guzzle\SchemaValidator;use GuzzleHttp\Command\ToArrayInterface;/** * @covers \GuzzleHttp\Command\Guzzle\SchemaValidator */class SchemaValidatorTest extends \PHPUnit_Framework_TestCase{    /** @var SchemaValidator */    protected $validator;    public function setUp()    {        $this->validator = new SchemaValidator();    }    public function testValidatesArrayListsAreNumericallyIndexed()    {        $value = [[1]];        $this->assertFalse($this->validator->validate($this->getComplexParam(), $value));        $this->assertEquals(            ['[Foo][0] must be an array of properties. Got a numerically indexed array.'],            $this->validator->getErrors()        );    }    public function testValidatesArrayListsContainProperItems()    {        $value = [true];        $this->assertFalse($this->validator->validate($this->getComplexParam(), $value));        $this->assertEquals(            ['[Foo][0] must be of type object'],            $this->validator->getErrors()        );    }    public function testAddsDefaultValuesInLists()    {        $value = [[]];        $this->assertTrue($this->validator->validate($this->getComplexParam(), $value));        $this->assertEquals([['Bar' => true]], $value);    }    public function testMergesDefaultValuesInLists()    {        $value = [            ['Baz' => 'hello!'],            ['Bar' => false],        ];        $this->assertTrue($this->validator->validate($this->getComplexParam(), $value));        $this->assertEquals([            [                'Baz' => 'hello!',                'Bar' => true,            ],            ['Bar' => false],        ], $value);    }    public function testCorrectlyConvertsParametersToArrayWhenArraysArePresent()    {        $param = $this->getComplexParam();        $result = $param->toArray();        $this->assertInternalType('array', $result['items']);        $this->assertEquals('array', $result['type']);        $this->assertInstanceOf('GuzzleHttp\Command\Guzzle\Parameter', $param->getItems());    }    public function testEnforcesInstanceOfOnlyWhenObject()    {        $p = new Parameter([            'name'       => 'foo',            'type'       => ['object', 'string'],            'instanceOf' => get_class($this)        ]);        $this->assertTrue($this->validator->validate($p, $this));        $s = 'test';        $this->assertTrue($this->validator->validate($p, $s));    }    public function testConvertsObjectsToArraysWhenToArrayInterface()    {        $o = $this->getMockBuilder(ToArrayInterface::class)            ->setMethods(['toArray'])            ->getMockForAbstractClass();        $o->expects($this->once())            ->method('toArray')            ->will($this->returnValue(['foo' => 'bar']));        $p = new Parameter([            'name'       => 'test',            'type'       => 'object',            'properties' => [                'foo' => ['required' => 'true'],            ],        ]);        $this->assertTrue($this->validator->validate($p, $o));    }    public function testMergesValidationErrorsInPropertiesWithParent()    {        $p = new Parameter([            'name'       => 'foo',            'type'       => 'object',            'properties' => [                'bar'   => ['type' => 'string', 'required' => true, 'description' => 'This is what it does'],                'test'  => ['type' => 'string', 'minLength' => 2, 'maxLength' => 5],                'test2' => ['type' => 'string', 'minLength' => 2, 'maxLength' => 2],                'test3' => ['type' => 'integer', 'minimum' => 100],                'test4' => ['type' => 'integer', 'maximum' => 10],                'test5' => ['type' => 'array', 'maxItems' => 2],                'test6' => ['type' => 'string', 'enum' => ['a', 'bc']],                'test7' => ['type' => 'string', 'pattern' => '/[0-9]+/'],                'test8' => ['type' => 'number'],                'baz' => [                    'type'     => 'array',                    'minItems' => 2,                    'required' => true,                    "items"    => ["type" => "string"],                ],            ],        ]);        $value = [            'test' => 'a',            'test2' => 'abc',            'baz' => [false],            'test3' => 10,            'test4' => 100,            'test5' => [1, 3, 4],            'test6' => 'Foo',            'test7' => 'abc',            'test8' => 'abc',        ];        $this->assertFalse($this->validator->validate($p, $value));        $this->assertEquals([            '[foo][bar] is a required string: This is what it does',            '[foo][baz] must contain 2 or more elements',            '[foo][baz][0] must be of type string',            '[foo][test2] length must be less than or equal to 2',            '[foo][test3] must be greater than or equal to 100',            '[foo][test4] must be less than or equal to 10',            '[foo][test5] must contain 2 or fewer elements',            '[foo][test6] must be one of "a" or "bc"',            '[foo][test7] must match the following regular expression: /[0-9]+/',            '[foo][test8] must be of type number',            '[foo][test] length must be greater than or equal to 2',        ], $this->validator->getErrors());    }    public function testHandlesNullValuesInArraysWithDefaults()    {        $p = new Parameter([            'name'       => 'foo',            'type'       => 'object',            'required'   => true,            'properties' => [                'bar' => [                    'type' => 'object',                    'required' => true,                    'properties' => [                        'foo' => ['default' => 'hi'],                    ],                ],            ],        ]);        $value = [];        $this->assertTrue($this->validator->validate($p, $value));        $this->assertEquals(['bar' => ['foo' => 'hi']], $value);    }    public function testFailsWhenNullValuesInArraysWithNoDefaults()    {        $p = new Parameter([            'name'       => 'foo',            'type'       => 'object',            'required'   => true,            'properties' => [                'bar' => [                    'type' => 'object',                    'required' => true,                    'properties' => [                        'foo' => ['type' => 'string'],                    ],                ],            ],        ]);        $value = [];        $this->assertFalse($this->validator->validate($p, $value));        $this->assertEquals(['[foo][bar] is a required object'], $this->validator->getErrors());    }    public function testChecksTypes()    {        $p = new SchemaValidator();        $r = new \ReflectionMethod($p, 'determineType');        $r->setAccessible(true);        $this->assertEquals('any', $r->invoke($p, 'any', 'hello'));        $this->assertEquals(false, $r->invoke($p, 'foo', 'foo'));        $this->assertEquals('string', $r->invoke($p, 'string', 'hello'));        $this->assertEquals(false, $r->invoke($p, 'string', false));        $this->assertEquals('integer', $r->invoke($p, 'integer', 1));        $this->assertEquals(false, $r->invoke($p, 'integer', 'abc'));        $this->assertEquals('numeric', $r->invoke($p, 'numeric', 1));        $this->assertEquals('numeric', $r->invoke($p, 'numeric', '1'));        $this->assertEquals('number', $r->invoke($p, 'number', 1));        $this->assertEquals('number', $r->invoke($p, 'number', '1'));        $this->assertEquals(false, $r->invoke($p, 'numeric', 'a'));        $this->assertEquals('boolean', $r->invoke($p, 'boolean', true));        $this->assertEquals('boolean', $r->invoke($p, 'boolean', false));        $this->assertEquals(false, $r->invoke($p, 'boolean', 'false'));        $this->assertEquals('null', $r->invoke($p, 'null', null));        $this->assertEquals(false, $r->invoke($p, 'null', 'abc'));        $this->assertEquals('array', $r->invoke($p, 'array', []));        $this->assertEquals(false, $r->invoke($p, 'array', 'foo'));    }    public function testValidatesFalseAdditionalProperties()    {        $param = new Parameter([            'name'      => 'foo',            'type'      => 'object',            'properties' => [                'bar' => ['type' => 'string'],            ],            'additionalProperties' => false,        ]);        $value = ['test' => '123'];        $this->assertFalse($this->validator->validate($param, $value));        $this->assertEquals(['[foo][test] is not an allowed property'], $this->validator->getErrors());        $value = ['bar' => '123'];        $this->assertTrue($this->validator->validate($param, $value));    }    public function testAllowsUndefinedAdditionalProperties()    {        $param = new Parameter([            'name'      => 'foo',            'type'      => 'object',            'properties' => [                'bar' => ['type' => 'string'],            ]        ]);        $value = ['test' => '123'];        $this->assertTrue($this->validator->validate($param, $value));    }    public function testValidatesAdditionalProperties()    {        $param = new Parameter([            'name'      => 'foo',            'type'      => 'object',            'properties' => [                'bar' => ['type' => 'string'],            ],            'additionalProperties' => ['type' => 'integer'],        ]);        $value = ['test' => 'foo'];        $this->assertFalse($this->validator->validate($param, $value));        $this->assertEquals(['[foo][test] must be of type integer'], $this->validator->getErrors());    }    public function testValidatesAdditionalPropertiesThatArrayArrays()    {        $param = new Parameter([            'name' => 'foo',            'type' => 'object',            'additionalProperties' => [                'type'  => 'array',                'items' => ['type' => 'string'],            ],        ]);        $value = ['test' => [true]];        $this->assertFalse($this->validator->validate($param, $value));        $this->assertEquals(['[foo][test][0] must be of type string'], $this->validator->getErrors());    }    public function testIntegersCastToStringWhenTypeMismatch()    {        $param = new Parameter([            'name' => 'test',            'type' => 'string',        ]);        $value = 12;        $this->assertTrue($this->validator->validate($param, $value));        $this->assertEquals('12', $value);    }    public function testRequiredMessageIncludesType()    {        $param = new Parameter([            'name' => 'test',            'type' => [                'string',                'boolean',            ],            'required' => true,        ]);        $value = null;        $this->assertFalse($this->validator->validate($param, $value));        $this->assertEquals(['[test] is a required string or boolean'], $this->validator->getErrors());    }    protected function getComplexParam()    {        return new Parameter([            'name'     => 'Foo',            'type'     => 'array',            'required' => true,            'min'      => 1,            'items'    => [                'type'       => 'object',                'properties' => [                    'Baz' => [                        'type'    => 'string',                    ],                    'Bar' => [                        'required' => true,                        'type'     => 'boolean',                        'default'  => true,                    ],                ],            ],        ]);    }}
 |