|
18 | 18 | render_returning_session, |
19 | 19 | get_buddy_config, |
20 | 20 | type_text, |
| 21 | + _to_ascii, |
| 22 | + _detect_unicode_support, |
21 | 23 | GREETINGS, |
22 | 24 | FAREWELL_GREETINGS, |
23 | 25 | FAREWELL_MESSAGES, |
@@ -554,6 +556,154 @@ def test_typing_with_custom_greeting(self, capsys, monkeypatch): |
554 | 556 | assert "Custom hello!" in captured.err |
555 | 557 |
|
556 | 558 |
|
| 559 | +class TestToAscii: |
| 560 | + """Tests for _to_ascii Unicode→ASCII conversion (#1040).""" |
| 561 | + |
| 562 | + def test_box_drawing_converted(self): |
| 563 | + assert _to_ascii("\u256d\u2501\u2501\u2501\u256e") == "+---+" |
| 564 | + |
| 565 | + def test_pipe_converted(self): |
| 566 | + assert _to_ascii("\u2503") == "|" |
| 567 | + |
| 568 | + def test_buddy_face_converted(self): |
| 569 | + assert _to_ascii("\u25d5\u203f\u25d5") == ":_:" |
| 570 | + |
| 571 | + def test_emoji_converted(self): |
| 572 | + assert _to_ascii("\u26a1") == "*" |
| 573 | + assert _to_ascii("\U0001f527") == "[tool]" |
| 574 | + assert _to_ascii("\U0001f4c1") == "[file]" |
| 575 | + |
| 576 | + def test_plain_ascii_unchanged(self): |
| 577 | + assert _to_ascii("Hello world") == "Hello world" |
| 578 | + |
| 579 | + def test_mixed_content(self): |
| 580 | + result = _to_ascii("\u2503 \u25d5\u203f\u25d5 \u2503 Hey!") |
| 581 | + assert result == "| :_: | Hey!" |
| 582 | + |
| 583 | + |
| 584 | +class TestDetectUnicodeSupport: |
| 585 | + """Tests for _detect_unicode_support (#1040).""" |
| 586 | + |
| 587 | + def test_utf8_lang_returns_true(self, monkeypatch): |
| 588 | + monkeypatch.setenv("LANG", "en_US.UTF-8") |
| 589 | + monkeypatch.delenv("LC_ALL", raising=False) |
| 590 | + assert _detect_unicode_support() is True |
| 591 | + |
| 592 | + def test_dumb_term_returns_false(self, monkeypatch): |
| 593 | + monkeypatch.setenv("TERM", "dumb") |
| 594 | + monkeypatch.delenv("LANG", raising=False) |
| 595 | + monkeypatch.delenv("LC_ALL", raising=False) |
| 596 | + assert _detect_unicode_support() is False |
| 597 | + |
| 598 | + def test_default_returns_true(self, monkeypatch): |
| 599 | + monkeypatch.delenv("LANG", raising=False) |
| 600 | + monkeypatch.delenv("LC_ALL", raising=False) |
| 601 | + monkeypatch.delenv("TERM", raising=False) |
| 602 | + assert _detect_unicode_support() is True |
| 603 | + |
| 604 | + |
| 605 | +class TestAsciiModeConfig: |
| 606 | + """Tests for asciiMode in get_buddy_config (#1040).""" |
| 607 | + |
| 608 | + def test_ascii_mode_true(self): |
| 609 | + config = {"buddy": {"asciiMode": True}} |
| 610 | + result = get_buddy_config(config) |
| 611 | + assert result["asciiMode"] is True |
| 612 | + |
| 613 | + def test_ascii_mode_false(self): |
| 614 | + config = {"buddy": {"asciiMode": False}} |
| 615 | + result = get_buddy_config(config) |
| 616 | + assert result["asciiMode"] is False |
| 617 | + |
| 618 | + def test_ascii_mode_default(self): |
| 619 | + config = {"buddy": {"name": "Bot"}} |
| 620 | + result = get_buddy_config(config) |
| 621 | + assert result["asciiMode"] is False |
| 622 | + |
| 623 | + def test_ascii_mode_auto_with_utf8(self, monkeypatch): |
| 624 | + monkeypatch.setenv("LANG", "en_US.UTF-8") |
| 625 | + config = {"buddy": {"asciiMode": "auto"}} |
| 626 | + result = get_buddy_config(config) |
| 627 | + assert result["asciiMode"] is False # Unicode supported → no ASCII |
| 628 | + |
| 629 | + def test_ascii_mode_auto_dumb_term(self, monkeypatch): |
| 630 | + monkeypatch.setenv("TERM", "dumb") |
| 631 | + monkeypatch.delenv("LANG", raising=False) |
| 632 | + monkeypatch.delenv("LC_ALL", raising=False) |
| 633 | + config = {"buddy": {"asciiMode": "auto"}} |
| 634 | + result = get_buddy_config(config) |
| 635 | + assert result["asciiMode"] is True # No Unicode → ASCII |
| 636 | + |
| 637 | + |
| 638 | +class TestAsciiModeRendering: |
| 639 | + """Tests for ASCII mode in render functions (#1040).""" |
| 640 | + |
| 641 | + def _ascii_buddy_config(self): |
| 642 | + return { |
| 643 | + "name": "Buddy", "face": BUDDY_FACE, |
| 644 | + "greeting": "", "farewell": "", "asciiMode": True, |
| 645 | + } |
| 646 | + |
| 647 | + def test_session_start_ascii_no_unicode_box(self): |
| 648 | + bc = self._ascii_buddy_config() |
| 649 | + scan = {"name": "app"} |
| 650 | + result = render_session_start(scan, [], "casual", "en", buddy_config=bc) |
| 651 | + # Box drawing replaced |
| 652 | + assert "\u256d" not in result # no ╭ |
| 653 | + assert "\u2501" not in result # no ━ |
| 654 | + assert "\u2503" not in result # no ┃ |
| 655 | + assert "+---+" in result |
| 656 | + assert "|" in result |
| 657 | + |
| 658 | + def test_session_start_ascii_face_converted(self): |
| 659 | + bc = self._ascii_buddy_config() |
| 660 | + scan = {"name": "app"} |
| 661 | + result = render_session_start(scan, [], "casual", "en", buddy_config=bc) |
| 662 | + assert ":_:" in result |
| 663 | + assert "\u25d5" not in result # no ◕ |
| 664 | + |
| 665 | + def test_session_start_ascii_emoji_converted(self): |
| 666 | + bc = self._ascii_buddy_config() |
| 667 | + scan = {"name": "app", "framework": "Next.js 15", "file_count": 42} |
| 668 | + result = render_session_start(scan, [], "casual", "en", buddy_config=bc) |
| 669 | + assert "*" in result # ⚡ → * |
| 670 | + assert "[file]" in result # 📁 → [file] |
| 671 | + assert "\u26a1" not in result |
| 672 | + assert "\U0001f4c1" not in result |
| 673 | + |
| 674 | + def test_session_start_unicode_mode_unchanged(self): |
| 675 | + """Default (no asciiMode) should keep Unicode characters.""" |
| 676 | + scan = {"name": "app"} |
| 677 | + result = render_session_start(scan, [], "casual", "en") |
| 678 | + assert "\u256d" in result # ╭ still present |
| 679 | + assert "\u25d5" in result # ◕ still present |
| 680 | + |
| 681 | + def test_session_summary_ascii_mode(self): |
| 682 | + bc = self._ascii_buddy_config() |
| 683 | + stats = {"duration_minutes": 10, "tool_count": 5, "files_changed": 2} |
| 684 | + result = render_session_summary(stats, [], "casual", "en", buddy_config=bc) |
| 685 | + assert "+---+" in result |
| 686 | + assert "\u256d" not in result |
| 687 | + assert "[time]" in result # ⏱ → [time] |
| 688 | + assert "[tool]" in result # 🔧 → [tool] |
| 689 | + |
| 690 | + def test_session_summary_unicode_mode_unchanged(self): |
| 691 | + stats = {"duration_minutes": 10, "tool_count": 5, "files_changed": 2} |
| 692 | + result = render_session_summary(stats, [], "casual", "en") |
| 693 | + assert "\u256d" in result |
| 694 | + assert "\U0001f527" in result # 🔧 |
| 695 | + |
| 696 | + def test_typing_mode_ascii(self, capsys, monkeypatch): |
| 697 | + monkeypatch.setattr("buddy_renderer.time.sleep", lambda _s: None) |
| 698 | + bc = self._ascii_buddy_config() |
| 699 | + scan = {"name": "app"} |
| 700 | + result = render_session_start(scan, [], "casual", "en", buddy_config=bc, typing=True) |
| 701 | + assert result == "" |
| 702 | + captured = capsys.readouterr() |
| 703 | + assert "+---+" in captured.err |
| 704 | + assert "\u256d" not in captured.err |
| 705 | + |
| 706 | + |
557 | 707 | if __name__ == "__main__": |
558 | 708 | import pytest |
559 | 709 | pytest.main([__file__, "-v"]) |
0 commit comments