1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2012,2013 Intel Corporation
4 *
5 * This program is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Mathias Hasselmann <mathias@openismus.com>
18 */
19
20 #include "evolution-data-server-config.h"
21
22 #include <libebook-contacts/libebook-contacts.h>
23 #include <locale.h>
24
25 /* Pick a locale category to set and test. */
26 #ifdef LC_ADDRESS
27 /* LC_ADDRESS is a GNU extension. */
28 #define CATEGORY LC_ADDRESS
29 #else
30 /* Mimic the fallback branch in EBookQuery. */
31 #ifdef G_OS_WIN32
32 #ifndef LC_MESSAGES
33 #define LC_MESSAGES LC_CTYPE
34 #endif
35 #endif
36 #define CATEGORY LC_MESSAGES
37 #endif /* LC_ADDRESS */
38
39 static const gchar *match_candidates[] = {
40 "not-a-number",
41 "+1-617-4663489", "617-4663489", "4663489",
42 "+1.408.845.5246", "4088455246", "8455246",
43 "+1-857-4663489"
44 };
45
46 #ifdef ENABLE_PHONENUMBER
47 static const EPhoneNumberMatch expected_matches[] = {
48 /* not a number */
49 E_PHONE_NUMBER_MATCH_NONE,
50 E_PHONE_NUMBER_MATCH_NONE,
51 E_PHONE_NUMBER_MATCH_NONE,
52 E_PHONE_NUMBER_MATCH_NONE,
53 E_PHONE_NUMBER_MATCH_NONE,
54 E_PHONE_NUMBER_MATCH_NONE,
55 E_PHONE_NUMBER_MATCH_NONE,
56 E_PHONE_NUMBER_MATCH_NONE,
57
58 /* +1-617-4663489 */
59 E_PHONE_NUMBER_MATCH_NONE,
60 E_PHONE_NUMBER_MATCH_EXACT,
61 E_PHONE_NUMBER_MATCH_NATIONAL,
62 E_PHONE_NUMBER_MATCH_SHORT,
63 E_PHONE_NUMBER_MATCH_NONE,
64 E_PHONE_NUMBER_MATCH_NONE,
65 E_PHONE_NUMBER_MATCH_NONE,
66 E_PHONE_NUMBER_MATCH_NONE,
67
68 /* 617-4663489 */
69 E_PHONE_NUMBER_MATCH_NONE,
70 E_PHONE_NUMBER_MATCH_NATIONAL,
71 E_PHONE_NUMBER_MATCH_NATIONAL,
72 E_PHONE_NUMBER_MATCH_SHORT,
73 E_PHONE_NUMBER_MATCH_NONE,
74 E_PHONE_NUMBER_MATCH_NONE,
75 E_PHONE_NUMBER_MATCH_NONE,
76 E_PHONE_NUMBER_MATCH_NONE,
77
78 /* 4663489 */
79 E_PHONE_NUMBER_MATCH_NONE,
80 E_PHONE_NUMBER_MATCH_SHORT,
81 E_PHONE_NUMBER_MATCH_SHORT,
82 E_PHONE_NUMBER_MATCH_NATIONAL, /* XXX - Google, really? I'd expect a full match here. */
83 E_PHONE_NUMBER_MATCH_NONE,
84 E_PHONE_NUMBER_MATCH_NONE,
85 E_PHONE_NUMBER_MATCH_NONE,
86 E_PHONE_NUMBER_MATCH_SHORT,
87
88 /* +1.408.845.5246 */
89 E_PHONE_NUMBER_MATCH_NONE,
90 E_PHONE_NUMBER_MATCH_NONE,
91 E_PHONE_NUMBER_MATCH_NONE,
92 E_PHONE_NUMBER_MATCH_NONE,
93 E_PHONE_NUMBER_MATCH_EXACT,
94 E_PHONE_NUMBER_MATCH_NATIONAL,
95 E_PHONE_NUMBER_MATCH_SHORT,
96 E_PHONE_NUMBER_MATCH_NONE,
97
98 /* 4088455246 */
99 E_PHONE_NUMBER_MATCH_NONE,
100 E_PHONE_NUMBER_MATCH_NONE,
101 E_PHONE_NUMBER_MATCH_NONE,
102 E_PHONE_NUMBER_MATCH_NONE,
103 E_PHONE_NUMBER_MATCH_NATIONAL,
104 E_PHONE_NUMBER_MATCH_NATIONAL,
105 E_PHONE_NUMBER_MATCH_SHORT,
106 E_PHONE_NUMBER_MATCH_NONE,
107
108 /* 8455246 */
109 E_PHONE_NUMBER_MATCH_NONE,
110 E_PHONE_NUMBER_MATCH_NONE,
111 E_PHONE_NUMBER_MATCH_NONE,
112 E_PHONE_NUMBER_MATCH_NONE,
113 E_PHONE_NUMBER_MATCH_SHORT,
114 E_PHONE_NUMBER_MATCH_SHORT,
115 E_PHONE_NUMBER_MATCH_NATIONAL, /* XXX - Google, really? I'd expect a full match here. */
116 E_PHONE_NUMBER_MATCH_NONE,
117
118 /* +1-857-4663489 */
119 E_PHONE_NUMBER_MATCH_NONE,
120 E_PHONE_NUMBER_MATCH_NONE,
121 E_PHONE_NUMBER_MATCH_NONE,
122 E_PHONE_NUMBER_MATCH_SHORT,
123 E_PHONE_NUMBER_MATCH_NONE,
124 E_PHONE_NUMBER_MATCH_NONE,
125 E_PHONE_NUMBER_MATCH_NONE,
126 E_PHONE_NUMBER_MATCH_EXACT
127 };
128 #endif /* ENABLE_PHONENUMBER */
129
130 typedef struct {
131 gchar *phone_number;
132 gchar *region_code;
133 EPhoneNumberCountrySource country_source;
134 gint country_code;
135 gchar *national_number;
136 gchar *formatted_numbers[4];
137 } ParseAndFormatData;
138
139 static ParseAndFormatData *
parse_and_format_data_new(const gchar * phone_number,const gchar * region_code,EPhoneNumberCountrySource country_source,gint country_code,const gchar * national_number,const gchar * formatted_e164,const gchar * formatted_intl,const gchar * formatted_natl,const gchar * formatted_uri)140 parse_and_format_data_new (const gchar *phone_number,
141 const gchar *region_code,
142 EPhoneNumberCountrySource country_source,
143 gint country_code,
144 const gchar *national_number,
145 const gchar *formatted_e164,
146 const gchar *formatted_intl,
147 const gchar *formatted_natl,
148 const gchar *formatted_uri)
149 {
150 ParseAndFormatData *test_data = g_slice_new0 (ParseAndFormatData);
151
152 test_data->phone_number = g_strdup (phone_number);
153 test_data->region_code = g_strdup (region_code);
154 test_data->country_source = country_source;
155 test_data->country_code = country_code;
156 test_data->national_number = g_strdup (national_number);
157 test_data->formatted_numbers[0] = g_strdup (formatted_e164);
158 test_data->formatted_numbers[1] = g_strdup (formatted_intl);
159 test_data->formatted_numbers[2] = g_strdup (formatted_natl);
160 test_data->formatted_numbers[3] = g_strdup (formatted_uri);
161
162 return test_data;
163 }
164
165 static void
parse_and_format_data_free(gpointer data)166 parse_and_format_data_free (gpointer data)
167 {
168 ParseAndFormatData *const test_data = data;
169
170 g_free (test_data->phone_number);
171 g_free (test_data->region_code);
172 g_free (test_data->national_number);
173 g_free (test_data->formatted_numbers[0]);
174 g_free (test_data->formatted_numbers[1]);
175 g_free (test_data->formatted_numbers[2]);
176 g_free (test_data->formatted_numbers[3]);
177
178 g_slice_free (ParseAndFormatData, test_data);
179 }
180
181 static void
test_parse_and_format(gconstpointer data)182 test_parse_and_format (gconstpointer data)
183 {
184 const ParseAndFormatData *const test_data = data;
185 GError *error = NULL;
186 EPhoneNumber *parsed;
187
188 parsed = e_phone_number_from_string (
189 test_data->phone_number, test_data->region_code, &error);
190
191 #ifdef ENABLE_PHONENUMBER
192
193 {
194 EPhoneNumberCountrySource source;
195 gchar *national;
196 gint i;
197
198 g_assert_cmpint (
199 e_phone_number_get_country_code (parsed, &source), ==,
200 test_data->country_code);
201 g_assert_cmpuint (source, ==, test_data->country_source);
202
203 national = e_phone_number_get_national_number (parsed);
204 g_assert_cmpstr (national, ==, test_data->national_number);
205 g_free (national);
206
207 g_assert (parsed != NULL);
208 g_assert (error == NULL);
209
210 for (i = 0; i < G_N_ELEMENTS (test_data->formatted_numbers); ++i) {
211 gchar *formatted = e_phone_number_to_string (parsed, i);
212 g_assert (formatted != NULL);
213 g_assert_cmpstr (formatted, ==, test_data->formatted_numbers[i]);
214 g_free (formatted);
215 }
216
217 e_phone_number_free (parsed);
218 }
219
220 #else /* ENABLE_PHONENUMBER */
221
222 g_assert (parsed == NULL);
223 g_assert (error != NULL);
224 g_assert (error->domain == E_PHONE_NUMBER_ERROR);
225 g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
226 g_assert (error->message != NULL);
227
228 #endif /* ENABLE_PHONENUMBER */
229
230 g_clear_error (&error);
231 }
232
233 static void
test_parse_bad_number(void)234 test_parse_bad_number (void)
235 {
236 GError *error = NULL;
237 EPhoneNumber *parsed;
238
239 parsed = e_phone_number_from_string ("+1-NOT-A-NUMBER", "US", &error);
240
241 g_assert (parsed == NULL);
242 g_assert (error != NULL);
243 g_assert (error->domain == E_PHONE_NUMBER_ERROR);
244 #ifdef ENABLE_PHONENUMBER
245 g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_A_NUMBER);
246 #else /* ENABLE_PHONENUMBER */
247 g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
248 #endif /* ENABLE_PHONENUMBER */
249 g_assert (error->message != NULL);
250
251 g_clear_error (&error);
252 }
253
254 static void
test_parse_auto_region(void)255 test_parse_auto_region (void)
256 {
257 GError *error = NULL;
258 EPhoneNumber *parsed;
259
260 parsed = e_phone_number_from_string ("212-5423789", NULL, &error);
261
262 #ifdef ENABLE_PHONENUMBER
263
264 {
265 EPhoneNumberCountrySource source;
266 gchar *national;
267 gchar *formatted;
268
269 g_assert (parsed != NULL);
270 g_assert (error == NULL);
271
272 g_assert_cmpint (e_phone_number_get_country_code (parsed, &source), ==, 1);
273 g_assert_cmpuint (source, ==, E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT);
274
275 national = e_phone_number_get_national_number (parsed);
276 g_assert_cmpstr (national, ==, "2125423789");
277 g_free (national);
278
279 formatted = e_phone_number_to_string (parsed, E_PHONE_NUMBER_FORMAT_E164);
280 g_assert_cmpstr (formatted, ==, "+12125423789");
281 g_free (formatted);
282
283 e_phone_number_free (parsed);
284 }
285
286 #else /* ENABLE_PHONENUMBER */
287
288 g_assert (parsed == NULL);
289 g_assert (error != NULL);
290 g_assert (error->domain == E_PHONE_NUMBER_ERROR);
291 g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
292 g_assert (error->message != NULL);
293 g_clear_error (&error);
294
295 #endif /* ENABLE_PHONENUMBER */
296 }
297
298 static void
test_compare_numbers(gconstpointer data)299 test_compare_numbers (gconstpointer data)
300 {
301 const size_t n = GPOINTER_TO_UINT (data);
302 const size_t i = n % G_N_ELEMENTS (match_candidates);
303 const size_t j = n / G_N_ELEMENTS (match_candidates);
304
305 #ifdef ENABLE_PHONENUMBER
306 const gboolean error_expected = !(i && j);
307 #else /* ENABLE_PHONENUMBER */
308 const gboolean error_expected = TRUE;
309 #endif /* ENABLE_PHONENUMBER */
310
311 EPhoneNumberMatch actual_match;
312 GError *error = NULL;
313
314 actual_match = e_phone_number_compare_strings (
315 match_candidates[i],
316 match_candidates[j],
317 &error);
318
319 #ifdef ENABLE_PHONENUMBER
320 g_assert_cmpuint (actual_match, ==, expected_matches[n]);
321 #else /* ENABLE_PHONENUMBER */
322 g_assert_cmpuint (actual_match, ==, E_PHONE_NUMBER_MATCH_NONE);
323 #endif /* ENABLE_PHONENUMBER */
324
325 if (!error_expected) {
326 g_assert (error == NULL);
327 } else {
328 g_assert (error != NULL);
329 g_assert (error->domain == E_PHONE_NUMBER_ERROR);
330 #ifdef ENABLE_PHONENUMBER
331 g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_A_NUMBER);
332 #else /* ENABLE_PHONENUMBER */
333 g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
334 #endif /* ENABLE_PHONENUMBER */
335 g_assert (error->message != NULL);
336
337 g_clear_error (&error);
338 }
339 }
340
341 static void
test_supported(void)342 test_supported (void)
343 {
344 #ifdef ENABLE_PHONENUMBER
345 g_assert (e_phone_number_is_supported ());
346 #else /* ENABLE_PHONENUMBER */
347 g_assert (!e_phone_number_is_supported ());
348 #endif /* ENABLE_PHONENUMBER */
349 }
350
351 static void
test_country_code_for_region(void)352 test_country_code_for_region (void)
353 {
354 GError *error = NULL;
355 gint code;
356
357 g_assert_cmpstr (setlocale (CATEGORY, NULL), ==, "en_US.UTF-8");
358
359 #ifdef ENABLE_PHONENUMBER
360
361 code = e_phone_number_get_country_code_for_region ("CH", &error);
362 g_assert_cmpstr (error ? error->message : NULL, ==, NULL);
363 g_assert_cmpint (code, ==, 41);
364
365 code = e_phone_number_get_country_code_for_region (NULL, &error);
366 g_assert_cmpstr (error ? error->message : NULL, ==, NULL);
367 g_assert_cmpint (code, ==, 1);
368
369 code = e_phone_number_get_country_code_for_region ("C", &error);
370 g_assert_cmpstr (error ? error->message : NULL, ==, NULL);
371 g_assert_cmpint (code, ==, 0);
372
373 code = e_phone_number_get_country_code_for_region ("", &error);
374 g_assert_cmpstr (error ? error->message : NULL, ==, NULL);
375 g_assert_cmpint (code, ==, 1);
376
377 #else /* ENABLE_PHONENUMBER */
378
379 code = e_phone_number_get_country_code_for_region ("CH", &error);
380
381 g_assert (error != NULL);
382 g_assert (error->domain == E_PHONE_NUMBER_ERROR);
383 g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
384 g_assert (error->message != NULL);
385 g_assert_cmpint (code, ==, 0);
386
387 #endif /* ENABLE_PHONENUMBER */
388 }
389
390 static void
test_default_region(void)391 test_default_region (void)
392 {
393 GError *error = NULL;
394 gchar *country;
395
396 g_assert_cmpstr (setlocale (CATEGORY, NULL), ==, "en_US.UTF-8");
397 country = e_phone_number_get_default_region (&error);
398
399 #ifdef ENABLE_PHONENUMBER
400
401 g_assert_cmpstr (error ? error->message : NULL, ==, NULL);
402 g_assert_cmpstr (country, ==, "US");
403
404 #else /* ENABLE_PHONENUMBER */
405
406 g_assert (error != NULL);
407 g_assert (error->domain == E_PHONE_NUMBER_ERROR);
408 g_assert (error->code == E_PHONE_NUMBER_ERROR_NOT_IMPLEMENTED);
409 g_assert (error->message != NULL);
410 g_assert_cmpstr (country, ==, NULL);
411
412 #endif /* ENABLE_PHONENUMBER */
413
414 g_free (country);
415 }
416
417 gint
main(gint argc,gchar ** argv)418 main (gint argc,
419 gchar **argv)
420 {
421 size_t i, j;
422
423 if (setlocale (LC_ALL, "en_US.UTF-8") == NULL) {
424 g_message ("Failed to set locale to en_US.UTF-8");
425 g_message ("Skipping all /ebook-phone-number/* tests");
426 return 0;
427 }
428
429 g_test_init (&argc, &argv, NULL);
430 g_test_bug_base ("http://bugzilla.gnome.org/");
431
432 g_test_add_func (
433 "/ebook-phone-number/supported",
434 test_supported);
435
436 g_test_add_data_func_full (
437 "/ebook-phone-number/parse-and-format/i164",
438 parse_and_format_data_new (
439 "+493011223344", NULL,
440 E_PHONE_NUMBER_COUNTRY_FROM_FQTN,
441 49, "3011223344",
442 "+493011223344",
443 "+49 30 11223344",
444 "030 11223344",
445 "tel:+49-30-11223344"),
446 test_parse_and_format,
447 parse_and_format_data_free);
448 g_test_add_data_func_full (
449 "/ebook-phone-number/parse-and-format/national",
450 parse_and_format_data_new (
451 "(030) 22334-455", "DE",
452 E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT,
453 49, "3022334455",
454 "+493022334455",
455 "+49 30 22334455",
456 "030 22334455",
457 "tel:+49-30-22334455"),
458 test_parse_and_format,
459 parse_and_format_data_free);
460 g_test_add_data_func_full (
461 "/ebook-phone-number/parse-and-format/national2",
462 parse_and_format_data_new (
463 "0049 (30) 22334-455", "DE",
464 E_PHONE_NUMBER_COUNTRY_FROM_IDD,
465 49, "3022334455",
466 "+493022334455",
467 "+49 30 22334455",
468 "030 22334455",
469 "tel:+49-30-22334455"),
470 test_parse_and_format,
471 parse_and_format_data_free);
472 g_test_add_data_func_full (
473 "/ebook-phone-number/parse-and-format/international",
474 parse_and_format_data_new (
475 "+1 212 33445566", NULL,
476 E_PHONE_NUMBER_COUNTRY_FROM_FQTN,
477 1, "21233445566",
478 "+121233445566",
479 "+1 21233445566",
480 "21233445566",
481 "tel:+1-21233445566"),
482 test_parse_and_format,
483 parse_and_format_data_free);
484 g_test_add_data_func_full (
485 "/ebook-phone-number/parse-and-format/rfc3966",
486 parse_and_format_data_new (
487 "tel:+358-71-44556677", NULL,
488 E_PHONE_NUMBER_COUNTRY_FROM_FQTN,
489 358, "7144556677",
490 "+3587144556677",
491 "+358 71 44556677",
492 "071 44556677",
493 "tel:+358-71-44556677"),
494 test_parse_and_format,
495 parse_and_format_data_free);
496
497 g_test_add_func (
498 "/ebook-phone-number/parse-and-format/bad-number",
499 test_parse_bad_number);
500
501 g_test_add_func (
502 "/ebook-phone-number/parse-and-format/auto-region",
503 test_parse_auto_region);
504
505 #ifdef ENABLE_PHONENUMBER
506 g_assert_cmpint (
507 G_N_ELEMENTS (match_candidates) * G_N_ELEMENTS (match_candidates),
508 ==, G_N_ELEMENTS (expected_matches));
509 #endif
510
511 for (i = 0; i < G_N_ELEMENTS (match_candidates); ++i) {
512 for (j = 0; j < G_N_ELEMENTS (match_candidates); ++j) {
513 const size_t n = j + i * G_N_ELEMENTS (match_candidates);
514 gchar *path = g_strdup_printf (
515 "/ebook-phone-number/compare/%s/%s",
516 match_candidates[i], match_candidates[j]);
517
518 g_test_add_data_func (
519 path,
520 GUINT_TO_POINTER (n),
521 test_compare_numbers);
522 g_free (path);
523 }
524 }
525
526 g_test_add_func (
527 "/ebook-phone-number/country-code/for-region",
528 test_country_code_for_region);
529 g_test_add_func (
530 "/ebook-phone-number/country-code/default-region",
531 test_default_region);
532
533 return g_test_run ();
534 }
535