Some checks failed
Security / Security check (push) Failing after 2s
A black window on launch, no error anywhere: main() awaited loadPersistedEndpoint before the first frame, and SharedPreferences.getBool threw 'int is not a subtype of bool?' — the store is writable from outside the app and hub.secure had been written as int 0. Pref reads now go through defensive typed helpers (int coerces to bool, wrong types fall back to defaults), and every pre-frame restore step is failure-isolated: a broken store can cost a preference, never the first frame. Regression tests stage the corrupt store (the exact observed value and worse). Also removes the CocoaPods leftovers from the macOS project (Podfile, [CP] script phases, Pods framework references, xcconfig includes): the project builds via Swift Package Manager, and the dual wiring ran both dependency managers on every build — Flutter's persistent 'removing CocoaPods will improve build time' warning. Verified: clean profile build produces a launchable bundle (plugins statically linked via SwiftPM), suite green, analyze clean. Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
50 lines
2 KiB
Dart
50 lines
2 KiB
Dart
// Startup must survive a corrupt preference store. The store is
|
|
// writable from outside the app (`defaults write` stores an int
|
|
// where a bool belongs); shared_preferences then THROWS on the
|
|
// typed getter, and before the hardening that exception escaped
|
|
// from main() before the first frame — a black window with no
|
|
// visible error (observed live on 2026-07-15: `hub.secure = 0`).
|
|
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'package:chain_studio/data/hub.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
test('loadPersistedEndpoint tolerates an int where a bool belongs', () async {
|
|
SharedPreferences.setMockInitialValues({
|
|
'hub.host': '127.0.0.1',
|
|
'hub.port': 50051,
|
|
'hub.secure': 0, // the corrupt value that killed startup
|
|
});
|
|
// Must not throw; the int coerces to false.
|
|
await HubService.instance.loadPersistedEndpoint();
|
|
expect(HubService.instance.currentEndpoint.host, '127.0.0.1');
|
|
expect(HubService.instance.currentEndpoint.port, 50051);
|
|
expect(HubService.instance.currentEndpoint.secure, false);
|
|
});
|
|
|
|
test('loadPersistedEndpoint tolerates wholesale wrong types', () async {
|
|
SharedPreferences.setMockInitialValues({
|
|
'hub.host': 12345, // wrong type → treated as absent
|
|
'hub.port': 'not-a-port', // wrong type → treated as absent
|
|
'hub.secure': 'yes', // wrong type → treated as absent
|
|
});
|
|
await HubService.instance.loadPersistedEndpoint();
|
|
// No explicit endpoint restored → discovery/default path; the
|
|
// call simply must not throw.
|
|
});
|
|
|
|
test('theme + locale loaders tolerate wrong types', () async {
|
|
SharedPreferences.setMockInitialValues({
|
|
'theme.mode': 42,
|
|
'locale.code': true,
|
|
});
|
|
final mode = await HubService.instance.loadThemeMode();
|
|
final locale = await HubService.instance.loadLocale();
|
|
expect(mode, ThemeModeValue.system);
|
|
expect(locale.languageCode, 'en');
|
|
});
|
|
}
|