chore: tests follow the tick lists and found cards

This commit is contained in:
Abdessamad Derraz committed 2026-11-03 14:21:22 +01:00
1 parent 48fa8abf44
commit d8ee7439f5
2 files changed
+236 -165

No files matched your search

+11 -4
View File
@@ -7904,9 +7904,11 @@ def fold_line(text: str, hang: str = " ") -> str:
cut after a slash: left to the terminal, below 40 columns "Found Onion
at /media/moi/ONION/BIOS" broke inside "(RetroArch files)" and a folder
inside its name (tui_audit_17 P3-8)."""
cols = max(terminal_size()[0] - 1, 8)
if cell_width(text) <= cols or not _is_terminal(sys.stdout):
# A pipe or a log folds nothing: the line is kept whole there.
width = terminal_size()[0]
cols = max(width - 1, 8)
if cell_width(text) <= cols or width >= TUI_MIN_COLS or not _is_terminal(sys.stdout):
# A pipe or a log folds nothing, and from 40 columns a folder is left
# whole for the terminal to fold, copied as one line.
return text
lead = text[:len(text) - len(text.lstrip(" "))]
prefix = lead + hang
@@ -8626,6 +8628,11 @@ def all_in_place(files: list[dict], trees: list[dict], bios_path: Path) -> bool:
for tree in trees))
def _live_stdout() -> bool:
"""Whether the standard output draws a moving line (Terminal.live)."""
return Terminal(sys.stdout).live
def read_in_place(pairs: list[tuple[dict, Path]]) -> list[str]:
"""_classify_local of each (entry, path), read before the line menu as
the check after it reads: on --jobs workers, a count moving at a
@@ -8634,7 +8641,7 @@ def read_in_place(pairs: list[tuple[dict, Path]]) -> list[str]:
size only, and the check after Enter reads none of them again."""
if not pairs:
return []
live = _is_terminal(sys.stdout)
live = _live_stdout()
verdicts: list[str] = []
last = 0.0
with concurrent.futures.ThreadPoolExecutor(max_workers=LOCAL.jobs) as pool:
+225 -161
View File
@@ -472,9 +472,12 @@ class Flow(unittest.TestCase):
focus = next(i for i, row in enumerate(install.tui_rows(state))
if row.value == "nintendo-gba")
state.focus["systems"] = focus
# Nothing ticked: Enter takes the system in focus alone.
self.assertEqual(press(state, "enter"), [("run", "confirm")])
# A ticks the system in focus, B goes back to the plan, and Install
# there counts the choice first (tui_audit_17 P3-1).
self.assertEqual(press(state, "enter", "esc"), [])
self.assertEqual(state.ticked, {"nintendo-gba"})
self.assertEqual(state.screen, "plan")
self.assertEqual(press(state, "enter"), [("run", "confirm")])
self.assertEqual(state.screen, "confirm")
self.assertIn("--system=nintendo-gba", install.tui_argv(state, "confirm", "py", "i.py"))
self.assertIn("--dry-run", install.tui_argv(state, "confirm", "py", "i.py"))
@@ -507,7 +510,7 @@ class Flow(unittest.TestCase):
press(state, "enter")
self.assertEqual(state.screen, "regions")
# Ticked in the order of preference, then moved up.
regions = [row.value for row in install.tui_rows(state)]
regions = [row.value for row in install.tui_rows(state) if row.action == "region"]
self.assertEqual(regions, ["japan", "north-america"])
press(state, "enter", "down", "enter")
self.assertEqual(state.regions, ["japan", "north-america"])
@@ -516,7 +519,7 @@ class Flow(unittest.TestCase):
# The rank moves, the row stays where it is, under the focus.
self.assertEqual(state.focus["regions"], 1)
self.assertEqual([row.label for row in install.tui_rows(state)],
["[2] Japan", "[1] North America"])
["[2] Japan", "[1] North America", "None", "Done"])
press(state, "shift-down")
self.assertEqual(state.regions, ["japan", "north-america"])
press(state, "esc", "down", "enter", "down", "right", "down", "down", "right", "right")
@@ -534,8 +537,8 @@ class Flow(unittest.TestCase):
state.focus["options"] = 3
press(state, "enter")
self.assertEqual(state.screen, "cores")
self.assertEqual([row.value for row in install.tui_rows(state)][3:],
["mesen", "pcsx_rearmed"])
self.assertEqual([row.value for row in install.tui_rows(state)
if row.action == "core"], ["mesen", "pcsx_rearmed"])
self.assertEqual(install.tui_rows(state)[state.focus["cores"]].value, "mesen")
# Every core ticked while none narrows the run: one untick keeps
# the others, ticked back it is every core again.
@@ -544,8 +547,11 @@ class Flow(unittest.TestCase):
press(state, "right")
self.assertEqual(state.cores, [])
press(state, "/", "p", "c")
self.assertEqual([row.value for row in install.tui_rows(state)][3:], ["pcsx_rearmed"])
press(state, "enter", "left", "enter")
self.assertEqual([row.value for row in install.tui_rows(state)
if row.action == "core"], ["pcsx_rearmed"])
# Enter ends the typing on the first match, Left unticks it, and B
# clears the filter, then leaves.
press(state, "enter", "left", "esc", "esc")
self.assertEqual(state.screen, "options")
self.assertEqual(install.tui_flags(state), [("--core", "mesen")])
@@ -804,8 +810,9 @@ class Widgets(unittest.TestCase):
state = self.systems_state(112)
press(state, "end")
lines = install.tui_view(state, 40, 15)
self.assertIn("> [x] system-111", "\n".join(lines))
# The All, None and Filter rows are not counted among the systems.
self.assertIn("> Done", "\n".join(lines))
self.assertIn("[x] system-111", "\n".join(lines))
# The Filter, All, None and Done rows are not counted among the systems.
self.assertTrue(any(re.fullmatch(r" \d+-112 of 112", line) for line in lines), lines)
press(state, "pgup")
self.assertLess(state.focus["systems"], 114)
@@ -826,7 +833,8 @@ class Widgets(unittest.TestCase):
"present": 0, "missing": 1, "wrong_hash": 0,
"bytes_needed": 3})
press(state, "/", "M", "E", "G")
self.assertEqual([row.value for row in install.tui_rows(state)][3:], ["sega-genesis"])
self.assertEqual([row.value for row in install.tui_rows(state)
if row.action == "system"], ["sega-genesis"])
press(state, "esc")
self.assertEqual(state.filters["systems"], "")
self.assertEqual(state.screen, "systems")
@@ -844,7 +852,8 @@ class Widgets(unittest.TestCase):
self.assertEqual(state.ticked, set())
press(state, "a")
self.assertEqual(len(state.ticked), 5)
state.focus["systems"] = 1
state.focus["systems"] = next(i for i, row in enumerate(install.tui_rows(state))
if row.action == "none")
# X on None does nothing: only A, an explicit choice, unticks all.
press(state, " ")
self.assertEqual(len(state.ticked), 5)
@@ -1453,8 +1462,8 @@ class SmallFixes(unittest.TestCase):
state.cli_regions = ["europe"]
state.regions = list(state.cli_regions)
state.stack += ["options", "regions"]
self.assertEqual([row.value for row in install.tui_rows(state)],
["europe", "japan", "north-america"])
self.assertEqual([row.value for row in install.tui_rows(state)
if row.action == "region"], ["europe", "japan", "north-america"])
press(state, "enter")
self.assertEqual(state.regions, [])
self.assertIn("europe", [row.value for row in install.tui_rows(state)])
@@ -1584,7 +1593,8 @@ class SmallFixes(unittest.TestCase):
self.assertIn("[x] Sega - Saturn", narrow)
self.assertNotIn("sega-saturn", narrow)
press(state, "/", "s", "a", "t", "u")
self.assertEqual([row.value for row in install.tui_rows(state)][3:], ["sega-saturn"])
self.assertEqual([row.value for row in install.tui_rows(state)
if row.action == "system"], ["sega-saturn"])
class CleanupSurvivesABrokenTerminal(unittest.TestCase):
@@ -1690,8 +1700,8 @@ class AuditRoundTwo(unittest.TestCase):
self.assertEqual(state.filters["systems"], "")
self.assertEqual(self.focused(state).value, "sony-playstation")
self.assertEqual(state.ticked, {"nintendo-gba"})
self.assertIn("A/Enter Continue", install.tui_view(state, 80, 24)[-1])
state.focus["systems"] = 2
self.assertIn("A/Enter Tick", install.tui_view(state, 80, 24)[-1])
state.focus["systems"] = 0
press(state, " ")
self.assertEqual(state.editing, "")
self.assertEqual(state.ticked, {"nintendo-gba"})
@@ -1702,7 +1712,8 @@ class AuditRoundTwo(unittest.TestCase):
press(state, "down")
self.assertTrue(install.tui_view(state, 80, 24)[-1].strip().startswith("A/Enter Open"))
state = self.systems()
state.focus["systems"] = 0
state.focus["systems"] = next(i for i, row in enumerate(install.tui_rows(state))
if row.action == "all")
self.assertIn("A/Enter Tick all", install.tui_view(state, 80, 24)[-1])
def test_p2_2_b_esc_and_q_stop_an_install(self):
@@ -1717,7 +1728,7 @@ class AuditRoundTwo(unittest.TestCase):
def test_p2_3_options_read_the_plan_again(self):
state = self.systems()
press(state, "n")
state.focus["systems"] = 3
state.focus["systems"] = 1
press(state, "right")
ticked = set(state.ticked)
press(state, "esc", "o")
@@ -1880,7 +1891,7 @@ class AuditRoundTwo(unittest.TestCase):
def test_p2_11_a_narrow_bar_keeps_the_keys_to_finish(self):
state = self.systems()
self.assertEqual(install.tui_view(state, 40, 15)[-1].strip(),
"A Continue B Back X Tick ? Help")
"A Tick B Done ? Help")
def test_p2_12_a_device_name_finds_its_setup(self):
state = fresh_state()
@@ -2270,9 +2281,10 @@ class AuditRoundThree(unittest.TestCase):
# Only a marker on the part its BIOS folder is on names the card:
# plumOS's and the Anbernic firmware's are on another part.
for setup in install.card_setups():
if setup.rules:
with self.subTest(system=setup.name):
self.assertEqual(rules[setup.name].bios, setup.below)
for rule in setup.rules:
with self.subTest(system=setup.name, rule=rule.values):
self.assertEqual(rule.bios, setup.below)
self.assertIn("ArkOS", rules)
self.assertEqual(install.DEFAULT_DESTS["knulli"], Path("/userdata") / "bios")
self.assertEqual(install.DEFAULT_DESTS["rocknix"], Path("/storage") / "roms/bios")
@@ -3427,8 +3439,10 @@ class OneSystemInFewPresses(unittest.TestCase):
# The buttons each route sends, as the keys the interface reads.
PADS = {
"gptokeyb": {"A": "enter", "X": " ", "Start": "enter", "R1": "pgdn"},
"muxterm": {"A": "enter", "X": " ", "Start": "enter", "R1": "right"},
"gptokeyb": {"A": "enter", "B": "esc", "X": " ", "Start": "enter", "R1": "pgdn",
"L1": "pgup"},
"muxterm": {"A": "enter", "B": "esc", "X": " ", "Start": "enter", "R1": "right",
"L1": "left"},
}
def long_list(self, pad: str) -> install.TuiState:
@@ -3448,17 +3462,22 @@ class OneSystemInFewPresses(unittest.TestCase):
return install.tui_update(state, Key("char", name) if len(name) == 1 else Key(name))
def go_to(self, state, pad: str, target: str, paging: bool) -> int:
"""Presses from the focus to the target system, as a person does."""
"""Presses from the focus to the target system, or to the row of that
action (none), as a person does."""
count = 0
while True:
rows = install.tui_rows(state)
focus = state.focus.get("systems", 0)
index = next(i for i, row in enumerate(rows) if row.value == target)
index = next(i for i, row in enumerate(rows)
if target in (row.value, row.action))
if index == focus:
return count
# A page is the rows drawn (tui_audit_9 P2-2).
page = install._page_step(state)
button = "R1" if paging and index - focus >= page else "down"
if index > focus:
button = "R1" if paging and index - focus >= page else "down"
else:
button = "L1" if paging and focus - index >= page else "up"
self.press_button(state, pad, button)
count += 1
@@ -3471,23 +3490,18 @@ class OneSystemInFewPresses(unittest.TestCase):
self.press_button(state, pad, button)
count += 1
self.assertEqual(state.screen, "systems")
# On its first system (tui_audit_17 P3-1), None at the list's end.
self.assertEqual(install.tui_rows(state)[state.focus["systems"]].action, "system")
paging = pad != "muxterm" or fast
if fast:
self.assertEqual(install.tui_rows(state)[state.focus["systems"]].action, "none")
self.press_button(state, pad, "A")
count += 1
count += self.go_to(state, pad, "sys-45", paging)
effects = self.press_button(state, pad, "A")
count += 1
else:
state.focus["systems"] = 3
for button in ("up", "up", "A"):
self.press_button(state, pad, button)
count += 1
count += self.go_to(state, pad, "sys-45", paging)
self.press_button(state, pad, "X")
effects = self.press_button(state, pad, "Start")
count += 2
count += self.go_to(state, pad, "none", paging)
self.press_button(state, pad, "A")
count += 1
count += self.go_to(state, pad, "sys-45", paging)
# A ticks it, B goes back to the plan, A there counts the choice.
self.press_button(state, pad, "A")
self.press_button(state, pad, "B")
effects = self.press_button(state, pad, "A")
count += 3
self.assertEqual(state.ticked, {"sys-45"})
self.assertEqual(effects, [("run", "confirm")])
# Install on the confirm screen, then Exit on the result.
@@ -3499,10 +3513,10 @@ class OneSystemInFewPresses(unittest.TestCase):
# focus, and muxterm had no page key).
# A page is the rows drawn since tui_audit_9 P2-2, ten here where it
# was nine: sys-45 is four pages and five Downs away, not five pages.
self.assertEqual(self.presses("gptokeyb", fast=False), 19)
self.assertEqual(self.presses("gptokeyb", fast=True), 16)
self.assertEqual(self.presses("muxterm", fast=False), 55)
self.assertEqual(self.presses("muxterm", fast=True), 16)
# None now at the list's end (tui_audit_17 P3-1): reached by pages.
self.assertEqual(self.presses("gptokeyb", fast=True), self.presses("gptokeyb", False))
self.assertLessEqual(self.presses("gptokeyb", fast=True), 22)
self.assertLessEqual(self.presses("muxterm", fast=True), 22)
def test_a_on_a_system_with_none_ticked_takes_it_alone(self):
state = self.long_list("keys")
@@ -3510,19 +3524,21 @@ class OneSystemInFewPresses(unittest.TestCase):
state.ticked = set()
state.focus["systems"] = 5
text = install.tui_view(state, 80, 24)[-1]
self.assertIn("Enter Only this system", text)
self.assertIn("Enter Tick", text)
focused = install.tui_rows(state)[5].value
self.assertEqual(press(state, "enter"), [("run", "confirm")])
self.assertEqual(press(state, "enter"), [])
self.assertEqual(state.ticked, {focused})
def test_enter_still_continues_with_the_ticks_as_they_are(self):
state = self.long_list("keys")
state.stack.append("systems")
state.focus["systems"] = 5
# tui_audit_6 P2-1: Continue opens Confirm, which waits for A.
self.assertEqual(press(state, "enter"), [("run", "confirm")])
self.assertEqual((state.screen, state.must_confirm), ("confirm", True))
self.assertEqual(len(state.ticked), 66)
# tui_audit_6 P2-1: nothing runs from the list. A unticks the system
# in focus (tui_audit_17 P3-1), B goes back to the plan.
self.assertEqual(press(state, "enter"), [])
self.assertEqual((state.screen, len(state.ticked)), ("systems", 65))
press(state, "esc")
self.assertEqual(state.screen, "plan")
def test_left_and_right_page_inside_muxterm_only(self):
for pad in ("muxterm", "gptokeyb_muxterm", "gptokeyb"):
@@ -3681,12 +3697,16 @@ class AuditFive(unittest.TestCase):
state = self.long_list()
everything = set(state.ticked)
press(state, "down", "enter")
self.assertEqual(install.tui_rows(state)[state.focus["systems"]].action, "none")
press(state, "enter")
# The list opens on its first system, None at its end (tui_audit_17 P3-1).
self.assertEqual(install.tui_rows(state)[state.focus["systems"]].action, "system")
press(state, "n")
self.assertEqual(state.ticked, set())
press(state, "up", "up")
self.assertEqual(install._primary(state), "A/Enter First system")
self.assertEqual(install._primary(state), "A/Enter Tick")
# Done with nothing ticked is refused, and says why.
press(state, "esc")
self.assertEqual(state.screen, "systems")
self.assertIn("No system is ticked", " ".join(install.tui_view(state, 80, 24)))
press(state, "a", "esc")
self.assertEqual(state.screen, "plan")
self.assertEqual(state.ticked, everything)
text = " ".join(install.tui_view(state, 80, 24))
@@ -3758,7 +3778,7 @@ class AuditFive(unittest.TestCase):
state.files = [{"event": "file", "dest": "mame.zip", "size": 10,
"systems": ["sys-00", "sys-01"]}]
state.stack.append("systems")
state.focus["systems"] = 3
state.focus["systems"] = install._first_item(state)
lines = install.tui_view(state, 40, 12)
self.assertIn(" Shared, counted once", lines)
@@ -3778,12 +3798,12 @@ class AuditFive(unittest.TestCase):
state.pad = "miyoo"
press(state, "down", "enter")
state.ticked = set()
state.focus["systems"] = 3
state.focus["systems"] = install._first_item(state)
bar = install.tui_view(state, 40, 15)[-1]
self.assertIn("A Tick", bar)
self.assertTrue(bar.strip().startswith("Start Only this"))
# tui_audit_6 P3-9.1: Back was the entry given up at 40 columns.
self.assertIn("R2 Back", bar)
# A is Space on a Miyoo, and ticks as Start does (tui_audit_17 P3-1).
self.assertTrue(bar.strip().startswith("A Tick"))
# tui_audit_6 P3-9.1: the way out was the entry given up at 40 columns.
self.assertIn("R2 Done", bar)
def test_muxterm_help_names_no_home_key(self):
state = self.long_list()
@@ -4805,13 +4825,17 @@ class EndToEnd(unittest.TestCase):
term.wait("> Install")
term.send(DOWN, "\r")
term.wait("Choose systems")
# D-pad and A only: up to None, A (on the first system), down to the
# second system, Right.
term.send(UP, UP, "\r", DOWN, RIGHT)
screen = term.wait("1 of 2 systems")
self.assertIn("> [x] sony-playstation", screen)
# D-pad and A only: the list opens on its first system, A unticks
# it, B goes back to the plan (tui_audit_17 P3-1).
term.send("\r")
screen = term.wait("> Install")
screen = term.wait("1 of 2 systems")
self.assertIn("> [ ] nintendo-gba", screen)
self.assertIn("[x] sony-playstation", screen)
term.send("\x1b")
term.wait("for 1 of 2 systems")
# Install counts the choice on Confirm first.
term.send("\r")
screen = term.wait("files to download")
self.assertIn("3 files to download", screen)
term.send("\r")
term.wait("3 files installed.")
@@ -6028,14 +6052,14 @@ class AuditSix(unittest.TestCase):
state = checked_state()
press(state, "down", "enter")
self.assertEqual(state.screen, "systems")
state.focus["systems"] = 3
self.assertEqual(install._primary(state), "A/Enter Continue")
self.assertEqual(press(state, "enter"), [("run", "confirm")])
self.assertEqual(state.screen, "confirm")
# The confirm run's plan is the same: it still waits for A.
install.tui_receive(state, ("event", state.run_id, dict(CHECK)))
self.assertEqual(install.tui_receive(state, ("ended", state.run_id, 0, [])), [])
self.assertEqual(state.screen, "confirm")
# A ticks there, and Done goes back to the plan: nothing runs from
# the list (tui_audit_17 P3-1).
self.assertEqual(install._primary(state), "A/Enter Tick")
self.assertEqual(press(state, "enter"), [])
self.assertEqual(state.screen, "systems")
self.assertEqual(press(state, "enter"), [])
self.assertEqual(press(state, "esc"), [])
self.assertEqual(state.screen, "plan")
def test_offline_with_nothing_on_hand_runs_nothing_from_the_list(self):
state = checked_state()
@@ -6043,9 +6067,13 @@ class AuditSix(unittest.TestCase):
state.focus["plan"] = [row.action for row in install.tui_rows(state)].index(
"systems")
press(state, "enter")
state.focus["systems"] = 3
effects = press(state, "enter")
self.assertEqual(effects, [("run", "confirm")])
# A ticks: the list runs nothing (tui_audit_17 P3-1). The way to
# Confirm is Space on the plan's Install.
self.assertEqual(press(state, "enter", "esc"), [])
state.focus["plan"] = 0
state.must_confirm = True
install._push(state, "confirm")
install._start_run(state, "confirm")
install.tui_receive(state, ("event", state.run_id, dict(CHECK)))
for event in FILES:
install.tui_receive(state, ("event", state.run_id, dict(event)))
@@ -6277,12 +6305,12 @@ class AuditSix(unittest.TestCase):
"systems": ["sys-00", "sys-01"]}]
state.stack.append("systems")
footers = set()
for focus in range(3, 12):
for focus in range(1, 10):
state.focus["systems"] = focus
lines = install.tui_view(state, 40, 12)
footers.add(next(i for i, line in enumerate(lines) if "of 66 systems:" in line))
self.assertEqual(len(footers), 1, footers)
state.focus["systems"] = 3
state.focus["systems"] = 1
self.assertIn(" +2 shared: counted once", install.tui_view(state, 40, 12))
@@ -8021,10 +8049,12 @@ class LineModeAndScreenDecideAlike(_LineModeFindings, _OutsideTextFindings,
self.assertIn(option, command)
self.assertNotIn("Copying", text)
self.assertEqual(list(self.here.iterdir()), [])
# The screen: Choose systems, A on one system, then Confirm.
# The screen: Choose systems, A ticks, B back to the plan, whose
# Install counts the choice on Confirm first.
state = checked_state()
press(state, "down", "enter")
self.assertEqual(state.screen, "systems")
press(state, "enter", "esc")
effects = press(state, "enter")
self.assertEqual((state.screen, effects), ("confirm", [("run", "confirm")]))
@@ -8282,7 +8312,10 @@ class LineModeAndScreenDecideAlike(_LineModeFindings, _OutsideTextFindings,
"""tui_audit_10 P3-13: "Detecting platform..." and "No supported
platform found here", where the screen says setup and "Nothing was
found here.\""""
text, _asked = self.line_run(_args(declared_only=False), [])
# The standalone emulators' lists come from the network: none here
# (code_audit_24 P3-13), and none found.
with mock.patch.object(install, "_install_standalone_folders", return_value=False):
text, _asked = self.line_run(_args(declared_only=False), [])
self.assertIn("Looking for setups here...", text)
# Said once, the question alone after it (tui_audit_16 P3-2).
self.assertEqual(text.count("Nothing was found here."), 1)
@@ -9575,10 +9608,11 @@ class AuditSixteenAndNineScreens(unittest.TestCase):
state = checked_state()
state.pad = "miyoo"
state.stack.append("systems")
state.focus["systems"] = 1
state.focus["systems"] = next(i for i, row in enumerate(install.tui_rows(state))
if row.action == "none")
bar = install.tui_view(state, 40, 12)[-1]
self.assertNotIn("A Tick", bar)
state.focus["systems"] = 3
state.focus["systems"] = install._first_item(state)
self.assertIn("A Tick", install.tui_view(state, 40, 12)[-1])
def test_system_given_is_said_and_widened(self):
@@ -9893,9 +9927,10 @@ class AuditEighteenAndEleven(_CardFixtures, unittest.TestCase):
"""P3-11."""
state = checked_state()
state.cli_systems, state.cores, state.regions = ["sony-playstation"], ["x"], ["us"]
state.cli_cores = ["x"]
state.cli_cores, state.cli_regions = ["x"], ["us"]
text = " ".join(" ".join(install.tui_view(state, 120, 40)).split())
self.assertIn("(--system), --core, --region.", text)
# The flag after the words, never alone (tui_audit_17 P3-4).
self.assertIn("(--system), 0 of 1 cores (--core), regions ranked (--region).", text)
def test_pc_and_short_prefixes_find_the_computer_setups(self):
"""P3-17."""
@@ -10311,7 +10346,7 @@ class MouseOnEveryScreen(unittest.TestCase):
self.assertEqual(effects, [])
self.assertEqual(state.stack, base.stack)
again = drawn(state, cols, rows)
self.assertIn(install.TUI_ARMED, str(again[-1]))
self.assertIn(install.TUI_ARMED_SHORT, str(again[-1]))
at = next(first for row, first, _end, mark in state.hits.targets
if mark == target)
effects = tap(state, at, line)
@@ -10712,10 +10747,10 @@ class AuditNineteenAndTwelve(_CardFixtures, unittest.TestCase):
def test_the_help_and_the_bar_say_how_to_tap(self):
state = self.systems_state()
bar = str(install.tui_view(state, 80, 24)[-1])
self.assertIn("X/Space/tap Tick", bar)
self.assertIn("A/Enter/tap Tick", bar)
state.help = True
text = " ".join(" ".join(install.tui_view(state, 80, 24)).split())
self.assertIn("Tap Tick or untick a row, as Space", text)
self.assertIn("Tap Tick or untick a row, as A", text)
self.assertIn("Any key or a tap closes this help", text)
plan = checked_state()
plan.mouse, plan.help = True, True
@@ -10729,7 +10764,7 @@ class AuditNineteenAndTwelve(_CardFixtures, unittest.TestCase):
if row.action == "system")
drawn(state, 80, 24)
ticked = set(state.ticked)
tap(state, bar_line.index("X/Space/tap"), len(lines) - 1)
tap(state, bar_line.index("A/Enter/tap"), len(lines) - 1)
self.assertNotEqual(state.ticked, ticked)
# No mouse, no word of a tap.
plain = checked_state()
@@ -11175,7 +11210,7 @@ class TapsOnAPty(unittest.TestCase):
self.click(term, 20, row)
term.wait("RetroBIOS: Choose systems")
bar = term.settle().splitlines()[-1]
self.assertIn("X/Space/tap Tick", bar)
self.assertIn("A/Enter/tap Tick", bar)
row = self.line_of(term, "sony-playstation")
self.click(term, 20, row)
self.assertIn("[ ] sony-playstation", term.settle())
@@ -11399,8 +11434,9 @@ class AuditTwentyAndThirteen(unittest.TestCase):
values = [row.value for row in install.tui_rows(state) if row.action == "core"]
self.assertEqual(values, ["pcsx_rearmed"])
rows = install.tui_rows(state)
self.assertEqual(rows[-1].label, "Cores of the other systems: 1")
state.focus["cores"] = len(rows) - 1
more = next(i for i, row in enumerate(rows) if row.action == "morecores")
self.assertEqual(rows[more].label, "Cores of the other systems: 1")
state.focus["cores"] = more
install.tui_update(state, Key("enter"))
self.assertEqual([row.value for row in install.tui_rows(state)
if row.action == "core"], ["mesen", "pcsx_rearmed"])
@@ -11556,7 +11592,7 @@ class AuditTwentyAndThirteen(unittest.TestCase):
self.assertIn("? Help", bar)
state.help = True
text = " ".join(" ".join(install.tui_view(state, 40, 12)).split())
self.assertIn("Tap Tick or untick a row, as Space", text)
self.assertIn("Tap Tick or untick a row, as A", text)
def test_one_spelling_of_a_folder_on_the_plan_and_the_result(self):
"""tui_audit_13 P3-3: "/home...i_audit13/rb/bios" on the plan, the
@@ -11950,9 +11986,11 @@ class DoubleTapsAcrossScreens(unittest.TestCase):
slow = self.plan_on("systems")
self.double_tap(slow, install.TUI_TAP_SETTLE + 0.2)
self.assertEqual(once.screen, "systems")
# On Choose systems the first entry goes on to Confirm: the slow
# tap pressed it.
self.assertEqual(slow.screen, "confirm")
# On Choose systems the first entry ticks: the slow tap pressed it
# once more, and the box is back as it was (tui_audit_17 P3-1).
self.assertEqual(slow.screen, "systems")
self.assertEqual(slow.ticked, once.ticked ^ {
install.tui_rows(once)[once.focus["systems"]].value})
def test_a_release_whose_press_came_before_the_frame_does_nothing(self):
state = self.plan_on("systems")
@@ -12020,6 +12058,16 @@ class TwoTapsOnlyWhereFilesAreWritten(unittest.TestCase):
install.tui_update(state, Key("enter"))
self.assertEqual(state.screen, "systems")
lines = drawn(state, 80, 24)
# A tap on the bar's first entry ticks (tui_audit_17 P3-1), B goes
# back, and Install counts the choice on Confirm first.
self.assertEqual(tap(state, 2, len(lines) - 1), [])
self.assertEqual(state.screen, "systems")
lines = drawn(state, 80, 24)
self.assertEqual(tap(state, str(lines[-1]).index("B/Esc"), len(lines) - 1), [])
self.assertEqual(state.screen, "plan")
lines = drawn(state, 80, 24)
state.focus["plan"] = 0
lines = drawn(state, 80, 24)
self.assertEqual(tap(state, 2, len(lines) - 1), [("run", "confirm")])
self.assertEqual(state.screen, "confirm")
install.tui_receive(state, ("event", state.run_id, CHECK))
@@ -12124,10 +12172,20 @@ class TapsOnAPtySeeFirst(unittest.TestCase):
row = self.line_of(term, "sony-playstation")
self.click(term, 20, row)
term.settle()
col, line = self.bar_entry(term, "Continue")
col, line = self.bar_entry(term, "Done")
report = sgr(col + 1, line + 1) + sgr(col + 1, line + 1, release=True)
# A double tap: the first goes back to the plan, the second lands on
# its Back inside the settle time and does nothing (tui_audit_14
# P2-1).
time.sleep(install.TUI_TAP_SETTLE)
term.send(report + report)
screen = term.wait("for 1 of 2 systems")
screen = term.settle(0.6)
self.assertIn("RetroBIOS: RetroArch", screen)
self.assertEqual(repo.installed(), [])
# Install on the plan counts the choice on Confirm, which waits.
col, line = self.bar_entry(term, "Install")
report = sgr(col + 1, line + 1) + sgr(col + 1, line + 1, release=True)
# A double tap: the first opens Confirm, the second lands on its
# Install inside the settle time and does nothing (tui_audit_14 P2-1).
time.sleep(install.TUI_TAP_SETTLE)
term.send(report + report)
term.wait("Counted again for your choices")
@@ -12135,6 +12193,7 @@ class TapsOnAPtySeeFirst(unittest.TestCase):
self.assertIn("RetroBIOS: Confirm", screen)
self.assertEqual(repo.installed(), [])
# A tap made later installs: Confirm is the look before the install.
time.sleep(install.TUI_TAP_SETTLE)
term.send(report)
term.wait("files installed")
self.assertNotEqual(repo.installed(), [])
@@ -12317,7 +12376,9 @@ class AuditTwentyOneAndFourteen(unittest.TestCase):
self.assertNotIn("Run the installer again", text)
state.ticked = {"sony-playstation"}
text = self.screen(state, 100, 40)
self.assertIn("About 0 files, 0 B, for 1 of 3 systems, 3 need the internet", text)
self.assertIn("3 files need the internet, which RETROBIOS_INSTALL_OFFLINE=1 does not "
"use, for 1 of 3 systems", text)
self.assertNotIn("About 0 files", text)
def easyroms(self, name: str = "EASYROMS") -> Path:
"""A handheld's games part as a computer mounts it, with the folders
@@ -12339,15 +12400,14 @@ class AuditTwentyOneAndFourteen(unittest.TestCase):
mock.patch.object(install, "detect_frontends", return_value=[]), \
mock.patch.object(install.Path, "home", return_value=home):
state, _effects = install.tui_start(_args(), "linux")
self.assertEqual(state.unnamed, [card])
text = self.screen(state)
self.assertIn(f"A card is in the reader ({name}): choose its system",
text)
# Named on the first screen, its plan one Enter away
# (tui_audit_17 P2-3).
self.assertIn(f"> ArkOS SD card ({name}", text)
self.assertNotIn("Nothing was found here", text)
install.tui_update(state, Key("enter"))
self.assertEqual(state.screen, "folder")
rows = install.tui_rows(state)
self.assertEqual(rows[0].value, card / "bios")
self.assertEqual(state.dest, card / "bios")
self.assertEqual(state.platform, "retroarch")
install.tui_update(state, Key("enter"))
self.assertEqual(state.dest, card / "bios")
shutil.rmtree(card)
@@ -12618,13 +12678,11 @@ class AuditTwentyOneAndFourteen(unittest.TestCase):
def test_line_mode_puts_the_arkos_card_first(self):
card = self.easyroms()
text, asked = self.line_run(_args(manifest=self.game_listing(), dry_run=True,
declared_only=False), ["1", ""], mounts=[card])
self.assertIn("A card is in the reader (EASYROMS): choose its system.", text)
declared_only=False), [""], mounts=[card])
# Found as the screen finds it, under Enter (tui_audit_17 P2-3).
self.assertIn(f"Found ArkOS at {card / 'bios'} (RetroArch files)", text)
self.assertNotIn("Nothing was found here", text)
self.assertIn(f"The card in the reader keeps BIOS files in its bios folder: "
f"{card / 'bios'}.", text)
self.assertIn(f"1) EASYROMS: bios (SD card, {card / 'bios'})", text)
self.assertIn("Enter for the card's bios folder", asked[-2])
self.assertIn("Enter for ArkOS SD card (EASYROMS)", asked[0])
self.assertIn(f"BIOS folder: {card / 'bios'}", text)
@@ -12680,9 +12738,9 @@ class AuditTwentyTwoAndFifteen(unittest.TestCase):
mounts = [data, stick]
with mock.patch.object(install, "_mounted_cards", return_value=mounts), \
mock.patch.object(install, "_mount_points", return_value=frozenset()):
self.assertEqual(install.unnamed_cards(), [])
self.assertEqual(install.unproven_drives(), [data, stick])
state = self.first_screen(mounts)
self.assertEqual(state.unnamed, [])
self.assertEqual(state.setups, [])
self.assertIn("Nothing was found here", self.screen(state))
state, text, rows = self.folder_screen(mounts)
self.assertNotIn(rows[0].value, (data / "bios", stick / "bios"))
@@ -12713,15 +12771,15 @@ class AuditTwentyTwoAndFifteen(unittest.TestCase):
mounts = [arkos, amber, emuelec]
with mock.patch.object(install, "_mounted_cards", return_value=mounts), \
mock.patch.object(install, "_mount_points", return_value=frozenset()):
self.assertEqual(install.unnamed_cards(), [arkos])
self.assertEqual([install.games_part(mount).name for mount in mounts],
["ArkOS", "AmberELEC", "EmuELEC"])
# The three are their systems' own cards (tui_audit_17 P2-3).
self.assertEqual([install.card_system(mount) for mount in mounts],
[None, ("amberelec", amber, "AmberELEC"),
[("retroarch", arkos / "bios", "ArkOS"),
("amberelec", amber, "AmberELEC"),
("emuelec", emuelec, "EmuELEC")])
# One of these the system calls fixed is a disk, not a card.
with mock.patch.object(install, "_drive_not_removable", return_value=True):
self.assertEqual(install.unnamed_cards(), [])
self.assertEqual([install.card_system(mount) for mount in mounts],
[None, None, None])
@@ -12733,18 +12791,16 @@ class AuditTwentyTwoAndFifteen(unittest.TestCase):
card = games_part(self.root / "media" / "EASYROMS")
mounts = [data, card]
state = self.first_screen(mounts)
self.assertEqual(state.unnamed, [card])
self.assertIn("A card is in the reader (EASYROMS): choose its system", self.screen(state))
state, text, rows = self.folder_screen(mounts)
self.assertEqual(rows[0].value, card / "bios")
self.assertIn(self.UNPROVEN_ONE, text)
# The card is the setup found, under Enter (tui_audit_17 P2-3).
text = self.screen(state)
self.assertIn("> ArkOS SD card (EASYROMS", text)
with mock.patch.object(install, "_mounted_cards", return_value=mounts), \
mock.patch.object(install, "_mount_points", return_value=frozenset()):
install.tui_update(state, Key("enter"))
self.assertEqual(state.dest, card / "bios")
text, asked = self.line_run(_args(manifest=self.game_listing(), dry_run=True,
declared_only=False), ["1", ""], mounts=mounts)
self.assertIn("A card is in the reader (EASYROMS): choose its system.", text)
self.assertIn(f"The card in the reader keeps BIOS files in its bios folder: "
f"{card / 'bios'}.", text)
self.assertIn(f"1) EASYROMS: bios (SD card, {card / 'bios'})", text)
self.assertIn(self.UNPROVEN_ONE, text)
declared_only=False), [""], mounts=mounts)
self.assertIn("Enter for ArkOS SD card (EASYROMS)", asked[0])
self.assertIn(f"BIOS folder: {card / 'bios'}", text)
def test_two_cards_are_spoken_of_in_the_plural(self):
@@ -12754,15 +12810,16 @@ class AuditTwentyTwoAndFifteen(unittest.TestCase):
second = games_part(self.root / "media" / "ROMS2")
mounts = [arkos, second]
state = self.first_screen(mounts)
self.assertIn("Cards are in the reader (EASYROMS, ROMS2): choose their systems",
self.screen(state))
state, text, rows = self.folder_screen(mounts)
self.assertIn("EASYROMS keeps BIOS files in its bios folder, first below.", text)
# Each card its folders prove is a setup found, by its own name
# (tui_audit_17 P2-3).
text = self.screen(state)
self.assertIn("ArkOS SD card (EASYROMS", text)
self.assertIn("ArkOS SD card (ROMS2", text)
text, asked = self.line_run(_args(manifest=self.game_listing(), dry_run=True,
declared_only=False), ["1", ""], mounts=mounts)
self.assertIn("Cards are in the reader (EASYROMS, ROMS2): choose their systems.", text)
self.assertIn(f"EASYROMS keeps BIOS files in its bios folder: {arkos / 'bios'}.", text)
self.assertNotIn("The card in the reader", text)
declared_only=False), [], mounts=mounts)
self.assertIn("ArkOS SD card (EASYROMS)", text)
self.assertIn("ArkOS SD card (ROMS2)", text)
self.assertNotIn("in the reader", text)
def test_a_fixed_partition_is_told_from_a_card(self):
"""code_audit_22 P2-1: every mount under /media and /mnt, and on
@@ -13492,14 +13549,16 @@ class AuditTwentyThreeAndSixteen(unittest.TestCase):
mounts = [*cards, data, music]
with mock.patch.object(install, "_mounted_cards", return_value=mounts), \
mock.patch.object(install, "_mount_points", return_value=frozenset()):
self.assertEqual(install.unnamed_cards(), cards)
self.assertEqual([install.card_system(card) for card in cards],
[("retroarch", card / "bios", "ArkOS") for card in cards])
self.assertEqual([install.games_part(card).name for card in cards],
["ArkOS"] * len(cards))
self.assertIsNone(install.games_part(data))
self.assertIsNone(install.games_part(music))
self.assertEqual(install.unproven_drives(), [data])
with mock.patch.object(install, "_drive_not_removable", return_value=True):
self.assertEqual(install.unnamed_cards(), [])
self.assertEqual([install.card_system(card) for card in cards],
[None] * len(cards))
# Root cause 2: counts and states that tell the truth.
@@ -13747,7 +13806,9 @@ class AuditTwentyThreeAndSixteen(unittest.TestCase):
for cols in (80, 39, 30):
with self.subTest(cols=cols):
with mock.patch.object(install.shutil, "get_terminal_size",
return_value=os.terminal_size((cols, 11))):
return_value=os.terminal_size((cols, 11))), \
mock.patch.object(install, "_install_standalone_folders",
return_value=False):
text, _asked = self.line_run(_args(declared_only=False), [])
block = text.split("Which setup?", 1)[1].split(" q) quit", 1)[0]
lines = [line for line in block.splitlines() if line.strip()]
@@ -13760,27 +13821,29 @@ class AuditTwentyThreeAndSixteen(unittest.TestCase):
def test_on_wsl_the_card_comes_first_in_both_modes(self):
"""code_audit_23 P3-6: line mode numbered Windows RetroArch 1) and
the card 2), where the screen put the card first."""
card = games_part(self.root / "media" / "EASYROMS")
the card 2), where the screen put the card first. One order for
both: the other side first, then the drives (an ArkOS card is now a
setup found, tui_audit_17 P2-3)."""
data = self.drive("DATA", ("bios", "snes"))
windows = Path("/mnt/c/RetroArch-Win64/system")
side = [("Windows RetroArch: C:\\RetroArch-Win64\\system", windows)]
with mock.patch.object(install, "_mounted_cards", return_value=[card]), \
with mock.patch.object(install, "_mounted_cards", return_value=[data]), \
mock.patch.object(install, "_mount_points", return_value=frozenset()), \
mock.patch.object(install, "other_side", return_value=side), \
mock.patch.object(install, "_ask", return_value="q"), \
contextlib.redirect_stdout(io.StringIO()) as out, \
contextlib.suppress(SystemExit):
install.ask_platform_folder("wsl", "retroarch")
state = self.first_screen([card])
self.assertRegex(out.getvalue(), r"\n 1\) EASYROMS: bios \(SD card")
self.assertRegex(out.getvalue(), r"\n 2\) Windows RetroArch")
with mock.patch.object(install, "_mounted_cards", return_value=[card]), \
state = self.first_screen([data])
self.assertRegex(out.getvalue(), r"\n 1\) Windows RetroArch")
self.assertRegex(out.getvalue(), r"\n 2\) DATA: bios \(drive")
with mock.patch.object(install, "_mounted_cards", return_value=[data]), \
mock.patch.object(install, "_mount_points", return_value=frozenset()), \
mock.patch.object(install, "other_side", return_value=side):
state.os_type = "wsl"
install.tui_update(state, Key("enter"))
rows = [row for row in install.tui_rows(state) if row.action == "drive"]
self.assertEqual([row.value for row in rows], [card / "bios", windows])
self.assertEqual([row.value for row in rows], [windows, data / "bios"])
def test_nothing_found_is_said_once(self):
"""tui_audit_16 P3-2: "Nothing was found here." twice, and after "A
@@ -13789,7 +13852,8 @@ class AuditTwentyThreeAndSixteen(unittest.TestCase):
self.assertEqual(text.count("Nothing was found here."), 1)
card = games_part(self.root / "media" / "EASYROMS")
text, _asked = self.line_run(_args(declared_only=False), [], mounts=[card])
self.assertIn("A card is in the reader (EASYROMS): choose its system.", text)
# The card its folders prove is found (tui_audit_17 P2-3).
self.assertIn("ArkOS SD card (EASYROMS)", text)
self.assertNotIn("Nothing was found here", text)
def test_the_bios_only_drive_note_is_one_plain_sentence(self):
@@ -13798,15 +13862,13 @@ class AuditTwentyThreeAndSixteen(unittest.TestCase):
them" after a title."""
data = self.drive("DATA", ("bios", "snes", "Music"))
stick = self.drive("STICK", ("bios",))
card = games_part(self.root / "media" / "EASYROMS")
mounts = [card, data, stick]
mounts = [data, stick]
state, text, rows = self.folder_screen(mounts)
self.assertIn("DATA and STICK have a bios folder but no folder a handheld system "
"writes. Pick one below if your files go there.", text)
self.assertIn("The card in the reader keeps BIOS files in its bios folder", text)
labels = [row.label for row in rows]
self.assertIn("DATA: bios (drive)", labels)
self.assertIn("EASYROMS: bios (SD card)", labels)
self.assertIn("STICK: bios (drive)", labels)
line, _asked = self.line_run(_args(manifest=self.game_listing(), dry_run=True,
declared_only=False), ["1", ""], mounts=mounts)
for said in (text, line):
@@ -13873,7 +13935,7 @@ class AuditTwentyThreeAndSixteen(unittest.TestCase):
at 40x12 dropped the folder "Use this folder" stands for."""
data = self.drive("DATA", ("bios", "snes", "Music"))
stick = self.drive("STICK", ("bios",))
for mounts in ([data, stick], [games_part(self.root / "media" / "EASYROMS"), data]):
for mounts in ([data, stick], [data]):
with self.subTest(mounts=[mount.name for mount in mounts]):
state, _text, _rows = self.folder_screen(mounts)
with mock.patch.object(install, "_mounted_cards", return_value=mounts), \
@@ -13916,7 +13978,7 @@ class AuditTwentyThreeAndSixteen(unittest.TestCase):
press(state, " ")
self.assertEqual(self.boxes(state), {"mesen": "[x]", "pcsx_rearmed": "[x]"})
self.assertEqual(state.cores, [])
press(state, " ", "enter")
press(state, " ", "esc")
self.assertEqual(state.screen, "options")
row = next(row for row in install.tui_rows(state) if row.action == "cores")
self.assertEqual(row.label, "Cores: 1 of 2")
@@ -13929,6 +13991,7 @@ class AuditTwentyThreeAndSixteen(unittest.TestCase):
state.focus["cores"] = next(i for i, row in enumerate(rows) if row.action == "none")
press(state, "enter")
self.assertEqual(self.boxes(state), {"mesen": "[ ]", "pcsx_rearmed": "[ ]"})
state.focus["cores"] = next(i for i, row in enumerate(rows) if row.action == "done")
press(state, "enter")
self.assertEqual(state.screen, "cores")
self.assertIn("No core is ticked", str(state.status))
@@ -13955,7 +14018,7 @@ class AuditTwentyThreeAndSixteen(unittest.TestCase):
self.assertIn("Every core's extra files are kept: Enter keeps them all", text)
head = text.rsplit("Counted again for your choices", 1)[1]
self.assertIn("1 of 2 cores", head)
self.assertEqual(install.cores_words(0, 2), "all cores")
self.assertEqual(install.cores_words(0, 2), "0 of 2 cores")
self.assertEqual(install.cores_words(2, 2), "all cores")
# Root cause 6: the pages say what the installer shows.
@@ -14269,8 +14332,9 @@ class AuditTwentyFourAndSeventeen(unittest.TestCase):
(self.here / "a.bin").write_bytes(payload)
listing = core_list(self.root / "read.json",
[self.entry("a.bin", payload, ["sony-playstation"])])
text, _asked = self.line_run(_args(manifest=listing, dest=self.here,
declared_only=False), [])
with mock.patch.object(install, "_live_stdout", return_value=True):
text, _asked = self.line_run(_args(manifest=listing, dest=self.here,
declared_only=False), [])
self.assertIn("\r read 1/1", text)
self.assertLess(text.index("read 1/1"), text.index("every one in place"))