mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-07-04 18:23:07 +02:00
Fix ruff violations in ~15 source files and ~60+ test files to minimize per-file-ignores in pyproject.toml. Remaining ignores are justified with comments explaining why each suppression is necessary. Source fixes: FBT003 (keyword args), S310 (URL validation), SLF001 (private access), T201 (print→logging), C901 (complexity), E501 (line length), E402 (import order). Test fixes: SIM117 (combined with), FBT (boolean args), PERF203 (try in loop), S310/S607 (URLs/executables), E402/E501 (imports/lines), S108 (tmp paths), PLR0913 (too many args), ARG (unused args), ANN (type annotations), RUF059 (unused unpacked vars), PT019 (fixture naming). Remaining per-file-ignores (with justifications): - Tests: ARG, D, PLC0415, PLR2004, S101, SLF001 - music_gen sources: PLC0415 (heavy ML lazy imports) - moviepy_showcase: PLC0415 (circular dependency) - generate_images: PLR0913 (matplotlib helpers need many params) - praca_magisterska_video: E501, E402 (long paths, mpl.use)
348 lines
12 KiB
Python
348 lines
12 KiB
Python
"""Tests for python_pkg.puzzle_solver.main and __main__ modules."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Any
|
|
from unittest.mock import MagicMock, mock_open, patch
|
|
|
|
import pytest
|
|
|
|
from python_pkg.puzzle_solver.main import (
|
|
cmd_debug,
|
|
cmd_parse,
|
|
cmd_run,
|
|
cmd_solve,
|
|
main,
|
|
)
|
|
|
|
|
|
def _minimal_puzzle_data() -> dict[str, Any]:
|
|
return {
|
|
"squares": [
|
|
{"pos": [0, 0], "type": "player"},
|
|
{"pos": [0, 1], "type": "normal"},
|
|
{"pos": [0, 2], "type": "goal"},
|
|
],
|
|
}
|
|
|
|
|
|
# ── cmd_parse ────────────────────────────────────────────────────────
|
|
|
|
|
|
class TestCmdParse:
|
|
@patch("python_pkg.puzzle_solver.main.save_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_with_output(self, mock_parse: MagicMock, mock_save: MagicMock) -> None:
|
|
mock_parse.return_value = {"squares": [], "notes": []}
|
|
args = MagicMock()
|
|
args.image = "test.png"
|
|
args.output = "out.json"
|
|
args.threshold = 55
|
|
cmd_parse(args)
|
|
mock_save.assert_called_once_with({"squares": [], "notes": []}, "out.json")
|
|
|
|
@patch("python_pkg.puzzle_solver.main.save_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_default_output(self, mock_parse: MagicMock, mock_save: MagicMock) -> None:
|
|
mock_parse.return_value = {"squares": [], "notes": []}
|
|
args = MagicMock()
|
|
args.image = "screenshot.png"
|
|
args.output = None
|
|
args.threshold = 55
|
|
cmd_parse(args)
|
|
mock_save.assert_called_once_with(
|
|
{"squares": [], "notes": []}, "screenshot_puzzle.json"
|
|
)
|
|
|
|
@patch("python_pkg.puzzle_solver.main.save_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_with_notes(self, mock_parse: MagicMock, mock_save: MagicMock) -> None:
|
|
mock_parse.return_value = {
|
|
"squares": [],
|
|
"notes": ["note1", "note2"],
|
|
}
|
|
args = MagicMock()
|
|
args.image = "test.png"
|
|
args.output = "out.json"
|
|
args.threshold = 55
|
|
cmd_parse(args)
|
|
|
|
@patch("python_pkg.puzzle_solver.main.save_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_no_notes(self, mock_parse: MagicMock, mock_save: MagicMock) -> None:
|
|
mock_parse.return_value = {"squares": []}
|
|
args = MagicMock()
|
|
args.image = "test.png"
|
|
args.output = "out.json"
|
|
args.threshold = 55
|
|
cmd_parse(args)
|
|
|
|
|
|
# ── cmd_solve ────────────────────────────────────────────────────────
|
|
|
|
|
|
class TestCmdSolve:
|
|
@patch("python_pkg.puzzle_solver.main.print_solution")
|
|
@patch("python_pkg.puzzle_solver.main.solve")
|
|
@patch("python_pkg.puzzle_solver.main.print_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.Puzzle")
|
|
def test_solvable(
|
|
self,
|
|
mock_puzzle_cls: MagicMock,
|
|
mock_print: MagicMock,
|
|
mock_solve: MagicMock,
|
|
mock_print_sol: MagicMock,
|
|
) -> None:
|
|
data = _minimal_puzzle_data()
|
|
m = mock_open(read_data=json.dumps(data))
|
|
mock_puzzle = MagicMock()
|
|
mock_puzzle_cls.from_json.return_value = mock_puzzle
|
|
mock_solve.return_value = ["right"]
|
|
|
|
with patch("pathlib.Path.open", m):
|
|
args = MagicMock()
|
|
args.puzzle = "test.json"
|
|
cmd_solve(args)
|
|
mock_print_sol.assert_called_once()
|
|
|
|
@patch("python_pkg.puzzle_solver.main.solve")
|
|
@patch("python_pkg.puzzle_solver.main.print_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.Puzzle")
|
|
def test_unsolvable(
|
|
self,
|
|
mock_puzzle_cls: MagicMock,
|
|
mock_print: MagicMock,
|
|
mock_solve: MagicMock,
|
|
) -> None:
|
|
data = _minimal_puzzle_data()
|
|
m = mock_open(read_data=json.dumps(data))
|
|
mock_puzzle = MagicMock()
|
|
mock_puzzle_cls.from_json.return_value = mock_puzzle
|
|
mock_solve.return_value = None
|
|
|
|
args = MagicMock()
|
|
args.puzzle = "test.json"
|
|
with patch("pathlib.Path.open", m), pytest.raises(SystemExit):
|
|
cmd_solve(args)
|
|
|
|
|
|
# ── cmd_run ──────────────────────────────────────────────────────────
|
|
|
|
|
|
class TestCmdRun:
|
|
@patch("python_pkg.puzzle_solver.main.print_solution")
|
|
@patch("python_pkg.puzzle_solver.main.solve")
|
|
@patch("python_pkg.puzzle_solver.main.print_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.Puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_solvable(
|
|
self,
|
|
mock_parse: MagicMock,
|
|
mock_puzzle_cls: MagicMock,
|
|
mock_print: MagicMock,
|
|
mock_solve: MagicMock,
|
|
mock_print_sol: MagicMock,
|
|
) -> None:
|
|
mock_parse.return_value = _minimal_puzzle_data()
|
|
mock_puzzle = MagicMock()
|
|
mock_puzzle_cls.from_json.return_value = mock_puzzle
|
|
mock_solve.return_value = ["right"]
|
|
|
|
args = MagicMock()
|
|
args.image = "test.png"
|
|
args.threshold = 55
|
|
cmd_run(args)
|
|
mock_print_sol.assert_called_once()
|
|
|
|
@patch("python_pkg.puzzle_solver.main.save_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.solve")
|
|
@patch("python_pkg.puzzle_solver.main.print_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.Puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_unsolvable(
|
|
self,
|
|
mock_parse: MagicMock,
|
|
mock_puzzle_cls: MagicMock,
|
|
mock_print: MagicMock,
|
|
mock_solve: MagicMock,
|
|
mock_save: MagicMock,
|
|
) -> None:
|
|
mock_parse.return_value = _minimal_puzzle_data()
|
|
mock_puzzle = MagicMock()
|
|
mock_puzzle_cls.from_json.return_value = mock_puzzle
|
|
mock_solve.return_value = None
|
|
|
|
args = MagicMock()
|
|
args.image = "test.png"
|
|
args.threshold = 55
|
|
with pytest.raises(SystemExit):
|
|
cmd_run(args)
|
|
mock_save.assert_called_once()
|
|
|
|
@patch("python_pkg.puzzle_solver.main.print_solution")
|
|
@patch("python_pkg.puzzle_solver.main.solve")
|
|
@patch("python_pkg.puzzle_solver.main.print_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.Puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_with_notes(
|
|
self,
|
|
mock_parse: MagicMock,
|
|
mock_puzzle_cls: MagicMock,
|
|
mock_print: MagicMock,
|
|
mock_solve: MagicMock,
|
|
mock_print_sol: MagicMock,
|
|
) -> None:
|
|
data = _minimal_puzzle_data()
|
|
data["notes"] = ["note1"]
|
|
mock_parse.return_value = data
|
|
mock_puzzle = MagicMock()
|
|
mock_puzzle_cls.from_json.return_value = mock_puzzle
|
|
mock_solve.return_value = ["right"]
|
|
|
|
args = MagicMock()
|
|
args.image = "test.png"
|
|
args.threshold = 55
|
|
cmd_run(args)
|
|
|
|
@patch("python_pkg.puzzle_solver.main.print_solution")
|
|
@patch("python_pkg.puzzle_solver.main.solve")
|
|
@patch("python_pkg.puzzle_solver.main.print_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.Puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_no_notes_key(
|
|
self,
|
|
mock_parse: MagicMock,
|
|
mock_puzzle_cls: MagicMock,
|
|
mock_print: MagicMock,
|
|
mock_solve: MagicMock,
|
|
mock_print_sol: MagicMock,
|
|
) -> None:
|
|
data = _minimal_puzzle_data()
|
|
# no "notes" key at all
|
|
mock_parse.return_value = data
|
|
mock_puzzle = MagicMock()
|
|
mock_puzzle_cls.from_json.return_value = mock_puzzle
|
|
mock_solve.return_value = ["right"]
|
|
|
|
args = MagicMock()
|
|
args.image = "test.png"
|
|
args.threshold = 55
|
|
cmd_run(args)
|
|
|
|
|
|
# ── cmd_debug ────────────────────────────────────────────────────────
|
|
|
|
|
|
class TestCmdDebug:
|
|
@patch("python_pkg.puzzle_solver.main.draw_debug")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_with_output(self, mock_parse: MagicMock, mock_draw: MagicMock) -> None:
|
|
mock_parse.return_value = {
|
|
"squares": [
|
|
{"type": "normal"},
|
|
{"type": "normal"},
|
|
{"type": "goal"},
|
|
],
|
|
}
|
|
args = MagicMock()
|
|
args.image = "test.png"
|
|
args.output = "debug.png"
|
|
args.threshold = 55
|
|
cmd_debug(args)
|
|
mock_draw.assert_called_once_with(
|
|
"test.png", mock_parse.return_value, "debug.png"
|
|
)
|
|
|
|
@patch("python_pkg.puzzle_solver.main.draw_debug")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_default_output(self, mock_parse: MagicMock, mock_draw: MagicMock) -> None:
|
|
mock_parse.return_value = {
|
|
"squares": [{"type": "normal"}],
|
|
}
|
|
args = MagicMock()
|
|
args.image = "screenshot.png"
|
|
args.output = None
|
|
args.threshold = 55
|
|
cmd_debug(args)
|
|
mock_draw.assert_called_once_with(
|
|
"screenshot.png", mock_parse.return_value, "screenshot_debug.png"
|
|
)
|
|
|
|
|
|
# ── main ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
class TestMain:
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
@patch("python_pkg.puzzle_solver.main.save_puzzle")
|
|
def test_parse_command(self, mock_save: MagicMock, mock_parse: MagicMock) -> None:
|
|
mock_parse.return_value = {"squares": [], "notes": []}
|
|
with patch("sys.argv", ["prog", "parse", "img.png", "-o", "out.json"]):
|
|
main()
|
|
|
|
@patch("python_pkg.puzzle_solver.main.print_solution")
|
|
@patch("python_pkg.puzzle_solver.main.solve")
|
|
@patch("python_pkg.puzzle_solver.main.print_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.Puzzle")
|
|
def test_solve_command(
|
|
self,
|
|
mock_puzzle_cls: MagicMock,
|
|
mock_print: MagicMock,
|
|
mock_solve: MagicMock,
|
|
mock_print_sol: MagicMock,
|
|
) -> None:
|
|
data = _minimal_puzzle_data()
|
|
m = mock_open(read_data=json.dumps(data))
|
|
mock_puzzle = MagicMock()
|
|
mock_puzzle_cls.from_json.return_value = mock_puzzle
|
|
mock_solve.return_value = ["right"]
|
|
|
|
with (
|
|
patch("pathlib.Path.open", m),
|
|
patch("sys.argv", ["prog", "solve", "puzzle.json"]),
|
|
):
|
|
main()
|
|
|
|
@patch("python_pkg.puzzle_solver.main.print_solution")
|
|
@patch("python_pkg.puzzle_solver.main.solve")
|
|
@patch("python_pkg.puzzle_solver.main.print_puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.Puzzle")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_run_command(
|
|
self,
|
|
mock_parse: MagicMock,
|
|
mock_puzzle_cls: MagicMock,
|
|
mock_print: MagicMock,
|
|
mock_solve: MagicMock,
|
|
mock_print_sol: MagicMock,
|
|
) -> None:
|
|
mock_parse.return_value = _minimal_puzzle_data()
|
|
mock_puzzle = MagicMock()
|
|
mock_puzzle_cls.from_json.return_value = mock_puzzle
|
|
mock_solve.return_value = ["right"]
|
|
|
|
with patch("sys.argv", ["prog", "run", "img.png"]):
|
|
main()
|
|
|
|
@patch("python_pkg.puzzle_solver.main.draw_debug")
|
|
@patch("python_pkg.puzzle_solver.main.parse_image")
|
|
def test_debug_command(self, mock_parse: MagicMock, mock_draw: MagicMock) -> None:
|
|
mock_parse.return_value = {"squares": [{"type": "normal"}]}
|
|
with patch("sys.argv", ["prog", "debug", "img.png", "-o", "d.png"]):
|
|
main()
|
|
|
|
|
|
# ── __main__.py ──────────────────────────────────────────────────────
|
|
|
|
|
|
class TestDunderMain:
|
|
@patch("python_pkg.puzzle_solver.main.main")
|
|
def test_main_called(self, mock_main: MagicMock) -> None:
|
|
import importlib
|
|
|
|
import python_pkg.puzzle_solver.__main__ as mod
|
|
|
|
importlib.reload(mod)
|
|
mock_main.assert_called()
|