nandi/vflutter_ffipublic Fork 0
4506a586d7400b00d732dcb97167be75ab41cab1
Commits
Clone
git clone https://git.rickub.com/nandi/vflutter_ffi.git
git clone ssh://git@rickub.com/nandi/vflutter_ffi.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

widget_test.dart · 121 lines · 4.7 KBDart Blame HistoryRaw
Replace V with Nim 472eb49 nandithebull 20h ago1// Runs against the real Nim library, so it needs the native build on the loader
Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 22h ago2// path — `flutter test` runs on the host VM, not in the app bundle:
3//
4// ./tool/build.sh
5// cd example && LD_LIBRARY_PATH=../build flutter test
6//
7// This is a smoke test of the bridge as the app uses it, not of the widgets.
8import 'package:flutter/material.dart';
9import 'package:flutter_test/flutter_test.dart';
Replace V with Nim 472eb49 nandithebull 20h ago10import 'package:nimflutter_ffi/nimflutter_ffi.dart' as v;
11import 'package:nimflutter_ffi_example/mandelbrot_dart.dart';
Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 22h ago12
13void main() {
14 _zoomTests();
15
16 const view = v.FractalView(width: 64, height: 48, maxIter: 80);
17
Replace V with Nim 472eb49 nandithebull 20h ago18 test('Nim fills the caller-owned buffer', () {
Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 22h ago19 final pixels = v.render(view);
20 expect(pixels.length, view.width * view.height * 4);
21 // Alpha is written for every pixel, inside the set and out.
22 for (var i = 3; i < pixels.length; i += 4) {
23 expect(pixels[i], 255);
24 }
25 // The frame is not uniform — it actually contains a fractal.
26 expect(pixels.toSet().length, greaterThan(8));
27 });
28
29 test('band split matches a single-shot render', () async {
30 final whole = v.render(view);
31 final tiled = await v.renderParallel(view, tiles: 4);
32 expect(tiled, equals(whole));
33 });
34
Replace V with Nim 472eb49 nandithebull 20h ago35 test('the Nim and Dart kernels agree pixel-for-pixel', () {
Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 22h ago36 expect(v.render(view), equals(renderDart(view)));
37 });
38
Replace V with Nim 472eb49 nandithebull 20h ago39 testWidgets('renders a frame computed in Nim', (tester) async {
Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 22h ago40 await tester.pumpWidget(const MaterialApp(home: SizedBox()));
41 // The explorer renders asynchronously; just assert the bridge is usable
42 // from the test binding, which is where FFI setup usually breaks.
43 expect(v.add(20, 22), 42);
Replace V with Nim 472eb49 nandithebull 20h ago44 expect(v.greet('Flutter'), 'Hello, Flutter, from Nim!');
Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 22h ago45 });
46}
47
48void _zoomTests() {
49 group('zoomedAt', () {
50 const view = v.FractalView(width: 800, height: 600);
51
52 test('keeps the anchor point fixed in the complex plane', () {
53 // The plane coordinate under a given viewport fraction must be the same
54 // before and after the zoom. This is the property that broke when the
55 // maths lived inline in the widget.
56 double planeX(v.FractalView f, double fx) =>
57 f.centerX + (fx - 0.5) * f.scale * (f.width / f.height);
58 double planeY(v.FractalView f, double fy) =>
59 f.centerY + (fy - 0.5) * f.scale;
60
61 for (final p in [0.0, 0.25, 0.5, 0.73, 1.0]) {
62 final zoomed = view.zoomedAt(p, p, 0.5);
63 expect(planeX(zoomed, p), closeTo(planeX(view, p), 1e-12));
64 expect(planeY(zoomed, p), closeTo(planeY(view, p), 1e-12));
65 }
66 });
67
68 test('one tap is exactly one zoom level', () {
69 expect(view.zoomedAt(0.5, 0.5, 0.5).scale, closeTo(view.scale / 2, 1e-12));
70 expect(
71 view.zoomedAt(0.5, 0.5, 0.5).zoomedAt(0.5, 0.5, 0.5).scale,
72 closeTo(view.scale / 4, 1e-12),
73 );
74 });
75
Add drag-to-pan 0ed90f3 nandithebull 22h ago76 test('panning moves the plane under the viewport, not the other way', () {
77 // Dragging right must reveal what was to the LEFT, so the centre moves
78 // left. Getting this backwards is the classic panning bug.
79 final right = view.pannedBy(0.5, 0.0);
80 expect(right.centerX, lessThan(view.centerX));
81 expect(right.centerY, view.centerY);
82
83 final down = view.pannedBy(0.0, 0.5);
84 expect(down.centerY, lessThan(view.centerY));
85 expect(down.centerX, view.centerX);
86 });
87
88 test('a full-width drag moves exactly one viewport', () {
89 final panned = view.pannedBy(1.0, 0.0);
90 final aspect = view.width / view.height;
91 expect(panned.centerX,
92 closeTo(view.centerX - view.scale * aspect, 1e-12));
93 });
94
95 test('panning does not change the zoom level', () {
96 expect(view.pannedBy(0.3, -0.7).scale, view.scale);
97 });
98
99 test('panning back and forth returns to the starting view', () {
100 final round = view.pannedBy(0.4, 0.25).pannedBy(-0.4, -0.25);
101 expect(round.centerX, closeTo(view.centerX, 1e-12));
102 expect(round.centerY, closeTo(view.centerY, 1e-12));
103 });
104
105 test('pan distance scales with zoom depth', () {
106 // The same drag must cover less ground when zoomed in, or deep zooms
107 // become unnavigable.
108 final deep = view.copyWith(scale: view.scale / 1000);
109 final shallowShift = (view.pannedBy(0.5, 0).centerX - view.centerX).abs();
110 final deepShift = (deep.pannedBy(0.5, 0).centerX - deep.centerX).abs();
111 expect(deepShift, lessThan(shallowShift / 100));
112 });
113
Add a Mandelbrot example app, and a V kernel worth demonstrating 81540bb nandithebull 22h ago114 test('zooming in then out returns to the starting view', () {
115 final round = view.zoomedAt(0.3, 0.8, 0.5).zoomedAt(0.3, 0.8, 2.0);
116 expect(round.scale, closeTo(view.scale, 1e-12));
117 expect(round.centerX, closeTo(view.centerX, 1e-12));
118 expect(round.centerY, closeTo(view.centerY, 1e-12));
119 });
120 });
121}