test: the lab prints from a signed-in lesson, and judges black and white on the job
A lesson site for the lab (session cookie, one-time addresses, a second origin, a request log) and real right-clicks on its words and on a JPEG, a PNG, a transparent PNG, a one-time picture, another site's, a blob:, a WebP, a canvas, a linked picture, a broken one, and Cancel. Each is judged on the job CUPS kept — where and how large, no other ink — and on the site log: nothing was fetched again. The clipboard is the teacher's afterwards. Black and white: a colourful lesson turned back and forth five times on page 2, a worksheet, a picture at 50% top left, a page full of pictures, back to Color, and Cancel. Every grey preview is grey pixel for pixel and the job is byte-for-byte the file shown, through pxlmono. The three 0.2.6.2 black-and-white scenarios now wait for the grey file before Print, as a teacher has to. 343 checks, none failing. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
594fbd810e
commit
cb12e59dea
@@ -59,7 +59,53 @@ def when(cond, then, label, limit=30):
|
||||
def preview(): return window._preview
|
||||
def ready(): return preview() is not None and preview()._pdf is not None
|
||||
def describe(d):
|
||||
return f"picture={d._picture_box.isVisible()} shown={d._page in d._images} pages={d._pages} printers={[d._printer.itemText(i) for i in range(d._printer.count())]} paper={d.paper()} colour_offered={d._colour.isVisible()} status={d._status.text()!r}"
|
||||
return f"picture={d._picture_box.isVisible()} shown={(d._pdf, d._page) in d._images} pages={d._pages} printers={[d._printer.itemText(i) for i in range(d._printer.count())]} paper={d.paper()} colour_offered={d._colour.isVisible()} status={d._status.text()!r}"
|
||||
|
||||
def shown_gray():
|
||||
"""Is the page the preview is drawing grey, pixel for pixel?"""
|
||||
pixmap = preview()._view._pixmap
|
||||
return None if pixmap is None else pixmap.toImage().allGray()
|
||||
|
||||
def keep_preview():
|
||||
import shutil
|
||||
out = Path("/tmp/rig-out"); out.mkdir(exist_ok=True)
|
||||
shutil.copy(preview()._pdf, out / "preview.pdf")
|
||||
|
||||
def toggles(sequence, then):
|
||||
"""Color (0) and Black and white (1) in turn, as a teacher would, each shown before the next."""
|
||||
def step(i):
|
||||
if i == len(sequence): return then()
|
||||
start = time.monotonic(); preview()._colour.setCurrentIndex(sequence[i])
|
||||
def shown():
|
||||
d = preview()
|
||||
stamp(f"TOGGLE {i} want={'gray' if sequence[i] else 'colour'} took={time.monotonic() - start:.2f} "
|
||||
f"pdf={d._pdf.name} source={d._source.name} page={d._page}/{d._pages} shown_gray={shown_gray()}")
|
||||
step(i + 1)
|
||||
when(ready, shown, f"toggle {i}")
|
||||
step(0)
|
||||
|
||||
def colour_lesson(view, title="Rainbow lesson"):
|
||||
# Backgrounds do not print, so the colour is in the words and the drawings.
|
||||
shapes = ("<svg width='600' height='120'><circle cx='60' cy='60' r='50' fill='#e00000'/>"
|
||||
"<rect x='130' y='10' width='200' height='100' fill='#0050e0'/>"
|
||||
"<circle cx='450' cy='60' r='50' fill='#00a000'/></svg>")
|
||||
view.setHtml(f"<html><head><title>{title}</title></head><body>" + "".join(
|
||||
f"<h1 style='color:#c00'>{title}, part {i}</h1>{shapes}"
|
||||
f"<p style='color:#060'>{'God put a rainbow in the sky. ' * 60}</p>" for i in range(4)
|
||||
) + "</body></html>", QUrl("https://app.wonderink.org/rainbow"))
|
||||
|
||||
def colour_worksheet(name="Colour the Rainbow"):
|
||||
from PyQt6.QtGui import QColor
|
||||
d = wi.DOWNLOADS; d.mkdir(parents=True, exist_ok=True)
|
||||
p = d / f"{name}.pdf"
|
||||
w = QPdfWriter(str(p)); w.setPageSize(QPageSize(QPageSize.PageSizeId.Letter)); w.setResolution(300)
|
||||
pa = QPainter(w); pa.setFont(QFont("DejaVu Sans", 28))
|
||||
for page, colours in enumerate((("#e00000", "#ff9900"), ("#00a000", "#0050e0"))):
|
||||
if page: w.newPage()
|
||||
pa.setPen(QColor(colours[0])); pa.drawText(200, 400, f"WORKSHEET {name} page {page + 1}")
|
||||
pa.fillRect(200, 600, 1000, 800, QColor(colours[1]))
|
||||
pa.end()
|
||||
return p
|
||||
|
||||
def finish(code=0):
|
||||
stamp(f"RESULT notes={notes} preview_open={preview() is not None} tabs={window._tabs.count()}")
|
||||
@@ -76,7 +122,8 @@ actions = {
|
||||
"cancel": lambda view: when(ready, lambda: (stamp("PREVIEW " + describe(preview())), preview()._cancel.click(), finish()), "preview"),
|
||||
"options": lambda view: when(ready, lambda: (
|
||||
preview()._which.setCurrentIndex(1), preview()._range.setText("2-3"),
|
||||
preview()._copies.setValue(2), preview()._colour.setCurrentIndex(1), press_print()), "preview"),
|
||||
preview()._copies.setValue(2), preview()._colour.setCurrentIndex(1),
|
||||
when(ready, press_print, "black and white")), "preview"),
|
||||
"bad-range": lambda view: when(ready, lambda: (
|
||||
preview()._which.setCurrentIndex(1), preview()._range.setText("7"), preview()._print.click(),
|
||||
stamp(f"bad range: open={preview() is not None} status={preview()._status.text()!r}"),
|
||||
@@ -100,7 +147,120 @@ actions = {
|
||||
QTimer.singleShot(800, lambda: (stamp(f"second request while open: still one preview={preview() is not None}"), press_print()))), "preview"),
|
||||
}
|
||||
|
||||
if scenario.startswith("picture:"):
|
||||
SITE = "http://127.0.0.1:8094"
|
||||
|
||||
if scenario.startswith("bw-"):
|
||||
# bw-web: a colourful lesson, turned to page 2, Color and Black and white
|
||||
# back and forth, then page 2 twice in black and white.
|
||||
# bw-pdf: a colourful worksheet, all of it, in black and white.
|
||||
# bw-colour-again: black and white, then back to Color, then Print.
|
||||
# bw-cancel: black and white, then Cancel.
|
||||
if scenario == "bw-pdf":
|
||||
window.open_pdf(colour_worksheet()); view = window.current()
|
||||
else:
|
||||
view = window.open_tab(); colour_lesson(view)
|
||||
def colour_first():
|
||||
stamp(f"COLOUR FIRST shown_gray={shown_gray()} pdf={preview()._pdf.name}")
|
||||
if scenario == "bw-web":
|
||||
preview()._turn(1)
|
||||
toggles([1, 0, 1, 0, 1], lambda: (
|
||||
preview()._which.setCurrentIndex(1), preview()._range.setText("2"),
|
||||
preview()._copies.setValue(2), keep_preview(), press_print()))
|
||||
elif scenario == "bw-pdf":
|
||||
toggles([1], lambda: (keep_preview(), press_print()))
|
||||
elif scenario == "bw-colour-again":
|
||||
toggles([1, 0], lambda: (keep_preview(), press_print()))
|
||||
else:
|
||||
toggles([1], lambda: (stamp("PREVIEW " + describe(preview())), preview()._cancel.click(), finish()))
|
||||
begin = lambda *_: (QTimer.singleShot(0, lambda: window.print_view(view)), when(ready, colour_first, "preview"))
|
||||
if scenario == "bw-pdf":
|
||||
QTimer.singleShot(2500, begin)
|
||||
else:
|
||||
view.loadFinished.connect(begin)
|
||||
elif scenario.startswith("rclick"):
|
||||
# A lesson behind a sign-in, with pictures in it; a real right-click.
|
||||
# rclick-page on the words: the page prints
|
||||
# rclick-image:ID:SIZE:POSITION[:gray] on a picture: that picture prints
|
||||
# rclick-broken a picture that never loaded
|
||||
# rclick-cancel a picture, then Cancel
|
||||
from PyQt6.QtCore import QEvent, QPointF, Qt
|
||||
from PyQt6.QtGui import QMouseEvent
|
||||
from PyQt6.QtWidgets import QApplication as Application
|
||||
parts = scenario.split(":")
|
||||
target = {"rclick-page": "words", "rclick-page-gray": "words", "rclick-broken": "broken",
|
||||
"rclick-cancel": "private-jpg"}.get(parts[0], parts[1] if len(parts) > 1 else "")
|
||||
clipboard = Application.clipboard()
|
||||
view = window.open_tab(); view.load(QUrl(f"{SITE}/login"))
|
||||
page_ready = []
|
||||
def poll_ready():
|
||||
if view.url().path() == "/lesson":
|
||||
view.page().runJavaScript("window.__ready === true", lambda ok: page_ready.append(1) if ok else None)
|
||||
if not page_ready: QTimer.singleShot(200, poll_ready)
|
||||
QTimer.singleShot(500, poll_ready)
|
||||
def right_click(then):
|
||||
js = ("(function(){var e=document.getElementById(%r);e.scrollIntoView({block:'center'});"
|
||||
"var r=e.getBoundingClientRect();return [r.x+r.width/2,r.y+r.height/2]})()" % target)
|
||||
def at(xy):
|
||||
zoom = view.zoomFactor(); x, y = xy[0] * zoom, xy[1] * zoom
|
||||
clipboard.setText("TEACHER'S TEXT, John 3:16")
|
||||
stamp(f"RCLICK {target} at {x:.0f},{y:.0f} since={time.time():.3f}")
|
||||
for kind, buttons in ((QEvent.Type.MouseButtonPress, Qt.MouseButton.RightButton),
|
||||
(QEvent.Type.MouseButtonRelease, Qt.MouseButton.NoButton)):
|
||||
Application.sendEvent(view.focusProxy(), QMouseEvent(
|
||||
kind, QPointF(x, y), QPointF(view.mapToGlobal(QPointF(x, y))),
|
||||
Qt.MouseButton.RightButton, buttons, Qt.KeyboardModifier.NoModifier))
|
||||
when(lambda: Application.activePopupWidget() is not None,
|
||||
lambda: then(Application.activePopupWidget()), "menu")
|
||||
view.page().runJavaScript(js, at)
|
||||
def choose(menu, text, after):
|
||||
items = [a.text() for a in menu.actions() if a.text()]
|
||||
stamp(f"MENU {items}")
|
||||
action = next((a for a in menu.actions() if a.text() == text), None)
|
||||
menu.close()
|
||||
if action is None:
|
||||
stamp(f"NO {text!r} IN THE MENU"); return finish(5)
|
||||
after()
|
||||
QTimer.singleShot(0, action.trigger)
|
||||
def picture_ready():
|
||||
d = preview(); return d is not None and d._picture is not None and d._pdf is not None
|
||||
def clipboard_line():
|
||||
stamp(f"CLIPBOARD {clipboard.text()!r}")
|
||||
if parts[0] == "rclick-page":
|
||||
go = lambda: right_click(lambda m: choose(m, "Print page…", lambda: when(ready, lambda: (
|
||||
clipboard_line(), keep_preview(), press_print()), "page preview")))
|
||||
elif parts[0] == "rclick-page-gray":
|
||||
# The page with all its pictures, in black and white: the slow case.
|
||||
def gray_page():
|
||||
start = time.monotonic(); preview()._colour.setCurrentIndex(1)
|
||||
when(ready, lambda: (
|
||||
stamp(f"GRAY PAGE took={time.monotonic() - start:.1f} shown_gray={shown_gray()} pages={preview()._pages}"),
|
||||
keep_preview(), press_print()), "black and white", limit=70)
|
||||
go = lambda: right_click(lambda m: choose(m, "Print page…", lambda: when(ready, gray_page, "page preview")))
|
||||
elif parts[0] == "rclick-broken":
|
||||
go = lambda: right_click(lambda m: choose(m, "Print image…", lambda: when(
|
||||
lambda: preview() is not None and "could not be taken" in preview()._status.text(), lambda: (
|
||||
stamp(f"BROKEN status={preview()._status.text()!r} print_enabled={preview()._print.isEnabled()} "
|
||||
f"pages={preview()._pages} picture={preview()._picture is not None}"),
|
||||
clipboard_line(), preview()._cancel.click(), finish()), "the picture failing", limit=15)))
|
||||
elif parts[0] == "rclick-cancel":
|
||||
go = lambda: right_click(lambda m: choose(m, "Print image…", lambda: when(picture_ready, lambda: (
|
||||
stamp("PREVIEW " + describe(preview())), clipboard_line(), preview()._cancel.click(), finish()),
|
||||
"picture preview")))
|
||||
else:
|
||||
_, _, size, position, *colour = parts
|
||||
def lay_out():
|
||||
d = preview()
|
||||
d._size.setCurrentIndex(d._size.findData(int(size)))
|
||||
d._place.choose(position.replace("-", " "))
|
||||
if colour == ["gray"]:
|
||||
d._colour.setCurrentIndex(1)
|
||||
QTimer.singleShot(900, lambda: when(ready, lambda: (
|
||||
stamp(f"PICTURE picture_box={d._picture_box.isVisible()} image={d._picture.width()}x{d._picture.height()} "
|
||||
f"title={d._title!r} shown_gray={shown_gray()}"),
|
||||
clipboard_line(), keep_preview(), press_print()), "layout"))
|
||||
go = lambda: right_click(lambda m: choose(m, "Print image…", lambda: when(picture_ready, lay_out, "picture preview")))
|
||||
when(lambda: bool(page_ready), go, "the lesson and its pictures", limit=30)
|
||||
elif scenario.startswith("picture:"):
|
||||
# picture:FILE:SIZE:POSITION:PAPER:FILL[:color]
|
||||
# Opens a picture on its own, chooses the layout with the preview's own
|
||||
# controls, keeps the exact PDF the preview showed, then prints it.
|
||||
@@ -117,14 +277,16 @@ if scenario.startswith("picture:"):
|
||||
d._fill.setChecked(fill == "fill")
|
||||
if rest and rest[0] == "gray":
|
||||
d._colour.setCurrentIndex(1)
|
||||
QTimer.singleShot(900, keep_and_print)
|
||||
# The layout settles (120 ms), then black and white if asked for.
|
||||
QTimer.singleShot(900, lambda: when(ready, keep_and_print, "layout"))
|
||||
def keep_and_print():
|
||||
import shutil
|
||||
d = preview()
|
||||
out = Path("/tmp/rig-out"); out.mkdir(exist_ok=True)
|
||||
shutil.copy(d._pdf, out / "preview.pdf")
|
||||
stamp(f"PICTURE picture_box={d._picture_box.isVisible()} size_enabled={d._size.isEnabled()} "
|
||||
f"image={d._picture.width()}x{d._picture.height()} labels={d._colour_label.text()!r},{d._colour.itemText(0)!r}")
|
||||
f"image={d._picture.width()}x{d._picture.height()} labels={d._colour_label.text()!r},{d._colour.itemText(0)!r} "
|
||||
f"shown_gray={shown_gray()}")
|
||||
press_print()
|
||||
QTimer.singleShot(2500, lambda: (QTimer.singleShot(0, lambda: window.print_view(view)),
|
||||
when(ready_picture, choose, "picture preview")))
|
||||
@@ -154,7 +316,8 @@ elif scenario in ("pdf", "pdf-options"):
|
||||
if scenario == "pdf-options":
|
||||
actions["pdf-options"] = lambda view: when(ready, lambda: (
|
||||
preview()._which.setCurrentIndex(1), preview()._range.setText("2"),
|
||||
preview()._copies.setValue(3), preview()._colour.setCurrentIndex(1), press_print()), "preview")
|
||||
preview()._copies.setValue(3), preview()._colour.setCurrentIndex(1),
|
||||
when(ready, press_print, "black and white")), "preview")
|
||||
QTimer.singleShot(2500, lambda: (QTimer.singleShot(0, lambda: window.print_view(view)),
|
||||
actions[scenario if scenario == "pdf-options" else "web"](view)))
|
||||
elif scenario == "pdf-viewer-button":
|
||||
|
||||
Reference in New Issue
Block a user