blob: 3f268a422d5d4e327336a0c96d842c84527a5bfc [file] [log] [blame]
Simon Glass57df0f52025-03-18 16:20:47 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2024 Google LLC
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
7#include <membuf.h>
8#include <os.h>
9#include <rand.h>
10#include <string.h>
11#include <test/lib.h>
12#include <test/test.h>
13#include <test/ut.h>
14
15#define TEST_SIZE 16
16#define TEST_COUNT 10000
17
18static void membuf_zero(struct membuf *mb)
19{
20 memset(mb->start, '\0', mb->end - mb->start);
21}
22
23static int membuf_check(struct unit_test_state *uts, struct membuf *mb,
24 int value)
25{
26 /* head is out of range */
27 ut_assert(!(mb->head < mb->start || mb->head >= mb->end));
28
29 /* tail is out of range */
30 ut_assert(!(mb->tail < mb->start || mb->tail >= mb->end));
31
32 return 0;
33}
34
35/* write from 1 to test_size bytes, and check they come back OK */
36static int lib_test_membuf_one(struct unit_test_state *uts)
37{
38 char in[TEST_SIZE * 2], out[TEST_SIZE * 2];
39 struct membuf mb;
40 int size, ret, test_size, i;
41
42 ut_assertok(membuf_new(&mb, TEST_SIZE));
43
44 /* setup in test */
45 for (i = 0; i < TEST_SIZE; i++) {
46 in[i] = (i & 63) + '0';
47 in[i + TEST_SIZE] = in[i];
48 }
49
50 test_size = TEST_SIZE;
51
52 for (i = 1; i < TEST_COUNT; i++) {
53 membuf_zero(&mb);
54 size = rand() % test_size;
55
56 // now write patterns and check they come back OK
57 ret = membuf_put(&mb, in, 0);
58 ret = membuf_put(&mb, in, size);
59 ut_asserteq(size, ret);
60
61 ret = membuf_put(&mb, in, 0);
62 ut_assertok(membuf_check(uts, &mb, i));
63
64 ret = membuf_get(&mb, out, 0);
65 ret = membuf_get(&mb, out, size);
66 ut_asserteq(size, ret);
67
68 ret = membuf_get(&mb, out, 0);
69 ut_assertok(membuf_check(uts, &mb, i));
70
71 ut_asserteq_mem(in, out, size);
72 }
73
74 return 0;
75}
76LIB_TEST(lib_test_membuf_one, 0);
77
78/* write random number of bytes, and check they come back OK */
79static int lib_test_membuf_random(struct unit_test_state *uts)
80{
81 char in[TEST_SIZE * 2];
82 char buf[TEST_SIZE * 2];
83 struct membuf mb;
84 int size, ret, test_size, i;
85 char *inptr, *outptr;
86 int max_avail, min_free;
87
88 ut_assertok(membuf_new(&mb, TEST_SIZE));
89
90 for (i = 0; i < TEST_SIZE; i++) {
91 in[i] = (i & 63) + '0';
92 in[i + TEST_SIZE] = in[i];
93 }
94
95 test_size = TEST_SIZE;
96
97 inptr = in;
98 outptr = in;
99 min_free = TEST_COUNT;
100 max_avail = 0;
101 membuf_zero(&mb);
102 for (i = 0; i < TEST_COUNT; i++) {
103 size = rand() % test_size;
104
105 if (membuf_free(&mb) < min_free)
106 min_free = membuf_free(&mb);
107
108 ret = membuf_put(&mb, inptr, size);
109 ut_assertok(membuf_check(uts, &mb, i));
110 inptr += ret;
111 if (inptr >= in + TEST_SIZE)
112 inptr -= TEST_SIZE;
113
114 size = rand() % (test_size - 1);
115
116 if (membuf_avail(&mb) > max_avail)
117 max_avail = membuf_avail(&mb);
118
119 ret = membuf_get(&mb, buf, size);
120 ut_assertok(membuf_check(uts, &mb, i));
121 ut_asserteq_mem(buf, outptr, ret);
122
123 outptr += ret;
124 if (outptr >= in + TEST_SIZE)
125 outptr -= TEST_SIZE;
126 }
127
128 return 0;
129}
130LIB_TEST(lib_test_membuf_random, 0);
131
132/* test membuf_extend() with split segments */
133static int lib_test_membuf_extend(struct unit_test_state *uts)
134{
135 char in[TEST_SIZE * 2];
136 char buf[TEST_SIZE * 2];
137 struct membuf mb;
138 int ret, test_size, i, cur;
139 char *data;
140
141 ut_assertok(membuf_new(&mb, TEST_SIZE));
142
143 for (i = 0; i < TEST_SIZE; i++) {
144 in[i] = (i & 63) + '0';
145 in[i + TEST_SIZE] = in[i];
146 }
147
148 test_size = TEST_SIZE - 1;
149
150 for (cur = 0; cur <= test_size; cur++) {
151 ut_assertok(membuf_new(&mb, TEST_SIZE));
152
153 membuf_zero(&mb);
154
155 /*
156 * add some bytes, then remove them - this will force the membuf
157 * to have data split into two segments when we fill it
158 */
159 ret = membuf_putraw(&mb, TEST_SIZE / 2, true, &data);
160 membuf_getraw(&mb, ret, true, &data);
161 ut_asserteq(TEST_SIZE / 2, ret);
162
163 /* fill it */
164 ret = membuf_put(&mb, in, cur);
165 ut_assertok(membuf_check(uts, &mb, cur));
166 ut_asserteq(cur, ret);
167
168 /* extend the buffer */
169 ut_assertok(membuf_extend_by(&mb, TEST_SIZE, -1));
170 ut_assertok(membuf_check(uts, &mb, cur));
171
172 /* check our data is still there */
173 ret = membuf_get(&mb, buf, TEST_SIZE * 2);
174 ut_assertok(membuf_check(uts, &mb, cur));
175 ut_asserteq(cur, ret);
176 ut_asserteq_mem(in, buf, cur);
177 membuf_uninit(&mb);
178 }
179
180 return 0;
181}
182LIB_TEST(lib_test_membuf_extend, 0);
183
184/* test membuf_readline() with generated data */
185static int lib_test_membuf_readline(struct unit_test_state *uts)
186{
187 char *buf;
188 int size, cur, i, ret, readptr, cmpptr;
189 struct membuf mb;
190 char *data;
191 char str[256];
192 char *s;
193
194 ut_assertok(membuf_new(&mb, 1024));
195 membuf_zero(&mb);
196
197 /* Use the README as test data */
198 ut_assertok(os_read_file("README", (void **)&buf, &size));
199
200 cur = 0;
201 readptr = 0;
202 cmpptr = 0;
203 for (i = 0; i < 100000; i++, cur += 1) {
204 /* fill the buffer with up to 'cur' bytes */
205 ret = membuf_putraw(&mb, cur, false, &data);
206
207 if (ret > 0) {
208 int can_read = min(ret, size - readptr);
209
210 memcpy(data, &buf[readptr], can_read);
211 readptr += can_read;
212
213 membuf_putraw(&mb, can_read, true, &data);
214 ut_assertok(membuf_check(uts, &mb, i));
215 }
216
217 /* read a line and compare */
218 ret = membuf_readline(&mb, str, 256, 0, true);
219 ut_assertok(membuf_check(uts, &mb, i));
220 if (ret) {
221 char *ptr;
222
223 s = &buf[cmpptr];
224 ptr = strchr(s, '\n');
225 *ptr = '\0';
226
227 ut_asserteq_str(s, str);
228 cmpptr += strlen(s) + 1;
229 *ptr = '\n';
230 } else {
231 ut_assert(membuf_free(&mb));
232 }
233 }
234 membuf_dispose(&mb);
235 os_free(buf);
236
237 return 0;
238}
239LIB_TEST(lib_test_membuf_readline, 0);