goldens_test.dart 7.35 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
// 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);
  });

27 28 29 30 31 32 33 34 35 36
  /// 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);
  }

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  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(() {
72
      comparator = new LocalFileComparator(fs.file(fix('/golden_test.dart')).uri, pathStyle: fs.path.style);
73 74 75
    });

    test('calculates basedir correctly', () {
76 77 78
      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);
79 80
    });

81 82 83 84 85
    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('./'));
    });

86 87
    group('compare', () {
      Future<bool> doComparison([String golden = 'golden.png']) {
88
        final Uri uri = fs.file(fix(golden)).uri;
89 90 91 92 93 94 95 96
        return comparator.compare(
          new Uint8List.fromList(_kExpectedBytes),
          uri,
        );
      }

      group('succeeds', () {
        test('when golden file is in same folder as test', () async {
97
          fs.file(fix('/golden.png')).writeAsBytesSync(_kExpectedBytes);
98 99 100 101 102
          final bool success = await doComparison();
          expect(success, isTrue);
        });

        test('when golden file is in subfolder of test', () async {
103
          fs.file(fix('/sub/foo.png'))
104 105 106 107 108
            ..createSync(recursive: true)
            ..writeAsBytesSync(_kExpectedBytes);
          final bool success = await doComparison('sub/foo.png');
          expect(success, isTrue);
        });
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

        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);
          });
        });
131 132 133 134 135 136 137 138 139
      });

      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 {
140
          fs.file(fix('/golden.png')).writeAsBytesSync(<int>[1, 2]);
141 142 143 144
          expect(await doComparison(), isFalse);
        });

        test('when golden bytes are leading superset of image bytes', () async {
145
          fs.file(fix('/golden.png')).writeAsBytesSync(<int>[1, 2, 3, 4]);
146 147 148 149
          expect(await doComparison(), isFalse);
        });

        test('when golden bytes are trailing subset of image bytes', () async {
150
          fs.file(fix('/golden.png')).writeAsBytesSync(<int>[2, 3]);
151 152 153 154
          expect(await doComparison(), isFalse);
        });

        test('when golden bytes are trailing superset of image bytes', () async {
155
          fs.file(fix('/golden.png')).writeAsBytesSync(<int>[0, 1, 2, 3]);
156 157 158 159
          expect(await doComparison(), isFalse);
        });

        test('when golden bytes are disjoint from image bytes', () async {
160
          fs.file(fix('/golden.png')).writeAsBytesSync(<int>[4, 5, 6]);
161 162 163 164
          expect(await doComparison(), isFalse);
        });

        test('when golden bytes are empty', () async {
165
          fs.file(fix('/golden.png')).writeAsBytesSync(<int>[]);
166 167 168 169 170 171 172
          expect(await doComparison(), isFalse);
        });
      });
    });

    group('update', () {
      test('updates existing file', () async {
173
        fs.file(fix('/golden.png')).writeAsBytesSync(_kExpectedBytes);
174
        const List<int> newBytes = const <int>[11, 12, 13];
175 176
        await comparator.update(fs.file('golden.png').uri, new Uint8List.fromList(newBytes));
        expect(fs.file(fix('/golden.png')).readAsBytesSync(), newBytes);
177 178 179
      });

      test('creates non-existent file', () async {
180
        expect(fs.file(fix('/foo.png')).existsSync(), isFalse);
181
        const List<int> newBytes = const <int>[11, 12, 13];
182 183 184
        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);
185 186 187 188
      });
    });
  });
}