Files
Anthony PERARD ddf34d4bb8 tools/tests: Fix return value of test-rangeset
Otherwise, failed tests are ignored by automated test.

Fixes: 7bf777b42c ("tootls/tests: introduce unit tests for rangesets")
Signed-off-by: Anthony PERARD <anthony.perard@vates.tech>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
2025-06-06 12:00:40 +02:00

229 lines
5.2 KiB
C

/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Unit tests for rangesets.
*
* Copyright (C) 2025 Cloud Software Group
*/
#include "harness.h"
struct range {
unsigned long start, end;
};
struct action {
enum {
ADD,
REMOVE,
} action;
struct range r;
};
#define DECLARE_ACTIONS(nr) static const struct action actions ## nr []
#define DECLARE_RESULTS(nr) static const struct range results ## nr []
/*
* Subtract range with tail overlap on existing range:
*
* { 0, 1, 4, 5 } - { 3, 4 } = { 0, 1, 5, 5 }
*/
DECLARE_ACTIONS(0) = {
{ ADD, { 0, 1 } },
{ ADD, { 4, 5 } },
{ REMOVE, { 3, 4 } },
};
DECLARE_RESULTS(0) = {
{ 0, 1 }, { 5, 5 },
};
/*
* Subtract range with complete and tail overlap on existing ranges:
*
* { 0, 1, 4, 5, 7, 8 } - { 3, 4, 5, 6, 7 } = { 0, 1, 8 }
*/
DECLARE_ACTIONS(1) = {
{ ADD, { 0, 1 } },
{ ADD, { 4, 5 } },
{ ADD, { 7, 8 } },
{ REMOVE, { 3, 7 } },
};
DECLARE_RESULTS(1) = {
{ 0, 1 }, { 8, 8 },
};
/*
* Subtract range with no overlap:
*
* { 0, 1, 4, 5 } - { 2, 3 } = { 0, 1, 4, 5 }
*/
DECLARE_ACTIONS(2) = {
{ ADD, { 0, 1 } },
{ ADD, { 4, 5 } },
{ REMOVE, { 2, 3 } },
};
DECLARE_RESULTS(2) = {
{ 0, 1 }, { 4, 5 },
};
/*
* Subtract range with partial overlap on two existing ranges:
*
* { 0, 1, 4, 5 } - { 1, 4 } = { 0, 5 }
*/
DECLARE_ACTIONS(3) = {
{ ADD, { 0, 1 } },
{ ADD, { 4, 5 } },
{ REMOVE, { 1, 4 } },
};
DECLARE_RESULTS(3) = {
{ 0, 0 }, { 5, 5 },
};
static const struct test {
unsigned int nr_actions, nr_results;
const struct action *actions;
const struct range *result;
} tests[] = {
#define DECLARE_TEST(nr) \
{ \
.actions = actions ## nr, \
.nr_actions = ARRAY_SIZE(actions ## nr), \
.result = results ## nr, \
.nr_results = ARRAY_SIZE(results ## nr), \
}
DECLARE_TEST(0),
DECLARE_TEST(1),
DECLARE_TEST(2),
DECLARE_TEST(3),
#undef DECLARE_TEST
};
static int print_range(unsigned long s, unsigned long e, void *data)
{
printf("[%ld, %ld]\n", s, e);
return 0;
}
static int count_ranges(unsigned long s, unsigned long e, void *data)
{
unsigned int *nr = data;
++*nr;
return 0;
}
static const struct range *expected;
static int check_ranges(unsigned long s, unsigned long e, void *data)
{
unsigned int *nr = data;
int rc = 0;
if ( s != expected[*nr].start || e != expected[*nr].end )
rc = -EINVAL;
++*nr;
return rc;
}
static void print_both(struct rangeset *r, const struct range *expected,
unsigned int nr_expected)
{
unsigned int i;
printf("Result:\n");
rangeset_report_ranges(r, 0, ~0UL, print_range, NULL);
printf("Expected:\n");
for ( i = 0; i < nr_expected; i++ )
printf("[%ld, %ld]\n", expected[i].start, expected[i].end);
}
int main(int argc, char **argv)
{
struct rangeset *r = rangeset_new(NULL, NULL, 0);
unsigned int i;
int ret_code = 0;
ASSERT(r);
for ( i = 0 ; i < ARRAY_SIZE(tests); i++ )
{
unsigned int j, nr = 0;
int rc = 0;
rangeset_purge(r);
for ( j = 0; j < tests[i].nr_actions; j++ )
{
const struct action *a = &tests[i].actions[j];
switch ( a->action )
{
case ADD:
rc = rangeset_add_range(r, a->r.start, a->r.end);
break;
case REMOVE:
rc = rangeset_remove_range(r, a->r.start, a->r.end);
break;
}
if ( rc )
{
printf("Test %u failed to %s range [%ld, %ld]\n",
i, a->action == ADD ? "add" : "remove",
a->r.start, a->r.end);
rangeset_report_ranges(r, 0, ~0UL, print_range, NULL);
break;
}
}
if ( rc )
{
/* Action failed, skip this test and set exit code to failure. */
ret_code = EXIT_FAILURE;
continue;
}
rc = rangeset_report_ranges(r, 0, ~0UL, count_ranges, &nr);
if ( rc )
{
printf("Test %u unable to count number of result ranges\n", i);
rangeset_report_ranges(r, 0, ~0UL, print_range, NULL);
ret_code = EXIT_FAILURE;
continue;
}
if ( nr != tests[i].nr_results )
{
printf("Test %u unexpected number of result ranges, expected: %u got: %u\n",
i, tests[i].nr_results, nr);
print_both(r, tests[i].result, tests[i].nr_results);
ret_code = EXIT_FAILURE;
continue;
}
nr = 0;
expected = tests[i].result;
rc = rangeset_report_ranges(r, 0, ~0UL, check_ranges, &nr);
if ( rc )
{
printf("Test %u range checking failed\n", i);
print_both(r, tests[i].result, tests[i].nr_results);
ret_code = EXIT_FAILURE;
continue;
}
}
return ret_code;
}
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/