Unverified Commit f05bb9a1 authored by Kostia Sokolovskyi's avatar Kostia Sokolovskyi Committed by GitHub

Instrument RestorationBucket, _RouteEntry and DisposableBuildContext for leak tracking. (#137477)

parent 50ecd570
...@@ -420,6 +420,12 @@ class RestorationManager extends ChangeNotifier { ...@@ -420,6 +420,12 @@ class RestorationManager extends ChangeNotifier {
_doSerialization(); _doSerialization();
assert(!_serializationScheduled); assert(!_serializationScheduled);
} }
@override
void dispose() {
_rootBucket?.dispose();
super.dispose();
}
} }
/// A [RestorationBucket] holds pieces of the restoration data that a part of /// A [RestorationBucket] holds pieces of the restoration data that a part of
...@@ -507,6 +513,9 @@ class RestorationBucket { ...@@ -507,6 +513,9 @@ class RestorationBucket {
_debugOwner = debugOwner; _debugOwner = debugOwner;
return true; return true;
}()); }());
if (kFlutterMemoryAllocationsEnabled) {
_maybeDispatchObjectCreation();
}
} }
/// Creates the root [RestorationBucket] for the provided restoration /// Creates the root [RestorationBucket] for the provided restoration
...@@ -540,6 +549,9 @@ class RestorationBucket { ...@@ -540,6 +549,9 @@ class RestorationBucket {
_debugOwner = manager; _debugOwner = manager;
return true; return true;
}()); }());
if (kFlutterMemoryAllocationsEnabled) {
_maybeDispatchObjectCreation();
}
} }
/// Creates a child bucket initialized with the data that the provided /// Creates a child bucket initialized with the data that the provided
...@@ -563,6 +575,9 @@ class RestorationBucket { ...@@ -563,6 +575,9 @@ class RestorationBucket {
_debugOwner = debugOwner; _debugOwner = debugOwner;
return true; return true;
}()); }());
if (kFlutterMemoryAllocationsEnabled) {
_maybeDispatchObjectCreation();
}
} }
static const String _childrenMapKey = 'c'; static const String _childrenMapKey = 'c';
...@@ -934,6 +949,19 @@ class RestorationBucket { ...@@ -934,6 +949,19 @@ class RestorationBucket {
_parent?._addChildData(this); _parent?._addChildData(this);
} }
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
/// Dispatches event of object creation to [MemoryAllocations.instance].
void _maybeDispatchObjectCreation() {
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectCreated(
library: 'package:flutter/services.dart',
className: '$RestorationBucket',
object: this,
);
}
}
/// Deletes the bucket and all the data stored in it from the bucket /// Deletes the bucket and all the data stored in it from the bucket
/// hierarchy. /// hierarchy.
/// ///
...@@ -948,6 +976,11 @@ class RestorationBucket { ...@@ -948,6 +976,11 @@ class RestorationBucket {
/// This method must only be called by the object's owner. /// This method must only be called by the object's owner.
void dispose() { void dispose() {
assert(_debugAssertNotDisposed()); assert(_debugAssertNotDisposed());
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
}
_visitChildren(_dropChild, concurrentModification: true); _visitChildren(_dropChild, concurrentModification: true);
_claimedChildren.clear(); _claimedChildren.clear();
_childrenToAdd.clear(); _childrenToAdd.clear();
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'framework.dart'; import 'framework.dart';
/// Provides non-leaking access to a [BuildContext]. /// Provides non-leaking access to a [BuildContext].
...@@ -28,7 +30,17 @@ class DisposableBuildContext<T extends State> { ...@@ -28,7 +30,17 @@ class DisposableBuildContext<T extends State> {
/// ///
/// [State.mounted] must be true. /// [State.mounted] must be true.
DisposableBuildContext(T this._state) DisposableBuildContext(T this._state)
: assert(_state.mounted, 'A DisposableBuildContext was given a BuildContext for an Element that is not mounted.'); : assert(_state.mounted, 'A DisposableBuildContext was given a BuildContext for an Element that is not mounted.') {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectCreated(
library: 'package:flutter/widgets.dart',
className: '$DisposableBuildContext',
object: this,
);
}
}
T? _state; T? _state;
...@@ -66,6 +78,11 @@ class DisposableBuildContext<T extends State> { ...@@ -66,6 +78,11 @@ class DisposableBuildContext<T extends State> {
/// Creators of this object must call [dispose] when their [Element] is /// Creators of this object must call [dispose] when their [Element] is
/// unmounted, i.e. when [State.dispose] is called. /// unmounted, i.e. when [State.dispose] is called.
void dispose() { void dispose() {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
}
_state = null; _state = null;
} }
} }
...@@ -2913,7 +2913,17 @@ class _RouteEntry extends RouteTransitionRecord { ...@@ -2913,7 +2913,17 @@ class _RouteEntry extends RouteTransitionRecord {
initialState == _RouteLifecycle.pushReplace || initialState == _RouteLifecycle.pushReplace ||
initialState == _RouteLifecycle.replace, initialState == _RouteLifecycle.replace,
), ),
currentState = initialState; currentState = initialState {
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectCreated(
library: 'package:flutter/widgets.dart',
className: '$_RouteEntry',
object: this,
);
}
}
@override @override
final Route<dynamic> route; final Route<dynamic> route;
...@@ -3125,6 +3135,11 @@ class _RouteEntry extends RouteTransitionRecord { ...@@ -3125,6 +3135,11 @@ class _RouteEntry extends RouteTransitionRecord {
/// before disposing. /// before disposing.
void forcedDispose() { void forcedDispose() {
assert(currentState.index < _RouteLifecycle.disposed.index); assert(currentState.index < _RouteLifecycle.disposed.index);
// TODO(polina-c): stop duplicating code across disposables
// https://github.com/flutter/flutter/issues/137435
if (kFlutterMemoryAllocationsEnabled) {
MemoryAllocations.instance.dispatchObjectDisposed(object: this);
}
currentState = _RouteLifecycle.disposed; currentState = _RouteLifecycle.disposed;
route.dispose(); route.dispose();
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:leak_tracker_flutter_testing/leak_tracker_flutter_testing.dart';
import 'restoration.dart'; import 'restoration.dart';
...@@ -562,6 +563,51 @@ void main() { ...@@ -562,6 +563,51 @@ void main() {
expect(() => bucket.rename('bar'), throwsFlutterError); expect(() => bucket.rename('bar'), throwsFlutterError);
expect(() => bucket.dispose(), throwsFlutterError); expect(() => bucket.dispose(), throwsFlutterError);
}); });
test('$RestorationBucket dispatches memory events', () async {
await expectLater(
await memoryEvents(
() => RestorationBucket.empty(
restorationId: 'child1',
debugOwner: null,
).dispose(),
RestorationBucket,
),
areCreateAndDispose,
);
final MockRestorationManager manager1 = MockRestorationManager();
addTearDown(manager1.dispose);
await expectLater(
await memoryEvents(
() => RestorationBucket.root(
manager: manager1,
rawData: null,
).dispose(),
RestorationBucket,
),
areCreateAndDispose,
);
final MockRestorationManager manager2 = MockRestorationManager();
addTearDown(manager2.dispose);
final RestorationBucket parent = RestorationBucket.root(
manager: manager2,
rawData: _createRawDataSet()
);
addTearDown(parent.dispose);
await expectLater(
await memoryEvents(
() => RestorationBucket.child(
restorationId: 'child1',
parent: parent,
debugOwner: null,
).dispose(),
RestorationBucket,
),
areCreateAndDispose,
);
});
} }
Map<String, dynamic> _createRawDataSet() { Map<String, dynamic> _createRawDataSet() {
......
...@@ -57,6 +57,7 @@ void main() { ...@@ -57,6 +57,7 @@ void main() {
expect(rootBucket!.read<int>('value1'), 10); expect(rootBucket!.read<int>('value1'), 10);
expect(rootBucket!.read<String>('value2'), 'Hello'); expect(rootBucket!.read<String>('value2'), 'Hello');
final RestorationBucket child = rootBucket!.claimChild('child1', debugOwner: null); final RestorationBucket child = rootBucket!.claimChild('child1', debugOwner: null);
addTearDown(child.dispose);
expect(child.read<int>('another value'), 22); expect(child.read<int>('another value'), 22);
// Accessing the root bucket again completes synchronously with same bucket. // Accessing the root bucket again completes synchronously with same bucket.
...@@ -157,6 +158,7 @@ void main() { ...@@ -157,6 +158,7 @@ void main() {
expect(newRoot!.read<int>('foo'), 33); expect(newRoot!.read<int>('foo'), 33);
expect(newRoot!.read<int>('value1'), null); expect(newRoot!.read<int>('value1'), null);
final RestorationBucket newChild = newRoot!.claimChild('childFoo', debugOwner: null); final RestorationBucket newChild = newRoot!.claimChild('childFoo', debugOwner: null);
addTearDown(newChild.dispose);
expect(newChild.read<String>('bar'), 'Hello'); expect(newChild.read<String>('bar'), 'Hello');
}); });
......
...@@ -30,6 +30,21 @@ void main() { ...@@ -30,6 +30,21 @@ void main() {
expect(() => DisposableBuildContext(state), throwsAssertionError); expect(() => DisposableBuildContext(state), throwsAssertionError);
}); });
testWidgetsWithLeakTracking('DisposableBuildContext dispatches memory events', (WidgetTester tester) async {
final GlobalKey<TestWidgetState> key = GlobalKey<TestWidgetState>();
await tester.pumpWidget(TestWidget(key));
final TestWidgetState state = key.currentState!;
await expectLater(
await memoryEvents(
() => DisposableBuildContext<TestWidgetState>(state).dispose(),
DisposableBuildContext<TestWidgetState>,
),
areCreateAndDispose,
);
});
} }
class TestWidget extends StatefulWidget { class TestWidget extends StatefulWidget {
......
...@@ -15,6 +15,7 @@ void main() { ...@@ -15,6 +15,7 @@ void main() {
addTearDown(manager.dispose); addTearDown(manager.dispose);
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
addTearDown(root.dispose);
expect(rawData, isEmpty); expect(rawData, isEmpty);
await tester.pumpWidget( await tester.pumpWidget(
...@@ -41,6 +42,7 @@ void main() { ...@@ -41,6 +42,7 @@ void main() {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose); addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet());
addTearDown(root.dispose);
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
...@@ -64,6 +66,7 @@ void main() { ...@@ -64,6 +66,7 @@ void main() {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose); addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet());
addTearDown(root.dispose);
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
...@@ -107,6 +110,7 @@ void main() { ...@@ -107,6 +110,7 @@ void main() {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose); addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet());
addTearDown(root.dispose);
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
...@@ -144,6 +148,7 @@ void main() { ...@@ -144,6 +148,7 @@ void main() {
addTearDown(manager.dispose); addTearDown(manager.dispose);
final Map<String, dynamic> rawData = _createRawDataSet(); final Map<String, dynamic> rawData = _createRawDataSet();
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
addTearDown(root.dispose);
expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isTrue); expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isTrue);
await tester.pumpWidget( await tester.pumpWidget(
...@@ -173,6 +178,7 @@ void main() { ...@@ -173,6 +178,7 @@ void main() {
addTearDown(manager.dispose); addTearDown(manager.dispose);
final Map<String, dynamic> rawData = _createRawDataSet(); final Map<String, dynamic> rawData = _createRawDataSet();
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
addTearDown(root.dispose);
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
...@@ -235,6 +241,7 @@ void main() { ...@@ -235,6 +241,7 @@ void main() {
addTearDown(manager.dispose); addTearDown(manager.dispose);
final Map<String, dynamic> rawData = _createRawDataSet(); final Map<String, dynamic> rawData = _createRawDataSet();
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
addTearDown(root.dispose);
await tester.pumpWidget( await tester.pumpWidget(
_TestRestorableWidget( _TestRestorableWidget(
...@@ -297,6 +304,7 @@ void main() { ...@@ -297,6 +304,7 @@ void main() {
addTearDown(manager.dispose); addTearDown(manager.dispose);
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
addTearDown(root.dispose);
final Key key = GlobalKey(); final Key key = GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(
......
...@@ -15,6 +15,7 @@ void main() { ...@@ -15,6 +15,7 @@ void main() {
restorationId: 'foo', restorationId: 'foo',
debugOwner: 'owner', debugOwner: 'owner',
); );
addTearDown(bucket1.dispose);
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
...@@ -31,6 +32,8 @@ void main() { ...@@ -31,6 +32,8 @@ void main() {
restorationId: 'foo2', restorationId: 'foo2',
debugOwner: 'owner', debugOwner: 'owner',
); );
addTearDown(bucket2.dispose);
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
bucket: bucket2, bucket: bucket2,
...@@ -104,6 +107,7 @@ void main() { ...@@ -104,6 +107,7 @@ void main() {
addTearDown(manager.dispose); addTearDown(manager.dispose);
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
addTearDown(root.dispose);
expect(rawData, isEmpty); expect(rawData, isEmpty);
await tester.pumpWidget( await tester.pumpWidget(
...@@ -126,6 +130,7 @@ void main() { ...@@ -126,6 +130,7 @@ void main() {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose); addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet());
addTearDown(root.dispose);
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
...@@ -147,6 +152,7 @@ void main() { ...@@ -147,6 +152,7 @@ void main() {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose); addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet());
addTearDown(root.dispose);
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
...@@ -187,6 +193,7 @@ void main() { ...@@ -187,6 +193,7 @@ void main() {
addTearDown(manager.dispose); addTearDown(manager.dispose);
final Map<String, dynamic> rawData = _createRawDataSet(); final Map<String, dynamic> rawData = _createRawDataSet();
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
addTearDown(root.dispose);
expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isTrue); expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isTrue);
await tester.pumpWidget( await tester.pumpWidget(
...@@ -216,6 +223,7 @@ void main() { ...@@ -216,6 +223,7 @@ void main() {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose); addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: <String, dynamic>{}); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: <String, dynamic>{});
addTearDown(root.dispose);
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
...@@ -274,6 +282,8 @@ void main() { ...@@ -274,6 +282,8 @@ void main() {
final MockRestorationManager manager = MockRestorationManager(); final MockRestorationManager manager = MockRestorationManager();
addTearDown(manager.dispose); addTearDown(manager.dispose);
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: <String, dynamic>{}); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: <String, dynamic>{});
addTearDown(root.dispose);
await tester.pumpWidget( await tester.pumpWidget(
UnmanagedRestorationScope( UnmanagedRestorationScope(
bucket: root, bucket: root,
...@@ -316,6 +326,7 @@ void main() { ...@@ -316,6 +326,7 @@ void main() {
addTearDown(manager.dispose); addTearDown(manager.dispose);
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
addTearDown(root.dispose);
final Key scopeKey = GlobalKey(); final Key scopeKey = GlobalKey();
await tester.pumpWidget( await tester.pumpWidget(
......
...@@ -27,6 +27,7 @@ void main() { ...@@ -27,6 +27,7 @@ void main() {
addTearDown(manager.dispose); addTearDown(manager.dispose);
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData);
addTearDown(root.dispose);
expect(rawData, isEmpty); expect(rawData, isEmpty);
await tester.pumpWidget( await tester.pumpWidget(
...@@ -77,6 +78,7 @@ void main() { ...@@ -77,6 +78,7 @@ void main() {
// Complete the future. // Complete the future.
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: rawData);
addTearDown(root.dispose);
bucketCompleter.complete(root); bucketCompleter.complete(root);
await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100));
...@@ -92,6 +94,7 @@ void main() { ...@@ -92,6 +94,7 @@ void main() {
testWidgetsWithLeakTracking('no delay when root is available synchronously', (WidgetTester tester) async { testWidgetsWithLeakTracking('no delay when root is available synchronously', (WidgetTester tester) async {
final Map<String, dynamic> rawData = <String, dynamic>{}; final Map<String, dynamic> rawData = <String, dynamic>{};
final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: rawData); final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: rawData);
addTearDown(root.dispose);
binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root);
await tester.pumpWidget( await tester.pumpWidget(
...@@ -156,6 +159,7 @@ void main() { ...@@ -156,6 +159,7 @@ void main() {
// Complete the future. // Complete the future.
final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: <String, dynamic>{}); final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: <String, dynamic>{});
addTearDown(root.dispose);
bucketCompleter.complete(root); bucketCompleter.complete(root);
await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100));
...@@ -187,6 +191,7 @@ void main() { ...@@ -187,6 +191,7 @@ void main() {
addTearDown(manager.dispose); addTearDown(manager.dispose);
final Map<String, dynamic> inScopeRawData = <String, dynamic>{}; final Map<String, dynamic> inScopeRawData = <String, dynamic>{};
final RestorationBucket inScopeRootBucket = RestorationBucket.root(manager: manager, rawData: inScopeRawData); final RestorationBucket inScopeRootBucket = RestorationBucket.root(manager: manager, rawData: inScopeRawData);
addTearDown(inScopeRootBucket.dispose);
await tester.pumpWidget( await tester.pumpWidget(
Directionality( Directionality(
...@@ -231,6 +236,7 @@ void main() { ...@@ -231,6 +236,7 @@ void main() {
final Map<String, dynamic> outOfScopeRawData = <String, dynamic>{}; final Map<String, dynamic> outOfScopeRawData = <String, dynamic>{};
final RestorationBucket outOfScopeRootBucket = RestorationBucket.root(manager: binding.restorationManager, rawData: outOfScopeRawData); final RestorationBucket outOfScopeRootBucket = RestorationBucket.root(manager: binding.restorationManager, rawData: outOfScopeRawData);
addTearDown(outOfScopeRootBucket.dispose);
bucketCompleter.complete(outOfScopeRootBucket); bucketCompleter.complete(outOfScopeRootBucket);
await tester.pump(const Duration(milliseconds: 100)); await tester.pump(const Duration(milliseconds: 100));
...@@ -267,6 +273,7 @@ void main() { ...@@ -267,6 +273,7 @@ void main() {
testWidgetsWithLeakTracking('injects new root when old one is decommissioned', (WidgetTester tester) async { testWidgetsWithLeakTracking('injects new root when old one is decommissioned', (WidgetTester tester) async {
final Map<String, dynamic> firstRawData = <String, dynamic>{}; final Map<String, dynamic> firstRawData = <String, dynamic>{};
final RestorationBucket firstRoot = RestorationBucket.root(manager: binding.restorationManager, rawData: firstRawData); final RestorationBucket firstRoot = RestorationBucket.root(manager: binding.restorationManager, rawData: firstRawData);
addTearDown(firstRoot.dispose);
binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(firstRoot); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(firstRoot);
await tester.pumpWidget( await tester.pumpWidget(
...@@ -299,9 +306,9 @@ void main() { ...@@ -299,9 +306,9 @@ void main() {
}, },
}; };
final RestorationBucket secondRoot = RestorationBucket.root(manager: binding.restorationManager, rawData: secondRawData); final RestorationBucket secondRoot = RestorationBucket.root(manager: binding.restorationManager, rawData: secondRawData);
addTearDown(secondRoot.dispose);
binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(secondRoot); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(secondRoot);
await tester.pump(); await tester.pump();
firstRoot.dispose();
expect(state.bucket, isNot(same(firstBucket))); expect(state.bucket, isNot(same(firstBucket)));
expect(state.bucket!.read<int>('foo'), 22); expect(state.bucket!.read<int>('foo'), 22);
...@@ -336,6 +343,7 @@ void main() { ...@@ -336,6 +343,7 @@ void main() {
expect(state.bucket, isNull); expect(state.bucket, isNull);
final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: null); final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: null);
addTearDown(root.dispose);
binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root);
await tester.pump(); await tester.pump();
...@@ -346,6 +354,7 @@ void main() { ...@@ -346,6 +354,7 @@ void main() {
testWidgetsWithLeakTracking('can switch to null', (WidgetTester tester) async { testWidgetsWithLeakTracking('can switch to null', (WidgetTester tester) async {
final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: null); final RestorationBucket root = RestorationBucket.root(manager: binding.restorationManager, rawData: null);
addTearDown(root.dispose);
binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket>(root);
await tester.pumpWidget( await tester.pumpWidget(
...@@ -367,7 +376,6 @@ void main() { ...@@ -367,7 +376,6 @@ void main() {
binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket?>(null); binding.restorationManager.rootBucket = SynchronousFuture<RestorationBucket?>(null);
await tester.pump(); await tester.pump();
root.dispose();
expect(binding.restorationManager.rootBucketAccessed, 2); expect(binding.restorationManager.rootBucketAccessed, 2);
expect(find.text('Hello'), findsOneWidget); expect(find.text('Hello'), findsOneWidget);
......
...@@ -39,6 +39,7 @@ void main() { ...@@ -39,6 +39,7 @@ void main() {
await tester.pumpWidget(TestWidget(key)); await tester.pumpWidget(TestWidget(key));
final DisposableBuildContext context = DisposableBuildContext(key.currentState!); final DisposableBuildContext context = DisposableBuildContext(key.currentState!);
addTearDown(context.dispose);
final TestImageProvider testImageProvider = TestImageProvider(testImage.clone()); final TestImageProvider testImageProvider = TestImageProvider(testImage.clone());
final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>( final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>(
context: context, context: context,
...@@ -74,6 +75,7 @@ void main() { ...@@ -74,6 +75,7 @@ void main() {
)); ));
final DisposableBuildContext context = DisposableBuildContext(key.currentState!); final DisposableBuildContext context = DisposableBuildContext(key.currentState!);
addTearDown(context.dispose);
final TestImageProvider testImageProvider = TestImageProvider(testImage.clone()); final TestImageProvider testImageProvider = TestImageProvider(testImage.clone());
final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>( final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>(
context: context, context: context,
...@@ -115,6 +117,7 @@ void main() { ...@@ -115,6 +117,7 @@ void main() {
)); ));
final DisposableBuildContext context = DisposableBuildContext(keys.last.currentState!); final DisposableBuildContext context = DisposableBuildContext(keys.last.currentState!);
addTearDown(context.dispose);
final TestImageProvider testImageProvider = TestImageProvider(testImage.clone()); final TestImageProvider testImageProvider = TestImageProvider(testImage.clone());
final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>( final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>(
context: context, context: context,
...@@ -173,6 +176,7 @@ void main() { ...@@ -173,6 +176,7 @@ void main() {
)); ));
final DisposableBuildContext context = DisposableBuildContext(keys.last.currentState!); final DisposableBuildContext context = DisposableBuildContext(keys.last.currentState!);
addTearDown(context.dispose);
final TestImageProvider testImageProvider = TestImageProvider(testImage.clone()); final TestImageProvider testImageProvider = TestImageProvider(testImage.clone());
final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>( final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>(
context: context, context: context,
...@@ -241,6 +245,7 @@ void main() { ...@@ -241,6 +245,7 @@ void main() {
)); ));
final DisposableBuildContext context = DisposableBuildContext(keys.last.currentState!); final DisposableBuildContext context = DisposableBuildContext(keys.last.currentState!);
addTearDown(context.dispose);
final TestImageProvider testImageProvider = TestImageProvider(testImage.clone()); final TestImageProvider testImageProvider = TestImageProvider(testImage.clone());
final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>( final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>(
context: context, context: context,
...@@ -307,6 +312,7 @@ void main() { ...@@ -307,6 +312,7 @@ void main() {
)); ));
final DisposableBuildContext context = DisposableBuildContext(key.currentState!); final DisposableBuildContext context = DisposableBuildContext(key.currentState!);
addTearDown(context.dispose);
final TestImageProvider testImageProvider = TestImageProvider(testImage.clone()); final TestImageProvider testImageProvider = TestImageProvider(testImage.clone());
final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>( final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>(
context: context, context: context,
...@@ -359,6 +365,7 @@ void main() { ...@@ -359,6 +365,7 @@ void main() {
)); ));
final DisposableBuildContext context = DisposableBuildContext(key.currentState!); final DisposableBuildContext context = DisposableBuildContext(key.currentState!);
addTearDown(context.dispose);
final TestImageProvider testImageProvider = TestImageProvider(testImage.clone()); final TestImageProvider testImageProvider = TestImageProvider(testImage.clone());
final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>( final ScrollAwareImageProvider<TestImageProvider> imageProvider = ScrollAwareImageProvider<TestImageProvider>(
context: context, context: context,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment