| // 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/kotlin_generator.dart'; |
| import 'package:test/test.dart'; |
| |
| const String DEFAULT_PACKAGE_NAME = 'test_package'; |
| |
| final Class emptyClass = Class(name: 'className', fields: <NamedType>[ |
| NamedType( |
| name: 'namedTypeName', |
| type: const TypeDeclaration(baseName: 'baseName', isNullable: false), |
| ) |
| ]); |
| |
| final Enum emptyEnum = Enum( |
| name: 'enumName', |
| members: <EnumMember>[EnumMember(name: 'enumMemberName')], |
| ); |
| |
| void main() { |
| test('gen one class', () { |
| final Class classDefinition = Class( |
| name: 'Foobar', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| name: 'field1', |
| ), |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[classDefinition], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('data class Foobar (')); |
| expect(code, contains('val field1: Long? = null')); |
| expect(code, contains('fun fromList(__pigeon_list: List<Any?>): Foobar')); |
| expect(code, contains('fun toList(): List<Any?>')); |
| }); |
| |
| test('gen one enum', () { |
| final Enum anEnum = Enum( |
| name: 'Foobar', |
| members: <EnumMember>[ |
| EnumMember(name: 'one'), |
| EnumMember(name: 'two'), |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[], |
| enums: <Enum>[anEnum], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('enum class Foobar(val raw: Int) {')); |
| expect(code, contains('ONE(0)')); |
| expect(code, contains('TWO(1)')); |
| }); |
| |
| test('gen class with enum', () { |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[ |
| Class( |
| name: 'Bar', |
| fields: <NamedType>[ |
| NamedType( |
| name: 'field1', |
| type: TypeDeclaration( |
| baseName: 'Foo', |
| isNullable: false, |
| associatedEnum: emptyEnum, |
| ), |
| ), |
| NamedType( |
| name: 'field2', |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: false, |
| ), |
| ), |
| ], |
| ), |
| ], |
| enums: <Enum>[ |
| Enum( |
| name: 'Foo', |
| members: <EnumMember>[ |
| EnumMember(name: 'one'), |
| EnumMember(name: 'two'), |
| ], |
| ), |
| ], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('enum class Foo(val raw: Int) {')); |
| expect(code, contains('data class Bar (')); |
| expect(code, contains('val field1: Foo,')); |
| expect(code, contains('val field2: String')); |
| expect(code, contains('fun fromList(__pigeon_list: List<Any?>): Bar')); |
| expect(code, contains('Foo.ofRaw(it)')); |
| expect(code, contains('val field1 = __pigeon_list[0] as Foo')); |
| expect(code, contains('val field2 = __pigeon_list[1] as String\n')); |
| expect(code, contains('fun toList(): List<Any?>')); |
| }); |
| |
| test('primitive enum host', () { |
| final Root root = Root(apis: <Api>[ |
| AstHostApi(name: 'Bar', methods: <Method>[ |
| Method( |
| name: 'bar', |
| location: ApiLocation.host, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'foo', |
| type: TypeDeclaration( |
| baseName: 'Foo', |
| isNullable: false, |
| associatedEnum: emptyEnum, |
| )) |
| ]) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[ |
| Enum(name: 'Foo', members: <EnumMember>[ |
| EnumMember(name: 'one'), |
| EnumMember(name: 'two'), |
| ]) |
| ]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('enum class Foo(val raw: Int) {')); |
| expect(code, contains('Foo.ofRaw(it)')); |
| }); |
| |
| test('gen one host api', () { |
| final Root root = Root(apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| location: ApiLocation.host, |
| parameters: <Parameter>[ |
| Parameter( |
| type: TypeDeclaration( |
| baseName: 'Input', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| name: 'input', |
| ) |
| ], |
| returnType: TypeDeclaration( |
| baseName: 'Output', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| ) |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| ) |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('interface Api')); |
| expect(code, contains('fun doSomething(input: Input): Output')); |
| expect(code, contains(''' |
| @JvmOverloads |
| fun setUp(binaryMessenger: BinaryMessenger, api: Api?, messageChannelSuffix: String = "") { |
| ''')); |
| expect(code, contains('channel.setMessageHandler')); |
| expect(code, contains(''' |
| if (api != null) { |
| channel.setMessageHandler { message, reply -> |
| val args = message as List<Any?> |
| val inputArg = args[0] as Input |
| val wrapped: List<Any?> = try { |
| listOf(api.doSomething(inputArg)) |
| } catch (exception: Throwable) { |
| wrapError(exception) |
| } |
| reply.reply(wrapped) |
| } |
| } else { |
| channel.setMessageHandler(null) |
| } |
| ''')); |
| }); |
| |
| test('all the simple datatypes header', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Foobar', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'bool', |
| isNullable: false, |
| ), |
| name: 'aBool', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: false, |
| ), |
| name: 'aInt', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'double', |
| isNullable: false, |
| ), |
| name: 'aDouble', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: false, |
| ), |
| name: 'aString', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Uint8List', |
| isNullable: true, |
| ), |
| name: 'aUint8List', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Int32List', |
| isNullable: false, |
| ), |
| name: 'aInt32List', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Int64List', |
| isNullable: false, |
| ), |
| name: 'aInt64List', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Float64List', |
| isNullable: false, |
| ), |
| name: 'aFloat64List', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'bool', |
| isNullable: true, |
| ), |
| name: 'aNullableBool', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| name: 'aNullableInt', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'double', |
| isNullable: true, |
| ), |
| name: 'aNullableDouble', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'aNullableString', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Uint8List', |
| isNullable: true, |
| ), |
| name: 'aNullableUint8List', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Int32List', |
| isNullable: true, |
| ), |
| name: 'aNullableInt32List', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Int64List', |
| isNullable: true, |
| ), |
| name: 'aNullableInt64List', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Float64List', |
| isNullable: true, |
| ), |
| name: 'aNullableFloat64List', |
| ), |
| ]), |
| ], enums: <Enum>[]); |
| |
| final StringBuffer sink = StringBuffer(); |
| |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('val aBool: Boolean')); |
| expect(code, contains('val aInt: Long')); |
| expect(code, contains('val aDouble: Double')); |
| expect(code, contains('val aString: String')); |
| expect(code, contains('val aUint8List: ByteArray')); |
| expect(code, contains('val aInt32List: IntArray')); |
| expect(code, contains('val aInt64List: LongArray')); |
| expect(code, contains('val aFloat64List: DoubleArray')); |
| expect( |
| code, |
| contains( |
| 'val aInt = __pigeon_list[1].let { num -> if (num is Int) num.toLong() else num as Long }')); |
| expect(code, contains('val aNullableBool: Boolean? = null')); |
| expect(code, contains('val aNullableInt: Long? = null')); |
| expect(code, contains('val aNullableDouble: Double? = null')); |
| expect(code, contains('val aNullableString: String? = null')); |
| expect(code, contains('val aNullableUint8List: ByteArray? = null')); |
| expect(code, contains('val aNullableInt32List: IntArray? = null')); |
| expect(code, contains('val aNullableInt64List: LongArray? = null')); |
| expect(code, contains('val aNullableFloat64List: DoubleArray? = null')); |
| expect( |
| code, |
| contains( |
| 'val aNullableInt = __pigeon_list[9].let { num -> if (num is Int) num.toLong() else num as Long? }')); |
| }); |
| |
| test('gen one flutter api', () { |
| final Root root = Root(apis: <Api>[ |
| AstFlutterApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| location: ApiLocation.flutter, |
| parameters: <Parameter>[ |
| Parameter( |
| type: TypeDeclaration( |
| baseName: 'Input', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| name: '', |
| ) |
| ], |
| returnType: TypeDeclaration( |
| baseName: 'Output', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| ) |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| ) |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| 'class Api(private val binaryMessenger: BinaryMessenger, private val messageChannelSuffix: String = "")')); |
| expect(code, matches('fun doSomething.*Input.*Output')); |
| }); |
| |
| test('gen host void api', () { |
| final Root root = Root(apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| location: ApiLocation.host, |
| parameters: <Parameter>[ |
| Parameter( |
| type: TypeDeclaration( |
| baseName: 'Input', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| name: '', |
| ) |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| ) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, isNot(matches('.*doSomething(.*) ->'))); |
| expect(code, matches('doSomething(.*)')); |
| }); |
| |
| test('gen flutter void return api', () { |
| final Root root = Root(apis: <Api>[ |
| AstFlutterApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| location: ApiLocation.flutter, |
| parameters: <Parameter>[ |
| Parameter( |
| type: TypeDeclaration( |
| baseName: 'Input', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| name: '', |
| ) |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| ) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('callback: (Result<Unit>) -> Unit')); |
| expect(code, contains('callback(Result.success(Unit))')); |
| // Lines should not end in semicolons. |
| expect(code, isNot(contains(RegExp(r';\n')))); |
| }); |
| |
| test('gen host void argument api', () { |
| final Root root = Root(apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| location: ApiLocation.host, |
| parameters: <Parameter>[], |
| returnType: TypeDeclaration( |
| baseName: 'Output', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| ) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('fun doSomething(): Output')); |
| expect(code, contains('listOf(api.doSomething())')); |
| expect(code, contains('wrapError(exception)')); |
| expect(code, contains('reply(wrapped)')); |
| }); |
| |
| test('gen flutter void argument api', () { |
| final Root root = Root(apis: <Api>[ |
| AstFlutterApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| location: ApiLocation.flutter, |
| parameters: <Parameter>[], |
| returnType: TypeDeclaration( |
| baseName: 'Output', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| ) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect( |
| code, contains('fun doSomething(callback: (Result<Output>) -> Unit)')); |
| expect(code, contains('channel.send(null)')); |
| }); |
| |
| test('gen list', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Foobar', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: true, |
| ), |
| name: 'field1', |
| ) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('data class Foobar')); |
| expect(code, contains('val field1: List<Any?>? = null')); |
| }); |
| |
| test('gen map', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Foobar', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Map', |
| isNullable: true, |
| ), |
| name: 'field1', |
| ) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('data class Foobar')); |
| expect(code, contains('val field1: Map<Any, Any?>? = null')); |
| }); |
| |
| test('gen nested', () { |
| final Class classDefinition = Class( |
| name: 'Outer', |
| fields: <NamedType>[ |
| NamedType( |
| type: TypeDeclaration( |
| baseName: 'Nested', |
| associatedClass: emptyClass, |
| isNullable: true, |
| ), |
| name: 'nested', |
| ) |
| ], |
| ); |
| final Class nestedClass = Class( |
| name: 'Nested', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| name: 'data', |
| ) |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[classDefinition, nestedClass], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('data class Outer')); |
| expect(code, contains('data class Nested')); |
| expect(code, contains('val nested: Nested? = null')); |
| expect(code, contains('fun fromList(__pigeon_list: List<Any?>): Outer')); |
| expect(code, contains('val nested = __pigeon_list[0] as Nested?')); |
| expect(code, contains('fun toList(): List<Any?>')); |
| }); |
| |
| test('gen one async Host Api', () { |
| final Root root = Root(apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| location: ApiLocation.host, |
| parameters: <Parameter>[ |
| Parameter( |
| type: TypeDeclaration( |
| baseName: 'Input', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| name: 'arg', |
| ) |
| ], |
| returnType: TypeDeclaration( |
| baseName: 'Output', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| isAsynchronous: true, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| ) |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| ) |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('interface Api')); |
| expect(code, contains('api.doSomething(argArg) {')); |
| expect(code, contains('reply.reply(wrapResult(data))')); |
| }); |
| |
| test('gen one async Flutter Api', () { |
| final Root root = Root(apis: <Api>[ |
| AstFlutterApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| location: ApiLocation.flutter, |
| parameters: <Parameter>[ |
| Parameter( |
| type: TypeDeclaration( |
| baseName: 'Input', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| name: '', |
| ) |
| ], |
| returnType: TypeDeclaration( |
| baseName: 'Output', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| isAsynchronous: true, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| ) |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| ) |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('class Api')); |
| expect(code, matches('fun doSomething.*Input.*callback.*Output.*Unit')); |
| }); |
| |
| test('gen one enum class', () { |
| final Enum anEnum = Enum( |
| name: 'SampleEnum', |
| members: <EnumMember>[ |
| EnumMember(name: 'sampleVersion'), |
| EnumMember(name: 'sampleTest'), |
| ], |
| ); |
| final Class classDefinition = Class( |
| name: 'EnumClass', |
| fields: <NamedType>[ |
| NamedType( |
| type: TypeDeclaration( |
| baseName: 'SampleEnum', |
| associatedEnum: emptyEnum, |
| isNullable: true, |
| ), |
| name: 'sampleEnum', |
| ), |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[classDefinition], |
| enums: <Enum>[anEnum], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('enum class SampleEnum(val raw: Int)')); |
| expect(code, contains('SAMPLE_VERSION(0)')); |
| expect(code, contains('SAMPLE_TEST(1)')); |
| }); |
| |
| Iterable<String> makeIterable(String string) sync* { |
| yield string; |
| } |
| |
| test('header', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| final KotlinOptions kotlinOptions = KotlinOptions( |
| copyrightHeader: makeIterable('hello world'), |
| ); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, startsWith('// hello world')); |
| }); |
| |
| test('generics - list', () { |
| final Class classDefinition = Class( |
| name: 'Foobar', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: true, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| name: 'field1', |
| ), |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[classDefinition], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('data class Foobar')); |
| expect(code, contains('val field1: List<Long?>')); |
| }); |
| |
| test('generics - maps', () { |
| final Class classDefinition = Class( |
| name: 'Foobar', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Map', |
| isNullable: true, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'String', isNullable: true), |
| TypeDeclaration(baseName: 'String', isNullable: true), |
| ]), |
| name: 'field1', |
| ), |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[classDefinition], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('data class Foobar')); |
| expect(code, contains('val field1: Map<String?, String?>')); |
| }); |
| |
| test('host generics argument', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doit', |
| location: ApiLocation.host, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| type: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: false, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| name: 'arg', |
| ) |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('fun doit(arg: List<Long?>')); |
| }); |
| |
| test('flutter generics argument', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstFlutterApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doit', |
| location: ApiLocation.flutter, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| type: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: false, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| name: 'arg', |
| ) |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('fun doit(argArg: List<Long?>')); |
| }); |
| |
| test('host generics return', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doit', |
| location: ApiLocation.host, |
| returnType: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: false, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| parameters: <Parameter>[]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('fun doit(): List<Long?>')); |
| expect(code, contains('listOf(api.doit())')); |
| expect(code, contains('reply.reply(wrapped)')); |
| }); |
| |
| test('flutter generics return', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstFlutterApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doit', |
| location: ApiLocation.flutter, |
| returnType: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: false, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| parameters: <Parameter>[]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('fun doit(callback: (Result<List<Long?>>) -> Unit)')); |
| expect(code, contains('val output = it[0] as List<Long?>')); |
| expect(code, contains('callback(Result.success(output))')); |
| }); |
| |
| test('host multiple args', () { |
| final Root root = Root(apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'add', |
| location: ApiLocation.host, |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'x', |
| type: |
| const TypeDeclaration(isNullable: false, baseName: 'int')), |
| Parameter( |
| name: 'y', |
| type: |
| const TypeDeclaration(isNullable: false, baseName: 'int')), |
| ], |
| returnType: const TypeDeclaration(baseName: 'int', isNullable: false), |
| ) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('fun add(x: Long, y: Long): Long')); |
| expect(code, contains('val args = message as List<Any?>')); |
| expect( |
| code, |
| contains( |
| 'val xArg = args[0].let { num -> if (num is Int) num.toLong() else num as Long }')); |
| expect( |
| code, |
| contains( |
| 'val yArg = args[1].let { num -> if (num is Int) num.toLong() else num as Long }')); |
| expect(code, contains('listOf(api.add(xArg, yArg))')); |
| expect(code, contains('reply.reply(wrapped)')); |
| }); |
| |
| test('flutter multiple args', () { |
| final Root root = Root(apis: <Api>[ |
| AstFlutterApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'add', |
| location: ApiLocation.flutter, |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'x', |
| type: |
| const TypeDeclaration(baseName: 'int', isNullable: false)), |
| Parameter( |
| name: 'y', |
| type: |
| const TypeDeclaration(baseName: 'int', isNullable: false)), |
| ], |
| returnType: const TypeDeclaration(baseName: 'int', isNullable: false), |
| ) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('val channel = BasicMessageChannel')); |
| expect( |
| code, |
| contains( |
| 'val output = it[0].let { num -> if (num is Int) num.toLong() else num as Long }'), |
| ); |
| expect(code, contains('callback(Result.success(output))')); |
| expect( |
| code, |
| contains( |
| 'fun add(xArg: Long, yArg: Long, callback: (Result<Long>) -> Unit)')); |
| expect(code, contains('channel.send(listOf(xArg, yArg)) {')); |
| }); |
| |
| test('return nullable host', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doit', |
| location: ApiLocation.host, |
| returnType: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| parameters: <Parameter>[]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('fun doit(): Long?')); |
| }); |
| |
| test('return nullable host async', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doit', |
| location: ApiLocation.host, |
| returnType: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| isAsynchronous: true, |
| parameters: <Parameter>[]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('fun doit(callback: (Result<Long?>) -> Unit')); |
| }); |
| |
| test('nullable argument host', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doit', |
| location: ApiLocation.host, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'foo', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| )), |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| 'val fooArg = args[0].let { num -> if (num is Int) num.toLong() else num as Long? }')); |
| }); |
| |
| test('nullable argument flutter', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstFlutterApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doit', |
| location: ApiLocation.flutter, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'foo', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| )), |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains('fun doit(fooArg: Long?, callback: (Result<Unit>) -> Unit)'), |
| ); |
| }); |
| |
| test('nonnull fields', () { |
| final Root root = Root(apis: <Api>[ |
| AstHostApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| location: ApiLocation.host, |
| parameters: <Parameter>[ |
| Parameter( |
| type: TypeDeclaration( |
| baseName: 'Input', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| name: '', |
| ) |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: false, |
| ), |
| name: 'input', |
| ) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('val input: String\n')); |
| }); |
| |
| test('transfers documentation comments', () { |
| final List<String> comments = <String>[ |
| ' api comment', |
| ' api method comment', |
| ' class comment', |
| ' class field comment', |
| ' enum comment', |
| ' enum member comment', |
| ]; |
| int count = 0; |
| |
| final List<String> unspacedComments = <String>['////////']; |
| int unspacedCount = 0; |
| |
| final Root root = Root( |
| apis: <Api>[ |
| AstFlutterApi( |
| name: 'api', |
| documentationComments: <String>[comments[count++]], |
| methods: <Method>[ |
| Method( |
| name: 'method', |
| location: ApiLocation.flutter, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| documentationComments: <String>[comments[count++]], |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'field', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| ), |
| ], |
| ) |
| ], |
| ) |
| ], |
| classes: <Class>[ |
| Class( |
| name: 'class', |
| documentationComments: <String>[comments[count++]], |
| fields: <NamedType>[ |
| NamedType( |
| documentationComments: <String>[comments[count++]], |
| type: const TypeDeclaration( |
| baseName: 'Map', |
| isNullable: true, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'String', isNullable: true), |
| TypeDeclaration(baseName: 'int', isNullable: true), |
| ]), |
| name: 'field1', |
| ), |
| ], |
| ), |
| ], |
| enums: <Enum>[ |
| Enum( |
| name: 'enum', |
| documentationComments: <String>[ |
| comments[count++], |
| unspacedComments[unspacedCount++] |
| ], |
| members: <EnumMember>[ |
| EnumMember( |
| name: 'one', |
| documentationComments: <String>[comments[count++]], |
| ), |
| EnumMember(name: 'two'), |
| ], |
| ), |
| ], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| for (final String comment in comments) { |
| // This regex finds the comment only between the open and close comment block |
| expect( |
| RegExp(r'(?<=\/\*\*.*?)' + comment + r'(?=.*?\*\/)', dotAll: true) |
| .hasMatch(code), |
| true); |
| } |
| expect(code, isNot(contains('*//'))); |
| }); |
| |
| test('creates custom codecs', () { |
| final Root root = Root(apis: <Api>[ |
| AstFlutterApi(name: 'Api', methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| location: ApiLocation.flutter, |
| parameters: <Parameter>[ |
| Parameter( |
| type: TypeDeclaration( |
| baseName: 'Input', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| name: '') |
| ], |
| returnType: TypeDeclaration( |
| baseName: 'Output', |
| associatedClass: emptyClass, |
| isNullable: false, |
| ), |
| isAsynchronous: true, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input') |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output') |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains(' : StandardMessageCodec() ')); |
| }); |
| |
| test('creates api error class for custom errors', () { |
| final Method method = Method( |
| name: 'doSomething', |
| location: ApiLocation.host, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[]); |
| final AstHostApi api = |
| AstHostApi(name: 'SomeApi', methods: <Method>[method]); |
| final Root root = Root( |
| apis: <Api>[api], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = |
| KotlinOptions(errorClassName: 'SomeError'); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('class SomeError')); |
| expect(code, contains('if (exception is SomeError)')); |
| expect(code, contains('exception.code,')); |
| expect(code, contains('exception.message,')); |
| expect(code, contains('exception.details')); |
| }); |
| |
| test('connection error contains channel name', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstFlutterApi( |
| name: 'Api', |
| methods: <Method>[ |
| Method( |
| name: 'method', |
| location: ApiLocation.flutter, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'field', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| ), |
| ], |
| ) |
| ], |
| ) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| 'return FlutterError("channel-error", "Unable to establish connection on channel: \'\$channelName\'.", "")')); |
| expect( |
| code, |
| contains( |
| 'callback(Result.failure(createConnectionError(channelName)))')); |
| }); |
| |
| test('gen host uses default error class', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstHostApi( |
| name: 'Api', |
| methods: <Method>[ |
| Method( |
| name: 'method', |
| location: ApiLocation.host, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'field', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| ), |
| ], |
| ) |
| ], |
| ) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('FlutterError')); |
| }); |
| |
| test('gen flutter uses default error class', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstFlutterApi( |
| name: 'Api', |
| methods: <Method>[ |
| Method( |
| name: 'method', |
| location: ApiLocation.flutter, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'field', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| ), |
| ], |
| ) |
| ], |
| ) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const KotlinOptions kotlinOptions = KotlinOptions(); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains('FlutterError')); |
| }); |
| |
| test('gen host uses error class', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstHostApi( |
| name: 'Api', |
| methods: <Method>[ |
| Method( |
| name: 'method', |
| location: ApiLocation.host, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'field', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| ), |
| ], |
| ) |
| ], |
| ) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const String errorClassName = 'FooError'; |
| const KotlinOptions kotlinOptions = |
| KotlinOptions(errorClassName: errorClassName); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains(errorClassName)); |
| expect(code, isNot(contains('FlutterError'))); |
| }); |
| |
| test('gen flutter uses error class', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstFlutterApi( |
| name: 'Api', |
| methods: <Method>[ |
| Method( |
| name: 'method', |
| location: ApiLocation.flutter, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'field', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| ), |
| ], |
| ) |
| ], |
| ) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const String errorClassName = 'FooError'; |
| const KotlinOptions kotlinOptions = |
| KotlinOptions(errorClassName: errorClassName); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| final String code = sink.toString(); |
| expect(code, contains(errorClassName)); |
| expect(code, isNot(contains('FlutterError'))); |
| }); |
| |
| test('do not generate duplicated entries in writeValue', () { |
| final Root root = Root( |
| apis: <Api>[ |
| AstHostApi( |
| name: 'FooBar', |
| methods: <Method>[ |
| Method( |
| name: 'fooBar', |
| location: ApiLocation.host, |
| returnType: const TypeDeclaration.voidDeclaration(), |
| parameters: <Parameter>[ |
| Parameter( |
| name: 'bar', |
| type: const TypeDeclaration( |
| baseName: 'Bar', |
| isNullable: false, |
| ), |
| ), |
| ], |
| ) |
| ], |
| ) |
| ], |
| classes: <Class>[ |
| Class( |
| name: 'Foo', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: false, |
| ), |
| name: 'foo', |
| ), |
| ], |
| ), |
| Class( |
| name: 'Bar', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Foo', |
| isNullable: false, |
| ), |
| name: 'foo', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Foo', |
| isNullable: true, |
| ), |
| name: 'foo2', |
| ), |
| ], |
| ), |
| ], |
| enums: <Enum>[], |
| ); |
| |
| final StringBuffer sink = StringBuffer(); |
| const String errorClassName = 'FooError'; |
| const KotlinOptions kotlinOptions = |
| KotlinOptions(errorClassName: errorClassName); |
| const KotlinGenerator generator = KotlinGenerator(); |
| generator.generate( |
| kotlinOptions, |
| root, |
| sink, |
| dartPackageName: DEFAULT_PACKAGE_NAME, |
| ); |
| |
| final String code = sink.toString(); |
| |
| // Extract override fun writeValue block |
| final int blockStart = code.indexOf('override fun writeValue'); |
| expect(blockStart, isNot(-1)); |
| final int blockEnd = code.indexOf('super.writeValue', blockStart); |
| expect(blockEnd, isNot(-1)); |
| final String writeValueBlock = code.substring(blockStart, blockEnd); |
| |
| // Count the occurrence of 'is Foo' in the block |
| int count = 0; |
| int index = 0; |
| while (index != -1) { |
| index = writeValueBlock.indexOf('is Foo', index); |
| if (index != -1) { |
| count++; |
| index += 'is Foo'.length; |
| } |
| } |
| |
| // There should be only one occurrence of 'is Foo' in the block |
| expect(count, 1); |
| }); |
| } |