From 229124ab91e802af21574fa084145d73070cf31b Mon Sep 17 00:00:00 2001 From: Remi Rousselet Date: Tue, 16 Jan 2024 19:23:09 +0100 Subject: [PATCH] Enable leak tracking (#856) --- .github/workflows/build.yml | 5 ---- .gitignore | 1 + packages/provider/pubspec.yaml | 2 ++ .../provider/test/flutter_test_config.dart | 11 ++++++++ .../provider/test/null_safe/builder_test.dart | 23 ++++++++++++++--- .../change_notifier_provider_test.dart | 1 + .../provider/test/null_safe/context_test.dart | 25 +++++++++++++++++-- .../provider/test/null_safe/devtool_test.dart | 1 + .../null_safe/inherited_provider_test.dart | 17 +++++++++++-- .../null_safe/listenable_provider_test.dart | 7 ++++++ .../listenable_proxy_provider_test.dart | 3 +++ .../test/null_safe/value_listenable_test.dart | 21 +++++++++++++--- 12 files changed, 100 insertions(+), 17 deletions(-) create mode 100644 packages/provider/test/flutter_test_config.dart diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4cc7740e..c50311c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,14 +25,9 @@ jobs: matrix: channel: - master - - dev - - beta steps: - - uses: actions/checkout@v2 - uses: actions/checkout@v3.1.0 - with: - fetch-depth: 2 - uses: subosito/flutter-action@v2.7.1 with: diff --git a/.gitignore b/.gitignore index 673e009a..b5e820eb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ android/ ios/ macos/ .packages +build # Remove the following pattern if you wish to check in your lock file pubspec.lock diff --git a/packages/provider/pubspec.yaml b/packages/provider/pubspec.yaml index 57cfcda9..b3942b2b 100644 --- a/packages/provider/pubspec.yaml +++ b/packages/provider/pubspec.yaml @@ -17,5 +17,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter + # The version is `any` because it is defined by Flutter SDK. + leak_tracker: any mockito: ^5.0.0 test: ^1.15.5 diff --git a/packages/provider/test/flutter_test_config.dart b/packages/provider/test/flutter_test_config.dart new file mode 100644 index 00000000..36f2cfc4 --- /dev/null +++ b/packages/provider/test/flutter_test_config.dart @@ -0,0 +1,11 @@ +import 'dart:async'; + +import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart'; + +FutureOr testExecutable(FutureOr Function() testMain) { + LeakTesting.enable(); + LeakTesting.settings = LeakTesting.settings + .withIgnored(allNotGCed: true, createdByTestHelpers: true); + + return testMain(); +} diff --git a/packages/provider/test/null_safe/builder_test.dart b/packages/provider/test/null_safe/builder_test.dart index c3ae23a3..f3c1c26e 100644 --- a/packages/provider/test/null_safe/builder_test.dart +++ b/packages/provider/test/null_safe/builder_test.dart @@ -22,9 +22,12 @@ void main() { }); testWidgets('.value', (tester) async { + final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); + await tester.pumpWidget( ChangeNotifierProvider.value( - value: ValueNotifier(0), + value: notifier, builder: (context, child) { context.watch>(); return child!; @@ -41,7 +44,12 @@ void main() { testWidgets('default', (tester) async { await tester.pumpWidget( ListenableProvider( - create: (_) => ValueNotifier(0), + create: (_) { + final valueNotifier = ValueNotifier(0); + addTearDown(valueNotifier.dispose); + + return valueNotifier; + }, builder: (context, child) { context.watch>(); return child!; @@ -54,9 +62,12 @@ void main() { }); testWidgets('.value', (tester) async { + final valueNotifier = ValueNotifier(0); + addTearDown(valueNotifier.dispose); + await tester.pumpWidget( ListenableProvider.value( - value: ValueNotifier(0), + value: valueNotifier, builder: (context, child) { context.watch>(); return child!; @@ -326,7 +337,11 @@ void main() { MultiProvider( providers: [ ListenableProvider( - create: (_) => ValueNotifier(0), + create: (_) { + final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); + return notifier; + }, ), ], builder: (context, child) { diff --git a/packages/provider/test/null_safe/change_notifier_provider_test.dart b/packages/provider/test/null_safe/change_notifier_provider_test.dart index 060fe099..4745b265 100644 --- a/packages/provider/test/null_safe/change_notifier_provider_test.dart +++ b/packages/provider/test/null_safe/change_notifier_provider_test.dart @@ -8,6 +8,7 @@ void main() { group('ChangeNotifierProvider', () { testWidgets('value', (tester) async { final myNotifier = ValueNotifier(0); + addTearDown(myNotifier.dispose); await tester.pumpWidget( MultiProvider( diff --git a/packages/provider/test/null_safe/context_test.dart b/packages/provider/test/null_safe/context_test.dart index 6f809d76..f922cb89 100644 --- a/packages/provider/test/null_safe/context_test.dart +++ b/packages/provider/test/null_safe/context_test.dart @@ -9,6 +9,7 @@ void main() { group('context.watch', () { testWidgets('can watch T', (tester) async { final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); await tester.pumpWidget( ChangeNotifierProvider>.value( @@ -36,6 +37,7 @@ void main() { testWidgets('can watch T?', (tester) async { final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); await tester.pumpWidget( ChangeNotifierProvider?>.value( @@ -98,6 +100,8 @@ void main() { expect(find.text(''), findsOneWidget); final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); + await tester.pumpWidget( ChangeNotifierProvider?>.value( value: notifier, @@ -117,6 +121,7 @@ void main() { group('context.watch', () { testWidgets('can watch T?', (tester) async { final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); await tester.pumpWidget( ChangeNotifierProvider?>.value( @@ -175,6 +180,7 @@ void main() { group('context.select', () { testWidgets('can watch T', (tester) async { final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); await tester.pumpWidget( ChangeNotifierProvider>.value( @@ -203,6 +209,7 @@ void main() { testWidgets('can watch T?', (tester) async { final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); await tester.pumpWidget( ChangeNotifierProvider?>.value( @@ -268,6 +275,8 @@ void main() { expect(find.text(''), findsOneWidget); final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); + await tester.pumpWidget( ChangeNotifierProvider?>.value( value: notifier, @@ -287,6 +296,7 @@ void main() { group('context.select', () { testWidgets('can watch T?', (tester) async { final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); await tester.pumpWidget( ChangeNotifierProvider?>.value( @@ -315,6 +325,7 @@ void main() { testWidgets('can watch T', (tester) async { final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); await tester.pumpWidget( ChangeNotifierProvider>.value( @@ -386,9 +397,12 @@ void main() { }, ); + final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); + await tester.pumpWidget( ChangeNotifierProvider?>.value( - value: ValueNotifier(0), + value: notifier, child: child, ), ); @@ -691,10 +705,13 @@ void main() { testWidgets("don't call old selectors if the child rebuilds individually", (tester) async { final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); var buildCount = 0; + final selectedNotifier = ValueNotifier(0); + addTearDown(selectedNotifier.dispose); final selector = - MockSelector.identity>(ValueNotifier(0)); + MockSelector.identity>(selectedNotifier); final child = Builder(builder: (c) { buildCount++; c.select, ValueNotifier>(selector); @@ -1057,6 +1074,7 @@ void main() { testWidgets('context.select deeply compares maps', (tester) async { final notifier = ValueNotifier({}); + addTearDown(notifier.dispose); var buildCount = 0; final selector = MockSelector.identity>({}); @@ -1100,6 +1118,7 @@ void main() { testWidgets('context.select deeply compares lists', (tester) async { final notifier = ValueNotifier([]); + addTearDown(notifier.dispose); var buildCount = 0; final selector = MockSelector.identity>([]); @@ -1142,6 +1161,7 @@ void main() { testWidgets('context.select deeply compares iterables', (tester) async { final notifier = ValueNotifier>([]); + addTearDown(notifier.dispose); var buildCount = 0; final selector = MockSelector.identity>({}); @@ -1184,6 +1204,7 @@ void main() { testWidgets('context.select deeply compares sets', (tester) async { final notifier = ValueNotifier>({}); + addTearDown(notifier.dispose); var buildCount = 0; final selector = MockSelector.identity>({}); diff --git a/packages/provider/test/null_safe/devtool_test.dart b/packages/provider/test/null_safe/devtool_test.dart index 6c5493ea..2338c724 100644 --- a/packages/provider/test/null_safe/devtool_test.dart +++ b/packages/provider/test/null_safe/devtool_test.dart @@ -16,6 +16,7 @@ void main() { testWidgets('calls postEvent whenever a provider is updated', (tester) async { final notifier = ValueNotifier(42); + addTearDown(notifier.dispose); await tester.pumpWidget( MultiProvider( diff --git a/packages/provider/test/null_safe/inherited_provider_test.dart b/packages/provider/test/null_safe/inherited_provider_test.dart index 0cede616..963fbbaa 100644 --- a/packages/provider/test/null_safe/inherited_provider_test.dart +++ b/packages/provider/test/null_safe/inherited_provider_test.dart @@ -271,6 +271,8 @@ void main() { 'Provider.of(listen: false) outside of build works when it loads a provider', (tester) async { final notifier = ValueNotifier(42); + addTearDown(notifier.dispose); + await tester.pumpWidget( MultiProvider( providers: [ @@ -329,9 +331,10 @@ void main() { testWidgets( 'builder receives the current value and updates independently from `update`', (tester) async { - final child = Container(); - final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); + + final child = Container(); final builder = TransitionBuilderMock((c, child) { final notifier = Provider.of>(c); return Text( @@ -365,6 +368,8 @@ void main() { final child = Container(); final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); + final builder = TransitionBuilderMock((c, child) { return const Text('foo', textDirection: TextDirection.ltr); }); @@ -392,6 +397,8 @@ void main() { final child = Container(); final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); + final builder = TransitionBuilderMock((c, child) { return const Text('foo', textDirection: TextDirection.ltr); }); @@ -1663,6 +1670,7 @@ DeferredInheritedProvider(controller: 42, value: 24)'''), }, ); final controller = ValueNotifier(0); + addTearDown(controller.dispose); await tester.pumpWidget( DeferredInheritedProvider, int>.value( @@ -1714,6 +1722,7 @@ DeferredInheritedProvider(controller: 42, value: 24)'''), }, ); final controller = ValueNotifier(0); + addTearDown(controller.dispose); await tester.pumpWidget( DeferredInheritedProvider, int>.value( @@ -1729,6 +1738,7 @@ DeferredInheritedProvider(controller: 42, value: 24)'''), DeferredStartListeningMock, int>(); when(startListening2(any, any, any, any)).thenReturn(() {}); final controller2 = ValueNotifier(0); + addTearDown(controller2.dispose); await tester.pumpWidget( DeferredInheritedProvider, int>.value( @@ -1849,6 +1859,7 @@ DeferredInheritedProvider(controller: 42, value: 24)'''), DeferredStartListeningMock, int>(); when(startListening(any, any, any, any)).thenReturn(() {}); final controller = ValueNotifier(0); + addTearDown(controller.dispose); await tester.pumpWidget( DeferredInheritedProvider, int>.value( @@ -1882,6 +1893,7 @@ DeferredInheritedProvider(controller: 42, value: 24)'''), }, ); final controller = ValueNotifier(0); + addTearDown(controller.dispose); await tester.pumpWidget( DeferredInheritedProvider, int>.value( @@ -1905,6 +1917,7 @@ DeferredInheritedProvider(controller: 42, value: 24)'''), }, ); final controller2 = ValueNotifier(1); + addTearDown(controller2.dispose); await tester.pumpWidget( DeferredInheritedProvider, int>.value( diff --git a/packages/provider/test/null_safe/listenable_provider_test.dart b/packages/provider/test/null_safe/listenable_provider_test.dart index 832bcfb9..49504d6c 100644 --- a/packages/provider/test/null_safe/listenable_provider_test.dart +++ b/packages/provider/test/null_safe/listenable_provider_test.dart @@ -11,6 +11,7 @@ void main() { testWidgets('works with MultiProvider', (tester) async { final key = GlobalKey(); final listenable = ChangeNotifier(); + addTearDown(listenable.dispose); await tester.pumpWidget( MultiProvider( @@ -30,6 +31,7 @@ void main() { (tester) async { final key = GlobalKey(); final notifier = ValueNotifier(0)..addListener(() {}); + addTearDown(notifier.dispose); await tester.pumpWidget( ListenableProvider( @@ -258,6 +260,8 @@ void main() { when(builder(any)).thenReturn(Container()); var listenable = ChangeNotifier(); + addTearDown(listenable.dispose); + Widget build() { return ListenableProvider.value( value: listenable, @@ -276,6 +280,7 @@ void main() { final previousNotifier = listenable; listenable = ChangeNotifier(); + addTearDown(listenable.dispose); await tester.pumpWidget(build()); @@ -349,6 +354,8 @@ void main() { testWidgets('notifylistener rebuilds descendants', (tester) async { final listenable = ChangeNotifier(); + addTearDown(listenable.dispose); + final keyChild = GlobalKey(); final builder = BuilderMock(); when(builder(any)).thenReturn(Container()); diff --git a/packages/provider/test/null_safe/listenable_proxy_provider_test.dart b/packages/provider/test/null_safe/listenable_proxy_provider_test.dart index f4257f29..f2d3bc8b 100644 --- a/packages/provider/test/null_safe/listenable_proxy_provider_test.dart +++ b/packages/provider/test/null_safe/listenable_proxy_provider_test.dart @@ -31,6 +31,8 @@ void main() { testWidgets('rebuilds dependendents when listeners are called', (tester) async { final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); + await tester.pumpWidget( MultiProvider( providers: [ @@ -117,6 +119,7 @@ void main() { testWidgets('disposes of created value', (tester) async { final dispose = DisposeMock>(); final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); final key = GlobalKey(); await tester.pumpWidget( diff --git a/packages/provider/test/null_safe/value_listenable_test.dart b/packages/provider/test/null_safe/value_listenable_test.dart index b87b3a3a..ded95df2 100644 --- a/packages/provider/test/null_safe/value_listenable_test.dart +++ b/packages/provider/test/null_safe/value_listenable_test.dart @@ -37,10 +37,16 @@ void main() { group('valueListenableProvider', () { testWidgets('rebuilds when value change', (tester) async { final listenable = ValueNotifier(0); + addTearDown(listenable.dispose); final child = Builder( - builder: (context) => Text(Provider.of(context).toString(), - textDirection: TextDirection.ltr)); + builder: (context) { + return Text( + Provider.of(context).toString(), + textDirection: TextDirection.ltr, + ); + }, + ); await tester.pumpWidget( ValueListenableProvider.value( @@ -58,6 +64,8 @@ void main() { testWidgets("don't rebuild dependents by default", (tester) async { var buildCount = 0; final listenable = ValueNotifier(0); + addTearDown(listenable.dispose); + final child = Builder(builder: (context) { buildCount++; return Container(); @@ -84,10 +92,13 @@ void main() { testWidgets('pass keys', (tester) async { final key = GlobalKey(); + final valueNotifier = ValueNotifier(42); + addTearDown(valueNotifier.dispose); + await tester.pumpWidget( ValueListenableProvider.value( key: key, - value: ValueNotifier(42), + value: valueNotifier, child: Container(), ), ); @@ -117,10 +128,12 @@ void main() { }); testWidgets('pass updateShouldNotify', (tester) async { + final notifier = ValueNotifier(0); + addTearDown(notifier.dispose); + final shouldNotify = UpdateShouldNotifyMock(); when(shouldNotify(0, 1)).thenReturn(true); - final notifier = ValueNotifier(0); await tester.pumpWidget( ValueListenableProvider.value( value: notifier,