mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Infrastructure for testing RapydScript code
This commit is contained in:
parent
f0f5ca509e
commit
4f106199d6
@ -329,6 +329,59 @@ def atomic_write(base, name, content):
|
||||
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():
|
||||
base = base_dir()
|
||||
rapydscript_dir = os.path.join(base, 'src', 'pyj')
|
||||
|
47
src/pyj/test.pyj
Normal file
47
src/pyj/test.pyj
Normal 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
78
src/pyj/testing.pyj
Normal 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
|
Loading…
x
Reference in New Issue
Block a user