feat(poc/bridge): add flutter_rust_bridge hello spike

Proof-of-concept proving the Flutter/Rust bridge exit criterion from
docs/architecture/proof-of-concept-plan.md §2:
  "Flutter can call Rust and receive event stream data."

The spike exposes one synchronous fallible command (greet) returning
a typed GreetResult / GreetError DTO, and one async event stream
(counter_stream) emitting typed CounterTick events. The Flutter app
demonstrates both flows on a Material 3 surface; the headless test
suite in test/poc_verification_test.dart exercises the same API
directly through dart:ffi.

Verified on 2026-05-13 (Linux desktop, Flutter 3.41.9 / Dart 3.11.5,
flutter_rust_bridge 2.12.0, Rust 1.95). All three tests pass:
  - greet() returns typed result for valid input
  - greet() surfaces typed error for empty input
  - counterStream() delivers the expected event sequence

Authority: PoC plan §2, DEC-014 (typed Flutter/Rust bridge),
SAD-068, SDD-079, SysDes-049.
Naming note: the PoC plan lists this as flutter-rust-bridge-hello,
but Dart pubspec.yaml package names require underscores; the
directory uses underscores accordingly.
Not product code; not promoted into chanora_bridge.

Layout note: includes the full Flutter platform scaffold (android,
ios, macos, windows, web, linux). Only the Linux desktop target has
been built and verified.
This commit is contained in:
EdisonJwa
2026-05-14 12:26:09 +08:00
parent 02c11ead7e
commit 2bbad5feb9
186 changed files with 11579 additions and 0 deletions
@@ -0,0 +1,40 @@
// Same content as integration_test/simple_test.dart, but runnable via
// `flutter test` (flutter_tester, no display required).
//
// Reasoning: the PoC exit criterion is "Flutter can call Rust and receive
// event stream data". flutter_rust_bridge v2 uses dart:ffi on desktop,
// which works inside flutter_tester. A full integration_test driver run
// is not required to evidence the criterion.
import 'package:flutter_rust_bridge_hello/src/rust/api/simple.dart';
import 'package:flutter_rust_bridge_hello/src/rust/frb_generated.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
setUpAll(() async => await RustLib.init());
group('Chanora FRB hello PoC', () {
test('greet() returns typed result for valid input', () {
final r = greet(name: 'Chanora');
expect(r.message, contains('Hello, Chanora!'));
expect(r.elapsedMicros.toInt(), greaterThanOrEqualTo(0));
});
test('greet() surfaces typed error for empty input', () {
expect(() => greet(name: ' '), throwsA(isA<GreetError>()));
});
test('counterStream() delivers the expected event sequence', () async {
const count = 4;
final events = <CounterTick>[];
await for (final tick in counterStream(count: count, intervalMs: 50)) {
events.add(tick);
}
expect(events, hasLength(count));
for (var i = 0; i < count; i++) {
expect(events[i].seq.toInt(), i);
expect(events[i].note, 'tick $i/$count');
}
});
});
}