Hide keyboard shortcuts

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 

2 

3""" 

4camcops_server/cc_modules/tests/cc_validator_tests.py 

5 

6=============================================================================== 

7 

8 Copyright (C) 2012-2020 Rudolf Cardinal (rudolf@pobox.com). 

9 

10 This file is part of CamCOPS. 

11 

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. 

16 

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. 

21 

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/>. 

24 

25=============================================================================== 

26 

27""" 

28 

29from typing import List 

30import unittest 

31 

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) 

47 

48 

49# ============================================================================= 

50# Unit tests 

51# ============================================================================= 

52 

53class ValidatorTests(unittest.TestCase): 

54 """ 

55 Test our validators. 

56 """ 

57 

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) 

73 

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") 

80 

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}") 

86 

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 ) 

139 

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 ) 

153 

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 ) 

169 

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 ) 

184 

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 )