Skip to content

Commit bfbf4c8

Browse files
improve test coverage
1 parent 04f644e commit bfbf4c8

4 files changed

Lines changed: 390 additions & 7 deletions

File tree

tests/src/test_intrusive_guards.c

Lines changed: 111 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ static bool eject_stub(udpard_tx_t* const tx, udpard_tx_ejection_t* const ejecti
4141
return true;
4242
}
4343

44-
static const udpard_tx_vtable_t tx_vtable = { .eject = eject_stub };
44+
static const udpard_tx_vtable_t tx_vtable = { .eject = eject_stub };
45+
static const udpard_tx_vtable_t tx_vtable_null_eject = { .eject = NULL };
4546

4647
// RX callback stub used for constructor checks.
4748
static void on_message_stub(udpard_rx_t* const rx, udpard_rx_port_t* const port, const udpard_rx_transfer_t transfer)
@@ -51,7 +52,9 @@ static void on_message_stub(udpard_rx_t* const rx, udpard_rx_port_t* const port,
5152
(void)transfer;
5253
}
5354

54-
static const udpard_rx_port_vtable_t rx_vtable = { .on_message = on_message_stub };
55+
static const udpard_rx_port_vtable_t rx_vtable = { .on_message = on_message_stub };
56+
static const udpard_rx_port_vtable_t rx_vtable_null_cb = { .on_message = NULL };
57+
static const udpard_deleter_vtable_t del_vtable_null_free = { .free = NULL };
5558

5659
static void test_misc_guards(void)
5760
{
@@ -82,6 +85,16 @@ static void test_tx_new_guards(void)
8285
TEST_ASSERT_FALSE(udpard_tx_new(NULL, 1U, 1U, 1U, mem_ok, &tx_vtable));
8386
TEST_ASSERT_FALSE(udpard_tx_new(&tx, 0U, 1U, 1U, mem_ok, &tx_vtable));
8487
TEST_ASSERT_FALSE(udpard_tx_new(&tx, 1U, 1U, 1U, mem_ok, NULL));
88+
TEST_ASSERT_FALSE(udpard_tx_new(&tx, 1U, 1U, 1U, mem_ok, &tx_vtable_null_eject));
89+
90+
// Reject invalid payload memory resources.
91+
const udpard_mem_vtable_t bad_alloc = { .base = { .free = free_heap }, .alloc = NULL };
92+
const udpard_tx_mem_resources_t mem_bad_payload = {
93+
.transfer = make_mem(transfer_pool),
94+
.payload = { make_mem(payload_pool), { .vtable = &bad_alloc, .context = NULL }, make_mem(payload_pool) },
95+
};
96+
TEST_ASSERT_FALSE(udpard_tx_new(&tx, 1U, 1U, 1U, mem_bad_payload, &tx_vtable));
97+
8598
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 1U, 1U, 4U, mem_ok, &tx_vtable));
8699
udpard_tx_free(&tx);
87100
}
@@ -99,15 +112,27 @@ static void test_tx_push_guards(void)
99112
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 1U, 1U, 4U, mem_ok, &tx_vtable));
100113

101114
// Validate argument checks for subject push.
102-
const udpard_bytes_scattered_t empty_payload = make_scattered("", 0U);
115+
const udpard_bytes_scattered_t empty_payload = make_scattered("", 0U);
116+
const udpard_bytes_scattered_t empty_payload_null = { .bytes = { .size = 0U, .data = NULL }, .next = NULL };
117+
const udpard_bytes_scattered_t invalid_payload_ptr = { .bytes = { .size = 1U, .data = NULL }, .next = NULL };
103118
TEST_ASSERT_FALSE(
104119
udpard_tx_push(NULL, 0, 1, 1U, udpard_prio_fast, 1U, udpard_make_subject_endpoint(1U), empty_payload, NULL));
105120
TEST_ASSERT_FALSE(
106121
udpard_tx_push(&tx, 2, 1, 1U, udpard_prio_fast, 1U, udpard_make_subject_endpoint(1U), empty_payload, NULL));
122+
TEST_ASSERT_FALSE(
123+
udpard_tx_push(&tx, -1, 1, 1U, udpard_prio_fast, 1U, udpard_make_subject_endpoint(1U), empty_payload, NULL));
124+
tx.local_uid = 0U;
125+
TEST_ASSERT_FALSE(
126+
udpard_tx_push(&tx, 0, 1, 1U, udpard_prio_fast, 1U, udpard_make_subject_endpoint(1U), empty_payload, NULL));
127+
tx.local_uid = 1U;
107128
TEST_ASSERT_FALSE(
108129
udpard_tx_push(&tx, 0, 1, 0U, udpard_prio_fast, 1U, udpard_make_subject_endpoint(1U), empty_payload, NULL));
109130
TEST_ASSERT_FALSE(udpard_tx_push(
110131
&tx, 0, 1, 1U, udpard_prio_fast, 1U, (udpard_udpip_ep_t){ .ip = 0U, .port = 0U }, empty_payload, NULL));
132+
TEST_ASSERT_FALSE(
133+
udpard_tx_push(&tx, 0, 1, 1U, udpard_prio_fast, 1U, udpard_make_subject_endpoint(1U), invalid_payload_ptr, NULL));
134+
TEST_ASSERT_TRUE(
135+
udpard_tx_push(&tx, 0, 1, 1U, udpard_prio_fast, 1U, udpard_make_subject_endpoint(1U), empty_payload_null, NULL));
111136
TEST_ASSERT_TRUE(
112137
udpard_tx_push(&tx, 0, 1, 1U, udpard_prio_fast, 1U, udpard_make_subject_endpoint(1U), empty_payload, NULL));
113138
udpard_tx_free(&tx);
@@ -126,17 +151,85 @@ static void test_tx_push_unicast_guards(void)
126151
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 2U, 2U, 4U, mem_ok, &tx_vtable));
127152

128153
// Validate argument checks for unicast push.
129-
const udpard_bytes_scattered_t empty_payload = make_scattered("", 0U);
154+
const udpard_bytes_scattered_t empty_payload = make_scattered("", 0U);
155+
const udpard_bytes_scattered_t empty_payload_null = { .bytes = { .size = 0U, .data = NULL }, .next = NULL };
156+
const udpard_bytes_scattered_t invalid_payload_ptr = { .bytes = { .size = 1U, .data = NULL }, .next = NULL };
130157
udpard_udpip_ep_t endpoints[UDPARD_IFACE_COUNT_MAX] = { 0 };
131158
endpoints[0] = (udpard_udpip_ep_t){ .ip = 0x0A000001U, .port = 9000U };
132159
TEST_ASSERT_FALSE(udpard_tx_push_unicast(NULL, 0, 1, udpard_prio_nominal, endpoints, empty_payload, NULL));
133160
TEST_ASSERT_FALSE(udpard_tx_push_unicast(&tx, 2, 1, udpard_prio_nominal, endpoints, empty_payload, NULL));
161+
TEST_ASSERT_FALSE(udpard_tx_push_unicast(&tx, -1, 1, udpard_prio_nominal, endpoints, empty_payload, NULL));
162+
tx.local_uid = 0U;
163+
TEST_ASSERT_FALSE(udpard_tx_push_unicast(&tx, 0, 1, udpard_prio_nominal, endpoints, empty_payload, NULL));
164+
tx.local_uid = 2U;
165+
TEST_ASSERT_FALSE(udpard_tx_push_unicast(&tx, 0, 1, udpard_prio_nominal, endpoints, invalid_payload_ptr, NULL));
166+
TEST_ASSERT_TRUE(udpard_tx_push_unicast(&tx, 0, 1, udpard_prio_nominal, endpoints, empty_payload_null, NULL));
134167
TEST_ASSERT_TRUE(udpard_tx_push_unicast(&tx, 0, 1, udpard_prio_nominal, endpoints, empty_payload, NULL));
135168
endpoints[0] = (udpard_udpip_ep_t){ .ip = 0U, .port = 0U };
136169
TEST_ASSERT_FALSE(udpard_tx_push_unicast(&tx, 0, 1, udpard_prio_nominal, endpoints, empty_payload, NULL));
137170
udpard_tx_free(&tx);
138171
}
139172

173+
static void test_tx_poll_and_free_guards(void)
174+
{
175+
// Validate no-op guard behavior for poll/free helpers.
176+
static byte_t transfer_pool[1024];
177+
static byte_t payload_pool[1024];
178+
const udpard_tx_mem_resources_t mem_ok = {
179+
.transfer = make_mem(transfer_pool),
180+
.payload = { make_mem(payload_pool), make_mem(payload_pool), make_mem(payload_pool) },
181+
};
182+
udpard_tx_t tx = { 0 };
183+
TEST_ASSERT_TRUE(udpard_tx_new(&tx, 10U, 11U, 4U, mem_ok, &tx_vtable));
184+
udpard_tx_poll(NULL, 0, UDPARD_IFACE_BITMAP_ALL);
185+
udpard_tx_poll(&tx, -1, UDPARD_IFACE_BITMAP_ALL);
186+
TEST_ASSERT_EQUAL_UINT16(0U, udpard_tx_pending_ifaces(NULL));
187+
udpard_tx_free(&tx);
188+
udpard_tx_free(NULL);
189+
}
190+
191+
static void test_rx_port_ctor_guards(void)
192+
{
193+
// Reject invalid memory resources and callback descriptors.
194+
static byte_t session_pool[1024];
195+
static byte_t fragment_pool[1024];
196+
const udpard_rx_mem_resources_t rx_mem_ok = {
197+
.session = make_mem(session_pool),
198+
.slot = make_mem(session_pool),
199+
.fragment = make_mem(fragment_pool),
200+
};
201+
const udpard_mem_vtable_t bad_alloc = { .base = { .free = free_heap }, .alloc = NULL };
202+
const udpard_mem_vtable_t bad_free = { .base = { .free = NULL }, .alloc = alloc_heap };
203+
const udpard_rx_mem_resources_t rx_mem_bad_session = {
204+
.session = { .vtable = &bad_alloc, .context = NULL },
205+
.slot = make_mem(session_pool),
206+
.fragment = make_mem(fragment_pool),
207+
};
208+
const udpard_rx_mem_resources_t rx_mem_bad_slot = {
209+
.session = make_mem(session_pool),
210+
.slot = { .vtable = &bad_alloc, .context = NULL },
211+
.fragment = make_mem(fragment_pool),
212+
};
213+
const udpard_rx_mem_resources_t rx_mem_bad_fragment = {
214+
.session = make_mem(session_pool),
215+
.slot = make_mem(session_pool),
216+
.fragment = { .vtable = &bad_free, .context = NULL },
217+
};
218+
219+
udpard_rx_port_t port = { 0 };
220+
TEST_ASSERT_FALSE(udpard_rx_port_new(NULL, 1U, rx_mem_ok, &rx_vtable));
221+
TEST_ASSERT_FALSE(udpard_rx_port_new(&port, 1U, rx_mem_bad_session, &rx_vtable));
222+
TEST_ASSERT_FALSE(udpard_rx_port_new(&port, 1U, rx_mem_bad_slot, &rx_vtable));
223+
TEST_ASSERT_FALSE(udpard_rx_port_new(&port, 1U, rx_mem_bad_fragment, &rx_vtable));
224+
TEST_ASSERT_FALSE(udpard_rx_port_new(&port, 1U, rx_mem_ok, NULL));
225+
TEST_ASSERT_FALSE(udpard_rx_port_new(&port, 1U, rx_mem_ok, &rx_vtable_null_cb));
226+
TEST_ASSERT_TRUE(udpard_rx_port_new(&port, 1U, rx_mem_ok, &rx_vtable));
227+
228+
// Wrapper constructors should fail consistently when base validation fails.
229+
TEST_ASSERT_FALSE(udpard_rx_port_new_stateless(&port, 1U, rx_mem_bad_session, &rx_vtable));
230+
TEST_ASSERT_FALSE(udpard_rx_port_new_unicast(&port, 1U, rx_mem_bad_session, &rx_vtable));
231+
}
232+
140233
static void test_rx_port_push_guards(void)
141234
{
142235
// Prepare RX and port.
@@ -163,9 +256,14 @@ static void test_rx_port_push_guards(void)
163256
(void)header_serialize(datagram, meta, 0U, crc_full(0U, NULL));
164257
const udpard_bytes_mut_t payload = { .size = sizeof(datagram), .data = datagram };
165258
const udpard_deleter_t del = { .vtable = &del_vtable, .context = NULL };
259+
const udpard_deleter_t del_bad = { .vtable = &del_vtable_null_free, .context = NULL };
166260
TEST_ASSERT_FALSE(
167261
udpard_rx_port_push(NULL, &port, 0, (udpard_udpip_ep_t){ .ip = 1U, .port = 1U }, payload, del, 0U));
168262
TEST_ASSERT_FALSE(udpard_rx_port_push(&rx, NULL, 0, (udpard_udpip_ep_t){ .ip = 1U, .port = 1U }, payload, del, 0U));
263+
TEST_ASSERT_FALSE(
264+
udpard_rx_port_push(&rx, &port, -1, (udpard_udpip_ep_t){ .ip = 1U, .port = 1U }, payload, del, 0U));
265+
TEST_ASSERT_FALSE(
266+
udpard_rx_port_push(&rx, &port, 0, (udpard_udpip_ep_t){ .ip = 0U, .port = 1U }, payload, del, 0U));
169267
TEST_ASSERT_FALSE(
170268
udpard_rx_port_push(&rx, &port, 0, (udpard_udpip_ep_t){ .ip = 1U, .port = 1U }, payload, del, 99U));
171269
TEST_ASSERT_FALSE(udpard_rx_port_push(&rx,
@@ -175,8 +273,15 @@ static void test_rx_port_push_guards(void)
175273
(udpard_bytes_mut_t){ .size = 1U, .data = NULL },
176274
del,
177275
0U));
276+
TEST_ASSERT_FALSE(udpard_rx_port_push(
277+
&rx, &port, 0, (udpard_udpip_ep_t){ .ip = 1U, .port = 1U }, payload, (udpard_deleter_t){ 0 }, 0U));
278+
TEST_ASSERT_FALSE(
279+
udpard_rx_port_push(&rx, &port, 0, (udpard_udpip_ep_t){ .ip = 1U, .port = 1U }, payload, del_bad, 0U));
178280
TEST_ASSERT_TRUE(udpard_rx_port_push(&rx, &port, 0, (udpard_udpip_ep_t){ .ip = 1U, .port = 1U }, payload, del, 0U));
179281

282+
// Free should ignore null arguments.
283+
udpard_rx_port_free(NULL, &port);
284+
udpard_rx_port_free(&rx, NULL);
180285
udpard_rx_port_free(&rx, &port);
181286
}
182287

@@ -190,6 +295,8 @@ int main(void)
190295
RUN_TEST(test_tx_new_guards);
191296
RUN_TEST(test_tx_push_guards);
192297
RUN_TEST(test_tx_push_unicast_guards);
298+
RUN_TEST(test_tx_poll_and_free_guards);
299+
RUN_TEST(test_rx_port_ctor_guards);
193300
RUN_TEST(test_rx_port_push_guards);
194301
return UNITY_END();
195302
}

tests/src/test_intrusive_misc.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,11 @@ static void test_misc_helpers(void)
192192
endpoints[1] = (udpard_udpip_ep_t){ .ip = 0x0A000001U, .port = 9999U };
193193
TEST_ASSERT_TRUE(mem_same(mem_frag, mem_frag));
194194
TEST_ASSERT_FALSE(mem_same(mem_frag, mem_payload));
195+
// Use same context with different vtables to force the second mem_same() predicate.
196+
const udpard_mem_vtable_t alt_vtable = { .base = { .free = instrumented_allocator_free },
197+
.alloc = instrumented_allocator_alloc };
198+
const udpard_mem_t alt_vtable_same_context = { .vtable = &alt_vtable, .context = mem_frag.context };
199+
TEST_ASSERT_FALSE(mem_same(mem_frag, alt_vtable_same_context));
195200
TEST_ASSERT_EQUAL_UINT16(0U, valid_ep_bitmap(NULL));
196201
TEST_ASSERT_EQUAL_UINT16((uint16_t)(1U << 1U), valid_ep_bitmap(endpoints));
197202
mem_free_payload(del_payload, (udpard_bytes_mut_t){ 0 });
@@ -225,6 +230,27 @@ static void test_misc_helpers(void)
225230
key = 9U;
226231
TEST_ASSERT_EQUAL_INT32(+1, cavl_compare_fragment_end(&key, &probe.index_offset));
227232

233+
// Exercise fragment helpers on null inputs.
234+
char sink = 0;
235+
const udpard_fragment_t* null_cursor = NULL;
236+
TEST_ASSERT_NULL(udpard_fragment_seek(NULL, 0U));
237+
TEST_ASSERT_NULL(udpard_fragment_next(NULL));
238+
TEST_ASSERT_EQUAL_size_t(0U, udpard_fragment_gather(NULL, 0U, 1U, &sink));
239+
TEST_ASSERT_EQUAL_size_t(0U, udpard_fragment_gather(&null_cursor, 0U, 1U, &sink));
240+
241+
// Drive each disjunct in is_listed().
242+
udpard_list_t list = { .head = NULL, .tail = NULL };
243+
udpard_listed_t member = { .next = NULL, .prev = NULL };
244+
TEST_ASSERT_FALSE(is_listed(&list, &member));
245+
member.next = &member;
246+
TEST_ASSERT_TRUE(is_listed(&list, &member));
247+
member.next = NULL;
248+
member.prev = &member;
249+
TEST_ASSERT_TRUE(is_listed(&list, &member));
250+
member.prev = NULL;
251+
list.head = &member;
252+
TEST_ASSERT_TRUE(is_listed(&list, &member));
253+
228254
// Free a small tree starting from a child to cover descent and ascent.
229255
udpard_fragment_t* const root = make_fragment(mem_frag, mem_payload, del_payload, 2U, "BB", 2U);
230256
udpard_fragment_t* const left = make_fragment(mem_frag, mem_payload, del_payload, 0U, "AA", 2U);

0 commit comments

Comments
 (0)