| // 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:pigeon/objc_generator.dart'; |
| import 'package:pigeon/pigeon_lib.dart'; |
| import 'package:test/test.dart'; |
| |
| void main() { |
| test('gen one class header', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Foobar', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'field1') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@interface Foobar')); |
| expect(code, matches('@property.*NSString.*field1')); |
| }); |
| |
| test('gen one class source', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Foobar', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'field1') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('#import "foo.h"')); |
| expect(code, contains('@implementation Foobar')); |
| }); |
| |
| test('gen one enum header', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[], enums: <Enum>[ |
| Enum( |
| name: 'Enum1', |
| members: <EnumMember>[ |
| EnumMember(name: 'one'), |
| EnumMember(name: 'two'), |
| ], |
| ) |
| ]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('typedef NS_ENUM(NSUInteger, Enum1) {')); |
| expect(code, contains(' Enum1One = 0,')); |
| expect(code, contains(' Enum1Two = 1,')); |
| }); |
| |
| test('gen one enum header with prefix', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[], enums: <Enum>[ |
| Enum( |
| name: 'Enum1', |
| members: <EnumMember>[ |
| EnumMember(name: 'one'), |
| EnumMember(name: 'two'), |
| ], |
| ) |
| ]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(prefix: 'PREFIX'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('typedef NS_ENUM(NSUInteger, PREFIXEnum1) {')); |
| expect(code, contains(' PREFIXEnum1One = 0,')); |
| expect(code, contains(' PREFIXEnum1Two = 1,')); |
| }); |
| |
| test('gen one class source with enum', () { |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[ |
| Class( |
| name: 'Foobar', |
| fields: <NamedType>[ |
| NamedType( |
| type: |
| const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'field1'), |
| NamedType( |
| type: |
| const TypeDeclaration(baseName: 'Enum1', isNullable: true), |
| name: 'enum1'), |
| ], |
| ), |
| ], |
| enums: <Enum>[ |
| Enum( |
| name: 'Enum1', |
| members: <EnumMember>[ |
| EnumMember(name: 'one'), |
| EnumMember(name: 'two'), |
| ], |
| ) |
| ], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('#import "foo.h"')); |
| expect(code, contains('@implementation Foobar')); |
| expect( |
| code, |
| contains( |
| 'pigeonResult.enum1 = [GetNullableObjectAtIndex(list, 1) integerValue];')); |
| }); |
| |
| test('primitive enum host', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Bar', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'bar', |
| returnType: const TypeDeclaration.voidDeclaration(), |
| arguments: <NamedType>[ |
| NamedType( |
| name: 'foo', |
| type: |
| const TypeDeclaration(baseName: 'Foo', isNullable: false)) |
| ]) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[ |
| Enum(name: 'Foo', members: <EnumMember>[ |
| EnumMember(name: 'one'), |
| EnumMember(name: 'two'), |
| ]) |
| ]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcOptions options = |
| ObjcOptions(headerIncludePath: 'foo.h', prefix: 'AC'); |
| { |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: options, |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('typedef NS_ENUM(NSUInteger, ACFoo)')); |
| expect(code, contains(':(ACFoo)foo error:')); |
| } |
| { |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: options, |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| 'ACFoo arg_foo = [GetNullableObjectAtIndex(args, 0) integerValue];')); |
| } |
| }); |
| |
| test('validate nullable primitive enum', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Bar', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'bar', |
| returnType: const TypeDeclaration.voidDeclaration(), |
| arguments: <NamedType>[ |
| NamedType( |
| name: 'foo', |
| type: |
| const TypeDeclaration(baseName: 'Foo', isNullable: true)) |
| ]) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[ |
| Enum(name: 'Foo', members: <EnumMember>[ |
| EnumMember(name: 'one'), |
| EnumMember(name: 'two'), |
| ]) |
| ]); |
| const ObjcOptions options = ObjcOptions(headerIncludePath: 'foo.h'); |
| final List<Error> errors = validateObjc(options, root); |
| expect(errors.length, 1); |
| expect(errors[0].message, contains('Nullable enum')); |
| }); |
| |
| test('gen one class header with enum', () { |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[ |
| Class( |
| name: 'Foobar', |
| fields: <NamedType>[ |
| NamedType( |
| type: |
| const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'field1'), |
| NamedType( |
| type: |
| const TypeDeclaration(baseName: 'Enum1', isNullable: true), |
| name: 'enum1'), |
| ], |
| ), |
| ], |
| enums: <Enum>[ |
| Enum( |
| name: 'Enum1', |
| members: <EnumMember>[ |
| EnumMember(name: 'one'), |
| EnumMember(name: 'two'), |
| ], |
| ) |
| ], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@property(nonatomic, assign) Enum1 enum1')); |
| }); |
| |
| test('gen one api header', () { |
| 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: '') |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@interface Input')); |
| expect(code, contains('@interface Output')); |
| expect(code, contains('@protocol Api')); |
| expect(code, contains('/// @return `nil` only when `error != nil`.')); |
| expect(code, matches('nullable Output.*doSomething.*Input.*FlutterError')); |
| expect(code, matches('ApiSetup.*<Api>.*_Nullable')); |
| }); |
| |
| test('gen one api source', () { |
| 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: '') |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('#import "foo.h"')); |
| expect(code, contains('@implementation Input')); |
| expect(code, contains('@implementation Output')); |
| expect(code, contains('ApiSetup(')); |
| expect( |
| code, |
| contains( |
| 'NSCAssert([api respondsToSelector:@selector(doSomething:error:)')); |
| }); |
| |
| 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: true), |
| name: 'aBool'), |
| NamedType( |
| type: const TypeDeclaration(baseName: 'int', isNullable: true), |
| name: 'aInt'), |
| NamedType( |
| type: const TypeDeclaration(baseName: 'double', isNullable: true), |
| name: 'aDouble'), |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'aString'), |
| NamedType( |
| type: |
| const TypeDeclaration(baseName: 'Uint8List', isNullable: true), |
| name: 'aUint8List'), |
| NamedType( |
| type: |
| const TypeDeclaration(baseName: 'Int32List', isNullable: true), |
| name: 'aInt32List'), |
| NamedType( |
| type: |
| const TypeDeclaration(baseName: 'Int64List', isNullable: true), |
| name: 'aInt64List'), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Float64List', isNullable: true), |
| name: 'aFloat64List'), |
| ]), |
| ], enums: <Enum>[]); |
| |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@interface Foobar')); |
| expect(code, contains('@class FlutterStandardTypedData;')); |
| expect(code, matches('@property.*strong.*NSNumber.*aBool')); |
| expect(code, matches('@property.*strong.*NSNumber.*aInt')); |
| expect(code, matches('@property.*strong.*NSNumber.*aDouble')); |
| expect(code, matches('@property.*copy.*NSString.*aString')); |
| expect(code, |
| matches('@property.*strong.*FlutterStandardTypedData.*aUint8List')); |
| expect(code, |
| matches('@property.*strong.*FlutterStandardTypedData.*aInt32List')); |
| expect(code, |
| matches('@property.*strong.*FlutterStandardTypedData.*Int64List')); |
| expect(code, |
| matches('@property.*strong.*FlutterStandardTypedData.*Float64List')); |
| }); |
| |
| test('bool source', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Foobar', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'bool', isNullable: true), |
| name: 'aBool'), |
| ]), |
| ], enums: <Enum>[]); |
| |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@implementation Foobar')); |
| expect(code, |
| contains('pigeonResult.aBool = GetNullableObjectAtIndex(list, 0);')); |
| }); |
| |
| test('nested class header', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'input') |
| ]), |
| Class(name: 'Nested', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'Input', isNullable: true), |
| name: 'nested') |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, |
| contains('@property(nonatomic, strong, nullable) Input * nested;')); |
| }); |
| |
| test('nested class source', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'input') |
| ]), |
| Class(name: 'Nested', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'Input', isNullable: true), |
| name: 'nested') |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| 'pigeonResult.nested = [Input nullableFromList:(GetNullableObjectAtIndex(list, 0))];')); |
| expect( |
| code, contains('self.nested ? [self.nested toList] : [NSNull null]')); |
| }); |
| |
| test('prefix class header', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Foobar', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'field1') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@interface ABCFoobar')); |
| }); |
| |
| test('prefix class source', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Foobar', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'field1') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@implementation ABCFoobar')); |
| }); |
| |
| test('prefix nested class header', () { |
| 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: '') |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Nested', isNullable: false)) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'input') |
| ]), |
| Class(name: 'Nested', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'Input', isNullable: true), |
| name: 'nested') |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, matches('property.*ABCInput')); |
| expect(code, matches('ABCNested.*doSomething.*ABCInput')); |
| expect(code, contains('@protocol ABCApi')); |
| }); |
| |
| test('prefix nested class source', () { |
| 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: '') |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Nested', isNullable: false)) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Input', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'input') |
| ]), |
| Class(name: 'Nested', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'Input', isNullable: true), |
| name: 'nested') |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('ABCInput fromList')); |
| expect(code, matches(r'ABCInput.*=.*args.*0.*\;')); |
| expect(code, contains('void ABCApiSetup(')); |
| }); |
| |
| test('gen flutter api header', () { |
| 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: '') |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@interface Api : NSObject')); |
| expect( |
| code, |
| contains( |
| 'initWithBinaryMessenger:(id<FlutterBinaryMessenger>)binaryMessenger;')); |
| expect(code, matches('void.*doSomething.*Input.*Output')); |
| }); |
| |
| test('gen flutter api source', () { |
| 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: '') |
| ], |
| returnType: |
| const TypeDeclaration(baseName: 'Output', 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(headerIncludePath: 'foo.h'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@implementation Api')); |
| expect(code, matches('void.*doSomething.*Input.*Output.*{')); |
| }); |
| |
| test('gen host void header', () { |
| 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: '') |
| ], |
| 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('(void)doSomething:')); |
| }); |
| |
| test('gen host void source', () { |
| 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: '') |
| ], |
| 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, isNot(matches('=.*doSomething'))); |
| expect(code, matches('[.*doSomething:.*]')); |
| expect(code, contains('callback(wrapResult(nil, error))')); |
| }); |
| |
| test('gen flutter void return header', () { |
| 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: '') |
| ], |
| 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('completion:(void (^)(NSError *_Nullable))')); |
| }); |
| |
| test('gen flutter void return source', () { |
| 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: '') |
| ], |
| 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('completion:(void (^)(NSError *_Nullable))')); |
| expect(code, contains('completion(nil)')); |
| }); |
| |
| test('gen host void arg header', () { |
| 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)) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'output') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, matches('ABCOutput.*doSomethingWithError:[(]FlutterError')); |
| }); |
| |
| test('gen host void arg source', () { |
| 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)) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'output') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, matches('output.*=.*api doSomethingWithError:&error')); |
| }); |
| |
| test('gen flutter void arg header', () { |
| 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)) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'output') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '(void)doSomethingWithCompletion:(void (^)(ABCOutput *_Nullable, NSError *_Nullable))completion')); |
| }); |
| |
| test('gen flutter void arg source', () { |
| 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)) |
| ]) |
| ], classes: <Class>[ |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'output') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '(void)doSomethingWithCompletion:(void (^)(ABCOutput *_Nullable, NSError *_Nullable))completion')); |
| expect(code, contains('channel sendMessage:nil')); |
| }); |
| |
| 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@interface Foobar')); |
| expect(code, matches('@property.*NSArray.*field1')); |
| }); |
| |
| 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@interface Foobar')); |
| expect(code, matches('@property.*NSDictionary.*field1')); |
| }); |
| |
| test('gen map field with object', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Foobar', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'Map', |
| isNullable: true, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'String', isNullable: true), |
| TypeDeclaration(baseName: 'Object', isNullable: true), |
| ]), |
| name: 'field1') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@interface Foobar')); |
| expect( |
| code, |
| contains( |
| '@property(nonatomic, strong, nullable) NSDictionary<NSString *, id> *')); |
| }); |
| |
| test('gen map argument with object', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration.voidDeclaration(), |
| arguments: <NamedType>[ |
| NamedType( |
| name: 'foo', |
| type: const TypeDeclaration( |
| baseName: 'Map', |
| isNullable: false, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration(baseName: 'String', isNullable: true), |
| TypeDeclaration(baseName: 'Object', isNullable: true), |
| ])) |
| ]), |
| ]) |
| ], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('(NSDictionary<NSString *, id> *)foo')); |
| }); |
| |
| test('async void (input) HostApi header', () { |
| 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') |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '(void)doSomethingInput:(ABCInput *)input completion:(void (^)(FlutterError *_Nullable))completion')); |
| }); |
| |
| test('async output(input) HostApi header', () { |
| 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') |
| ], |
| 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') |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'output') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '(void)doSomethingInput:(ABCInput *)input completion:(void (^)(ABCOutput *_Nullable, FlutterError *_Nullable))completion')); |
| }); |
| |
| test('async output(void) HostApi header', () { |
| 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') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '(void)doSomethingWithCompletion:(void (^)(ABCOutput *_Nullable, FlutterError *_Nullable))completion')); |
| }); |
| |
| test('async void (void) HostApi header', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| isAsynchronous: true) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '(void)doSomethingWithCompletion:(void (^)(FlutterError *_Nullable))completion')); |
| }); |
| |
| test('async output(input) HostApi source', () { |
| 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: '') |
| ], |
| 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') |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: true), |
| name: 'output') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '[api doSomething:arg0 completion:^(ABCOutput *_Nullable output, FlutterError *_Nullable error) {')); |
| }); |
| |
| test('async void (input) HostApi source', () { |
| 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: 'foo') |
| ], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '[api doSomethingFoo:arg_foo completion:^(FlutterError *_Nullable error) {')); |
| }); |
| |
| test('async void (void) HostApi source', () { |
| final Root root = Root(apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doSomething', |
| arguments: <NamedType>[], |
| returnType: const TypeDeclaration.voidDeclaration(), |
| isAsynchronous: true) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '[api doSomethingWithCompletion:^(FlutterError *_Nullable error) {')); |
| }); |
| |
| test('async output(void) HostApi source', () { |
| 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') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '[api doSomethingWithCompletion:^(ABCOutput *_Nullable output, FlutterError *_Nullable error) {')); |
| }); |
| |
| Iterable<String> makeIterable(String string) sync* { |
| yield string; |
| } |
| |
| test('source copyright', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: ObjcOptions( |
| headerIncludePath: 'foo.h', |
| prefix: 'ABC', |
| copyrightHeader: makeIterable('hello world')), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, startsWith('// hello world')); |
| }); |
| |
| test('header copyright', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: ObjcOptions( |
| headerIncludePath: 'foo.h', |
| prefix: 'ABC', |
| copyrightHeader: makeIterable('hello world')), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, startsWith('// hello world')); |
| }); |
| |
| test('field 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'), |
| ], |
| ); |
| final Root root = Root( |
| apis: <Api>[], |
| classes: <Class>[klass], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('NSArray<NSNumber *> * 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') |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('doitArg:(NSArray<NSNumber *> *)arg')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| 'NSArray<NSNumber *> *arg_arg = GetNullableObjectAtIndex(args, 0)')); |
| } |
| }); |
| |
| test('flutter generics argument', () { |
| 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') |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('doitArg:(NSArray<NSNumber *> *)arg')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('doitArg:(NSArray<NSNumber *> *)arg')); |
| } |
| }); |
| |
| test('host nested generic 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: 'List', |
| isNullable: true, |
| typeArguments: <TypeDeclaration>[ |
| TypeDeclaration( |
| baseName: 'bool', isNullable: true) |
| ]), |
| ]), |
| name: 'arg') |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('doitArg:(NSArray<NSArray<NSNumber *> *> *)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(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, contains('- (nullable NSArray<NSNumber *> *)doitWithError:')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('NSArray<NSNumber *> *output =')); |
| } |
| }); |
| |
| test('flutter generics 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>[]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, contains('doitWithCompletion:(void (^)(NSArray<NSNumber *> *')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, contains('doitWithCompletion:(void (^)(NSArray<NSNumber *> *')); |
| } |
| }); |
| |
| 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), |
| ) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[]); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '- (nullable NSNumber *)addX:(NSNumber *)x y:(NSNumber *)y error:(FlutterError *_Nullable *_Nonnull)error;')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('NSArray *args = message;')); |
| expect(code, |
| contains('NSNumber *arg_x = GetNullableObjectAtIndex(args, 0);')); |
| expect(code, |
| contains('NSNumber *arg_y = GetNullableObjectAtIndex(args, 1);')); |
| expect(code, |
| contains('NSNumber *output = [api addX:arg_x y:arg_y error:&error]')); |
| } |
| }); |
| |
| test('host multiple args async', () { |
| 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: true, |
| ) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[]); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '- (void)addX:(NSNumber *)x y:(NSNumber *)y completion:(void (^)(NSNumber *_Nullable, FlutterError *_Nullable))completion;')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('NSArray *args = message;')); |
| expect(code, |
| contains('NSNumber *arg_x = GetNullableObjectAtIndex(args, 0);')); |
| expect(code, |
| contains('NSNumber *arg_y = GetNullableObjectAtIndex(args, 1);')); |
| expect(code, contains('[api addX:arg_x y:arg_y completion:')); |
| } |
| }); |
| |
| 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), |
| ) |
| ]) |
| ], classes: <Class>[], enums: <Enum>[]); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '- (void)addX:(NSNumber *)x y:(NSNumber *)y completion:(void (^)(NSNumber *_Nullable, NSError *_Nullable))completion;')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| '- (void)addX:(NSNumber *)arg_x y:(NSNumber *)arg_y completion:(void (^)(NSNumber *_Nullable, NSError *_Nullable))completion {')); |
| expect( |
| code, |
| contains( |
| '[channel sendMessage:@[arg_x ?: [NSNull null], arg_y ?: [NSNull null]] reply:')); |
| } |
| }); |
| |
| Root getDivideRoot(ApiLocation location) => Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: location, methods: <Method>[ |
| Method( |
| name: 'divide', |
| objcSelector: 'divideValue:by:', |
| arguments: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'int', isNullable: false), |
| name: 'x', |
| ), |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'int', isNullable: false), |
| name: 'y', |
| ), |
| ], |
| returnType: const TypeDeclaration( |
| baseName: 'double', isNullable: false)) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| |
| test('host custom objc selector', () { |
| final Root divideRoot = getDivideRoot(ApiLocation.host); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, divideRoot, sink); |
| final String code = sink.toString(); |
| expect(code, matches('divideValue:.*by:.*error.*;')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, divideRoot, sink); |
| final String code = sink.toString(); |
| expect(code, matches('divideValue:.*by:.*error.*;')); |
| } |
| }); |
| |
| test('flutter custom objc selector', () { |
| final Root divideRoot = getDivideRoot(ApiLocation.flutter); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, divideRoot, sink); |
| final String code = sink.toString(); |
| expect(code, matches('divideValue:.*by:.*completion.*;')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: |
| const ObjcOptions(headerIncludePath: 'foo.h', prefix: 'ABC'), |
| ); |
| generator.generate(generatorOptions, divideRoot, sink); |
| final String code = sink.toString(); |
| expect(code, matches('divideValue:.*by:.*completion.*{')); |
| } |
| }); |
| |
| test('test non null field', () { |
| final Root root = Root(apis: <Api>[], classes: <Class>[ |
| Class(name: 'Foobar', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration(baseName: 'String', isNullable: false), |
| name: 'field1') |
| ]), |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('@interface Foobar')); |
| expect(code, contains('@property(nonatomic, copy) NSString * field1')); |
| }); |
| |
| test('return nullable flutter header', () { |
| 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(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| matches( |
| r'doitWithCompletion.*void.*NSNumber \*_Nullable.*NSError.*completion;')); |
| }); |
| |
| test('return nullable flutter source', () { |
| 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(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, matches(r'doitWithCompletion.*NSNumber \*_Nullable')); |
| }); |
| |
| test('return nullable host header', () { |
| 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(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, matches(r'nullable NSNumber.*doitWithError')); |
| }); |
| |
| test('nullable argument host', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.host, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration.voidDeclaration(), |
| arguments: <NamedType>[ |
| NamedType( |
| name: 'foo', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| )), |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('doitFoo:(nullable NSNumber *)foo')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, |
| contains('NSNumber *arg_foo = GetNullableObjectAtIndex(args, 0);')); |
| } |
| }); |
| |
| test('nullable argument flutter', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api(name: 'Api', location: ApiLocation.flutter, methods: <Method>[ |
| Method( |
| name: 'doit', |
| returnType: const TypeDeclaration.voidDeclaration(), |
| arguments: <NamedType>[ |
| NamedType( |
| name: 'foo', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| )), |
| ]) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('doitFoo:(nullable NSNumber *)foo')); |
| } |
| { |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains('- (void)doitFoo:(nullable NSNumber *)arg_foo')); |
| } |
| }); |
| |
| test('background platform channel', () { |
| 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>[], |
| taskQueueType: TaskQueueType.serialBackgroundThread) |
| ]) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect( |
| code, |
| contains( |
| 'NSObject<FlutterTaskQueue> *taskQueue = [binaryMessenger makeBackgroundTaskQueue];')); |
| expect(code, contains('taskQueue:taskQueue')); |
| }); |
| |
| 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>[ |
| Api( |
| name: 'api', |
| location: ApiLocation.flutter, |
| documentationComments: <String>[comments[count++]], |
| methods: <Method>[ |
| Method( |
| name: 'method', |
| returnType: const TypeDeclaration.voidDeclaration(), |
| documentationComments: <String>[comments[count++]], |
| arguments: <NamedType>[ |
| NamedType( |
| 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 ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.header, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| for (final String comment in comments) { |
| expect(code, contains('///$comment')); |
| } |
| expect(code, contains('/// ///')); |
| }); |
| |
| test('doesnt create codecs if no custom datatypes', () { |
| final Root root = Root( |
| apis: <Api>[ |
| Api( |
| name: 'Api', |
| location: ApiLocation.flutter, |
| methods: <Method>[ |
| Method( |
| name: 'method', |
| returnType: const TypeDeclaration.voidDeclaration(), |
| arguments: <NamedType>[ |
| NamedType( |
| name: 'field', |
| type: const TypeDeclaration( |
| baseName: 'int', |
| isNullable: true, |
| ), |
| ), |
| ], |
| ) |
| ], |
| ) |
| ], |
| classes: <Class>[], |
| enums: <Enum>[], |
| ); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, isNot(contains(' : FlutterStandardReader'))); |
| }); |
| |
| test('creates custom codecs if custom datatypes present', () { |
| 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: '') |
| ], |
| 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') |
| ]), |
| Class(name: 'Output', fields: <NamedType>[ |
| NamedType( |
| type: const TypeDeclaration( |
| baseName: 'String', |
| isNullable: true, |
| ), |
| name: 'output') |
| ]) |
| ], enums: <Enum>[]); |
| final StringBuffer sink = StringBuffer(); |
| const ObjcGenerator generator = ObjcGenerator(); |
| final OutputFileOptions<ObjcOptions> generatorOptions = |
| OutputFileOptions<ObjcOptions>( |
| fileType: FileType.source, |
| languageOptions: const ObjcOptions(), |
| ); |
| generator.generate(generatorOptions, root, sink); |
| final String code = sink.toString(); |
| expect(code, contains(' : FlutterStandardReader')); |
| }); |
| } |