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  * @returns {String}
 13  */
 14 jasmine.PrettyPrinter.prototype.format = function(value) {
 15   if (this.ppNestLevel_ > 40) {
 16     //    return '(jasmine.pp nested too deeply!)';
 17     throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
 18   }
 19 
 20   this.ppNestLevel_++;
 21   try {
 22     if (value === undefined) {
 23       this.emitScalar('undefined');
 24     } else if (value === null) {
 25       this.emitScalar('null');
 26     } else if (value.navigator && value.frames && value.setTimeout) {
 27       this.emitScalar('<window>');
 28     } else if (value instanceof jasmine.Matchers.Any) {
 29       this.emitScalar(value.toString());
 30     } else if (typeof value === 'string') {
 31       this.emitString(value);
 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.__Jasmine_been_here_before__) {
 39       this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
 40     } else if (jasmine.isArray_(value) || typeof value == 'object') {
 41       value.__Jasmine_been_here_before__ = true;
 42       if (jasmine.isArray_(value)) {
 43         this.emitArray(value);
 44       } else {
 45         this.emitObject(value);
 46       }
 47       delete value.__Jasmine_been_here_before__;
 48     } else {
 49       this.emitScalar(value.toString());
 50     }
 51   } finally {
 52     this.ppNestLevel_--;
 53   }
 54 };
 55 
 56 jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
 57   for (var property in obj) {
 58     if (property == '__Jasmine_been_here_before__') continue;
 59     fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) != null) : false);
 60   }
 61 };
 62 
 63 jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
 64 jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
 65 jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
 66 jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
 67 
 68 jasmine.StringPrettyPrinter = function() {
 69   jasmine.PrettyPrinter.call(this);
 70 
 71   this.string = '';
 72 };
 73 jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
 74 
 75 jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
 76   this.append(value);
 77 };
 78 
 79 jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
 80   this.append("'" + value + "'");
 81 };
 82 
 83 jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
 84   this.append('[ ');
 85   for (var i = 0; i < array.length; i++) {
 86     if (i > 0) {
 87       this.append(', ');
 88     }
 89     this.format(array[i]);
 90   }
 91   this.append(' ]');
 92 };
 93 
 94 jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
 95   var self = this;
 96   this.append('{ ');
 97   var first = true;
 98 
 99   this.iterateObject(obj, function(property, isGetter) {
100     if (first) {
101       first = false;
102     } else {
103       self.append(', ');
104     }
105 
106     self.append(property);
107     self.append(' : ');
108     if (isGetter) {
109       self.append('<getter>');
110     } else {
111       self.format(obj[property]);
112     }
113   });
114 
115   this.append(' }');
116 };
117 
118 jasmine.StringPrettyPrinter.prototype.append = function(value) {
119   this.string += value;
120 };
121