context.dart 6.88 KB
Newer Older
1 2 3 4 5 6
// Copyright 2016 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';

7
import 'package:flutter_tools/src/artifacts.dart';
8
import 'package:flutter_tools/src/base/config.dart';
9
import 'package:flutter_tools/src/base/context.dart';
10
import 'package:flutter_tools/src/base/file_system.dart';
11
import 'package:flutter_tools/src/base/logger.dart';
12
import 'package:flutter_tools/src/base/os.dart';
13
import 'package:flutter_tools/src/base/platform.dart';
14
import 'package:flutter_tools/src/base/port_scanner.dart';
15
import 'package:flutter_tools/src/cache.dart';
16
import 'package:flutter_tools/src/devfs.dart';
17
import 'package:flutter_tools/src/device.dart';
18 19
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/ios/mac.dart';
20
import 'package:flutter_tools/src/ios/simulators.dart';
21
import 'package:flutter_tools/src/run_hot.dart';
22
import 'package:flutter_tools/src/usage.dart';
23
import 'package:mockito/mockito.dart';
24
import 'package:process/process.dart';
25 26
import 'package:test/test.dart';

27 28
import 'common.dart';

29 30 31
/// Return the test logger. This assumes that the current Logger is a BufferLogger.
BufferLogger get testLogger => context[Logger];

32 33 34
MockDeviceManager get testDeviceManager => context[DeviceManager];
MockDoctor get testDoctor => context[Doctor];

35 36
typedef dynamic Generator();

37 38 39
typedef void ContextInitializer(AppContext testContext);

void _defaultInitializeContext(AppContext testContext) {
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
  testContext
    ..putIfAbsent(DeviceManager, () => new MockDeviceManager())
    ..putIfAbsent(DevFSConfig, () => new DevFSConfig())
    ..putIfAbsent(Doctor, () => new MockDoctor())
    ..putIfAbsent(HotRunnerConfig, () => new HotRunnerConfig())
    ..putIfAbsent(Cache, () => new Cache())
    ..putIfAbsent(Artifacts, () => new CachedArtifacts())
    ..putIfAbsent(OperatingSystemUtils, () => new MockOperatingSystemUtils())
    ..putIfAbsent(PortScanner, () => new MockPortScanner())
    ..putIfAbsent(Xcode, () => new Xcode())
    ..putIfAbsent(IOSSimulatorUtils, () {
      final MockIOSSimulatorUtils mock = new MockIOSSimulatorUtils();
      when(mock.getAttachedDevices()).thenReturn(<IOSSimulator>[]);
      return mock;
    })
    ..putIfAbsent(SimControl, () => new MockSimControl())
    ..putIfAbsent(Usage, () => new MockUsage());
57 58
}

59 60
void testUsingContext(String description, dynamic testMethod(), {
  Timeout timeout,
61
  Map<Type, Generator> overrides: const <Type, Generator>{},
62
  ContextInitializer initializeContext: _defaultInitializeContext,
63
  bool skip, // should default to `false`, but https://github.com/dart-lang/test/issues/545 doesn't allow this
64
}) {
65
  test(description, () async {
66
    final AppContext testContext = new AppContext();
67

68
    // The context always starts with these value since others depend on them.
69 70 71 72 73 74
    testContext
      ..putIfAbsent(Platform, () => const LocalPlatform())
      ..putIfAbsent(FileSystem, () => const LocalFileSystem())
      ..putIfAbsent(ProcessManager, () => const LocalProcessManager())
      ..putIfAbsent(Logger, () => new BufferLogger())
      ..putIfAbsent(Config, () => new Config());
75

76 77 78 79 80
    // Apply the initializer after seeding the base value above.
    initializeContext(testContext);

    final String flutterRoot = getFlutterRoot();

81
    try {
82
      return await testContext.runInZone(() async {
83 84 85 86 87
        // Apply the overrides to the test context in the zone since their
        // instantiation may reference items already stored on the context.
        overrides.forEach((Type type, dynamic value()) {
          context.setVariable(type, value());
        });
88

89
        // Provide a sane default for the flutterRoot directory. Individual
90 91 92
        // tests can override this either in the test or during setup.
        Cache.flutterRoot ??= flutterRoot;

93 94 95 96
        return await testMethod();
      }, onError: (dynamic error, StackTrace stackTrace) {
        _printBufferedErrors(testContext);
        throw error;
97
      });
98
    } catch (error) {
99
      _printBufferedErrors(testContext);
100
      rethrow;
101 102
    }

103
  }, timeout: timeout, skip: skip);
104 105
}

106 107 108 109 110 111 112 113 114
void _printBufferedErrors(AppContext testContext) {
  if (testContext[Logger] is BufferLogger) {
    final BufferLogger bufferLogger = testContext[Logger];
    if (bufferLogger.errorText.isNotEmpty)
      print(bufferLogger.errorText);
    bufferLogger.clear();
  }
}

115 116 117 118 119 120 121 122 123 124
class MockPortScanner extends PortScanner {
  static int _nextAvailablePort = 12345;

  @override
  Future<bool> isPortAvailable(int port) async => true;

  @override
  Future<int> findAvailablePort() async => _nextAvailablePort++;
}

125
class MockDeviceManager implements DeviceManager {
126 127
  List<Device> devices = <Device>[];

128
  @override
129
  String specifiedDeviceId;
130 131

  @override
132 133
  bool get hasSpecifiedDeviceId => specifiedDeviceId != null;

134
  @override
Ian Hickson's avatar
Ian Hickson committed
135
  Future<List<Device>> getAllConnectedDevices() => new Future<List<Device>>.value(devices);
136

137
  @override
138 139
  Future<List<Device>> getDevicesById(String deviceId) async {
    return devices.where((Device device) => device.id == deviceId).toList();
140 141
  }

142
  @override
143 144 145 146
  Future<List<Device>> getDevices() async {
    if (specifiedDeviceId == null) {
      return getAllConnectedDevices();
    } else {
147
      return getDevicesById(specifiedDeviceId);
148 149 150 151 152 153 154
    }
  }

  void addDevice(Device device) => devices.add(device);
}

class MockDoctor extends Doctor {
155 156 157 158
  // True for testing.
  @override
  bool get canListAnything => true;

159
  // True for testing.
160
  @override
161
  bool get canLaunchAnything => true;
162
}
163 164 165

class MockSimControl extends Mock implements SimControl {
  MockSimControl() {
166
    when(this.getConnectedDevices()).thenReturn(<SimDevice>[]);
167 168 169
  }
}

170 171 172
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {
  @override
  List<File> whichAll(String execName) => <File>[];
173 174 175

  @override
  String get name => 'fake OS name and version';
176
}
177 178

class MockIOSSimulatorUtils extends Mock implements IOSSimulatorUtils {}
179 180 181 182 183

class MockUsage implements Usage {
  @override
  bool get isFirstRun => false;

184 185 186 187 188 189
  @override
  bool get suppressAnalytics => false;

  @override
  set suppressAnalytics(bool value) { }

190 191 192 193 194 195
  @override
  bool get enabled => true;

  @override
  set enabled(bool value) { }

196 197 198
  @override
  String get clientId => '00000000-0000-4000-0000-000000000000';

199 200 201 202 203 204
  @override
  void sendCommand(String command) { }

  @override
  void sendEvent(String category, String parameter) { }

205 206 207
  @override
  void sendTiming(String category, String variableName, Duration duration) { }

208 209 210 211 212 213 214 215 216 217 218
  @override
  UsageTimer startTimer(String event) => new _MockUsageTimer(event);

  @override
  void sendException(dynamic exception, StackTrace trace) { }

  @override
  Stream<Map<String, dynamic>> get onSend => null;

  @override
  Future<Null> ensureAnalyticsSent() => new Future<Null>.value();
219 220 221

  @override
  void printUsage() { }
222 223 224 225 226 227 228 229 230 231 232
}

class _MockUsageTimer implements UsageTimer {
  _MockUsageTimer(this.event);

  @override
  final String event;

  @override
  void finish() { }
}