import unittest from app.validator.disposable import FREE_PROVIDERS, check_disposable, domain_is_known class FreeProviderCoverageTests(unittest.TestCase): """ISP and consumer mailbox domains must be recognised deterministically. Found live: `g.lombardi@sbcglobal.net` (AT&T's consumer mail) was passed to the ML advisory, which flagged it DISPOSABLE at 0.995. Consumer ISP domains are not disposable — they belong to the deterministic free-provider path, which also removes them from the model's remit entirely. """ ISP_DOMAINS = [ "sbcglobal.net", # AT&T "att.net", "comcast.net", "verizon.net", "bellsouth.net", "cox.net", "charter.net", "earthlink.net", "btinternet.com", "sky.com", "virginmedia.com", "web.de", "t-online.de", "laposte.net", "free.fr", "naver.com", "rediffmail.com", ] def test_isp_domains_are_free_providers(self): missing = [d for d in self.ISP_DOMAINS if d not in FREE_PROVIDERS] self.assertEqual(missing, [], f"ISP domains missing: {missing}") def test_isp_domains_are_known_and_not_disposable(self): for domain in self.ISP_DOMAINS: with self.subTest(domain=domain): self.assertTrue(domain_is_known(domain)) result = check_disposable(f"user@{domain}", domain) self.assertTrue(result.is_free_provider) self.assertFalse(result.is_disposable) def test_known_domains_are_never_sent_to_the_ml_advisory(self): # The engine gates the model on `not domain_is_known(domain)`; this # asserts the gate input for every ISP domain. for domain in self.ISP_DOMAINS: with self.subTest(domain=domain): self.assertTrue( domain_is_known(domain), f"{domain} would reach the ML advisory", ) if __name__ == "__main__": unittest.main()