|
@@ -1,35 +1,320 @@
|
1
|
|
-#include <stdint.h>
|
|
1
|
+/*
|
|
2
|
+ * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
|
|
3
|
+ *
|
|
4
|
+ * This program is free software; you can redistribute it and/or
|
|
5
|
+ * modify it under the terms of the GNU General Public License as
|
|
6
|
+ * published by the Free Software Foundation; either version 2 of the
|
|
7
|
+ * License, or (at your option) any later version.
|
|
8
|
+ *
|
|
9
|
+ * This program is distributed in the hope that it will be useful, but
|
|
10
|
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12
|
+ * General Public License for more details.
|
|
13
|
+ *
|
|
14
|
+ * You should have received a copy of the GNU General Public License
|
|
15
|
+ * along with this program; if not, write to the Free Software
|
|
16
|
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
17
|
+ * 02110-1301, USA.
|
|
18
|
+ *
|
|
19
|
+ * You can also choose to distribute this program under the terms of
|
|
20
|
+ * the Unmodified Binary Distribution Licence (as given in the file
|
|
21
|
+ * COPYING.UBDL), provided that you have satisfied its requirements.
|
|
22
|
+ */
|
|
23
|
+
|
|
24
|
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
25
|
+
|
|
26
|
+/** @file
|
|
27
|
+ *
|
|
28
|
+ * Line buffer self-tests
|
|
29
|
+ *
|
|
30
|
+ */
|
|
31
|
+
|
|
32
|
+/* Forcibly enable assertions */
|
|
33
|
+#undef NDEBUG
|
|
34
|
+
|
2
|
35
|
#include <string.h>
|
3
|
|
-#include <stdio.h>
|
|
36
|
+#include <assert.h>
|
4
|
37
|
#include <ipxe/linebuf.h>
|
|
38
|
+#include <ipxe/test.h>
|
5
|
39
|
|
6
|
|
-static const char data1[] =
|
7
|
|
-"Hello world\r\n"
|
8
|
|
-"This is a reasonably nice set of lines\n"
|
9
|
|
-"with not many different terminators\r\n\r\n"
|
10
|
|
-"There should be exactly one blank line above\n"
|
11
|
|
-"and this line should never appear at all since it has no terminator";
|
|
40
|
+/** Define inline raw data */
|
|
41
|
+#define DATA(...) { __VA_ARGS__ }
|
12
|
42
|
|
13
|
|
-void linebuf_test ( void ) {
|
14
|
|
- struct line_buffer linebuf;
|
15
|
|
- const char *data = data1;
|
16
|
|
- size_t len = ( sizeof ( data1 ) - 1 /* be mean; strip the NUL */ );
|
17
|
|
- ssize_t frag_len;
|
18
|
|
- char *line;
|
19
|
|
-
|
20
|
|
- memset ( &linebuf, 0, sizeof ( linebuf ) );
|
21
|
|
- while ( len ) {
|
22
|
|
- frag_len = line_buffer ( &linebuf, data, len );
|
23
|
|
- if ( frag_len < 0 ) {
|
24
|
|
- printf ( "line_buffer() failed: %s\n",
|
25
|
|
- strerror ( frag_len ) );
|
|
43
|
+/** Define inline lines */
|
|
44
|
+#define LINES(...) { __VA_ARGS__ }
|
|
45
|
+
|
|
46
|
+/** A line buffer test */
|
|
47
|
+struct linebuf_test {
|
|
48
|
+ /** Raw data */
|
|
49
|
+ const void *data;
|
|
50
|
+ /** Length of raw data */
|
|
51
|
+ size_t len;
|
|
52
|
+ /** Expected sequence of lines */
|
|
53
|
+ const char **lines;
|
|
54
|
+ /** Number of expected lines */
|
|
55
|
+ unsigned int count;
|
|
56
|
+};
|
|
57
|
+
|
|
58
|
+/** Line buffer test expected failure indicator */
|
|
59
|
+static const char linebuf_failure[1];
|
|
60
|
+
|
|
61
|
+/**
|
|
62
|
+ * Define a line buffer test
|
|
63
|
+ *
|
|
64
|
+ * @v name Test name
|
|
65
|
+ * @v DATA Raw data
|
|
66
|
+ * @v LINES Expected sequence of lines
|
|
67
|
+ * @ret test Line buffer test
|
|
68
|
+ */
|
|
69
|
+#define LINEBUF_TEST( name, DATA, LINES ) \
|
|
70
|
+ static const char name ## _data[] = DATA; \
|
|
71
|
+ static const char * name ## _lines[] = LINES; \
|
|
72
|
+ static struct linebuf_test name = { \
|
|
73
|
+ .data = name ## _data, \
|
|
74
|
+ .len = ( sizeof ( name ## _data ) - 1 /* NUL */ ), \
|
|
75
|
+ .lines = name ## _lines, \
|
|
76
|
+ .count = ( sizeof ( name ## _lines ) / \
|
|
77
|
+ sizeof ( name ## _lines[0] ) ), \
|
|
78
|
+ }
|
|
79
|
+
|
|
80
|
+/** Simple line buffer test */
|
|
81
|
+LINEBUF_TEST ( simple,
|
|
82
|
+ ( "HTTP/1.1 200 OK\r\n"
|
|
83
|
+ "Content-Length: 123\r\n"
|
|
84
|
+ "Content-Type: text/plain\r\n"
|
|
85
|
+ "\r\n" ),
|
|
86
|
+ LINES ( "HTTP/1.1 200 OK",
|
|
87
|
+ "Content-Length: 123",
|
|
88
|
+ "Content-Type: text/plain",
|
|
89
|
+ "" ) );
|
|
90
|
+
|
|
91
|
+/** Mixed line terminators */
|
|
92
|
+LINEBUF_TEST ( mixed,
|
|
93
|
+ ( "LF only\n" "CRLF\r\n" "\n" "\n" "\r\n" "\r\n" "CR only\r" ),
|
|
94
|
+ LINES ( "LF only", "CRLF", "", "", "", "",
|
|
95
|
+ NULL /* \r should not be treated as a terminator */ ) );
|
|
96
|
+
|
|
97
|
+/** Split consumption: part 1 */
|
|
98
|
+LINEBUF_TEST ( split_1,
|
|
99
|
+ ( "This line was" ),
|
|
100
|
+ LINES ( NULL ) );
|
|
101
|
+
|
|
102
|
+/** Split consumption: part 2 */
|
|
103
|
+LINEBUF_TEST ( split_2,
|
|
104
|
+ ( " split across" ),
|
|
105
|
+ LINES ( NULL ) );
|
|
106
|
+
|
|
107
|
+/** Split consumption: part 3 */
|
|
108
|
+LINEBUF_TEST ( split_3,
|
|
109
|
+ ( " multiple calls\r\nand so was this one\r" ),
|
|
110
|
+ LINES ( "This line was split across multiple calls", NULL ) );
|
|
111
|
+
|
|
112
|
+/** Split consumption: part 4 */
|
|
113
|
+LINEBUF_TEST ( split_4,
|
|
114
|
+ ( "\nbut not this one\r\n" ),
|
|
115
|
+ LINES ( "and so was this one", "but not this one" ) );
|
|
116
|
+
|
|
117
|
+/** Split consumption: part 5 */
|
|
118
|
+LINEBUF_TEST ( split_5,
|
|
119
|
+ ( "" ),
|
|
120
|
+ LINES ( NULL ) );
|
|
121
|
+
|
|
122
|
+/** Split consumption: part 6 */
|
|
123
|
+LINEBUF_TEST ( split_6,
|
|
124
|
+ ( "This line came after a zero-length call\r\n" ),
|
|
125
|
+ LINES ( "This line came after a zero-length call" ) );
|
|
126
|
+
|
|
127
|
+/** Embedded NULs */
|
|
128
|
+LINEBUF_TEST ( embedded_nuls,
|
|
129
|
+ ( "This\r\ntest\r\nincludes\r\n\r\nsome\0binary\0data\r\n" ),
|
|
130
|
+ LINES ( "This", "test", "includes", "", linebuf_failure ) );
|
|
131
|
+
|
|
132
|
+/**
|
|
133
|
+ * Report line buffer initialisation test result
|
|
134
|
+ *
|
|
135
|
+ * @v linebuf Line buffer
|
|
136
|
+ * @v file Test code file
|
|
137
|
+ * @v line Test code line
|
|
138
|
+ */
|
|
139
|
+static void linebuf_init_okx ( struct line_buffer *linebuf,
|
|
140
|
+ const char *file, unsigned int line ) {
|
|
141
|
+
|
|
142
|
+ /* Initialise line buffer */
|
|
143
|
+ memset ( linebuf, 0, sizeof ( *linebuf ) );
|
|
144
|
+ okx ( buffered_line ( linebuf ) == NULL, file, line );
|
|
145
|
+}
|
|
146
|
+#define linebuf_init_ok( linebuf ) \
|
|
147
|
+ linebuf_init_okx ( linebuf, __FILE__, __LINE__ )
|
|
148
|
+
|
|
149
|
+/**
|
|
150
|
+ * Report line buffer consumption test result
|
|
151
|
+ *
|
|
152
|
+ * @v test Line buffer test
|
|
153
|
+ * @v linebuf Line buffer
|
|
154
|
+ * @v file Test code file
|
|
155
|
+ * @v line Test code line
|
|
156
|
+ */
|
|
157
|
+static void linebuf_consume_okx ( struct linebuf_test *test,
|
|
158
|
+ struct line_buffer *linebuf,
|
|
159
|
+ const char *file, unsigned int line ) {
|
|
160
|
+ const char *data = test->data;
|
|
161
|
+ size_t remaining = test->len;
|
|
162
|
+ int len;
|
|
163
|
+ unsigned int i;
|
|
164
|
+ const char *expected;
|
|
165
|
+ char *actual;
|
|
166
|
+ int rc;
|
|
167
|
+
|
|
168
|
+ DBGC ( test, "LINEBUF %p:\n", test );
|
|
169
|
+ DBGC_HDA ( test, 0, data, remaining );
|
|
170
|
+
|
|
171
|
+ /* Consume data one line at a time */
|
|
172
|
+ for ( i = 0 ; i < test->count ; i++ ) {
|
|
173
|
+
|
|
174
|
+ /* Add data to line buffer */
|
|
175
|
+ len = line_buffer ( linebuf, data, remaining );
|
|
176
|
+
|
|
177
|
+ /* Get buffered line, if any */
|
|
178
|
+ actual = buffered_line ( linebuf );
|
|
179
|
+ if ( len < 0 ) {
|
|
180
|
+ rc = len;
|
|
181
|
+ DBGC ( test, "LINEBUF %p %s\n", test, strerror ( rc ) );
|
|
182
|
+ } else if ( actual != NULL ) {
|
|
183
|
+ DBGC ( test, "LINEBUF %p \"%s\" (consumed %d)\n",
|
|
184
|
+ test, actual, len );
|
|
185
|
+ } else {
|
|
186
|
+ DBGC ( test, "LINEBUF %p unterminated (consumed %d)\n",
|
|
187
|
+ test, len );
|
|
188
|
+ }
|
|
189
|
+
|
|
190
|
+ /* Check for success/failure */
|
|
191
|
+ expected = test->lines[i];
|
|
192
|
+ if ( expected == linebuf_failure ) {
|
|
193
|
+ rc = len;
|
|
194
|
+ okx ( rc < 0, file, line );
|
|
195
|
+ okx ( remaining > 0, file, line );
|
26
|
196
|
return;
|
27
|
197
|
}
|
28
|
|
- data += frag_len;
|
29
|
|
- len -= frag_len;
|
30
|
|
- if ( ( line = buffered_line ( &linebuf ) ) )
|
31
|
|
- printf ( "\"%s\"\n", line );
|
|
198
|
+ okx ( len >= 0, file, line );
|
|
199
|
+ okx ( ( ( size_t ) len ) <= remaining, file, line );
|
|
200
|
+
|
|
201
|
+ /* Check expected result */
|
|
202
|
+ if ( expected == NULL ) {
|
|
203
|
+ okx ( actual == NULL, file, line );
|
|
204
|
+ } else {
|
|
205
|
+ okx ( actual != NULL, file, line );
|
|
206
|
+ okx ( strcmp ( actual, expected ) == 0, file, line );
|
|
207
|
+ }
|
|
208
|
+
|
|
209
|
+ /* Consume data */
|
|
210
|
+ data += len;
|
|
211
|
+ remaining -= len;
|
|
212
|
+ }
|
|
213
|
+
|
|
214
|
+ /* Check that all data was consumed */
|
|
215
|
+ okx ( remaining == 0, file, line );
|
|
216
|
+}
|
|
217
|
+#define linebuf_consume_ok( test, linebuf ) \
|
|
218
|
+ linebuf_consume_okx ( test, linebuf, __FILE__, __LINE__ )
|
|
219
|
+
|
|
220
|
+/**
|
|
221
|
+ * Report line buffer accumulation test result
|
|
222
|
+ *
|
|
223
|
+ * @v test Line buffer test
|
|
224
|
+ * @v linebuf Line buffer
|
|
225
|
+ * @v file Test code file
|
|
226
|
+ * @v line Test code line
|
|
227
|
+ */
|
|
228
|
+static void linebuf_accumulated_okx ( struct linebuf_test *test,
|
|
229
|
+ struct line_buffer *linebuf,
|
|
230
|
+ const char *file, unsigned int line ) {
|
|
231
|
+ const char *actual;
|
|
232
|
+ const char *expected;
|
|
233
|
+ unsigned int i;
|
|
234
|
+
|
|
235
|
+ /* Check each accumulated line */
|
|
236
|
+ actual = linebuf->data;
|
|
237
|
+ for ( i = 0 ; i < test->count ; i++ ) {
|
|
238
|
+
|
|
239
|
+ /* Check accumulated line */
|
|
240
|
+ okx ( actual != NULL, file, line );
|
|
241
|
+ okx ( actual >= linebuf->data, file, line );
|
|
242
|
+ expected = test->lines[i];
|
|
243
|
+ if ( ( expected == NULL ) || ( expected == linebuf_failure ) )
|
|
244
|
+ return;
|
|
245
|
+ okx ( strcmp ( actual, expected ) == 0, file, line );
|
|
246
|
+
|
|
247
|
+ /* Move to next line */
|
|
248
|
+ actual += ( strlen ( actual ) + 1 /* NUL */ );
|
|
249
|
+ okx ( actual <= ( linebuf->data + linebuf->len ), file, line );
|
32
|
250
|
}
|
|
251
|
+}
|
|
252
|
+#define linebuf_accumulated_ok( test, linebuf ) \
|
|
253
|
+ linebuf_accumulated_okx ( test, linebuf, __FILE__, __LINE__ )
|
|
254
|
+
|
|
255
|
+/**
|
|
256
|
+ * Report line buffer emptying test result
|
|
257
|
+ *
|
|
258
|
+ * @v linebuf Line buffer
|
|
259
|
+ * @v file Test code file
|
|
260
|
+ * @v line Test code line
|
|
261
|
+ */
|
|
262
|
+static void linebuf_empty_okx ( struct line_buffer *linebuf,
|
|
263
|
+ const char *file, unsigned int line ) {
|
33
|
264
|
|
34
|
|
- empty_line_buffer ( &linebuf );
|
|
265
|
+ /* Empty line buffer */
|
|
266
|
+ empty_line_buffer ( linebuf );
|
|
267
|
+ okx ( buffered_line ( linebuf ) == NULL, file, line );
|
35
|
268
|
}
|
|
269
|
+#define linebuf_empty_ok( linebuf ) \
|
|
270
|
+ linebuf_empty_okx ( linebuf, __FILE__, __LINE__ )
|
|
271
|
+
|
|
272
|
+/**
|
|
273
|
+ * Report line buffer combined test result
|
|
274
|
+ *
|
|
275
|
+ * @v test Line buffer test
|
|
276
|
+ * @v file Test code file
|
|
277
|
+ * @v line Test code line
|
|
278
|
+ */
|
|
279
|
+static void linebuf_okx ( struct linebuf_test *test, const char *file,
|
|
280
|
+ unsigned int line ) {
|
|
281
|
+ struct line_buffer linebuf;
|
|
282
|
+
|
|
283
|
+ linebuf_init_okx ( &linebuf, file, line );
|
|
284
|
+ linebuf_consume_okx ( test, &linebuf, file, line );
|
|
285
|
+ linebuf_accumulated_okx ( test, &linebuf, file, line );
|
|
286
|
+ linebuf_empty_okx ( &linebuf, file, line );
|
|
287
|
+}
|
|
288
|
+#define linebuf_ok( test ) \
|
|
289
|
+ linebuf_okx ( test, __FILE__, __LINE__ )
|
|
290
|
+
|
|
291
|
+/**
|
|
292
|
+ * Perform line buffer self-tests
|
|
293
|
+ *
|
|
294
|
+ */
|
|
295
|
+static void linebuf_test_exec ( void ) {
|
|
296
|
+ struct line_buffer linebuf;
|
|
297
|
+
|
|
298
|
+ /* Basic tests */
|
|
299
|
+ linebuf_ok ( &simple );
|
|
300
|
+ linebuf_ok ( &mixed );
|
|
301
|
+
|
|
302
|
+ /* Split consumption test */
|
|
303
|
+ linebuf_init_ok ( &linebuf );
|
|
304
|
+ linebuf_consume_ok ( &split_1, &linebuf );
|
|
305
|
+ linebuf_consume_ok ( &split_2, &linebuf );
|
|
306
|
+ linebuf_consume_ok ( &split_3, &linebuf );
|
|
307
|
+ linebuf_consume_ok ( &split_4, &linebuf );
|
|
308
|
+ linebuf_consume_ok ( &split_5, &linebuf );
|
|
309
|
+ linebuf_consume_ok ( &split_6, &linebuf );
|
|
310
|
+ linebuf_empty_ok ( &linebuf );
|
|
311
|
+
|
|
312
|
+ /* Embedded NULs */
|
|
313
|
+ linebuf_ok ( &embedded_nuls );
|
|
314
|
+}
|
|
315
|
+
|
|
316
|
+/** Line buffer self-test */
|
|
317
|
+struct self_test linebuf_test __self_test = {
|
|
318
|
+ .name = "linebuf",
|
|
319
|
+ .exec = linebuf_test_exec,
|
|
320
|
+};
|