Bug 1337133 - Fix creation of pointer InputState; r?ato draft
authorMaja Frydrychowicz <mjzffr@gmail.com>
Mon, 20 Feb 2017 13:13:43 -0500
changeset 490014 5c9bb060a305cb93f4876780be51c591d2e55c94
parent 490013 46836d7b3a7b4bc6a413f2eea9b550937f9e05a6
child 490015 aa12c04f031718cf5f6891d26003a3fa0a2f90d1
push id46970
push userbmo:mjzffr@gmail.com
push dateMon, 27 Feb 2017 14:54:25 +0000
reviewersato
bugs1337133
milestone54.0a1
Bug 1337133 - Fix creation of pointer InputState; r?ato Previously, the pointer input state was always being created with an undefined subtype, which should actually be mouse, pen or touch. MozReview-Commit-ID: JcarsRRecQl
testing/marionette/action.js
testing/marionette/test_action.js
--- a/testing/marionette/action.js
+++ b/testing/marionette/action.js
@@ -431,32 +431,41 @@ class InputState {
   }
 
   toString() {
     return `[object ${this.constructor.name}InputState]`;
   }
 
   /**
    * @param {?} obj
-   *     Object with property |type|, representing an action sequence or an
-   *     action item.
+   *     Object with property |type| and optionally |parameters| or |pointerType|,
+   *     representing an action sequence or an action item.
    *
    * @return {action.InputState}
    *     An |action.InputState| object for the type of the |actionSequence|.
    *
    * @throws {InvalidArgumentError}
    *     If |actionSequence.type| is not valid.
    */
   static fromJson(obj) {
     let type = obj.type;
     if (!(type in ACTIONS)) {
       throw new InvalidArgumentError(`Unknown action type: ${type}`);
     }
     let name = type == "none" ? "Null" : capitalize(type);
-    return new action.InputState[name]();
+    if (name == "Pointer") {
+      if (!obj.pointerType && (!obj.parameters || !obj.parameters.pointerType)) {
+        throw new InvalidArgumentError(
+            error.pprint`Expected obj to have pointerType, got: ${obj}`);
+      }
+      let pointerType = obj.pointerType || obj.parameters.pointerType;
+      return new action.InputState[name](pointerType);
+    } else {
+      return new action.InputState[name]();
+    }
   }
 }
 
 /** Possible kinds of |InputState| for supported input sources. */
 action.InputState = {};
 
 /**
  * Input state associated with a keyboard-type device.
@@ -541,22 +550,26 @@ action.InputState.Null = class Null exte
   }
 };
 
 /**
  * Input state associated with a pointer-type input device.
  *
  * @param {string} subtype
  *     Kind of pointing device: mouse, pen, touch.
+ *
+ * @throws {InvalidArgumentError}
+ *     If subtype is undefined or an invalid pointer type.
  */
 action.InputState.Pointer = class Pointer extends InputState {
   constructor(subtype) {
     super();
     this.pressed = new Set();
-    this.subtype = subtype;
+    assert.defined(subtype, error.pprint`Expected subtype to be defined, got: ${subtype}`);
+    this.subtype = action.PointerType.get(subtype);
     this.x = 0;
     this.y = 0;
   }
 };
 
 /**
  * Repesents an action for dispatch. Used in |action.Chain| and |action.Sequence|.
  *
@@ -799,24 +812,29 @@ action.PointerParameters = class {
  *     Input source ID.
  * @param {action.PointerParams} pointerParams
  *     Input source pointer parameters.
  * @param {action.Action} act
  *     Action to be updated.
  *
  * @throws {InvalidArgumentError}
  *     If |id| is already mapped to an |action.InputState| that is
- *     not compatible with |act.subtype|.
+ *     not compatible with |act.type| or |pointerParams.pointerType|.
  */
 action.processPointerAction = function processPointerAction(id, pointerParams, act) {
-  let subtype = act.subtype;
-  if (action.inputStateMap.has(id) && action.inputStateMap.get(id).subtype !== subtype) {
+  if (action.inputStateMap.has(id) && action.inputStateMap.get(id).type !== act.type) {
+    throw new InvalidArgumentError(
+        `Expected 'id' ${id} to be mapped to InputState whose type is ` +
+        `${action.inputStateMap.get(id).type}, got: ${act.type}`);
+  }
+  let pointerType = pointerParams.pointerType;
+  if (action.inputStateMap.has(id) && action.inputStateMap.get(id).subtype !== pointerType) {
     throw new InvalidArgumentError(
         `Expected 'id' ${id} to be mapped to InputState whose subtype is ` +
-        `${action.inputStateMap.get(id).subtype}, got: ${subtype}`);
+        `${action.inputStateMap.get(id).subtype}, got: ${pointerType}`);
   }
   act.pointerType = pointerParams.pointerType;
 };
 
 /** Collect properties associated with KeyboardEvent */
 action.Key = class {
   constructor(rawKey) {
     this.key = NORMALIZED_KEY_LOOKUP[rawKey] || rawKey;
--- a/testing/marionette/test_action.js
+++ b/testing/marionette/test_action.js
@@ -376,40 +376,58 @@ add_test(function test_processInputSourc
   run_next_test();
 });
 
 add_test(function test_processPointerActionInputStateMap() {
   let actionItem = {type: "pointerDown"};
   let id = "1";
   let parameters = {pointerType: "mouse"};
   let a = new action.Action(id, "pointer", actionItem.type);
-  let wrongInputState = new action.InputState.Pointer("pause", true);
+  let wrongInputState = new action.InputState.Key();
+  action.inputStateMap.set(id, wrongInputState);
+  checkErrors(
+      /to be mapped to InputState whose type is/, action.processPointerAction,
+      [id, parameters, a],
+      `type "pointer" with ${wrongInputState.type} in inputState`);
+  action.inputStateMap.clear();
+
+  wrongInputState = new action.InputState.Pointer("pen");
   action.inputStateMap.set(id, wrongInputState);
   checkErrors(
       /to be mapped to InputState whose subtype is/, action.processPointerAction,
       [id, parameters, a],
-      `$subtype ${actionItem.type} with ${wrongInputState.subtype} in inputState`);
+      `subtype ${parameters.pointerType} with ${wrongInputState.subtype} in inputState`);
   action.inputStateMap.clear();
-  let rightInputState = new action.InputState.Pointer("pointerDown", false);
+
+  let rightInputState = new action.InputState.Pointer("mouse");
   action.inputStateMap.set(id, rightInputState);
   action.processPointerAction(id, parameters, a);
   action.inputStateMap.clear();
   run_next_test();
 });
 
 add_test(function test_createInputState() {
   for (let kind in action.InputState) {
-    let state = new action.InputState[kind]();
+    let state;
+    if (kind == "Pointer") {
+      state = new action.InputState[kind]("mouse");
+    } else {
+      state = new action.InputState[kind]();
+    }
     ok(state);
     if (kind === "Null") {
       equal(state.type, "none");
     } else {
       equal(state.type, kind.toLowerCase());
     }
   }
+  Assert.throws(() => new action.InputState.Pointer(), InvalidArgumentError,
+      "Missing InputState.Pointer constructor arg");
+  Assert.throws(() => new action.InputState.Pointer("foo"), InvalidArgumentError,
+      "Invalid InputState.Pointer constructor arg");
   run_next_test();
 });
 
 add_test(function test_extractActionChainValidation() {
   for (let actions of [-1, "a", undefined, null]) {
     let message = `actions: ${getTypeString(actions)}`;
     Assert.throws(() => action.Chain.fromJson(actions),
         InvalidArgumentError, message);