1 /** 2 * Base class for pretty printing for expectation results. 3 */ 4 jasmine.PrettyPrinter = function() { 5 this.ppNestLevel_ = 0; 6 }; 7 8 /** 9 * Formats a value in a nice, human-readable string. 10 * 11 * @param value 12 */ 13 jasmine.PrettyPrinter.prototype.format = function(value) { 14 if (this.ppNestLevel_ > 40) { 15 throw new Error('jasmine.PrettyPrinter: format() nested too deeply!'); 16 } 17 18 this.ppNestLevel_++; 19 try { 20 if (value === undefined) { 21 this.emitScalar('undefined'); 22 } else if (value === null) { 23 this.emitScalar('null'); 24 } else if (value.navigator /* && value.frames */ && value.setTimeout) { 25 this.emitScalar('<window>'); 26 } else if (value instanceof jasmine.Matchers.Any) { 27 this.emitScalar(value.toString()); 28 } else if (typeof value === 'string') { 29 this.emitString(value); 30 } else if (jasmine.isSpy(value)) { 31 this.emitScalar("spy on " + value.identity); 32 } else if (typeof value === 'function') { 33 this.emitScalar('Function'); 34 } else if (typeof value.nodeType === 'number') { 35 this.emitScalar('HTMLNode'); 36 } else if (value instanceof Date) { 37 this.emitScalar('Date(' + value + ')'); 38 } else if (value instanceof RegExp) { 39 this.emitScalar(value.toString()); 40 } else if (value.__Jasmine_been_here_before__) { 41 this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>'); 42 } else if (jasmine.isArray_(value) || typeof value == 'object') { 43 value.__Jasmine_been_here_before__ = true; 44 if (jasmine.isArray_(value)) { 45 this.emitArray(value); 46 } else { 47 this.emitObject(value); 48 } 49 delete value.__Jasmine_been_here_before__; 50 } else { 51 this.emitScalar(value.toString()); 52 } 53 } finally { 54 this.ppNestLevel_--; 55 } 56 }; 57 58 jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { 59 for (var property in obj) { 60 if (property == '__Jasmine_been_here_before__') continue; 61 fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) != null) : false); 62 } 63 }; 64 65 jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; 66 jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; 67 jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; 68 jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; 69 70 jasmine.StringPrettyPrinter = function() { 71 jasmine.PrettyPrinter.call(this); 72 73 this.string = ''; 74 }; 75 jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); 76 77 jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { 78 this.append(value); 79 }; 80 81 jasmine.StringPrettyPrinter.prototype.emitString = function(value) { 82 this.append("'" + value + "'"); 83 }; 84 85 jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { 86 this.append('[ '); 87 for (var i = 0; i < array.length; i++) { 88 if (i > 0) { 89 this.append(', '); 90 } 91 this.format(array[i]); 92 } 93 this.append(' ]'); 94 }; 95 96 jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { 97 var self = this; 98 this.append('{ '); 99 var first = true; 100 101 this.iterateObject(obj, function(property, isGetter) { 102 if (first) { 103 first = false; 104 } else { 105 self.append(', '); 106 } 107 108 self.append(property); 109 self.append(' : '); 110 if (isGetter) { 111 self.append('<getter>'); 112 } else { 113 self.format(obj[property]); 114 } 115 }); 116 117 this.append(' }'); 118 }; 119 120 jasmine.StringPrettyPrinter.prototype.append = function(value) { 121 this.string += value; 122 }; 123