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.emitScalar("'" + 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__(property) != null);
 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 
 67 jasmine.StringPrettyPrinter = function() {
 68   jasmine.PrettyPrinter.call(this);
 69 
 70   this.string = '';
 71 };
 72 jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
 73 
 74 jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
 75   this.append(value);
 76 };
 77 
 78 jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
 79   this.append('[ ');
 80   for (var i = 0; i < array.length; i++) {
 81     if (i > 0) {
 82       this.append(', ');
 83     }
 84     this.format(array[i]);
 85   }
 86   this.append(' ]');
 87 };
 88 
 89 jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
 90   var self = this;
 91   this.append('{ ');
 92   var first = true;
 93 
 94   this.iterateObject(obj, function(property, isGetter) {
 95     if (first) {
 96       first = false;
 97     } else {
 98       self.append(', ');
 99     }
100 
101     self.append(property);
102     self.append(' : ');
103     if (isGetter) {
104       self.append('<getter>');
105     } else {
106       self.format(obj[property]);
107     }
108   });
109 
110   this.append(' }');
111 };
112 
113 jasmine.StringPrettyPrinter.prototype.append = function(value) {
114   this.string += value;
115 };
116