Browse Source
- Only mark objects as clean if they have not been modified since we started saving.pull/5/head
Herbert Poul
3 years ago
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