Spaces:
Configuration error
Configuration error
| """Validator tests using published Australian government test values.""" | |
| from pii_redactor.models import PIICategory | |
| from pii_redactor.validators import ( | |
| PATTERNS, | |
| validate_abn, | |
| validate_acn, | |
| validate_bsb, | |
| validate_medicare, | |
| validate_tfn, | |
| ) | |
| class TestTFN: | |
| def test_valid_9_digit(self): | |
| # ATO published test TFNs | |
| assert validate_tfn("123 456 782") | |
| assert validate_tfn("876 543 210") | |
| assert validate_tfn("123456782") # no spaces | |
| def test_invalid_9_digit(self): | |
| assert not validate_tfn("999 999 999") | |
| assert not validate_tfn("000 000 000") | |
| assert not validate_tfn("123 456 789") # wrong checksum | |
| def test_wrong_length(self): | |
| assert not validate_tfn("123") | |
| assert not validate_tfn("12345") | |
| assert not validate_tfn("12345678901234") | |
| class TestABN: | |
| def test_valid(self): | |
| # Real Australian ABNs (publicly searchable) | |
| assert validate_abn("33 051 775 556") # Telstra | |
| assert validate_abn("51 824 753 556") # ATO test value | |
| assert validate_abn("33051775556") # no spaces | |
| def test_invalid(self): | |
| assert not validate_abn("11 111 111 111") | |
| assert not validate_abn("12 345 678 901") # bad checksum | |
| def test_wrong_length(self): | |
| assert not validate_abn("123") | |
| assert not validate_abn("1234567890") # 10 digits | |
| class TestACN: | |
| def test_valid(self): | |
| # Real Australian ACNs | |
| assert validate_acn("051 775 556") # Telstra (sub-component of ABN) | |
| assert validate_acn("004 085 616") | |
| assert validate_acn("051775556") # no spaces | |
| def test_invalid(self): | |
| assert not validate_acn("123 456 789") | |
| assert not validate_acn("000 000 001") | |
| def test_wrong_length(self): | |
| assert not validate_acn("12345") | |
| assert not validate_acn("1234567890") # 10 digits | |
| class TestMedicare: | |
| def test_valid(self): | |
| # Synthetic but algorithm-valid Medicare numbers | |
| # Format: XXXX XXXXX X (10 digits) or XXXX XXXXX X-X (11 digits) | |
| # Generate one programmatically by computing the check digit: | |
| # First 8 digits: 29572019 | |
| # Weights: 1,3,7,9,1,3,7,9 → 2*1+9*3+5*7+7*9+2*1+0*3+1*7+9*9 | |
| # = 2 + 27 + 35 + 63 + 2 + 0 + 7 + 81 = 217 → 217 % 10 = 7 | |
| # So check digit is 7. Add issue digit '1': 2957201971 | |
| assert validate_medicare("2957 20197 1") | |
| assert validate_medicare("2957201971") | |
| assert validate_medicare("2957 20197 1-1") # with IRN | |
| def test_invalid(self): | |
| assert not validate_medicare("1234 56789 0") # bad checksum | |
| def test_wrong_length(self): | |
| assert not validate_medicare("123 456 789") | |
| assert not validate_medicare("123456789012345") | |
| class TestBSB: | |
| def test_valid(self): | |
| assert validate_bsb("062-000") # CBA | |
| assert validate_bsb("062000") | |
| assert validate_bsb("083 000") # NAB | |
| def test_invalid(self): | |
| assert not validate_bsb("12345") | |
| assert not validate_bsb("1234567") | |
| class TestPhoneRegex: | |
| """Regression tests for Bug 1 — phone regex must cover all AU formats.""" | |
| def _find(self, text: str): | |
| return PATTERNS[PIICategory.PHONE].search(text) | |
| def test_bracketed_02(self): | |
| m = self._find("(02) 6271 7000") | |
| assert m is not None and m.group() == "(02) 6271 7000" | |
| def test_bracketed_03(self): | |
| m = self._find("(03) 9123 4567") | |
| assert m is not None and m.group() == "(03) 9123 4567" | |
| def test_mobile_04(self): | |
| m = self._find("0412 345 678") | |
| assert m is not None and m.group() == "0412 345 678" | |
| def test_international_plus61(self): | |
| m = self._find("+61 2 6271 7000") | |
| assert m is not None | |
| def test_no_match_inside_abn(self): | |
| # Bug 3: bare digit run from a bad ABN must not produce a phone span | |
| assert PATTERNS[PIICategory.PHONE].search("12 345 678 901") is None | |
| class TestBSBRegex: | |
| """Regression tests for Bug 2 — BSB must not fire inside TFN digit runs.""" | |
| def test_standalone_bsb_matches(self): | |
| m = PATTERNS[PIICategory.BSB_ACCOUNT].search("BSB: 062-000") | |
| assert m is not None and m.group() == "062-000" | |
| def test_no_false_positive_in_compact_tfn(self): | |
| # No spaces — BSB lookahead can't split the 9-digit run | |
| assert PATTERNS[PIICategory.BSB_ACCOUNT].search("123456782") is None | |
| class TestNewDocumentPatterns: | |
| """New regex coverage: driver licence, passport, Centrelink CRN.""" | |
| def test_numeric_driver_licence(self): | |
| m = PATTERNS[PIICategory.DRIVER_LICENCE].search("licence 12345678") | |
| assert m is not None and m.group() == "12345678" | |
| def test_letter_prefix_driver_licence(self): | |
| m = PATTERNS[PIICategory.DRIVER_LICENCE].search("SA licence C123456") | |
| assert m is not None and m.group() == "C123456" | |
| def test_passport_two_letter(self): | |
| m = PATTERNS[PIICategory.PASSPORT].search("passport PA1234567") | |
| assert m is not None and m.group() == "PA1234567" | |
| def test_centrelink_crn(self): | |
| m = PATTERNS[PIICategory.CRN].search("CRN 555444333A") | |
| assert m is not None and m.group() == "555444333A" | |
| def test_patient_id_is_context_bound(self): | |
| text = "Patient ID: PT-448812" | |
| m = PATTERNS[PIICategory.PATIENT_ID].search(text) | |
| assert m is not None | |
| assert m.group("value") == "PT-448812" | |
| def test_medical_record_number_is_context_bound(self): | |
| text = "MRN HOSP-998271" | |
| m = PATTERNS[PIICategory.MEDICAL_RECORD_NUMBER].search(text) | |
| assert m is not None | |
| assert m.group("value") == "HOSP-998271" | |
| def test_healthcare_identifier_is_context_bound(self): | |
| text = "IHI 8003 6000 0000 0000" | |
| m = PATTERNS[PIICategory.HEALTHCARE_IDENTIFIER].search(text) | |
| assert m is not None | |
| assert m.group("value") == "8003 6000 0000 0000" | |