def testSecurityChecks(self): with STPyV8.JSContext() as env1: env1.securityToken = "foo" # Create a function in env1. env1.eval("spy = function(){return spy;}") spy = env1.locals.spy self.assertTrue(isinstance(spy, STPyV8.JSFunction)) # Create another function accessing global objects. env1.eval("spy2 = function(){return 123;}") spy2 = env1.locals.spy2 self.assertTrue(isinstance(spy2, STPyV8.JSFunction)) # Switch to env2 in the same domain and invoke spy on env2. env2 = STPyV8.JSContext() env2.securityToken = "foo" with env2: result = spy.apply(env2.locals) self.assertTrue(isinstance(result, STPyV8.JSFunction)) env2.securityToken = "bar"
def run(): with STPyV8.JSIsolate(): with STPyV8.JSContext(g) as ctxt: ctxt.eval(""" for (i=0; i<10; i++) add(i); """)
def testMultiNamespace(self): self.assertTrue(not bool(STPyV8.JSContext.inContext)) self.assertTrue(not bool(STPyV8.JSContext.entered)) class Global(object): name = "global" g = Global() with STPyV8.JSContext(g) as ctxt: self.assertTrue(ctxt) self.assertTrue(bool(STPyV8.JSContext.inContext)) self.assertEqual(g.name, str(STPyV8.JSContext.entered.locals.name)) class Local(object): name = "local" l = Local() with STPyV8.JSContext(l): self.assertTrue(bool(STPyV8.JSContext.inContext)) self.assertEqual(l.name, str(STPyV8.JSContext.entered.locals.name)) self.assertTrue(bool(STPyV8.JSContext.inContext)) self.assertEqual(g.name, str(STPyV8.JSContext.current.locals.name)) self.assertTrue(not bool(STPyV8.JSContext.entered)) self.assertTrue(not bool(STPyV8.JSContext.inContext))
def testErrorInfo(self): with STPyV8.JSContext(): with STPyV8.JSEngine() as engine: try: engine.compile( """ function hello() { throw Error("hello world"); } hello();""", "test", 10, 10).run() self.fail() except STPyV8.JSError as e: self.assertTrue( "JSError: Error: hello world ( test @ 14 : 28 ) ->" in str(e)) self.assertEqual("Error", e.name) self.assertEqual("hello world", e.message) self.assertEqual("test", e.scriptName) self.assertEqual(14, e.lineNum) self.assertEqual(96, e.startPos) self.assertEqual(97, e.endPos) self.assertEqual(28, e.startCol) self.assertEqual(29, e.endCol) self.assertEqual('throw Error("hello world");', e.sourceLine.strip()) self.assertEqual( 'Error: hello world\n' + ' at hello (test:14:35)\n' + ' at test:17:25', e.stackTrace)
def testCompile(self): with STPyV8.JSContext(): with STPyV8.JSEngine() as engine: s = engine.compile("1+2") self.assertTrue(isinstance(s, STPyV8.JSScript)) self.assertEqual("1+2", s.source) self.assertEqual(3, int(s.run())) self.assertRaises(SyntaxError, engine.compile, "1+")
def run(): with STPyV8.JSIsolate(): with STPyV8.JSContext(g) as ctxt: ctxt.eval(""" started.wait(); for (i=0; i<10; i++) { sleep(100); } finished.release(); """)
def testStackLimit(self): with STPyV8.JSIsolate(): STPyV8.JSEngine.setStackLimit(256 * 1024) with STPyV8.JSContext() as ctxt: oldStackSize = ctxt.eval("var maxStackSize = function(i){try{(function m(){++i&&m()}())}catch(e){return i}}(0); maxStackSize") with STPyV8.JSIsolate(): STPyV8.JSEngine.setStackLimit(512 * 1024) with STPyV8.JSContext() as ctxt: newStackSize = ctxt.eval("var maxStackSize = function(i){try{(function m(){++i&&m()}())}catch(e){return i}}(0); maxStackSize") self.assertTrue(newStackSize > oldStackSize * 2)
def testUnicodeSource(self): class Global(STPyV8.JSClass): var = u'测试' def __getattr__(self, name): if name: return self.var return STPyV8.JSClass.__getattr__(self, name) g = Global() with STPyV8.JSContext(g) as ctxt: with STPyV8.JSEngine() as engine: src = u""" function 函数() { return 变量.length; } 函数(); var func = function () {}; """ s = engine.compile(src) self.assertTrue(isinstance(s, STPyV8.JSScript)) self.assertEqual(src, s.source) self.assertEqual(2, s.run()) func_name = u'函数' self.assertTrue(hasattr(ctxt.locals, func_name)) func = getattr(ctxt.locals, func_name) self.assertTrue(isinstance(func, STPyV8.JSFunction)) self.assertEqual(func_name, func.name) self.assertEqual("", func.resname) self.assertEqual(1, func.linenum) self.assertEqual(0, func.lineoff) self.assertEqual(0, func.coloff) var_name = u'变量' setattr(ctxt.locals, var_name, u'测试长字符串') self.assertEqual(6, func()) self.assertEqual("func", ctxt.locals.func.inferredname)
def _testOutOfMemory(self): with STPyV8.JSIsolate(): STPyV8.JSEngine.setMemoryLimit(max_young_space_size=16 * 1024, max_old_space_size=4 * 1024 * 1024) with STPyV8.JSContext() as ctxt: STPyV8.JSEngine.ignoreOutOfMemoryException() ctxt.eval("var a = new Array(); while(true) a.push(a);") self.assertTrue(ctxt.hasOutOfMemoryException) STPyV8.JSEngine.setMemoryLimit() STPyV8.JSEngine.collect()
def testThis(self): class Global(STPyV8.JSClass): version = 1.0 with STPyV8.JSContext(Global()) as ctxt: self.assertEqual("[object Global]", str(ctxt.eval("this"))) self.assertEqual(1.0, float(ctxt.eval("this.version")))
def testMultiJavascriptThread(self): class Global(STPyV8.JSContext): result = [] def add(self, value): with STPyV8.JSUnlocker(): self.result.append(value) g = Global() def run(): with STPyV8.JSIsolate(): with STPyV8.JSContext(g) as ctxt: ctxt.eval(""" for (i=0; i<10; i++) add(i); """) threads = [threading.Thread(target=run), threading.Thread(target=run)] with STPyV8.JSLocker(): for t in threads: t.start() for t in threads: t.join() self.assertEqual(20, len(g.result))
def testForEach(self): class NamedClass(object): foo = 1 # pylint:disable=disallowed-name def __init__(self): self.bar = 2 # pylint:disable=disallowed-name @property def foobar(self): return self.foo + self.bar def gen(x): for i in range(x): yield i with STPyV8.JSContext() as ctxt: func = ctxt.eval("""(function (k) { var result = []; for (var prop in k) { result.push(prop); } return result; })""") self.assertTrue(set(["bar", "foo", "foobar"]).issubset(set(func(NamedClass())))) self.assertEqual(["0", "1", "2"], list(func([1, 2, 3]))) self.assertEqual(["0", "1", "2"], list(func((1, 2, 3)))) self.assertEqual(["1", "2", "3"], list(func({'1' : 1, '2' : 2, '3' : 3}))) self.assertEqual(["0", "1", "2"], list(func(list(gen(3)))))
def testPromiseRejected(self): with STPyV8.JSContext() as ctxt: ctxt.eval(""" var message; let done = false; const isItDoneYet = new Promise((resolve, reject) => { if (done) { const workDone = 'Here is the thing I built' resolve(workDone) } else { const why = 'Still working on something else' reject(why) } }) const checkIfItsDone = () => { isItDoneYet.then(ok => { message = ok; }).catch(err => { message = err; }) } checkIfItsDone() """) self.assertEqual('Still working on something else', ctxt.locals.message)
def testPythonWrapper(self): with STPyV8.JSContext() as ctxt: typeof = ctxt.eval( "(function type(value) { return typeof value; })") protoof = ctxt.eval( "(function protoof(value) { return Object.prototype.toString.apply(value); })" ) self.assertEqual('[object Null]', protoof(None)) self.assertEqual('boolean', typeof(True)) self.assertEqual('number', typeof(123)) self.assertEqual('number', typeof(3.14)) self.assertEqual('string', typeof('test')) self.assertEqual('string', typeof(u'test')) self.assertEqual('[object Date]', protoof(datetime.datetime.now())) self.assertEqual('[object Date]', protoof(datetime.date.today())) self.assertEqual('[object Date]', protoof(datetime.time())) def test(): pass self.assertEqual('[object Function]', protoof(abs)) self.assertEqual('[object Function]', protoof(test)) self.assertEqual('[object Function]', protoof(self.testPythonWrapper)) self.assertEqual('[object Function]', protoof(int))
def testWatch(self): class Obj(STPyV8.JSClass): def __init__(self): self.p = 1 class Global(STPyV8.JSClass): def __init__(self): self.o = Obj() with STPyV8.JSContext(Global()) as ctxt: ctxt.eval(""" o.watch("p", function (id, oldval, newval) { return oldval + newval; }); """) self.assertEqual(1, ctxt.eval("o.p")) ctxt.eval("o.p = 2;") self.assertEqual(3, ctxt.eval("o.p")) ctxt.eval("delete o.p;") self.assertEqual(None, ctxt.eval("o.p")) ctxt.eval("o.p = 2;") self.assertEqual(2, ctxt.eval("o.p")) ctxt.eval("o.unwatch('p');") ctxt.eval("o.p = 1;") self.assertEqual(1, ctxt.eval("o.p"))
def testNamedSetter(self): class Obj(STPyV8.JSClass): @property def p(self): return self._p @p.setter def p(self, value): self._p = value class Global(STPyV8.JSClass): def __init__(self): self.obj = Obj() self.d = {} self.p = None with STPyV8.JSContext(Global()) as ctxt: ctxt.eval(""" x = obj; x.y = 10; x.p = 10; d.y = 10; """) self.assertEqual(10, ctxt.eval("obj.y")) self.assertEqual(10, ctxt.eval("obj.p")) self.assertEqual(10, ctxt.locals.d['y'])
def testFunction(self): with STPyV8.JSContext() as ctxt: func = ctxt.eval(""" (function () { function a() { return "abc"; } return a(); }) """) self.assertEqual("abc", str(func())) self.assertTrue(func != None) self.assertFalse(func == None) func = ctxt.eval("(function test() {})") self.assertEqual("test", func.name) self.assertEqual("", func.resname) self.assertEqual(0, func.linenum) self.assertEqual(14, func.colnum) self.assertEqual(0, func.lineoff) self.assertEqual(0, func.coloff) # FIXME # Why the setter doesn't work? # # func.name = "hello" # self.assertEqual("hello", func.name) func.setName("hello") self.assertEqual("hello", func.name)
def testRefCount(self): count = sys.getrefcount(None) class Global(STPyV8.JSClass): pass g = Global() g_refs = sys.getrefcount(g) with STPyV8.JSContext(g) as ctxt: ctxt.eval(""" var none = null; """) self.assertEqual(count + 1, sys.getrefcount(None)) ctxt.eval(""" var none = null; """) self.assertEqual(count + 1, sys.getrefcount(None)) del ctxt self.assertEqual(g_refs, sys.getrefcount(g))
def testDict(self): with STPyV8.JSContext() as ctxt: obj = ctxt.eval("var r = { 'a' : 1, 'b' : 2 }; r") self.assertEqual(1, obj.a) self.assertEqual(2, obj.b) self.assertEqual({'a': 1, 'b': 2}, dict(obj)) self.assertEqual( { 'a': 1, 'b': [1, 2, 3], 'c': { 'str': 'goofy', 'float': 1.234, 'obj': { 'name': 'john doe' } }, 'd': True, 'e': None }, convert( ctxt.eval("""var x = { a: 1, b: [1, 2, 3], c: { str: 'goofy', float: 1.234, obj: { name: 'john doe' }}, d: true, e: null }; x""")))
def testJSError(self): with STPyV8.JSContext() as ctxt: try: ctxt.eval('throw "test"') self.fail() except Exception: self.assertTrue(STPyV8.JSError, sys.exc_info()[0])
def testLazyConstructor(self): class Globals(STPyV8.JSClass): def __init__(self): self.array = STPyV8.JSArray([1, 2, 3]) with STPyV8.JSContext(Globals()) as ctxt: self.assertEqual(2, ctxt.eval("""array[1]"""))
def testStackTrace(self): class Global(STPyV8.JSClass): def GetCurrentStackTrace(self, limit): return STPyV8.JSStackTrace.GetCurrentStackTrace( 4, STPyV8.JSStackTrace.Options.Detailed) with STPyV8.JSContext(Global()) as ctxt: st = ctxt.eval( """ function a() { return GetCurrentStackTrace(10); } function b() { return eval("a()"); } function c() { return new b(); } c();""", "test") self.assertEqual(4, len(st)) self.assertEqual( "\tat a (test:4:28)\n\tat eval ((eval))\n\tat b (test:8:28)\n\tat c (test:12:28)\n", str(st)) self.assertEqual( "test.a (4:28)\n.eval (1:1) eval\ntest.b (8:28) constructor\ntest.c (12:28)", "\n".join([ "%s.%s (%d:%d)%s%s" % (f.scriptName, f.funcName, f.lineNum, f.column, ' eval' if f.isEval else '', ' constructor' if f.isConstructor else '') for f in st ]))
def testConstructor(self): with STPyV8.JSContext() as ctx: ctx.eval(""" var Test = function() { this.trySomething(); }; Test.prototype.trySomething = function() { this.name = 'soirv8'; }; var Test2 = function(first_name, last_name) { this.name = first_name + ' ' + last_name; }; """) self.assertTrue(isinstance(ctx.locals.Test, STPyV8.JSFunction)) test = STPyV8.JSObject.create(ctx.locals.Test) self.assertTrue(isinstance(ctx.locals.Test, STPyV8.JSObject)) self.assertEqual("soirv8", test.name) test2 = STPyV8.JSObject.create(ctx.locals.Test2, ('John', 'Doe')) self.assertEqual("John Doe", test2.name) test3 = STPyV8.JSObject.create( ctx.locals.Test2, ('John', 'Doe'), {'email': '*****@*****.**'}) self.assertEqual("*****@*****.**", test3.email)
def testUnicode(self): with STPyV8.JSContext() as ctxt: self.assertEqual(u"人", ctxt.eval(u"\"人\"")) self.assertEqual(u"é", ctxt.eval(u"\"é\"")) func = ctxt.eval("(function (msg) { return msg.length; })") self.assertEqual(2, func(u"测试"))
def testExceptionMapping(self): class TestException(Exception): pass class Global(STPyV8.JSClass): def raiseIndexError(self): return [1, 2, 3][5] def raiseAttributeError(self): None.hello() def raiseSyntaxError(self): eval("???") def raiseTypeError(self): int(sys) def raiseNotImplementedError(self): raise NotImplementedError("Not supported") def raiseExceptions(self): raise TestException() with STPyV8.JSContext(Global()) as ctxt: ctxt.eval("try { this.raiseIndexError(); } catch (e) { msg = e; }") self.assertEqual("RangeError: list index out of range", str(ctxt.locals.msg)) ctxt.eval( "try { this.raiseAttributeError(); } catch (e) { msg = e; }") self.assertEqual( "ReferenceError: 'NoneType' object has no attribute 'hello'", str(ctxt.locals.msg)) ctxt.eval( "try { this.raiseSyntaxError(); } catch (e) { msg = e; }") self.assertEqual("SyntaxError: invalid syntax", str(ctxt.locals.msg)) ctxt.eval("try { this.raiseTypeError(); } catch (e) { msg = e; }") self.assertEqual( "TypeError: int() argument must be a string, a bytes-like object or a number, not 'module'", str(ctxt.locals.msg)) ctxt.eval( "try { this.raiseNotImplementedError(); } catch (e) { msg = e; }" ) self.assertEqual("Error: Not supported", str(ctxt.locals.msg)) self.assertRaises(TestException, ctxt.eval, "this.raiseExceptions();")
def testLivingObjectCache(self): class Global(STPyV8.JSClass): i = 1 b = True o = object() with STPyV8.JSContext(Global()) as ctxt: self.assertTrue(ctxt.eval("i == i")) self.assertTrue(ctxt.eval("b == b")) self.assertTrue(ctxt.eval("o == o"))
def testMultiContext(self): with STPyV8.JSContext() as ctxt0: ctxt0.securityToken = "password" global0 = ctxt0.locals global0.custom = 1234 self.assertEqual(1234, int(global0.custom)) with STPyV8.JSContext() as ctxt1: ctxt1.securityToken = ctxt0.securityToken global1 = ctxt1.locals global1.custom = 1234 with ctxt0: self.assertEqual(1234, int(global0.custom)) self.assertEqual(1234, int(global1.custom))
def testCall(self): class Hello(object): def __call__(self, name): return "hello " + name class Global(STPyV8.JSClass): hello = Hello() with STPyV8.JSContext(Global()) as ctxt: self.assertEqual("hello world", ctxt.eval("hello('world')"))
def testObject(self): with STPyV8.JSContext() as ctxt: o = ctxt.eval("new Object()") self.assertTrue(hash(o) > 0) o1 = o.clone() self.assertEqual(hash(o1), hash(o)) self.assertTrue(o != o1) self.assertRaises(UnboundLocalError, o.clone)
def testUndefined(self): class Global(STPyV8.JSClass): def returnNull(self): return STPyV8.JSNull() def returnUndefined(self): return STPyV8.JSUndefined() def returnNone(self): return None with STPyV8.JSContext(Global()) as ctxt: self.assertFalse(bool(STPyV8.JSNull())) self.assertFalse(bool(STPyV8.JSUndefined())) self.assertEqual("null", str(STPyV8.JSNull())) self.assertEqual("undefined", str(STPyV8.JSUndefined())) self.assertTrue(ctxt.eval('null == returnNull()')) self.assertTrue(ctxt.eval('undefined == returnUndefined()')) self.assertTrue(ctxt.eval('null == returnNone()'))