libtest: Add push/pop fixture support

Update #3199.
This commit is contained in:
Sebastian Huber
2020-06-09 15:55:22 +02:00
parent 6b27e3251e
commit cb3c6bdc0f
4 changed files with 200 additions and 30 deletions

View File

@@ -66,6 +66,13 @@ typedef struct T_fixture {
void *initial_context;
} T_fixture;
typedef struct T_fixture_node {
struct T_fixture_node *next;
struct T_fixture_node *previous;
const T_fixture *fixture;
void *context;
} T_fixture_node;
#define T_ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
/*
@@ -2232,6 +2239,10 @@ void *T_fixture_context(void);
void T_set_fixture_context(void *);
void *T_push_fixture(T_fixture_node *, const T_fixture *);
void T_pop_fixture(void);
#ifdef __rtems__
#define T_TEST_CASE_FIXTURE(name, fixture) \
void T_case_body_##name(void); \

View File

@@ -1,7 +1,7 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2018, 2019 embedded brains GmbH
* Copyright (C) 2018, 2020 embedded brains GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -62,7 +62,8 @@ typedef struct {
T_verbosity verbosity;
const T_case_context *registered_cases;
const T_case_context *current_case;
void *fixture_context;
T_fixture_node *fixtures;
T_fixture_node case_fixture;
LIST_HEAD(, T_destructor) destructors;
T_time case_begin_time;
atomic_uint planned_steps;
@@ -288,7 +289,7 @@ static const char *
T_scope(T_context *ctx, char *buf)
{
const char *r;
const T_case_context *tc;
T_fixture_node *node;
#if defined(__rtems__)
ISR_Level level;
@@ -327,19 +328,23 @@ T_scope(T_context *ctx, char *buf)
r = buf;
#endif
tc = ctx->current_case;
if (tc != NULL) {
node = &ctx->case_fixture;
do {
const T_fixture *fixture;
fixture = tc->fixture;
fixture = node->fixture;
if (fixture != NULL && fixture->scope != NULL) {
size_t n;
n = strlen(r);
(*fixture->scope)(ctx->fixture_context, buf + n,
(*fixture->scope)(node->context, buf + n,
T_SCOPE_SIZE - n);
}
}
node = node->previous;
} while (node != NULL);
return r;
}
@@ -421,18 +426,20 @@ T_add_failure(T_context *ctx)
static void
T_stop(T_context *ctx)
{
const T_case_context *tc;
T_fixture_node *node;
tc = ctx->current_case;
node = ctx->fixtures;
if (tc != NULL) {
while (node != NULL) {
const T_fixture *fixture;
fixture = tc->fixture;
fixture = node->fixture;
if (fixture != NULL && fixture->stop != NULL) {
(*fixture->stop)(ctx->fixture_context);
(*fixture->stop)(node->context);
}
node = node->next;
}
longjmp(ctx->case_begin_context, 1);
@@ -478,13 +485,13 @@ T_set_verbosity(T_verbosity verbosity)
void *
T_fixture_context(void)
{
return T_instance.fixture_context;
return T_instance.fixtures->context;
}
void
T_set_fixture_context(void *context)
{
T_instance.fixture_context = context;
T_instance.fixtures->context = context;
}
const char *
@@ -730,6 +737,7 @@ T_do_run_initialize(const T_config *config)
ctx->buf_mask = 0;
}
ctx->fixtures = &ctx->case_fixture;
atomic_store_explicit(&ctx->buf_head, 0, memory_order_relaxed);
ctx->buf_tail = 0;
ctx->putchar = config->putchar;
@@ -761,6 +769,7 @@ T_do_case_begin(T_context *ctx, const T_case_context *tc)
fixture = tc->fixture;
ctx->verbosity = config->verbosity;
ctx->current_case = tc;
ctx->fixtures = &ctx->case_fixture;
LIST_INIT(&ctx->destructors);
atomic_store_explicit(&ctx->planned_steps, UINT_MAX,
memory_order_relaxed);
@@ -773,10 +782,11 @@ T_do_case_begin(T_context *ctx, const T_case_context *tc)
T_actions_forward(config, T_EVENT_CASE_BEGIN, tc->name);
if (fixture != NULL) {
ctx->fixture_context = fixture->initial_context;
ctx->case_fixture.fixture = fixture;
ctx->case_fixture.context = fixture->initial_context;
if (fixture->setup != NULL) {
(*fixture->setup)(ctx->fixture_context);
(*fixture->setup)(ctx->case_fixture.context);
}
}
}
@@ -785,7 +795,7 @@ static void
T_do_case_end(T_context *ctx, const T_case_context *tc)
{
const T_config *config;
const T_fixture *fixture;
T_fixture_node *node;
unsigned int planned_steps;
unsigned int steps;
unsigned int failures;
@@ -793,10 +803,22 @@ T_do_case_end(T_context *ctx, const T_case_context *tc)
T_time_string ts;
config = ctx->config;
fixture = tc->fixture;
node = ctx->fixtures;
ctx->fixtures = NULL;
if (fixture != NULL && fixture->teardown != NULL) {
(*fixture->teardown)(ctx->fixture_context);
while (node != NULL) {
const T_fixture *fixture;
T_fixture_node *dead;
fixture = node->fixture;
if (fixture != NULL && fixture->teardown != NULL) {
(*fixture->teardown)(node->context);
}
dead = node;
node = node->next;
memset(dead, 0, sizeof(*dead));
}
T_call_destructors(ctx);
@@ -1027,3 +1049,49 @@ T_now(void)
config = ctx->config;
return (*config->now)();
}
void *
T_push_fixture(T_fixture_node *node, const T_fixture *fixture)
{
T_context *ctx;
T_fixture_node *old;
void *context;
ctx = &T_instance;
old = ctx->fixtures;
old->previous = node;
node->next = old;
node->previous = NULL;
node->fixture = fixture;
context = fixture->initial_context;
node->context = context;
ctx->fixtures = node;
if (fixture != NULL && fixture->setup != NULL) {
(*fixture->setup)(context);
}
return context;
}
void
T_pop_fixture(void)
{
T_context *ctx;
T_fixture_node *node;
const T_fixture *fixture;
T_fixture_node *next;
ctx = &T_instance;
node = ctx->fixtures;
next = node->next;
next->previous = NULL;
ctx->fixtures = next;
fixture = node->fixture;
if (fixture != NULL && fixture->teardown != NULL) {
(*fixture->teardown)(node->context);
}
memset(node, 0, sizeof(*node));
}

View File

@@ -182,8 +182,8 @@ run_initialize(void)
T_set_putchar(censor_putchar, ctx, &ctx->putchar, &ctx->putchar_arg);
}
static const char expected_final[] = "Z:ttest01:C:342:N:1316:F:791:D:0.687999\n"
"Y:ReportHash:SHA256:efd7b69ac3ec0cac31fa147008bba87a077e6d53c0cfb8a836a4de2ae90ecc27\n";
static const char expected_final[] = "Z:ttest01:C:342:N:1329:F:791:D:0.687999\n"
"Y:ReportHash:SHA256:e5c3847558c805663117be13ef27fd89579f595148b8515c42a38bd1b9dd79c2\n";
static void
run_finalize(void)

View File

@@ -58,9 +58,77 @@ static const T_fixture fixture = {
.initial_context = &initial_value
};
static int initial_value_2 = 7;
static int counter_2;
static void
setup_2(void *ctx)
{
int *c;
T_log(T_QUIET, "setup 2 begin");
T_eq_ptr(ctx, &initial_value_2);
T_eq_ptr(ctx, T_fixture_context());
c = ctx;
counter_2 = *c;
T_set_fixture_context(&counter_2);
T_eq_ptr(&counter_2, T_fixture_context());
T_log(T_QUIET, "setup 2 end");
}
static void
stop_2(void *ctx)
{
int *c;
T_log(T_QUIET, "stop 2 begin");
T_eq_ptr(ctx, &counter_2);
c = ctx;
++(*c);
T_log(T_QUIET, "stop 2 end");
}
static void
teardown_2(void *ctx)
{
int *c;
T_log(T_QUIET, "teardown 2 begin");
T_eq_ptr(ctx, &counter_2);
c = ctx;
T_eq_int(*c, 8);
T_log(T_QUIET, "teardown 2 end");
}
static void
scope_2(void *ctx, char *buf, size_t n)
{
strlcpy(buf, "/AndMore", n);
}
static const T_fixture fixture_2 = {
.setup = setup_2,
.stop = stop_2,
.teardown = teardown_2,
.scope = scope_2,
.initial_context = &initial_value_2
};
static T_fixture_node node;
T_TEST_CASE_FIXTURE(fixture, &fixture)
{
void *ctx;
T_assert_true(true, "all right");
ctx = T_push_fixture(&node, &fixture_2);
T_eq_ptr(ctx, &initial_value_2);
++counter_2;
T_pop_fixture();
ctx = T_push_fixture(&node, &fixture_2);
T_eq_ptr(ctx, &initial_value_2);
T_assert_true(false, "test fails and we stop the test case");
T_log(T_QUIET, "not reached");
}
@@ -74,16 +142,39 @@ T_TEST_OUTPUT(fixture,
"P:1:0:UI1/More:test-fixture.c:14\n"
"P:2:0:UI1/More:test-fixture.c:18\n"
"L:setup end\n"
"P:3:0:UI1/More:test-fixture.c:63\n"
"F:4:0:UI1/More:test-fixture.c:64:test fails and we stop the test case\n"
"P:3:0:UI1/More:test-fixture.c:125\n"
"L:setup 2 begin\n"
"P:4:0:UI1/More/AndMore:test-fixture.c:71\n"
"P:5:0:UI1/More/AndMore:test-fixture.c:72\n"
"P:6:0:UI1/More/AndMore:test-fixture.c:76\n"
"L:setup 2 end\n"
"P:7:0:UI1/More/AndMore:test-fixture.c:127\n"
"L:teardown 2 begin\n"
"P:8:0:UI1/More:test-fixture.c:98\n"
"P:9:0:UI1/More:test-fixture.c:100\n"
"L:teardown 2 end\n"
"L:setup 2 begin\n"
"P:10:0:UI1/More/AndMore:test-fixture.c:71\n"
"P:11:0:UI1/More/AndMore:test-fixture.c:72\n"
"P:12:0:UI1/More/AndMore:test-fixture.c:76\n"
"L:setup 2 end\n"
"P:13:0:UI1/More/AndMore:test-fixture.c:131\n"
"F:14:0:UI1/More/AndMore:test-fixture.c:132:test fails and we stop the test case\n"
"L:stop 2 begin\n"
"P:15:0:UI1/More/AndMore:test-fixture.c:86\n"
"L:stop 2 end\n"
"L:stop begin\n"
"P:5:0:UI1/More:test-fixture.c:28\n"
"P:16:0:UI1/More/AndMore:test-fixture.c:28\n"
"L:stop end\n"
"L:teardown 2 begin\n"
"P:17:0:UI1/More/AndMore:test-fixture.c:98\n"
"P:18:0:UI1/More/AndMore:test-fixture.c:100\n"
"L:teardown 2 end\n"
"L:teardown begin\n"
"P:6:0:UI1/More:test-fixture.c:40\n"
"P:7:0:UI1/More:test-fixture.c:42\n"
"P:19:0:UI1/More:test-fixture.c:40\n"
"P:20:0:UI1/More:test-fixture.c:42\n"
"L:teardown end\n"
"E:fixture:N:8:F:1:D:0.001000\n");
"E:fixture:N:21:F:1:D:0.001000\n");
/*
* The license is at the end of the file to be able to use the test code and
@@ -94,7 +185,7 @@ T_TEST_OUTPUT(fixture,
/*
* SPDX-License-Identifier: BSD-2-Clause OR CC-BY-SA-4.0
*
* Copyright (C) 2018, 2019 embedded brains GmbH
* Copyright (C) 2018, 2020 embedded brains GmbH
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions