Unverified Commit 41e553bb authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] migrate flutter_goldens, flutter_goldens client to null-safety (#64201)

parent 302f9f75
...@@ -103,10 +103,7 @@ abstract class FlutterGoldenFileComparator extends GoldenFileComparator { ...@@ -103,10 +103,7 @@ abstract class FlutterGoldenFileComparator extends GoldenFileComparator {
this.skiaClient, { this.skiaClient, {
this.fs = const LocalFileSystem(), this.fs = const LocalFileSystem(),
this.platform = const LocalPlatform(), this.platform = const LocalPlatform(),
}) : assert(basedir != null), });
assert(skiaClient != null),
assert(fs != null),
assert(platform != null);
/// The directory to which golden file URIs will be resolved in [compare] and /// The directory to which golden file URIs will be resolved in [compare] and
/// [update], cannot be null. /// [update], cannot be null.
...@@ -132,7 +129,7 @@ abstract class FlutterGoldenFileComparator extends GoldenFileComparator { ...@@ -132,7 +129,7 @@ abstract class FlutterGoldenFileComparator extends GoldenFileComparator {
} }
@override @override
Uri getTestUri(Uri key, int version) => key; Uri getTestUri(Uri key, int? version) => key;
/// Calculate the appropriate basedir for the current test context. /// Calculate the appropriate basedir for the current test context.
/// ///
...@@ -231,8 +228,8 @@ class FlutterPostSubmitFileComparator extends FlutterGoldenFileComparator { ...@@ -231,8 +228,8 @@ class FlutterPostSubmitFileComparator extends FlutterGoldenFileComparator {
/// purposes only. /// purposes only.
static Future<FlutterPostSubmitFileComparator> fromDefaultComparator( static Future<FlutterPostSubmitFileComparator> fromDefaultComparator(
final Platform platform, { final Platform platform, {
SkiaGoldClient goldens, SkiaGoldClient? goldens,
LocalFileComparator defaultComparator, LocalFileComparator? defaultComparator,
}) async { }) async {
defaultComparator ??= goldenFileComparator as LocalFileComparator; defaultComparator ??= goldenFileComparator as LocalFileComparator;
...@@ -326,9 +323,9 @@ class FlutterPreSubmitFileComparator extends FlutterGoldenFileComparator { ...@@ -326,9 +323,9 @@ class FlutterPreSubmitFileComparator extends FlutterGoldenFileComparator {
/// purposes only. /// purposes only.
static Future<FlutterGoldenFileComparator> fromDefaultComparator( static Future<FlutterGoldenFileComparator> fromDefaultComparator(
final Platform platform, { final Platform platform, {
SkiaGoldClient goldens, SkiaGoldClient? goldens,
LocalFileComparator defaultComparator, LocalFileComparator? defaultComparator,
final Directory testBasedir, Directory? testBasedir,
}) async { }) async {
defaultComparator ??= goldenFileComparator as LocalFileComparator; defaultComparator ??= goldenFileComparator as LocalFileComparator;
...@@ -353,7 +350,7 @@ class FlutterPreSubmitFileComparator extends FlutterGoldenFileComparator { ...@@ -353,7 +350,7 @@ class FlutterPreSubmitFileComparator extends FlutterGoldenFileComparator {
// Some contributors may not have permission on Cirrus to decrypt the // Some contributors may not have permission on Cirrus to decrypt the
// service account. // service account.
onCirrusWithPermission = onCirrusWithPermission =
!platform.environment['GOLD_SERVICE_ACCOUNT'].startsWith('ENCRYPTED'); !platform.environment['GOLD_SERVICE_ACCOUNT']!.startsWith('ENCRYPTED');
} }
final bool onLuci = platform.environment.containsKey('SWARMING_TASK_ID'); final bool onLuci = platform.environment.containsKey('SWARMING_TASK_ID');
if (onCirrusWithPermission || onLuci) { if (onCirrusWithPermission || onLuci) {
...@@ -457,7 +454,7 @@ class _UnauthorizedFlutterPreSubmitComparator extends FlutterPreSubmitFileCompar ...@@ -457,7 +454,7 @@ class _UnauthorizedFlutterPreSubmitComparator extends FlutterPreSubmitFileCompar
// low. // low.
skiaClient.getExpectations(); skiaClient.getExpectations();
final String testName = skiaClient.cleanTestName(golden.path); final String testName = skiaClient.cleanTestName(golden.path);
final List<String> testExpectations = skiaClient.expectations[testName]; final List<String>? testExpectations = skiaClient.expectations[testName];
if (testExpectations == null) { if (testExpectations == null) {
// This is a new test. // This is a new test.
print('No expectations provided by Skia Gold for test: $golden. ' print('No expectations provided by Skia Gold for test: $golden. '
...@@ -502,8 +499,7 @@ class FlutterSkippingFileComparator extends FlutterGoldenFileComparator { ...@@ -502,8 +499,7 @@ class FlutterSkippingFileComparator extends FlutterGoldenFileComparator {
final Uri basedir, final Uri basedir,
final SkiaGoldClient skiaClient, final SkiaGoldClient skiaClient,
this.reason, this.reason,
) : assert(reason != null), ) : super(basedir, skiaClient);
super(basedir, skiaClient);
/// Describes the reason for using the [FlutterSkippingFileComparator]. /// Describes the reason for using the [FlutterSkippingFileComparator].
/// ///
...@@ -514,12 +510,12 @@ class FlutterSkippingFileComparator extends FlutterGoldenFileComparator { ...@@ -514,12 +510,12 @@ class FlutterSkippingFileComparator extends FlutterGoldenFileComparator {
/// relative path resolution of the default [goldenFileComparator]. /// relative path resolution of the default [goldenFileComparator].
static FlutterSkippingFileComparator fromDefaultComparator( static FlutterSkippingFileComparator fromDefaultComparator(
String reason, { String reason, {
LocalFileComparator defaultComparator, LocalFileComparator? defaultComparator,
}) { }) {
defaultComparator ??= goldenFileComparator as LocalFileComparator; defaultComparator ??= goldenFileComparator as LocalFileComparator;
const FileSystem fs = LocalFileSystem(); const FileSystem fs = LocalFileSystem();
final Uri basedir = defaultComparator.basedir; final Uri basedir = defaultComparator.basedir;
final SkiaGoldClient skiaClient = SkiaGoldClient(fs.directory(basedir)); final SkiaGoldClient skiaClient = SkiaGoldClient(fs.directory(basedir), ci: ContinuousIntegrationEnvironment.none);
return FlutterSkippingFileComparator(basedir, skiaClient, reason); return FlutterSkippingFileComparator(basedir, skiaClient, reason);
} }
...@@ -532,7 +528,7 @@ class FlutterSkippingFileComparator extends FlutterGoldenFileComparator { ...@@ -532,7 +528,7 @@ class FlutterSkippingFileComparator extends FlutterGoldenFileComparator {
} }
@override @override
Future<void> update(Uri golden, Uint8List imageBytes) => null; Future<void> update(Uri golden, Uint8List imageBytes) async {}
/// Decides, based on the current environment, if this comparator should be /// Decides, based on the current environment, if this comparator should be
/// used. /// used.
...@@ -596,9 +592,9 @@ class FlutterLocalFileComparator extends FlutterGoldenFileComparator with LocalC ...@@ -596,9 +592,9 @@ class FlutterLocalFileComparator extends FlutterGoldenFileComparator with LocalC
/// visible for testing purposes only. /// visible for testing purposes only.
static Future<FlutterGoldenFileComparator> fromDefaultComparator( static Future<FlutterGoldenFileComparator> fromDefaultComparator(
final Platform platform, { final Platform platform, {
SkiaGoldClient goldens, SkiaGoldClient? goldens,
LocalFileComparator defaultComparator, LocalFileComparator? defaultComparator,
Directory baseDirectory, Directory? baseDirectory,
}) async { }) async {
defaultComparator ??= goldenFileComparator as LocalFileComparator; defaultComparator ??= goldenFileComparator as LocalFileComparator;
baseDirectory ??= FlutterGoldenFileComparator.getBaseDirectory( baseDirectory ??= FlutterGoldenFileComparator.getBaseDirectory(
...@@ -611,7 +607,7 @@ class FlutterLocalFileComparator extends FlutterGoldenFileComparator with LocalC ...@@ -611,7 +607,7 @@ class FlutterLocalFileComparator extends FlutterGoldenFileComparator with LocalC
baseDirectory.createSync(recursive: true); baseDirectory.createSync(recursive: true);
} }
goldens ??= SkiaGoldClient(baseDirectory); goldens ??= SkiaGoldClient(baseDirectory, ci: ContinuousIntegrationEnvironment.none);
try { try {
await goldens.getExpectations(); await goldens.getExpectations();
...@@ -638,7 +634,7 @@ class FlutterLocalFileComparator extends FlutterGoldenFileComparator with LocalC ...@@ -638,7 +634,7 @@ class FlutterLocalFileComparator extends FlutterGoldenFileComparator with LocalC
Future<bool> compare(Uint8List imageBytes, Uri golden) async { Future<bool> compare(Uint8List imageBytes, Uri golden) async {
golden = _addPrefix(golden); golden = _addPrefix(golden);
final String testName = skiaClient.cleanTestName(golden.path); final String testName = skiaClient.cleanTestName(golden.path);
final List<String> testExpectations = skiaClient.expectations[testName]; final List<String>? testExpectations = skiaClient.expectations[testName];
if (testExpectations == null) { if (testExpectations == null) {
// There is no baseline for this test // There is no baseline for this test
print('No expectations provided by Skia Gold for test: $golden. ' print('No expectations provided by Skia Gold for test: $golden. '
......
...@@ -2,7 +2,7 @@ name: flutter_goldens ...@@ -2,7 +2,7 @@ name: flutter_goldens
environment: environment:
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite. # The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
sdk: ">=2.0.0-dev.68.0 <3.0.0" sdk: ">=2.10.0-4.0.dev <2.10.0"
dependencies: dependencies:
# To update these, use "flutter update-packages --force-upgrade". # To update these, use "flutter update-packages --force-upgrade".
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.8
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:core'; import 'dart:core';
...@@ -75,6 +76,7 @@ void main() { ...@@ -75,6 +76,7 @@ void main() {
process: process, process: process,
platform: platform, platform: platform,
httpClient: mockHttpClient, httpClient: mockHttpClient,
ci: ContinuousIntegrationEnvironment.luci,
); );
}); });
...@@ -148,6 +150,7 @@ void main() { ...@@ -148,6 +150,7 @@ void main() {
process: process, process: process,
platform: platform, platform: platform,
httpClient: mockHttpClient, httpClient: mockHttpClient,
ci: ContinuousIntegrationEnvironment.luci
); );
when(process.run( when(process.run(
......
...@@ -25,6 +25,7 @@ const String _kTestBrowserKey = 'FLUTTER_TEST_BROWSER'; ...@@ -25,6 +25,7 @@ const String _kTestBrowserKey = 'FLUTTER_TEST_BROWSER';
enum ContinuousIntegrationEnvironment { enum ContinuousIntegrationEnvironment {
luci, luci,
cirrus, cirrus,
none,
} }
/// A client for uploading image tests and making baseline requests to the /// A client for uploading image tests and making baseline requests to the
...@@ -35,13 +36,9 @@ class SkiaGoldClient { ...@@ -35,13 +36,9 @@ class SkiaGoldClient {
this.fs = const LocalFileSystem(), this.fs = const LocalFileSystem(),
this.process = const LocalProcessManager(), this.process = const LocalProcessManager(),
this.platform = const LocalPlatform(), this.platform = const LocalPlatform(),
this.ci, required this.ci,
io.HttpClient httpClient, io.HttpClient? httpClient,
}) : assert(workDirectory != null), }) : httpClient = httpClient ?? io.HttpClient();
assert(fs != null),
assert(process != null),
assert(platform != null),
httpClient = httpClient ?? io.HttpClient();
/// The file system to use for storing the local clone of the repository. /// The file system to use for storing the local clone of the repository.
/// ///
...@@ -83,7 +80,7 @@ class SkiaGoldClient { ...@@ -83,7 +80,7 @@ class SkiaGoldClient {
/// [_UnauthorizedFlutterPreSubmitComparator] to test against golden masters /// [_UnauthorizedFlutterPreSubmitComparator] to test against golden masters
/// maintained in the Flutter Gold dashboard. /// maintained in the Flutter Gold dashboard.
Map<String, List<String>> get expectations => _expectations; Map<String, List<String>> get expectations => _expectations;
Map<String, List<String>> _expectations; late Map<String, List<String>> _expectations;
/// The local [Directory] where the Flutter repository is hosted. /// The local [Directory] where the Flutter repository is hosted.
/// ///
...@@ -93,13 +90,13 @@ class SkiaGoldClient { ...@@ -93,13 +90,13 @@ class SkiaGoldClient {
/// The path to the local [Directory] where the goldctl tool is hosted. /// The path to the local [Directory] where the goldctl tool is hosted.
/// ///
/// Uses the [platform] environment in this implementation. /// Uses the [platform] environment in this implementation.
String/*!*/ get _goldctl => platform.environment[_kGoldctlKey]; String get _goldctl => platform.environment[_kGoldctlKey]!;
/// The path to the local [Directory] where the service account key is /// The path to the local [Directory] where the service account key is
/// hosted. /// hosted.
/// ///
/// Uses the [platform] environment in this implementation. /// Uses the [platform] environment in this implementation.
String/*!*/ get _serviceAccount => platform.environment[_kServiceAccountKey]; String get _serviceAccount => platform.environment[_kServiceAccountKey]!;
/// Prepares the local work space for golden file testing and calls the /// Prepares the local work space for golden file testing and calls the
/// goldctl `auth` command. /// goldctl `auth` command.
...@@ -116,9 +113,9 @@ class SkiaGoldClient { ...@@ -116,9 +113,9 @@ class SkiaGoldClient {
return; return;
List<String> authArguments; List<String> authArguments;
/*late*/ String failureContext; String failureContext;
switch (ci/*!*/) { switch (ci) {
case ContinuousIntegrationEnvironment.luci: case ContinuousIntegrationEnvironment.luci:
authArguments = <String>[ authArguments = <String>[
'auth', 'auth',
...@@ -154,6 +151,8 @@ class SkiaGoldClient { ...@@ -154,6 +151,8 @@ class SkiaGoldClient {
'Cirrus, if the debug information below contains ENCRYPTED, the wrong ' 'Cirrus, if the debug information below contains ENCRYPTED, the wrong '
'comparator was chosen for the test case.'; 'comparator was chosen for the test case.';
break; break;
case ContinuousIntegrationEnvironment.none:
return;
} }
final io.ProcessResult result = await io.Process.run( final io.ProcessResult result = await io.Process.run(
...@@ -267,9 +266,6 @@ class SkiaGoldClient { ...@@ -267,9 +266,6 @@ class SkiaGoldClient {
/// The [testName] and [goldenFile] parameters reference the current /// The [testName] and [goldenFile] parameters reference the current
/// comparison being evaluated by the [FlutterPostSubmitFileComparator]. /// comparison being evaluated by the [FlutterPostSubmitFileComparator].
Future<bool> imgtestAdd(String testName, File goldenFile) async { Future<bool> imgtestAdd(String testName, File goldenFile) async {
assert(testName != null);
assert(goldenFile != null);
final List<String> imgtestArguments = <String>[ final List<String> imgtestArguments = <String>[
'imgtest', 'add', 'imgtest', 'add',
'--work-dir', workDirectory '--work-dir', workDirectory
...@@ -361,9 +357,6 @@ class SkiaGoldClient { ...@@ -361,9 +357,6 @@ class SkiaGoldClient {
/// The [testName] and [goldenFile] parameters reference the current /// The [testName] and [goldenFile] parameters reference the current
/// comparison being evaluated by the [_AuthorizedFlutterPreSubmitComparator]. /// comparison being evaluated by the [_AuthorizedFlutterPreSubmitComparator].
Future<void> tryjobAdd(String testName, File goldenFile) async { Future<void> tryjobAdd(String testName, File goldenFile) async {
assert(testName != null);
assert(goldenFile != null);
final List<String> imgtestArguments = <String>[ final List<String> imgtestArguments = <String>[
'imgtest', 'add', 'imgtest', 'add',
'--work-dir', workDirectory '--work-dir', workDirectory
...@@ -410,9 +403,6 @@ class SkiaGoldClient { ...@@ -410,9 +403,6 @@ class SkiaGoldClient {
/// comparison being evaluated by the /// comparison being evaluated by the
/// [_UnauthorizedFlutterPreSubmitComparator]. /// [_UnauthorizedFlutterPreSubmitComparator].
Future<bool> imgtestCheck(String testName, File goldenFile) async { Future<bool> imgtestCheck(String testName, File goldenFile) async {
assert(testName != null);
assert(goldenFile != null);
final List<String> imgtestArguments = <String>[ final List<String> imgtestArguments = <String>[
'imgtest', 'check', 'imgtest', 'check',
'--work-dir', workDirectory '--work-dir', workDirectory
...@@ -440,7 +430,7 @@ class SkiaGoldClient { ...@@ -440,7 +430,7 @@ class SkiaGoldClient {
); );
const String mainKey = 'master'; const String mainKey = 'master';
const String temporaryKey = 'master_str'; const String temporaryKey = 'master_str';
String rawResponse; late String rawResponse;
try { try {
final io.HttpClientRequest request = await httpClient.getUrl(requestForExpectations); final io.HttpClientRequest request = await httpClient.getUrl(requestForExpectations);
final io.HttpClientResponse response = await request.close(); final io.HttpClientResponse response = await request.close();
...@@ -448,7 +438,7 @@ class SkiaGoldClient { ...@@ -448,7 +438,7 @@ class SkiaGoldClient {
final dynamic jsonResponse = json.decode(rawResponse); final dynamic jsonResponse = json.decode(rawResponse);
if (jsonResponse is! Map<String, dynamic>) if (jsonResponse is! Map<String, dynamic>)
throw const FormatException('Skia gold expectations do not match expected format.'); throw const FormatException('Skia gold expectations do not match expected format.');
final Map<String, dynamic> skiaJson = (jsonResponse[mainKey] ?? jsonResponse[temporaryKey]) as Map<String, dynamic>; final Map<String, dynamic>? skiaJson = (jsonResponse[mainKey] ?? jsonResponse[temporaryKey]) as Map<String, dynamic>?;
if (skiaJson == null) if (skiaJson == null)
throw FormatException('Skia gold expectations are missing the "$mainKey" key (and also doesn\'t have "$temporaryKey")! Available keys: ${jsonResponse.keys.join(", ")}'); throw FormatException('Skia gold expectations are missing the "$mainKey" key (and also doesn\'t have "$temporaryKey")! Available keys: ${jsonResponse.keys.join(", ")}');
skiaJson.forEach((String key, dynamic value) { skiaJson.forEach((String key, dynamic value) {
...@@ -506,7 +496,7 @@ class SkiaGoldClient { ...@@ -506,7 +496,7 @@ class SkiaGoldClient {
Future<bool> testIsIgnoredForPullRequest(String pullRequest, String testName) async { Future<bool> testIsIgnoredForPullRequest(String pullRequest, String testName) async {
bool ignoreIsActive = false; bool ignoreIsActive = false;
testName = cleanTestName(testName); testName = cleanTestName(testName);
String rawResponse; late String rawResponse;
await io.HttpOverrides.runWithHttpOverrides<Future<void>>(() async { await io.HttpOverrides.runWithHttpOverrides<Future<void>>(() async {
final Uri requestForIgnores = Uri.parse( final Uri requestForIgnores = Uri.parse(
'https://flutter-gold.skia.org/json/ignores' 'https://flutter-gold.skia.org/json/ignores'
...@@ -565,7 +555,7 @@ class SkiaGoldClient { ...@@ -565,7 +555,7 @@ class SkiaGoldClient {
Future<bool> isValidDigestForExpectation(String expectation, String testName) async { Future<bool> isValidDigestForExpectation(String expectation, String testName) async {
bool isValid = false; bool isValid = false;
testName = cleanTestName(testName); testName = cleanTestName(testName);
String rawResponse; late String rawResponse;
await io.HttpOverrides.runWithHttpOverrides<Future<void>>(() async { await io.HttpOverrides.runWithHttpOverrides<Future<void>>(() async {
final Uri requestForDigest = Uri.parse( final Uri requestForDigest = Uri.parse(
'https://flutter-gold.skia.org/json/details?test=$testName&digest=$expectation' 'https://flutter-gold.skia.org/json/details?test=$testName&digest=$expectation'
...@@ -653,22 +643,24 @@ class SkiaGoldClient { ...@@ -653,22 +643,24 @@ class SkiaGoldClient {
/// Returns a list of arguments for initializing a tryjob based on the testing /// Returns a list of arguments for initializing a tryjob based on the testing
/// environment. /// environment.
List<String> getCIArguments() { List<String> getCIArguments() {
/*late*/ String/*!*/ pullRequest; String pullRequest;
/*late*/ String/*!*/ jobId; String jobId;
/*late*/ String cis; String cis;
switch (ci/*!*/) { switch (ci) {
case ContinuousIntegrationEnvironment.luci: case ContinuousIntegrationEnvironment.luci:
jobId = platform.environment['LOGDOG_STREAM_PREFIX'].split('/').last; jobId = platform.environment['LOGDOG_STREAM_PREFIX']!.split('/').last;
final List<String> refs = platform.environment['GOLD_TRYJOB'].split('/'); final List<String> refs = platform.environment['GOLD_TRYJOB']!.split('/');
pullRequest = refs[refs.length - 2]; pullRequest = refs[refs.length - 2];
cis = 'buildbucket'; cis = 'buildbucket';
break; break;
case ContinuousIntegrationEnvironment.cirrus: case ContinuousIntegrationEnvironment.cirrus:
pullRequest = platform.environment['CIRRUS_PR']; pullRequest = platform.environment['CIRRUS_PR']!;
jobId = platform.environment['CIRRUS_TASK_ID']; jobId = platform.environment['CIRRUS_TASK_ID']!;
cis = 'cirrus'; cis = 'cirrus';
break; break;
case ContinuousIntegrationEnvironment.none:
return <String>[];
} }
return <String>[ return <String>[
...@@ -685,17 +677,17 @@ class SkiaGoldHttpOverrides extends io.HttpOverrides {} ...@@ -685,17 +677,17 @@ class SkiaGoldHttpOverrides extends io.HttpOverrides {}
/// A digest returned from a request to the Flutter Gold dashboard. /// A digest returned from a request to the Flutter Gold dashboard.
class SkiaGoldDigest { class SkiaGoldDigest {
const SkiaGoldDigest({ const SkiaGoldDigest({
this.imageHash, required this.imageHash,
this.paramSet, required this.paramSet,
this.testName, required this.testName,
this.status, required this.status,
}); });
/// Create a digest from requested JSON. /// Create a digest from requested JSON.
factory SkiaGoldDigest.fromJson(Map<String, dynamic> json) { factory SkiaGoldDigest.fromJson(Map<String, dynamic> json) {
return SkiaGoldDigest( return SkiaGoldDigest(
imageHash: json['digest'] as String, imageHash: json['digest'] as String,
paramSet: Map<String, dynamic>.from(json['paramset'] as Map<String, dynamic> ?? paramSet: Map<String, dynamic>.from(json['paramset'] as Map<String, dynamic>? ??
<String, List<String>>{ <String, List<String>>{
'Platform': <String>[], 'Platform': <String>[],
'Browser' : <String>[], 'Browser' : <String>[],
...@@ -706,16 +698,16 @@ class SkiaGoldDigest { ...@@ -706,16 +698,16 @@ class SkiaGoldDigest {
} }
/// Unique identifier for the image associated with the digest. /// Unique identifier for the image associated with the digest.
final String/*!*/ imageHash; final String imageHash;
/// Parameter set for the given test, e.g. Platform : Windows. /// Parameter set for the given test, e.g. Platform : Windows.
final Map<String, dynamic>/*!*/ paramSet; final Map<String, dynamic> paramSet;
/// Test name associated with the digest, e.g. positive or un-triaged. /// Test name associated with the digest, e.g. positive or un-triaged.
final String/*!*/ testName; final String testName;
/// Status of the given digest, e.g. positive or un-triaged. /// Status of the given digest, e.g. positive or un-triaged.
final String/*!*/ status; final String status;
/// Validates a given digest against the current testing conditions. /// Validates a given digest against the current testing conditions.
bool isValid(Platform platform, String name, String expectation) { bool isValid(Platform platform, String name, String expectation) {
......
...@@ -2,7 +2,7 @@ name: flutter_goldens_client ...@@ -2,7 +2,7 @@ name: flutter_goldens_client
environment: environment:
# The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite. # The pub client defaults to an <2.0.0 sdk constraint which we need to explicitly overwrite.
sdk: ">=2.0.0-dev.68.0 <3.0.0" sdk: ">=2.10.0-4.0.dev <2.10.0 <3.0.0"
dependencies: dependencies:
# To update these, use "flutter update-packages --force-upgrade". # To update these, use "flutter update-packages --force-upgrade".
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.10
import 'dart:async'; import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:math' as math; import 'dart:math' as math;
...@@ -61,15 +62,15 @@ class LocalFileComparator extends GoldenFileComparator with LocalComparisonOutpu ...@@ -61,15 +62,15 @@ class LocalFileComparator extends GoldenFileComparator with LocalComparisonOutpu
/// directory in which [testFile] resides. /// directory in which [testFile] resides.
/// ///
/// The [testFile] URL must represent a file. /// The [testFile] URL must represent a file.
LocalFileComparator(Uri testFile, {path.Style pathStyle}) LocalFileComparator(Uri testFile, {path.Style? pathStyle})
: basedir = _getBasedir(testFile, pathStyle), : basedir = _getBasedir(testFile, pathStyle),
_path = _getPath(pathStyle); _path = _getPath(pathStyle);
static path.Context _getPath(path.Style style) { static path.Context _getPath(path.Style? style) {
return path.Context(style: style ?? path.Style.platform); return path.Context(style: style ?? path.Style.platform);
} }
static Uri _getBasedir(Uri testFile, path.Style pathStyle) { static Uri _getBasedir(Uri testFile, path.Style? pathStyle) {
final path.Context context = _getPath(pathStyle); final path.Context context = _getPath(pathStyle);
final String testFilePath = context.fromUri(testFile); final String testFilePath = context.fromUri(testFile);
final String testDirectoryPath = context.dirname(testFilePath); final String testDirectoryPath = context.dirname(testFilePath);
...@@ -135,7 +136,7 @@ class LocalComparisonOutput { ...@@ -135,7 +136,7 @@ class LocalComparisonOutput {
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(
key.isEmpty ? entry.key : entry.key + '_' + key, key.isEmpty ? entry.key : entry.key + '_' + key,
...@@ -143,9 +144,9 @@ class LocalComparisonOutput { ...@@ -143,9 +144,9 @@ 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( throw test_package.TestFailure(
...@@ -169,7 +170,7 @@ class LocalComparisonOutput { ...@@ -169,7 +170,7 @@ class LocalComparisonOutput {
/// Returns a [ComparisonResult] to describe the pixel differential of the /// Returns a [ComparisonResult] to describe the pixel differential of the
/// [test] and [master] image bytes provided. /// [test] and [master] image bytes provided.
Future<ComparisonResult> compareLists(List<int> test, List<int> master) async { Future<ComparisonResult> compareLists(List<int>? test, List<int>? master) async {
if (identical(test, master)) if (identical(test, master))
return ComparisonResult(passed: true); return ComparisonResult(passed: true);
...@@ -183,15 +184,12 @@ Future<ComparisonResult> compareLists(List<int> test, List<int> master) async { ...@@ -183,15 +184,12 @@ Future<ComparisonResult> compareLists(List<int> test, List<int> master) async {
final Codec testImageCodec = final Codec testImageCodec =
await instantiateImageCodec(Uint8List.fromList(test)); await instantiateImageCodec(Uint8List.fromList(test));
final Image testImage = (await testImageCodec.getNextFrame()).image; final Image testImage = (await testImageCodec.getNextFrame()).image;
final ByteData testImageRgba = await testImage.toByteData(); final ByteData? testImageRgba = await testImage.toByteData();
final Codec masterImageCodec = final Codec masterImageCodec =
await instantiateImageCodec(Uint8List.fromList(master)); await instantiateImageCodec(Uint8List.fromList(master));
final Image masterImage = (await masterImageCodec.getNextFrame()).image; final Image masterImage = (await masterImageCodec.getNextFrame()).image;
final ByteData masterImageRgba = await masterImage.toByteData(); final ByteData? masterImageRgba = await masterImage.toByteData();
assert(testImage != null);
assert(masterImage != null);
final int width = testImage.width; final int width = testImage.width;
final int height = testImage.height; final int height = testImage.height;
...@@ -207,10 +205,10 @@ Future<ComparisonResult> compareLists(List<int> test, List<int> master) async { ...@@ -207,10 +205,10 @@ Future<ComparisonResult> compareLists(List<int> test, List<int> master) async {
int pixelDiffCount = 0; int pixelDiffCount = 0;
final int totalPixels = width * height; final int totalPixels = width * height;
final ByteData invertedMasterRgba = _invert(masterImageRgba); final ByteData invertedMasterRgba = _invert(masterImageRgba!);
final ByteData invertedTestRgba = _invert(testImageRgba); final ByteData invertedTestRgba = _invert(testImageRgba!);
final Uint8List testImageBytes = (await testImage.toByteData()).buffer.asUint8List(); final Uint8List testImageBytes = (await testImage.toByteData())!.buffer.asUint8List();
final ByteData maskedDiffRgba = ByteData(testImageBytes.length); final ByteData maskedDiffRgba = ByteData(testImageBytes.length);
maskedDiffRgba.buffer.asUint8List().setRange(0, testImageBytes.length, testImageBytes); maskedDiffRgba.buffer.asUint8List().setRange(0, testImageBytes.length, testImageBytes);
final ByteData isolatedDiffRgba = ByteData(width * height * 4); final ByteData isolatedDiffRgba = ByteData(width * height * 4);
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.10
import 'dart:convert'; import 'dart:convert';
import 'dart:html' as html; import 'dart:html' as html;
import 'dart:typed_data'; import 'dart:typed_data';
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// @dart = 2.10
import 'dart:async'; import 'dart:async';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import '_goldens_io.dart' if (dart.library.html) '_goldens_web.dart' as _goldens; import '_goldens_io.dart' if (dart.library.html) '_goldens_web.dart' as _goldens;
...@@ -82,7 +82,7 @@ abstract class GoldenFileComparator { ...@@ -82,7 +82,7 @@ abstract class GoldenFileComparator {
/// ///
/// Version numbers are used in golden file tests for package:flutter. You can /// Version numbers are used in golden file tests for package:flutter. You can
/// learn more about these tests [here](https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter). /// learn more about these tests [here](https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter).
Uri getTestUri(Uri key, int version) { Uri getTestUri(Uri key, int? version) {
if (version == null) if (version == null)
return key; return key;
final String keyString = key.toString(); final String keyString = key.toString();
...@@ -130,7 +130,6 @@ abstract class GoldenFileComparator { ...@@ -130,7 +130,6 @@ abstract class GoldenFileComparator {
GoldenFileComparator get goldenFileComparator => _goldenFileComparator; GoldenFileComparator get goldenFileComparator => _goldenFileComparator;
GoldenFileComparator _goldenFileComparator = const TrivialComparator._(); GoldenFileComparator _goldenFileComparator = const TrivialComparator._();
set goldenFileComparator(GoldenFileComparator value) { set goldenFileComparator(GoldenFileComparator value) {
assert(value != null);
_goldenFileComparator = value; _goldenFileComparator = value;
} }
...@@ -194,7 +193,7 @@ abstract class WebGoldenComparator { ...@@ -194,7 +193,7 @@ abstract class WebGoldenComparator {
/// ///
/// Version numbers are used in golden file tests for package:flutter. You can /// Version numbers are used in golden file tests for package:flutter. You can
/// learn more about these tests [here](https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter). /// learn more about these tests [here](https://github.com/flutter/flutter/wiki/Writing-a-golden-file-test-for-package:flutter).
Uri getTestUri(Uri key, int version) { Uri getTestUri(Uri key, int? version) {
if (version == null) if (version == null)
return key; return key;
final String keyString = key.toString(); final String keyString = key.toString();
...@@ -239,7 +238,6 @@ abstract class WebGoldenComparator { ...@@ -239,7 +238,6 @@ abstract class WebGoldenComparator {
WebGoldenComparator get webGoldenComparator => _webGoldenComparator; WebGoldenComparator get webGoldenComparator => _webGoldenComparator;
WebGoldenComparator _webGoldenComparator = const _TrivialWebGoldenComparator._(); WebGoldenComparator _webGoldenComparator = const _TrivialWebGoldenComparator._();
set webGoldenComparator(WebGoldenComparator value) { set webGoldenComparator(WebGoldenComparator value) {
assert(value != null);
_webGoldenComparator = value; _webGoldenComparator = value;
} }
...@@ -289,7 +287,7 @@ class TrivialComparator implements GoldenFileComparator { ...@@ -289,7 +287,7 @@ class TrivialComparator implements GoldenFileComparator {
} }
@override @override
Uri getTestUri(Uri key, int version) { Uri getTestUri(Uri key, int? version) {
return key; return key;
} }
} }
...@@ -309,7 +307,7 @@ class _TrivialWebGoldenComparator implements WebGoldenComparator { ...@@ -309,7 +307,7 @@ class _TrivialWebGoldenComparator implements WebGoldenComparator {
} }
@override @override
Uri getTestUri(Uri key, int version) { Uri getTestUri(Uri key, int? version) {
return key; return key;
} }
} }
...@@ -322,10 +320,10 @@ class _TrivialWebGoldenComparator implements WebGoldenComparator { ...@@ -322,10 +320,10 @@ class _TrivialWebGoldenComparator implements WebGoldenComparator {
class ComparisonResult { class ComparisonResult {
/// Creates a new [ComparisonResult] for the current test. /// Creates a new [ComparisonResult] for the current test.
ComparisonResult({ ComparisonResult({
@required this.passed, required this.passed,
this.error, this.error,
this.diffs, this.diffs,
}) : assert(passed != null); });
/// Indicates whether or not a pixel comparison test has failed. /// Indicates whether or not a pixel comparison test has failed.
/// ///
...@@ -333,10 +331,10 @@ class ComparisonResult { ...@@ -333,10 +331,10 @@ class ComparisonResult {
final bool passed; final bool passed;
/// Error message used to describe the cause of the pixel comparison failure. /// Error message used to describe the cause of the pixel comparison failure.
final String error; final String? error;
/// Map containing differential images to illustrate found variants in pixel /// Map containing differential images to illustrate found variants in pixel
/// values in the execution of the pixel test. /// values in the execution of the pixel test.
// TODO(jonahwilliams): fix type signature when image is updated to support web. // TODO(jonahwilliams): fix type signature when image is updated to support web.
final Map<String, Object> diffs; final Map<String, Object>? diffs;
} }
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