the-mews/app/test/fonts_test.dart

98 lines
3.8 KiB
Dart

import 'dart:io';
import 'package:drift/native.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mews/application/controllers/reader_settings_controller.dart';
import 'package:mews/application/fonts.dart';
import 'package:mews/database/database.dart';
/// The families pubspec.yaml declares, with the asset paths of each.
Map<String, List<String>> _declaredFonts() {
final lines = File('pubspec.yaml').readAsLinesSync();
final declared = <String, List<String>>{};
String? family;
for (final line in lines) {
final name = RegExp(r'^ - family: (.+)$').firstMatch(line);
if (name != null) {
family = name.group(1)!.trim();
declared[family] = [];
continue;
}
final asset = RegExp(r'^ - asset: (.+)$').firstMatch(line);
if (asset != null && family != null) {
declared[family]!.add(asset.group(1)!.trim());
}
}
return declared;
}
void main() {
test('every offered typeface is bundled under the name it is stored by', () {
final declared = _declaredFonts();
for (final font in readerFonts) {
// A family named here but not in pubspec renders in the platform's font
// instead, silently: the reader would pick it and see no change.
expect(declared, contains(font.family),
reason: '${font.family} is offered but not declared in pubspec.yaml');
expect(declared[font.family], hasLength(4),
reason: '${font.family} needs regular, italic, bold and bold italic');
for (final asset in declared[font.family]!) {
expect(File(asset).existsSync(), isTrue, reason: '$asset is missing');
}
}
});
test('a fallback only names a typeface that is bundled', () {
final declared = _declaredFonts();
for (final font in readerFonts) {
for (final family in font.fallback) {
// A fallback naming a family the build does not carry is silently
// skipped, so the glyph would come from the platform after all.
expect(declared, contains(family),
reason: '${font.family} falls back to an absent $family');
expect(family, isNot(font.family), reason: 'falls back to itself');
for (final asset in declared[family]!) {
expect(File(asset).existsSync(), isTrue, reason: '$asset is missing');
}
}
}
expect(readerFonts.map((f) => f.family), contains(defaultFontFamily));
expect(fallbackFor('Comic Sans MS'), isEmpty);
});
test('every typeface can reach Hebrew without the platform', () {
// Hebrew ships from the start, so it must never depend on what the device
// happens to have installed.
for (final font in readerFonts) {
expect(font.fallback, anyElement(anyOf(hebrewSans, hebrewSerif)),
reason: '${font.family} has no Hebrew to fall back on');
}
});
test('every typeface has a label of its own', () {
final ftl = File('locales/en-US/main.ftl').readAsStringSync();
final ids = <String>{};
for (final font in readerFonts) {
expect(ftl, contains('${font.labelId} ='),
reason: '${font.family} has no label');
expect(ids.add(font.labelId), isTrue, reason: 'duplicate label id');
}
});
test('a typeface this build does not ship is refused', () async {
final db = MewsDatabase.test(NativeDatabase.memory());
addTearDown(db.close);
final settings = ReaderSettingsController(db);
expect(await settings.setFont('Literata'), isTrue);
expect(settings.font.value, 'Literata');
// Comic Sans is not bundled; accepting it would render in the platform
// font while the settings page claimed otherwise.
expect(await settings.setFont('Comic Sans MS'), isFalse);
expect(settings.font.value, 'Literata');
expect(await settings.setFont(''), isFalse);
expect(settings.font.value, 'Literata');
});
}