Bug 1439772 - Avoid truncating operands when reporting failure for Assert.deepEqual r?mikedeboer draft
authorThom Chiovoloni <tchiovoloni@mozilla.com>
Tue, 20 Feb 2018 18:17:16 -0500
changeset 757633 31fc6895e7767a72e3630d3dcae4804cded5d798
parent 757244 2c000486eac466da6623e4d7f7f1fd4e318f60e8
push id99811
push userbmo:tchiovoloni@mozilla.com
push dateTue, 20 Feb 2018 23:17:30 +0000
reviewersmikedeboer
bugs1439772
milestone60.0a1
Bug 1439772 - Avoid truncating operands when reporting failure for Assert.deepEqual r?mikedeboer MozReview-Commit-ID: 1hlYFE3Xcwn
testing/modules/Assert.jsm
testing/modules/tests/xpcshell/test_assert.js
--- a/testing/modules/Assert.jsm
+++ b/testing/modules/Assert.jsm
@@ -82,44 +82,46 @@ function getMessage(error, prefix = "") 
   }
   try {
     expected = JSON.stringify(error.expected, replacer);
   } catch (ex) {
     expected = Object.prototype.toString.call(error.expected);
   }
   let message = prefix;
   if (error.operator) {
-    message += (prefix ? " - " : "") + truncate(actual) + " " + error.operator +
-               " " + truncate(expected);
+    let truncateLength = error.truncate ? kTruncateLength : Infinity;
+    message += (prefix ? " - " : "") + truncate(actual, truncateLength) + " " +
+               error.operator + " " + truncate(expected, truncateLength);
   }
   return message;
 }
 
 /**
  * 2. The AssertionError is defined in assert.
  *
  * Example:
  * new assert.AssertionError({
  *   message: message,
  *   actual: actual,
  *   expected: expected,
- *   operator: operator
+ *   operator: operator,
+ *   truncate: truncate
  * });
  *
  * At present only the four keys mentioned above are used and
  * understood by the spec. Implementations or sub modules can pass
  * other keys to the AssertionError's constructor - they will be
  * ignored.
  */
 Assert.AssertionError = function(options) {
   this.name = "AssertionError";
   this.actual = options.actual;
   this.expected = options.expected;
   this.operator = options.operator;
-  this.message = getMessage(this, options.message);
+  this.message = getMessage(this, options.message, options.truncate);
   // The part of the stack that comes from this module is not interesting.
   let stack = Components.stack;
   do {
     stack = stack.asyncCaller || stack.caller;
   } while (stack && stack.filename && stack.filename.includes("Assert.jsm"));
   this.stack = stack;
 };
 
@@ -183,23 +185,26 @@ proto.setReporter = function(reporterFun
  * @param actual
  *        (mixed) The result of evaluating the assertion
  * @param expected (optional)
  *        (mixed) Expected result from the test author
  * @param message (optional)
  *        (string) Short explanation of the expected result
  * @param operator (optional)
  *        (string) Operation qualifier used by the assertion method (ex: '==')
+ * @param truncate (optional) [true]
+ *        (boolean) Whether or not `actual` and `expected` should be truncated when printing
  */
-proto.report = function(failed, actual, expected, message, operator) {
+proto.report = function(failed, actual, expected, message, operator, truncate = true) {
   let err = new Assert.AssertionError({
     message,
     actual,
     expected,
-    operator
+    operator,
+    truncate
   });
   if (!this._reporter) {
     // If no custom reporter is set, throw the error.
     if (failed) {
       throw err;
     }
   } else {
     this._reporter(failed ? err : null, err.message, err.stack);
@@ -264,32 +269,32 @@ proto.notEqual = function notEqual(actua
  * @param actual
  *        (mixed) Test subject to be evaluated as equivalent to `expected`, including nested properties
  * @param expected
  *        (mixed) Test reference to evaluate against `actual`
  * @param message (optional)
  *        (string) Short explanation of the expected result
  */
 proto.deepEqual = function deepEqual(actual, expected, message) {
-  this.report(!ObjectUtils.deepEqual(actual, expected), actual, expected, message, "deepEqual");
+  this.report(!ObjectUtils.deepEqual(actual, expected), actual, expected, message, "deepEqual", false);
 };
 
 /**
  * 8. The non-equivalence assertion tests for any deep inequality.
  * assert.notDeepEqual(actual, expected, message_opt);
  *
  * @param actual
  *        (mixed) Test subject to be evaluated as NOT equivalent to `expected`, including nested properties
  * @param expected
  *        (mixed) Test reference to evaluate against `actual`
  * @param message (optional)
  *        (string) Short explanation of the expected result
  */
 proto.notDeepEqual = function notDeepEqual(actual, expected, message) {
-  this.report(ObjectUtils.deepEqual(actual, expected), actual, expected, message, "notDeepEqual");
+  this.report(ObjectUtils.deepEqual(actual, expected), actual, expected, message, "notDeepEqual", false);
 };
 
 /**
  * 9. The strict equality assertion tests strict equality, as determined by ===.
  * assert.strictEqual(actual, expected, message_opt);
  *
  * @param actual
  *        (mixed) Test subject to be evaluated as strictly equivalent to `expected`
--- a/testing/modules/tests/xpcshell/test_assert.js
+++ b/testing/modules/tests/xpcshell/test_assert.js
@@ -265,16 +265,28 @@ function run_test() {
   }
 
   try {
     assert.equal(1, 2, "oh no");
   } catch (e) {
     assert.equal(e.toString().split("\n")[0], "AssertionError: oh no - 1 == 2");
   }
 
+  // Need to JSON.stringify so that their length is > 128 characters.
+  let longArray0 = Array.from(Array(50), (v, i) => i);
+  let longArray1 = longArray0.concat([51]);
+  try {
+    assert.deepEqual(longArray0, longArray1);
+  } catch (e) {
+    let message = e.toString();
+    // Just check that they're both entirely present in the message
+    assert.ok(message.includes(JSON.stringify(longArray0)));
+    assert.ok(message.includes(JSON.stringify(longArray1)));
+  }
+
   // Test XPCShell-test integration:
   ok(true, "OK, this went well");
   deepEqual(/a/g, /a/g, "deep equal should work on RegExp");
   deepEqual(/a/igm, /a/igm, "deep equal should work on RegExp");
   deepEqual({a: 4, b: "1"}, {b: "1", a: 4}, "deep equal should work on regular Object");
   deepEqual(a1, a2, "deep equal should work on Array with Object properties");
 
   // Test robustness of reporting: