1// Copyright 2018 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5import 'dart:async'; 6import 'dart:io' as io; 7import 'dart:typed_data'; 8 9import 'package:file/memory.dart'; 10import 'package:flutter_test/flutter_test.dart' hide test; 11import 'package:flutter_test/flutter_test.dart' as test_package; 12 13const List<int> _kExpectedBytes = <int>[1, 2, 3]; 14 15void main() { 16 MemoryFileSystem fs; 17 18 setUp(() { 19 final FileSystemStyle style = io.Platform.isWindows 20 ? FileSystemStyle.windows 21 : FileSystemStyle.posix; 22 fs = MemoryFileSystem(style: style); 23 }); 24 25 /// Converts posix-style paths to the style associated with [fs]. 26 /// 27 /// This allows us to deal in posix-style paths in the tests. 28 String fix(String path) { 29 if (path.startsWith('/')) { 30 path = '${fs.style.drive}$path'; 31 } 32 return path.replaceAll('/', fs.path.separator); 33 } 34 35 void test(String description, FutureOr<void> body()) { 36 test_package.test(description, () { 37 return io.IOOverrides.runZoned<FutureOr<void>>( 38 body, 39 createDirectory: (String path) => fs.directory(path), 40 createFile: (String path) => fs.file(path), 41 createLink: (String path) => fs.link(path), 42 getCurrentDirectory: () => fs.currentDirectory, 43 setCurrentDirectory: (String path) => fs.currentDirectory = path, 44 getSystemTempDirectory: () => fs.systemTempDirectory, 45 stat: (String path) => fs.stat(path), 46 statSync: (String path) => fs.statSync(path), 47 fseIdentical: (String p1, String p2) => fs.identical(p1, p2), 48 fseIdenticalSync: (String p1, String p2) => fs.identicalSync(p1, p2), 49 fseGetType: (String path, bool followLinks) => fs.type(path, followLinks: followLinks), 50 fseGetTypeSync: (String path, bool followLinks) => fs.typeSync(path, followLinks: followLinks), 51 fsWatch: (String a, int b, bool c) => throw UnsupportedError('unsupported'), 52 fsWatchIsSupported: () => fs.isWatchSupported, 53 ); 54 }); 55 } 56 57 group('goldenFileComparator', () { 58 test('is initialized by test framework', () { 59 expect(goldenFileComparator, isNotNull); 60 expect(goldenFileComparator, isInstanceOf<LocalFileComparator>()); 61 final LocalFileComparator comparator = goldenFileComparator; 62 expect(comparator.basedir.path, contains('flutter_test')); 63 }); 64 }); 65 66 group('LocalFileComparator', () { 67 LocalFileComparator comparator; 68 69 setUp(() { 70 comparator = LocalFileComparator(fs.file(fix('/golden_test.dart')).uri, pathStyle: fs.path.style); 71 }); 72 73 test('calculates basedir correctly', () { 74 expect(comparator.basedir, fs.file(fix('/')).uri); 75 comparator = LocalFileComparator(fs.file(fix('/foo/bar/golden_test.dart')).uri, pathStyle: fs.path.style); 76 expect(comparator.basedir, fs.directory(fix('/foo/bar/')).uri); 77 }); 78 79 test('can be instantiated with uri that represents file in same folder', () { 80 comparator = LocalFileComparator(Uri.parse('foo_test.dart'), pathStyle: fs.path.style); 81 expect(comparator.basedir, Uri.parse('./')); 82 }); 83 84 group('compare', () { 85 Future<bool> doComparison([ String golden = 'golden.png' ]) { 86 final Uri uri = fs.file(fix(golden)).uri; 87 return comparator.compare( 88 Uint8List.fromList(_kExpectedBytes), 89 uri, 90 ); 91 } 92 93 group('succeeds', () { 94 test('when golden file is in same folder as test', () async { 95 fs.file(fix('/golden.png')).writeAsBytesSync(_kExpectedBytes); 96 final bool success = await doComparison(); 97 expect(success, isTrue); 98 }); 99 100 test('when golden file is in subfolder of test', () async { 101 fs.file(fix('/sub/foo.png')) 102 ..createSync(recursive: true) 103 ..writeAsBytesSync(_kExpectedBytes); 104 final bool success = await doComparison('sub/foo.png'); 105 expect(success, isTrue); 106 }); 107 108 group('when comparator instantiated with uri that represents file in same folder', () { 109 test('and golden file is in same folder as test', () async { 110 fs.file(fix('/foo/bar/golden.png')) 111 ..createSync(recursive: true) 112 ..writeAsBytesSync(_kExpectedBytes); 113 fs.currentDirectory = fix('/foo/bar'); 114 comparator = LocalFileComparator(Uri.parse('local_test.dart'), pathStyle: fs.path.style); 115 final bool success = await doComparison('golden.png'); 116 expect(success, isTrue); 117 }); 118 119 test('and golden file is in subfolder of test', () async { 120 fs.file(fix('/foo/bar/baz/golden.png')) 121 ..createSync(recursive: true) 122 ..writeAsBytesSync(_kExpectedBytes); 123 fs.currentDirectory = fix('/foo/bar'); 124 comparator = LocalFileComparator(Uri.parse('local_test.dart'), pathStyle: fs.path.style); 125 final bool success = await doComparison('baz/golden.png'); 126 expect(success, isTrue); 127 }); 128 }); 129 }); 130 131 group('fails', () { 132 test('when golden file does not exist', () async { 133 final Future<bool> comparison = doComparison(); 134 expect(comparison, throwsA(isInstanceOf<TestFailure>())); 135 }); 136 137 test('when golden bytes are leading subset of image bytes', () async { 138 fs.file(fix('/golden.png')).writeAsBytesSync(<int>[1, 2]); 139 expect(await doComparison(), isFalse); 140 }); 141 142 test('when golden bytes are leading superset of image bytes', () async { 143 fs.file(fix('/golden.png')).writeAsBytesSync(<int>[1, 2, 3, 4]); 144 expect(await doComparison(), isFalse); 145 }); 146 147 test('when golden bytes are trailing subset of image bytes', () async { 148 fs.file(fix('/golden.png')).writeAsBytesSync(<int>[2, 3]); 149 expect(await doComparison(), isFalse); 150 }); 151 152 test('when golden bytes are trailing superset of image bytes', () async { 153 fs.file(fix('/golden.png')).writeAsBytesSync(<int>[0, 1, 2, 3]); 154 expect(await doComparison(), isFalse); 155 }); 156 157 test('when golden bytes are disjoint from image bytes', () async { 158 fs.file(fix('/golden.png')).writeAsBytesSync(<int>[4, 5, 6]); 159 expect(await doComparison(), isFalse); 160 }); 161 162 test('when golden bytes are empty', () async { 163 fs.file(fix('/golden.png')).writeAsBytesSync(<int>[]); 164 expect(await doComparison(), isFalse); 165 }); 166 }); 167 }); 168 169 group('update', () { 170 test('updates existing file', () async { 171 fs.file(fix('/golden.png')).writeAsBytesSync(_kExpectedBytes); 172 const List<int> newBytes = <int>[11, 12, 13]; 173 await comparator.update(fs.file('golden.png').uri, Uint8List.fromList(newBytes)); 174 expect(fs.file(fix('/golden.png')).readAsBytesSync(), newBytes); 175 }); 176 177 test('creates non-existent file', () async { 178 expect(fs.file(fix('/foo.png')).existsSync(), isFalse); 179 const List<int> newBytes = <int>[11, 12, 13]; 180 await comparator.update(fs.file('foo.png').uri, Uint8List.fromList(newBytes)); 181 expect(fs.file(fix('/foo.png')).existsSync(), isTrue); 182 expect(fs.file(fix('/foo.png')).readAsBytesSync(), newBytes); 183 }); 184 }); 185 186 group('getTestUri', () { 187 test('updates file name with version number', () { 188 final Uri key = Uri.parse('foo.png'); 189 final Uri key1 = comparator.getTestUri(key, 1); 190 expect(key1, Uri.parse('foo.1.png')); 191 }); 192 test('does nothing for null version number', () { 193 final Uri key = Uri.parse('foo.png'); 194 final Uri keyNull = comparator.getTestUri(key, null); 195 expect(keyNull, Uri.parse('foo.png')); 196 }); 197 }); 198 }); 199} 200