| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter/widgets.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import 'restoration.dart'; |
| |
| void main() { |
| testWidgets('claims bucket', (WidgetTester tester) async { |
| const String id = 'hello world 1234'; |
| final MockRestorationManager manager = MockRestorationManager(); |
| addTearDown(manager.dispose); |
| final Map<String, dynamic> rawData = <String, dynamic>{}; |
| final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); |
| addTearDown(root.dispose); |
| expect(rawData, isEmpty); |
| |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: const _TestRestorableWidget( |
| restorationId: id, |
| ), |
| ), |
| ); |
| manager.doSerialization(); |
| |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(state.bucket?.restorationId, id); |
| expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey(id), isTrue); |
| expect(state.property.value, 10); |
| expect((((rawData[childrenMapKey] as Map<Object?, Object?>)[id]! as Map<String, dynamic>)[valuesMapKey] as Map<Object?, Object?>)['foo'], 10); |
| expect(state.property.log, <String>['createDefaultValue', 'initWithValue', 'toPrimitives']); |
| expect(state.toggleBucketLog, isEmpty); |
| expect(state.restoreStateLog.single, isNull); |
| }); |
| |
| testWidgets('claimed bucket with data', (WidgetTester tester) async { |
| final MockRestorationManager manager = MockRestorationManager(); |
| addTearDown(manager.dispose); |
| final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); |
| addTearDown(root.dispose); |
| |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: const _TestRestorableWidget( |
| restorationId: 'child1', |
| ), |
| ), |
| ); |
| manager.doSerialization(); |
| |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(state.bucket!.restorationId, 'child1'); |
| expect(state.property.value, 22); |
| expect(state.property.log, <String>['fromPrimitives', 'initWithValue']); |
| expect(state.toggleBucketLog, isEmpty); |
| expect(state.restoreStateLog.single, isNull); |
| }); |
| |
| testWidgets('renames existing bucket when new ID is provided via widget', (WidgetTester tester) async { |
| final MockRestorationManager manager = MockRestorationManager(); |
| addTearDown(manager.dispose); |
| final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); |
| addTearDown(root.dispose); |
| |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: const _TestRestorableWidget( |
| restorationId: 'child1', |
| ), |
| ), |
| ); |
| manager.doSerialization(); |
| |
| // Claimed existing bucket with data. |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(state.bucket!.restorationId, 'child1'); |
| expect(state.bucket!.read<int>('foo'), 22); |
| final RestorationBucket bucket = state.bucket!; |
| |
| state.property.log.clear(); |
| state.restoreStateLog.clear(); |
| |
| // Rename the existing bucket. |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: const _TestRestorableWidget( |
| restorationId: 'something else', |
| ), |
| ), |
| ); |
| manager.doSerialization(); |
| |
| expect(state.bucket!.restorationId, 'something else'); |
| expect(state.bucket!.read<int>('foo'), 22); |
| expect(state.bucket, same(bucket)); |
| expect(state.property.log, isEmpty); |
| expect(state.restoreStateLog, isEmpty); |
| expect(state.toggleBucketLog, isEmpty); |
| }); |
| |
| testWidgets('renames existing bucket when didUpdateRestorationId is called', (WidgetTester tester) async { |
| final MockRestorationManager manager = MockRestorationManager(); |
| addTearDown(manager.dispose); |
| final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: _createRawDataSet()); |
| addTearDown(root.dispose); |
| |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: const _TestRestorableWidget( |
| restorationId: 'child1', |
| ), |
| ), |
| ); |
| manager.doSerialization(); |
| |
| // Claimed existing bucket with data. |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(state.bucket!.restorationId, 'child1'); |
| expect(state.bucket!.read<int>('foo'), 22); |
| final RestorationBucket bucket = state.bucket!; |
| |
| state.property.log.clear(); |
| state.restoreStateLog.clear(); |
| |
| // Rename the existing bucket. |
| state.injectId('newnewnew'); |
| manager.doSerialization(); |
| |
| expect(state.bucket!.restorationId, 'newnewnew'); |
| expect(state.bucket!.read<int>('foo'), 22); |
| expect(state.bucket, same(bucket)); |
| expect(state.property.log, isEmpty); |
| expect(state.restoreStateLog, isEmpty); |
| expect(state.toggleBucketLog, isEmpty); |
| }); |
| |
| testWidgets('Disposing widget removes its data', (WidgetTester tester) async { |
| final MockRestorationManager manager = MockRestorationManager(); |
| addTearDown(manager.dispose); |
| final Map<String, dynamic> rawData = _createRawDataSet(); |
| final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); |
| addTearDown(root.dispose); |
| |
| expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isTrue); |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: const _TestRestorableWidget( |
| restorationId: 'child1', |
| ), |
| ), |
| ); |
| manager.doSerialization(); |
| expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isTrue); |
| |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: Container(), |
| ), |
| ); |
| manager.doSerialization(); |
| |
| expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isFalse); |
| }); |
| |
| testWidgets('toggling id between null and non-null', (WidgetTester tester) async { |
| final MockRestorationManager manager = MockRestorationManager(); |
| addTearDown(manager.dispose); |
| final Map<String, dynamic> rawData = _createRawDataSet(); |
| final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); |
| addTearDown(root.dispose); |
| |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: const _TestRestorableWidget(), |
| ), |
| ); |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(state.bucket, isNull); |
| expect(state.property.value, 10); // Initialized to default. |
| expect((((rawData[childrenMapKey] as Map<String, dynamic>)['child1'] as Map<String, dynamic>)[valuesMapKey] as Map<String, dynamic>)['foo'], 22); |
| expect(state.property.log, <String>['createDefaultValue', 'initWithValue']); |
| state.property.log.clear(); |
| expect(state.restoreStateLog.single, isNull); |
| expect(state.toggleBucketLog, isEmpty); |
| state.restoreStateLog.clear(); |
| state.toggleBucketLog.clear(); |
| |
| // Change id to non-null. |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: const _TestRestorableWidget( |
| restorationId: 'child1', |
| ), |
| ), |
| ); |
| manager.doSerialization(); |
| expect(state.bucket, isNotNull); |
| expect(state.bucket!.restorationId, 'child1'); |
| expect(state.property.value, 10); |
| expect((((rawData[childrenMapKey] as Map<String, dynamic>)['child1'] as Map<String, dynamic>)[valuesMapKey] as Map<String, dynamic>)['foo'], 10); |
| expect(state.property.log, <String>['toPrimitives']); |
| state.property.log.clear(); |
| expect(state.restoreStateLog, isEmpty); |
| expect(state.toggleBucketLog.single, isNull); |
| state.restoreStateLog.clear(); |
| state.toggleBucketLog.clear(); |
| |
| final RestorationBucket bucket = state.bucket!; |
| |
| // Change id back to null. |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: const _TestRestorableWidget(), |
| ), |
| ); |
| manager.doSerialization(); |
| expect(state.bucket, isNull); |
| expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isFalse); |
| expect(state.property.log, isEmpty); |
| expect(state.restoreStateLog, isEmpty); |
| expect(state.toggleBucketLog.single, same(bucket)); |
| }); |
| |
| testWidgets('move in and out of scope', (WidgetTester tester) async { |
| final Key key = GlobalKey(); |
| final MockRestorationManager manager = MockRestorationManager(); |
| addTearDown(manager.dispose); |
| final Map<String, dynamic> rawData = _createRawDataSet(); |
| final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); |
| addTearDown(root.dispose); |
| |
| await tester.pumpWidget( |
| _TestRestorableWidget( |
| key: key, |
| restorationId: 'child1', |
| ), |
| ); |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(state.bucket, isNull); |
| expect(state.property.value, 10); // Initialized to default. |
| expect((((rawData[childrenMapKey] as Map<String, dynamic>)['child1'] as Map<String, dynamic>)[valuesMapKey] as Map<String, dynamic>)['foo'], 22); |
| expect(state.property.log, <String>['createDefaultValue', 'initWithValue']); |
| state.property.log.clear(); |
| expect(state.restoreStateLog.single, isNull); |
| expect(state.toggleBucketLog, isEmpty); |
| state.restoreStateLog.clear(); |
| state.toggleBucketLog.clear(); |
| |
| // Move it under a valid scope. |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: _TestRestorableWidget( |
| key: key, |
| restorationId: 'child1', |
| ), |
| ), |
| ); |
| manager.doSerialization(); |
| expect(state.bucket, isNotNull); |
| expect(state.bucket!.restorationId, 'child1'); |
| expect(state.property.value, 10); |
| expect((((rawData[childrenMapKey] as Map<String, dynamic>)['child1'] as Map<String, dynamic>)[valuesMapKey] as Map<String, dynamic>)['foo'], 10); |
| expect(state.property.log, <String>['toPrimitives']); |
| state.property.log.clear(); |
| expect(state.restoreStateLog, isEmpty); |
| expect(state.toggleBucketLog.single, isNull); |
| state.restoreStateLog.clear(); |
| state.toggleBucketLog.clear(); |
| |
| final RestorationBucket bucket = state.bucket!; |
| |
| // Move out of scope again. |
| await tester.pumpWidget( |
| _TestRestorableWidget( |
| key: key, |
| restorationId: 'child1', |
| ), |
| ); |
| manager.doSerialization(); |
| expect(state.bucket, isNull); |
| expect((rawData[childrenMapKey] as Map<String, dynamic>).containsKey('child1'), isFalse); |
| expect(state.property.log, isEmpty); |
| expect(state.restoreStateLog, isEmpty); |
| expect(state.toggleBucketLog.single, same(bucket)); |
| }); |
| |
| testWidgets('moving scope moves its data', (WidgetTester tester) async { |
| final MockRestorationManager manager = MockRestorationManager(); |
| addTearDown(manager.dispose); |
| final Map<String, dynamic> rawData = <String, dynamic>{}; |
| final RestorationBucket root = RestorationBucket.root(manager: manager, rawData: rawData); |
| addTearDown(root.dispose); |
| final Key key = GlobalKey(); |
| |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: Row( |
| textDirection: TextDirection.ltr, |
| children: <Widget>[ |
| RestorationScope( |
| restorationId: 'fixed', |
| child: _TestRestorableWidget( |
| key: key, |
| restorationId: 'moving-child', |
| ), |
| ), |
| ], |
| ), |
| ), |
| ); |
| manager.doSerialization(); |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(state.bucket!.restorationId, 'moving-child'); |
| expect((((rawData[childrenMapKey] as Map<Object?, Object?>)['fixed']! as Map<String, dynamic>)[childrenMapKey] as Map<Object?, Object?>).containsKey('moving-child'), isTrue); |
| final RestorationBucket bucket = state.bucket!; |
| state.property.log.clear(); |
| state.restoreStateLog.clear(); |
| |
| state.bucket!.write('value', 11); |
| manager.doSerialization(); |
| |
| // Move widget. |
| await tester.pumpWidget( |
| UnmanagedRestorationScope( |
| bucket: root, |
| child: Row( |
| textDirection: TextDirection.ltr, |
| children: <Widget>[ |
| RestorationScope( |
| restorationId: 'fixed', |
| child: Container(), |
| ), |
| _TestRestorableWidget( |
| key: key, |
| restorationId: 'moving-child', |
| ), |
| ], |
| ), |
| ), |
| ); |
| manager.doSerialization(); |
| expect(state.bucket!.restorationId, 'moving-child'); |
| expect(state.bucket, same(bucket)); |
| expect(state.bucket!.read<int>('value'), 11); |
| expect(state.property.log, isEmpty); |
| expect(state.toggleBucketLog, isEmpty); |
| expect(state.restoreStateLog, isEmpty); |
| |
| expect((rawData[childrenMapKey] as Map<Object?, Object?>)['fixed'], isEmpty); |
| expect((rawData[childrenMapKey] as Map<Object?, Object?>).containsKey('moving-child'), isTrue); |
| }); |
| |
| testWidgets('restartAndRestore', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const RootRestorationScope( |
| restorationId: 'root-child', |
| child: _TestRestorableWidget( |
| restorationId: 'widget', |
| ), |
| ), |
| ); |
| |
| _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(state.bucket, isNotNull); |
| expect(state.property.value, 10); // default |
| expect(state.property.log, <String>['createDefaultValue', 'initWithValue', 'toPrimitives']); |
| expect(state.restoreStateLog.single, isNull); |
| expect(state.toggleBucketLog, isEmpty); |
| _clearLogs(state); |
| |
| state.setProperties(() { |
| state.property.value = 20; |
| }); |
| await tester.pump(); |
| expect(state.property.value, 20); |
| expect(state.property.log, <String>['toPrimitives']); |
| expect(state.restoreStateLog, isEmpty); |
| expect(state.toggleBucketLog, isEmpty); |
| _clearLogs(state); |
| |
| final _TestRestorableWidgetState oldState = state; |
| await tester.restartAndRestore(); |
| state = tester.state(find.byType(_TestRestorableWidget)); |
| |
| expect(state, isNot(same(oldState))); |
| expect(state.property.value, 20); |
| expect(state.property.log, <String>['fromPrimitives', 'initWithValue']); |
| expect(state.restoreStateLog.single, isNull); |
| expect(state.toggleBucketLog, isEmpty); |
| }); |
| |
| testWidgets('restore while running', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const RootRestorationScope( |
| restorationId: 'root-child', |
| child: _TestRestorableWidget( |
| restorationId: 'widget', |
| ), |
| ), |
| ); |
| |
| _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| |
| state.setProperties(() { |
| state.property.value = 20; |
| }); |
| await tester.pump(); |
| expect(state.property.value, 20); |
| |
| final TestRestorationData data = await tester.getRestorationData(); |
| |
| state.setProperties(() { |
| state.property.value = 30; |
| }); |
| await tester.pump(); |
| expect(state.property.value, 30); |
| _clearLogs(state); |
| |
| final _TestRestorableWidgetState oldState = state; |
| final RestorationBucket oldBucket = oldState.bucket!; |
| await tester.restoreFrom(data); |
| state = tester.state(find.byType(_TestRestorableWidget)); |
| |
| expect(state, same(oldState)); |
| expect(state.property.value, 20); |
| expect(state.property.log, <String>['fromPrimitives', 'initWithValue']); |
| expect(state.restoreStateLog.single, oldBucket); |
| expect(state.toggleBucketLog, isEmpty); |
| }); |
| |
| testWidgets('can register additional property outside of restoreState', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const RootRestorationScope( |
| restorationId: 'root-child', |
| child: _TestRestorableWidget( |
| restorationId: 'widget', |
| ), |
| ), |
| ); |
| |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| state.registerAdditionalProperty(); |
| expect(state.additionalProperty!.value, 11); |
| expect(state.additionalProperty!.log, <String>['createDefaultValue', 'initWithValue', 'toPrimitives']); |
| |
| state.setProperties(() { |
| state.additionalProperty!.value = 33; |
| }); |
| await tester.pump(); |
| expect(state.additionalProperty!.value, 33); |
| |
| final TestRestorationData data = await tester.getRestorationData(); |
| |
| state.setProperties(() { |
| state.additionalProperty!.value = 44; |
| }); |
| await tester.pump(); |
| expect(state.additionalProperty!.value, 44); |
| _clearLogs(state); |
| |
| await tester.restoreFrom(data); |
| |
| expect(state, same(tester.state(find.byType(_TestRestorableWidget)))); |
| expect(state.additionalProperty!.value, 33); |
| expect(state.property.log, <String>['fromPrimitives', 'initWithValue']); |
| }); |
| |
| testWidgets('cannot register same property twice', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const RootRestorationScope( |
| restorationId: 'root-child', |
| child: _TestRestorableWidget( |
| restorationId: 'widget', |
| ), |
| ), |
| ); |
| |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| state.registerAdditionalProperty(); |
| await tester.pump(); |
| expect(() => state.registerAdditionalProperty(), throwsAssertionError); |
| }); |
| |
| testWidgets('cannot register under ID that is already in use', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const RootRestorationScope( |
| restorationId: 'root-child', |
| child: _TestRestorableWidget( |
| restorationId: 'widget', |
| ), |
| ), |
| ); |
| |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(() => state.registerPropertyUnderSameId(), throwsAssertionError); |
| }); |
| |
| testWidgets('data of disabled property is not stored', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const RootRestorationScope( |
| restorationId: 'root-child', |
| child: _TestRestorableWidget( |
| restorationId: 'widget', |
| ), |
| ), |
| ); |
| _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| |
| state.setProperties(() { |
| state.property.value = 30; |
| }); |
| await tester.pump(); |
| expect(state.property.value, 30); |
| expect(state.bucket!.read<int>('foo'), 30); |
| _clearLogs(state); |
| |
| state.setProperties(() { |
| state.property.enabled = false; |
| }); |
| await tester.pump(); |
| expect(state.property.value, 30); |
| expect(state.bucket!.contains('foo'), isFalse); |
| expect(state.property.log, isEmpty); |
| |
| state.setProperties(() { |
| state.property.value = 40; |
| }); |
| await tester.pump(); |
| expect(state.bucket!.contains('foo'), isFalse); |
| expect(state.property.log, isEmpty); |
| |
| await tester.restartAndRestore(); |
| state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(state.property.log, <String>['createDefaultValue', 'initWithValue', 'toPrimitives']); |
| expect(state.property.value, 10); // Initialized to default value. |
| }); |
| |
| testWidgets('Enabling property stores its data again', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const RootRestorationScope( |
| restorationId: 'root-child', |
| child: _TestRestorableWidget( |
| restorationId: 'widget', |
| ), |
| ), |
| ); |
| _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| _clearLogs(state); |
| |
| state.setProperties(() { |
| state.property.enabled = false; |
| }); |
| await tester.pump(); |
| expect(state.bucket!.contains('foo'), isFalse); |
| state.setProperties(() { |
| state.property.value = 40; |
| }); |
| await tester.pump(); |
| expect(state.property.value, 40); |
| expect(state.bucket!.contains('foo'), isFalse); |
| expect(state.property.log, isEmpty); |
| |
| state.setProperties(() { |
| state.property.enabled = true; |
| }); |
| await tester.pump(); |
| expect(state.bucket!.read<int>('foo'), 40); |
| expect(state.property.log, <String>['toPrimitives']); |
| |
| await tester.restartAndRestore(); |
| state = tester.state(find.byType(_TestRestorableWidget)); |
| expect(state.property.log, <String>['fromPrimitives', 'initWithValue']); |
| expect(state.property.value, 40); |
| }); |
| |
| testWidgets('Unregistering a property removes its data', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const RootRestorationScope( |
| restorationId: 'root-child', |
| child: _TestRestorableWidget( |
| restorationId: 'widget', |
| ), |
| ), |
| ); |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| state.registerAdditionalProperty(); |
| await tester.pump(); |
| expect(state.additionalProperty!.value, 11); |
| expect(state.bucket!.read<int>('additional'), 11); |
| state.unregisterAdditionalProperty(); |
| await tester.pump(); |
| expect(state.bucket!.contains('additional'), isFalse); |
| expect(() => state.additionalProperty!.value, throwsAssertionError); // No longer registered. |
| |
| // Can register the same property again. |
| state.registerAdditionalProperty(); |
| await tester.pump(); |
| expect(state.additionalProperty!.value, 11); |
| expect(state.bucket!.read<int>('additional'), 11); |
| }); |
| |
| testWidgets('Disposing a property unregisters it, but keeps data', (WidgetTester tester) async { |
| await tester.pumpWidget( |
| const RootRestorationScope( |
| restorationId: 'root-child', |
| child: _TestRestorableWidget( |
| restorationId: 'widget', |
| ), |
| ), |
| ); |
| final _TestRestorableWidgetState state = tester.state(find.byType(_TestRestorableWidget)); |
| state.registerAdditionalProperty(); |
| await tester.pump(); |
| expect(state.additionalProperty!.value, 11); |
| expect(state.bucket!.read<int>('additional'), 11); |
| |
| state.additionalProperty!.dispose(); |
| await tester.pump(); |
| expect(state.bucket!.read<int>('additional'), 11); |
| |
| // Can register property under same id again. |
| state.additionalProperty = _TestRestorableProperty(22); |
| state.registerAdditionalProperty(); |
| await tester.pump(); |
| |
| expect(state.additionalProperty!.value, 11); // Old value restored. |
| expect(state.bucket!.read<int>('additional'), 11); |
| }); |
| |
| test('RestorableProperty throws after disposed', () { |
| final RestorableProperty<Object?> property = _TestRestorableProperty(10); |
| property.dispose(); |
| expect(() => property.dispose(), throwsFlutterError); |
| }); |
| } |
| |
| void _clearLogs(_TestRestorableWidgetState state) { |
| state.property.log.clear(); |
| state.additionalProperty?.log.clear(); |
| state.restoreStateLog.clear(); |
| state.toggleBucketLog.clear(); |
| } |
| |
| class _TestRestorableWidget extends StatefulWidget { |
| |
| const _TestRestorableWidget({super.key, this.restorationId}); |
| |
| final String? restorationId; |
| |
| @override |
| State<_TestRestorableWidget> createState() => _TestRestorableWidgetState(); |
| } |
| |
| class _TestRestorableWidgetState extends State<_TestRestorableWidget> with RestorationMixin { |
| final _TestRestorableProperty property = _TestRestorableProperty(10); |
| _TestRestorableProperty? additionalProperty; |
| bool _reregisterAdditionalProperty = false; |
| |
| final List<RestorationBucket?> restoreStateLog = <RestorationBucket?>[]; |
| final List<RestorationBucket?> toggleBucketLog = <RestorationBucket?>[]; |
| |
| @override |
| void restoreState(RestorationBucket? oldBucket, bool initialRestore) { |
| restoreStateLog.add(oldBucket); |
| registerForRestoration(property, 'foo'); |
| if (_reregisterAdditionalProperty && additionalProperty != null) { |
| registerForRestoration(additionalProperty!, 'additional'); |
| } |
| } |
| |
| @override |
| void didToggleBucket(RestorationBucket? oldBucket) { |
| toggleBucketLog.add(oldBucket); |
| super.didToggleBucket(oldBucket); |
| } |
| |
| @override |
| void dispose() { |
| super.dispose(); |
| property.dispose(); |
| additionalProperty?.dispose(); |
| } |
| |
| @override |
| Widget build(BuildContext context) { |
| return Container(); |
| } |
| |
| void setProperties(VoidCallback fn) => setState(fn); |
| |
| String? _injectedId; |
| void injectId(String id) { |
| _injectedId = id; |
| didUpdateRestorationId(); |
| } |
| |
| void registerAdditionalProperty({bool reregister = true}) { |
| additionalProperty ??= _TestRestorableProperty(11); |
| registerForRestoration(additionalProperty!, 'additional'); |
| _reregisterAdditionalProperty = reregister; |
| } |
| |
| void unregisterAdditionalProperty() { |
| unregisterFromRestoration(additionalProperty!); |
| } |
| |
| void registerPropertyUnderSameId() { |
| registerForRestoration(_TestRestorableProperty(11), 'foo'); |
| } |
| |
| @override |
| String? get restorationId => _injectedId ?? widget.restorationId; |
| } |
| |
| Map<String, dynamic> _createRawDataSet() { |
| return <String, dynamic>{ |
| valuesMapKey: <String, dynamic>{ |
| 'value1' : 10, |
| 'value2' : 'Hello', |
| }, |
| childrenMapKey: <String, dynamic>{ |
| 'child1' : <String, dynamic>{ |
| valuesMapKey : <String, dynamic>{ |
| 'foo': 22, |
| }, |
| }, |
| 'child2' : <String, dynamic>{ |
| valuesMapKey : <String, dynamic>{ |
| 'bar': 33, |
| }, |
| }, |
| }, |
| }; |
| } |
| |
| class _TestRestorableProperty extends RestorableProperty<Object?> { |
| _TestRestorableProperty(this._value); |
| |
| List<String> log = <String>[]; |
| |
| @override |
| bool get enabled => _enabled; |
| bool _enabled = true; |
| set enabled(bool value) { |
| _enabled = value; |
| notifyListeners(); |
| } |
| |
| @override |
| Object? createDefaultValue() { |
| log.add('createDefaultValue'); |
| return _value; |
| } |
| |
| @override |
| Object? fromPrimitives(Object? data) { |
| log.add('fromPrimitives'); |
| return data; |
| } |
| |
| Object? get value { |
| assert(isRegistered); |
| return _value; |
| } |
| Object? _value; |
| set value(Object? value) { |
| _value = value; |
| notifyListeners(); |
| } |
| |
| @override |
| void initWithValue(Object? v) { |
| log.add('initWithValue'); |
| _value = v; |
| } |
| |
| @override |
| Object? toPrimitives() { |
| log.add('toPrimitives'); |
| return _value; |
| } |
| } |