mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-12-05 04:35:04 -05:00
206 lines
6.0 KiB
Python
206 lines
6.0 KiB
Python
import os
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
from threading import Event, Thread
|
|
|
|
import dukpy
|
|
|
|
undefined, JSError, Context = dukpy.undefined, dukpy.JSError, dukpy.Context
|
|
|
|
|
|
class ContextTests(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.ctx = Context()
|
|
self.g = self.ctx.g
|
|
|
|
def test_create_context(self):
|
|
pass
|
|
|
|
def test_create_new_global_env(self):
|
|
new = self.ctx.new_global_env()
|
|
|
|
# The new context should have a distinct global object
|
|
self.g.a = 1
|
|
self.assertIs(new.g.a, undefined)
|
|
|
|
def test_eval(self):
|
|
pass
|
|
|
|
def test_eval_file(self):
|
|
pass
|
|
|
|
def test_undefined(self):
|
|
self.assertEqual(repr(undefined), 'undefined')
|
|
|
|
def test_roundtrip(self):
|
|
self.g.g = self.ctx.eval('function f() {return 1;}; f')
|
|
self.assertEqual(self.g.g.name, 'f')
|
|
self.g.a = self.ctx.eval('[1,2,3]')
|
|
self.assertEqual(self.g.a[2], 3)
|
|
|
|
|
|
class ValueTests(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.ctx = Context()
|
|
self.g = self.ctx.g
|
|
|
|
def test_simple(self):
|
|
for value in [undefined, None, True, False]:
|
|
self.g.value = value
|
|
self.assertIs(self.g.value, value)
|
|
|
|
for value in ["foo", 42, 3.141592, 3.141592e20]:
|
|
self.g.value = value
|
|
self.assertEqual(self.g.value, value)
|
|
|
|
def test_object(self):
|
|
self.g.value = {}
|
|
self.assertEqual(dict(self.g.value), {})
|
|
|
|
self.g.value = {'a': 1}
|
|
self.assertEqual(dict(self.g.value), {'a': 1})
|
|
|
|
self.g.value = {'a': {'b': 2}}
|
|
self.assertEqual(dict(self.g.value.a), {'b': 2})
|
|
|
|
def test_array(self):
|
|
self.g.value = []
|
|
self.assertEqual(list(self.g.value), [])
|
|
|
|
self.g.value = [0, 1, 2]
|
|
self.assertEqual(self.g.value[0], 0)
|
|
self.assertEqual(self.g.value[1], 1)
|
|
self.assertEqual(self.g.value[2], 2)
|
|
self.assertEqual(self.g.value[3], undefined)
|
|
self.assertEqual(list(self.g.value), [0, 1, 2])
|
|
self.assertEqual(len(self.g.value), 3)
|
|
|
|
self.g.value[1] = 9
|
|
self.assertEqual(self.g.value[0], 0)
|
|
self.assertEqual(self.g.value[1], 9)
|
|
self.assertEqual(self.g.value[2], 2)
|
|
self.assertEqual(self.g.value[3], undefined)
|
|
self.assertEqual(list(self.g.value), [0, 9, 2])
|
|
self.assertEqual(len(self.g.value), 3)
|
|
|
|
def test_callable(self):
|
|
def f(x):
|
|
return x * x
|
|
num = sys.getrefcount(f)
|
|
self.g.func = f
|
|
self.assertEqual(sys.getrefcount(f), num + 1)
|
|
self.assertEqual(self.g.func(123), 15129)
|
|
self.g.func = undefined
|
|
self.assertEqual(sys.getrefcount(f), num)
|
|
|
|
a = 13450234
|
|
|
|
def rval():
|
|
return a
|
|
num = sys.getrefcount(a)
|
|
self.g.func = rval
|
|
self.assertEqual(self.g.eval('func()'), a)
|
|
self.assertEqual(sys.getrefcount(a), num)
|
|
|
|
def bad():
|
|
raise Exception('testing a python exception xyz')
|
|
self.g.func = bad
|
|
val = self.g.eval('try{func();}catch(err) {err.message}')
|
|
self.assertTrue('testing a python exception xyz' in val)
|
|
self.assertTrue('bad at 0x' in val)
|
|
|
|
def test_proxy(self):
|
|
self.g.obj1 = {'a': 42}
|
|
self.g.obj2 = self.g.obj1
|
|
self.assertEqual(self.g.obj1.a, self.g.obj2.a)
|
|
self.ctx.eval('function f() {nonexistent()}')
|
|
try:
|
|
self.g.f()
|
|
self.assert_('No error raised for bad function')
|
|
except JSError as e:
|
|
e = e.args[0]
|
|
self.assertEqual('ReferenceError', e['name'])
|
|
self.assertIn('nonexistent', e['message'])
|
|
|
|
|
|
class EvalTests(unittest.TestCase):
|
|
|
|
def setUp(self):
|
|
self.ctx = Context()
|
|
self.g = self.ctx.g
|
|
|
|
with tempfile.NamedTemporaryFile(
|
|
prefix='dukpy-test-', suffix='.js', delete=False) as fobj:
|
|
fobj.write(b'1+1')
|
|
self.testfile = fobj.name
|
|
|
|
def tearDown(self):
|
|
os.remove(self.testfile)
|
|
|
|
def test_eval_invalid_args(self):
|
|
with self.assertRaises(TypeError):
|
|
self.ctx.eval()
|
|
|
|
with self.assertRaises(TypeError):
|
|
self.ctx.eval(123)
|
|
|
|
def test_eval(self):
|
|
self.assertEqual(self.ctx.eval("1+1"), 2)
|
|
|
|
def test_eval_kwargs(self):
|
|
self.assertEqual(self.ctx.eval(code="1+1"), 2)
|
|
|
|
def test_eval_errors(self):
|
|
try:
|
|
self.ctx.eval('1+/1')
|
|
self.assert_('No error raised for malformed js')
|
|
except JSError as e:
|
|
e = e.args[0]
|
|
self.assertEqual('SyntaxError', e['name'])
|
|
self.assertEqual('<eval>', e['fileName'])
|
|
self.assertEqual(1, e['lineNumber'])
|
|
self.assertIn('line 1', e['message'])
|
|
|
|
try:
|
|
self.ctx.eval('\na()', fname='xxx')
|
|
self.assert_('No error raised for malformed js')
|
|
except JSError as e:
|
|
e = e.args[0]
|
|
self.assertEqual('ReferenceError', e['name'])
|
|
self.assertEqual('xxx', e['fileName'])
|
|
self.assertEqual(2, e['lineNumber'])
|
|
|
|
def test_eval_multithreading(self):
|
|
ev = Event()
|
|
self.ctx.g.func = ev.wait
|
|
t = Thread(target=self.ctx.eval, args=('func()',))
|
|
t.daemon = True
|
|
t.start()
|
|
t.join(0.01)
|
|
self.assertTrue(t.is_alive())
|
|
ev.set()
|
|
t.join(1)
|
|
self.assertFalse(t.is_alive())
|
|
|
|
def test_eval_noreturn(self):
|
|
self.assertIsNone(self.ctx.eval("1+1", noreturn=True))
|
|
|
|
def test_eval_file_invalid_args(self):
|
|
with self.assertRaises(TypeError):
|
|
self.ctx.eval_file()
|
|
|
|
with self.assertRaises(TypeError):
|
|
self.ctx.eval_file(123)
|
|
|
|
def test_eval_file(self):
|
|
self.assertEqual(self.ctx.eval_file(self.testfile), 2)
|
|
|
|
def test_eval_file_kwargs(self):
|
|
self.assertEqual(self.ctx.eval_file(path=self.testfile), 2)
|
|
|
|
def test_eval_file_noreturn(self):
|
|
self.assertIsNone(self.ctx.eval_file(self.testfile, noreturn=True))
|