ace76183e5
Testy / Testy warstwy logicznej (silnik) (push) Successful in 10m56s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m43s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 30s
Testy / Kontrola składni wszystkich warstw (push) Successful in 19s
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m55s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m43s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 37s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 21s
Warunek wstępny pod kosmogram (PRE-12): planety i znaki na kole rysujemy symbolami. Nowy moduł engine/glyphs.py: - forward: nazwa → glif (planety, punkty, Loty, znaki, aspekty, retro ℞), - reverse: glif → nazwa (znosi obecność/brak selektora wariantu), - glyphify(): tokeny [XX z bazy → glify; przyklad z wymagan „[Sa [Pis 26°08' [conj [PF" → „♄ ♓ 26°08' ☌ ⊗" (stopnie nietkniete). DAN-18 „tylko tekst, nigdy emoji" potraktowane serio, TRZEMA warstwami — bo sam selektor NIE wystarcza (potwierdzone wizualnie w przegladarce): 1. w danych: selektor wariantu tekstowego U+FE0E na znakach zodiaku oraz ♀/♂ (maja wariant emoji); ☉ i reszta go nie dostaja (zbedny), 2. CSS font-variant-emoji:text, 3. CSS font-family celujacy w MONOCHROMATYCZNE fonty symboli PRZED emoji. Bez pkt. 3 macOS/Chromium i tak renderowal znaki ♈–♓ jako kolorowe kafelki Apple Color Emoji mimo VS15 — planety wychodzily tekstem, znaki nie. Stack „Apple Symbols / Segoe UI Symbol / Noto Sans Symbols2" naprawia render. NIGDZIE nie emitujemy U+FE0F (emoji) — pilnuje tego test. Wpiete w build_chart: kazda pozycja dostaje glyph (planeta) + sign_glyph (znak, zalezny od zodiaku, wiec po przesunieciu), osie i Loty tak samo (Fortuna ⊗, reszta Lotow bez standardowego symbolu → None), aspekty dostaja glif, result[„sign_glyphs"] to pierscien 12 znakow pod kolo. UI: kolumna „Sym." w tabeli pozycji (planeta + znak) i symbol przy aspekcie. Testy: 14 (kompletnosc — kazdy obiekt/znak/aspekt ma glif; dwukierunkowosc; DAN-18 brak FE0F, znaki maja VS15, ☉ nie; przyklad glyphify z wymagan). Calosc: logika 265 passed / 1 skipped, prezentacja 25. Render znakow potwierdzony wizualnie (czarno-biale symbole, nie emoji). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
115 lines
4.0 KiB
Python
115 lines
4.0 KiB
Python
"""Konwersja tekst ↔ symbol astrologiczny (LOG-22).
|
||
|
||
Sedno: glify muszą być KOMPLETNE (każdy obiekt/znak/aspekt, który liczymy, ma
|
||
symbol), DWUKIERUNKOWE (symbol → tekst z powrotem) i TEKSTOWE, nigdy emoji
|
||
(DAN-18) — inaczej na kosmogramie wyjdą kolorowe kwadraty zamiast czarno-białych
|
||
symboli.
|
||
"""
|
||
import pytest
|
||
|
||
from app.engine import glyphs as G
|
||
from app.engine.aspects import MAJOR
|
||
from app.engine.formats import SIGNS
|
||
from app.engine.models import DEFAULT_OBJECTS
|
||
|
||
VS15, VS16 = "︎", "️"
|
||
|
||
|
||
def _all_glyphs():
|
||
return (list(G.PLANET.values()) + list(G.POINT.values()) + list(G.LOT.values())
|
||
+ list(G.SIGN.values()) + list(G.ASPECT.values()) + [G.RETROGRADE])
|
||
|
||
|
||
# ------------------------------------------------------------- kompletność
|
||
|
||
def test_every_default_object_has_a_glyph():
|
||
"""Każdy obiekt z kanonicznego zestawu musi mieć symbol — inaczej na kole
|
||
zostanie dziura."""
|
||
missing = [name for name in DEFAULT_OBJECTS if G.glyph_for(name) is None]
|
||
assert not missing, f"obiekty bez glifu: {missing}"
|
||
|
||
|
||
def test_every_sign_has_a_glyph():
|
||
missing = [s for s in SIGNS if G.sign_glyph(s) is None]
|
||
assert not missing, f"znaki bez glifu: {missing}"
|
||
|
||
|
||
def test_every_major_aspect_has_a_glyph():
|
||
missing = [a for a in MAJOR if G.aspect_glyph(a) is None]
|
||
assert not missing, f"aspekty główne bez glifu: {missing}"
|
||
|
||
|
||
def test_fortune_and_retrograde_from_requirement():
|
||
"""Wymóg wprost wymienia ⊗ (Fortuna) i ℞ (retrogradacja)."""
|
||
assert G.glyph_for("Fortune") == "⊗"
|
||
assert G.RETROGRADE == "℞"
|
||
|
||
|
||
# ------------------------------------------------------ DAN-18: tekst, nie emoji
|
||
|
||
def test_no_glyph_uses_emoji_variation_selector():
|
||
"""VS16 (U+FE0F) wymusiłby prezentację emoji — nie może go być NIGDZIE."""
|
||
offenders = [g for g in _all_glyphs() if VS16 in g]
|
||
assert not offenders, f"glify z wariantem emoji (FE0F): {offenders!r}"
|
||
|
||
|
||
def test_signs_force_text_presentation():
|
||
"""Znaki zodiaku mają domyślnie wariant emoji → MUSZĄ nieść VS15."""
|
||
for s in SIGNS:
|
||
assert VS15 in G.sign_glyph(s), f"{s} bez wymuszenia tekstu (VS15)"
|
||
|
||
|
||
def test_venus_mars_force_text_but_sun_does_not():
|
||
"""♀/♂ mają wariant emoji (VS15 konieczny); ☉ nie ma (VS15 zbędny)."""
|
||
assert VS15 in G.glyph_for("Venus")
|
||
assert VS15 in G.glyph_for("Mars")
|
||
assert VS15 not in G.glyph_for("Sun") # bez zaśmiecania niepotrzebnym selektorem
|
||
|
||
|
||
# ---------------------------------------------------------- dwukierunkowość
|
||
|
||
def test_object_round_trip():
|
||
for name in DEFAULT_OBJECTS:
|
||
assert G.name_for_glyph(G.glyph_for(name)) == name
|
||
|
||
|
||
def test_sign_round_trip():
|
||
for s in SIGNS:
|
||
assert G.sign_for_glyph(G.sign_glyph(s)) == s
|
||
|
||
|
||
def test_aspect_round_trip():
|
||
for a in MAJOR:
|
||
assert G.aspect_for_glyph(G.aspect_glyph(a)) == a
|
||
|
||
|
||
def test_reverse_tolerates_missing_variant_selector():
|
||
"""Symbol wklejony bez VS15 też musi się rozpoznać — bo z zewnątrz przyjdzie
|
||
dowolna forma (DAN-17: łańcuch znosi każdy Unicode)."""
|
||
assert G.sign_for_glyph("♓") == "Pisces" # ♓ bez VS15
|
||
assert G.sign_for_glyph("♓" + VS15) == "Pisces" # ♓ z VS15
|
||
assert G.name_for_glyph("♀") == "Venus" # ♀ bez VS15
|
||
|
||
|
||
# --------------------------------------------------------- glifikacja tekstu
|
||
|
||
def test_glyphify_matches_requirement_example():
|
||
"""Przykład z wymagań: [Sa [Pis 26°08' [conj [PF -> ♄ ♓ 26°08' ☌ ⊗."""
|
||
out = G.glyphify("[Sa [Pis 26°08' [conj [PF")
|
||
assert G.glyph_for("Saturn") in out
|
||
assert G.sign_glyph("Pisces") in out
|
||
assert G.aspect_glyph("conjunction") in out
|
||
assert G.glyph_for("Fortune") in out
|
||
assert "26°08'" in out # stopnie nietknięte
|
||
|
||
|
||
def test_glyphify_handles_retrograde_and_leaves_unknown():
|
||
out = G.glyphify("[Ma Rx w [Xyz")
|
||
assert G.glyph_for("Mars") in out
|
||
assert G.RETROGRADE in out
|
||
assert "[Xyz" in out # nieznany token bez zmian
|
||
|
||
|
||
def test_glyphify_empty_is_safe():
|
||
assert G.glyphify("") == ""
|