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> _declaredFonts() { final lines = File('pubspec.yaml').readAsLinesSync(); final declared = >{}; 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 = {}; 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'); }); }