-
Notifications
You must be signed in to change notification settings - Fork 3
/
gjsunit.js
269 lines (219 loc) · 7.27 KB
/
gjsunit.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/// [Begin] Adapted from JsUnit
function _getStackTrace() {
var result = '';
// fake an exception so we can get Mozilla's error stack
try {
foo.bar;
}
catch(e) {
result = _parseStackTrace(e);
}
return result;
};
function _parseStackTrace(e) {
let result = '';
if ((e !== null) && (e.stack !== null)) {
let stacklist = e.stack.split('\n');
// We start at 2 because we don't need to get the 'getStackTrace' &
// 'GjsUnitException' lines
for (let i = 0; i < stacklist.length - 1; i++) {
let framedata = stacklist[i];
let line = ' at ';
let name = framedata.split('@')[0].replace('<', '');
line += name === '' ? '_anonymous_' : name;
line += " (";
line += framedata.substring(framedata.lastIndexOf('/') + 1);
line += ")";
result += line + '\n';
}
}
else {
result = 'No stack trace';
}
return result;
};
function GjsUnitException(message) {
this.isGjsUnitException = true;
this.message = message;
this.stackTrace = _getStackTrace();
};
function _processException(e, prefix) {
let result = '\n' + prefix + e.message;
if (e.stackTrace)
result += '\nStack trace:\n' + e.stackTrace;
return result;
};
// Assertion functions
function _assert(condition, message) {
if(!condition)
throw new GjsUnitException("GjsUnitException: " + message);
};
function assertNull(o) {
_assert(o === null, "The object should be null and is not");
};
function assertTrue(o) {
_assert(o === true, "The input should be true and is false");
};
function assertFalse(o) {
_assert(o === false, "The input should be false and is true");
};
function assertNotNull(o) {
_assert(o !== null, "The object is null and should not be");
};
function assertEquals(o1, o2) {
_assert(o1 === o2, "The objects are differents and should be equal");
};
function assertNotEquals(o1, o2) {
_assert(o1 !== o2, "The objects are same and should be differents");
};
function fail(message) {
_assert(false, message);
};
/// [End] Adapted from JsUnit
// A suite is a child of this class
const Suite = new imports.lang.Class({
Name: 'Suite',
// default constructor
_init: function(title) {
this._tests = null;
this._descriptions = null;
this._title = title;
instance.addSuite(this);
},
// This function is called before each test execution
// It is valid for all tests of this suite
// If a different setup is needed, write a new suite
setup: function() {
},
// This function is called after each test execution
// It is valid for all tests of this suite
// If a different teardown is needed, write a new suite
teardown: function() {
},
// Title property
get title() {
return this._title;
},
set title(title) {
this._title = title;
},
// Add a new test case to the suite
// @description of the test
// @f the test function, this function must take the suite as parameter
addTest: function(description, f) {
if(this._tests == null) {
this._tests = new Array();
this._descriptions = new Array();
}
this._descriptions.push(description);
this._tests.push(f);
},
// Writing this as a property would be better but I don't know how
// to code indexed properties in JS
getTestDescription: function(index) {
if(this._descriptions == null) {
return null;
} else if (index < 0 || index >= this._descriptions.length) {
throw new Error("Suite.test_description: Index is out of range");
} else {
return this._descriptions[index];
}
},
// Writing this as a property would be better but I don't know how
// to code indexed properties in JS
getTest: function(index) {
if(this._tests == null) {
return null;
} else if (index < 0 || index >= this._tests.length) {
throw new Error("Suite.test: Index is out of range");
} else {
return this._tests[index];
}
},
get nbTests() {
return this._tests == null ? 0 : this._tests.length;
}
});
// The test runner is a singleton
const Runner = new imports.lang.Class({
Name: 'Runner',
// default constructor
_init: function() {
this._suites = null;
this._instance = null;
},
addSuite: function(suite) {
if(this._suites == null) {
this._suites = new Array();
}
this._suites.push(suite);
},
run: function() {
if(this._suites == null) {
print("No test suite to run. End");
return;
}
let nbSuites = this._suites.length;
print("GjsUnit to run " + nbSuites + " suite(s)");
let gFailed = 0, gErrors = 0, gRun = 0;
for(let i = 0; i < nbSuites; i++) {
let aSuite = this._suites[i];
let nb = aSuite.nbTests;
let failed = 0, errors = 0;
gRun += nb;
print("Starting suite: " + aSuite.title + " - " + nb + " test(s) to run");
for(let j = 0; j < nb; j++) {
let test = "Test: " + aSuite.getTestDescription(j) + "..........";
let stack = '';
try {
aSuite.setup();
aSuite.getTest(j)();
aSuite.teardown();
test += "OK";
}
catch(e) {
if (typeof(e.isGjsUnitException) != 'undefined' && e.isGjsUnitException) {
stack += '\n' + e.message;
stack += '\n' + e.stackTrace;
failed++;
}
else {
stack += '\n' + e;
stack += '\n' + _parseStackTrace(e);
errors++;
}
test += "KO";
}
print(test);
if(stack.length > 0) {
print(stack);
}
};
// Display the results for the suite
let passed = nb - failed - errors;
let rate = (passed / nb * 100).toPrecision(4);
let trace = "Suite(" + rate + "%) - Run: " + nb + " - OK: " + passed + " - Failed: " + failed + " - Errors: " + errors;
print(this._createSep(trace.length));
print(trace);
gFailed += failed;
gErrors += errors;
};
// Output global results
let gPassed = gRun - gFailed - gErrors;
let gRate = (gPassed / gRun * 100).toPrecision(4);
let trace = "GLOBAL(" + gRate + "%) - Suites: " + nbSuites + " - Tests: " + gRun + " - OK: " + gPassed + " - Failed: " + gFailed + " - Errors: " + gErrors;
let sep = this._createSep(trace.length);
print(sep);
print(trace);
print(sep);
},
_createSep: function(length) {
let sep = new Array(length);
for(let i = 0; i < length; i++) {
sep[i] = '-';
};
return sep.join('');
},
});
// The runner is a singleton, use only this instance.
var instance = new Runner();