1 | 'use strict'
|
2 |
|
3 | var Assert = require('./assert').Assert
|
4 | , Log = require('./log').Log
|
5 |
|
6 | , ERR_COMPLETED_ASSERT = 'Assert in completed test'
|
7 | , ERR_COMPLETED_COMPLETE = 'Attemt to complete test more then one times'
|
8 | , ERR_EXPECT = 'AssertionError'
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | function Test(options) {
|
14 | var self = Object.create(Test.prototype,
|
15 | { name: { value: options.name }
|
16 | , mute: { value: options.mute }
|
17 | , unit: { value: options.unit }
|
18 | , log: { value: options.log }
|
19 | , passes: { value: [] }
|
20 | , fails: { value: [] }
|
21 | , errors: { value: [] }
|
22 | })
|
23 | self.assert = options.Assert(self)
|
24 | return self
|
25 | }
|
26 | Test.prototype =
|
27 | { constructor: Test
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | , name: null
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 | , log: null
|
39 |
|
40 |
|
41 |
|
42 |
|
43 | , unit: null
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | , fails: null
|
49 |
|
50 |
|
51 |
|
52 |
|
53 | , errors: null
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | , passes: null
|
59 |
|
60 |
|
61 |
|
62 |
|
63 | , completed: false
|
64 | , pass: function pass(message) {
|
65 | message = message || ''
|
66 | if (this.completed) return this.error(new Error(ERR_COMPLETED_ASSERT))
|
67 | this.passes.push(message)
|
68 | if (!this.mute) this.log.pass(message)
|
69 | }
|
70 | , fail: function fail(e) {
|
71 | if (this.completed) return this.error(new Error(ERR_COMPLETED_ASSERT))
|
72 | this.fails.push(e)
|
73 | if (!this.mute) this.log.fail(e)
|
74 | }
|
75 | , error: function error(e) {
|
76 | this.errors.push(e)
|
77 | if (!this.mute) this.log.error(e)
|
78 | }
|
79 | , complete: function complete(callback) {
|
80 | if (this.completed) return this.error(new Error(ERR_COMPLETED_COMPLETE))
|
81 | callback(this, this.completed = true)
|
82 | }
|
83 | , run: function run(callback) {
|
84 | var unit = this.unit
|
85 | , sync = unit.length <= 1
|
86 | , failFast = unit.length == 0
|
87 | , assert = this.assert
|
88 | , complete = this.complete = this.complete.bind(this, callback)
|
89 | try {
|
90 | if (!this.mute) this.log.print(this.name)
|
91 | unit(assert, complete)
|
92 | if (failFast) this.pass()
|
93 | if (sync) this.complete()
|
94 | } catch(e) {
|
95 | if (ERR_EXPECT == e.name) assert.fail(e)
|
96 | else assert.error(e)
|
97 | this.complete()
|
98 | }
|
99 | }
|
100 | }
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 | function Suite(options) {
|
117 | var log = options.log
|
118 | , units = []
|
119 | , unitMap = options.units
|
120 |
|
121 | for (var name in unitMap) {
|
122 | if (0 !== name.indexOf('test')) continue
|
123 | var unit = unitMap[name]
|
124 | units.push(('function' == typeof unit ? Test : Suite)(
|
125 | { name: name
|
126 | , mute: options.mute
|
127 | , units: unit
|
128 | , unit: unit
|
129 | , Assert: unitMap.Assert || Assert
|
130 | , log: log.section()
|
131 | }))
|
132 | }
|
133 |
|
134 | return Object.create(Suite.prototype,
|
135 | { name: { value: options.name }
|
136 | , mute: { value: options.mute }
|
137 | , log: { value: log }
|
138 | , units: { value: units }
|
139 | })
|
140 | }
|
141 | Suite.prototype = Object.create(
|
142 | { constructor: Suite
|
143 | |
144 |
|
145 |
|
146 |
|
147 | , name: null
|
148 | |
149 |
|
150 |
|
151 |
|
152 |
|
153 | , log: null
|
154 | |
155 |
|
156 |
|
157 |
|
158 | , fails: null
|
159 | |
160 |
|
161 |
|
162 |
|
163 | , errors: null
|
164 | |
165 |
|
166 |
|
167 |
|
168 | , passes: null
|
169 | |
170 |
|
171 |
|
172 |
|
173 | , units: null
|
174 | |
175 |
|
176 |
|
177 |
|
178 | , index: 0
|
179 | |
180 |
|
181 |
|
182 |
|
183 | , complete: null
|
184 | |
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 | , run: function run(callback) {
|
191 | if (!this.mute) this.log.print(this.name)
|
192 | this.complete = callback
|
193 | this.next = this.next.bind(this)
|
194 | this.next()
|
195 | }
|
196 | |
197 |
|
198 |
|
199 |
|
200 | , next: function next() {
|
201 | var units = this.units
|
202 | if (this.index < units.length) {
|
203 | units[this.index ++].run(this.next)
|
204 | }
|
205 | else this.complete(this)
|
206 | }
|
207 | }
|
208 | , { passes: { get: UnitedProprerty('passes') }
|
209 | , fails: { get: UnitedProprerty('fails') }
|
210 | , errors: { get: UnitedProprerty('errors') }
|
211 | }
|
212 | )
|
213 |
|
214 | function UnitedProprerty(name) {
|
215 | return function Property() {
|
216 | return this.units.reduce(function(value, unit) {
|
217 | return value.concat(unit[name])
|
218 | }, [])
|
219 | }
|
220 | }
|
221 |
|
222 |
|
223 |
|
224 |
|
225 | function run(units, callback) {
|
226 | var log = Log()
|
227 | Suite(
|
228 | { name: 'Running all tests:'
|
229 | , units: units
|
230 | , mute: units.mute === true
|
231 | , log: log
|
232 | }
|
233 | ).run(function(suite) {
|
234 | if (callback) return callback(suite)
|
235 | if (suite.mute) return
|
236 | log.print
|
237 | ( 'Passed:' + suite.passes.length
|
238 | + ' Failed:' + suite.fails.length
|
239 | + ' Errors:' + suite.errors.length
|
240 | )
|
241 | })
|
242 | }
|
243 | exports.run = run
|