the-mews/app/test/browser_controller_test.dart

104 lines
3.6 KiB
Dart
Raw Normal View History

import 'dart:io';
import 'package:drift/native.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mews/application/controllers/browser_controller.dart';
import 'package:mews/application/key_store.dart';
import 'package:mews/database/database.dart';
import 'package:mews/protocols/tofu.dart';
import 'fake_fetch.dart';
void main() {
late MewsDatabase db;
late Directory keyDir;
late KeyStore keys;
setUp(() async {
db = MewsDatabase.test(NativeDatabase.memory());
keyDir = await Directory.systemTemp.createTemp('mews-keys');
keys = KeyStore(() async => keyDir);
});
tearDown(() async {
await db.close();
keyDir.deleteSync(recursive: true);
});
BrowserController browser(FakeFetch fetch) =>
BrowserController(db: db, fetch: fetch, keys: keys);
test('a bare hostname that answers on gemini is found there', () async {
final controller =
browser(FakeFetch({'gemini://capsule.example': '# Hello\n\nText.'}));
await controller.open('capsule.example');
expect(controller.error.value, isNull);
expect(controller.currentPage.value!.url, 'gemini://capsule.example');
expect(controller.currentPage.value!.title, 'Hello');
});
test('a bare hostname that answers on spartan is found there', () async {
final controller =
browser(FakeFetch({'spartan://capsule.example': '# Hello\n\nText.'}));
await controller.open('capsule.example');
expect(controller.error.value, isNull);
expect(controller.currentPage.value!.url, 'spartan://capsule.example');
});
test('an explicit scheme is not second-guessed', () async {
final controller =
browser(FakeFetch({'gemini://capsule.example': '# Hello\n\nText.'}));
// The reader named the web, so a missing web page is an error, not an
// invitation to try the capsule protocols.
await controller.open('https://capsule.example');
expect(controller.error.value, isA<LoadFailed>());
expect(controller.currentPage.value, isNull);
});
test('a changed certificate blocks until the reader trusts the new one', () async {
final presented = TofuPin(fingerprint: 'new', expires: DateTime(2036));
final controller = browser(FakeFetch(
{'gemini://capsule.example': '# Hello\n\nText.'},
changedCertificates: {'gemini://capsule.example': presented},
));
await controller.open('gemini://capsule.example');
expect(controller.error.value, isA<CertificateChanged>());
// Trusting records the presented certificate as the host's new pin.
await controller.trustPresentedCertificate();
expect(await db.allPins(), {'capsule.example:1965': presented});
});
test('a certificate request is answered by binding an identity', () async {
final controller = browser(FakeFetch(
{'gemini://capsule.example': '# Hello\n\nText.'},
certificateRequired: {'gemini://capsule.example'},
));
final id = await db.addClientCertificate('Reader', 'CERT PEM');
await keys.save(id, 'KEY PEM');
// The site asks before anything shows; the reader's answer is a choice,
// not an automatic presentation.
await controller.open('gemini://capsule.example');
expect(controller.error.value, isA<ClientCertificateRequired>());
await controller.chooseCertificate(id);
expect(await db.bindingFor('capsule.example', 1965), id);
expect(controller.error.value, isNull);
expect(controller.currentPage.value!.title, 'Hello');
// The binding is worn on the next visit too, without asking again.
await controller.open('gemini://capsule.example');
expect(controller.error.value, isNull);
expect(controller.currentPage.value!.title, 'Hello');
});
}