Mercurial > pymonkey
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() |