summaryrefslogtreecommitdiff
path: root/test/test_jsinterp.py
blob: 5121c8cf8da7ee10faaa7b8b6d5e311cdf5cffbb (plain)
    1 #!/usr/bin/env python
    2 
    3 from __future__ import unicode_literals
    4 
    5 # Allow direct execution
    6 import os
    7 import sys
    8 import unittest
    9 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
   10 
   11 import math
   12 import re
   13 
   14 from youtube_dl.compat import compat_re_Pattern
   15 
   16 from youtube_dl.jsinterp import JS_Undefined, JSInterpreter
   17 
   18 
   19 class TestJSInterpreter(unittest.TestCase):
   20     def test_basic(self):
   21         jsi = JSInterpreter('function x(){;}')
   22         self.assertEqual(jsi.call_function('x'), None)
   23 
   24         jsi = JSInterpreter('function x3(){return 42;}')
   25         self.assertEqual(jsi.call_function('x3'), 42)
   26 
   27         jsi = JSInterpreter('function x3(){42}')
   28         self.assertEqual(jsi.call_function('x3'), None)
   29 
   30         jsi = JSInterpreter('var x5 = function(){return 42;}')
   31         self.assertEqual(jsi.call_function('x5'), 42)
   32 
   33     def test_calc(self):
   34         jsi = JSInterpreter('function x4(a){return 2*a+1;}')
   35         self.assertEqual(jsi.call_function('x4', 3), 7)
   36 
   37     def test_empty_return(self):
   38         jsi = JSInterpreter('function f(){return; y()}')
   39         self.assertEqual(jsi.call_function('f'), None)
   40 
   41     def test_morespace(self):
   42         jsi = JSInterpreter('function x (a) { return 2 * a + 1 ; }')
   43         self.assertEqual(jsi.call_function('x', 3), 7)
   44 
   45         jsi = JSInterpreter('function f () { x =  2  ; return x; }')
   46         self.assertEqual(jsi.call_function('f'), 2)
   47 
   48     def test_strange_chars(self):
   49         jsi = JSInterpreter('function $_xY1 ($_axY1) { var $_axY2 = $_axY1 + 1; return $_axY2; }')
   50         self.assertEqual(jsi.call_function('$_xY1', 20), 21)
   51 
   52     def test_operators(self):
   53         jsi = JSInterpreter('function f(){return 1 << 5;}')
   54         self.assertEqual(jsi.call_function('f'), 32)
   55 
   56         jsi = JSInterpreter('function f(){return 2 ** 5}')
   57         self.assertEqual(jsi.call_function('f'), 32)
   58 
   59         jsi = JSInterpreter('function f(){return 19 & 21;}')
   60         self.assertEqual(jsi.call_function('f'), 17)
   61 
   62         jsi = JSInterpreter('function f(){return 11 >> 2;}')
   63         self.assertEqual(jsi.call_function('f'), 2)
   64 
   65         jsi = JSInterpreter('function f(){return []? 2+3: 4;}')
   66         self.assertEqual(jsi.call_function('f'), 5)
   67 
   68         jsi = JSInterpreter('function f(){return 1 == 2}')
   69         self.assertEqual(jsi.call_function('f'), False)
   70 
   71         jsi = JSInterpreter('function f(){return 0 && 1 || 2;}')
   72         self.assertEqual(jsi.call_function('f'), 2)
   73 
   74         jsi = JSInterpreter('function f(){return 0 ?? 42;}')
   75         self.assertEqual(jsi.call_function('f'), 0)
   76 
   77         jsi = JSInterpreter('function f(){return "life, the universe and everything" < 42;}')
   78         self.assertFalse(jsi.call_function('f'))
   79 
   80     def test_array_access(self):
   81         jsi = JSInterpreter('function f(){var x = [1,2,3]; x[0] = 4; x[0] = 5; x[2.0] = 7; return x;}')
   82         self.assertEqual(jsi.call_function('f'), [5, 2, 7])
   83 
   84     def test_parens(self):
   85         jsi = JSInterpreter('function f(){return (1) + (2) * ((( (( (((((3)))))) )) ));}')
   86         self.assertEqual(jsi.call_function('f'), 7)
   87 
   88         jsi = JSInterpreter('function f(){return (1 + 2) * 3;}')
   89         self.assertEqual(jsi.call_function('f'), 9)
   90 
   91     def test_quotes(self):
   92         jsi = JSInterpreter(r'function f(){return "a\"\\("}')
   93         self.assertEqual(jsi.call_function('f'), r'a"\(')
   94 
   95     def test_assignments(self):
   96         jsi = JSInterpreter('function f(){var x = 20; x = 30 + 1; return x;}')
   97         self.assertEqual(jsi.call_function('f'), 31)
   98 
   99         jsi = JSInterpreter('function f(){var x = 20; x += 30 + 1; return x;}')
  100         self.assertEqual(jsi.call_function('f'), 51)
  101 
  102         jsi = JSInterpreter('function f(){var x = 20; x -= 30 + 1; return x;}')
  103         self.assertEqual(jsi.call_function('f'), -11)
  104 
  105     def test_comments(self):
  106         'Skipping: Not yet fully implemented'
  107         return
  108         jsi = JSInterpreter('''
  109         function x() {
  110             var x = /* 1 + */ 2;
  111             var y = /* 30
  112             * 40 */ 50;
  113             return x + y;
  114         }
  115         ''')
  116         self.assertEqual(jsi.call_function('x'), 52)
  117 
  118         jsi = JSInterpreter('''
  119         function f() {
  120             var x = "/*";
  121             var y = 1 /* comment */ + 2;
  122             return y;
  123         }
  124         ''')
  125         self.assertEqual(jsi.call_function('f'), 3)
  126 
  127     def test_precedence(self):
  128         jsi = JSInterpreter('''
  129         function x() {
  130             var a = [10, 20, 30, 40, 50];
  131             var b = 6;
  132             a[0]=a[b%a.length];
  133             return a;
  134         }''')
  135         self.assertEqual(jsi.call_function('x'), [20, 20, 30, 40, 50])
  136 
  137     def test_builtins(self):
  138         jsi = JSInterpreter('''
  139         function x() { return NaN }
  140         ''')
  141         self.assertTrue(math.isnan(jsi.call_function('x')))
  142 
  143         jsi = JSInterpreter('''
  144         function x() { return new Date('Wednesday 31 December 1969 18:01:26 MDT') - 0; }
  145         ''')
  146         self.assertEqual(jsi.call_function('x'), 86000)
  147         jsi = JSInterpreter('''
  148         function x(dt) { return new Date(dt) - 0; }
  149         ''')
  150         self.assertEqual(jsi.call_function('x', 'Wednesday 31 December 1969 18:01:26 MDT'), 86000)
  151 
  152     def test_call(self):
  153         jsi = JSInterpreter('''
  154         function x() { return 2; }
  155         function y(a) { return x() + (a?a:0); }
  156         function z() { return y(3); }
  157         ''')
  158         self.assertEqual(jsi.call_function('z'), 5)
  159         self.assertEqual(jsi.call_function('y'), 2)
  160 
  161     def test_for_loop(self):
  162         # function x() { a=0; for (i=0; i-10; i++) {a++} a }
  163         jsi = JSInterpreter('''
  164         function x() { a=0; for (i=0; i-10; i++) {a++} return a }
  165         ''')
  166         self.assertEqual(jsi.call_function('x'), 10)
  167 
  168     def test_switch(self):
  169         jsi = JSInterpreter('''
  170         function x(f) { switch(f){
  171             case 1:f+=1;
  172             case 2:f+=2;
  173             case 3:f+=3;break;
  174             case 4:f+=4;
  175             default:f=0;
  176         } return f }
  177         ''')
  178         self.assertEqual(jsi.call_function('x', 1), 7)
  179         self.assertEqual(jsi.call_function('x', 3), 6)
  180         self.assertEqual(jsi.call_function('x', 5), 0)
  181 
  182     def test_switch_default(self):
  183         jsi = JSInterpreter('''
  184         function x(f) { switch(f){
  185             case 2: f+=2;
  186             default: f-=1;
  187             case 5:
  188             case 6: f+=6;
  189             case 0: break;
  190             case 1: f+=1;
  191         } return f }
  192         ''')
  193         self.assertEqual(jsi.call_function('x', 1), 2)
  194         self.assertEqual(jsi.call_function('x', 5), 11)
  195         self.assertEqual(jsi.call_function('x', 9), 14)
  196 
  197     def test_try(self):
  198         jsi = JSInterpreter('''
  199         function x() { try{return 10} catch(e){return 5} }
  200         ''')
  201         self.assertEqual(jsi.call_function('x'), 10)
  202 
  203     def test_catch(self):
  204         jsi = JSInterpreter('''
  205         function x() { try{throw 10} catch(e){return 5} }
  206         ''')
  207         self.assertEqual(jsi.call_function('x'), 5)
  208 
  209     def test_finally(self):
  210         jsi = JSInterpreter('''
  211         function x() { try{throw 10} finally {return 42} }
  212         ''')
  213         self.assertEqual(jsi.call_function('x'), 42)
  214         jsi = JSInterpreter('''
  215         function x() { try{throw 10} catch(e){return 5} finally {return 42} }
  216         ''')
  217         self.assertEqual(jsi.call_function('x'), 42)
  218 
  219     def test_nested_try(self):
  220         jsi = JSInterpreter('''
  221         function x() {try {
  222             try{throw 10} finally {throw 42}
  223             } catch(e){return 5} }
  224         ''')
  225         self.assertEqual(jsi.call_function('x'), 5)
  226 
  227     def test_for_loop_continue(self):
  228         jsi = JSInterpreter('''
  229         function x() { a=0; for (i=0; i-10; i++) { continue; a++ } return a }
  230         ''')
  231         self.assertEqual(jsi.call_function('x'), 0)
  232 
  233     def test_for_loop_break(self):
  234         jsi = JSInterpreter('''
  235         function x() { a=0; for (i=0; i-10; i++) { break; a++ } return a }
  236         ''')
  237         self.assertEqual(jsi.call_function('x'), 0)
  238 
  239     def test_for_loop_try(self):
  240         jsi = JSInterpreter('''
  241         function x() {
  242             for (i=0; i-10; i++) { try { if (i == 5) throw i} catch {return 10} finally {break} };
  243             return 42 }
  244         ''')
  245         self.assertEqual(jsi.call_function('x'), 42)
  246 
  247     def test_literal_list(self):
  248         jsi = JSInterpreter('''
  249         function x() { return [1, 2, "asdf", [5, 6, 7]][3] }
  250         ''')
  251         self.assertEqual(jsi.call_function('x'), [5, 6, 7])
  252 
  253     def test_comma(self):
  254         jsi = JSInterpreter('''
  255         function x() { a=5; a -= 1, a+=3; return a }
  256         ''')
  257         self.assertEqual(jsi.call_function('x'), 7)
  258         jsi = JSInterpreter('''
  259         function x() { a=5; return (a -= 1, a+=3, a); }
  260         ''')
  261         self.assertEqual(jsi.call_function('x'), 7)
  262 
  263         jsi = JSInterpreter('''
  264         function x() { return (l=[0,1,2,3], function(a, b){return a+b})((l[1], l[2]), l[3]) }
  265         ''')
  266         self.assertEqual(jsi.call_function('x'), 5)
  267 
  268     def test_void(self):
  269         jsi = JSInterpreter('''
  270         function x() { return void 42; }
  271         ''')
  272         self.assertEqual(jsi.call_function('x'), None)
  273 
  274     def test_return_function(self):
  275         jsi = JSInterpreter('''
  276         function x() { return [1, function(){return 1}][1] }
  277         ''')
  278         self.assertEqual(jsi.call_function('x')([]), 1)
  279 
  280     def test_null(self):
  281         jsi = JSInterpreter('''
  282         function x() { return null; }
  283         ''')
  284         self.assertIs(jsi.call_function('x'), None)
  285 
  286         jsi = JSInterpreter('''
  287         function x() { return [null > 0, null < 0, null == 0, null === 0]; }
  288         ''')
  289         self.assertEqual(jsi.call_function('x'), [False, False, False, False])
  290 
  291         jsi = JSInterpreter('''
  292         function x() { return [null >= 0, null <= 0]; }
  293         ''')
  294         self.assertEqual(jsi.call_function('x'), [True, True])
  295 
  296     def test_undefined(self):
  297         jsi = JSInterpreter('''
  298         function x() { return undefined === undefined; }
  299         ''')
  300         self.assertTrue(jsi.call_function('x'))
  301 
  302         jsi = JSInterpreter('''
  303         function x() { return undefined; }
  304         ''')
  305         self.assertIs(jsi.call_function('x'), JS_Undefined)
  306 
  307         jsi = JSInterpreter('''
  308         function x() { let v; return v; }
  309         ''')
  310         self.assertIs(jsi.call_function('x'), JS_Undefined)
  311 
  312         jsi = JSInterpreter('''
  313         function x() { return [undefined === undefined, undefined == undefined, undefined < undefined, undefined > undefined]; }
  314         ''')
  315         self.assertEqual(jsi.call_function('x'), [True, True, False, False])
  316 
  317         jsi = JSInterpreter('''
  318         function x() { return [undefined === 0, undefined == 0, undefined < 0, undefined > 0]; }
  319         ''')
  320         self.assertEqual(jsi.call_function('x'), [False, False, False, False])
  321 
  322         jsi = JSInterpreter('''
  323         function x() { return [undefined >= 0, undefined <= 0]; }
  324         ''')
  325         self.assertEqual(jsi.call_function('x'), [False, False])
  326 
  327         jsi = JSInterpreter('''
  328         function x() { return [undefined > null, undefined < null, undefined == null, undefined === null]; }
  329         ''')
  330         self.assertEqual(jsi.call_function('x'), [False, False, True, False])
  331 
  332         jsi = JSInterpreter('''
  333         function x() { return [undefined === null, undefined == null, undefined < null, undefined > null]; }
  334         ''')
  335         self.assertEqual(jsi.call_function('x'), [False, True, False, False])
  336 
  337         jsi = JSInterpreter('''
  338         function x() { let v; return [42+v, v+42, v**42, 42**v, 0**v]; }
  339         ''')
  340         for y in jsi.call_function('x'):
  341             self.assertTrue(math.isnan(y))
  342 
  343         jsi = JSInterpreter('''
  344         function x() { let v; return v**0; }
  345         ''')
  346         self.assertEqual(jsi.call_function('x'), 1)
  347 
  348         jsi = JSInterpreter('''
  349         function x() { let v; return [v>42, v<=42, v&&42, 42&&v]; }
  350         ''')
  351         self.assertEqual(jsi.call_function('x'), [False, False, JS_Undefined, JS_Undefined])
  352 
  353         jsi = JSInterpreter('function x(){return undefined ?? 42; }')
  354         self.assertEqual(jsi.call_function('x'), 42)
  355 
  356     def test_object(self):
  357         jsi = JSInterpreter('''
  358         function x() { return {}; }
  359         ''')
  360         self.assertEqual(jsi.call_function('x'), {})
  361 
  362         jsi = JSInterpreter('''
  363         function x() { let a = {m1: 42, m2: 0 }; return [a["m1"], a.m2]; }
  364         ''')
  365         self.assertEqual(jsi.call_function('x'), [42, 0])
  366 
  367         jsi = JSInterpreter('''
  368         function x() { let a; return a?.qq; }
  369         ''')
  370         self.assertIs(jsi.call_function('x'), JS_Undefined)
  371 
  372         jsi = JSInterpreter('''
  373         function x() { let a = {m1: 42, m2: 0 }; return a?.qq; }
  374         ''')
  375         self.assertIs(jsi.call_function('x'), JS_Undefined)
  376 
  377     def test_regex(self):
  378         jsi = JSInterpreter('''
  379         function x() { let a=/,,[/,913,/](,)}/; }
  380         ''')
  381         self.assertIs(jsi.call_function('x'), None)
  382 
  383         jsi = JSInterpreter('''
  384         function x() { let a=/,,[/,913,/](,)}/; return a; }
  385         ''')
  386         self.assertIsInstance(jsi.call_function('x'), compat_re_Pattern)
  387 
  388         jsi = JSInterpreter('''
  389         function x() { let a=/,,[/,913,/](,)}/i; return a; }
  390         ''')
  391         self.assertEqual(jsi.call_function('x').flags & ~re.U, re.I)
  392 
  393     def test_char_code_at(self):
  394         jsi = JSInterpreter('function x(i){return "test".charCodeAt(i)}')
  395         self.assertEqual(jsi.call_function('x', 0), 116)
  396         self.assertEqual(jsi.call_function('x', 1), 101)
  397         self.assertEqual(jsi.call_function('x', 2), 115)
  398         self.assertEqual(jsi.call_function('x', 3), 116)
  399         self.assertEqual(jsi.call_function('x', 4), None)
  400         self.assertEqual(jsi.call_function('x', 'not_a_number'), 116)
  401 
  402     def test_bitwise_operators_overflow(self):
  403         jsi = JSInterpreter('function x(){return -524999584 << 5}')
  404         self.assertEqual(jsi.call_function('x'), 379882496)
  405 
  406         jsi = JSInterpreter('function x(){return 1236566549 << 5}')
  407         self.assertEqual(jsi.call_function('x'), 915423904)
  408 
  409 
  410 if __name__ == '__main__':
  411     unittest.main()

Generated by cgit