1 /* $Id: buffer-t.c 10396 2020-11-12 20:19:41Z iulius $
2  *
3  * buffer test suite.
4  *
5  * The canonical version of this file is maintained in the rra-c-util package,
6  * which can be found at <https://www.eyrie.org/~eagle/software/rra-c-util/>.
7  *
8  * Written by Russ Allbery <eagle@eyrie.org>
9  * Copyright 2002-2004, 2006, 2014-2015, 2020 Russ Allbery <eagle@eyrie.org>
10  * Copyright 2011-2014
11  *     The Board of Trustees of the Leland Stanford Junior University
12  *
13  * Copying and distribution of this file, with or without modification, are
14  * permitted in any medium without royalty provided the copyright notice and
15  * this notice are preserved.  This file is offered as-is, without any
16  * warranty.
17  *
18  * SPDX-License-Identifier: FSFAP
19  */
20 
21 #define LIBTEST_NEW_FORMAT 1
22 
23 #include "config.h"
24 #include "clibrary.h"
25 
26 #include <fcntl.h>
27 
28 #include "tap/basic.h"
29 #include "inn/buffer.h"
30 #include "inn/xwrite.h"
31 
32 static const char test_string1[] = "This is a test";
33 static const char test_string2[] = " of the buffer system";
34 static const char test_string3[] = "This is a test\0 of the buffer system";
35 
36 
37 /*
38  * Test buffer_vsprintf.  Wrapper needed to generate the va_list.
39  */
40 static void __attribute__((__format__(printf, 2, 3)))
test_vsprintf(struct buffer * buffer,const char * format,...)41 test_vsprintf(struct buffer *buffer, const char *format, ...)
42 {
43     va_list args;
44 
45     va_start(args, format);
46     buffer_vsprintf(buffer, format, args);
47     va_end(args);
48 }
49 
50 
51 /*
52  * Likewise for buffer_append_vsprintf.
53  */
54 static void __attribute__((__format__(printf, 2, 3)))
test_append_vsprintf(struct buffer * buffer,const char * format,...)55 test_append_vsprintf(struct buffer *buffer, const char *format, ...)
56 {
57     va_list args;
58 
59     va_start(args, format);
60     buffer_append_vsprintf(buffer, format, args);
61     va_end(args);
62 }
63 
64 
65 int
main(void)66 main(void)
67 {
68     struct buffer one = {0, 0, 0, NULL};
69     struct buffer two = {0, 0, 0, NULL};
70     struct buffer *three;
71     int fd;
72     char *data;
73     ssize_t count;
74     size_t offset;
75 
76     plan(89);
77 
78     /* buffer_set, buffer_append, buffer_swap */
79     buffer_set(&one, test_string1, sizeof(test_string1));
80     is_int(1024, one.size, "minimum size is 1024");
81     is_int(0, one.used, "used starts at 0");
82     is_int(sizeof(test_string1), one.left, "left is correct");
83     is_string(test_string1, one.data, "data is correct");
84     buffer_append(&one, test_string2, sizeof(test_string2));
85     is_int(1024, one.size, "appended data doesn't change size");
86     is_int(0, one.used, "or used");
87     is_int(sizeof(test_string3), one.left, "but left is the right size");
88     ok(memcmp(one.data, test_string3, sizeof(test_string3)) == 0,
89        "and the resulting data is correct");
90     one.left -= sizeof(test_string1);
91     one.used += sizeof(test_string1);
92     buffer_append(&one, test_string1, sizeof(test_string1));
93     is_int(1024, one.size, "size still isn't larger after adding data");
94     is_int(sizeof(test_string1), one.used, "and used is preserved on append");
95     is_int(sizeof(test_string3), one.left, "and left is updated properly");
96     ok(memcmp(one.data + one.used, test_string2, sizeof(test_string2)) == 0,
97        "and the middle data is unchanged");
98     ok(memcmp(one.data + one.used + sizeof(test_string2), test_string1,
99               sizeof(test_string1))
100            == 0,
101        "and the final data is correct");
102     buffer_set(&one, test_string1, sizeof(test_string1));
103     buffer_set(&two, test_string2, sizeof(test_string2));
104     buffer_swap(&one, &two);
105     is_int(1024, one.size, "swap #1 size is correct");
106     is_int(0, one.used, "swap #1 used is correct");
107     is_int(sizeof(test_string2), one.left, "swap #1 left is correct");
108     is_string(test_string2, one.data, "swap #1 data is correct");
109     is_int(1024, two.size, "swap #2 size is correct");
110     is_int(0, two.used, "swap #2 used is correct");
111     is_int(sizeof(test_string1), two.left, "swap #2 left is correct");
112     is_string(test_string1, two.data, "swap #2 data is correct");
113     free(one.data);
114     free(two.data);
115     one.data = NULL;
116     two.data = NULL;
117     one.size = 0;
118     two.size = 0;
119 
120     /* buffer_resize */
121     three = buffer_new();
122     ok(three != NULL, "buffer_new works");
123     if (three == NULL)
124         bail("buffer_new returned NULL");
125     is_int(0, three->size, "initial size is 0");
126     buffer_set(three, test_string1, sizeof(test_string1));
127     is_int(1024, three->size, "size becomes 1024 when adding data");
128     buffer_resize(three, 512);
129     is_int(1024, three->size, "resizing to something smaller doesn't change");
130     buffer_resize(three, 1025);
131     is_int(2048, three->size, "resizing to something larger goes to 2048");
132     buffer_free(three);
133 
134     /* buffer_read, buffer_find_string, buffer_compact */
135     fd = open("buffer-test", O_RDWR | O_CREAT | O_TRUNC, 0666);
136     if (fd < 0)
137         sysbail("cannot create buffer-test");
138     data = bmalloc(2048);
139     memset(data, 'a', 1023);
140     data[1023] = '\r';
141     data[1024] = '\n';
142     memset(data + 1025, 'b', 1023);
143     if (xwrite(fd, data, 2048) < 2048)
144         sysbail("cannot write to buffer-test");
145     if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
146         sysbail("cannot rewind buffer-test");
147     three = buffer_new();
148     ok(three != NULL, "buffer_new works");
149     if (three == NULL)
150         bail("buffer_new returned NULL");
151     is_int(0, three->size, "and initial size is 0");
152     buffer_resize(three, 1024);
153     is_int(1024, three->size, "resize to 1024 works");
154     count = buffer_read(three, fd);
155     is_int(1024, count, "reading into a buffer of size 1024 reads 1024");
156     offset = 0;
157     ok(!buffer_find_string(three, "\r\n", 0, &offset),
158        "buffer_find_string with truncated string fails");
159     is_int(0, offset, "and offset is unchanged");
160     ok(memcmp(three->data, data, three->size) == 0, "buffer data is correct");
161     buffer_resize(three, 2048);
162     is_int(2048, three->size, "resizing the buffer to 2048 works");
163     count = buffer_read(three, fd);
164     is_int(1024, count, "and now we can read the rest of the data");
165     ok(memcmp(three->data, data, 2048) == 0, "and it's all there");
166     ok(!buffer_find_string(three, "\r\n", 1024, &offset),
167        "buffer_find_string with a string starting before offset fails");
168     is_int(0, offset, "and offset is unchanged");
169     ok(buffer_find_string(three, "\r\n", 0, &offset),
170        "finding the string on the whole buffer works");
171     is_int(1023, offset, "and returns the correct location");
172     three->used += 400;
173     three->left -= 400;
174     buffer_compact(three);
175     is_int(2048, three->size, "compacting buffer doesn't change the size");
176     is_int(0, three->used, "but used is now zero");
177     is_int(1648, three->left, "and left is decreased appropriately");
178     ok(memcmp(three->data, data + 400, 1648) == 0, "and the data is correct");
179     count = buffer_read(three, fd);
180     is_int(0, count, "reading at EOF returns 0");
181     close(fd);
182     unlink("buffer-test");
183     free(data);
184     buffer_free(three);
185 
186     /* buffer_sprintf and buffer_append_sprintf */
187     three = buffer_new();
188     buffer_append_sprintf(three, "testing %d testing", 6);
189     is_int(0, three->used, "buffer_append_sprintf doesn't change used");
190     is_int(17, three->left, "but sets left correctly");
191     buffer_append(three, "", 1);
192     is_int(18, three->left, "appending a nul works");
193     is_string("testing 6 testing", three->data, "and the data is correct");
194     three->left--;
195     three->used += 5;
196     three->left -= 5;
197     buffer_append_sprintf(three, " %d", 7);
198     is_int(14, three->left, "appending a digit works");
199     buffer_append(three, "", 1);
200     is_string("testing 6 testing 7", three->data, "and the data is correct");
201     buffer_sprintf(three, "%d testing", 8);
202     is_int(9, three->left, "replacing the buffer works");
203     is_string("8 testing", three->data, "and the results are correct");
204     data = bmalloc(1050);
205     memset(data, 'a', 1049);
206     data[1049] = '\0';
207     is_int(1024, three->size, "size before large sprintf is 1024");
208     buffer_sprintf(three, "%s", data);
209     is_int(2048, three->size, "size after large sprintf is 2048");
210     is_int(1049, three->left, "and left is correct");
211     buffer_append(three, "", 1);
212     is_string(data, three->data, "and data is correct");
213     free(data);
214     buffer_free(three);
215 
216     /* buffer_read_all */
217     fd = open("buffer-test", O_RDWR | O_CREAT | O_TRUNC, 0666);
218     if (fd < 0)
219         sysbail("cannot create buffer-test");
220     data = bmalloc(2049);
221     memset(data, 'a', 2049);
222     if (xwrite(fd, data, 2049) < 2049)
223         sysbail("cannot write to buffer-test");
224     if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
225         sysbail("cannot rewind buffer-test");
226     three = buffer_new();
227     ok(buffer_read_all(three, fd), "buffer_read_all succeeds");
228     is_int(0, three->used, "and unused is zero");
229     is_int(2049, three->left, "and left is correct");
230     is_int(4096, three->size, "and size is correct");
231     ok(memcmp(data, three->data, 2049) == 0, "and data is correct");
232     if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
233         sysbail("cannot rewind buffer-test");
234     ok(buffer_read_all(three, fd), "reading again succeeds");
235     is_int(0, three->used, "and used is correct");
236     is_int(4098, three->left, "and left is now larger");
237     is_int(8192, three->size, "and size doubled");
238     ok(memcmp(data, three->data + 2049, 2049) == 0, "and data is correct");
239 
240     /* buffer_read_file */
241     if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
242         sysbail("cannot rewind buffer-test");
243     buffer_free(three);
244     three = buffer_new();
245     ok(buffer_read_file(three, fd), "buffer_read_file succeeds");
246     is_int(0, three->used, "and leaves unused at 0");
247     is_int(2049, three->left, "and left is correct");
248     is_int(3072, three->size, "and size is a multiple of 1024");
249     ok(memcmp(data, three->data, 2049) == 0, "and the data is correct");
250 
251     /* buffer_read_all and buffer_read_file errors */
252     close(fd);
253     ok(!buffer_read_all(three, fd), "buffer_read_all on closed fd fails");
254     is_int(3072, three->size, "and size is unchanged");
255     ok(!buffer_read_file(three, fd), "buffer_read_file on closed fd fails");
256     is_int(3072, three->size, "and size is unchanged");
257     is_int(2049, three->left, "and left is unchanged");
258     unlink("buffer-test");
259     free(data);
260     buffer_free(three);
261 
262     /* buffer_vsprintf and buffer_append_vsprintf */
263     three = buffer_new();
264     test_append_vsprintf(three, "testing %d testing", 6);
265     is_int(0, three->used, "buffer_append_vsprintf leaves used as 0");
266     is_int(17, three->left, "and left is correct");
267     buffer_append(three, "", 1);
268     is_int(18, three->left, "and left is correct after appending a nul");
269     is_string("testing 6 testing", three->data, "and data is correct");
270     three->left--;
271     three->used += 5;
272     three->left -= 5;
273     test_append_vsprintf(three, " %d", 7);
274     is_int(14, three->left, "and appending results in the correct left");
275     buffer_append(three, "", 1);
276     is_string("testing 6 testing 7", three->data, "and the right data");
277     test_vsprintf(three, "%d testing", 8);
278     is_int(9, three->left, "replacing the buffer results in the correct size");
279     is_string("8 testing", three->data, "and the correct data");
280     data = bmalloc(1050);
281     memset(data, 'a', 1049);
282     data[1049] = '\0';
283     is_int(1024, three->size, "size is 1024 before large vsprintf");
284     test_vsprintf(three, "%s", data);
285     is_int(2048, three->size, "and 2048 afterwards");
286     is_int(1049, three->left, "and left is correct");
287     buffer_append(three, "", 1);
288     is_string(data, three->data, "and data is correct");
289     free(data);
290     buffer_free(three);
291 
292     /* Test buffer_free with NULL and ensure it doesn't explode. */
293     buffer_free(NULL);
294 
295     return 0;
296 }
297