fix(flutter): preserve dev-version safety net + update version tests

Two test failures from the comparator rewrite:

1. "different unparseable strings → newer" was useful — branch-name
   builds (e.g. PackageInfo reports 'main' while server reports
   'dev') should still surface the banner so the operator sees that
   something is misaligned. Restore that fallback: if both sides
   parse to all-zero components (no numeric structure on either),
   compare as strings.

2. "honors prerelease ordering" tested pub_semver behavior we no
   longer use. Replaced with tests that cover what the new
   comparator actually does: zero-padding for length mismatch,
   leading-zero normalization, 4-part date+build comparisons, and
   month-rollover correctness without leading zeros.
This commit is contained in:
2026-05-11 10:48:06 -04:00
parent a65474284a
commit 74cc76b369
2 changed files with 34 additions and 8 deletions
@@ -71,6 +71,18 @@ bool isVersionNewer(String serverVersion, String installedVersion) {
final svr = parts(serverVersion);
final ins = parts(installedVersion);
// Safety net for non-numeric versions (e.g. branch-name builds like
// "main" vs "dev"): if neither side parsed any non-zero component,
// fall back to string inequality so an operator on a dev build
// still gets the banner instead of silently matching everything.
final svrAllZero = svr.every((c) => c == 0);
final insAllZero = ins.every((c) => c == 0);
if (svrAllZero && insAllZero) {
return serverVersion.replaceFirst(RegExp(r'^v'), '') !=
installedVersion.replaceFirst(RegExp(r'^v'), '');
}
final n = svr.length > ins.length ? svr.length : ins.length;
while (svr.length < n) {
svr.add(0);
@@ -24,17 +24,19 @@ void main() {
expect(isVersionNewer('v0.1.0', 'v0.1.0'), isFalse);
});
test('honors prerelease ordering', () {
// 0.1.0 > 0.1.0-rc.1 per semver
expect(isVersionNewer('0.1.0', '0.1.0-rc.1'), isTrue);
expect(isVersionNewer('0.1.0-rc.1', '0.1.0'), isFalse);
test('zero-pads shorter version when comparing', () {
// "1.2" treated as "1.2.0" — shorter side gets zero-padded so
// comparison is component-wise.
expect(isVersionNewer('1.2.1', '1.2'), isTrue);
expect(isVersionNewer('1.2', '1.2.1'), isFalse);
expect(isVersionNewer('1.2', '1.2.0'), isFalse);
});
});
group('isVersionNewer (date-style versions parse as semver)', () {
// pub_semver is permissive with leading zeros — '2026.05.10'
// parses as 2026.5.10. So date-style tags get strict ordering,
// not the unparseable-fallback path.
group('isVersionNewer (date-style versions)', () {
// Date tags are 3- or 4-part: 2026.05.10 or 2026.05.10.1. The
// numeric comparator parses each component as int (so "05" == 5)
// and zero-pads the shorter side.
test('newer date → newer', () {
expect(isVersionNewer('2026.05.10', '2026.05.09'), isTrue);
});
@@ -44,6 +46,18 @@ void main() {
test('equal date → not newer', () {
expect(isVersionNewer('2026.05.10', '2026.05.10'), isFalse);
});
test('leading zeros do not affect ordering', () {
// "2026.5.11" and "2026.05.11" parse to the same components.
// 12 > 5 numerically so month rollover stays correct.
expect(isVersionNewer('2026.5.11', '2026.05.11'), isFalse);
expect(isVersionNewer('2026.12.1', '2026.5.31'), isTrue);
});
test('4-part build suffix breaks the tie', () {
// 2026.05.10 vs 2026.05.10.1 — first three equal, server has a
// 4th component (1), client zero-pads → server is newer.
expect(isVersionNewer('2026.05.10.1', '2026.05.10'), isTrue);
expect(isVersionNewer('2026.05.10', '2026.05.10.0'), isFalse);
});
});
group('isVersionNewer (truly non-semver fallback)', () {