tests/test_campaign_engine.py:18:                                          TemplateSequencer, PhoneSelector,
tests/test_security_rotation.py:17:    PhoneSelector,
tests/test_security_rotation.py:258:class TestPhoneSelector:
tests/test_security_rotation.py:261:        ps = PhoneSelector(phones, "round_robin")
tests/test_security_rotation.py:267:        assert PhoneSelector(phones, "fixed").next_phone() == "+15550001"
tests/test_security_rotation.py:271:        ps = PhoneSelector(phones, "round_robin")
tests/test_security_rotation.py:275:        assert PhoneSelector([], "round_robin").next_phone() == ""
===
class TestTemplateSequencer:
    def test_repeat_mode_cycles(self):
        tpls = [FakeTemplate(1, "T1"), FakeTemplate(2, "T2")]
        ts = TemplateSequencer(tpls, "repeat")
        got = [ts.next_template().id for _ in range(5)]
        assert got == [1, 2, 1, 2, 1]
        assert ts.stopped is False

    def test_stop_mode_halts(self):
        tpls = [FakeTemplate(1, "T1"), FakeTemplate(2, "T2")]
        ts = TemplateSequencer(tpls, "stop")
        assert ts.next_template().id == 1
        assert ts.next_template().id == 2
        assert ts.next_template() is None
        assert ts.stopped is True

    def test_random_mode(self):
        tpls = [FakeTemplate(i, f"T{i}") for i in range(1, 6)]
        ts = TemplateSequencer(tpls, "random")
        got = {ts.next_template().id for _ in range(50)}
        assert len(got) > 1

    def test_empty(self):
        assert TemplateSequencer([], "repeat").next_template() is None


class TestPhoneSelector:
    def test_round_robin(self):
        phones = [FakePhone(1, "+15550001"), FakePhone(2, "+15550002")]
        ps = PhoneSelector(phones, "round_robin")
        got = [ps.next_phone() for _ in range(4)]
        assert got == ["+15550001", "+15550002", "+15550001", "+15550002"]

    def test_fixed(self):
        phones = [FakePhone(1, "+15550001"), FakePhone(2, "+15550002")]
        assert PhoneSelector(phones, "fixed").next_phone() == "+15550001"

    def test_inactive_excluded(self):
        phones = [FakePhone(1, "+15550001", active=False), FakePhone(2, "+15550002")]
        ps = PhoneSelector(phones, "round_robin")
        assert all(p == "+15550002" for _ in range(3) for p in [ps.next_phone()])

    def test_empty_returns_blank(self):
        assert PhoneSelector([], "round_robin").next_phone() == ""
