Files
federated-calendar/tests/test-range.c
T
Georges Basile Stavracas Neto 6234566874 core/range: Compute and use timestamps for comparison
Using GDateTime utilities is costly and shows up high in profiling.
That's because GDateTime has to run timezone offset checks for every
comparison. We can amortize this cost by converting these datetimes
to unix timestamps upfront, and using them for comparisons.

A complication is date-only ranges, for which unix timestamps wouldn't
work. For this, add a new kind of timestamp that only accounts for the
dates.

Add a new test case for date-only comparison.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/770>
2026-06-13 23:22:01 +02:00

274 lines
8.3 KiB
C

/* test-range.c
*
* Copyright 2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "gcal-range.h"
/*********************************************************************************************************************/
static void
range_new (void)
{
g_autoptr (GcalRange) range = NULL;
g_autoptr (GDateTime) start = NULL;
g_autoptr (GDateTime) end = NULL;
start = g_date_time_new_now_utc ();
end = g_date_time_add_seconds (start, 1);
range = gcal_range_new (start, end, GCAL_RANGE_DEFAULT);
g_assert_nonnull (range);
}
/*********************************************************************************************************************/
static void
range_invalid (void)
{
g_autoptr (GcalRange) range = NULL;
g_autoptr (GDateTime) start = NULL;
g_autoptr (GDateTime) end = NULL;
start = g_date_time_new_now_utc ();
end = g_date_time_add_seconds (start, 1);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "gcal_range_new: assertion 'range_start' failed");
range = gcal_range_new (NULL, NULL, GCAL_RANGE_DEFAULT);
g_test_assert_expected_messages ();
g_assert_null (range);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "gcal_range_new: assertion 'range_start' failed");
range = gcal_range_new (NULL, end, GCAL_RANGE_DEFAULT);
g_test_assert_expected_messages ();
g_assert_null (range);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "gcal_range_new: assertion 'range_end' failed");
range = gcal_range_new (start, NULL, GCAL_RANGE_DEFAULT);
g_test_assert_expected_messages ();
g_assert_null (range);
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "gcal_range_new: assertion 'g_date_time_compare (range_start, range_end) <= 0' failed");
range = gcal_range_new (end, start, GCAL_RANGE_DEFAULT);
g_test_assert_expected_messages ();
g_assert_null (range);
}
/*********************************************************************************************************************/
typedef struct
{
const gchar *start;
const gchar *end;
} TextRange;
static struct {
TextRange first;
TextRange second;
GcalRangeOverlap expected_overlap;
GcalRangePosition expected_position;
} ranges[] = {
/* Equal */
{
{ "2020-03-05T00:00:00", "2020-03-10T00:00:00" },
{ "2020-03-05T00:00:00", "2020-03-10T00:00:00" },
GCAL_RANGE_EQUAL,
GCAL_RANGE_MATCH,
},
/* Superset */
{
{ "2020-03-05T00:00:00", "2020-03-10T00:00:00" },
{ "2020-03-05T00:00:00", "2020-03-08T00:00:00" },
GCAL_RANGE_SUPERSET,
GCAL_RANGE_AFTER,
},
{
{ "2020-03-05T00:00:00", "2020-03-10T00:00:00" },
{ "2020-03-07T00:00:00", "2020-03-08T00:00:00" },
GCAL_RANGE_SUPERSET,
GCAL_RANGE_BEFORE,
},
{
{ "2020-03-05T00:00:00", "2020-03-10T00:00:00" },
{ "2020-03-07T00:00:00", "2020-03-10T00:00:00" },
GCAL_RANGE_SUPERSET,
GCAL_RANGE_BEFORE,
},
/* Subset */
{
{ "2020-03-05T00:00:00", "2020-03-08T00:00:00" },
{ "2020-03-05T00:00:00", "2020-03-10T00:00:00" },
GCAL_RANGE_SUBSET,
GCAL_RANGE_BEFORE,
},
{
{ "2020-03-07T00:00:00", "2020-03-08T00:00:00" },
{ "2020-03-05T00:00:00", "2020-03-10T00:00:00" },
GCAL_RANGE_SUBSET,
GCAL_RANGE_AFTER,
},
{
{ "2020-03-07T00:00:00", "2020-03-10T00:00:00" },
{ "2020-03-05T00:00:00", "2020-03-10T00:00:00" },
GCAL_RANGE_SUBSET,
GCAL_RANGE_AFTER,
},
/* Intersection */
{
{ "2020-03-05T00:00:00", "2020-03-08T00:00:00" },
{ "2020-03-07T00:00:00", "2020-03-10T00:00:00" },
GCAL_RANGE_INTERSECTS,
GCAL_RANGE_BEFORE,
},
{
{ "2020-03-07T00:00:00", "2020-03-10T00:00:00" },
{ "2020-03-05T00:00:00", "2020-03-08T00:00:00" },
GCAL_RANGE_INTERSECTS,
GCAL_RANGE_AFTER,
},
/* No Overlap */
{
{ "2020-03-05T00:00:00", "2020-03-10T00:00:00" },
{ "2020-03-10T00:00:00", "2020-03-15T00:00:00" },
GCAL_RANGE_NO_OVERLAP,
GCAL_RANGE_BEFORE,
},
{
{ "2020-03-10T00:00:00", "2020-03-15T00:00:00" },
{ "2020-03-05T00:00:00", "2020-03-10T00:00:00" },
GCAL_RANGE_NO_OVERLAP,
GCAL_RANGE_AFTER,
},
/* Zero length */
{
{ "2020-03-10T00:00:00", "2020-03-15T00:00:00" },
{ "2020-03-15T00:00:00", "2020-03-15T00:00:00" },
GCAL_RANGE_NO_OVERLAP,
GCAL_RANGE_BEFORE,
},
{
{ "2020-03-10T00:00:00", "2020-03-15T00:00:00" },
{ "2020-03-10T00:00:00", "2020-03-10T00:00:00" },
GCAL_RANGE_SUPERSET,
GCAL_RANGE_AFTER,
},
{
{ "2020-03-15T00:00:00", "2020-03-15T00:00:00" },
{ "2020-03-10T00:00:00", "2020-03-15T00:00:00" },
GCAL_RANGE_NO_OVERLAP,
GCAL_RANGE_AFTER,
},
{
{ "2020-03-10T00:00:00", "2020-03-10T00:00:00" },
{ "2020-03-10T00:00:00", "2020-03-15T00:00:00" },
GCAL_RANGE_SUBSET,
GCAL_RANGE_BEFORE,
},
{
{ "2020-03-10T00:00:00", "2020-03-10T00:00:00" },
{ "2020-03-10T00:00:00", "2020-03-10T00:00:00" },
GCAL_RANGE_EQUAL,
GCAL_RANGE_MATCH,
},
};
static void
range_calculate_overlap (void)
{
g_autoptr (GTimeZone) utc = NULL;
gint i;
utc = g_time_zone_new_utc ();
for (i = 0; i < G_N_ELEMENTS (ranges); i++)
{
g_autoptr (GDateTime) second_start = NULL;
g_autoptr (GDateTime) second_end = NULL;
g_autoptr (GDateTime) first_start = NULL;
g_autoptr (GDateTime) first_end = NULL;
g_autoptr (GcalRange) range_a = NULL;
g_autoptr (GcalRange) range_b = NULL;
GcalRangePosition position;
GcalRangeOverlap overlap;
first_start = g_date_time_new_from_iso8601 (ranges[i].first.start, utc);
first_end = g_date_time_new_from_iso8601 (ranges[i].first.end, utc);
second_start = g_date_time_new_from_iso8601 (ranges[i].second.start, utc);
second_end = g_date_time_new_from_iso8601 (ranges[i].second.end, utc);
range_a = gcal_range_new (first_start, first_end, GCAL_RANGE_DEFAULT);
g_assert_nonnull (range_a);
range_b = gcal_range_new (second_start, second_end, GCAL_RANGE_DEFAULT);
g_assert_nonnull (range_b);
overlap = gcal_range_calculate_overlap (range_a, range_b, &position);
g_assert_cmpint (overlap, ==, ranges[i].expected_overlap);
g_assert_cmpint (position, ==, ranges[i].expected_position);
}
}
/*********************************************************************************************************************/
static void
range_calculate_overlap_date_only (void)
{
g_autoptr (GcalRange) range_a = NULL;
g_autoptr (GcalRange) range_b = NULL;
GcalRangePosition position;
GcalRangeOverlap overlap;
range_a = gcal_range_new_take (g_date_time_new_utc (1921, 12, 31, 0, 0, 0),
g_date_time_new_utc (1922, 1, 1, 0, 0, 0),
GCAL_RANGE_DATE_ONLY);
g_assert_nonnull (range_a);
range_b = gcal_range_new_take (g_date_time_new_utc (2121, 10, 31, 0, 0, 0),
g_date_time_new_utc (2121, 11, 1, 0, 0, 0),
GCAL_RANGE_DATE_ONLY);
g_assert_nonnull (range_b);
overlap = gcal_range_calculate_overlap (range_a, range_b, &position);
g_assert_cmpint (overlap, ==, GCAL_RANGE_NO_OVERLAP);
g_assert_cmpint (position, ==, GCAL_RANGE_BEFORE);
}
/*********************************************************************************************************************/
gint
main (gint argc,
gchar *argv[])
{
g_setenv ("TZ", "UTC", TRUE);
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/range/new", range_new);
g_test_add_func ("/range/invalid-ranges", range_invalid);
g_test_add_func ("/range/calculate-overlap", range_calculate_overlap);
g_test_add_func ("/range/calculate-overlap-date-only", range_calculate_overlap_date_only);
return g_test_run ();
}