c1a3fc9bf05d489efa7ba13c00b6ba21756120db
[platform/framework/web/crosswalk-tizen.git] /
1 /*
2   Copyright (C) 2012 Ariya Hidayat <ariya.hidayat@gmail.com>
3   Copyright (C) 2012 Joost-Wim Boekesteijn <joost-wim@boekesteijn.nl>
4   Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
5   Copyright (C) 2012 Arpad Borsos <arpad.borsos@googlemail.com>
6   Copyright (C) 2011 Ariya Hidayat <ariya.hidayat@gmail.com>
7   Copyright (C) 2011 Yusuke Suzuki <utatane.tea@gmail.com>
8   Copyright (C) 2011 Arpad Borsos <arpad.borsos@googlemail.com>
9
10   Redistribution and use in source and binary forms, with or without
11   modification, are permitted provided that the following conditions are met:
12
13     * Redistributions of source code must retain the above copyright
14       notice, this list of conditions and the following disclaimer.
15     * Redistributions in binary form must reproduce the above copyright
16       notice, this list of conditions and the following disclaimer in the
17       documentation and/or other materials provided with the distribution.
18
19   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22   ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 /*jslint browser:true node:true */
32 /*global esprima:true, testFixture:true */
33
34 var runTests;
35
36 // Special handling for regular expression literal since we need to
37 // convert it to a string literal, otherwise it will be decoded
38 // as object "{}" and the regular expression would be lost.
39 function adjustRegexLiteral(key, value) {
40     'use strict';
41     if (key === 'value' && value instanceof RegExp) {
42         value = value.toString();
43     }
44     return value;
45 }
46
47 function NotMatchingError(expected, actual) {
48     'use strict';
49     Error.call(this, 'Expected ');
50     this.expected = expected;
51     this.actual = actual;
52 }
53 NotMatchingError.prototype = new Error();
54
55 function errorToObject(e) {
56     'use strict';
57     var msg = e.toString();
58
59     // Opera 9.64 produces an non-standard string in toString().
60     if (msg.substr(0, 6) !== 'Error:') {
61         if (typeof e.message === 'string') {
62             msg = 'Error: ' + e.message;
63         }
64     }
65
66     return {
67         index: e.index,
68         lineNumber: e.lineNumber,
69         column: e.column,
70         message: msg
71     };
72 }
73
74 function testParse(esprima, code, syntax) {
75     'use strict';
76     var expected, tree, actual, options, StringObject, i, len, err;
77
78     // alias, so that JSLint does not complain.
79     StringObject = String;
80
81     options = {
82         comment: (typeof syntax.comments !== 'undefined'),
83         range: true,
84         loc: true,
85         tokens: (typeof syntax.tokens !== 'undefined'),
86         raw: true,
87         tolerant: (typeof syntax.errors !== 'undefined')
88     };
89
90     if (typeof syntax.tokens !== 'undefined') {
91         if (syntax.tokens.length > 0) {
92             options.range = (typeof syntax.tokens[0].range !== 'undefined');
93             options.loc = (typeof syntax.tokens[0].loc !== 'undefined');
94         }
95     }
96
97     if (typeof syntax.comments !== 'undefined') {
98         if (syntax.comments.length > 0) {
99             options.range = (typeof syntax.comments[0].range !== 'undefined');
100             options.loc = (typeof syntax.comments[0].loc !== 'undefined');
101         }
102     }
103
104     expected = JSON.stringify(syntax, null, 4);
105     try {
106         tree = esprima.parse(code, options);
107         tree = (options.comment || options.tokens || options.tolerant) ? tree : tree.body[0];
108
109         if (options.tolerant) {
110             for (i = 0, len = tree.errors.length; i < len; i += 1) {
111                 tree.errors[i] = errorToObject(tree.errors[i]);
112             }
113         }
114
115         actual = JSON.stringify(tree, adjustRegexLiteral, 4);
116
117         // Only to ensure that there is no error when using string object.
118         esprima.parse(new StringObject(code), options);
119
120     } catch (e) {
121         throw new NotMatchingError(expected, e.toString());
122     }
123     if (expected !== actual) {
124         throw new NotMatchingError(expected, actual);
125     }
126
127     function filter(key, value) {
128         if (key === 'value' && value instanceof RegExp) {
129             value = value.toString();
130         }
131         return (key === 'loc' || key === 'range') ? undefined : value;
132     }
133
134     if (options.tolerant) {
135         return;
136     }
137
138
139     // Check again without any location info.
140     options.range = false;
141     options.loc = false;
142     expected = JSON.stringify(syntax, filter, 4);
143     try {
144         tree = esprima.parse(code, options);
145         tree = (options.comment || options.tokens) ? tree : tree.body[0];
146
147         if (options.tolerant) {
148             for (i = 0, len = tree.errors.length; i < len; i += 1) {
149                 tree.errors[i] = errorToObject(tree.errors[i]);
150             }
151         }
152
153         actual = JSON.stringify(tree, filter, 4);
154     } catch (e) {
155         throw new NotMatchingError(expected, e.toString());
156     }
157     if (expected !== actual) {
158         throw new NotMatchingError(expected, actual);
159     }
160 }
161
162 function testError(esprima, code, exception) {
163     'use strict';
164     var i, options, expected, actual, handleInvalidRegexFlag;
165
166     // Different parsing options should give the same error.
167     options = [
168         {},
169         { comment: true },
170         { raw: true },
171         { raw: true, comment: true }
172     ];
173
174     // If handleInvalidRegexFlag is true, an invalid flag in a regular expression
175     // will throw an exception. In some old version V8, this is not the case
176     // and hence handleInvalidRegexFlag is false.
177     handleInvalidRegexFlag = false;
178     try {
179         'test'.match(new RegExp('[a-z]', 'x'));
180     } catch (e) {
181         handleInvalidRegexFlag = true;
182     }
183
184     expected = JSON.stringify(exception);
185
186     for (i = 0; i < options.length; i += 1) {
187
188         try {
189             esprima.parse(code, options[i]);
190         } catch (e) {
191             actual = JSON.stringify(errorToObject(e));
192         }
193
194         if (expected !== actual) {
195
196             // Compensate for old V8 which does not handle invalid flag.
197             if (exception.message.indexOf('Invalid regular expression') > 0) {
198                 if (typeof actual === 'undefined' && !handleInvalidRegexFlag) {
199                     return;
200                 }
201             }
202
203             throw new NotMatchingError(expected, actual);
204         }
205
206     }
207 }
208
209 function testAPI(esprima, code, result) {
210     'use strict';
211     var expected, res, actual;
212
213     expected = JSON.stringify(result.result, null, 4);
214     try {
215         if (typeof result.property !== 'undefined') {
216             res = esprima[result.property];
217         } else {
218             res = esprima[result.call].apply(esprima, result.args);
219         }
220         actual = JSON.stringify(res, adjustRegexLiteral, 4);
221     } catch (e) {
222         throw new NotMatchingError(expected, e.toString());
223     }
224     if (expected !== actual) {
225         throw new NotMatchingError(expected, actual);
226     }
227 }
228
229 function runTest(esprima, code, result) {
230     'use strict';
231     if (result.hasOwnProperty('lineNumber')) {
232         testError(esprima, code, result);
233     } else if (result.hasOwnProperty('result')) {
234         testAPI(esprima, code, result);
235     } else {
236         testParse(esprima, code, result);
237     }
238 }
239
240 if (typeof window !== 'undefined') {
241     // Run all tests in a browser environment.
242     runTests = function () {
243         'use strict';
244         var total = 0,
245             failures = 0,
246             category,
247             fixture,
248             source,
249             tick,
250             expected,
251             index,
252             len;
253
254         function setText(el, str) {
255             if (typeof el.innerText === 'string') {
256                 el.innerText = str;
257             } else {
258                 el.textContent = str;
259             }
260         }
261
262         function startCategory(category) {
263             var report, e;
264             report = document.getElementById('report');
265             e = document.createElement('h4');
266             setText(e, category);
267             report.appendChild(e);
268         }
269
270         function reportSuccess(code) {
271             var report, e;
272             report = document.getElementById('report');
273             e = document.createElement('pre');
274             e.setAttribute('class', 'code');
275             setText(e, code);
276             report.appendChild(e);
277         }
278
279         function reportFailure(code, expected, actual) {
280             var report, e;
281
282             report = document.getElementById('report');
283
284             e = document.createElement('p');
285             setText(e, 'Code:');
286             report.appendChild(e);
287
288             e = document.createElement('pre');
289             e.setAttribute('class', 'code');
290             setText(e, code);
291             report.appendChild(e);
292
293             e = document.createElement('p');
294             setText(e, 'Expected');
295             report.appendChild(e);
296
297             e = document.createElement('pre');
298             e.setAttribute('class', 'expected');
299             setText(e, expected);
300             report.appendChild(e);
301
302             e = document.createElement('p');
303             setText(e, 'Actual');
304             report.appendChild(e);
305
306             e = document.createElement('pre');
307             e.setAttribute('class', 'actual');
308             setText(e, actual);
309             report.appendChild(e);
310         }
311
312         setText(document.getElementById('version'), esprima.version);
313
314         tick = new Date();
315         for (category in testFixture) {
316             if (testFixture.hasOwnProperty(category)) {
317                 startCategory(category);
318                 fixture = testFixture[category];
319                 for (source in fixture) {
320                     if (fixture.hasOwnProperty(source)) {
321                         expected = fixture[source];
322                         total += 1;
323                         try {
324                             runTest(esprima, source, expected);
325                             reportSuccess(source, JSON.stringify(expected, null, 4));
326                         } catch (e) {
327                             failures += 1;
328                             reportFailure(source, e.expected, e.actual);
329                         }
330                     }
331                 }
332             }
333         }
334         tick = (new Date()) - tick;
335
336         if (failures > 0) {
337             setText(document.getElementById('status'), total + ' tests. ' +
338                 'Failures: ' + failures + '. ' + tick + ' ms');
339         } else {
340             setText(document.getElementById('status'), total + ' tests. ' +
341                 'No failure. ' + tick + ' ms');
342         }
343     };
344 } else {
345     (function () {
346         'use strict';
347
348         var esprima = require('../esprima'),
349             vm = require('vm'),
350             fs = require('fs'),
351             total = 0,
352             failures = [],
353             tick = new Date(),
354             expected,
355             header;
356
357         vm.runInThisContext(fs.readFileSync(__dirname + '/test.js', 'utf-8'));
358
359         Object.keys(testFixture).forEach(function (category) {
360             Object.keys(testFixture[category]).forEach(function (source) {
361                 total += 1;
362                 expected = testFixture[category][source];
363                 try {
364                     runTest(esprima, source, expected);
365                 } catch (e) {
366                     e.source = source;
367                     failures.push(e);
368                 }
369             });
370         });
371         tick = (new Date()) - tick;
372
373         header = total + ' tests. ' + failures.length + ' failures. ' +
374             tick + ' ms';
375         if (failures.length) {
376             console.error(header);
377             failures.forEach(function (failure) {
378                 console.error(failure.source + ': Expected\n    ' +
379                     failure.expected.split('\n').join('\n    ') +
380                     '\nto match\n    ' + failure.actual);
381             });
382         } else {
383             console.log(header);
384         }
385         process.exit(failures.length === 0 ? 0 : 1);
386     }());
387 }