You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
5.0 KiB
137 lines
5.0 KiB
import 'package:clock/clock.dart'; |
|
import 'package:kdbx/kdbx.dart'; |
|
import 'package:kdbx/src/kdbx_xml.dart'; |
|
import 'package:kdbx/src/utils/print_utils.dart'; |
|
import 'package:logging/logging.dart'; |
|
import 'package:test/test.dart'; |
|
import 'package:xml/xml.dart'; |
|
|
|
import '../internal/test_utils.dart'; |
|
import '../kdbx_test.dart'; |
|
|
|
final _logger = Logger('kdbx_merge_test'); |
|
|
|
void main() { |
|
final testUtil = TestUtil(); |
|
var now = DateTime.fromMillisecondsSinceEpoch(0); |
|
|
|
final fakeClock = Clock(() => now); |
|
void proceedSeconds(int seconds) { |
|
now = now.add(Duration(seconds: seconds)); |
|
} |
|
|
|
setUp(() { |
|
now = DateTime.fromMillisecondsSinceEpoch(0); |
|
}); |
|
group('Simple merges', () { |
|
Future<KdbxFile> createSimpleFile() async { |
|
final file = testUtil.createEmptyFile(); |
|
_createEntry(file, file.body.rootGroup, 'test1', 'test1'); |
|
final subGroup = |
|
file.createGroup(parent: file.body.rootGroup, name: 'Sub Group'); |
|
_createEntry(file, subGroup, 'test2', 'test2'); |
|
proceedSeconds(10); |
|
return await testUtil.saveAndRead(file); |
|
} |
|
|
|
test('Noop merge', () async { |
|
final file = await createSimpleFile(); |
|
final file2 = await testUtil.saveAndRead(file); |
|
final merge = file.merge(file2); |
|
final set = Set<KdbxUuid>.from(merge.merged.keys); |
|
expect(set, hasLength(4)); |
|
expect(merge.changes, isEmpty); |
|
}); |
|
test('Username change', () async { |
|
await withClock(fakeClock, () async { |
|
final file = await createSimpleFile(); |
|
|
|
final fileMod = await testUtil.saveAndRead(file); |
|
|
|
fileMod.body.rootGroup.entries.first |
|
.setString(KdbxKeyCommon.USER_NAME, PlainValue('changed.')); |
|
_logger.info('mod date: ${fileMod.body.rootGroup.entries.first.times.lastModificationTime |
|
.get()}'); |
|
final file2 = await testUtil.saveAndRead(fileMod); |
|
|
|
_logger.info('\n\n\nstarting merge.\n'); |
|
final merge = file.merge(file2); |
|
expect(file.body.rootGroup.entries.first.history, hasLength(1)); |
|
final set = Set<KdbxUuid>.from(merge.merged.keys); |
|
expect(set, hasLength(4)); |
|
expect(merge.changes, hasLength(1)); |
|
}); |
|
}); |
|
test( |
|
'Change Group Name', |
|
() async => await withClock(fakeClock, () async { |
|
final file = await createSimpleFile(); |
|
|
|
final fileMod = await testUtil.saveAndRead(file); |
|
|
|
fileMod.body.rootGroup.groups.first.name.set('Sub Group New Name.'); |
|
final file2 = await testUtil.saveAndRead(fileMod); |
|
final merge = file.merge(file2); |
|
final set = Set<KdbxUuid>.from(merge.merged.keys); |
|
expect(set, hasLength(4)); |
|
expect(merge.changes, hasLength(1)); |
|
}), |
|
); |
|
test( |
|
'Move Entry to recycle bin', |
|
() async => await withClock(fakeClock, () async { |
|
final file = await createSimpleFile(); |
|
|
|
final fileMod = await testUtil.saveAndRead(file); |
|
|
|
expect(fileMod.recycleBin, isNull); |
|
fileMod.deleteEntry(fileMod.body.rootGroup.entries.first); |
|
expect(fileMod.recycleBin, isNotNull); |
|
final file2 = await testUtil.saveAndRead(fileMod); |
|
final merge = file.merge(file2); |
|
_logger.info('Merged file:\n' |
|
'${KdbxPrintUtils().catGroupToString(file.body.rootGroup)}'); |
|
final set = Set<KdbxUuid>.from(merge.merged.keys); |
|
expect(set, hasLength(5)); |
|
expect( |
|
Set<KdbxNode>.from(merge.changes.map<KdbxNode?>((e) => e.object)), |
|
hasLength(2)); |
|
}), |
|
); |
|
test( |
|
'permanently delete an entry', |
|
() async => await withClock(fakeClock, () async { |
|
final file = await createSimpleFile(); |
|
final objCount = file.body.rootGroup.getAllGroupsAndEntries().length; |
|
final fileMod = await testUtil.saveAndRead(file); |
|
final entryDelete = fileMod.body.rootGroup.entries.first; |
|
fileMod.deletePermanently(entryDelete); |
|
expect(fileMod.body.rootGroup.getAllGroupsAndEntries(), |
|
hasLength(objCount - 1)); |
|
|
|
final file2 = await testUtil.saveAndRead(fileMod); |
|
final merge = file.merge(file2); |
|
_logger.info('Merged file:\n' |
|
'${KdbxPrintUtils().catGroupToString(file.body.rootGroup)}'); |
|
expect(merge.deletedObjects, hasLength(1)); |
|
expect( |
|
file.body.rootGroup.getAllGroupsAndEntries().length, objCount - 1); |
|
final xml = file.body.generateXml(FakeProtectedSaltGenerator()); |
|
final deleted = xml.findAllElements(KdbxXml.NODE_DELETED_OBJECT); |
|
expect(deleted, hasLength(1)); |
|
expect( |
|
deleted.first.findAllElements(KdbxXml.NODE_UUID).map((e) => e.text), |
|
[entryDelete.uuid.uuid]); |
|
}), |
|
); |
|
}); |
|
} |
|
|
|
KdbxEntry _createEntry( |
|
KdbxFile file, KdbxGroup group, String username, String password) { |
|
final entry = KdbxEntry.create(file, group); |
|
group.addEntry(entry); |
|
entry.setString(KdbxKeyCommon.USER_NAME, PlainValue(username)); |
|
entry.setString(KdbxKeyCommon.PASSWORD, ProtectedValue.fromString(password)); |
|
return entry; |
|
}
|
|
|