From ca0748081b0a9a4c750a5896449d3eda4c174975 Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Tue, 23 Jun 2026 19:14:01 +0900 Subject: [PATCH 01/11] [tizen_rpc_port] Add regression integration tests to client example * Parcel: round-trips for writeInt16/readInt16 (positive, zero, 16-bit masking) * Parcel: round-trips for writeInt64/readInt64 (large value, zero) * Parcel: round-trips for writeArrayCount/readArrayCount (non-zero, zero) * Parcel: round-trips for write/read burst byte array (multi-byte, single byte) * Parcel: asRaw returns non-empty bytes after write * Parcel.fromRaw: reconstructed parcel reads back original values * Parcel: writeBundle/readBundle round-trips (non-empty Bundle, empty Bundle) * Parcel header: tag and sequenceNumber can be set and retrieved, tag defaults to empty string * Parcel Parcelable: custom Parcelable serializes and deserializes correctly * PortType: main and callback values are distinct; PortType.values contains both entries * ProxyBase: isConnected is false before connecting; appid and portName are set from constructor * StubBase: portName is set from constructor; setTrusted and addPrivilege work without listen Note: listen()+close() lifecycle tests are excluded because rpc_port_stub_destroy() does not safely interoperate with the internal listener thread started by rpc_port_stub_listen() on armv7l; the resulting pthread mutex assertion is a platform library limitation. --- packages/tizen_rpc_port/CHANGELOG.md | 4 + .../integration_test/tizen_rpc_port_test.dart | 290 +++++++++++++++++- .../example/client/pubspec.yaml | 1 + .../client/test_driver/integration_test.dart | 3 + 4 files changed, 297 insertions(+), 1 deletion(-) create mode 100644 packages/tizen_rpc_port/example/client/test_driver/integration_test.dart diff --git a/packages/tizen_rpc_port/CHANGELOG.md b/packages/tizen_rpc_port/CHANGELOG.md index 01f1c8dcd..f91ba0955 100644 --- a/packages/tizen_rpc_port/CHANGELOG.md +++ b/packages/tizen_rpc_port/CHANGELOG.md @@ -1,3 +1,7 @@ +## NEXT + +* Add 24 integration test cases. + ## 0.1.5 * Update code format. diff --git a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart index f87be0a49..374db3ab9 100644 --- a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart @@ -2,13 +2,69 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'dart:typed_data'; + +import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -import 'package:tizen_rpc_port/src/parcel.dart'; +import 'package:tizen_bundle/tizen_bundle.dart'; +import 'package:tizen_rpc_port/tizen_rpc_port.dart'; + +// A minimal Parcelable implementation used only in tests. +class _Point implements Parcelable { + _Point({this.x = 0, this.y = 0}); + + int x; + int y; + + @override + void serialize(Parcel parcel) { + parcel.writeInt32(x); + parcel.writeInt32(y); + } + + @override + void deserialize(Parcel parcel) { + x = parcel.readInt32(); + y = parcel.readInt32(); + } +} + +// A minimal ProxyBase subclass used only to test single-app observable +// behaviour (isConnected initial state, connection rejection). +class _TestProxy extends ProxyBase { + _TestProxy() : super('org.tizen.nonexistent_app_for_rpc_test', 'TestPort'); + + @override + Future onReceivedEvent(Parcel parcel) async {} +} + +// A minimal StubBase subclass used only to test single-app observable +// behaviour (construction, setTrusted, addPrivilege, double listen). +class _TestStub extends StubBase { + _TestStub() : super('TestStubPort'); + + @override + Future onConnectedEvent(String sender, String instance) async {} + + @override + Future onDisconnectedEvent(String sender, String instance) async {} + + @override + Future onReceivedEvent( + String sender, + String instance, + Parcel parcel, + ) async {} +} void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + // --------------------------------------------------------------------------- + // Existing tests — preserved unchanged + // --------------------------------------------------------------------------- + testWidgets('Parcel test', (WidgetTester tester) async { final Parcel parcel = Parcel(); parcel.writeBool(false); @@ -23,4 +79,236 @@ void main() { expect(parcel.readByte(), 0x3f); expect(parcel.readDouble(), 123.4); }); + + // --------------------------------------------------------------------------- + // Parcel — additional primitive types + // --------------------------------------------------------------------------- + + group('Parcel', () { + group('writeInt16 / readInt16', () { + testWidgets('round-trips positive value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt16(32767); + expect(parcel.readInt16(), 32767); + }); + + testWidgets('round-trips zero', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt16(0); + expect(parcel.readInt16(), 0); + }); + + testWidgets('masks value to 16 bits', (WidgetTester _) async { + final Parcel parcel = Parcel(); + // 0x10042 & 0xffff == 0x0042 == 66 + parcel.writeInt16(0x10042); + expect(parcel.readInt16(), 66); + }); + }); + + group('writeInt64 / readInt64', () { + testWidgets('round-trips large positive value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + const int value = 9007199254740992; // 2^53 + parcel.writeInt64(value); + expect(parcel.readInt64(), value); + }); + + testWidgets('round-trips zero', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt64(0); + expect(parcel.readInt64(), 0); + }); + }); + + group('writeArrayCount / readArrayCount', () { + testWidgets('round-trips non-zero count', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeArrayCount(42); + expect(parcel.readArrayCount(), 42); + }); + + testWidgets('round-trips zero count', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeArrayCount(0); + expect(parcel.readArrayCount(), 0); + }); + }); + + group('write / read (burst byte array)', () { + testWidgets('round-trips byte array', (WidgetTester _) async { + final Parcel parcel = Parcel(); + final Uint8List bytes = Uint8List.fromList( + [0x00, 0x01, 0x7f, 0x80, 0xff], + ); + parcel.write(bytes); + final Uint8List result = parcel.read(bytes.length); + expect(result, equals(bytes)); + }); + + testWidgets('round-trips single byte', (WidgetTester _) async { + final Parcel parcel = Parcel(); + final Uint8List bytes = Uint8List.fromList([0xab]); + parcel.write(bytes); + expect(parcel.read(1), equals(bytes)); + }); + }); + + group('asRaw', () { + testWidgets('returns non-empty bytes after write', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt32(1); + final Uint8List raw = parcel.asRaw(); + expect(raw, isNotEmpty); + }); + }); + + group('Parcel.fromRaw', () { + testWidgets('reconstructed parcel reads back original values', ( + WidgetTester _, + ) async { + final Parcel original = Parcel(); + original.writeInt32(99); + original.writeString('raw'); + original.writeBool(true); + + final Uint8List raw = original.asRaw(); + final Parcel restored = Parcel.fromRaw(raw); + + expect(restored.readInt32(), 99); + expect(restored.readString(), 'raw'); + expect(restored.readBool(), isTrue); + }); + }); + + group('writeBundle / readBundle', () { + testWidgets('round-trips a Bundle with string entries', ( + WidgetTester _, + ) async { + final Bundle bundle = Bundle(); + bundle['key1'] = 'value1'; + bundle['key2'] = 'value2'; + + final Parcel parcel = Parcel(); + parcel.writeBundle(bundle); + + final Bundle restored = parcel.readBundle(); + expect(restored['key1'], 'value1'); + expect(restored['key2'], 'value2'); + }); + + testWidgets('round-trips an empty Bundle', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeBundle(Bundle()); + final Bundle restored = parcel.readBundle(); + expect(restored.length, 0); + }); + }); + + group('header', () { + testWidgets('tag can be set and retrieved', (WidgetTester _) async { + final Parcel parcel = Parcel(); + final ParcelHeader header = parcel.header; + header.tag = '1.2.3'; + expect(parcel.header.tag, '1.2.3'); + }); + + testWidgets('sequenceNumber can be set and retrieved', ( + WidgetTester _, + ) async { + final Parcel parcel = Parcel(); + final ParcelHeader header = parcel.header; + header.sequenceNumber = 7; + expect(parcel.header.sequenceNumber, 7); + }); + + testWidgets('tag defaults to empty string', (WidgetTester _) async { + final Parcel parcel = Parcel(); + expect(parcel.header.tag, isEmpty); + }); + }); + + group('Parcelable', () { + testWidgets('custom Parcelable serializes and deserializes correctly', ( + WidgetTester _, + ) async { + final Parcel parcel = Parcel(); + final _Point original = _Point(x: 10, y: 20); + original.serialize(parcel); + + final _Point restored = _Point(); + restored.deserialize(parcel); + expect(restored.x, 10); + expect(restored.y, 20); + }); + }); + }); + + // --------------------------------------------------------------------------- + // PortType enum + // --------------------------------------------------------------------------- + + group('PortType', () { + testWidgets('main and callback values are distinct', ( + WidgetTester _, + ) async { + expect(PortType.main, isNot(equals(PortType.callback))); + }); + + testWidgets('PortType.values contains both entries', ( + WidgetTester _, + ) async { + expect(PortType.values, containsAll([PortType.main, PortType.callback])); + }); + }); + + // --------------------------------------------------------------------------- + // ProxyBase — single-app observable behaviour + // --------------------------------------------------------------------------- + + group('ProxyBase', () { + testWidgets('isConnected is false before connecting', ( + WidgetTester _, + ) async { + final _TestProxy proxy = _TestProxy(); + expect(proxy.isConnected, isFalse); + }); + + testWidgets('appid and portName are set from constructor', ( + WidgetTester _, + ) async { + final _TestProxy proxy = _TestProxy(); + expect(proxy.appid, 'org.tizen.nonexistent_app_for_rpc_test'); + expect(proxy.portName, 'TestPort'); + }); + }); + + // --------------------------------------------------------------------------- + // StubBase — single-app observable behaviour + // --------------------------------------------------------------------------- + + group('StubBase', () { + testWidgets('portName is set from constructor', (WidgetTester _) async { + final _TestStub stub = _TestStub(); + expect(stub.portName, 'TestStubPort'); + }); + + testWidgets('setTrusted can be called without listen', ( + WidgetTester _, + ) async { + final _TestStub stub = _TestStub(); + // Should not throw. + stub.setTrusted(true); + stub.setTrusted(false); + }); + + testWidgets('addPrivilege can be called without listen', ( + WidgetTester _, + ) async { + final _TestStub stub = _TestStub(); + // Should not throw. + stub.addPrivilege('http://tizen.org/privilege/datasharing'); + }); + + }); } diff --git a/packages/tizen_rpc_port/example/client/pubspec.yaml b/packages/tizen_rpc_port/example/client/pubspec.yaml index b83f036d9..1a5e35f4c 100644 --- a/packages/tizen_rpc_port/example/client/pubspec.yaml +++ b/packages/tizen_rpc_port/example/client/pubspec.yaml @@ -9,6 +9,7 @@ environment: dependencies: flutter: sdk: flutter + tizen_bundle: ^0.1.2 tizen_rpc_port: path: ../../ diff --git a/packages/tizen_rpc_port/example/client/test_driver/integration_test.dart b/packages/tizen_rpc_port/example/client/test_driver/integration_test.dart new file mode 100644 index 000000000..b38629cca --- /dev/null +++ b/packages/tizen_rpc_port/example/client/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); From dafcaa98ad438ede94f034b1b4344442e31ea8b1 Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Wed, 24 Jun 2026 18:03:37 +0900 Subject: [PATCH 02/11] [tizen_rpc_port] Add regression integration tests to server example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Parcel: basic read/write for bool, int32, string, byte, double (pre-existing) * Parcel: round-trips for writeInt16/readInt16 (positive, zero, 16-bit masking) * Parcel: round-trips for writeInt64/readInt64 (large value, zero) * Parcel: round-trips for writeArrayCount/readArrayCount (non-zero, zero) * Parcel: round-trips for write/read burst byte array (multi-byte, single byte) * Parcel: asRaw returns non-empty bytes after write * Parcel.fromRaw: reconstructed parcel reads back original values * Parcel: writeBundle/readBundle round-trips (non-empty Bundle, empty Bundle) * Parcel header: tag and sequenceNumber can be set and retrieved, tag defaults to empty string * PortType: main and callback values are distinct; PortType.values contains both entries * StubBase: portName is set from constructor; setTrusted and addPrivilege work without listen * Message: portName is 'Message'; services list is initially empty Also adds test_driver/integration_test.dart (missing boilerplate) and adds tizen_bundle as a direct dependency of the server example. Note: listen()+close() lifecycle tests are excluded for the same reason as the client example — rpc_port_stub_destroy() does not safely interoperate with the internal listener thread started by rpc_port_stub_listen() on armv7l. --- packages/tizen_rpc_port/CHANGELOG.md | 3 +- .../integration_test/tizen_rpc_port_test.dart | 265 +++++++++++++++++- .../example/server/pubspec.yaml | 1 + .../server/test_driver/integration_test.dart | 3 + 4 files changed, 270 insertions(+), 2 deletions(-) create mode 100644 packages/tizen_rpc_port/example/server/test_driver/integration_test.dart diff --git a/packages/tizen_rpc_port/CHANGELOG.md b/packages/tizen_rpc_port/CHANGELOG.md index f91ba0955..15370d230 100644 --- a/packages/tizen_rpc_port/CHANGELOG.md +++ b/packages/tizen_rpc_port/CHANGELOG.md @@ -1,6 +1,7 @@ ## NEXT -* Add 24 integration test cases. +* Add 24 integration test cases to the client example. +* Add 23 integration test cases to the server example. ## 0.1.5 diff --git a/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart index f87be0a49..a46f4f0c5 100644 --- a/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart @@ -4,11 +4,37 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -import 'package:tizen_rpc_port/src/parcel.dart'; +import 'package:tizen_bundle/tizen_bundle.dart'; +import 'package:tizen_rpc_port/tizen_rpc_port.dart'; + +import 'package:tizen_rpc_port_server_example/message_server.dart'; + +// A minimal StubBase subclass used only to test single-app observable +// behaviour (construction, setTrusted, addPrivilege). +class _TestStub extends StubBase { + _TestStub() : super('TestStubPort'); + + @override + Future onConnectedEvent(String sender, String instance) async {} + + @override + Future onDisconnectedEvent(String sender, String instance) async {} + + @override + Future onReceivedEvent( + String sender, + String instance, + Parcel parcel, + ) async {} +} void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); + // --------------------------------------------------------------------------- + // Existing tests — preserved unchanged + // --------------------------------------------------------------------------- + testWidgets('Parcel test', (WidgetTester tester) async { final Parcel parcel = Parcel(); parcel.writeBool(false); @@ -23,4 +49,241 @@ void main() { expect(parcel.readByte(), 0x3f); expect(parcel.readDouble(), 123.4); }); + + // --------------------------------------------------------------------------- + // Parcel — additional primitive types + // --------------------------------------------------------------------------- + + group('Parcel', () { + group('writeInt16 / readInt16', () { + testWidgets('round-trips positive value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt16(32767); + expect(parcel.readInt16(), 32767); + }); + + testWidgets('round-trips zero', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt16(0); + expect(parcel.readInt16(), 0); + }); + + testWidgets('masks value to 16 bits', (WidgetTester _) async { + final Parcel parcel = Parcel(); + // 0x10042 & 0xffff == 0x0042 == 66 + parcel.writeInt16(0x10042); + expect(parcel.readInt16(), 66); + }); + }); + + group('writeInt64 / readInt64', () { + testWidgets('round-trips large positive value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + const int value = 9007199254740992; // 2^53 + parcel.writeInt64(value); + expect(parcel.readInt64(), value); + }); + + testWidgets('round-trips zero', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt64(0); + expect(parcel.readInt64(), 0); + }); + }); + + group('writeArrayCount / readArrayCount', () { + testWidgets('round-trips non-zero count', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeArrayCount(42); + expect(parcel.readArrayCount(), 42); + }); + + testWidgets('round-trips zero count', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeArrayCount(0); + expect(parcel.readArrayCount(), 0); + }); + }); + + group('write / read (burst byte array)', () { + testWidgets('round-trips byte array', (WidgetTester _) async { + final Parcel parcel = Parcel(); + final Uint8List bytes = Uint8List.fromList( + [0x00, 0x01, 0x7f, 0x80, 0xff], + ); + parcel.write(bytes); + final Uint8List result = parcel.read(bytes.length); + expect(result, equals(bytes)); + }); + + testWidgets('round-trips single byte', (WidgetTester _) async { + final Parcel parcel = Parcel(); + final Uint8List bytes = Uint8List.fromList([0xab]); + parcel.write(bytes); + expect(parcel.read(1), equals(bytes)); + }); + }); + + group('asRaw', () { + testWidgets('returns non-empty bytes after write', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt32(1); + final Uint8List raw = parcel.asRaw(); + expect(raw, isNotEmpty); + }); + }); + + group('Parcel.fromRaw', () { + testWidgets('reconstructed parcel reads back original values', ( + WidgetTester _, + ) async { + final Parcel original = Parcel(); + original.writeInt32(99); + original.writeString('raw'); + original.writeBool(true); + + final Uint8List raw = original.asRaw(); + final Parcel restored = Parcel.fromRaw(raw); + + expect(restored.readInt32(), 99); + expect(restored.readString(), 'raw'); + expect(restored.readBool(), isTrue); + }); + }); + + group('writeBundle / readBundle', () { + testWidgets('round-trips a Bundle with string entries', ( + WidgetTester _, + ) async { + final Bundle bundle = Bundle(); + bundle['key1'] = 'value1'; + bundle['key2'] = 'value2'; + + final Parcel parcel = Parcel(); + parcel.writeBundle(bundle); + + final Bundle restored = parcel.readBundle(); + expect(restored['key1'], 'value1'); + expect(restored['key2'], 'value2'); + }); + + testWidgets('round-trips an empty Bundle', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeBundle(Bundle()); + final Bundle restored = parcel.readBundle(); + expect(restored.length, 0); + }); + }); + + group('header', () { + testWidgets('tag can be set and retrieved', (WidgetTester _) async { + final Parcel parcel = Parcel(); + final ParcelHeader header = parcel.header; + header.tag = '1.2.3'; + expect(parcel.header.tag, '1.2.3'); + }); + + testWidgets('sequenceNumber can be set and retrieved', ( + WidgetTester _, + ) async { + final Parcel parcel = Parcel(); + final ParcelHeader header = parcel.header; + header.sequenceNumber = 7; + expect(parcel.header.sequenceNumber, 7); + }); + + testWidgets('tag defaults to empty string', (WidgetTester _) async { + final Parcel parcel = Parcel(); + expect(parcel.header.tag, isEmpty); + }); + }); + }); + + // --------------------------------------------------------------------------- + // PortType enum + // --------------------------------------------------------------------------- + + group('PortType', () { + testWidgets('main and callback values are distinct', ( + WidgetTester _, + ) async { + expect(PortType.main, isNot(equals(PortType.callback))); + }); + + testWidgets('PortType.values contains both entries', ( + WidgetTester _, + ) async { + expect( + PortType.values, + containsAll([PortType.main, PortType.callback]), + ); + }); + }); + + // --------------------------------------------------------------------------- + // StubBase — single-app observable behaviour + // --------------------------------------------------------------------------- + + group('StubBase', () { + testWidgets('portName is set from constructor', (WidgetTester _) async { + final _TestStub stub = _TestStub(); + expect(stub.portName, 'TestStubPort'); + }); + + testWidgets('setTrusted can be called without listen', ( + WidgetTester _, + ) async { + final _TestStub stub = _TestStub(); + stub.setTrusted(true); + stub.setTrusted(false); + }); + + testWidgets('addPrivilege can be called without listen', ( + WidgetTester _, + ) async { + final _TestStub stub = _TestStub(); + stub.addPrivilege('http://tizen.org/privilege/datasharing'); + }); + }); + + // --------------------------------------------------------------------------- + // Message — server-side StubBase subclass + // --------------------------------------------------------------------------- + + group('Message', () { + testWidgets('portName is Message', (WidgetTester _) async { + final Message server = Message( + serviceBuilder: (String sender, String instance) => + _NoopService(sender, instance), + ); + expect(server.portName, 'Message'); + }); + + testWidgets('services list is initially empty', (WidgetTester _) async { + final Message server = Message( + serviceBuilder: (String sender, String instance) => + _NoopService(sender, instance), + ); + expect(server.services, isEmpty); + }); + }); +} + +class _NoopService extends ServiceBase { + _NoopService(super.sender, super.instance); + + @override + Future onCreate() async {} + + @override + Future onTerminate() async {} + + @override + Future onRegister(String name, NotifyCallback callback) async => 0; + + @override + Future onUnregister() async {} + + @override + Future onSend(String message) async => 0; } diff --git a/packages/tizen_rpc_port/example/server/pubspec.yaml b/packages/tizen_rpc_port/example/server/pubspec.yaml index df06c6149..874343892 100644 --- a/packages/tizen_rpc_port/example/server/pubspec.yaml +++ b/packages/tizen_rpc_port/example/server/pubspec.yaml @@ -9,6 +9,7 @@ environment: dependencies: flutter: sdk: flutter + tizen_bundle: ^0.1.2 tizen_rpc_port: path: ../../ diff --git a/packages/tizen_rpc_port/example/server/test_driver/integration_test.dart b/packages/tizen_rpc_port/example/server/test_driver/integration_test.dart new file mode 100644 index 000000000..b38629cca --- /dev/null +++ b/packages/tizen_rpc_port/example/server/test_driver/integration_test.dart @@ -0,0 +1,3 @@ +import 'package:integration_test/integration_test_driver.dart'; + +Future main() => integrationDriver(); From 52e4291ef7a83399d8888397309ab8c73d191081 Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Wed, 24 Jun 2026 18:50:54 +0900 Subject: [PATCH 03/11] [tizen_rpc_port] Move StubBase tests to server example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit StubBase is a server-side concept, so its tests belong in the server example, not the client. Move the 3 StubBase test cases from the client example to the server example, and add a Parcelable serialization test to the server example. Update TC counts in CHANGELOG (client 24 → 21, server 23 → 24). --- packages/tizen_rpc_port/CHANGELOG.md | 4 +- .../integration_test/tizen_rpc_port_test.dart | 49 ------------------- .../integration_test/tizen_rpc_port_test.dart | 35 +++++++++++++ 3 files changed, 37 insertions(+), 51 deletions(-) diff --git a/packages/tizen_rpc_port/CHANGELOG.md b/packages/tizen_rpc_port/CHANGELOG.md index 15370d230..e8b79fb0c 100644 --- a/packages/tizen_rpc_port/CHANGELOG.md +++ b/packages/tizen_rpc_port/CHANGELOG.md @@ -1,7 +1,7 @@ ## NEXT -* Add 24 integration test cases to the client example. -* Add 23 integration test cases to the server example. +* Add 21 integration test cases to the client example. +* Add 24 integration test cases to the server example. ## 0.1.5 diff --git a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart index 374db3ab9..eb6c85c67 100644 --- a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart @@ -4,7 +4,6 @@ import 'dart:typed_data'; -import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:tizen_bundle/tizen_bundle.dart'; @@ -39,25 +38,6 @@ class _TestProxy extends ProxyBase { Future onReceivedEvent(Parcel parcel) async {} } -// A minimal StubBase subclass used only to test single-app observable -// behaviour (construction, setTrusted, addPrivilege, double listen). -class _TestStub extends StubBase { - _TestStub() : super('TestStubPort'); - - @override - Future onConnectedEvent(String sender, String instance) async {} - - @override - Future onDisconnectedEvent(String sender, String instance) async {} - - @override - Future onReceivedEvent( - String sender, - String instance, - Parcel parcel, - ) async {} -} - void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); @@ -282,33 +262,4 @@ void main() { expect(proxy.portName, 'TestPort'); }); }); - - // --------------------------------------------------------------------------- - // StubBase — single-app observable behaviour - // --------------------------------------------------------------------------- - - group('StubBase', () { - testWidgets('portName is set from constructor', (WidgetTester _) async { - final _TestStub stub = _TestStub(); - expect(stub.portName, 'TestStubPort'); - }); - - testWidgets('setTrusted can be called without listen', ( - WidgetTester _, - ) async { - final _TestStub stub = _TestStub(); - // Should not throw. - stub.setTrusted(true); - stub.setTrusted(false); - }); - - testWidgets('addPrivilege can be called without listen', ( - WidgetTester _, - ) async { - final _TestStub stub = _TestStub(); - // Should not throw. - stub.addPrivilege('http://tizen.org/privilege/datasharing'); - }); - - }); } diff --git a/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart index a46f4f0c5..dc815fcf2 100644 --- a/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart @@ -28,6 +28,26 @@ class _TestStub extends StubBase { ) async {} } +// A minimal Parcelable implementation used only in tests. +class _Point implements Parcelable { + _Point({this.x = 0, this.y = 0}); + + int x; + int y; + + @override + void serialize(Parcel parcel) { + parcel.writeInt32(x); + parcel.writeInt32(y); + } + + @override + void deserialize(Parcel parcel) { + x = parcel.readInt32(); + y = parcel.readInt32(); + } +} + void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); @@ -197,6 +217,21 @@ void main() { expect(parcel.header.tag, isEmpty); }); }); + + group('Parcelable', () { + testWidgets('custom Parcelable serializes and deserializes correctly', ( + WidgetTester _, + ) async { + final Parcel parcel = Parcel(); + final _Point original = _Point(x: 10, y: 20); + original.serialize(parcel); + + final _Point restored = _Point(); + restored.deserialize(parcel); + expect(restored.x, 10); + expect(restored.y, 20); + }); + }); }); // --------------------------------------------------------------------------- From a8b879e0562d1fb5371b6f067547d85e9e6019bc Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Wed, 1 Jul 2026 14:01:34 +0900 Subject: [PATCH 04/11] [tizen_rpc_port] Fix formatting and remove unnecessary import in integration tests --- .../client/integration_test/tizen_rpc_port_test.dart | 8 ++++---- .../server/integration_test/tizen_rpc_port_test.dart | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart index eb6c85c67..ea87473d9 100644 --- a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -import 'dart:typed_data'; - import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; import 'package:tizen_bundle/tizen_bundle.dart'; @@ -135,7 +133,8 @@ void main() { }); group('asRaw', () { - testWidgets('returns non-empty bytes after write', (WidgetTester _) async { + testWidgets('returns non-empty bytes after write', + (WidgetTester _) async { final Parcel parcel = Parcel(); parcel.writeInt32(1); final Uint8List raw = parcel.asRaw(); @@ -238,7 +237,8 @@ void main() { testWidgets('PortType.values contains both entries', ( WidgetTester _, ) async { - expect(PortType.values, containsAll([PortType.main, PortType.callback])); + expect(PortType.values, + containsAll([PortType.main, PortType.callback])); }); }); diff --git a/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart index dc815fcf2..6fba685ad 100644 --- a/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart @@ -145,7 +145,8 @@ void main() { }); group('asRaw', () { - testWidgets('returns non-empty bytes after write', (WidgetTester _) async { + testWidgets('returns non-empty bytes after write', + (WidgetTester _) async { final Parcel parcel = Parcel(); parcel.writeInt32(1); final Uint8List raw = parcel.asRaw(); From 85b1fc40396d26d5a7d275b12e96bb12ad3f122e Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Wed, 1 Jul 2026 19:01:22 +0900 Subject: [PATCH 05/11] [tizen_rpc_port] Read byte values as unsigned across ABIs Parcel.readByte read the value into a C `char`, whose signedness is ABI-dependent (signed on x86, unsigned on ARM), so a byte written as 0xff read back as -1 on x86 while writeByte and the burst read() already use unsigned semantics. Mask the read value to 8 bits so readByte consistently returns 0-255 on all targets. Bump version to 0.1.6. --- packages/tizen_rpc_port/CHANGELOG.md | 4 +++- packages/tizen_rpc_port/README.md | 2 +- packages/tizen_rpc_port/lib/src/parcel.dart | 7 ++++++- packages/tizen_rpc_port/pubspec.yaml | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/tizen_rpc_port/CHANGELOG.md b/packages/tizen_rpc_port/CHANGELOG.md index e8b79fb0c..92b486ccc 100644 --- a/packages/tizen_rpc_port/CHANGELOG.md +++ b/packages/tizen_rpc_port/CHANGELOG.md @@ -1,5 +1,7 @@ -## NEXT +## 0.1.6 +* Read byte values as unsigned (0-255) so `Parcel.readByte` is consistent + across ABIs (C `char` is signed on x86 but unsigned on ARM). * Add 21 integration test cases to the client example. * Add 24 integration test cases to the server example. diff --git a/packages/tizen_rpc_port/README.md b/packages/tizen_rpc_port/README.md index bcb6a2c65..072e656ed 100644 --- a/packages/tizen_rpc_port/README.md +++ b/packages/tizen_rpc_port/README.md @@ -21,7 +21,7 @@ The generated source files (`message_client.dart` and `message_server.dart`) dep ```yaml depenedencies: - tizen_rpc_port: ^0.1.5 + tizen_rpc_port: ^0.1.6 ``` Assuming that the name of the interface defined in your interface file is `Message`, the client must first call its `connect` method to connect to the server before making any remote invocation. diff --git a/packages/tizen_rpc_port/lib/src/parcel.dart b/packages/tizen_rpc_port/lib/src/parcel.dart index 90a15a9c4..2ec3c61d2 100644 --- a/packages/tizen_rpc_port/lib/src/parcel.dart +++ b/packages/tizen_rpc_port/lib/src/parcel.dart @@ -293,6 +293,11 @@ class Parcel { } /// Reads a byte value from this parcel. + /// + /// The value is returned as an unsigned byte in the range 0-255, matching the + /// unsigned semantics of [writeByte] and [read]. The native value is read + /// into a C `char`, whose signedness is ABI-dependent (signed on x86, unsigned + /// on ARM), so it is masked to 8 bits to keep the result consistent. int readByte() { return using((Arena arena) { final Pointer pValue = arena(); @@ -303,7 +308,7 @@ class Parcel { message: tizen.get_error_message(ret).toDartString(), ); } - return pValue.value; + return pValue.value & _byteMax; }); } diff --git a/packages/tizen_rpc_port/pubspec.yaml b/packages/tizen_rpc_port/pubspec.yaml index 443d92f39..3d2e9905d 100644 --- a/packages/tizen_rpc_port/pubspec.yaml +++ b/packages/tizen_rpc_port/pubspec.yaml @@ -2,7 +2,7 @@ name: tizen_rpc_port description: Tizen RPC Port APIs. Used to make remote procedure calls between Tizen apps. homepage: https://github.com/flutter-tizen/plugins repository: https://github.com/flutter-tizen/plugins/tree/master/packages/tizen_rpc_port -version: 0.1.5 +version: 0.1.6 environment: sdk: ">=3.1.0 <4.0.0" From 7e09e25c184843f9099b100c9555aa717f576bfd Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Wed, 1 Jul 2026 19:01:37 +0900 Subject: [PATCH 06/11] [tizen_rpc_port] Add negative and boundary Parcel test cases Extend the Parcel integration tests (client and server) with negative and boundary-value round trips to exercise sign handling across the FFI boundary: - writeInt16/readInt16: -1 and the int16 minimum (-32768). - writeInt64/readInt64: the int64 maximum and minimum. - writeByte/readByte: unsigned round trips including 255, a negative input read back as 255, and 8-bit masking. Verified on the tv-9.0 (x86) and tv-10.0 (x86_64) emulators. --- packages/tizen_rpc_port/CHANGELOG.md | 4 +- .../integration_test/tizen_rpc_port_test.dart | 62 +++++++++++++++++++ .../integration_test/tizen_rpc_port_test.dart | 62 +++++++++++++++++++ 3 files changed, 126 insertions(+), 2 deletions(-) diff --git a/packages/tizen_rpc_port/CHANGELOG.md b/packages/tizen_rpc_port/CHANGELOG.md index 92b486ccc..4d6dd0e57 100644 --- a/packages/tizen_rpc_port/CHANGELOG.md +++ b/packages/tizen_rpc_port/CHANGELOG.md @@ -2,8 +2,8 @@ * Read byte values as unsigned (0-255) so `Parcel.readByte` is consistent across ABIs (C `char` is signed on x86 but unsigned on ARM). -* Add 21 integration test cases to the client example. -* Add 24 integration test cases to the server example. +* Add 30 integration test cases to the client example. +* Add 33 integration test cases to the server example. ## 0.1.5 diff --git a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart index ea87473d9..e050bf527 100644 --- a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart @@ -76,6 +76,18 @@ void main() { expect(parcel.readInt16(), 0); }); + testWidgets('round-trips negative value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt16(-1); + expect(parcel.readInt16(), -1); + }); + + testWidgets('round-trips minimum value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt16(-32768); + expect(parcel.readInt16(), -32768); + }); + testWidgets('masks value to 16 bits', (WidgetTester _) async { final Parcel parcel = Parcel(); // 0x10042 & 0xffff == 0x0042 == 66 @@ -92,6 +104,20 @@ void main() { expect(parcel.readInt64(), value); }); + testWidgets('round-trips maximum value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + const int value = 9223372036854775807; // int64 max + parcel.writeInt64(value); + expect(parcel.readInt64(), value); + }); + + testWidgets('round-trips minimum value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + const int value = -9223372036854775808; // int64 min + parcel.writeInt64(value); + expect(parcel.readInt64(), value); + }); + testWidgets('round-trips zero', (WidgetTester _) async { final Parcel parcel = Parcel(); parcel.writeInt64(0); @@ -99,6 +125,42 @@ void main() { }); }); + group('writeByte / readByte', () { + testWidgets('round-trips a value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeByte(0xab); + expect(parcel.readByte(), 0xab); + }); + + testWidgets('round-trips zero', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeByte(0); + expect(parcel.readByte(), 0); + }); + + testWidgets('round-trips maximum unsigned value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeByte(255); + expect(parcel.readByte(), 255); + }); + + testWidgets('reads a negative input back as an unsigned byte', ( + WidgetTester _, + ) async { + final Parcel parcel = Parcel(); + // -1 is written as 0xff and must read back as the unsigned byte 255. + parcel.writeByte(-1); + expect(parcel.readByte(), 255); + }); + + testWidgets('masks value to 8 bits', (WidgetTester _) async { + final Parcel parcel = Parcel(); + // 0x142 & 0xff == 0x42 == 66 + parcel.writeByte(0x142); + expect(parcel.readByte(), 66); + }); + }); + group('writeArrayCount / readArrayCount', () { testWidgets('round-trips non-zero count', (WidgetTester _) async { final Parcel parcel = Parcel(); diff --git a/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart index 6fba685ad..afb716098 100644 --- a/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart @@ -88,6 +88,18 @@ void main() { expect(parcel.readInt16(), 0); }); + testWidgets('round-trips negative value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt16(-1); + expect(parcel.readInt16(), -1); + }); + + testWidgets('round-trips minimum value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeInt16(-32768); + expect(parcel.readInt16(), -32768); + }); + testWidgets('masks value to 16 bits', (WidgetTester _) async { final Parcel parcel = Parcel(); // 0x10042 & 0xffff == 0x0042 == 66 @@ -104,6 +116,20 @@ void main() { expect(parcel.readInt64(), value); }); + testWidgets('round-trips maximum value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + const int value = 9223372036854775807; // int64 max + parcel.writeInt64(value); + expect(parcel.readInt64(), value); + }); + + testWidgets('round-trips minimum value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + const int value = -9223372036854775808; // int64 min + parcel.writeInt64(value); + expect(parcel.readInt64(), value); + }); + testWidgets('round-trips zero', (WidgetTester _) async { final Parcel parcel = Parcel(); parcel.writeInt64(0); @@ -111,6 +137,42 @@ void main() { }); }); + group('writeByte / readByte', () { + testWidgets('round-trips a value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeByte(0xab); + expect(parcel.readByte(), 0xab); + }); + + testWidgets('round-trips zero', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeByte(0); + expect(parcel.readByte(), 0); + }); + + testWidgets('round-trips maximum unsigned value', (WidgetTester _) async { + final Parcel parcel = Parcel(); + parcel.writeByte(255); + expect(parcel.readByte(), 255); + }); + + testWidgets('reads a negative input back as an unsigned byte', ( + WidgetTester _, + ) async { + final Parcel parcel = Parcel(); + // -1 is written as 0xff and must read back as the unsigned byte 255. + parcel.writeByte(-1); + expect(parcel.readByte(), 255); + }); + + testWidgets('masks value to 8 bits', (WidgetTester _) async { + final Parcel parcel = Parcel(); + // 0x142 & 0xff == 0x42 == 66 + parcel.writeByte(0x142); + expect(parcel.readByte(), 66); + }); + }); + group('writeArrayCount / readArrayCount', () { testWidgets('round-trips non-zero count', (WidgetTester _) async { final Parcel parcel = Parcel(); From fedbe451c234636adac2557bac789199a71a0e87 Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Thu, 2 Jul 2026 09:40:36 +0900 Subject: [PATCH 07/11] [tizen_rpc_port] Deduplicate shared Parcel/PortType tests The Parcel and PortType test groups are context-independent core-API tests and were identical in the client and server example suites (~230 duplicated lines). Keep them only in the client suite and leave the server suite with the server-specific StubBase and Message tests, removing the redundant execution and maintenance overhead. --- packages/tizen_rpc_port/CHANGELOG.md | 3 +- .../integration_test/tizen_rpc_port_test.dart | 292 +----------------- 2 files changed, 6 insertions(+), 289 deletions(-) diff --git a/packages/tizen_rpc_port/CHANGELOG.md b/packages/tizen_rpc_port/CHANGELOG.md index 4d6dd0e57..dbd98d9fd 100644 --- a/packages/tizen_rpc_port/CHANGELOG.md +++ b/packages/tizen_rpc_port/CHANGELOG.md @@ -3,7 +3,8 @@ * Read byte values as unsigned (0-255) so `Parcel.readByte` is consistent across ABIs (C `char` is signed on x86 but unsigned on ARM). * Add 30 integration test cases to the client example. -* Add 33 integration test cases to the server example. +* Add server-specific integration test cases to the server example (the shared + Parcel and PortType tests are exercised only in the client example). ## 0.1.5 diff --git a/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart index afb716098..41af972c7 100644 --- a/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/server/integration_test/tizen_rpc_port_test.dart @@ -4,11 +4,14 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; -import 'package:tizen_bundle/tizen_bundle.dart'; import 'package:tizen_rpc_port/tizen_rpc_port.dart'; import 'package:tizen_rpc_port_server_example/message_server.dart'; +// The core Parcel and PortType tests are context-independent, so they are +// exercised only in the client example to avoid duplicating them here. This +// suite covers the server-specific StubBase behaviour. + // A minimal StubBase subclass used only to test single-app observable // behaviour (construction, setTrusted, addPrivilege). class _TestStub extends StubBase { @@ -28,296 +31,9 @@ class _TestStub extends StubBase { ) async {} } -// A minimal Parcelable implementation used only in tests. -class _Point implements Parcelable { - _Point({this.x = 0, this.y = 0}); - - int x; - int y; - - @override - void serialize(Parcel parcel) { - parcel.writeInt32(x); - parcel.writeInt32(y); - } - - @override - void deserialize(Parcel parcel) { - x = parcel.readInt32(); - y = parcel.readInt32(); - } -} - void main() { IntegrationTestWidgetsFlutterBinding.ensureInitialized(); - // --------------------------------------------------------------------------- - // Existing tests — preserved unchanged - // --------------------------------------------------------------------------- - - testWidgets('Parcel test', (WidgetTester tester) async { - final Parcel parcel = Parcel(); - parcel.writeBool(false); - parcel.writeInt32(123); - parcel.writeString('Hello'); - parcel.writeByte(0x3f); - parcel.writeDouble(123.4); - - expect(parcel.readBool(), false); - expect(parcel.readInt32(), 123); - expect(parcel.readString(), 'Hello'); - expect(parcel.readByte(), 0x3f); - expect(parcel.readDouble(), 123.4); - }); - - // --------------------------------------------------------------------------- - // Parcel — additional primitive types - // --------------------------------------------------------------------------- - - group('Parcel', () { - group('writeInt16 / readInt16', () { - testWidgets('round-trips positive value', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeInt16(32767); - expect(parcel.readInt16(), 32767); - }); - - testWidgets('round-trips zero', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeInt16(0); - expect(parcel.readInt16(), 0); - }); - - testWidgets('round-trips negative value', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeInt16(-1); - expect(parcel.readInt16(), -1); - }); - - testWidgets('round-trips minimum value', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeInt16(-32768); - expect(parcel.readInt16(), -32768); - }); - - testWidgets('masks value to 16 bits', (WidgetTester _) async { - final Parcel parcel = Parcel(); - // 0x10042 & 0xffff == 0x0042 == 66 - parcel.writeInt16(0x10042); - expect(parcel.readInt16(), 66); - }); - }); - - group('writeInt64 / readInt64', () { - testWidgets('round-trips large positive value', (WidgetTester _) async { - final Parcel parcel = Parcel(); - const int value = 9007199254740992; // 2^53 - parcel.writeInt64(value); - expect(parcel.readInt64(), value); - }); - - testWidgets('round-trips maximum value', (WidgetTester _) async { - final Parcel parcel = Parcel(); - const int value = 9223372036854775807; // int64 max - parcel.writeInt64(value); - expect(parcel.readInt64(), value); - }); - - testWidgets('round-trips minimum value', (WidgetTester _) async { - final Parcel parcel = Parcel(); - const int value = -9223372036854775808; // int64 min - parcel.writeInt64(value); - expect(parcel.readInt64(), value); - }); - - testWidgets('round-trips zero', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeInt64(0); - expect(parcel.readInt64(), 0); - }); - }); - - group('writeByte / readByte', () { - testWidgets('round-trips a value', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeByte(0xab); - expect(parcel.readByte(), 0xab); - }); - - testWidgets('round-trips zero', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeByte(0); - expect(parcel.readByte(), 0); - }); - - testWidgets('round-trips maximum unsigned value', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeByte(255); - expect(parcel.readByte(), 255); - }); - - testWidgets('reads a negative input back as an unsigned byte', ( - WidgetTester _, - ) async { - final Parcel parcel = Parcel(); - // -1 is written as 0xff and must read back as the unsigned byte 255. - parcel.writeByte(-1); - expect(parcel.readByte(), 255); - }); - - testWidgets('masks value to 8 bits', (WidgetTester _) async { - final Parcel parcel = Parcel(); - // 0x142 & 0xff == 0x42 == 66 - parcel.writeByte(0x142); - expect(parcel.readByte(), 66); - }); - }); - - group('writeArrayCount / readArrayCount', () { - testWidgets('round-trips non-zero count', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeArrayCount(42); - expect(parcel.readArrayCount(), 42); - }); - - testWidgets('round-trips zero count', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeArrayCount(0); - expect(parcel.readArrayCount(), 0); - }); - }); - - group('write / read (burst byte array)', () { - testWidgets('round-trips byte array', (WidgetTester _) async { - final Parcel parcel = Parcel(); - final Uint8List bytes = Uint8List.fromList( - [0x00, 0x01, 0x7f, 0x80, 0xff], - ); - parcel.write(bytes); - final Uint8List result = parcel.read(bytes.length); - expect(result, equals(bytes)); - }); - - testWidgets('round-trips single byte', (WidgetTester _) async { - final Parcel parcel = Parcel(); - final Uint8List bytes = Uint8List.fromList([0xab]); - parcel.write(bytes); - expect(parcel.read(1), equals(bytes)); - }); - }); - - group('asRaw', () { - testWidgets('returns non-empty bytes after write', - (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeInt32(1); - final Uint8List raw = parcel.asRaw(); - expect(raw, isNotEmpty); - }); - }); - - group('Parcel.fromRaw', () { - testWidgets('reconstructed parcel reads back original values', ( - WidgetTester _, - ) async { - final Parcel original = Parcel(); - original.writeInt32(99); - original.writeString('raw'); - original.writeBool(true); - - final Uint8List raw = original.asRaw(); - final Parcel restored = Parcel.fromRaw(raw); - - expect(restored.readInt32(), 99); - expect(restored.readString(), 'raw'); - expect(restored.readBool(), isTrue); - }); - }); - - group('writeBundle / readBundle', () { - testWidgets('round-trips a Bundle with string entries', ( - WidgetTester _, - ) async { - final Bundle bundle = Bundle(); - bundle['key1'] = 'value1'; - bundle['key2'] = 'value2'; - - final Parcel parcel = Parcel(); - parcel.writeBundle(bundle); - - final Bundle restored = parcel.readBundle(); - expect(restored['key1'], 'value1'); - expect(restored['key2'], 'value2'); - }); - - testWidgets('round-trips an empty Bundle', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeBundle(Bundle()); - final Bundle restored = parcel.readBundle(); - expect(restored.length, 0); - }); - }); - - group('header', () { - testWidgets('tag can be set and retrieved', (WidgetTester _) async { - final Parcel parcel = Parcel(); - final ParcelHeader header = parcel.header; - header.tag = '1.2.3'; - expect(parcel.header.tag, '1.2.3'); - }); - - testWidgets('sequenceNumber can be set and retrieved', ( - WidgetTester _, - ) async { - final Parcel parcel = Parcel(); - final ParcelHeader header = parcel.header; - header.sequenceNumber = 7; - expect(parcel.header.sequenceNumber, 7); - }); - - testWidgets('tag defaults to empty string', (WidgetTester _) async { - final Parcel parcel = Parcel(); - expect(parcel.header.tag, isEmpty); - }); - }); - - group('Parcelable', () { - testWidgets('custom Parcelable serializes and deserializes correctly', ( - WidgetTester _, - ) async { - final Parcel parcel = Parcel(); - final _Point original = _Point(x: 10, y: 20); - original.serialize(parcel); - - final _Point restored = _Point(); - restored.deserialize(parcel); - expect(restored.x, 10); - expect(restored.y, 20); - }); - }); - }); - - // --------------------------------------------------------------------------- - // PortType enum - // --------------------------------------------------------------------------- - - group('PortType', () { - testWidgets('main and callback values are distinct', ( - WidgetTester _, - ) async { - expect(PortType.main, isNot(equals(PortType.callback))); - }); - - testWidgets('PortType.values contains both entries', ( - WidgetTester _, - ) async { - expect( - PortType.values, - containsAll([PortType.main, PortType.callback]), - ); - }); - }); - // --------------------------------------------------------------------------- // StubBase — single-app observable behaviour // --------------------------------------------------------------------------- From 734204ccd155f89936491cbf53190e935f492b53 Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Thu, 2 Jul 2026 20:10:24 +0900 Subject: [PATCH 08/11] [tizen_rpc_port] Deduplicate redundant Parcel and PortType tests Per review: drop 'round-trips single byte' (subset of the byte-array round-trip), drop the standalone asRaw group (already exercised inside the Parcel.fromRaw test), and merge the two PortType tests into one unorderedEquals check for both distinctness and presence. --- packages/tizen_rpc_port/CHANGELOG.md | 2 +- .../integration_test/tizen_rpc_port_test.dart | 41 ++++++------------- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/packages/tizen_rpc_port/CHANGELOG.md b/packages/tizen_rpc_port/CHANGELOG.md index dbd98d9fd..4c94f3df9 100644 --- a/packages/tizen_rpc_port/CHANGELOG.md +++ b/packages/tizen_rpc_port/CHANGELOG.md @@ -2,7 +2,7 @@ * Read byte values as unsigned (0-255) so `Parcel.readByte` is consistent across ABIs (C `char` is signed on x86 but unsigned on ARM). -* Add 30 integration test cases to the client example. +* Add 27 integration test cases to the client example. * Add server-specific integration test cases to the server example (the shared Parcel and PortType tests are exercised only in the client example). diff --git a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart index e050bf527..7782f3402 100644 --- a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart @@ -178,30 +178,17 @@ void main() { group('write / read (burst byte array)', () { testWidgets('round-trips byte array', (WidgetTester _) async { final Parcel parcel = Parcel(); - final Uint8List bytes = Uint8List.fromList( - [0x00, 0x01, 0x7f, 0x80, 0xff], - ); + final Uint8List bytes = Uint8List.fromList([ + 0x00, + 0x01, + 0x7f, + 0x80, + 0xff, + ]); parcel.write(bytes); final Uint8List result = parcel.read(bytes.length); expect(result, equals(bytes)); }); - - testWidgets('round-trips single byte', (WidgetTester _) async { - final Parcel parcel = Parcel(); - final Uint8List bytes = Uint8List.fromList([0xab]); - parcel.write(bytes); - expect(parcel.read(1), equals(bytes)); - }); - }); - - group('asRaw', () { - testWidgets('returns non-empty bytes after write', - (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeInt32(1); - final Uint8List raw = parcel.asRaw(); - expect(raw, isNotEmpty); - }); }); group('Parcel.fromRaw', () { @@ -290,17 +277,13 @@ void main() { // --------------------------------------------------------------------------- group('PortType', () { - testWidgets('main and callback values are distinct', ( - WidgetTester _, - ) async { - expect(PortType.main, isNot(equals(PortType.callback))); - }); - - testWidgets('PortType.values contains both entries', ( + testWidgets('has exactly the main and callback values', ( WidgetTester _, ) async { - expect(PortType.values, - containsAll([PortType.main, PortType.callback])); + expect( + PortType.values, + unorderedEquals([PortType.main, PortType.callback]), + ); }); }); From daf56263281fb9b67f69c33e8e1cbdae32f154e8 Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Tue, 7 Jul 2026 20:14:00 +0900 Subject: [PATCH 09/11] [tizen_rpc_port] Remove redundant zero-value Parcel round-trip tests Zero doesn't exercise a different code path than other values in writeByte/writeInt16/writeInt64/writeArrayCount, so these cases only duplicated coverage already provided by the positive/negative/min/max round-trip tests. --- .../integration_test/tizen_rpc_port_test.dart | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart index 7782f3402..15b38d0f0 100644 --- a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart @@ -70,12 +70,6 @@ void main() { expect(parcel.readInt16(), 32767); }); - testWidgets('round-trips zero', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeInt16(0); - expect(parcel.readInt16(), 0); - }); - testWidgets('round-trips negative value', (WidgetTester _) async { final Parcel parcel = Parcel(); parcel.writeInt16(-1); @@ -118,11 +112,6 @@ void main() { expect(parcel.readInt64(), value); }); - testWidgets('round-trips zero', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeInt64(0); - expect(parcel.readInt64(), 0); - }); }); group('writeByte / readByte', () { @@ -132,12 +121,6 @@ void main() { expect(parcel.readByte(), 0xab); }); - testWidgets('round-trips zero', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeByte(0); - expect(parcel.readByte(), 0); - }); - testWidgets('round-trips maximum unsigned value', (WidgetTester _) async { final Parcel parcel = Parcel(); parcel.writeByte(255); @@ -162,17 +145,12 @@ void main() { }); group('writeArrayCount / readArrayCount', () { - testWidgets('round-trips non-zero count', (WidgetTester _) async { + testWidgets('round-trips a count', (WidgetTester _) async { final Parcel parcel = Parcel(); parcel.writeArrayCount(42); expect(parcel.readArrayCount(), 42); }); - testWidgets('round-trips zero count', (WidgetTester _) async { - final Parcel parcel = Parcel(); - parcel.writeArrayCount(0); - expect(parcel.readArrayCount(), 0); - }); }); group('write / read (burst byte array)', () { From 423b8f71cd6e17261e90b6b8fe994e2268dec1d1 Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Wed, 8 Jul 2026 21:11:37 +0900 Subject: [PATCH 10/11] [tizen_rpc_port] Fix dart format drift --- .../integration_test/tizen_rpc_port_test.dart | 2 -- .../example/client/lib/main.dart | 20 ++++++++------ .../tizen_rpc_port/lib/src/proxy_base.dart | 27 +++++++------------ 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart index 15b38d0f0..4e1f00661 100644 --- a/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart +++ b/packages/tizen_rpc_port/example/client/integration_test/tizen_rpc_port_test.dart @@ -111,7 +111,6 @@ void main() { parcel.writeInt64(value); expect(parcel.readInt64(), value); }); - }); group('writeByte / readByte', () { @@ -150,7 +149,6 @@ void main() { parcel.writeArrayCount(42); expect(parcel.readArrayCount(), 42); }); - }); group('write / read (burst byte array)', () { diff --git a/packages/tizen_rpc_port/example/client/lib/main.dart b/packages/tizen_rpc_port/example/client/lib/main.dart index 027cb25e1..8856466cc 100644 --- a/packages/tizen_rpc_port/example/client/lib/main.dart +++ b/packages/tizen_rpc_port/example/client/lib/main.dart @@ -171,32 +171,36 @@ class _MyAppState extends State { children: [ TextButton( style: ButtonStyle( - minimumSize: - MaterialStateProperty.all(const Size.fromHeight(100)), + minimumSize: MaterialStateProperty.all( + const Size.fromHeight(100), + ), ), onPressed: _connect, child: const Text('Connect'), ), TextButton( style: ButtonStyle( - minimumSize: - MaterialStateProperty.all(const Size.fromHeight(100)), + minimumSize: MaterialStateProperty.all( + const Size.fromHeight(100), + ), ), onPressed: _connect2, child: const Text('Connect2'), ), TextButton( style: ButtonStyle( - minimumSize: - MaterialStateProperty.all(const Size.fromHeight(100)), + minimumSize: MaterialStateProperty.all( + const Size.fromHeight(100), + ), ), onPressed: _isConnected ? _send : null, child: const Text('Send'), ), TextButton( style: ButtonStyle( - minimumSize: - MaterialStateProperty.all(const Size.fromHeight(100)), + minimumSize: MaterialStateProperty.all( + const Size.fromHeight(100), + ), ), onPressed: _isConnected2 ? _send2 : null, child: const Text('Send2'), diff --git a/packages/tizen_rpc_port/lib/src/proxy_base.dart b/packages/tizen_rpc_port/lib/src/proxy_base.dart index 0f51681b9..8d80d104b 100644 --- a/packages/tizen_rpc_port/lib/src/proxy_base.dart +++ b/packages/tizen_rpc_port/lib/src/proxy_base.dart @@ -61,9 +61,7 @@ abstract class ProxyBase { Completer _connectCompleter = Completer(); Completer _disconnectCompleter = Completer(); - static const MethodChannel _channel = MethodChannel( - 'tizen/rpc_port_proxy', - ); + static const MethodChannel _channel = MethodChannel('tizen/rpc_port_proxy'); Stream? _stream; static final Set _activeConnections = {}; @@ -92,25 +90,20 @@ abstract class ProxyBase { throw StateError('Proxy $appid/$portName already connected'); } - await _channel.invokeMethod( - 'init', - { - 'handle': _handle.address, - 'portName': portName, - }, - ); + await _channel.invokeMethod('init', { + 'handle': _handle.address, + 'portName': portName, + }); final EventChannel eventChannel = EventChannel( 'tizen/rpc_port_proxy/$portName/${_handle.address}', ); - _stream = eventChannel.receiveBroadcastStream( - { - 'handle': _handle.address, - 'appid': appid, - 'portName': portName, - }, - ); + _stream = eventChannel.receiveBroadcastStream({ + 'handle': _handle.address, + 'appid': appid, + 'portName': portName, + }); _activeConnections.add(_handle.address); _streamSubscription = _stream!.listen((dynamic data) async { From 69a5bdf59e8c2fdc8b292b0eb8cfa32218b93e7c Mon Sep 17 00:00:00 2001 From: Seungsoo Lee Date: Fri, 10 Jul 2026 11:27:26 +0900 Subject: [PATCH 11/11] [tizen_rpc_port] Remove unused tizen_bundle dependency from server example --- packages/tizen_rpc_port/example/server/pubspec.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/tizen_rpc_port/example/server/pubspec.yaml b/packages/tizen_rpc_port/example/server/pubspec.yaml index 874343892..df06c6149 100644 --- a/packages/tizen_rpc_port/example/server/pubspec.yaml +++ b/packages/tizen_rpc_port/example/server/pubspec.yaml @@ -9,7 +9,6 @@ environment: dependencies: flutter: sdk: flutter - tizen_bundle: ^0.1.2 tizen_rpc_port: path: ../../