Skip to content

Commit

Permalink
Test loading of invalid fonts
Browse files Browse the repository at this point in the history
  • Loading branch information
passsy committed Nov 19, 2024
1 parent 8a42b38 commit 7ff8673
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 33 deletions.
81 changes: 54 additions & 27 deletions lib/src/screenshot/load_fonts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,39 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';

/// Loads all font from the FontManifest (Asset fonts defined in pubspec.yaml and
/// other Flutter package dependencies) and the following fonts from Flutter SDK:
/// Loads all font from the apps FontManifest and embedded in the Flutter SDK
///
/// ## App Fonts (FontManifest)
/// - All fonts defined in the pubspec.yaml
/// - All fonts of dependencies that define fonts in their pubspec.yaml
///
/// ## Embedded Flutter SDK Fonts
/// - Roboto
/// - RobotoCondensed
/// - MaterialIcons
///
/// By default, widget tests run with [TargetPlatform.android] which
/// uses the Roboto font by default (see [Typography]). Loading this font,
/// although not defined as asset, allows most Flutter apps to render text.
/// ## Why load Roboto by default?
///
/// Widget test run with [TargetPlatform.android] by default. [MaterialApp] sets
/// the Roboto fontFamily as default for [TargetPlatform.android] (see
/// [Typography]). Loading the Roboto fontFamily therefore allows showing text
/// in the default scenario of a Flutter app.
/// Fortunately, Robot is part of the Flutter SDK and can be loaded right away.
///
/// ## Custom fonts
///
/// Apps that use custom fonts, should declare them in the pubspec.yaml file (https://docs.flutter.dev/cookbook/design/fonts#declare-the-font-in-the-pubspec-yaml-file).
/// Those fonts are automatically added to the FontManifest.json file during build.
///
/// The [loadAppFonts] function loads all font defined in the FontManifest.json file.
///
/// If your app depends on other system fonts (like "Segoe UI" on [TargetPlatform.windows]
/// or "Apple Color Emoji" on [TargetPlatform.iOS]) use [loadFont].
/// ## Depending on System fonts
///
/// Sometimes you don't want to ship a font with your app, but use a system
/// font e.g. "Segoe UI" on [TargetPlatform.windows] or "Apple Color Emoji"
/// on [TargetPlatform.iOS].
/// Those fonts are not loaded by [loadAppFonts], load them individually with
/// [loadFont].
Future<void> loadAppFonts() async {
TestWidgetsFlutterBinding.ensureInitialized();

Expand Down Expand Up @@ -55,15 +76,21 @@ Future<void> loadAppFonts() async {
/// ```
///
/// Flutter support the following formats: .ttf, .otf, .ttc
///
/// Calling [loadFont] multiple times with the same family will overwrite the previous
///
/// The [family] is optional: '' will extract the family name from the font file.
Future<void> loadFont(String family, List<String> fontPaths) async {
if (fontPaths.isEmpty) {
return;
}
final fontLoader = FontLoader(family);
for (final path in fontPaths) {
final Uint8List bytes = File(path).readAsBytesSync();

/// TODO catch error when path loads to an unsupported font format (docx);
/// TODO print warning
fontLoader.addFont(Future.sync(() => bytes.buffer.asByteData()));
}
// the fontLoader is unusable after calling load().
// No need to cache or return it.
await fontLoader.load();
}

Expand All @@ -83,23 +110,23 @@ Future<void> _loadMaterialFontsFromSdk() async {
(font) => fontFormats.any((element) => font.path.endsWith(element)),
);

final robotoFonts =
existingFonts.where((font) => font.path.contains('Roboto-'));
await loadFont('Roboto', [
for (final font in robotoFonts) font.path,
]);

final robotoCondensedFonts =
existingFonts.where((font) => font.path.contains('RobotoCondensed-'));
await loadFont('RobotoCondensed', [
for (final font in robotoCondensedFonts) font.path,
]);

final materialIcons =
existingFonts.where((font) => font.path.contains('MaterialIcons-'));
await loadFont('MaterialIcons', [
for (final font in materialIcons) font.path,
]);
final robotoFonts = existingFonts
.map((font) => font.path)
.where((path) => path.contains('Roboto-'))
.toList();
await loadFont('Roboto', robotoFonts);

final robotoCondensedFonts = existingFonts
.map((font) => font.path)
.where((path) => path.contains('RobotoCondensed-'))
.toList();
await loadFont('RobotoCondensed', robotoCondensedFonts);

final materialIcons = existingFonts
.map((font) => font.path)
.where((path) => path.contains('MaterialIcons-'))
.toList();
await loadFont('MaterialIcons', materialIcons);
}

/// Returns the Flutter SDK root directory based on the current flutter
Expand Down
3 changes: 1 addition & 2 deletions test/fonts/default_font_test.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import 'dart:convert';
import 'dart:io';

import 'package:flutter/rendering.dart';
import 'package:dartx/dartx_io.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';

import '../spot/screenshot_test.dart';
import 'font_test_project.dart';

void main() {
Expand Down
32 changes: 32 additions & 0 deletions test/fonts/load_font_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'dart:io';
import 'dart:ui';

import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:spot/spot.dart';

void main() {
testWidgets('load non-font file does not throw', (tester) async {
final tempDir = Directory.systemTemp.createTempSync();
addTearDown(() => tempDir.deleteSync(recursive: true));
final notAFont = File('${tempDir.path}/someFile.txt');
notAFont.writeAsStringSync('some data');

final List<dynamic> messages = [];
// ignore: deprecated_member_use
PlatformDispatcher.instance.onPlatformMessage = (
String name,
ByteData? data,
PlatformMessageResponseCallback? callback,
) {
final decoded = SystemChannels.system.codec.decodeMessage(data);
final type = (decoded! as Map)['type'];
messages.add(type);
callback?.call(null);
};

expect(messages, isEmpty);
await loadFont('someFont', [notAFont.path]);
expect(messages, ['fontsChange']); // success regardless of file content
});
}
2 changes: 0 additions & 2 deletions test/fonts/templates/app_font/test/test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables

import 'dart:ui';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Expand Down
1 change: 0 additions & 1 deletion test/fonts/templates/default_font/test/test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables

import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
Expand Down
1 change: 0 additions & 1 deletion test/fonts/templates/dependency_font/test/test.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// ignore_for_file: prefer_const_constructors, prefer_const_literals_to_create_immutables

import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
Expand Down

0 comments on commit 7ff8673

Please sign in to comment.