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