diff --git a/tests/Executor/ListsTest.php b/tests/Executor/ListsTest.php index 1cad0e8..dbcffa5 100644 --- a/tests/Executor/ListsTest.php +++ b/tests/Executor/ListsTest.php @@ -1,9 +1,11 @@ checkHandlesNullableLists( + [ 1, 2 ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesNullableLists( + [ 1, null, 2 ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ] + ); + + // Returns null + $this->checkHandlesNullableLists( + null, + [ 'data' => [ 'nest' => [ 'test' => null ] ] ] + ); + } + + /** + * @describe [T] + */ + public function testHandlesNullableListsWithPromiseArray() + { + // Contains values + $this->checkHandlesNullableLists( + \React\Promise\resolve([ 1, 2 ]), + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesNullableLists( + \React\Promise\resolve([ 1, null, 2 ]), + [ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ] + ); + + // Returns null + $this->checkHandlesNullableLists( + \React\Promise\resolve(null), + [ 'data' => [ 'nest' => [ 'test' => null ] ] ] + ); + + // Rejected + $this->checkHandlesNullableLists( + function () { + return \React\Promise\reject(new \Exception('bad')); + }, + [ + 'data' => ['nest' => ['test' => null]], + 'errors' => [ + [ + 'message' => 'bad', + 'locations' => [['line' => 1, 'column' => 10]], + 'path' => ['nest', 'test'] + ] + ] + ] + ); + } + + /** + * @describe [T] + */ + public function testHandlesNullableListsWithArrayPromise() + { + // Contains values + $this->checkHandlesNullableLists( + [ \React\Promise\resolve(1), \React\Promise\resolve(2) ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesNullableLists( + [ \React\Promise\resolve(1), \React\Promise\resolve(null), \React\Promise\resolve(2) ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ] + ); + + // Returns null + $this->checkHandlesNullableLists( + \React\Promise\resolve(null), + [ 'data' => [ 'nest' => [ 'test' => null ] ] ] + ); + + // Contains reject + $this->checkHandlesNullableLists( + function () { + return [ \React\Promise\resolve(1), \React\Promise\reject(new \Exception('bad')), \React\Promise\resolve(2) ]; + }, + [ + 'data' => ['nest' => ['test' => [1, null, 2]]], + 'errors' => [ + [ + 'message' => 'bad', + 'locations' => [['line' => 1, 'column' => 10]], + 'path' => ['nest', 'test', 1] + ] + ] + ] + ); + } + + /** + * @describe [T]! + */ + public function testHandlesNonNullableListsWithArray() + { + // Contains values + $this->checkHandlesNonNullableLists( + [ 1, 2 ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesNonNullableLists( + [ 1, null, 2 ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ] + ); + + // Returns null + $this->checkHandlesNonNullableLists( + null, + [ + 'data' => [ 'nest' => null ], + 'errors' => [ + FormattedError::create( + 'Cannot return null for non-nullable field DataType.test.', + [ new SourceLocation(1, 10) ] + ) + ] + ] + ); + } + + /** + * @describe [T]! + */ + public function testHandlesNonNullableListsWithPromiseArray() + { + // Contains values + $this->checkHandlesNonNullableLists( + \React\Promise\resolve([ 1, 2 ]), + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesNonNullableLists( + \React\Promise\resolve([ 1, null, 2 ]), + [ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ] + ); + + // Returns null + $this->checkHandlesNonNullableLists( + null, + [ + 'data' => [ 'nest' => null ], + 'errors' => [ + FormattedError::create( + 'Cannot return null for non-nullable field DataType.test.', + [ new SourceLocation(1, 10) ] + ) + ] + ] + ); + + // Rejected + $this->checkHandlesNonNullableLists( + function () { + return \React\Promise\reject(new \Exception('bad')); + }, + [ + 'data' => ['nest' => null], + 'errors' => [ + [ + 'message' => 'bad', + 'locations' => [['line' => 1, 'column' => 10]], + 'path' => ['nest', 'test'] + ] + ] + ] + ); + } + + /** + * @describe [T]! + */ + public function testHandlesNonNullableListsWithArrayPromise() + { + // Contains values + $this->checkHandlesNonNullableLists( + [ \React\Promise\resolve(1), \React\Promise\resolve(2) ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesNonNullableLists( + [ \React\Promise\resolve(1), \React\Promise\resolve(null), \React\Promise\resolve(2) ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ] + ); + + // Contains reject + $this->checkHandlesNonNullableLists( + function () { + return [ \React\Promise\resolve(1), \React\Promise\reject(new \Exception('bad')), \React\Promise\resolve(2) ]; + }, + [ + 'data' => ['nest' => ['test' => [1, null, 2]]], + 'errors' => [ + [ + 'message' => 'bad', + 'locations' => [['line' => 1, 'column' => 10]], + 'path' => ['nest', 'test', 1] + ] + ] + ] + ); + } + + /** + * @describe [T!] + */ + public function testHandlesListOfNonNullsWithArray() + { + // Contains values + $this->checkHandlesListOfNonNulls( + [ 1, 2 ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesListOfNonNulls( + [ 1, null, 2 ], + [ + 'data' => [ 'nest' => [ 'test' => null ] ], + 'errors' => [ + FormattedError::create( + 'Cannot return null for non-nullable field DataType.test.', + [ new SourceLocation(1, 10) ] + ) + ] + ] + ); + + // Returns null + $this->checkHandlesListOfNonNulls( + null, + [ 'data' => [ 'nest' => [ 'test' => null ] ] ] + ); + } + + /** + * @describe [T!] + */ + public function testHandlesListOfNonNullsWithPromiseArray() + { + // Contains values + $this->checkHandlesListOfNonNulls( + \React\Promise\resolve([ 1, 2 ]), + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesListOfNonNulls( + \React\Promise\resolve([ 1, null, 2 ]), + [ + 'data' => [ 'nest' => [ 'test' => null ] ], + 'errors' => [ + FormattedError::create( + 'Cannot return null for non-nullable field DataType.test.', + [ new SourceLocation(1, 10) ] + ) + ] + ] + ); + + // Returns null + $this->checkHandlesListOfNonNulls( + \React\Promise\resolve(null), + [ 'data' => [ 'nest' => [ 'test' => null ] ] ] + ); + + // Rejected + $this->checkHandlesListOfNonNulls( + function () { + return \React\Promise\reject(new \Exception('bad')); + }, + [ + 'data' => ['nest' => ['test' => null]], + 'errors' => [ + [ + 'message' => 'bad', + 'locations' => [['line' => 1, 'column' => 10]], + 'path' => ['nest', 'test'] + ] + ] + ] + ); + } + + /** + * @describe [T]! + */ + public function testHandlesListOfNonNullsWithArrayPromise() + { + // Contains values + $this->checkHandlesListOfNonNulls( + [ \React\Promise\resolve(1), \React\Promise\resolve(2) ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesListOfNonNulls( + [ \React\Promise\resolve(1), \React\Promise\resolve(null), \React\Promise\resolve(2) ], + [ 'data' => [ 'nest' => [ 'test' => null ] ] ] + ); + + // Contains reject + $this->checkHandlesListOfNonNulls( + function () { + return [ \React\Promise\resolve(1), \React\Promise\reject(new \Exception('bad')), \React\Promise\resolve(2) ]; + }, + [ + 'data' => ['nest' => ['test' => null]], + 'errors' => [ + [ + 'message' => 'bad', + 'locations' => [['line' => 1, 'column' => 10]], + 'path' => ['nest', 'test', 1] + ] + ] + ] + ); + } + + /** + * @describe [T!]! + */ + public function testHandlesNonNullListOfNonNullsWithArray() + { + // Contains values + $this->checkHandlesNonNullListOfNonNulls( + [ 1, 2 ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + + // Contains null + $this->checkHandlesNonNullListOfNonNulls( + [ 1, null, 2 ], + [ + 'data' => [ 'nest' => null ], + 'errors' => [ + FormattedError::create( + 'Cannot return null for non-nullable field DataType.test.', + [ new SourceLocation(1, 10) ] + ) + ] + ] + ); + + // Returns null + $this->checkHandlesNonNullListOfNonNulls( + null, + [ + 'data' => [ 'nest' => null ], + 'errors' => [ + FormattedError::create( + 'Cannot return null for non-nullable field DataType.test.', + [ new SourceLocation(1, 10) ] + ) + ] + ] + ); + } + + /** + * @describe [T!]! + */ + public function testHandlesNonNullListOfNonNullsWithPromiseArray() + { + // Contains values + $this->checkHandlesNonNullListOfNonNulls( + \React\Promise\resolve([ 1, 2 ]), + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesNonNullListOfNonNulls( + \React\Promise\resolve([ 1, null, 2 ]), + [ + 'data' => [ 'nest' => null ], + 'errors' => [ + FormattedError::create( + 'Cannot return null for non-nullable field DataType.test.', + [ new SourceLocation(1, 10) ] + ) + ] + ] + ); + + // Returns null + $this->checkHandlesNonNullListOfNonNulls( + \React\Promise\resolve(null), + [ + 'data' => [ 'nest' => null ], + 'errors' => [ + FormattedError::create( + 'Cannot return null for non-nullable field DataType.test.', + [ new SourceLocation(1, 10) ] + ) + ] + ] + ); + + // Rejected + $this->checkHandlesNonNullListOfNonNulls( + function () { + return \React\Promise\reject(new \Exception('bad')); + }, + [ + 'data' => ['nest' => null ], + 'errors' => [ + [ + 'message' => 'bad', + 'locations' => [['line' => 1, 'column' => 10]], + 'path' => ['nest', 'test'] + ] + ] + ] + ); + } + + /** + * @describe [T!]! + */ + public function testHandlesNonNullListOfNonNullsWithArrayPromise() + { + // Contains values + $this->checkHandlesNonNullListOfNonNulls( + [ \React\Promise\resolve(1), \React\Promise\resolve(2) ], + [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] + ); + + // Contains null + $this->checkHandlesNonNullListOfNonNulls( + [ \React\Promise\resolve(1), \React\Promise\resolve(null), \React\Promise\resolve(2) ], + [ + 'data' => [ 'nest' => null ], + 'errors' => [ + FormattedError::create( + 'Cannot return null for non-nullable field DataType.test.', + [ new SourceLocation(1, 10) ] + ) + ] + ] + ); + + // Contains reject + $this->checkHandlesNonNullListOfNonNulls( + function () { + return [ \React\Promise\resolve(1), \React\Promise\reject(new \Exception('bad')), \React\Promise\resolve(2) ]; + }, + [ + 'data' => ['nest' => null ], + 'errors' => [ + [ + 'message' => 'bad', + 'locations' => [['line' => 1, 'column' => 10]], + 'path' => ['nest', 'test'] + ] + ] + ] + ); + } + + private function checkHandlesNullableLists($testData, $expected) + { + $testType = Type::listOf(Type::int());; + $this->check($testType, $testData, $expected); + } + + private function checkHandlesNonNullableLists($testData, $expected) + { + $testType = Type::nonNull(Type::listOf(Type::int())); + $this->check($testType, $testData, $expected); + } + + private function checkHandlesListOfNonNulls($testData, $expected) + { + $testType = Type::listOf(Type::nonNull(Type::int())); + $this->check($testType, $testData, $expected); + } + + public function checkHandlesNonNullListOfNonNulls($testData, $expected) + { + $testType = Type::nonNull(Type::listOf(Type::nonNull(Type::int()))); + $this->check($testType, $testData, $expected); + } + private function check($testType, $testData, $expected) { $data = ['test' => $testData]; @@ -41,157 +558,19 @@ class ListsTest extends \PHPUnit_Framework_TestCase $ast = Parser::parse('{ nest { test } }'); $result = Executor::execute($schema, $ast, $data); - $this->assertArraySubset($expected, $result->toArray()); - } - - // Describe: Execute: Handles list nullability - - /** - * @describe [T] - */ - public function testHandlesNullableLists() - { - $type = Type::listOf(Type::int()); - - // Contains values - $this->check( - $type, - [ 1, 2 ], - [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] - ); - - // Contains null - $this->check( - $type, - [ 1, null, 2 ], - [ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ] - ); - - // Returns null - $this->check( - $type, - null, - [ 'data' => [ 'nest' => [ 'test' => null ] ] ] - ); + $this->assertArraySubset($expected, self::awaitPromise($result)); } /** - * @describe [T]! + * @param \GraphQL\Executor\Promise\Promise $promise + * @return array */ - public function testHandlesNonNullableLists() + private static function awaitPromise($promise) { - $type = Type::nonNull(Type::listOf(Type::int())); - - // Contains values - $this->check( - $type, - [ 1, 2 ], - [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] - ); - - // Contains null - $this->check( - $type, - [ 1, null, 2 ], - [ 'data' => [ 'nest' => [ 'test' => [ 1, null, 2 ] ] ] ] - ); - - // Returns null - $this->check( - $type, - null, - [ - 'data' => [ 'nest' => null ], - 'errors' => [ - FormattedError::create( - 'Cannot return null for non-nullable field DataType.test.', - [ new SourceLocation(1, 10) ] - ) - ] - ] - ); - } - - /** - * @describe [T!] - */ - public function testHandlesListOfNonNulls() - { - $type = Type::listOf(Type::nonNull(Type::int())); - - // Contains values - $this->check( - $type, - [ 1, 2 ], - [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] - ); - - // Contains null - $this->check( - $type, - [ 1, null, 2 ], - [ - 'data' => [ 'nest' => [ 'test' => null ] ], - 'errors' => [ - FormattedError::create( - 'Cannot return null for non-nullable field DataType.test.', - [ new SourceLocation(1, 10) ] - ) - ] - ] - ); - - // Returns null - $this->check( - $type, - null, - [ 'data' => [ 'nest' => [ 'test' => null ] ] ] - ); - } - - /** - * @describe [T!]! - */ - public function testHandlesNonNullListOfNonNulls() - { - $type = Type::nonNull(Type::listOf(Type::nonNull(Type::int()))); - - // Contains values - $this->check( - $type, - [ 1, 2 ], - [ 'data' => [ 'nest' => [ 'test' => [ 1, 2 ] ] ] ] - ); - - - // Contains null - $this->check( - $type, - [ 1, null, 2 ], - [ - 'data' => [ 'nest' => null ], - 'errors' => [ - FormattedError::create( - 'Cannot return null for non-nullable field DataType.test.', - [ new SourceLocation(1, 10) ] - ) - ] - ] - ); - - // Returns null - $this->check( - $type, - null, - [ - 'data' => [ 'nest' => null ], - 'errors' => [ - FormattedError::create( - 'Cannot return null for non-nullable field DataType.test.', - [ new SourceLocation(1, 10) ] - ) - ] - ] - ); + $results = null; + $promise->then(function (ExecutionResult $executionResult) use (&$results) { + $results = $executionResult->toArray(); + }); + return $results; } }