Fixed definition tests; added enum tests

This commit is contained in:
vladar 2016-05-01 03:05:10 +06:00
parent 183a9d72cf
commit 00f12b3197
4 changed files with 473 additions and 28 deletions

View File

@ -0,0 +1,30 @@
<?php
namespace GraphQL\Type\Definition;
class CustomScalarType extends ScalarType
{
private $config;
function __construct(array $config)
{
$this->name = $config['name'];
$this->config = $config;
parent::__construct();
}
public function serialize($value)
{
return call_user_func($this->config['serialize'], $value);
}
public function parseValue($value)
{
return call_user_func($this->config['parseValue'], $value);
}
public function parseLiteral(/* GraphQL\Language\AST\Value */ $valueAST)
{
return call_user_func($this->config['parseLiteral'], $valueAST);
}
}

View File

@ -39,6 +39,11 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
*/ */
public $blogQuery; public $blogQuery;
/**
* @var ObjectType
*/
public $blogSubscription;
/** /**
* @var ObjectType * @var ObjectType
*/ */
@ -124,11 +129,28 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
'writeArticle' => ['type' => $this->blogArticle] 'writeArticle' => ['type' => $this->blogArticle]
] ]
]); ]);
$this->blogSubscription = new ObjectType([
'name' => 'Subscription',
'fields' => [
'articleSubscribe' => [
'args' => [ 'id' => [ 'type' => Type::string() ]],
'type' => $this->blogArticle
]
]
]);
} }
// Type System: Example
/**
* @it defines a query only schema
*/
public function testDefinesAQueryOnlySchema() public function testDefinesAQueryOnlySchema()
{ {
$blogSchema = new Schema($this->blogQuery); $blogSchema = new Schema([
'query' => $this->blogQuery
]);
$this->assertSame($blogSchema->getQueryType(), $this->blogQuery); $this->assertSame($blogSchema->getQueryType(), $this->blogQuery);
@ -165,9 +187,15 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
$this->assertSame($this->blogArticle, $feedFieldType->getWrappedType()); $this->assertSame($this->blogArticle, $feedFieldType->getWrappedType());
} }
/**
* @it defines a mutation schema
*/
public function testDefinesAMutationSchema() public function testDefinesAMutationSchema()
{ {
$schema = new Schema($this->blogQuery, $this->blogMutation); $schema = new Schema([
'query' => $this->blogQuery,
'mutation' => $this->blogMutation
]);
$this->assertSame($this->blogMutation, $schema->getMutationType()); $this->assertSame($this->blogMutation, $schema->getMutationType());
$writeMutation = $this->blogMutation->getField('writeArticle'); $writeMutation = $this->blogMutation->getField('writeArticle');
@ -178,6 +206,27 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
$this->assertSame('writeArticle', $writeMutation->name); $this->assertSame('writeArticle', $writeMutation->name);
} }
/**
* @it defines a subscription schema
*/
public function testDefinesSubscriptionSchema()
{
$schema = new Schema([
'query' => $this->blogQuery,
'subscription' => $this->blogSubscription
]);
$this->assertEquals($this->blogSubscription, $schema->getSubscriptionType());
$sub = $this->blogSubscription->getField('articleSubscribe');
$this->assertEquals($sub->getType(), $this->blogArticle);
$this->assertEquals($sub->getType()->name, 'Article');
$this->assertEquals($sub->name, 'articleSubscribe');
}
/**
* @it includes nested input objects in the map
*/
public function testIncludesNestedInputObjectInTheMap() public function testIncludesNestedInputObjectInTheMap()
{ {
$nestedInputObject = new InputObjectType([ $nestedInputObject = new InputObjectType([
@ -198,10 +247,16 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
] ]
]); ]);
$schema = new Schema($this->blogQuery, $someMutation); $schema = new Schema([
'query' => $this->blogQuery,
'mutation' => $someMutation
]);
$this->assertSame($nestedInputObject, $schema->getType('NestedInputObject')); $this->assertSame($nestedInputObject, $schema->getType('NestedInputObject'));
} }
/**
* @it includes interfaces\' subtypes in the type map
*/
public function testIncludesInterfaceSubtypesInTheTypeMap() public function testIncludesInterfaceSubtypesInTheTypeMap()
{ {
$someInterface = new InterfaceType([ $someInterface = new InterfaceType([
@ -220,18 +275,23 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
'isTypeOf' => function() {return true;} 'isTypeOf' => function() {return true;}
]); ]);
$schema = new Schema(new ObjectType([ $schema = new Schema([
'query' => new ObjectType([
'name' => 'Query', 'name' => 'Query',
'fields' => [ 'fields' => [
'iface' => ['type' => $someInterface] 'iface' => ['type' => $someInterface]
] ]
])); ]),
'types' => [$someSubtype]
]);
$this->assertSame($someSubtype, $schema->getType('SomeSubtype')); $this->assertSame($someSubtype, $schema->getType('SomeSubtype'));
} }
/**
* @it includes interfaces\' thunk subtypes in the type map
*/
public function testIncludesInterfacesThunkSubtypesInTheTypeMap() public function testIncludesInterfacesThunkSubtypesInTheTypeMap()
{ {
// includes interfaces' thunk subtypes in the type map
$someInterface = null; $someInterface = null;
$someSubtype = new ObjectType([ $someSubtype = new ObjectType([
@ -250,16 +310,22 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
] ]
]); ]);
$schema = new Schema(new ObjectType([ $schema = new Schema([
'query' => new ObjectType([
'name' => 'Query', 'name' => 'Query',
'fields' => [ 'fields' => [
'iface' => ['type' => $someInterface] 'iface' => ['type' => $someInterface]
] ]
])); ]),
'types' => [$someSubtype]
]);
$this->assertSame($someSubtype, $schema->getType('SomeSubtype')); $this->assertSame($someSubtype, $schema->getType('SomeSubtype'));
} }
/**
* @it stringifies simple types
*/
public function testStringifiesSimpleTypes() public function testStringifiesSimpleTypes()
{ {
$this->assertSame('Int', (string) Type::int()); $this->assertSame('Int', (string) Type::int());
@ -278,6 +344,9 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
$this->assertSame('[[Int]]', (string) new ListOfType(new ListOfType(Type::int()))); $this->assertSame('[[Int]]', (string) new ListOfType(new ListOfType(Type::int())));
} }
/**
* @it identifies input types
*/
public function testIdentifiesInputTypes() public function testIdentifiesInputTypes()
{ {
$expected = [ $expected = [
@ -294,6 +363,9 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
} }
} }
/**
* @it identifies output types
*/
public function testIdentifiesOutputTypes() public function testIdentifiesOutputTypes()
{ {
$expected = [ $expected = [
@ -310,12 +382,18 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
} }
} }
/**
* @it prohibits nesting NonNull inside NonNull
*/
public function testProhibitsNonNullNesting() public function testProhibitsNonNullNesting()
{ {
$this->setExpectedException('\Exception'); $this->setExpectedException('\Exception');
new NonNull(new NonNull(Type::int())); new NonNull(new NonNull(Type::int()));
} }
/**
* @it prohibits putting non-Object types in unions
*/
public function testProhibitsPuttingNonObjectTypesInUnions() public function testProhibitsPuttingNonObjectTypesInUnions()
{ {
$int = Type::int(); $int = Type::int();
@ -387,12 +465,15 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
} }
]); ]);
$schema = new Schema(new ObjectType([ $schema = new Schema([
'query' => new ObjectType([
'name' => 'Query', 'name' => 'Query',
'fields' => [ 'fields' => [
'node' => ['type' => $node] 'node' => ['type' => $node]
] ]
])); ]),
'types' => [$user, $blog]
]);
$this->assertTrue($called); $this->assertTrue($called);
@ -429,7 +510,10 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
] ]
]); ]);
$schema = new Schema($this->blogQuery, $someMutation); $schema = new Schema([
'query' => $this->blogQuery,
'mutation' => $someMutation
]);
$this->assertTrue($called); $this->assertTrue($called);
$this->assertSame($inputObject, $schema->getType('InputObject')); $this->assertSame($inputObject, $schema->getType('InputObject'));
@ -459,7 +543,9 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
] ]
]); ]);
$schema = new Schema($query); $schema = new Schema([
'query' => $query
]);
$this->assertTrue($called); $this->assertTrue($called);
$this->assertSame($interface, $schema->getType('SomeInterface')); $this->assertSame($interface, $schema->getType('SomeInterface'));

306
tests/Type/EnumTypeTest.php Normal file
View File

@ -0,0 +1,306 @@
<?php
namespace GraphQL\Tests\Type;
use GraphQL\Error;
use GraphQL\GraphQL;
use GraphQL\Schema;
use GraphQL\Type\Definition\EnumType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
class EnumTypeTest extends \PHPUnit_Framework_TestCase
{
private $schema;
public function setUp()
{
$ColorType = new EnumType([
'name' => 'Color',
'values' => [
'RED' => ['value' => 0],
'GREEN' => ['value' => 1],
'BLUE' => ['value' => 2],
]
]);
$QueryType = new ObjectType([
'name' => 'Query',
'fields' => [
'colorEnum' => [
'type' => $ColorType,
'args' => [
'fromEnum' => ['type' => $ColorType],
'fromInt' => ['type' => Type::int()],
'fromString' => ['type' => Type::string()],
],
'resolve' => function ($value, $args) {
if (isset($args['fromInt'])) {
return $args['fromInt'];
}
if (isset($args['fromString'])) {
return $args['fromString'];
}
if (isset($args['fromEnum'])) {
return $args['fromEnum'];
}
}
],
'colorInt' => [
'type' => Type::int(),
'args' => [
'fromEnum' => ['type' => $ColorType],
'fromInt' => ['type' => Type::int()],
],
'resolve' => function ($value, $args) {
if (isset($args['fromInt'])) {
return $args['fromInt'];
}
if (isset($args['fromEnum'])) {
return $args['fromEnum'];
}
}
]
]
]);
$MutationType = new ObjectType([
'name' => 'Mutation',
'fields' => [
'favoriteEnum' => [
'type' => $ColorType,
'args' => ['color' => ['type' => $ColorType]],
'resolve' => function ($value, $args) {
return isset($args['color']) ? $args['color'] : null;
}
]
]
]);
$SubscriptionType = new ObjectType([
'name' => 'Subscription',
'fields' => [
'subscribeToEnum' => [
'type' => $ColorType,
'args' => ['color' => ['type' => $ColorType]],
'resolve' => function ($value, $args) {
return isset($args['color']) ? $args['color'] : null;
}
]
]
]);
$this->schema = new Schema([
'query' => $QueryType,
'mutation' => $MutationType,
'subscription' => $SubscriptionType
]);
}
// Describe: Type System: Enum Values
/**
* @it accepts enum literals as input
*/
public function testAcceptsEnumLiteralsAsInput()
{
$this->assertEquals(
['data' => ['colorInt' => 1]],
GraphQL::execute($this->schema, '{ colorInt(fromEnum: GREEN) }')
);
}
/**
* @it enum may be output type
*/
public function testEnumMayBeOutputType()
{
$this->assertEquals(
['data' => ['colorEnum' => 'GREEN']],
GraphQL::execute($this->schema, '{ colorEnum(fromInt: 1) }')
);
}
/**
* @it enum may be both input and output type
*/
public function testEnumMayBeBothInputAndOutputType()
{
$this->assertEquals(
['data' => ['colorEnum' => 'GREEN']],
GraphQL::execute($this->schema, '{ colorEnum(fromEnum: GREEN) }')
);
}
/**
* @it does not accept string literals
*/
public function testDoesNotAcceptStringLiterals()
{
$this->expectFailure(
'{ colorEnum(fromEnum: "GREEN") }',
null,
"Argument \"fromEnum\" has invalid value \"GREEN\".\nExpected type \"Color\", found \"GREEN\"."
);
}
/**
* @it does not accept incorrect internal value
*/
public function testDoesNotAcceptIncorrectInternalValue()
{
$this->assertEquals(
['data' => ['colorEnum' => null]],
GraphQL::execute($this->schema, '{ colorEnum(fromString: "GREEN") }')
);
}
/**
* @it does not accept internal value in place of enum literal
*/
public function testDoesNotAcceptInternalValueInPlaceOfEnumLiteral()
{
$this->expectFailure(
'{ colorEnum(fromEnum: 1) }',
null,
"Argument \"fromEnum\" has invalid value 1.\nExpected type \"Color\", found 1."
);
}
/**
* @it does not accept enum literal in place of int
*/
public function testDoesNotAcceptEnumLiteralInPlaceOfInt()
{
$this->expectFailure(
'{ colorEnum(fromInt: GREEN) }',
null,
"Argument \"fromInt\" has invalid value GREEN.\nExpected type \"Int\", found GREEN."
);
}
/**
* @it accepts JSON string as enum variable
*/
public function testAcceptsJSONStringAsEnumVariable()
{
$this->assertEquals(
['data' => ['colorEnum' => 'BLUE']],
GraphQL::execute(
$this->schema,
'query test($color: Color!) { colorEnum(fromEnum: $color) }',
null,
['color' => 'BLUE']
)
);
}
/**
* @it accepts enum literals as input arguments to mutations
*/
public function testAcceptsEnumLiteralsAsInputArgumentsToMutations()
{
$this->assertEquals(
['data' => ['favoriteEnum' => 'GREEN']],
GraphQL::execute(
$this->schema,
'mutation x($color: Color!) { favoriteEnum(color: $color) }',
null,
['color' => 'GREEN']
)
);
}
/**
* @it accepts enum literals as input arguments to subscriptions
* @todo
*/
public function testAcceptsEnumLiteralsAsInputArgumentsToSubscriptions()
{
$this->markTestIncomplete('Enable when subscription support is implemented');
$this->assertEquals(
['data' => ['subscribeToEnum' => 'GREEN'], 'errors' => [[]]],
GraphQL::execute(
$this->schema,
'subscription x($color: Color!) { subscribeToEnum(color: $color) }',
null,
['color' => 'GREEN']
)
);
}
/**
* @it does not accept internal value as enum variable
*/
public function testDoesNotAcceptInternalValueAsEnumVariable()
{
$this->expectFailure(
'query test($color: Color!) { colorEnum(fromEnum: $color) }',
['color' => 2],
"Variable \"\$color\" got invalid value 2.\nExpected type \"Color\", found 2."
);
}
/**
* @it does not accept string variables as enum input
*/
public function testDoesNotAcceptStringVariablesAsEnumInput()
{
$this->expectFailure(
'query test($color: String!) { colorEnum(fromEnum: $color) }',
['color' => 'BLUE'],
'Variable "$color" of type "String!" used in position expecting type "Color".'
);
}
/**
* @it does not accept internal value variable as enum input
*/
public function testDoesNotAcceptInternalValueVariableSsEnumInput()
{
$this->expectFailure(
'query test($color: Int!) { colorEnum(fromEnum: $color) }',
['color' => 2],
'Variable "$color" of type "Int!" used in position ' . 'expecting type "Color".'
);
}
/**
* @it enum value may have an internal value of 0
*/
public function testEnumValueMayHaveAnInternalValueOf0()
{
$this->assertEquals(
['data' => ['colorEnum' => 'RED', 'colorInt' => 0]],
GraphQL::execute($this->schema, "{
colorEnum(fromEnum: RED)
colorInt(fromEnum: RED)
}")
);
}
/**
* @it enum inputs may be nullable
*/
public function testEnumInputsMayBeNullable()
{
$this->assertEquals(
['data' => ['colorEnum' => null, 'colorInt' => null]],
GraphQL::execute($this->schema, "{
colorEnum
colorInt
}")
);
}
private function expectFailure($query, $vars, $err)
{
$result = GraphQL::executeAndReturnResult($this->schema, $query, null, $vars);
$this->assertEquals(1, count($result->errors));
$this->assertEquals(
$err,
$result->errors[0]->getMessage()
);
}
}

View File

@ -5,38 +5,57 @@ use GraphQL\Type\Definition\Type;
class ScalarSerializationTest extends \PHPUnit_Framework_TestCase class ScalarSerializationTest extends \PHPUnit_Framework_TestCase
{ {
public function testCoercesOutputInt() // Type System: Scalar coercion
/**
* @it serializes output int
*/
public function testSerializesOutputInt()
{ {
$intType = Type::int(); $intType = Type::int();
$this->assertSame(1, $intType->serialize(1)); $this->assertSame(1, $intType->serialize(1));
$this->assertSame(0, $intType->serialize(0)); $this->assertSame(0, $intType->serialize(0));
$this->assertSame(-1, $intType->serialize(-1));
$this->assertSame(0, $intType->serialize(0.1)); $this->assertSame(0, $intType->serialize(0.1));
$this->assertSame(1, $intType->serialize(1.1)); $this->assertSame(1, $intType->serialize(1.1));
$this->assertSame(-1, $intType->serialize(-1.1)); $this->assertSame(-1, $intType->serialize(-1.1));
$this->assertSame(100000, $intType->serialize(1e5)); $this->assertSame(100000, $intType->serialize(1e5));
// Maybe a safe PHP int, but bigger than 2^32, so not
// representable as a GraphQL Int
$this->assertSame(null, $intType->serialize(9876504321));
$this->assertSame(null, $intType->serialize(-9876504321));
$this->assertSame(null, $intType->serialize(1e100)); $this->assertSame(null, $intType->serialize(1e100));
$this->assertSame(null, $intType->serialize(-1e100)); $this->assertSame(null, $intType->serialize(-1e100));
$this->assertSame(-1, $intType->serialize('-1.1')); $this->assertSame(-1, $intType->serialize('-1.1'));
$this->assertSame(null, $intType->serialize('one')); $this->assertSame(null, $intType->serialize('one'));
$this->assertSame(0, $intType->serialize(false)); $this->assertSame(0, $intType->serialize(false));
$this->assertSame(1, $intType->serialize(true));
} }
public function testCoercesOutputFloat() /**
* @it serializes output float
*/
public function testSerializesOutputFloat()
{ {
$floatType = Type::float(); $floatType = Type::float();
$this->assertSame(1.0, $floatType->serialize(1)); $this->assertSame(1.0, $floatType->serialize(1));
$this->assertSame(0.0, $floatType->serialize(0));
$this->assertSame(-1.0, $floatType->serialize(-1)); $this->assertSame(-1.0, $floatType->serialize(-1));
$this->assertSame(0.1, $floatType->serialize(0.1)); $this->assertSame(0.1, $floatType->serialize(0.1));
$this->assertSame(1.1, $floatType->serialize(1.1)); $this->assertSame(1.1, $floatType->serialize(1.1));
$this->assertSame(-1.1, $floatType->serialize(-1.1)); $this->assertSame(-1.1, $floatType->serialize(-1.1));
$this->assertSame(-1.1, $floatType->serialize('-1.1'));
$this->assertSame(null, $floatType->serialize('one')); $this->assertSame(null, $floatType->serialize('one'));
$this->assertSame(0.0, $floatType->serialize(false)); $this->assertSame(0.0, $floatType->serialize(false));
$this->assertSame(1.0, $floatType->serialize(true)); $this->assertSame(1.0, $floatType->serialize(true));
} }
public function testCoercesOutputStrings() /**
* @it serializes output strings
*/
public function testSerializesOutputStrings()
{ {
$stringType = Type::string(); $stringType = Type::string();
@ -47,12 +66,16 @@ class ScalarSerializationTest extends \PHPUnit_Framework_TestCase
$this->assertSame('false', $stringType->serialize(false)); $this->assertSame('false', $stringType->serialize(false));
} }
public function testCoercesOutputBoolean() /**
* @it serializes output boolean
*/
public function testSerializesOutputBoolean()
{ {
$boolType = Type::boolean(); $boolType = Type::boolean();
$this->assertSame(true, $boolType->serialize('string')); $this->assertSame(true, $boolType->serialize('string'));
$this->assertSame(false, $boolType->serialize('')); $this->assertSame(false, $boolType->serialize(''));
$this->assertSame(true, $boolType->serialize('1'));
$this->assertSame(true, $boolType->serialize(1)); $this->assertSame(true, $boolType->serialize(1));
$this->assertSame(false, $boolType->serialize(0)); $this->assertSame(false, $boolType->serialize(0));
$this->assertSame(true, $boolType->serialize(true)); $this->assertSame(true, $boolType->serialize(true));