Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2026 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU General Public License as published by the Free Software
7 : Foundation; either version 3, or (at your option) any later version.
8 :
9 : TALER is distributed in the hope that it will be useful, but WITHOUT ANY
10 : WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 : A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 :
17 : /**
18 : * @file util/test_validators.c
19 : * @brief Tests for validators.
20 : * @author Christian Grothoff (ivan@avalos.me)
21 : */
22 : #include "taler/platform.h"
23 : #include <gnunet/gnunet_util_lib.h>
24 : #include "taler/taler_merchant_util.h"
25 :
26 : static bool
27 1 : check_email (void)
28 : {
29 : struct
30 : {
31 : const char *email;
32 : bool expected;
33 1 : } tests[] = {
34 : /* Valid emails */
35 : {"user@example.com", true},
36 : {"john.doe@example.co.uk", true},
37 : {"alice+tag@domain.org", true},
38 : {"test_underscore@test.example", true},
39 : {"user!special@example.com", true},
40 : {"first.last@sub.domain.example.com", true},
41 : {"\"john doe\"@example.com", true},
42 : {"\"very.unusual.@.unusual.com\"@example.com", true},
43 : {"user@192.168.1.1", true},
44 : {"user@[192.168.1.1]", true},
45 : {"user@[IPv6:2001:db8::1]", true},
46 : {"user@[IPv6::1]", true},
47 : {"a@b.c", true},
48 : {"test+123@test-domain.org", true},
49 : {"_test@example.com", true},
50 : {"1234567890@example.com", true},
51 :
52 : /* Invalid emails */
53 : {"", false},
54 : {"plainaddress", false},
55 : {"@example.com", false},
56 : {"user@", false},
57 : {"user name@example.com", false},
58 : {"user@domain", false}, /* No TLD - debatable, but common validation */
59 : {"user..name@example.com", false},
60 : {".user@example.com", false},
61 : {"user.@example.com", false},
62 : {"user@.example.com", false},
63 : {"user@example.com.", false},
64 : {"user@-example.com", false},
65 : {"user@example-.com", false},
66 : {"user@@example.com", false},
67 : {"user@exam ple.com", false},
68 : {"user@[256.256.256.256]", false},
69 : {"user@[IPv6:zzzz::1]", false},
70 : };
71 :
72 1 : unsigned int num_tests = sizeof (tests) / sizeof (tests[0]);
73 1 : unsigned int passed = 0;
74 1 : unsigned int failed = 0;
75 :
76 34 : for (unsigned int i = 0; i < num_tests; i++)
77 : {
78 33 : bool result = TALER_MERCHANT_email_valid (tests[i].email);
79 33 : bool success = (result == tests[i].expected);
80 :
81 33 : if (success)
82 : {
83 33 : passed++;
84 33 : continue;
85 : }
86 0 : failed++;
87 0 : fprintf (stderr,
88 : "FAIL: \"%s\" -> %s (expected %s)\n",
89 0 : tests[i].email ? tests[i].email : "(NULL)",
90 : result ? "VALID" : "INVALID",
91 0 : tests[i].expected ? "VALID" : "INVALID");
92 : }
93 1 : return (failed > 0) ? 1 : 0;
94 : }
95 :
96 :
97 : static bool
98 1 : check_phone (void)
99 : {
100 : struct
101 : {
102 : const char *phone;
103 : const char *expected_normalized;
104 : bool allow_letters;
105 1 : } tests[] = {
106 : /* Valid phone numbers with +CC - digits only */
107 : {"+1-202-555-0173", "+12025550173", false},
108 : {"+1 202 555 0173", "+12025550173", false},
109 : {"+1 (202) 555-0173", "+12025550173", false},
110 : {"+33142685300", "+33142685300", false},
111 : {"+33 1 42 68 53 00", "+33142685300", false},
112 : {"+44 20 7946 0958", "+442079460958", false},
113 : {"+44.20.7946.0958", "+442079460958", false},
114 : {"+49-30-12345678", "+493012345678", false},
115 : {"+886 2 2345 6789", "+886223456789", false},
116 : {"+1-800-555-0123", "+18005550123", false},
117 : {"+81-3-1234-5678", "+81312345678", false},
118 : {"+39 06 6994 0255", "+390669940255", false},
119 : {"+34-91-577-3200", "+34915773200", false},
120 : {"+46 8 123456", "+468123456", false},
121 : {"+1(555)1234567", "+15551234567", false},
122 : {"+1-555-1234567", "+15551234567", false},
123 : {"+358 9 1234567", "+35891234567", false},
124 : {"+1 202-555.0173", "+12025550173", false},
125 : {"+7 495 123-45-67", "+74951234567", false},
126 :
127 : /* Valid phone numbers with letters (allow_letters=true) */
128 : {"+1-800-CALL-NOW", "+18002255669", true},
129 : {"+1-800-FLOWERS", "+18003569377", true},
130 : {"+1-888-PIZZA", "+188874992", true},
131 : {"+1 800 CALL NOW", "+18002255669", true},
132 : {"+44-HELLO-WORLD", "+444355696753", true},
133 : {"+1-555-ABCDEFGH", "+155522233344", true},
134 :
135 : /* Letters should fail when allow_letters=false */
136 : {"+1-800-CALL-NOW", NULL, false},
137 : {"+1-800-FLOWERS", NULL, false},
138 :
139 : /* Invalid phone numbers */
140 : {"", NULL, false},
141 : {"202-555-0173", NULL, false}, /* Missing + */
142 : {"1-202-555-0173", NULL, false}, /* Missing + */
143 : {"+1", NULL, false}, /* Only country code */
144 : {"+1 abc def ghij", NULL, false}, /* Invalid format */
145 : {"1-800-555-0123", NULL, false}, /* No plus sign */
146 : {"++1-202-555-0173", NULL, false}, /* Double plus */
147 : {"+1--202-555-0173", NULL, false}, /* Double hyphen */
148 : {"+12025550173 ", NULL, false}, /* Trailing space */
149 : {" +12025550173", NULL, false}, /* Leading space */
150 : {"+1 (555", NULL, false}, /* Unclosed parenthesis */
151 : {"+1 555)", NULL, false}, /* Unmatched closing paren */
152 : {"+1-555-", NULL, false}, /* Trailing hyphen */
153 : {"+1-555-01a3", NULL, false}, /* Lowercase letter without allow_letters */
154 : {"+1 (202", NULL, false}, /* Unmatched paren */
155 : };
156 :
157 1 : unsigned int num_tests = sizeof (tests) / sizeof (tests[0]);
158 1 : unsigned int passed = 0;
159 1 : unsigned int failed = 0;
160 :
161 43 : for (unsigned int i = 0; i < num_tests; i++)
162 : {
163 42 : char *result = TALER_MERCHANT_phone_validate_normalize (tests[i].phone,
164 42 : tests[i].allow_letters);
165 : bool success;
166 :
167 42 : if (NULL == tests[i].expected_normalized)
168 : {
169 17 : success = (NULL == result);
170 : }
171 : else
172 : {
173 50 : success = (NULL != result &&
174 25 : 0 == strcmp (result,
175 : tests[i].expected_normalized));
176 : }
177 42 : if (success)
178 : {
179 42 : passed++;
180 : }
181 : else
182 : {
183 0 : failed++;
184 0 : fprintf (stderr,
185 : "FAIL: (`%s' (letters=%s) -> `%s'",
186 : tests[i].phone,
187 0 : tests[i].allow_letters ? "true" : "false",
188 : result);
189 : }
190 42 : GNUNET_free (result);
191 : }
192 1 : return (failed > 0) ? 1 : 0;
193 : }
194 :
195 :
196 : int
197 1 : main (void)
198 : {
199 1 : if (check_email ())
200 : {
201 0 : fprintf (stderr,
202 : "email failed\n");
203 0 : return 1;
204 : }
205 1 : if (check_phone ())
206 : {
207 0 : fprintf (stderr,
208 : "phone failed\n");
209 0 : return 1;
210 : }
211 1 : return 0;
212 : }
|