import 'package:drift/drift.dart' hide isNotNull, isNull; import 'package:drift_offline_sync/drift_offline_sync.dart'; import 'package:test/test.dart'; import '../utils/crdt_context.dart'; import '../utils/database.dart'; import '../utils/tables.dart'; void main() { group('Given a data object with every column type', () { late CrdtDatabase crdtDb; late TableWithEveryColumnTypeData createdData; late Hlc testHlc; setUp(() async { createdData = _createTestData(); (_, crdtDb, _) = database.crdtContext; testHlc = Hlc.now(crdtDb.nodeId); }); group('when converting the data to CRDT data entries', () { late Iterable entries; setUp(() async { entries = crdtDb.convertToCrdtDataEntry(createdData, testHlc); }); test('then it creates an entry for each column.', () async { expect( entries.map((e) => e.columnName).toSet(), equals( database.tableWithEveryColumnType.$columns.map((c) => c.$name).toSet(), ), ); }); test('then each entry has the correct user ID.', () async { expect(entries.map((e) => e.userId), everyElement(equals(crdtDb.userId))); }); test('then each entry has the correct table name.', () async { expect( entries.map((e) => e.tblName), everyElement(equals('table_with_every_column_type')), ); }); test('then each entry has the correct HLC timestamp.', () async { expect(entries.map((e) => e.hlcTimestamp), everyElement(equals(testHlc))); }); test('then all entries have expected column names and values.', () async { final mappedData = await database.tableWithEveryColumnType.fromCrdtDataEntries( entries, ); expect(mappedData.single, equals(createdData)); }); }); }); group('Given a changeset converted from a data object with every column type', () { late OfflineSyncCrdt crdt; late CrdtDatabase crdtDb; late TableWithEveryColumnTypeData createdData; late List expectedChangeset; late Hlc testHlc; setUp(() async { createdData = _createTestData(); (crdt, crdtDb, _) = database.crdtContext; // Perform an insert to the database to get the exact changeset that would // be generated by the CRDT triggers. await database.tableWithEveryColumnType.insertOne(createdData); expectedChangeset = await crdtDb.managers.crdtDataTable .filter( (f) => f.columnName.equals(crdtDb.sqlBuilder.isDeletedColumnName).not(), ) .get(); testHlc = expectedChangeset.first.hlcTimestamp; await crdtDb.crdtDataTable.deleteAll(); }); group('when saving the changeset to the CRDT database', () { late Iterable entries; setUp(() async { entries = crdtDb.convertToCrdtDataEntry(createdData, testHlc); await crdt.saveChangeset(entries, [testHlc]); }); test('then the saved data is equal to the generated by CRDT triggers.', () async { final savedChangeset = await crdtDb.managers.crdtDataTable.get(); // The list object is not equal to the other objects because it is a // different instance. So we remove it from the list and compare the // it separately. final savedListObject = savedChangeset.removeAt(7); final expectedListObject = expectedChangeset.removeAt(7); expect(savedChangeset, equals(expectedChangeset)); expect( savedListObject.unwrappedValue, equals(expectedListObject.unwrappedValue), ); }); }); }); } TableWithEveryColumnTypeData _createTestData() => TableWithEveryColumnTypeData( id: const RowId(1), aBool: true, aDateTime: DateTime.now(), aText: 'test', anInt: 1, anInt64: BigInt.one, aReal: 1.0, aBlob: Uint8List.fromList([1, 2, 3]), anIntEnum: TodoStatus.open, aTextWithConverter: MyCustomObject('test'), aUuid: UuidValue.fromString('123e4567-e89b-12d3-a456-426614174000'), );