Mercurial > pymonkey
diff tests/test_pydermonkey.py @ 170:dd32a92f6b4f
Initial attempt at renaming pymonkey to pydermonkey.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Tue, 01 Sep 2009 03:07:24 -0700 |
parents | tests/test_pymonkey.py@2eaae00d5e30 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/test_pydermonkey.py Tue Sep 01 03:07:24 2009 -0700 @@ -0,0 +1,830 @@ +import gc +import sys +import unittest +import weakref +import time +import threading + +import pydermonkey + +class PydermonkeyTests(unittest.TestCase): + def setUp(self): + self._teardowns = [] + + def tearDown(self): + self.last_exception = None + while self._teardowns: + obj = self._teardowns.pop() + runtime = obj.get_runtime() + runtime.new_context().clear_object_private(obj) + del runtime + del obj + self.assertEqual(pydermonkey.get_debug_info()['runtime_count'], 0) + + def _clearOnTeardown(self, obj): + self._teardowns.append(obj) + + def _evaljs(self, code): + rt = pydermonkey.Runtime() + cx = rt.new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + return cx.evaluate_script(obj, code, '<string>', 1) + + def _execjs(self, code): + rt = pydermonkey.Runtime() + cx = rt.new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + script = cx.compile_script(code, '<string>', 1) + return cx.execute_script(obj, script) + + def _evalJsWrappedPyFunc(self, func, code): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc = cx.new_function(func, func.__name__) + self._clearOnTeardown(jsfunc) + cx.define_property(obj, func.__name__, jsfunc) + return cx.evaluate_script(obj, code, '<string>', 1) + + def assertRaises(self, exctype, func, *args): + was_raised = False + try: + func(*args) + except exctype, e: + self.last_exception = e + was_raised = True + self.assertTrue(was_raised) + + def testSyntaxErrorsAreRaised(self): + for run in [self._evaljs, self._execjs]: + self.assertRaises(pydermonkey.error, run, '5f') + self.assertEqual( + self.last_exception.args[1], + u'SyntaxError: missing ; before statement' + ) + + def testGetStackOnEmptyStackReturnsNone(self): + cx = pydermonkey.Runtime().new_context() + self.assertEqual(cx.get_stack(), None) + + def testGetStackWorks(self): + stack_holder = [] + + def func(cx, this, args): + stack_holder.append(cx.get_stack()) + + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc = cx.new_function(func, func.__name__) + self._clearOnTeardown(jsfunc) + cx.define_property(obj, func.__name__, jsfunc) + cx.evaluate_script(obj, '(function closure() { \nfunc() })()', + '<string>', 1) + stack = stack_holder[0] + script = stack['caller']['caller']['script'] + pc = stack['caller']['caller']['pc'] + closure = stack['caller']['function'] + self.assertEqual(closure.name, 'closure') + self.assertEqual(closure.filename, '<string>') + self.assertEqual(stack['caller']['script'], None) + self.assertEqual(stack['caller']['lineno'], 2) + self.assertEqual(script.filename, '<string>') + self.assertEqual(stack['caller']['caller']['lineno'], 1) + self.assertTrue(pc >= 0 and pc < len(buffer(script))) + self.assertEqual(stack['caller']['caller']['caller'], None) + + def testScriptHasFilenameMember(self): + cx = pydermonkey.Runtime().new_context() + script = cx.compile_script('foo', '<string>', 1) + self.assertEqual(script.filename, '<string>') + + def testScriptHasLineInfo(self): + cx = pydermonkey.Runtime().new_context() + script = cx.compile_script('foo\nbar', '<string>', 1) + self.assertEqual(script.base_lineno, 1) + self.assertEqual(script.line_extent, 2) + + def testScriptIsExposedAsBuffer(self): + rt = pydermonkey.Runtime() + cx = rt.new_context() + script = cx.compile_script('foo', '<string>', 1) + self.assertTrue(len(buffer(script)) > 0) + + def testCompileScriptWorks(self): + self.assertEqual(self._execjs('5 + 1'), 6) + + def testErrorsRaisedIncludeStrings(self): + self.assertRaises(pydermonkey.error, self._evaljs, 'boop()') + self.assertEqual(self.last_exception.args[1], + u'ReferenceError: boop is not defined') + + def testThreadSafetyExceptionIsRaised(self): + stuff = {} + def make_runtime(): + stuff['rt'] = pydermonkey.Runtime() + thread = threading.Thread(target = make_runtime) + thread.start() + thread.join() + self.assertRaises(pydermonkey.error, + stuff['rt'].new_context) + self.assertEqual(self.last_exception.args[0], + 'Function called from wrong thread') + del stuff['rt'] + + def testClearObjectPrivateWorks(self): + class Foo(object): + pass + pyobj = Foo() + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object(pyobj) + pyobj = weakref.ref(pyobj) + self.assertEqual(pyobj(), cx.get_object_private(obj)) + cx.clear_object_private(obj) + self.assertEqual(cx.get_object_private(obj), None) + self.assertEqual(pyobj(), None) + + def testGetObjectPrivateWorks(self): + class Foo(object): + pass + pyobj = Foo() + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object(pyobj) + pyobj = weakref.ref(pyobj) + self.assertEqual(pyobj(), cx.get_object_private(obj)) + del obj + del cx + self.assertEqual(pyobj(), None) + + def testContextSupportsCyclicGc(self): + def makecx(): + cx = pydermonkey.Runtime().new_context() + + def opcb(othercx): + return cx + + cx.set_operation_callback(opcb) + return cx + + gc.disable() + cx = makecx() + wcx = weakref.ref(cx) + self.assertEqual(wcx(), cx) + del cx + self.assertTrue(wcx()) + gc.enable() + gc.collect() + self.assertEqual(wcx(), None) + + def testOperationCallbackIsCalled(self): + def opcb(cx): + raise Exception("stop eet!") + + cx = pydermonkey.Runtime().new_context() + cx.set_operation_callback(opcb) + obj = cx.new_object() + cx.init_standard_classes(obj) + + def watchdog(): + time.sleep(0.1) + cx.trigger_operation_callback() + + thread = threading.Thread(target = watchdog) + thread.start() + + self.assertRaises( + pydermonkey.error, + cx.evaluate_script, + obj, 'while (1) {}', '<string>', 1 + ) + + def testUndefinedStrIsUndefined(self): + self.assertEqual(str(pydermonkey.undefined), + "pydermonkey.undefined") + + def testScriptedJsFuncHasIsPythonFalse(self): + cx = pydermonkey.Runtime().new_context() + jsfunc = cx.evaluate_script(cx.new_object(), + '(function(){})', '<string>', 1) + self.assertFalse(jsfunc.is_python) + + def testJsWrappedPythonFuncHasIsPythonTrue(self): + def foo(cx, this, args): + pass + + cx = pydermonkey.Runtime().new_context() + jsfunc = cx.new_function(foo, foo.__name__) + self.assertTrue(jsfunc.is_python) + + def testJsWrappedPythonFuncHasNoFilename(self): + def foo(cx, this, args): + pass + + cx = pydermonkey.Runtime().new_context() + jsfunc = cx.new_function(foo, foo.__name__) + self.assertEqual(jsfunc.filename, None) + + def testJsScriptedFuncHasNoPrivate(self): + cx = pydermonkey.Runtime().new_context() + jsfunc = cx.evaluate_script(cx.new_object(), + '(function(){})', '<string>', 1) + self.assertEqual(cx.get_object_private(jsfunc), None) + + def testGetPendingExceptionReturnsNone(self): + cx = pydermonkey.Runtime().new_context() + self.assertFalse(cx.is_exception_pending()) + self.assertEqual(cx.get_pending_exception(), None) + + def testThrowHookWorks(self): + exceptions = [] + def throwhook(cx): + self.assertTrue(cx.is_exception_pending()) + exceptions.append(cx.get_pending_exception()) + + cx = pydermonkey.Runtime().new_context() + cx.set_throw_hook(throwhook) + self.assertRaises( + pydermonkey.error, + cx.evaluate_script, + cx.new_object(), + '(function() { throw "hi"; })()', + '<string>', 1 + ) + self.assertEqual(exceptions, ['hi', 'hi']) + self.assertFalse(cx.is_exception_pending()) + self.assertEqual(cx.get_pending_exception(), None) + + def testJsWrappedPythonFuncHasPrivate(self): + def foo(cx, this, args): + pass + + cx = pydermonkey.Runtime().new_context() + jsfunc = cx.new_function(foo, foo.__name__) + self.assertEqual(cx.get_object_private(jsfunc), foo) + + def testJsWrappedPythonFuncIsNotGCd(self): + def define(cx, obj): + def func(cx, this, args): + return u'func was called' + jsfunc = cx.new_function(func, func.__name__) + cx.define_property(obj, func.__name__, jsfunc) + return weakref.ref(func) + rt = pydermonkey.Runtime() + cx = rt.new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + ref = define(cx, obj) + cx.gc() + self.assertNotEqual(ref(), None) + result = cx.evaluate_script(obj, 'func()', '<string>', 1) + self.assertEqual(result, u'func was called') + + # Now ensure that the wrapped function is GC'd when it's + # no longer reachable from JS space. + cx.define_property(obj, 'func', 0) + cx.gc() + self.assertEqual(ref(), None) + + def testCircularJsWrappedPythonFuncIsGCdIfPrivateCleared(self): + def define(cx, obj): + rt = cx.get_runtime() + def func(cx, this, args): + # Oh noes, a circular reference is born! + rt + jsfunc = cx.new_function(func, func.__name__) + cx.define_property(obj, func.__name__, jsfunc) + return (jsfunc, weakref.ref(func)) + rt = pydermonkey.Runtime() + cx = rt.new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc, ref = define(cx, obj) + + # This will break the circular reference. + cx.clear_object_private(jsfunc) + + del jsfunc + del rt + del cx + del obj + self.assertEqual(ref(), None) + + def testFunctionsWithClosuresAreNotIdentical(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + cx.evaluate_script( + obj, "function build(x) { return function foo() { return x; } }", + "<string>", 1 + ) + func1 = cx.evaluate_script(obj, "build(1)", "<string>", 1) + func2 = cx.evaluate_script(obj, "build(2)", "<string>", 1) + self.assertNotEqual(func1, func2) + self.assertEqual(func1.name, 'foo') + self.assertEqual(func1.name, func2.name) + + def testAnonymousJsFunctionHasNullNameAttribute(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc = cx.evaluate_script(obj, "(function() {})", + "<string>", 1) + self.assertEqual(jsfunc.name, None) + + def testJsFunctionHasNameAttribute(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc = cx.evaluate_script(obj, "(function blarg() {})", + "<string>", 1) + self.assertEqual(jsfunc.name, "blarg") + + def testJsWrappedPythonFuncHasNameAttribute(self): + def func(cx, this, args): + return True + + cx = pydermonkey.Runtime().new_context() + jsfunc = cx.new_function(func, "foo") + self.assertEqual(jsfunc.name, "foo") + + def testJsWrappedPythonFuncIsGCdAtRuntimeDestruction(self): + def define(cx, obj): + def func(cx, this, args): + return u'func was called' + jsfunc = cx.new_function(func, func.__name__) + cx.define_property(obj, func.__name__, jsfunc) + return weakref.ref(func) + rt = pydermonkey.Runtime() + cx = rt.new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + ref = define(cx, obj) + del rt + del cx + del obj + self.assertEqual(ref(), None) + + def testJsWrappedPythonFuncThrowsExcIfPrivateCleared(self): + def func(cx, this, args): + return True + + code = "func()" + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc = cx.new_function(func, func.__name__) + cx.define_property(obj, func.__name__, jsfunc) + cx.clear_object_private(jsfunc) + self.assertRaises(pydermonkey.error, + cx.evaluate_script, + obj, code, '<string>', 1) + self.assertEqual( + self._tostring(cx, self.last_exception.args[0]), + "Error: Wrapped Python function no longer exists" + ) + + def testJsWrappedPythonFuncPassesContext(self): + contexts = [] + + def func(cx, this, args): + contexts.append(cx) + return True + + code = "func()" + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc = cx.new_function(func, func.__name__) + self._clearOnTeardown(jsfunc) + cx.define_property(obj, func.__name__, jsfunc) + cx.evaluate_script(obj, code, '<string>', 1) + self.assertEqual(contexts[0], cx) + + def testJsWrappedPythonFuncPassesThisArg(self): + thisObjs = [] + + def func(cx, this, args): + thisObjs.append(this) + return True + + code = "func()" + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc = cx.new_function(func, func.__name__) + self._clearOnTeardown(jsfunc) + cx.define_property(obj, func.__name__, jsfunc) + cx.evaluate_script(obj, code, '<string>', 1) + self.assertEqual(thisObjs[0], obj) + + def testJsWrappedPythonFuncPassesFuncArgs(self): + funcArgs = [] + + def func(cx, this, args): + funcArgs.append(args) + return True + + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc = cx.new_function(func, func.__name__) + self._clearOnTeardown(jsfunc) + + cx.define_property(obj, func.__name__, jsfunc) + + cx.evaluate_script(obj, "func()", '<string>', 1) + self.assertEqual(len(funcArgs[0]), 0) + self.assertTrue(isinstance(funcArgs[0], tuple)) + + cx.evaluate_script(obj, "func(1, 'foo')", '<string>', 1) + self.assertEqual(len(funcArgs[1]), 2) + self.assertEqual(funcArgs[1][0], 1) + self.assertEqual(funcArgs[1][1], u'foo') + + def testJsWrappedPythonFunctionReturnsUnicodeWithEmbeddedNULs(self): + def hai2u(cx, this, args): + return args[0] + u"o hai" + self.assertEqual(self._evalJsWrappedPyFunc(hai2u, + 'hai2u("blah\x00 ")'), + u"blah\x00 o hai") + + def testJsWrappedPythonFunctionReturnsString(self): + def hai2u(cx, this, args): + return "o hai" + self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'), + "o hai") + + def testJsWrappedPythonFunctionReturnsUnicode(self): + def hai2u(cx, this, args): + return u"o hai\u2026" + self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'), + u"o hai\u2026") + + def testJsWrappedPythonFunctionThrowsJsException(self): + def hai2u(cx, this, args): + raise pydermonkey.error(u"blarg") + self.assertRaises(pydermonkey.error, + self._evalJsWrappedPyFunc, + hai2u, 'hai2u()') + self.assertEqual(self.last_exception.args[0], u"blarg") + + def testJsWrappedPythonFunctionThrowsPyException(self): + thecx = [] + def hai2u(cx, this, args): + thecx.append(cx) + raise Exception("hello") + self.assertRaises(pydermonkey.error, + self._evalJsWrappedPyFunc, + hai2u, 'hai2u()') + exc = thecx[0].get_object_private(self.last_exception.args[0]) + self.assertEqual(exc.args[0], "hello") + + def testJsWrappedPythonFunctionReturnsNone(self): + def hai2u(cx, this, args): + pass + self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'), + None) + + def testJsWrappedPythonFunctionReturnsTrue(self): + def hai2u(cx, this, args): + return True + self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'), + True) + + def testJsWrappedPythonFunctionReturnsFalse(self): + def hai2u(cx, this, args): + return False + self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'), + False) + + def testJsWrappedPythonFunctionReturnsSmallInt(self): + def hai2u(cx, this, args): + return 5 + self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'), + 5) + + def testJsWrappedPythonFunctionReturnsFloat(self): + def hai2u(cx, this, args): + return 5.1 + self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'), + 5.1) + + def testJsWrappedPythonFunctionReturnsNegativeInt(self): + def hai2u(cx, this, args): + return -5 + self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'), + -5) + + def testJsWrappedPythonFunctionReturnsBigInt(self): + def hai2u(cx, this, args): + return 2147483647 + self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'), + 2147483647) + + def testHasPropertyWorks(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + foo = cx.new_object() + cx.define_property(obj, u"foo\u2026", foo) + self.assertTrue(cx.has_property(obj, u"foo\u2026")) + self.assertFalse(cx.has_property(obj, "bar")) + + def testDefinePropertyWorksWithUnicodePropertyNames(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + foo = cx.new_object() + cx.define_property(obj, u"foo\u2026", foo) + self.assertEqual( + cx.get_property(obj, u"foo\u2026"), + foo + ) + + def testDefinePropertyWorksWithObject(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + foo = cx.new_object() + cx.define_property(obj, "foo", foo) + self.assertEqual( + cx.evaluate_script(obj, 'foo', '<string>', 1), + foo + ) + + def testDefinePropertyWorksWithString(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + foo = cx.new_object() + cx.define_property(obj, "foo", u"hello") + self.assertEqual( + cx.evaluate_script(obj, 'foo', '<string>', 1), + u"hello" + ) + + def testObjectIsIdentityPreserving(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + cx.evaluate_script(obj, 'var foo = {bar: 1}', '<string>', 1) + self.assertTrue(isinstance(cx.get_property(obj, u"foo"), + pydermonkey.Object)) + self.assertTrue(cx.get_property(obj, u"foo") is + cx.get_property(obj, "foo")) + + def testObjectGetattrThrowsException(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + result = cx.evaluate_script(obj, '({get foo() { throw "blah"; }})', + '<string>', 1) + self.assertRaises(pydermonkey.error, + cx.get_property, + result, + u"foo") + self.assertEqual(self.last_exception.args[0], u"blah") + + def testInfiniteRecursionRaisesError(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + self.assertRaises( + pydermonkey.error, + cx.evaluate_script, + obj, '(function foo() { foo(); })();', '<string>', 1 + ) + self.assertEqual( + self._tostring(cx, self.last_exception.args[0]), + "InternalError: too much recursion" + ) + + def testObjectGetattrWorks(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + cx.evaluate_script(obj, 'var boop = 5', '<string>', 1) + cx.evaluate_script(obj, 'this["blarg\u2026"] = 5', '<string>', 1) + self.assertEqual(cx.get_property(obj, u"beans"), + pydermonkey.undefined) + self.assertEqual(cx.get_property(obj, u"blarg\u2026"), 5) + self.assertEqual(cx.get_property(obj, u"boop"), 5) + + def testContextIsInstance(self): + cx = pydermonkey.Runtime().new_context() + self.assertTrue(isinstance(cx, pydermonkey.Context)) + + def testContextTypeCannotBeInstantiated(self): + self.assertRaises(TypeError, pydermonkey.Context) + + def testObjectIsInstance(self): + obj = pydermonkey.Runtime().new_context().new_object() + self.assertTrue(isinstance(obj, pydermonkey.Object)) + self.assertFalse(isinstance(obj, pydermonkey.Function)) + + def testObjectTypeCannotBeInstantiated(self): + self.assertRaises(TypeError, pydermonkey.Object) + + def testFunctionIsInstance(self): + def boop(): + pass + obj = pydermonkey.Runtime().new_context().new_function(boop, "boop") + self.assertTrue(isinstance(obj, pydermonkey.Object)) + self.assertTrue(isinstance(obj, pydermonkey.Function)) + + def testFunctionTypeCannotBeInstantiated(self): + self.assertRaises(TypeError, pydermonkey.Function) + + def testObjectGetRuntimeWorks(self): + rt = pydermonkey.Runtime() + obj = rt.new_context().new_object() + self.assertEqual(obj.get_runtime(), rt) + + def testContextGetRuntimeWorks(self): + rt = pydermonkey.Runtime() + cx = rt.new_context() + self.assertEqual(cx.get_runtime(), rt) + + def testRuntimesAreWeakReferencable(self): + rt = pydermonkey.Runtime() + wrt = weakref.ref(rt) + self.assertEqual(rt, wrt()) + del rt + self.assertEqual(wrt(), None) + + def testContextsAreWeakReferencable(self): + rt = pydermonkey.Runtime() + cx = rt.new_context() + wcx = weakref.ref(cx) + self.assertEqual(cx, wcx()) + del cx + self.assertEqual(wcx(), None) + + def testUndefinedCannotBeInstantiated(self): + self.assertRaises(TypeError, pydermonkey.undefined) + + def testEvaluateThrowsException(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + self.assertRaises(pydermonkey.error, + cx.evaluate_script, + obj, 'hai2u()', '<string>', 1) + self.assertEqual(self._tostring(cx, + self.last_exception.args[0]), + 'ReferenceError: hai2u is not defined') + + def testThrowingObjWithBadToStringWorks(self): + self.assertRaises( + pydermonkey.error, + self._evaljs, + "throw {toString: function() { throw 'dujg' }}" + ) + self.assertEqual( + self.last_exception.args[1], + "<string conversion failed>" + ) + + def testEvaluateTakesUnicodeCode(self): + self.assertEqual(self._evaljs(u"'foo\u2026'"), + u"foo\u2026") + + def testEvaluateReturnsUndefined(self): + retval = self._evaljs("") + self.assertTrue(retval is pydermonkey.undefined) + + def testEvaludateReturnsUnicodeWithEmbeddedNULs(self): + retval = self._evaljs("'\x00hi'") + self.assertEqual(retval, u'\x00hi') + + def testEvaluateReturnsSMPUnicode(self): + # This is 'LINEAR B SYLLABLE B008 A', in the supplementary + # multilingual plane (SMP). + retval = self._evaljs("'\uD800\uDC00'") + self.assertEqual(retval, u'\U00010000') + self.assertEqual(retval.encode('utf-16'), + '\xff\xfe\x00\xd8\x00\xdc') + + def testEvaluateReturnsBMPUnicode(self): + retval = self._evaljs("'o hai\u2026'") + self.assertTrue(type(retval) == unicode) + self.assertEqual(retval, u'o hai\u2026') + + def testEvaluateReturnsObject(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + obj = cx.evaluate_script(obj, '({boop: 1})', '<string>', 1) + self.assertTrue(isinstance(obj, pydermonkey.Object)) + self.assertEqual(cx.get_property(obj, u"boop"), 1) + + def testScriptedFunctionsHaveFilenameInfo(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + jsfunc = cx.evaluate_script(obj, + '(function boop() { \nreturn 1; })', + 'somefile', 5) + self.assertEqual(jsfunc.filename, 'somefile') + self.assertEqual(jsfunc.base_lineno, 5) + self.assertEqual(jsfunc.line_extent, 2) + + def testEvaluateReturnsFunction(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + cx.init_standard_classes(obj) + obj = cx.evaluate_script(obj, '(function boop() { return 1; })', + '<string>', 1) + self.assertTrue(isinstance(obj, pydermonkey.Function)) + + def testJsExceptionStateIsClearedAfterExceptionIsCaught(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + self.assertRaises(pydermonkey.error, + cx.evaluate_script, + obj, 'blah()', '<string>', 1) + self.assertEqual(cx.evaluate_script(obj, '5+3', '<string>', 1), + 8) + + def testCallFunctionRaisesErrorOnBadFuncArgs(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + obj = cx.evaluate_script( + obj, + '(function boop(a, b) { return a+b+this.c; })', + '<string>', 1 + ) + self.assertRaises( + NotImplementedError, + cx.call_function, + obj, obj, (1, self) + ) + + def _tostring(self, cx, obj): + return cx.call_function(obj, + cx.get_property(obj, u"toString"), + ()) + + def testCallFunctionRaisesErrorFromJS(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + obj = cx.evaluate_script( + obj, + '(function boop(a, b) { blarg(); })', + '<string>', 1 + ) + self.assertRaises(pydermonkey.error, + cx.call_function, + obj, obj, (1,)) + self.assertEqual(self._tostring(cx, + self.last_exception.args[0]), + 'ReferenceError: blarg is not defined') + + def testInitStandardClassesRaisesExcOnRuntimeMismatch(self): + cx2 = pydermonkey.Runtime().new_context() + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + self.assertRaises(ValueError, + cx2.init_standard_classes, + obj) + self.assertEqual(self.last_exception.args[0], + 'JS runtime mismatch') + + def testCallFunctionWorks(self): + cx = pydermonkey.Runtime().new_context() + obj = cx.new_object() + thisArg = cx.new_object() + cx.define_property(thisArg, "c", 3) + cx.init_standard_classes(obj) + obj = cx.evaluate_script( + obj, + '(function boop(a, b) { return a+b+this.c; })', + '<string>', 1 + ) + self.assertEqual(cx.call_function(thisArg, obj, (1,2)), 6) + + def testEvaluateReturnsTrue(self): + self.assertTrue(self._evaljs('true') is True) + + def testEvaluateReturnsFalse(self): + self.assertTrue(self._evaljs('false') is False) + + def testEvaluateReturnsNone(self): + self.assertTrue(self._evaljs('null') is None) + + def testEvaluateReturnsIntegers(self): + self.assertEqual(self._evaljs('1+3'), 4) + + def testEvaluateReturnsNegativeIntegers(self): + self.assertEqual(self._evaljs('-5'), -5) + + def testEvaluateReturnsBigIntegers(self): + self.assertEqual(self._evaljs('2147483647*2'), + 2147483647*2) + + def testEvaluateReturnsFloats(self): + self.assertEqual(self._evaljs('1.1+3'), 4.1) + +if __name__ == '__main__': + unittest.main()