chore: Publish version 0.0.1 of the packages (#103)

This commit is contained in:
Marcelo Mendonça Soares 2026-07-10 13:16:43 -03:00 • committed by GitHub
commit a24faf39af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 112 additions and 156 deletions

View file

@ -0,0 +1,129 @@
import 'package:serverpod_offline_sync/serverpod_offline_sync.dart';
import 'package:test/test.dart';
import 'package:uuid/uuid.dart';
final _dateTime = DateTime.parse('2001-09-09T01:46:40.000Z');
final _nodeId = const Uuid().v4obj();
void main() {
group('Given two Hlcs with same dateTime, counter and nodeId when comparing ', () {
final hlc1 = Hlc(_dateTime, 17, _nodeId);
final hlc2 = Hlc(_dateTime, 17, _nodeId);
test('then they are equal.', () {
expect(hlc1, hlc2);
expect(hlc1 == hlc2, isTrue);
expect(hlc1, equals(hlc2));
});
test('then compareTo returns 0.', () {
expect(hlc1.compareTo(hlc2), 0);
});
test('then <= is true.', () {
expect(hlc1 <= hlc2, isTrue);
expect(hlc1, lessThanOrEqualTo(hlc2));
});
test('then >= is true.', () {
expect(hlc1 >= hlc2, isTrue);
expect(hlc1, greaterThanOrEqualTo(hlc2));
});
});
group(
'Given two Hlcs with same dateTime and counter and different nodeId when comparing ',
() {
final node2 = const Uuid().v4obj();
final hlc1 = Hlc(_dateTime, 17, _nodeId);
final hlc2 = Hlc(_dateTime, 17, node2);
test('then they are not equal.', () {
expect(hlc1, isNot(hlc2));
});
test('then compareTo follows lexicographic node uuid order.', () {
expect(
hlc1.compareTo(hlc2),
hlc1.nodeId.uuid.compareTo(hlc2.nodeId.uuid),
);
});
test('then one is greater or less by uuid order.', () {
if (_nodeId.uuid.compareTo(node2.uuid) > 0) {
expect(hlc1 > hlc2, isTrue);
} else {
expect(hlc1 < hlc2, isTrue);
}
});
},
);
group('Given two Hlcs with same dateTime and different counter when comparing ', () {
final hlc1 = Hlc(_dateTime, 17, _nodeId);
final hlc2 = Hlc(_dateTime, 18, _nodeId);
test('then they are not equal.', () {
expect(hlc1, isNot(hlc2));
});
test('then compareTo returns -1.', () {
expect(hlc1.compareTo(hlc2), -1);
});
test('then < is true.', () {
expect(hlc1 < hlc2, isTrue);
expect(hlc1, lessThan(hlc2));
});
test('then <= is true.', () {
expect(hlc1 <= hlc2, isTrue);
expect(hlc1, lessThanOrEqualTo(hlc2));
});
test('then > is false.', () {
expect(hlc1 > hlc2, isFalse);
});
test('then >= is false.', () {
expect(hlc1 >= hlc2, isFalse);
expect(hlc1, isNot(greaterThanOrEqualTo(hlc2)));
});
});
group(
'Given two Hlcs with different dateTime when comparing ',
() {
final hlc1 = Hlc(_dateTime, 0, _nodeId);
final hlc2 = Hlc(_dateTime.add(const Duration(milliseconds: 1)), 17, _nodeId);
test('then they are not equal.', () {
expect(hlc1, isNot(hlc2));
});
test('then compareTo returns -1.', () {
expect(hlc1.compareTo(hlc2), -1);
});
test('then < is true.', () {
expect(hlc1 < hlc2, isTrue);
expect(hlc1, lessThan(hlc2));
});
test('then <= is true.', () {
expect(hlc1 <= hlc2, isTrue);
expect(hlc1, lessThanOrEqualTo(hlc2));
});
test('then > is false.', () {
expect(hlc1 > hlc2, isFalse);
});
test('then >= is false.', () {
expect(hlc1 >= hlc2, isFalse);
expect(hlc1, isNot(greaterThanOrEqualTo(hlc2)));
});
},
);
}

View file

@ -0,0 +1,32 @@
import 'package:serverpod_offline_sync/serverpod_offline_sync.dart';
import 'package:test/test.dart';
import 'package:uuid/uuid.dart';
final _dateTime = DateTime.parse('2001-09-09T01:46:40.000Z');
final _nodeId = const Uuid().v4obj();
void main() {
group('Given an HLC', () {
final hlc = Hlc(_dateTime, 17, _nodeId);
test('when calling copyWith with new dateTime then result has new dateTime.', () {
final newDateTime = _dateTime.add(const Duration(minutes: 1));
final newHlc = hlc.copyWith(datetime: newDateTime);
expect(newHlc.datetime, newDateTime);
});
test('when calling copyWith with new counter then result has new counter.', () {
final newHlc = hlc.copyWith(counter: 18);
expect(newHlc.counter, 18);
});
test('when calling copyWith with new nodeId then result has new nodeId.', () {
final newNodeId = const Uuid().v4obj();
final newHlc = hlc.copyWith(nodeId: newNodeId);
expect(newHlc.nodeId, newNodeId);
});
});
}

View file

@ -0,0 +1,84 @@
import 'package:clock/clock.dart';
import 'package:serverpod_offline_sync/serverpod_offline_sync.dart';
import 'package:test/test.dart';
import 'package:uuid/uuid.dart';
final _dateTime = DateTime.parse('2001-09-09T01:46:40.000Z');
final _nodeId = const Uuid().v4obj();
void main() {
group('Given an HLC with lower canonical time than wall time', () {
final hlc = Hlc(_dateTime, 17, _nodeId);
final wallTime = _dateTime.advance();
test('when incrementing then dateTime becomes wall time and counter resets.', () {
withClock(Clock.fixed(wallTime), () {
final sendHlc = hlc.increment();
expect(sendHlc, isNot(hlc));
expect(sendHlc.datetime, wallTime);
expect(sendHlc.counter, 0);
expect(sendHlc.nodeId, hlc.nodeId);
});
});
});
group('Given an HLC with equal canonical time and wall time', () {
final hlc = Hlc(_dateTime, 17, _nodeId);
final wallTime = _dateTime;
test('when incrementing then counter increments and dateTime is unchanged.', () {
withClock(Clock.fixed(wallTime), () {
final sendHlc = hlc.increment();
expect(sendHlc, isNot(hlc));
expect(sendHlc.datetime, hlc.datetime);
expect(sendHlc.counter, 18);
expect(sendHlc.nodeId, hlc.nodeId);
});
});
});
group('Given an HLC with higher canonical time than wall time', () {
final hlc = Hlc(_dateTime, 17, _nodeId);
final wallTime = _dateTime.retreat();
test('when incrementing then counter increments and dateTime is unchanged.', () {
withClock(Clock.fixed(wallTime), () {
final sendHlc = hlc.increment();
expect(sendHlc, isNot(hlc));
expect(sendHlc.datetime, hlc.datetime);
expect(sendHlc.counter, 18);
expect(sendHlc.nodeId, hlc.nodeId);
});
});
});
group('Given an HLC with canonical time more than one minute ahead of wall time', () {
final hlc = Hlc(_dateTime.add(const Duration(minutes: 1, seconds: 5)), 0, _nodeId);
final wallTime = _dateTime;
test('when incrementing then ClockDriftException is thrown.', () {
withClock(Clock.fixed(wallTime), () {
expect(hlc.increment, throwsA(isA<ClockDriftException>()));
});
});
});
group('Given an HLC with counter at maximum and canonical time at wall time', () {
final hlc = Hlc(_dateTime, 0xFFFF, _nodeId);
final wallTime = _dateTime;
test('when incrementing at same time then OverflowException is thrown.', () {
withClock(Clock.fixed(wallTime), () {
expect(hlc.increment, throwsA(isA<OverflowException>()));
});
});
});
}
extension on DateTime {
DateTime advance() => add(const Duration(milliseconds: 1));
DateTime retreat() => subtract(const Duration(milliseconds: 1));
}

View file

@ -0,0 +1,113 @@
import 'package:clock/clock.dart';
import 'package:serverpod_offline_sync/serverpod_offline_sync.dart';
import 'package:test/test.dart';
import 'package:uuid/uuid.dart';
final _dateTime = DateTime.now().toUtc();
final _nodeId = const Uuid().v4obj();
final _nodeIdAfter = const Uuid().v4obj();
void main() {
group('Given local canonical Hlc and remote with higher time', () {
final canonical = Hlc(_dateTime, 17, _nodeId);
final remote = Hlc(_dateTime.advance(), 2, _nodeIdAfter);
test('when merging then result has remote time and counter with local nodeId.', () {
final hlc = canonical.merge(remote);
expect(hlc, Hlc(remote.datetime, remote.counter, canonical.nodeId));
});
});
group('Given local canonical Hlc and remote with same time but higher counter', () {
final canonical = Hlc(_dateTime, 17, _nodeId);
final remote = Hlc(_dateTime, 18, _nodeIdAfter);
test('when merging then result has remote counter with local nodeId.', () {
final hlc = canonical.merge(remote);
expect(hlc, Hlc(canonical.datetime, remote.counter, canonical.nodeId));
});
});
group('Given local canonical Hlc and remote with same time and counter', () {
final canonical = Hlc(_dateTime, 17, _nodeId);
final remote = Hlc(_dateTime, 17, _nodeIdAfter);
test('when merging then local is returned.', () {
final hlc = canonical.merge(remote);
expect(hlc, equals(canonical));
});
});
group('Given local canonical Hlc and remote with lower time', () {
final canonical = Hlc(_dateTime, 17, _nodeId);
final remote = Hlc(_dateTime.retreat(), 17, _nodeIdAfter);
test('when merging then local is returned.', () {
final hlc = canonical.merge(remote);
expect(hlc, equals(canonical));
});
});
group('Given local canonical Hlc and remote with same nodeId and same time', () {
final canonical = Hlc(_dateTime, 17, _nodeId);
final remote = Hlc(_dateTime, 17, _nodeId);
test('when merging then node id is not checked and local is returned.', () {
expect(canonical.merge(remote), canonical);
});
});
group('Given local canonical Hlc and remote with same nodeId and lower time', () {
final canonical = Hlc(_dateTime, 17, _nodeId);
final remote = Hlc(_dateTime.retreat(), 17, _nodeId);
test('when merging then node id is not checked and local is returned.', () {
expect(canonical.merge(remote), canonical);
});
});
group('Given local canonical Hlc and remote with same nodeId and higher time', () {
final canonical = Hlc(_dateTime, 17, _nodeId);
final remote = Hlc(_dateTime.advance(), 0, _nodeId);
test('when merging then DuplicateNodeException is thrown.', () {
expect(
() => canonical.merge(remote),
throwsA(isA<DuplicateNodeException>()),
);
});
});
group(
'Given local canonical Hlc and remote with time more than one minute ahead of wall',
() {
final canonical = Hlc(_dateTime, 17, _nodeId);
final remote = Hlc(
_dateTime.advance(const Duration(minutes: 2)),
17,
_nodeIdAfter,
);
test('when merging then ClockDriftException is thrown.', () {
withClock(Clock.fixed(_dateTime.advance()), () {
expect(
() => canonical.merge(remote),
throwsA(isA<ClockDriftException>()),
);
});
});
},
);
}
extension on DateTime {
DateTime advance([Duration duration = const Duration(milliseconds: 1)]) =>
add(duration);
DateTime retreat([Duration duration = const Duration(milliseconds: 1)]) =>
subtract(duration);
}

View file

@ -0,0 +1,74 @@
import 'package:serverpod_offline_sync/serverpod_offline_sync.dart';
import 'package:test/test.dart';
import 'package:uuid/uuid.dart';
const _isoTime = '2001-09-09T01:46:40.000Z';
final _dateTime = DateTime.parse(_isoTime);
final _nodeId = const Uuid().v4obj();
void main() {
test('Given an HLC built with dateTime, counter and nodeId '
'when reading properties '
'then dateTime, counter and nodeId match.', () {
final hlc = Hlc(_dateTime, 0x17, _nodeId);
expect(hlc.datetime, _dateTime);
expect(hlc.counter, 0x17);
expect(hlc.nodeId, _nodeId);
});
test('Given Hlc.zero '
'when building for a nodeId '
'then it equals epoch with zero counter.', () {
final zero = Hlc.zero(_nodeId);
expect(zero.unixTimestamp, 0);
expect(zero.counter, 0);
expect(zero.nodeId, _nodeId);
});
test('Given an ISO HLC string '
'when parsing '
'then it returns the equivalent Hlc.', () {
final hlc = Hlc(_dateTime, 0x17, _nodeId);
expect(Hlc.parse('${_dateTime.toIso8601String()}-0017-$_nodeId'), hlc);
});
test('Given a Unix timestamp HLC string '
'when parsing '
'then it returns the equivalent Hlc.', () {
final hlc = Hlc(_dateTime, 0x17, _nodeId);
expect(Hlc.parse('${_dateTime.millisecondsSinceEpoch}-0017-$_nodeId'), hlc);
});
test('Given legacy string with :worker suffix '
'when parsing '
'then node id is the uuid only.', () {
final hlc = Hlc.parse('$_isoTime-0017-$_nodeId:7');
expect(hlc.nodeId, _nodeId);
expect(hlc.counter, 0x17);
expect(hlc.datetime, _dateTime);
});
test('Given a parsed Hlc '
'when calling toString '
'then it returns the ISO HLC string.', () {
final hlc = Hlc.parse('$_isoTime-0017-$_nodeId');
expect(hlc.toString(), '$_isoTime-0017-$_nodeId');
});
test('Given an HLC '
'when converting to JSON '
'then it returns the equivalent string.', () {
final hlc = Hlc(_dateTime, 0x17, _nodeId);
expect(hlc.toJson(), {
'datetime': _dateTime.toIso8601String(),
'counter': '0017',
'node': _nodeId.toString(),
});
});
}