f
This commit is contained in:
@@ -3,19 +3,41 @@
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from src.tarot.attributes import (
|
||||
Month, Day, Weekday, Hour, ClockHour, Zodiac, Suit, Meaning, Letter, Sephera, Degree, Element,
|
||||
AstrologicalInfluence, TreeOfLife, Correspondences, CardImage,
|
||||
EnglishAlphabet, GreekAlphabet, HebrewAlphabet, Number, Color, Planet, God,
|
||||
Cipher, CipherResult,
|
||||
AstrologicalInfluence,
|
||||
CardImage,
|
||||
Cipher,
|
||||
CipherResult,
|
||||
ClockHour,
|
||||
Color,
|
||||
Correspondences,
|
||||
Day,
|
||||
Degree,
|
||||
Element,
|
||||
EnglishAlphabet,
|
||||
God,
|
||||
GreekAlphabet,
|
||||
HebrewAlphabet,
|
||||
Hour,
|
||||
Letter,
|
||||
Meaning,
|
||||
Month,
|
||||
Number,
|
||||
Planet,
|
||||
Sephera,
|
||||
Suit,
|
||||
TreeOfLife,
|
||||
Weekday,
|
||||
Zodiac,
|
||||
)
|
||||
from src.tarot.card.data import CardDataLoader, calculate_digital_root
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Basic Attribute Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class TestMonth:
|
||||
def test_month_creation(self):
|
||||
month = Month(1, "January", "Capricorn", "Aquarius")
|
||||
@@ -24,10 +46,7 @@ class TestMonth:
|
||||
assert month.zodiac_start == "Capricorn"
|
||||
|
||||
def test_month_all_months(self):
|
||||
months = [
|
||||
Month(i, f"Month_{i}", "Sign_1", "Sign_2")
|
||||
for i in range(1, 13)
|
||||
]
|
||||
months = [Month(i, f"Month_{i}", "Sign_1", "Sign_2") for i in range(1, 13)]
|
||||
assert len(months) == 12
|
||||
assert months[0].number == 1
|
||||
assert months[11].number == 12
|
||||
@@ -41,10 +60,7 @@ class TestDay:
|
||||
assert day.planetary_correspondence == "Sun"
|
||||
|
||||
def test_all_weekdays(self):
|
||||
days = [
|
||||
Day(i, f"Day_{i}", f"Planet_{i}")
|
||||
for i in range(1, 8)
|
||||
]
|
||||
days = [Day(i, f"Day_{i}", f"Planet_{i}") for i in range(1, 8)]
|
||||
assert len(days) == 7
|
||||
|
||||
|
||||
@@ -99,6 +115,7 @@ class TestMeaning:
|
||||
# Sepheric Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class TestSephera:
|
||||
def test_sephera_creation(self):
|
||||
sephera = Sephera(1, "Kether", "כתר", "Crown", "Metatron", "Chaioth", "Primum")
|
||||
@@ -118,6 +135,7 @@ class TestSephera:
|
||||
# Alphabet Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class TestEnglishAlphabet:
|
||||
def test_english_letter_creation(self):
|
||||
letter = EnglishAlphabet("A", 1, "ay")
|
||||
@@ -189,6 +207,7 @@ class TestHebrewAlphabet:
|
||||
# Number Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class TestNumber:
|
||||
def test_number_creation(self):
|
||||
num = Number(1, "Kether", "Spirit", 0) # compliment is auto-calculated
|
||||
@@ -220,6 +239,7 @@ class TestNumber:
|
||||
# Color Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class TestColor:
|
||||
def test_color_creation(self):
|
||||
color = Color("Red", "#FF0000", (255, 0, 0), "Gevurah", 5, "Fire", "Briah", "Power")
|
||||
@@ -248,7 +268,9 @@ class TestColor:
|
||||
for r in [0, 128, 255]:
|
||||
for g in [0, 128, 255]:
|
||||
for b in [0, 128, 255]:
|
||||
color = Color("Test", "#000000", (r, g, b), "Sephera", 1, "Element", "Scale", "Meaning")
|
||||
color = Color(
|
||||
"Test", "#000000", (r, g, b), "Sephera", 1, "Element", "Scale", "Meaning"
|
||||
)
|
||||
assert color.rgb == (r, g, b)
|
||||
|
||||
|
||||
@@ -260,7 +282,9 @@ class TestColor:
|
||||
class TestPlanet:
|
||||
def test_planet_creation(self):
|
||||
number = Number(6, "Tiphareth", "Fire", 0)
|
||||
color = Color("Gold", "#FFD700", (255, 215, 0), "Tiphareth", 6, "Fire", "Yetzirah", "Beauty")
|
||||
color = Color(
|
||||
"Gold", "#FFD700", (255, 215, 0), "Tiphareth", 6, "Fire", "Yetzirah", "Beauty"
|
||||
)
|
||||
planet = Planet(
|
||||
name="Sun",
|
||||
symbol="☉",
|
||||
@@ -342,6 +366,7 @@ class TestGod:
|
||||
# Cipher Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class TestCipher:
|
||||
def test_cipher_mapping_basic(self):
|
||||
cipher = Cipher("Test", "test", [1, 2, 3])
|
||||
@@ -374,6 +399,7 @@ class TestCipherResult:
|
||||
# Digital Root Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class TestDigitalRoot:
|
||||
def test_digital_root_single_digit(self):
|
||||
"""Single digits should return themselves."""
|
||||
@@ -389,7 +415,7 @@ class TestDigitalRoot:
|
||||
|
||||
def test_digital_root_large_numbers(self):
|
||||
"""Test large numbers."""
|
||||
assert calculate_digital_root(99) == 9 # 9+9 = 18, 1+8 = 9
|
||||
assert calculate_digital_root(99) == 9 # 9+9 = 18, 1+8 = 9
|
||||
assert calculate_digital_root(100) == 1 # 1+0+0 = 1
|
||||
assert calculate_digital_root(123) == 6 # 1+2+3 = 6
|
||||
|
||||
@@ -398,13 +424,13 @@ class TestDigitalRoot:
|
||||
# Major Arcana cards 0-21
|
||||
assert calculate_digital_root(14) == 5 # Card 14 (Temperance) -> 5
|
||||
assert calculate_digital_root(21) == 3 # Card 21 (The World) -> 3
|
||||
assert calculate_digital_root(1) == 1 # Card 1 (Magician) -> 1
|
||||
assert calculate_digital_root(1) == 1 # Card 1 (Magician) -> 1
|
||||
|
||||
def test_digital_root_invalid_input(self):
|
||||
"""Test that invalid inputs raise errors."""
|
||||
with pytest.raises(ValueError):
|
||||
calculate_digital_root(0)
|
||||
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
calculate_digital_root(-5)
|
||||
|
||||
@@ -413,6 +439,7 @@ class TestDigitalRoot:
|
||||
# CardDataLoader Tests
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class TestCardDataLoader:
|
||||
@pytest.fixture
|
||||
def loader(self):
|
||||
@@ -443,33 +470,35 @@ class TestCardDataLoader:
|
||||
sephera = loader.sephera(i)
|
||||
assert sephera is not None
|
||||
assert sephera.number == i
|
||||
|
||||
|
||||
def test_load_ciphers(self, loader):
|
||||
"""Ensure cipher catalog is populated."""
|
||||
ciphers = loader.cipher()
|
||||
assert "english_simple" in ciphers
|
||||
assert ciphers["english_simple"].default_alphabet == "english"
|
||||
|
||||
|
||||
def test_word_cipher_request(self, loader):
|
||||
"""word().cipher() should return meaningful totals."""
|
||||
result = loader.word("tarot").cipher("english_simple")
|
||||
assert isinstance(result, CipherResult)
|
||||
assert result.total == 74
|
||||
assert result.alphabet_name == "english"
|
||||
|
||||
|
||||
def test_word_cipher_custom_alphabet(self, loader):
|
||||
result = loader.word("אמש").cipher("kabbalah_three_mother")
|
||||
assert result.values == (1, 40, 300)
|
||||
|
||||
def test_trigram_line_diagram(self, loader):
|
||||
from letter import trigram
|
||||
|
||||
tri = trigram.trigram.name("Zhen") # Thunder
|
||||
assert tri is not None
|
||||
assert tri.data.line_diagram == "|::"
|
||||
|
||||
def test_hexagram_line_diagram(self, loader):
|
||||
from letter import hexagram
|
||||
hex_result = hexagram.hexagram.filter('number:1').first()
|
||||
|
||||
hex_result = hexagram.hexagram.filter("number:1").first()
|
||||
assert hex_result is not None
|
||||
assert hex_result.data.line_diagram == "||||||"
|
||||
|
||||
@@ -575,7 +604,7 @@ class TestCardDataLoader:
|
||||
assert "english" in alphabets
|
||||
assert "greek" in alphabets
|
||||
assert "hebrew" in alphabets
|
||||
|
||||
|
||||
assert len(alphabets["english"]) == 26
|
||||
assert len(alphabets["greek"]) == 24
|
||||
assert len(alphabets["hebrew"]) == 22
|
||||
@@ -592,16 +621,16 @@ class TestCardDataLoader:
|
||||
|
||||
class TestDigitalRootIntegration:
|
||||
"""Integration tests for digital root with Tarot cards."""
|
||||
|
||||
|
||||
def test_all_major_arcana_digital_roots(self):
|
||||
"""Test digital root for all Major Arcana cards (0-21)."""
|
||||
loader = CardDataLoader()
|
||||
|
||||
|
||||
# All Major Arcana cards should map to colors 1-9
|
||||
for card_num in range(22):
|
||||
if card_num == 0:
|
||||
continue # Skip The Fool (0)
|
||||
|
||||
|
||||
color = loader.color_by_number(card_num)
|
||||
assert color is not None
|
||||
assert 1 <= color.number <= 9
|
||||
@@ -609,7 +638,7 @@ class TestDigitalRootIntegration:
|
||||
def test_color_consistency(self):
|
||||
"""Test that equivalent numbers map to same color."""
|
||||
loader = CardDataLoader()
|
||||
|
||||
|
||||
# 5 and 14 should map to same color (both have digital root 5)
|
||||
color_5 = loader.color_by_number(5)
|
||||
color_14 = loader.color_by_number(14)
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
import pytest
|
||||
from tarot.ui import CardDisplay
|
||||
from tarot.deck import Card
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from tarot.deck import Card
|
||||
from tarot.ui import CardDisplay
|
||||
|
||||
|
||||
def test_card_display_delegation():
|
||||
"""Test that CardDisplay delegates to SpreadDisplay correctly."""
|
||||
with patch('tarot.ui.SpreadDisplay') as MockSpreadDisplay:
|
||||
with patch("tarot.ui.SpreadDisplay") as MockSpreadDisplay:
|
||||
# Mock HAS_PILLOW to True to ensure we proceed
|
||||
with patch('tarot.ui.HAS_PILLOW', True):
|
||||
with patch("tarot.ui.HAS_PILLOW", True):
|
||||
display = CardDisplay()
|
||||
|
||||
|
||||
# Create dummy card
|
||||
card = MagicMock(spec=Card)
|
||||
card.name = "The Fool"
|
||||
card.image_path = "fool.jpg"
|
||||
cards = [card]
|
||||
|
||||
|
||||
display.show_cards(cards, title="Test Spread")
|
||||
|
||||
|
||||
# Verify SpreadDisplay was instantiated
|
||||
assert MockSpreadDisplay.call_count == 1
|
||||
|
||||
|
||||
# Verify run was called
|
||||
MockSpreadDisplay.return_value.run.assert_called_once()
|
||||
|
||||
|
||||
# Verify arguments passed to SpreadDisplay
|
||||
args, _ = MockSpreadDisplay.call_args
|
||||
reading = args[0]
|
||||
deck_name = args[1]
|
||||
|
||||
|
||||
assert deck_name == "default"
|
||||
assert reading.spread.name == "Card List"
|
||||
assert reading.spread.description == "Test Spread"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import pytest
|
||||
from tarot.ui import CubeDisplay
|
||||
|
||||
from tarot.tarot_api import Tarot
|
||||
from tarot.ui import CubeDisplay
|
||||
|
||||
|
||||
def test_cube_display_init():
|
||||
cube = Tarot.cube
|
||||
@@ -8,38 +10,40 @@ def test_cube_display_init():
|
||||
assert display.current_wall_name == "North"
|
||||
assert display.deck_name == "default"
|
||||
|
||||
|
||||
def test_cube_navigation():
|
||||
cube = Tarot.cube
|
||||
display = CubeDisplay(cube)
|
||||
|
||||
|
||||
# North -> Right -> East
|
||||
display._navigate("Right")
|
||||
assert display.current_wall_name == "East"
|
||||
|
||||
|
||||
# East -> Up -> Above
|
||||
display._navigate("Up")
|
||||
assert display.current_wall_name == "Above"
|
||||
|
||||
|
||||
# Above -> Down -> North
|
||||
display._navigate("Down")
|
||||
assert display.current_wall_name == "North"
|
||||
|
||||
|
||||
# North -> Left -> West
|
||||
display._navigate("Left")
|
||||
assert display.current_wall_name == "West"
|
||||
|
||||
|
||||
def test_find_card_for_direction():
|
||||
cube = Tarot.cube
|
||||
display = CubeDisplay(cube)
|
||||
|
||||
|
||||
# North Wall, Center Direction -> Aleph -> The Fool
|
||||
wall = cube.wall("North")
|
||||
direction = wall.direction("Center") # Should be Aleph?
|
||||
direction = wall.direction("Center") # Should be Aleph?
|
||||
# Wait, let's check what Center of North is.
|
||||
# Actually, let's just mock a direction
|
||||
|
||||
|
||||
from kaballah.cube.attributes import WallDirection
|
||||
|
||||
|
||||
# Aleph -> The Fool
|
||||
d = WallDirection("Center", "Aleph")
|
||||
card = display._find_card_for_direction(d)
|
||||
|
||||
@@ -1,27 +1,30 @@
|
||||
import pytest
|
||||
from tarot.ui import CubeDisplay
|
||||
|
||||
from tarot.tarot_api import Tarot
|
||||
from tarot.ui import CubeDisplay
|
||||
|
||||
|
||||
def test_cube_zoom():
|
||||
cube = Tarot.cube
|
||||
display = CubeDisplay(cube)
|
||||
assert display.zoom_level == 1.0
|
||||
|
||||
|
||||
display._zoom(1.1)
|
||||
assert display.zoom_level > 1.0
|
||||
|
||||
|
||||
display._zoom(0.5)
|
||||
assert display.zoom_level < 1.0
|
||||
|
||||
|
||||
def test_cube_zoom_limits():
|
||||
cube = Tarot.cube
|
||||
display = CubeDisplay(cube)
|
||||
|
||||
|
||||
# Test upper limit
|
||||
for _ in range(20):
|
||||
display._zoom(1.5)
|
||||
assert display.zoom_level <= 3.0
|
||||
|
||||
|
||||
# Test lower limit
|
||||
for _ in range(20):
|
||||
display._zoom(0.5)
|
||||
|
||||
@@ -1,60 +1,131 @@
|
||||
import pytest
|
||||
from tarot.ui import CubeDisplay
|
||||
from tarot.tarot_api import Tarot
|
||||
import tkinter as tk
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from tarot.tarot_api import Tarot
|
||||
from tarot.ui import CubeDisplay
|
||||
|
||||
|
||||
def test_zoom_limits():
|
||||
# Mock Tk root
|
||||
class MockRoot:
|
||||
def __init__(self):
|
||||
self.bindings = {}
|
||||
self.images = []
|
||||
def bind(self, key, callback): pass
|
||||
def title(self, _): pass
|
||||
def update_idletasks(self): pass
|
||||
def winfo_reqwidth(self): return 800
|
||||
def winfo_reqheight(self): return 600
|
||||
def winfo_screenwidth(self): return 1920
|
||||
def winfo_screenheight(self): return 1080
|
||||
def geometry(self, _): pass
|
||||
def mainloop(self): pass
|
||||
def focus_force(self): pass
|
||||
|
||||
|
||||
def bind(self, key, callback):
|
||||
pass
|
||||
|
||||
def title(self, _):
|
||||
pass
|
||||
|
||||
def update_idletasks(self):
|
||||
pass
|
||||
|
||||
def winfo_reqwidth(self):
|
||||
return 800
|
||||
|
||||
def winfo_reqheight(self):
|
||||
return 600
|
||||
|
||||
def winfo_screenwidth(self):
|
||||
return 1920
|
||||
|
||||
def winfo_screenheight(self):
|
||||
return 1080
|
||||
|
||||
def geometry(self, _):
|
||||
pass
|
||||
|
||||
def mainloop(self):
|
||||
pass
|
||||
|
||||
def focus_force(self):
|
||||
pass
|
||||
|
||||
# Mock Frame
|
||||
class MockFrame:
|
||||
def __init__(self, master=None, **kwargs):
|
||||
self.children = []
|
||||
self.master = master
|
||||
def pack(self, **kwargs): pass
|
||||
def place(self, **kwargs): pass
|
||||
def grid(self, **kwargs): pass
|
||||
def grid_propagate(self, flag): pass
|
||||
def winfo_children(self): return self.children
|
||||
def destroy(self): pass
|
||||
def update_idletasks(self): pass
|
||||
def winfo_reqwidth(self): return 100
|
||||
def winfo_reqheight(self): return 100
|
||||
def bind(self, event, callback): pass
|
||||
|
||||
|
||||
def pack(self, **kwargs):
|
||||
pass
|
||||
|
||||
def place(self, **kwargs):
|
||||
pass
|
||||
|
||||
def grid(self, **kwargs):
|
||||
pass
|
||||
|
||||
def grid_propagate(self, flag):
|
||||
pass
|
||||
|
||||
def winfo_children(self):
|
||||
return self.children
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def update_idletasks(self):
|
||||
pass
|
||||
|
||||
def winfo_reqwidth(self):
|
||||
return 100
|
||||
|
||||
def winfo_reqheight(self):
|
||||
return 100
|
||||
|
||||
def bind(self, event, callback):
|
||||
pass
|
||||
|
||||
# Mock Canvas
|
||||
class MockCanvas:
|
||||
def __init__(self, master=None, **kwargs):
|
||||
self.master = master
|
||||
def pack(self, **kwargs): pass
|
||||
def bind(self, event, callback): pass
|
||||
def create_window(self, coords, **kwargs): return 1
|
||||
def config(self, **kwargs): pass
|
||||
def bbox(self, tag): return (0,0,100,100)
|
||||
def winfo_width(self): return 800
|
||||
def winfo_height(self): return 600
|
||||
def coords(self, item, x, y): pass
|
||||
def scan_mark(self, x, y): pass
|
||||
def scan_dragto(self, x, y, gain=1): pass
|
||||
def canvasx(self, x): return x
|
||||
def canvasy(self, y): return y
|
||||
def xview_moveto(self, fraction): pass
|
||||
def yview_moveto(self, fraction): pass
|
||||
|
||||
def pack(self, **kwargs):
|
||||
pass
|
||||
|
||||
def bind(self, event, callback):
|
||||
pass
|
||||
|
||||
def create_window(self, coords, **kwargs):
|
||||
return 1
|
||||
|
||||
def config(self, **kwargs):
|
||||
pass
|
||||
|
||||
def bbox(self, tag):
|
||||
return (0, 0, 100, 100)
|
||||
|
||||
def winfo_width(self):
|
||||
return 800
|
||||
|
||||
def winfo_height(self):
|
||||
return 600
|
||||
|
||||
def coords(self, item, x, y):
|
||||
pass
|
||||
|
||||
def scan_mark(self, x, y):
|
||||
pass
|
||||
|
||||
def scan_dragto(self, x, y, gain=1):
|
||||
pass
|
||||
|
||||
def canvasx(self, x):
|
||||
return x
|
||||
|
||||
def canvasy(self, y):
|
||||
return y
|
||||
|
||||
def xview_moveto(self, fraction):
|
||||
pass
|
||||
|
||||
def yview_moveto(self, fraction):
|
||||
pass
|
||||
|
||||
# Monkey patch tk
|
||||
original_tk = tk.Tk
|
||||
@@ -62,60 +133,68 @@ def test_zoom_limits():
|
||||
original_canvas = tk.Canvas
|
||||
original_label = tk.ttk.Label
|
||||
original_button = tk.ttk.Button
|
||||
|
||||
|
||||
# Mock Label and Button
|
||||
class MockWidget:
|
||||
def __init__(self, master=None, **kwargs):
|
||||
self.master = master
|
||||
def pack(self, **kwargs): pass
|
||||
def place(self, **kwargs): pass
|
||||
def grid(self, **kwargs): pass
|
||||
def grid_propagate(self, flag): pass
|
||||
|
||||
|
||||
def pack(self, **kwargs):
|
||||
pass
|
||||
|
||||
def place(self, **kwargs):
|
||||
pass
|
||||
|
||||
def grid(self, **kwargs):
|
||||
pass
|
||||
|
||||
def grid_propagate(self, flag):
|
||||
pass
|
||||
|
||||
try:
|
||||
tk.Tk = MockRoot
|
||||
tk.ttk.Frame = MockFrame
|
||||
tk.Canvas = MockCanvas
|
||||
tk.ttk.Label = MockWidget
|
||||
tk.ttk.Button = MockWidget
|
||||
|
||||
|
||||
# Mock Image to avoid memory issues
|
||||
with patch('PIL.Image.open') as mock_open:
|
||||
with patch("PIL.Image.open") as mock_open:
|
||||
mock_img = MagicMock()
|
||||
mock_img.size = (100, 100)
|
||||
mock_img.resize.return_value = mock_img
|
||||
mock_open.return_value = mock_img
|
||||
|
||||
with patch('PIL.ImageTk.PhotoImage') as mock_photo:
|
||||
|
||||
|
||||
with patch("PIL.ImageTk.PhotoImage") as mock_photo:
|
||||
|
||||
cube = Tarot.cube
|
||||
display = CubeDisplay(cube)
|
||||
display.root = MockRoot()
|
||||
display.canvas = MockCanvas()
|
||||
display.content_frame = MockFrame()
|
||||
display.canvas_window = 1 # Mock window ID
|
||||
|
||||
display.canvas_window = 1 # Mock window ID
|
||||
|
||||
# Test initial zoom
|
||||
assert display.zoom_level == 1.0
|
||||
|
||||
|
||||
# Test zoom in
|
||||
display._zoom(1.22)
|
||||
assert display.zoom_level == 1.22
|
||||
|
||||
|
||||
# Test max limit (should be 50.0)
|
||||
# Zoom way in
|
||||
for _ in range(100):
|
||||
display._zoom(1.22)
|
||||
|
||||
|
||||
assert display.zoom_level == 50.0
|
||||
|
||||
|
||||
# Test min limit (should be 0.1)
|
||||
# Zoom way out
|
||||
for _ in range(200):
|
||||
display._zoom(0.5)
|
||||
|
||||
|
||||
assert display.zoom_level == 0.1
|
||||
|
||||
|
||||
finally:
|
||||
tk.Tk = original_tk
|
||||
tk.ttk.Frame = original_frame
|
||||
|
||||
@@ -3,8 +3,9 @@ Tests for Tarot deck and card classes.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from src.tarot.deck import Deck, Card, MajorCard, MinorCard, PipCard, AceCard, CourtCard
|
||||
from src.tarot.attributes import Meaning, Suit, CardImage
|
||||
|
||||
from src.tarot.attributes import CardImage, Meaning, Suit
|
||||
from src.tarot.deck import AceCard, Card, CourtCard, Deck, MajorCard, MinorCard, PipCard
|
||||
|
||||
|
||||
class TestCard:
|
||||
@@ -30,7 +31,7 @@ class TestMajorCard:
|
||||
name="The Magician",
|
||||
meaning=Meaning("Upright", "Reversed"),
|
||||
arcana="Major",
|
||||
kabbalistic_number=1
|
||||
kabbalistic_number=1,
|
||||
)
|
||||
assert card.number == 1
|
||||
assert card.arcana == "Major"
|
||||
@@ -42,7 +43,7 @@ class TestMajorCard:
|
||||
name="Test",
|
||||
meaning=Meaning("Up", "Rev"),
|
||||
arcana="Major",
|
||||
kabbalistic_number=-1
|
||||
kabbalistic_number=-1,
|
||||
)
|
||||
|
||||
def test_major_card_invalid_high(self):
|
||||
@@ -52,16 +53,13 @@ class TestMajorCard:
|
||||
name="Test",
|
||||
meaning=Meaning("Up", "Rev"),
|
||||
arcana="Major",
|
||||
kabbalistic_number=22
|
||||
kabbalistic_number=22,
|
||||
)
|
||||
|
||||
def test_major_card_valid_range(self):
|
||||
for i in range(22):
|
||||
card = MajorCard(
|
||||
number=i,
|
||||
name=f"Card {i}",
|
||||
meaning=Meaning("Up", "Rev"),
|
||||
arcana="Major"
|
||||
number=i, name=f"Card {i}", meaning=Meaning("Up", "Rev"), arcana="Major"
|
||||
)
|
||||
assert card.number == i
|
||||
|
||||
@@ -75,7 +73,7 @@ class TestMinorCard:
|
||||
meaning=Meaning("Upright", "Reversed"),
|
||||
arcana="Minor",
|
||||
suit=suit,
|
||||
pip=1
|
||||
pip=1,
|
||||
)
|
||||
assert card.number == 1
|
||||
assert card.suit.name == "Cups"
|
||||
@@ -90,7 +88,7 @@ class TestMinorCard:
|
||||
meaning=Meaning("Up", "Rev"),
|
||||
arcana="Minor",
|
||||
suit=suit,
|
||||
pip=0
|
||||
pip=0,
|
||||
)
|
||||
|
||||
def test_minor_card_invalid_pip_high(self):
|
||||
@@ -102,7 +100,7 @@ class TestMinorCard:
|
||||
meaning=Meaning("Up", "Rev"),
|
||||
arcana="Minor",
|
||||
suit=suit,
|
||||
pip=15
|
||||
pip=15,
|
||||
)
|
||||
|
||||
def test_minor_card_valid_pips(self):
|
||||
@@ -114,7 +112,7 @@ class TestMinorCard:
|
||||
meaning=Meaning("Up", "Rev"),
|
||||
arcana="Minor",
|
||||
suit=suit,
|
||||
pip=i
|
||||
pip=i,
|
||||
)
|
||||
assert card.pip == i
|
||||
|
||||
@@ -137,10 +135,10 @@ class TestDeck:
|
||||
def test_deck_shuffle(self):
|
||||
deck1 = Deck()
|
||||
cards_before = [c.name for c in deck1.cards]
|
||||
|
||||
|
||||
deck1.shuffle()
|
||||
cards_after = [c.name for c in deck1.cards]
|
||||
|
||||
|
||||
# After shuffle, order should change (with high probability)
|
||||
# We don't assert they're different since shuffle could randomly give same order
|
||||
assert len(cards_after) == 78
|
||||
@@ -148,18 +146,18 @@ class TestDeck:
|
||||
def test_deck_draw_single(self):
|
||||
deck = Deck()
|
||||
initial_count = len(deck.cards)
|
||||
|
||||
|
||||
drawn = deck.draw(1)
|
||||
|
||||
|
||||
assert len(drawn) == 1
|
||||
assert len(deck.cards) == initial_count - 1
|
||||
|
||||
def test_deck_draw_multiple(self):
|
||||
deck = Deck()
|
||||
initial_count = len(deck.cards)
|
||||
|
||||
|
||||
drawn = deck.draw(5)
|
||||
|
||||
|
||||
assert len(drawn) == 5
|
||||
assert len(deck.cards) == initial_count - 5
|
||||
|
||||
@@ -177,28 +175,28 @@ class TestDeck:
|
||||
deck = Deck()
|
||||
deck.draw(5)
|
||||
assert len(deck.cards) < 78
|
||||
|
||||
|
||||
deck.reset()
|
||||
assert len(deck.cards) == 78
|
||||
|
||||
def test_deck_remaining(self):
|
||||
deck = Deck()
|
||||
assert deck.remaining() == 78
|
||||
|
||||
|
||||
deck.draw(1)
|
||||
assert deck.remaining() == 77
|
||||
|
||||
def test_deck_len(self):
|
||||
deck = Deck()
|
||||
assert len(deck) == 78
|
||||
|
||||
|
||||
deck.draw(1)
|
||||
assert len(deck) == 77
|
||||
|
||||
def test_deck_repr(self):
|
||||
deck = Deck()
|
||||
assert "78 cards" in repr(deck)
|
||||
|
||||
|
||||
deck.draw(1)
|
||||
assert "77 cards" in repr(deck)
|
||||
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from tarot.ui import CardDisplay
|
||||
|
||||
|
||||
def test_card_display_init():
|
||||
display = CardDisplay("default")
|
||||
assert display.deck_name == "default"
|
||||
# Check if path resolves correctly relative to src/tarot/ui.py
|
||||
# src/tarot/ui.py -> src/tarot -> src/tarot/deck/default
|
||||
expected_suffix = os.path.join("src", "tarot", "deck", "default")
|
||||
assert str(display.deck_path).endswith(expected_suffix) or str(display.deck_path).endswith("default")
|
||||
assert str(display.deck_path).endswith(expected_suffix) or str(display.deck_path).endswith(
|
||||
"default"
|
||||
)
|
||||
|
||||
|
||||
def test_card_display_resolve_path():
|
||||
display = CardDisplay("thoth")
|
||||
assert display.deck_name == "thoth"
|
||||
assert str(display.deck_path).endswith("thoth")
|
||||
|
||||
|
||||
import os
|
||||
|
||||
@@ -1,60 +1,63 @@
|
||||
import pytest
|
||||
from tarot.ui import CubeDisplay
|
||||
from tarot.tarot_api import Tarot
|
||||
import tkinter as tk
|
||||
|
||||
import pytest
|
||||
|
||||
from tarot.tarot_api import Tarot
|
||||
from tarot.ui import CubeDisplay
|
||||
|
||||
|
||||
def test_recursive_binding():
|
||||
# Mock Tk root and widgets
|
||||
class MockWidget:
|
||||
def __init__(self):
|
||||
self.children = []
|
||||
self.bindings = {}
|
||||
|
||||
|
||||
def bind(self, key, callback):
|
||||
self.bindings[key] = callback
|
||||
|
||||
|
||||
def winfo_children(self):
|
||||
return self.children
|
||||
|
||||
|
||||
def add_child(self, child):
|
||||
self.children.append(child)
|
||||
|
||||
# Monkey patch tk
|
||||
original_tk = tk.Tk
|
||||
original_frame = tk.ttk.Frame
|
||||
|
||||
|
||||
try:
|
||||
# We don't need to mock everything, just enough to test _bind_recursive
|
||||
|
||||
|
||||
cube = Tarot.cube
|
||||
# We can instantiate CubeDisplay without showing it
|
||||
display = CubeDisplay(cube)
|
||||
|
||||
|
||||
# Create a mock widget tree
|
||||
parent = MockWidget()
|
||||
child1 = MockWidget()
|
||||
child2 = MockWidget()
|
||||
grandchild = MockWidget()
|
||||
|
||||
|
||||
parent.add_child(child1)
|
||||
parent.add_child(child2)
|
||||
child1.add_child(grandchild)
|
||||
|
||||
|
||||
# Run recursive binding
|
||||
display._bind_recursive(parent)
|
||||
|
||||
|
||||
# Verify bindings
|
||||
assert "<ButtonPress-1>" in parent.bindings
|
||||
assert "<B1-Motion>" in parent.bindings
|
||||
|
||||
|
||||
assert "<ButtonPress-1>" in child1.bindings
|
||||
assert "<B1-Motion>" in child1.bindings
|
||||
|
||||
|
||||
assert "<ButtonPress-1>" in child2.bindings
|
||||
assert "<B1-Motion>" in child2.bindings
|
||||
|
||||
|
||||
assert "<ButtonPress-1>" in grandchild.bindings
|
||||
assert "<B1-Motion>" in grandchild.bindings
|
||||
|
||||
|
||||
finally:
|
||||
pass
|
||||
|
||||
@@ -1,72 +1,99 @@
|
||||
import pytest
|
||||
from tarot.ui import CubeDisplay
|
||||
from tarot.tarot_api import Tarot
|
||||
import tkinter as tk
|
||||
|
||||
import pytest
|
||||
|
||||
from tarot.tarot_api import Tarot
|
||||
from tarot.ui import CubeDisplay
|
||||
|
||||
|
||||
def test_zoom_key_bindings():
|
||||
# This test verifies that the bindings are set up,
|
||||
# This test verifies that the bindings are set up,
|
||||
# but cannot easily simulate key presses in headless environment.
|
||||
# We check if the bind method was called with correct keys.
|
||||
|
||||
|
||||
# Mock Tk root
|
||||
class MockRoot:
|
||||
def __init__(self):
|
||||
self.bindings = {}
|
||||
|
||||
|
||||
def bind(self, key, callback):
|
||||
self.bindings[key] = callback
|
||||
|
||||
def title(self, _): pass
|
||||
def update_idletasks(self): pass
|
||||
def winfo_reqwidth(self): return 800
|
||||
def winfo_reqheight(self): return 600
|
||||
def winfo_screenwidth(self): return 1920
|
||||
def winfo_screenheight(self): return 1080
|
||||
def geometry(self, _): pass
|
||||
def mainloop(self): pass
|
||||
def focus_force(self): pass
|
||||
|
||||
|
||||
def title(self, _):
|
||||
pass
|
||||
|
||||
def update_idletasks(self):
|
||||
pass
|
||||
|
||||
def winfo_reqwidth(self):
|
||||
return 800
|
||||
|
||||
def winfo_reqheight(self):
|
||||
return 600
|
||||
|
||||
def winfo_screenwidth(self):
|
||||
return 1920
|
||||
|
||||
def winfo_screenheight(self):
|
||||
return 1080
|
||||
|
||||
def geometry(self, _):
|
||||
pass
|
||||
|
||||
def mainloop(self):
|
||||
pass
|
||||
|
||||
def focus_force(self):
|
||||
pass
|
||||
|
||||
# Mock Frame
|
||||
class MockFrame:
|
||||
def __init__(self, master=None, **kwargs):
|
||||
self.children = []
|
||||
def pack(self, **kwargs): pass
|
||||
def winfo_children(self): return self.children
|
||||
def destroy(self): pass
|
||||
|
||||
|
||||
def pack(self, **kwargs):
|
||||
pass
|
||||
|
||||
def winfo_children(self):
|
||||
return self.children
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
# Monkey patch tk
|
||||
original_tk = tk.Tk
|
||||
original_frame = tk.ttk.Frame
|
||||
|
||||
|
||||
try:
|
||||
tk.Tk = MockRoot
|
||||
tk.ttk.Frame = MockFrame
|
||||
|
||||
|
||||
cube = Tarot.cube
|
||||
display = CubeDisplay(cube)
|
||||
|
||||
|
||||
# We need to call show() to trigger bindings, but avoid mainloop
|
||||
# We can't easily mock show() without refactoring,
|
||||
# We can't easily mock show() without refactoring,
|
||||
# so we'll just inspect the code logic or trust the manual test.
|
||||
# However, we can manually call the binding logic if we extract it.
|
||||
|
||||
|
||||
# Since we can't easily mock the entire UI startup in a unit test without
|
||||
# a display, we'll rely on the fact that we added the bindings in the code.
|
||||
pass
|
||||
|
||||
|
||||
finally:
|
||||
tk.Tk = original_tk
|
||||
tk.ttk.Frame = original_frame
|
||||
|
||||
|
||||
def test_zoom_logic_direct():
|
||||
cube = Tarot.cube
|
||||
display = CubeDisplay(cube)
|
||||
display.zoom_level = 1.0
|
||||
|
||||
|
||||
# Simulate + key press effect
|
||||
display._zoom(1.1)
|
||||
assert display.zoom_level > 1.0
|
||||
|
||||
|
||||
# Simulate - key press effect
|
||||
display._zoom(0.9)
|
||||
assert display.zoom_level < 1.1
|
||||
|
||||
@@ -1,83 +1,140 @@
|
||||
import pytest
|
||||
from tarot.ui import CubeDisplay
|
||||
from tarot.tarot_api import Tarot
|
||||
import tkinter as tk
|
||||
|
||||
import pytest
|
||||
|
||||
from tarot.tarot_api import Tarot
|
||||
from tarot.ui import CubeDisplay
|
||||
|
||||
|
||||
def test_canvas_structure():
|
||||
# Mock Tk root
|
||||
class MockRoot:
|
||||
def __init__(self):
|
||||
self.bindings = {}
|
||||
def bind(self, key, callback): pass
|
||||
def title(self, _): pass
|
||||
def update_idletasks(self): pass
|
||||
def winfo_reqwidth(self): return 800
|
||||
def winfo_reqheight(self): return 600
|
||||
def winfo_screenwidth(self): return 1920
|
||||
def winfo_screenheight(self): return 1080
|
||||
def geometry(self, _): pass
|
||||
def mainloop(self): pass
|
||||
def focus_force(self): pass
|
||||
|
||||
|
||||
def bind(self, key, callback):
|
||||
pass
|
||||
|
||||
def title(self, _):
|
||||
pass
|
||||
|
||||
def update_idletasks(self):
|
||||
pass
|
||||
|
||||
def winfo_reqwidth(self):
|
||||
return 800
|
||||
|
||||
def winfo_reqheight(self):
|
||||
return 600
|
||||
|
||||
def winfo_screenwidth(self):
|
||||
return 1920
|
||||
|
||||
def winfo_screenheight(self):
|
||||
return 1080
|
||||
|
||||
def geometry(self, _):
|
||||
pass
|
||||
|
||||
def mainloop(self):
|
||||
pass
|
||||
|
||||
def focus_force(self):
|
||||
pass
|
||||
|
||||
# Mock Frame
|
||||
class MockFrame:
|
||||
def __init__(self, master=None, **kwargs):
|
||||
self.children = []
|
||||
self.master = master
|
||||
def pack(self, **kwargs): pass
|
||||
def place(self, **kwargs): pass
|
||||
def winfo_children(self): return self.children
|
||||
def destroy(self): pass
|
||||
def update_idletasks(self): pass
|
||||
def winfo_reqwidth(self): return 100
|
||||
def winfo_reqheight(self): return 100
|
||||
|
||||
|
||||
def pack(self, **kwargs):
|
||||
pass
|
||||
|
||||
def place(self, **kwargs):
|
||||
pass
|
||||
|
||||
def winfo_children(self):
|
||||
return self.children
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def update_idletasks(self):
|
||||
pass
|
||||
|
||||
def winfo_reqwidth(self):
|
||||
return 100
|
||||
|
||||
def winfo_reqheight(self):
|
||||
return 100
|
||||
|
||||
# Mock Canvas
|
||||
class MockCanvas:
|
||||
def __init__(self, master=None, **kwargs):
|
||||
self.master = master
|
||||
def pack(self, **kwargs): pass
|
||||
def bind(self, event, callback): pass
|
||||
def create_window(self, coords, **kwargs): return 1
|
||||
def config(self, **kwargs): pass
|
||||
def bbox(self, tag): return (0,0,100,100)
|
||||
def winfo_width(self): return 800
|
||||
def winfo_height(self): return 600
|
||||
def coords(self, item, x, y): pass
|
||||
def scan_mark(self, x, y): pass
|
||||
def scan_dragto(self, x, y, gain=1): pass
|
||||
|
||||
def pack(self, **kwargs):
|
||||
pass
|
||||
|
||||
def bind(self, event, callback):
|
||||
pass
|
||||
|
||||
def create_window(self, coords, **kwargs):
|
||||
return 1
|
||||
|
||||
def config(self, **kwargs):
|
||||
pass
|
||||
|
||||
def bbox(self, tag):
|
||||
return (0, 0, 100, 100)
|
||||
|
||||
def winfo_width(self):
|
||||
return 800
|
||||
|
||||
def winfo_height(self):
|
||||
return 600
|
||||
|
||||
def coords(self, item, x, y):
|
||||
pass
|
||||
|
||||
def scan_mark(self, x, y):
|
||||
pass
|
||||
|
||||
def scan_dragto(self, x, y, gain=1):
|
||||
pass
|
||||
|
||||
# Monkey patch tk
|
||||
original_tk = tk.Tk
|
||||
original_frame = tk.ttk.Frame
|
||||
original_canvas = tk.Canvas
|
||||
|
||||
|
||||
try:
|
||||
tk.Tk = MockRoot
|
||||
tk.ttk.Frame = MockFrame
|
||||
tk.Canvas = MockCanvas
|
||||
|
||||
|
||||
cube = Tarot.cube
|
||||
display = CubeDisplay(cube)
|
||||
|
||||
|
||||
# Trigger show to build UI
|
||||
# We can't fully run show() because of mainloop, but we can instantiate parts
|
||||
# Actually, show() creates the root.
|
||||
# Let's just verify the structure by inspecting the code or trusting the manual test.
|
||||
# But we can test the pan methods directly.
|
||||
|
||||
|
||||
display.canvas = MockCanvas()
|
||||
|
||||
|
||||
# Test pan methods
|
||||
class MockEvent:
|
||||
x = 10
|
||||
y = 20
|
||||
x_root = 110
|
||||
y_root = 120
|
||||
|
||||
|
||||
display._start_pan(MockEvent())
|
||||
display._pan(MockEvent())
|
||||
|
||||
|
||||
finally:
|
||||
tk.Tk = original_tk
|
||||
tk.ttk.Frame = original_frame
|
||||
|
||||
@@ -1,68 +1,137 @@
|
||||
import pytest
|
||||
from tarot.ui import CubeDisplay
|
||||
from tarot.tarot_api import Tarot
|
||||
import tkinter as tk
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from tarot.tarot_api import Tarot
|
||||
from tarot.ui import CubeDisplay
|
||||
|
||||
|
||||
def test_wasd_panning():
|
||||
# Mock Tk root
|
||||
class MockRoot:
|
||||
def __init__(self):
|
||||
self.bindings = {}
|
||||
self.images = []
|
||||
def bind(self, key, callback):
|
||||
|
||||
def bind(self, key, callback):
|
||||
self.bindings[key] = callback
|
||||
def title(self, _): pass
|
||||
def update_idletasks(self): pass
|
||||
def winfo_reqwidth(self): return 800
|
||||
def winfo_reqheight(self): return 600
|
||||
def winfo_screenwidth(self): return 1920
|
||||
def winfo_screenheight(self): return 1080
|
||||
def geometry(self, _): pass
|
||||
def mainloop(self): pass
|
||||
def focus_force(self): pass
|
||||
|
||||
|
||||
def title(self, _):
|
||||
pass
|
||||
|
||||
def update_idletasks(self):
|
||||
pass
|
||||
|
||||
def winfo_reqwidth(self):
|
||||
return 800
|
||||
|
||||
def winfo_reqheight(self):
|
||||
return 600
|
||||
|
||||
def winfo_screenwidth(self):
|
||||
return 1920
|
||||
|
||||
def winfo_screenheight(self):
|
||||
return 1080
|
||||
|
||||
def geometry(self, _):
|
||||
pass
|
||||
|
||||
def mainloop(self):
|
||||
pass
|
||||
|
||||
def focus_force(self):
|
||||
pass
|
||||
|
||||
# Mock Frame
|
||||
class MockFrame:
|
||||
def __init__(self, master=None, **kwargs):
|
||||
self.children = []
|
||||
self.master = master
|
||||
def pack(self, **kwargs): pass
|
||||
def place(self, **kwargs): pass
|
||||
def grid(self, **kwargs): pass
|
||||
def grid_propagate(self, flag): pass
|
||||
def winfo_children(self): return self.children
|
||||
def destroy(self): pass
|
||||
def update_idletasks(self): pass
|
||||
def winfo_reqwidth(self): return 100
|
||||
def winfo_reqheight(self): return 100
|
||||
def bind(self, event, callback): pass
|
||||
|
||||
|
||||
def pack(self, **kwargs):
|
||||
pass
|
||||
|
||||
def place(self, **kwargs):
|
||||
pass
|
||||
|
||||
def grid(self, **kwargs):
|
||||
pass
|
||||
|
||||
def grid_propagate(self, flag):
|
||||
pass
|
||||
|
||||
def winfo_children(self):
|
||||
return self.children
|
||||
|
||||
def destroy(self):
|
||||
pass
|
||||
|
||||
def update_idletasks(self):
|
||||
pass
|
||||
|
||||
def winfo_reqwidth(self):
|
||||
return 100
|
||||
|
||||
def winfo_reqheight(self):
|
||||
return 100
|
||||
|
||||
def bind(self, event, callback):
|
||||
pass
|
||||
|
||||
# Mock Canvas
|
||||
class MockCanvas:
|
||||
def __init__(self, master=None, **kwargs):
|
||||
self.master = master
|
||||
self.x_scrolls = []
|
||||
self.y_scrolls = []
|
||||
|
||||
def pack(self, **kwargs): pass
|
||||
def bind(self, event, callback): pass
|
||||
def create_window(self, coords, **kwargs): return 1
|
||||
def config(self, **kwargs): pass
|
||||
def bbox(self, tag): return (0,0,100,100)
|
||||
def winfo_width(self): return 800
|
||||
def winfo_height(self): return 600
|
||||
def coords(self, item, x, y): pass
|
||||
def scan_mark(self, x, y): pass
|
||||
def scan_dragto(self, x, y, gain=1): pass
|
||||
def canvasx(self, x): return x
|
||||
def canvasy(self, y): return y
|
||||
def xview_moveto(self, fraction): pass
|
||||
def yview_moveto(self, fraction): pass
|
||||
|
||||
|
||||
def pack(self, **kwargs):
|
||||
pass
|
||||
|
||||
def bind(self, event, callback):
|
||||
pass
|
||||
|
||||
def create_window(self, coords, **kwargs):
|
||||
return 1
|
||||
|
||||
def config(self, **kwargs):
|
||||
pass
|
||||
|
||||
def bbox(self, tag):
|
||||
return (0, 0, 100, 100)
|
||||
|
||||
def winfo_width(self):
|
||||
return 800
|
||||
|
||||
def winfo_height(self):
|
||||
return 600
|
||||
|
||||
def coords(self, item, x, y):
|
||||
pass
|
||||
|
||||
def scan_mark(self, x, y):
|
||||
pass
|
||||
|
||||
def scan_dragto(self, x, y, gain=1):
|
||||
pass
|
||||
|
||||
def canvasx(self, x):
|
||||
return x
|
||||
|
||||
def canvasy(self, y):
|
||||
return y
|
||||
|
||||
def xview_moveto(self, fraction):
|
||||
pass
|
||||
|
||||
def yview_moveto(self, fraction):
|
||||
pass
|
||||
|
||||
def xview_scroll(self, number, what):
|
||||
self.x_scrolls.append((number, what))
|
||||
|
||||
|
||||
def yview_scroll(self, number, what):
|
||||
self.y_scrolls.append((number, what))
|
||||
|
||||
@@ -72,54 +141,62 @@ def test_wasd_panning():
|
||||
original_canvas = tk.Canvas
|
||||
original_label = tk.ttk.Label
|
||||
original_button = tk.ttk.Button
|
||||
|
||||
|
||||
# Mock Label and Button
|
||||
class MockWidget:
|
||||
def __init__(self, master=None, **kwargs):
|
||||
self.master = master
|
||||
def pack(self, **kwargs): pass
|
||||
def place(self, **kwargs): pass
|
||||
def grid(self, **kwargs): pass
|
||||
def grid_propagate(self, flag): pass
|
||||
|
||||
|
||||
def pack(self, **kwargs):
|
||||
pass
|
||||
|
||||
def place(self, **kwargs):
|
||||
pass
|
||||
|
||||
def grid(self, **kwargs):
|
||||
pass
|
||||
|
||||
def grid_propagate(self, flag):
|
||||
pass
|
||||
|
||||
try:
|
||||
tk.Tk = MockRoot
|
||||
tk.ttk.Frame = MockFrame
|
||||
tk.Canvas = MockCanvas
|
||||
tk.ttk.Label = MockWidget
|
||||
tk.ttk.Button = MockWidget
|
||||
|
||||
|
||||
# Mock Image to avoid memory issues
|
||||
with patch('PIL.Image.open') as mock_open:
|
||||
with patch("PIL.Image.open") as mock_open:
|
||||
mock_img = MagicMock()
|
||||
mock_img.size = (100, 100)
|
||||
mock_img.resize.return_value = mock_img
|
||||
mock_open.return_value = mock_img
|
||||
|
||||
with patch('PIL.ImageTk.PhotoImage') as mock_photo:
|
||||
|
||||
|
||||
with patch("PIL.ImageTk.PhotoImage") as mock_photo:
|
||||
|
||||
cube = Tarot.cube
|
||||
display = CubeDisplay(cube)
|
||||
display.root = MockRoot()
|
||||
display.canvas = MockCanvas()
|
||||
display.content_frame = MockFrame()
|
||||
display.canvas_window = 1
|
||||
|
||||
display.canvas_window = 1
|
||||
|
||||
# Manually trigger bindings (since we can't easily simulate key press in mock root without event loop)
|
||||
# But we can call _pan_key directly to test logic
|
||||
|
||||
|
||||
display._pan_key("up")
|
||||
assert display.canvas.y_scrolls[-1] == (-1, "units")
|
||||
|
||||
|
||||
display._pan_key("down")
|
||||
assert display.canvas.y_scrolls[-1] == (1, "units")
|
||||
|
||||
|
||||
display._pan_key("left")
|
||||
assert display.canvas.x_scrolls[-1] == (-1, "units")
|
||||
|
||||
|
||||
display._pan_key("right")
|
||||
assert display.canvas.x_scrolls[-1] == (1, "units")
|
||||
|
||||
|
||||
finally:
|
||||
tk.Tk = original_tk
|
||||
tk.ttk.Frame = original_frame
|
||||
|
||||
Reference in New Issue
Block a user