Skip to content

Commit 5a2f10b

Browse files
test: import CWNG regression tests for #1074 (cwasync no-active-document guards)
CWA merged PR #1074 (@SethMilliken) with just the code change in main.lua. CWNG's backport (fork PR #266, commit 31bdd5d) added 5 pattern-pin tests that verify the hasActiveDocument() guard, statusTextIfActionUnavailable() helper, and auto-sync early-return against the Lua source. Imported verbatim from CWNG. Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 7fcabab commit 5a2f10b

1 file changed

Lines changed: 96 additions & 0 deletions

File tree

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# SPDX-License-Identifier: GPL-3.0-or-later
2+
"""Regression coverage for the cwasync no-active-document guards (CWA #1074).
3+
4+
Backport of CWA #1074 by @SethMilliken. Prior behavior: the Push / Pull
5+
menu entries and the auto-sync toggle stayed enabled whenever a password
6+
was set, even when opened from the file browser with no document loaded.
7+
Tapping them dereferenced `self.ui.document` and crashed the plugin.
8+
9+
The fix:
10+
11+
* Adds `hasActiveDocument()` (returns true only when `self.ui.document`
12+
is set) and uses it in the `enabled_func` of the Push / Pull menu items
13+
alongside the existing password check.
14+
* Adds `statusTextIfActionUnavailable()` which appends a parenthetical
15+
reason — `(Password Not Set)` or `(No Active Document)` — to the menu
16+
label so users see *why* the entry is greyed out.
17+
* Early-returns from the auto-sync toggle handler when no document is
18+
open, so flipping the switch from the file browser is a no-op rather
19+
than a crash.
20+
21+
The plugin itself is Lua and we don't run a Lua test runner in CI, so
22+
these tests pattern-pin the load-bearing call sites against `main.lua`.
23+
"""
24+
25+
from __future__ import annotations
26+
27+
from pathlib import Path
28+
29+
import pytest
30+
31+
pytestmark = pytest.mark.unit
32+
33+
REPO_ROOT = Path(__file__).resolve().parents[2]
34+
MAIN_LUA = REPO_ROOT / "koreader" / "plugins" / "cwasync.koplugin" / "main.lua"
35+
36+
37+
def _read() -> str:
38+
assert MAIN_LUA.exists(), f"missing file: {MAIN_LUA}"
39+
return MAIN_LUA.read_text(encoding="utf-8")
40+
41+
42+
def test_has_active_document_helper_defined():
43+
body = _read()
44+
assert "function CWASync:hasActiveDocument()" in body, (
45+
"main.lua must define CWASync:hasActiveDocument() (CWA #1074)"
46+
)
47+
assert "(self.ui and self.ui.document) ~= nil" in body, (
48+
"hasActiveDocument must check both self.ui and self.ui.document — "
49+
"the file-browser entry point has self.ui but no document"
50+
)
51+
52+
53+
def test_status_text_helper_defined():
54+
body = _read()
55+
assert "function CWASync:statusTextIfActionUnavailable()" in body, (
56+
"main.lua must define CWASync:statusTextIfActionUnavailable() (CWA #1074)"
57+
)
58+
assert '_(" (Password Not Set)")' in body, (
59+
"statusTextIfActionUnavailable must surface the missing-password reason"
60+
)
61+
assert '_(" (No Active Document)")' in body, (
62+
"statusTextIfActionUnavailable must surface the no-active-document reason"
63+
)
64+
65+
66+
def test_push_menu_uses_status_text_and_active_document_guard():
67+
body = _read()
68+
assert (
69+
'_("Push progress from this device now") .. self:statusTextIfActionUnavailable()'
70+
in body
71+
), "Push menu entry must append statusTextIfActionUnavailable() (CWA #1074)"
72+
# The enabled_func now combines the password check with hasActiveDocument().
73+
# We pin the exact predicate so a future edit that drops either side trips
74+
# this test.
75+
assert (
76+
"return self.settings.password ~= nil and self:hasActiveDocument()"
77+
in body
78+
), "Push/Pull enabled_func must AND password presence with hasActiveDocument()"
79+
80+
81+
def test_pull_menu_uses_status_text():
82+
body = _read()
83+
assert (
84+
'_("Pull progress from other devices now") .. self:statusTextIfActionUnavailable()'
85+
in body
86+
), "Pull menu entry must append statusTextIfActionUnavailable() (CWA #1074)"
87+
88+
89+
def test_auto_sync_toggle_early_returns_when_no_active_document():
90+
body = _read()
91+
# The auto-sync toggle handler now bails out before scheduling tasks if no
92+
# document is open. Pin the exact guard so a refactor doesn't quietly drop
93+
# the early return and revive the original crash path.
94+
assert "if not(self:hasActiveDocument()) then\n return" in body, (
95+
"auto-sync toggle must early-return when hasActiveDocument() is false (CWA #1074)"
96+
)

0 commit comments

Comments
 (0)