[test] Adding jstests test suite

This commit is contained in:
sulyi 2016-12-14 18:21:57 +01:00
parent cd0bb42f4e
commit ab37e2b811
34 changed files with 1347 additions and 1279 deletions

46
test/jstests/__init__.py Normal file
View File

@ -0,0 +1,46 @@
from . import (
basic,
calc,
empty_return,
morespace,
strange_chars,
operators,
array_access,
parens,
assignments,
comments,
precedence,
call,
getfield,
branch,
switch,
for_loop,
for_empty,
for_in,
do_loop,
while_loop,
label,
func_expr,
object_literal,
try_statement,
with_statement,
debug,
unshift
)
modules = [basic, calc, empty_return, morespace, strange_chars, operators, array_access, parens, assignments, comments,
precedence, call, getfield, branch, switch, for_loop, for_empty, for_in, do_loop, while_loop, label,
func_expr, object_literal, try_statement, with_statement, debug, unshift]
def gettestcases():
for module in modules:
if hasattr(module, 'tests'):
case = {'name': module.__name__[len(__name__) + 1:], 'subtests': []}
for test in getattr(module, 'tests'):
if 'code' in test:
case['subtests'].append(test)
if hasattr(module, 'skip'):
case['skip'] = getattr(module, 'skip')
yield case

View File

@ -0,0 +1,76 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS
tests = [
{'code': 'var x = [1,2,3]; x[0] = 4; x[0] = 5; x[2] = 7; return x;',
'asserts': [{'value': [5, 2, 7]}],
'ast': [(Token.VAR,
zip(['x'],
[(Token.ASSIGN,
None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.ARRAY, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 1), None, None)]), None),
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 2), None, None)]), None),
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 3), None, None)]), None)
]), None, None),
]),
None)
])
),
(Token.EXPR, [
(Token.ASSIGN,
_ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'x'),
None,
(Token.ELEM,
(Token.EXPR, [
(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]),
None)
]),
None))
]),
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 4), None, None)]), None)
)
]),
(Token.EXPR, [
(Token.ASSIGN,
_ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'),
None,
(Token.ELEM, (Token.EXPR, [
(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]),
None)
]), None))
]),
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 5), None, None)]), None))
]),
(Token.EXPR, [
(Token.ASSIGN,
_ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'),
None,
(Token.ELEM, (Token.EXPR, [
(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.INT, 2), None, None)]),
None)
]), None))
]),
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 7), None, None)]), None))
]),
(Token.RETURN,
(Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]), None)
])
)]
}
]

View File

@ -0,0 +1,42 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _OPERATORS, _ASSIGN_OPERATORS
tests = [
{
'code': 'var x = 20; x = 30 + 1; return x;',
'asserts': [{'value': 31}],
'ast': [
(Token.VAR, zip(
['x'],
[(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.INT, 20), None, None)]),
None)]
)),
(Token.EXPR, [
(Token.ASSIGN,
_ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]),
(Token.ASSIGN, None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 30), None, None),
(Token.MEMBER, (Token.INT, 1), None, None),
(Token.OP, _OPERATORS['+'][1])]),
None))
]),
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'x'), None, None)
]), None)
]))
]
}, {
'code': 'var x = 20; x += 30 + 1; return x;',
'asserts': [{'value': 51}],
}, {
'code': 'var x = 20; x -= 30 + 1; return x;',
'asserts': [{'value': -11}],
}
]

24
test/jstests/basic.py Normal file
View File

@ -0,0 +1,24 @@
from youtube_dl.jsinterp.jsgrammar import Token
tests = [
{
'code': 'return 42;',
'asserts': [{'value': 42}],
'ast': [(Token.RETURN,
(Token.EXPR, [
(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.INT, 42), None, None)]),
None)
]))]
},
{
'code': ';',
'asserts': [{'value': None}],
'ast': [None]
},
{
'code': 'var x5 = function(){return 42;}',
'asserts': [{'value': 42, 'call': ('x5',)}]
}
]

35
test/jstests/branch.py Normal file
View File

@ -0,0 +1,35 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _RELATIONS
skip = {'i': 'Interpreting if statement not yet implemented'}
tests = [
{
'code': '''
function a(x) {
if (x > 0)
return true;
else
return false;
}
''',
'asserts': [{'value': True, 'call': ('a', 1)}, {'value': False, 'call': ('a', 0)}],
'ast': [
(Token.FUNC, 'a',
['x'],
(Token.BLOCK, [
(Token.IF,
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'x'), None, None),
(Token.MEMBER, (Token.INT, 0), None, None),
(Token.REL, _RELATIONS['>'][1])
]), None)]),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.BOOL, True), None, None)]), None)])),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.BOOL, False), None, None)]), None)])))
]))
]
}
]

24
test/jstests/calc.py Normal file
View File

@ -0,0 +1,24 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _OPERATORS
tests = [
{'code': 'return 2*a+1;',
'globals': {'a': 3},
'asserts': [{'value': 7}],
'ast': [(Token.RETURN,
(Token.EXPR, [
(Token.ASSIGN,
None,
(Token.OPEXPR, [
# Reverse Polish Notation!
(Token.MEMBER, (Token.INT, 2), None, None),
(Token.MEMBER, (Token.ID, 'a'), None, None),
(Token.OP, _OPERATORS['*'][1]),
(Token.MEMBER, (Token.INT, 1), None, None),
(Token.OP, _OPERATORS['+'][1])
]),
None)
])
)]
}
]

111
test/jstests/call.py Normal file
View File

@ -0,0 +1,111 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _OPERATORS
skip = {'i': 'Interpreting function call not yet implemented'}
tests = [
{
'code': '''
function x() { return 2; }
function y(a) { return x() + a; }
function z() { return y(3); }
''',
'asserts': [{'value': 5, 'call': ('z',)}],
'ast': [
(Token.FUNC, 'x',
[],
(Token.BLOCK, [
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 2), None, None)]), None)
])
)
])),
(Token.FUNC, 'y',
['a'],
(Token.BLOCK, [
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'x'), None, (Token.CALL, [], None)),
(Token.MEMBER, (Token.ID, 'a'), None, None),
(Token.OP, _OPERATORS['+'][1])
]), None)
])
)
])),
(Token.FUNC, 'z',
[],
(Token.BLOCK, [
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'y'), None, (Token.CALL, [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 3), None, None)]), None)
], None))
]), None)
])
)
]))
]
}, {
'code': 'function x(a) { return a.split(""); }',
'asserts': [{'value': ["a", "b", "c"], 'call': ('x',)}],
'ast': [
(Token.FUNC, 'x',
['a'],
(Token.BLOCK, [
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'a'), None,
(Token.FIELD, 'split',
(Token.CALL, [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.STR, ''), None, None)]), None)
], None))
)]),
None)
])
)
]))
]
}, {
'code': '''
function a(x) { return x; }
function b(x) { return x; }
function c() { return [a, b][0](0); }
''',
'asserts': [{'value': 0}],
'ast': [
(Token.FUNC, 'a', ['x'],
(Token.BLOCK, [
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]), None)
])
)
])),
(Token.FUNC, 'b', ['x'],
(Token.BLOCK, [
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]), None)
])
)
])),
(Token.FUNC, 'c', [],
(Token.BLOCK, [
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ARRAY, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None),
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'b'), None, None)]), None)
]), None, (Token.ELEM, (Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
]), (Token.CALL, [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
], None)))
]), None)
])
)
]))
]
}
]

69
test/jstests/comments.py Normal file
View File

@ -0,0 +1,69 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _OPERATORS
tests = [
{
'code': '''
var x = /* 1 + */ 2;
var y = /* 30
* 40 */ 50;
return x + y;''',
'asserts': [{'value': 52}],
'ast': [
(Token.VAR, zip(
['x'],
[(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.INT, 2), None, None)]),
None)]
)),
(Token.VAR, zip(
['y'],
[(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.INT, 50), None, None)]),
None)]
)),
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'x'), None, None),
(Token.MEMBER, (Token.ID, 'y'), None, None),
(Token.OP, _OPERATORS['+'][1])
]), None)
]))
]
}, {
'code': '''
var x = "/*";
var y = 1 /* comment */ + 2;
return y;
''',
'asserts': [{'value': 3}],
'ast': [
(Token.VAR, zip(
['x'],
[(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.STR, '/*'), None, None)]),
None)]
)),
(Token.VAR, zip(
['y'],
[(Token.ASSIGN,
None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 1), None, None),
(Token.MEMBER, (Token.INT, 2), None, None),
(Token.OP, _OPERATORS['+'][1])
]),
None)]
)),
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None,
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'y'), None, None)]),
None)
]))
]
}
]

12
test/jstests/debug.py Normal file
View File

@ -0,0 +1,12 @@
from youtube_dl.jsinterp.jsgrammar import Token
skip = {'i': 'Interpreting debugger statement not yet implemented',
'p': 'Test not yet implemented: missing code and ast'}
tests = [
{
'code': '',
'asserts': [{'value': 0}],
'ast': []
}
]

47
test/jstests/do_loop.py Normal file
View File

@ -0,0 +1,47 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS, _UNARY_OPERATORS, _RELATIONS
skip = {'i': 'Interpreting do loop not yet implemented'}
tests = [
{
'code': '''
function f(x){
i = 1;
do{
i++;
} while (i < x);
return i;
}
''',
'asserts': [{'value': 5, 'call': 5}],
'ast': [
(Token.FUNC, 'f', ['x'],
(Token.BLOCK, [
(Token.EXPR, [
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'i'), None, None)]),
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 1), None, None)]), None))
]),
(Token.DO,
(Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'i'), None, None),
(Token.MEMBER, (Token.ID, 'x'), None, None),
(Token.REL, _RELATIONS['<'][1])
]), None)
]),
(Token.BLOCK, [
(Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'i'), None, None),
(Token.UOP, _UNARY_OPERATORS['++'][1])
]), None)
])
])),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'i'), None, None)]), None)]))
]))
]
}
]

View File

@ -0,0 +1,21 @@
from youtube_dl.jsinterp.jsgrammar import Token
tests = [
{'code': 'return; y()',
'asserts': [{'value': None}],
'ast': [
(Token.RETURN, None),
(Token.EXPR, [
(Token.ASSIGN,
None,
(Token.OPEXPR, [
(Token.MEMBER,
(Token.ID, 'y'),
None,
(Token.CALL, [], None)
)
]),
None)
])]
}
]

47
test/jstests/for_empty.py Normal file
View File

@ -0,0 +1,47 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS, _UNARY_OPERATORS, _RELATIONS
skip = {'i': 'Interpreting for empty loop not yet implemented'}
tests = [
{
'code': '''
function f(x){
var h = 0;
for (; h <= x; ++h) {
a = h;
}
return a;
}
''',
'asserts': [{'value': 5, 'call': ('f', 5)}],
'ast': [
(Token.FUNC, 'f', ['x'],
(Token.BLOCK, [
(Token.VAR, zip(['h'], [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
])),
(Token.FOR,
None,
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'h'), None, None),
(Token.MEMBER, (Token.ID, 'x'), None, None),
(Token.REL, _RELATIONS['<='][1])
]), None)]),
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'h'), None, None),
(Token.UOP, _UNARY_OPERATORS['++'][1])
]), None)]),
(Token.BLOCK, [
(Token.EXPR, [
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'a'), None, None)]),
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'h'), None, None)]), None))
])
])),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None)]))
]))
]
}
]

40
test/jstests/for_in.py Normal file
View File

@ -0,0 +1,40 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS
skip = {'i': 'Interpreting for in loop not yet implemented'}
tests = [
{
'code': '''
function f(z){
for (h in z) {
a = h;
}
return a;
}
''',
'asserts': [{'value': 'c', 'call': ('f', ['a', 'b', 'c'])}],
'ast': [
(Token.FUNC, 'f', ['z'],
(Token.BLOCK, [
(Token.FOR,
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'h'), None, None)
]), None)]),
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'z'), None, None)
]), None)]),
None,
(Token.BLOCK, [
(Token.EXPR, [
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'a'), None, None)]),
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'h'), None, None)]), None))
])
])),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None)]))
]))
]
}
]

45
test/jstests/for_loop.py Normal file
View File

@ -0,0 +1,45 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS, _UNARY_OPERATORS, _RELATIONS
skip = {'i': 'Interpreting for loop not yet implemented'}
tests = [
{
'code': '''
function f(x){
for (var h = 0; h <= x; ++h) {
a = h;
}
return a;
}
''',
'asserts': [{'value': 5, 'call': ('f', 5)}],
'ast': [
(Token.FUNC, 'f', ['x'],
(Token.BLOCK, [
(Token.FOR,
(Token.VAR, zip(['h'], [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
])),
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'h'), None, None),
(Token.MEMBER, (Token.ID, 'x'), None, None),
(Token.REL, _RELATIONS['<='][1])
]), None)]),
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'h'), None, None),
(Token.UOP, _UNARY_OPERATORS['++'][1])
]), None)]),
(Token.BLOCK, [
(Token.EXPR, [
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'a'), None, None)]),
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'h'), None, None)]), None))
])
])),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'a'), None, None)]), None)]))
]))
]
}
]

58
test/jstests/func_expr.py Normal file
View File

@ -0,0 +1,58 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS
skip = {'i': 'Interpreting function expression not yet implemented'}
tests = [
{
'code': '''
function f() {
var add = (function () {
var counter = 0;
return function () {return counter += 1;};
})();
add();
add();
return add();
}
''',
'asserts': [{'value': 3, 'call': ('f',)}],
'ast': [
(Token.FUNC, 'f', [],
(Token.BLOCK, [
(Token.VAR, zip(['add'], [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.FUNC, None, [], (Token.BLOCK, [
(Token.VAR, zip(
['counter'],
[(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 0), None, None)
]), None)]
)),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.FUNC, None, [], (Token.BLOCK, [
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, _ASSIGN_OPERATORS['+='][1], (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'counter'), None, None)
]), (Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 1), None, None)
]), None))
]))
])), None, None)
]), None)]))
])), None, None),
]), None)]), None, (Token.CALL, [], None))
]), None)])),
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'add'), None, (Token.CALL, [], None))
]), None)]),
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'add'), None, (Token.CALL, [], None))
]), None)]),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'add'), None, (Token.CALL, [], None))
]), None)]))
]))
]
}
]

25
test/jstests/getfield.py Normal file
View File

@ -0,0 +1,25 @@
from youtube_dl.jsinterp.jsgrammar import Token
skip = {'i': 'Interpreting get field not yet implemented'}
tests = [
{
'code': 'return a.var;',
'asserts': [{'value': 3}],
'globals': {'a': {'var': 3}},
'ast': [
(Token.RETURN,
(Token.EXPR, [
(Token.ASSIGN,
None,
(Token.OPEXPR, [
(Token.MEMBER,
(Token.ID, 'a'),
None,
(Token.FIELD, 'var', None)),
]),
None)
]))
]
}
]

12
test/jstests/label.py Normal file
View File

@ -0,0 +1,12 @@
from youtube_dl.jsinterp.jsgrammar import Token
skip = {'i': 'Interpreting label not yet implemented',
'p': 'Test not yet implemented: missing code and ast'}
tests = [
{
'code': '',
'asserts': [{'value': 0}],
'ast': []
}
]

33
test/jstests/morespace.py Normal file
View File

@ -0,0 +1,33 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS
skip = {'i': 'Interpreting set field not yet implemented'}
tests = [
{
'code': 'x = 2 ; return x;',
'asserts': [{'value': 2}],
'ast': [
(Token.EXPR,
[(Token.ASSIGN,
_ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]),
(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.INT, 2), None, None)]),
None)
)]
),
(Token.RETURN,
(Token.EXPR, [
(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]),
None)
])
)]
}, {
'code': 'function x (a) { return 2 * a + 1 ; }',
'asserts': [{'value': 7, 'call': ('x', 3)}]
}
]

View File

@ -0,0 +1,59 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS, _OPERATORS
skip = {'i': 'Interpreting object literals not yet implemented'}
tests = [
{
'code': '''
function f() {
var o = {
a: 7,
get b() { return this.a + 1; },
set c(x) { this.a = x / 2; }
};
return o;
}
''',
'ast': [
(Token.FUNC, 'f', [],
(Token.BLOCK, [
(Token.VAR,
zip(['o'],
[(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.OBJECT, [
('a', (Token.PROPVALUE, (Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 7), None, None)
]), None))),
('b', (Token.PROPGET, (Token.BLOCK, [
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.RSV, 'this'), None, (Token.FIELD, 'a', None)),
(Token.MEMBER, (Token.INT, 1), None, None),
(Token.OP, _OPERATORS['+'][1])
]), None)]))
]))),
('c', (Token.PROPSET, 'x', (Token.BLOCK, [
(Token.EXPR, [
(Token.ASSIGN,
_ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [
(Token.MEMBER, (Token.RSV, 'this'), None, (Token.FIELD, 'a', None))
]),
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'x'), None, None),
(Token.MEMBER, (Token.INT, 2), None, None),
(Token.OP, _OPERATORS['/'][1])
]), None))
])
])))
]),
None, None)
]), None)]
)
),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'o'), None, None)]), None)]))
]))
]
}
]

43
test/jstests/operators.py Normal file
View File

@ -0,0 +1,43 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _OPERATORS
tests = [
{
'code': 'return 1 << 5;',
'asserts': [{'value': 32}],
'ast': [
(Token.RETURN,
(Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 1), None, None),
(Token.MEMBER, (Token.INT, 5), None, None),
(Token.OP, _OPERATORS['<<'][1])
]), None)
]))]
}, {
'code': 'return 19 & 21;',
'asserts': [{'value': 17}],
'ast': [
(Token.RETURN,
(Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 19), None, None),
(Token.MEMBER, (Token.INT, 21), None, None),
(Token.OP, _OPERATORS['&'][1])
]), None)
]))
]
}, {
'code': 'return 11 >> 2;',
'asserts': [{'value': 2}],
'ast': [
(Token.RETURN,
(Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 11), None, None),
(Token.MEMBER, (Token.INT, 2), None, None),
(Token.OP, _OPERATORS['>>'][1])
]), None)
]))]
}
]

73
test/jstests/parens.py Normal file
View File

@ -0,0 +1,73 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _OPERATORS
tests = [
{
'code': 'return (1 + 2) * 3;',
'asserts': [{'value': 9}],
'ast': [
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [
(Token.ASSIGN, None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 1), None, None),
(Token.MEMBER, (Token.INT, 2), None, None),
(Token.OP, _OPERATORS['+'][1])
]), None)
]), None, None),
(Token.MEMBER, (Token.INT, 3), None, None),
(Token.OP, _OPERATORS['*'][1])
]), None)
]))]
}, {
'code': 'return (1) + (2) * ((( (( (((((3)))))) )) ));',
'asserts': [{'value': 7}],
'ast': [
(Token.RETURN, (Token.EXPR, [
(Token.ASSIGN, None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 1), None, None)
]), None)]), None, None),
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 2), None, None)
]), None)]), None, None),
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER,
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 3), None, None)
]), None)]), None, None)
]), None)]), None, None)
]), None)]), None, None)
]), None)]), None, None)
]), None)]), None, None)
]), None)]), None, None)
]), None)]), None, None)
]), None)]), None, None)
]), None)]), None, None)
]), None)]), None, None),
(Token.OP, _OPERATORS['*'][1]),
(Token.OP, _OPERATORS['+'][1])
]), None)
]))
]
}
]

View File

@ -0,0 +1,80 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS, _OPERATORS
skip = {'i': 'Interpreting get field not yet implemented'}
tests = [
{
'code': '''
var a = [10, 20, 30, 40, 50];
var b = 6;
a[0]=a[b%a.length];
return a;
''',
'asserts': [{'value': [20, 20, 30, 40, 50]}],
'ast': [
(Token.VAR,
zip(['a'],
[(Token.ASSIGN,
None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.ARRAY, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 10), None, None)]), None),
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 20), None, None)]), None),
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 30), None, None)]), None),
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 40), None, None)]), None),
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 50), None, None)]), None)
]), None, None),
]),
None)
])
),
(Token.VAR,
zip(['b'],
[(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 6), None, None)]), None)]
)
),
(Token.EXPR, [
(Token.ASSIGN,
_ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'a'),
None,
(Token.ELEM,
(Token.EXPR, [
(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]),
None)
]),
None))
]),
(Token.ASSIGN,
None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'a'),
None,
(Token.ELEM, (Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'b'), None, None),
(Token.MEMBER, (Token.ID, 'a'), None, (Token.FIELD, 'length', None)),
(Token.OP, _OPERATORS['%'][1])
]), None)]),
None))
]),
None)
)
]),
(Token.RETURN,
(Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'a'), None, None)]), None)
])
)
]
}
]

View File

@ -0,0 +1,31 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _OPERATORS
tests = [
{
'code': 'var $_axY2 = $_xY1 + 1; return $_axY2;',
'globals': {'$_xY1': 20},
'asserts': [{'value': 21}],
'ast': [
(Token.VAR,
zip(['$_axY2'],
[(Token.ASSIGN,
None,
(Token.OPEXPR, [
(Token.MEMBER, (Token.ID, '$_xY1'), None, None),
(Token.MEMBER, (Token.INT, 1), None, None),
(Token.OP, _OPERATORS['+'][1])
]),
None)
])
),
(Token.RETURN,
(Token.EXPR, [
(Token.ASSIGN,
None,
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, '$_axY2'), None, None)]),
None)]
)
)]
}
]

73
test/jstests/switch.py Normal file
View File

@ -0,0 +1,73 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS, _UNARY_OPERATORS
skip = {'i': 'Interpreting switch statement not yet implemented'}
tests = [
{
'code': '''
function a(x) {
switch (x) {
case 6:
break;
case 5:
x++;
case 8:
x--;
break;
default:
x = 0;
}
return x;
}
''',
'asserts': [{'value': 4, 'call': ('a', 0)},
{'value': 5, 'call': ('a', 5)},
{'value': 6, 'call': ('a', 6)},
{'value': 8, 'call': ('a', 7)}],
'ast': [
(Token.FUNC, 'a', ['x'],
(Token.BLOCK, [
(Token.SWITCH, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'x'), None, None)
]), None)]),
[
((Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 6), None, None)]), None)]),
[
(Token.BREAK, None)
]),
((Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 5), None, None)]), None)]),
[
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'x'), None, None),
(Token.UOP, _UNARY_OPERATORS['++'][1])
]), None)])
]),
((Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.INT, 8), None, None)]), None)]),
[
(Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'x'), None, None),
(Token.UOP, _UNARY_OPERATORS['--'][1])
]), None)]),
(Token.BREAK, None)
]),
(None,
[
(Token.EXPR, [
(Token.ASSIGN,
_ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'x'), None, None)]),
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 0), None, None)]), None)
)
])
])
]
),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'x'), None, None)]), None)]))
]))]
}
]

View File

@ -0,0 +1,12 @@
from youtube_dl.jsinterp.jsgrammar import Token
skip = {'i': 'Interpreting try statement not yet implemented',
'p': 'Test not yet implemented: missing code and ast'}
tests = [
{
'code': '',
'asserts': [{'value': 0}],
'ast': []
}
]

30
test/jstests/unshift.py Normal file
View File

@ -0,0 +1,30 @@
skip = {'p': 'Signed integers not yet supported'}
tests = [
{
'code': '''
var MAX_LENGTH = 0xffffffff;
var a = {};
a.length = MAX_LENGTH + 1;
assertEq([].unshift.call(a), MAX_LENGTH);
assertEq(a.length, MAX_LENGTH);
function testGetSet(len, expected) {
var newlen;
var a = { get length() { return len; }, set length(v) { newlen = v; } };
var res = [].unshift.call(a);
assertEq(res, expected);
assertEq(newlen, expected);
}
testGetSet(0, 0);
testGetSet(10, 10);
testGetSet("1", 1);
testGetSet(null, 0);
testGetSet(MAX_LENGTH + 2, MAX_LENGTH);
testGetSet(-5, 0);
'''
}
]

View File

@ -0,0 +1,47 @@
from youtube_dl.jsinterp.jsgrammar import Token
from youtube_dl.jsinterp.tstream import _ASSIGN_OPERATORS, _UNARY_OPERATORS, _RELATIONS
skip = {'i': 'Interpreting while loop not yet implemented'}
tests = [
{
'code': '''
function f(x){
i = 1;
while (i < x) {
i++;
}
return i;
}
''',
'asserts': [{'value': 5, 'call': ('f', 5)}],
'ast': [
(Token.FUNC, 'f', ['x'],
(Token.BLOCK, [
(Token.EXPR, [
(Token.ASSIGN, _ASSIGN_OPERATORS['='][1],
(Token.OPEXPR, [(Token.MEMBER, (Token.ID, 'i'), None, None)]),
(Token.ASSIGN, None, (Token.OPEXPR, [(Token.MEMBER, (Token.INT, 1), None, None)]), None))
]),
(Token.WHILE,
(Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'i'), None, None),
(Token.MEMBER, (Token.ID, 'x'), None, None),
(Token.REL, _RELATIONS['<'][1])
]), None)
]),
(Token.BLOCK, [
(Token.EXPR, [
(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'i'), None, None),
(Token.UOP, _UNARY_OPERATORS['++'][1])
]), None)
])
])),
(Token.RETURN, (Token.EXPR, [(Token.ASSIGN, None, (Token.OPEXPR, [
(Token.MEMBER, (Token.ID, 'i'), None, None)]), None)]))
]))
]
}
]

View File

@ -0,0 +1,12 @@
from youtube_dl.jsinterp.jsgrammar import Token
skip = {'i': 'Interpreting with statement not yet implemented',
'p': 'Test not yet implemented: missing code and ast'}
tests = [
{
'code': '',
'asserts': [{'value': 0}],
'ast': []
}
]

View File

@ -2,9 +2,9 @@
from __future__ import unicode_literals
# Allow direct execution
import os
import sys
if sys.version_info < (2, 7):
import unittest2 as unittest
else:
@ -12,127 +12,44 @@ else:
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from youtube_dl.jsinterp import JSInterpreter
from test.jstests import gettestcases
defs = gettestcases()
class TestJSInterpreter(unittest.TestCase):
def test_basic(self):
jsi = JSInterpreter('function x(){;}')
self.assertEqual(jsi.call_function('x'), None)
def setUp(self):
self.defs = defs
jsi = JSInterpreter('function x3(){return 42;}')
self.assertEqual(jsi.call_function('x3'), 42)
jsi = JSInterpreter('var x5 = function(){return 42;}')
self.assertEqual(jsi.call_function('x5'), 42)
def generator(test_case):
def test_template(self):
for test in test_case['subtests']:
jsi = JSInterpreter(test['code'], variables=None if 'globals' not in test else test['globals'])
if 'asserts' in test:
for a in test['asserts']:
if 'call' in a:
self.assertEqual(jsi.call_function(*a['call']), a['value'])
else:
self.assertEqual(jsi.run(), a['value'])
def test_calc(self):
jsi = JSInterpreter('function x4(a){return 2*a+1;}')
self.assertEqual(jsi.call_function('x4', 3), 7)
if 'skip' not in test_case or 'i' not in test_case['skip']:
reason = False
else:
reason = test_case['skip']['i']
def test_empty_return(self):
jsi = JSInterpreter('function f(){return; y()}')
self.assertEqual(jsi.call_function('f'), None)
return test_template if not reason else unittest.skip(reason)(test_template)
@unittest.skip('Interpreting set field not yet implemented')
def test_morespace(self):
jsi = JSInterpreter('function x (a) { return 2 * a + 1 ; }')
self.assertEqual(jsi.call_function('x', 3), 7)
jsi = JSInterpreter('function f () { x = 2 ; return x; }')
self.assertEqual(jsi.call_function('f'), 2)
def test_strange_chars(self):
jsi = JSInterpreter('function $_xY1 ($_axY1) { var $_axY2 = $_axY1 + 1; return $_axY2; }')
self.assertEqual(jsi.call_function('$_xY1', 20), 21)
# TODO test prefix and postfix operators
def test_operators(self):
jsi = JSInterpreter('function f(){return 1 << 5;}')
self.assertEqual(jsi.call_function('f'), 32)
jsi = JSInterpreter('function f(){return 19 & 21;}')
self.assertEqual(jsi.call_function('f'), 17)
jsi = JSInterpreter('function f(){return 11 >> 2;}')
self.assertEqual(jsi.call_function('f'), 2)
def test_array_access(self):
jsi = JSInterpreter('function f(){var x = [1,2,3]; x[0] = 4; x[0] = 5; x[2] = 7; return x;}')
self.assertEqual(jsi.call_function('f'), [5, 2, 7])
def test_parens(self):
jsi = JSInterpreter('function f(){return (1) + (2) * ((( (( (((((3)))))) )) ));}')
self.assertEqual(jsi.call_function('f'), 7)
jsi = JSInterpreter('function f(){return (1 + 2) * 3;}')
self.assertEqual(jsi.call_function('f'), 9)
def test_assignments(self):
jsi = JSInterpreter('function f(){var x = 20; x = 30 + 1; return x;}')
self.assertEqual(jsi.call_function('f'), 31)
jsi = JSInterpreter('function f(){var x = 20; x += 30 + 1; return x;}')
self.assertEqual(jsi.call_function('f'), 51)
jsi = JSInterpreter('function f(){var x = 20; x -= 30 + 1; return x;}')
self.assertEqual(jsi.call_function('f'), -11)
def test_comments(self):
jsi = JSInterpreter('''
function x() {
var x = /* 1 + */ 2;
var y = /* 30
* 40 */ 50;
return x + y;
}
''')
self.assertEqual(jsi.call_function('x'), 52)
jsi = JSInterpreter('''
function f() {
var x = "/*";
var y = 1 /* comment */ + 2;
return y;
}
''')
self.assertEqual(jsi.call_function('f'), 3)
@unittest.skip('Interpreting get field not yet implemented')
def test_precedence(self):
jsi = JSInterpreter('''
function x() {
var a = [10, 20, 30, 40, 50];
var b = 6;
a[0]=a[b%a.length];
return a;
}''')
self.assertEqual(jsi.call_function('x'), [20, 20, 30, 40, 50])
@unittest.skip('Interpreting function call not yet implemented')
def test_call(self):
jsi = JSInterpreter('''
function x() { return 2; }
function y(a) { return x() + a; }
function z() { return y(3); }
''')
self.assertEqual(jsi.call_function('z'), 5)
jsi = JSInterpreter('function x(a) { return a.split(""); }', variables={'a': 'abc'})
self.assertEqual(jsi.call_function('x'), ["a", "b", "c"])
@unittest.skip('Interpreting function call not yet implemented')
def test_complex_call(self):
jsi = JSInterpreter('''
function a(x) { return x; }
function b(x) { return x; }
function c() { return [a, b][0](0); }
''')
self.assertEqual(jsi.call_function('c'), 0)
@unittest.skip('Interpreting get field not yet implemented')
def test_getfield(self):
jsi = JSInterpreter('function c() { return a.var; }', variables={'a': {'var': 3}})
self.assertEqual(jsi.call_function('c'), 3)
if __name__ == '__main__':
unittest.main()
# And add them to TestJSInterpreter
for n, tc in enumerate(defs):
if any('asserts' in test for test in tc['subtests']):
test_method = generator(tc)
tname = 'test_' + str(tc['name'])
i = 1
while hasattr(TestJSInterpreter, tname):
tname = 'test_%s_%d' % (tc['name'], i)
i += 1
test_method.__name__ = str(tname)
setattr(TestJSInterpreter, test_method.__name__, test_method)
del test_method

View File

@ -0,0 +1,65 @@
#!/usr/bin/env python
from __future__ import unicode_literals
import os
import sys
import copy
if sys.version_info < (2, 7):
import unittest2 as unittest
else:
import unittest
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from youtube_dl.jsinterp import JSInterpreter
from test.jstests import gettestcases
def traverse(node, tree_types=(list, tuple)):
if type(node) == zip:
node = list(copy.deepcopy(node))
if isinstance(node, tree_types):
tree = []
for value in node:
tree.append(traverse(value, tree_types))
return tree
else:
return node
defs = gettestcases()
class TestJSInterpreterParse(unittest.TestCase):
def setUp(self):
self.defs = defs
def generator(test_case):
def test_template(self):
for a in test_case['subtests']:
jsi = JSInterpreter(a['code'], variables=None if 'globals' not in a else a['globals'])
parsed = list(jsi.statements())
if 'ast' in a:
self.assertEqual(traverse(parsed), traverse(a['ast']))
if 'skip' not in test_case or 'p' not in test_case['skip']:
reason = False
else:
reason = test_case['skip']['p']
return test_template if not reason else unittest.skip(reason)(test_template)
# And add them to TestJSInterpreter
for n, tc in enumerate(defs):
test_method = generator(tc)
tname = 'test_' + str(tc['name'])
i = 1
while hasattr(TestJSInterpreterParse, tname):
tname = 'test_%s_%d' % (tc['name'], i)
i += 1
test_method.__name__ = str(tname)
setattr(TestJSInterpreterParse, test_method.__name__, test_method)
del test_method

File diff suppressed because it is too large Load Diff

View File

@ -48,6 +48,7 @@ _SINGLE_QUOTED_RE = r"""'(?:(?:\\'|\n)|[^'\n])*'"""
_DOUBLE_QUOTED_RE = r'''"(?:(?:\\"|\n)|[^"\n])*"'''
_STRING_RE = r'(?:%s)|(?:%s)' % (_SINGLE_QUOTED_RE, _DOUBLE_QUOTED_RE)
# FIXME signed values
_INTEGER_RE = r'(?:%(hex)s)|(?:%(dec)s)|(?:%(oct)s)' % {'hex': __HEXADECIMAL_RE, 'dec': __DECIMAL_RE, 'oct': __OCTAL_RE}
_FLOAT_RE = r'(?:(?:%(dec)s\.[0-9]*)|(?:\.[0-9]+))(?:[eE][+-]?[0-9]+)?' % {'dec': __DECIMAL_RE}

View File

@ -55,7 +55,7 @@ class JSInterpreter(object):
for k, v in dict(variables).items():
# XXX validate identifiers
self.global_vars[k] = Reference(v, (self.global_vars, k))
self._context = Context(self.global_vars)
self._context = Context()
self._context_stack = []
def statements(self, code=None, pos=0, stack_size=100):
@ -920,7 +920,8 @@ class JSInterpreter(object):
elif name is Token.ID:
# XXX error handling (unknown id)
ref = self._context.local_vars[expr[1]] if expr[1] in self._context.local_vars else self.global_vars[expr[1]]
ref = (self._context.local_vars[expr[1]] if expr[1] in self._context.local_vars else
self.global_vars[expr[1]])
# literal
elif name in _token_keys:
@ -939,6 +940,18 @@ class JSInterpreter(object):
return ref
def run(self, cx=None):
if cx is not None:
self.push_context(cx)
res = None
for stmt in self.statements():
res = self.interpret_statement(stmt)
if self._context.ended:
if cx is not None:
self.pop_context()
break
return res
def extract_object(self, objname):
obj = {}
obj_m = re.search(

View File

@ -124,7 +124,10 @@ class TokenStream(object):
elif token_id is Token.STR:
yield (token_id, token_value[1:-1], pos)
elif token_id is Token.INT:
yield (token_id, int(token_value), pos)
# FIXME signed values
root = ((16 if len(token_value) > 2 and token_value[1] in 'xX' else 8)
if token_value.startswith('0') else 10)
yield (token_id, int(token_value, root), pos)
elif token_id is Token.FLOAT:
yield (token_id, float(token_value), pos)
elif token_id is Token.REGEX:
@ -142,6 +145,8 @@ class TokenStream(object):
else:
raise ExtractorError('Unexpected token at %d' % pos)
pos = feed_m.end()
elif pos >= len(self.code):
self.ended = True
else:
raise ExtractorError('Unrecognised sequence at %d' % pos)
raise StopIteration