zapretgui/tests/test_theme_paint_caches.py
loop-uh 008b25004c
All checks were successful
Zapret source guards / validate (push) Successful in 8s
Windows-сборка / Dev Dev 21.1.7.56 опубликован
Список стратегий: вдвое легче отрисовка, значки нарисованы заново, перебор идёт по всему каталогу
Ошибка выпуска 21.1.7.54: значок «не пробовал» был взят из набора fa5,
которого нет в сборке (кладутся только fa5s и fa5b) — у плиток не было
значков. На Linux есть все наборы, поэтому при проверке он рисовался.

Нагрузка на процессор:
- кадр списка на Windows 9,3 мс вместо 16,9: цвета темы, шрифты и их мерки
  собираются один раз на кадр, а не на каждую плитку; значок — готовая картинка;
- ui.theme.to_qcolor запоминает разобранные цвета: строки с цветами темы
  разбирались регулярным выражением тысячи раз за кадр по всей программе;
- кэш значков запоминает неудачу: отсутствующий значок больше не проходит
  всю загрузку при каждой перерисовке, в журнал о нём пишется один раз;
- подсчёт частоты по готовым пресетам ищет стратегию по словарю (0,38 с
  вместо 0,61) и делается заранее, в фоновом прогреве после запуска.

Значки плиток нарисованы линиями (profile/ui/strategy_list/icons.py): способ
обхода в цветной подложке, в углу — оценка человека. От шрифтов значков
не зависят.

Перебор «Не работает — следующая» не кончается на советуемых: дальше идут
стратегии, стоящие в готовых пресетах на других сервисах, затем остальные
с чередованием способов обхода.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 23:28:25 +03:00

68 lines
2.7 KiB
Python

"""Общие кэши отрисовки: разбор цветов темы и значки, которые не удалось нарисовать."""
from __future__ import annotations
import os
import sys
import unittest
from pathlib import Path
from unittest.mock import patch
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from PyQt6.QtGui import QColor
from PyQt6.QtWidgets import QApplication
from ui import theme
class ColorCacheTests(unittest.TestCase):
def test_same_text_is_parsed_once(self) -> None:
theme._QCOLOR_TEXT_CACHE.clear()
with patch.object(theme, "_parse_color_text", wraps=theme._parse_color_text) as parse:
first = theme.to_qcolor("rgba(10, 20, 30, 0.5)")
second = theme.to_qcolor("rgba(10, 20, 30, 0.5)")
self.assertEqual(parse.call_count, 1)
self.assertEqual((first.red(), first.green(), first.blue(), first.alpha()), (10, 20, 30, 128))
self.assertEqual(first, second)
def test_caller_may_change_returned_color_without_spoiling_the_cache(self) -> None:
first = theme.to_qcolor("#102030")
first.setAlpha(5)
self.assertEqual(theme.to_qcolor("#102030").alpha(), 255)
def test_qcolor_argument_is_copied_and_bad_text_falls_back(self) -> None:
source = QColor(1, 2, 3)
result = theme.to_qcolor(source)
result.setAlpha(9)
self.assertEqual(source.alpha(), 255)
self.assertEqual(theme.to_qcolor("not a color", "#ff0000"), QColor("#ff0000"))
self.assertEqual(theme.to_qcolor("not a color", "also bad"), QColor(0, 0, 0))
self.assertEqual(theme.to_qcolor(""), QColor(0, 0, 0))
class FailedIconCacheTests(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
cls._app = QApplication.instance() or QApplication([])
def test_icon_that_cannot_be_rendered_is_tried_once(self) -> None:
"""Строка списка рисуется десятки раз в секунду: отсутствующий значок
не должен каждый раз заново проходить всю загрузку."""
theme._QTA_PIXMAP_CACHE.clear()
theme._QTA_FAILED_ICONS.clear()
with patch.object(theme, "_render_qta_pixmap", side_effect=RuntimeError("нет шрифта")) as render:
results = [theme.get_cached_qta_pixmap("zz.missing", color="#ffffff", size=14) for _ in range(5)]
self.assertEqual(render.call_count, 1)
self.assertTrue(all(pixmap.isNull() for pixmap in results))
self.assertIn("zz.missing", theme._QTA_FAILED_ICONS)
theme._QTA_PIXMAP_CACHE.clear()
if __name__ == "__main__":
unittest.main()