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/tariff.h>
28 : : #include <libmogwai-tariff/tariff-builder.h>
29 : : #include <libmogwai-tariff/tariff-loader.h>
30 : : #include <locale.h>
31 : :
32 : : #include "common.h"
33 : :
34 : :
35 : : static GTimeZone *
36 : 90 : time_zone_new (const gchar *tz_str)
37 : : {
38 : : #if GLIB_CHECK_VERSION(2, 68, 0)
39 : 180 : g_autoptr(GTimeZone) tz = g_time_zone_new_identifier (tz_str);
40 [ - + ]: 90 : g_assert_nonnull (tz);
41 : 90 : return g_steal_pointer (&tz);
42 : : #else
43 : : return g_time_zone_new (tz_str);
44 : : #endif
45 : : }
46 : :
47 : : /* Test the GObject properties on a tariff. */
48 : : static void
49 : 1 : test_tariff_properties (void)
50 : : {
51 : 1 : g_autoptr(MwtTariff) tariff = NULL;
52 : 2 : g_autoptr(GPtrArray) periods = g_ptr_array_new_with_free_func (NULL);
53 : 2 : g_autoptr(GDateTime) period_start = g_date_time_new_utc (2018, 1, 22, 0, 0, 0);
54 : 2 : g_autoptr(GDateTime) period_end = g_date_time_new_utc (2018, 2, 22, 0, 0, 0);
55 : 2 : g_autoptr(MwtPeriod) period = mwt_period_new (period_start, period_end,
56 : : MWT_PERIOD_REPEAT_NONE, 0,
57 : : NULL);
58 : 1 : g_ptr_array_add (periods, period);
59 : 1 : tariff = mwt_tariff_new ("name", periods);
60 [ - + ]: 1 : g_assert_true (MWT_IS_TARIFF (tariff));
61 : :
62 [ - + ]: 1 : g_assert_cmpstr (mwt_tariff_get_name (tariff), ==, "name");
63 : 1 : GPtrArray *actual_periods = mwt_tariff_get_periods (tariff);
64 [ - + ]: 1 : g_assert_cmpuint (actual_periods->len, ==, 1);
65 : :
66 : 1 : g_autofree gchar *actual_name = NULL;
67 : 1 : g_autoptr(GPtrArray) actual_periods2 = NULL;
68 : :
69 : 1 : g_object_get (G_OBJECT (tariff),
70 : : "name", &actual_name,
71 : : "periods", &actual_periods2,
72 : : NULL);
73 : :
74 [ - + ]: 1 : g_assert_cmpstr (actual_name, ==, "name");
75 [ - + ]: 1 : g_assert_cmpuint (actual_periods2->len, ==, 1);
76 : 1 : }
77 : :
78 : : /* Test mwt_tariff_lookup_period() with various dates/times for a generic
79 : : * tariff. */
80 : : static void
81 : 1 : test_tariff_lookup (void)
82 : : {
83 : : /* Construct a tariff. */
84 : 2 : g_autoptr(GPtrArray) periods = g_ptr_array_new_with_free_func (NULL);
85 : :
86 : 2 : g_autoptr(GDateTime) period1_start = g_date_time_new_utc (2018, 1, 22, 0, 0, 0);
87 : 2 : g_autoptr(GDateTime) period1_end = g_date_time_new_utc (2018, 2, 22, 0, 0, 0);
88 : 2 : g_autoptr(MwtPeriod) period1 = mwt_period_new (period1_start, period1_end,
89 : : MWT_PERIOD_REPEAT_NONE, 0,
90 : : "capacity-limit", (guint64) 2000,
91 : : NULL);
92 : 1 : g_ptr_array_add (periods, period1);
93 : :
94 : 2 : g_autoptr(GDateTime) period2_start = g_date_time_new_utc (2018, 1, 22, 0, 0, 0);
95 : 2 : g_autoptr(GDateTime) period2_end = g_date_time_new_utc (2018, 1, 22, 12, 0, 0);
96 : 2 : g_autoptr(MwtPeriod) period2 = mwt_period_new (period2_start, period2_end,
97 : : MWT_PERIOD_REPEAT_WEEK, 1,
98 : : "capacity-limit", (guint64) 1000,
99 : : NULL);
100 : 1 : g_ptr_array_add (periods, period2);
101 : :
102 : 1 : g_autoptr(MwtTariff) tariff = NULL;
103 : 1 : tariff = mwt_tariff_new ("name", periods);
104 : :
105 : : /* Check whether periods are looked up correctly. */
106 : : const struct
107 : : {
108 : : gint year;
109 : : gint month;
110 : : gint day;
111 : : gint hour;
112 : : gint minute;
113 : : gdouble seconds;
114 : : MwtPeriod *expected_period;
115 : : }
116 : 1 : vectors[] =
117 : : {
118 : : { 2018, 1, 21, 23, 59, 59, NULL },
119 : : { 2018, 1, 22, 0, 0, 0, period2 },
120 : : { 2018, 1, 22, 1, 0, 0, period2 },
121 : : { 2018, 1, 22, 11, 59, 59, period2 },
122 : : { 2018, 1, 22, 12, 0, 0, period1 },
123 : : { 2018, 1, 22, 12, 0, 1, period1 },
124 : : { 2018, 1, 23, 0, 0, 0, period1 },
125 : : { 2018, 2, 21, 23, 59, 59, period1 },
126 : : { 2018, 2, 22, 0, 0, 0, NULL },
127 : : /* FIXME: Test recurrence */
128 : : };
129 : :
130 [ + + ]: 10 : for (gsize i = 0; i < G_N_ELEMENTS (vectors); i++)
131 : : {
132 : 9 : g_test_message ("Vector %" G_GSIZE_FORMAT ": %04d-%02d-%02dT%02d:%02d:%02fZ, %p",
133 : 9 : i, vectors[i].year, vectors[i].month, vectors[i].day,
134 : 9 : vectors[i].hour, vectors[i].minute, vectors[i].seconds,
135 : 9 : vectors[i].expected_period);
136 : 9 : g_autoptr(GDateTime) lookup_date =
137 : 9 : g_date_time_new_utc (vectors[i].year, vectors[i].month, vectors[i].day,
138 : 9 : vectors[i].hour, vectors[i].minute, vectors[i].seconds);
139 : 9 : MwtPeriod *lookup_period = mwt_tariff_lookup_period (tariff, lookup_date);
140 [ + + ]: 9 : if (vectors[i].expected_period == NULL)
141 : : {
142 [ - + ]: 2 : g_assert_null (lookup_period);
143 : : }
144 : : else
145 : : {
146 [ - + ]: 7 : g_assert_true (MWT_IS_PERIOD (lookup_period));
147 [ - + ]: 7 : g_assert_true (lookup_period == vectors[i].expected_period);
148 : : }
149 : : }
150 : 1 : }
151 : :
152 : : /* Test getting the next transition using mwt_tariff_get_next_transition(), and
153 : : * check that it’s calculated correctly, and returns the correct to/from periods
154 : : * for a variety of tariffs and date/times. */
155 : : static void
156 : 1 : test_tariff_next_transition (void)
157 : : {
158 : : /* Construct various test tariffs. Firstly, one with a non-recurring period. */
159 : 2 : g_autoptr(GPtrArray) periods1 = g_ptr_array_new_with_free_func (NULL);
160 : :
161 : 2 : g_autoptr(GDateTime) period1a_start = g_date_time_new_utc (2018, 1, 22, 0, 0, 0);
162 : 2 : g_autoptr(GDateTime) period1a_end = g_date_time_new_utc (2018, 2, 22, 0, 0, 0);
163 : 2 : g_autoptr(MwtPeriod) period1a = mwt_period_new (period1a_start, period1a_end,
164 : : MWT_PERIOD_REPEAT_NONE, 0,
165 : : NULL);
166 : 1 : g_ptr_array_add (periods1, period1a);
167 : :
168 : 2 : g_autoptr(MwtTariff) tariff1 = mwt_tariff_new ("name", periods1);
169 : :
170 : : /* One with a single recurring period. */
171 : 2 : g_autoptr(GPtrArray) periods2 = g_ptr_array_new_with_free_func (NULL);
172 : :
173 : 2 : g_autoptr(GDateTime) period2a_start = g_date_time_new_utc (2018, 1, 10, 2, 0, 0);
174 : 2 : g_autoptr(GDateTime) period2a_end = g_date_time_new_utc (2018, 1, 10, 6, 0, 0);
175 : 2 : g_autoptr(MwtPeriod) period2a = mwt_period_new (period2a_start, period2a_end,
176 : : MWT_PERIOD_REPEAT_DAY, 1,
177 : : NULL);
178 : 1 : g_ptr_array_add (periods2, period2a);
179 : :
180 : 2 : g_autoptr(MwtTariff) tariff2 = mwt_tariff_new ("name", periods2);
181 : :
182 : : /* One period which covers all time, and another recurring on top. */
183 : 2 : g_autoptr(GPtrArray) periods3 = g_ptr_array_new_with_free_func (NULL);
184 : :
185 : 2 : g_autoptr(GDateTime) period3a_start = g_date_time_new_utc (1970, 1, 1, 0, 0, 0);
186 : 2 : g_autoptr(GDateTime) period3a_end = g_date_time_new_utc (9999, 12, 31, 23, 59, 59.99);
187 : 2 : g_autoptr(MwtPeriod) period3a = mwt_period_new (period3a_start, period3a_end,
188 : : MWT_PERIOD_REPEAT_NONE, 0,
189 : : NULL);
190 : 1 : g_ptr_array_add (periods3, period3a);
191 : :
192 : 2 : g_autoptr(GDateTime) period3b_start = g_date_time_new_utc (2018, 1, 10, 2, 0, 0);
193 : 2 : g_autoptr(GDateTime) period3b_end = g_date_time_new_utc (2018, 1, 10, 6, 0, 0);
194 : 2 : g_autoptr(MwtPeriod) period3b = mwt_period_new (period3b_start, period3b_end,
195 : : MWT_PERIOD_REPEAT_DAY, 1,
196 : : NULL);
197 : 1 : g_ptr_array_add (periods3, period3b);
198 : :
199 : 2 : g_autoptr(MwtTariff) tariff3 = mwt_tariff_new ("name", periods3);
200 : :
201 : : /* Two recurring periods, one inside the other. */
202 : 2 : g_autoptr(GPtrArray) periods4 = g_ptr_array_new_with_free_func (NULL);
203 : :
204 : 2 : g_autoptr(GDateTime) period4a_start = g_date_time_new_utc (2018, 1, 8, 1, 0, 0);
205 : 2 : g_autoptr(GDateTime) period4a_end = g_date_time_new_utc (2018, 1, 14, 22, 0, 0);
206 : 2 : g_autoptr(MwtPeriod) period4a = mwt_period_new (period4a_start, period4a_end,
207 : : MWT_PERIOD_REPEAT_WEEK, 1,
208 : : NULL);
209 : 1 : g_ptr_array_add (periods4, period4a);
210 : :
211 : 2 : g_autoptr(GDateTime) period4b_start = g_date_time_new_utc (2018, 1, 8, 2, 0, 0);
212 : 2 : g_autoptr(GDateTime) period4b_end = g_date_time_new_utc (2018, 1, 8, 6, 0, 0);
213 : 2 : g_autoptr(MwtPeriod) period4b = mwt_period_new (period4b_start, period4b_end,
214 : : MWT_PERIOD_REPEAT_DAY, 1,
215 : : NULL);
216 : 1 : g_ptr_array_add (periods4, period4b);
217 : :
218 : 2 : g_autoptr(MwtTariff) tariff4 = mwt_tariff_new ("name", periods4);
219 : :
220 : : /* Two recurring periods, ending at the same time. */
221 : 2 : g_autoptr(GPtrArray) periods5 = g_ptr_array_new_with_free_func (NULL);
222 : :
223 : 2 : g_autoptr(GDateTime) period5a_start = g_date_time_new_utc (2018, 1, 8, 10, 0, 0);
224 : 2 : g_autoptr(GDateTime) period5a_end = g_date_time_new_utc (2018, 1, 8, 22, 0, 0);
225 : 2 : g_autoptr(MwtPeriod) period5a = mwt_period_new (period5a_start, period5a_end,
226 : : MWT_PERIOD_REPEAT_DAY, 1,
227 : : NULL);
228 : 1 : g_ptr_array_add (periods5, period5a);
229 : :
230 : 2 : g_autoptr(GDateTime) period5b_start = g_date_time_new_utc (2018, 1, 8, 12, 0, 0);
231 : 2 : g_autoptr(GDateTime) period5b_end = g_date_time_new_utc (2018, 1, 8, 22, 0, 0);
232 : 2 : g_autoptr(MwtPeriod) period5b = mwt_period_new (period5b_start, period5b_end,
233 : : MWT_PERIOD_REPEAT_DAY, 1,
234 : : NULL);
235 : 1 : g_ptr_array_add (periods5, period5b);
236 : :
237 : 2 : g_autoptr(MwtTariff) tariff5 = mwt_tariff_new ("name", periods5);
238 : :
239 : : /* Two recurring periods, each starting as the other ends. */
240 : 2 : g_autoptr(GPtrArray) periods6 = g_ptr_array_new_with_free_func (NULL);
241 : :
242 : 2 : g_autoptr(GDateTime) period6a_start = g_date_time_new_utc (2018, 1, 8, 0, 0, 0);
243 : 2 : g_autoptr(GDateTime) period6a_end = g_date_time_new_utc (2018, 1, 9, 0, 0, 0);
244 : 2 : g_autoptr(MwtPeriod) period6a = mwt_period_new (period6a_start, period6a_end,
245 : : MWT_PERIOD_REPEAT_DAY, 2,
246 : : NULL);
247 : 1 : g_ptr_array_add (periods6, period6a);
248 : :
249 : 2 : g_autoptr(GDateTime) period6b_start = g_date_time_new_utc (2018, 1, 9, 0, 0, 0);
250 : 2 : g_autoptr(GDateTime) period6b_end = g_date_time_new_utc (2018, 1, 10, 0, 0, 0);
251 : 2 : g_autoptr(MwtPeriod) period6b = mwt_period_new (period6b_start, period6b_end,
252 : : MWT_PERIOD_REPEAT_DAY, 2,
253 : : NULL);
254 : 1 : g_ptr_array_add (periods6, period6b);
255 : :
256 : 2 : g_autoptr(MwtTariff) tariff6 = mwt_tariff_new ("name", periods6);
257 : :
258 : : /* Two recurring periods, starting at the same time. */
259 : 2 : g_autoptr(GPtrArray) periods7 = g_ptr_array_new_with_free_func (NULL);
260 : :
261 : 2 : g_autoptr(GDateTime) period7a_start = g_date_time_new_utc (2018, 1, 8, 10, 0, 0);
262 : 2 : g_autoptr(GDateTime) period7a_end = g_date_time_new_utc (2018, 1, 8, 22, 0, 0);
263 : 2 : g_autoptr(MwtPeriod) period7a = mwt_period_new (period7a_start, period7a_end,
264 : : MWT_PERIOD_REPEAT_DAY, 1,
265 : : NULL);
266 : 1 : g_ptr_array_add (periods7, period7a);
267 : :
268 : 2 : g_autoptr(GDateTime) period7b_start = g_date_time_new_utc (2018, 1, 8, 10, 0, 0);
269 : 2 : g_autoptr(GDateTime) period7b_end = g_date_time_new_utc (2018, 1, 8, 12, 0, 0);
270 : 2 : g_autoptr(MwtPeriod) period7b = mwt_period_new (period7b_start, period7b_end,
271 : : MWT_PERIOD_REPEAT_DAY, 1,
272 : : NULL);
273 : 1 : g_ptr_array_add (periods7, period7b);
274 : :
275 : 2 : g_autoptr(MwtTariff) tariff7 = mwt_tariff_new ("name", periods7);
276 : :
277 : : /* One period, recurring so it starts when it ends. */
278 : 2 : g_autoptr(GPtrArray) periods8 = g_ptr_array_new_with_free_func (NULL);
279 : :
280 : 2 : g_autoptr(GDateTime) period8a_start = g_date_time_new_utc (2018, 1, 8, 0, 0, 0);
281 : 2 : g_autoptr(GDateTime) period8a_end = g_date_time_new_utc (2018, 1, 9, 0, 0, 0);
282 : 2 : g_autoptr(MwtPeriod) period8a = mwt_period_new (period8a_start, period8a_end,
283 : : MWT_PERIOD_REPEAT_DAY, 1,
284 : : NULL);
285 : 1 : g_ptr_array_add (periods8, period8a);
286 : :
287 : 2 : g_autoptr(MwtTariff) tariff8 = mwt_tariff_new ("name", periods8);
288 : :
289 : : const struct
290 : : {
291 : : MwtTariff *tariff;
292 : :
293 : : gint after_year;
294 : : gint after_month;
295 : : gint after_day;
296 : : gint after_hour;
297 : : gint after_minute;
298 : : gdouble after_seconds;
299 : : const gchar *after_tz;
300 : :
301 : : gint expected_next_year;
302 : : gint expected_next_month;
303 : : gint expected_next_day;
304 : : gint expected_next_hour;
305 : : gint expected_next_minute;
306 : : gdouble expected_next_seconds;
307 : : const gchar *expected_next_tz; /* (nullable) */
308 : :
309 : : gboolean expected_next_is_first;
310 : :
311 : : MwtPeriod *expected_from_period; /* (nullable) */
312 : : MwtPeriod *expected_to_period; /* (nullable) */
313 : : }
314 : 1 : vectors[] =
315 : : {
316 : : /* Some simple tests with a single period tariff, with no recurrence. */
317 : : { tariff1,
318 : : 2018, 1, 1, 0, 0, 0.0, "Z",
319 : : 2018, 1, 22, 0, 0, 0.0, "Z", TRUE,
320 : : NULL, period1a },
321 : : { tariff1,
322 : : 2018, 1, 21, 23, 59, 59.99, "Z",
323 : : 2018, 1, 22, 0, 0, 0.0, "Z", FALSE,
324 : : NULL, period1a },
325 : : { tariff1,
326 : : 2018, 1, 22, 0, 0, 0.0, "Z",
327 : : 2018, 2, 22, 0, 0, 0.0, "Z", FALSE,
328 : : period1a, NULL },
329 : : { tariff1,
330 : : 2018, 2, 10, 0, 0, 0.0, "Z",
331 : : 2018, 2, 22, 0, 0, 0.0, "Z", FALSE,
332 : : period1a, NULL },
333 : : { tariff1,
334 : : 2018, 2, 21, 23, 59, 59.99, "Z",
335 : : 2018, 2, 22, 0, 0, 0.0, "Z", FALSE,
336 : : period1a, NULL },
337 : : { tariff1,
338 : : 2018, 2, 22, 0, 0, 0.0, "Z",
339 : : 0, 0, 0, 0, 0, 0.0, NULL, FALSE,
340 : : NULL, NULL },
341 : : { tariff1,
342 : : 2018, 3, 1, 0, 0, 0.0, "Z",
343 : : 0, 0, 0, 0, 0, 0.0, NULL, FALSE,
344 : : NULL, NULL },
345 : : /* A single recurring period. */
346 : : { tariff2,
347 : : 2018, 1, 1, 0, 0, 0.0, "Z",
348 : : 2018, 1, 10, 2, 0, 0.0, "Z", TRUE,
349 : : NULL, period2a },
350 : : { tariff2,
351 : : 2018, 1, 10, 2, 0, 0.0, "Z",
352 : : 2018, 1, 10, 6, 0, 0.0, "Z", FALSE,
353 : : period2a, NULL },
354 : : { tariff2,
355 : : 2018, 1, 10, 4, 0, 0.0, "Z",
356 : : 2018, 1, 10, 6, 0, 0.0, "Z", FALSE,
357 : : period2a, NULL },
358 : : { tariff2,
359 : : 2018, 1, 10, 6, 0, 0.0, "Z",
360 : : 2018, 1, 11, 2, 0, 0.0, "Z", FALSE,
361 : : NULL, period2a },
362 : : { tariff2,
363 : : 2018, 1, 11, 4, 0, 0.0, "Z",
364 : : 2018, 1, 11, 6, 0, 0.0, "Z", FALSE,
365 : : period2a, NULL },
366 : : /* A recurring period over one which lasts for all time (the g-c-c case). */
367 : : { tariff3,
368 : : 1990, 1, 1, 0, 0, 0.0, "Z",
369 : : 2018, 1, 10, 2, 0, 0.0, "Z", FALSE,
370 : : period3a, period3b },
371 : : { tariff3,
372 : : 2018, 1, 10, 1, 59, 59.99, "Z",
373 : : 2018, 1, 10, 2, 0, 0.0, "Z", FALSE,
374 : : period3a, period3b },
375 : : { tariff3,
376 : : 2018, 1, 10, 2, 0, 0.0, "Z",
377 : : 2018, 1, 10, 6, 0, 0.0, "Z", FALSE,
378 : : period3b, period3a },
379 : : { tariff3,
380 : : 2018, 1, 10, 4, 0, 0.0, "Z",
381 : : 2018, 1, 10, 6, 0, 0.0, "Z", FALSE,
382 : : period3b, period3a },
383 : : { tariff3,
384 : : 2018, 1, 10, 6, 0, 0.0, "Z",
385 : : 2018, 1, 11, 2, 0, 0.0, "Z", FALSE,
386 : : period3a, period3b },
387 : : { tariff3,
388 : : 2018, 1, 11, 2, 0, 0.0, "Z",
389 : : 2018, 1, 11, 6, 0, 0.0, "Z", FALSE,
390 : : period3b, period3a },
391 : : { tariff3,
392 : : 9999, 12, 31, 4, 0, 0.0, "Z",
393 : : 9999, 12, 31, 6, 0, 0.0, "Z", FALSE,
394 : : period3b, period3a },
395 : : { tariff3,
396 : : 9999, 12, 31, 6, 0, 0.0, "Z",
397 : : 9999, 12, 31, 23, 59, 59.99, "Z", FALSE,
398 : : period3a, NULL },
399 : : /* Two recurring periods, one inside the other. */
400 : : { tariff4,
401 : : 2018, 1, 1, 1, 0, 0.0, "Z",
402 : : 2018, 1, 8, 1, 0, 0.0, "Z", TRUE,
403 : : NULL, period4a },
404 : : { tariff4,
405 : : 2018, 1, 8, 1, 0, 0.0, "Z",
406 : : 2018, 1, 8, 2, 0, 0.0, "Z", FALSE,
407 : : period4a, period4b },
408 : : { tariff4,
409 : : 2018, 1, 8, 2, 0, 0.0, "Z",
410 : : 2018, 1, 8, 6, 0, 0.0, "Z", FALSE,
411 : : period4b, period4a },
412 : : { tariff4,
413 : : 2018, 1, 8, 6, 0, 0.0, "Z",
414 : : 2018, 1, 9, 2, 0, 0.0, "Z", FALSE,
415 : : period4a, period4b },
416 : : { tariff4,
417 : : 2018, 1, 14, 1, 0, 0.0, "Z",
418 : : 2018, 1, 14, 2, 0, 0.0, "Z", FALSE,
419 : : period4a, period4b },
420 : : { tariff4,
421 : : 2018, 1, 14, 2, 0, 0.0, "Z",
422 : : 2018, 1, 14, 6, 0, 0.0, "Z", FALSE,
423 : : period4b, period4a },
424 : : { tariff4,
425 : : 2018, 1, 14, 6, 0, 0.0, "Z",
426 : : 2018, 1, 14, 22, 0, 0.0, "Z", FALSE,
427 : : period4a, NULL },
428 : : { tariff4,
429 : : 2018, 1, 14, 22, 0, 0.0, "Z",
430 : : 2018, 1, 15, 1, 0, 0.0, "Z", FALSE,
431 : : NULL, period4a },
432 : : { tariff4,
433 : : 2018, 1, 15, 1, 0, 0.0, "Z",
434 : : 2018, 1, 15, 2, 0, 0.0, "Z", FALSE,
435 : : period4a, period4b },
436 : : /* Two periods, ending at the same time. */
437 : : { tariff5,
438 : : 2018, 1, 8, 9, 0, 0.0, "Z",
439 : : 2018, 1, 8, 10, 0, 0.0, "Z", TRUE,
440 : : NULL, period5a },
441 : : { tariff5,
442 : : 2018, 1, 8, 10, 0, 0.0, "Z",
443 : : 2018, 1, 8, 12, 0, 0.0, "Z", FALSE,
444 : : period5a, period5b },
445 : : { tariff5,
446 : : 2018, 1, 8, 12, 0, 0.0, "Z",
447 : : 2018, 1, 8, 22, 0, 0.0, "Z", FALSE,
448 : : period5b, NULL },
449 : : { tariff5,
450 : : 2018, 1, 8, 22, 0, 0.0, "Z",
451 : : 2018, 1, 9, 10, 0, 0.0, "Z", FALSE,
452 : : NULL, period5a },
453 : : /* Two periods, each starting as the other ends. */
454 : : { tariff6,
455 : : 2018, 1, 7, 10, 0, 0.0, "Z",
456 : : 2018, 1, 8, 0, 0, 0.0, "Z", TRUE,
457 : : NULL, period6a },
458 : : { tariff6,
459 : : 2018, 1, 8, 0, 0, 0.0, "Z",
460 : : 2018, 1, 9, 0, 0, 0.0, "Z", FALSE,
461 : : period6a, period6b },
462 : : { tariff6,
463 : : 2018, 1, 9, 0, 0, 0.0, "Z",
464 : : 2018, 1, 10, 0, 0, 0.0, "Z", FALSE,
465 : : period6b, period6a },
466 : : { tariff6,
467 : : 2018, 1, 10, 0, 0, 0.0, "Z",
468 : : 2018, 1, 11, 0, 0, 0.0, "Z", FALSE,
469 : : period6a, period6b },
470 : : { tariff6,
471 : : 2018, 1, 11, 0, 0, 0.0, "Z",
472 : : 2018, 1, 12, 0, 0, 0.0, "Z", FALSE,
473 : : period6b, period6a },
474 : : /* Two periods, starting at the same time. */
475 : : { tariff7,
476 : : 2018, 1, 8, 9, 0, 0.0, "Z",
477 : : 2018, 1, 8, 10, 0, 0.0, "Z", TRUE,
478 : : NULL, period7b },
479 : : { tariff7,
480 : : 2018, 1, 8, 10, 0, 0.0, "Z",
481 : : 2018, 1, 8, 12, 0, 0.0, "Z", FALSE,
482 : : period7b, period7a },
483 : : { tariff7,
484 : : 2018, 1, 8, 12, 0, 0.0, "Z",
485 : : 2018, 1, 8, 22, 0, 0.0, "Z", FALSE,
486 : : period7a, NULL },
487 : : { tariff7,
488 : : 2018, 1, 8, 22, 0, 0.0, "Z",
489 : : 2018, 1, 9, 10, 0, 0.0, "Z", FALSE,
490 : : NULL, period7b },
491 : : /* One period, recurring so it starts when it ends. */
492 : : { tariff8,
493 : : 2018, 1, 7, 5, 0, 0.0, "Z",
494 : : 2018, 1, 8, 0, 0, 0.0, "Z", TRUE,
495 : : NULL, period8a },
496 : : { tariff8,
497 : : 2018, 1, 8, 0, 0, 0.0, "Z",
498 : : 2018, 1, 9, 0, 0, 0.0, "Z", FALSE,
499 : : period8a, period8a },
500 : : { tariff8,
501 : : 2018, 1, 9, 0, 0, 0.0, "Z",
502 : : 2018, 1, 10, 0, 0, 0.0, "Z", FALSE,
503 : : period8a, period8a },
504 : : };
505 : :
506 [ + + ]: 46 : for (gsize i = 0; i < G_N_ELEMENTS (vectors); i++)
507 : : {
508 : 90 : g_autoptr(GTimeZone) after_tz = time_zone_new (vectors[i].after_tz);
509 : 45 : g_autoptr(GDateTime) after =
510 : 45 : g_date_time_new (after_tz, vectors[i].after_year, vectors[i].after_month,
511 : 45 : vectors[i].after_day, vectors[i].after_hour,
512 : 45 : vectors[i].after_minute, vectors[i].after_seconds);
513 : :
514 : 45 : g_autoptr(GDateTime) expected_next = NULL;
515 : :
516 [ + + ]: 45 : if (vectors[i].expected_next_tz != NULL)
517 : : {
518 : 43 : g_autoptr(GTimeZone) expected_next_tz = time_zone_new (vectors[i].expected_next_tz);
519 : 43 : expected_next =
520 : 43 : g_date_time_new (expected_next_tz, vectors[i].expected_next_year, vectors[i].expected_next_month,
521 : 43 : vectors[i].expected_next_day, vectors[i].expected_next_hour,
522 : 43 : vectors[i].expected_next_minute, vectors[i].expected_next_seconds);
523 : : }
524 : :
525 : 90 : g_autofree gchar *after_str = g_date_time_format (after, "%FT%T%:::z");
526 : 45 : g_autofree gchar *expected_next_str =
527 [ + + ]: 45 : (expected_next != NULL) ? g_date_time_format (expected_next, "%FT%T%:::z") : g_strdup ("never");
528 : :
529 : 45 : g_test_message ("Vector %" G_GSIZE_FORMAT ": after: %s, expected next: %s",
530 : : i, after_str, expected_next_str);
531 : :
532 : 45 : g_autoptr(GDateTime) next = NULL;
533 : 45 : MwtPeriod *from_period = NULL, *to_period = NULL;
534 : 45 : next = mwt_tariff_get_next_transition (vectors[i].tariff, after,
535 : : &from_period, &to_period);
536 : :
537 [ + + ]: 45 : if (expected_next != NULL)
538 : : {
539 [ - + ]: 43 : g_assert_nonnull (next);
540 [ - + ]: 43 : g_assert_true (g_date_time_equal (next, expected_next));
541 [ - + ]: 43 : g_assert_true (from_period == vectors[i].expected_from_period);
542 [ - + ]: 43 : g_assert_true (to_period == vectors[i].expected_to_period);
543 : : }
544 : : else
545 : : {
546 [ - + ]: 2 : g_assert_null (next);
547 [ - + ]: 2 : g_assert_null (from_period);
548 [ - + ]: 2 : g_assert_null (to_period);
549 : : }
550 : :
551 : : /* Test calling with (@after == NULL). */
552 [ + + ]: 45 : if (vectors[i].expected_next_is_first)
553 : : {
554 : 7 : g_autoptr(GDateTime) next2 = NULL;
555 : 7 : MwtPeriod *from_period2 = NULL, *to_period2 = NULL;
556 : 7 : next2 = mwt_tariff_get_next_transition (vectors[i].tariff, NULL,
557 : : &from_period2, &to_period2);
558 : :
559 [ - + ]: 7 : g_assert_nonnull (next2);
560 [ - + ]: 7 : g_assert_nonnull (expected_next);
561 [ - + ]: 7 : g_assert_true (g_date_time_equal (next2, expected_next));
562 [ - + ]: 7 : g_assert_null (from_period2);
563 [ - + ]: 7 : g_assert_true (to_period2 == vectors[i].expected_to_period);
564 : : }
565 : : }
566 : :
567 : : /* Special extra test for period 3 to check that (@after == NULL) works to get
568 : : * the first transition. We can’t include this in the test vectors above,
569 : : * because it’s impossible to represent a date/time before the first
570 : : * transition for that tariff. */
571 : 1 : g_autoptr(GDateTime) next = NULL;
572 : 1 : MwtPeriod *from_period = NULL, *to_period = NULL;
573 : 1 : next = mwt_tariff_get_next_transition (tariff3, NULL, &from_period, &to_period);
574 : :
575 [ - + ]: 1 : g_assert_nonnull (next);
576 [ - + ]: 1 : g_assert_true (g_date_time_equal (next, period3a_start));
577 [ - + ]: 1 : g_assert_null (from_period);
578 [ - + ]: 1 : g_assert_true (to_period == period3a);
579 : 1 : }
580 : :
581 : : /* Test that serialising a tariff with #MwtTariffBuilder, then loading it with
582 : : * #MwtTariffLoader, gives an identical tariff to the original one. Particularly,
583 : : * we care that the timezones have not changed. */
584 : : static void
585 : 1 : test_tariff_serialisation_roundtrip (void)
586 : : {
587 : 1 : g_autoptr(MwtTariffBuilder) builder = NULL;
588 : :
589 : : /* Build the tariff. */
590 : 1 : builder = mwt_tariff_builder_new ();
591 : 1 : mwt_tariff_builder_set_name (builder, "test-tariff");
592 : :
593 : : /* Period 1. */
594 : 2 : g_autoptr(GTimeZone) start1_tz = time_zone_new ("Europe/London");
595 : 2 : g_autoptr(GDateTime) start1 = g_date_time_new (start1_tz, 2018, 1, 1, 0, 0, 0);
596 : 2 : g_autoptr(GTimeZone) end1_tz = time_zone_new ("America/Atka");
597 : 2 : g_autoptr(GDateTime) end1 = g_date_time_new (end1_tz, 2018, 2, 1, 0, 0, 0);
598 : :
599 : 1 : g_autoptr(MwtPeriod) period1 = NULL;
600 : 1 : period1 = mwt_period_new (start1, end1, MWT_PERIOD_REPEAT_MONTH, 1,
601 : : "capacity-limit", G_GUINT64_CONSTANT (2 * 1000 * 1000 * 1000),
602 : : NULL);
603 : 1 : mwt_tariff_builder_add_period (builder, period1);
604 : :
605 : : /* Period 2. */
606 : 2 : g_autoptr(GDateTime) start2 = g_date_time_new_utc (2018, 1, 6, 0, 0, 0);
607 : 2 : g_autoptr(GDateTime) end2 = g_date_time_new_utc (2018, 1, 8, 0, 0, 0);
608 : :
609 : 1 : g_autoptr(MwtPeriod) period2 = NULL;
610 : 1 : period2 = mwt_period_new (start2, end2, MWT_PERIOD_REPEAT_WEEK, 1,
611 : : "capacity-limit", G_MAXUINT64,
612 : : NULL);
613 : 1 : mwt_tariff_builder_add_period (builder, period2);
614 : :
615 : : /* Finish building the tariff and get it in variant form. */
616 : 1 : g_autoptr(MwtTariff) built_tariff = NULL;
617 : 1 : built_tariff = mwt_tariff_builder_get_tariff (builder);
618 : :
619 : 1 : g_autoptr(GVariant) variant = NULL;
620 : 1 : variant = mwt_tariff_builder_get_tariff_as_variant (builder);
621 : :
622 : : /* Load it again. */
623 : 2 : g_autoptr(MwtTariffLoader) loader = mwt_tariff_loader_new ();
624 : 1 : g_autoptr(GError) local_error = NULL;
625 : :
626 : 1 : gboolean retval = mwt_tariff_loader_load_from_variant (loader, variant, &local_error);
627 [ - + ]: 1 : g_assert_no_error (local_error);
628 [ - + ]: 1 : g_assert_true (retval);
629 : :
630 : 1 : MwtTariff *loaded_tariff = mwt_tariff_loader_get_tariff (loader);
631 : :
632 : : /* Check properties. */
633 [ - + ]: 1 : g_assert_cmpstr (mwt_tariff_get_name (loaded_tariff), ==,
634 : : mwt_tariff_get_name (built_tariff));
635 : :
636 : 1 : GPtrArray *built_periods = mwt_tariff_get_periods (built_tariff);
637 : 1 : GPtrArray *loaded_periods = mwt_tariff_get_periods (loaded_tariff);
638 [ - + ]: 1 : g_assert_cmpuint (loaded_periods->len, ==, built_periods->len);
639 : :
640 [ + + ]: 3 : for (gsize i = 0; i < loaded_periods->len; i++)
641 : : {
642 : 2 : MwtPeriod *built_period = g_ptr_array_index (built_periods, i);
643 : 2 : MwtPeriod *loaded_period = g_ptr_array_index (loaded_periods, i);
644 : :
645 : 2 : assert_periods_equal (loaded_period, built_period);
646 : : }
647 : 1 : }
648 : :
649 : : int
650 : 1 : main (int argc,
651 : : char **argv)
652 : : {
653 : 1 : setlocale (LC_ALL, "");
654 : 1 : g_test_init (&argc, &argv, NULL);
655 : :
656 : 1 : g_test_add_func ("/tariff/properties", test_tariff_properties);
657 : 1 : g_test_add_func ("/tariff/lookup", test_tariff_lookup);
658 : 1 : g_test_add_func ("/tariff/next-transition", test_tariff_next_transition);
659 : 1 : g_test_add_func ("/tariff/serialisation/roundtrip", test_tariff_serialisation_roundtrip);
660 : :
661 : 1 : return g_test_run ();
662 : : }
|