comparison 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
comparison
equal deleted inserted replaced
169:2b98d4643c44 170:dd32a92f6b4f
1 import gc
2 import sys
3 import unittest
4 import weakref
5 import time
6 import threading
7
8 import pydermonkey
9
10 class PydermonkeyTests(unittest.TestCase):
11 def setUp(self):
12 self._teardowns = []
13
14 def tearDown(self):
15 self.last_exception = None
16 while self._teardowns:
17 obj = self._teardowns.pop()
18 runtime = obj.get_runtime()
19 runtime.new_context().clear_object_private(obj)
20 del runtime
21 del obj
22 self.assertEqual(pydermonkey.get_debug_info()['runtime_count'], 0)
23
24 def _clearOnTeardown(self, obj):
25 self._teardowns.append(obj)
26
27 def _evaljs(self, code):
28 rt = pydermonkey.Runtime()
29 cx = rt.new_context()
30 obj = cx.new_object()
31 cx.init_standard_classes(obj)
32 return cx.evaluate_script(obj, code, '<string>', 1)
33
34 def _execjs(self, code):
35 rt = pydermonkey.Runtime()
36 cx = rt.new_context()
37 obj = cx.new_object()
38 cx.init_standard_classes(obj)
39 script = cx.compile_script(code, '<string>', 1)
40 return cx.execute_script(obj, script)
41
42 def _evalJsWrappedPyFunc(self, func, code):
43 cx = pydermonkey.Runtime().new_context()
44 obj = cx.new_object()
45 cx.init_standard_classes(obj)
46 jsfunc = cx.new_function(func, func.__name__)
47 self._clearOnTeardown(jsfunc)
48 cx.define_property(obj, func.__name__, jsfunc)
49 return cx.evaluate_script(obj, code, '<string>', 1)
50
51 def assertRaises(self, exctype, func, *args):
52 was_raised = False
53 try:
54 func(*args)
55 except exctype, e:
56 self.last_exception = e
57 was_raised = True
58 self.assertTrue(was_raised)
59
60 def testSyntaxErrorsAreRaised(self):
61 for run in [self._evaljs, self._execjs]:
62 self.assertRaises(pydermonkey.error, run, '5f')
63 self.assertEqual(
64 self.last_exception.args[1],
65 u'SyntaxError: missing ; before statement'
66 )
67
68 def testGetStackOnEmptyStackReturnsNone(self):
69 cx = pydermonkey.Runtime().new_context()
70 self.assertEqual(cx.get_stack(), None)
71
72 def testGetStackWorks(self):
73 stack_holder = []
74
75 def func(cx, this, args):
76 stack_holder.append(cx.get_stack())
77
78 cx = pydermonkey.Runtime().new_context()
79 obj = cx.new_object()
80 cx.init_standard_classes(obj)
81 jsfunc = cx.new_function(func, func.__name__)
82 self._clearOnTeardown(jsfunc)
83 cx.define_property(obj, func.__name__, jsfunc)
84 cx.evaluate_script(obj, '(function closure() { \nfunc() })()',
85 '<string>', 1)
86 stack = stack_holder[0]
87 script = stack['caller']['caller']['script']
88 pc = stack['caller']['caller']['pc']
89 closure = stack['caller']['function']
90 self.assertEqual(closure.name, 'closure')
91 self.assertEqual(closure.filename, '<string>')
92 self.assertEqual(stack['caller']['script'], None)
93 self.assertEqual(stack['caller']['lineno'], 2)
94 self.assertEqual(script.filename, '<string>')
95 self.assertEqual(stack['caller']['caller']['lineno'], 1)
96 self.assertTrue(pc >= 0 and pc < len(buffer(script)))
97 self.assertEqual(stack['caller']['caller']['caller'], None)
98
99 def testScriptHasFilenameMember(self):
100 cx = pydermonkey.Runtime().new_context()
101 script = cx.compile_script('foo', '<string>', 1)
102 self.assertEqual(script.filename, '<string>')
103
104 def testScriptHasLineInfo(self):
105 cx = pydermonkey.Runtime().new_context()
106 script = cx.compile_script('foo\nbar', '<string>', 1)
107 self.assertEqual(script.base_lineno, 1)
108 self.assertEqual(script.line_extent, 2)
109
110 def testScriptIsExposedAsBuffer(self):
111 rt = pydermonkey.Runtime()
112 cx = rt.new_context()
113 script = cx.compile_script('foo', '<string>', 1)
114 self.assertTrue(len(buffer(script)) > 0)
115
116 def testCompileScriptWorks(self):
117 self.assertEqual(self._execjs('5 + 1'), 6)
118
119 def testErrorsRaisedIncludeStrings(self):
120 self.assertRaises(pydermonkey.error, self._evaljs, 'boop()')
121 self.assertEqual(self.last_exception.args[1],
122 u'ReferenceError: boop is not defined')
123
124 def testThreadSafetyExceptionIsRaised(self):
125 stuff = {}
126 def make_runtime():
127 stuff['rt'] = pydermonkey.Runtime()
128 thread = threading.Thread(target = make_runtime)
129 thread.start()
130 thread.join()
131 self.assertRaises(pydermonkey.error,
132 stuff['rt'].new_context)
133 self.assertEqual(self.last_exception.args[0],
134 'Function called from wrong thread')
135 del stuff['rt']
136
137 def testClearObjectPrivateWorks(self):
138 class Foo(object):
139 pass
140 pyobj = Foo()
141 cx = pydermonkey.Runtime().new_context()
142 obj = cx.new_object(pyobj)
143 pyobj = weakref.ref(pyobj)
144 self.assertEqual(pyobj(), cx.get_object_private(obj))
145 cx.clear_object_private(obj)
146 self.assertEqual(cx.get_object_private(obj), None)
147 self.assertEqual(pyobj(), None)
148
149 def testGetObjectPrivateWorks(self):
150 class Foo(object):
151 pass
152 pyobj = Foo()
153 cx = pydermonkey.Runtime().new_context()
154 obj = cx.new_object(pyobj)
155 pyobj = weakref.ref(pyobj)
156 self.assertEqual(pyobj(), cx.get_object_private(obj))
157 del obj
158 del cx
159 self.assertEqual(pyobj(), None)
160
161 def testContextSupportsCyclicGc(self):
162 def makecx():
163 cx = pydermonkey.Runtime().new_context()
164
165 def opcb(othercx):
166 return cx
167
168 cx.set_operation_callback(opcb)
169 return cx
170
171 gc.disable()
172 cx = makecx()
173 wcx = weakref.ref(cx)
174 self.assertEqual(wcx(), cx)
175 del cx
176 self.assertTrue(wcx())
177 gc.enable()
178 gc.collect()
179 self.assertEqual(wcx(), None)
180
181 def testOperationCallbackIsCalled(self):
182 def opcb(cx):
183 raise Exception("stop eet!")
184
185 cx = pydermonkey.Runtime().new_context()
186 cx.set_operation_callback(opcb)
187 obj = cx.new_object()
188 cx.init_standard_classes(obj)
189
190 def watchdog():
191 time.sleep(0.1)
192 cx.trigger_operation_callback()
193
194 thread = threading.Thread(target = watchdog)
195 thread.start()
196
197 self.assertRaises(
198 pydermonkey.error,
199 cx.evaluate_script,
200 obj, 'while (1) {}', '<string>', 1
201 )
202
203 def testUndefinedStrIsUndefined(self):
204 self.assertEqual(str(pydermonkey.undefined),
205 "pydermonkey.undefined")
206
207 def testScriptedJsFuncHasIsPythonFalse(self):
208 cx = pydermonkey.Runtime().new_context()
209 jsfunc = cx.evaluate_script(cx.new_object(),
210 '(function(){})', '<string>', 1)
211 self.assertFalse(jsfunc.is_python)
212
213 def testJsWrappedPythonFuncHasIsPythonTrue(self):
214 def foo(cx, this, args):
215 pass
216
217 cx = pydermonkey.Runtime().new_context()
218 jsfunc = cx.new_function(foo, foo.__name__)
219 self.assertTrue(jsfunc.is_python)
220
221 def testJsWrappedPythonFuncHasNoFilename(self):
222 def foo(cx, this, args):
223 pass
224
225 cx = pydermonkey.Runtime().new_context()
226 jsfunc = cx.new_function(foo, foo.__name__)
227 self.assertEqual(jsfunc.filename, None)
228
229 def testJsScriptedFuncHasNoPrivate(self):
230 cx = pydermonkey.Runtime().new_context()
231 jsfunc = cx.evaluate_script(cx.new_object(),
232 '(function(){})', '<string>', 1)
233 self.assertEqual(cx.get_object_private(jsfunc), None)
234
235 def testGetPendingExceptionReturnsNone(self):
236 cx = pydermonkey.Runtime().new_context()
237 self.assertFalse(cx.is_exception_pending())
238 self.assertEqual(cx.get_pending_exception(), None)
239
240 def testThrowHookWorks(self):
241 exceptions = []
242 def throwhook(cx):
243 self.assertTrue(cx.is_exception_pending())
244 exceptions.append(cx.get_pending_exception())
245
246 cx = pydermonkey.Runtime().new_context()
247 cx.set_throw_hook(throwhook)
248 self.assertRaises(
249 pydermonkey.error,
250 cx.evaluate_script,
251 cx.new_object(),
252 '(function() { throw "hi"; })()',
253 '<string>', 1
254 )
255 self.assertEqual(exceptions, ['hi', 'hi'])
256 self.assertFalse(cx.is_exception_pending())
257 self.assertEqual(cx.get_pending_exception(), None)
258
259 def testJsWrappedPythonFuncHasPrivate(self):
260 def foo(cx, this, args):
261 pass
262
263 cx = pydermonkey.Runtime().new_context()
264 jsfunc = cx.new_function(foo, foo.__name__)
265 self.assertEqual(cx.get_object_private(jsfunc), foo)
266
267 def testJsWrappedPythonFuncIsNotGCd(self):
268 def define(cx, obj):
269 def func(cx, this, args):
270 return u'func was called'
271 jsfunc = cx.new_function(func, func.__name__)
272 cx.define_property(obj, func.__name__, jsfunc)
273 return weakref.ref(func)
274 rt = pydermonkey.Runtime()
275 cx = rt.new_context()
276 obj = cx.new_object()
277 cx.init_standard_classes(obj)
278 ref = define(cx, obj)
279 cx.gc()
280 self.assertNotEqual(ref(), None)
281 result = cx.evaluate_script(obj, 'func()', '<string>', 1)
282 self.assertEqual(result, u'func was called')
283
284 # Now ensure that the wrapped function is GC'd when it's
285 # no longer reachable from JS space.
286 cx.define_property(obj, 'func', 0)
287 cx.gc()
288 self.assertEqual(ref(), None)
289
290 def testCircularJsWrappedPythonFuncIsGCdIfPrivateCleared(self):
291 def define(cx, obj):
292 rt = cx.get_runtime()
293 def func(cx, this, args):
294 # Oh noes, a circular reference is born!
295 rt
296 jsfunc = cx.new_function(func, func.__name__)
297 cx.define_property(obj, func.__name__, jsfunc)
298 return (jsfunc, weakref.ref(func))
299 rt = pydermonkey.Runtime()
300 cx = rt.new_context()
301 obj = cx.new_object()
302 cx.init_standard_classes(obj)
303 jsfunc, ref = define(cx, obj)
304
305 # This will break the circular reference.
306 cx.clear_object_private(jsfunc)
307
308 del jsfunc
309 del rt
310 del cx
311 del obj
312 self.assertEqual(ref(), None)
313
314 def testFunctionsWithClosuresAreNotIdentical(self):
315 cx = pydermonkey.Runtime().new_context()
316 obj = cx.new_object()
317 cx.init_standard_classes(obj)
318 cx.evaluate_script(
319 obj, "function build(x) { return function foo() { return x; } }",
320 "<string>", 1
321 )
322 func1 = cx.evaluate_script(obj, "build(1)", "<string>", 1)
323 func2 = cx.evaluate_script(obj, "build(2)", "<string>", 1)
324 self.assertNotEqual(func1, func2)
325 self.assertEqual(func1.name, 'foo')
326 self.assertEqual(func1.name, func2.name)
327
328 def testAnonymousJsFunctionHasNullNameAttribute(self):
329 cx = pydermonkey.Runtime().new_context()
330 obj = cx.new_object()
331 cx.init_standard_classes(obj)
332 jsfunc = cx.evaluate_script(obj, "(function() {})",
333 "<string>", 1)
334 self.assertEqual(jsfunc.name, None)
335
336 def testJsFunctionHasNameAttribute(self):
337 cx = pydermonkey.Runtime().new_context()
338 obj = cx.new_object()
339 cx.init_standard_classes(obj)
340 jsfunc = cx.evaluate_script(obj, "(function blarg() {})",
341 "<string>", 1)
342 self.assertEqual(jsfunc.name, "blarg")
343
344 def testJsWrappedPythonFuncHasNameAttribute(self):
345 def func(cx, this, args):
346 return True
347
348 cx = pydermonkey.Runtime().new_context()
349 jsfunc = cx.new_function(func, "foo")
350 self.assertEqual(jsfunc.name, "foo")
351
352 def testJsWrappedPythonFuncIsGCdAtRuntimeDestruction(self):
353 def define(cx, obj):
354 def func(cx, this, args):
355 return u'func was called'
356 jsfunc = cx.new_function(func, func.__name__)
357 cx.define_property(obj, func.__name__, jsfunc)
358 return weakref.ref(func)
359 rt = pydermonkey.Runtime()
360 cx = rt.new_context()
361 obj = cx.new_object()
362 cx.init_standard_classes(obj)
363 ref = define(cx, obj)
364 del rt
365 del cx
366 del obj
367 self.assertEqual(ref(), None)
368
369 def testJsWrappedPythonFuncThrowsExcIfPrivateCleared(self):
370 def func(cx, this, args):
371 return True
372
373 code = "func()"
374 cx = pydermonkey.Runtime().new_context()
375 obj = cx.new_object()
376 cx.init_standard_classes(obj)
377 jsfunc = cx.new_function(func, func.__name__)
378 cx.define_property(obj, func.__name__, jsfunc)
379 cx.clear_object_private(jsfunc)
380 self.assertRaises(pydermonkey.error,
381 cx.evaluate_script,
382 obj, code, '<string>', 1)
383 self.assertEqual(
384 self._tostring(cx, self.last_exception.args[0]),
385 "Error: Wrapped Python function no longer exists"
386 )
387
388 def testJsWrappedPythonFuncPassesContext(self):
389 contexts = []
390
391 def func(cx, this, args):
392 contexts.append(cx)
393 return True
394
395 code = "func()"
396 cx = pydermonkey.Runtime().new_context()
397 obj = cx.new_object()
398 cx.init_standard_classes(obj)
399 jsfunc = cx.new_function(func, func.__name__)
400 self._clearOnTeardown(jsfunc)
401 cx.define_property(obj, func.__name__, jsfunc)
402 cx.evaluate_script(obj, code, '<string>', 1)
403 self.assertEqual(contexts[0], cx)
404
405 def testJsWrappedPythonFuncPassesThisArg(self):
406 thisObjs = []
407
408 def func(cx, this, args):
409 thisObjs.append(this)
410 return True
411
412 code = "func()"
413 cx = pydermonkey.Runtime().new_context()
414 obj = cx.new_object()
415 cx.init_standard_classes(obj)
416 jsfunc = cx.new_function(func, func.__name__)
417 self._clearOnTeardown(jsfunc)
418 cx.define_property(obj, func.__name__, jsfunc)
419 cx.evaluate_script(obj, code, '<string>', 1)
420 self.assertEqual(thisObjs[0], obj)
421
422 def testJsWrappedPythonFuncPassesFuncArgs(self):
423 funcArgs = []
424
425 def func(cx, this, args):
426 funcArgs.append(args)
427 return True
428
429 cx = pydermonkey.Runtime().new_context()
430 obj = cx.new_object()
431 cx.init_standard_classes(obj)
432 jsfunc = cx.new_function(func, func.__name__)
433 self._clearOnTeardown(jsfunc)
434
435 cx.define_property(obj, func.__name__, jsfunc)
436
437 cx.evaluate_script(obj, "func()", '<string>', 1)
438 self.assertEqual(len(funcArgs[0]), 0)
439 self.assertTrue(isinstance(funcArgs[0], tuple))
440
441 cx.evaluate_script(obj, "func(1, 'foo')", '<string>', 1)
442 self.assertEqual(len(funcArgs[1]), 2)
443 self.assertEqual(funcArgs[1][0], 1)
444 self.assertEqual(funcArgs[1][1], u'foo')
445
446 def testJsWrappedPythonFunctionReturnsUnicodeWithEmbeddedNULs(self):
447 def hai2u(cx, this, args):
448 return args[0] + u"o hai"
449 self.assertEqual(self._evalJsWrappedPyFunc(hai2u,
450 'hai2u("blah\x00 ")'),
451 u"blah\x00 o hai")
452
453 def testJsWrappedPythonFunctionReturnsString(self):
454 def hai2u(cx, this, args):
455 return "o hai"
456 self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
457 "o hai")
458
459 def testJsWrappedPythonFunctionReturnsUnicode(self):
460 def hai2u(cx, this, args):
461 return u"o hai\u2026"
462 self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
463 u"o hai\u2026")
464
465 def testJsWrappedPythonFunctionThrowsJsException(self):
466 def hai2u(cx, this, args):
467 raise pydermonkey.error(u"blarg")
468 self.assertRaises(pydermonkey.error,
469 self._evalJsWrappedPyFunc,
470 hai2u, 'hai2u()')
471 self.assertEqual(self.last_exception.args[0], u"blarg")
472
473 def testJsWrappedPythonFunctionThrowsPyException(self):
474 thecx = []
475 def hai2u(cx, this, args):
476 thecx.append(cx)
477 raise Exception("hello")
478 self.assertRaises(pydermonkey.error,
479 self._evalJsWrappedPyFunc,
480 hai2u, 'hai2u()')
481 exc = thecx[0].get_object_private(self.last_exception.args[0])
482 self.assertEqual(exc.args[0], "hello")
483
484 def testJsWrappedPythonFunctionReturnsNone(self):
485 def hai2u(cx, this, args):
486 pass
487 self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
488 None)
489
490 def testJsWrappedPythonFunctionReturnsTrue(self):
491 def hai2u(cx, this, args):
492 return True
493 self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
494 True)
495
496 def testJsWrappedPythonFunctionReturnsFalse(self):
497 def hai2u(cx, this, args):
498 return False
499 self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
500 False)
501
502 def testJsWrappedPythonFunctionReturnsSmallInt(self):
503 def hai2u(cx, this, args):
504 return 5
505 self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
506 5)
507
508 def testJsWrappedPythonFunctionReturnsFloat(self):
509 def hai2u(cx, this, args):
510 return 5.1
511 self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
512 5.1)
513
514 def testJsWrappedPythonFunctionReturnsNegativeInt(self):
515 def hai2u(cx, this, args):
516 return -5
517 self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
518 -5)
519
520 def testJsWrappedPythonFunctionReturnsBigInt(self):
521 def hai2u(cx, this, args):
522 return 2147483647
523 self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
524 2147483647)
525
526 def testHasPropertyWorks(self):
527 cx = pydermonkey.Runtime().new_context()
528 obj = cx.new_object()
529 cx.init_standard_classes(obj)
530 foo = cx.new_object()
531 cx.define_property(obj, u"foo\u2026", foo)
532 self.assertTrue(cx.has_property(obj, u"foo\u2026"))
533 self.assertFalse(cx.has_property(obj, "bar"))
534
535 def testDefinePropertyWorksWithUnicodePropertyNames(self):
536 cx = pydermonkey.Runtime().new_context()
537 obj = cx.new_object()
538 cx.init_standard_classes(obj)
539 foo = cx.new_object()
540 cx.define_property(obj, u"foo\u2026", foo)
541 self.assertEqual(
542 cx.get_property(obj, u"foo\u2026"),
543 foo
544 )
545
546 def testDefinePropertyWorksWithObject(self):
547 cx = pydermonkey.Runtime().new_context()
548 obj = cx.new_object()
549 cx.init_standard_classes(obj)
550 foo = cx.new_object()
551 cx.define_property(obj, "foo", foo)
552 self.assertEqual(
553 cx.evaluate_script(obj, 'foo', '<string>', 1),
554 foo
555 )
556
557 def testDefinePropertyWorksWithString(self):
558 cx = pydermonkey.Runtime().new_context()
559 obj = cx.new_object()
560 cx.init_standard_classes(obj)
561 foo = cx.new_object()
562 cx.define_property(obj, "foo", u"hello")
563 self.assertEqual(
564 cx.evaluate_script(obj, 'foo', '<string>', 1),
565 u"hello"
566 )
567
568 def testObjectIsIdentityPreserving(self):
569 cx = pydermonkey.Runtime().new_context()
570 obj = cx.new_object()
571 cx.init_standard_classes(obj)
572 cx.evaluate_script(obj, 'var foo = {bar: 1}', '<string>', 1)
573 self.assertTrue(isinstance(cx.get_property(obj, u"foo"),
574 pydermonkey.Object))
575 self.assertTrue(cx.get_property(obj, u"foo") is
576 cx.get_property(obj, "foo"))
577
578 def testObjectGetattrThrowsException(self):
579 cx = pydermonkey.Runtime().new_context()
580 obj = cx.new_object()
581 cx.init_standard_classes(obj)
582 result = cx.evaluate_script(obj, '({get foo() { throw "blah"; }})',
583 '<string>', 1)
584 self.assertRaises(pydermonkey.error,
585 cx.get_property,
586 result,
587 u"foo")
588 self.assertEqual(self.last_exception.args[0], u"blah")
589
590 def testInfiniteRecursionRaisesError(self):
591 cx = pydermonkey.Runtime().new_context()
592 obj = cx.new_object()
593 cx.init_standard_classes(obj)
594 self.assertRaises(
595 pydermonkey.error,
596 cx.evaluate_script,
597 obj, '(function foo() { foo(); })();', '<string>', 1
598 )
599 self.assertEqual(
600 self._tostring(cx, self.last_exception.args[0]),
601 "InternalError: too much recursion"
602 )
603
604 def testObjectGetattrWorks(self):
605 cx = pydermonkey.Runtime().new_context()
606 obj = cx.new_object()
607 cx.init_standard_classes(obj)
608 cx.evaluate_script(obj, 'var boop = 5', '<string>', 1)
609 cx.evaluate_script(obj, 'this["blarg\u2026"] = 5', '<string>', 1)
610 self.assertEqual(cx.get_property(obj, u"beans"),
611 pydermonkey.undefined)
612 self.assertEqual(cx.get_property(obj, u"blarg\u2026"), 5)
613 self.assertEqual(cx.get_property(obj, u"boop"), 5)
614
615 def testContextIsInstance(self):
616 cx = pydermonkey.Runtime().new_context()
617 self.assertTrue(isinstance(cx, pydermonkey.Context))
618
619 def testContextTypeCannotBeInstantiated(self):
620 self.assertRaises(TypeError, pydermonkey.Context)
621
622 def testObjectIsInstance(self):
623 obj = pydermonkey.Runtime().new_context().new_object()
624 self.assertTrue(isinstance(obj, pydermonkey.Object))
625 self.assertFalse(isinstance(obj, pydermonkey.Function))
626
627 def testObjectTypeCannotBeInstantiated(self):
628 self.assertRaises(TypeError, pydermonkey.Object)
629
630 def testFunctionIsInstance(self):
631 def boop():
632 pass
633 obj = pydermonkey.Runtime().new_context().new_function(boop, "boop")
634 self.assertTrue(isinstance(obj, pydermonkey.Object))
635 self.assertTrue(isinstance(obj, pydermonkey.Function))
636
637 def testFunctionTypeCannotBeInstantiated(self):
638 self.assertRaises(TypeError, pydermonkey.Function)
639
640 def testObjectGetRuntimeWorks(self):
641 rt = pydermonkey.Runtime()
642 obj = rt.new_context().new_object()
643 self.assertEqual(obj.get_runtime(), rt)
644
645 def testContextGetRuntimeWorks(self):
646 rt = pydermonkey.Runtime()
647 cx = rt.new_context()
648 self.assertEqual(cx.get_runtime(), rt)
649
650 def testRuntimesAreWeakReferencable(self):
651 rt = pydermonkey.Runtime()
652 wrt = weakref.ref(rt)
653 self.assertEqual(rt, wrt())
654 del rt
655 self.assertEqual(wrt(), None)
656
657 def testContextsAreWeakReferencable(self):
658 rt = pydermonkey.Runtime()
659 cx = rt.new_context()
660 wcx = weakref.ref(cx)
661 self.assertEqual(cx, wcx())
662 del cx
663 self.assertEqual(wcx(), None)
664
665 def testUndefinedCannotBeInstantiated(self):
666 self.assertRaises(TypeError, pydermonkey.undefined)
667
668 def testEvaluateThrowsException(self):
669 cx = pydermonkey.Runtime().new_context()
670 obj = cx.new_object()
671 self.assertRaises(pydermonkey.error,
672 cx.evaluate_script,
673 obj, 'hai2u()', '<string>', 1)
674 self.assertEqual(self._tostring(cx,
675 self.last_exception.args[0]),
676 'ReferenceError: hai2u is not defined')
677
678 def testThrowingObjWithBadToStringWorks(self):
679 self.assertRaises(
680 pydermonkey.error,
681 self._evaljs,
682 "throw {toString: function() { throw 'dujg' }}"
683 )
684 self.assertEqual(
685 self.last_exception.args[1],
686 "<string conversion failed>"
687 )
688
689 def testEvaluateTakesUnicodeCode(self):
690 self.assertEqual(self._evaljs(u"'foo\u2026'"),
691 u"foo\u2026")
692
693 def testEvaluateReturnsUndefined(self):
694 retval = self._evaljs("")
695 self.assertTrue(retval is pydermonkey.undefined)
696
697 def testEvaludateReturnsUnicodeWithEmbeddedNULs(self):
698 retval = self._evaljs("'\x00hi'")
699 self.assertEqual(retval, u'\x00hi')
700
701 def testEvaluateReturnsSMPUnicode(self):
702 # This is 'LINEAR B SYLLABLE B008 A', in the supplementary
703 # multilingual plane (SMP).
704 retval = self._evaljs("'\uD800\uDC00'")
705 self.assertEqual(retval, u'\U00010000')
706 self.assertEqual(retval.encode('utf-16'),
707 '\xff\xfe\x00\xd8\x00\xdc')
708
709 def testEvaluateReturnsBMPUnicode(self):
710 retval = self._evaljs("'o hai\u2026'")
711 self.assertTrue(type(retval) == unicode)
712 self.assertEqual(retval, u'o hai\u2026')
713
714 def testEvaluateReturnsObject(self):
715 cx = pydermonkey.Runtime().new_context()
716 obj = cx.new_object()
717 cx.init_standard_classes(obj)
718 obj = cx.evaluate_script(obj, '({boop: 1})', '<string>', 1)
719 self.assertTrue(isinstance(obj, pydermonkey.Object))
720 self.assertEqual(cx.get_property(obj, u"boop"), 1)
721
722 def testScriptedFunctionsHaveFilenameInfo(self):
723 cx = pydermonkey.Runtime().new_context()
724 obj = cx.new_object()
725 cx.init_standard_classes(obj)
726 jsfunc = cx.evaluate_script(obj,
727 '(function boop() { \nreturn 1; })',
728 'somefile', 5)
729 self.assertEqual(jsfunc.filename, 'somefile')
730 self.assertEqual(jsfunc.base_lineno, 5)
731 self.assertEqual(jsfunc.line_extent, 2)
732
733 def testEvaluateReturnsFunction(self):
734 cx = pydermonkey.Runtime().new_context()
735 obj = cx.new_object()
736 cx.init_standard_classes(obj)
737 obj = cx.evaluate_script(obj, '(function boop() { return 1; })',
738 '<string>', 1)
739 self.assertTrue(isinstance(obj, pydermonkey.Function))
740
741 def testJsExceptionStateIsClearedAfterExceptionIsCaught(self):
742 cx = pydermonkey.Runtime().new_context()
743 obj = cx.new_object()
744 self.assertRaises(pydermonkey.error,
745 cx.evaluate_script,
746 obj, 'blah()', '<string>', 1)
747 self.assertEqual(cx.evaluate_script(obj, '5+3', '<string>', 1),
748 8)
749
750 def testCallFunctionRaisesErrorOnBadFuncArgs(self):
751 cx = pydermonkey.Runtime().new_context()
752 obj = cx.new_object()
753 obj = cx.evaluate_script(
754 obj,
755 '(function boop(a, b) { return a+b+this.c; })',
756 '<string>', 1
757 )
758 self.assertRaises(
759 NotImplementedError,
760 cx.call_function,
761 obj, obj, (1, self)
762 )
763
764 def _tostring(self, cx, obj):
765 return cx.call_function(obj,
766 cx.get_property(obj, u"toString"),
767 ())
768
769 def testCallFunctionRaisesErrorFromJS(self):
770 cx = pydermonkey.Runtime().new_context()
771 obj = cx.new_object()
772 obj = cx.evaluate_script(
773 obj,
774 '(function boop(a, b) { blarg(); })',
775 '<string>', 1
776 )
777 self.assertRaises(pydermonkey.error,
778 cx.call_function,
779 obj, obj, (1,))
780 self.assertEqual(self._tostring(cx,
781 self.last_exception.args[0]),
782 'ReferenceError: blarg is not defined')
783
784 def testInitStandardClassesRaisesExcOnRuntimeMismatch(self):
785 cx2 = pydermonkey.Runtime().new_context()
786 cx = pydermonkey.Runtime().new_context()
787 obj = cx.new_object()
788 self.assertRaises(ValueError,
789 cx2.init_standard_classes,
790 obj)
791 self.assertEqual(self.last_exception.args[0],
792 'JS runtime mismatch')
793
794 def testCallFunctionWorks(self):
795 cx = pydermonkey.Runtime().new_context()
796 obj = cx.new_object()
797 thisArg = cx.new_object()
798 cx.define_property(thisArg, "c", 3)
799 cx.init_standard_classes(obj)
800 obj = cx.evaluate_script(
801 obj,
802 '(function boop(a, b) { return a+b+this.c; })',
803 '<string>', 1
804 )
805 self.assertEqual(cx.call_function(thisArg, obj, (1,2)), 6)
806
807 def testEvaluateReturnsTrue(self):
808 self.assertTrue(self._evaljs('true') is True)
809
810 def testEvaluateReturnsFalse(self):
811 self.assertTrue(self._evaljs('false') is False)
812
813 def testEvaluateReturnsNone(self):
814 self.assertTrue(self._evaljs('null') is None)
815
816 def testEvaluateReturnsIntegers(self):
817 self.assertEqual(self._evaljs('1+3'), 4)
818
819 def testEvaluateReturnsNegativeIntegers(self):
820 self.assertEqual(self._evaljs('-5'), -5)
821
822 def testEvaluateReturnsBigIntegers(self):
823 self.assertEqual(self._evaljs('2147483647*2'),
824 2147483647*2)
825
826 def testEvaluateReturnsFloats(self):
827 self.assertEqual(self._evaljs('1.1+3'), 4.1)
828
829 if __name__ == '__main__':
830 unittest.main()