@@ -154,6 +154,109 @@ void test_udpard_fragment_seek()
154154 TEST_ASSERT_EQUAL_size_t (0 , alloc_payload.allocated_fragments );
155155}
156156
157+ void test_udpard_fragment_gather ()
158+ {
159+ instrumented_allocator_t alloc_frag{};
160+ instrumented_allocator_new (&alloc_frag);
161+ const udpard_mem_resource_t mem_frag = instrumented_allocator_make_resource (&alloc_frag);
162+
163+ instrumented_allocator_t alloc_payload{};
164+ instrumented_allocator_new (&alloc_payload);
165+ const udpard_mem_resource_t mem_payload = instrumented_allocator_make_resource (&alloc_payload);
166+ const udpard_mem_deleter_t del_payload = instrumented_allocator_make_deleter (&alloc_payload);
167+
168+ // Test 1: NULL fragment returns 0.
169+ char buf[100 ]; // NOLINT(*-avoid-c-arrays)
170+ TEST_ASSERT_EQUAL_size_t (0 , udpard_fragment_gather (nullptr , sizeof (buf), static_cast <void *>(buf)));
171+
172+ // Test 2: NULL destination returns 0.
173+ udpard_fragment_t * single = make_test_fragment (mem_frag, mem_payload, del_payload, 0 , 5 , " hello" );
174+ TEST_ASSERT_NOT_NULL (single);
175+ single->index_offset .up = nullptr ;
176+ single->index_offset .lr [0 ] = nullptr ;
177+ single->index_offset .lr [1 ] = nullptr ;
178+ single->index_offset .bf = 0 ;
179+ TEST_ASSERT_EQUAL_size_t (0 , udpard_fragment_gather (single, sizeof (buf), nullptr ));
180+
181+ // Test 3: Single fragment - gather all.
182+ (void ) std::memset (static_cast <void *>(buf), 0 , sizeof (buf));
183+ TEST_ASSERT_EQUAL_size_t (5 , udpard_fragment_gather (single, sizeof (buf), static_cast <void *>(buf)));
184+ TEST_ASSERT_EQUAL_MEMORY (" hello" , buf, 5 );
185+
186+ // Test 4: Single fragment - truncation (destination smaller than fragment).
187+ (void ) std::memset (static_cast <void *>(buf), 0 , sizeof (buf));
188+ TEST_ASSERT_EQUAL_size_t (3 , udpard_fragment_gather (single, 3 , static_cast <void *>(buf)));
189+ TEST_ASSERT_EQUAL_MEMORY (" hel" , buf, 3 );
190+
191+ // Cleanup single fragment.
192+ mem_payload.free (mem_payload.user , single->origin .size , single->origin .data );
193+ mem_frag.free (mem_frag.user , sizeof (udpard_fragment_t ), single);
194+
195+ // Test 5: Multiple fragments forming a tree.
196+ // Create tree: root at offset 5 ("MID"), left at offset 0 ("ABCDE"), right at offset 10 ("WXYZ")
197+ // Total payload when gathered: "ABCDE" + "MID" + "WXYZ" = "ABCDEMIDWXYZ" (12 bytes)
198+ udpard_fragment_t * root = make_test_fragment (mem_frag, mem_payload, del_payload, 5 , 3 , " MID" );
199+ udpard_fragment_t * left = make_test_fragment (mem_frag, mem_payload, del_payload, 0 , 5 , " ABCDE" );
200+ udpard_fragment_t * right = make_test_fragment (mem_frag, mem_payload, del_payload, 10 , 4 , " WXYZ" );
201+ TEST_ASSERT_NOT_NULL (root);
202+ TEST_ASSERT_NOT_NULL (left);
203+ TEST_ASSERT_NOT_NULL (right);
204+
205+ // Build tree structure.
206+ root->index_offset .up = nullptr ;
207+ root->index_offset .lr [0 ] = &left->index_offset ;
208+ root->index_offset .lr [1 ] = &right->index_offset ;
209+ root->index_offset .bf = 0 ;
210+
211+ left->index_offset .up = &root->index_offset ;
212+ left->index_offset .lr [0 ] = nullptr ;
213+ left->index_offset .lr [1 ] = nullptr ;
214+ left->index_offset .bf = 0 ;
215+
216+ right->index_offset .up = &root->index_offset ;
217+ right->index_offset .lr [0 ] = nullptr ;
218+ right->index_offset .lr [1 ] = nullptr ;
219+ right->index_offset .bf = 0 ;
220+
221+ // Gather from root - should collect all fragments in order.
222+ (void ) std::memset (static_cast <void *>(buf), 0 , sizeof (buf));
223+ TEST_ASSERT_EQUAL_size_t (12 , udpard_fragment_gather (root, sizeof (buf), static_cast <void *>(buf)));
224+ TEST_ASSERT_EQUAL_MEMORY (" ABCDEMIDWXYZ" , buf, 12 );
225+
226+ // Gather from left child - should still collect all fragments (traverses to root first).
227+ (void ) std::memset (static_cast <void *>(buf), 0 , sizeof (buf));
228+ TEST_ASSERT_EQUAL_size_t (12 , udpard_fragment_gather (left, sizeof (buf), static_cast <void *>(buf)));
229+ TEST_ASSERT_EQUAL_MEMORY (" ABCDEMIDWXYZ" , buf, 12 );
230+
231+ // Gather from right child - should still collect all fragments.
232+ (void ) std::memset (static_cast <void *>(buf), 0 , sizeof (buf));
233+ TEST_ASSERT_EQUAL_size_t (12 , udpard_fragment_gather (right, sizeof (buf), static_cast <void *>(buf)));
234+ TEST_ASSERT_EQUAL_MEMORY (" ABCDEMIDWXYZ" , buf, 12 );
235+
236+ // Test 6: Truncation with multiple fragments - buffer smaller than total.
237+ (void ) std::memset (static_cast <void *>(buf), 0 , sizeof (buf));
238+ TEST_ASSERT_EQUAL_size_t (7 , udpard_fragment_gather (root, 7 , static_cast <void *>(buf)));
239+ TEST_ASSERT_EQUAL_MEMORY (" ABCDEMI" , buf, 7 );
240+
241+ // Test 7: Truncation mid-fragment.
242+ (void ) std::memset (static_cast <void *>(buf), 0 , sizeof (buf));
243+ TEST_ASSERT_EQUAL_size_t (3 , udpard_fragment_gather (root, 3 , static_cast <void *>(buf)));
244+ TEST_ASSERT_EQUAL_MEMORY (" ABC" , buf, 3 );
245+
246+ // Test 8: Zero-size destination.
247+ TEST_ASSERT_EQUAL_size_t (0 , udpard_fragment_gather (root, 0 , static_cast <void *>(buf)));
248+
249+ // Cleanup.
250+ mem_payload.free (mem_payload.user , left->origin .size , left->origin .data );
251+ mem_frag.free (mem_frag.user , sizeof (udpard_fragment_t ), left);
252+ mem_payload.free (mem_payload.user , root->origin .size , root->origin .data );
253+ mem_frag.free (mem_frag.user , sizeof (udpard_fragment_t ), root);
254+ mem_payload.free (mem_payload.user , right->origin .size , right->origin .data );
255+ mem_frag.free (mem_frag.user , sizeof (udpard_fragment_t ), right);
256+ TEST_ASSERT_EQUAL_size_t (0 , alloc_frag.allocated_fragments );
257+ TEST_ASSERT_EQUAL_size_t (0 , alloc_payload.allocated_fragments );
258+ }
259+
157260} // namespace
158261
159262extern " C" void setUp () {}
@@ -164,5 +267,6 @@ int main()
164267{
165268 UNITY_BEGIN ();
166269 RUN_TEST (test_udpard_fragment_seek);
270+ RUN_TEST (test_udpard_fragment_gather);
167271 return UNITY_END ();
168272}
0 commit comments