Browse Source
			
			
			
			
				
		- Only mark objects as clean if they have not been modified since we started saving.pull/5/head
				 9 changed files with 148 additions and 33 deletions
			
			
		@ -0,0 +1,28 @@ | 
				
			|||||||
 | 
					import 'package:clock/clock.dart'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Simple class to assign a unique integer for any point in time. | 
				
			||||||
 | 
					/// This is basically to ensure that even if two events happen at the | 
				
			||||||
 | 
					/// same millisecond we know which came first. | 
				
			||||||
 | 
					/// (realistically this will only make a difference in tests). | 
				
			||||||
 | 
					class TimeSequence { | 
				
			||||||
 | 
					  TimeSequence._(this._sequenceIndex); | 
				
			||||||
 | 
					  factory TimeSequence.now() => TimeSequence._(_sequenceCounter++); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static int _sequenceCounter = 0; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  final int _sequenceIndex; | 
				
			||||||
 | 
					  final DateTime _date = clock.now(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool isAfter(TimeSequence other) { | 
				
			||||||
 | 
					    return _sequenceIndex > other._sequenceIndex; | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool isBefore(TimeSequence other) { | 
				
			||||||
 | 
					    return _sequenceIndex < other._sequenceIndex; | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override | 
				
			||||||
 | 
					  String toString() { | 
				
			||||||
 | 
					    return '{Sequence: $_sequenceIndex time: $_date}'; | 
				
			||||||
 | 
					  } | 
				
			||||||
 | 
					} | 
				
			||||||
@ -0,0 +1,58 @@ | 
				
			|||||||
 | 
					import 'package:kdbx/kdbx.dart'; | 
				
			||||||
 | 
					import 'package:test/test.dart'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'internal/test_utils.dart'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main() { | 
				
			||||||
 | 
					  final testUtil = TestUtil(); | 
				
			||||||
 | 
					  group('test save with dirty objects', () { | 
				
			||||||
 | 
					    test('modify object after save', () async { | 
				
			||||||
 | 
					      final file = testUtil.createEmptyFile(); | 
				
			||||||
 | 
					      final group = file.body.rootGroup; | 
				
			||||||
 | 
					      final entry = testUtil.createEntry(file, group, 'user', 'pass'); | 
				
			||||||
 | 
					      final entry2 = testUtil.createEntry(file, group, 'user', 'pass'); | 
				
			||||||
 | 
					      await file.save(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const value1 = 'new'; | 
				
			||||||
 | 
					      const value2 = 'new2'; | 
				
			||||||
 | 
					      entry.setString(TestUtil.keyTitle, PlainValue(value1)); | 
				
			||||||
 | 
					      entry2.setString(TestUtil.keyTitle, PlainValue(value1)); | 
				
			||||||
 | 
					      expect(file.isDirty, isTrue); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      await file.save((bytes) async { | 
				
			||||||
 | 
					        // must still be dirty as long as we are not finished saving. | 
				
			||||||
 | 
					        expect(file.isDirty, isTrue); | 
				
			||||||
 | 
					        expect(entry.isDirty, isTrue); | 
				
			||||||
 | 
					        expect(entry2.isDirty, isTrue); | 
				
			||||||
 | 
					        return 1; | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					      expect(file.isDirty, isFalse); | 
				
			||||||
 | 
					      expect(entry.isDirty, isFalse); | 
				
			||||||
 | 
					      expect(entry2.isDirty, isFalse); | 
				
			||||||
 | 
					    }); | 
				
			||||||
 | 
					    test('parallel modify', () async { | 
				
			||||||
 | 
					      final file = testUtil.createEmptyFile(); | 
				
			||||||
 | 
					      final group = file.body.rootGroup; | 
				
			||||||
 | 
					      final entry = testUtil.createEntry(file, group, 'user', 'pass'); | 
				
			||||||
 | 
					      final entry2 = testUtil.createEntry(file, group, 'user', 'pass'); | 
				
			||||||
 | 
					      await file.save(); | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      const value1 = 'new'; | 
				
			||||||
 | 
					      const value2 = 'new2'; | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      entry.setString(TestUtil.keyTitle, PlainValue(value2)); | 
				
			||||||
 | 
					      entry2.setString(TestUtil.keyTitle, PlainValue(value2)); | 
				
			||||||
 | 
					      await file.save((bytes) async { | 
				
			||||||
 | 
					        // must still be dirty as long as we are not finished saving. | 
				
			||||||
 | 
					        expect(file.isDirty, isTrue); | 
				
			||||||
 | 
					        expect(entry.isDirty, isTrue); | 
				
			||||||
 | 
					        expect(entry2.isDirty, isTrue); | 
				
			||||||
 | 
					        entry2.setString(TestUtil.keyTitle, PlainValue(value1)); | 
				
			||||||
 | 
					        return 1; | 
				
			||||||
 | 
					      }); | 
				
			||||||
 | 
					      expect(file.isDirty, isTrue); | 
				
			||||||
 | 
					      expect(entry.isDirty, isFalse); | 
				
			||||||
 | 
					      expect(entry2.isDirty, isTrue); | 
				
			||||||
 | 
					    }); | 
				
			||||||
 | 
					  }); | 
				
			||||||
 | 
					} | 
				
			||||||
					Loading…
					
					
				
		Reference in new issue