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 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 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 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 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 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 testLocker(self): with STPyV8.JSIsolate(): self.assertFalse(STPyV8.JSLocker.active) self.assertFalse(STPyV8.JSLocker.locked) with STPyV8.JSLocker() as outter_locker: self.assertTrue(STPyV8.JSLocker.active) self.assertTrue(STPyV8.JSLocker.locked) self.assertTrue(outter_locker) with STPyV8.JSLocker() as inner_locker: self.assertTrue(STPyV8.JSLocker.locked) self.assertTrue(outter_locker) self.assertTrue(inner_locker) with STPyV8.JSUnlocker(): self.assertFalse(STPyV8.JSLocker.locked) self.assertTrue(outter_locker) self.assertTrue(inner_locker) self.assertTrue(STPyV8.JSLocker.locked) self.assertTrue(STPyV8.JSLocker.active) self.assertFalse(STPyV8.JSLocker.locked) locker = STPyV8.JSLocker() with STPyV8.JSContext(): self.assertRaises(RuntimeError, locker.__enter__) self.assertRaises(RuntimeError, locker.__exit__, None, None, None) del locker
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 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 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 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 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 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 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 run(): with STPyV8.JSIsolate(): with STPyV8.JSContext(g) as ctxt: ctxt.eval(""" for (i=0; i<10; i++) add(i); """)
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 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 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 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 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 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 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 testObjectBuiltInMethods(self): class Global(STPyV8.JSClass): version = 1.0 with STPyV8.JSContext(Global()) as ctxt: self.assertEqual("[object Global]", str(ctxt.eval("this.toString()"))) self.assertEqual("[object Global]", str(ctxt.eval("this.toLocaleString()"))) self.assertEqual(Global.version, float(ctxt.eval("this.valueOf()").version)) self.assertTrue(bool(ctxt.eval("this.hasOwnProperty(\"version\")"))) self.assertFalse(ctxt.eval("this.hasOwnProperty(\"nonexistent\")"))
def testJavascriptWrapper(self): with STPyV8.JSContext() as ctxt: self.assertEqual(type(None), type(ctxt.eval("null"))) self.assertEqual(type(None), type(ctxt.eval("undefined"))) self.assertEqual(bool, type(ctxt.eval("true"))) self.assertEqual(str, type(ctxt.eval("'test'"))) self.assertEqual(int, type(ctxt.eval("123"))) self.assertEqual(float, type(ctxt.eval("3.14"))) self.assertEqual(datetime.datetime, type(ctxt.eval("new Date()"))) self.assertEqual(STPyV8.JSArray, type(ctxt.eval("[1, 2, 3]"))) self.assertEqual(STPyV8.JSFunction, type(ctxt.eval("(function() {})"))) self.assertEqual(STPyV8.JSObject, type(ctxt.eval("new Object()")))
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 test(): with STPyV8.JSContext() as ctxt: fn = ctxt.eval("(function (obj) { obj.say(); })") obj = Hello() self.assertEqual(2, sys.getrefcount(obj)) fn(obj) self.assertEqual(4, sys.getrefcount(obj)) del obj
def testClassicStyleObject(self): class FileSystemWrapper: @property def cwd(self): return os.getcwd() class Global: @property def fs(self): return FileSystemWrapper() with STPyV8.JSContext(Global()) as ctxt: self.assertEqual(os.getcwd(), ctxt.eval("fs.cwd"))