Coverage for cc_modules/tests/cc_validator_tests.py : 33%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1#!/usr/bin/env python
3"""
4camcops_server/cc_modules/tests/cc_validator_tests.py
6===============================================================================
8 Copyright (C) 2012-2020 Rudolf Cardinal (rudolf@pobox.com).
10 This file is part of CamCOPS.
12 CamCOPS is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
17 CamCOPS is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
25===============================================================================
27"""
29from typing import List
30import unittest
32from camcops_server.cc_modules.cc_validators import (
33 anchor,
34 min_max_copies,
35 one_or_more,
36 STRING_VALIDATOR_TYPE,
37 validate_alphanum,
38 validate_alphanum_underscore,
39 validate_email,
40 validate_human_name,
41 validate_ip_address,
42 validate_new_password,
43 validate_restricted_sql_search_literal,
44 validate_task_tablename,
45 zero_or_more,
46)
49# =============================================================================
50# Unit tests
51# =============================================================================
53class ValidatorTests(unittest.TestCase):
54 """
55 Test our validators.
56 """
58 def good_bad(self, validator: STRING_VALIDATOR_TYPE,
59 good: List[str], bad: List[str]) -> None:
60 """
61 Test a validator with a bunch of known-good and known-bad strings.
62 """
63 for g in good:
64 # print(f"Testing good: {g!r}")
65 try:
66 validator(g, None)
67 except ValueError as e:
68 print(f"Validator failed for good value {g!r}: {e}")
69 raise
70 for b in bad:
71 # print(f"Testing bad: {b!r}")
72 self.assertRaises(ValueError, validator, b)
74 def test_regex_manipulation(self) -> None:
75 self.assertEqual(anchor("x"), "^x$")
76 self.assertEqual(anchor("x", anchor_start=False), "x$")
77 self.assertEqual(anchor("x", anchor_end=False), "^x")
78 self.assertEqual(anchor("x", anchor_start=False, anchor_end=False),
79 "x")
81 self.assertEqual(zero_or_more("x"), "x*")
82 self.assertEqual(one_or_more("x"), "x+")
83 self.assertEqual(min_max_copies("x", max_count=5), "x{1,5}")
84 self.assertEqual(min_max_copies("x", min_count=0, max_count=5),
85 "x{0,5}")
87 def test_generic_validators(self) -> None:
88 self.good_bad(
89 validate_alphanum,
90 good=["hello123"],
91 bad=["hello!"]
92 )
93 self.good_bad(
94 validate_alphanum_underscore,
95 good=["hello123_blah"],
96 bad=["hello!"]
97 )
98 self.good_bad(
99 validate_human_name,
100 good=[
101 "Al-Assad",
102 "Al Assad",
103 "John",
104 "João",
105 "タロウ",
106 "やまだ",
107 "山田",
108 "先生",
109 "мыхаыл",
110 "Θεοκλεια",
111 # NOT WORKING: "आकाङ्क्षा",
112 "علاء الدين",
113 # NOT WORKING: "אַבְרָהָם",
114 # NOT WORKING: "മലയാളം",
115 "상",
116 "D'Addario",
117 "John-Doe",
118 "P.A.M.",
119 ],
120 bad=[
121 "hello!",
122 "' --",
123 # "<xss>",
124 # "\"",
125 # "Robert'); DROP TABLE students;--",
126 ]
127 )
128 self.good_bad(
129 validate_restricted_sql_search_literal,
130 good=[
131 "F20%",
132 "F2_0",
133 "F200",
134 ],
135 bad=[
136 "F200!",
137 ]
138 )
140 def test_email_validator(self) -> None:
141 self.good_bad(
142 validate_email,
143 good=[
144 "blah@somewhere.com",
145 "r&d@sillydomain.co.uk",
146 ],
147 bad=[
148 "plaintext",
149 "plain.domain.com",
150 "two@at@symbols.com",
151 ]
152 )
154 def test_ip_address_validator(self) -> None:
155 self.good_bad(
156 validate_ip_address,
157 good=[
158 "127.0.0.1",
159 "131.141.8.42",
160 "0.0.0.0",
161 ],
162 bad=[
163 "plaintext",
164 "plain.domain.com",
165 "two@at@symbols.com",
166 "999.999.999.999",
167 ]
168 )
170 def test_password_validator(self) -> None:
171 self.good_bad(
172 validate_new_password,
173 good=[
174 "gibberishfly93",
175 "myotherarmadilloisintheworkshop",
176 ],
177 bad=[
178 "",
179 " ",
180 "aork",
181 "hastalavista",
182 ]
183 )
185 def test_task_tablename_validator(self) -> None:
186 self.good_bad(
187 validate_task_tablename,
188 good=[
189 "phq9",
190 "gad7_with_extra_bits",
191 ],
192 bad=[
193 "7hah",
194 "thing space",
195 "table!",
196 # ... and of course:
197 "Robert'); DROP TABLE students;--",
198 ]
199 )