blob: 879ae116748dba3953c5bbc79f36ee74faebc6a3 [file] [log] [blame]
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:_fe_analyzer_shared/src/macros/api.dart';
import 'package:_fe_analyzer_shared/src/macros/executor_shared/introspection_impls.dart';
import 'package:_fe_analyzer_shared/src/macros/executor_shared/remote_instance.dart';
import 'package:_fe_analyzer_shared/src/macros/executor_shared/serialization.dart';
import 'package:_fe_analyzer_shared/src/macros/executor_shared/serialization_extensions.dart';
import 'package:test/test.dart';
import '../util.dart';
void main() {
group('json serializer', () {
test('can serialize and deserialize basic data', () {
var serializer = JsonSerializer();
serializer
..addNum(1)
..addNullableNum(null)
..addString('hello')
..addNullableString(null)
..startList()
..addBool(true)
..startList()
..addNull()
..endList()
..addNullableBool(null)
..endList()
..addNum(1.0)
..startList()
..endList();
expect(
serializer.result,
equals([
1,
null,
'hello',
null,
[
true,
[null],
null
],
1.0,
[],
]));
var deserializer = JsonDeserializer(serializer.result);
expect(deserializer.moveNext(), true);
expect(deserializer.expectNum(), 1);
expect(deserializer.moveNext(), true);
expect(deserializer.expectNullableNum(), null);
expect(deserializer.moveNext(), true);
expect(deserializer.expectString(), 'hello');
expect(deserializer.moveNext(), true);
expect(deserializer.expectNullableString(), null);
expect(deserializer.moveNext(), true);
deserializer.expectList();
expect(deserializer.moveNext(), true);
expect(deserializer.expectBool(), true);
expect(deserializer.moveNext(), true);
deserializer.expectList();
expect(deserializer.moveNext(), true);
expect(deserializer.checkNull(), true);
expect(deserializer.moveNext(), false);
expect(deserializer.moveNext(), true);
expect(deserializer.expectNullableBool(), null);
expect(deserializer.moveNext(), false);
// Have to move the parent again to advance it past the list entry.
expect(deserializer.moveNext(), true);
expect(deserializer.expectNum(), 1.0);
expect(deserializer.moveNext(), true);
deserializer.expectList();
expect(deserializer.moveNext(), false);
expect(deserializer.moveNext(), false);
});
test('remote instances', () async {
var string = NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
isNullable: false,
identifier:
IdentifierImpl(id: RemoteInstance.uniqueId, name: 'String'),
typeArguments: const []);
var foo = NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
isNullable: false,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
typeArguments: [string]);
Object? serializedFoo;
var serializer = JsonSerializer();
withSerializationMode(SerializationMode.server, () {
foo.serialize(serializer);
serializedFoo = serializer.result;
var response = roundTrip(serializedFoo);
var deserializer = JsonDeserializer(response as List<Object?>);
var instance = RemoteInstance.deserialize(deserializer);
expect(instance, foo);
});
});
group('declarations', () {
final barType = NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
isNullable: false,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Bar'),
typeArguments: []);
final fooType = NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
isNullable: true,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
typeArguments: [barType]);
test('NamedTypeAnnotation', () {
expectSerializationEquality(fooType);
});
final fooNamedParam = ParameterDeclarationImpl(
id: RemoteInstance.uniqueId,
isNamed: true,
isRequired: true,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'foo'),
type: fooType);
final barPositionalParam = ParameterDeclarationImpl(
id: RemoteInstance.uniqueId,
isNamed: false,
isRequired: false,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'bar'),
type: barType);
final zapTypeParam = TypeParameterDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Zap'),
bound: barType);
// Transitively tests `TypeParameterDeclaration` and
// `ParameterDeclaration`.
test('FunctionTypeAnnotation', () {
var functionType = FunctionTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
isNullable: true,
namedParameters: [fooNamedParam],
positionalParameters: [barPositionalParam],
returnType: fooType,
typeParameters: [zapTypeParam],
);
expectSerializationEquality(functionType);
});
test('FunctionDeclaration', () {
var function = FunctionDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier:
IdentifierImpl(id: RemoteInstance.uniqueId, name: 'name'),
isAbstract: true,
isExternal: false,
isGetter: true,
isOperator: false,
isSetter: false,
namedParameters: [],
positionalParameters: [],
returnType: fooType,
typeParameters: []);
expectSerializationEquality(function);
});
test('MethodDeclaration', () {
var method = MethodDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier:
IdentifierImpl(id: RemoteInstance.uniqueId, name: 'zorp'),
isAbstract: false,
isExternal: false,
isGetter: false,
isOperator: false,
isSetter: true,
namedParameters: [fooNamedParam],
positionalParameters: [barPositionalParam],
returnType: fooType,
typeParameters: [zapTypeParam],
definingClass: fooType.identifier);
expectSerializationEquality(method);
});
test('ConstructorDeclaration', () {
var constructor = ConstructorDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'new'),
isAbstract: false,
isExternal: false,
isGetter: false,
isOperator: true,
isSetter: false,
namedParameters: [fooNamedParam],
positionalParameters: [barPositionalParam],
returnType: fooType,
typeParameters: [zapTypeParam],
definingClass: fooType.identifier,
isFactory: true,
);
expectSerializationEquality(constructor);
});
test('VariableDeclaration', () {
var bar = VariableDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'bar'),
isExternal: true,
isFinal: false,
isLate: true,
type: barType,
);
expectSerializationEquality(bar);
});
test('FieldDeclaration', () {
var bar = FieldDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'bar'),
isExternal: false,
isFinal: true,
isLate: false,
type: barType,
definingClass: fooType.identifier,
);
expectSerializationEquality(bar);
});
var objectType = NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Object'),
isNullable: false,
typeArguments: [],
);
var serializableType = NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
identifier:
IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Serializable'),
isNullable: false,
typeArguments: [],
);
test('ClassDeclaration', () {
var fooClass = ClassDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier: IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
interfaces: [barType],
isAbstract: true,
isExternal: false,
mixins: [serializableType],
superclass: objectType,
typeParameters: [zapTypeParam],
);
expectSerializationEquality(fooClass);
});
test('TypeAliasDeclaration', () {
var typeAlias = TypeAliasDeclarationImpl(
id: RemoteInstance.uniqueId,
identifier:
IdentifierImpl(id: RemoteInstance.uniqueId, name: 'FooOfBar'),
typeParameters: [zapTypeParam],
aliasedType: NamedTypeAnnotationImpl(
id: RemoteInstance.uniqueId,
isNullable: false,
identifier:
IdentifierImpl(id: RemoteInstance.uniqueId, name: 'Foo'),
typeArguments: [barType]),
);
expectSerializationEquality(typeAlias);
});
});
});
}
/// Serializes [serializable] in server mode, then deserializes it in client
/// mode, and checks that all the fields are the same.
void expectSerializationEquality(Serializable serializable) {
var serializer = JsonSerializer();
withSerializationMode(SerializationMode.server, () {
serializable.serialize(serializer);
});
withSerializationMode(SerializationMode.client, () {
var deserializer = JsonDeserializer(serializer.result);
var deserialized = (deserializer..moveNext()).expectRemoteInstance();
if (deserialized is Declaration) {
expect(serializable, deepEqualsDeclaration(deserialized));
} else if (deserialized is TypeAnnotation) {
expect(serializable, deepEqualsTypeAnnotation(deserialized));
} else {
throw new UnsupportedError('Unsupported object type $deserialized');
}
});
}
/// Deserializes [serialized] in client mode and sends it back.
Object? roundTrip<Declaration>(Object? serialized) {
return withSerializationMode(SerializationMode.client, () {
var deserializer = JsonDeserializer(serialized as List<Object?>);
var instance =
RemoteInstance.deserialize<NamedTypeAnnotationImpl>(deserializer);
var serializer = JsonSerializer();
instance.serialize(serializer);
return serializer.result;
});
}