mirror of
https://github.com/kuhyx/diet-guard.git
synced 2026-11-11 18:13:55 +01:00
Final batch of the 250-line sweep. `check_file_length.sh --all` exits 0: every file in the repo is at or under 250 lines. github_mirror_screen.dart 391 -> 205 (+ actions, client_id_dialog parts) foodbank_service.dart 314 -> 209 (+ foodbank_service_manual part) settings_screen.dart 286 -> 237 (+ settings_kcal_goal part) firebase_backend.dart 282 -> 100 (+ firebase_client.dart) Three of the four are `part` files rather than separate libraries, and that is forced rather than stylistic: the moved code drives private state (`_busy`, `_status`, the text controllers) and calls private helpers (`_readBank`, `_normalize`), none of which are visible across a library boundary in Dart. Widening them to public just to split a file would leak internals the rest of the app has no business calling. Within those parts, mixins rather than extensions, for a concrete reason: an extension is not a subclass of `State`, so calling `setState` from one is an `invalid_use_of_protected_member`. Fields the State must own (the controllers it creates and disposes) stay declared there and are reached through abstract getters. `firebase_client.dart` is a real library split -- opening an authenticated client has no private coupling to the keystore-backed account record, only to its public API. The one exception, dropping the account marker without setting the opt-out flag, became `forgetAccountMarker()` rather than exposing the secure store. Verified: flutter test 555 (unchanged), flutter analyze clean, 707 Python tests / 100% branch coverage, check_patch_targets 0, pre-commit clean, check_file_length.sh --all exit 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RA9ynjqXPnexRQnR5oAuCC
90 lines
2.7 KiB
Dart
90 lines
2.7 KiB
Dart
/// Tests for the revision cache and the backend choice.
|
|
///
|
|
/// The cache is what keeps a sync tick from re-downloading every peer's whole
|
|
/// food log when nothing changed, so "does it survive a restart" and "does a
|
|
/// dead platform channel take sync down with it" are the behaviours worth
|
|
/// pinning.
|
|
@TestOn('vm')
|
|
library;
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:crdt_sync/crdt_sync.dart';
|
|
import 'package:diet_guard_app/services/firebase_client.dart';
|
|
import 'package:diet_guard_app/services/sync_state_factory_io.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
/// A do-nothing [RemoteStore], standing in for the GitHub client.
|
|
class _StubRemote implements RemoteStore {
|
|
@override
|
|
Future<List<String>> listDirectory(String path) async => [];
|
|
|
|
@override
|
|
Future<String?> getFileText(String path) async => null;
|
|
|
|
@override
|
|
Future<void> putFileText(
|
|
String path,
|
|
String text, {
|
|
required String message,
|
|
}) async {}
|
|
|
|
@override
|
|
Future<void> deleteFile(String path, {String message = ''}) async {}
|
|
|
|
@override
|
|
Future<bool> canAccessRemote() async => true;
|
|
|
|
@override
|
|
void close() {}
|
|
}
|
|
|
|
void main() {
|
|
late Directory dir;
|
|
|
|
setUp(() async {
|
|
dir = await Directory.systemTemp.createTemp('dg_state_');
|
|
});
|
|
|
|
tearDown(() async {
|
|
if (dir.existsSync()) await dir.delete(recursive: true);
|
|
});
|
|
|
|
test('persists revisions across a restart', () async {
|
|
// A fresh store instance stands in for the next app launch: an in-memory
|
|
// cache would forget every peer and re-download all of them.
|
|
await openSyncStateStoreIn(dir.path).save(
|
|
const SyncState(pushedRev: 'mine', peerRevs: {'pc': 'theirs'}),
|
|
);
|
|
|
|
final reloaded = await openSyncStateStoreIn(dir.path).load();
|
|
|
|
expect(reloaded.pushedRev, 'mine');
|
|
expect(reloaded.peerRevs, {'pc': 'theirs'});
|
|
});
|
|
|
|
test('writes beside the log it describes', () async {
|
|
await openSyncStateStoreIn(dir.path).save(const SyncState(pushedRev: 'x'));
|
|
|
|
expect(File(p.join(dir.path, kSyncStateFileName)).existsSync(), isTrue);
|
|
});
|
|
|
|
test('degrades to memory when the platform channel is unavailable', () async {
|
|
// No binding under `flutter test`. Losing the cache costs one tick of
|
|
// extra traffic; failing would take sync down entirely.
|
|
final store = await openSyncStateStore();
|
|
|
|
expect(store, isA<SyncStateStore>());
|
|
expect((await store.load()).pushedRev, isNull);
|
|
});
|
|
|
|
test('stays on GitHub when Firebase is not set up', () async {
|
|
// The pre-migration path, and the rollback. Reaching the keystore without
|
|
// a binding must read as "not configured", not as an error.
|
|
final github = _StubRemote();
|
|
|
|
expect(await syncBackend(github), same(github));
|
|
});
|
|
}
|