flutter_goldens_test.dart 8.28 KB
Newer Older
1 2 3 4
// 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.

5
import 'dart:io' as io;
6 7 8 9 10 11 12 13 14 15 16
import 'dart:typed_data';

import 'package:file/file.dart';
import 'package:file/memory.dart';
import 'package:flutter_goldens/flutter_goldens.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:platform/platform.dart';
import 'package:process/process.dart';

const String _kFlutterRoot = '/flutter';
17 18 19 20
const String _kRepositoryRoot = '$_kFlutterRoot/bin/cache/pkg/goldens';
const String _kVersionFile = '$_kFlutterRoot/bin/internal/goldens.version';
const String _kGoldensVersion = '123456abcdef';

21 22 23 24 25
void main() {
  MemoryFileSystem fs;
  FakePlatform platform;
  MockProcessManager process;

26
  setUp(() {
27
    fs = MemoryFileSystem();
28
    platform = FakePlatform(environment: <String, String>{'FLUTTER_ROOT': _kFlutterRoot});
29
    process = MockProcessManager();
30 31 32 33
    fs.directory(_kFlutterRoot).createSync(recursive: true);
    fs.directory(_kRepositoryRoot).createSync(recursive: true);
    fs.file(_kVersionFile).createSync(recursive: true);
    fs.file(_kVersionFile).writeAsStringSync(_kGoldensVersion);
34 35
  });

36
  group('GoldensClient', () {
37
    GoldensRepositoryClient goldens;
38 39

    setUp(() {
40
      goldens = GoldensRepositoryClient(
41
        fs: fs,
42
        process: process,
43
        platform: platform,
44 45 46
      );
    });

47 48 49 50 51 52 53 54 55 56 57 58 59
    group('prepare', () {
      test('performs minimal work if versions match', () async {
        when(process.run(any, workingDirectory: anyNamed('workingDirectory')))
            .thenAnswer((_) => Future<io.ProcessResult>.value(io.ProcessResult(123, 0, _kGoldensVersion, '')));
        await goldens.prepare();

        // Verify that we only spawned `git rev-parse HEAD`
        final VerificationResult verifyProcessRun =
            verify(process.run(captureAny, workingDirectory: captureAnyNamed('workingDirectory')));
        verifyProcessRun.called(1);
        expect(verifyProcessRun.captured.first, <String>['git', 'rev-parse', 'HEAD']);
        expect(verifyProcessRun.captured.last, _kRepositoryRoot);
      });
60 61 62
    });
  });

63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
  group('SkiaGoldClient', () {
    SkiaGoldClient goldens;

    setUp(() {
      goldens = SkiaGoldClient(
        fs: fs,
        process: process,
        platform: platform,
      );
    });

    group('auth', () {
      test('performs minimal work if already authorized', () async {
        final Directory workDirectory = fs.directory('/workDirectory')..createSync(recursive: true);
        fs.file('/workDirectory/temp/auth_opt.json')..createSync(recursive: true);
        when(process.run(any)).thenAnswer((_) => Future<io.ProcessResult>.value(io.ProcessResult(123, 0, '', '')));
        await goldens.auth(workDirectory);

        // Verify that we spawned no process calls
        final VerificationResult verifyProcessRun =
          verifyNever(process.run(captureAny, workingDirectory: captureAnyNamed('workingDirectory')));
        expect(verifyProcessRun.callCount, 0);
      });
    });
  });

89
  group('FlutterGoldenFileComparator', () {
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
    test('calculates the basedir correctly', () async {
      final MockSkiaGoldClient goldens = MockSkiaGoldClient();
      final MockLocalFileComparator defaultComparator = MockLocalFileComparator();
      final Directory flutterRoot = fs.directory('/foo')..createSync(recursive: true);
      final Directory goldensRoot = flutterRoot.childDirectory('bar')..createSync(recursive: true);
      when(goldens.fs).thenReturn(fs);
      when(goldens.flutterRoot).thenReturn(flutterRoot);
      when(goldens.comparisonRoot).thenReturn(goldensRoot);
      when(defaultComparator.basedir).thenReturn(flutterRoot.childDirectory('baz').uri);
      final Directory basedir = FlutterGoldenFileComparator.getBaseDirectory(goldens, defaultComparator);
      expect(basedir.uri, fs.directory('/foo/bar/baz').uri);
    });
  });

  group('FlutterGoldensRepositoryFileComparator', () {
105
    MemoryFileSystem fs;
106
    FlutterGoldensRepositoryFileComparator comparator;
107 108

    setUp(() {
109
      fs = MemoryFileSystem();
110 111 112 113
      platform = FakePlatform(
        operatingSystem: 'linux',
        environment: <String, String>{'FLUTTER_ROOT': _kFlutterRoot},
      );
114 115
      final Directory flutterRoot = fs.directory('/path/to/flutter')..createSync(recursive: true);
      final Directory goldensRoot = flutterRoot.childDirectory('bin/cache/goldens')..createSync(recursive: true);
116
      final Directory testDirectory = goldensRoot.childDirectory('test/foo/bar')..createSync(recursive: true);
117 118 119 120 121
      comparator = FlutterGoldensRepositoryFileComparator(
        testDirectory.uri,
        fs: fs,
        platform: platform,
      );
122 123 124
    });

    group('compare', () {
125 126 127 128 129 130 131
      test('throws if golden file is not found', () async {
        try {
          await comparator.compare(Uint8List.fromList(<int>[1, 2, 3]), Uri.parse('test.png'));
          fail('TestFailure expected but not thrown');
        } on TestFailure catch (error) {
          expect(error.message, contains('Could not be compared against non-existent file'));
        }
132 133
      });

134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
      test('returns false if golden bytes do not match', () async {
        final File goldenFile = fs.file('/path/to/flutter/bin/cache/goldens/test/foo/bar/test.png')
          ..createSync(recursive: true);
        goldenFile.writeAsBytesSync(<int>[4, 5, 6], flush: true);
        final bool result = await comparator.compare(Uint8List.fromList(<int>[1, 2, 3]), Uri.parse('test.png'));
        expect(result, isFalse);
      });

      test('returns true if golden bytes match', () async {
        final File goldenFile = fs.file('/path/to/flutter/bin/cache/goldens/test/foo/bar/test.png')
          ..createSync(recursive: true);
        goldenFile.writeAsBytesSync(<int>[1, 2, 3], flush: true);
        final bool result = await comparator.compare(Uint8List.fromList(<int>[1, 2, 3]), Uri.parse('test.png'));
        expect(result, isTrue);
      });
149 150 151 152 153 154
    });

    group('update', () {
      test('creates golden file if it does not already exist', () async {
        final File goldenFile = fs.file('/path/to/flutter/bin/cache/goldens/test/foo/bar/test.png');
        expect(goldenFile.existsSync(), isFalse);
155
        await comparator.update(Uri.parse('test.png'), Uint8List.fromList(<int>[1, 2, 3]));
156 157 158 159 160 161 162 163
        expect(goldenFile.existsSync(), isTrue);
        expect(goldenFile.readAsBytesSync(), <int>[1, 2, 3]);
      });

      test('overwrites golden bytes if golden file already exist', () async {
        final File goldenFile = fs.file('/path/to/flutter/bin/cache/goldens/test/foo/bar/test.png')
          ..createSync(recursive: true);
        goldenFile.writeAsBytesSync(<int>[4, 5, 6], flush: true);
164
        await comparator.update(Uri.parse('test.png'), Uint8List.fromList(<int>[1, 2, 3]));
165 166 167
        expect(goldenFile.readAsBytesSync(), <int>[1, 2, 3]);
      });
    });
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201

    group('getTestUri', () {
      test('incorporates version number', () {
        final Uri key = comparator.getTestUri(Uri.parse('foo.png'), 1);
        expect(key, Uri.parse('foo.1.png'));
      });
      test('ignores null version number', () {
        final Uri key = comparator.getTestUri(Uri.parse('foo.png'), null);
        expect(key, Uri.parse('foo.png'));
      });
    });
  });

  group('FlutterSkiaGoldFileComparator', () {
    FlutterSkiaGoldFileComparator comparator;

    setUp(() {
      final Directory flutterRoot = fs.directory('/path/to/flutter')..createSync(recursive: true);
      final Directory goldensRoot = flutterRoot.childDirectory('bin/cache/goldens')..createSync(recursive: true);
      final Directory testDirectory = goldensRoot.childDirectory('test/foo/bar')..createSync(recursive: true);
      comparator = FlutterSkiaGoldFileComparator(
        testDirectory.uri,
        MockSkiaGoldClient(),
        fs: fs,
        platform: platform,
      );
    });

    group('getTestUri', () {
      test('ignores version number', () {
        final Uri key = comparator.getTestUri(Uri.parse('foo.png'), 1);
        expect(key, Uri.parse('foo.png'));
      });
    });
202 203 204 205
  });
}

class MockProcessManager extends Mock implements ProcessManager {}
206 207
class MockGoldensRepositoryClient extends Mock implements GoldensRepositoryClient {}
class MockSkiaGoldClient extends Mock implements SkiaGoldClient {}
208
class MockLocalFileComparator extends Mock implements LocalFileComparator {}