LCOV - code coverage report
Current view: top level - libmogwai-tariff/tests - period.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 174 174 100.0 %
Date: 2022-06-30 20:59:16 Functions: 9 9 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 56 102 54.9 %

           Branch data     Line data    Source code
       1                 :            : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
       2                 :            :  *
       3                 :            :  * Copyright © 2018 Endless Mobile, Inc.
       4                 :            :  *
       5                 :            :  * This library is free software; you can redistribute it and/or
       6                 :            :  * modify it under the terms of the GNU Lesser General Public
       7                 :            :  * License as published by the Free Software Foundation; either
       8                 :            :  * version 2.1 of the License, or (at your option) any later version.
       9                 :            :  *
      10                 :            :  * This library is distributed in the hope that it will be useful,
      11                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13                 :            :  * Lesser General Public License for more details.
      14                 :            :  *
      15                 :            :  * You should have received a copy of the GNU Lesser General Public
      16                 :            :  * License along with this library; if not, write to the Free Software
      17                 :            :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      18                 :            :  *
      19                 :            :  * Authors:
      20                 :            :  *  - Philip Withnall <withnall@endlessm.com>
      21                 :            :  */
      22                 :            : 
      23                 :            : #include "config.h"
      24                 :            : 
      25                 :            : #include <glib.h>
      26                 :            : #include <gio/gio.h>
      27                 :            : #include <libmogwai-tariff/period.h>
      28                 :            : #include <locale.h>
      29                 :            : 
      30                 :            : 
      31                 :            : static void
      32                 :          6 : assert_period_validate (GDateTime           *start,
      33                 :            :                         GDateTime           *end,
      34                 :            :                         MwtPeriodRepeatType  repeat_type,
      35                 :            :                         guint                repeat_period)
      36                 :            : {
      37                 :          6 :   g_autoptr(GError) error = NULL;
      38                 :            : 
      39                 :          6 :   gboolean retval = mwt_period_validate (start, end, repeat_type, repeat_period, &error);
      40   [ +  -  +  -  :          6 :   g_assert_error (error, MWT_PERIOD_ERROR, MWT_PERIOD_ERROR_INVALID);
                   -  + ]
      41         [ -  + ]:          6 :   g_assert_false (retval);
      42                 :          6 : }
      43                 :            : 
      44                 :            : static GTimeZone *
      45                 :        572 : time_zone_new (const gchar *tz_str)
      46                 :            : {
      47                 :            : #if GLIB_CHECK_VERSION(2, 68, 0)
      48                 :       1144 :   g_autoptr(GTimeZone) tz = g_time_zone_new_identifier (tz_str);
      49         [ -  + ]:        572 :   g_assert_nonnull (tz);
      50                 :        572 :   return g_steal_pointer (&tz);
      51                 :            : #else
      52                 :            :   return g_time_zone_new (tz_str);
      53                 :            : #endif
      54                 :            : }
      55                 :            : 
      56                 :            : /* Test constructing a #MwtPeriod object with invalid arguments. */
      57                 :            : static void
      58                 :          1 : test_period_validation (void)
      59                 :            : {
      60                 :          2 :   g_autoptr(GDateTime) start = g_date_time_new_utc (2000, 01, 01, 01, 01, 01);
      61                 :          2 :   g_autoptr(GDateTime) end = g_date_time_new_utc (2000, 02, 01, 01, 01, 01);
      62                 :            : 
      63                 :          1 :   assert_period_validate (NULL, end, MWT_PERIOD_REPEAT_HOUR, 1);
      64                 :          1 :   assert_period_validate (start, NULL, MWT_PERIOD_REPEAT_HOUR, 1);
      65                 :          1 :   assert_period_validate (end, start, MWT_PERIOD_REPEAT_HOUR, 1);
      66                 :          1 :   assert_period_validate (start, end, MWT_PERIOD_REPEAT_NONE, 1);
      67                 :          1 :   assert_period_validate (start, end, MWT_PERIOD_REPEAT_HOUR, 0);
      68                 :          1 :   assert_period_validate (start, end, 500, 1);
      69                 :          1 : }
      70                 :            : 
      71                 :            : /* Test the GObject properties on a period. */
      72                 :            : static void
      73                 :          1 : test_period_properties (void)
      74                 :            : {
      75                 :          2 :   g_autoptr(GDateTime) start = g_date_time_new_utc (2000, 01, 01, 01, 01, 01);
      76                 :          2 :   g_autoptr(GDateTime) end = g_date_time_new_utc (2000, 02, 01, 01, 01, 01);
      77                 :            : 
      78                 :          1 :   g_autoptr(MwtPeriod) period = NULL;
      79                 :          1 :   period = mwt_period_new (start, end, MWT_PERIOD_REPEAT_HOUR, 1,
      80                 :            :                            "capacity-limit", (guint64) 5671,
      81                 :            :                            NULL);
      82         [ -  + ]:          1 :   g_assert_true (MWT_IS_PERIOD (period));
      83                 :            : 
      84         [ -  + ]:          1 :   g_assert_true (g_date_time_equal (mwt_period_get_start (period), start));
      85         [ -  + ]:          1 :   g_assert_true (g_date_time_equal (mwt_period_get_end (period), end));
      86         [ -  + ]:          1 :   g_assert_cmpint (mwt_period_get_repeat_type (period), ==, MWT_PERIOD_REPEAT_HOUR);
      87         [ -  + ]:          1 :   g_assert_cmpuint (mwt_period_get_repeat_period (period), ==, 1);
      88         [ -  + ]:          1 :   g_assert_cmpuint (mwt_period_get_capacity_limit (period), ==, 5671);
      89                 :            : 
      90                 :          1 :   g_autoptr(GDateTime) actual_start = NULL;
      91                 :          1 :   g_autoptr(GDateTime) actual_end = NULL;
      92                 :            :   MwtPeriodRepeatType repeat_type;
      93                 :            :   guint repeat_period;
      94                 :            :   guint64 capacity_limit;
      95                 :            : 
      96                 :          1 :   g_object_get (G_OBJECT (period),
      97                 :            :                 "start", &actual_start,
      98                 :            :                 "end", &actual_end,
      99                 :            :                 "repeat-type", &repeat_type,
     100                 :            :                 "repeat-period", &repeat_period,
     101                 :            :                 "capacity-limit", &capacity_limit,
     102                 :            :                 NULL);
     103                 :            : 
     104         [ -  + ]:          1 :   g_assert_true (g_date_time_equal (actual_start, start));
     105         [ -  + ]:          1 :   g_assert_true (g_date_time_equal (actual_end, end));
     106         [ -  + ]:          1 :   g_assert_cmpint (repeat_type, ==, MWT_PERIOD_REPEAT_HOUR);
     107         [ -  + ]:          1 :   g_assert_cmpuint (repeat_period, ==, 1);
     108         [ -  + ]:          1 :   g_assert_cmpuint (capacity_limit, ==, 5671);
     109                 :          1 : }
     110                 :            : 
     111                 :            : /* Test that the default values of all the limit properties for a period are
     112                 :            :  * sensible. */
     113                 :            : static void
     114                 :          1 : test_period_properties_defaults (void)
     115                 :            : {
     116                 :          2 :   g_autoptr(GDateTime) start = g_date_time_new_utc (2000, 01, 01, 01, 01, 01);
     117                 :          2 :   g_autoptr(GDateTime) end = g_date_time_new_utc (2000, 02, 01, 01, 01, 01);
     118                 :            : 
     119                 :          1 :   g_autoptr(MwtPeriod) period = NULL;
     120                 :          1 :   period = mwt_period_new (start, end, MWT_PERIOD_REPEAT_NONE, 0,
     121                 :            :                            /* leave everything as default */
     122                 :            :                            NULL);
     123         [ -  + ]:          1 :   g_assert_true (MWT_IS_PERIOD (period));
     124                 :            : 
     125                 :            :   /* Test default property values. */
     126         [ -  + ]:          1 :   g_assert_cmpuint (mwt_period_get_capacity_limit (period), ==, G_MAXUINT64);
     127                 :          1 : }
     128                 :            : 
     129                 :            : /* Test mwt_period_contains_time() returns correct results for a variety of
     130                 :            :  * situations. This tests mwt_period_get_next_recurrence() at the same time,
     131                 :            :  * since their results are quite tightly linked. */
     132                 :            : static void
     133                 :          1 : test_period_contains_time (void)
     134                 :            : {
     135                 :            :   const struct
     136                 :            :     {
     137                 :            :       gint start_year;
     138                 :            :       gint start_month;
     139                 :            :       gint start_day;
     140                 :            :       gint start_hour;
     141                 :            :       gint start_minute;
     142                 :            :       gdouble start_seconds;
     143                 :            :       const gchar *start_tz;
     144                 :            : 
     145                 :            :       gint end_year;
     146                 :            :       gint end_month;
     147                 :            :       gint end_day;
     148                 :            :       gint end_hour;
     149                 :            :       gint end_minute;
     150                 :            :       gdouble end_seconds;
     151                 :            :       const gchar *end_tz;
     152                 :            : 
     153                 :            :       MwtPeriodRepeatType repeat_type;
     154                 :            :       guint repeat_period;
     155                 :            : 
     156                 :            :       gint when_year;
     157                 :            :       gint when_month;
     158                 :            :       gint when_day;
     159                 :            :       gint when_hour;
     160                 :            :       gint when_minute;
     161                 :            :       gdouble when_seconds;
     162                 :            :       const gchar *when_tz;
     163                 :            : 
     164                 :            :       gboolean expected_contains;
     165                 :            : 
     166                 :            :       gint expected_contains_start_year;
     167                 :            :       gint expected_contains_start_month;
     168                 :            :       gint expected_contains_start_day;
     169                 :            :       gint expected_contains_start_hour;
     170                 :            :       gint expected_contains_start_minute;
     171                 :            :       gdouble expected_contains_start_seconds;
     172                 :            :       const gchar *expected_contains_start_tz;
     173                 :            : 
     174                 :            :       gint expected_contains_end_year;
     175                 :            :       gint expected_contains_end_month;
     176                 :            :       gint expected_contains_end_day;
     177                 :            :       gint expected_contains_end_hour;
     178                 :            :       gint expected_contains_end_minute;
     179                 :            :       gdouble expected_contains_end_seconds;
     180                 :            :       const gchar *expected_contains_end_tz;
     181                 :            : 
     182                 :            :       gboolean expected_next;
     183                 :            : 
     184                 :            :       gint expected_next_start_year;
     185                 :            :       gint expected_next_start_month;
     186                 :            :       gint expected_next_start_day;
     187                 :            :       gint expected_next_start_hour;
     188                 :            :       gint expected_next_start_minute;
     189                 :            :       gdouble expected_next_start_seconds;
     190                 :            :       const gchar *expected_next_start_tz;
     191                 :            : 
     192                 :            :       gint expected_next_end_year;
     193                 :            :       gint expected_next_end_month;
     194                 :            :       gint expected_next_end_day;
     195                 :            :       gint expected_next_end_hour;
     196                 :            :       gint expected_next_end_minute;
     197                 :            :       gdouble expected_next_end_seconds;
     198                 :            :       const gchar *expected_next_end_tz;
     199                 :            :     }
     200                 :          1 :   vectors[] =
     201                 :            :     {
     202                 :            :       /* Test boundaries on a simple period-1 weekly repeat. */
     203                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     204                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     205                 :            :         2017, 12, 31, 23, 59, 59.99, "Z",
     206                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     207                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z" },
     208                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     209                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     210                 :            :         2018, 1, 1, 0, 0, 0.0, "Z",
     211                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     212                 :            :         TRUE, 2018, 1, 8, 0, 0, 0.0, "Z", 2018, 1, 8, 4, 0, 0.0, "Z" },
     213                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     214                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     215                 :            :         2018, 1, 1, 2, 0, 0.0, "Z",
     216                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     217                 :            :         TRUE, 2018, 1, 8, 0, 0, 0.0, "Z", 2018, 1, 8, 4, 0, 0.0, "Z" },
     218                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     219                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     220                 :            :         2018, 1, 1, 3, 59, 59.99, "Z",
     221                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     222                 :            :         TRUE, 2018, 1, 8, 0, 0, 0.0, "Z", 2018, 1, 8, 4, 0, 0.0, "Z" },
     223                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     224                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     225                 :            :         2018, 1, 1, 4, 0, 0.0, "Z",
     226                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     227                 :            :         TRUE, 2018, 1, 8, 0, 0, 0.0, "Z", 2018, 1, 8, 4, 0, 0.0, "Z" },
     228                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     229                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     230                 :            :         2018, 1, 7, 23, 59, 59.99, "Z",
     231                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     232                 :            :         TRUE, 2018, 1, 8, 0, 0, 0.0, "Z", 2018, 1, 8, 4, 0, 0.0, "Z" },
     233                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     234                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     235                 :            :         2018, 1, 8, 0, 0, 0.0, "Z",
     236                 :            :         TRUE, 2018, 1, 8, 0, 0, 0.0, "Z", 2018, 1, 8, 4, 0, 0.0, "Z",
     237                 :            :         TRUE, 2018, 1, 15, 0, 0, 0.0, "Z", 2018, 1, 15, 4, 0, 0.0, "Z" },
     238                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     239                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     240                 :            :         2018, 1, 8, 2, 0, 0.0, "Z",
     241                 :            :         TRUE, 2018, 1, 8, 0, 0, 0.0, "Z", 2018, 1, 8, 4, 0, 0.0, "Z",
     242                 :            :         TRUE, 2018, 1, 15, 0, 0, 0.0, "Z", 2018, 1, 15, 4, 0, 0.0, "Z" },
     243                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     244                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     245                 :            :         2018, 1, 8, 3, 59, 59.99, "Z",
     246                 :            :         TRUE, 2018, 1, 8, 0, 0, 0.0, "Z", 2018, 1, 8, 4, 0, 0.0, "Z",
     247                 :            :         TRUE, 2018, 1, 15, 0, 0, 0.0, "Z", 2018, 1, 15, 4, 0, 0.0, "Z" },
     248                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     249                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     250                 :            :         2018, 1, 8, 4, 0, 0.0, "Z",
     251                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     252                 :            :         TRUE, 2018, 1, 15, 0, 0, 0.0, "Z", 2018, 1, 15, 4, 0, 0.0, "Z" },
     253                 :            :       /* The same, but with a period-3 repeat. */
     254                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     255                 :            :         MWT_PERIOD_REPEAT_WEEK, 3,
     256                 :            :         2018, 1, 1, 2, 0, 0.0, "Z",
     257                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     258                 :            :         TRUE, 2018, 1, 22, 0, 0, 0.0, "Z", 2018, 1, 22, 4, 0, 0.0, "Z" },
     259                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     260                 :            :         MWT_PERIOD_REPEAT_WEEK, 3,
     261                 :            :         2018, 1, 8, 2, 0, 0.0, "Z",
     262                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     263                 :            :         TRUE, 2018, 1, 22, 0, 0, 0.0, "Z", 2018, 1, 22, 4, 0, 0.0, "Z" },
     264                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     265                 :            :         MWT_PERIOD_REPEAT_WEEK, 3,
     266                 :            :         2018, 1, 15, 2, 0, 0.0, "Z",
     267                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     268                 :            :         TRUE, 2018, 1, 22, 0, 0, 0.0, "Z", 2018, 1, 22, 4, 0, 0.0, "Z" },
     269                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     270                 :            :         MWT_PERIOD_REPEAT_WEEK, 3,
     271                 :            :         2018, 1, 22, 2, 0, 0.0, "Z",
     272                 :            :         TRUE, 2018, 1, 22, 0, 0, 0.0, "Z", 2018, 1, 22, 4, 0, 0.0, "Z",
     273                 :            :         TRUE, 2018, 2, 12, 0, 0, 0.0, "Z", 2018, 2, 12, 4, 0, 0.0, "Z" },
     274                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     275                 :            :         MWT_PERIOD_REPEAT_WEEK, 3,
     276                 :            :         2018, 1, 29, 2, 0, 0.0, "Z",
     277                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     278                 :            :         TRUE, 2018, 2, 12, 0, 0, 0.0, "Z", 2018, 2, 12, 4, 0, 0.0, "Z" },
     279                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     280                 :            :         MWT_PERIOD_REPEAT_WEEK, 3,
     281                 :            :         2018, 2, 5, 2, 0, 0.0, "Z",
     282                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     283                 :            :         TRUE, 2018, 2, 12, 0, 0, 0.0, "Z", 2018, 2, 12, 4, 0, 0.0, "Z" },
     284                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     285                 :            :         MWT_PERIOD_REPEAT_WEEK, 3,
     286                 :            :         2018, 2, 12, 2, 0, 0.0, "Z",
     287                 :            :         TRUE, 2018, 2, 12, 0, 0, 0.0, "Z", 2018, 2, 12, 4, 0, 0.0, "Z",
     288                 :            :         TRUE, 2018, 3, 5, 0, 0, 0.0, "Z", 2018, 3, 5, 4, 0, 0.0, "Z" },
     289                 :            :       /* Test hourly repeats. */
     290                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 0, 30, 0.0, "Z",
     291                 :            :         MWT_PERIOD_REPEAT_HOUR, 1,
     292                 :            :         2017, 12, 31, 23, 59, 59.99, "Z",
     293                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     294                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 0, 30, 0.0, "Z" },
     295                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 0, 30, 0.0, "Z",
     296                 :            :         MWT_PERIOD_REPEAT_HOUR, 1,
     297                 :            :         2018, 1, 1, 0, 0, 0.0, "Z",
     298                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 0, 30, 0.0, "Z",
     299                 :            :         TRUE, 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 1, 30, 0.0, "Z" },
     300                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 0, 30, 0.0, "Z",
     301                 :            :         MWT_PERIOD_REPEAT_HOUR, 1,
     302                 :            :         2018, 1, 1, 0, 29, 59.99, "Z",
     303                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 0, 30, 0.0, "Z",
     304                 :            :         TRUE, 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 1, 30, 0.0, "Z" },
     305                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 0, 30, 0.0, "Z",
     306                 :            :         MWT_PERIOD_REPEAT_HOUR, 1,
     307                 :            :         2018, 1, 1, 0, 30, 0.0, "Z",
     308                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     309                 :            :         TRUE, 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 1, 30, 0.0, "Z" },
     310                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 0, 30, 0.0, "Z",
     311                 :            :         MWT_PERIOD_REPEAT_HOUR, 1,
     312                 :            :         2018, 1, 1, 1, 0, 0.0, "Z",
     313                 :            :         TRUE, 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 1, 30, 0.0, "Z",
     314                 :            :         TRUE, 2018, 1, 1, 2, 0, 0.0, "Z", 2018, 1, 1, 2, 30, 0.0, "Z" },
     315                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 0, 30, 0.0, "Z",
     316                 :            :         MWT_PERIOD_REPEAT_HOUR, 1,
     317                 :            :         2018, 1, 1, 2, 5, 0.0, "Z",
     318                 :            :         TRUE, 2018, 1, 1, 2, 0, 0.0, "Z", 2018, 1, 1, 2, 30, 0.0, "Z",
     319                 :            :         TRUE, 2018, 1, 1, 3, 0, 0.0, "Z", 2018, 1, 1, 3, 30, 0.0, "Z" },
     320                 :            :       /* Test daily repeats. */
     321                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     322                 :            :         MWT_PERIOD_REPEAT_DAY, 2,
     323                 :            :         2017, 12, 31, 23, 59, 59.99, "Z",
     324                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     325                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z" },
     326                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     327                 :            :         MWT_PERIOD_REPEAT_DAY, 2,
     328                 :            :         2018, 1, 1, 0, 0, 0.0, "Z",
     329                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     330                 :            :         TRUE, 2018, 1, 3, 0, 0, 0.0, "Z", 2018, 1, 3, 4, 0, 0.0, "Z" },
     331                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     332                 :            :         MWT_PERIOD_REPEAT_DAY, 2,
     333                 :            :         2018, 1, 1, 3, 0, 0.0, "Z",
     334                 :            :         TRUE, 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     335                 :            :         TRUE, 2018, 1, 3, 0, 0, 0.0, "Z", 2018, 1, 3, 4, 0, 0.0, "Z" },
     336                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     337                 :            :         MWT_PERIOD_REPEAT_DAY, 2,
     338                 :            :         2018, 1, 1, 4, 0, 0.0, "Z",
     339                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     340                 :            :         TRUE, 2018, 1, 3, 0, 0, 0.0, "Z", 2018, 1, 3, 4, 0, 0.0, "Z" },
     341                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     342                 :            :         MWT_PERIOD_REPEAT_DAY, 2,
     343                 :            :         2018, 1, 2, 0, 0, 0.0, "Z",
     344                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     345                 :            :         TRUE, 2018, 1, 3, 0, 0, 0.0, "Z", 2018, 1, 3, 4, 0, 0.0, "Z" },
     346                 :            :       { 2018, 1, 1, 0, 0, 0.0, "Z", 2018, 1, 1, 4, 0, 0.0, "Z",
     347                 :            :         MWT_PERIOD_REPEAT_DAY, 2,
     348                 :            :         2018, 1, 3, 0, 0, 0.0, "Z",
     349                 :            :         TRUE, 2018, 1, 3, 0, 0, 0.0, "Z", 2018, 1, 3, 4, 0, 0.0, "Z",
     350                 :            :         TRUE, 2018, 1, 5, 0, 0, 0.0, "Z", 2018, 1, 5, 4, 0, 0.0, "Z" },
     351                 :            :       /* Test monthly repeats (at period-2). */
     352                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     353                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     354                 :            :         2018, 1, 1, 0, 0, 0.0, "Z",
     355                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     356                 :            :         TRUE, 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z" },
     357                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     358                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     359                 :            :         2018, 1, 1, 1, 0, 0.0, "Z",
     360                 :            :         TRUE, 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     361                 :            :         TRUE, 2018, 3, 1, 1, 0, 0.0, "Z", 2018, 3, 1, 5, 0, 0.0, "Z" },
     362                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     363                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     364                 :            :         2018, 1, 1, 4, 0, 0.0, "Z",
     365                 :            :         TRUE, 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     366                 :            :         TRUE, 2018, 3, 1, 1, 0, 0.0, "Z", 2018, 3, 1, 5, 0, 0.0, "Z" },
     367                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     368                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     369                 :            :         2018, 1, 1, 5, 0, 0.0, "Z",
     370                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     371                 :            :         TRUE, 2018, 3, 1, 1, 0, 0.0, "Z", 2018, 3, 1, 5, 0, 0.0, "Z" },
     372                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     373                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     374                 :            :         2018, 1, 8, 4, 0, 0.0, "Z",
     375                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     376                 :            :         TRUE, 2018, 3, 1, 1, 0, 0.0, "Z", 2018, 3, 1, 5, 0, 0.0, "Z" },
     377                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     378                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     379                 :            :         2018, 1, 31, 4, 0, 0.0, "Z",
     380                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     381                 :            :         TRUE, 2018, 3, 1, 1, 0, 0.0, "Z", 2018, 3, 1, 5, 0, 0.0, "Z" },
     382                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     383                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     384                 :            :         2018, 2, 1, 4, 0, 0.0, "Z",
     385                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     386                 :            :         TRUE, 2018, 3, 1, 1, 0, 0.0, "Z", 2018, 3, 1, 5, 0, 0.0, "Z" },
     387                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     388                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     389                 :            :         2018, 3, 1, 4, 0, 0.0, "Z",
     390                 :            :         TRUE, 2018, 3, 1, 1, 0, 0.0, "Z", 2018, 3, 1, 5, 0, 0.0, "Z",
     391                 :            :         TRUE, 2018, 5, 1, 1, 0, 0.0, "Z", 2018, 5, 1, 5, 0, 0.0, "Z" },
     392                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     393                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     394                 :            :         2018, 4, 1, 4, 0, 0.0, "Z",
     395                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     396                 :            :         TRUE, 2018, 5, 1, 1, 0, 0.0, "Z", 2018, 5, 1, 5, 0, 0.0, "Z" },
     397                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     398                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     399                 :            :         2018, 5, 1, 4, 0, 0.0, "Z",
     400                 :            :         TRUE, 2018, 5, 1, 1, 0, 0.0, "Z", 2018, 5, 1, 5, 0, 0.0, "Z",
     401                 :            :         TRUE, 2018, 7, 1, 1, 0, 0.0, "Z", 2018, 7, 1, 5, 0, 0.0, "Z" },
     402                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     403                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     404                 :            :         2018, 11, 1, 4, 0, 0.0, "Z",
     405                 :            :         TRUE, 2018, 11, 1, 1, 0, 0.0, "Z", 2018, 11, 1, 5, 0, 0.0, "Z",
     406                 :            :         TRUE, 2019, 1, 1, 1, 0, 0.0, "Z", 2019, 1, 1, 5, 0, 0.0, "Z" },
     407                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     408                 :            :         MWT_PERIOD_REPEAT_MONTH, 2,
     409                 :            :         2118, 1, 1, 4, 0, 0.0, "Z",
     410                 :            :         TRUE, 2118, 1, 1, 1, 0, 0.0, "Z", 2118, 1, 1, 5, 0, 0.0, "Z",
     411                 :            :         TRUE, 2118, 3, 1, 1, 0, 0.0, "Z", 2118, 3, 1, 5, 0, 0.0, "Z" },
     412                 :            :       /* Test yearly repeats. */
     413                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     414                 :            :         MWT_PERIOD_REPEAT_YEAR, 1,
     415                 :            :         2018, 1, 1, 0, 0, 0.0, "Z",
     416                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     417                 :            :         TRUE, 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z" },
     418                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     419                 :            :         MWT_PERIOD_REPEAT_YEAR, 1,
     420                 :            :         2018, 1, 1, 1, 0, 0.0, "Z",
     421                 :            :         TRUE, 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     422                 :            :         TRUE, 2019, 1, 1, 1, 0, 0.0, "Z", 2019, 1, 1, 5, 0, 0.0, "Z" },
     423                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     424                 :            :         MWT_PERIOD_REPEAT_YEAR, 1,
     425                 :            :         2019, 1, 1, 4, 0, 0.0, "Z",
     426                 :            :         TRUE, 2019, 1, 1, 1, 0, 0.0, "Z", 2019, 1, 1, 5, 0, 0.0, "Z",
     427                 :            :         TRUE, 2020, 1, 1, 1, 0, 0.0, "Z", 2020, 1, 1, 5, 0, 0.0, "Z" },
     428                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     429                 :            :         MWT_PERIOD_REPEAT_YEAR, 1,
     430                 :            :         2020, 1, 1, 4, 0, 0.0, "Z",
     431                 :            :         TRUE, 2020, 1, 1, 1, 0, 0.0, "Z", 2020, 1, 1, 5, 0, 0.0, "Z",
     432                 :            :         TRUE, 2021, 1, 1, 1, 0, 0.0, "Z", 2021, 1, 1, 5, 0, 0.0, "Z" },
     433                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     434                 :            :         MWT_PERIOD_REPEAT_YEAR, 1,
     435                 :            :         3000, 1, 1, 0, 59, 59.99, "Z",
     436                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     437                 :            :         TRUE, 3000, 1, 1, 1, 0, 0.0, "Z", 3000, 1, 1, 5, 0, 0.0, "Z" },
     438                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     439                 :            :         MWT_PERIOD_REPEAT_YEAR, 1,
     440                 :            :         3000, 1, 1, 1, 0, 0.0, "Z",
     441                 :            :         TRUE, 3000, 1, 1, 1, 0, 0.0, "Z", 3000, 1, 1, 5, 0, 0.0, "Z",
     442                 :            :         TRUE, 3001, 1, 1, 1, 0, 0.0, "Z", 3001, 1, 1, 5, 0, 0.0, "Z" },
     443                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     444                 :            :         MWT_PERIOD_REPEAT_YEAR, 1,
     445                 :            :         3000, 1, 1, 4, 0, 0.0, "Z",
     446                 :            :         TRUE, 3000, 1, 1, 1, 0, 0.0, "Z", 3000, 1, 1, 5, 0, 0.0, "Z",
     447                 :            :         TRUE, 3001, 1, 1, 1, 0, 0.0, "Z", 3001, 1, 1, 5, 0, 0.0, "Z" },
     448                 :            :       { 2018, 1, 1, 1, 0, 0.0, "Z", 2018, 1, 1, 5, 0, 0.0, "Z",
     449                 :            :         MWT_PERIOD_REPEAT_YEAR, 1,
     450                 :            :         3000, 1, 1, 5, 0, 0.0, "Z",
     451                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     452                 :            :         TRUE, 3001, 1, 1, 1, 0, 0.0, "Z", 3001, 1, 1, 5, 0, 0.0, "Z" },
     453                 :            :       /* Leap year handling. 2020 is a leap year. A period on the 30th of January
     454                 :            :        * which repeats monthly should repeat on the last day of February. */
     455                 :            :       { 2018, 1, 30, 1, 0, 0.0, "Z", 2018, 1, 30, 5, 0, 0.0, "Z",
     456                 :            :         MWT_PERIOD_REPEAT_MONTH, 1,
     457                 :            :         2018, 1, 30, 4, 0, 0.0, "Z",
     458                 :            :         TRUE, 2018, 1, 30, 1, 0, 0.0, "Z", 2018, 1, 30, 5, 0, 0.0, "Z",
     459                 :            :         TRUE, 2018, 2, 28, 1, 0, 0.0, "Z", 2018, 2, 28, 5, 0, 0.0, "Z" },
     460                 :            :       { 2018, 1, 30, 1, 0, 0.0, "Z", 2018, 1, 30, 5, 0, 0.0, "Z",
     461                 :            :         MWT_PERIOD_REPEAT_MONTH, 1,
     462                 :            :         2018, 2, 28, 4, 0, 0.0, "Z",
     463                 :            :         TRUE, 2018, 2, 28, 1, 0, 0.0, "Z", 2018, 2, 28, 5, 0, 0.0, "Z",
     464                 :            :         TRUE, 2018, 3, 30, 1, 0, 0.0, "Z", 2018, 3, 30, 5, 0, 0.0, "Z" },
     465                 :            :       { 2018, 1, 30, 1, 0, 0.0, "Z", 2018, 1, 30, 5, 0, 0.0, "Z",
     466                 :            :         MWT_PERIOD_REPEAT_MONTH, 1,
     467                 :            :         2020, 1, 28, 4, 0, 0.0, "Z",
     468                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     469                 :            :         TRUE, 2020, 1, 30, 1, 0, 0.0, "Z", 2020, 1, 30, 5, 0, 0.0, "Z" },
     470                 :            :       { 2018, 1, 30, 1, 0, 0.0, "Z", 2018, 1, 30, 5, 0, 0.0, "Z",
     471                 :            :         MWT_PERIOD_REPEAT_MONTH, 1,
     472                 :            :         2020, 2, 29, 4, 0, 0.0, "Z",
     473                 :            :         TRUE, 2020, 2, 29, 1, 0, 0.0, "Z", 2020, 2, 29, 5, 0, 0.0, "Z",
     474                 :            :         TRUE, 2020, 3, 30, 1, 0, 0.0, "Z", 2020, 3, 30, 5, 0, 0.0, "Z" },
     475                 :            :       /* Check DST handling. There’s a DST switch on 2018-03-25 in Europe/London,
     476                 :            :        * where the clocks go forward 1h at 01:00, so the period 01:00–01:59 does
     477                 :            :        * not exist: so we expect no recurrences on 2018-03-25 at all, but expect
     478                 :            :        * recurrences during the normal time period (01:30–01:45) in subsequent
     479                 :            :        * weeks. */
     480                 :            :       { 2018, 3, 18, 1, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 45, 0.0, "Europe/London",
     481                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     482                 :            :         2018, 3, 18, 1, 35, 0.0, "Europe/London",
     483                 :            :         TRUE, 2018, 3, 18, 1, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 45, 0.0, "Europe/London",
     484                 :            :         TRUE, 2018, 4, 1, 1, 30, 0.0, "Europe/London", 2018, 4, 1, 1, 45, 0.0, "Europe/London" },
     485                 :            :       { 2018, 3, 18, 1, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 45, 0.0, "Europe/London",
     486                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     487                 :            :         2018, 3, 25, 1, 0, 0.0, "Europe/London",
     488                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Europe/London", 0, 0, 0, 0, 0, 0.0, "Europe/London",
     489                 :            :         TRUE, 2018, 4, 1, 1, 30, 0.0, "Europe/London", 2018, 4, 1, 1, 45, 0.0, "Europe/London" },
     490                 :            :       { 2018, 3, 18, 1, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 45, 0.0, "Europe/London",
     491                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     492                 :            :         2018, 3, 25, 0, 59, 59.99, "Europe/London",
     493                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Europe/London", 0, 0, 0, 0, 0, 0.0, "Europe/London",
     494                 :            :         TRUE, 2018, 4, 1, 1, 30, 0.0, "Europe/London", 2018, 4, 1, 1, 45, 0.0, "Europe/London" },
     495                 :            :       { 2018, 3, 18, 1, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 45, 0.0, "Europe/London",
     496                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     497                 :            :         2018, 3, 25, 1, 35, 0.0, "Europe/London",
     498                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Europe/London", 0, 0, 0, 0, 0, 0.0, "Europe/London",
     499                 :            :         TRUE, 2018, 4, 1, 1, 30, 0.0, "Europe/London", 2018, 4, 1, 1, 45, 0.0, "Europe/London" },
     500                 :            :       { 2018, 3, 18, 1, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 45, 0.0, "Europe/London",
     501                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     502                 :            :         2018, 3, 25, 2, 0, 0.0, "Europe/London",
     503                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Europe/London", 0, 0, 0, 0, 0, 0.0, "Europe/London",
     504                 :            :         TRUE, 2018, 4, 1, 1, 30, 0.0, "Europe/London", 2018, 4, 1, 1, 45, 0.0, "Europe/London" },
     505                 :            :       { 2018, 3, 18, 1, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 45, 0.0, "Europe/London",
     506                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     507                 :            :         2018, 4, 1, 1, 29, 59.99, "Europe/London",
     508                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Europe/London", 0, 0, 0, 0, 0, 0.0, "Europe/London",
     509                 :            :         TRUE, 2018, 4, 1, 1, 30, 0.0, "Europe/London", 2018, 4, 1, 1, 45, 0.0, "Europe/London" },
     510                 :            :       { 2018, 3, 18, 1, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 45, 0.0, "Europe/London",
     511                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     512                 :            :         2018, 4, 1, 1, 35, 0.0, "Europe/London",
     513                 :            :         TRUE, 2018, 4, 1, 1, 30, 0.0, "Europe/London", 2018, 4, 1, 1, 45, 0.0, "Europe/London",
     514                 :            :         TRUE, 2018, 4, 8, 1, 30, 0.0, "Europe/London", 2018, 4, 8, 1, 45, 0.0, "Europe/London" },
     515                 :            :       { 2018, 3, 18, 1, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 45, 0.0, "Europe/London",
     516                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     517                 :            :         2018, 4, 1, 1, 45, 0.0, "Europe/London",
     518                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Europe/London", 0, 0, 0, 0, 0, 0.0, "Europe/London",
     519                 :            :         TRUE, 2018, 4, 8, 1, 30, 0.0, "Europe/London", 2018, 4, 8, 1, 45, 0.0, "Europe/London" },
     520                 :            :       { 2018, 3, 18, 1, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 45, 0.0, "Europe/London",
     521                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     522                 :            :         2018, 4, 8, 1, 35, 0.0, "Europe/London",
     523                 :            :         TRUE, 2018, 4, 8, 1, 30, 0.0, "Europe/London", 2018, 4, 8, 1, 45, 0.0, "Europe/London",
     524                 :            :         TRUE, 2018, 4, 15, 1, 30, 0.0, "Europe/London", 2018, 4, 15, 1, 45, 0.0, "Europe/London" },
     525                 :            :       /* A DST check for a period which contains a DST hole and some time on
     526                 :            :        * either side. This is the same DST switch as above; the period
     527                 :            :        * 01:00–01:59 does not exist. However, since our recurrence contains time
     528                 :            :        * either side, we expect the recurrence to exist every week, including
     529                 :            :        * the week of the DST switch. The length of the recurrence (not tested
     530                 :            :        * here) will be 60 minutes shorter on that week, though. */
     531                 :            :       { 2018, 3, 18, 0, 30, 0.0, "Europe/London", 2018, 3, 18, 2, 30, 0.0, "Europe/London",
     532                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     533                 :            :         2018, 3, 18, 1, 35, 0.0, "Europe/London",
     534                 :            :         TRUE, 2018, 3, 18, 0, 30, 0.0, "Europe/London", 2018, 3, 18, 2, 30, 0.0, "Europe/London",
     535                 :            :         TRUE, 2018, 3, 25, 0, 30, 0.0, "Europe/London", 2018, 3, 25, 2, 30, 0.0, "Europe/London" },
     536                 :            :       { 2018, 3, 18, 0, 30, 0.0, "Europe/London", 2018, 3, 18, 2, 30, 0.0, "Europe/London",
     537                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     538                 :            :         2018, 3, 25, 0, 30, 0.0, "Europe/London",
     539                 :            :         TRUE, 2018, 3, 25, 0, 30, 0.0, "Europe/London", 2018, 3, 25, 2, 30, 0.0, "Europe/London",
     540                 :            :         TRUE, 2018, 4, 1, 0, 30, 0.0, "Europe/London", 2018, 4, 1, 2, 30, 0.0, "Europe/London" },
     541                 :            :       { 2018, 3, 18, 0, 30, 0.0, "Europe/London", 2018, 3, 18, 2, 30, 0.0, "Europe/London",
     542                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     543                 :            :         2018, 3, 25, 1, 0, 0.0, "Europe/London",
     544                 :            :         TRUE, 2018, 3, 25, 0, 30, 0.0, "Europe/London", 2018, 3, 25, 2, 30, 0.0, "Europe/London",
     545                 :            :         TRUE, 2018, 4, 1, 0, 30, 0.0, "Europe/London", 2018, 4, 1, 2, 30, 0.0, "Europe/London" },
     546                 :            :       { 2018, 3, 18, 0, 30, 0.0, "Europe/London", 2018, 3, 18, 2, 30, 0.0, "Europe/London",
     547                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     548                 :            :         2018, 3, 25, 2, 0, 0.0, "Europe/London",
     549                 :            :         TRUE, 2018, 3, 25, 0, 30, 0.0, "Europe/London", 2018, 3, 25, 2, 30, 0.0, "Europe/London",
     550                 :            :         TRUE, 2018, 4, 1, 0, 30, 0.0, "Europe/London", 2018, 4, 1, 2, 30, 0.0, "Europe/London" },
     551                 :            :       /* Partial overlap with a DST hole, using all the same setup as
     552                 :            :        * immediately above. */
     553                 :            :       { 2018, 3, 18, 0, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 30, 0.0, "Europe/London",
     554                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     555                 :            :         2018, 3, 18, 0, 35, 0.0, "Europe/London",
     556                 :            :         TRUE, 2018, 3, 18, 0, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 30, 0.0, "Europe/London",
     557                 :            :         TRUE, 2018, 3, 25, 0, 30, 0.0, "Europe/London", 2018, 3, 25, 2, 0, 0.0, "Europe/London" },
     558                 :            :       { 2018, 3, 18, 0, 30, 0.0, "Europe/London", 2018, 3, 18, 1, 30, 0.0, "Europe/London",
     559                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     560                 :            :         2018, 3, 25, 0, 35, 0.0, "Europe/London",
     561                 :            :         TRUE, 2018, 3, 25, 0, 30, 0.0, "Europe/London", 2018, 3, 25, 2, 0, 0.0, "Europe/London",
     562                 :            :         TRUE, 2018, 4, 1, 0, 30, 0.0, "Europe/London", 2018, 4, 1, 1, 30, 0.0, "Europe/London" },
     563                 :            :       /* Test what gnome-control-center does, which is to have two periods: one
     564                 :            :        * covers all time (no need to test that, as it doesn’t recur), and the
     565                 :            :        * other covers 22:00–06:00 at the start of the Unix time period in 1970,
     566                 :            :        * and recurs every day. Test that works, and doesn’t perform badly. (This
     567                 :            :        * is an implicit performance test, in that the test shouldn’t take
     568                 :            :        * forever to run, rather than an explicit one counting loop cycles. We’re
     569                 :            :        * not *that* concerned about performance. */
     570                 :            :       { 1970, 1, 1, 22, 0, 0.0, "Z", 1970, 1, 2, 6, 0, 0.0, "Z",
     571                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     572                 :            :         2018, 2, 1, 21, 59, 59.99, "Z",
     573                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     574                 :            :         TRUE, 2018, 2, 1, 22, 0, 0.0, "Z", 2018, 2, 2, 6, 0, 0.0, "Z" },
     575                 :            :       { 1970, 1, 1, 22, 0, 0.0, "Z", 1970, 1, 2, 6, 0, 0.0, "Z",
     576                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     577                 :            :         2018, 2, 1, 22, 0, 0.0, "Z",
     578                 :            :         TRUE, 2018, 2, 1, 22, 0, 0.0, "Z", 2018, 2, 2, 6, 0, 0.0, "Z",
     579                 :            :         TRUE, 2018, 2, 2, 22, 0, 0.0, "Z", 2018, 2, 3, 6, 0, 0.0, "Z" },
     580                 :            :       { 1970, 1, 1, 22, 0, 0.0, "Z", 1970, 1, 2, 6, 0, 0.0, "Z",
     581                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     582                 :            :         2018, 2, 2, 1, 0, 0.0, "Z",
     583                 :            :         TRUE, 2018, 2, 1, 22, 0, 0.0, "Z", 2018, 2, 2, 6, 0, 0.0, "Z",
     584                 :            :         TRUE, 2018, 2, 2, 22, 0, 0.0, "Z", 2018, 2, 3, 6, 0, 0.0, "Z" },
     585                 :            :       { 1970, 1, 1, 22, 0, 0.0, "Z", 1970, 1, 2, 6, 0, 0.0, "Z",
     586                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     587                 :            :         2018, 2, 2, 6, 0, 0.0, "Z",
     588                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     589                 :            :         TRUE, 2018, 2, 2, 22, 0, 0.0, "Z", 2018, 2, 3, 6, 0, 0.0, "Z" },
     590                 :            :       /* Test situations where there is no next recurrence (THE END OF TIME),
     591                 :            :        * where either the next recurring start time, or end time, or both, would
     592                 :            :        * overflow #GDateTime. */
     593                 :            :       { 1970, 1, 1, 22, 0, 0.0, "Z", 1970, 1, 2, 6, 0, 0.0, "Z",
     594                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     595                 :            :         9999, 12, 29, 22, 0, 0.0, "Z",
     596                 :            :         TRUE, 9999, 12, 29, 22, 0, 0.0, "Z", 9999, 12, 30, 6, 0, 0.0, "Z",
     597                 :            :         TRUE, 9999, 12, 30, 22, 0, 0.0, "Z", 9999, 12, 31, 6, 0, 0.0, "Z" },
     598                 :            :       { 1970, 1, 1, 22, 0, 0.0, "Z", 1970, 1, 2, 6, 0, 0.0, "Z",
     599                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     600                 :            :         9999, 12, 30, 22, 0, 0.0, "Z",
     601                 :            :         TRUE, 9999, 12, 30, 22, 0, 0.0, "Z", 9999, 12, 31, 6, 0, 0.0, "Z",
     602                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z" },
     603                 :            :       { 1970, 1, 1, 22, 0, 0.0, "Z", 1970, 1, 2, 6, 0, 0.0, "Z",
     604                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     605                 :            :         9999, 12, 31, 22, 0, 0.0, "Z",
     606                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     607                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z" },
     608                 :            :       { 2018, 1, 1, 22, 0, 0.0, "Z", 2018, 1, 1, 23, 0, 0.0, "Z",
     609                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     610                 :            :         9999, 12, 29, 22, 0, 0.0, "Z",
     611                 :            :         TRUE, 9999, 12, 29, 22, 0, 0.0, "Z", 9999, 12, 29, 23, 0, 0.0, "Z",
     612                 :            :         TRUE, 9999, 12, 30, 22, 0, 0.0, "Z", 9999, 12, 30, 23, 0, 0.0, "Z" },
     613                 :            :       { 2018, 1, 1, 22, 0, 0.0, "Z", 2018, 1, 1, 23, 0, 0.0, "Z",
     614                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     615                 :            :         9999, 12, 30, 22, 0, 0.0, "Z",
     616                 :            :         TRUE, 9999, 12, 30, 22, 0, 0.0, "Z", 9999, 12, 30, 23, 0, 0.0, "Z",
     617                 :            :         TRUE, 9999, 12, 31, 22, 0, 0.0, "Z", 9999, 12, 31, 23, 0, 0.0, "Z" },
     618                 :            :       { 2018, 1, 1, 22, 0, 0.0, "Z", 2018, 1, 1, 23, 0, 0.0, "Z",
     619                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     620                 :            :         9999, 12, 31, 22, 0, 0.0, "Z",
     621                 :            :         TRUE, 9999, 12, 31, 22, 0, 0.0, "Z", 9999, 12, 31, 23, 0, 0.0, "Z",
     622                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z" },
     623                 :            :       { 2018, 1, 1, 22, 0, 0.0, "Z", 2018, 1, 1, 23, 0, 0.0, "Z",
     624                 :            :         MWT_PERIOD_REPEAT_DAY, 1,
     625                 :            :         9999, 12, 31, 23, 0, 0.0, "Z",
     626                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     627                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z" },
     628                 :            :       /* More DST checks. There’s a DST switch on 2018-10-28 in Europe/London,
     629                 :            :        * where the clocks go backward 1h at 02:00, so the period 01:00–01:59
     630                 :            :        * happens twice (once in the daylight savings timezone, once outside it).
     631                 :            :        * We expect a recurrence to fall on the first occurrence of those hours,
     632                 :            :        * but not the second (since that’s not a week later).
     633                 :            :        * In this test, we sometimes express the timezone as ±hh to make it clear
     634                 :            :        * which side of the DST switch a time is on: the times
     635                 :            :        * 2018-10-28T01:30:00+01 and 2018-10-28T01:30:00+00 both happen in
     636                 :            :        * Europe/London (in that order). */
     637                 :            :       { 2018, 10, 21, 1, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 45, 0.0, "Europe/London",
     638                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     639                 :            :         2018, 10, 21, 1, 35, 0.0, "Europe/London",
     640                 :            :         TRUE, 2018, 10, 21, 1, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 45, 0.0, "Europe/London",
     641                 :            :         TRUE, 2018, 10, 28, 1, 30, 0.0, "+01", 2018, 10, 28, 1, 45, 0.0, "+01" },
     642                 :            :       { 2018, 10, 21, 1, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 45, 0.0, "Europe/London",
     643                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     644                 :            :         2018, 10, 28, 1, 35, 0.0, "+01",
     645                 :            :         TRUE, 2018, 10, 28, 1, 30, 0.0, "+01", 2018, 10, 28, 1, 45, 0.0, "+01",
     646                 :            :         TRUE, 2018, 11, 04, 1, 30, 0.0, "Europe/London", 2018, 11, 04, 1, 45, 0.0, "Europe/London" },
     647                 :            :       { 2018, 10, 21, 1, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 45, 0.0, "Europe/London",
     648                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     649                 :            :         2018, 10, 28, 2, 0, 0.0, "+01",
     650                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     651                 :            :         TRUE, 2018, 11, 04, 1, 30, 0.0, "Europe/London", 2018, 11, 04, 1, 45, 0.0, "Europe/London" },
     652                 :            :       { 2018, 10, 21, 1, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 45, 0.0, "Europe/London",
     653                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     654                 :            :         2018, 10, 28, 1, 0, 0.0, "+00",
     655                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     656                 :            :         TRUE, 2018, 11, 04, 1, 30, 0.0, "Europe/London", 2018, 11, 04, 1, 45, 0.0, "Europe/London" },
     657                 :            :       { 2018, 10, 21, 1, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 45, 0.0, "Europe/London",
     658                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     659                 :            :         2018, 10, 28, 1, 35, 0.0, "+00",
     660                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     661                 :            :         TRUE, 2018, 11, 04, 1, 30, 0.0, "Europe/London", 2018, 11, 04, 1, 45, 0.0, "Europe/London" },
     662                 :            :       { 2018, 10, 21, 1, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 45, 0.0, "Europe/London",
     663                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     664                 :            :         2018, 11, 04, 1, 35, 0.0, "+00",
     665                 :            :         TRUE, 2018, 11, 04, 1, 30, 0.0, "Europe/London", 2018, 11, 04, 1, 45, 0.0, "Europe/London",
     666                 :            :         TRUE, 2018, 11, 11, 1, 30, 0.0, "Europe/London", 2018, 11, 11, 1, 45, 0.0, "Europe/London" },
     667                 :            :       /* Another DST check with looping time as above, where the period contains
     668                 :            :        * the looping time period, plus some extra normal time before and after.
     669                 :            :        * We expect that the recurrence will contain both the first and second
     670                 :            :        * occurrence of the looped hours. */
     671                 :            :       { 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 2, 30, 0.0, "Europe/London",
     672                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     673                 :            :         2018, 10, 21, 1, 35, 0.0, "Europe/London",
     674                 :            :         TRUE, 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 2, 30, 0.0, "Europe/London",
     675                 :            :         TRUE, 2018, 10, 28, 0, 30, 0.0, "+01", 2018, 10, 28, 2, 30, 0.0, "+00" },
     676                 :            :       { 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 2, 30, 0.0, "Europe/London",
     677                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     678                 :            :         2018, 10, 28, 1, 35, 0.0, "+01",
     679                 :            :         TRUE, 2018, 10, 28, 0, 30, 0.0, "+01", 2018, 10, 28, 2, 30, 0.0, "+00",
     680                 :            :         TRUE, 2018, 11, 04, 0, 30, 0.0, "Europe/London", 2018, 11, 04, 2, 30, 0.0, "Europe/London" },
     681                 :            :       { 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 2, 30, 0.0, "Europe/London",
     682                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     683                 :            :         2018, 10, 28, 1, 35, 0.0, "+00",
     684                 :            :         TRUE, 2018, 10, 28, 0, 30, 0.0, "+01", 2018, 10, 28, 2, 30, 0.0, "+00",
     685                 :            :         TRUE, 2018, 11, 04, 0, 30, 0.0, "Europe/London", 2018, 11, 04, 2, 30, 0.0, "Europe/London" },
     686                 :            :       { 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 2, 30, 0.0, "Europe/London",
     687                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     688                 :            :         2018, 10, 28, 2, 30, 0.0, "+00",
     689                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     690                 :            :         TRUE, 2018, 11, 04, 0, 30, 0.0, "Europe/London", 2018, 11, 04, 2, 30, 0.0, "Europe/London" },
     691                 :            :       /* Another DST check with looping time as above, where the period
     692                 :            :        * partially overlaps the looping time period, plus some extra normal time
     693                 :            :        * before it (but not after it). We expect that the recurrence will
     694                 :            :        * contain part of the first occurrence of the looped hours, but none of
     695                 :            :        * the second. */
     696                 :            :       { 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 30, 0.0, "Europe/London",
     697                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     698                 :            :         2018, 10, 21, 0, 35, 0.0, "Europe/London",
     699                 :            :         TRUE, 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 30, 0.0, "Europe/London",
     700                 :            :         TRUE, 2018, 10, 28, 0, 30, 0.0, "+01", 2018, 10, 28, 1, 30, 0.0, "+01" },
     701                 :            :       { 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 30, 0.0, "Europe/London",
     702                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     703                 :            :         2018, 10, 28, 0, 35, 0.0, "+01",
     704                 :            :         TRUE, 2018, 10, 28, 0, 30, 0.0, "+01", 2018, 10, 28, 1, 30, 0.0, "+01",
     705                 :            :         TRUE, 2018, 11, 4, 0, 30, 0.0, "Europe/London", 2018, 11, 4, 1, 30, 0.0, "Europe/London" },
     706                 :            :       { 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 30, 0.0, "Europe/London",
     707                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     708                 :            :         2018, 10, 28, 1, 29, 0.0, "+01",
     709                 :            :         TRUE, 2018, 10, 28, 0, 30, 0.0, "+01", 2018, 10, 28, 1, 30, 0.0, "+01",
     710                 :            :         TRUE, 2018, 11, 4, 0, 30, 0.0, "Europe/London", 2018, 11, 4, 1, 30, 0.0, "Europe/London" },
     711                 :            :       { 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 30, 0.0, "Europe/London",
     712                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     713                 :            :         2018, 10, 28, 1, 30, 0.0, "+01",
     714                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     715                 :            :         TRUE, 2018, 11, 4, 0, 30, 0.0, "Europe/London", 2018, 11, 4, 1, 30, 0.0, "Europe/London" },
     716                 :            :       { 2018, 10, 21, 0, 30, 0.0, "Europe/London", 2018, 10, 21, 1, 30, 0.0, "Europe/London",
     717                 :            :         MWT_PERIOD_REPEAT_WEEK, 1,
     718                 :            :         2018, 10, 28, 1, 30, 0.0, "+00",
     719                 :            :         FALSE, 0, 0, 0, 0, 0, 0.0, "Z", 0, 0, 0, 0, 0, 0.0, "Z",
     720                 :            :         TRUE, 2018, 11, 4, 0, 30, 0.0, "Europe/London", 2018, 11, 4, 1, 30, 0.0, "Europe/London" },
     721                 :            :     };
     722                 :            : 
     723         [ +  + ]:         95 :   for (gsize i = 0; i < G_N_ELEMENTS (vectors); i++)
     724                 :            :     {
     725                 :        188 :       g_autoptr(GTimeZone) start_tz = time_zone_new (vectors[i].start_tz);
     726                 :         94 :       g_autoptr(GDateTime) start =
     727                 :         94 :           g_date_time_new (start_tz, vectors[i].start_year, vectors[i].start_month,
     728                 :         94 :                            vectors[i].start_day, vectors[i].start_hour,
     729                 :         94 :                            vectors[i].start_minute, vectors[i].start_seconds);
     730                 :        188 :       g_autoptr(GTimeZone) end_tz = time_zone_new (vectors[i].end_tz);
     731                 :         94 :       g_autoptr(GDateTime) end =
     732                 :         94 :           g_date_time_new (end_tz, vectors[i].end_year, vectors[i].end_month,
     733                 :         94 :                            vectors[i].end_day, vectors[i].end_hour,
     734                 :         94 :                            vectors[i].end_minute, vectors[i].end_seconds);
     735                 :        188 :       g_autoptr(GTimeZone) when_tz = time_zone_new (vectors[i].when_tz);
     736                 :         94 :       g_autoptr(GDateTime) when =
     737                 :         94 :           g_date_time_new (when_tz, vectors[i].when_year, vectors[i].when_month,
     738                 :         94 :                            vectors[i].when_day, vectors[i].when_hour,
     739                 :         94 :                            vectors[i].when_minute, vectors[i].when_seconds);
     740                 :            : 
     741                 :         94 :       g_autoptr(GDateTime) expected_contains_start = NULL;
     742                 :         94 :       g_autoptr(GDateTime) expected_contains_end = NULL;
     743                 :            : 
     744         [ +  + ]:         94 :       if (vectors[i].expected_contains)
     745                 :            :         {
     746                 :        110 :           g_autoptr(GTimeZone) expected_contains_start_tz = time_zone_new (vectors[i].expected_contains_start_tz);
     747                 :         55 :           expected_contains_start =
     748                 :         55 :               g_date_time_new (expected_contains_start_tz, vectors[i].expected_contains_start_year, vectors[i].expected_contains_start_month,
     749                 :         55 :                                vectors[i].expected_contains_start_day, vectors[i].expected_contains_start_hour,
     750                 :         55 :                                vectors[i].expected_contains_start_minute, vectors[i].expected_contains_start_seconds);
     751                 :         55 :           g_autoptr(GTimeZone) expected_contains_end_tz = time_zone_new (vectors[i].expected_contains_end_tz);
     752                 :         55 :           expected_contains_end =
     753                 :         55 :               g_date_time_new (expected_contains_end_tz, vectors[i].expected_contains_end_year, vectors[i].expected_contains_end_month,
     754                 :         55 :                                vectors[i].expected_contains_end_day, vectors[i].expected_contains_end_hour,
     755                 :         55 :                                vectors[i].expected_contains_end_minute, vectors[i].expected_contains_end_seconds);
     756                 :            :         }
     757                 :            : 
     758                 :         94 :       g_autoptr(GDateTime) expected_next_start = NULL;
     759                 :         94 :       g_autoptr(GDateTime) expected_next_end = NULL;
     760                 :            : 
     761         [ +  + ]:         94 :       if (vectors[i].expected_next)
     762                 :            :         {
     763                 :        180 :           g_autoptr(GTimeZone) expected_next_start_tz = time_zone_new (vectors[i].expected_next_start_tz);
     764                 :         90 :           expected_next_start =
     765                 :         90 :               g_date_time_new (expected_next_start_tz, vectors[i].expected_next_start_year, vectors[i].expected_next_start_month,
     766                 :         90 :                                vectors[i].expected_next_start_day, vectors[i].expected_next_start_hour,
     767                 :         90 :                                vectors[i].expected_next_start_minute, vectors[i].expected_next_start_seconds);
     768                 :         90 :           g_autoptr(GTimeZone) expected_next_end_tz = time_zone_new (vectors[i].expected_next_end_tz);
     769                 :         90 :           expected_next_end =
     770                 :         90 :               g_date_time_new (expected_next_end_tz, vectors[i].expected_next_end_year, vectors[i].expected_next_end_month,
     771                 :         90 :                                vectors[i].expected_next_end_day, vectors[i].expected_next_end_hour,
     772                 :         90 :                                vectors[i].expected_next_end_minute, vectors[i].expected_next_end_seconds);
     773                 :            :         }
     774                 :            : 
     775                 :        188 :       g_autofree gchar *start_str = g_date_time_format (start, "%FT%T%:::z");
     776                 :        188 :       g_autofree gchar *end_str = g_date_time_format (end, "%FT%T%:::z");
     777                 :        188 :       g_autofree gchar *when_str = g_date_time_format (when, "%FT%T%:::z");
     778                 :            : 
     779                 :         94 :       g_test_message ("Vector %" G_GSIZE_FORMAT ": start %s, end %s, when %s",
     780                 :            :                       i, start_str, end_str, when_str);
     781                 :            : 
     782                 :         94 :       g_autoptr(MwtPeriod) period =
     783                 :         94 :           mwt_period_new (start, end, vectors[i].repeat_type,
     784                 :         94 :                           vectors[i].repeat_period,
     785                 :            :                           /* leave everything as default */
     786                 :            :                           NULL);
     787                 :            : 
     788                 :         94 :       g_autoptr(GDateTime) out_contains_start = NULL;
     789                 :         94 :       g_autoptr(GDateTime) out_contains_end = NULL;
     790                 :         94 :       g_autoptr(GDateTime) out_next_start = NULL;
     791                 :         94 :       g_autoptr(GDateTime) out_next_end = NULL;
     792                 :            : 
     793                 :            :       gboolean actual_contains =
     794                 :         94 :           mwt_period_contains_time (period, when, &out_contains_start, &out_contains_end);
     795                 :            :       gboolean actual_next =
     796                 :         94 :           mwt_period_get_next_recurrence (period, when, &out_next_start, &out_next_end);
     797                 :            : 
     798         [ +  + ]:         94 :       if (vectors[i].expected_contains)
     799                 :            :         {
     800         [ -  + ]:         55 :           g_assert_true (actual_contains);
     801         [ -  + ]:         55 :           g_assert_nonnull (out_contains_start);
     802         [ -  + ]:         55 :           g_assert_nonnull (out_contains_end);
     803         [ -  + ]:         55 :           g_assert_true (g_date_time_equal (out_contains_start, expected_contains_start));
     804         [ -  + ]:         55 :           g_assert_true (g_date_time_equal (out_contains_end, expected_contains_end));
     805                 :            :         }
     806                 :            :       else
     807                 :            :         {
     808         [ -  + ]:         39 :           g_assert_false (actual_contains);
     809         [ -  + ]:         39 :           g_assert_null (out_contains_start);
     810         [ -  + ]:         39 :           g_assert_null (out_contains_end);
     811                 :            :         }
     812                 :            : 
     813         [ +  + ]:         94 :       if (vectors[i].expected_next)
     814                 :            :         {
     815         [ -  + ]:         90 :           g_assert_true (actual_next);
     816         [ -  + ]:         90 :           g_assert_nonnull (out_next_start);
     817         [ -  + ]:         90 :           g_assert_nonnull (out_next_end);
     818         [ -  + ]:         90 :           g_assert_true (g_date_time_equal (out_next_start, expected_next_start));
     819         [ -  + ]:         90 :           g_assert_true (g_date_time_equal (out_next_end, expected_next_end));
     820                 :            :         }
     821                 :            :       else
     822                 :            :         {
     823         [ -  + ]:          4 :           g_assert_false (actual_next);
     824         [ -  + ]:          4 :           g_assert_null (out_next_start);
     825         [ -  + ]:          4 :           g_assert_null (out_next_end);
     826                 :            :         }
     827                 :            :     }
     828                 :          1 : }
     829                 :            : 
     830                 :            : /* Test overflow handling in mwt_period_contains_time(). */
     831                 :            : static void
     832                 :          1 : test_period_contains_time_overflow (void)
     833                 :            : {
     834                 :            :   /* This tries to trigger an overflow in the overflow check at the top of
     835                 :            :    * date_time_add_repeat_period(). */
     836                 :          2 :   g_autoptr(GDateTime) start1 = g_date_time_new_utc (2018, 2, 1, 1, 0, 0.0);
     837                 :          2 :   g_autoptr(GDateTime) end1 = g_date_time_new_utc (2018, 2, 1, 5, 0, 0.0);
     838                 :          2 :   g_autoptr(GDateTime) when1 = g_date_time_new_utc (9999, 1, 1, 2, 0, 0.0);
     839                 :            : 
     840                 :          1 :   g_autoptr(MwtPeriod) period1 =
     841                 :          1 :       mwt_period_new (start1, end1, MWT_PERIOD_REPEAT_YEAR, G_MAXUINT,
     842                 :            :                       /* leave everything as default */
     843                 :            :                       NULL);
     844                 :          1 :   g_autoptr(GDateTime) out_start1 = NULL;
     845                 :          1 :   g_autoptr(GDateTime) out_end1 = NULL;
     846         [ -  + ]:          1 :   g_assert_false (mwt_period_contains_time (period1, when1, &out_start1, &out_end1));
     847         [ -  + ]:          1 :   g_assert_null (out_start1);
     848         [ -  + ]:          1 :   g_assert_null (out_end1);
     849                 :            : 
     850                 :            :   /* This tries to trigger an overflow in the g_date_time_add_days() call in
     851                 :            :    * date_time_add_repeat_period(). However, I think min_n_periods is always
     852                 :            :    * calculated such that an overflow is not possible. Keep the test case just
     853                 :            :    * in case. */
     854                 :          2 :   g_autoptr(GDateTime) start2 = g_date_time_new_utc (9999, 12, 31, 1, 0, 0.0);
     855                 :          2 :   g_autoptr(GDateTime) end2 = g_date_time_new_utc (9999, 12, 31, 5, 0, 0.0);
     856                 :          2 :   g_autoptr(GDateTime) when2 = g_date_time_new_utc (9999, 12, 31, 6, 0, 0.0);
     857                 :            : 
     858                 :          1 :   g_autoptr(MwtPeriod) period2 =
     859                 :          1 :       mwt_period_new (start2, end2, MWT_PERIOD_REPEAT_DAY, 1,
     860                 :            :                       /* leave everything as default */
     861                 :            :                       NULL);
     862                 :          1 :   g_autoptr(GDateTime) out_start2 = NULL;
     863                 :          1 :   g_autoptr(GDateTime) out_end2 = NULL;
     864         [ -  + ]:          1 :   g_assert_false (mwt_period_contains_time (period2, when2, &out_start2, &out_end2));
     865         [ -  + ]:          1 :   g_assert_null (out_start2);
     866         [ -  + ]:          1 :   g_assert_null (out_end2);
     867                 :          1 : }
     868                 :            : 
     869                 :            : /* Test that calling mwt_period_next_recurrence() with a %NULL #GDateTime gives
     870                 :            :  * the base time for the #MwtPeriod, regardless of whether the period has any
     871                 :            :  * recurrences. */
     872                 :            : static void
     873                 :          1 : test_period_next_recurrence_first (void)
     874                 :            : {
     875                 :          2 :   g_autoptr(GDateTime) start = g_date_time_new_utc (2018, 2, 1, 1, 0, 0.0);
     876                 :          2 :   g_autoptr(GDateTime) end = g_date_time_new_utc (2018, 2, 1, 5, 0, 0.0);
     877                 :            : 
     878                 :          1 :   g_autoptr(MwtPeriod) period1 =
     879                 :          1 :       mwt_period_new (start, end, MWT_PERIOD_REPEAT_NONE, 0,
     880                 :            :                       /* leave everything as default */
     881                 :            :                       NULL);
     882                 :          1 :   g_autoptr(GDateTime) out_start1 = NULL;
     883                 :          1 :   g_autoptr(GDateTime) out_end1 = NULL;
     884         [ -  + ]:          1 :   g_assert_true (mwt_period_get_next_recurrence (period1, NULL, &out_start1, &out_end1));
     885         [ -  + ]:          1 :   g_assert_true (g_date_time_equal (start, out_start1));
     886         [ -  + ]:          1 :   g_assert_true (g_date_time_equal (end, out_end1));
     887                 :            : 
     888                 :          1 :   g_autoptr(MwtPeriod) period2 =
     889                 :          1 :       mwt_period_new (start, end, MWT_PERIOD_REPEAT_DAY, 1,
     890                 :            :                       /* leave everything as default */
     891                 :            :                       NULL);
     892                 :          1 :   g_autoptr(GDateTime) out_start2 = NULL;
     893                 :          1 :   g_autoptr(GDateTime) out_end2 = NULL;
     894         [ -  + ]:          1 :   g_assert_true (mwt_period_get_next_recurrence (period2, NULL, &out_start2, &out_end2));
     895         [ -  + ]:          1 :   g_assert_true (g_date_time_equal (start, out_start2));
     896         [ -  + ]:          1 :   g_assert_true (g_date_time_equal (end, out_end2));
     897                 :          1 : }
     898                 :            : 
     899                 :            : int
     900                 :          1 : main (int    argc,
     901                 :            :       char **argv)
     902                 :            : {
     903                 :          1 :   setlocale (LC_ALL, "");
     904                 :          1 :   g_test_init (&argc, &argv, NULL);
     905                 :            : 
     906                 :          1 :   g_test_add_func ("/period/validation", test_period_validation);
     907                 :          1 :   g_test_add_func ("/period/properties", test_period_properties);
     908                 :          1 :   g_test_add_func ("/period/properties/defaults", test_period_properties_defaults);
     909                 :          1 :   g_test_add_func ("/period/contains-time", test_period_contains_time);
     910                 :          1 :   g_test_add_func ("/period/contains-time/overflow", test_period_contains_time_overflow);
     911                 :          1 :   g_test_add_func ("/period/next-recurrence/first", test_period_next_recurrence_first);
     912                 :            : 
     913                 :          1 :   return g_test_run ();
     914                 :            : }

Generated by: LCOV version 1.16