Bug 1408454 - Move error.pprint to format.pprint. r?whimboo draft
authorAndreas Tolfsen <ato@sny.no>
Fri, 13 Oct 2017 17:59:30 +0100
changeset 680208 90ad43164450a5ea9ea87d18fba5fb16c3f7ffdd
parent 680024 196dadb2fe500e75c6fbddcac78106648676cf10
child 735787 8991bf6a6b67360f12aab59baa450f596e578987
push id84423
push userbmo:ato@sny.no
push dateFri, 13 Oct 2017 17:02:30 +0000
reviewerswhimboo
bugs1408454
milestone58.0a1
Bug 1408454 - Move error.pprint to format.pprint. r?whimboo Pretty-printing an object belongs more naturally to the new format module. MozReview-Commit-ID: AfXLMPAT5ar
testing/marionette/action.js
testing/marionette/assert.js
testing/marionette/cookie.js
testing/marionette/element.js
testing/marionette/error.js
testing/marionette/format.js
testing/marionette/interaction.js
testing/marionette/test_error.js
testing/marionette/test_format.js
--- a/testing/marionette/action.js
+++ b/testing/marionette/action.js
@@ -6,22 +6,22 @@
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("chrome://marionette/content/assert.js");
 Cu.import("chrome://marionette/content/element.js");
 const {
-  pprint,
   InvalidArgumentError,
   MoveTargetOutOfBoundsError,
   UnsupportedOperationError,
 } = Cu.import("chrome://marionette/content/error.js", {});
 Cu.import("chrome://marionette/content/event.js");
+const {pprint} = Cu.import("chrome://marionette/content/format.js", {});
 Cu.import("chrome://marionette/content/interaction.js");
 
 this.EXPORTED_SYMBOLS = ["action"];
 
 // TODO? With ES 2016 and Symbol you can make a safer approximation
 // to an enum e.g. https://gist.github.com/xmlking/e86e4f15ec32b12c4689
 /**
  * Implements WebDriver Actions API: a low-level interface for providing
--- a/testing/marionette/assert.js
+++ b/testing/marionette/assert.js
@@ -9,20 +9,20 @@ const {utils: Cu} = Components;
 Cu.import("resource://gre/modules/AppConstants.jsm");
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 const {
   InvalidArgumentError,
   InvalidSessionIDError,
   NoSuchWindowError,
-  pprint,
   UnexpectedAlertOpenError,
   UnsupportedOperationError,
 } = Cu.import("chrome://marionette/content/error.js", {});
+const {pprint} = Cu.import("chrome://marionette/content/format.js", {});
 
 this.EXPORTED_SYMBOLS = ["assert"];
 
 const isFennec = () => AppConstants.platform == "android";
 const isFirefox = () =>
     Services.appinfo.ID == "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}";
 
 /**
--- a/testing/marionette/cookie.js
+++ b/testing/marionette/cookie.js
@@ -4,20 +4,18 @@
 
 "use strict";
 
 const {interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 Cu.import("chrome://marionette/content/assert.js");
-const {
-  InvalidCookieDomainError,
-  pprint,
-} = Cu.import("chrome://marionette/content/error.js", {});
+const {InvalidCookieDomainError} = Cu.import("chrome://marionette/content/error.js", {});
+const {pprint} = Cu.import("chrome://marionette/content/format.js", {});
 
 this.EXPORTED_SYMBOLS = ["cookie"];
 
 const IPV4_PORT_EXPR = /:\d+$/;
 
 /** @namespace */
 this.cookie = {
   manager: Services.cookies,
--- a/testing/marionette/element.js
+++ b/testing/marionette/element.js
@@ -7,19 +7,19 @@
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("chrome://marionette/content/assert.js");
 Cu.import("chrome://marionette/content/atom.js");
 const {
   InvalidSelectorError,
   NoSuchElementError,
-  pprint,
   StaleElementReferenceError,
 } = Cu.import("chrome://marionette/content/error.js", {});
+const {pprint} = Cu.import("chrome://marionette/content/format.js", {});
 const {PollPromise} = Cu.import("chrome://marionette/content/sync.js", {});
 
 this.EXPORTED_SYMBOLS = ["element"];
 
 const XMLNS = "http://www.w3.org/1999/xhtml";
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 /** XUL elements that support checked property. */
--- a/testing/marionette/error.js
+++ b/testing/marionette/error.js
@@ -1,16 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {interfaces: Ci, utils: Cu} = Components;
 
+const {pprint} = Cu.import("chrome://marionette/content/format.js", {});
+
 const ERRORS = new Set([
   "ElementClickInterceptedError",
   "ElementNotAccessibleError",
   "ElementNotInteractableError",
   "InsecureCertificateError",
   "InvalidArgumentError",
   "InvalidCookieDomainError",
   "InvalidElementStateError",
@@ -42,17 +44,16 @@ const BUILTIN_ERRORS = new Set([
   "ReferenceError",
   "SyntaxError",
   "TypeError",
   "URIError",
 ]);
 
 this.EXPORTED_SYMBOLS = [
   "error",
-  "pprint",
   "stack",
 ].concat(Array.from(ERRORS));
 
 /** @namespace */
 this.error = {};
 
 /**
  * Check if |val| is an instance of the |Error| prototype.
@@ -143,84 +144,16 @@ error.stringify = function(err) {
       s += "\n" + err.stack;
     }
     return s;
   } catch (e) {
     return "<unprintable error>";
   }
 };
 
-/**
- * Pretty-print values passed to template strings.
- *
- * Usage:
- *
- *     const {pprint} = Cu.import("chrome://marionette/content/error.js", {});
- *     let bool = {value: true};
- *     pprint`Expected boolean, got ${bool}`;
- *     => 'Expected boolean, got [object Object] {"value": true}'
- *
- *     let htmlElement = document.querySelector("input#foo");
- *     pprint`Expected element ${htmlElement}`;
- *     => 'Expected element <input id="foo" class="bar baz">'
- */
-this.pprint = function(ss, ...values) {
-  function prettyObject(obj) {
-    let proto = Object.prototype.toString.call(obj);
-    let s = "";
-    try {
-      s = JSON.stringify(obj);
-    } catch (e) {
-      if (e instanceof TypeError) {
-        s = `<${e.message}>`;
-      } else {
-        throw e;
-      }
-    }
-    return proto + " " + s;
-  }
-
-  function prettyElement(el) {
-    let ident = [];
-    if (el.id) {
-      ident.push(`id="${el.id}"`);
-    }
-    if (el.classList.length > 0) {
-      ident.push(`class="${el.className}"`);
-    }
-
-    let idents = "";
-    if (ident.length > 0) {
-      idents = " " + ident.join(" ");
-    }
-
-    return `<${el.localName}${idents}>`;
-  }
-
-  let res = [];
-  for (let i = 0; i < ss.length; i++) {
-    res.push(ss[i]);
-    if (i < values.length) {
-      let val = values[i];
-      let s;
-      try {
-        if (val && val.nodeType === 1) {
-          s = prettyElement(val);
-        } else {
-          s = prettyObject(val);
-        }
-      } catch (e) {
-        s = typeof val;
-      }
-      res.push(s);
-    }
-  }
-  return res.join("");
-};
-
 /** Create a stacktrace to the current line in the program. */
 this.stack = function() {
   let trace = new Error().stack;
   let sa = trace.split("\n");
   sa = sa.slice(1);
   return "stacktrace:\n" + sa.join("\n");
 };
 
--- a/testing/marionette/format.js
+++ b/testing/marionette/format.js
@@ -1,19 +1,90 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-this.EXPORTED_SYMBOLS = ["truncate"];
+this.EXPORTED_SYMBOLS = ["pprint", "truncate"];
 
 const MAX_STRING_LENGTH = 250;
 
 /**
+ * Pretty-print values passed to template strings.
+ *
+ * Usage:
+ *
+ * <pre><code>
+ *     const {pprint} = Cu.import("chrome://marionette/content/error.js", {});
+ *     let bool = {value: true};
+ *     pprint`Expected boolean, got ${bool}`;
+ *     => 'Expected boolean, got [object Object] {"value": true}'
+ *
+ *     let htmlElement = document.querySelector("input#foo");
+ *     pprint`Expected element ${htmlElement}`;
+ *     => 'Expected element <input id="foo" class="bar baz">'
+ * </code></pre>
+ */
+function pprint(ss, ...values) {
+  function prettyObject(obj) {
+    let proto = Object.prototype.toString.call(obj);
+    let s = "";
+    try {
+      s = JSON.stringify(obj);
+    } catch (e) {
+      if (e instanceof TypeError) {
+        s = `<${e.message}>`;
+      } else {
+        throw e;
+      }
+    }
+    return proto + " " + s;
+  }
+
+  function prettyElement(el) {
+    let ident = [];
+    if (el.id) {
+      ident.push(`id="${el.id}"`);
+    }
+    if (el.classList.length > 0) {
+      ident.push(`class="${el.className}"`);
+    }
+
+    let idents = "";
+    if (ident.length > 0) {
+      idents = " " + ident.join(" ");
+    }
+
+    return `<${el.localName}${idents}>`;
+  }
+
+  let res = [];
+  for (let i = 0; i < ss.length; i++) {
+    res.push(ss[i]);
+    if (i < values.length) {
+      let val = values[i];
+      let s;
+      try {
+        if (val && val.nodeType === 1) {
+          s = prettyElement(val);
+        } else {
+          s = prettyObject(val);
+        }
+      } catch (e) {
+        s = typeof val;
+      }
+      res.push(s);
+    }
+  }
+  return res.join("");
+}
+this.pprint = pprint;
+
+/**
  * Template literal that truncates string values in arbitrary objects.
  *
  * Given any object, the template will walk the object and truncate
  * any strings it comes across to a reasonable limit.  This is suitable
  * when you have arbitrary data and data integrity is not important.
  *
  * The strings are truncated in the middle so that the beginning and
  * the end is preserved.  This will make a long, truncated string look
--- a/testing/marionette/interaction.js
+++ b/testing/marionette/interaction.js
@@ -8,19 +8,19 @@ const {utils: Cu} = Components;
 
 Cu.import("chrome://marionette/content/accessibility.js");
 Cu.import("chrome://marionette/content/atom.js");
 const {
   ElementClickInterceptedError,
   ElementNotInteractableError,
   InvalidArgumentError,
   InvalidElementStateError,
-  pprint,
 } = Cu.import("chrome://marionette/content/error.js", {});
 Cu.import("chrome://marionette/content/element.js");
+const {pprint} = Cu.import("chrome://marionette/content/format.js", {});
 Cu.import("chrome://marionette/content/event.js");
 
 Cu.importGlobalProperties(["File"]);
 
 this.EXPORTED_SYMBOLS = ["interaction"];
 
 /** XUL elements that support disabled attribute. */
 const DISABLED_ATTRIBUTE_SUPPORTED_XUL = new Set([
--- a/testing/marionette/test_error.js
+++ b/testing/marionette/test_error.js
@@ -16,17 +16,16 @@ const {
   InvalidSelectorError,
   InvalidSessionIDError,
   JavaScriptError,
   MoveTargetOutOfBoundsError,
   NoAlertOpenError,
   NoSuchElementError,
   NoSuchFrameError,
   NoSuchWindowError,
-  pprint,
   ScriptTimeoutError,
   SessionNotCreatedError,
   stack,
   StaleElementReferenceError,
   TimeoutError,
   UnableToSetCookieError,
   UnexpectedAlertOpenError,
   UnknownCommandError,
@@ -113,43 +112,16 @@ add_test(function test_stringify() {
   equal("WebDriverError: foo",
       error.stringify(new WebDriverError("foo")).split("\n")[0]);
   equal("InvalidArgumentError: foo",
       error.stringify(new InvalidArgumentError("foo")).split("\n")[0]);
 
   run_next_test();
 });
 
-add_test(function test_pprint() {
-  equal('[object Object] {"foo":"bar"}', pprint`${{foo: "bar"}}`);
-
-  equal("[object Number] 42", pprint`${42}`);
-  equal("[object Boolean] true", pprint`${true}`);
-  equal("[object Undefined] undefined", pprint`${undefined}`);
-  equal("[object Null] null", pprint`${null}`);
-
-  let complexObj = {toJSON: () => "foo"};
-  equal('[object Object] "foo"', pprint`${complexObj}`);
-
-  let cyclic = {};
-  cyclic.me = cyclic;
-  equal("[object Object] <cyclic object value>", pprint`${cyclic}`);
-
-  let el = {
-    nodeType: 1,
-    localName: "input",
-    id: "foo",
-    classList: {length: 1},
-    className: "bar baz",
-  };
-  equal('<input id="foo" class="bar baz">', pprint`${el}`);
-
-  run_next_test();
-});
-
 add_test(function test_stack() {
   equal("string", typeof stack());
   ok(stack().includes("test_stack"));
   ok(!stack().includes("add_test"));
 
   run_next_test();
 });
 
--- a/testing/marionette/test_format.js
+++ b/testing/marionette/test_format.js
@@ -1,19 +1,46 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {utils: Cu} = Components;
 
-const {truncate} = Cu.import("chrome://marionette/content/format.js", {});
+const {pprint, truncate} = Cu.import("chrome://marionette/content/format.js", {});
 
 const MAX_STRING_LENGTH = 250;
 const HALF = "x".repeat(MAX_STRING_LENGTH / 2);
 
+add_test(function test_pprint() {
+  equal('[object Object] {"foo":"bar"}', pprint`${{foo: "bar"}}`);
+
+  equal("[object Number] 42", pprint`${42}`);
+  equal("[object Boolean] true", pprint`${true}`);
+  equal("[object Undefined] undefined", pprint`${undefined}`);
+  equal("[object Null] null", pprint`${null}`);
+
+  let complexObj = {toJSON: () => "foo"};
+  equal('[object Object] "foo"', pprint`${complexObj}`);
+
+  let cyclic = {};
+  cyclic.me = cyclic;
+  equal("[object Object] <cyclic object value>", pprint`${cyclic}`);
+
+  let el = {
+    nodeType: 1,
+    localName: "input",
+    id: "foo",
+    classList: {length: 1},
+    className: "bar baz",
+  };
+  equal('<input id="foo" class="bar baz">', pprint`${el}`);
+
+  run_next_test();
+});
+
 add_test(function test_truncate_empty() {
   equal(truncate``, "");
   run_next_test();
 });
 
 add_test(function test_truncate_noFields() {
   equal(truncate`foo bar`, "foo bar");
   run_next_test();