Commit d745e208 authored by Ian Hickson's avatar Ian Hickson

Even more types

parent 229253f4
......@@ -500,10 +500,11 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
return fling(scrollVelocity.clamp(-kMaxFlingVelocity, kMaxFlingVelocity)).then(_endScroll);
}
void _endScroll([_]) {
Null _endScroll([Null _]) {
_numberOfInProgressScrolls -= 1;
if (_numberOfInProgressScrolls == 0)
dispatchOnScrollEnd();
return null;
}
/// Calls the dispatchOnScrollEnd callback.
......
......@@ -64,7 +64,7 @@ class FlutterDriver {
// Attempts to resume the isolate, but does not crash if it fails because
// the isolate is already resumed. There could be a race with other tools,
// such as a debugger, any of which could have resumed the isolate.
Future<Null> resumeLeniently() {
Future<dynamic> resumeLeniently() {
_log.trace('Attempting to resume isolate');
return isolate.resume().catchError((dynamic e) {
const int vmMustBePausedCode = 101;
......@@ -87,7 +87,7 @@ class FlutterDriver {
_log.trace('Isolate is paused at start.');
// Waits for a signal from the VM service that the extension is registered
Future<Null> waitForServiceExtension() {
Future<String> waitForServiceExtension() {
return isolate.onExtensionAdded.firstWhere((String extension) {
return extension == _kFlutterExtensionMethod;
});
......@@ -96,8 +96,8 @@ class FlutterDriver {
// If the isolate is paused at the start, e.g. via the --start-paused
// option, then the VM service extension is not registered yet. Wait for
// it to be registered.
Future<Null> whenResumed = resumeLeniently();
Future<Null> whenServiceExtensionReady = Future.any(<Future<dynamic>>[
Future<dynamic> whenResumed = resumeLeniently();
Future<dynamic> whenServiceExtensionReady = Future.any/*dynamic*/(<Future<dynamic>>[
waitForServiceExtension(),
// We will never receive the extension event if the user does not
// register it. If that happens time out.
......@@ -180,7 +180,7 @@ class FlutterDriver {
}
Future<Null> tap(ObjectRef ref) async {
return await _sendCommand(new Tap(ref)).then((_) => null);
return await _sendCommand(new Tap(ref)).then((Map<String, dynamic> _) => null);
}
/// Tell the driver to perform a scrolling action.
......@@ -197,7 +197,7 @@ class FlutterDriver {
/// The move events are generated at a given [frequency] in Hz (or events per
/// second). It defaults to 60Hz.
Future<Null> scroll(ObjectRef ref, double dx, double dy, Duration duration, {int frequency: 60}) async {
return await _sendCommand(new Scroll(ref, dx, dy, duration, frequency)).then((_) => null);
return await _sendCommand(new Scroll(ref, dx, dy, duration, frequency)).then((Map<String, dynamic> _) => null);
}
Future<String> getText(ObjectRef ref) async {
......
......@@ -16,13 +16,13 @@ import 'package:vm_service_client/vm_service_client.dart';
void main() {
group('FlutterDriver.connect', () {
List<LogRecord> log;
StreamSubscription logSub;
StreamSubscription<LogRecord> logSub;
MockVMServiceClient mockClient;
MockVM mockVM;
MockIsolate mockIsolate;
void expectLogContains(String message) {
expect(log.map((r) => '$r'), anyElement(contains(message)));
expect(log.map((LogRecord r) => '$r'), anyElement(contains(message)));
}
setUp(() {
......@@ -35,8 +35,8 @@ void main() {
when(mockVM.isolates).thenReturn([mockIsolate]);
when(mockIsolate.loadRunnable()).thenReturn(mockIsolate);
when(mockIsolate.invokeExtension(any, any))
.thenReturn(new Future.value({'status': 'ok'}));
vmServiceConnectFunction = (_) => new Future.value(mockClient);
.thenReturn(new Future<Map<String, dynamic>>.value(<String, String>{'status': 'ok'}));
vmServiceConnectFunction = (String url) => new Future<VMServiceClient>.value(mockClient);
});
tearDown(() async {
......@@ -46,9 +46,8 @@ void main() {
test('connects to isolate paused at start', () async {
when(mockIsolate.pauseEvent).thenReturn(new MockVMPauseStartEvent());
when(mockIsolate.resume()).thenReturn(new Future.value());
when(mockIsolate.onExtensionAdded)
.thenReturn(new Stream.fromIterable(['ext.flutter_driver']));
when(mockIsolate.resume()).thenReturn(new Future<Null>.value());
when(mockIsolate.onExtensionAdded).thenReturn(new Stream<String>.fromIterable(<String>['ext.flutter_driver']));
FlutterDriver driver = await FlutterDriver.connect();
expect(driver, isNotNull);
......@@ -57,7 +56,7 @@ void main() {
test('connects to isolate paused mid-flight', () async {
when(mockIsolate.pauseEvent).thenReturn(new MockVMPauseBreakpointEvent());
when(mockIsolate.resume()).thenReturn(new Future.value());
when(mockIsolate.resume()).thenReturn(new Future<Null>.value());
FlutterDriver driver = await FlutterDriver.connect();
expect(driver, isNotNull);
......@@ -73,7 +72,7 @@ void main() {
when(mockIsolate.resume()).thenAnswer((_) {
// This needs to be wrapped in a closure to not be considered uncaught
// by package:test
return new Future.error(new rpc.RpcException(101, ''));
return new Future<Null>.error(new rpc.RpcException(101, ''));
});
FlutterDriver driver = await FlutterDriver.connect();
......@@ -101,7 +100,7 @@ void main() {
});
test('checks the health of the driver extension', () async {
when(mockIsolate.invokeExtension(any, any)).thenReturn(new Future.value({
when(mockIsolate.invokeExtension(any, any)).thenReturn(new Future<Map<String, dynamic>>.value(<String, dynamic>{
'status': 'ok',
}));
Health result = await driver.checkHealth();
......@@ -109,7 +108,7 @@ void main() {
});
test('closes connection', () async {
when(mockClient.close()).thenReturn(new Future.value());
when(mockClient.close()).thenReturn(new Future<Null>.value());
await driver.close();
});
......@@ -127,7 +126,7 @@ void main() {
'keyValueString': 'foo',
'keyValueType': 'String'
});
return new Future.value({
return new Future<Map<String, dynamic>>.value(<String, dynamic>{
'objectReferenceKey': '123',
});
});
......@@ -149,11 +148,11 @@ void main() {
test('sends the tap command', () async {
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
expect(i.positionalArguments[1], {
expect(i.positionalArguments[1], <String, dynamic>{
'command': 'tap',
'targetRef': '123'
});
return new Future.value();
return new Future<Map<String, dynamic>>.value();
});
await driver.tap(new ObjectRef('123'));
});
......@@ -171,11 +170,11 @@ void main() {
test('sends the getText command', () async {
when(mockIsolate.invokeExtension(any, any)).thenAnswer((Invocation i) {
expect(i.positionalArguments[1], {
expect(i.positionalArguments[1], <String, dynamic>{
'command': 'get_text',
'targetRef': '123'
});
return new Future.value({
return new Future<Map<String, dynamic>>.value({
'text': 'hello'
});
});
......@@ -188,7 +187,7 @@ void main() {
test('waits for a condition', () {
expect(
driver.waitFor(() {
return new Future.delayed(
return new Future<int>.delayed(
new Duration(milliseconds: 50),
() => 123
);
......@@ -228,7 +227,7 @@ void main() {
equals(2),
timeout: new Duration(milliseconds: 10),
pauseBetweenRetries: new Duration(milliseconds: 2)
).catchError((err, stack) {
).catchError((dynamic err, dynamic stack) {
timedOut = true;
});
......
......@@ -62,7 +62,7 @@ void main() {
() async => retryCount++,
new Duration(milliseconds: 30),
new Duration(milliseconds: 10),
predicate: (value) => value == 2
predicate: (int value) => value == 2
),
completion(2)
);
......@@ -85,7 +85,7 @@ void main() {
},
new Duration(milliseconds: 7),
new Duration(milliseconds: 2)
).catchError((error, stackTrace) {
).catchError((dynamic error, dynamic stackTrace) {
timedOut = true;
lastError = error;
lastStackTrace = stackTrace;
......
......@@ -16,14 +16,13 @@ analyzer:
strong_mode_static_type_error: ignore
strong_mode_down_cast_composite: ignore
type_argument_not_matching_bounds: ignore
argument_type_not_assignable: ignore
# we allow having TODOs in the code
todo: ignore
linter:
rules:
- avoid_empty_else
- always_declare_return_types
# - always_specify_types # still a lot of work to do before enabling this one
- always_specify_types
# - annotate_overrides # still a lot of work to do before enabling this one
# - avoid_as # https://github.com/dart-lang/linter/issues/195
- avoid_init_to_null
......
......@@ -10,17 +10,17 @@ import 'src/flx.dart' as flx;
/// Assembles a Flutter .flx file from a pre-existing manifest descriptor and a
/// pre-compiled snapshot.
Future<int> assembleFlx({
Map manifestDescriptor: const {},
Map<String, dynamic> manifestDescriptor: const <String, dynamic>{},
File snapshotFile: null,
String assetBasePath: flx.defaultAssetBasePath,
String outputPath: flx.defaultFlxOutputPath,
String privateKeyPath: flx.defaultPrivateKeyPath
}) async {
return flx.assemble(
manifestDescriptor: manifestDescriptor,
snapshotFile: snapshotFile,
assetBasePath: assetBasePath,
outputPath: outputPath,
privateKeyPath: privateKeyPath
manifestDescriptor: manifestDescriptor,
snapshotFile: snapshotFile,
assetBasePath: assetBasePath,
outputPath: outputPath,
privateKeyPath: privateKeyPath
);
}
......@@ -82,7 +82,7 @@ class Adb {
Socket socket;
bool isFirstNotification = true;
controller = new StreamController(
controller = new StreamController<List<AdbDevice>>(
onListen: () async {
socket = await Socket.connect(InternetAddress.LOOPBACK_IP_V4, adbServerPort);
printTrace('--> host:track-devices');
......@@ -121,7 +121,7 @@ class Adb {
return controller.stream;
}
Future _populateDeviceNames(List<AdbDevice> devices) async {
Future<Null> _populateDeviceNames(List<AdbDevice> devices) async {
for (AdbDevice device in devices) {
if (device.modelID == null) {
// If we don't have a name of a device in our cache, call `device -l` to populate it.
......@@ -135,7 +135,7 @@ class Adb {
}
}
Future _populateDeviceCache() async {
Future<Null> _populateDeviceCache() async {
List<AdbDevice> devices = await listDevices();
for (AdbDevice device in devices)
_idToNameCache[device.id] = device.modelID;
......
......@@ -180,7 +180,7 @@ class AndroidDevice extends Device {
return true;
}
Future _forwardObservatoryPort(int port) async {
Future<Null> _forwardObservatoryPort(int port) async {
bool portWasZero = port == 0;
try {
......@@ -485,8 +485,8 @@ class _AdbLogReader extends DeviceLogReader {
new StreamController<String>.broadcast();
Process _process;
StreamSubscription _stdoutSubscription;
StreamSubscription _stderrSubscription;
StreamSubscription<String> _stdoutSubscription;
StreamSubscription<String> _stderrSubscription;
Stream<String> get lines => _linesStreamController.stream;
......@@ -494,9 +494,9 @@ class _AdbLogReader extends DeviceLogReader {
bool get isReading => _process != null;
Future get finished => _process != null ? _process.exitCode : new Future.value(0);
Future<int> get finished => _process != null ? _process.exitCode : new Future<int>.value(0);
Future start() async {
Future<Null> start() async {
if (_process != null)
throw new StateError('_AdbLogReader must be stopped before it can be started.');
......@@ -516,7 +516,7 @@ class _AdbLogReader extends DeviceLogReader {
_process.exitCode.then(_onExit);
}
Future stop() async {
Future<Null> stop() async {
if (_process == null)
throw new StateError('_AdbLogReader must be started before it can be stopped.');
......@@ -604,7 +604,7 @@ class _AndroidDevicePortForwarder extends DevicePortForwarder {
return hostPort;
}
Future unforward(ForwardedPort forwardedPort) async {
Future<Null> unforward(ForwardedPort forwardedPort) async {
runCheckedSync(device.adbCommandForDevice(
<String>['forward', '--remove', 'tcp:${forwardedPort.hostPort}']
));
......
......@@ -235,7 +235,7 @@ class ArtifactStore {
/// Download a file from the given url and write it to the cache.
/// If [unzip] is true, treat the url as a zip file, and unzip it to the
/// directory given.
static Future _downloadFileToCache(Uri url, FileSystemEntity cachedFile, bool unzip) async {
static Future<Null> _downloadFileToCache(Uri url, FileSystemEntity cachedFile, bool unzip) async {
if (!cachedFile.parent.existsSync())
cachedFile.parent.createSync(recursive: true);
......
......@@ -46,7 +46,7 @@ void restoreFileSystem() {
}
/// Uses in-memory replacments for `dart:io` functionality. Useful in tests.
void useInMemoryFileSystem({ cwd: '/', ExitFunction exitFunction }) {
void useInMemoryFileSystem({ String cwd: '/', ExitFunction exitFunction }) {
MemoryFileSystem memFs = new MemoryFileSystem();
fs = memFs;
syncFs = new SyncMemoryFileSystem(backedBy: memFs.storage);
......
......@@ -4,7 +4,7 @@
import 'dart:io';
final _terminal = new _AnsiTerminal();
final _AnsiTerminal _terminal = new _AnsiTerminal();
abstract class Logger {
bool get isVerbose => false;
......
......@@ -57,9 +57,9 @@ Future<int> runCommandAndStreamOutput(List<String> cmd, {
return await process.exitCode;
}
Future runAndKill(List<String> cmd, Duration timeout) {
Future<Null> runAndKill(List<String> cmd, Duration timeout) {
Future<Process> proc = runDetached(cmd);
return new Future.delayed(timeout, () async {
return new Future<Null>.delayed(timeout, () async {
printTrace('Intentionally killing ${cmd[0]}');
Process.killPid((await proc).pid);
});
......
......@@ -223,7 +223,7 @@ class AnalyzeCommand extends FlutterCommand {
// determine what all the various .packages files depend on
PackageDependencyTracker dependencies = new PackageDependencyTracker();
for (Directory directory in pubSpecDirectories.map((path) => new Directory(path))) {
for (Directory directory in pubSpecDirectories.map((String path) => new Directory(path))) {
String pubSpecYamlPath = path.join(directory.path, 'pubspec.yaml');
File pubSpecYamlFile = new File(pubSpecYamlPath);
if (pubSpecYamlFile.existsSync()) {
......@@ -242,8 +242,8 @@ class AnalyzeCommand extends FlutterCommand {
dotPackages
.readAsStringSync()
.split('\n')
.where((line) => !line.startsWith(new RegExp(r'^ *#')))
.forEach((line) {
.where((String line) => !line.startsWith(new RegExp(r'^ *#')))
.forEach((String line) {
int colon = line.indexOf(':');
if (colon > 0)
dependencies.add(line.substring(0, colon), path.normalize(path.absolute(directory.path, path.fromUri(line.substring(colon+1)))), dotPackagesPath);
......@@ -634,7 +634,7 @@ class AnalysisServer {
int _id = 0;
Future start() async {
Future<Null> start() async {
String snapshot = path.join(sdk, 'bin/snapshots/analysis_server.dart.snapshot');
List<String> args = <String>[snapshot, '--sdk', sdk];
......@@ -687,12 +687,12 @@ class AnalysisServer {
dynamic response = JSON.decode(line);
if (response is Map) {
if (response is Map<dynamic, dynamic>) {
if (response['event'] != null) {
String event = response['event'];
dynamic params = response['params'];
if (params is Map) {
if (params is Map<dynamic, dynamic>) {
if (event == 'server.status')
_handleStatus(response['params']);
else if (event == 'analysis.errors')
......@@ -725,7 +725,7 @@ class AnalysisServer {
_errorsController.add(new FileAnalysisErrors(file, errors));
}
Future dispose() async => _process?.kill();
Future<bool> dispose() async => _process?.kill();
}
class FileAnalysisErrors {
......
......@@ -135,7 +135,7 @@ All done! In order to run your application, type:
printStatus('Creating project ${path.basename(projectName)}:');
Map templateContext = <String, dynamic>{
Map<String, dynamic> templateContext = <String, dynamic>{
'projectName': projectName,
'androidIdentifier': _createAndroidIdentifier(projectName),
'iosIdentifier': _createUTIIdentifier(projectName),
......
......@@ -53,7 +53,7 @@ class DaemonCommand extends FlutterCommand {
return JSON.decode(line);
});
Daemon daemon = new Daemon(commandStream, (Map command) {
Daemon daemon = new Daemon(commandStream, (Map<String, dynamic> command) {
stdout.writeln('[${JSON.encode(command, toEncodable: _jsonEncodeObject)}]');
}, daemonCommand: this, notifyingLogger: notifyingLogger);
......@@ -73,7 +73,7 @@ typedef void DispatchComand(Map<String, dynamic> command);
typedef Future<dynamic> CommandHandler(dynamic args);
class Daemon {
Daemon(Stream<Map> commandStream, this.sendCommand, {
Daemon(Stream<Map<String, dynamic>> commandStream, this.sendCommand, {
this.daemonCommand,
this.notifyingLogger
}) {
......@@ -84,7 +84,7 @@ class Daemon {
// Start listening.
commandStream.listen(
(Map request) => _handleRequest(request),
(Map<String, dynamic> request) => _handleRequest(request),
onDone: () => _onExitCompleter.complete(0)
);
}
......@@ -106,7 +106,7 @@ class Daemon {
Future<int> get onExit => _onExitCompleter.future;
void _handleRequest(Map request) {
void _handleRequest(Map<String, dynamic> request) {
// {id, method, params}
// [id] is an opaque type to us.
......@@ -133,7 +133,7 @@ class Daemon {
}
}
void _send(Map map) => sendCommand(map);
void _send(Map<String, dynamic> map) => sendCommand(map);
void shutdown() {
_domainMap.values.forEach((Domain domain) => domain.dispose());
......@@ -147,7 +147,7 @@ abstract class Domain {
final Daemon daemon;
final String name;
final Map<String, CommandHandler> _handlers = {};
final Map<String, CommandHandler> _handlers = <String, CommandHandler>{};
void registerHandler(String name, CommandHandler handler) {
_handlers[name] = handler;
......@@ -158,18 +158,18 @@ abstract class Domain {
String toString() => name;
void handleCommand(String command, dynamic id, dynamic args) {
new Future.sync(() {
new Future<dynamic>.sync(() {
if (_handlers.containsKey(command))
return _handlers[command](args);
throw 'command not understood: $name.$command';
}).then((result) {
}).then((dynamic result) {
if (result == null) {
_send({'id': id});
_send(<String, dynamic>{'id': id});
} else {
_send({'id': id, 'result': _toJsonable(result)});
_send(<String, dynamic>{'id': id, 'result': _toJsonable(result)});
}
}).catchError((error, trace) {
_send({'id': id, 'error': _toJsonable(error)});
}).catchError((dynamic error, dynamic trace) {
_send(<String, dynamic>{'id': id, 'error': _toJsonable(error)});
});
}
......@@ -180,7 +180,7 @@ abstract class Domain {
_send(map);
}
void _send(Map map) => daemon._send(map);
void _send(Map<String, dynamic> map) => daemon._send(map);
void dispose() { }
}
......@@ -212,12 +212,12 @@ class DaemonDomain extends Domain {
StreamSubscription<LogMessage> _subscription;
Future<String> version(dynamic args) {
return new Future.value(protocolVersion);
return new Future<String>.value(protocolVersion);
}
Future shutdown(dynamic args) {
Future<Null> shutdown(dynamic args) {
Timer.run(() => daemon.shutdown());
return new Future.value();
return new Future<Null>.value();
}
void dispose() {
......@@ -352,23 +352,23 @@ class DeviceDomain extends Domain {
List<Device> devices = _discoverers.expand((PollingDeviceDiscovery discoverer) {
return discoverer.devices;
}).toList();
return new Future.value(devices);
return new Future<List<Device>>.value(devices);
}
/// Enable device events.
Future enable(dynamic args) {
Future<Null> enable(dynamic args) {
for (PollingDeviceDiscovery discoverer in _discoverers) {
discoverer.startPolling();
}
return new Future.value();
return new Future<Null>.value();
}
/// Disable device events.
Future disable(dynamic args) {
Future<Null> disable(dynamic args) {
for (PollingDeviceDiscovery discoverer in _discoverers) {
discoverer.stopPolling();
}
return new Future.value();
return new Future<Null>.value();
}
void dispose() {
......@@ -398,7 +398,7 @@ String _enumToString(dynamic enumValue) {
}
dynamic _toJsonable(dynamic obj) {
if (obj is String || obj is int || obj is bool || obj is Map || obj is List || obj == null)
if (obj is String || obj is int || obj is bool || obj is Map<dynamic, dynamic> || obj is List<dynamic> || obj == null)
return obj;
if (obj is Device)
return obj;
......
......@@ -106,7 +106,7 @@ class DriveCommand extends RunCommandBase {
try {
return await testRunner([testFile])
.then((_) => 0)
.catchError((error, stackTrace) {
.catchError((dynamic error, dynamic stackTrace) {
printError('CAUGHT EXCEPTION: $error\n$stackTrace');
return 1;
});
......@@ -182,9 +182,9 @@ Future<Device> findTargetDevice() async {
// we look for an Android device. If there's one, we use that. Otherwise,
// we launch a new iOS Simulator.
Device reusableDevice = devices.firstWhere(
(d) => d.isLocalEmulator,
(Device d) => d.isLocalEmulator,
orElse: () {
return devices.firstWhere((d) => d is AndroidDevice,
return devices.firstWhere((Device d) => d is AndroidDevice,
orElse: () => null);
}
);
......@@ -210,7 +210,7 @@ Future<Device> findTargetDevice() async {
return null;
} else if (devices.length > 1) {
printStatus('Found multiple connected devices:');
printStatus(devices.map((d) => ' - ${d.name}\n').join(''));
printStatus(devices.map((Device d) => ' - ${d.name}\n').join(''));
}
printStatus('Using device ${devices.first.name}.');
return devices.first;
......
......@@ -38,7 +38,7 @@ class LogsCommand extends FlutterCommand {
if (!logReader.isReading)
await logReader.start();
StreamSubscription subscription = logReader.lines.listen(printStatus);
StreamSubscription<String> subscription = logReader.lines.listen(printStatus);
// Wait for the log reader to be finished.
int result = await logReader.finished;
......
......@@ -185,7 +185,7 @@ Future<int> startApp(
}
// Allow any stop commands from above to start work.
await new Future.delayed(Duration.ZERO);
await new Future<Duration>.delayed(Duration.ZERO);
if (install) {
printTrace('Running install command.');
......@@ -234,7 +234,7 @@ Future<int> startApp(
///
/// This does not fail if we're unable to connect, and times out after the given
/// [timeout].
Future delayUntilObservatoryAvailable(String host, int port, {
Future<Null> delayUntilObservatoryAvailable(String host, int port, {
Duration timeout: const Duration(seconds: 10)
}) async {
Stopwatch stopwatch = new Stopwatch()..start();
......@@ -246,10 +246,10 @@ Future delayUntilObservatoryAvailable(String host, int port, {
try {
WebSocket ws = await WebSocket.connect(url);
printTrace('Connected to the observatory port.');
ws.close().catchError((error) => null);
ws.close().catchError((dynamic error) => null);
return;
} catch (error) {
await new Future.delayed(new Duration(milliseconds: 250));
await new Future<Null>.delayed(new Duration(milliseconds: 250));
}
}
......
......@@ -22,7 +22,7 @@ class RunMojoCommand extends FlutterCommand {
final String description = 'Run a Flutter app in mojo (from github.com/domokit/mojo).';
final bool _hideCommand;
RunMojoCommand({ hideCommand: false }) : _hideCommand = hideCommand {
RunMojoCommand({ bool hideCommand: false }) : _hideCommand = hideCommand {
argParser.addFlag('android', negatable: false, help: 'Run on an Android device');
argParser.addFlag('checked', negatable: false, help: 'Run Flutter in checked mode');
argParser.addFlag('mojo-debug', negatable: false, help: 'Use Debug build of mojo');
......@@ -64,7 +64,7 @@ class RunMojoCommand extends FlutterCommand {
}
String _getMojoShellPath() {
final mojoBuildType = argResults['mojo-debug'] ? 'Debug' : 'Release';
final String mojoBuildType = argResults['mojo-debug'] ? 'Debug' : 'Release';
return _makePathAbsolute(path.join(argResults['mojo-path'], 'out', mojoBuildType, 'mojo_shell'));
}
......
......@@ -41,7 +41,7 @@ class TraceCommand extends FlutterCommand {
// Setting neither flags or both flags means do both commands and wait
// duration seconds in between.
device.startTracing(androidApp);
await new Future.delayed(
await new Future<Null>.delayed(
new Duration(seconds: int.parse(argResults['duration'])),
() => _stopTracing(device, androidApp)
);
......@@ -53,7 +53,7 @@ class TraceCommand extends FlutterCommand {
return 0;
}
Future _stopTracing(AndroidDevice android, AndroidApk androidApp) async {
Future<Null> _stopTracing(AndroidDevice android, AndroidApk androidApp) async {
String tracePath = await android.stopTracing(androidApp, outPath: argResults['out']);
if (tracePath == null) {
printError('No trace file saved.');
......
......@@ -24,7 +24,7 @@ Future<int> _runPub(Directory directory, { bool upgrade: false }) async {
}
class UpdatePackagesCommand extends FlutterCommand {
UpdatePackagesCommand({ hideCommand: false }) : _hideCommand = hideCommand {
UpdatePackagesCommand({ bool hideCommand: false }) : _hideCommand = hideCommand {
argParser.addFlag(
'upgrade',
help: 'Run "pub upgrade" rather than "pub get".',
......
......@@ -225,7 +225,7 @@ abstract class DevicePortForwarder {
Future<int> forward(int devicePort, {int hostPort: null});
/// Stops forwarding [forwardedPort].
Future unforward(ForwardedPort forwardedPort);
Future<Null> unforward(ForwardedPort forwardedPort);
}
/// Read the log for a particular device. Subclasses must implement `hashCode`
......@@ -240,16 +240,16 @@ abstract class DeviceLogReader {
Stream<String> get lines;
/// Start reading logs from the device.
Future start();
Future<Null> start();
/// Actively reading lines from the log?
bool get isReading;
/// Actively stop reading logs from the device.
Future stop();
Future<Null> stop();
/// Completes when the log is finished.
Future get finished;
Future<int> get finished;
int get hashCode;
bool operator ==(dynamic other);
......
......@@ -38,7 +38,7 @@ class _Asset {
const String _kMaterialIconsKey = 'fonts/MaterialIcons-Regular.ttf';
List _getMaterialFonts() {
List<Map<String, dynamic>> _getMaterialFonts() {
return [{
'family': 'MaterialIcons',
'fonts': [{
......@@ -57,7 +57,7 @@ List<_Asset> _getMaterialAssets() {
];
}
Map<_Asset, List<_Asset>> _parseAssets(Map manifestDescriptor, String assetBase) {
Map<_Asset, List<_Asset>> _parseAssets(Map<String, dynamic> manifestDescriptor, String assetBase) {
Map<_Asset, List<_Asset>> result = <_Asset, List<_Asset>>{};
if (manifestDescriptor == null)
return result;
......@@ -112,8 +112,8 @@ ZipEntry _createAssetManifest(Map<_Asset, List<_Asset>> assets) {
return new ZipEntry.fromString('AssetManifest.json', JSON.encode(json));
}
ZipEntry _createFontManifest(Map manifestDescriptor, List additionalFonts) {
List fonts = [];
ZipEntry _createFontManifest(Map<String, dynamic> manifestDescriptor, List<Map<String, dynamic>> additionalFonts) {
List<Map<String, dynamic>> fonts = <Map<String, dynamic>>[];
if (additionalFonts != null)
fonts.addAll(additionalFonts);
if (manifestDescriptor != null && manifestDescriptor.containsKey('fonts'))
......@@ -167,7 +167,7 @@ Future<int> build(
String workingDirPath: defaultWorkingDirPath,
bool precompiledSnapshot: false
}) async {
Map manifestDescriptor = _loadManifest(manifestPath);
Map<String, dynamic> manifestDescriptor = _loadManifest(manifestPath);
String assetBasePath = path.dirname(path.absolute(manifestPath));
File snapshotFile;
......@@ -197,7 +197,7 @@ Future<int> build(
}
Future<int> assemble({
Map manifestDescriptor: const {},
Map<String, dynamic> manifestDescriptor: const <String, dynamic>{},
File snapshotFile,
String assetBasePath: defaultAssetBasePath,
String outputPath: defaultFlxOutputPath,
......@@ -244,7 +244,7 @@ Future<int> assemble({
if (fontManifest != null)
zipBuilder.addEntry(fontManifest);
AsymmetricKeyPair keyPair = keyPairFromPrivateKeyFileSync(privateKeyPath);
AsymmetricKeyPair<PublicKey, PrivateKey> keyPair = keyPairFromPrivateKeyFileSync(privateKeyPath);
printTrace('KeyPair from $privateKeyPath: $keyPair.');
if (keyPair != null) {
......
......@@ -253,8 +253,8 @@ class _IOSDeviceLogReader extends DeviceLogReader {
new StreamController<String>.broadcast();
Process _process;
StreamSubscription _stdoutSubscription;
StreamSubscription _stderrSubscription;
StreamSubscription<String> _stdoutSubscription;
StreamSubscription<String> _stderrSubscription;
Stream<String> get lines => _linesStreamController.stream;
......@@ -262,13 +262,15 @@ class _IOSDeviceLogReader extends DeviceLogReader {
bool get isReading => _process != null;
Future get finished =>
_process != null ? _process.exitCode : new Future.value(0);
Future<int> get finished {
return _process != null ? _process.exitCode : new Future<int>.value(0);
}
Future start() async {
Future<Null> start() async {
if (_process != null) {
throw new StateError(
'_IOSDeviceLogReader must be stopped before it can be started.');
'_IOSDeviceLogReader must be stopped before it can be started.'
);
}
_process = await runCommand(<String>[device.loggerPath]);
_stdoutSubscription =
......@@ -280,10 +282,11 @@ class _IOSDeviceLogReader extends DeviceLogReader {
_process.exitCode.then(_onExit);
}
Future stop() async {
Future<Null> stop() async {
if (_process == null) {
throw new StateError(
'_IOSDeviceLogReader must be started before it can be stopped.');
'_IOSDeviceLogReader must be started before it can be stopped.'
);
}
_stdoutSubscription?.cancel();
_stdoutSubscription = null;
......@@ -341,7 +344,7 @@ class _IOSDevicePortForwarder extends DevicePortForwarder {
return hostPort;
}
Future unforward(ForwardedPort forwardedPort) async {
Future<Null> unforward(ForwardedPort forwardedPort) async {
// TODO(chinmaygarde): Implement.
}
}
......@@ -181,7 +181,7 @@ String _getIOSEngineRevision(ApplicationPackage app) {
}
}
Future _addServicesToBundle(Directory bundle) async {
Future<Null> _addServicesToBundle(Directory bundle) async {
List<Map<String, String>> services = [];
printTrace("Trying to resolve native pub services.");
......@@ -200,7 +200,7 @@ Future _addServicesToBundle(Directory bundle) async {
_copyServiceDefinitionsManifest(services, manifestFile);
}
Future _copyServiceFrameworks(List<Map<String, String>> services, Directory frameworksDirectory) async {
Future<Null> _copyServiceFrameworks(List<Map<String, String>> services, Directory frameworksDirectory) async {
printTrace("Copying service frameworks to '${path.absolute(frameworksDirectory.path)}'.");
frameworksDirectory.createSync(recursive: true);
for (Map<String, String> service in services) {
......
......@@ -79,7 +79,7 @@ class SimControl {
connected = await _isAnyConnected();
if (!connected) {
printStatus('Still waiting for iOS Simulator to boot...');
await new Future.delayed(new Duration(seconds: 1));
await new Future<Null>.delayed(new Duration(seconds: 1));
}
attempted++;
}
......@@ -106,7 +106,7 @@ class SimControl {
// Delete any old test devices
getDevices()
.where((d) => d.name == _kFlutterTestDevice)
.where((SimDevice d) => d.name == _kFlutterTestDevice)
.forEach(_deleteDevice);
// Create new device
......@@ -114,15 +114,15 @@ class SimControl {
printTrace(args.join(' '));
runCheckedSync(args);
return getDevices().firstWhere((d) => d.name == _kFlutterTestDevice);
return getDevices().firstWhere((SimDevice d) => d.name == _kFlutterTestDevice);
}
String _findSuitableDeviceType() {
List<Map<String, dynamic>> allTypes = _list(SimControlListSection.devicetypes);
List<Map<String, dynamic>> usableTypes = allTypes
.where((info) => info['name'].startsWith('iPhone'))
.where((Map<String, dynamic> info) => info['name'].startsWith('iPhone'))
.toList()
..sort((r1, r2) => -compareIphoneVersions(r1['identifier'], r2['identifier']));
..sort((Map<String, dynamic> r1, Map<String, dynamic> r2) => -compareIphoneVersions(r1['identifier'], r2['identifier']));
if (usableTypes.isEmpty) {
printError(
......@@ -139,9 +139,9 @@ class SimControl {
String _findSuitableRuntime() {
List<Map<String, dynamic>> allRuntimes = _list(SimControlListSection.runtimes);
List<Map<String, dynamic>> usableRuntimes = allRuntimes
.where((info) => info['name'].startsWith('iOS'))
.where((Map<String, dynamic> info) => info['name'].startsWith('iOS'))
.toList()
..sort((r1, r2) => -compareIosVersions(r1['version'], r2['version']));
..sort((Map<String, dynamic> r1, Map<String, dynamic> r2) => -compareIosVersions(r1['version'], r2['version']));
if (usableRuntimes.isEmpty) {
printError(
......@@ -206,7 +206,7 @@ class SimControl {
Map<String, dynamic> devicesSection = _list(SimControlListSection.devices);
for (String deviceCategory in devicesSection.keys) {
List<dynamic> devicesData = devicesSection[deviceCategory];
List<Map<String, String>> devicesData = devicesSection[deviceCategory];
for (Map<String, String> data in devicesData) {
devices.add(new SimDevice(deviceCategory, data));
......@@ -232,15 +232,12 @@ class SimControl {
if (_trackDevicesControler == null) {
Timer timer;
Set<String> deviceIds = new Set<String>();
_trackDevicesControler = new StreamController.broadcast(
_trackDevicesControler = new StreamController<List<SimDevice>>.broadcast(
onListen: () {
timer = new Timer.periodic(new Duration(seconds: 4), (Timer timer) {
List<SimDevice> devices = getConnectedDevices();
if (_updateDeviceIds(devices, deviceIds)) {
if (_updateDeviceIds(devices, deviceIds))
_trackDevicesControler.add(devices);
}
});
}, onCancel: () {
timer?.cancel();
......@@ -290,13 +287,14 @@ class SimControl {
/// Enumerates all data sections of `xcrun simctl list --json` command.
class SimControlListSection {
static const devices = const SimControlListSection._('devices');
static const devicetypes = const SimControlListSection._('devicetypes');
static const runtimes = const SimControlListSection._('runtimes');
static const pairs = const SimControlListSection._('pairs');
const SimControlListSection._(this.name);
final String name;
const SimControlListSection._(this.name);
static const SimControlListSection devices = const SimControlListSection._('devices');
static const SimControlListSection devicetypes = const SimControlListSection._('devicetypes');
static const SimControlListSection runtimes = const SimControlListSection._('runtimes');
static const SimControlListSection pairs = const SimControlListSection._('pairs');
}
class SimDevice {
......@@ -580,12 +578,12 @@ class _IOSSimulatorLogReader extends DeviceLogReader {
// We log from two logs: the device and the system log.
Process _deviceProcess;
StreamSubscription _deviceStdoutSubscription;
StreamSubscription _deviceStderrSubscription;
StreamSubscription<String> _deviceStdoutSubscription;
StreamSubscription<String> _deviceStderrSubscription;
Process _systemProcess;
StreamSubscription _systemStdoutSubscription;
StreamSubscription _systemStderrSubscription;
StreamSubscription<String> _systemStdoutSubscription;
StreamSubscription<String> _systemStderrSubscription;
Stream<String> get lines => _linesStreamController.stream;
......@@ -593,13 +591,15 @@ class _IOSSimulatorLogReader extends DeviceLogReader {
bool get isReading => (_deviceProcess != null) && (_systemProcess != null);
Future get finished =>
(_deviceProcess != null) ? _deviceProcess.exitCode : new Future.value(0);
Future<int> get finished {
return (_deviceProcess != null) ? _deviceProcess.exitCode : new Future<int>.value(0);
}
Future start() async {
Future<Null> start() async {
if (isReading) {
throw new StateError(
'_IOSSimulatorLogReader must be stopped before it can be started.');
'_IOSSimulatorLogReader must be stopped before it can be started.'
);
}
// TODO(johnmccutchan): Add a ProcessSet abstraction that handles running
......@@ -630,10 +630,11 @@ class _IOSSimulatorLogReader extends DeviceLogReader {
_systemProcess.exitCode.then(_onSystemExit);
}
Future stop() async {
Future<Null> stop() async {
if (!isReading) {
throw new StateError(
'_IOSSimulatorLogReader must be started before it can be stopped.');
'_IOSSimulatorLogReader must be started before it can be stopped.'
);
}
if (_deviceProcess != null) {
await _deviceProcess.kill();
......@@ -774,7 +775,7 @@ int compareIphoneVersions(String id1, String id2) {
return v1.compareTo(v2);
// Sorted in the least preferred first order.
const qualifiers = const <String>['-Plus', '', 's-Plus', 's'];
const List<String> qualifiers = const <String>['-Plus', '', 's-Plus', 's'];
int q1 = qualifiers.indexOf(m1[2]);
int q2 = qualifiers.indexOf(m2[2]);
......@@ -801,7 +802,7 @@ class _IOSSimulatorDevicePortForwarder extends DevicePortForwarder {
return hostPort;
}
Future unforward(ForwardedPort forwardedPort) async {
Future<Null> unforward(ForwardedPort forwardedPort) async {
_ports.remove(forwardedPort);
}
}
......@@ -35,11 +35,11 @@ abstract class FlutterCommand extends Command {
List<BuildConfiguration> get buildConfigurations => runner.buildConfigurations;
Future downloadToolchain() async {
Future<Null> downloadToolchain() async {
toolchain ??= await Toolchain.forConfigs(buildConfigurations);
}
Future downloadApplicationPackages() async {
Future<Null> downloadApplicationPackages() async {
applicationPackages ??= await ApplicationPackageStore.forConfigs(buildConfigurations);
}
......@@ -127,7 +127,7 @@ abstract class FlutterCommand extends Command {
void addTargetOption() {
argParser.addOption('target',
abbr: 't',
callback: (val) => _targetSpecified = true,
callback: (dynamic val) => _targetSpecified = true,
defaultsTo: flx.defaultMainPath,
help: 'Target app path / main entry-point file.');
_targetOptionSpecified = true;
......
......@@ -19,7 +19,7 @@ class ServiceProtocolDiscovery {
}
final DeviceLogReader _logReader;
Completer _completer = new Completer();
Completer<int> _completer = new Completer<int>();
/// The [Future] returned by this function will complete when the next
/// service protocol port is found.
......@@ -32,21 +32,20 @@ class ServiceProtocolDiscovery {
if (line.startsWith('Observatory listening on http://')) {
try {
RegExp portExp = new RegExp(r"\d+.\d+.\d+.\d+:(\d+)");
var port = portExp.firstMatch(line).group(1);
String port = portExp.firstMatch(line).group(1);
portNumber = int.parse(port);
} catch (_) {
// Ignore errors.
}
}
if (portNumber != 0) {
if (portNumber != 0)
_located(portNumber);
}
}
void _located(int port) {
assert(_completer != null);
assert(!_completer.isCompleted);
_completer.complete(port);
_completer = new Completer();
_completer = new Completer<int>();
}
}
......@@ -25,7 +25,7 @@ dynamic _loadYamlFile(String path) {
/// Loads all services specified in `flutter.yaml`. Parses each service config file,
/// storing metadata in [services] and the list of jar files in [jars].
Future parseServiceConfigs(
Future<Null> parseServiceConfigs(
List<Map<String, String>> services, { List<File> jars }
) async {
if (!ArtifactStore.isPackageRootValid) {
......
......@@ -55,11 +55,11 @@ Future<Process> _startProcess(String mainPath, { String packageRoot }) {
}
class FlutterPlatform extends PlatformPlugin {
StreamChannel loadChannel(String mainPath, TestPlatform platform) {
StreamChannel<String> loadChannel(String mainPath, TestPlatform platform) {
return StreamChannelCompleter.fromFuture(_startTest(mainPath));
}
Future<StreamChannel> _startTest(String mainPath) async {
Future<StreamChannel<String>> _startTest(String mainPath) async {
_ServerInfo info = await _startServer();
Directory tempDir = Directory.systemTemp.createTempSync(
'dart_test_listener');
......@@ -108,19 +108,19 @@ void main() {
try {
WebSocket socket = await info.socket;
StreamChannel channel = new StreamChannel(socket.map(JSON.decode), socket);
StreamChannel<String> channel = new StreamChannel<String>(socket.map(JSON.decode), socket);
return channel.transformStream(
new StreamTransformer.fromHandlers(
handleDone: (sink) {
new StreamTransformer<String, String>.fromHandlers(
handleDone: (EventSink<String> sink) {
finalize();
sink.close();
}
)
).transformSink(new StreamSinkTransformer.fromHandlers(
handleData: (data, StreamSink sink) {
).transformSink(new StreamSinkTransformer<String, String>.fromHandlers(
handleData: (String data, StreamSink<String> sink) {
sink.add(JSON.encode(data));
},
handleDone: (sink) {
handleDone: (EventSink<String> sink) {
finalize();
sink.close();
}
......
......@@ -36,7 +36,7 @@ void main() {
server = new AnalysisServer(dartSdkPath, <String>[tempDir.path]);
int errorCount = 0;
Future onDone = server.onAnalyzing.where((bool analyzing) => analyzing == false).first;
Future<bool> onDone = server.onAnalyzing.where((bool analyzing) => analyzing == false).first;
server.onErrors.listen((FileAnalysisErrors errors) => errorCount += errors.errors.length);
await server.start();
......@@ -55,7 +55,7 @@ void main() {
server = new AnalysisServer(dartSdkPath, <String>[tempDir.path]);
int errorCount = 0;
Future onDone = server.onAnalyzing.where((bool analyzing) => analyzing == false).first;
Future<bool> onDone = server.onAnalyzing.where((bool analyzing) => analyzing == false).first;
server.onErrors.listen((FileAnalysisErrors errors) => errorCount += errors.errors.length);
await server.start();
......
......@@ -45,15 +45,15 @@ void main() {
});
_testUsingContext('daemon.version', () async {
StreamController<Map<String, dynamic>> commands = new StreamController();
StreamController<Map<String, dynamic>> responses = new StreamController();
StreamController<Map<String, dynamic>> commands = new StreamController<Map<String, dynamic>>();
StreamController<Map<String, dynamic>> responses = new StreamController<Map<String, dynamic>>();
daemon = new Daemon(
commands.stream,
(Map<String, dynamic> result) => responses.add(result),
notifyingLogger: notifyingLogger
);
commands.add({'id': 0, 'method': 'daemon.version'});
Map response = await responses.stream.where(_notEvent).first;
commands.add(<String, dynamic>{'id': 0, 'method': 'daemon.version'});
Map<String, dynamic> response = await responses.stream.where(_notEvent).first;
expect(response['id'], 0);
expect(response['result'], isNotEmpty);
expect(response['result'] is String, true);
......@@ -61,8 +61,8 @@ void main() {
_testUsingContext('daemon.logMessage', () {
return appContext.runInZone(() async {
StreamController<Map<String, dynamic>> commands = new StreamController();
StreamController<Map<String, dynamic>> responses = new StreamController();
StreamController<Map<String, dynamic>> commands = new StreamController<Map<String, dynamic>>();
StreamController<Map<String, dynamic>> responses = new StreamController<Map<String, dynamic>>();
daemon = new Daemon(
commands.stream,
(Map<String, dynamic> result) => responses.add(result),
......@@ -81,8 +81,8 @@ void main() {
});
_testUsingContext('daemon.shutdown', () async {
StreamController<Map<String, dynamic>> commands = new StreamController();
StreamController<Map<String, dynamic>> responses = new StreamController();
StreamController<Map<String, dynamic>> commands = new StreamController<Map<String, dynamic>>();
StreamController<Map<String, dynamic>> responses = new StreamController<Map<String, dynamic>>();
daemon = new Daemon(
commands.stream,
(Map<String, dynamic> result) => responses.add(result),
......@@ -98,8 +98,8 @@ void main() {
DaemonCommand command = new DaemonCommand();
applyMocksToCommand(command);
StreamController<Map<String, dynamic>> commands = new StreamController();
StreamController<Map<String, dynamic>> responses = new StreamController();
StreamController<Map<String, dynamic>> commands = new StreamController<Map<String, dynamic>>();
StreamController<Map<String, dynamic>> responses = new StreamController<Map<String, dynamic>>();
daemon = new Daemon(
commands.stream,
(Map<String, dynamic> result) => responses.add(result),
......@@ -108,21 +108,21 @@ void main() {
);
commands.add(<String, dynamic>{ 'id': 0, 'method': 'app.stop' });
Map response = await responses.stream.where(_notEvent).first;
Map<String, dynamic> response = await responses.stream.where(_notEvent).first;
expect(response['id'], 0);
expect(response['error'], contains('deviceId is required'));
});
_testUsingContext('device.getDevices', () async {
StreamController<Map<String, dynamic>> commands = new StreamController();
StreamController<Map<String, dynamic>> responses = new StreamController();
StreamController<Map<String, dynamic>> commands = new StreamController<Map<String, dynamic>>();
StreamController<Map<String, dynamic>> responses = new StreamController<Map<String, dynamic>>();
daemon = new Daemon(
commands.stream,
(Map<String, dynamic> result) => responses.add(result),
notifyingLogger: notifyingLogger
);
commands.add({'id': 0, 'method': 'device.getDevices'});
Map response = await responses.stream.where(_notEvent).first;
Map<String, dynamic> response = await responses.stream.where(_notEvent).first;
expect(response['id'], 0);
expect(response['result'], isList);
});
......
......@@ -16,7 +16,7 @@ void main() {
ServiceProtocolDiscovery discoverer =
new ServiceProtocolDiscovery(logReader);
// Get next port future.
Future nextPort = discoverer.nextPort();
Future<int> nextPort = discoverer.nextPort();
expect(nextPort, isNotNull);
// Inject some lines.
logReader.addLine('HELLO WORLD');
......
......@@ -72,11 +72,11 @@ class MockDeviceManager implements DeviceManager {
String specifiedDeviceId;
bool get hasSpecifiedDeviceId => specifiedDeviceId != null;
Future<List<Device>> getAllConnectedDevices() => new Future.value(devices);
Future<List<Device>> getAllConnectedDevices() => new Future<List<Device>>.value(devices);
Future<Device> getDeviceById(String deviceId) {
Device device = devices.firstWhere((Device device) => device.id == deviceId, orElse: () => null);
return new Future.value(device);
return new Future<Device>.value(device);
}
Future<List<Device>> getDevices() async {
......
......@@ -52,7 +52,7 @@ class MockDeviceLogReader extends DeviceLogReader {
final StreamController<String> _linesStreamController =
new StreamController<String>.broadcast();
final Completer _finishedCompleter = new Completer();
final Completer<int> _finishedCompleter = new Completer<int>();
Stream<String> get lines => _linesStreamController.stream;
......@@ -62,21 +62,20 @@ class MockDeviceLogReader extends DeviceLogReader {
bool _started = false;
Future start() {
Future<Null> start() async {
assert(!_started);
_started = true;
return new Future.value(this);
}
bool get isReading => _started;
Future stop() {
Future<Null> stop() {
assert(_started);
_started = false;
return new Future.value(this);
return new Future<Null>.value();
}
Future get finished => _finishedCompleter.future;
Future<int> get finished => _finishedCompleter.future;
}
void applyMocksToCommand(FlutterCommand command) {
......
......@@ -18,7 +18,7 @@ void main() {
StopCommand command = new StopCommand();
applyMocksToCommand(command);
MockAndroidDevice device = new MockAndroidDevice();
when(device.stopApp(any)).thenReturn(new Future.value(true));
when(device.stopApp(any)).thenReturn(new Future<bool>.value(true));
testDeviceManager.addDevice(device);
return createTestCommandRunner(command).run(['stop']).then((int code) {
expect(code, equals(0));
......@@ -29,7 +29,7 @@ void main() {
StopCommand command = new StopCommand();
applyMocksToCommand(command);
MockIOSDevice device = new MockIOSDevice();
when(device.stopApp(any)).thenReturn(new Future.value(true));
when(device.stopApp(any)).thenReturn(new Future<bool>.value(true));
testDeviceManager.addDevice(device);
return createTestCommandRunner(command).run(['stop']).then((int code) {
......
......@@ -72,14 +72,14 @@ class Bundle {
this.path,
this.manifest,
List<int> contentBytes,
AsymmetricKeyPair keyPair
AsymmetricKeyPair<PublicKey, PrivateKey> keyPair
}) : _contentBytes = contentBytes {
assert(path != null);
assert(manifest != null);
assert(_contentBytes != null);
manifestBytes = serializeManifest(manifest, keyPair?.publicKey, _contentBytes);
signatureBytes = signManifest(manifestBytes, keyPair?.privateKey);
_openContentStream = () => new Stream.fromIterable(<List<int>>[_contentBytes]);
_openContentStream = () => new Stream<List<int>>.fromIterable(<List<int>>[_contentBytes]);
}
final String path;
......
......@@ -12,7 +12,7 @@ import 'package:bignum/bignum.dart';
import 'package:crypto/crypto.dart';
import 'package:pointycastle/pointycastle.dart';
export 'package:pointycastle/pointycastle.dart' show AsymmetricKeyPair;
export 'package:pointycastle/pointycastle.dart' show AsymmetricKeyPair, PublicKey, PrivateKey;
// The ECDSA algorithm parameters we're using. These match the parameters used
// by the Flutter updater package.
......@@ -50,7 +50,7 @@ class CipherParameters {
SecureRandom _random;
void _initRandom(Uint8List key, Uint8List iv) {
KeyParameter keyParam = new KeyParameter(key);
ParametersWithIV params = new ParametersWithIV(keyParam, iv);
ParametersWithIV<KeyParameter> params = new ParametersWithIV<KeyParameter>(keyParam, iv);
_random = new SecureRandom('AES/CTR/AUTO-SEED-PRNG')
..seed(params);
}
......@@ -65,7 +65,7 @@ final CipherParameters _params = CipherParameters._init();
// Returns a serialized manifest, with the public key and hash of the content
// included.
Uint8List serializeManifest(Map manifestDescriptor, ECPublicKey publicKey, Uint8List zipBytes) {
Uint8List serializeManifest(Map<String, dynamic> manifestDescriptor, ECPublicKey publicKey, Uint8List zipBytes) {
if (manifestDescriptor == null)
return null;
final List<String> kSavedKeys = <String>[
......@@ -73,8 +73,8 @@ Uint8List serializeManifest(Map manifestDescriptor, ECPublicKey publicKey, Uint8
'version',
'update-url'
];
Map outputManifest = new Map();
manifestDescriptor.forEach((key, value) {
Map<String, dynamic> outputManifest = new Map<String, dynamic>();
manifestDescriptor.forEach((String key, dynamic value) {
if (kSavedKeys.contains(key))
outputManifest[key] = value;
});
......@@ -97,8 +97,8 @@ Uint8List signManifest(Uint8List manifestBytes, ECPrivateKey privateKey) {
if (manifestBytes == null || privateKey == null)
return new Uint8List(0);
Signer signer = new Signer(_params.signerAlgorithm);
PrivateKeyParameter params = new PrivateKeyParameter(privateKey);
signer.init(true, new ParametersWithRandom(params, _params.random));
PrivateKeyParameter<PrivateKey> params = new PrivateKeyParameter<PrivateKey>(privateKey);
signer.init(true, new ParametersWithRandom<PrivateKeyParameter<PrivateKey>>(params, _params.random));
ECSignature signature = signer.generateSignature(manifestBytes);
ASN1Sequence asn1 = new ASN1Sequence()
..add(new ASN1Integer(signature.r))
......@@ -115,10 +115,10 @@ bool verifyManifestSignature(Map<String, dynamic> manifest,
List<int> keyBytes = BASE64.decode(manifest['key']);
ECPoint q = _params.domain.curve.decodePoint(keyBytes);
ECPublicKey publicKey = new ECPublicKey(q, _params.domain);
PublicKey publicKey = new ECPublicKey(q, _params.domain);
Signer signer = new Signer(_params.signerAlgorithm);
signer.init(false, new PublicKeyParameter(publicKey));
signer.init(false, new PublicKeyParameter<PublicKey>(publicKey));
return signer.verifySignature(manifestBytes, signature);
}
......@@ -166,24 +166,24 @@ ECSignature _asn1ParseSignature(Uint8List signature) {
}
}
ECPublicKey _publicKeyFromPrivateKey(ECPrivateKey privateKey) {
PublicKey _publicKeyFromPrivateKey(ECPrivateKey privateKey) {
ECPoint Q = privateKey.parameters.G * privateKey.d;
return new ECPublicKey(Q, privateKey.parameters);
}
AsymmetricKeyPair keyPairFromPrivateKeyFileSync(String privateKeyPath) {
AsymmetricKeyPair<PublicKey, PrivateKey> keyPairFromPrivateKeyFileSync(String privateKeyPath) {
File file = new File(privateKeyPath);
if (!file.existsSync())
return null;
return keyPairFromPrivateKeyBytes(file.readAsBytesSync());
}
AsymmetricKeyPair keyPairFromPrivateKeyBytes(List<int> privateKeyBytes) {
AsymmetricKeyPair<PublicKey, PrivateKey> keyPairFromPrivateKeyBytes(List<int> privateKeyBytes) {
ECPrivateKey privateKey = _asn1ParsePrivateKey(
_params.domain, new Uint8List.fromList(privateKeyBytes));
if (privateKey == null)
return null;
ECPublicKey publicKey = _publicKeyFromPrivateKey(privateKey);
return new AsymmetricKeyPair(publicKey, privateKey);
PublicKey publicKey = _publicKeyFromPrivateKey(privateKey);
return new AsymmetricKeyPair<PublicKey, PrivateKey>(publicKey, privateKey);
}
......@@ -8,7 +8,7 @@ import 'package:flx/bundle.dart';
import 'package:flx/signing.dart';
import 'package:test/test.dart';
Future main() async {
Future<Null> main() async {
// The following constant was generated via the openssl shell commands:
// openssl ecparam -genkey -name prime256v1 -out privatekey.pem
// openssl ec -in privatekey.pem -outform DER | base64
......@@ -28,9 +28,10 @@ Future main() async {
Directory tempDir = await Directory.systemTemp.createTempSync('bundle_test');
String bundlePath = tempDir.path + '/bundle.flx';
AsymmetricKeyPair keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER);
AsymmetricKeyPair<PublicKey, PrivateKey> keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER);
Map<String, dynamic> manifest = JSON.decode(UTF8.decode(
serializeManifest(kManifest, keyPair.publicKey, kTestBytes)));
serializeManifest(kManifest, keyPair.publicKey, kTestBytes)
));
test('verifyContent works', () async {
Bundle bundle = new Bundle.fromContent(
......
......@@ -8,7 +8,7 @@ import 'package:crypto/crypto.dart';
import 'package:flx/signing.dart';
import 'package:test/test.dart';
Future main() async {
Future<Null> main() async {
// The following constant was generated via the openssl shell commands:
// openssl ecparam -genkey -name prime256v1 -out privatekey.pem
// openssl ec -in privatekey.pem -outform DER | base64
......@@ -42,18 +42,21 @@ Future main() async {
keyGenerator.init(keyGeneratorParams);
test('can read openssl key pair', () {
AsymmetricKeyPair keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER);
AsymmetricKeyPair<PublicKey, PrivateKey> keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER);
expect(keyPair != null, equals(true));
expect(keyPair.privateKey.d.intValue(), equals(kPrivateKeyD));
expect(keyPair.publicKey.Q.x.toBigInteger().intValue(), equals(kPublicKeyQx));
expect(keyPair.publicKey.Q.y.toBigInteger().intValue(), equals(kPublicKeyQy));
ECPrivateKey keyPairPrivateKey = keyPair.privateKey;
ECPublicKey keyPairPublicKey = keyPair.publicKey;
expect(keyPairPrivateKey.d.intValue(), equals(kPrivateKeyD));
expect(keyPairPublicKey.Q.x.toBigInteger().intValue(), equals(kPublicKeyQx));
expect(keyPairPublicKey.Q.y.toBigInteger().intValue(), equals(kPublicKeyQy));
});
test('serializeManifest adds key and content-hash', () {
AsymmetricKeyPair keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER);
Uint8List manifestBytes = serializeManifest(kManifest, keyPair.publicKey, kTestBytes);
AsymmetricKeyPair<PublicKey, PrivateKey> keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER);
ECPublicKey keyPairPublicKey = keyPair.publicKey;
Uint8List manifestBytes = serializeManifest(kManifest, keyPairPublicKey, kTestBytes);
Map<String, dynamic> decodedManifest = JSON.decode(UTF8.decode(manifestBytes));
String expectedKey = BASE64.encode(keyPair.publicKey.Q.getEncoded());
String expectedKey = BASE64.encode(keyPairPublicKey.Q.getEncoded());
expect(decodedManifest != null, equals(true));
expect(decodedManifest['name'], equals(kManifest['name']));
expect(decodedManifest['version'], equals(kManifest['version']));
......@@ -62,10 +65,13 @@ Future main() async {
});
test('signManifest and verifyManifestSignature work', () {
AsymmetricKeyPair keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER);
AsymmetricKeyPair<PublicKey, PrivateKey> keyPair = keyPairFromPrivateKeyBytes(kPrivateKeyDER);
ECPrivateKey keyPairPrivateKey = keyPair.privateKey;
ECPublicKey keyPairPublicKey = keyPair.publicKey;
Map<String, dynamic> manifest = JSON.decode(UTF8.decode(
serializeManifest(kManifest, keyPair.publicKey, kTestBytes)));
Uint8List signatureBytes = signManifest(kTestBytes, keyPair.privateKey);
serializeManifest(kManifest, keyPairPublicKey, kTestBytes))
);
Uint8List signatureBytes = signManifest(kTestBytes, keyPairPrivateKey);
bool verifies = verifyManifestSignature(manifest, kTestBytes, signatureBytes);
expect(verifies, equals(true));
......@@ -79,11 +85,14 @@ Future main() async {
});
test('signing works with arbitrary key', () {
AsymmetricKeyPair keyPair = keyGenerator.generateKeyPair();
String failReason = 'offending private key: ${keyPair.privateKey.d}';
AsymmetricKeyPair<PublicKey, PrivateKey> keyPair = keyGenerator.generateKeyPair();
ECPrivateKey keyPairPrivateKey = keyPair.privateKey;
ECPublicKey keyPairPublicKey = keyPair.publicKey;
String failReason = 'offending private key: ${keyPairPrivateKey.d}';
Map<String, dynamic> manifest = JSON.decode(UTF8.decode(
serializeManifest(kManifest, keyPair.publicKey, kTestBytes)));
Uint8List signatureBytes = signManifest(kTestBytes, keyPair.privateKey);
serializeManifest(kManifest, keyPairPublicKey, kTestBytes))
);
Uint8List signatureBytes = signManifest(kTestBytes, keyPairPrivateKey);
bool verifies = verifyManifestSignature(manifest, kTestBytes, signatureBytes);
expect(verifies, equals(true), reason: failReason);
......@@ -97,17 +106,18 @@ Future main() async {
});
test('verifyContentHash works', () async {
Stream contentStream = new Stream.fromIterable(kTestBytesList);
Stream<Uint8List> contentStream = new Stream<Uint8List>.fromIterable(kTestBytesList);
bool verifies = await verifyContentHash(new BigInteger(kTestHash), contentStream);
expect(verifies, equals(true));
// Ensure it fails with invalid hash or content.
contentStream = new Stream.fromIterable(kTestBytesList);
contentStream = new Stream<Uint8List>.fromIterable(kTestBytesList);
verifies = await verifyContentHash(new BigInteger(0xdeadbeef), contentStream);
expect(verifies, equals(false));
Stream badContentStream =
new Stream.fromIterable([new Uint8List.fromList(<int>[42])]);
Stream<Uint8List> badContentStream = new Stream<Uint8List>.fromIterable(
<Uint8List>[new Uint8List.fromList(<int>[42])]
);
verifies = await verifyContentHash(new BigInteger(kTestHash), badContentStream);
expect(verifies, equals(false));
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment