def test_bound_funcs_in_methods(self): class MyClass16: def foo1(self): self.a = 3 f = lambda i: self.a return f() def foo2(self): self.a = 3 def bar(): return self.a return bar() def foo3(self): self.a = 3 def bar(self): return self.a return bar() code = py2js(MyClass16) assert evaljs(code + 'var m = new MyClass16(); m.foo1()') == '3' assert evaljs(code + 'var m = new MyClass16(); m.foo2()') == '3' assert evaljs( code + 'var m = new MyClass16(); try {m.foo3();} catch (err) {"ok"}' ) == 'ok'
def test_overload_truthy(self): def foo(): PSCRIPT_OVERLOAD = False for v in [true, 0, "a", "", [], {}]: if v: print('1') else: print('0') return None or False js = py2js(foo) assert "PSCRIPT_OVERLOAD" not in js assert "pyfunc" not in js ans = '1', '0', '1', '0', '1', '1', 'false' assert evaljs(js + '\nfoo();') == '\n'.join(ans) def bar(): PSCRIPT_OVERLOAD = False for v in [true, 0, "a", "", [], {}]: if v: print('1' + bool(v)) else: print('0' + bool(v)) return None or False js = py2js(bar) assert "PSCRIPT_OVERLOAD" not in js # assert "pyfunc" not in js # bool() does pyfunc_truthy() ans = '1true', '0false', '1true', '0false', '1false', '1false', 'false' assert evaljs(js + '\nbar();') == '\n'.join(ans)
def test_overload_scope(self): # Can turn on and off def foo(): print({} or 'x') PSCRIPT_OVERLOAD = False print({} or 'x') PSCRIPT_OVERLOAD = True print({} or 'x') # js = py2js(foo) assert evaljs(js + '\nfoo();').replace('\n', ' ') == 'x {} x null' # Scoped per function def foo(): def x1(): print({} or 'x') def x2(): PSCRIPT_OVERLOAD = False print({} or 'x') def x3(): print({} or 'x') print({} or 'x') x1() x2() x3() print({} or 'x') # js = py2js(foo) assert evaljs(js + '\nfoo();').replace('\n', ' ') == 'x x {} x x null' # Scope is maintained def foo(): PSCRIPT_OVERLOAD = False def x1(): print({} or 'x') def x2(): PSCRIPT_OVERLOAD = False print({} or 'x') def x3(): print({} or 'x') print({} or 'x') x1() x2() x3() print({} or 'x') # js = py2js(foo) assert evaljs(js + '\nfoo();').replace('\n', ' ') == '{} x {} x {} null'
def test_calling_method_from_init(self): # Note that all class names inside a module need to be unique # for js() to find the correct source. class MyClass11: def __init__(self): self._res = self.m1() + self.m2() + self.m3() def m1(self): return 100 def m2(self): return 10 class MyClass12(MyClass11): def m2(self): return 20 def m3(self): return 2 code = py2js(MyClass11) + py2js(MyClass12) assert evaljs(code + 'var m = new MyClass12(); m._res') == '122' assert evaljs(code + 'var m = new MyClass12(); m.m1()') == '100'
def test_bound_methods(self): class MyClass14: def __init__(self): self.a = 1 def add2(self): self.a += 2 class MyClass15(MyClass14): def add3(self): self.a += 3 code = py2js(MyClass14) + py2js(MyClass15) assert evaljs( code + 'var m = new MyClass14(); m.add2(); m.add2(); m.a') == '5' assert evaljs( code + 'var m = new MyClass14(); var f = m.add2; f(); f(); m.a') == '5' assert evaljs( code + 'var m = new MyClass15(); var f = m.add3; f(); f(); m.a') == '7' assert evaljs( code + 'var m = new MyClass15(); var f2 = m.add2, f3 = m.add3; f2(); f3(); m.a' ) == '6'
def test_py2s_rename_function(): code = py2js(foo1, 'bar') assert 'foo' not in code.lower() assert evaljs(code + 'bar()') == '42' code = py2js(foo1, 'xx.bar') assert 'foo' not in code.lower() assert evaljs('var xx={};\n' + code + 'xx.bar();') == '42'
def test_assert(self): assert 'throw' in py2js('assert True') evalpy('assert true; 7') == '7' evalpy('assert true, "msg"; 7') == '7' catcher = 'try { %s } catch(err) { console.log(err); }' assert evaljs(catcher % py2js('assert false')).count('AssertionError') assert evaljs(catcher % py2js('assert false, "foo"')).count('foo')
def test_py2js_rename_class(): code = py2js(Foo2, 'Bar') assert 'foo' not in code.lower() assert evaljs(code + 'var m=new Bar(); [m.res1(), m.res2()];') == '[ 42, 7 ]' code = py2js(Foo2, 'xx.Bar') assert 'foo' not in code.lower() assert evaljs('var xx={};\n' + code + 'var m=new xx.Bar(); [m.res1(), m.res2()];') == '[ 42, 7 ]'
def test_raw_js(self): def func(a, b): RawJS(""" var c = 3; return a + b + c; """) code = py2js(func) assert evaljs(code + 'func(100, 10)') == '113' assert evaljs(code + 'func("x", 10)') == 'x103'
def test_ensure_use_new(self): class MyClass13: def __init__(self): pass code = py2js(MyClass13) err = 'Class constructor is called as a function.' assert evaljs(code + 'try { var m = new MyClass13(); "ok"} catch (err) { err; }') == 'ok' assert evaljs(code + 'try { var m = MyClass13();} catch (err) { err; }') == err assert evaljs(code + 'try { MyClass13.apply(global);} catch (err) { err; }') == err assert evaljs(code + 'var window = global;try { MyClass13.apply(window);} catch (err) { err; }') == err
def test_isinstance(self): # The resulting code is not particularly pretty, so we just # test outcome assert evalpy('isinstance(3.0, list) == True') == 'false' assert evalpy('isinstance(3.0, float) == True') == 'true' assert evalpy('x={}; isinstance(x.foo, "undefined")') == 'true' assert evalpy('isinstance(None, "null")') == 'true' assert evalpy('isinstance(undefined, "undefined")') == 'true' # assert evalpy('isinstance(None, "undefined")') == 'false' assert evalpy('isinstance(undefined, "null")') == 'false' assert evalpy('isinstance(3, float)') == 'true' assert evalpy('isinstance(3, (int, float))') == 'true' assert evalpy('isinstance(3, "number")') == 'true' # #assert evalpy('isinstance(3, int)') == 'false' # int is not defined assert evalpy('isinstance("", str)') == 'true' assert evalpy('isinstance("", "string")') == 'true' # assert evalpy('isinstance("", list)') == 'false' assert evalpy('isinstance(True, bool)') == 'true' assert evalpy('isinstance(True, "boolean")') == 'true' # assert evalpy('isinstance(True, float)') == 'false' assert evalpy('isinstance([], list)') == 'true' assert evalpy('isinstance([], "array")') == 'true' # assert evalpy('isinstance([], "object")') == 'false' assert evalpy('isinstance([], "Object")') == 'false' assert evalpy('isinstance([], dict)') == 'false' assert evalpy('isinstance({}, dict)') == 'true' assert evalpy('isinstance({}, "object")') == 'true' # assert evalpy('isinstance({}, list)') == 'false' assert evalpy('isinstance({}, "array")') == 'false' assert evalpy('isinstance(eval, types.FunctionType)') == 'true' assert evalpy('isinstance(eval, FunctionType)') == 'true' assert evalpy('isinstance(3, types.FunctionType)') == 'false' # own class code = 'function MyClass () {return this;}\nvar x = new MyClass();\n' assert evaljs(code + py2js('isinstance(x, "object")')) == 'true' assert evaljs(code + py2js('isinstance(x, "Object")')) == 'true' assert evaljs(code + py2js('isinstance(x, "MyClass")')) == 'true' assert evaljs(code + py2js('isinstance(x, MyClass)')) == 'true'
def test_raise(self): assert 'throw' in py2js('raise MyException("foo")') assert 'MyException' in py2js('raise MyException("foo")') assert 'foo' in py2js('raise MyException("foo")') catcher = 'try { %s } catch(err) { console.log(err); }' assert evaljs(catcher % py2js('raise "foo"')) == 'foo' assert evaljs(catcher % py2js('raise 42')) == '42' assert evaljs(catcher % py2js('raise ValueError')).count('ValueError') assert evaljs(catcher % py2js('raise ValueError("foo")')).count('foo') assert evaljs(catcher % py2js('xx = "bar"; raise xx;')).count('bar')
def test_docstring(self): # And that its not interpreted as raw js def func(a, b): """ docstring """ return a + b code = py2js(func) assert evaljs(code + 'func(100, 10)') == '110' assert evaljs(code + 'func("x", 10)') == 'x10' assert code.count('// docstring') == 1
def test_default_args(self): def func(self, foo, bar=2): return foo - bar code = py2js(func) lines = [line for line in code.split('\n') if line] assert lines[1] == 'func = function (foo, bar) {' assert '2' in code assert evaljs(code + 'func(2)') == '0' assert evaljs(code + 'func(4, 3)') == '1' assert evaljs(code + 'func(0, 0)') == '0'
def test_var_args2(self): def func(self, foo, *args): return args code1 = py2js(func) #lines = [line for line in code1.split('\n') if line] code2 = py2js('func(0, 2, 3)') assert evaljs(code1 + code2, False) == '[2,3]' code2 = py2js('func(0)') assert evaljs(code1 + code2, False) == '[]' code2 = py2js('a=[0,2,3]\nfunc(*a)') assert evaljs(code1 + code2, False) == '[2,3]' code2 = py2js('a=[2,3]\nfunc(0,1,2,*a)') assert evaljs(code1 + code2, False) == '[1,2,2,3]'
def test_async_and_await(self): if sys.version_info < (3, 6): return foo = py2js('async def foo(): return 42\n\n') spam = py2js('async def spam(): print(await foo())\n\n') eggs = py2js('async def eggs(): return await foo()\n\n') js = foo + spam + eggs assert 'Promise' in evaljs(js + 'foo()') assert 'Promise' in evaljs(js + 'spam()') assert 'Promise' in evaljs(js + 'eggs()') assert '42' in evaljs(js + 'spam()') assert '42' not in evaljs(js + 'eggs()')
def test_py2s_rename_function_to_method(): code1 = py2js(Foo2, 'Bar') code = code1 + py2js(foo2, 'Bar.prototype.bar') assert 'foo' not in code.lower() assert evaljs(code + 'var m=new Bar(); m.bar();') == '49' code1 = py2js(Foo2, 'Bar') code = code1 + '\nvar $Bar = Bar.prototype;\n' + py2js(foo2, '$Bar.bar') assert 'foo' not in code.lower() assert evaljs(code + 'var m=new Bar(); m.bar();') == '49' code1 = py2js(Foo2, 'xx.Bar') code = code1 + py2js(foo2, 'xx.Bar.prototype.bar') assert 'foo' not in code.lower() assert evaljs('var xx={};\n' + code + 'var m=new xx.Bar(); m.bar();') == '49'
def test_scope(self): def func(self): def foo(z): y = 2 stub = False # noqa only_here = 1 # noqa return x + y + z x = 1 y = 0 y = 1 # noqa z = 1 # noqa res = foo(3) stub = True # noqa return res + y # should return 1+2+3+1 == 7 # Find function start code = py2js(func) i = code.splitlines().index('var func;') assert i >= 0 # Find first lines of functions, where the vars are defined vars1 = code.splitlines()[i+2] vars2 = code.splitlines()[i+4] assert vars1.strip().startswith('var ') assert vars2.strip().startswith('var ') assert 'y' in vars1 and 'y' in vars2 assert 'stub' in vars1 and 'stub' in vars2 assert 'only_here' in vars2 and 'only_here' not in vars1 assert evaljs(code + 'func()') == '7'
def test_assert_catch(self): def catchtest(x): try: assert False except AssertionError: print('assertion-error') return undefined assert evaljs(py2js(catchtest, 'f') + 'f(1)') == 'assertion-error'
def test_catching2(self): def catchtest(x): try: raise ValueError('foo') except Exception as err: print(err.message) return undefined assert evaljs(py2js(catchtest, 'f') + 'f(1)').endswith('foo')
def test_with_simple(self): def contexttest(): c = dict(__enter__=lambda: print('enter'), __exit__=lambda: print('exit')) with c: print(42) print('.') return undefined assert evaljs(py2js(contexttest, 'f') + 'f()') == 'enter\n42\nexit\n.'
def test_inheritance_super_more(self): class MyClass4: def foo(self): return self class MyClass5(MyClass4): def foo(self, test): return super().foo() def foo(): return super().foo() code = py2js(MyClass4) + py2js(MyClass5) code += py2js(foo).replace('super()', 'MyClass4.prototype') code += 'var m4=new MyClass4(), m5=new MyClass5();' assert evaljs(code + 'm4.foo() === m4') == 'true' assert evaljs(code + 'm4.foo() === m4') == 'true' assert evaljs(code + 'foo.call(m4) === m4') == 'true'
def test_with_exception(self): def contexttest(x): c = dict(__enter__=lambda: print('enter'), __exit__=lambda et, ev, tb: print(et)) try: with c: print(42) if x != 1: raise AttributeError('fooerror') print(43) except Exception as e: print(e.message) print('.') return undefined assert evaljs(py2js(contexttest, 'f') + 'f(1)') == 'enter\n42\n43\nnull\n.' s = 'enter\n42\nAttributeError\nAttributeError: fooerror\n.' assert evaljs(py2js(contexttest, 'f') + 'f(0)') == s
def test_catching(self): def catchtest(x): try: if x == 1: raise ValueError('foo') elif x == 2: raise RuntimeError('foo') else: raise "oh crap" except ValueError: print('value-error') except RuntimeError: print('runtime-error') except Exception: print('other-error') return undefined assert evaljs(py2js(catchtest, 'f') + 'f(1)') == 'value-error' assert evaljs(py2js(catchtest, 'f') + 'f(2)') == 'runtime-error' assert evaljs(py2js(catchtest, 'f') + 'f(3)') == 'other-error'
def test_dict_literals(self): # JS has a different way to define dict literals, with limitation # (especially on IE), so we add some magic sause to make it work. def tester1(): a = 'foo' d = {a: 'bar1', 2: 'bar2', 'sp' + 'am': 'bar3'} print(d.foo, d[2], d.spam) js = py2js(tester1) assert evaljs(js + 'tester1()') == 'bar1 bar2 bar3\nnull'
def test_class(self): class MyClass: """ docstring """ foo = 7 foo = foo + 1 def __init__(self): self.bar = 7 def addOne(self): self.bar += 1 code = py2js(MyClass) + 'var m = new MyClass();' assert code.count('// docstring') == 1 assert evaljs(code + 'm.bar;') == '7' assert evaljs(code + 'm.addOne();m.bar;') == '8' # class vars assert evaljs(code + 'm.foo;') == '8'
def test_global(self): assert py2js('global foo;foo = 3').strip() == 'foo = 3;' def func1(): def inner(): x = 3 x = 2 inner() return x def func2(): def inner(): global x x = 3 x = 2 inner() return x assert evaljs(py2js(func1)+'func1()') == '2' assert evaljs(py2js(func2)+'func2()') == '3'
def test_with_as1(self): def contexttest(): c = dict(__enter__=lambda: 7, __exit__=lambda: print('exit')) with c as item: print(42) print(item) print(43) print('.') return undefined assert evaljs(py2js(contexttest, 'f') + 'f()') == '42\n7\n43\nexit\n.'
def test_class_name_mangling1(self): class FooMang1: __y = 12 def __init__(self): self.__x = 30 def __foo(self): return self.__x + self.__y def bar(self): return self.__foo() code = py2js(FooMang1) code += 'var m=new FooMang1();' assert '._FooMang1__foo' in code assert '._FooMang1__x' in code assert '._FooMang1__y' in code assert evaljs(code + 'm.bar();') == '42' assert evaljs(code + 'm.__x;') == '' assert evaljs(code + 'm.__y;') == ''
def test_nonlocal(self): assert py2js('nonlocal foo;foo = 3').strip() == 'foo = 3;' func3_code = """def func3(): def inner(): nonlocal x x = 3 x = 2 inner() return x """ assert evaljs(py2js(func3_code)+'func3()') == '3'