Commit 008785be authored by yjbanov's avatar yjbanov

[driver] serialize commands to plain strings

Turns out VM service only accepts flat parameter name/value pairs. It
only worked this far because vm_service_client (mistakenly) uses JSON
encoder to encode parameters.

This change separates the Command type hierarchy from that of Result and
tightens type constraints on Command object parameters.
parent 60b81271
......@@ -148,9 +148,9 @@ class FlutterDriver {
final VMIsolateRef _appIsolate;
Future<Map<String, dynamic>> _sendCommand(Command command) async {
Map<String, dynamic> json = <String, dynamic>{'command': command.kind}
..addAll(command.toJson());
return _appIsolate.invokeExtension(_kFlutterExtensionMethod, json)
Map<String, String> parameters = <String, String>{'command': command.kind}
..addAll(command.serialize());
return _appIsolate.invokeExtension(_kFlutterExtensionMethod, parameters)
.then((Map<String, dynamic> result) => result, onError: (error, stackTrace) {
throw new DriverError(
'Failed to fulfill ${command.runtimeType} due to remote error',
......
......@@ -60,11 +60,11 @@ class FlutterDriverExtension {
};
_commandDeserializers = {
'get_health': GetHealth.fromJson,
'find': Find.fromJson,
'tap': Tap.fromJson,
'get_text': GetText.fromJson,
'scroll': Scroll.fromJson,
'get_health': GetHealth.deserialize,
'find': Find.deserialize,
'tap': Tap.deserialize,
'get_text': GetText.deserialize,
'scroll': Scroll.deserialize,
};
}
......
......@@ -15,10 +15,10 @@ class Find extends Command {
final SearchSpecification searchSpec;
Map<String, dynamic> toJson() => searchSpec.toJson();
Map<String, String> serialize() => searchSpec.serialize();
static Find fromJson(Map<String, dynamic> json) {
return new Find(SearchSpecification.fromJson(json));
static Find deserialize(Map<String, String> json) {
return new Find(SearchSpecification.deserialize(json));
}
static _throwInvalidKeyValueType(String invalidType) {
......@@ -27,20 +27,20 @@ class Find extends Command {
}
/// Describes how to the driver should search for elements.
abstract class SearchSpecification extends Message {
abstract class SearchSpecification {
String get searchSpecType;
static SearchSpecification fromJson(Map<String, dynamic> json) {
static SearchSpecification deserialize(Map<String, String> json) {
String searchSpecType = json['searchSpecType'];
switch(searchSpecType) {
case 'ByValueKey': return ByValueKey.fromJson(json);
case 'ByTooltipMessage': return ByTooltipMessage.fromJson(json);
case 'ByText': return ByText.fromJson(json);
case 'ByValueKey': return ByValueKey.deserialize(json);
case 'ByTooltipMessage': return ByTooltipMessage.deserialize(json);
case 'ByText': return ByText.deserialize(json);
}
throw new DriverError('Unsupported search specification type $searchSpecType');
}
Map<String, dynamic> toJson() => {
Map<String, String> serialize() => {
'searchSpecType': searchSpecType,
};
}
......@@ -54,11 +54,11 @@ class ByTooltipMessage extends SearchSpecification {
/// Tooltip message text.
final String text;
Map<String, dynamic> toJson() => super.toJson()..addAll({
Map<String, String> serialize() => super.serialize()..addAll({
'text': text,
});
static ByTooltipMessage fromJson(Map<String, dynamic> json) {
static ByTooltipMessage deserialize(Map<String, String> json) {
return new ByTooltipMessage(json['text']);
}
}
......@@ -71,11 +71,11 @@ class ByText extends SearchSpecification {
final String text;
Map<String, dynamic> toJson() => super.toJson()..addAll({
Map<String, String> serialize() => super.serialize()..addAll({
'text': text,
});
static ByText fromJson(Map<String, dynamic> json) {
static ByText deserialize(Map<String, String> json) {
return new ByText(json['text']);
}
}
......@@ -103,12 +103,12 @@ class ByValueKey extends SearchSpecification {
/// May be one of "String", "int". The list of supported types may change.
final String keyValueType;
Map<String, dynamic> toJson() => super.toJson()..addAll({
Map<String, String> serialize() => super.serialize()..addAll({
'keyValueString': keyValueString,
'keyValueType': keyValueType,
});
static ByValueKey fromJson(Map<String, dynamic> json) {
static ByValueKey deserialize(Map<String, String> json) {
String keyValueString = json['keyValueString'];
String keyValueType = json['keyValueType'];
switch(keyValueType) {
......@@ -130,14 +130,14 @@ class ByValueKey extends SearchSpecification {
class GetText extends CommandWithTarget {
final String kind = 'get_text';
static GetText fromJson(Map<String, dynamic> json) {
static GetText deserialize(Map<String, String> json) {
return new GetText(new ObjectRef(json['targetRef']));
}
/// [targetRef] identifies an element that contains a piece of text.
GetText(ObjectRef targetRef) : super(targetRef);
Map<String, dynamic> toJson() => super.toJson();
Map<String, String> serialize() => super.serialize();
}
class GetTextResult extends Result {
......
......@@ -9,11 +9,11 @@ class Tap extends CommandWithTarget {
Tap(ObjectRef targetRef) : super(targetRef);
static Tap fromJson(Map<String, dynamic> json) {
static Tap deserialize(Map<String, String> json) {
return new Tap(new ObjectRef(json['targetRef']));
}
Map<String, dynamic> toJson() => super.toJson();
Map<String, String> serialize() => super.serialize();
}
class TapResult extends Result {
......@@ -37,7 +37,7 @@ class Scroll extends CommandWithTarget {
this.frequency
) : super(targetRef);
static Scroll fromJson(Map<String, dynamic> json) {
static Scroll deserialize(Map<String, dynamic> json) {
return new Scroll(
new ObjectRef(json['targetRef']),
double.parse(json['dx']),
......@@ -59,11 +59,11 @@ class Scroll extends CommandWithTarget {
/// The frequency in Hz of the generated move events.
final int frequency;
Map<String, dynamic> toJson() => super.toJson()..addAll({
'dx': dx,
'dy': dy,
'duration': duration.inMicroseconds,
'frequency': frequency,
Map<String, String> serialize() => super.serialize()..addAll({
'dx': '$dx',
'dy': '$dy',
'duration': '${duration.inMicroseconds}',
'frequency': '$frequency',
});
}
......
......@@ -9,9 +9,9 @@ import 'message.dart';
class GetHealth implements Command {
final String kind = 'get_health';
static fromJson(Map<String, dynamic> json) => new GetHealth();
static deserialize(Map<String, String> json) => new GetHealth();
Map<String, dynamic> toJson() => const {};
Map<String, String> serialize() => const {};
}
/// Application health status.
......
......@@ -4,22 +4,22 @@
import 'error.dart';
/// A piece of data travelling between Flutter Driver and a Flutter application.
abstract class Message {
/// Serializes this message to a JSON map.
Map<String, dynamic> toJson();
}
/// A message that travels from the Flutter Driver to a Flutter application to
/// instruct the application to perform a task.
abstract class Command extends Message {
/// An object sent from the Flutter Driver to a Flutter application to instruct
/// the application to perform a task.
abstract class Command {
/// Identifies the type of the command object and of the handler.
String get kind;
/// Serializes this command to parameter name/value pairs.
Map<String, String> serialize();
}
/// A message sent from a Flutter application back to the Flutter Driver in
/// An object sent from a Flutter application back to the Flutter Driver in
/// response to a command.
abstract class Result extends Message { }
abstract class Result {
/// Serializes this message to a JSON map.
Map<String, dynamic> toJson();
}
/// A serializable reference to an object that lives in the application isolate.
class ObjectRef extends Result {
......@@ -47,7 +47,7 @@ class ObjectRef extends Result {
/// A command aimed at an object represented by [targetRef].
///
/// Implementations must provide a concrete [kind]. If additional data is
/// required beyond the [targetRef] the implementation may override [toJson]
/// required beyond the [targetRef] the implementation may override [serialize]
/// and add more keys to the returned map.
abstract class CommandWithTarget extends Command {
CommandWithTarget(ObjectRef ref) : this.targetRef = ref?.objectReferenceKey {
......@@ -66,10 +66,10 @@ abstract class CommandWithTarget extends Command {
///
/// Example:
///
/// Map<String, dynamic> toJson() => super.toJson()..addAll({
/// Map<String, String> toJson() => super.toJson()..addAll({
/// 'foo': this.foo,
/// });
Map<String, dynamic> toJson() => {
Map<String, String> serialize() => <String, String>{
'targetRef': targetRef,
};
}
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