Skip to content
This repository has been archived by the owner on Mar 8, 2023. It is now read-only.

Commit

Permalink
Add type system definition tests
Browse files Browse the repository at this point in the history
  • Loading branch information
crisu83 committed Feb 11, 2018
1 parent 8df899f commit 0ec7246
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 9 deletions.
8 changes: 5 additions & 3 deletions src/Type/Schema/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -347,9 +347,11 @@ function typeMapReducer(array $map, ?TypeInterface $type): array
return typeMapReducer($map, $type->getOfType());
}

if (isset($map[$type->getName()])) {
$typeName = $type->getName();

if (isset($map[$typeName])) {
invariant(
$map[$type->getName()] instanceof $type,
$map[$typeName] === $type,
sprintf(
'Schema must contain unique named types but contains multiple types named "%s".',
$type->getName()
Expand All @@ -359,7 +361,7 @@ function typeMapReducer(array $map, ?TypeInterface $type): array
return $map;
}

$map[$type->getName()] = $type;
$map[$typeName] = $type;

$reducedMap = $map;

Expand Down
11 changes: 7 additions & 4 deletions src/Type/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,18 @@ function resolveThunk($thunk): ?array
}

/**
* @param array $array
* @param mixed $value
* @return bool
*/
function isAssocArray(array $array): bool
function isAssocArray($value): bool
{
if (empty($array)) {
if (!is_array($value)) {
return false;
}
if (empty($value)) {
return true;
}
$keys = array_keys($array);
$keys = array_keys($value);
return $keys !== array_keys($keys);
}

Expand Down
235 changes: 233 additions & 2 deletions tests/Functional/Type/DefinitionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,6 @@ public function testRejectsAnInputObjectTypeWithFieldsFunctionThatReturnsIncorre
// Type System: Input Object fields must not have resolvers

/**
* @throws \Exception
* @expectedException \Exception
*/
public function testRejectsAnInputObjectTypeWithResolvers()
Expand All @@ -1196,6 +1195,8 @@ public function testRejectsAnInputObjectTypeWithResolvers()
]);

$inputObjectType->getFields();

$this->addToAssertionCount(1);
}

// TODO: Asses if we want to test "rejects an Input Object type with resolver constant".
Expand All @@ -1208,7 +1209,7 @@ public function testRejectsAnInputObjectTypeWithResolvers()
public function testAcceptsAWellDefinedEnumTypeWithEmptyValueDefinition()
{
$enumType = GraphQLEnumType([
'name' => 'SomeEnum',
'name' => 'SomeEnum',
'values' => [
'FOO' => ['value' => 10],
'BAR' => ['value' => 20],
Expand All @@ -1218,4 +1219,234 @@ public function testAcceptsAWellDefinedEnumTypeWithEmptyValueDefinition()
$this->assertEquals(10, $enumType->getValue('FOO')->getValue());
$this->assertEquals(20, $enumType->getValue('BAR')->getValue());
}

/**
* @expectedException \Exception
*/
public function testRejectsAnEnumWithIncorrectlyTypedValues()
{
$enumType = GraphQLEnumType([
'name' => 'SomeEnum',
'values' => ['FOO' => 10],
]);

$enumType->getValues();

$this->addToAssertionCount(1);
}

/**
* @expectedException \Exception
*/
public function testRejectsAnEnumTypeWithMissingValueDefinition()
{
$enumType = GraphQLEnumType([
'name' => 'SomeEnum',
'values' => ['FOO' => null],
]);

$enumType->getValues();

$this->addToAssertionCount(1);
}

/**
* @expectedException \Exception
*/
public function testRejectsAnEnumTypeWithIncorrectlyTypedValueDefinition()
{
$enumType = GraphQLEnumType([
'name' => 'SomeEnum',
'values' => ['FOO' => 10],
]);

$enumType->getValues();

$this->addToAssertionCount(1);
}

/**
* @expectedException \Exception
*/
public function testDoesNotAllowIsDeprecatedWithoutDeprecationReasonOnEnum()
{
$enumType = GraphQLEnumType([
'name' => 'SomeEnum',
'values' => ['FOO' => ['isDeprecated' => true]],
]);

$enumType->getValues();

$this->addToAssertionCount(1);
}

// Type System: List must accept only types

/**
* @throws \TypeError
*/
public function testListMustAcceptOnlyTypes()
{
$types = [
GraphQLString(),
$this->scalarType,
$this->objectType,
$this->unionType,
$this->interfaceType,
$this->enumType,
$this->inputObjectType,
GraphQLList(GraphQLString()),
GraphQLNonNull(GraphQLString()),
];

foreach ($types as $type) {
GraphQLList($type);
}

$this->addToAssertionCount(9);
}

/**
* @expectedException \TypeError
*/
public function testListMustNotAcceptNonTypes()
{
$nonTypes = [[], '', null];

foreach ($nonTypes as $nonType) {
GraphQLList($nonType);
}

$this->addToAssertionCount(3);
}

// Type System: NonNull must only accept non-nullable types

/**
* @throws \TypeError
*/
public function testNonNullMustAcceptOnlyNonNullableTypes()
{
$types = [
GraphQLString(),
$this->scalarType,
$this->objectType,
$this->unionType,
$this->interfaceType,
$this->enumType,
$this->inputObjectType,
GraphQLList(GraphQLString()),
GraphQLList(GraphQLNonNull(GraphQLString())),
];

foreach ($types as $type) {
GraphQLNonNull($type);
$this->addToAssertionCount(1);
}
}

/**
* @expectedException \TypeError
*/
public function testNonNullMustNotAcceptNonTypes()
{
$nonTypes = [GraphQLNonNull(GraphQLString()), [], '', null];

foreach ($nonTypes as $nonType) {
GraphQLNonNull($nonType);
$this->addToAssertionCount(1);
}
}

// Type System: A Schema must contain uniquely named types

/**
* @expectedException \Exception
*/
public function testRejectsASchemaWhichDefinesABuiltInType()
{
$fakeString = GraphQLScalarType([
'name' => 'String',
'serialize' => function () {
return null;
},
]);

$queryType = GraphQLObjectType([
'name' => 'Query',
'fields' => [
'normal' => ['type' => GraphQLString()],
'fake' => ['type' => $fakeString],
]
]);

GraphQLSchema(['query' => $queryType]);

$this->addToAssertionCount(1);
}

/**
* @expectedException \Exception
*/
public function testRejectsASchemaWhichDefinesAnObjectTypeTwice()
{
$a = GraphQLObjectType([
'name' => 'SameName',
'fields' => ['f' => ['type' => GraphQLString()]],
]);

$b = GraphQLObjectType([
'name' => 'SameName',
'fields' => ['f' => ['type' => GraphQLString()]],
]);

$queryType = GraphQLObjectType([
'name' => 'Query',
'fields' => [
'a' => ['type' => $a],
'b' => ['type' => $b],
]
]);

GraphQLSchema(['query' => $queryType]);

$this->addToAssertionCount(1);
}

/**
* @expectedException \Exception
*/
public function testRejectsASchemaWhichHaveSameNamedObjectsImplementingAnInterface()
{
$anotherInterface = GraphQLInterfaceType([
'name' => 'AnotherInterface',
'fields' => ['f' => ['type' => GraphQLString()]],
]);

$firstBadObject = GraphQLObjectType([
'name' => 'BadObject',
'interfaces' => [$anotherInterface],
'fields' => ['f' => ['type' => GraphQLString()]],
]);

$secondBadObject = GraphQLObjectType([
'name' => 'BadObject',
'interfaces' => [$anotherInterface],
'fields' => ['f' => ['type' => GraphQLString()]],
]);

$queryType = GraphQLObjectType([
'name' => 'Query',
'fields' => [
'iface' => ['type' => $anotherInterface],
]
]);

GraphQLSchema([
'query' => $queryType,
'types' => [$firstBadObject, $secondBadObject],
]);

$this->addToAssertionCount(1);
}
}

0 comments on commit 0ec7246

Please sign in to comment.