zapretgui/tests/test_dataclass_json.py
loop-uh a0dc66fdef
All checks were successful
Zapret source guards / validate (push) Successful in 10s
Проверка домена: прошлая проверка открывается теми же карточками, а не сырым текстом
Раньше от прошлой проверки домена сохранялся только текст, и нажатие на
плитку «Прошлых проверок» открывало его страницей-редактором. Пользователь
попросил показывать прошлые проверки так же, как свежие.

- в файл проверки (domain_lookup_*.json) теперь кладётся и сам отчёт, а не
  только его текст;
- общий модуль utils.dataclass_json: отчёт из дата-классов — в JSON и обратно
  в те же дата-классы по объявленным типам полей; неизвестные поля файла
  пропускаются, недостающие берутся по умолчанию;
- нажатие на плитку прошлой проверки показывает её на вкладке теми же
  карточками, с пометкой «Показана прошлая проверка: сайт · время»; кнопка
  «Отчёт» открывает её текст;
- у записей, сохранённых до этой правки, отчёта в файле нет — для них
  остаётся страница с текстом.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 16:10:13 +03:00

62 lines
2.2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Отчёт из дата-классов сохраняется в JSON и возвращается тем же объектом."""
from __future__ import annotations
import json
import unittest
from dataclasses import dataclass
from utils.dataclass_json import from_plain, to_plain
@dataclass(frozen=True, slots=True)
class _Inner:
name: str
values: tuple[int, ...] = ()
@dataclass(frozen=True, slots=True)
class _Outer:
title: str
inner: _Inner | None = None
items: tuple[_Inner, ...] = ()
pair: tuple[str, int] = ("", 0)
pairs: tuple[tuple[str, str], ...] = ()
extra: dict | None = None
score: float | None = None
done: bool = False
class DataclassJsonTests(unittest.TestCase):
def test_nested_report_survives_a_trip_through_json(self) -> None:
report = _Outer(
"отчёт",
inner=_Inner("а", (1, 2)),
items=(_Inner("б"), _Inner("в", (3,))),
pair=("x", 7),
pairs=(("k", "v"),),
extra={"список": [1, 2]},
score=1.5,
done=True,
)
restored = from_plain(_Outer, json.loads(json.dumps(to_plain(report), ensure_ascii=False)))
self.assertEqual(restored, report)
self.assertIsInstance(restored.items[1].values, tuple)
def test_old_and_newer_files_are_read_without_errors(self) -> None:
# Поля, которых программа не знает, пропускаются; недостающие берутся по умолчанию.
restored = from_plain(_Outer, {"title": "старый", "выдумано": 1, "inner": {"name": "а", "лишнее": True}})
self.assertEqual(restored, _Outer("старый", inner=_Inner("а")))
def test_broken_data_gives_nothing_instead_of_an_exception(self) -> None:
self.assertIsNone(from_plain(_Outer, None))
self.assertIsNone(from_plain(_Outer, ["не словарь"]))
# Нет обязательного поля — отчёт не собрать.
self.assertIsNone(from_plain(_Outer, {"done": True}))
self.assertEqual(from_plain(_Outer, {"title": "т", "items": "не список"}).items, ())
if __name__ == "__main__":
unittest.main()