| // 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/dart_generator.dart'; |
| import 'package:pigeon/generator_tools.dart'; |
| import 'package:test/test.dart'; |
| |
| void main() { |
| test('gen one class', () { |
| final Class klass = Class( |
| name: 'Foobar', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'dataType1', |
| isNullable: true, |
| ), |
| name: 'field1', |
| offset: null), |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[klass], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('class Foobar')); |
| expect(code, contains(' dataType1 field1;')); |
| }); |
| |
| test('gen one enum', () { |
| final Enum anEnum = Enum( |
| name: 'Foobar', |
| members: <String>[ |
| 'one', |
| 'two', |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[], |
| enums: <Enum>[anEnum], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('enum Foobar')); |
| expect(code, contains(' one,')); |
| expect(code, contains(' two,')); |
| }); |
| |
| test('gen one host api', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Input', |
| isNullable: false, |
| ), |
| name: 'input', |
| offset: null) |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', isNullable: false), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| offset: null) |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| offset: null) |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('class Api')); |
| expect(code, contains('Future<Output> doSomething(Input arg_input)')); |
| }); |
| |
| test('host multiple args', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'add', |
| arguments: <NamedType>[ |
| NamedType( |
| name: 'x', |
| type: |
| const TypeDeclaration(isNullable: false, baseName: 'int')), |
| NamedType( |
| name: 'y', |
| type: |
| const TypeDeclaration(isNullable: false, baseName: 'int')), |
| ], |
| returnType: const TypeDeclaration(baseName: 'int', isNullable: false), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('class Api')); |
| expect(code, contains('Future<int> add(int arg_x, int arg_y)')); |
| expect(code, contains('await channel.send(<Object>[arg_x, arg_y])')); |
| }); |
| |
| test('flutter multiple args', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'add', |
| arguments: <NamedType>[ |
| NamedType( |
| name: 'x', |
| type: |
| const TypeDeclaration(isNullable: false, baseName: 'int')), |
| NamedType( |
| name: 'y', |
| type: |
| const TypeDeclaration(isNullable: false, baseName: 'int')), |
| ], |
| returnType: const TypeDeclaration(baseName: 'int', isNullable: false), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('class Api')); |
| expect(code, contains('int add(int x, int y)')); |
| expect(code, |
| contains('final List<Object?> args = (message as List<Object?>?)!')); |
| expect(code, contains('final int? arg_x = (args[0] as int?)')); |
| expect(code, contains('final int? arg_y = (args[1] as int?)')); |
| expect(code, contains('final int output = api.add(arg_x!, arg_y!)')); |
| }); |
| |
| test('nested class', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class( |
| name: 'Input', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| offset: null) |
| ], |
| ), |
| Class( |
| name: 'Nested', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Input', |
| isNullable: true, |
| ), |
| name: 'nested', |
| offset: null) |
| ], |
| ) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| 'pigeonMap[\'nested\'] = nested == null ? null : nested.encode()', |
| ), |
| ); |
| expect( |
| code.replaceAll('\n', ' ').replaceAll(' ', ''), |
| contains( |
| 'nested: pigeonMap[\'nested\'] != null ? Input.decode(pigeonMap[\'nested\']) : null', |
| ), |
| ); |
| }); |
| |
| test('flutterapi', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Input', |
| isNullable: false, |
| ), |
| name: 'input', |
| offset: null) |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', isNullable: false), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| offset: null) |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| offset: null) |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('abstract class Api')); |
| expect(code, contains('static void setup(Api')); |
| expect(code, contains('Output doSomething(Input input)')); |
| }); |
| |
| test('host void', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Input', |
| isNullable: false, |
| ), |
| name: '', |
| offset: null) |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| offset: null) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('Future<void> doSomething')); |
| expect(code, contains('return;')); |
| }); |
| |
| test('flutter void return', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Input', |
| isNullable: false, |
| ), |
| name: '', |
| offset: null) |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| offset: null) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| // The next line verifies that we're not setting a variable to the value of "doSomething", but |
| // ignores the line where we assert the value of the argument isn't null, since on that line |
| // we mention "doSomething" in the assertion message. |
| expect(code, isNot(matches('[^!]=.*doSomething'))); |
| expect(code, contains('doSomething(')); |
| }); |
| |
| test('flutter void argument', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', isNullable: false), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| offset: null) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, matches('output.*=.*doSomething[(][)]')); |
| expect(code, contains('Output doSomething();')); |
| }); |
| |
| test('flutter enum argument with enum class', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'EnumClass', |
| isNullable: false, |
| ), |
| name: '', |
| offset: null) |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'EnumClass', isNullable: false), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'EnumClass', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Enum', |
| isNullable: true, |
| ), |
| name: 'enum1', |
| offset: null) |
| ]), |
| ], enums: <Enum>[ |
| Enum( |
| name: 'Enum', |
| members: <String>[ |
| 'one', |
| 'two', |
| ], |
| ) |
| ]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, |
| contains('pigeonMap[\'enum1\'] = enum1 == null ? null : enum1.index;')); |
| expect(code, contains('? Enum.values[pigeonMap[\'enum1\'] as int]')); |
| expect(code, contains('EnumClass doSomething(EnumClass arg0);')); |
| }); |
| |
| test('flutter enum argument with enum class nullsafe', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'EnumClass', |
| isNullable: false, |
| ), |
| name: '', |
| offset: null) |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'EnumClass', isNullable: false), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'EnumClass', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Enum', |
| isNullable: true, |
| ), |
| name: 'enum1', |
| offset: null) |
| ]), |
| ], enums: <Enum>[ |
| Enum( |
| name: 'Enum', |
| members: <String>[ |
| 'one', |
| 'two', |
| ], |
| ) |
| ]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| 'pigeonMap[\'enum1\'] = enum1 == null ? null : enum1!.index;')); |
| expect(code, contains('? Enum.values[pigeonMap[\'enum1\']! as int]')); |
| expect(code, contains('EnumClass doSomething(EnumClass arg0);')); |
| }); |
| |
| test('host void argument', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', isNullable: false), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| offset: null) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, matches('channel.send[(]null[)]')); |
| }); |
| |
| test('mock dart handler', () { |
| final Root root = Root(apis: <Api>[ |
| Api( |
| name: 'Api', |
| location: ApiLocation.host, |
| dartHostTestHandler: 'ApiMock', |
| methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Input', |
| isNullable: false, |
| ), |
| name: '', |
| offset: null) |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', isNullable: false), |
| isAsynchronous: false, |
| ), |
| Method( |
| name: 'voidReturner', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Input', |
| isNullable: false, |
| ), |
| name: '', |
| offset: null) |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| isAsynchronous: false, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| offset: null) |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| offset: null) |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer mainCodeSink = StringBuffer(); |
| final StringBuffer testCodeSink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, mainCodeSink); |
| final String mainCode = mainCodeSink.toString(); |
| expect(mainCode, isNot(contains('import \'fo\\\'o.dart\';'))); |
| expect(mainCode, contains('class Api {')); |
| expect(mainCode, isNot(contains('abstract class ApiMock'))); |
| expect(mainCode, isNot(contains('.ApiMock.doSomething'))); |
| expect(mainCode, isNot(contains('\'${Keys.result}\': output'))); |
| expect(mainCode, isNot(contains('return <Object, Object>{};'))); |
| generateTestDart( |
| const DartOptions(isNullSafe: false), root, testCodeSink, "fo'o.dart"); |
| final String testCode = testCodeSink.toString(); |
| expect(testCode, contains('import \'fo\\\'o.dart\';')); |
| expect(testCode, isNot(contains('class Api {'))); |
| expect(testCode, contains('abstract class ApiMock')); |
| expect(testCode, isNot(contains('.ApiMock.doSomething'))); |
| expect(testCode, contains('\'${Keys.result}\': output')); |
| expect(testCode, contains('return <Object, Object>{};')); |
| }); |
| |
| test('opt out of nndb', () { |
| final Class klass = Class( |
| name: 'Foobar', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'dataType1', |
| isNullable: true, |
| ), |
| name: 'field1', |
| offset: null), |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[klass], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('// @dart = 2.8')); |
| }); |
| |
| test('gen one async Flutter Api', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Input', |
| isNullable: false, |
| ), |
| name: '', |
| offset: null) |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', isNullable: false), |
| isAsynchronous: true, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| offset: null) |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| offset: null) |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('abstract class Api')); |
| expect(code, contains('Future<Output> doSomething(Input arg0);')); |
| expect( |
| code, contains('final Output output = await api.doSomething(arg0);')); |
| }); |
| |
| test('gen one async Flutter Api with void return', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Input', |
| isNullable: false, |
| ), |
| name: '', |
| offset: null) |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| isAsynchronous: true, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| offset: null) |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| offset: null) |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, isNot(matches('=.s*doSomething'))); |
| expect(code, contains('await api.doSomething(')); |
| expect(code, isNot(contains('._toMap()'))); |
| }); |
| |
| test('gen one async Host Api', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Input', |
| isNullable: false, |
| ), |
| name: '', |
| offset: null) |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', isNullable: false), |
| isAsynchronous: true, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'input', |
| offset: null) |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| offset: null) |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('class Api')); |
| expect(code, matches('Output.*doSomething.*Input')); |
| }); |
| |
| test('async host void argument', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', isNullable: false), |
| isAsynchronous: true, |
| ) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output', |
| offset: null) |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: false), root, sink); |
| final String code = sink.toString(); |
| expect(code, matches('channel.send[(]null[)]')); |
| }); |
| |
| Iterable<String> _makeIterable(String string) sync* { |
| yield string; |
| } |
| |
| test('header', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| generateDart( |
| DartOptions( |
| isNullSafe: false, copyrightHeader: _makeIterable('hello world')), |
| root, |
| sink, |
| ); |
| final String code = sink.toString(); |
| expect(code, startsWith('// hello world')); |
| }); |
| |
| test('generics', () { |
| final Class klass = Class( |
| name: 'Foobar', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: true, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| name: 'field1', |
| offset: null), |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[klass], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('class Foobar')); |
| expect(code, contains(' List<int?>? field1;')); |
| }); |
| |
| test('map generics', () { |
| final Class klass = Class( |
| name: 'Foobar', |
| fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Map', |
| isNullable: true, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'String', isNullable: true), |
| TypeDeclaration(baseName: 'int', isNullable: true), |
| ]), |
| name: 'field1', |
| offset: null), |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[klass], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('class Foobar')); |
| expect(code, contains(' Map<String?, int?>? field1;')); |
| }); |
| |
| test('host generics argument', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration.voidDeclaration(), |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: false, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| name: 'arg', |
| offset: null) |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('doit(List<int?> arg')); |
| }); |
| |
| test('flutter generics argument with void return', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration.voidDeclaration(), |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: false, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| name: 'arg', |
| offset: null) |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('doit(List<int?> arg')); |
| }); |
| |
| test('host generics return', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: false, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| arguments: <NamedType>[]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('Future<List<int?>> doit(')); |
| expect( |
| code, |
| contains( |
| 'return (replyMap[\'result\'] as List<Object?>?)!.cast<int?>();')); |
| }); |
| |
| test('flutter generics argument non void return', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: false, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'List', |
| isNullable: false, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'int', isNullable: true) |
| ]), |
| name: 'foo', |
| offset: null) |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('List<int?> doit(')); |
| expect( |
| code, |
| contains( |
| 'final List<int?>? arg_foo = (args[0] as List<Object?>?)?.cast<int?>()')); |
| expect(code, contains('final List<int?> output = api.doit(arg_foo!)')); |
| }); |
| |
| test('return nullable host', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| arguments: <NamedType>[]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('Future<int?> doit()')); |
| expect(code, contains('return (replyMap[\'result\'] as int?);')); |
| }); |
| |
| test('return nullable async host', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| arguments: <NamedType>[], |
| isAsynchronous: true) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('Future<int?> doit()')); |
| expect(code, contains('return (replyMap[\'result\'] as int?);')); |
| }); |
| |
| test('return nullable flutter', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| arguments: <NamedType>[]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('int? doit();')); |
| expect(code, contains('final int? output = api.doit();')); |
| }); |
| |
| test('return nullable async flutter', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| arguments: <NamedType>[], |
| isAsynchronous: true) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('Future<int?> doit();')); |
| expect(code, contains('final int? output = await api.doit();')); |
| }); |
| |
| test('platform error for return nil on nonnull', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: false, |
| ), |
| arguments: <NamedType>[]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| generateDart(const DartOptions(isNullSafe: true), root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| 'Host platform returned null value for non-null return value.')); |
| }); |
| } |