Tests for enum type conversion from mirror

This commit is contained in:
Tobe O 2018-08-03 18:41:13 -04:00
parent fe27845bd1
commit 79ffc00fb1
6 changed files with 116 additions and 21 deletions

View 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>

View file

@ -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),

View file

@ -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;

View file

@ -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',

View file

@ -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);

View 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,
}