'use strict';
(function (root, factory) {
if (typeof module === 'object' && module.exports) {
module.exports = factory(
require('../../'),
require('./error-to-object')
);
} else {
root.evaluateTestCase = factory(esprima, errorToObject);
}
}(this, function (esprima, errorToObject) {
function NotMatchingError(expected, actual) {
Error.call(this, 'Expected ');
this.expected = expected;
this.actual = actual;
}
NotMatchingError.prototype = new Error();
function assertEquality(expected, actual) {
if (expected !== actual) {
throw new NotMatchingError(expected, actual);
}
}
function sortedObject(o) {
var keys, result;
if (o === null) {
return o;
}
if (Array.isArray(o)) {
return o.map(sortedObject);
}
if (typeof o !== 'object') {
return o;
}
if (o instanceof RegExp) {
return o;
}
keys = Object.keys(o);
result = {
range: undefined,
loc: undefined
};
keys.forEach(function (key) {
if (o.hasOwnProperty(key)) {
result[key] = sortedObject(o[key]);
if (key === 'value' && o.hasOwnProperty('regex')) {
if (o.regex.flags.match(/[uy]/)) {
result[key] = null;
}
}
}
});
return result;
}
function hasAttachedComment(syntax) {
var key;
for (key in syntax) {
if (key === 'leadingComments' || key === 'trailingComments' || key === 'innerComments') {
return true;
}
if (typeof syntax[key] === 'object' && syntax[key] !== null) {
if (hasAttachedComment(syntax[key])) {
return true;
}
}
}
return false;
}
function testParse(code, syntax) {
'use strict';
var expected, tree, actual, options, i, len, nodes;
options = {
jsx: true,
comment: (typeof syntax.comments !== 'undefined'),
range: true,
loc: true,
tokens: true,
raw: true,
tolerant: (typeof syntax.errors !== 'undefined'),
source: null,
sourceType: syntax.sourceType
};
if (options.comment) {
options.attachComment = hasAttachedComment(syntax);
}
if (typeof syntax.tokens !== 'undefined') {
if (syntax.tokens.length > 0) {
options.range = (typeof syntax.tokens[0].range !== 'undefined');
options.loc = (typeof syntax.tokens[0].loc !== 'undefined');
}
}
if (typeof syntax.comments !== 'undefined') {
if (syntax.comments.length > 0) {
options.range = (typeof syntax.comments[0].range !== 'undefined');
options.loc = (typeof syntax.comments[0].loc !== 'undefined');
}
}
if (options.loc) {
options.source = syntax.loc.source;
}
syntax = sortedObject(syntax);
expected = JSON.stringify(syntax, null, 4);
try {
tree = esprima.parse(code, { jsx: options.jsx, tolerant: options.tolerant, sourceType: options.sourceType });
tree = esprima.parse(code, { jsx: options.jsx, tolerant: options.tolerant, sourceType: options.sourceType, range: true });
tree = esprima.parse(code, { jsx: options.jsx, tolerant: options.tolerant, sourceType: options.sourceType, loc: true });
tree = (options.sourceType === 'script') ? esprima.parseScript(code, options) : esprima.parseModule(code, options);
esprima.parse(code, options);
if (options.tolerant) {
for (i = 0, len = tree.errors.length; i < len; i += 1) {
tree.errors[i] = errorToObject(tree.errors[i]);
}
}
tree = sortedObject(tree);
actual = JSON.stringify(tree, null, 4);
esprima.parse(new String(code), options);
} catch (e) {
throw new NotMatchingError(expected, e.toString());
}
assertEquality(expected, actual);
function filter(key, value) {
return (key === 'loc' || key === 'range') ? undefined : value;
}
if (options.tolerant) {
return;
}
options.range = false;
options.loc = false;
syntax = sortedObject(syntax);
expected = JSON.stringify(syntax, filter, 4);
try {
tree = esprima.parse(code, options);
if (options.tolerant) {
for (i = 0, len = tree.errors.length; i < len; i += 1) {
tree.errors[i] = errorToObject(tree.errors[i]);
}
}
tree = sortedObject(tree);
actual = JSON.stringify(tree, filter, 4);
} catch (e) {
throw new NotMatchingError(expected, e.toString());
}
assertEquality(expected, actual);
function collect(node) {
nodes.push(node);
}
function filter(node) {
if (node.type === 'Program') {
nodes.push(node);
}
}
try {
nodes = [];
esprima.parse(code, options, collect);
} catch (e) {
throw new NotMatchingError(expected, e.toString());
}
assertEquality('Program', nodes.pop().type);
try {
nodes = [];
esprima.parse(code, options, filter);
} catch (e) {
throw new NotMatchingError(expected, e.toString());
}
assertEquality('Program', nodes[0].type);
try {
esprima.parse(code);
(options.sourceType === 'module') ? esprima.parseModule(code) : esprima.parseScript(code);
esprima.parse(code, { range: false, loc: false, comment: false }, filter);
esprima.parse(code, { range: true, loc: false, comment: false }, filter);
esprima.parse(code, { range: false, loc: true, comment: false }, filter);
esprima.parse(code, { range: true, loc: true, comment: false }, filter);
esprima.parse(code, { range: false, loc: false, comment: true }, filter);
esprima.parse(code, { range: true, loc: false, comment: true }, filter);
esprima.parse(code, { range: false, loc: true, comment: true }, filter);
esprima.parse(code, { range: true, loc: true, comment: true }, filter);
} catch (e) {
}
}
function testTokenize(code, tokens) {
'use strict';
var options, expected, actual, list, entries, types;
options = {
comment: true,
tolerant: true,
loc: true,
range: true
};
expected = JSON.stringify(tokens, null, 4);
try {
esprima.tokenize(code, { tolerant: true, comment: false, loc: false, range: false });
esprima.tokenize(code, { tolerant: true, comment: false, loc: false, range: true });
esprima.tokenize(code, { tolerant: true, comment: false, loc: true, range: false });
esprima.tokenize(code, { tolerant: true, comment: false, loc: true, range: true });
esprima.tokenize(code, { tolerant: true, comment: true, loc: false, range: false });
esprima.tokenize(code, { tolerant: true, comment: true, loc: false, range: true });
esprima.tokenize(code, { tolerant: true, comment: true, loc: true, range: false });
list = esprima.tokenize(code, options);
actual = JSON.stringify(list, null, 4);
} catch (e) {
throw new NotMatchingError(expected, e.toString());
}
if (expected !== actual) {
throw new NotMatchingError(expected, actual);
}
try {
entries = [];
esprima.tokenize(code, options, function (token) {
entries.push(token);
return token;
});
actual = JSON.stringify(entries, null, 4);
} catch (e) {
throw new NotMatchingError(expected, e.toString());
}
if (expected !== actual) {
throw new NotMatchingError(expected, actual);
}
try {
entries = esprima.tokenize(code, options, function (token) {
return token.type;
});
actual = JSON.stringify(entries, null, 4);
} catch (e) {
throw new NotMatchingError(expected, e.toString());
}
types = tokens.map(function (t) {
return t.type;
});
expected = JSON.stringify(types, null, 4);
if (expected !== actual) {
throw new NotMatchingError(expected, actual);
}
try {
esprima.tokenize(code);
esprima.tokenize(code, { tolerant: false });
} catch (e) {
}
}
function testError(testCase) {
'use strict';
var sourceType, i, options, exception, expected, code, actual, err, handleInvalidRegexFlag, tokenize;
sourceType = testCase.key.match(/\.module$/) ? 'module' : 'script';
options = [
{ jsx: true, sourceType: sourceType },
{ jsx: true, comment: true, sourceType: sourceType },
{ jsx: true, raw: true, sourceType: sourceType },
{ jsx: true, raw: true, comment: true, sourceType: sourceType }
];
handleInvalidRegexFlag = false;
try {
'test'.match(new RegExp('[a-z]', 'x'));
} catch (e) {
handleInvalidRegexFlag = true;
}
exception = testCase.failure;
exception.description = exception.message.replace(/Error: Line [0-9]+: /, '');
if (exception.tokenize) {
tokenize = true;
exception.tokenize = undefined;
}
expected = JSON.stringify(exception);
code = testCase.case || testCase.source || '';
for (i = 0; i < options.length; i += 1) {
try {
if (tokenize) {
esprima.tokenize(code, options[i]);
} else {
esprima.parse(code, options[i]);
}
} catch (e) {
err = errorToObject(e);
err.description = e.description;
actual = JSON.stringify(err);
}
if (expected !== actual) {
if (exception.message.indexOf('Invalid regular expression') > 0) {
if (typeof actual === 'undefined' && !handleInvalidRegexFlag) {
return;
}
}
throw new NotMatchingError(expected, actual);
}
}
}
return function (testCase) {
var code = testCase.case || testCase.source || "";
if (testCase.hasOwnProperty('tree')) {
testParse(code, testCase.tree);
} else if (testCase.hasOwnProperty('tokens')) {
testTokenize(testCase.case, testCase.tokens);
} else if (testCase.hasOwnProperty('failure')) {
testError(testCase);
}
}
}));