mirror of https://github.com/pyodide/pyodide.git
Use multi-line code snippets in tests
This commit is contained in:
parent
8c27b0b44b
commit
d869ac5bfc
|
@ -4,6 +4,7 @@ Various common utilities for testing.
|
||||||
|
|
||||||
import atexit
|
import atexit
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
|
import textwrap
|
||||||
import os
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
import queue
|
import queue
|
||||||
|
@ -73,10 +74,16 @@ class SeleniumWrapper:
|
||||||
self.driver.execute_script("window.logs = []")
|
self.driver.execute_script("window.logs = []")
|
||||||
|
|
||||||
def run(self, code):
|
def run(self, code):
|
||||||
|
if isinstance(code, str) and code.startswith('\n'):
|
||||||
|
# we have a multiline string, fix indentation
|
||||||
|
code = textwrap.dedent(code)
|
||||||
return self.run_js(
|
return self.run_js(
|
||||||
'return pyodide.runPython({!r})'.format(code))
|
'return pyodide.runPython({!r})'.format(code))
|
||||||
|
|
||||||
def run_js(self, code):
|
def run_js(self, code):
|
||||||
|
if isinstance(code, str) and code.startswith('\n'):
|
||||||
|
# we have a multiline string, fix indentation
|
||||||
|
code = textwrap.dedent(code)
|
||||||
catch = f"""
|
catch = f"""
|
||||||
Error.stackTraceLimit = Infinity;
|
Error.stackTraceLimit = Infinity;
|
||||||
try {{ {code} }}
|
try {{ {code} }}
|
||||||
|
|
|
@ -43,16 +43,21 @@ def test_python2js(selenium):
|
||||||
'(x.length === 5) && '
|
'(x.length === 5) && '
|
||||||
'(x[0] === 98)')
|
'(x[0] === 98)')
|
||||||
assert selenium.run_js(
|
assert selenium.run_js(
|
||||||
'let x = pyodide.runPython("[1, 2, 3]");\n'
|
"""
|
||||||
'return (x instanceof window.Array) && (x.length === 3) && '
|
let x = pyodide.runPython("[1, 2, 3]");
|
||||||
'(x[0] == 1) && (x[1] == 2) && (x[2] == 3)')
|
return ((x instanceof window.Array) && (x.length === 3) &&
|
||||||
|
(x[0] == 1) && (x[1] == 2) && (x[2] == 3))
|
||||||
|
""")
|
||||||
assert selenium.run_js(
|
assert selenium.run_js(
|
||||||
'let x = pyodide.runPython("{42: 64}");\n'
|
"""
|
||||||
'return (typeof x === "object") && '
|
let x = pyodide.runPython("{42: 64}");
|
||||||
'(x[42] === 64)')
|
return (typeof x === "object") && (x[42] === 64)
|
||||||
|
""")
|
||||||
assert selenium.run_js(
|
assert selenium.run_js(
|
||||||
'let x = pyodide.runPython("open(\'/foo.txt\', \'wb\')")\n'
|
"""
|
||||||
'return (x.tell() === 0)\n')
|
let x = pyodide.runPython("open('/foo.txt', 'wb')")
|
||||||
|
return (x.tell() === 0)
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
def test_pythonexc2js(selenium):
|
def test_pythonexc2js(selenium):
|
||||||
|
@ -66,17 +71,19 @@ def test_pythonexc2js(selenium):
|
||||||
|
|
||||||
def test_js2python(selenium):
|
def test_js2python(selenium):
|
||||||
selenium.run_js(
|
selenium.run_js(
|
||||||
'window.jsstring = "碘化物";\n'
|
"""
|
||||||
'window.jsnumber0 = 42;\n'
|
window.jsstring = "碘化物";
|
||||||
'window.jsnumber1 = 42.5;\n'
|
window.jsnumber0 = 42;
|
||||||
'window.jsundefined = undefined;\n'
|
window.jsnumber1 = 42.5;
|
||||||
'window.jsnull = null;\n'
|
window.jsundefined = undefined;
|
||||||
'window.jstrue = true;\n'
|
window.jsnull = null;
|
||||||
'window.jsfalse = false;\n'
|
window.jstrue = true;
|
||||||
'window.jspython = pyodide.pyimport("open");\n'
|
window.jsfalse = false;
|
||||||
'window.jsbytes = new Uint8Array([1, 2, 3]);\n'
|
window.jspython = pyodide.pyimport("open");
|
||||||
'window.jsfloats = new Float32Array([1, 2, 3]);\n'
|
window.jsbytes = new Uint8Array([1, 2, 3]);
|
||||||
'window.jsobject = new XMLHttpRequest();\n'
|
window.jsfloats = new Float32Array([1, 2, 3]);
|
||||||
|
window.jsobject = new XMLHttpRequest();
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
'from js import jsstring\n'
|
'from js import jsstring\n'
|
||||||
|
@ -100,23 +107,27 @@ def test_js2python(selenium):
|
||||||
'from js import jspython\n'
|
'from js import jspython\n'
|
||||||
'jspython is open')
|
'jspython is open')
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
'from js import jsbytes\n'
|
"""
|
||||||
'(jsbytes.tolist() == [1, 2, 3]) '
|
from js import jsbytes
|
||||||
'and (jsbytes.tobytes() == b"\x01\x02\x03")')
|
((jsbytes.tolist() == [1, 2, 3])
|
||||||
|
and (jsbytes.tobytes() == b"\x01\x02\x03"))
|
||||||
|
""")
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
'from js import jsfloats\n'
|
"""
|
||||||
'import struct\n'
|
from js import jsfloats
|
||||||
'expected = struct.pack("fff", 1, 2, 3)\n'
|
import struct
|
||||||
'(jsfloats.tolist() == [1, 2, 3]) '
|
expected = struct.pack("fff", 1, 2, 3)
|
||||||
'and (jsfloats.tobytes() == expected)')
|
(jsfloats.tolist() == [1, 2, 3]) and (jsfloats.tobytes() == expected)
|
||||||
|
""")
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
'from js import jsobject\n'
|
'from js import jsobject\n'
|
||||||
'str(jsobject) == "[object XMLHttpRequest]"')
|
'str(jsobject) == "[object XMLHttpRequest]"')
|
||||||
|
|
||||||
|
|
||||||
def test_typed_arrays(selenium):
|
@pytest.mark.parametrize('wasm_heap', (False, True))
|
||||||
for wasm_heap in (False, True):
|
@pytest.mark.parametrize(
|
||||||
for (jstype, pytype) in (
|
'jstype, pytype',
|
||||||
|
(
|
||||||
('Int8Array', 'b'),
|
('Int8Array', 'b'),
|
||||||
('Uint8Array', 'B'),
|
('Uint8Array', 'B'),
|
||||||
('Uint8ClampedArray', 'B'),
|
('Uint8ClampedArray', 'B'),
|
||||||
|
@ -125,45 +136,55 @@ def test_typed_arrays(selenium):
|
||||||
('Int32Array', 'i'),
|
('Int32Array', 'i'),
|
||||||
('Uint32Array', 'I'),
|
('Uint32Array', 'I'),
|
||||||
('Float32Array', 'f'),
|
('Float32Array', 'f'),
|
||||||
('Float64Array', 'd')):
|
('Float64Array', 'd')))
|
||||||
print(wasm_heap, jstype, pytype)
|
def test_typed_arrays(selenium, wasm_heap, jstype, pytype):
|
||||||
if not wasm_heap:
|
if not wasm_heap:
|
||||||
selenium.run_js(
|
selenium.run_js(
|
||||||
f'window.array = new {jstype}([1, 2, 3, 4]);\n')
|
f'window.array = new {jstype}([1, 2, 3, 4]);\n')
|
||||||
else:
|
else:
|
||||||
selenium.run_js(
|
selenium.run_js(
|
||||||
'var buffer = pyodide._malloc('
|
f"""
|
||||||
f'4 * {jstype}.BYTES_PER_ELEMENT);\n'
|
var buffer = pyodide._malloc(
|
||||||
f'window.array = new {jstype}('
|
4 * {jstype}.BYTES_PER_ELEMENT);
|
||||||
'pyodide.HEAPU8.buffer, buffer, 4);\n'
|
window.array = new {jstype}(
|
||||||
'window.array[0] = 1;\n'
|
pyodide.HEAPU8.buffer, buffer, 4);
|
||||||
'window.array[1] = 2;\n'
|
window.array[0] = 1;
|
||||||
'window.array[2] = 3;\n'
|
window.array[1] = 2;
|
||||||
'window.array[3] = 4;\n')
|
window.array[2] = 3;
|
||||||
|
window.array[3] = 4;
|
||||||
|
""")
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
'from js import array\n'
|
f"""
|
||||||
'import struct\n'
|
from js import array
|
||||||
f'expected = struct.pack("{pytype*4}", 1, 2, 3, 4)\n'
|
import struct
|
||||||
'print(array.format, array.tolist(), array.tobytes())\n'
|
expected = struct.pack("{pytype*4}", 1, 2, 3, 4)
|
||||||
f'array.format == "{pytype}" '
|
print(array.format, array.tolist(), array.tobytes())
|
||||||
'and array.tolist() == [1, 2, 3, 4] '
|
((array.format == "{pytype}")
|
||||||
'and array.tobytes() == expected '
|
and array.tolist() == [1, 2, 3, 4]
|
||||||
f'and array.obj._has_bytes() is {not wasm_heap}')
|
and array.tobytes() == expected
|
||||||
|
and array.obj._has_bytes() is {not wasm_heap})
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
def test_import_js(selenium):
|
def test_import_js(selenium):
|
||||||
result = selenium.run(
|
result = selenium.run(
|
||||||
"from js import window\nwindow.title = 'Foo'\nwindow.title")
|
"""
|
||||||
|
from js import window
|
||||||
|
window.title = 'Foo'
|
||||||
|
window.title
|
||||||
|
""")
|
||||||
assert result == 'Foo'
|
assert result == 'Foo'
|
||||||
|
|
||||||
|
|
||||||
def test_pyproxy(selenium):
|
def test_pyproxy(selenium):
|
||||||
selenium.run(
|
selenium.run(
|
||||||
"class Foo:\n"
|
"""
|
||||||
" bar = 42\n"
|
class Foo:
|
||||||
" def get_value(self, value):\n"
|
bar = 42
|
||||||
" return value * 64\n"
|
def get_value(self, value):
|
||||||
"f = Foo()\n"
|
return value * 64
|
||||||
|
f = Foo()
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
assert selenium.run_js("return pyodide.pyimport('f').get_value(2)") == 128
|
assert selenium.run_js("return pyodide.pyimport('f').get_value(2)") == 128
|
||||||
assert selenium.run_js("return pyodide.pyimport('f').bar") == 42
|
assert selenium.run_js("return pyodide.pyimport('f').bar") == 42
|
||||||
|
@ -188,18 +209,22 @@ def test_pyproxy(selenium):
|
||||||
|
|
||||||
def test_pyproxy_destroy(selenium):
|
def test_pyproxy_destroy(selenium):
|
||||||
selenium.run(
|
selenium.run(
|
||||||
"class Foo:\n"
|
"""
|
||||||
" bar = 42\n"
|
class Foo:
|
||||||
" def get_value(self, value):\n"
|
bar = 42
|
||||||
" return value * 64\n"
|
def get_value(self, value):
|
||||||
"f = Foo()\n"
|
return value * 64
|
||||||
|
f = Foo()
|
||||||
|
"""
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
selenium.run_js(
|
selenium.run_js(
|
||||||
"let f = pyodide.pyimport('f');\n"
|
"""
|
||||||
"console.assert(f.get_value(1) === 64);\n"
|
let f = pyodide.pyimport('f');
|
||||||
"f.destroy();\n"
|
console.assert(f.get_value(1) === 64);
|
||||||
"f.get_value();\n")
|
f.destroy();
|
||||||
|
f.get_value();
|
||||||
|
""")
|
||||||
except selenium.JavascriptException as e:
|
except selenium.JavascriptException as e:
|
||||||
assert 'Object has already been destroyed' in str(e)
|
assert 'Object has already been destroyed' in str(e)
|
||||||
else:
|
else:
|
||||||
|
@ -208,10 +233,11 @@ def test_pyproxy_destroy(selenium):
|
||||||
|
|
||||||
def test_jsproxy(selenium):
|
def test_jsproxy(selenium):
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
"from js import document\n"
|
"""
|
||||||
"el = document.createElement('div')\n"
|
from js import document
|
||||||
"document.body.appendChild(el)\n"
|
el = document.createElement('div')
|
||||||
"document.body.children.length\n"
|
document.body.appendChild(el)
|
||||||
|
document.body.children.length"""
|
||||||
) == 1
|
) == 1
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
"document.body.children[0].tagName") == 'DIV'
|
"document.body.children[0].tagName") == 'DIV'
|
||||||
|
@ -229,50 +255,59 @@ def test_jsproxy(selenium):
|
||||||
"from js import ImageData\n"
|
"from js import ImageData\n"
|
||||||
"ImageData.typeof") == 'function'
|
"ImageData.typeof") == 'function'
|
||||||
selenium.run_js(
|
selenium.run_js(
|
||||||
"class Point {\n"
|
"""
|
||||||
" constructor(x, y) {\n"
|
class Point {
|
||||||
" this.x = x;\n"
|
constructor(x, y) {
|
||||||
" this.y = y;\n"
|
this.x = x;
|
||||||
" }\n"
|
this.y = y;
|
||||||
"}\n"
|
}
|
||||||
"window.TEST = new Point(42, 43);")
|
}
|
||||||
|
window.TEST = new Point(42, 43);""")
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
"from js import TEST\n"
|
"""
|
||||||
"del TEST.y\n"
|
from js import TEST
|
||||||
"TEST.y\n") is None
|
del TEST.y
|
||||||
|
TEST.y""") is None
|
||||||
selenium.run_js(
|
selenium.run_js(
|
||||||
"class Point {\n"
|
"""
|
||||||
" constructor(x, y) {\n"
|
class Point {
|
||||||
" this.x = x;\n"
|
constructor(x, y) {
|
||||||
" this.y = y;\n"
|
this.x = x;
|
||||||
" }\n"
|
this.y = y;
|
||||||
"}\n"
|
}
|
||||||
"window.TEST = new Point(42, 43);")
|
}
|
||||||
|
window.TEST = new Point(42, 43);""")
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
"from js import TEST\n"
|
"""
|
||||||
"del TEST['y']\n"
|
from js import TEST
|
||||||
"TEST['y']\n") is None
|
del TEST['y']
|
||||||
|
TEST['y']""") is None
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
"from js import TEST\n"
|
"""
|
||||||
"TEST == TEST\n")
|
from js import TEST
|
||||||
|
TEST == TEST
|
||||||
|
""")
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
"from js import TEST\n"
|
"""
|
||||||
"TEST != 'foo'\n")
|
from js import TEST
|
||||||
|
TEST != 'foo'
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
def test_jsproxy_iter(selenium):
|
def test_jsproxy_iter(selenium):
|
||||||
selenium.run_js(
|
selenium.run_js(
|
||||||
"function makeIterator(array) {\n"
|
"""
|
||||||
" var nextIndex = 0;\n"
|
function makeIterator(array) {
|
||||||
" return {\n"
|
var nextIndex = 0;
|
||||||
" next: function() {\n"
|
return {
|
||||||
" return nextIndex < array.length ?\n"
|
next: function() {
|
||||||
" {value: array[nextIndex++], done: false} :\n"
|
return nextIndex < array.length ?
|
||||||
" {done: true};\n"
|
{value: array[nextIndex++], done: false} :
|
||||||
" }\n"
|
{done: true};
|
||||||
" };\n"
|
}
|
||||||
"}\n"
|
};
|
||||||
"window.ITER = makeIterator([1, 2, 3]);")
|
}
|
||||||
|
window.ITER = makeIterator([1, 2, 3]);""")
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
"from js import ITER\n"
|
"from js import ITER\n"
|
||||||
"list(ITER)") == [1, 2, 3]
|
"list(ITER)") == [1, 2, 3]
|
||||||
|
@ -280,8 +315,10 @@ def test_jsproxy_iter(selenium):
|
||||||
|
|
||||||
def test_open_url(selenium):
|
def test_open_url(selenium):
|
||||||
assert selenium.run(
|
assert selenium.run(
|
||||||
"import pyodide\n"
|
"""
|
||||||
"pyodide.open_url('test_data.txt').read()\n") == 'HELLO\n'
|
import pyodide
|
||||||
|
pyodide.open_url('test_data.txt').read()
|
||||||
|
""") == 'HELLO\n'
|
||||||
|
|
||||||
|
|
||||||
def test_run_core_python_test(python_test, selenium, request):
|
def test_run_core_python_test(python_test, selenium, request):
|
||||||
|
@ -296,13 +333,14 @@ def test_run_core_python_test(python_test, selenium, request):
|
||||||
selenium.load_package('test')
|
selenium.load_package('test')
|
||||||
try:
|
try:
|
||||||
selenium.run(
|
selenium.run(
|
||||||
"from test.libregrtest import main\n"
|
"""
|
||||||
"try:\n"
|
from test.libregrtest import main
|
||||||
" main(['{}'], verbose=True, verbose3=True)\n"
|
try:
|
||||||
"except SystemExit as e:\n"
|
main(['{}'], verbose=True, verbose3=True)
|
||||||
" if e.code != 0:\n"
|
except SystemExit as e:
|
||||||
" raise RuntimeError(f'Failed with code: {{e.code}}')\n"
|
if e.code != 0:
|
||||||
.format(name))
|
raise RuntimeError(f'Failed with code: {{e.code}}')
|
||||||
|
""".format(name))
|
||||||
except selenium.JavascriptException as e:
|
except selenium.JavascriptException as e:
|
||||||
print(selenium.logs)
|
print(selenium.logs)
|
||||||
raise
|
raise
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
def test_pytest(selenium):
|
def test_pytest(selenium):
|
||||||
selenium.load_package('pytest')
|
selenium.load_package(['pytest', 'numpy', 'nose'])
|
||||||
selenium.load_package('numpy')
|
|
||||||
selenium.load_package('nose')
|
selenium.run(
|
||||||
selenium.run('from pathlib import Path')
|
"""
|
||||||
selenium.run('import os')
|
from pathlib import Path
|
||||||
selenium.run('import numpy')
|
import os
|
||||||
selenium.run('base_dir = Path(numpy.__file__).parent / "core" / "tests"')
|
import numpy
|
||||||
selenium.run("import pytest;"
|
import pytest
|
||||||
"pytest.main([base_dir / 'test_api.py'])")
|
|
||||||
|
base_dir = Path(numpy.__file__).parent / "core" / "tests"
|
||||||
|
""")
|
||||||
|
|
||||||
|
selenium.run("pytest.main([base_dir / 'test_api.py'])")
|
||||||
|
|
||||||
logs = '\n'.join(selenium.logs)
|
logs = '\n'.join(selenium.logs)
|
||||||
assert 'INTERNALERROR' not in logs
|
assert 'INTERNALERROR' not in logs
|
||||||
|
|
Loading…
Reference in New Issue