From beeb872a82693844c58b3f28bdacccd364d8f87a Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Sun, 4 Mar 2012 16:18:43 -0800 Subject: [PATCH 1/2] When pretty-printing objects, don't include inherited properties. When making assertions about complex objects, Jasmine's failure message are sometimes gigantic and difficult to read because the string representation of an object contains all of the methods and properties in its prototype chain. This commit causes the pretty printer to only display on object's own properties. --- spec/core/PrettyPrintSpec.js | 8 ++++++++ src/core/PrettyPrinter.js | 1 + 2 files changed, 9 insertions(+) diff --git a/spec/core/PrettyPrintSpec.js b/spec/core/PrettyPrintSpec.js index becf8a61..6d1cfc08 100644 --- a/spec/core/PrettyPrintSpec.js +++ b/spec/core/PrettyPrintSpec.js @@ -32,6 +32,14 @@ describe("jasmine.pp", function () { }, bar: [1, 2, 3]})).toEqual("{ foo : Function, bar : [ 1, 2, 3 ] }"); }); + it("should not include inherited properties when stringifying an object", function() { + var SomeClass = function() {}; + SomeClass.prototype.foo = "inherited foo"; + var instance = new SomeClass(); + instance.bar = "my own bar"; + expect(jasmine.pp(instance)).toEqual("{ bar : 'my own bar' }"); + }); + it("should stringify RegExp objects properly", function() { expect(jasmine.pp(/x|y|z/)).toEqual("/x|y|z/"); }); diff --git a/src/core/PrettyPrinter.js b/src/core/PrettyPrinter.js index a7d283b6..74fa4e7a 100644 --- a/src/core/PrettyPrinter.js +++ b/src/core/PrettyPrinter.js @@ -57,6 +57,7 @@ jasmine.PrettyPrinter.prototype.format = function(value) { jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { for (var property in obj) { + if (!obj.hasOwnProperty(property)) continue; if (property == '__Jasmine_been_here_before__') continue; fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && obj.__lookupGetter__(property) !== null) : false); From ddbee65aa8225b2b9abca954929e41031d88381e Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Sun, 4 Mar 2012 16:27:16 -0800 Subject: [PATCH 2/2] Allow users to set the pretty-printer's recursion depth Currently, jasmine's pretty printer traverses objects to 40 levels of nesting. If an object is more deeply nested than that, an exception is thrown. I find that after a few levels of nesting, the output becomes difficult to read. The process of serializing such deep objects also sometimes crashes the browser or causes a 'slow script' warning. This commit exposes a 'MAX_PRETTY_PRINT_DEPTH' option. It also causes the pretty printer to skip over parts of an object that are nested to deeply by simply printing out 'Object' or 'Array', rather than throwing an exception. --- spec/core/PrettyPrintSpec.js | 22 ++++++++++++++++++++++ src/core/PrettyPrinter.js | 14 ++++++++++---- src/core/base.js | 5 +++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/spec/core/PrettyPrintSpec.js b/spec/core/PrettyPrintSpec.js index 6d1cfc08..14d0d3e0 100644 --- a/spec/core/PrettyPrintSpec.js +++ b/spec/core/PrettyPrintSpec.js @@ -40,6 +40,28 @@ describe("jasmine.pp", function () { expect(jasmine.pp(instance)).toEqual("{ bar : 'my own bar' }"); }); + it("should not recurse objects and arrays more deeply than jasmine.MAX_PRETTY_PRINT_DEPTH", function() { + var originalMaxDepth = jasmine.MAX_PRETTY_PRINT_DEPTH; + var nestedObject = { level1: { level2: { level3: { level4: "leaf" } } } }; + var nestedArray = [1, [2, [3, [4, "leaf"]]]]; + + try { + jasmine.MAX_PRETTY_PRINT_DEPTH = 2; + expect(jasmine.pp(nestedObject)).toEqual("{ level1 : { level2 : Object } }"); + expect(jasmine.pp(nestedArray)).toEqual("[ 1, [ 2, Array ] ]"); + + jasmine.MAX_PRETTY_PRINT_DEPTH = 3; + expect(jasmine.pp(nestedObject)).toEqual("{ level1 : { level2 : { level3 : Object } } }"); + expect(jasmine.pp(nestedArray)).toEqual("[ 1, [ 2, [ 3, Array ] ] ]"); + + jasmine.MAX_PRETTY_PRINT_DEPTH = 4; + expect(jasmine.pp(nestedObject)).toEqual("{ level1 : { level2 : { level3 : { level4 : 'leaf' } } } }"); + expect(jasmine.pp(nestedArray)).toEqual("[ 1, [ 2, [ 3, [ 4, 'leaf' ] ] ] ]"); + } finally { + jasmine.MAX_PRETTY_PRINT_DEPTH = originalMaxDepth; + } + }); + it("should stringify RegExp objects properly", function() { expect(jasmine.pp(/x|y|z/)).toEqual("/x|y|z/"); }); diff --git a/src/core/PrettyPrinter.js b/src/core/PrettyPrinter.js index 74fa4e7a..f276cea3 100644 --- a/src/core/PrettyPrinter.js +++ b/src/core/PrettyPrinter.js @@ -11,10 +11,6 @@ jasmine.PrettyPrinter = function() { * @param value */ jasmine.PrettyPrinter.prototype.format = function(value) { - if (this.ppNestLevel_ > 40) { - throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); - } - this.ppNestLevel_++; try { if (value === jasmine.undefined) { @@ -85,6 +81,11 @@ jasmine.StringPrettyPrinter.prototype.emitString = function(value) { }; jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { + if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { + this.append("Array"); + return; + } + this.append('[ '); for (var i = 0; i < array.length; i++) { if (i > 0) { @@ -96,6 +97,11 @@ jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { }; jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { + if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { + this.append("Object"); + return; + } + var self = this; this.append('{ '); var first = true; diff --git a/src/core/base.js b/src/core/base.js index 51761ba2..af8d3ea0 100644 --- a/src/core/base.js +++ b/src/core/base.js @@ -34,6 +34,11 @@ jasmine.VERBOSE = false; */ jasmine.DEFAULT_UPDATE_INTERVAL = 250; +/** + * Maximum levels of nesting that will be included when an object is pretty-printed + */ +jasmine.MAX_PRETTY_PRINT_DEPTH = 40; + /** * Default timeout interval in milliseconds for waitsFor() blocks. */