kirakira/test/store_test.dart

94 lines
3.3 KiB
Dart
Raw Normal View History

// Store-level behavior against the real native store: master lifecycle, read
// marks, pins and the settings the app owns in Hive.
import "dart:io";
import "dart:math";
import "dart:typed_data";
import "package:flutter_test/flutter_test.dart";
import "package:hive_flutter/hive_flutter.dart";
import "package:smol_mail/smol/store.dart";
Uint8List randomBytes(int n) =>
Uint8List.fromList(List.generate(n, (_) => Random.secure().nextInt(256)));
Future<SmolStore> freshStore(String tag) => SmolStore.open(
dbPath: "${Directory.systemTemp.createTempSync("smol-store-$tag").path}/store.db",
stateBox: "$tag-state",
readBox: "$tag-read");
void main() {
setUpAll(() async {
TestWidgetsFlutterBinding.ensureInitialized();
final dir = await Directory.systemTemp.createTemp("smol-store-test");
Hive.init(dir.path);
});
test("master set, restore and rotations", () async {
final store = await freshStore("master");
expect(store.master(), isNull);
expect(store.identity(), isNull);
final master = randomBytes(32);
store.setMaster(master);
expect(store.master(), master);
// A fresh identity's public key is the native-derived one.
expect(store.identity()!.publicKey.length, 52);
expect(store.rotations(), 0);
final other = randomBytes(32);
store.restoreMaster(other, 3);
expect(store.master(), other);
// The account handle was rebuilt at the restored rotation index.
expect(store.identity()!.publicKey.length, 52);
});
test("leave-on-server is a setting, not protocol state", () async {
final store = await freshStore("leave");
expect(store.leaveOnServer(), isFalse);
await store.setLeaveOnServer(true);
expect(store.leaveOnServer(), isTrue);
await store.setLeaveOnServer(false);
expect(store.leaveOnServer(), isFalse);
});
test("read marks drive the unread counts", () async {
final store = await freshStore("read");
expect(store.unreadCount(), 0);
// Nothing is stored yet, so marking an id is harmless bookkeeping.
store.markRead("ab" * 32);
expect(store.isRead("ab" * 32), isTrue);
});
test("pins save, list and unpin", () async {
final store = await freshStore("pins");
expect(store.allPins(), isEmpty);
// A syntactically valid key: the system server's, a real 52-char form.
const key = "lm2gqd7e5q67xq3isc5hx6jfj2q7a7xvq4l7trctxipudujovmgq";
store.pinServer("example.org", key);
expect(store.serverPin("example.org"), key);
expect(store.allPins().length, 1);
await store.unpinServer("example.org");
expect(store.serverPin("example.org"), isNull);
});
test("wipe clears every secret and mark, overwriting the master", () async {
final store = await freshStore("wipe");
final master = randomBytes(32);
store.setMaster(master);
store.pinServer("example.org",
"lm2gqd7e5q67xq3isc5hx6jfj2q7a7xvq4l7trctxipudujovmgq");
store.markRead("cd" * 32);
await store.wipe();
// The bytes the store owned are overwritten, not just dereferenced —
// the caller's reference sees the zeros too.
expect(master.every((b) => b == 0), isTrue);
expect(store.master(), isNull);
expect(store.identity(), isNull);
expect(store.serverPin("example.org"), isNull);
expect(store.isRead("cd" * 32), isFalse);
});
}