mirror of
https://github.com/retailcrm/graphql-php.git
synced 2025-02-11 10:09:24 +03:00
parent
ddfeee314c
commit
d71b45d60e
@ -5,10 +5,12 @@
|
|||||||
|
|
||||||
namespace GraphQL\Utils;
|
namespace GraphQL\Utils;
|
||||||
|
|
||||||
|
use GraphQL\Type\Definition\Directive;
|
||||||
use GraphQL\Type\Definition\EnumType;
|
use GraphQL\Type\Definition\EnumType;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ListOfType;
|
use GraphQL\Type\Definition\ListOfType;
|
||||||
|
use GraphQL\Type\Definition\NamedType;
|
||||||
use GraphQL\Type\Definition\NonNull;
|
use GraphQL\Type\Definition\NonNull;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\ScalarType;
|
use GraphQL\Type\Definition\ScalarType;
|
||||||
@ -30,6 +32,10 @@ class FindBreakingChanges
|
|||||||
const BREAKING_CHANGE_NON_NULL_ARG_ADDED = 'NON_NULL_ARG_ADDED';
|
const BREAKING_CHANGE_NON_NULL_ARG_ADDED = 'NON_NULL_ARG_ADDED';
|
||||||
const BREAKING_CHANGE_NON_NULL_INPUT_FIELD_ADDED = 'NON_NULL_INPUT_FIELD_ADDED';
|
const BREAKING_CHANGE_NON_NULL_INPUT_FIELD_ADDED = 'NON_NULL_INPUT_FIELD_ADDED';
|
||||||
const BREAKING_CHANGE_INTERFACE_REMOVED_FROM_OBJECT = 'INTERFACE_REMOVED_FROM_OBJECT';
|
const BREAKING_CHANGE_INTERFACE_REMOVED_FROM_OBJECT = 'INTERFACE_REMOVED_FROM_OBJECT';
|
||||||
|
const BREAKING_CHANGE_DIRECTIVE_REMOVED = 'DIRECTIVE_REMOVED';
|
||||||
|
const BREAKING_CHANGE_DIRECTIVE_ARG_REMOVED = 'DIRECTIVE_ARG_REMOVED';
|
||||||
|
const BREAKING_CHANGE_DIRECTIVE_LOCATION_REMOVED = 'DIRECTIVE_LOCATION_REMOVED';
|
||||||
|
const BREAKING_CHANGE_NON_NULL_DIRECTIVE_ARG_ADDED = 'NON_NULL_DIRECTIVE_ARG_ADDED';
|
||||||
|
|
||||||
const DANGEROUS_CHANGE_ARG_DEFAULT_VALUE = 'ARG_DEFAULT_VALUE_CHANGE';
|
const DANGEROUS_CHANGE_ARG_DEFAULT_VALUE = 'ARG_DEFAULT_VALUE_CHANGE';
|
||||||
const DANGEROUS_CHANGE_VALUE_ADDED_TO_ENUM = 'VALUE_ADDED_TO_ENUM';
|
const DANGEROUS_CHANGE_VALUE_ADDED_TO_ENUM = 'VALUE_ADDED_TO_ENUM';
|
||||||
@ -53,7 +59,11 @@ class FindBreakingChanges
|
|||||||
self::findTypesRemovedFromUnions($oldSchema, $newSchema),
|
self::findTypesRemovedFromUnions($oldSchema, $newSchema),
|
||||||
self::findValuesRemovedFromEnums($oldSchema, $newSchema),
|
self::findValuesRemovedFromEnums($oldSchema, $newSchema),
|
||||||
self::findArgChanges($oldSchema, $newSchema)['breakingChanges'],
|
self::findArgChanges($oldSchema, $newSchema)['breakingChanges'],
|
||||||
self::findInterfacesRemovedFromObjectTypes($oldSchema, $newSchema)
|
self::findInterfacesRemovedFromObjectTypes($oldSchema, $newSchema),
|
||||||
|
self::findRemovedDirectives($oldSchema, $newSchema),
|
||||||
|
self::findRemovedDirectiveArgs($oldSchema, $newSchema),
|
||||||
|
self::findAddedNonNullDirectiveArgs($oldSchema, $newSchema),
|
||||||
|
self::findRemovedDirectiveLocations($oldSchema, $newSchema)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,8 +293,8 @@ class FindBreakingChanges
|
|||||||
$isSafe = self::isChangeSafeForObjectOrInterfaceField($oldFieldType, $newfieldType);
|
$isSafe = self::isChangeSafeForObjectOrInterfaceField($oldFieldType, $newfieldType);
|
||||||
if (!$isSafe) {
|
if (!$isSafe) {
|
||||||
|
|
||||||
$oldFieldTypeString = self::isNamedType($oldFieldType) ? $oldFieldType->name : $oldFieldType;
|
$oldFieldTypeString = $oldFieldType instanceof NamedType ? $oldFieldType->name : $oldFieldType;
|
||||||
$newFieldTypeString = self::isNamedType($newfieldType) ? $newfieldType->name : $newfieldType;
|
$newFieldTypeString = $newfieldType instanceof NamedType ? $newfieldType->name : $newfieldType;
|
||||||
$breakingChanges[] = ['type' => self::BREAKING_CHANGE_FIELD_CHANGED, 'description' => "${typeName}->${fieldName} changed type from ${oldFieldTypeString} to ${newFieldTypeString}."];
|
$breakingChanges[] = ['type' => self::BREAKING_CHANGE_FIELD_CHANGED, 'description' => "${typeName}->${fieldName} changed type from ${oldFieldTypeString} to ${newFieldTypeString}."];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -323,11 +333,11 @@ class FindBreakingChanges
|
|||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
$oldFieldType = $oldTypeFieldsDef[$fieldName]->getType();
|
$oldFieldType = $oldTypeFieldsDef[$fieldName]->getType();
|
||||||
$newfieldType = $newTypeFieldsDef[$fieldName]->getType();
|
$newFieldType = $newTypeFieldsDef[$fieldName]->getType();
|
||||||
$isSafe = self::isChangeSafeForInputObjectFieldOrFieldArg($oldFieldType, $newfieldType);
|
$isSafe = self::isChangeSafeForInputObjectFieldOrFieldArg($oldFieldType, $newFieldType);
|
||||||
if (!$isSafe) {
|
if (!$isSafe) {
|
||||||
$oldFieldTypeString = self::isNamedType($oldFieldType) ? $oldFieldType->name : $oldFieldType;
|
$oldFieldTypeString = $oldFieldType instanceof NamedType ? $oldFieldType->name : $oldFieldType;
|
||||||
$newFieldTypeString = self::isNamedType($newfieldType) ? $newfieldType->name : $newfieldType;
|
$newFieldTypeString = $newFieldType instanceof NamedType ? $newFieldType->name : $newFieldType;
|
||||||
$breakingChanges[] = [
|
$breakingChanges[] = [
|
||||||
'type' => self::BREAKING_CHANGE_FIELD_CHANGED,
|
'type' => self::BREAKING_CHANGE_FIELD_CHANGED,
|
||||||
'description' => "${typeName}->${fieldName} changed type from ${oldFieldTypeString} to ${newFieldTypeString}."];
|
'description' => "${typeName}->${fieldName} changed type from ${oldFieldTypeString} to ${newFieldTypeString}."];
|
||||||
@ -361,9 +371,9 @@ class FindBreakingChanges
|
|||||||
Type $oldType, Type $newType
|
Type $oldType, Type $newType
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if (self::isNamedType($oldType)) {
|
if ($oldType instanceof NamedType) {
|
||||||
// if they're both named types, see if their names are equivalent
|
// if they're both named types, see if their names are equivalent
|
||||||
return (self::isNamedType($newType) && $oldType->name === $newType->name)
|
return ($newType instanceof NamedType && $oldType->name === $newType->name)
|
||||||
// moving from nullable to non-null of the same underlying type is safe
|
// moving from nullable to non-null of the same underlying type is safe
|
||||||
|| ($newType instanceof NonNull
|
|| ($newType instanceof NonNull
|
||||||
&& self::isChangeSafeForObjectOrInterfaceField(
|
&& self::isChangeSafeForObjectOrInterfaceField(
|
||||||
@ -387,16 +397,16 @@ class FindBreakingChanges
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Type $oldType
|
* @param Type $oldType
|
||||||
* @param Schema $newSchema
|
* @param Type $newType
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
private static function isChangeSafeForInputObjectFieldOrFieldArg(
|
private static function isChangeSafeForInputObjectFieldOrFieldArg(
|
||||||
Type $oldType, Type $newType
|
Type $oldType,
|
||||||
)
|
Type $newType
|
||||||
{
|
) {
|
||||||
if (self::isNamedType($oldType)) {
|
if ($oldType instanceof NamedType) {
|
||||||
return self::isNamedType($newType) && $oldType->name === $newType->name;
|
return $newType instanceof NamedType && $oldType->name === $newType->name;
|
||||||
} elseif ($oldType instanceof ListOfType) {
|
} elseif ($oldType instanceof ListOfType) {
|
||||||
return $newType instanceof ListOfType && self::isChangeSafeForInputObjectFieldOrFieldArg($oldType->getWrappedType(), $newType->getWrappedType());
|
return $newType instanceof ListOfType && self::isChangeSafeForInputObjectFieldOrFieldArg($oldType->getWrappedType(), $newType->getWrappedType());
|
||||||
} elseif ($oldType instanceof NonNull) {
|
} elseif ($oldType instanceof NonNull) {
|
||||||
@ -583,20 +593,135 @@ class FindBreakingChanges
|
|||||||
return $breakingChanges;
|
return $breakingChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public static function findRemovedDirectives(Schema $oldSchema, Schema $newSchema)
|
||||||
* @param Type $type
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
private static function isNamedType(Type $type)
|
|
||||||
{
|
{
|
||||||
return (
|
$removedDirectives = [];
|
||||||
$type instanceof ScalarType ||
|
|
||||||
$type instanceof ObjectType ||
|
$newSchemaDirectiveMap = self::getDirectiveMapForSchema($newSchema);
|
||||||
$type instanceof InterfaceType ||
|
foreach($oldSchema->getDirectives() as $directive) {
|
||||||
$type instanceof UnionType ||
|
if (!isset($newSchemaDirectiveMap[$directive->name])) {
|
||||||
$type instanceof EnumType ||
|
$removedDirectives[] = [
|
||||||
$type instanceof InputObjectType
|
'type' => self::BREAKING_CHANGE_DIRECTIVE_REMOVED,
|
||||||
);
|
'description' => "{$directive->name} was removed",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $removedDirectives;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function findRemovedArgsForDirectives(Directive $oldDirective, Directive $newDirective)
|
||||||
|
{
|
||||||
|
$removedArgs = [];
|
||||||
|
$newArgMap = self::getArgumentMapForDirective($newDirective);
|
||||||
|
foreach((array) $oldDirective->args as $arg) {
|
||||||
|
if (!isset($newArgMap[$arg->name])) {
|
||||||
|
$removedArgs[] = $arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $removedArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function findRemovedDirectiveArgs(Schema $oldSchema, Schema $newSchema)
|
||||||
|
{
|
||||||
|
$removedDirectiveArgs = [];
|
||||||
|
$oldSchemaDirectiveMap = self::getDirectiveMapForSchema($oldSchema);
|
||||||
|
|
||||||
|
foreach($newSchema->getDirectives() as $newDirective) {
|
||||||
|
if (!isset($oldSchemaDirectiveMap[$newDirective->name])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(self::findRemovedArgsForDirectives($oldSchemaDirectiveMap[$newDirective->name], $newDirective) as $arg) {
|
||||||
|
$removedDirectiveArgs[] = [
|
||||||
|
'type' => self::BREAKING_CHANGE_DIRECTIVE_ARG_REMOVED,
|
||||||
|
'description' => "{$arg->name} was removed from {$newDirective->name}",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $removedDirectiveArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function findAddedArgsForDirective(Directive $oldDirective, Directive $newDirective)
|
||||||
|
{
|
||||||
|
$addedArgs = [];
|
||||||
|
$oldArgMap = self::getArgumentMapForDirective($oldDirective);
|
||||||
|
foreach((array) $newDirective->args as $arg) {
|
||||||
|
if (!isset($oldArgMap[$arg->name])) {
|
||||||
|
$addedArgs[] = $arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $addedArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function findAddedNonNullDirectiveArgs(Schema $oldSchema, Schema $newSchema)
|
||||||
|
{
|
||||||
|
$addedNonNullableArgs = [];
|
||||||
|
$oldSchemaDirectiveMap = self::getDirectiveMapForSchema($oldSchema);
|
||||||
|
|
||||||
|
foreach($newSchema->getDirectives() as $newDirective) {
|
||||||
|
if (!isset($oldSchemaDirectiveMap[$newDirective->name])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(self::findAddedArgsForDirective($oldSchemaDirectiveMap[$newDirective->name], $newDirective) as $arg) {
|
||||||
|
if (!$arg->getType() instanceof NonNull) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$addedNonNullableArgs[] = [
|
||||||
|
'type' => self::BREAKING_CHANGE_NON_NULL_DIRECTIVE_ARG_ADDED,
|
||||||
|
'description' => "A non-null arg {$arg->name} on directive {$newDirective->name} was added",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $addedNonNullableArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function findRemovedLocationsForDirective(Directive $oldDirective, Directive $newDirective)
|
||||||
|
{
|
||||||
|
$removedLocations = [];
|
||||||
|
$newLocationSet = array_flip($newDirective->locations);
|
||||||
|
foreach($oldDirective->locations as $oldLocation) {
|
||||||
|
if (!array_key_exists($oldLocation, $newLocationSet)) {
|
||||||
|
$removedLocations[] = $oldLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $removedLocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function findRemovedDirectiveLocations(Schema $oldSchema, Schema $newSchema)
|
||||||
|
{
|
||||||
|
$removedLocations = [];
|
||||||
|
$oldSchemaDirectiveMap = self::getDirectiveMapForSchema($oldSchema);
|
||||||
|
|
||||||
|
foreach($newSchema->getDirectives() as $newDirective) {
|
||||||
|
if (!isset($oldSchemaDirectiveMap[$newDirective->name])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(self::findRemovedLocationsForDirective($oldSchemaDirectiveMap[$newDirective->name], $newDirective) as $location) {
|
||||||
|
$removedLocations[] = [
|
||||||
|
'type' => self::BREAKING_CHANGE_DIRECTIVE_LOCATION_REMOVED,
|
||||||
|
'description' => "{$location} was removed from {$newDirective->name}",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $removedLocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getDirectiveMapForSchema(Schema $schema)
|
||||||
|
{
|
||||||
|
return Utils::keyMap($schema->getDirectives(), function ($dir) { return $dir->name; });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function getArgumentMapForDirective(Directive $directive)
|
||||||
|
{
|
||||||
|
return Utils::keyMap($directive->args ?: [], function ($arg) { return $arg->name; });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace GraphQL\Tests\Utils;
|
namespace GraphQL\Tests\Utils;
|
||||||
|
|
||||||
|
use GraphQL\Language\DirectiveLocation;
|
||||||
|
use GraphQL\Type\Definition\Directive;
|
||||||
use GraphQL\Type\Definition\EnumType;
|
use GraphQL\Type\Definition\EnumType;
|
||||||
|
use GraphQL\Type\Definition\FieldArgument;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\InterfaceType;
|
use GraphQL\Type\Definition\InterfaceType;
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
@ -1134,32 +1137,78 @@ class FindBreakingChangesTest extends \PHPUnit_Framework_TestCase
|
|||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$directiveThatIsRemoved = Directive::skipDirective();
|
||||||
|
$directiveThatRemovesArgOld = new Directive([
|
||||||
|
'name' => 'DirectiveThatRemovesArg',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
'args' => FieldArgument::createMap([
|
||||||
|
'arg1' => [
|
||||||
|
'name' => 'arg1',
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
$directiveThatRemovesArgNew = new Directive([
|
||||||
|
'name' => 'DirectiveThatRemovesArg',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
]);
|
||||||
|
$nonNullDirectiveAddedOld = new Directive([
|
||||||
|
'name' => 'NonNullDirectiveAdded',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
]);
|
||||||
|
$nonNullDirectiveAddedNew = new Directive([
|
||||||
|
'name' => 'NonNullDirectiveAdded',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
'args' => FieldArgument::createMap([
|
||||||
|
'arg1' => [
|
||||||
|
'name' => 'arg1',
|
||||||
|
'type' => Type::nonNull(Type::boolean()),
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
$directiveRemovedLocationOld = new Directive([
|
||||||
|
'name' => 'Directive Name',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION, DirectiveLocation::QUERY],
|
||||||
|
]);
|
||||||
|
$directiveRemovedLocationNew = new Directive([
|
||||||
|
'name' => 'Directive Name',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
]);
|
||||||
|
|
||||||
$oldSchema = new Schema([
|
$oldSchema = new Schema([
|
||||||
'query' => $this->queryType,
|
'query' => $this->queryType,
|
||||||
'types' =>
|
'types' => [
|
||||||
[
|
'TypeThatGetsRemoved' => $typeThatGetsRemoved,
|
||||||
'TypeThatGetsRemoved' => $typeThatGetsRemoved,
|
'TypeThatChangesType' => $typeThatChangesTypeOld,
|
||||||
'TypeThatChangesType' => $typeThatChangesTypeOld,
|
'TypeThatHasBreakingFieldChanges' => $typeThatHasBreakingFieldChangesOld,
|
||||||
'TypeThatHasBreakingFieldChanges' => $typeThatHasBreakingFieldChangesOld,
|
'UnionTypeThatLosesAType' => $unionTypeThatLosesATypeOld,
|
||||||
'UnionTypeThatLosesAType' => $unionTypeThatLosesATypeOld,
|
'EnumTypeThatLosesAValue' => $enumTypeThatLosesAValueOld,
|
||||||
'EnumTypeThatLosesAValue' => $enumTypeThatLosesAValueOld,
|
'ArgThatChanges' => $argThatChanges,
|
||||||
'ArgThatChanges' => $argThatChanges,
|
'TypeThatLosesInterface' => $typeThatLosesInterfaceOld
|
||||||
'TypeThatLosesInterface' => $typeThatLosesInterfaceOld
|
],
|
||||||
]
|
'directives' => [
|
||||||
|
$directiveThatIsRemoved,
|
||||||
|
$directiveThatRemovesArgOld,
|
||||||
|
$nonNullDirectiveAddedOld,
|
||||||
|
$directiveRemovedLocationOld,
|
||||||
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$newSchema = new Schema([
|
$newSchema = new Schema([
|
||||||
'query' => $this->queryType,
|
'query' => $this->queryType,
|
||||||
'types' =>
|
'types' => [
|
||||||
[
|
'TypeThatChangesType' => $typeThatChangesTypeNew,
|
||||||
'TypeThatChangesType' => $typeThatChangesTypeNew,
|
'TypeThatHasBreakingFieldChanges' => $typeThatHasBreakingFieldChangesNew,
|
||||||
'TypeThatHasBreakingFieldChanges' => $typeThatHasBreakingFieldChangesNew,
|
'UnionTypeThatLosesAType' => $unionTypeThatLosesATypeNew,
|
||||||
'UnionTypeThatLosesAType' => $unionTypeThatLosesATypeNew,
|
'EnumTypeThatLosesAValue' => $enumTypeThatLosesAValueNew,
|
||||||
'EnumTypeThatLosesAValue' => $enumTypeThatLosesAValueNew,
|
'ArgThatChanges' => $argChanged,
|
||||||
'ArgThatChanges' => $argChanged,
|
'TypeThatLosesInterface' => $typeThatLosesInterfaceNew,
|
||||||
'TypeThatLosesInterface' => $typeThatLosesInterfaceNew,
|
'Interface1' => $interface1
|
||||||
'Interface1' => $interface1
|
],
|
||||||
]
|
'directives' => [
|
||||||
|
$directiveThatRemovesArgNew,
|
||||||
|
$nonNullDirectiveAddedNew,
|
||||||
|
$directiveRemovedLocationNew,
|
||||||
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$expectedBreakingChanges = [
|
$expectedBreakingChanges = [
|
||||||
@ -1206,13 +1255,208 @@ class FindBreakingChangesTest extends \PHPUnit_Framework_TestCase
|
|||||||
[
|
[
|
||||||
'type' => FindBreakingChanges::BREAKING_CHANGE_INTERFACE_REMOVED_FROM_OBJECT,
|
'type' => FindBreakingChanges::BREAKING_CHANGE_INTERFACE_REMOVED_FROM_OBJECT,
|
||||||
'description' => 'TypeThatLosesInterface1 no longer implements interface Interface1.',
|
'description' => 'TypeThatLosesInterface1 no longer implements interface Interface1.',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'type' => FindBreakingChanges::BREAKING_CHANGE_DIRECTIVE_REMOVED,
|
||||||
|
'description' => 'skip was removed',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'type' => FindBreakingChanges::BREAKING_CHANGE_DIRECTIVE_ARG_REMOVED,
|
||||||
|
'description' => 'arg1 was removed from DirectiveThatRemovesArg',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'type' => FindBreakingChanges::BREAKING_CHANGE_NON_NULL_DIRECTIVE_ARG_ADDED,
|
||||||
|
'description' => 'A non-null arg arg1 on directive NonNullDirectiveAdded was added',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'type' => FindBreakingChanges::BREAKING_CHANGE_DIRECTIVE_LOCATION_REMOVED,
|
||||||
|
'description' => 'QUERY was removed from Directive Name',
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
$this->assertEquals($expectedBreakingChanges, FindBreakingChanges::findBreakingChanges($oldSchema, $newSchema));
|
$this->assertEquals($expectedBreakingChanges, FindBreakingChanges::findBreakingChanges($oldSchema, $newSchema));
|
||||||
}
|
}
|
||||||
|
|
||||||
// findDangerousChanges tests below here
|
/**
|
||||||
|
* @it should detect if a directive was explicitly removed
|
||||||
|
*/
|
||||||
|
public function testShouldDetectIfADirectiveWasExplicitlyRemoved()
|
||||||
|
{
|
||||||
|
$oldSchema = new Schema([
|
||||||
|
'directives' => [Directive::skipDirective(), Directive::includeDirective()],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$newSchema = new Schema([
|
||||||
|
'directives' => [Directive::skipDirective()],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$includeDirective = Directive::includeDirective();
|
||||||
|
|
||||||
|
$expectedBreakingChanges = [
|
||||||
|
[
|
||||||
|
'type' => FindBreakingChanges::BREAKING_CHANGE_DIRECTIVE_REMOVED,
|
||||||
|
'description' => "{$includeDirective->name} was removed",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expectedBreakingChanges, FindBreakingChanges::findRemovedDirectives($oldSchema, $newSchema));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it should detect if a directive was implicitly removed
|
||||||
|
*/
|
||||||
|
public function testShouldDetectIfADirectiveWasImplicitlyRemoved()
|
||||||
|
{
|
||||||
|
$oldSchema = new Schema([]);
|
||||||
|
|
||||||
|
$newSchema = new Schema([
|
||||||
|
'directives' => [Directive::skipDirective(), Directive::includeDirective()],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$deprecatedDirective = Directive::deprecatedDirective();
|
||||||
|
|
||||||
|
$expectedBreakingChanges = [
|
||||||
|
[
|
||||||
|
'type' => FindBreakingChanges::BREAKING_CHANGE_DIRECTIVE_REMOVED,
|
||||||
|
'description' => "{$deprecatedDirective->name} was removed",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expectedBreakingChanges, FindBreakingChanges::findRemovedDirectives($oldSchema, $newSchema));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it should detect if a directive argument was removed
|
||||||
|
*/
|
||||||
|
public function testShouldDetectIfADirectiveArgumentWasRemoved()
|
||||||
|
{
|
||||||
|
$oldSchema = new Schema([
|
||||||
|
'directives' => [
|
||||||
|
new Directive([
|
||||||
|
'name' => 'DirectiveWithArg',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
'args' => FieldArgument::createMap([
|
||||||
|
'arg1' => [
|
||||||
|
'name' => 'arg1',
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$newSchema = new Schema([
|
||||||
|
'directives' => [
|
||||||
|
new Directive([
|
||||||
|
'name' => 'DirectiveWithArg',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
])
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$expectedBreakingChanges = [
|
||||||
|
[
|
||||||
|
'type' => FindBreakingChanges::BREAKING_CHANGE_DIRECTIVE_ARG_REMOVED,
|
||||||
|
'description' => "arg1 was removed from DirectiveWithArg",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expectedBreakingChanges, FindBreakingChanges::findRemovedDirectiveArgs($oldSchema, $newSchema));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it should detect if a non-nullable directive argument was added
|
||||||
|
*/
|
||||||
|
public function testShouldDetectIfANonNullableDirectiveArgumentWasAdded()
|
||||||
|
{
|
||||||
|
$oldSchema = new Schema([
|
||||||
|
'directives' => [
|
||||||
|
new Directive([
|
||||||
|
'name' => 'DirectiveName',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
])
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$newSchema = new Schema([
|
||||||
|
'directives' => [
|
||||||
|
new Directive([
|
||||||
|
'name' => 'DirectiveName',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
'args' => FieldArgument::createMap([
|
||||||
|
'arg1' => [
|
||||||
|
'name' => 'arg1',
|
||||||
|
'type' => Type::nonNull(Type::boolean()),
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
])
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$expectedBreakingChanges = [
|
||||||
|
[
|
||||||
|
'type' => FindBreakingChanges::BREAKING_CHANGE_NON_NULL_DIRECTIVE_ARG_ADDED,
|
||||||
|
'description' => "A non-null arg arg1 on directive DirectiveName was added",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expectedBreakingChanges, FindBreakingChanges::findAddedNonNullDirectiveArgs($oldSchema, $newSchema));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it should detect locations removed from a directive
|
||||||
|
*/
|
||||||
|
public function testShouldDetectLocationsRemovedFromADirective()
|
||||||
|
{
|
||||||
|
$d1 = new Directive([
|
||||||
|
'name' => 'Directive Name',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION, DirectiveLocation::QUERY],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$d2 = new Directive([
|
||||||
|
'name' => 'Directive Name',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals([DirectiveLocation::QUERY], FindBreakingChanges::findRemovedLocationsForDirective($d1, $d2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it should detect locations removed directives within a schema
|
||||||
|
*/
|
||||||
|
public function testShouldDetectLocationsRemovedDirectiveWithinASchema()
|
||||||
|
{
|
||||||
|
$oldSchema = new Schema([
|
||||||
|
'directives' => [
|
||||||
|
new Directive([
|
||||||
|
'name' => 'Directive Name',
|
||||||
|
'locations' => [
|
||||||
|
DirectiveLocation::FIELD_DEFINITION,
|
||||||
|
DirectiveLocation::QUERY
|
||||||
|
],
|
||||||
|
])
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$newSchema = new Schema([
|
||||||
|
'directives' => [
|
||||||
|
new Directive([
|
||||||
|
'name' => 'Directive Name',
|
||||||
|
'locations' => [DirectiveLocation::FIELD_DEFINITION],
|
||||||
|
])
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$expectedBreakingChanges = [
|
||||||
|
[
|
||||||
|
'type' => FindBreakingChanges::BREAKING_CHANGE_DIRECTIVE_LOCATION_REMOVED,
|
||||||
|
'description' => "QUERY was removed from Directive Name",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->assertEquals($expectedBreakingChanges, FindBreakingChanges::findRemovedDirectiveLocations($oldSchema, $newSchema));
|
||||||
|
}
|
||||||
|
|
||||||
|
// DESCRIBE: findDangerousChanges
|
||||||
|
|
||||||
public function testFindDangerousArgChanges()
|
public function testFindDangerousArgChanges()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user