Skip to content

test: cover the whole-word chat trigger conversions (refs #49439) - #25

Merged
Avicennasis merged 1 commit into
mainfrom
test/49439-trigger-word-boundaries
Aug 14, 2026
Merged

test: cover the whole-word chat trigger conversions (refs #49439)#25
Avicennasis merged 1 commit into
mainfrom
test/49439-trigger-word-boundaries

Conversation

@Avicennasis

@Avicennasis Avicennasis commented Aug 14, 2026

Copy link
Copy Markdown
Owner

What this is

tests/test_triggers.py — one parametrized regression case per trigger converted
in 86c924e, exercising the real TwitchBot._handle_triggers path with the
socket-facing methods stubbed.

Why it has a home

86c924e ("convert remaining bare-substring chat triggers to whole-word matching",
refs #49439) touched twitch.py only: 12 insertions, 12 deletions, no tests.
tests/ has two commits in its entire history, both initial setup, and nothing
under tests/ imported twitch at all — so twelve behavioural conversions
shipped with zero regression coverage while CI happily ran pytest tests/ -v.

Each case asserts three things:

  1. Negative control — the old bare-substring check does match the
    false-positive message, so the case cannot pass vacuously and the bug being
    fixed is demonstrably real.
  2. The fixed code sends nothing at all for that false-positive message.
  3. The fixed code still fires on a legitimate whole-word message.

Changed from the scratch harness

This started as a standalone verification script run while #49439 was being
fixed. Converting it to a pytest test:

  • Dropped the sys.path.insert("/home/…/AvicBotChat") — pytest's rootdir
    already resolves the import, the same way tests/test_irc.py imports
    avicbotwikimedia.
  • Replaced the module-level twitch.time.sleep = lambda … and the
    send_message / _sing_major_general stubs with a function-scoped
    monkeypatch fixture. As written they leaked into any test that ran later in
    the session. The delays are zeroed via MESSAGE_DELAY / LONG_MESSAGE_DELAY
    rather than by stubbing time.sleep, so the stdlib is never touched.
  • CASES is now @pytest.mark.parametrize with the trigger word as the test id,
    so a failure names the trigger.
  • The "<MAJOR-GENERAL>" in-band sentinel became its own sings_major_general
    parametrize field and its own assertion branch.

Test result

Full suite, current HEAD (22 pre-existing tests still pass, 12 new):

$ python3 -m pytest tests/ -v
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-9.0.2, pluggy-1.6.0
collected 34 items

tests/test_dotenv.py::test_load_basic_key_value PASSED                   [  2%]
tests/test_dotenv.py::test_load_strips_double_quotes PASSED              [  5%]
tests/test_dotenv.py::test_load_strips_single_quotes PASSED              [  8%]
tests/test_dotenv.py::test_skips_comments PASSED                         [ 11%]
tests/test_dotenv.py::test_skips_blank_lines PASSED                      [ 14%]
tests/test_dotenv.py::test_does_not_override_existing PASSED             [ 17%]
tests/test_dotenv.py::test_missing_file_is_noop PASSED                   [ 20%]
tests/test_dotenv.py::test_skips_lines_without_equals PASSED             [ 23%]
tests/test_irc.py::TestParseMessage::test_privmsg PASSED                 [ 26%]
tests/test_irc.py::TestParseMessage::test_privmsg_no_message PASSED      [ 29%]
tests/test_irc.py::TestParseMessage::test_ping PASSED                    [ 32%]
tests/test_irc.py::TestParseMessage::test_empty_message PASSED           [ 35%]
tests/test_irc.py::TestParseMessage::test_message_with_colons PASSED     [ 38%]
tests/test_irc.py::TestParseMessage::test_sender_extraction PASSED       [ 41%]
tests/test_irc.py::TestLanguageLookups::test_common_codes PASSED         [ 44%]
tests/test_irc.py::TestLanguageLookups::test_special_codes PASSED        [ 47%]
tests/test_irc.py::TestLanguageLookups::test_regional_codes PASSED       [ 50%]
tests/test_irc.py::TestLanguageLookups::test_unknown_code PASSED         [ 52%]
tests/test_irc.py::TestLanguageLookups::test_dictionary_size PASSED      [ 55%]
tests/test_irc.py::TestConversationalPatterns::test_pattern_before_nick PASSED [ 58%]
tests/test_irc.py::TestConversationalPatterns::test_pattern_after_nick PASSED [ 61%]
tests/test_irc.py::TestConversationalPatterns::test_no_match PASSED      [ 64%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[lemons] PASSED [ 67%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[rainbow] PASSED [ 70%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[racist] PASSED [ 73%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[hitler] PASSED [ 76%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[nazi] PASSED [ 79%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[major-general] PASSED [ 82%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[thanks] PASSED [ 85%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[thank you] PASSED [ 88%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[boobs] PASSED [ 91%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[boobies] PASSED [ 94%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[yay] PASSED [ 97%]
tests/test_triggers.py::test_trigger_matches_whole_words_only[crazy] PASSED [100%]

============================== 34 passed in 0.17s ==============================

Proof it discriminates

twitch.py checked out at 86c924e^ (the revision immediately before the fix),
test file unchanged — all twelve cases fail:

$ git checkout 86c924e^ -- twitch.py
$ python3 -m pytest tests/test_triggers.py -v
>       assert sent == [], f"{word!r} still fires on {fp_message!r}"
E       AssertionError: 'crazy' still fires on 'welcome to crazytown'
E       assert ['Crazy? I wa...ve me crazy.'] == []

FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[lemons]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[rainbow]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[racist]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[hitler]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[nazi]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[major-general]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[thanks]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[thank you]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[boobs]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[boobies]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[yay]
FAILED tests/test_triggers.py::test_trigger_matches_whole_words_only[crazy]
============================== 12 failed in 0.13s ==============================

twitch.py restored, suite green again (34 passed). No source file is modified
by this PR — only tests/test_triggers.py is added.

Lint

$ ruff check .           # All checks passed!
$ ruff format --check .  # 7 files already formatted

Local ruff is 0.15.20; CI pins 0.15.22. CI's own Lint job passes on this branch,
so the pinned version agrees.

CI on this branch

Both jobs green (Lint and Tests), and the Tests job confirms the suite on the
Python version CI actually uses:

platform linux -- Python 3.14.7, pytest-9.1.1, pluggy-1.6.0
============================== 34 passed in 0.13s ==============================

Not verified

  • The tests stub send_message, so nothing about the actual IRC socket path is
    covered — this is a trigger-matching test, not an integration test.

Commit 86c924e converted twelve bare-substring triggers in
TwitchBot._handle_triggers to the _word_in whole-word helper and shipped
with no test — nothing under tests/ imported twitch at all.

Add tests/test_triggers.py, one parametrized case per converted trigger,
each asserting three things: the old bare-substring check does match the
false-positive message (negative control, so the case cannot pass
vacuously), the fixed code sends nothing for that message, and the fixed
code still responds to a legitimate whole-word message.

Run against 86c924e^ all twelve cases fail; against HEAD all pass.
@Avicennasis
Avicennasis merged commit b42126d into main Aug 14, 2026
5 checks passed
@Avicennasis
Avicennasis deleted the test/49439-trigger-word-boundaries branch August 14, 2026 10:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant