From 9a5d6a31ec7e3469b559fe8dbc17a1e94964d986 Mon Sep 17 00:00:00 2001 From: Sam Stenvall Date: Mon, 22 Oct 2018 14:50:23 +0300 Subject: [PATCH 1/2] Add a broken test case for dealing with false non-null booleans in input types --- .../Functional/Execution/ValuesHelperTest.php | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/tests/Functional/Execution/ValuesHelperTest.php b/tests/Functional/Execution/ValuesHelperTest.php index 00263a67..f6c08a1c 100644 --- a/tests/Functional/Execution/ValuesHelperTest.php +++ b/tests/Functional/Execution/ValuesHelperTest.php @@ -3,13 +3,16 @@ namespace Digia\GraphQL\Test\Functional\Execution; use Digia\GraphQL\Execution\ExecutionContext; +use Digia\GraphQL\Execution\ValuesHelper; use Digia\GraphQL\Language\Node\ArgumentsAwareInterface; use Digia\GraphQL\Language\Node\OperationDefinitionNode; +use Digia\GraphQL\Language\Node\StringValueNode; use Digia\GraphQL\Test\TestCase; use function Digia\GraphQL\Execution\coerceArgumentValues; use function Digia\GraphQL\Execution\coerceVariableValues; use function Digia\GraphQL\parse; use function Digia\GraphQL\Type\booleanType; +use function Digia\GraphQL\Type\newInputObjectType; use function Digia\GraphQL\Type\newNonNull; use function Digia\GraphQL\Type\newObjectType; use function Digia\GraphQL\Type\newSchema; @@ -97,4 +100,131 @@ public function testCoerceVariableValues(): void $this->assertEquals([], $coercedValue->getValue()); $this->assertTrue($coercedValue->hasErrors()); } + + public function testCoerceValuesForInputObjectTypes(): void + { + // Test input object types + /** @noinspection PhpUnhandledExceptionInspection */ + $schema = newSchema([ + 'query' => newObjectType([ + 'name' => 'Query', + 'fields' => [ + 'inputObjectField' => [ + 'type' => booleanType(), + 'args' => [ + 'inputObject' => [ + 'type' => newInputObjectType([ + 'name' => 'InputObject', + 'fields' => [ + 'a' => ['type' => stringType()], + 'b' => ['type' => newNonNull(stringType())] + ] + ] + ) + ], + ], + ], + ], + ]), + ]); + + /** @noinspection PhpUnhandledExceptionInspection */ + $documentNode = parse(' + query ($inputObject: InputObject!) { + inputObjectField(inputObject: $inputObject) + } + '); + + /** @var OperationDefinitionNode $operation */ + $operation = $documentNode->getDefinitions()[0]; + $variableDefinitions = $operation->getVariableDefinitions(); + + // Test with a missing non-null string + $coercedValue = coerceVariableValues($schema, $variableDefinitions, [ + 'inputObject' => [ + 'a' => 'some string' + ] + ]); + + $this->assertTrue($coercedValue->hasErrors()); + $this->assertEquals('Variable "$inputObject" got invalid value {"a":"some string"}; Field value.b of required type String! was not provided.', + $coercedValue->getErrors()[0]->getMessage()); + + // Test again with all variables, no errors expected + $coercedValue = coerceVariableValues($schema, $variableDefinitions, [ + 'inputObject' => [ + 'a' => 'some string', + 'b' => 'some other required string', + ] + ]); + + $this->assertFalse($coercedValue->hasErrors()); + + // Test with non-nullable boolean input fields + /** @noinspection PhpUnhandledExceptionInspection */ + $schema = newSchema([ + 'query' => newObjectType([ + 'name' => 'Query', + 'fields' => [ + 'inputObjectField' => [ + 'type' => booleanType(), + 'args' => [ + 'inputObject' => [ + 'type' => newInputObjectType([ + 'name' => 'InputObject', + 'fields' => [ + 'a' => ['type' => booleanType()], + 'b' => ['type' => newNonNull(booleanType())] + ] + ] + ) + ], + ], + ], + ], + ]), + ]); + + /** @noinspection PhpUnhandledExceptionInspection */ + $documentNode = parse(' + query ($inputObject: InputObject!) { + inputObjectField(inputObject: $inputObject) + } + '); + + /** @var OperationDefinitionNode $operation */ + $operation = $documentNode->getDefinitions()[0]; + $variableDefinitions = $operation->getVariableDefinitions(); + + // Test with a missing non-null string + $coercedValue = coerceVariableValues($schema, $variableDefinitions, [ + 'inputObject' => [ + 'a' => true + ] + ]); + + $this->assertTrue($coercedValue->hasErrors()); + $this->assertEquals('Variable "$inputObject" got invalid value {"a":true}; Field value.b of required type Boolean! was not provided.', + $coercedValue->getErrors()[0]->getMessage()); + + // Test again with all fields present, all booleans true + $coercedValue = coerceVariableValues($schema, $variableDefinitions, [ + 'inputObject' => [ + 'a' => true, + 'b' => true, + ] + ]); + + $this->assertFalse($coercedValue->hasErrors()); + + // Test again with all fields present, all booleans false (this has been problematic before) + $coercedValue = coerceVariableValues($schema, $variableDefinitions, [ + 'inputObject' => [ + 'a' => false, + 'b' => false, + ] + ]); + + $this->assertFalse($coercedValue->hasErrors()); + } } From fce30f3ccf3650c375e70d8b1299cc5d340d1f4f Mon Sep 17 00:00:00 2001 From: Sam Stenvall Date: Mon, 22 Oct 2018 14:50:32 +0300 Subject: [PATCH 2/2] Fix the bug, replace empty() with !isset() --- src/Execution/ValuesHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Execution/ValuesHelper.php b/src/Execution/ValuesHelper.php index 781d6673..0989bad6 100644 --- a/src/Execution/ValuesHelper.php +++ b/src/Execution/ValuesHelper.php @@ -400,7 +400,7 @@ protected function coerceValueForInputObjectType( foreach ($fields as $field) { $fieldType = $field->getType(); - if (empty($value[$field->getName()])) { + if (!isset($value[$field->getName()])) { if (!empty($field->getDefaultValue())) { $coercedValue[$field->getName()] = $field->getDefaultValue(); } elseif ($fieldType instanceof NonNullType) {