diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart index 743b4da59e..9f18ec1630 100644 --- a/packages/flutter/test/widgets/widget_inspector_test.dart +++ b/packages/flutter/test/widgets/widget_inspector_test.dart @@ -10,6 +10,7 @@ library; import 'dart:convert'; +import 'dart:developer'; import 'dart:math'; import 'dart:ui' as ui; @@ -240,6 +241,29 @@ extension TextFromString on String { } } +/// Forces garbage collection by aggressive memory allocation. +/// +/// Copied from internal code of +/// https://github.com/dart-lang/leak_tracker +Future _forceGC() async { + const int gcCycles = 3; // 1 should be enough, but we do 3 to make sure test is not flaky. + final int barrier = reachabilityBarrier; + + final List> storage = >[]; + + void allocateMemory() { + storage.add(Iterable.generate(10000, (_) => DateTime.now()).toList()); + if (storage.length > 100) { + storage.removeAt(0); + } + } + + while (reachabilityBarrier < barrier + gcCycles) { + await Future.delayed(Duration.zero); + allocateMemory(); + } +} + final List _weakValueTests = [1, 1.0, 'hello', true, false, Object(), [3, 4], DateTime(2023)]; void main() { @@ -299,6 +323,19 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { expect(WidgetInspectorService.objectToDiagnosticsNode(Alignment.bottomCenter), isNull); }); + test('WidgetInspector does not hold objects from GC', () async { + List? someObject = [DateTime.now(), DateTime.now()]; + final String? id = service.toId(someObject, 'group_name'); + + expect(id, isNotNull); + + final WeakReference ref = WeakReference(someObject); + someObject = null; + await _forceGC(); + + expect(ref.target, null); + }); + testWidgets('WidgetInspector smoke test', (WidgetTester tester) async { // This is a smoke test to verify that adding the inspector doesn't crash. await tester.pumpWidget( @@ -3775,7 +3812,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { _CreationLocation location = knownLocations[id]!; expect(location.file, equals(file)); // ClockText widget. - expect(location.line, equals(55)); + expect(location.line, equals(56)); expect(location.column, equals(9)); expect(location.name, equals('ClockText')); expect(count, equals(1)); @@ -3785,7 +3822,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { location = knownLocations[id]!; expect(location.file, equals(file)); // Text widget in _ClockTextState build method. - expect(location.line, equals(93)); + expect(location.line, equals(94)); expect(location.column, equals(12)); expect(location.name, equals('Text')); expect(count, equals(1)); @@ -3812,7 +3849,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { location = knownLocations[id]!; expect(location.file, equals(file)); // ClockText widget. - expect(location.line, equals(55)); + expect(location.line, equals(56)); expect(location.column, equals(9)); expect(location.name, equals('ClockText')); expect(count, equals(3)); // 3 clock widget instances rebuilt. @@ -3822,7 +3859,7 @@ class _TestWidgetInspectorService extends TestWidgetInspectorService { location = knownLocations[id]!; expect(location.file, equals(file)); // Text widget in _ClockTextState build method. - expect(location.line, equals(93)); + expect(location.line, equals(94)); expect(location.column, equals(12)); expect(location.name, equals('Text')); expect(count, equals(3)); // 3 clock widget instances rebuilt.