Name: js-handler/node_modules/nodeunit/node_modules/tap/lib/tap-harness.js 
1:
// a thing that runs tests.
2:
// Every "test" is also a harness.  If they do not have a harness,
3:
// then they are attached to the defaut "global harness",
4:
// which writes its results to stdout.
5:
 
6:
 
7:
// TODO:
8:
// - Bailout should stop running any tests.
9:
// - "skip" in the test config obj should skip it.
10:
 
11:
module.exports = Harness
12:
var EE = require("events").EventEmitter
13:
require("inherits")(Harness, EE)
14:
 
15:
var Results = require("./tap-results")
16:
  , TapProducer = require("./tap-producer")
17:
  , assert = require("./tap-assert")
18:
 
19:
function Harness (Test) {
20:
  if (!(this instanceof Harness)) return new Harness(Test)
21:
 
22:
  //console.error("Test in "+this.constructor.name, Test)
23:
 
24:
  this._Test = Test
25:
  this._plan = null
26:
  this._children = []
27:
  this._started = false
28:
 
29:
  this._testCount = 0
30:
  this._planSum = 0
31:
 
32:
  this.results = new Results()
33:
  // emit result events on the harness.
34:
  //this.results.on("result", function (res) {
35:
  //  console.error("proxying result ev from res to harness")
36:
  //  this.emit("result", res)
37:
  //}.bind(this))
38:
  var me = this
39:
  this.results.on("result", this.emit.bind(this, "result"))
40:
 
41:
  var p = this.process.bind(this)
42:
  this.process = function () {
43:
    this._started = true
44:
    process.nextTick(p)
45:
  }
46:
 
47:
  this.output = new TapProducer()
48:
  EE.call(this)
49:
}
50:
 
51:
// this function actually only gets called bound to
52:
// the Harness object, and on process.nextTick.  Even if
53:
// passed as an event handler, everything *else* will
54:
// happen before it gets called.
55:
Harness.prototype.process = function () {
56:
  //console.error("harness process")
57:
  // "end" can emit multiple times, so only actually move on
58:
  // to the next test if the current one is actually over.
59:
  // TODO: multiple in-process tests, if all are marked "async"
60:
  if (this._current) {
61:
    if (!this._current._ended) return
62:
    // handle the current one before moving onto the next.
63:
    this.childEnd(this._current)
64:
  }
65:
  var skip = true
66:
  while (skip) {
67:
    //console.error("checking for skips")
68:
    var current = this._current = this._children.shift()
69:
    if (current) {
70:
      skip = current.conf.skip
71:
      if (skip) {
72:
        //console.error("add a failure for the skipping")
73:
        this.results.add(assert.fail(current.conf.name
74:
                                    ,{skip:true, diag:false}))
75:
      }
76:
    } else skip = false
77:
  }
78:
 
79:
  // keep processing through skipped tests, instead of running them.
80:
  if (current && this._bailedOut) {
81:
    return this.process()
82:
  }
83:
 
84:
  //console.error("got current?", !!current)
85:
  if (current) {
86:
    current.on("end", this.process)
87:
    current.emit("ready")
88:
    //console.error("emitted ready")
89:
    //console.error("_plan", this._plan, this.constructor.name)
90:
  } else {
91:
    //console.error("Harness process: no more left.  ending")
92:
    if (this._endNice) {
93:
      this._endNice()
94:
    } else {
95:
      this.end()
96:
    }
97:
  }
98:
}
99:
 
100:
Harness.prototype.end = function () {
101:
  if (this._children.length) {
102:
    return this.process()
103:
  }
104:
  //console.error("harness end", this.constructor.name)
105:
  if (this._bailedOut) return
106:
 
107:
  // can't call .end() more than once.
108:
  if (this._ended) {
109:
    //console.error("adding failure for end calling")
110:
    this.results.add(assert.fail("end called more than once"))
111:
  }
112:
 
113:
  // see if the plan is completed properly, if there was one.
114:
  if (this._plan !== null) {
115:
    var total = this._testCount
116:
    if (total !== this._plan) {
117:
      this.results.add(assert.equal(total, this._plan, "test count != plan"))
118:
    }
119:
    this._plan = total
120:
  }
121:
 
122:
  //console.error("setting ended true", this.constructor.name)
123:
  this._ended = true
124:
  this.emit("end")
125:
}
126:
 
127:
Harness.prototype.plan = function (p) {
128:
  //console.error("setting plan", new Error().stack)
129:
  if (this._plan !== null) {
130:
    //console.error("about to add failure for calling plan")
131:
    return this.results.add(assert.fail("plan set multiple times"))
132:
  }
133:
  this._plan = p
134:
  if (p === 0 || this.results.testsTotal) {
135:
    this.end()
136:
  }
137:
}
138:
 
139:
Harness.prototype.childEnd = function (child) {
140:
  //console.error("childEnd")
141:
  this._testCount ++
142:
  this._planSum += child._plan
143:
  //console.error("adding set of child.results")
144:
 
145:
  this.results.add(child.conf.name || "(unnamed test)")
146:
  this.results.addSet(child.results)
147:
  this.emit("childEnd", child)
148:
  // was this planned?
149:
  if (this._plan === this._testCount) {
150:
    //console.error("plan", [this._plan, this._testCount])
151:
    return this.end()
152:
  }
153:
}
154:
 
155:
function copyObj(o) {
156:
  var copied = {}
157:
  Object.keys(o).forEach(function (k) { copied[k] = o[k] })
158:
  return copied
159:
}
160:
 
161:
Harness.prototype.test = function test (name, conf, cb) {
162:
  if (this._bailedOut) return
163:
 
164:
  if (typeof conf === "function") cb = conf, conf = null
165:
  if (typeof name === "object") conf = name, name = null
166:
  if (typeof name === "function") cb = name, name = null
167:
 
168:
  conf = (conf ? copyObj(conf) : {})
169:
  name = name || ""
170:
 
171:
  //console.error("making test", [name, conf, cb])
172:
 
173:
  // timeout: value in milliseconds. Defaults to 30s
174:
  // Set to Infinity to have no timeout.
175:
  if (isNaN(conf.timeout)) conf.timeout = 30000
176:
  var t = new this._Test(this, name, conf)
177:
  var self = this
178:
  if (cb) {
179:
    //console.error("attaching cb to ready event")
180:
    t.on("ready", function () {
181:
      if (!isNaN(conf.timeout) && isFinite(conf.timeout)) {
182:
        var timer = setTimeout(this.timeout.bind(this), conf.timeout)
183:
        var clear = function () {
184:
          clearTimeout(timer)
185:
        }
186:
        t.on("end", clear)
187:
        t.on("bailout", function (message) {
188:
          self.bailout(message)
189:
          clear()
190:
        })
191:
      }
192:
    })
193:
    t.on("ready", cb.bind(t, t))
194:
    // proxy the child results to this object.
195:
    //t.on("result", function (res) {
196:
    //  console.error("in harness, proxying result up")
197:
    //  t.results.add(res)
198:
    //})
199:
  }
200:
  return t
201:
}
202:
 
203:
Harness.prototype.bailout = function (message) {
204:
  // console.error("Harness bailout", this.constructor.name)
205:
  message = message || ""
206:
  //console.error("adding bailout message result")
207:
  this.results.add({bailout: message})
208:
  // console.error(">>> results after bailout" , this.results)
209:
  this._bailedOut = true
210:
  this.emit("bailout", message)
211:
  this.output.end({bailout: message})
212:
}
213:
 
214:
Harness.prototype.add = function (child) {
215:
  //console.error("adding child")
216:
  this._children.push(child)
217:
  if (!this._started) this.process()
218:
}
219:
 
220:
// the tearDown function is *always* guaranteed to happen.
221:
// Even if there's a bailout.
222:
Harness.prototype.tearDown = function (fn) {
223:
  this.on("end", fn)
224:
}