diff --git a/shell/platform/android/BUILD.gn b/shell/platform/android/BUILD.gn index 05b176b421273..8869eadc95489 100644 --- a/shell/platform/android/BUILD.gn +++ b/shell/platform/android/BUILD.gn @@ -439,6 +439,7 @@ action("robolectric_tests") { "test/io/flutter/embedding/engine/renderer/FlutterRendererTest.java", "test/io/flutter/external/FlutterLaunchTests.java", "test/io/flutter/plugin/common/StandardMessageCodecTest.java", + "test/io/flutter/plugin/common/StandardMethodCodecTest.java", "test/io/flutter/plugin/editing/InputConnectionAdaptorTest.java", "test/io/flutter/plugin/editing/TextInputPluginTest.java", "test/io/flutter/plugin/platform/PlatformPluginTest.java", diff --git a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java index 65ea2393d6cd4..f8cbb2c71090b 100644 --- a/shell/platform/android/io/flutter/plugin/common/MethodChannel.java +++ b/shell/platform/android/io/flutter/plugin/common/MethodChannel.java @@ -166,8 +166,8 @@ public interface Result { * Handles a successful result. * * @param result The result, possibly null. The result must be an Object type supported by the - * codec. For instance, if you are using StandardCodec (default), please see {@link - * StandardMessageCodec} documentation on what types are supported. + * codec. For instance, if you are using {@link StandardMessageCodec} (default), please see + * its documentation on what types are supported. */ @UiThread void success(@Nullable Object result); @@ -178,8 +178,8 @@ public interface Result { * @param errorCode An error code String. * @param errorMessage A human-readable error message String, possibly null. * @param errorDetails Error details, possibly null. The details must be an Object type - * supported by the codec. For instance, if you are using StandardCodec (default), please - * see {@link StandardMessageCodec} documentation on what types are supported. + * supported by the codec. For instance, if you are using {@link StandardMessageCodec} + * (default), please see its documentation on what types are supported. */ @UiThread void error(String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails); diff --git a/shell/platform/android/io/flutter/plugin/common/MethodCodec.java b/shell/platform/android/io/flutter/plugin/common/MethodCodec.java index 8c9a867785ae9..fba950f9a499c 100644 --- a/shell/platform/android/io/flutter/plugin/common/MethodCodec.java +++ b/shell/platform/android/io/flutter/plugin/common/MethodCodec.java @@ -48,7 +48,8 @@ public interface MethodCodec { * * @param errorCode An error code String. * @param errorMessage An error message String, possibly null. - * @param errorDetails Error details, possibly null. + * @param errorDetails Error details, possibly null. Consider supporting {@link Throwable} in your + * codec. This is the most common value passed to this field. * @return a {@link ByteBuffer} containing the encoding between position 0 and the current * position. */ diff --git a/shell/platform/android/test/io/flutter/FlutterTestSuite.java b/shell/platform/android/test/io/flutter/FlutterTestSuite.java index 509c91c298988..820e428fce715 100644 --- a/shell/platform/android/test/io/flutter/FlutterTestSuite.java +++ b/shell/platform/android/test/io/flutter/FlutterTestSuite.java @@ -17,6 +17,7 @@ import io.flutter.embedding.engine.renderer.FlutterRendererTest; import io.flutter.external.FlutterLaunchTests; import io.flutter.plugin.common.StandardMessageCodecTest; +import io.flutter.plugin.common.StandardMethodCodecTest; import io.flutter.plugin.editing.InputConnectionAdaptorTest; import io.flutter.plugin.editing.TextInputPluginTest; import io.flutter.plugin.platform.PlatformPluginTest; @@ -52,6 +53,7 @@ PreconditionsTest.class, RenderingComponentTest.class, StandardMessageCodecTest.class, + StandardMethodCodecTest.class, ShimPluginRegistryTest.class, SingleViewPresentationTest.class, SmokeTest.class, diff --git a/shell/platform/android/test/io/flutter/plugin/common/StandardMethodCodecTest.java b/shell/platform/android/test/io/flutter/plugin/common/StandardMethodCodecTest.java new file mode 100644 index 0000000000000..c99a30f5d7fac --- /dev/null +++ b/shell/platform/android/test/io/flutter/plugin/common/StandardMethodCodecTest.java @@ -0,0 +1,92 @@ +package io.flutter.plugin.common; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +@Config(manifest = Config.NONE) +@RunWith(RobolectricTestRunner.class) +public class StandardMethodCodecTest { + + @Test + public void encodeMethodTest() { + final Map args = new HashMap<>(); + args.put("testArg", "testValue"); + MethodCall call = new MethodCall("testMethod", args); + final ByteBuffer buffer = StandardMethodCodec.INSTANCE.encodeMethodCall(call); + assertNotNull(buffer); + buffer.flip(); + final MethodCall result = StandardMethodCodec.INSTANCE.decodeMethodCall(buffer); + assertEquals(call.method, result.method); + assertEquals(call.arguments, result.arguments); + } + + @Test + public void encodeSuccessEnvelopeTest() { + final Map success = new HashMap<>(); + success.put("result", 1); + final ByteBuffer buffer = StandardMethodCodec.INSTANCE.encodeSuccessEnvelope(success); + assertNotNull(buffer); + buffer.flip(); + final Object result = StandardMethodCodec.INSTANCE.decodeEnvelope(buffer); + assertEquals(success, result); + } + + @Test + public void encodeSuccessEnvelopeUnsupportedObjectTest() { + final StandardMethodCodecTest joke = new StandardMethodCodecTest(); + try { + final ByteBuffer buffer = StandardMethodCodec.INSTANCE.encodeSuccessEnvelope(joke); + fail("Should have failed to convert unsupported type."); + } catch (IllegalArgumentException e) { + // pass. + } + } + + @Test + public void encodeErrorEnvelopeWithNullDetailsTest() { + final ByteBuffer buffer = + StandardMethodCodec.INSTANCE.encodeErrorEnvelope("code", "error", null); + assertNotNull(buffer); + buffer.flip(); + try { + StandardMethodCodec.INSTANCE.decodeEnvelope(buffer); + fail("Should have thrown a FlutterException since this is an error envelope."); + } catch (FlutterException result) { + assertEquals("code", result.code); + assertEquals("error", result.getMessage()); + assertNull(result.details); + } + } + + @Test + public void encodeErrorEnvelopeWithThrowableTest() { + final Exception e = new IllegalArgumentException("foo"); + final ByteBuffer buffer = + StandardMethodCodec.INSTANCE.encodeErrorEnvelope("code", e.getMessage(), e); + assertNotNull(buffer); + buffer.flip(); + try { + StandardMethodCodec.INSTANCE.decodeEnvelope(buffer); + fail("Should have thrown a FlutterException since this is an error envelope."); + } catch (FlutterException result) { + assertEquals("code", result.code); + assertEquals("foo", result.getMessage()); + // Must contain part of a stack. + String stack = (String) result.details; + assertTrue( + stack.contains( + "at io.flutter.plugin.common.StandardMethodCodecTest.encodeErrorEnvelopeWithThrowableTest(StandardMethodCodecTest.java:")); + } + } +}