Infrastructure for testing RapydScript code

This commit is contained in:
Kovid Goyal 2020-04-01 19:07:54 +05:30
parent f0f5ca509e
commit 4f106199d6
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 178 additions and 0 deletions

View File

@ -329,6 +329,59 @@ def atomic_write(base, name, content):
atomic_rename(tname, name) atomic_rename(tname, name)
def run_rapydscript_tests():
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineScript
from PyQt5.Qt import QApplication, QEventLoop
from calibre.gui2.webengine import secure_webengine
from calibre.gui2 import must_use_qt
must_use_qt()
base = base_dir()
rapydscript_dir = os.path.join(base, 'src', 'pyj')
fname = os.path.join(rapydscript_dir, 'test.pyj')
with lopen(fname, 'rb') as f:
js = compile_fast(f.read(), fname)
def create_script(src, name):
s = QWebEngineScript()
s.setName(name)
s.setInjectionPoint(QWebEngineScript.DocumentReady)
s.setWorldId(QWebEngineScript.ApplicationWorld)
s.setRunsOnSubFrames(False)
s.setSourceCode(src)
return s
class Tester(QWebEnginePage):
def __init__(self):
QWebEnginePage.__init__(self)
self.titleChanged.connect(self.title_changed)
secure_webengine(self)
self.scripts().insert(create_script(js, 'test-rapydscript.js'))
self.setHtml('<p>initialize')
self.working = True
def title_changed(self, title):
if title == 'initialized':
self.titleChanged.disconnect()
self.runJavaScript('window.main()', QWebEngineScript.ApplicationWorld, self.callback)
def spin_loop(self):
while self.working:
QApplication.instance().processEvents(QEventLoop.ExcludeUserInputEvents)
return self.result
def callback(self, result):
self.result = result
self.working = False
def javaScriptConsoleMessage(self, level, msg, line_num, source_id):
print(msg, file=sys.stderr if level > 0 else sys.stdout)
tester = Tester()
result = tester.spin_loop()
raise SystemExit(int(result))
def compile_editor(): def compile_editor():
base = base_dir() base = base_dir()
rapydscript_dir = os.path.join(base, 'src', 'pyj') rapydscript_dir = os.path.join(base, 'src', 'pyj')

47
src/pyj/test.pyj Normal file
View File

@ -0,0 +1,47 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import bound_methods, hash_literals
import traceback
from testing import registered_tests, reset_dom
def get_matching_tests_for_name(name):
ans = []
for k in Object.keys(registered_tests):
q = k.split('.')[-1]
if not name or q is name:
ans.append(registered_tests[k])
return ans
def run_tests(tests):
failed_tests = []
count = 0
for f in tests:
print(f.test_name, '...')
reset_dom()
try:
f()
count += 1
except:
traceback.print_stack()
failed_tests.append((f.test_name, traceback.format_stack()))
return failed_tests, count
def main():
tests = get_matching_tests_for_name()
st = window.performance.now()
failed_tests, total = run_tests(tests)
time = window.performance.now() - st
if failed_tests.length:
console.error(f'{failed_tests.length} out of {total} failed in {time:.1f} seconds')
else:
print(f'Ran {total} tests in {time:.1f} seconds')
return 1 if failed_tests.length else 0
window.main = main
document.title = 'initialized'

78
src/pyj/testing.pyj Normal file
View File

@ -0,0 +1,78 @@
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2020, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import bound_methods, hash_literals
from dom import clear
def raise_fail(preamble, msg):
if msg:
msg = '. ' + msg
else:
msg = ''
raise AssertionError(preamble + msg)
def assert_equal(a, b, msg):
def fail():
raise_fail(f'{a} != {b}', msg)
atype = jstype(a)
btype = jstype(b)
base_types = {'number': True, 'boolean': True, 'string': True, 'undefined': True}
if base_types[a] or base_types[b] or a is None or b is None:
if a is not b:
fail()
return
if a.__eq__:
if not a.__eq__(b):
fail()
return
if b.__eq__:
if not b.__eq__(a):
fail()
return
if a.length? or b.length?:
if a.length is not b.length:
fail()
for i in range(a.length):
assert_equal(a[i], b[i])
return
if atype is 'object':
for key in Object.keys(a):
assert_equal(a[key], b[key])
if btype is 'object':
for key in Object.keys(b):
assert_equal(a[key], b[key])
if a is not b:
fail()
def assert_true(x, msg):
if not x:
raise_fail(f'{x} is not truthy', msg)
def assert_fale(x, msg):
if x:
raise_fail(f'{x} is truthy', msg)
def reset_dom():
html = document.documentElement
clear(html)
head = document.createElement('head')
body = document.createElement('body')
html.appendChild(head)
html.appendChild(body)
registered_tests = {}
def test(f):
mod = f.__module__ or 'unknown_test_module'
f.test_name = mod + '.' + f.name
registered_tests[f.test_name] = f
return f