Tests for enum type conversion from mirror
This commit is contained in:
parent
fe27845bd1
commit
79ffc00fb1
6 changed files with 116 additions and 21 deletions
7
.idea/runConfigurations/tests_in_mirrors_test_dart.xml
Normal file
7
.idea/runConfigurations/tests_in_mirrors_test_dart.xml
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="tests in mirrors_test.dart" type="DartTestRunConfigurationType" factoryName="Dart Test" singleton="true" nameIsGenerated="true">
|
||||||
|
<option name="filePath" value="$PROJECT_DIR$/graphql_server/test/mirrors_test.dart" />
|
||||||
|
<option name="testRunnerOptions" value="-j4" />
|
||||||
|
<method />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
|
@ -25,7 +25,7 @@ main() async {
|
||||||
fields: [
|
fields: [
|
||||||
field(
|
field(
|
||||||
'todo',
|
'todo',
|
||||||
type: listType(objectTypeFromDartType(Todo).nonNullable()),
|
type: listType(convertDartType(Todo).nonNullable()),
|
||||||
resolve: resolveFromService(todoService),
|
resolve: resolveFromService(todoService),
|
||||||
arguments: [
|
arguments: [
|
||||||
new GraphQLFieldArgument('id', graphQLId),
|
new GraphQLFieldArgument('id', graphQLId),
|
||||||
|
|
|
@ -1,39 +1,54 @@
|
||||||
part of graphql_schema.src.schema;
|
part of graphql_schema.src.schema;
|
||||||
|
|
||||||
GraphQLEnumType enumType(String name, List<String> values,
|
GraphQLEnumType enumType<Value>(String name, Map<String, Value> values,
|
||||||
{String description}) {
|
{String description}) {
|
||||||
return new GraphQLEnumType(
|
return new GraphQLEnumType<Value>(
|
||||||
name, values.map((s) => new GraphQLEnumValue(s)).toList(),
|
name, values.keys.map((k) => new GraphQLEnumValue(k, values[k])).toList(),
|
||||||
description: description);
|
description: description);
|
||||||
}
|
}
|
||||||
|
|
||||||
class GraphQLEnumType extends _GraphQLStringType {
|
GraphQLEnumType enumTypeFromStrings(String name, List<String> values,
|
||||||
|
{String description}) {
|
||||||
|
return new GraphQLEnumType<String>(
|
||||||
|
name, values.map((s) => new GraphQLEnumValue(s, s)).toList(),
|
||||||
|
description: description);
|
||||||
|
}
|
||||||
|
|
||||||
|
class GraphQLEnumType<Value> extends GraphQLScalarType<Value, String>
|
||||||
|
with _NonNullableMixin<Value, String> {
|
||||||
final String name;
|
final String name;
|
||||||
final List<GraphQLEnumValue> values;
|
final List<GraphQLEnumValue<Value>> values;
|
||||||
final String description;
|
final String description;
|
||||||
|
|
||||||
GraphQLEnumType(this.name, this.values, {this.description}) : super._();
|
GraphQLEnumType(this.name, this.values, {this.description});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String serialize(Value value) {
|
||||||
|
return values.firstWhere((v) => v.value == value).name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Value deserialize(String serialized) {
|
||||||
|
return values.firstWhere((v) => v.name == serialized).value;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ValidationResult<String> validate(String key, String input) {
|
ValidationResult<String> validate(String key, String input) {
|
||||||
var result = super.validate(key, input);
|
if (!values.any((v) => v.name == input)) {
|
||||||
|
return new ValidationResult<String>._failure(
|
||||||
if (result.successful &&
|
['"$input" is not a valid value for the enum "$name".']);
|
||||||
!values.map((v) => v.name).contains(result.value)) {
|
|
||||||
return result._asFailure()
|
|
||||||
..errors.add(
|
|
||||||
'"${result.value}" is not a valid value for the enum "$name".');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return new ValidationResult<String>._ok(input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GraphQLEnumValue {
|
class GraphQLEnumValue<Value> {
|
||||||
final String name;
|
final String name;
|
||||||
|
final Value value;
|
||||||
final String deprecationReason;
|
final String deprecationReason;
|
||||||
|
|
||||||
GraphQLEnumValue(this.name, {this.deprecationReason});
|
GraphQLEnumValue(this.name, this.value, {this.deprecationReason});
|
||||||
|
|
||||||
bool get isDeprecated => deprecationReason != null;
|
bool get isDeprecated => deprecationReason != null;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:graphql_schema/graphql_schema.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
var typeType = enumType('Type', [
|
var typeType = enumTypeFromStrings('Type', [
|
||||||
'FIRE',
|
'FIRE',
|
||||||
'WATER',
|
'WATER',
|
||||||
'GRASS',
|
'GRASS',
|
||||||
|
|
|
@ -9,7 +9,7 @@ import 'package:tuple/tuple.dart';
|
||||||
///
|
///
|
||||||
/// This function is aware of the annotations from `package:angel_serialize`, and works seamlessly
|
/// This function is aware of the annotations from `package:angel_serialize`, and works seamlessly
|
||||||
/// with them.
|
/// with them.
|
||||||
GraphQLType objectTypeFromDartType(Type type, [List<Type> typeArguments]) {
|
GraphQLType convertDartType(Type type, [List<Type> typeArguments]) {
|
||||||
var tuple = new Tuple2(type, typeArguments);
|
var tuple = new Tuple2(type, typeArguments);
|
||||||
return _cache.putIfAbsent(
|
return _cache.putIfAbsent(
|
||||||
tuple, () => _objectTypeFromDartType(type, typeArguments));
|
tuple, () => _objectTypeFromDartType(type, typeArguments));
|
||||||
|
@ -44,7 +44,13 @@ GraphQLType _objectTypeFromDartType(Type type, [List<Type> typeArguments]) {
|
||||||
'$type is not a class, and therefore cannot be converted into a GraphQL object type.');
|
'$type is not a class, and therefore cannot be converted into a GraphQL object type.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return objectTypeFromClassMirror(mirror as ClassMirror);
|
var clazz = mirror as ClassMirror;
|
||||||
|
|
||||||
|
if (clazz.isEnum) {
|
||||||
|
return enumTypeFromClassMirror(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
return objectTypeFromClassMirror(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphQLObjectType objectTypeFromClassMirror(ClassMirror mirror) {
|
GraphQLObjectType objectTypeFromClassMirror(ClassMirror mirror) {
|
||||||
|
@ -69,9 +75,30 @@ GraphQLObjectType objectTypeFromClassMirror(ClassMirror mirror) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GraphQLEnumType enumTypeFromClassMirror(ClassMirror mirror) {
|
||||||
|
var values = <GraphQLEnumValue>[];
|
||||||
|
|
||||||
|
for (var name in mirror.staticMembers.keys) {
|
||||||
|
var methodMirror = mirror.staticMembers[name];
|
||||||
|
values.add(
|
||||||
|
new GraphQLEnumValue(
|
||||||
|
MirrorSystem.getName(name),
|
||||||
|
mirror.getField(name).reflectee,
|
||||||
|
deprecationReason: _getDeprecationReason(methodMirror.metadata),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GraphQLEnumType(
|
||||||
|
MirrorSystem.getName(mirror.simpleName),
|
||||||
|
values,
|
||||||
|
description: _getDescription(mirror.metadata),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
GraphQLField fieldFromGetter(
|
GraphQLField fieldFromGetter(
|
||||||
Symbol name, MethodMirror mirror, Exclude exclude, ClassMirror clazz) {
|
Symbol name, MethodMirror mirror, Exclude exclude, ClassMirror clazz) {
|
||||||
var type = objectTypeFromDartType(mirror.returnType.reflectedType,
|
var type = convertDartType(mirror.returnType.reflectedType,
|
||||||
mirror.returnType.typeArguments.map((t) => t.reflectedType).toList());
|
mirror.returnType.typeArguments.map((t) => t.reflectedType).toList());
|
||||||
|
|
||||||
var nameString = _getSerializedName(name, mirror, clazz);
|
var nameString = _getSerializedName(name, mirror, clazz);
|
||||||
|
|
46
graphql_server/test/mirrors_test.dart
Normal file
46
graphql_server/test/mirrors_test.dart
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import 'package:graphql_schema/graphql_schema.dart';
|
||||||
|
import 'package:graphql_server/mirrors.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
group('convertDartType', () {
|
||||||
|
group('on enum', () {
|
||||||
|
var type = convertDartType(RomanceLanguage);
|
||||||
|
var asEnumType = type as GraphQLEnumType;
|
||||||
|
|
||||||
|
test('produces enum type', () {
|
||||||
|
expect(type is GraphQLEnumType, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('rejects invalid value', () {
|
||||||
|
expect(asEnumType.validate('@root', 'GERMAN').successful, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('accepts valid value', () {
|
||||||
|
expect(asEnumType.validate('@root', 'SPANISH').successful, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('deserializes to concrete value', () {
|
||||||
|
expect(asEnumType.deserialize('ITALIAN'), RomanceLanguage.ITALIAN);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('serializes to concrete value', () {
|
||||||
|
expect(asEnumType.serialize(RomanceLanguage.FRANCE), 'FRANCE');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fails to serialize invalid value', () {
|
||||||
|
expect(() => asEnumType.serialize(34), throwsStateError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('fails to deserialize invalid value', () {
|
||||||
|
expect(() => asEnumType.deserialize('JAPANESE'), throwsStateError);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RomanceLanguage {
|
||||||
|
SPANISH,
|
||||||
|
FRANCE,
|
||||||
|
ITALIAN,
|
||||||
|
}
|
Loading…
Reference in a new issue