File size: 4,409 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
#include "../../unity/unity.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

/* Unity fixtures */
void setUp(void) {
  /* no-op */
}
void tearDown(void) {
  /* no-op */
}

/* Helper to initialize an empty line object */
static void init_empty_line(struct line* l)
{
  memset(l, 0, sizeof(*l));
}

/* Test: basic append on an empty line should allocate and store the field */
static void test_extract_field_basic_append(void)
{
  struct line l;
  init_empty_line(&l);

  char buf[] = "hello";
  extract_field(&l, buf, (idx_t)5);

  TEST_ASSERT_EQUAL_INT(1, (int)l.nfields);
  TEST_ASSERT_TRUE(l.nfields_allocated >= 1);
  TEST_ASSERT_NOT_NULL(l.fields);
  TEST_ASSERT_EQUAL_PTR(buf, l.fields[0].beg);
  TEST_ASSERT_EQUAL_INT(5, (int)l.fields[0].len);

  /* cleanup */
  freeline(&l);
}

/* Test: multiple appends should grow capacity as needed and preserve entries */
static void test_extract_field_multiple_growth_and_preserve(void)
{
  struct line l;
  init_empty_line(&l);

  enum { N = 50 }; /* enough iterations to ensure multiple growths */
  char storage[N][16];

  for (int i = 0; i < N; ++i)
    {
      /* create distinct content and pointers */
      int n = snprintf(storage[i], sizeof(storage[i]), "f%02d", i);
      if (n < 0) n = 0;
      extract_field(&l, storage[i], (idx_t)n);

      /* After each insertion, verify counters and last entry */
      TEST_ASSERT_EQUAL_INT(i + 1, (int)l.nfields);
      TEST_ASSERT_TRUE(l.nfields_allocated >= l.nfields);
      TEST_ASSERT_EQUAL_PTR(storage[i], l.fields[i].beg);
      TEST_ASSERT_EQUAL_INT(n, (int)l.fields[i].len);

      /* Also spot-check some earlier entries remain intact */
      if (i >= 3)
        {
          TEST_ASSERT_EQUAL_PTR(storage[0], l.fields[0].beg);
          TEST_ASSERT_EQUAL_PTR(storage[1], l.fields[1].beg);
          TEST_ASSERT_EQUAL_PTR(storage[2], l.fields[2].beg);
        }
    }

  /* Verify all entries match after the loop */
  for (int i = 0; i < N; ++i)
    {
      int n = (int)strlen(storage[i]); /* was written by snprintf */
      TEST_ASSERT_EQUAL_PTR(storage[i], l.fields[i].beg);
      TEST_ASSERT_EQUAL_INT(n, (int)l.fields[i].len);
    }

  /* cleanup */
  freeline(&l);
}

/* Test: when there is preallocated capacity, pointer should not change on insert */
static void test_extract_field_no_realloc_when_capacity_available(void)
{
  struct line l;
  init_empty_line(&l);

  /* Preallocate capacity for 8 fields */
  l.nfields_allocated = 8;
  l.fields = (struct field*) malloc(sizeof(struct field) * l.nfields_allocated);
  TEST_ASSERT_NOT_NULL(l.fields);

  struct field* oldptr = l.fields;

  char buf1[] = "A";
  extract_field(&l, buf1, (idx_t)1);

  TEST_ASSERT_EQUAL_PTR(oldptr, l.fields);
  TEST_ASSERT_EQUAL_INT(1, (int)l.nfields);
  TEST_ASSERT_EQUAL_PTR(buf1, l.fields[0].beg);
  TEST_ASSERT_EQUAL_INT(1, (int)l.fields[0].len);

  /* cleanup */
  freeline(&l);
}

/* Test: zero-length field should be recorded and increase count */
static void test_extract_field_zero_length(void)
{
  struct line l;
  init_empty_line(&l);

  char dummy = 'X';
  extract_field(&l, &dummy, (idx_t)0);

  TEST_ASSERT_EQUAL_INT(1, (int)l.nfields);
  TEST_ASSERT_EQUAL_PTR(&dummy, l.fields[0].beg);
  TEST_ASSERT_EQUAL_INT(0, (int)l.fields[0].len);

  /* Add another zero-length to ensure multiple zero-length fields work */
  char dummy2 = 'Y';
  extract_field(&l, &dummy2, (idx_t)0);
  TEST_ASSERT_EQUAL_INT(2, (int)l.nfields);
  TEST_ASSERT_EQUAL_PTR(&dummy2, l.fields[1].beg);
  TEST_ASSERT_EQUAL_INT(0, (int)l.fields[1].len);

  /* cleanup */
  freeline(&l);
}

/* Test: large length value should be stored as-is (no copying performed) */
static void test_extract_field_large_len_value(void)
{
  struct line l;
  init_empty_line(&l);

  char buf[] = "x";
  idx_t large_len = (idx_t)123456; /* arbitrary large length, not used for access */
  extract_field(&l, buf, large_len);

  TEST_ASSERT_EQUAL_INT(1, (int)l.nfields);
  TEST_ASSERT_EQUAL_PTR(buf, l.fields[0].beg);
  TEST_ASSERT_EQUAL_INT((int)large_len, (int)l.fields[0].len);

  /* cleanup */
  freeline(&l);
}

int main(void)
{
  UNITY_BEGIN();
  RUN_TEST(test_extract_field_basic_append);
  RUN_TEST(test_extract_field_multiple_growth_and_preserve);
  RUN_TEST(test_extract_field_no_realloc_when_capacity_available);
  RUN_TEST(test_extract_field_zero_length);
  RUN_TEST(test_extract_field_large_len_value);
  return UNITY_END();
}