"""
camcops_server/cc_modules/tests/cc_validator_tests.py
===============================================================================
Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
This file is part of CamCOPS.
CamCOPS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CamCOPS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
===============================================================================
"""
from typing import List
import unittest
from camcops_server.cc_modules.cc_validators import (
anchor,
min_max_copies,
one_or_more,
STRING_VALIDATOR_TYPE,
validate_alphanum,
validate_alphanum_underscore,
validate_download_filename,
validate_email,
validate_human_name,
validate_ip_address,
validate_new_password,
validate_restricted_sql_search_literal,
validate_task_tablename,
zero_or_more,
)
# =============================================================================
# Unit tests
# =============================================================================
[docs]class ValidatorTests(unittest.TestCase):
"""
Test our validators.
"""
[docs] def good_bad(
self, validator: STRING_VALIDATOR_TYPE, good: List[str], bad: List[str]
) -> None:
"""
Test a validator with a bunch of known-good and known-bad strings.
"""
for g in good:
# print(f"Testing good: {g!r}")
try:
validator(g, None)
except ValueError as e:
print(f"Validator failed for good value {g!r}: {e}")
raise
for b in bad:
# print(f"Testing bad: {b!r}")
self.assertRaises(ValueError, validator, b)
def test_regex_manipulation(self) -> None:
self.assertEqual(anchor("x"), "^x$")
self.assertEqual(anchor("x", anchor_start=False), "x$")
self.assertEqual(anchor("x", anchor_end=False), "^x")
self.assertEqual(
anchor("x", anchor_start=False, anchor_end=False), "x"
)
self.assertEqual(zero_or_more("x"), "x*")
self.assertEqual(one_or_more("x"), "x+")
self.assertEqual(min_max_copies("x", max_count=5), "x{1,5}")
self.assertEqual(
min_max_copies("x", min_count=0, max_count=5), "x{0,5}"
)
def test_generic_validators(self) -> None:
self.good_bad(validate_alphanum, good=["hello123"], bad=["hello!"])
self.good_bad(
validate_alphanum_underscore,
good=["hello123_blah"],
bad=["hello!"],
)
self.good_bad(
validate_human_name,
good=[
"Al-Assad",
"Al Assad",
"John",
"João",
"タロウ",
"やまだ",
"山田",
"先生",
"мыхаыл",
"Θεοκλεια",
# NOT WORKING: "आकाङ्क्षा",
"علاء الدين",
# NOT WORKING: "אַבְרָהָם",
# NOT WORKING: "മലയാളം",
"상",
"D'Addario",
"John-Doe",
"P.A.M.",
],
bad=[
"hello!",
"' --",
# "<xss>",
# "\"",
# "Robert'); DROP TABLE students;--",
],
)
self.good_bad(
validate_restricted_sql_search_literal,
good=["F20%", "F2_0", "F200"],
bad=["F200!"],
)
def test_email_validator(self) -> None:
self.good_bad(
validate_email,
good=["blah@somewhere.com", "r&d@sillydomain.co.uk"],
bad=["plaintext", "plain.domain.com", "two@at@symbols.com"],
)
def test_ip_address_validator(self) -> None:
self.good_bad(
validate_ip_address,
good=["127.0.0.1", "131.141.8.42", "0.0.0.0"],
bad=[
"plaintext",
"plain.domain.com",
"two@at@symbols.com",
"999.999.999.999",
],
)
def test_password_validator(self) -> None:
self.good_bad(
validate_new_password,
good=["gibberishfly93", "myotherarmadilloisintheworkshop"],
bad=["", " ", "aork", "hastalavista"],
)
def test_task_tablename_validator(self) -> None:
self.good_bad(
validate_task_tablename,
good=["phq9", "gad7_with_extra_bits"],
bad=[
"7hah",
"thing space",
"table!",
# ... and of course:
"Robert'); DROP TABLE students;--",
],
)
def test_download_filename_validator(self) -> None:
self.good_bad(
validate_download_filename,
good=[
"01.tsv",
"_._",
"_blah.txt",
"CamCOPS_dump_2021-06-04T100622.zip",
],
bad=["/etc/passwd", "_", "a", r"C:\autoexec.bat"],
)