File size: 7,638 Bytes
78d2150 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 |
#include "../../unity/unity.h"
#include <stdlib.h>
#include <string.h>
/* We rely on the definitions from the included program:
- static struct buffer_record *head;
- static void save_buffer(struct buffer_record *buf);
- struct buffer_record and struct line definitions.
Since this file is included into the same translation unit,
we can access them directly. */
/* Helper to allocate and zero a line node */
static struct line* helper_alloc_line(void) {
struct line* l = (struct line*)malloc(sizeof(struct line));
if (l) {
memset(l, 0, sizeof(*l));
}
return l;
}
/* Helper to allocate and zero a buffer_record, with a provided line_start.
curr_line is initialized to a different allocated line to verify that
save_buffer() updates it to line_start. */
static struct buffer_record* helper_alloc_buf(struct line* line_start, struct line** out_orig_curr_line) {
struct buffer_record* b = (struct buffer_record*)malloc(sizeof(struct buffer_record));
if (b) {
memset(b, 0, sizeof(*b));
b->line_start = line_start;
struct line* bogus_curr = helper_alloc_line();
b->curr_line = bogus_curr;
b->next = (struct buffer_record*)0x1; /* set non-NULL intentionally; will be reset */
if (out_orig_curr_line) {
*out_orig_curr_line = bogus_curr;
}
}
return b;
}
/* Helper to free a chain of buffers created in tests.
We only free line_start and the buffer itself since save_buffer()
sets curr_line = line_start. */
static void helper_free_chain(struct buffer_record* start) {
while (start) {
struct buffer_record* n = start->next;
if (start->line_start) {
free(start->line_start);
}
free(start);
start = n;
}
}
/* setUp/tearDown required by Unity */
void setUp(void) {
/* Reset the global list head to ensure isolation between tests. */
head = NULL;
}
void tearDown(void) {
/* Free any buffers that may still be linked from head. */
if (head) {
helper_free_chain(head);
head = NULL;
}
}
/* Test: When head is NULL, save_buffer should set head to buf,
set buf->curr_line to buf->line_start, and clear buf->next to NULL. */
void test_save_buffer_initial_insert_sets_head_and_fields(void) {
struct line* l1 = helper_alloc_line();
TEST_ASSERT_NOT_NULL(l1);
struct line* orig_curr = NULL;
struct buffer_record* buf = helper_alloc_buf(l1, &orig_curr);
TEST_ASSERT_NOT_NULL(buf);
TEST_ASSERT_NOT_NULL(orig_curr);
/* Also create a garbage next to ensure it is cleared (we'll free it ourselves). */
struct buffer_record* garbage_next = (struct buffer_record*)malloc(sizeof(struct buffer_record));
TEST_ASSERT_NOT_NULL(garbage_next);
memset(garbage_next, 0, sizeof(*garbage_next));
buf->next = garbage_next;
TEST_ASSERT_NULL(head);
save_buffer(buf);
TEST_ASSERT_EQUAL_PTR(buf, head);
TEST_ASSERT_EQUAL_PTR(buf->line_start, buf->curr_line);
TEST_ASSERT_NULL(buf->next);
/* Cleanup: free the original (now orphan) curr_line and garbage_next, then the chain via head */
free(orig_curr);
free(garbage_next);
helper_free_chain(head);
head = NULL;
}
/* Test: Appending to a single-element list. */
void test_save_buffer_appends_to_single_element_list(void) {
/* Prepare existing head */
struct line* l_head = helper_alloc_line();
struct line* orig_curr_head = NULL;
struct buffer_record* buf_head = helper_alloc_buf(l_head, &orig_curr_head);
TEST_ASSERT_NOT_NULL(buf_head);
/* First insert: set head */
save_buffer(buf_head);
TEST_ASSERT_EQUAL_PTR(buf_head, head);
TEST_ASSERT_EQUAL_PTR(buf_head->line_start, buf_head->curr_line);
TEST_ASSERT_NULL(buf_head->next);
/* Prepare new buffer to append */
struct line* l_new = helper_alloc_line();
struct line* orig_curr_new = NULL;
struct buffer_record* buf_new = helper_alloc_buf(l_new, &orig_curr_new);
TEST_ASSERT_NOT_NULL(buf_new);
/* Append */
save_buffer(buf_new);
TEST_ASSERT_EQUAL_PTR(buf_head, head);
TEST_ASSERT_EQUAL_PTR(buf_new, buf_head->next);
TEST_ASSERT_NULL(buf_new->next);
TEST_ASSERT_EQUAL_PTR(buf_new->line_start, buf_new->curr_line);
/* Ensure existing node's curr_line remained at its line_start (already set by first save_buffer) */
TEST_ASSERT_EQUAL_PTR(buf_head->line_start, buf_head->curr_line);
/* Cleanup orphan curr_line allocations and chain */
free(orig_curr_head);
free(orig_curr_new);
helper_free_chain(head);
head = NULL;
}
/* Test: Appending to a multi-element list (length >= 2). */
void test_save_buffer_appends_to_multi_element_list(void) {
/* Build initial chain of two buffers: A -> B */
struct line* la = helper_alloc_line();
struct line* lb = helper_alloc_line();
struct line* orig_curr_a = NULL;
struct line* orig_curr_b = NULL;
struct buffer_record* A = helper_alloc_buf(la, &orig_curr_a);
struct buffer_record* B = helper_alloc_buf(lb, &orig_curr_b);
TEST_ASSERT_NOT_NULL(A);
TEST_ASSERT_NOT_NULL(B);
/* Insert A then B via save_buffer to form the chain */
save_buffer(A);
save_buffer(B);
TEST_ASSERT_EQUAL_PTR(A, head);
TEST_ASSERT_EQUAL_PTR(B, A->next);
TEST_ASSERT_NULL(B->next);
/* Prepare C and append it */
struct line* lc = helper_alloc_line();
struct line* orig_curr_c = NULL;
struct buffer_record* C = helper_alloc_buf(lc, &orig_curr_c);
TEST_ASSERT_NOT_NULL(C);
/* Record B's curr_line before appending to ensure it doesn't change */
struct line* B_curr_before = B->curr_line;
save_buffer(C);
/* Verify the chain: A -> B -> C -> NULL */
TEST_ASSERT_EQUAL_PTR(A, head);
TEST_ASSERT_EQUAL_PTR(B, A->next);
TEST_ASSERT_EQUAL_PTR(C, B->next);
TEST_ASSERT_NULL(C->next);
/* Verify new node fields updated */
TEST_ASSERT_EQUAL_PTR(C->line_start, C->curr_line);
/* Verify previous nodes unchanged except B->next now points to C */
TEST_ASSERT_EQUAL_PTR(B_curr_before, B->curr_line);
/* Cleanup orphan curr_line allocations and chain */
free(orig_curr_a);
free(orig_curr_b);
free(orig_curr_c);
helper_free_chain(head);
head = NULL;
}
/* Test: Multiple appends in sequence to ensure traversal loop works repeatedly. */
void test_save_buffer_multiple_appends_sequence(void) {
struct line* l1 = helper_alloc_line();
struct line* l2 = helper_alloc_line();
struct line* l3 = helper_alloc_line();
struct line* oc1 = NULL;
struct line* oc2 = NULL;
struct line* oc3 = NULL;
struct buffer_record* b1 = helper_alloc_buf(l1, &oc1);
struct buffer_record* b2 = helper_alloc_buf(l2, &oc2);
struct buffer_record* b3 = helper_alloc_buf(l3, &oc3);
save_buffer(b1);
save_buffer(b2);
save_buffer(b3);
TEST_ASSERT_EQUAL_PTR(b1, head);
TEST_ASSERT_EQUAL_PTR(b2, b1->next);
TEST_ASSERT_EQUAL_PTR(b3, b2->next);
TEST_ASSERT_NULL(b3->next);
TEST_ASSERT_EQUAL_PTR(b1->line_start, b1->curr_line);
TEST_ASSERT_EQUAL_PTR(b2->line_start, b2->curr_line);
TEST_ASSERT_EQUAL_PTR(b3->line_start, b3->curr_line);
free(oc1);
free(oc2);
free(oc3);
helper_free_chain(head);
head = NULL;
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_save_buffer_initial_insert_sets_head_and_fields);
RUN_TEST(test_save_buffer_appends_to_single_element_list);
RUN_TEST(test_save_buffer_appends_to_multi_element_list);
RUN_TEST(test_save_buffer_multiple_appends_sequence);
return UNITY_END();
} |