542293c4b25246bc618cd5757b122d5446969336
[platform/upstream/glib.git] / glib / tests / date.c
1 #undef G_DISABLE_ASSERT
2 #undef G_LOG_DOMAIN
3
4 /* We are testing some deprecated APIs here */
5 #ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
6 #define GLIB_DISABLE_DEPRECATION_WARNINGS
7 #endif
8
9 #include "config.h"
10
11 #include "glib.h"
12
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <locale.h>
17 #include <time.h>
18
19 #ifdef G_OS_WIN32
20 #define WIN32_LEAN_AND_MEAN
21 #include <windows.h>
22 /* mingw defines it while msvc doesn't */
23 #ifndef SUBLANG_LITHUANIAN_LITHUANIA
24 #define SUBLANG_LITHUANIAN_LITHUANIA 0x01
25 #endif
26 #endif
27
28 static void
29 test_basic (void)
30 {
31   g_assert_cmpint (sizeof (GDate), <,  9);
32   g_assert (!g_date_valid_month (G_DATE_BAD_MONTH));
33   g_assert (!g_date_valid_month (13));
34   g_assert (!g_date_valid_day (G_DATE_BAD_DAY));
35   g_assert (!g_date_valid_day (32));
36   g_assert (!g_date_valid_year (G_DATE_BAD_YEAR));
37   g_assert (!g_date_valid_julian (G_DATE_BAD_JULIAN));
38   g_assert (!g_date_valid_weekday (G_DATE_BAD_WEEKDAY));
39   g_assert (g_date_is_leap_year (2000));
40   g_assert (!g_date_is_leap_year (1999));
41   g_assert (g_date_is_leap_year (1996));
42   g_assert (g_date_is_leap_year (1600));
43   g_assert (!g_date_is_leap_year (2100));
44   g_assert (!g_date_is_leap_year (1800));
45 }
46
47 static void
48 test_empty_constructor (void)
49 {
50   GDate *d;
51
52   d = g_date_new ();
53   g_assert (!g_date_valid (d));
54   g_date_free (d);
55 }
56
57 static void
58 test_dmy_constructor (void)
59 {
60   GDate *d;
61   guint32 j;
62
63   d = g_date_new_dmy (1, 1, 1);
64   g_assert (g_date_valid (d));
65   j = g_date_get_julian (d);
66   g_assert_cmpint (j, ==, 1);
67   g_assert_cmpint (g_date_get_month (d), ==, G_DATE_JANUARY);
68   g_assert_cmpint (g_date_get_day (d), ==, 1);
69   g_assert_cmpint (g_date_get_year (d), ==, 1);
70   g_date_free (d);
71 }
72
73 static void
74 test_julian_constructor (void)
75 {
76   GDate *d1;
77   GDate *d2;
78
79   d1 = g_date_new_julian (4000);
80   d2 = g_date_new_julian (5000);
81   g_assert_cmpint (g_date_get_julian (d1), ==, 4000);
82   g_assert_cmpint (g_date_days_between (d1, d2), ==, 1000);
83   g_assert_cmpint (g_date_get_year (d1), ==, 11);
84   g_assert_cmpint (g_date_get_day (d2), ==, 9);
85   g_date_free (d1);
86   g_date_free (d2);
87 }
88
89 static void
90 test_dates (void)
91 {
92   GDate *d;
93   GTimeVal tv;
94   time_t now;
95
96   d = g_date_new ();
97
98   /* today */
99   now = time (NULL);
100   g_assert_cmpint (now, !=, (time_t) -1);
101   g_date_set_time (d, now);
102   g_assert (g_date_valid (d));
103
104   /* Unix epoch */
105   g_date_set_time (d, 1);
106   g_assert (g_date_valid (d));
107
108   tv.tv_sec = 0;
109   tv.tv_usec = 0;
110   g_date_set_time_val (d, &tv);
111   g_assert (g_date_valid (d));
112
113   /* Julian day 1 */
114   g_date_set_julian (d, 1);
115   g_assert (g_date_valid (d));
116
117   g_date_set_year (d, 3);
118   g_date_set_day (d, 3);
119   g_date_set_month (d, 3);
120   g_assert (g_date_valid (d));
121   g_assert_cmpint (g_date_get_year (d), ==, 3);
122   g_assert_cmpint (g_date_get_month (d), ==, 3);
123   g_assert_cmpint (g_date_get_day (d), ==, 3);
124   g_assert (!g_date_is_first_of_month (d));
125   g_assert (!g_date_is_last_of_month (d));
126   g_date_set_day (d, 1);
127   g_assert (g_date_is_first_of_month (d));
128   g_date_subtract_days (d, 1);
129   g_assert (g_date_is_last_of_month (d));
130
131   g_date_free (d);
132 }
133
134 static void
135 test_parse (void)
136 {
137   GDate *d;
138   gchar buf[101];
139
140   d = g_date_new ();
141
142   g_date_set_dmy (d, 10, 1, 2000);
143   g_date_strftime (buf, 100, "%x", d);
144
145   g_date_set_parse (d, buf);
146   g_assert (g_date_valid (d));
147   g_assert_cmpint (g_date_get_month (d), ==, 1);
148   g_assert_cmpint (g_date_get_day (d), ==, 10);
149   g_assert_cmpint (g_date_get_year (d), ==, 2000);
150
151   g_date_set_parse (d, "2001 10 1");
152   g_assert (g_date_valid (d));
153   g_assert_cmpint (g_date_get_month (d), ==, 10);
154   g_assert_cmpint (g_date_get_day (d), ==, 1);
155   g_assert_cmpint (g_date_get_year (d), ==, 2001);
156
157   g_date_set_parse (d, "2001 10");
158   g_assert (!g_date_valid (d));
159
160   g_date_set_parse (d, "2001 10 1 1");
161   g_assert (!g_date_valid (d));
162
163   g_date_set_parse (d, "March 1999");
164   g_assert (g_date_valid (d));
165   g_assert_cmpint (g_date_get_month (d), ==, 3);
166   g_assert_cmpint (g_date_get_day (d), ==, 1);
167   g_assert_cmpint (g_date_get_year (d), ==, 1999);
168
169   g_date_set_parse (d, "10 Sep 1087");
170   g_assert (g_date_valid (d));
171   g_assert_cmpint (g_date_get_month (d), ==, 9);
172   g_assert_cmpint (g_date_get_day (d), ==, 10);
173   g_assert_cmpint (g_date_get_year (d), ==, 1087);
174
175   g_date_set_parse (d, "19990301");
176   g_assert (g_date_valid (d));
177   g_assert_cmpint (g_date_get_month (d), ==, 3);
178   g_assert_cmpint (g_date_get_day (d), ==, 1);
179   g_assert_cmpint (g_date_get_year (d), ==, 1999);
180
181   g_date_set_parse (d, "20011320");
182   g_assert (!g_date_valid (d));
183
184   g_date_free (d);
185 }
186
187 static void
188 test_parse_invalid (void)
189 {
190   const gchar * const strs[] =
191     {
192       /* Incomplete UTF-8 sequence */
193       "\xfd",
194       /* Ridiculously long input */
195       "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
196       "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
197       "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
198     };
199   gsize i;
200
201   for (i = 0; i < G_N_ELEMENTS (strs); i++)
202     {
203       GDate *d = g_date_new ();
204
205       g_test_message ("Test %" G_GSIZE_FORMAT, i);
206       g_date_set_parse (d, strs[i]);
207
208       g_assert_false (g_date_valid (d));
209
210       g_date_free (d);
211     }
212 }
213
214 static void
215 test_parse_locale_change (void)
216 {
217   /* Checks that g_date_set_parse correctly changes locale specific data as
218    * necessary. In this particular case year adjustment, as Thai calendar is
219    * 543 years ahead of the Gregorian calendar. */
220
221   GDate date;
222
223   if (setlocale (LC_ALL, "th_TH") == NULL)
224     {
225       g_test_skip ("locale th_TH not available");
226       return;
227     }
228
229   g_date_set_parse (&date, "04/07/2519");
230
231   setlocale (LC_ALL, "C");
232   g_date_set_parse (&date, "07/04/76");
233   g_assert_cmpint (g_date_get_day (&date), ==, 4);
234   g_assert_cmpint (g_date_get_month (&date), ==, 7);
235   g_assert_cmpint (g_date_get_year (&date), ==, 1976);
236
237   setlocale (LC_ALL, "");
238 }
239
240 static void
241 test_month_substring (void)
242 {
243   GDate date;
244
245   g_test_bug ("793550");
246
247   if (setlocale (LC_ALL, "pl_PL") == NULL)
248     {
249       g_test_skip ("pl_PL locale not available");
250       return;
251     }
252
253   /* In Polish language September is "wrzesień" and August is "sierpień"
254    * abbreviated as "sie". The former used to be confused with the latter
255    * because "sie" is a substring of "wrzesień" and was matched first. */
256
257   g_date_set_parse (&date, "wrzesień 2018");
258   g_assert_true (g_date_valid (&date));
259   g_assert_cmpint (g_date_get_month (&date), ==, G_DATE_SEPTEMBER);
260
261   g_date_set_parse (&date, "sie 2018");
262   g_assert_true (g_date_valid (&date));
263   g_assert_cmpint (g_date_get_month (&date), ==, G_DATE_AUGUST);
264
265   g_date_set_parse (&date, "sierpień 2018");
266   g_assert_true (g_date_valid (&date));
267   g_assert_cmpint (g_date_get_month (&date), ==, G_DATE_AUGUST);
268
269   setlocale (LC_ALL, "");
270 }
271
272
273 static void
274 test_month_names (void)
275 {
276 #if defined(HAVE_LANGINFO_ABALTMON) || defined(G_OS_WIN32)
277   GDate *gdate;
278   gchar buf[101];
279   gchar *oldlocale;
280 #ifdef G_OS_WIN32
281   LCID old_lcid;
282 #endif
283 #endif  /* defined(HAVE_LANGINFO_ABALTMON) || defined(G_OS_WIN32) */
284
285   g_test_bug ("749206");
286
287   /* If running uninstalled (G_TEST_BUILDDIR is set), skip this test, since we
288    * need the translations to be installed. We can’t mess around with
289    * bindtextdomain() here, as the compiled .gmo files in po/ are not in the
290    * right installed directory hierarchy to be successfully loaded by gettext. */
291   if (g_getenv ("G_TEST_BUILDDIR") != NULL)
292     {
293       g_test_skip ("Skipping due to running uninstalled. "
294                    "This test can only be run when the translations are installed.");
295       return;
296     }
297
298   /* This test can only work (on non-Windows platforms) if libc supports
299    * the %OB (etc.) format placeholders. If it doesn’t, strftime() (and hence
300    * g_date_strftime()) will return the placeholder unsubstituted.
301    * g_date_strftime() explicitly documents that it doesn’t provide any more
302    * format placeholders than the system strftime(), so we should skip the test
303    * in that case. If people need %OB support, they should depend on a suitable
304    * version of libc, or use g_date_time_format(). Note: a test for a support
305    * of _NL_ABALTMON_* is not strictly the same as checking for %OB support.
306    * Some platforms (BSD, OS X) support %OB while _NL_ABALTMON_* and %Ob
307    * are supported only by glibc 2.27 and newer. But we don’t care about BSD
308    * here, the aim of this test is to make sure that our custom implementation
309    * for Windows works the same as glibc 2.27 native implementation. */
310 #if !defined(HAVE_LANGINFO_ABALTMON) && !defined(G_OS_WIN32)
311   g_test_skip ("libc doesn’t support all alternative month names");
312 #else
313
314 #define TEST_DATE(d,m,y,f,o)                     G_STMT_START { \
315   gchar *o_casefold, *buf_casefold;                             \
316   g_date_set_dmy (gdate, d, m, y);                              \
317   g_date_strftime (buf, 100, f, gdate);                         \
318   buf_casefold = g_utf8_casefold (buf, -1);                     \
319   o_casefold = g_utf8_casefold ((o), -1);                       \
320   g_assert_cmpstr (buf_casefold, ==, o_casefold);               \
321   g_free (buf_casefold);                                        \
322   g_free (o_casefold);                                          \
323   g_date_set_parse (gdate, buf);                                \
324   g_assert (g_date_valid (gdate));                              \
325   g_assert_cmpint (g_date_get_day (gdate), ==, d);              \
326   g_assert_cmpint (g_date_get_month (gdate), ==, m);            \
327   g_assert_cmpint (g_date_get_year (gdate), ==, y);             \
328 } G_STMT_END
329
330   oldlocale = g_strdup (setlocale (LC_ALL, NULL));
331 #ifdef G_OS_WIN32
332   old_lcid = GetThreadLocale ();
333 #endif
334
335   gdate = g_date_new ();
336
337   /* Note: Windows implementation of g_date_strftime() does not support
338    * "-" format modifier (e.g., "%-d", "%-e") so we will not use it.
339    */
340
341   /* Make sure that nothing has been changed in western European languages.  */
342   setlocale (LC_ALL, "en_GB.utf-8");
343 #ifdef G_OS_WIN32
344   SetThreadLocale (MAKELCID (MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_UK), SORT_DEFAULT));
345 #endif
346   if (strstr (setlocale (LC_ALL, NULL), "en_GB") != NULL)
347     {
348       TEST_DATE (1,  1, 2018, "%B %d, %Y", "January 01, 2018");
349       TEST_DATE (1,  2, 2018,    "%OB %Y",    "February 2018");
350       TEST_DATE (1,  3, 2018,  "%e %b %Y",      " 1 Mar 2018");
351       TEST_DATE (1,  4, 2018,    "%Ob %Y",         "Apr 2018");
352       TEST_DATE (1,  5, 2018,  "%d %h %Y",      "01 May 2018");
353       TEST_DATE (1,  6, 2018,    "%Oh %Y",         "Jun 2018");
354     }
355   else
356     g_test_skip ("locale en_GB not available, skipping English month names test");
357
358   setlocale (LC_ALL, "de_DE.utf-8");
359 #ifdef G_OS_WIN32
360   SetThreadLocale (MAKELCID (MAKELANGID (LANG_GERMAN, SUBLANG_GERMAN), SORT_DEFAULT));
361 #endif
362   if (strstr (setlocale (LC_ALL, NULL), "de_DE") != NULL)
363     {
364       TEST_DATE (16,  7, 2018, "%d. %B %Y", "16. Juli 2018");
365       TEST_DATE ( 1,  8, 2018,    "%OB %Y",   "August 2018");
366       TEST_DATE (18,  9, 2018, "%e. %b %Y",  "18. Sep 2018");
367       TEST_DATE ( 1, 10, 2018,    "%Ob %Y",      "Okt 2018");
368       TEST_DATE (20, 11, 2018, "%d. %h %Y",  "20. Nov 2018");
369       TEST_DATE ( 1, 12, 2018,    "%Oh %Y",      "Dez 2018");
370     }
371   else
372     g_test_skip ("locale de_DE not available, skipping German month names test");
373
374
375   setlocale (LC_ALL, "es_ES.utf-8");
376 #ifdef G_OS_WIN32
377   SetThreadLocale (MAKELCID (MAKELANGID (LANG_SPANISH, SUBLANG_SPANISH_MODERN), SORT_DEFAULT));
378 #endif
379   if (strstr (setlocale (LC_ALL, NULL), "es_ES") != NULL)
380     {
381       TEST_DATE ( 9,  1, 2018, "%d de %B de %Y", "09 de enero de 2018");
382       TEST_DATE ( 1,  2, 2018,      "%OB de %Y",     "febrero de 2018");
383       TEST_DATE (10,  3, 2018, "%e de %b de %Y",   "10 de mar de 2018");
384       TEST_DATE ( 1,  4, 2018,      "%Ob de %Y",         "abr de 2018");
385       TEST_DATE (11,  5, 2018, "%d de %h de %Y",   "11 de may de 2018");
386       TEST_DATE ( 1,  6, 2018,      "%Oh de %Y",         "jun de 2018");
387     }
388   else
389     g_test_skip ("locale es_ES not available, skipping Spanish month names test");
390
391   setlocale (LC_ALL, "fr_FR.utf-8");
392 #ifdef G_OS_WIN32
393   SetThreadLocale (MAKELCID (MAKELANGID (LANG_FRENCH, SUBLANG_FRENCH), SORT_DEFAULT));
394 #endif
395   if (strstr (setlocale (LC_ALL, NULL), "fr_FR") != NULL)
396     {
397       TEST_DATE (31,  7, 2018, "%d %B %Y", "31 juillet 2018");
398       TEST_DATE ( 1,  8, 2018,   "%OB %Y",       "août 2018");
399       TEST_DATE (30,  9, 2018, "%e %b %Y",   "30 sept. 2018");
400       TEST_DATE ( 1, 10, 2018,   "%Ob %Y",       "oct. 2018");
401       TEST_DATE (29, 11, 2018, "%d %h %Y",    "29 nov. 2018");
402       TEST_DATE ( 1, 12, 2018,   "%Oh %Y",       "déc. 2018");
403     }
404   else
405     g_test_skip ("locale fr_FR not available, skipping French month names test");
406
407   /* Make sure that there are visible changes in some European languages.  */
408   setlocale (LC_ALL, "el_GR.utf-8");
409 #ifdef G_OS_WIN32
410   SetThreadLocale (MAKELCID (MAKELANGID (LANG_GREEK, SUBLANG_GREEK_GREECE), SORT_DEFAULT));
411 #endif
412   if (strstr (setlocale (LC_ALL, NULL), "el_GR") != NULL)
413     {
414       TEST_DATE ( 2,  1, 2018, "%d %B %Y",  "02 Ιανουαρίου 2018");
415       TEST_DATE ( 4,  2, 2018, "%e %B %Y", " 4 Φεβρουαρίου 2018");
416       TEST_DATE (15,  3, 2018, "%d %B %Y",     "15 Μαρτίου 2018");
417       TEST_DATE ( 1,  4, 2018,   "%OB %Y",       "Απρίλιος 2018");
418       TEST_DATE ( 1,  5, 2018,   "%OB %Y",          "Μάιος 2018");
419       TEST_DATE ( 1,  6, 2018,   "%OB %Y",        "Ιούνιος 2018");
420       TEST_DATE (16,  7, 2018, "%e %b %Y",        "16 Ιουλ 2018");
421       TEST_DATE ( 1,  8, 2018,   "%Ob %Y",            "Αύγ 2018");
422     }
423   else
424     g_test_skip ("locale el_GR not available, skipping Greek month names test");
425
426   setlocale (LC_ALL, "hr_HR.utf-8");
427 #ifdef G_OS_WIN32
428   SetThreadLocale (MAKELCID (MAKELANGID (LANG_CROATIAN, SUBLANG_CROATIAN_CROATIA), SORT_DEFAULT));
429 #endif
430   if (strstr (setlocale (LC_ALL, NULL), "hr_HR") != NULL)
431     {
432       TEST_DATE ( 8,  5, 2018, "%d. %B %Y", "08. svibnja 2018");
433       TEST_DATE ( 9,  6, 2018, "%e. %B %Y",  " 9. lipnja 2018");
434       TEST_DATE (10,  7, 2018, "%d. %B %Y",  "10. srpnja 2018");
435       TEST_DATE ( 1,  8, 2018,    "%OB %Y",     "Kolovoz 2018");
436       TEST_DATE ( 1,  9, 2018,    "%OB %Y",       "Rujan 2018");
437       TEST_DATE ( 1, 10, 2018,    "%OB %Y",    "Listopad 2018");
438       TEST_DATE (11, 11, 2018, "%e. %b %Y",     "11. Stu 2018");
439       TEST_DATE ( 1, 12, 2018,    "%Ob %Y",         "Pro 2018");
440     }
441   else
442     g_test_skip ("locale hr_HR not available, skipping Croatian month names test");
443
444   setlocale (LC_ALL, "lt_LT.utf-8");
445 #ifdef G_OS_WIN32
446   SetThreadLocale (MAKELCID (MAKELANGID (LANG_LITHUANIAN, SUBLANG_LITHUANIAN_LITHUANIA), SORT_DEFAULT));
447 #endif
448   if (strstr (setlocale (LC_ALL, NULL), "lt_LT") != NULL)
449     {
450       TEST_DATE ( 1,  1, 2018, "%Y m. %B %d d.",  "2018 m. sausio 01 d.");
451       TEST_DATE ( 2,  2, 2018, "%Y m. %B %e d.", "2018 m. vasario  2 d.");
452       TEST_DATE ( 3,  3, 2018, "%Y m. %B %d d.",    "2018 m. kovo 03 d.");
453       TEST_DATE ( 1,  4, 2018,      "%Y m. %OB",      "2018 m. balandis");
454       TEST_DATE ( 1,  5, 2018,      "%Y m. %OB",        "2018 m. gegužė");
455       TEST_DATE ( 1,  6, 2018,      "%Y m. %OB",      "2018 m. birželis");
456       TEST_DATE (17,  7, 2018, "%Y m. %b %e d.",   "2018 m. liep. 17 d.");
457       TEST_DATE ( 1,  8, 2018,      "%Y m. %Ob",         "2018 m. rugp.");
458     }
459   else
460     g_test_skip ("locale lt_LT not available, skipping Lithuanian month names test");
461
462   setlocale (LC_ALL, "pl_PL.utf-8");
463 #ifdef G_OS_WIN32
464   SetThreadLocale (MAKELCID (MAKELANGID (LANG_POLISH, SUBLANG_POLISH_POLAND), SORT_DEFAULT));
465 #endif
466   if (strstr (setlocale (LC_ALL, NULL), "pl_PL") != NULL)
467     {
468       TEST_DATE ( 3,  5, 2018, "%d %B %Y",     "03 maja 2018");
469       TEST_DATE ( 4,  6, 2018, "%e %B %Y",  " 4 czerwca 2018");
470       TEST_DATE (20,  7, 2018, "%d %B %Y",    "20 lipca 2018");
471       TEST_DATE ( 1,  8, 2018,   "%OB %Y",    "sierpień 2018");
472       TEST_DATE ( 1,  9, 2018,   "%OB %Y",    "wrzesień 2018");
473       TEST_DATE ( 1, 10, 2018,   "%OB %Y", "październik 2018");
474       TEST_DATE (25, 11, 2018, "%e %b %Y",      "25 lis 2018");
475       TEST_DATE ( 1, 12, 2018,   "%Ob %Y",         "gru 2018");
476     }
477   else
478     g_test_skip ("locale pl_PL not available, skipping Polish month names test");
479
480   setlocale (LC_ALL, "ru_RU.utf-8");
481 #ifdef G_OS_WIN32
482   SetThreadLocale (MAKELCID (MAKELANGID (LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA), SORT_DEFAULT));
483 #endif
484   if (strstr (setlocale (LC_ALL, NULL), "ru_RU") != NULL)
485     {
486       TEST_DATE ( 3,  1, 2018,      "%d %B %Y",  "03 января 2018");
487       TEST_DATE ( 4,  2, 2018,      "%e %B %Y", " 4 февраля 2018");
488       TEST_DATE (23,  3, 2018,      "%d %B %Y",   "23 марта 2018");
489       TEST_DATE ( 1,  4, 2018,        "%OB %Y",     "Апрель 2018");
490       TEST_DATE ( 1,  5, 2018,        "%OB %Y",        "Май 2018");
491       TEST_DATE ( 1,  6, 2018,        "%OB %Y",       "Июнь 2018");
492       TEST_DATE (24,  7, 2018,      "%e %b %Y",     "24 июл 2018");
493       TEST_DATE ( 1,  8, 2018,        "%Ob %Y",        "авг 2018");
494       /* This difference is very important in Russian:  */
495       TEST_DATE (19,  5, 2018,      "%e %b %Y",     "19 мая 2018");
496       TEST_DATE (20,  5, 2018, "%Ob, %d-е, %Y", "май, 20-е, 2018");
497     }
498   else
499     g_test_skip ("locale ru_RU not available, skipping Russian month names test");
500
501   g_date_free (gdate);
502
503   setlocale (LC_ALL, oldlocale);
504 #ifdef G_OS_WIN32
505   SetThreadLocale (old_lcid);
506 #endif
507   g_free (oldlocale);
508 #endif  /* defined(HAVE_LANGINFO_ABALTMON) || defined(G_OS_WIN32) */
509 }
510
511 static void
512 test_year (gconstpointer t)
513 {
514   GDateYear y = GPOINTER_TO_INT (t);
515   GDateMonth m;
516   GDateDay day;
517   guint32 j;
518   GDate *d;
519   gint i;
520   GDate tmp;
521
522   guint32 first_day_of_year = G_DATE_BAD_JULIAN;
523   guint16 days_in_year = g_date_is_leap_year (y) ? 366 : 365;
524   guint   sunday_week_of_year = 0;
525   guint   sunday_weeks_in_year = g_date_get_sunday_weeks_in_year (y);
526   guint   monday_week_of_year = 0;
527   guint   monday_weeks_in_year = g_date_get_monday_weeks_in_year (y);
528   guint   iso8601_week_of_year = 0;
529
530   g_assert (g_date_valid_year (y));
531   /* Years ought to have roundabout 52 weeks */
532   g_assert (sunday_weeks_in_year == 52 || sunday_weeks_in_year == 53);
533   g_assert (monday_weeks_in_year == 52 || monday_weeks_in_year == 53);
534
535   m = 1;
536   while (m < 13)
537     {
538       guint8 dim = g_date_get_days_in_month (m, y);
539       GDate days[31];
540
541       g_date_clear (days, 31);
542
543       g_assert (dim > 0 && dim < 32);
544       g_assert (g_date_valid_month (m));
545
546       day = 1;
547       while (day <= dim)
548         {
549           g_assert (g_date_valid_dmy (day, m, y));
550
551           d = &days[day - 1];
552           //g_assert (!g_date_valid (d));
553
554           g_date_set_dmy (d, day, m, y);
555
556           g_assert (g_date_valid (d));
557
558           if (m == G_DATE_JANUARY && day == 1)
559             first_day_of_year = g_date_get_julian (d);
560
561           g_assert (first_day_of_year != G_DATE_BAD_JULIAN);
562
563           g_assert_cmpint (g_date_get_month (d), ==, m);
564           g_assert_cmpint (g_date_get_year (d), ==, y);
565           g_assert_cmpint (g_date_get_day (d), ==, day);
566
567           g_assert (g_date_get_julian (d) + 1 - first_day_of_year ==
568                     g_date_get_day_of_year (d));
569
570           if (m == G_DATE_DECEMBER && day == 31)
571             g_assert_cmpint (g_date_get_day_of_year (d), ==, days_in_year);
572
573           g_assert_cmpint (g_date_get_day_of_year (d), <=, days_in_year);
574           g_assert_cmpint (g_date_get_monday_week_of_year (d), <=, monday_weeks_in_year);
575           g_assert_cmpint (g_date_get_monday_week_of_year (d), >=, monday_week_of_year);
576
577           if (g_date_get_weekday(d) == G_DATE_MONDAY)
578             {
579               g_assert_cmpint (g_date_get_monday_week_of_year (d) - monday_week_of_year, ==, 1);
580               if ((m == G_DATE_JANUARY && day <= 4) ||
581                   (m == G_DATE_DECEMBER && day >= 29))
582                  g_assert_cmpint (g_date_get_iso8601_week_of_year (d), ==, 1);
583               else
584                 g_assert_cmpint (g_date_get_iso8601_week_of_year (d) - iso8601_week_of_year, ==, 1);
585             }
586           else
587             {
588               g_assert_cmpint (g_date_get_monday_week_of_year(d) - monday_week_of_year, ==, 0);
589               if (!(day == 1 && m == G_DATE_JANUARY))
590                 g_assert_cmpint (g_date_get_iso8601_week_of_year(d) - iso8601_week_of_year, ==, 0);
591             }
592
593           monday_week_of_year = g_date_get_monday_week_of_year (d);
594           iso8601_week_of_year = g_date_get_iso8601_week_of_year (d);
595
596           g_assert_cmpint (g_date_get_sunday_week_of_year (d), <=, sunday_weeks_in_year);
597           g_assert_cmpint (g_date_get_sunday_week_of_year (d), >=, sunday_week_of_year);
598           if (g_date_get_weekday(d) == G_DATE_SUNDAY)
599             g_assert_cmpint (g_date_get_sunday_week_of_year (d) - sunday_week_of_year, ==, 1);
600           else
601             g_assert_cmpint (g_date_get_sunday_week_of_year (d) - sunday_week_of_year, ==, 0);
602
603           sunday_week_of_year = g_date_get_sunday_week_of_year (d);
604
605           g_assert_cmpint (g_date_compare (d, d), ==, 0);
606
607           i = 1;
608           while (i < 402) /* Need to get 400 year increments in */
609             {
610               tmp = *d;
611               g_date_add_days (d, i);
612               g_assert_cmpint (g_date_compare (d, &tmp), >, 0);
613               g_date_subtract_days (d, i);
614               g_assert_cmpint (g_date_get_day (d), ==, day);
615               g_assert_cmpint (g_date_get_month (d), ==, m);
616               g_assert_cmpint (g_date_get_year (d), ==, y);
617
618               tmp = *d;
619               g_date_add_months (d, i);
620               g_assert_cmpint (g_date_compare (d, &tmp), >, 0);
621               g_date_subtract_months (d, i);
622               g_assert_cmpint (g_date_get_month (d), ==, m);
623               g_assert_cmpint (g_date_get_year (d), ==, y);
624
625               if (day < 29)
626                 g_assert_cmpint (g_date_get_day (d), ==, day);
627               else
628                 g_date_set_day (d, day);
629
630               tmp = *d;
631               g_date_add_years (d, i);
632               g_assert_cmpint (g_date_compare (d, &tmp), >, 0);
633               g_date_subtract_years (d, i);
634               g_assert_cmpint (g_date_get_month (d), ==, m);
635               g_assert_cmpint (g_date_get_year (d), ==, y);
636
637               if (m != 2 && day != 29)
638                 g_assert_cmpint (g_date_get_day (d), ==, day);
639               else
640                 g_date_set_day (d, day); /* reset */
641
642               i += 10;
643             }
644
645           j = g_date_get_julian (d);
646
647           ++day;
648         }
649       ++m;
650    }
651
652   /* at this point, d is the last day of year y */
653   g_date_set_dmy (&tmp, 1, 1, y + 1);
654   g_assert_cmpint (j + 1, ==, g_date_get_julian (&tmp));
655
656   g_date_add_days (&tmp, 1);
657   g_assert_cmpint (j + 2, ==, g_date_get_julian (&tmp));
658 }
659
660 static void
661 test_clamp (void)
662 {
663   GDate d1, d2, d, o;
664
665   g_date_set_dmy (&d1, 1, 1, 1970);
666   g_date_set_dmy (&d2, 1, 1, 1980);
667   g_date_set_dmy (&d, 1, 1, 1);
668
669   o = d;
670   g_date_clamp (&o, NULL, NULL);
671   g_assert (g_date_compare (&o, &d) == 0);
672
673   g_date_clamp (&o,  &d1, &d2);
674   g_assert (g_date_compare (&o, &d1) == 0);
675
676   g_date_set_dmy (&o, 1, 1, 2000);
677
678   g_date_clamp (&o,  &d1, &d2);
679   g_assert (g_date_compare (&o, &d2) == 0);
680 }
681
682 static void
683 test_order (void)
684 {
685   GDate d1, d2;
686
687   g_date_set_dmy (&d1, 1, 1, 1970);
688   g_date_set_dmy (&d2, 1, 1, 1980);
689
690   g_assert (g_date_compare (&d1, &d2) == -1);
691   g_date_order (&d2, &d1);
692   g_assert (g_date_compare (&d1, &d2) == 1);
693 }
694
695 static void
696 test_copy (void)
697 {
698   GDate *d;
699   GDate *c;
700
701   d = g_date_new ();
702   g_assert_false (g_date_valid (d));
703
704   c = g_date_copy (d);
705   g_assert_nonnull (c);
706   g_assert_false (g_date_valid (c));
707   g_date_free (c);
708
709   g_date_set_day (d, 10);
710
711   c = g_date_copy (d);
712   g_date_set_month (c, 1);
713   g_date_set_year (c, 2015);
714   g_assert_true (g_date_valid (c));
715   g_assert_cmpuint (g_date_get_day (c), ==, 10);
716   g_date_free (c);
717
718   g_date_free (d);
719 }
720
721 /* Check the results of g_date_valid_dmy() for various inputs. */
722 static void
723 test_valid_dmy (void)
724 {
725   const struct
726     {
727       GDateDay day;
728       GDateMonth month;
729       GDateYear year;
730       gboolean expected_valid;
731     }
732   vectors[] =
733     {
734       /* Lower bounds */
735       { 0, 0, 0, FALSE },
736       { 1, 1, 1, TRUE },
737       { 1, 1, 0, FALSE },
738       /* Leap year month lengths */
739       { 30, 2, 2000, FALSE },
740       { 29, 2, 2000, TRUE },
741       { 29, 2, 2001, FALSE },
742       /* Maximum year */
743       { 1, 1, G_MAXUINT16, TRUE },
744     };
745   gsize i;
746
747   for (i = 0; i < G_N_ELEMENTS (vectors); i++)
748     {
749       gboolean valid;
750       g_test_message ("Vector %" G_GSIZE_FORMAT ": %04u-%02u-%02u, %s",
751                       i, vectors[i].year, vectors[i].month, vectors[i].day,
752                       vectors[i].expected_valid ? "valid" : "invalid");
753
754       valid = g_date_valid_dmy (vectors[i].day, vectors[i].month, vectors[i].year);
755
756       if (vectors[i].expected_valid)
757         g_assert_true (valid);
758       else
759         g_assert_false (valid);
760     }
761 }
762
763 int
764 main (int argc, char** argv)
765 {
766   gchar *path;
767   gsize i;
768
769   /* Try to get all the leap year cases. */
770   int check_years[] = {
771     1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
772     11, 12, 13, 14, 98, 99, 100, 101, 102, 103, 397,
773     398, 399, 400, 401, 402, 403, 404, 405, 406,
774     1598, 1599, 1600, 1601, 1602, 1650, 1651,
775     1897, 1898, 1899, 1900, 1901, 1902, 1903,
776     1961, 1962, 1963, 1964, 1965, 1967,
777     1968, 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1976,
778     1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985,
779     1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
780     1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
781     2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
782     3000, 3001, 3002, 3998, 3999, 4000, 4001, 4002, 4003
783   };
784
785   g_setenv ("LC_ALL", "en_US.utf-8", TRUE);
786   setlocale (LC_ALL, "");
787 #ifdef G_OS_WIN32
788   SetThreadLocale (MAKELCID (MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT));
789 #endif
790
791   g_test_init (&argc, &argv, NULL);
792   g_test_bug_base ("http://bugzilla.gnome.org/");
793
794   g_test_add_func ("/date/basic", test_basic);
795   g_test_add_func ("/date/empty", test_empty_constructor);
796   g_test_add_func ("/date/dmy", test_dmy_constructor);
797   g_test_add_func ("/date/julian", test_julian_constructor);
798   g_test_add_func ("/date/dates", test_dates);
799   g_test_add_func ("/date/parse", test_parse);
800   g_test_add_func ("/date/parse/invalid", test_parse_invalid);
801   g_test_add_func ("/date/parse_locale_change", test_parse_locale_change);
802   g_test_add_func ("/date/month_substring", test_month_substring);
803   g_test_add_func ("/date/month_names", test_month_names);
804   g_test_add_func ("/date/clamp", test_clamp);
805   g_test_add_func ("/date/order", test_order);
806   for (i = 0; i < G_N_ELEMENTS (check_years); i++)
807     {
808       path = g_strdup_printf ("/date/year/%d", check_years[i]);
809       g_test_add_data_func (path, GINT_TO_POINTER(check_years[i]), test_year);
810       g_free (path);
811     }
812   g_test_add_func ("/date/copy", test_copy);
813   g_test_add_func ("/date/valid-dmy", test_valid_dmy);
814
815   return g_test_run ();
816 }