flutter/packages/flutter_test/test/goldens_test.dart
Todd Volkert be09a200ee
Expose generateTestBootstrap() as public API in test harness (#17290)
This will allow external tools that wrap our test harness to share the
code that generates the test bootstrap.

This change exposed an issue whereby the LocalGoldenFileComparator
was being too strict in its URI handling, so this changes relaxes
that constraint as well (and adds associated tests).
2018-05-04 10:31:53 -07:00

189 lines
7.4 KiB
Dart

// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:io' as io;
import 'dart:typed_data';
import 'package:file/memory.dart';
import 'package:test/test.dart' as test_package;
import 'package:test/test.dart' hide test;
import 'package:flutter_test/flutter_test.dart' show goldenFileComparator, LocalFileComparator;
const List<int> _kExpectedBytes = const <int>[1, 2, 3];
void main() {
MemoryFileSystem fs;
setUp(() {
final FileSystemStyle style = io.Platform.isWindows
? FileSystemStyle.windows
: FileSystemStyle.posix;
fs = new MemoryFileSystem(style: style);
});
/// Converts posix-style paths to the style associated with [fs].
///
/// This allows us to deal in posix-style paths in the tests.
String fix(String path) {
if (path.startsWith('/')) {
path = '${fs.style.drive}$path';
}
return path.replaceAll('/', fs.path.separator);
}
void test(String description, FutureOr<void> body()) {
test_package.test(description, () {
return io.IOOverrides.runZoned(
body,
createDirectory: (String path) => fs.directory(path),
createFile: (String path) => fs.file(path),
createLink: (String path) => fs.link(path),
getCurrentDirectory: () => fs.currentDirectory,
setCurrentDirectory: (String path) => fs.currentDirectory = path,
getSystemTempDirectory: () => fs.systemTempDirectory,
stat: (String path) => fs.stat(path),
statSync: (String path) => fs.statSync(path),
fseIdentical: (String p1, String p2) => fs.identical(p1, p2),
fseIdenticalSync: (String p1, String p2) => fs.identicalSync(p1, p2),
fseGetType: (String path, bool followLinks) => fs.type(path, followLinks: followLinks),
fseGetTypeSync: (String path, bool followLinks) => fs.typeSync(path, followLinks: followLinks),
fsWatch: (String a, int b, bool c) => throw new UnsupportedError('unsupported'),
fsWatchIsSupported: () => fs.isWatchSupported,
);
});
}
group('goldenFileComparator', () {
test('is initialized by test framework', () {
expect(goldenFileComparator, isNotNull);
expect(goldenFileComparator, const isInstanceOf<LocalFileComparator>());
final LocalFileComparator comparator = goldenFileComparator;
expect(comparator.basedir.path, contains('flutter_test'));
});
});
group('LocalFileComparator', () {
LocalFileComparator comparator;
setUp(() {
comparator = new LocalFileComparator(fs.file(fix('/golden_test.dart')).uri, pathStyle: fs.path.style);
});
test('calculates basedir correctly', () {
expect(comparator.basedir, fs.file(fix('/')).uri);
comparator = new LocalFileComparator(fs.file(fix('/foo/bar/golden_test.dart')).uri, pathStyle: fs.path.style);
expect(comparator.basedir, fs.directory(fix('/foo/bar/')).uri);
});
test('can be instantiated with uri that represents file in same folder', () {
comparator = new LocalFileComparator(Uri.parse('foo_test.dart'), pathStyle: fs.path.style);
expect(comparator.basedir, Uri.parse('./'));
});
group('compare', () {
Future<bool> doComparison([String golden = 'golden.png']) {
final Uri uri = fs.file(fix(golden)).uri;
return comparator.compare(
new Uint8List.fromList(_kExpectedBytes),
uri,
);
}
group('succeeds', () {
test('when golden file is in same folder as test', () async {
fs.file(fix('/golden.png')).writeAsBytesSync(_kExpectedBytes);
final bool success = await doComparison();
expect(success, isTrue);
});
test('when golden file is in subfolder of test', () async {
fs.file(fix('/sub/foo.png'))
..createSync(recursive: true)
..writeAsBytesSync(_kExpectedBytes);
final bool success = await doComparison('sub/foo.png');
expect(success, isTrue);
});
group('when comparator instantiated with uri that represents file in same folder', () {
test('and golden file is in same folder as test', () async {
fs.file(fix('/foo/bar/golden.png'))
..createSync(recursive: true)
..writeAsBytesSync(_kExpectedBytes);
fs.currentDirectory = fix('/foo/bar');
comparator = new LocalFileComparator(Uri.parse('local_test.dart'), pathStyle: fs.path.style);
final bool success = await doComparison('golden.png');
expect(success, isTrue);
});
test('and golden file is in subfolder of test', () async {
fs.file(fix('/foo/bar/baz/golden.png'))
..createSync(recursive: true)
..writeAsBytesSync(_kExpectedBytes);
fs.currentDirectory = fix('/foo/bar');
comparator = new LocalFileComparator(Uri.parse('local_test.dart'), pathStyle: fs.path.style);
final bool success = await doComparison('baz/golden.png');
expect(success, isTrue);
});
});
});
group('fails', () {
test('when golden file does not exist', () async {
final Future<bool> comparison = doComparison();
expect(comparison, throwsA(const isInstanceOf<TestFailure>()));
});
test('when golden bytes are leading subset of image bytes', () async {
fs.file(fix('/golden.png')).writeAsBytesSync(<int>[1, 2]);
expect(await doComparison(), isFalse);
});
test('when golden bytes are leading superset of image bytes', () async {
fs.file(fix('/golden.png')).writeAsBytesSync(<int>[1, 2, 3, 4]);
expect(await doComparison(), isFalse);
});
test('when golden bytes are trailing subset of image bytes', () async {
fs.file(fix('/golden.png')).writeAsBytesSync(<int>[2, 3]);
expect(await doComparison(), isFalse);
});
test('when golden bytes are trailing superset of image bytes', () async {
fs.file(fix('/golden.png')).writeAsBytesSync(<int>[0, 1, 2, 3]);
expect(await doComparison(), isFalse);
});
test('when golden bytes are disjoint from image bytes', () async {
fs.file(fix('/golden.png')).writeAsBytesSync(<int>[4, 5, 6]);
expect(await doComparison(), isFalse);
});
test('when golden bytes are empty', () async {
fs.file(fix('/golden.png')).writeAsBytesSync(<int>[]);
expect(await doComparison(), isFalse);
});
});
});
group('update', () {
test('updates existing file', () async {
fs.file(fix('/golden.png')).writeAsBytesSync(_kExpectedBytes);
const List<int> newBytes = const <int>[11, 12, 13];
await comparator.update(fs.file('golden.png').uri, new Uint8List.fromList(newBytes));
expect(fs.file(fix('/golden.png')).readAsBytesSync(), newBytes);
});
test('creates non-existent file', () async {
expect(fs.file(fix('/foo.png')).existsSync(), isFalse);
const List<int> newBytes = const <int>[11, 12, 13];
await comparator.update(fs.file('foo.png').uri, new Uint8List.fromList(newBytes));
expect(fs.file(fix('/foo.png')).existsSync(), isTrue);
expect(fs.file(fix('/foo.png')).readAsBytesSync(), newBytes);
});
});
});
}