"""Tests for the gematria computation engine (issue #234). Alexander Whitestone = 222 in Simple English Gematria. This is not trivia. It is foundational. """ from __future__ import annotations import pytest from timmy.gematria import ( CIPHERS, NOTABLE_NUMBERS, analyze_number, compute_all, compute_value, factorize, gematria, letter_breakdown, reduce_number, ) # ── Core cipher computation ────────────────────────────────────────────────── class TestSimpleCipher: """Simple English: A=1, B=2, ..., Z=26.""" def test_single_letter_a(self): assert compute_value("A", "simple") == 1 def test_single_letter_z(self): assert compute_value("Z", "simple") == 26 def test_alexander_whitestone(self): """The foundational identity — Alexander Whitestone = 222.""" assert compute_value("Alexander Whitestone", "simple") == 222 def test_case_insensitive(self): assert compute_value("hello", "simple") == compute_value("HELLO", "simple") def test_ignores_non_alpha(self): assert compute_value("A-B!C", "simple") == compute_value("ABC", "simple") def test_empty_string(self): assert compute_value("", "simple") == 0 def test_spaces_only(self): assert compute_value(" ", "simple") == 0 def test_numbers_in_text_ignored(self): assert compute_value("ABC123", "simple") == compute_value("ABC", "simple") class TestReductionCipher: """Full Reduction: each letter reduced to single digit.""" def test_a_is_1(self): assert compute_value("A", "reduction") == 1 def test_j_is_1(self): # J=10 → 1+0=1 assert compute_value("J", "reduction") == 1 def test_s_is_1(self): # S=19 → 1+9=10 → 1+0=1 assert compute_value("S", "reduction") == 1 def test_z_is_8(self): # Z=26 → 2+6=8 assert compute_value("Z", "reduction") == 8 class TestReverseCipher: """Reverse Ordinal: A=26, B=25, ..., Z=1.""" def test_a_is_26(self): assert compute_value("A", "reverse") == 26 def test_z_is_1(self): assert compute_value("Z", "reverse") == 1 def test_m_is_14(self): # M is 13th letter → reverse = 27-13 = 14 assert compute_value("M", "reverse") == 14 class TestSumerianCipher: """Sumerian: Simple × 6.""" def test_a_is_6(self): assert compute_value("A", "sumerian") == 6 def test_z_is_156(self): assert compute_value("Z", "sumerian") == 156 def test_is_six_times_simple(self): text = "Alexander Whitestone" assert compute_value(text, "sumerian") == compute_value(text, "simple") * 6 class TestHebrewCipher: """Hebrew-mapped: traditional Hebrew values on Latin alphabet.""" def test_a_is_1(self): assert compute_value("A", "hebrew") == 1 def test_j_is_10(self): assert compute_value("J", "hebrew") == 10 def test_k_is_20(self): assert compute_value("K", "hebrew") == 20 def test_t_is_200(self): assert compute_value("T", "hebrew") == 200 class TestUnknownCipher: def test_raises_on_unknown(self): with pytest.raises(ValueError, match="Unknown cipher"): compute_value("test", "klingon") # ── compute_all ────────────────────────────────────────────────────────────── class TestComputeAll: def test_returns_all_ciphers(self): result = compute_all("ABC") assert set(result.keys()) == set(CIPHERS.keys()) def test_values_are_ints(self): result = compute_all("test") for v in result.values(): assert isinstance(v, int) # ── letter_breakdown ───────────────────────────────────────────────────────── class TestLetterBreakdown: def test_simple_breakdown(self): result = letter_breakdown("AB", "simple") assert result == [("A", 1), ("B", 2)] def test_strips_non_alpha(self): result = letter_breakdown("A B!", "simple") assert result == [("A", 1), ("B", 2)] def test_unknown_cipher_raises(self): with pytest.raises(ValueError): letter_breakdown("test", "nonexistent") # ── reduce_number ──────────────────────────────────────────────────────────── class TestReduceNumber: def test_single_digit(self): assert reduce_number(7) == 7 def test_double_digit_to_master(self): # 29 → 2+9=11 → master number, preserved assert reduce_number(29) == 11 def test_double_digit_non_master(self): # 28 → 2+8=10 → 1+0=1 assert reduce_number(28) == 1 def test_222_reduces_to_6(self): assert reduce_number(222) == 6 # 2+2+2=6 def test_master_11(self): assert reduce_number(11) == 11 def test_master_22(self): assert reduce_number(22) == 22 def test_master_33(self): assert reduce_number(33) == 33 def test_zero(self): assert reduce_number(0) == 0 def test_negative(self): assert reduce_number(-42) == 6 # abs(-42)=42 → 4+2=6 def test_large_number(self): assert reduce_number(9999) == 9 # 9+9+9+9=36 → 3+6=9 # ── factorize ──────────────────────────────────────────────────────────────── class TestFactorize: def test_prime(self): assert factorize(7) == [7] def test_composite(self): assert factorize(12) == [2, 2, 3] def test_222(self): assert factorize(222) == [2, 3, 37] def test_one(self): assert factorize(1) == [1] def test_zero(self): assert factorize(0) == [] def test_large_prime(self): assert factorize(997) == [997] # ── analyze_number ─────────────────────────────────────────────────────────── class TestAnalyzeNumber: def test_222(self): result = analyze_number(222) assert result["value"] == 222 assert result["numerological_reduction"] == 6 assert result["prime_factors"] == [2, 3, 37] assert result["is_prime"] is False assert result["significance"] == NOTABLE_NUMBERS[222] def test_prime_detection(self): assert analyze_number(17)["is_prime"] is True assert analyze_number(18)["is_prime"] is False def test_perfect_square(self): assert analyze_number(144)["is_perfect_square"] is True assert analyze_number(143)["is_perfect_square"] is False def test_triangular(self): assert analyze_number(6)["is_triangular"] is True # 1+2+3 assert analyze_number(7)["is_triangular"] is False def test_angel_number(self): assert analyze_number(333).get("angel_number") is True assert analyze_number(123).get("angel_number") is None def test_master_number(self): assert analyze_number(22).get("master_number") is True # ── gematria tool function (the main interface) ───────────────────────────── class TestGematriaTool: """Test the main gematria() tool function that Timmy calls.""" def test_phrase_mode(self): result = gematria("Alexander Whitestone") assert "222" in result assert "Simple" in result def test_number_mode(self): result = gematria("222") assert "Analysis of 222" in result assert "Alexander Whitestone" in result def test_compare_mode(self): result = gematria("compare: ABC, DEF") assert "Comparison" in result assert "ABC" in result assert "DEF" in result def test_compare_needs_two(self): result = gematria("compare: alone") assert "at least two" in result.lower() def test_empty_input(self): result = gematria("123 456") assert "No alphabetic" in result def test_whitespace_handling(self): result = gematria(" ABC ") assert "Simple" in result def test_letter_breakdown_in_output(self): result = gematria("ABC") assert "Breakdown" in result assert "A(1)" in result def test_notable_number_flagged(self): result = gematria("Alexander Whitestone") assert "★" in result or "222" in result def test_numerological_root_shown(self): result = gematria("ABC") assert "root" in result.lower() or "reduction" in result.lower()