context.dart 6.46 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/cache.dart';
15
import 'package:flutter_tools/src/devfs.dart';
16
import 'package:flutter_tools/src/device.dart';
17 18
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/ios/mac.dart';
19
import 'package:flutter_tools/src/ios/simulators.dart';
20
import 'package:flutter_tools/src/run_hot.dart';
21
import 'package:flutter_tools/src/usage.dart';
22
import 'package:mockito/mockito.dart';
23
import 'package:process/process.dart';
24 25
import 'package:test/test.dart';

26 27
import 'common.dart';

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

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

34 35
typedef dynamic Generator();

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
typedef void ContextInitializer(AppContext testContext);

void _defaultInitializeContext(AppContext testContext) {
  testContext.putIfAbsent(DeviceManager, () => new MockDeviceManager());
  testContext.putIfAbsent(DevFSConfig, () => new DevFSConfig());
  testContext.putIfAbsent(Doctor, () => new MockDoctor());
  testContext.putIfAbsent(HotRunnerConfig, () => new HotRunnerConfig());
  testContext.putIfAbsent(Cache, () => new Cache());
  testContext.putIfAbsent(Artifacts, () => new CachedArtifacts());
  testContext.putIfAbsent(OperatingSystemUtils, () => new MockOperatingSystemUtils());
  testContext.putIfAbsent(Xcode, () => new Xcode());
  testContext.putIfAbsent(IOSSimulatorUtils, () {
    final MockIOSSimulatorUtils mock = new MockIOSSimulatorUtils();
    when(mock.getAttachedDevices()).thenReturn(<IOSSimulator>[]);
    return mock;
  });
  testContext.putIfAbsent(SimControl, () => new MockSimControl());
  testContext.putIfAbsent(Usage, () => new MockUsage());
}

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

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

72 73 74 75 76
    // Apply the initializer after seeding the base value above.
    initializeContext(testContext);

    final String flutterRoot = getFlutterRoot();

77
    try {
78
      return await testContext.runInZone(() async {
79 80 81 82 83
        // 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());
        });
84 85 86
        // Provide a sane default for the flutterRoot directory. Individual
        // tests can override this.
        Cache.flutterRoot = flutterRoot;
87 88 89 90
        return await testMethod();
      }, onError: (dynamic error, StackTrace stackTrace) {
        _printBufferedErrors(testContext);
        throw error;
91
      });
92
    } catch (error) {
93
      _printBufferedErrors(testContext);
94
      rethrow;
95 96
    }

97
  }, timeout: timeout, skip: skip);
98 99
}

100 101 102 103 104 105 106 107 108
void _printBufferedErrors(AppContext testContext) {
  if (testContext[Logger] is BufferLogger) {
    final BufferLogger bufferLogger = testContext[Logger];
    if (bufferLogger.errorText.isNotEmpty)
      print(bufferLogger.errorText);
    bufferLogger.clear();
  }
}

109
class MockDeviceManager implements DeviceManager {
110 111
  List<Device> devices = <Device>[];

112
  @override
113
  String specifiedDeviceId;
114 115

  @override
116 117
  bool get hasSpecifiedDeviceId => specifiedDeviceId != null;

118
  @override
Ian Hickson's avatar
Ian Hickson committed
119
  Future<List<Device>> getAllConnectedDevices() => new Future<List<Device>>.value(devices);
120

121
  @override
122 123
  Future<List<Device>> getDevicesById(String deviceId) async {
    return devices.where((Device device) => device.id == deviceId).toList();
124 125
  }

126
  @override
127 128 129 130
  Future<List<Device>> getDevices() async {
    if (specifiedDeviceId == null) {
      return getAllConnectedDevices();
    } else {
131
      return getDevicesById(specifiedDeviceId);
132 133 134 135 136 137 138
    }
  }

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

class MockDoctor extends Doctor {
139 140 141 142
  // True for testing.
  @override
  bool get canListAnything => true;

143
  // True for testing.
144
  @override
145
  bool get canLaunchAnything => true;
146
}
147 148 149

class MockSimControl extends Mock implements SimControl {
  MockSimControl() {
150
    when(this.getConnectedDevices()).thenReturn(<SimDevice>[]);
151 152 153
  }
}

154 155 156 157
class MockOperatingSystemUtils extends Mock implements OperatingSystemUtils {
  @override
  List<File> whichAll(String execName) => <File>[];
}
158 159

class MockIOSSimulatorUtils extends Mock implements IOSSimulatorUtils {}
160 161 162 163 164

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

165 166 167 168 169 170
  @override
  bool get suppressAnalytics => false;

  @override
  set suppressAnalytics(bool value) { }

171 172 173 174 175 176 177 178 179 180 181 182
  @override
  bool get enabled => true;

  @override
  set enabled(bool value) { }

  @override
  void sendCommand(String command) { }

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

183 184 185
  @override
  void sendTiming(String category, String variableName, Duration duration) { }

186 187 188 189 190 191 192 193 194 195 196
  @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();
197 198 199

  @override
  void printUsage() { }
200 201 202 203 204 205 206 207 208 209 210
}

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

  @override
  final String event;

  @override
  void finish() { }
}