fzyzcjy / flutter_rust_bridge

Flutter/Dart <-> Rust binding generator, feature-rich, but seamless and simple.

Home Page:https://fzyzcjy.github.io/flutter_rust_bridge/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RustLib does not initializes in tests

dudozermaks opened this issue · comments

commented

Describe the bug

I try to make golden tests in my project and it seems like I can not initialize rust when testing.

Steps to reproduce

  1. git clone https://github.com/fzyzcjy/flutter_rust_bridge/ (we need only frb_example/flutter_via_integrate folder)
  2. cd frb_example/flutter_via_integrate
  3. flutter test (see logs 1)
  4. edit test/widget_test.dart like this:
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility in the flutter_test package. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

import 'package:flutter_via_integrate/main.dart';
import 'package:flutter_via_integrate/src/rust/frb_generated.dart';

void main() async {
  await RustLib.init();

  testWidgets('Counter increments smoke test', (WidgetTester tester) async {
    // Build our app and trigger a frame.
    await tester.pumpWidget(const MyApp());

    // Verify that our counter starts at 0.
    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsNothing);

    // Tap the '+' icon and trigger a frame.
    await tester.tap(find.byIcon(Icons.add));
    await tester.pump();

    // Verify that our counter has incremented.
    expect(find.text('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
  });
}
  1. flutter test (see logs 2)

Logs

# ------------------- 1 ------------------- 
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following StateError was thrown building MyApp(dirty):
Bad state: flutter_rust_bridge has not been initialized. Did you forget to call `await
RustLib.init();`? (If you have configured a different lib name, change `RustLib` to your name.)

The relevant error-causing widget was:
  MyApp
  MyApp:file:///home/maks/shit/work/flutter/flutter_rust_bridge-master/frb_example/flutter_via_integrate/test/widget_test.dart:20:35

When the exception was thrown, this was the stack:
#0      BaseEntrypoint._state (package:flutter_rust_bridge/src/main_components/entrypoint.dart:30:8)
#1      BaseEntrypoint.api (package:flutter_rust_bridge/src/main_components/entrypoint.dart:26:16)
#2      greet (package:flutter_via_integrate/src/rust/api/simple.dart:10:22)
#3      MyApp.build (package:flutter_via_integrate/main.dart:149:61)
#4      StatelessElement.build (package:flutter/src/widgets/framework.dart:5541:49)
#5      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5471:15)
#6      Element.rebuild (package:flutter/src/widgets/framework.dart:5187:7)
#7      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:5453:5)
#8      ComponentElement.mount (package:flutter/src/widgets/framework.dart:5447:5)
#9      Element.inflateWidget (package:flutter/src/widgets/framework.dart:4326:16)
#10     Element.updateChild (package:flutter/src/widgets/framework.dart:3831:20)
#11     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5496:16)
#12     Element.rebuild (package:flutter/src/widgets/framework.dart:5187:7)
#13     ProxyElement.update (package:flutter/src/widgets/framework.dart:5800:5)
#14     Element.updateChild (package:flutter/src/widgets/framework.dart:3815:15)
#15     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5496:16)
#16     StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5634:11)
#17     Element.rebuild (package:flutter/src/widgets/framework.dart:5187:7)
#18     StatefulElement.update (package:flutter/src/widgets/framework.dart:5657:5)
#19     Element.updateChild (package:flutter/src/widgets/framework.dart:3815:15)
#20     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5496:16)
#21     Element.rebuild (package:flutter/src/widgets/framework.dart:5187:7)
#22     ProxyElement.update (package:flutter/src/widgets/framework.dart:5800:5)
#23     Element.updateChild (package:flutter/src/widgets/framework.dart:3815:15)
#24     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5496:16)
#25     Element.rebuild (package:flutter/src/widgets/framework.dart:5187:7)
#26     ProxyElement.update (package:flutter/src/widgets/framework.dart:5800:5)
#27     Element.updateChild (package:flutter/src/widgets/framework.dart:3815:15)
#28     _RawViewElement._updateChild (package:flutter/src/widgets/view.dart:289:16)
#29     _RawViewElement.update (package:flutter/src/widgets/view.dart:376:5)
#30     Element.updateChild (package:flutter/src/widgets/framework.dart:3815:15)
#31     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5496:16)
#32     Element.rebuild (package:flutter/src/widgets/framework.dart:5187:7)
#33     StatelessElement.update (package:flutter/src/widgets/framework.dart:5547:5)
#34     Element.updateChild (package:flutter/src/widgets/framework.dart:3815:15)
#35     RootElement._rebuild (package:flutter/src/widgets/binding.dart:1334:16)
#36     RootElement.update (package:flutter/src/widgets/binding.dart:1312:5)
#37     RootElement.performRebuild (package:flutter/src/widgets/binding.dart:1326:7)
#38     Element.rebuild (package:flutter/src/widgets/framework.dart:5187:7)
#39     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2895:19)
#40     AutomatedTestWidgetsFlutterBinding.drawFrame (package:flutter_test/src/binding.dart:1409:19)
#41     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:457:5)
#42     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1325:15)
#43     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1255:9)
#44     AutomatedTestWidgetsFlutterBinding.pump.<anonymous closure> (package:flutter_test/src/binding.dart:1264:9)
#47     TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:71:41)
#48     AutomatedTestWidgetsFlutterBinding.pump (package:flutter_test/src/binding.dart:1251:27)
#49     WidgetTester.pumpWidget.<anonymous closure> (package:flutter_test/src/widget_tester.dart:578:22)
#52     TestAsyncUtils.guard (package:flutter_test/src/test_async_utils.dart:71:41)
#53     WidgetTester.pumpWidget (package:flutter_test/src/widget_tester.dart:575:27)
#54     main.<anonymous closure> (file:///home/maks/shit/work/flutter/flutter_rust_bridge-master/frb_example/flutter_via_integrate/test/widget_test.dart:20:18)
#55     testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:168:29)
<asynchronous suspension>
#56     TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1013:5)
<asynchronous suspension>
<asynchronous suspension>
(elided 5 frames from dart:async and package:stack_trace)

════════════════════════════════════════════════════════════════════════════════════════════════════
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure was thrown running a test:
Expected: exactly one matching candidate
  Actual: _TextWidgetFinder:<Found 0 widgets with text "0": []>
   Which: means none were found but one was expected

When the exception was thrown, this was the stack:
#4      main.<anonymous closure> (file:///home/maks/shit/work/flutter/flutter_rust_bridge-master/frb_example/flutter_via_integrate/test/widget_test.dart:23:5)
<asynchronous suspension>
#5      testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:168:15)
<asynchronous suspension>
#6      TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:1013:5)
<asynchronous suspension>
<asynchronous suspension>
(elided one frame from package:stack_trace)

This was caught by the test expectation on the following line:
  file:///home/maks/shit/work/flutter/flutter_rust_bridge-master/frb_example/flutter_via_integrate/test/widget_test.dart line 23
The test description was:
  Counter increments smoke test
════════════════════════════════════════════════════════════════════════════════════════════════════
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following message was thrown:
Multiple exceptions (2) were detected during the running of the current test, and at least one was
unexpected.
════════════════════════════════════════════════════════════════════════════════════════════════════
00:01 +0 -1: Counter increments smoke test [E]
  Test failed. See exception logs above.
  The test description was: Counter increments smoke test


To run this test again: /opt/flutter/bin/cache/dart-sdk/bin/dart test /home/maks/shit/work/flutter/flutter_rust_bridge-master/frb_example/flutter_via_integrate/test/widget_test.dart -p vm --plain-name 'Counter increments smoke test'
00:01 +0 -1: Some tests failed.




# ------------------- 2 ------------------- 
00:01 +0 -1: loading /home/maks/shit/work/flutter/flutter_rust_bridge-master/frb_example/flutter_via_integrate/test/widget_test.dart [E]
  Failed to load "/home/maks/shit/work/flutter/flutter_rust_bridge-master/frb_example/flutter_via_integrate/test/widget_test.dart": Invalid argument(s): Failed to load dynamic library 'librust_lib_flutter_via_integrate.so': librust_lib_flutter_via_integrate.so: cannot open shared object file: No such file or directory
  dart:ffi                                                                new DynamicLibrary.open
  package:flutter_rust_bridge/src/platform_types/_io.dart 39:47           new ExternalLibrary.open
  package:flutter_rust_bridge/src/loader/_io.dart 80:46                   loadExternalLibraryRaw.<fn>
  package:flutter_rust_bridge/src/loader/_io.dart 49:22                   loadExternalLibraryRaw.tryAssumingNonPackaged
  package:flutter_rust_bridge/src/loader/_io.dart 79:12                   loadExternalLibraryRaw
  package:flutter_rust_bridge/src/loader/_io.dart 14:10                   loadExternalLibrary
  package:flutter_rust_bridge/src/main_components/entrypoint.dart 107:13  BaseEntrypoint._loadDefaultExternalLibrary
  package:flutter_rust_bridge/src/main_components/entrypoint.dart 53:31   BaseEntrypoint.initImpl
  package:flutter_via_integrate/src/rust/frb_generated.dart 25:20         RustLib.init
  test/widget_test.dart 15:17                                             main


To run this test again: /opt/flutter/bin/cache/dart-sdk/bin/dart test /home/maks/shit/work/flutter/flutter_rust_bridge-master/frb_example/flutter_via_integrate/test/widget_test.dart -p vm --plain-name 'loading /home/maks/shit/work/flutter/flutter_rust_bridge-master/frb_example/flutter_via_integrate/test/widget_test.dart'
00:01 +0 -1: Some tests failed.

Expected behavior

No response

Generated binding code

No response

OS

Arch linux

Version of flutter_rust_bridge_codegen

2.0.0-dev.24

Flutter info

[✓] Flutter (Channel stable, 3.16.9, on Arch Linux 6.7.4-arch1-1, locale en_US.UTF-8)
    • Flutter version 3.16.9 on channel stable at /opt/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 41456452f2 (2 weeks ago), 2024-01-25 10:06:23 -0800
    • Engine revision f40e976bed
    • Dart version 3.2.6
    • DevTools version 2.28.5

[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.3)
    • Android SDK at /home/maks/.android-sdk
    • Platform android-34, build-tools 30.0.3
    • ANDROID_HOME = /home/maks/.android-sdk
    • ANDROID_SDK_ROOT = /opt/android-sdk
    • Java binary at: /usr/lib/jvm/java-17-openjdk/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.10+7)
    • All Android licenses accepted.

[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[✓] Linux toolchain - develop for Linux desktop
    • clang version 16.0.6
    • cmake version 3.28.3
    • ninja version 1.11.1
    • pkg-config version 2.1.0

[!] Android Studio (not installed)
    • Android Studio not found; download from https://developer.android.com/studio/index.html
      (or visit https://flutter.dev/docs/get-started/install/linux#android-setup for detailed
      instructions).

[✓] Connected device (1 available)
    • Linux (desktop) • linux • linux-x64 • Arch Linux 6.7.4-arch1-1

[✓] Network resources
    • All expected network resources are available.

Version of clang++

16.0.6

Additional context

No response

flutter test does not share the same mechanism as flutter run or flutter integration tests, thus the default template which uses cargokit does not trigger compilation of the Rust side.

One way maybe using the build.dart mechanism, which is demonstrated in https://github.com/fzyzcjy/flutter_rust_bridge/tree/master/frb_example/dart_minimal. This is a Dart feature that will be stablized (I guess soon?). Another way may be somehow utilize flutter_test_config.dart.

commented

I think I have a very small knowledge in this field, but I'll try to fix this using your suggested solutions. Thanks!

You are welcome!

commented

Hi again! I tried the first solution - and failed miserably :_). I created build.dart, inserted everything from dart_minimal/build.dart (including simpleBuild definition), added native_assets_cli as a dependency, enabled native_access feature. But I still get error after running flutter test:

Exception: Package(s) flutter_via_integrate require the native assets feature to be enabled. Enable using `flutter config --enable-native-assets`.
  package:flutter_tools/src/base/common.dart 10:3           throwToolExit
  package:flutter_tools/src/native_assets.dart 238:5        nativeBuildRequired
  ===== asynchronous gap ===========================
  package:flutter_tools/src/native_assets.dart 532:8        buildNativeAssetsSingleArchitecture
  ===== asynchronous gap ===========================
  package:flutter_tools/src/test/test_compiler.dart 192:35  TestCompiler._onCompilationRequest

I couldn't find solution for this bug.
The second (and the first, to be honest) method is just beyond my understanding of Flutter, Dart and this library. So, I think I can't help much more.

IIRC (months ago, so my memory is inaccurate) that config is available if you use master Flutter. Usually you should not do that, but since you are just running tests, it is ok to use master flutter.

commented

Ended up using integration_test. For my use case there is no difference between this two, integration_test suited my purpose even better. Maybe we need to add this to documentation: "Use integration tests instead of usual tests"? Is there any point to use standard test over integration_test? If not, do we even need to support this feature?

Looks great!

Is there any point to use standard test over integration_test?

It may execute faster, so if you have a ton of tests it is great.

Btw, yet another way of solving it is to compile manually. For example, just create a small script like cargo build && flutter test.