| // Copyright 2013 The Flutter Authors. 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:pigeon/ast.dart'; |
| import 'package:pigeon/generator_tools.dart'; |
| import 'package:test/test.dart'; |
| |
| bool _equalSet<T>(Set<T> x, Set<T> y) { |
| if (x.length != y.length) { |
| return false; |
| } |
| for (final T object in x) { |
| if (!y.contains(object)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool _equalMaps(Map<String, Object> x, Map<String, Object> y) { |
| if (!_equalSet(x.keys.toSet(), y.keys.toSet())) { |
| return false; |
| } |
| for (final String key in x.keys) { |
| final Object xValue = x[key]!; |
| if (xValue is Map<String, Object>) { |
| if (!_equalMaps(xValue, (y[key] as Map<String, Object>?)!)) { |
| return false; |
| } |
| } else { |
| if (xValue != y[key]) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| final Class emptyClass = Class(name: 'className', fields: <NamedType>[ |
| NamedType( |
| name: 'namedTypeName', |
| type: const TypeDeclaration(baseName: 'baseName', isNullable: false), |
| ) |
| ]); |
| |
| void main() { |
| test('test merge maps', () { |
| final Map<String, Object> source = <String, Object>{ |
| '1': '1', |
| '2': <String, Object>{ |
| '1': '1', |
| '3': '3', |
| }, |
| '3': '3', // not modified |
| }; |
| final Map<String, Object> modification = <String, Object>{ |
| '1': '2', // modify |
| '2': <String, Object>{ |
| '2': '2', // added |
| }, |
| }; |
| final Map<String, Object> expected = <String, Object>{ |
| '1': '2', |
| '2': <String, Object>{ |
| '1': '1', |
| '2': '2', |
| '3': '3', |
| }, |
| '3': '3', |
| }; |
| expect(_equalMaps(expected, mergeMaps(source, modification)), isTrue); |
| }); |
| |
| test('get codec types from all classes and enums', () { |
| final Root root = Root(classes: <Class>[ |
| Class(name: 'name', fields: <NamedType>[ |
| NamedType( |
| name: 'name', |
| type: const TypeDeclaration( |
| baseName: 'name', |
| isNullable: true, |
| )) |
| ]) |
| ], apis: <Api>[], enums: <Enum>[ |
| Enum(name: 'enum', members: <EnumMember>[ |
| EnumMember(name: 'enumMember'), |
| ]) |
| ]); |
| final List<EnumeratedType> types = getEnumeratedTypes(root).toList(); |
| expect(types.length, 2); |
| }); |
| |
| test('getEnumeratedTypes:ed type arguments', () { |
| final Root root = Root(apis: <Api>[ |
| AstFlutterApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'foo', |
| location: ApiLocation.flutter, |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'x', |
| type: TypeDeclaration( |
| isNullable: false, |
| baseName: 'List', |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration( |
| baseName: 'Foo', |
| isNullable: true, |
| associatedClass: emptyClass, |
| ) |
| ])), |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Foo', fields: <NamedType>[ |
| NamedType( |
| name: 'bar', |
| type: TypeDeclaration( |
| baseName: 'Bar', |
| isNullable: true, |
| associatedClass: emptyClass, |
| )), |
| ]), |
| Class(name: 'Bar', fields: <NamedType>[ |
| NamedType( |
| name: 'value', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| )) |
| ]) |
| ], enums: <Enum>[]); |
| final List<EnumeratedType> classes = getEnumeratedTypes(root).toList(); |
| expect(classes.length, 2); |
| expect( |
| classes.where((EnumeratedType element) => element.name == 'Foo').length, |
| 1); |
| expect( |
| classes.where((EnumeratedType element) => element.name == 'Bar').length, |
| 1); |
| }); |
| |
| test('getEnumeratedTypes: Object', () { |
| final Root root = Root(apis: <Api>[ |
| AstFlutterApi( |
| name: 'Api1', |
| methods: <Method>[ |
| Method( |
| name: 'foo', |
| location: ApiLocation.flutter, |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'x', |
| type: const TypeDeclaration( |
| isNullable: false, |
| baseName: 'List', |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'Object', isNullable: true) |
| ])), |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| ) |
| ], |
| ), |
| ], classes: <Class>[ |
| Class(name: 'Foo', fields: <NamedType>[ |
| NamedType( |
| name: 'bar', |
| type: const TypeDeclaration(baseName: 'int', isNullable: true)), |
| ]), |
| ], enums: <Enum>[]); |
| final List<EnumeratedType> classes = getEnumeratedTypes(root).toList(); |
| expect(classes.length, 1); |
| expect( |
| classes.where((EnumeratedType element) => element.name == 'Foo').length, |
| 1); |
| }); |
| |
| test('getEnumeratedTypes:ue entries', () { |
| final Root root = Root(apis: <Api>[ |
| AstFlutterApi( |
| name: 'Api1', |
| methods: <Method>[ |
| Method( |
| name: 'foo', |
| location: ApiLocation.flutter, |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'x', |
| type: TypeDeclaration( |
| isNullable: false, |
| baseName: 'Foo', |
| associatedClass: emptyClass, |
| )), |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| ) |
| ], |
| ), |
| AstHostApi( |
| name: 'Api2', |
| methods: <Method>[ |
| Method( |
| name: 'foo', |
| location: ApiLocation.host, |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'x', |
| type: TypeDeclaration( |
| isNullable: false, |
| baseName: 'Foo', |
| associatedClass: emptyClass, |
| )), |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| ) |
| ], |
| ) |
| ], classes: <Class>[ |
| Class(name: 'Foo', fields: <NamedType>[ |
| NamedType( |
| name: 'bar', |
| type: const TypeDeclaration(baseName: 'int', isNullable: true)), |
| ]), |
| ], enums: <Enum>[]); |
| final List<EnumeratedType> classes = getEnumeratedTypes(root).toList(); |
| expect(classes.length, 1); |
| expect( |
| classes.where((EnumeratedType element) => element.name == 'Foo').length, |
| 1); |
| }); |
| |
| test('deduces package name successfully', () { |
| final String? dartPackageName = |
| deducePackageName('./pigeons/core_tests.dart'); |
| |
| expect(dartPackageName, 'pigeon'); |
| }); |
| |
| test('recursiveGetSuperClassApisChain', () { |
| final AstProxyApi superClassOfSuperClassApi = AstProxyApi( |
| name: 'Api3', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| ); |
| final AstProxyApi superClassApi = AstProxyApi( |
| name: 'Api2', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| superClass: TypeDeclaration( |
| baseName: 'Api3', |
| isNullable: false, |
| associatedProxyApi: superClassOfSuperClassApi, |
| ), |
| ); |
| final AstProxyApi api = AstProxyApi( |
| name: 'Api', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| superClass: TypeDeclaration( |
| baseName: 'Api2', |
| isNullable: false, |
| associatedProxyApi: superClassApi, |
| ), |
| ); |
| |
| expect( |
| api.allSuperClasses().toList(), |
| containsAllInOrder(<AstProxyApi>[ |
| superClassApi, |
| superClassOfSuperClassApi, |
| ]), |
| ); |
| }); |
| |
| test('recursiveFindAllInterfacesApis', () { |
| final AstProxyApi interfaceOfInterfaceApi2 = AstProxyApi( |
| name: 'Api5', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| ); |
| final AstProxyApi interfaceOfInterfaceApi = AstProxyApi( |
| name: 'Api4', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| ); |
| final AstProxyApi interfaceApi2 = AstProxyApi( |
| name: 'Api3', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| interfaces: <TypeDeclaration>{ |
| TypeDeclaration( |
| baseName: 'Api5', |
| isNullable: false, |
| associatedProxyApi: interfaceOfInterfaceApi2, |
| ), |
| }, |
| ); |
| final AstProxyApi interfaceApi = AstProxyApi( |
| name: 'Api2', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| interfaces: <TypeDeclaration>{ |
| TypeDeclaration( |
| baseName: 'Api4', |
| isNullable: false, |
| associatedProxyApi: interfaceOfInterfaceApi, |
| ), |
| TypeDeclaration( |
| baseName: 'Api5', |
| isNullable: false, |
| associatedProxyApi: interfaceOfInterfaceApi2, |
| ), |
| }, |
| ); |
| final AstProxyApi api = AstProxyApi( |
| name: 'Api', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| interfaces: <TypeDeclaration>{ |
| TypeDeclaration( |
| baseName: 'Api2', |
| isNullable: false, |
| associatedProxyApi: interfaceApi, |
| ), |
| TypeDeclaration( |
| baseName: 'Api3', |
| isNullable: false, |
| associatedProxyApi: interfaceApi2, |
| ), |
| }, |
| ); |
| |
| expect( |
| api.apisOfInterfaces(), |
| containsAll(<AstProxyApi>[ |
| interfaceApi, |
| interfaceApi2, |
| interfaceOfInterfaceApi, |
| interfaceOfInterfaceApi2, |
| ]), |
| ); |
| }); |
| |
| test( |
| 'recursiveFindAllInterfacesApis throws error if api recursively implements itself', |
| () { |
| final AstProxyApi a = AstProxyApi( |
| name: 'A', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| ); |
| final AstProxyApi b = AstProxyApi( |
| name: 'B', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| ); |
| final AstProxyApi c = AstProxyApi( |
| name: 'C', |
| methods: <Method>[], |
| constructors: <Constructor>[], |
| fields: <ApiField>[], |
| ); |
| |
| a.interfaces = <TypeDeclaration>{ |
| TypeDeclaration(baseName: 'B', isNullable: false, associatedProxyApi: b), |
| }; |
| b.interfaces = <TypeDeclaration>{ |
| TypeDeclaration(baseName: 'C', isNullable: false, associatedProxyApi: c), |
| }; |
| c.interfaces = <TypeDeclaration>{ |
| TypeDeclaration(baseName: 'A', isNullable: false, associatedProxyApi: a), |
| }; |
| |
| expect(() => a.apisOfInterfaces(), throwsArgumentError); |
| }); |
| } |