Unverified Commit d1178ae7 authored by Kate Lovett's avatar Kate Lovett Committed by GitHub

Fix local gold output for flutter/flutter (#66139)

parent 978f912d
...@@ -9,6 +9,7 @@ import 'dart:typed_data' show Uint8List; ...@@ -9,6 +9,7 @@ import 'dart:typed_data' show Uint8List;
import 'package:file/file.dart'; import 'package:file/file.dart';
import 'package:file/local.dart'; import 'package:file/local.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
...@@ -670,7 +671,7 @@ class FlutterLocalFileComparator extends FlutterGoldenFileComparator with LocalC ...@@ -670,7 +671,7 @@ class FlutterLocalFileComparator extends FlutterGoldenFileComparator with LocalC
if (result.passed) if (result.passed)
return true; return true;
generateFailureOutput(result, golden, basedir); final String error = await generateFailureOutput(result, golden, basedir);
return false; throw FlutterError(error);
} }
} }
...@@ -8,11 +8,13 @@ import 'dart:math' as math; ...@@ -8,11 +8,13 @@ import 'dart:math' as math;
import 'dart:typed_data'; import 'dart:typed_data';
import 'dart:ui'; import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
// ignore: deprecated_member_use // ignore: deprecated_member_use
import 'package:test_api/test_api.dart' as test_package show TestFailure; import 'package:test_api/test_api.dart' as test_package show TestFailure;
import 'goldens.dart'; import 'goldens.dart';
import 'test_async_utils.dart';
/// The default [GoldenFileComparator] implementation for `flutter test`. /// The default [GoldenFileComparator] implementation for `flutter test`.
/// ///
...@@ -102,7 +104,8 @@ class LocalFileComparator extends GoldenFileComparator with LocalComparisonOutpu ...@@ -102,7 +104,8 @@ class LocalFileComparator extends GoldenFileComparator with LocalComparisonOutpu
); );
if (!result.passed) { if (!result.passed) {
await generateFailureOutput(result, golden, basedir); final String error = await generateFailureOutput(result, golden, basedir);
throw FlutterError(error);
} }
return result.passed; return result.passed;
} }
...@@ -125,16 +128,15 @@ class LocalComparisonOutput { ...@@ -125,16 +128,15 @@ class LocalComparisonOutput {
/// Writes out diffs from the [ComparisonResult] of a golden file test. /// Writes out diffs from the [ComparisonResult] of a golden file test.
/// ///
/// Will throw an error if a null result is provided. /// Will throw an error if a null result is provided.
Future<void> generateFailureOutput( Future<String> generateFailureOutput(
ComparisonResult result, ComparisonResult result,
Uri golden, Uri golden,
Uri basedir, { Uri basedir, {
String key = '', String key = '',
}) async { }) async => TestAsyncUtils.guard<String>(() async {
String additionalFeedback = ''; String additionalFeedback = '';
if (result.diffs != null) { if (result.diffs != null) {
additionalFeedback = '\nFailure feedback can be found at ' additionalFeedback = '\nFailure feedback can be found at ${path.join(basedir.path, 'failures')}';
'${path.join(basedir.path, 'failures')}';
final Map<String, Image> diffs = result.diffs!.cast<String, Image>(); final Map<String, Image> diffs = result.diffs!.cast<String, Image>();
for (final MapEntry<String, Image> entry in diffs.entries) { for (final MapEntry<String, Image> entry in diffs.entries) {
final File output = getFailureFile( final File output = getFailureFile(
...@@ -143,15 +145,12 @@ class LocalComparisonOutput { ...@@ -143,15 +145,12 @@ class LocalComparisonOutput {
basedir, basedir,
); );
output.parent.createSync(recursive: true); output.parent.createSync(recursive: true);
final ByteData? pngBytes = final ByteData? pngBytes = await entry.value.toByteData(format: ImageByteFormat.png);
await entry.value.toByteData(format: ImageByteFormat.png);
output.writeAsBytesSync(pngBytes!.buffer.asUint8List()); output.writeAsBytesSync(pngBytes!.buffer.asUint8List());
} }
} }
throw test_package.TestFailure( return 'Golden "$golden": ${result.error}$additionalFeedback';
'Golden "$golden": ${result.error}$additionalFeedback' });
);
}
/// Returns the appropriate file for a given diff from a [ComparisonResult]. /// Returns the appropriate file for a given diff from a [ComparisonResult].
File getFailureFile(String failure, Uri golden, Uri basedir) { File getFailureFile(String failure, Uri golden, Uri basedir) {
......
...@@ -9,6 +9,7 @@ import 'dart:io' as io; ...@@ -9,6 +9,7 @@ import 'dart:io' as io;
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter/foundation.dart' show DiagnosticLevel, DiagnosticsNode, DiagnosticPropertiesBuilder, FlutterError;
import 'package:flutter_test/flutter_test.dart' hide test; import 'package:flutter_test/flutter_test.dart' hide test;
import 'package:flutter_test/flutter_test.dart' as test_package; import 'package:flutter_test/flutter_test.dart' as test_package;
...@@ -102,6 +103,36 @@ void main() { ...@@ -102,6 +103,36 @@ void main() {
expect(comparator.basedir, Uri.parse('./')); expect(comparator.basedir, Uri.parse('./'));
}); });
test('throws if local output is not awaited', () {
try {
comparator.generateFailureOutput(
ComparisonResult(passed: false),
Uri.parse('foo_test.dart'),
Uri.parse('/foo/bar/'),
);
TestAsyncUtils.verifyAllScopesClosed();
throw 'unexpectedly did not throw';
} on FlutterError catch (e) {
final List<String> lines = e.message.split('\n');
expectSync(lines[0], 'Asynchronous call to guarded function leaked.');
expectSync(lines[1], 'You must use "await" with all Future-returning test APIs.');
expectSync(
lines[2],
matches(r'^The guarded method "generateFailureOutput" from class '
r'LocalComparisonOutput was called from .*goldens_test.dart on line '
r'[0-9]+, but never completed before its parent scope closed\.$'),
);
expectSync(lines.length, 3);
final DiagnosticPropertiesBuilder propertiesBuilder = DiagnosticPropertiesBuilder();
e.debugFillProperties(propertiesBuilder);
final List<DiagnosticsNode> information = propertiesBuilder.properties;
expectSync(information.length, 3);
expectSync(information[0].level, DiagnosticLevel.summary);
expectSync(information[1].level, DiagnosticLevel.hint);
expectSync(information[2].level, DiagnosticLevel.info);
}
});
group('compare', () { group('compare', () {
Future<bool> doComparison([ String golden = 'golden.png' ]) { Future<bool> doComparison([ String golden = 'golden.png' ]) {
final Uri uri = fs.file(fix(golden)).uri; final Uri uri = fs.file(fix(golden)).uri;
...@@ -157,7 +188,7 @@ void main() { ...@@ -157,7 +188,7 @@ void main() {
try { try {
await doComparison(); await doComparison();
fail('TestFailure expected but not thrown.'); fail('TestFailure expected but not thrown.');
} on TestFailure catch (error) { } on FlutterError catch (error) {
expect(error.message, contains('% diff detected')); expect(error.message, contains('% diff detected'));
final io.File master = fs.file( final io.File master = fs.file(
fix('/failures/golden_masterImage.png') fix('/failures/golden_masterImage.png')
...@@ -186,7 +217,7 @@ void main() { ...@@ -186,7 +217,7 @@ void main() {
try { try {
await doComparison('subdir/golden.png'); await doComparison('subdir/golden.png');
fail('TestFailure expected but not thrown.'); fail('TestFailure expected but not thrown.');
} on TestFailure catch (error) { } on FlutterError catch (error) {
expect(error.message, contains('% diff detected')); expect(error.message, contains('% diff detected'));
final io.File master = fs.file( final io.File master = fs.file(
fix('/failures/golden_masterImage.png') fix('/failures/golden_masterImage.png')
...@@ -221,7 +252,7 @@ void main() { ...@@ -221,7 +252,7 @@ void main() {
try { try {
await doComparison(); await doComparison();
fail('TestFailure expected but not thrown.'); fail('TestFailure expected but not thrown.');
} on TestFailure catch (error) { } on FlutterError catch (error) {
expect(error.message, contains('image sizes do not match')); expect(error.message, contains('image sizes do not match'));
} }
}); });
...@@ -231,7 +262,7 @@ void main() { ...@@ -231,7 +262,7 @@ void main() {
try { try {
await doComparison(); await doComparison();
fail('TestFailure expected but not thrown.'); fail('TestFailure expected but not thrown.');
} on TestFailure catch (error) { } on FlutterError catch (error) {
expect(error.message, contains('% diff detected')); expect(error.message, contains('% diff detected'));
} }
}); });
...@@ -241,7 +272,7 @@ void main() { ...@@ -241,7 +272,7 @@ void main() {
try { try {
await doComparison(); await doComparison();
fail('TestFailure expected but not thrown.'); fail('TestFailure expected but not thrown.');
} on TestFailure catch (error) { } on FlutterError catch (error) {
expect(error.message, contains('null image provided')); expect(error.message, contains('null image provided'));
} }
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment