Ox.doc: change test object from {statement, result} to {statement, expected}, plus some refactoring; Ox.test: allow source, file, files, docObject or docObjects as first argument, make it testable and add a test, plus some refactoring; Ox.tokenize: add error type, continue lexing on error
This commit is contained in:
parent
38016aa06b
commit
5dc654ad6d
1 changed files with 150 additions and 90 deletions
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
/*@
|
/*@
|
||||||
Ox.doc <f> Generates documentation for annotated JavaScript
|
Ox.doc <f> Generates documentation for annotated JavaScript
|
||||||
(source) -> <[o]> Array of doc objects
|
(source[, callback]) -> <[o]> Array of doc objects
|
||||||
(file, callback) -> <u> undefined
|
(file, callback) -> <u> undefined
|
||||||
(files, callback) -> <u> undefined
|
(files, callback) -> <u> undefined
|
||||||
source <s> JavaScript source code
|
source <s> JavaScript source code
|
||||||
|
@ -35,6 +35,8 @@ Ox.doc <f> Generates documentation for annotated JavaScript
|
||||||
Present if the <code>type</code> of the item is
|
Present if the <code>type</code> of the item is
|
||||||
<code>"function"</code>.
|
<code>"function"</code>.
|
||||||
tests <[o]> Tests (array of test objects)
|
tests <[o]> Tests (array of test objects)
|
||||||
|
expected <s> Expected result
|
||||||
|
statement <s> Statement
|
||||||
type <s> Type of the item
|
type <s> Type of the item
|
||||||
<script>
|
<script>
|
||||||
Ox.test.doc = Ox.doc(
|
Ox.test.doc = Ox.doc(
|
||||||
|
@ -46,10 +48,14 @@ Ox.doc <f> Generates documentation for annotated JavaScript
|
||||||
' Bar per baz is a good indicator of an item\'s foo-ness.\n' +
|
' Bar per baz is a good indicator of an item\'s foo-ness.\n' +
|
||||||
' (item) -> <n> Bar per baz, or NaN\n' +
|
' (item) -> <n> Bar per baz, or NaN\n' +
|
||||||
' item <o> Any item\n' +
|
' item <o> Any item\n' +
|
||||||
|
' > My.foo({bar: 1, baz: 10})\n' +
|
||||||
|
' 0.1\n' +
|
||||||
|
' > My.foo({})\n' +
|
||||||
|
' NaN\n' +
|
||||||
'@*' + '/\n' +
|
'@*' + '/\n' +
|
||||||
'My.foo = function(item) {\n' +
|
'My.foo = function(item) {\n' +
|
||||||
' return item.bar / item.baz;\n' +
|
' return item.bar / item.baz;\n' +
|
||||||
'}'
|
'};'
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
> Ox.test.doc[0].name
|
> Ox.test.doc[0].name
|
||||||
|
@ -64,6 +70,8 @@ Ox.doc <f> Generates documentation for annotated JavaScript
|
||||||
['number']
|
['number']
|
||||||
> Ox.test.doc[1].usage[0].summary
|
> Ox.test.doc[1].usage[0].summary
|
||||||
'Bar per baz, or NaN'
|
'Bar per baz, or NaN'
|
||||||
|
> Ox.test.doc[1].tests[1]
|
||||||
|
{expected: 'NaN', statement: 'My.foo({})'}
|
||||||
@*/
|
@*/
|
||||||
Ox.doc = (function() {
|
Ox.doc = (function() {
|
||||||
var re = {
|
var re = {
|
||||||
|
@ -127,12 +135,12 @@ Ox.doc = (function() {
|
||||||
item.usage.push(parseNode(node));
|
item.usage.push(parseNode(node));
|
||||||
} else if (subitem.types[0] == 'event') {
|
} else if (subitem.types[0] == 'event') {
|
||||||
item.events = item.events || [];
|
item.events = item.events || [];
|
||||||
item.events.push(parseNode(node));
|
item.events.push(parseNode(node));
|
||||||
} else {
|
} else {
|
||||||
key = item.types[0] == 'function'
|
key = item.types[0] == 'function'
|
||||||
? 'arguments' : 'properties'
|
? 'arguments' : 'properties'
|
||||||
item[key] = item[key] || [];
|
item[key] = item[key] || [];
|
||||||
item[key].push(parseNode(node));
|
item[key].push(parseNode(node));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
item.description = item.description
|
item.description = item.description
|
||||||
|
@ -203,14 +211,14 @@ Ox.doc = (function() {
|
||||||
section = tree.line.split(' ')[0]
|
section = tree.line.split(' ')[0]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
function parseTest(string) {
|
function parseTest(string) {
|
||||||
// fixme: we cannot properly handle tests where a string contains '\n '
|
// fixme: we cannot properly handle tests where a string contains '\n '
|
||||||
var lines = decodeLinebreaks(string).split('\n ');
|
var lines = decodeLinebreaks(string).split('\n ');
|
||||||
return {
|
return {
|
||||||
statement: lines[0].slice(2),
|
statement: lines[0].slice(2),
|
||||||
result: lines[1].trim()
|
expected: lines[1].trim()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function parseTokens(tokens, includeLeadingLinebreaks) {
|
function parseTokens(tokens, includeLeadingLinebreaks) {
|
||||||
|
@ -311,18 +319,22 @@ Ox.doc = (function() {
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return function(/* source | file, callback | files, callback*/) {
|
return function(argument, callback) {
|
||||||
var source = arguments.length == 1 ? arguments[0] : void 0,
|
var counter = 0, items = [], ret;
|
||||||
files = arguments.length == 2 ? Ox.makeArray(arguments[0]) : void 0,
|
if (arguments.length == 1) {
|
||||||
callback = arguments[1],
|
ret = parseSource(argument);
|
||||||
counter = 0, items = [];
|
} else {
|
||||||
files && files.forEach(function(file) {
|
argument = Ox.makeArray(argument);
|
||||||
Ox.get(file, function(source) {
|
argument.forEach(function(file) {
|
||||||
items = items.concat(parseSource(source, file.split('?')[0]));
|
Ox.get(file, function(source) {
|
||||||
++counter == files.length && callback(items);
|
items = items.concat(
|
||||||
});
|
parseSource(source, file.split('?')[0])
|
||||||
});
|
);
|
||||||
return source ? parseSource(source) : void 0;
|
++counter == argument.length && callback(items);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
@ -567,91 +579,128 @@ Ox.minify = function() {
|
||||||
|
|
||||||
/*@
|
/*@
|
||||||
Ox.test <f> Takes JavaScript, runs inline tests, returns results
|
Ox.test <f> Takes JavaScript, runs inline tests, returns results
|
||||||
|
(source, callback) -> <[o]> Array of results
|
||||||
(file, callback) -> <u> undefined
|
(file, callback) -> <u> undefined
|
||||||
(files, callback) -> <u> undefines
|
(files, callback) -> <u> undefined
|
||||||
file <s> Path to JavaScript file
|
(doc, callback) -> <u> undefined
|
||||||
files <[s]> List of paths to J
|
(docs, callback) -> <u> undefined
|
||||||
|
source <s> JavaScript source
|
||||||
|
file <s> JavaScript file
|
||||||
|
files <[s]> Array of JavaScript files
|
||||||
|
doc <o> Documentation object (as returned by Ox.doc)
|
||||||
|
docs <[o]> Array of documentation objects (as returned by Ox.doc)
|
||||||
callback <f> Callback function
|
callback <f> Callback function
|
||||||
results [<o>] Array of results
|
results <[o]> Array of results
|
||||||
actual <s> Actual result
|
actual <s> Actual result
|
||||||
expected <s> Expected result
|
expected <s> Expected result
|
||||||
name <s> Item name
|
name <s> Item name
|
||||||
section <s> Section in the file
|
section <s|u> Section in the file
|
||||||
statement <s> Test statement
|
statement <s> Test statement
|
||||||
passed <b> True if actual result and expected result are equal
|
passed <b> True if actual result and expected result are equal
|
||||||
|
<script>
|
||||||
|
Ox.test.foo = function(item) {
|
||||||
|
return item.bar / item.baz;
|
||||||
|
};
|
||||||
|
Ox.test.source =
|
||||||
|
'/*@\n'+
|
||||||
|
'Ox.test.foo <f> Returns an items\'s bar per baz\n' +
|
||||||
|
' Bar per baz is a good indicator of an item\'s foo-ness.\n' +
|
||||||
|
' (item) -> <n> Bar per baz, or NaN\n' +
|
||||||
|
' item <o> Any item\n' +
|
||||||
|
' > Ox.test.foo({bar: 1, baz: 10})\n' +
|
||||||
|
' 0.1\n' +
|
||||||
|
' > Ox.test.foo({})\n' +
|
||||||
|
' NaN\n' +
|
||||||
|
'@*' + '/\n' +
|
||||||
|
'Ox.test.foo = function(item) {\n' +
|
||||||
|
' return item.bar / item.baz;\n' +
|
||||||
|
'};';
|
||||||
|
</script>
|
||||||
|
> Ox.test(Ox.test.source, function(r) { Ox.test(r[0].passed, true); })
|
||||||
|
undefined
|
||||||
@*/
|
@*/
|
||||||
Ox.test = function(file, callback) {
|
Ox.test = function(argument, callback) {
|
||||||
var regexp = /(Ox\.test\()/;
|
Ox.print('Ox.test', argument, '----------------------------------')
|
||||||
if (arguments.length == 2) {
|
function runTests(items) {
|
||||||
Ox.doc(file, function(items) {
|
var id = Ox.uid(), regexp = /(.+Ox\.test\()/, results = [];
|
||||||
var results = [];
|
Ox.test.data[id] = {
|
||||||
file = file.split('?')[0];
|
callback: callback,
|
||||||
Ox.test.data[file] = {
|
done: false,
|
||||||
callback: callback,
|
results: results,
|
||||||
done: false,
|
tests: {}
|
||||||
results: [],
|
};
|
||||||
tests: {}
|
items.forEach(function(item) {
|
||||||
};
|
item.tests && item.tests.some(function(test) {
|
||||||
items.forEach(function(item) {
|
return test.expected;
|
||||||
item.tests && item.tests.some(function(test) {
|
}) && item.tests.forEach(function(test) {
|
||||||
return test.result;
|
var actual, isAsync = regexp.test(test.statement);
|
||||||
}) && item.tests.forEach(function(test) {
|
if (isAsync) {
|
||||||
var actual, isAsync = regexp.test(test.statement);
|
Ox.test.data[id].tests[test.statement] = {
|
||||||
if (isAsync) {
|
name: item.name,
|
||||||
Ox.test.data[file].tests[item.name] = {
|
section: item.section
|
||||||
section: item.section,
|
};
|
||||||
statement: test.statement
|
Ox.Log('TEST', 'XXX', test.statement);
|
||||||
};
|
test.statement = test.statement.replace(
|
||||||
test.statement = test.statement.replace(
|
regexp,
|
||||||
regexp, '$1\'' + item.name + '\', '
|
"$1'" + test.statement.replace(/'/g, "\\'") + "', "
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (test.result || test.statement.match(/Ox\.test/)) {
|
if (test.expected || test.statement.match(/Ox\.test\./)) {
|
||||||
// don't eval script tags without assignment to Ox.test.foo
|
// don't eval script tags without assignment to Ox.test.foo
|
||||||
actual = eval(test.statement);
|
Ox.Log('TEST', test.statement);
|
||||||
Ox.Log('TEST', test.statement);
|
actual = eval(test.statement);
|
||||||
}
|
}
|
||||||
if (!isAsync && test.result) {
|
if (!isAsync && test.expected) {
|
||||||
Ox.test.data[file].results.push({
|
Ox.test.data[id].results.push({
|
||||||
actual: JSON.stringify(actual),
|
actual: JSON.stringify(actual),
|
||||||
expected: test.result,
|
expected: test.expected,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
section: item.section,
|
section: item.section,
|
||||||
statement: test.statement,
|
statement: test.statement,
|
||||||
passed: Ox.isEqual(eval(
|
passed: Ox.isEqual(
|
||||||
'(' + test.result + ')'
|
actual, eval('(' + test.expected + ')')
|
||||||
), actual)
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
});
|
||||||
Ox.test.data[file].done = true;
|
|
||||||
if (Ox.isEmpty(Ox.test.data[file].tests)) {
|
|
||||||
callback(Ox.test.data[file].results);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
Ox.test.data[id].done = true;
|
||||||
|
if (Ox.isEmpty(Ox.test.data[id].tests)) {
|
||||||
|
callback(Ox.test.data[id].results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (arguments.length == 2) {
|
||||||
|
if (Ox.typeOf(argument) == 'string' && Ox.contains(argument, '\n')) {
|
||||||
|
runTests(Ox.doc(argument))
|
||||||
|
} else {
|
||||||
|
argument = Ox.makeArray(argument);
|
||||||
|
if (Ox.typeOf(argument[0]) == 'string') {
|
||||||
|
Ox.doc(argument, runTests);
|
||||||
|
} else {
|
||||||
|
runTests(argument);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var name = arguments[0],
|
var statement = arguments[0],
|
||||||
result = arguments[1],
|
result = arguments[1],
|
||||||
expected = arguments[2];
|
expected = arguments[2],
|
||||||
file = null;
|
id, test;
|
||||||
Ox.forEach(Ox.test.data, function(v, k) {
|
Ox.forEach(Ox.test.data, function(v, k) {
|
||||||
if (v.tests[name]) {
|
if (v.tests[statement]) {
|
||||||
file = k;
|
id = k;
|
||||||
|
test = v.tests[statement];
|
||||||
Ox.Break();
|
Ox.Break();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Ox.test.data[file].results.push({
|
Ox.test.data[id].results.push(Ox.extend(test, {
|
||||||
actual: result,
|
actual: result,
|
||||||
expected: expected,
|
expected: expected,
|
||||||
name: name,
|
statement: statement,
|
||||||
section: Ox.test.data[file].tests[name].section,
|
|
||||||
statement: Ox.test.data[file].tests[name].statement,
|
|
||||||
passed: Ox.isEqual(result, expected)
|
passed: Ox.isEqual(result, expected)
|
||||||
});
|
}));
|
||||||
delete Ox.test.data[file].tests[name];
|
delete Ox.test.data[id].tests[statement];
|
||||||
if (Ox.test.data[file].done && Ox.isEmpty(Ox.test.data[file].tests)) {
|
if (Ox.test.data[id].done && Ox.isEmpty(Ox.test.data[id].tests)) {
|
||||||
Ox.test.data[file].callback(Ox.test.data[file].results);
|
Ox.test.data[id].callback(Ox.test.data[id].results);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -663,10 +712,11 @@ Ox.tokenize <f> Tokenizes JavaScript
|
||||||
column <n> Column of the token
|
column <n> Column of the token
|
||||||
line <n> Line of the token
|
line <n> Line of the token
|
||||||
type <s> Type of the token
|
type <s> Type of the token
|
||||||
Type can be <code>"comment"</code>, <code>"identifier"</code>,
|
Type can be <code>"comment"</code>, <code>"error"</code>,
|
||||||
<code>"linebreak"</code>, <code>"number"</code>,
|
<code>"identifier"</code>, <code>"linebreak"</code>,
|
||||||
<code>"operator"</code>, <code>"regexp"</code>,
|
<code>"number"</code>, <code>"operator"</code>,
|
||||||
<code>"string"</code> or <code>"whitespace"</code>
|
<code>"regexp"</code>, <code>"string"</code> or
|
||||||
|
<code>"whitespace"</code>
|
||||||
value <s> Value of the token
|
value <s> Value of the token
|
||||||
source <s> JavaScript source code
|
source <s> JavaScript source code
|
||||||
> Ox.tokenize('// comment\nvar foo = bar / baz;').length
|
> Ox.tokenize('// comment\nvar foo = bar / baz;').length
|
||||||
|
@ -790,10 +840,20 @@ Ox.tokenize = (function() {
|
||||||
type = 'whitespace';
|
type = 'whitespace';
|
||||||
while (whitespace.indexOf(source[++cursor]) > -1) {}
|
while (whitespace.indexOf(source[++cursor]) > -1) {}
|
||||||
} else {
|
} else {
|
||||||
break;
|
type = 'error';
|
||||||
|
++cursor;
|
||||||
}
|
}
|
||||||
value = source.slice(start, cursor);
|
value = source.slice(start, cursor);
|
||||||
tokens.push({column: column, line: line, type: type, value: value});
|
if (
|
||||||
|
type == 'error' && tokens.length
|
||||||
|
&& tokens[tokens.length - 1].type == 'error'
|
||||||
|
) {
|
||||||
|
tokens[tokens.length - 1].value += value;
|
||||||
|
} else {
|
||||||
|
tokens.push(
|
||||||
|
{column: column, line: line, type: type, value: value}
|
||||||
|
);
|
||||||
|
}
|
||||||
if (type == 'comment') {
|
if (type == 'comment') {
|
||||||
lines = value.split('\n');
|
lines = value.split('\n');
|
||||||
column = lines[lines.length - 1].length;
|
column = lines[lines.length - 1].length;
|
||||||
|
|
Loading…
Reference in a new issue