diff --git a/packages/pigeon/pigeons/async_handlers.dart b/packages/pigeon/pigeons/async_handlers.dart deleted file mode 100644 index 1e7f570fa47c..000000000000 --- a/packages/pigeon/pigeons/async_handlers.dart +++ /dev/null @@ -1,23 +0,0 @@ -// 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/pigeon.dart'; - -class Value { - int? number; -} - -@HostApi() -abstract class Api2Host { - @async - Value calculate(Value value); - @async - void voidVoid(); -} - -@FlutterApi() -abstract class Api2Flutter { - @async - Value calculate(Value value); -} diff --git a/packages/pigeon/pigeons/core_tests.dart b/packages/pigeon/pigeons/core_tests.dart index a5a38c7334a0..27102d96254d 100644 --- a/packages/pigeon/pigeons/core_tests.dart +++ b/packages/pigeon/pigeons/core_tests.dart @@ -538,10 +538,68 @@ abstract class FlutterIntegrationCoreApi { @ObjCSelector('echoNullableMap:') @SwiftFunction('echoNullable(_:)') Map? echoNullableMap(Map? aMap); + + // ========== Async tests ========== + // These are minimal since async FlutterApi only changes Dart generation. + // Currently they aren't integration tested, but having them here ensures + // analysis coverage. + + /// A no-op function taking no arguments and returning no value, to sanity + /// test basic asynchronous calling. + @async + void noopAsync(); + + /// Returns the passed in generic Object asynchronously. + @async + @ObjCSelector('echoAsyncString:') + @SwiftFunction('echoAsync(_:)') + String echoAsyncString(String aString); } /// An API that can be implemented for minimal, compile-only tests. +// +// This is also here to test that multiple host APIs can be generated +// successfully in all languages (e.g., in Java where it requires having a +// wrapper class). @HostApi() abstract class HostTrivialApi { void noop(); } + +/// A simple API implemented in some unit tests. +// +// This is separate from HostIntegrationCoreApi to avoid having to update a +// lot of unit tests every time we add something to the integration test API. +// TODO(stuartmorgan): Restructure the unit tests to reduce the number of +// different APIs we define. +@HostApi() +abstract class HostSmallApi { + @async + @ObjCSelector('echoString:') + String echo(String aString); + + @async + void voidVoid(); +} + +/// A simple API called in some unit tests. +// +// This is separate from FlutterIntegrationCoreApi to allow for incrementally +// moving from the previous fragmented unit test structure to something more +// unified. +// TODO(stuartmorgan): Restructure the unit tests to reduce the number of +// different APIs we define. +@FlutterApi() +abstract class FlutterSmallApi { + @ObjCSelector('echoWrappedList:') + @SwiftFunction('echo(_:)') + TestMessage echoWrappedList(TestMessage msg); +} + +/// A data class containing a List, used in unit tests. +// TODO(stuartmorgan): Evaluate whether these unit tests are still useful; see +// TODOs above about restructring. +class TestMessage { + // ignore: always_specify_types, strict_raw_type + List? testList; +} diff --git a/packages/pigeon/pigeons/enum_args.dart b/packages/pigeon/pigeons/enum_args.dart deleted file mode 100644 index 886b92401ca2..000000000000 --- a/packages/pigeon/pigeons/enum_args.dart +++ /dev/null @@ -1,20 +0,0 @@ -// 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/pigeon.dart'; - -enum EnumArgsState { - Pending, - Success, - Error, -} - -class EnumArgsData { - EnumArgsState? state; -} - -@HostApi() -abstract class EnumArgs2Host { - void foo(EnumArgsState state); -} diff --git a/packages/pigeon/pigeons/host2flutter.dart b/packages/pigeon/pigeons/host2flutter.dart deleted file mode 100644 index 143df60f65e7..000000000000 --- a/packages/pigeon/pigeons/host2flutter.dart +++ /dev/null @@ -1,23 +0,0 @@ -// 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/pigeon.dart'; - -@ConfigurePigeon(PigeonOptions( - objcOptions: ObjcOptions( - prefix: 'H2F', - ), -)) -class Host2FlutterSearchRequest { - String? query; -} - -class Host2FlutterSearchReply { - String? result; -} - -@FlutterApi() -abstract class H2FApi { - Host2FlutterSearchReply search(Host2FlutterSearchRequest request); -} diff --git a/packages/pigeon/pigeons/java_double_host_api.dart b/packages/pigeon/pigeons/java_double_host_api.dart deleted file mode 100644 index d07cb58af0b0..000000000000 --- a/packages/pigeon/pigeons/java_double_host_api.dart +++ /dev/null @@ -1,21 +0,0 @@ -// 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/pigeon.dart'; - -class BridgeResponse { - int? result; -} - -@HostApi() -abstract class BridgeApi1 { - @async - BridgeResponse call(); -} - -@HostApi() -abstract class BridgeApi2 { - @async - BridgeResponse call(); -} diff --git a/packages/pigeon/pigeons/list.dart b/packages/pigeon/pigeons/list.dart deleted file mode 100644 index c813f7456058..000000000000 --- a/packages/pigeon/pigeons/list.dart +++ /dev/null @@ -1,20 +0,0 @@ -// 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/pigeon.dart'; - -class TestMessage { - // ignore: always_specify_types, strict_raw_type - List? testList; -} - -@HostApi() -abstract class TestApi { - void test(TestMessage msg); -} - -@FlutterApi() -abstract class EchoApi { - TestMessage echo(TestMessage msg); -} diff --git a/packages/pigeon/pigeons/void_arg_flutter.dart b/packages/pigeon/pigeons/void_arg_flutter.dart deleted file mode 100644 index 7428812fadcf..000000000000 --- a/packages/pigeon/pigeons/void_arg_flutter.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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/pigeon.dart'; - -class VoidArgFlutterResult { - int? code; -} - -@FlutterApi() -abstract class VoidArgApi { - VoidArgFlutterResult getCode(); -} diff --git a/packages/pigeon/pigeons/void_arg_host.dart b/packages/pigeon/pigeons/void_arg_host.dart deleted file mode 100644 index 44ba5ac24380..000000000000 --- a/packages/pigeon/pigeons/void_arg_host.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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/pigeon.dart'; - -class VoidArgHostResult { - int? code; -} - -@HostApi() -abstract class VoidArgHostApi { - VoidArgHostResult getCode(); -} diff --git a/packages/pigeon/pigeons/voidflutter.dart b/packages/pigeon/pigeons/voidflutter.dart deleted file mode 100644 index 51fe3a9afe85..000000000000 --- a/packages/pigeon/pigeons/voidflutter.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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/pigeon.dart'; - -class VoidFlutterSetRequest { - int? value; -} - -@FlutterApi() -abstract class VoidFlutterApi { - void setValue(VoidFlutterSetRequest request); -} diff --git a/packages/pigeon/pigeons/voidhost.dart b/packages/pigeon/pigeons/voidhost.dart deleted file mode 100644 index 3ff48f88149b..000000000000 --- a/packages/pigeon/pigeons/voidhost.dart +++ /dev/null @@ -1,14 +0,0 @@ -// 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/pigeon.dart'; - -class VoidHostSetRequest { - int? value; -} - -@HostApi() -abstract class VoidHostApi { - void setValue(VoidHostSetRequest request); -} diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java index 695c203d0f6b..bedbf244ec37 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java @@ -708,6 +708,53 @@ ArrayList toList() { } } + /** + * A data class containing a List, used in unit tests. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class TestMessage { + private @Nullable List testList; + + public @Nullable List getTestList() { + return testList; + } + + public void setTestList(@Nullable List setterArg) { + this.testList = setterArg; + } + + public static final class Builder { + + private @Nullable List testList; + + public @NonNull Builder setTestList(@Nullable List setterArg) { + this.testList = setterArg; + return this; + } + + public @NonNull TestMessage build() { + TestMessage pigeonReturn = new TestMessage(); + pigeonReturn.setTestList(testList); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(testList); + return toListResult; + } + + static @NonNull TestMessage fromList(@NonNull ArrayList list) { + TestMessage pigeonResult = new TestMessage(); + Object testList = list.get(0); + pigeonResult.setTestList((List) testList); + return pigeonResult; + } + } + public interface Result { void success(T result); @@ -728,6 +775,8 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { return AllNullableTypesWrapper.fromList((ArrayList) readValue(buffer)); case (byte) 130: return AllTypes.fromList((ArrayList) readValue(buffer)); + case (byte) 131: + return TestMessage.fromList((ArrayList) readValue(buffer)); default: return super.readValueOfType(type, buffer); } @@ -744,6 +793,9 @@ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { } else if (value instanceof AllTypes) { stream.write(130); writeValue(stream, ((AllTypes) value).toList()); + } else if (value instanceof TestMessage) { + stream.write(131); + writeValue(stream, ((TestMessage) value).toList()); } else { super.writeValue(stream, value); } @@ -3119,6 +3171,8 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { return AllNullableTypesWrapper.fromList((ArrayList) readValue(buffer)); case (byte) 130: return AllTypes.fromList((ArrayList) readValue(buffer)); + case (byte) 131: + return TestMessage.fromList((ArrayList) readValue(buffer)); default: return super.readValueOfType(type, buffer); } @@ -3135,6 +3189,9 @@ protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { } else if (value instanceof AllTypes) { stream.write(130); writeValue(stream, ((AllTypes) value).toList()); + } else if (value instanceof TestMessage) { + stream.write(131); + writeValue(stream, ((TestMessage) value).toList()); } else { super.writeValue(stream, value); } @@ -3453,6 +3510,33 @@ public void echoNullableMap( callback.reply(output); }); } + /** + * A no-op function taking no arguments and returning no value, to sanity test basic + * asynchronous calling. + */ + public void noopAsync(Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.FlutterIntegrationCoreApi.noopAsync", + getCodec()); + channel.send(null, channelReply -> callback.reply(null)); + } + /** Returns the passed in generic Object asynchronously. */ + public void echoAsyncString(@NonNull String aStringArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString", + getCodec()); + channel.send( + new ArrayList(Collections.singletonList(aStringArg)), + channelReply -> { + @SuppressWarnings("ConstantConditions") + String output = (String) channelReply; + callback.reply(output); + }); + } } /** * An API that can be implemented for minimal, compile-only tests. @@ -3492,4 +3576,154 @@ static void setup(BinaryMessenger binaryMessenger, HostTrivialApi api) { } } } + /** + * A simple API implemented in some unit tests. + * + *

Generated interface from Pigeon that represents a handler of messages from Flutter. + */ + public interface HostSmallApi { + + void echo(@NonNull String aString, Result result); + + void voidVoid(Result result); + + /** The codec used by HostSmallApi. */ + static MessageCodec getCodec() { + return new StandardMessageCodec(); + } + /** Sets up an instance of `HostSmallApi` to handle messages through the `binaryMessenger`. */ + static void setup(BinaryMessenger binaryMessenger, HostSmallApi api) { + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.HostSmallApi.echo", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + try { + ArrayList args = (ArrayList) message; + assert args != null; + String aStringArg = (String) args.get(0); + if (aStringArg == null) { + throw new NullPointerException("aStringArg unexpectedly null."); + } + Result resultCallback = + new Result() { + public void success(String result) { + wrapped.add(0, result); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.echo(aStringArg, resultCallback); + } catch (Error | RuntimeException exception) { + ArrayList wrappedError = wrapError(exception); + reply.reply(wrappedError); + } + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.HostSmallApi.voidVoid", getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + try { + Result resultCallback = + new Result() { + public void success(Void result) { + wrapped.add(0, null); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.voidVoid(resultCallback); + } catch (Error | RuntimeException exception) { + ArrayList wrappedError = wrapError(exception); + reply.reply(wrappedError); + } + }); + } else { + channel.setMessageHandler(null); + } + } + } + } + + private static class FlutterSmallApiCodec extends StandardMessageCodec { + public static final FlutterSmallApiCodec INSTANCE = new FlutterSmallApiCodec(); + + private FlutterSmallApiCodec() {} + + @Override + protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { + switch (type) { + case (byte) 128: + return TestMessage.fromList((ArrayList) readValue(buffer)); + default: + return super.readValueOfType(type, buffer); + } + } + + @Override + protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { + if (value instanceof TestMessage) { + stream.write(128); + writeValue(stream, ((TestMessage) value).toList()); + } else { + super.writeValue(stream, value); + } + } + } + + /** + * A simple API called in some unit tests. + * + *

Generated class from Pigeon that represents Flutter messages that can be called from Java. + */ + public static class FlutterSmallApi { + private final BinaryMessenger binaryMessenger; + + public FlutterSmallApi(BinaryMessenger argBinaryMessenger) { + this.binaryMessenger = argBinaryMessenger; + } + + /** Public interface for sending reply. */ + public interface Reply { + void reply(T reply); + } + /** The codec used by FlutterSmallApi. */ + static MessageCodec getCodec() { + return FlutterSmallApiCodec.INSTANCE; + } + + public void echoWrappedList(@NonNull TestMessage msgArg, Reply callback) { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, "dev.flutter.pigeon.FlutterSmallApi.echoWrappedList", getCodec()); + channel.send( + new ArrayList(Collections.singletonList(msgArg)), + channelReply -> { + @SuppressWarnings("ConstantConditions") + TestMessage output = (TestMessage) channelReply; + callback.reply(output); + }); + } + } } diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AsyncTest.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AsyncTest.java index 786aef3bf9bb..e5e795380a8f 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AsyncTest.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/AsyncTest.java @@ -7,7 +7,8 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; -import com.example.alternate_language_test_plugin.AsyncHandlers.*; +import androidx.annotation.NonNull; +import com.example.alternate_language_test_plugin.CoreTests.*; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MessageCodec; import java.nio.ByteBuffer; @@ -16,9 +17,9 @@ import org.mockito.ArgumentCaptor; public class AsyncTest { - class Success implements Api2Host { + class Success implements HostSmallApi { @Override - public void calculate(Value value, Result result) { + public void echo(@NonNull String value, Result result) { result.success(value); } @@ -28,9 +29,9 @@ public void voidVoid(Result result) { } } - class Error implements Api2Host { + class Error implements HostSmallApi { @Override - public void calculate(Value value, Result result) { + public void echo(@NonNull String value, Result result) { result.error(new Exception("error")); } @@ -44,13 +45,13 @@ public void voidVoid(Result result) { public void asyncSuccess() { Success api = new Success(); BinaryMessenger binaryMessenger = mock(BinaryMessenger.class); - Api2Host.setup(binaryMessenger, api); + HostSmallApi.setup(binaryMessenger, api); ArgumentCaptor handler = ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class); - verify(binaryMessenger).setMessageHandler(eq("dev.flutter.pigeon.Api2Host.calculate"), any()); + verify(binaryMessenger).setMessageHandler(eq("dev.flutter.pigeon.HostSmallApi.echo"), any()); verify(binaryMessenger) - .setMessageHandler(eq("dev.flutter.pigeon.Api2Host.voidVoid"), handler.capture()); - MessageCodec codec = Pigeon.AndroidApi.getCodec(); + .setMessageHandler(eq("dev.flutter.pigeon.HostSmallApi.voidVoid"), handler.capture()); + MessageCodec codec = HostSmallApi.getCodec(); ByteBuffer message = codec.encodeMessage(null); Boolean[] didCall = {false}; handler @@ -71,13 +72,13 @@ public void asyncSuccess() { public void asyncError() { Error api = new Error(); BinaryMessenger binaryMessenger = mock(BinaryMessenger.class); - Api2Host.setup(binaryMessenger, api); + HostSmallApi.setup(binaryMessenger, api); ArgumentCaptor handler = ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class); - verify(binaryMessenger).setMessageHandler(eq("dev.flutter.pigeon.Api2Host.calculate"), any()); + verify(binaryMessenger).setMessageHandler(eq("dev.flutter.pigeon.HostSmallApi.echo"), any()); verify(binaryMessenger) - .setMessageHandler(eq("dev.flutter.pigeon.Api2Host.voidVoid"), handler.capture()); - MessageCodec codec = Pigeon.AndroidApi.getCodec(); + .setMessageHandler(eq("dev.flutter.pigeon.HostSmallApi.voidVoid"), handler.capture()); + MessageCodec codec = HostSmallApi.getCodec(); ByteBuffer message = codec.encodeMessage(null); Boolean[] didCall = {false}; handler diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/ListTest.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/ListTest.java index a1345a00a1b3..37ecef9a0320 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/ListTest.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/ListTest.java @@ -7,8 +7,8 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; -import com.example.alternate_language_test_plugin.PigeonList.EchoApi; -import com.example.alternate_language_test_plugin.PigeonList.TestMessage; +import com.example.alternate_language_test_plugin.CoreTests.FlutterSmallApi; +import com.example.alternate_language_test_plugin.CoreTests.TestMessage; import io.flutter.plugin.common.BinaryMessenger; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -28,17 +28,17 @@ public void listInList() { ByteBuffer message = invocation.getArgument(1); BinaryMessenger.BinaryReply reply = invocation.getArgument(2); message.position(0); - ArrayList args = (ArrayList) EchoApi.getCodec().decodeMessage(message); - ByteBuffer replyData = EchoApi.getCodec().encodeMessage(args.get(0)); + ArrayList args = (ArrayList) FlutterSmallApi.getCodec().decodeMessage(message); + ByteBuffer replyData = FlutterSmallApi.getCodec().encodeMessage(args.get(0)); replyData.position(0); reply.reply(replyData); return null; }) .when(binaryMessenger) .send(anyString(), any(), any()); - EchoApi api = new EchoApi(binaryMessenger); + FlutterSmallApi api = new FlutterSmallApi(binaryMessenger); boolean[] didCall = {false}; - api.echo( + api.echoWrappedList( top, (result) -> { didCall[0] = true; diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/PigeonTest.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/PigeonTest.java index a8a88b190ebc..865d4ef81767 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/PigeonTest.java +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/test/java/com/example/alternate_language_test_plugin/PigeonTest.java @@ -7,63 +7,40 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import com.example.alternate_language_test_plugin.CoreTests.HostSmallApi; import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.MessageCodec; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Arrays; import org.junit.Test; import org.mockito.ArgumentCaptor; public class PigeonTest { - @Test - public void toListAndBack() { - Pigeon.AndroidSetRequest request = new Pigeon.AndroidSetRequest(); - request.setValue(1234l); - request.setState(Pigeon.AndroidLoadingState.COMPLETE); - ArrayList list = request.toList(); - Pigeon.AndroidSetRequest readRequest = Pigeon.AndroidSetRequest.fromList(list); - assertEquals(request.getValue(), readRequest.getValue()); - assertEquals(request.getState(), readRequest.getState()); - } - - @Test - public void toListAndBackNested() { - Pigeon.AndroidNestedRequest nested = new Pigeon.AndroidNestedRequest(); - Pigeon.AndroidSetRequest request = new Pigeon.AndroidSetRequest(); - request.setValue(1234l); - request.setState(Pigeon.AndroidLoadingState.COMPLETE); - nested.setRequest(request); - ArrayList list = nested.toList(); - Pigeon.AndroidNestedRequest readNested = Pigeon.AndroidNestedRequest.fromList(list); - assertEquals(nested.getRequest().getValue(), readNested.getRequest().getValue()); - assertEquals(nested.getRequest().getState(), readNested.getRequest().getState()); - } - @Test public void clearsHandler() { - Pigeon.AndroidApi mockApi = mock(Pigeon.AndroidApi.class); + HostSmallApi mockApi = mock(HostSmallApi.class); BinaryMessenger binaryMessenger = mock(BinaryMessenger.class); - Pigeon.AndroidApi.setup(binaryMessenger, mockApi); + HostSmallApi.setup(binaryMessenger, mockApi); ArgumentCaptor channelName = ArgumentCaptor.forClass(String.class); - verify(binaryMessenger).setMessageHandler(channelName.capture(), isNotNull()); - Pigeon.AndroidApi.setup(binaryMessenger, null); - verify(binaryMessenger).setMessageHandler(eq(channelName.getValue()), isNull()); + verify(binaryMessenger, atLeast(1)).setMessageHandler(channelName.capture(), isNotNull()); + HostSmallApi.setup(binaryMessenger, null); + verify(binaryMessenger, atLeast(1)).setMessageHandler(eq(channelName.getValue()), isNull()); } - /** Causes an exception in the handler by passing in null when a AndroidSetRequest is expected. */ + /** Causes an exception in the handler by passing in null when a non-null value is expected. */ @Test public void errorMessage() { - Pigeon.AndroidApi mockApi = mock(Pigeon.AndroidApi.class); + HostSmallApi mockApi = mock(HostSmallApi.class); BinaryMessenger binaryMessenger = mock(BinaryMessenger.class); - Pigeon.AndroidApi.setup(binaryMessenger, mockApi); + HostSmallApi.setup(binaryMessenger, mockApi); ArgumentCaptor handler = ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class); - verify(binaryMessenger).setMessageHandler(anyString(), handler.capture()); - MessageCodec codec = Pigeon.AndroidApi.getCodec(); + verify(binaryMessenger, atLeast(1)).setMessageHandler(anyString(), handler.capture()); + MessageCodec codec = HostSmallApi.getCodec(); ByteBuffer message = codec.encodeMessage(null); handler - .getValue() + .getAllValues() + .get(0) // "echo" is the first method. .onMessage( message, (bytes) -> { @@ -77,44 +54,4 @@ public void errorMessage() { assertTrue(details.contains("Stacktrace:")); }); } - - @Test - public void callsVoidMethod() { - Pigeon.AndroidApi mockApi = mock(Pigeon.AndroidApi.class); - BinaryMessenger binaryMessenger = mock(BinaryMessenger.class); - Pigeon.AndroidApi.setup(binaryMessenger, mockApi); - ArgumentCaptor handler = - ArgumentCaptor.forClass(BinaryMessenger.BinaryMessageHandler.class); - verify(binaryMessenger).setMessageHandler(anyString(), handler.capture()); - Pigeon.AndroidSetRequest request = new Pigeon.AndroidSetRequest(); - request.setValue(1234l); - request.setState(Pigeon.AndroidLoadingState.COMPLETE); - MessageCodec codec = Pigeon.AndroidApi.getCodec(); - ByteBuffer message = codec.encodeMessage(new ArrayList(Arrays.asList(request))); - message.rewind(); - handler - .getValue() - .onMessage( - message, - (bytes) -> { - bytes.rewind(); - @SuppressWarnings("unchecked") - ArrayList wrapped = (ArrayList) codec.decodeMessage(bytes); - assertTrue(wrapped.size() == 1); - assertNull(wrapped.get(0)); - }); - ArgumentCaptor receivedRequest = - ArgumentCaptor.forClass(Pigeon.AndroidSetRequest.class); - verify(mockApi).setValue(receivedRequest.capture()); - assertEquals(request.getValue(), receivedRequest.getValue().getValue()); - } - - @Test - public void encodeWithNullField() { - Pigeon.AndroidNestedRequest request = new Pigeon.AndroidNestedRequest(); - request.setContext("hello"); - MessageCodec codec = Pigeon.AndroidNestedApi.getCodec(); - ByteBuffer message = codec.encodeMessage(request); - assertNotNull(message); - } } diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AsyncHandlersTest.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AsyncHandlersTest.m index e72da1d274b1..35b9dc801626 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AsyncHandlersTest.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/AsyncHandlersTest.m @@ -10,26 +10,18 @@ #import "MockBinaryMessenger.h" /////////////////////////////////////////////////////////////////////////////////////////// -@interface Value () -+ (Value *)fromList:(NSArray *)list; -- (NSArray *)toList; -@end - -/////////////////////////////////////////////////////////////////////////////////////////// -@interface MockApi2Host : NSObject -@property(nonatomic, copy) NSNumber *output; +@interface MockHostSmallApi : NSObject +@property(nonatomic, copy) NSString *output; @property(nonatomic, retain) FlutterError *voidVoidError; @end /////////////////////////////////////////////////////////////////////////////////////////// -@implementation MockApi2Host +@implementation MockHostSmallApi -- (void)calculateValue:(Value *)input - completion:(nonnull void (^)(Value *_Nullable, FlutterError *_Nullable))completion { +- (void)echoString:(NSString *)value + completion:(nonnull void (^)(NSString *_Nullable, FlutterError *_Nullable))completion { if (self.output) { - Value *output = [[Value alloc] init]; - output.number = self.output; - completion(output, nil); + completion(self.output, nil); } else { completion(nil, [FlutterError errorWithCode:@"hey" message:@"ho" details:nil]); } @@ -50,15 +42,15 @@ @implementation AsyncHandlersTest - (void)testAsyncHost2Flutter { MockBinaryMessenger *binaryMessenger = - [[MockBinaryMessenger alloc] initWithCodec:Api2FlutterGetCodec()]; - binaryMessenger.result = [Value makeWithNumber:@(2)]; - Api2Flutter *api2Flutter = [[Api2Flutter alloc] initWithBinaryMessenger:binaryMessenger]; - Value *input = [[Value alloc] init]; - input.number = @(1); - XCTestExpectation *expectation = [self expectationWithDescription:@"calculate callback"]; - [api2Flutter calculateValue:input - completion:^(Value *_Nonnull output, FlutterError *_Nullable error) { - XCTAssertEqual(output.number.intValue, 2); + [[MockBinaryMessenger alloc] initWithCodec:FlutterIntegrationCoreApiGetCodec()]; + NSString *value = @"Test"; + binaryMessenger.result = value; + FlutterIntegrationCoreApi *flutterApi = + [[FlutterIntegrationCoreApi alloc] initWithBinaryMessenger:binaryMessenger]; + XCTestExpectation *expectation = [self expectationWithDescription:@"echo callback"]; + [flutterApi echoAsyncString:value + completion:^(NSString *_Nonnull output, FlutterError *_Nullable error) { + XCTAssertEqualObjects(output, value); [expectation fulfill]; }]; [self waitForExpectationsWithTimeout:1.0 handler:nil]; @@ -66,11 +58,10 @@ - (void)testAsyncHost2Flutter { - (void)testAsyncFlutter2HostVoidVoid { MockBinaryMessenger *binaryMessenger = - [[MockBinaryMessenger alloc] initWithCodec:Api2HostGetCodec()]; - MockApi2Host *mockApi2Host = [[MockApi2Host alloc] init]; - mockApi2Host.output = @(2); - Api2HostSetup(binaryMessenger, mockApi2Host); - NSString *channelName = @"dev.flutter.pigeon.Api2Host.voidVoid"; + [[MockBinaryMessenger alloc] initWithCodec:HostSmallApiGetCodec()]; + MockHostSmallApi *mockHostSmallApi = [[MockHostSmallApi alloc] init]; + HostSmallApiSetup(binaryMessenger, mockHostSmallApi); + NSString *channelName = @"dev.flutter.pigeon.HostSmallApi.voidVoid"; XCTAssertNotNil(binaryMessenger.handlers[channelName]); XCTestExpectation *expectation = [self expectationWithDescription:@"voidvoid callback"]; @@ -84,18 +75,20 @@ - (void)testAsyncFlutter2HostVoidVoid { - (void)testAsyncFlutter2HostVoidVoidError { MockBinaryMessenger *binaryMessenger = - [[MockBinaryMessenger alloc] initWithCodec:Api2HostGetCodec()]; - MockApi2Host *mockApi2Host = [[MockApi2Host alloc] init]; - mockApi2Host.voidVoidError = [FlutterError errorWithCode:@"code" message:@"message" details:nil]; - Api2HostSetup(binaryMessenger, mockApi2Host); - NSString *channelName = @"dev.flutter.pigeon.Api2Host.voidVoid"; + [[MockBinaryMessenger alloc] initWithCodec:HostSmallApiGetCodec()]; + MockHostSmallApi *mockHostSmallApi = [[MockHostSmallApi alloc] init]; + mockHostSmallApi.voidVoidError = [FlutterError errorWithCode:@"code" + message:@"message" + details:nil]; + HostSmallApiSetup(binaryMessenger, mockHostSmallApi); + NSString *channelName = @"dev.flutter.pigeon.HostSmallApi.voidVoid"; XCTAssertNotNil(binaryMessenger.handlers[channelName]); XCTestExpectation *expectation = [self expectationWithDescription:@"voidvoid callback"]; binaryMessenger.handlers[channelName](nil, ^(NSData *data) { NSArray *outputList = [binaryMessenger.codec decode:data]; XCTAssertNotNil(outputList); - XCTAssertEqualObjects(outputList[0], mockApi2Host.voidVoidError.code); + XCTAssertEqualObjects(outputList[0], mockHostSmallApi.voidVoidError.code); [expectation fulfill]; }); [self waitForExpectationsWithTimeout:1.0 handler:nil]; @@ -103,21 +96,20 @@ - (void)testAsyncFlutter2HostVoidVoidError { - (void)testAsyncFlutter2Host { MockBinaryMessenger *binaryMessenger = - [[MockBinaryMessenger alloc] initWithCodec:Api2HostGetCodec()]; - MockApi2Host *mockApi2Host = [[MockApi2Host alloc] init]; - mockApi2Host.output = @(2); - Api2HostSetup(binaryMessenger, mockApi2Host); - NSString *channelName = @"dev.flutter.pigeon.Api2Host.calculate"; + [[MockBinaryMessenger alloc] initWithCodec:HostSmallApiGetCodec()]; + MockHostSmallApi *mockHostSmallApi = [[MockHostSmallApi alloc] init]; + NSString *value = @"Test"; + mockHostSmallApi.output = value; + HostSmallApiSetup(binaryMessenger, mockHostSmallApi); + NSString *channelName = @"dev.flutter.pigeon.HostSmallApi.echo"; XCTAssertNotNil(binaryMessenger.handlers[channelName]); - Value *input = [[Value alloc] init]; - input.number = @(1); - NSData *inputEncoded = [binaryMessenger.codec encode:@[ input ]]; - XCTestExpectation *expectation = [self expectationWithDescription:@"calculate callback"]; + NSData *inputEncoded = [binaryMessenger.codec encode:@[ value ]]; + XCTestExpectation *expectation = [self expectationWithDescription:@"echo callback"]; binaryMessenger.handlers[channelName](inputEncoded, ^(NSData *data) { NSArray *outputList = [binaryMessenger.codec decode:data]; - Value *output = outputList[0]; - XCTAssertEqual(output.number.intValue, 2); + NSString *output = outputList[0]; + XCTAssertEqualObjects(output, value); [expectation fulfill]; }); [self waitForExpectationsWithTimeout:1.0 handler:nil]; @@ -125,16 +117,14 @@ - (void)testAsyncFlutter2Host { - (void)testAsyncFlutter2HostError { MockBinaryMessenger *binaryMessenger = - [[MockBinaryMessenger alloc] initWithCodec:Api2HostGetCodec()]; - MockApi2Host *mockApi2Host = [[MockApi2Host alloc] init]; - Api2HostSetup(binaryMessenger, mockApi2Host); - NSString *channelName = @"dev.flutter.pigeon.Api2Host.calculate"; + [[MockBinaryMessenger alloc] initWithCodec:HostSmallApiGetCodec()]; + MockHostSmallApi *mockHostSmallApi = [[MockHostSmallApi alloc] init]; + HostSmallApiSetup(binaryMessenger, mockHostSmallApi); + NSString *channelName = @"dev.flutter.pigeon.HostSmallApi.echo"; XCTAssertNotNil(binaryMessenger.handlers[channelName]); - Value *input = [[Value alloc] init]; - input.number = @(1); - NSData *inputEncoded = [binaryMessenger.codec encode:@[ [input toList] ]]; - XCTestExpectation *expectation = [self expectationWithDescription:@"calculate callback"]; + NSData *inputEncoded = [binaryMessenger.codec encode:@[ @"Test" ]]; + XCTestExpectation *expectation = [self expectationWithDescription:@"echo callback"]; binaryMessenger.handlers[channelName](inputEncoded, ^(NSData *data) { NSArray *outputList = [binaryMessenger.codec decode:data]; XCTAssertNotNil(outputList); diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/ListTest.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/ListTest.m index 479a80fd44b0..124de85973b2 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/ListTest.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/example/ios/RunnerTests/ListTest.m @@ -22,16 +22,16 @@ - (void)testListInList { inside.testList = @[ @1, @2, @3 ]; top.testList = @[ inside ]; EchoBinaryMessenger *binaryMessenger = - [[EchoBinaryMessenger alloc] initWithCodec:EchoApiGetCodec()]; - EchoApi *api = [[EchoApi alloc] initWithBinaryMessenger:binaryMessenger]; + [[EchoBinaryMessenger alloc] initWithCodec:FlutterSmallApiGetCodec()]; + FlutterSmallApi *api = [[FlutterSmallApi alloc] initWithBinaryMessenger:binaryMessenger]; XCTestExpectation *expectation = [self expectationWithDescription:@"callback"]; - [api echoMsg:top - completion:^(TestMessage *_Nonnull result, FlutterError *_Nullable err) { - XCTAssertEqual(1u, result.testList.count); - XCTAssertTrue([result.testList[0] isKindOfClass:[TestMessage class]]); - XCTAssertEqualObjects(inside.testList, [result.testList[0] testList]); - [expectation fulfill]; - }]; + [api echoWrappedList:top + completion:^(TestMessage *_Nonnull result, FlutterError *_Nullable err) { + XCTAssertEqual(1u, result.testList.count); + XCTAssertTrue([result.testList[0] isKindOfClass:[TestMessage class]]); + XCTAssertEqualObjects(inside.testList, [result.testList[0] testList]); + [expectation fulfill]; + }]; [self waitForExpectations:@[ expectation ] timeout:1.0]; } diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h index 8672344ed686..c0f834cfa831 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h @@ -23,6 +23,7 @@ typedef NS_ENUM(NSUInteger, AnEnum) { @class AllTypes; @class AllNullableTypes; @class AllNullableTypesWrapper; +@class TestMessage; @interface AllTypes : NSObject /// `init` unavailable to enforce nonnull fields, see the `make` class method. @@ -91,6 +92,12 @@ typedef NS_ENUM(NSUInteger, AnEnum) { @property(nonatomic, strong) AllNullableTypes *values; @end +/// A data class containing a List, used in unit tests. +@interface TestMessage : NSObject ++ (instancetype)makeWithTestList:(nullable NSArray *)testList; +@property(nonatomic, strong, nullable) NSArray *testList; +@end + /// The codec used by HostIntegrationCoreApi. NSObject *HostIntegrationCoreApiGetCodec(void); @@ -388,6 +395,12 @@ NSObject *FlutterIntegrationCoreApiGetCodec(void); - (void)echoNullableMap:(nullable NSDictionary *)aMap completion:(void (^)(NSDictionary *_Nullable, FlutterError *_Nullable))completion; +/// A no-op function taking no arguments and returning no value, to sanity +/// test basic asynchronous calling. +- (void)noopAsyncWithCompletion:(void (^)(FlutterError *_Nullable))completion; +/// Returns the passed in generic Object asynchronously. +- (void)echoAsyncString:(NSString *)aString + completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; @end /// The codec used by HostTrivialApi. @@ -401,4 +414,27 @@ NSObject *HostTrivialApiGetCodec(void); extern void HostTrivialApiSetup(id binaryMessenger, NSObject *_Nullable api); +/// The codec used by HostSmallApi. +NSObject *HostSmallApiGetCodec(void); + +/// A simple API implemented in some unit tests. +@protocol HostSmallApi +- (void)echoString:(NSString *)aString + completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion; +- (void)voidVoidWithCompletion:(void (^)(FlutterError *_Nullable))completion; +@end + +extern void HostSmallApiSetup(id binaryMessenger, + NSObject *_Nullable api); + +/// The codec used by FlutterSmallApi. +NSObject *FlutterSmallApiGetCodec(void); + +/// A simple API called in some unit tests. +@interface FlutterSmallApi : NSObject +- (instancetype)initWithBinaryMessenger:(id)binaryMessenger; +- (void)echoWrappedList:(TestMessage *)msg + completion:(void (^)(TestMessage *_Nullable, FlutterError *_Nullable))completion; +@end + NS_ASSUME_NONNULL_END diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m index 263b4608e33a..b3f948a4617e 100644 --- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m +++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m @@ -43,6 +43,12 @@ + (nullable AllNullableTypesWrapper *)nullableFromList:(NSArray *)list; - (NSArray *)toList; @end +@interface TestMessage () ++ (TestMessage *)fromList:(NSArray *)list; ++ (nullable TestMessage *)nullableFromList:(NSArray *)list; +- (NSArray *)toList; +@end + @implementation AllTypes + (instancetype)makeWithABool:(NSNumber *)aBool anInt:(NSNumber *)anInt @@ -210,6 +216,27 @@ - (NSArray *)toList { } @end +@implementation TestMessage ++ (instancetype)makeWithTestList:(nullable NSArray *)testList { + TestMessage *pigeonResult = [[TestMessage alloc] init]; + pigeonResult.testList = testList; + return pigeonResult; +} ++ (TestMessage *)fromList:(NSArray *)list { + TestMessage *pigeonResult = [[TestMessage alloc] init]; + pigeonResult.testList = GetNullableObjectAtIndex(list, 0); + return pigeonResult; +} ++ (nullable TestMessage *)nullableFromList:(NSArray *)list { + return (list) ? [TestMessage fromList:list] : nil; +} +- (NSArray *)toList { + return @[ + (self.testList ?: [NSNull null]), + ]; +} +@end + @interface HostIntegrationCoreApiCodecReader : FlutterStandardReader @end @implementation HostIntegrationCoreApiCodecReader @@ -221,6 +248,8 @@ - (nullable id)readValueOfType:(UInt8)type { return [AllNullableTypesWrapper fromList:[self readValue]]; case 130: return [AllTypes fromList:[self readValue]]; + case 131: + return [TestMessage fromList:[self readValue]]; default: return [super readValueOfType:type]; } @@ -240,6 +269,9 @@ - (void)writeValue:(id)value { } else if ([value isKindOfClass:[AllTypes class]]) { [self writeByte:130]; [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[TestMessage class]]) { + [self writeByte:131]; + [self writeValue:[value toList]]; } else { [super writeValue:value]; } @@ -1715,6 +1747,8 @@ - (nullable id)readValueOfType:(UInt8)type { return [AllNullableTypesWrapper fromList:[self readValue]]; case 130: return [AllTypes fromList:[self readValue]]; + case 131: + return [TestMessage fromList:[self readValue]]; default: return [super readValueOfType:type]; } @@ -1734,6 +1768,9 @@ - (void)writeValue:(id)value { } else if ([value isKindOfClass:[AllTypes class]]) { [self writeByte:130]; [self writeValue:[value toList]]; + } else if ([value isKindOfClass:[TestMessage class]]) { + [self writeByte:131]; + [self writeValue:[value toList]]; } else { [super writeValue:value]; } @@ -2022,6 +2059,28 @@ - (void)echoNullableMap:(nullable NSDictionary *)arg_aMap completion(output, nil); }]; } +- (void)noopAsyncWithCompletion:(void (^)(FlutterError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:@"dev.flutter.pigeon.FlutterIntegrationCoreApi.noopAsync" + binaryMessenger:self.binaryMessenger + codec:FlutterIntegrationCoreApiGetCodec()]; + [channel sendMessage:nil + reply:^(id reply) { + completion(nil); + }]; +} +- (void)echoAsyncString:(NSString *)arg_aString + completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:@"dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString" + binaryMessenger:self.binaryMessenger + codec:FlutterIntegrationCoreApiGetCodec()]; + [channel sendMessage:@[ arg_aString ?: [NSNull null] ] + reply:^(id reply) { + NSString *output = reply; + completion(output, nil); + }]; +} @end NSObject *HostTrivialApiGetCodec() { @@ -2050,3 +2109,123 @@ void HostTrivialApiSetup(id binaryMessenger, } } } +NSObject *HostSmallApiGetCodec() { + static FlutterStandardMessageCodec *sSharedObject = nil; + sSharedObject = [FlutterStandardMessageCodec sharedInstance]; + return sSharedObject; +} + +void HostSmallApiSetup(id binaryMessenger, NSObject *api) { + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] initWithName:@"dev.flutter.pigeon.HostSmallApi.echo" + binaryMessenger:binaryMessenger + codec:HostSmallApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(echoString:completion:)], + @"HostSmallApi api (%@) doesn't respond to @selector(echoString:completion:)", api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + NSArray *args = message; + NSString *arg_aString = GetNullableObjectAtIndex(args, 0); + [api echoString:arg_aString + completion:^(NSString *_Nullable output, FlutterError *_Nullable error) { + callback(wrapResult(output, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } + { + FlutterBasicMessageChannel *channel = + [[FlutterBasicMessageChannel alloc] initWithName:@"dev.flutter.pigeon.HostSmallApi.voidVoid" + binaryMessenger:binaryMessenger + codec:HostSmallApiGetCodec()]; + if (api) { + NSCAssert([api respondsToSelector:@selector(voidVoidWithCompletion:)], + @"HostSmallApi api (%@) doesn't respond to @selector(voidVoidWithCompletion:)", + api); + [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) { + [api voidVoidWithCompletion:^(FlutterError *_Nullable error) { + callback(wrapResult(nil, error)); + }]; + }]; + } else { + [channel setMessageHandler:nil]; + } + } +} +@interface FlutterSmallApiCodecReader : FlutterStandardReader +@end +@implementation FlutterSmallApiCodecReader +- (nullable id)readValueOfType:(UInt8)type { + switch (type) { + case 128: + return [TestMessage fromList:[self readValue]]; + default: + return [super readValueOfType:type]; + } +} +@end + +@interface FlutterSmallApiCodecWriter : FlutterStandardWriter +@end +@implementation FlutterSmallApiCodecWriter +- (void)writeValue:(id)value { + if ([value isKindOfClass:[TestMessage class]]) { + [self writeByte:128]; + [self writeValue:[value toList]]; + } else { + [super writeValue:value]; + } +} +@end + +@interface FlutterSmallApiCodecReaderWriter : FlutterStandardReaderWriter +@end +@implementation FlutterSmallApiCodecReaderWriter +- (FlutterStandardWriter *)writerWithData:(NSMutableData *)data { + return [[FlutterSmallApiCodecWriter alloc] initWithData:data]; +} +- (FlutterStandardReader *)readerWithData:(NSData *)data { + return [[FlutterSmallApiCodecReader alloc] initWithData:data]; +} +@end + +NSObject *FlutterSmallApiGetCodec() { + static FlutterStandardMessageCodec *sSharedObject = nil; + static dispatch_once_t sPred = 0; + dispatch_once(&sPred, ^{ + FlutterSmallApiCodecReaderWriter *readerWriter = + [[FlutterSmallApiCodecReaderWriter alloc] init]; + sSharedObject = [FlutterStandardMessageCodec codecWithReaderWriter:readerWriter]; + }); + return sSharedObject; +} + +@interface FlutterSmallApi () +@property(nonatomic, strong) NSObject *binaryMessenger; +@end + +@implementation FlutterSmallApi + +- (instancetype)initWithBinaryMessenger:(NSObject *)binaryMessenger { + self = [super init]; + if (self) { + _binaryMessenger = binaryMessenger; + } + return self; +} +- (void)echoWrappedList:(TestMessage *)arg_msg + completion:(void (^)(TestMessage *_Nullable, FlutterError *_Nullable))completion { + FlutterBasicMessageChannel *channel = [FlutterBasicMessageChannel + messageChannelWithName:@"dev.flutter.pigeon.FlutterSmallApi.echoWrappedList" + binaryMessenger:self.binaryMessenger + codec:FlutterSmallApiGetCodec()]; + [channel sendMessage:@[ arg_msg ?: [NSNull null] ] + reply:^(id reply) { + TestMessage *output = reply; + completion(output, nil); + }]; +} +@end diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart index 0766a11069a2..a4f08bc5f3e8 100644 --- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart +++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart @@ -199,6 +199,28 @@ class AllNullableTypesWrapper { } } +/// A data class containing a List, used in unit tests. +class TestMessage { + TestMessage({ + this.testList, + }); + + List? testList; + + Object encode() { + return [ + testList, + ]; + } + + static TestMessage decode(Object result) { + result as List; + return TestMessage( + testList: result[0] as List?, + ); + } +} + class _HostIntegrationCoreApiCodec extends StandardMessageCodec { const _HostIntegrationCoreApiCodec(); @override @@ -212,6 +234,9 @@ class _HostIntegrationCoreApiCodec extends StandardMessageCodec { } else if (value is AllTypes) { buffer.putUint8(130); writeValue(buffer, value.encode()); + } else if (value is TestMessage) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -226,6 +251,8 @@ class _HostIntegrationCoreApiCodec extends StandardMessageCodec { return AllNullableTypesWrapper.decode(readValue(buffer)!); case 130: return AllTypes.decode(readValue(buffer)!); + case 131: + return TestMessage.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); } @@ -1897,6 +1924,9 @@ class _FlutterIntegrationCoreApiCodec extends StandardMessageCodec { } else if (value is AllTypes) { buffer.putUint8(130); writeValue(buffer, value.encode()); + } else if (value is TestMessage) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -1911,6 +1941,8 @@ class _FlutterIntegrationCoreApiCodec extends StandardMessageCodec { return AllNullableTypesWrapper.decode(readValue(buffer)!); case 130: return AllTypes.decode(readValue(buffer)!); + case 131: + return TestMessage.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); } @@ -1986,6 +2018,13 @@ abstract class FlutterIntegrationCoreApi { /// Returns the passed map, to test serialization and deserialization. Map? echoNullableMap(Map? aMap); + /// A no-op function taking no arguments and returning no value, to sanity + /// test basic asynchronous calling. + Future noopAsync(); + + /// Returns the passed in generic Object asynchronously. + Future echoAsyncString(String aString); + static void setup(FlutterIntegrationCoreApi? api, {BinaryMessenger? binaryMessenger}) { { @@ -2354,6 +2393,39 @@ abstract class FlutterIntegrationCoreApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FlutterIntegrationCoreApi.noopAsync', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + await api.noopAsync(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString was null.'); + final List args = (message as List?)!; + final String? arg_aString = (args[0] as String?); + assert(arg_aString != null, + 'Argument for dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString was null, expected non-null String.'); + final String output = await api.echoAsyncString(arg_aString!); + return output; + }); + } + } } } @@ -2389,3 +2461,115 @@ class HostTrivialApi { } } } + +/// A simple API implemented in some unit tests. +class HostSmallApi { + /// Constructor for [HostSmallApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + HostSmallApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = StandardMessageCodec(); + + Future echo(String arg_aString) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.HostSmallApi.echo', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_aString]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as String?)!; + } + } + + Future voidVoid() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.HostSmallApi.voidVoid', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } +} + +class _FlutterSmallApiCodec extends StandardMessageCodec { + const _FlutterSmallApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is TestMessage) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return TestMessage.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// A simple API called in some unit tests. +abstract class FlutterSmallApi { + static const MessageCodec codec = _FlutterSmallApiCodec(); + + TestMessage echoWrappedList(TestMessage msg); + + static void setup(FlutterSmallApi? api, {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FlutterSmallApi.echoWrappedList', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FlutterSmallApi.echoWrappedList was null.'); + final List args = (message as List?)!; + final TestMessage? arg_msg = (args[0] as TestMessage?); + assert(arg_msg != null, + 'Argument for dev.flutter.pigeon.FlutterSmallApi.echoWrappedList was null, expected non-null TestMessage.'); + final TestMessage output = api.echoWrappedList(arg_msg!); + return output; + }); + } + } + } +} diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart index b789e4a7d761..fbc87c570b9a 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart @@ -1368,4 +1368,12 @@ class _FlutterApiTestImplementation implements FlutterIntegrationCoreApi { @override Uint8List? echoNullableUint8List(Uint8List? aList) => aList; + + @override + Future noopAsync() async {} + + @override + Future echoAsyncString(String aString) async { + return aString; + } } diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart index 0766a11069a2..a4f08bc5f3e8 100644 --- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart +++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart @@ -199,6 +199,28 @@ class AllNullableTypesWrapper { } } +/// A data class containing a List, used in unit tests. +class TestMessage { + TestMessage({ + this.testList, + }); + + List? testList; + + Object encode() { + return [ + testList, + ]; + } + + static TestMessage decode(Object result) { + result as List; + return TestMessage( + testList: result[0] as List?, + ); + } +} + class _HostIntegrationCoreApiCodec extends StandardMessageCodec { const _HostIntegrationCoreApiCodec(); @override @@ -212,6 +234,9 @@ class _HostIntegrationCoreApiCodec extends StandardMessageCodec { } else if (value is AllTypes) { buffer.putUint8(130); writeValue(buffer, value.encode()); + } else if (value is TestMessage) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -226,6 +251,8 @@ class _HostIntegrationCoreApiCodec extends StandardMessageCodec { return AllNullableTypesWrapper.decode(readValue(buffer)!); case 130: return AllTypes.decode(readValue(buffer)!); + case 131: + return TestMessage.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); } @@ -1897,6 +1924,9 @@ class _FlutterIntegrationCoreApiCodec extends StandardMessageCodec { } else if (value is AllTypes) { buffer.putUint8(130); writeValue(buffer, value.encode()); + } else if (value is TestMessage) { + buffer.putUint8(131); + writeValue(buffer, value.encode()); } else { super.writeValue(buffer, value); } @@ -1911,6 +1941,8 @@ class _FlutterIntegrationCoreApiCodec extends StandardMessageCodec { return AllNullableTypesWrapper.decode(readValue(buffer)!); case 130: return AllTypes.decode(readValue(buffer)!); + case 131: + return TestMessage.decode(readValue(buffer)!); default: return super.readValueOfType(type, buffer); } @@ -1986,6 +2018,13 @@ abstract class FlutterIntegrationCoreApi { /// Returns the passed map, to test serialization and deserialization. Map? echoNullableMap(Map? aMap); + /// A no-op function taking no arguments and returning no value, to sanity + /// test basic asynchronous calling. + Future noopAsync(); + + /// Returns the passed in generic Object asynchronously. + Future echoAsyncString(String aString); + static void setup(FlutterIntegrationCoreApi? api, {BinaryMessenger? binaryMessenger}) { { @@ -2354,6 +2393,39 @@ abstract class FlutterIntegrationCoreApi { }); } } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FlutterIntegrationCoreApi.noopAsync', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + // ignore message + await api.noopAsync(); + return; + }); + } + } + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString was null.'); + final List args = (message as List?)!; + final String? arg_aString = (args[0] as String?); + assert(arg_aString != null, + 'Argument for dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString was null, expected non-null String.'); + final String output = await api.echoAsyncString(arg_aString!); + return output; + }); + } + } } } @@ -2389,3 +2461,115 @@ class HostTrivialApi { } } } + +/// A simple API implemented in some unit tests. +class HostSmallApi { + /// Constructor for [HostSmallApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + HostSmallApi({BinaryMessenger? binaryMessenger}) + : _binaryMessenger = binaryMessenger; + final BinaryMessenger? _binaryMessenger; + + static const MessageCodec codec = StandardMessageCodec(); + + Future echo(String arg_aString) async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.HostSmallApi.echo', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = + await channel.send([arg_aString]) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else if (replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (replyList[0] as String?)!; + } + } + + Future voidVoid() async { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.HostSmallApi.voidVoid', codec, + binaryMessenger: _binaryMessenger); + final List? replyList = await channel.send(null) as List?; + if (replyList == null) { + throw PlatformException( + code: 'channel-error', + message: 'Unable to establish connection on channel.', + ); + } else if (replyList.length > 1) { + throw PlatformException( + code: replyList[0]! as String, + message: replyList[1] as String?, + details: replyList[2], + ); + } else { + return; + } + } +} + +class _FlutterSmallApiCodec extends StandardMessageCodec { + const _FlutterSmallApiCodec(); + @override + void writeValue(WriteBuffer buffer, Object? value) { + if (value is TestMessage) { + buffer.putUint8(128); + writeValue(buffer, value.encode()); + } else { + super.writeValue(buffer, value); + } + } + + @override + Object? readValueOfType(int type, ReadBuffer buffer) { + switch (type) { + case 128: + return TestMessage.decode(readValue(buffer)!); + default: + return super.readValueOfType(type, buffer); + } + } +} + +/// A simple API called in some unit tests. +abstract class FlutterSmallApi { + static const MessageCodec codec = _FlutterSmallApiCodec(); + + TestMessage echoWrappedList(TestMessage msg); + + static void setup(FlutterSmallApi? api, {BinaryMessenger? binaryMessenger}) { + { + final BasicMessageChannel channel = BasicMessageChannel( + 'dev.flutter.pigeon.FlutterSmallApi.echoWrappedList', codec, + binaryMessenger: binaryMessenger); + if (api == null) { + channel.setMessageHandler(null); + } else { + channel.setMessageHandler((Object? message) async { + assert(message != null, + 'Argument for dev.flutter.pigeon.FlutterSmallApi.echoWrappedList was null.'); + final List args = (message as List?)!; + final TestMessage? arg_msg = (args[0] as TestMessage?); + assert(arg_msg != null, + 'Argument for dev.flutter.pigeon.FlutterSmallApi.echoWrappedList was null, expected non-null TestMessage.'); + final TestMessage output = api.echoWrappedList(arg_msg!); + return output; + }); + } + } + } +} diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt index 1af54e1b8124..dffa64725cc0 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt @@ -167,6 +167,29 @@ data class AllNullableTypesWrapper ( } } +/** + * A data class containing a List, used in unit tests. + * + * Generated class from Pigeon that represents data sent in messages. + */ +data class TestMessage ( + val testList: List? = null + +) { + companion object { + @Suppress("UNCHECKED_CAST") + fun fromList(list: List): TestMessage { + val testList = list[0] as? List + return TestMessage(testList) + } + } + fun toList(): List { + return listOf( + testList, + ) + } +} + @Suppress("UNCHECKED_CAST") private object HostIntegrationCoreApiCodec : StandardMessageCodec() { override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { @@ -186,6 +209,11 @@ private object HostIntegrationCoreApiCodec : StandardMessageCodec() { AllTypes.fromList(it) } } + 131.toByte() -> { + return (readValue(buffer) as? List)?.let { + TestMessage.fromList(it) + } + } else -> super.readValueOfType(type, buffer) } } @@ -203,6 +231,10 @@ private object HostIntegrationCoreApiCodec : StandardMessageCodec() { stream.write(130) writeValue(stream, value.toList()) } + is TestMessage -> { + stream.write(131) + writeValue(stream, value.toList()) + } else -> super.writeValue(stream, value) } } @@ -1623,6 +1655,11 @@ private object FlutterIntegrationCoreApiCodec : StandardMessageCodec() { AllTypes.fromList(it) } } + 131.toByte() -> { + return (readValue(buffer) as? List)?.let { + TestMessage.fromList(it) + } + } else -> super.readValueOfType(type, buffer) } } @@ -1640,6 +1677,10 @@ private object FlutterIntegrationCoreApiCodec : StandardMessageCodec() { stream.write(130) writeValue(stream, value.toList()) } + is TestMessage -> { + stream.write(131) + writeValue(stream, value.toList()) + } else -> super.writeValue(stream, value) } } @@ -1824,6 +1865,24 @@ class FlutterIntegrationCoreApi(private val binaryMessenger: BinaryMessenger) { callback(result) } } + /** + * A no-op function taking no arguments and returning no value, to sanity + * test basic asynchronous calling. + */ + fun noopAsync(callback: () -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.FlutterIntegrationCoreApi.noopAsync", codec) + channel.send(null) { + callback() + } + } + /** Returns the passed in generic Object asynchronously. */ + fun echoAsyncString(aStringArg: String, callback: (String) -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString", codec) + channel.send(listOf(aStringArg)) { + val result = it as String + callback(result) + } + } } /** * An API that can be implemented for minimal, compile-only tests. @@ -1861,3 +1920,106 @@ interface HostTrivialApi { } } } +/** + * A simple API implemented in some unit tests. + * + * Generated interface from Pigeon that represents a handler of messages from Flutter. + */ +interface HostSmallApi { + fun echo(aString: String, callback: (Result) -> Unit) + fun voidVoid(callback: (Result) -> Unit) + + companion object { + /** The codec used by HostSmallApi. */ + val codec: MessageCodec by lazy { + StandardMessageCodec() + } + /** Sets up an instance of `HostSmallApi` to handle messages through the `binaryMessenger`. */ + @Suppress("UNCHECKED_CAST") + fun setUp(binaryMessenger: BinaryMessenger, api: HostSmallApi?) { + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.HostSmallApi.echo", codec) + if (api != null) { + channel.setMessageHandler { message, reply -> + var wrapped = listOf() + val args = message as List + val aStringArg = args[0] as String + api.echo(aStringArg) { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + val data = result.getOrNull() + reply.reply(wrapResult(data)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + run { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.HostSmallApi.voidVoid", codec) + if (api != null) { + channel.setMessageHandler { _, reply -> + var wrapped = listOf() + api.voidVoid() { result: Result -> + val error = result.exceptionOrNull() + if (error != null) { + reply.reply(wrapError(error)) + } else { + reply.reply(wrapResult(null)) + } + } + } + } else { + channel.setMessageHandler(null) + } + } + } + } +} +@Suppress("UNCHECKED_CAST") +private object FlutterSmallApiCodec : StandardMessageCodec() { + override fun readValueOfType(type: Byte, buffer: ByteBuffer): Any? { + return when (type) { + 128.toByte() -> { + return (readValue(buffer) as? List)?.let { + TestMessage.fromList(it) + } + } + else -> super.readValueOfType(type, buffer) + } + } + override fun writeValue(stream: ByteArrayOutputStream, value: Any?) { + when (value) { + is TestMessage -> { + stream.write(128) + writeValue(stream, value.toList()) + } + else -> super.writeValue(stream, value) + } + } +} + +/** + * A simple API called in some unit tests. + * + * Generated class from Pigeon that represents Flutter messages that can be called from Kotlin. + */ +@Suppress("UNCHECKED_CAST") +class FlutterSmallApi(private val binaryMessenger: BinaryMessenger) { + companion object { + /** The codec used by FlutterSmallApi. */ + val codec: MessageCodec by lazy { + FlutterSmallApiCodec + } + } + fun echoWrappedList(msgArg: TestMessage, callback: (TestMessage) -> Unit) { + val channel = BasicMessageChannel(binaryMessenger, "dev.flutter.pigeon.FlutterSmallApi.echoWrappedList", codec) + channel.send(listOf(msgArg)) { + val result = it as TestMessage + callback(result) + } + } +} diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AsyncHandlersTest.kt b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AsyncHandlersTest.kt index 7deea92db475..97c3bc5d91a8 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AsyncHandlersTest.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AsyncHandlersTest.kt @@ -18,53 +18,60 @@ internal class AsyncHandlersTest: TestCase() { @Test fun testAsyncHost2Flutter() { val binaryMessenger = mockk() - val api = Api2Flutter(binaryMessenger) + val api = FlutterIntegrationCoreApi(binaryMessenger) - val input = Value(1) - val output = Value(2) + val value = "Test" every { binaryMessenger.send(any(), any(), any()) } answers { - val codec = Api2Flutter.codec + val codec = FlutterIntegrationCoreApi.codec val message = arg(1) val reply = arg(2) message.position(0) - val replyData = codec.encodeMessage(output) + val replyData = codec.encodeMessage(value) replyData?.position(0) reply.reply(replyData) } var didCall = false - api.calculate(input) { + api.echoAsyncString(value) { didCall = true - assertEquals(it, output) + assertEquals(it, value) } assertTrue(didCall) - verify { binaryMessenger.send("dev.flutter.pigeon.Api2Flutter.calculate", any(), any()) } + verify { + binaryMessenger.send( + "dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString", + any(), + any() + ) + } } @Test - fun testAsyncFlutter2HostCalculate() { + fun testAsyncFlutter2HostEcho() { val binaryMessenger = mockk() - val api = mockk() + val api = mockk() val handlerSlot = slot() - val input = Value(1) - val output = Value(2) - val channelName = "dev.flutter.pigeon.Api2Host.calculate" + val input = "Test" + val output = input + val channelName = "dev.flutter.pigeon.HostSmallApi.echo" - every { binaryMessenger.setMessageHandler("dev.flutter.pigeon.Api2Host.voidVoid", any()) } returns Unit + every { + binaryMessenger.setMessageHandler("dev.flutter.pigeon.HostSmallApi.voidVoid", any()) + } returns Unit every { binaryMessenger.setMessageHandler(channelName, capture(handlerSlot)) } returns Unit - every { api.calculate(any(), any()) } answers { - val callback = arg<(Result) -> Unit>(1) + every { api.echo(any(), any()) } answers { + val callback = arg<(Result) -> Unit>(1) callback(Result.success(output)) } - Api2Host.setUp(binaryMessenger, api) + HostSmallApi.setUp(binaryMessenger, api) - val codec = Api2Host.codec + val codec = HostSmallApi.codec val message = codec.encodeMessage(listOf(input)) message?.rewind() handlerSlot.captured.onMessage(message) { @@ -79,28 +86,30 @@ internal class AsyncHandlersTest: TestCase() { } verify { binaryMessenger.setMessageHandler(channelName, handlerSlot.captured) } - verify { api.calculate(input, any()) } + verify { api.echo(input, any()) } } @Test fun asyncFlutter2HostVoidVoid() { val binaryMessenger = mockk() - val api = mockk() + val api = mockk() val handlerSlot = slot() - val channelName = "dev.flutter.pigeon.Api2Host.voidVoid" + val channelName = "dev.flutter.pigeon.HostSmallApi.voidVoid" every { binaryMessenger.setMessageHandler(channelName, capture(handlerSlot)) } returns Unit - every { binaryMessenger.setMessageHandler("dev.flutter.pigeon.Api2Host.calculate", any()) } returns Unit + every { + binaryMessenger.setMessageHandler("dev.flutter.pigeon.HostSmallApi.echo", any()) + } returns Unit every { api.voidVoid(any()) } answers { val callback = arg<() -> Unit>(0) callback() } - Api2Host.setUp(binaryMessenger, api) + HostSmallApi.setUp(binaryMessenger, api) - val codec = Api2Host.codec + val codec = HostSmallApi.codec val message = codec.encodeMessage(null) handlerSlot.captured.onMessage(message) { it?.rewind() diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/ListTest.kt b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/ListTest.kt index d0edb5e6c52a..1a071f2dfc12 100644 --- a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/ListTest.kt +++ b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/ListTest.kt @@ -16,13 +16,13 @@ class ListTest: TestCase() { @Test fun testListInList() { val binaryMessenger = mockk() - val api = EchoApi(binaryMessenger) + val api = FlutterSmallApi(binaryMessenger) val inside = TestMessage(listOf(1, 2, 3)) val input = TestMessage(listOf(inside)) every { binaryMessenger.send(any(), any(), any()) } answers { - val codec = EchoApi.codec + val codec = FlutterSmallApi.codec val message = arg(1) val reply = arg(2) message.position(0) @@ -33,7 +33,7 @@ class ListTest: TestCase() { } var didCall = false - api.echo(input) { + api.echoWrappedList(input) { didCall = true assertEquals(input, it) } diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift index b9f569114ef8..ee64c085abed 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift @@ -1,14 +1,15 @@ // 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 Flutter import XCTest @testable import test_plugin -class MockApi2Host: Api2Host { - var output: Int32? +class MockHostSmallApi: HostSmallApi { + var output: String? - func calculate(value: Value, completion: @escaping (Result) -> Void) { - completion(.success(Value(number: output))) + func echo(aString: String, completion: @escaping (Result) -> Void) { + completion(.success(output!)) } func voidVoid(completion: @escaping (Result) -> Void) { @@ -19,25 +20,24 @@ class MockApi2Host: Api2Host { class AsyncHandlersTest: XCTestCase { func testAsyncHost2Flutter() throws { - let binaryMessenger = MockBinaryMessenger(codec: Api2FlutterCodec.shared) - binaryMessenger.result = Value(number: 2) - let api2Flutter = Api2Flutter(binaryMessenger: binaryMessenger) - let input = Value(number: 1) + let value = "Test" + let binaryMessenger = MockBinaryMessenger(codec: FlutterIntegrationCoreApiCodec.shared) + binaryMessenger.result = value + let flutterApi = FlutterIntegrationCoreApi(binaryMessenger: binaryMessenger) - let expectation = XCTestExpectation(description: "calculate callback") - api2Flutter.calculate(value: input) { output in - XCTAssertEqual(output.number, 2) + let expectation = XCTestExpectation(description: "callback") + flutterApi.echo(value) { output in + XCTAssertEqual(output, value) expectation.fulfill() } wait(for: [expectation], timeout: 1.0) } func testAsyncFlutter2HostVoidVoid() throws { - let binaryMessenger = MockBinaryMessenger(codec: Api2HostCodec.shared) - let mockApi2Host = MockApi2Host() - mockApi2Host.output = 2 - Api2HostSetup.setUp(binaryMessenger: binaryMessenger, api: mockApi2Host) - let channelName = "dev.flutter.pigeon.Api2Host.voidVoid" + let binaryMessenger = MockBinaryMessenger(codec: FlutterStandardMessageCodec.sharedInstance()) + let mockHostSmallApi = MockHostSmallApi() + HostSmallApiSetup.setUp(binaryMessenger: binaryMessenger, api: mockHostSmallApi) + let channelName = "dev.flutter.pigeon.HostSmallApi.voidVoid" XCTAssertNotNil(binaryMessenger.handlers[channelName]) let expectation = XCTestExpectation(description: "voidvoid callback") @@ -50,21 +50,21 @@ class AsyncHandlersTest: XCTestCase { } func testAsyncFlutter2Host() throws { - let binaryMessenger = MockBinaryMessenger(codec: Api2HostCodec.shared) - let mockApi2Host = MockApi2Host() - mockApi2Host.output = 2 - Api2HostSetup.setUp(binaryMessenger: binaryMessenger, api: mockApi2Host) - let channelName = "dev.flutter.pigeon.Api2Host.calculate" + let binaryMessenger = MockBinaryMessenger(codec: FlutterStandardMessageCodec.sharedInstance()) + let mockHostSmallApi = MockHostSmallApi() + let value = "Test" + mockHostSmallApi.output = value + HostSmallApiSetup.setUp(binaryMessenger: binaryMessenger, api: mockHostSmallApi) + let channelName = "dev.flutter.pigeon.HostSmallApi.echo" XCTAssertNotNil(binaryMessenger.handlers[channelName]) - let input = Value(number: 1) - let inputEncoded = binaryMessenger.codec.encode([input]) + let inputEncoded = binaryMessenger.codec.encode([value]) - let expectation = XCTestExpectation(description: "calculate callback") + let expectation = XCTestExpectation(description: "echo callback") binaryMessenger.handlers[channelName]?(inputEncoded) { data in let outputList = binaryMessenger.codec.decode(data) as? [Any] - let output = outputList?.first as? Value - XCTAssertEqual(output?.number, 2) + let output = outputList?.first as? String + XCTAssertEqual(output, value) expectation.fulfill() } wait(for: [expectation], timeout: 1.0) diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/ListTests.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/ListTests.swift index 5726c1102671..c48068e234d8 100644 --- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/ListTests.swift +++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/ListTests.swift @@ -10,11 +10,11 @@ class ListTests: XCTestCase { func testListInList() throws { let inside = TestMessage(testList: [1, 2, 3]) let top = TestMessage(testList: [inside]) - let binaryMessenger = EchoBinaryMessenger(codec: EchoApiCodec.shared) - let api = EchoApi(binaryMessenger: binaryMessenger) + let binaryMessenger = EchoBinaryMessenger(codec: FlutterSmallApiCodec.shared) + let api = FlutterSmallApi(binaryMessenger: binaryMessenger) let expectation = XCTestExpectation(description: "callback") - api.echo(msg: top) { result in + api.echo(top) { result in XCTAssertEqual(1, result.testList?.count) XCTAssertTrue(result.testList?[0] is TestMessage) XCTAssert(equalsList(inside.testList, (result.testList?[0] as! TestMessage).testList)) diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift index ad1b2c1344f0..3f3d3bbd6b19 100644 --- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift @@ -190,6 +190,26 @@ struct AllNullableTypesWrapper { } } +/// A data class containing a List, used in unit tests. +/// +/// Generated class from Pigeon that represents data sent in messages. +struct TestMessage { + var testList: [Any?]? = nil + + static func fromList(_ list: [Any?]) -> TestMessage? { + let testList = list[0] as? [Any?] + + return TestMessage( + testList: testList + ) + } + func toList() -> [Any?] { + return [ + testList, + ] + } +} + private class HostIntegrationCoreApiCodecReader: FlutterStandardReader { override func readValue(ofType type: UInt8) -> Any? { switch type { @@ -199,6 +219,8 @@ private class HostIntegrationCoreApiCodecReader: FlutterStandardReader { return AllNullableTypesWrapper.fromList(self.readValue() as! [Any]) case 130: return AllTypes.fromList(self.readValue() as! [Any]) + case 131: + return TestMessage.fromList(self.readValue() as! [Any]) default: return super.readValue(ofType: type) } @@ -216,6 +238,9 @@ private class HostIntegrationCoreApiCodecWriter: FlutterStandardWriter { } else if let value = value as? AllTypes { super.writeByte(130) super.writeValue(value.toList()) + } else if let value = value as? TestMessage { + super.writeByte(131) + super.writeValue(value.toList()) } else { super.writeValue(value) } @@ -1448,6 +1473,8 @@ private class FlutterIntegrationCoreApiCodecReader: FlutterStandardReader { return AllNullableTypesWrapper.fromList(self.readValue() as! [Any]) case 130: return AllTypes.fromList(self.readValue() as! [Any]) + case 131: + return TestMessage.fromList(self.readValue() as! [Any]) default: return super.readValue(ofType: type) } @@ -1465,6 +1492,9 @@ private class FlutterIntegrationCoreApiCodecWriter: FlutterStandardWriter { } else if let value = value as? AllTypes { super.writeByte(130) super.writeValue(value.toList()) + } else if let value = value as? TestMessage { + super.writeByte(131) + super.writeValue(value.toList()) } else { super.writeValue(value) } @@ -1658,6 +1688,22 @@ class FlutterIntegrationCoreApi { completion(result) } } + /// A no-op function taking no arguments and returning no value, to sanity + /// test basic asynchronous calling. + func noopAsync(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.FlutterIntegrationCoreApi.noopAsync", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Returns the passed in generic Object asynchronously. + func echoAsync(_ aStringArg: String, completion: @escaping (String) -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([aStringArg] as [Any?]) { response in + let result = response as! String + completion(result) + } + } } /// An API that can be implemented for minimal, compile-only tests. /// @@ -1686,3 +1732,105 @@ class HostTrivialApiSetup { } } } +/// A simple API implemented in some unit tests. +/// +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol HostSmallApi { + func echo(aString: String, completion: @escaping (Result) -> Void) + func voidVoid(completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class HostSmallApiSetup { + /// The codec used by HostSmallApi. + /// Sets up an instance of `HostSmallApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: HostSmallApi?) { + let echoChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostSmallApi.echo", binaryMessenger: binaryMessenger) + if let api = api { + echoChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let aStringArg = args[0] as! String + api.echo(aString: aStringArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + echoChannel.setMessageHandler(nil) + } + let voidVoidChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostSmallApi.voidVoid", binaryMessenger: binaryMessenger) + if let api = api { + voidVoidChannel.setMessageHandler { _, reply in + api.voidVoid() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + voidVoidChannel.setMessageHandler(nil) + } + } +} +private class FlutterSmallApiCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 128: + return TestMessage.fromList(self.readValue() as! [Any]) + default: + return super.readValue(ofType: type) + } + } +} + +private class FlutterSmallApiCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? TestMessage { + super.writeByte(128) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class FlutterSmallApiCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return FlutterSmallApiCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return FlutterSmallApiCodecWriter(data: data) + } +} + +class FlutterSmallApiCodec: FlutterStandardMessageCodec { + static let shared = FlutterSmallApiCodec(readerWriter: FlutterSmallApiCodecReaderWriter()) +} + +/// A simple API called in some unit tests. +/// +/// Generated class from Pigeon that represents Flutter messages that can be called from Swift. +class FlutterSmallApi { + private let binaryMessenger: FlutterBinaryMessenger + init(binaryMessenger: FlutterBinaryMessenger){ + self.binaryMessenger = binaryMessenger + } + var codec: FlutterStandardMessageCodec { + return FlutterSmallApiCodec.shared + } + func echo(_ msgArg: TestMessage, completion: @escaping (TestMessage) -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.FlutterSmallApi.echoWrappedList", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([msgArg] as [Any?]) { response in + let result = response as! TestMessage + completion(result) + } + } +} diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift index ad1b2c1344f0..3f3d3bbd6b19 100644 --- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift +++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift @@ -190,6 +190,26 @@ struct AllNullableTypesWrapper { } } +/// A data class containing a List, used in unit tests. +/// +/// Generated class from Pigeon that represents data sent in messages. +struct TestMessage { + var testList: [Any?]? = nil + + static func fromList(_ list: [Any?]) -> TestMessage? { + let testList = list[0] as? [Any?] + + return TestMessage( + testList: testList + ) + } + func toList() -> [Any?] { + return [ + testList, + ] + } +} + private class HostIntegrationCoreApiCodecReader: FlutterStandardReader { override func readValue(ofType type: UInt8) -> Any? { switch type { @@ -199,6 +219,8 @@ private class HostIntegrationCoreApiCodecReader: FlutterStandardReader { return AllNullableTypesWrapper.fromList(self.readValue() as! [Any]) case 130: return AllTypes.fromList(self.readValue() as! [Any]) + case 131: + return TestMessage.fromList(self.readValue() as! [Any]) default: return super.readValue(ofType: type) } @@ -216,6 +238,9 @@ private class HostIntegrationCoreApiCodecWriter: FlutterStandardWriter { } else if let value = value as? AllTypes { super.writeByte(130) super.writeValue(value.toList()) + } else if let value = value as? TestMessage { + super.writeByte(131) + super.writeValue(value.toList()) } else { super.writeValue(value) } @@ -1448,6 +1473,8 @@ private class FlutterIntegrationCoreApiCodecReader: FlutterStandardReader { return AllNullableTypesWrapper.fromList(self.readValue() as! [Any]) case 130: return AllTypes.fromList(self.readValue() as! [Any]) + case 131: + return TestMessage.fromList(self.readValue() as! [Any]) default: return super.readValue(ofType: type) } @@ -1465,6 +1492,9 @@ private class FlutterIntegrationCoreApiCodecWriter: FlutterStandardWriter { } else if let value = value as? AllTypes { super.writeByte(130) super.writeValue(value.toList()) + } else if let value = value as? TestMessage { + super.writeByte(131) + super.writeValue(value.toList()) } else { super.writeValue(value) } @@ -1658,6 +1688,22 @@ class FlutterIntegrationCoreApi { completion(result) } } + /// A no-op function taking no arguments and returning no value, to sanity + /// test basic asynchronous calling. + func noopAsync(completion: @escaping () -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.FlutterIntegrationCoreApi.noopAsync", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage(nil) { _ in + completion() + } + } + /// Returns the passed in generic Object asynchronously. + func echoAsync(_ aStringArg: String, completion: @escaping (String) -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([aStringArg] as [Any?]) { response in + let result = response as! String + completion(result) + } + } } /// An API that can be implemented for minimal, compile-only tests. /// @@ -1686,3 +1732,105 @@ class HostTrivialApiSetup { } } } +/// A simple API implemented in some unit tests. +/// +/// Generated protocol from Pigeon that represents a handler of messages from Flutter. +protocol HostSmallApi { + func echo(aString: String, completion: @escaping (Result) -> Void) + func voidVoid(completion: @escaping (Result) -> Void) +} + +/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. +class HostSmallApiSetup { + /// The codec used by HostSmallApi. + /// Sets up an instance of `HostSmallApi` to handle messages through the `binaryMessenger`. + static func setUp(binaryMessenger: FlutterBinaryMessenger, api: HostSmallApi?) { + let echoChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostSmallApi.echo", binaryMessenger: binaryMessenger) + if let api = api { + echoChannel.setMessageHandler { message, reply in + let args = message as! [Any?] + let aStringArg = args[0] as! String + api.echo(aString: aStringArg) { result in + switch result { + case .success(let res): + reply(wrapResult(res)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + echoChannel.setMessageHandler(nil) + } + let voidVoidChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostSmallApi.voidVoid", binaryMessenger: binaryMessenger) + if let api = api { + voidVoidChannel.setMessageHandler { _, reply in + api.voidVoid() { result in + switch result { + case .success: + reply(wrapResult(nil)) + case .failure(let error): + reply(wrapError(error)) + } + } + } + } else { + voidVoidChannel.setMessageHandler(nil) + } + } +} +private class FlutterSmallApiCodecReader: FlutterStandardReader { + override func readValue(ofType type: UInt8) -> Any? { + switch type { + case 128: + return TestMessage.fromList(self.readValue() as! [Any]) + default: + return super.readValue(ofType: type) + } + } +} + +private class FlutterSmallApiCodecWriter: FlutterStandardWriter { + override func writeValue(_ value: Any) { + if let value = value as? TestMessage { + super.writeByte(128) + super.writeValue(value.toList()) + } else { + super.writeValue(value) + } + } +} + +private class FlutterSmallApiCodecReaderWriter: FlutterStandardReaderWriter { + override func reader(with data: Data) -> FlutterStandardReader { + return FlutterSmallApiCodecReader(data: data) + } + + override func writer(with data: NSMutableData) -> FlutterStandardWriter { + return FlutterSmallApiCodecWriter(data: data) + } +} + +class FlutterSmallApiCodec: FlutterStandardMessageCodec { + static let shared = FlutterSmallApiCodec(readerWriter: FlutterSmallApiCodecReaderWriter()) +} + +/// A simple API called in some unit tests. +/// +/// Generated class from Pigeon that represents Flutter messages that can be called from Swift. +class FlutterSmallApi { + private let binaryMessenger: FlutterBinaryMessenger + init(binaryMessenger: FlutterBinaryMessenger){ + self.binaryMessenger = binaryMessenger + } + var codec: FlutterStandardMessageCodec { + return FlutterSmallApiCodec.shared + } + func echo(_ msgArg: TestMessage, completion: @escaping (TestMessage) -> Void) { + let channel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.FlutterSmallApi.echoWrappedList", binaryMessenger: binaryMessenger, codec: codec) + channel.sendMessage([msgArg] as [Any?]) { response in + let result = response as! TestMessage + completion(result) + } + } +} diff --git a/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt b/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt index 97c0e7e4c96c..4e41dd7f3c92 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt +++ b/packages/pigeon/platform_tests/test_plugin/windows/CMakeLists.txt @@ -17,16 +17,10 @@ list(APPEND PLUGIN_SOURCES "test_plugin.cpp" "test_plugin.h" # Generated sources. - "pigeon/async_handlers.gen.cpp" - "pigeon/async_handlers.gen.h" "pigeon/core_tests.gen.cpp" "pigeon/core_tests.gen.h" "pigeon/enum.gen.cpp" "pigeon/enum.gen.h" - "pigeon/host2flutter.gen.cpp" - "pigeon/host2flutter.gen.h" - "pigeon/list.gen.cpp" - "pigeon/list.gen.h" "pigeon/message.gen.cpp" "pigeon/message.gen.h" "pigeon/multiple_arity.gen.cpp" @@ -39,14 +33,6 @@ list(APPEND PLUGIN_SOURCES "pigeon/nullable_returns.gen.h" "pigeon/primitive.gen.cpp" "pigeon/primitive.gen.h" - "pigeon/void_arg_flutter.gen.cpp" - "pigeon/void_arg_flutter.gen.h" - "pigeon/void_arg_host.gen.cpp" - "pigeon/void_arg_host.gen.h" - "pigeon/voidflutter.gen.cpp" - "pigeon/voidflutter.gen.h" - "pigeon/voidhost.gen.cpp" - "pigeon/voidhost.gen.h" ) # Define the plugin library target. Its name must not be changed (see comment diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp index 3d44397c4f3a..d390add49136 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp @@ -473,6 +473,36 @@ AllNullableTypesWrapper::AllNullableTypesWrapper(const EncodableList& list) { } } +// TestMessage + +const EncodableList* TestMessage::test_list() const { + return test_list_ ? &(*test_list_) : nullptr; +} +void TestMessage::set_test_list(const EncodableList* value_arg) { + test_list_ = + value_arg ? std::optional(*value_arg) : std::nullopt; +} +void TestMessage::set_test_list(const EncodableList& value_arg) { + test_list_ = value_arg; +} + +EncodableList TestMessage::ToEncodableList() const { + EncodableList list; + list.reserve(1); + list.push_back(test_list_ ? EncodableValue(*test_list_) : EncodableValue()); + return list; +} + +TestMessage::TestMessage() {} + +TestMessage::TestMessage(const EncodableList& list) { + auto& encodable_test_list = list[0]; + if (const EncodableList* pointer_test_list = + std::get_if(&encodable_test_list)) { + test_list_ = *pointer_test_list; + } +} + HostIntegrationCoreApiCodecSerializer::HostIntegrationCoreApiCodecSerializer() { } EncodableValue HostIntegrationCoreApiCodecSerializer::ReadValueOfType( @@ -487,6 +517,9 @@ EncodableValue HostIntegrationCoreApiCodecSerializer::ReadValueOfType( case 130: return CustomEncodableValue( AllTypes(std::get(ReadValue(stream)))); + case 131: + return CustomEncodableValue( + TestMessage(std::get(ReadValue(stream)))); default: return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); } @@ -519,6 +552,14 @@ void HostIntegrationCoreApiCodecSerializer::WriteValue( stream); return; } + if (custom_value->type() == typeid(TestMessage)) { + stream->WriteByte(131); + WriteValue( + EncodableValue( + std::any_cast(*custom_value).ToEncodableList()), + stream); + return; + } } flutter::StandardCodecSerializer::WriteValue(value, stream); } @@ -2881,6 +2922,9 @@ EncodableValue FlutterIntegrationCoreApiCodecSerializer::ReadValueOfType( case 130: return CustomEncodableValue( AllTypes(std::get(ReadValue(stream)))); + case 131: + return CustomEncodableValue( + TestMessage(std::get(ReadValue(stream)))); default: return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); } @@ -2913,6 +2957,14 @@ void FlutterIntegrationCoreApiCodecSerializer::WriteValue( stream); return; } + if (custom_value->type() == typeid(TestMessage)) { + stream->WriteByte(131); + WriteValue( + EncodableValue( + std::any_cast(*custom_value).ToEncodableList()), + stream); + return; + } } flutter::StandardCodecSerializer::WriteValue(value, stream); } @@ -3355,6 +3407,41 @@ void FlutterIntegrationCoreApi::EchoNullableMap( on_success(return_value); }); } +void FlutterIntegrationCoreApi::NoopAsync( + std::function&& on_success, + std::function&& on_error) { + auto channel = std::make_unique>( + binary_messenger_, + "dev.flutter.pigeon.FlutterIntegrationCoreApi.noopAsync", &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(); + channel->Send( + encoded_api_arguments, + [on_success = std::move(on_success), on_error = std::move(on_error)]( + const uint8_t* reply, size_t reply_size) { on_success(); }); +} +void FlutterIntegrationCoreApi::EchoAsyncString( + const std::string& a_string_arg, + std::function&& on_success, + std::function&& on_error) { + auto channel = std::make_unique>( + binary_messenger_, + "dev.flutter.pigeon.FlutterIntegrationCoreApi.echoAsyncString", + &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(a_string_arg), + }); + channel->Send( + encoded_api_arguments, + [on_success = std::move(on_success), on_error = std::move(on_error)]( + const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = + GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto& return_value = + std::get(encodable_return_value); + on_success(return_value); + }); +} /// The codec used by HostTrivialApi. const flutter::StandardMessageCodec& HostTrivialApi::GetCodec() { return flutter::StandardMessageCodec::GetInstance( @@ -3403,4 +3490,148 @@ EncodableValue HostTrivialApi::WrapError(const FlutterError& error) { error.details()}); } +/// The codec used by HostSmallApi. +const flutter::StandardMessageCodec& HostSmallApi::GetCodec() { + return flutter::StandardMessageCodec::GetInstance( + &flutter::StandardCodecSerializer::GetInstance()); +} + +// Sets up an instance of `HostSmallApi` to handle messages through the +// `binary_messenger`. +void HostSmallApi::SetUp(flutter::BinaryMessenger* binary_messenger, + HostSmallApi* api) { + { + auto channel = std::make_unique>( + binary_messenger, "dev.flutter.pigeon.HostSmallApi.echo", &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + const auto& args = std::get(message); + const auto& encodable_a_string_arg = args.at(0); + if (encodable_a_string_arg.IsNull()) { + reply(WrapError("a_string_arg unexpectedly null.")); + return; + } + const auto& a_string_arg = + std::get(encodable_a_string_arg); + api->Echo(a_string_arg, [reply](ErrorOr&& output) { + if (output.has_error()) { + reply(WrapError(output.error())); + return; + } + EncodableList wrapped; + wrapped.push_back( + EncodableValue(std::move(output).TakeValue())); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } + { + auto channel = std::make_unique>( + binary_messenger, "dev.flutter.pigeon.HostSmallApi.voidVoid", + &GetCodec()); + if (api != nullptr) { + channel->SetMessageHandler( + [api](const EncodableValue& message, + const flutter::MessageReply& reply) { + try { + api->VoidVoid([reply](std::optional&& output) { + if (output.has_value()) { + reply(WrapError(output.value())); + return; + } + EncodableList wrapped; + wrapped.push_back(EncodableValue()); + reply(EncodableValue(std::move(wrapped))); + }); + } catch (const std::exception& exception) { + reply(WrapError(exception.what())); + } + }); + } else { + channel->SetMessageHandler(nullptr); + } + } +} + +EncodableValue HostSmallApi::WrapError(std::string_view error_message) { + return EncodableValue( + EncodableList{EncodableValue(std::string(error_message)), + EncodableValue("Error"), EncodableValue()}); +} +EncodableValue HostSmallApi::WrapError(const FlutterError& error) { + return EncodableValue(EncodableList{EncodableValue(error.message()), + EncodableValue(error.code()), + error.details()}); +} + +FlutterSmallApiCodecSerializer::FlutterSmallApiCodecSerializer() {} +EncodableValue FlutterSmallApiCodecSerializer::ReadValueOfType( + uint8_t type, flutter::ByteStreamReader* stream) const { + switch (type) { + case 128: + return CustomEncodableValue( + TestMessage(std::get(ReadValue(stream)))); + default: + return flutter::StandardCodecSerializer::ReadValueOfType(type, stream); + } +} + +void FlutterSmallApiCodecSerializer::WriteValue( + const EncodableValue& value, flutter::ByteStreamWriter* stream) const { + if (const CustomEncodableValue* custom_value = + std::get_if(&value)) { + if (custom_value->type() == typeid(TestMessage)) { + stream->WriteByte(128); + WriteValue( + EncodableValue( + std::any_cast(*custom_value).ToEncodableList()), + stream); + return; + } + } + flutter::StandardCodecSerializer::WriteValue(value, stream); +} + +// Generated class from Pigeon that represents Flutter messages that can be +// called from C++. +FlutterSmallApi::FlutterSmallApi(flutter::BinaryMessenger* binary_messenger) { + this->binary_messenger_ = binary_messenger; +} + +const flutter::StandardMessageCodec& FlutterSmallApi::GetCodec() { + return flutter::StandardMessageCodec::GetInstance( + &FlutterSmallApiCodecSerializer::GetInstance()); +} + +void FlutterSmallApi::EchoWrappedList( + const TestMessage& msg_arg, + std::function&& on_success, + std::function&& on_error) { + auto channel = std::make_unique>( + binary_messenger_, "dev.flutter.pigeon.FlutterSmallApi.echoWrappedList", + &GetCodec()); + EncodableValue encoded_api_arguments = EncodableValue(EncodableList{ + EncodableValue(msg_arg.ToEncodableList()), + }); + channel->Send( + encoded_api_arguments, + [on_success = std::move(on_success), on_error = std::move(on_error)]( + const uint8_t* reply, size_t reply_size) { + std::unique_ptr response = + GetCodec().DecodeMessage(reply, reply_size); + const auto& encodable_return_value = *response; + const auto& return_value = std::any_cast( + std::get(encodable_return_value)); + on_success(return_value); + }); +} } // namespace core_tests_pigeontest diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h index 2bc6fcda86c0..513bae6682f8 100644 --- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h +++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h @@ -57,6 +57,8 @@ class ErrorOr { friend class HostIntegrationCoreApi; friend class FlutterIntegrationCoreApi; friend class HostTrivialApi; + friend class HostSmallApi; + friend class FlutterSmallApi; ErrorOr() = default; T TakeValue() && { return std::get(std::move(v_)); } @@ -111,6 +113,10 @@ class AllTypes { friend class FlutterIntegrationCoreApiCodecSerializer; friend class HostTrivialApi; friend class HostTrivialApiCodecSerializer; + friend class HostSmallApi; + friend class HostSmallApiCodecSerializer; + friend class FlutterSmallApi; + friend class FlutterSmallApiCodecSerializer; friend class CoreTestsTest; bool a_bool_; int64_t an_int_; @@ -197,6 +203,10 @@ class AllNullableTypes { friend class FlutterIntegrationCoreApiCodecSerializer; friend class HostTrivialApi; friend class HostTrivialApiCodecSerializer; + friend class HostSmallApi; + friend class HostSmallApiCodecSerializer; + friend class FlutterSmallApi; + friend class FlutterSmallApiCodecSerializer; friend class CoreTestsTest; std::optional a_nullable_bool_; std::optional a_nullable_int_; @@ -230,10 +240,41 @@ class AllNullableTypesWrapper { friend class FlutterIntegrationCoreApiCodecSerializer; friend class HostTrivialApi; friend class HostTrivialApiCodecSerializer; + friend class HostSmallApi; + friend class HostSmallApiCodecSerializer; + friend class FlutterSmallApi; + friend class FlutterSmallApiCodecSerializer; friend class CoreTestsTest; AllNullableTypes values_; }; +// A data class containing a List, used in unit tests. +// +// Generated class from Pigeon that represents data sent in messages. +class TestMessage { + public: + TestMessage(); + const flutter::EncodableList* test_list() const; + void set_test_list(const flutter::EncodableList* value_arg); + void set_test_list(const flutter::EncodableList& value_arg); + + private: + TestMessage(const flutter::EncodableList& list); + flutter::EncodableList ToEncodableList() const; + friend class HostIntegrationCoreApi; + friend class HostIntegrationCoreApiCodecSerializer; + friend class FlutterIntegrationCoreApi; + friend class FlutterIntegrationCoreApiCodecSerializer; + friend class HostTrivialApi; + friend class HostTrivialApiCodecSerializer; + friend class HostSmallApi; + friend class HostSmallApiCodecSerializer; + friend class FlutterSmallApi; + friend class FlutterSmallApiCodecSerializer; + friend class CoreTestsTest; + std::optional test_list_; +}; + class HostIntegrationCoreApiCodecSerializer : public flutter::StandardCodecSerializer { public: @@ -607,6 +648,14 @@ class FlutterIntegrationCoreApi { const flutter::EncodableMap* a_map, std::function&& on_success, std::function&& on_error); + // A no-op function taking no arguments and returning no value, to sanity + // test basic asynchronous calling. + void NoopAsync(std::function&& on_success, + std::function&& on_error); + // Returns the passed in generic Object asynchronously. + void EchoAsyncString(const std::string& a_string, + std::function&& on_success, + std::function&& on_error); }; // An API that can be implemented for minimal, compile-only tests. @@ -632,5 +681,65 @@ class HostTrivialApi { protected: HostTrivialApi() = default; }; +// A simple API implemented in some unit tests. +// +// Generated interface from Pigeon that represents a handler of messages from +// Flutter. +class HostSmallApi { + public: + HostSmallApi(const HostSmallApi&) = delete; + HostSmallApi& operator=(const HostSmallApi&) = delete; + virtual ~HostSmallApi() {} + virtual void Echo(const std::string& a_string, + std::function reply)> result) = 0; + virtual void VoidVoid( + std::function reply)> result) = 0; + + // The codec used by HostSmallApi. + static const flutter::StandardMessageCodec& GetCodec(); + // Sets up an instance of `HostSmallApi` to handle messages through the + // `binary_messenger`. + static void SetUp(flutter::BinaryMessenger* binary_messenger, + HostSmallApi* api); + static flutter::EncodableValue WrapError(std::string_view error_message); + static flutter::EncodableValue WrapError(const FlutterError& error); + + protected: + HostSmallApi() = default; +}; +class FlutterSmallApiCodecSerializer : public flutter::StandardCodecSerializer { + public: + inline static FlutterSmallApiCodecSerializer& GetInstance() { + static FlutterSmallApiCodecSerializer sInstance; + return sInstance; + } + + FlutterSmallApiCodecSerializer(); + + public: + void WriteValue(const flutter::EncodableValue& value, + flutter::ByteStreamWriter* stream) const override; + + protected: + flutter::EncodableValue ReadValueOfType( + uint8_t type, flutter::ByteStreamReader* stream) const override; +}; + +// A simple API called in some unit tests. +// +// Generated class from Pigeon that represents Flutter messages that can be +// called from C++. +class FlutterSmallApi { + private: + flutter::BinaryMessenger* binary_messenger_; + + public: + FlutterSmallApi(flutter::BinaryMessenger* binary_messenger); + static const flutter::StandardMessageCodec& GetCodec(); + void EchoWrappedList(const TestMessage& msg, + std::function&& on_success, + std::function&& on_error); +}; + } // namespace core_tests_pigeontest #endif // PIGEON_CORE_TESTS_GEN_H_ diff --git a/packages/pigeon/tool/shared/generation.dart b/packages/pigeon/tool/shared/generation.dart index 01efa09c8f5f..9cc1eedfe091 100644 --- a/packages/pigeon/tool/shared/generation.dart +++ b/packages/pigeon/tool/shared/generation.dart @@ -16,9 +16,7 @@ enum GeneratorLanguages { // A map of pigeons/ files to the languages that they can't yet be generated // for due to limitations of that generator. const Map> _unsupportedFiles = - >{ - 'enum_args': {GeneratorLanguages.cpp}, -}; + >{}; String _snakeToPascalCase(String snake) { final List parts = snake.split('_'); @@ -37,12 +35,7 @@ String _snakeToPascalCase(String snake) { // https://github.com/flutter/flutter/issues/115168. String _javaFilenameForName(String inputName) { const Map specialCases = { - 'android_unittests': 'Pigeon', - 'host2flutter': 'Host2Flutter', - 'list': 'PigeonList', 'message': 'MessagePigeon', - 'voidflutter': 'VoidFlutter', - 'voidhost': 'VoidHost', }; return specialCases[inputName] ?? _snakeToPascalCase(inputName); } @@ -51,25 +44,15 @@ Future generatePigeons({required String baseDir}) async { // TODO(stuartmorgan): Make this dynamic rather than hard-coded. Or eliminate // it entirely; see https://github.com/flutter/flutter/issues/115169. const List inputs = [ - 'android_unittests', - 'async_handlers', 'background_platform_channels', 'core_tests', - 'enum_args', 'enum', - 'host2flutter', - 'java_double_host_api', - 'list', 'message', 'multiple_arity', 'non_null_fields', 'null_fields', 'nullable_returns', 'primitive', - 'void_arg_flutter', - 'void_arg_host', - 'voidflutter', - 'voidhost', ]; final String outputBase = p.join(baseDir, 'platform_tests', 'test_plugin'); diff --git a/packages/pigeon/tool/shared/test_suites.dart b/packages/pigeon/tool/shared/test_suites.dart index 1ff1dd6da359..a62b70ba9c8f 100644 --- a/packages/pigeon/tool/shared/test_suites.dart +++ b/packages/pigeon/tool/shared/test_suites.dart @@ -216,18 +216,6 @@ Future _runFlutterUnitTests() async { 'non_null_fields', 'null_fields', 'nullable_returns', - // TODO(stuartmorgan): Eliminate these files by ensuring that everything - // they are intended to cover is in core_tests.dart (or, if necessary in - // the short term due to limitations in non-Dart generators, a single other - // file). They aren't being unit tested, only analyzed. - 'async_handlers', - 'host2flutter', - 'list', - 'message', - 'void_arg_flutter', - 'void_arg_host', - 'voidflutter', - 'voidhost', ]; final int generateCode = await _generateDart({ for (final String name in inputPigeons)