1 | /* GLib testing framework examples and tests |
2 | * Copyright (C) 2008 Red Hat, Inc. |
3 | * Authors: Tomas Bzatek <tbzatek@redhat.com> |
4 | * |
5 | * This work is provided "as is"; redistribution and modification |
6 | * in whole or in part, in any medium, physical or electronic is |
7 | * permitted without restriction. |
8 | * |
9 | * This work is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
12 | * |
13 | * In no event shall the authors or contributors be liable for any |
14 | * direct, indirect, incidental, special, exemplary, or consequential |
15 | * damages (including, but not limited to, procurement of substitute |
16 | * goods or services; loss of use, data, or profits; or business |
17 | * interruption) however caused and on any theory of liability, whether |
18 | * in contract, strict liability, or tort (including negligence or |
19 | * otherwise) arising in any way out of the use of this software, even |
20 | * if advised of the possibility of such damage. |
21 | */ |
22 | |
23 | #include <glib/glib.h> |
24 | #include <gio/gio.h> |
25 | #include <stdlib.h> |
26 | #include <string.h> |
27 | |
28 | #define MAX_LINES 0xFFF |
29 | #define MAX_BYTES 0x10000 |
30 | |
31 | static void |
32 | test_basic (void) |
33 | { |
34 | GInputStream *stream; |
35 | GInputStream *base_stream; |
36 | gint val; |
37 | |
38 | base_stream = g_memory_input_stream_new (); |
39 | stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream)); |
40 | |
41 | g_object_get (object: stream, first_property_name: "byte-order" , &val, NULL); |
42 | g_assert_cmpint (val, ==, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN); |
43 | g_object_set (object: stream, first_property_name: "byte-order" , G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN, NULL); |
44 | g_assert_cmpint (g_data_input_stream_get_byte_order (G_DATA_INPUT_STREAM (stream)), ==, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN); |
45 | |
46 | g_object_get (object: stream, first_property_name: "newline-type" , &val, NULL); |
47 | g_assert_cmpint (val, ==, G_DATA_STREAM_NEWLINE_TYPE_LF); |
48 | g_object_set (object: stream, first_property_name: "newline-type" , G_DATA_STREAM_NEWLINE_TYPE_CR_LF, NULL); |
49 | g_assert_cmpint (g_data_input_stream_get_newline_type (G_DATA_INPUT_STREAM (stream)), ==, G_DATA_STREAM_NEWLINE_TYPE_CR_LF); |
50 | |
51 | g_object_unref (object: stream); |
52 | g_object_unref (object: base_stream); |
53 | } |
54 | |
55 | static void |
56 | test_seek_to_start (GInputStream *stream) |
57 | { |
58 | GError *error = NULL; |
59 | gboolean res = g_seekable_seek (G_SEEKABLE (stream), offset: 0, type: G_SEEK_SET, NULL, error: &error); |
60 | g_assert_cmpint (res, ==, TRUE); |
61 | g_assert_no_error (error); |
62 | } |
63 | |
64 | static void |
65 | test_read_lines (GDataStreamNewlineType newline_type) |
66 | { |
67 | GInputStream *stream; |
68 | GInputStream *base_stream; |
69 | GError *error = NULL; |
70 | char *data; |
71 | int line; |
72 | const char* lines[MAX_LINES]; |
73 | const char* endl[4] = {"\n" , "\r" , "\r\n" , "\n" }; |
74 | |
75 | /* prepare data */ |
76 | int i; |
77 | for (i = 0; i < MAX_LINES; i++) |
78 | lines[i] = "some_text" ; |
79 | |
80 | base_stream = g_memory_input_stream_new (); |
81 | g_assert (base_stream != NULL); |
82 | stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream)); |
83 | g_assert(stream != NULL); |
84 | |
85 | /* Byte order testing */ |
86 | g_data_input_stream_set_byte_order (G_DATA_INPUT_STREAM (stream), order: G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN); |
87 | g_assert_cmpint (g_data_input_stream_get_byte_order (G_DATA_INPUT_STREAM (stream)), ==, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN); |
88 | g_data_input_stream_set_byte_order (G_DATA_INPUT_STREAM (stream), order: G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN); |
89 | g_assert_cmpint (g_data_input_stream_get_byte_order (G_DATA_INPUT_STREAM (stream)), ==, G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN); |
90 | |
91 | /* Line ends testing */ |
92 | g_data_input_stream_set_newline_type (G_DATA_INPUT_STREAM (stream), type: newline_type); |
93 | g_assert_cmpint (g_data_input_stream_get_newline_type (G_DATA_INPUT_STREAM (stream)), ==, newline_type); |
94 | |
95 | |
96 | /* Add sample data */ |
97 | for (i = 0; i < MAX_LINES; i++) |
98 | g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (base_stream), |
99 | data: g_strconcat (string1: lines[i], endl[newline_type], NULL), len: -1, destroy: g_free); |
100 | |
101 | /* Seek to the start */ |
102 | test_seek_to_start (stream: base_stream); |
103 | |
104 | /* Test read line */ |
105 | error = NULL; |
106 | data = (char*)1; |
107 | line = 0; |
108 | while (data) |
109 | { |
110 | gsize length = -1; |
111 | data = g_data_input_stream_read_line (G_DATA_INPUT_STREAM (stream), length: &length, NULL, error: &error); |
112 | if (data) |
113 | { |
114 | g_assert_cmpstr (data, ==, lines[line]); |
115 | g_free (mem: data); |
116 | g_assert_no_error (error); |
117 | line++; |
118 | } |
119 | if (error) |
120 | g_error_free (error); |
121 | } |
122 | g_assert_cmpint (line, ==, MAX_LINES); |
123 | |
124 | |
125 | g_object_unref (object: base_stream); |
126 | g_object_unref (object: stream); |
127 | } |
128 | |
129 | static void |
130 | test_read_lines_LF (void) |
131 | { |
132 | test_read_lines (newline_type: G_DATA_STREAM_NEWLINE_TYPE_LF); |
133 | } |
134 | |
135 | static void |
136 | test_read_lines_CR (void) |
137 | { |
138 | test_read_lines (newline_type: G_DATA_STREAM_NEWLINE_TYPE_CR); |
139 | } |
140 | |
141 | static void |
142 | test_read_lines_CR_LF (void) |
143 | { |
144 | test_read_lines (newline_type: G_DATA_STREAM_NEWLINE_TYPE_CR_LF); |
145 | } |
146 | |
147 | static void |
148 | test_read_lines_any (void) |
149 | { |
150 | test_read_lines (newline_type: G_DATA_STREAM_NEWLINE_TYPE_ANY); |
151 | } |
152 | |
153 | static void |
154 | test_read_lines_LF_valid_utf8 (void) |
155 | { |
156 | GInputStream *stream; |
157 | GInputStream *base_stream; |
158 | GError *error = NULL; |
159 | char *line; |
160 | guint n_lines = 0; |
161 | |
162 | base_stream = g_memory_input_stream_new (); |
163 | stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream)); |
164 | |
165 | g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (base_stream), |
166 | data: "foo\nthis is valid UTF-8 ☺!\nbar\n" , len: -1, NULL); |
167 | |
168 | /* Test read line */ |
169 | error = NULL; |
170 | while (TRUE) |
171 | { |
172 | gsize length = -1; |
173 | line = g_data_input_stream_read_line_utf8 (G_DATA_INPUT_STREAM (stream), length: &length, NULL, error: &error); |
174 | g_assert_no_error (error); |
175 | if (line == NULL) |
176 | break; |
177 | n_lines++; |
178 | g_free (mem: line); |
179 | } |
180 | g_assert_cmpint (n_lines, ==, 3); |
181 | |
182 | g_object_unref (object: base_stream); |
183 | g_object_unref (object: stream); |
184 | } |
185 | |
186 | static void |
187 | test_read_lines_LF_invalid_utf8 (void) |
188 | { |
189 | GInputStream *stream; |
190 | GInputStream *base_stream; |
191 | GError *error = NULL; |
192 | char *line; |
193 | guint n_lines = 0; |
194 | |
195 | base_stream = g_memory_input_stream_new (); |
196 | stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream)); |
197 | |
198 | g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (base_stream), |
199 | data: "foo\nthis is not valid UTF-8 \xE5 =(\nbar\n" , len: -1, NULL); |
200 | |
201 | /* Test read line */ |
202 | error = NULL; |
203 | while (TRUE) |
204 | { |
205 | gsize length = -1; |
206 | line = g_data_input_stream_read_line_utf8 (G_DATA_INPUT_STREAM (stream), length: &length, NULL, error: &error); |
207 | if (n_lines == 0) |
208 | g_assert_no_error (error); |
209 | else |
210 | { |
211 | g_assert (error != NULL); |
212 | g_clear_error (err: &error); |
213 | g_free (mem: line); |
214 | break; |
215 | } |
216 | n_lines++; |
217 | g_free (mem: line); |
218 | } |
219 | g_assert_cmpint (n_lines, ==, 1); |
220 | |
221 | g_object_unref (object: base_stream); |
222 | g_object_unref (object: stream); |
223 | } |
224 | |
225 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS |
226 | |
227 | static void |
228 | test_read_until (void) |
229 | { |
230 | GInputStream *stream; |
231 | GInputStream *base_stream; |
232 | GError *error = NULL; |
233 | char *data; |
234 | int line; |
235 | int i; |
236 | |
237 | #define REPEATS 10 /* number of rounds */ |
238 | #define DATA_STRING " part1 # part2 $ part3 % part4 ^" |
239 | #define DATA_PART_LEN 7 /* number of characters between separators */ |
240 | #define DATA_SEP "#$%^" |
241 | #define DATA_SEP_LEN 4 |
242 | const int DATA_PARTS_NUM = DATA_SEP_LEN * REPEATS; |
243 | |
244 | base_stream = g_memory_input_stream_new (); |
245 | stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream)); |
246 | |
247 | for (i = 0; i < REPEATS; i++) |
248 | g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (base_stream), DATA_STRING, len: -1, NULL); |
249 | |
250 | /* Test stop characters */ |
251 | error = NULL; |
252 | data = (char*)1; |
253 | line = 0; |
254 | while (data) |
255 | { |
256 | gsize length = -1; |
257 | data = g_data_input_stream_read_until (G_DATA_INPUT_STREAM (stream), DATA_SEP, length: &length, NULL, error: &error); |
258 | if (data) |
259 | { |
260 | g_assert_cmpint (strlen (data), ==, DATA_PART_LEN); |
261 | g_free (mem: data); |
262 | g_assert_no_error (error); |
263 | line++; |
264 | } |
265 | } |
266 | g_assert_no_error (error); |
267 | g_assert_cmpint (line, ==, DATA_PARTS_NUM); |
268 | |
269 | g_object_unref (object: base_stream); |
270 | g_object_unref (object: stream); |
271 | } |
272 | |
273 | G_GNUC_END_IGNORE_DEPRECATIONS |
274 | |
275 | static void |
276 | test_read_upto (void) |
277 | { |
278 | GInputStream *stream; |
279 | GInputStream *base_stream; |
280 | GError *error = NULL; |
281 | char *data; |
282 | int line; |
283 | int i; |
284 | guchar stop_char; |
285 | |
286 | #undef REPEATS |
287 | #undef DATA_STRING |
288 | #undef DATA_PART_LEN |
289 | #undef DATA_SEP |
290 | #undef DATA_SEP_LEN |
291 | #define REPEATS 10 /* number of rounds */ |
292 | #define DATA_STRING " part1 # part2 $ part3 \0 part4 ^" |
293 | #define DATA_PART_LEN 7 /* number of characters between separators */ |
294 | #define DATA_SEP "#$\0^" |
295 | #define DATA_SEP_LEN 4 |
296 | const int DATA_PARTS_NUM = DATA_SEP_LEN * REPEATS; |
297 | |
298 | base_stream = g_memory_input_stream_new (); |
299 | stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream)); |
300 | |
301 | for (i = 0; i < REPEATS; i++) |
302 | g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (base_stream), DATA_STRING, len: 32, NULL); |
303 | |
304 | /* Test stop characters */ |
305 | error = NULL; |
306 | data = (char*)1; |
307 | line = 0; |
308 | while (data) |
309 | { |
310 | gsize length = -1; |
311 | data = g_data_input_stream_read_upto (G_DATA_INPUT_STREAM (stream), DATA_SEP, DATA_SEP_LEN, length: &length, NULL, error: &error); |
312 | if (data) |
313 | { |
314 | g_assert_cmpint (strlen (data), ==, DATA_PART_LEN); |
315 | g_assert_no_error (error); |
316 | line++; |
317 | |
318 | stop_char = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (stream), NULL, error: &error); |
319 | g_assert (memchr (DATA_SEP, stop_char, DATA_SEP_LEN) != NULL); |
320 | g_assert_no_error (error); |
321 | } |
322 | g_free (mem: data); |
323 | } |
324 | g_assert_no_error (error); |
325 | g_assert_cmpint (line, ==, DATA_PARTS_NUM); |
326 | |
327 | g_object_unref (object: base_stream); |
328 | g_object_unref (object: stream); |
329 | } |
330 | enum TestDataType { |
331 | TEST_DATA_BYTE = 0, |
332 | TEST_DATA_INT16, |
333 | TEST_DATA_UINT16, |
334 | TEST_DATA_INT32, |
335 | TEST_DATA_UINT32, |
336 | TEST_DATA_INT64, |
337 | TEST_DATA_UINT64 |
338 | }; |
339 | |
340 | /* The order is reversed to avoid -Wduplicated-branches. */ |
341 | #define TEST_DATA_RETYPE_BUFF(a, t, v) \ |
342 | (a == TEST_DATA_UINT64 ? (t) *(guint64*)v : \ |
343 | (a == TEST_DATA_INT64 ? (t) *(gint64*)v : \ |
344 | (a == TEST_DATA_UINT32 ? (t) *(guint32*)v : \ |
345 | (a == TEST_DATA_INT32 ? (t) *(gint32*)v : \ |
346 | (a == TEST_DATA_UINT16 ? (t) *(guint16*)v : \ |
347 | (a == TEST_DATA_INT16 ? (t) *(gint16*)v : \ |
348 | (t) *(guchar*)v )))))) |
349 | |
350 | |
351 | static void |
352 | test_data_array (GInputStream *stream, GInputStream *base_stream, |
353 | gpointer buffer, int len, |
354 | enum TestDataType data_type, GDataStreamByteOrder byte_order) |
355 | { |
356 | GError *error = NULL; |
357 | int pos = 0; |
358 | int data_size = 1; |
359 | gint64 data; |
360 | GDataStreamByteOrder native; |
361 | gboolean swap; |
362 | |
363 | /* Seek to start */ |
364 | test_seek_to_start (stream: base_stream); |
365 | |
366 | /* Set correct data size */ |
367 | switch (data_type) |
368 | { |
369 | case TEST_DATA_BYTE: |
370 | data_size = 1; |
371 | break; |
372 | case TEST_DATA_INT16: |
373 | case TEST_DATA_UINT16: |
374 | data_size = 2; |
375 | break; |
376 | case TEST_DATA_INT32: |
377 | case TEST_DATA_UINT32: |
378 | data_size = 4; |
379 | break; |
380 | case TEST_DATA_INT64: |
381 | case TEST_DATA_UINT64: |
382 | data_size = 8; |
383 | break; |
384 | default: |
385 | g_assert_not_reached (); |
386 | break; |
387 | } |
388 | |
389 | /* Set flag to swap bytes if needed */ |
390 | native = (G_BYTE_ORDER == G_BIG_ENDIAN) ? G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN : G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN; |
391 | swap = (byte_order != G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN) && (byte_order != native); |
392 | |
393 | data = 1; |
394 | while (data != 0) |
395 | { |
396 | switch (data_type) |
397 | { |
398 | case TEST_DATA_BYTE: |
399 | data = g_data_input_stream_read_byte (G_DATA_INPUT_STREAM (stream), NULL, error: &error); |
400 | break; |
401 | case TEST_DATA_INT16: |
402 | data = g_data_input_stream_read_int16 (G_DATA_INPUT_STREAM (stream), NULL, error: &error); |
403 | if (swap) |
404 | data = (gint16)GUINT16_SWAP_LE_BE((gint16)data); |
405 | break; |
406 | case TEST_DATA_UINT16: |
407 | data = g_data_input_stream_read_uint16 (G_DATA_INPUT_STREAM (stream), NULL, error: &error); |
408 | if (swap) |
409 | data = (guint16)GUINT16_SWAP_LE_BE((guint16)data); |
410 | break; |
411 | case TEST_DATA_INT32: |
412 | data = g_data_input_stream_read_int32 (G_DATA_INPUT_STREAM (stream), NULL, error: &error); |
413 | if (swap) |
414 | data = (gint32)GUINT32_SWAP_LE_BE((gint32)data); |
415 | break; |
416 | case TEST_DATA_UINT32: |
417 | data = g_data_input_stream_read_uint32 (G_DATA_INPUT_STREAM (stream), NULL, error: &error); |
418 | if (swap) |
419 | data = (guint32)GUINT32_SWAP_LE_BE((guint32)data); |
420 | break; |
421 | case TEST_DATA_INT64: |
422 | data = g_data_input_stream_read_int64 (G_DATA_INPUT_STREAM (stream), NULL, error: &error); |
423 | if (swap) |
424 | data = (gint64)GUINT64_SWAP_LE_BE((gint64)data); |
425 | break; |
426 | case TEST_DATA_UINT64: |
427 | data = g_data_input_stream_read_uint64 (G_DATA_INPUT_STREAM (stream), NULL, error: &error); |
428 | if (swap) |
429 | data = (guint64)GUINT64_SWAP_LE_BE((guint64)data); |
430 | break; |
431 | default: |
432 | g_assert_not_reached (); |
433 | break; |
434 | } |
435 | if (!error) |
436 | g_assert_cmpint (data, ==, TEST_DATA_RETYPE_BUFF(data_type, gint64, ((guchar*)buffer + pos))); |
437 | |
438 | pos += data_size; |
439 | } |
440 | if (pos < len + 1) |
441 | g_assert_no_error (error); |
442 | if (error) |
443 | g_error_free (error); |
444 | g_assert_cmpint (pos - data_size, ==, len); |
445 | } |
446 | |
447 | static void |
448 | test_read_int (void) |
449 | { |
450 | GInputStream *stream; |
451 | GInputStream *base_stream; |
452 | GRand *randomizer; |
453 | int i; |
454 | gpointer buffer; |
455 | |
456 | randomizer = g_rand_new (); |
457 | buffer = g_malloc0 (MAX_BYTES); |
458 | |
459 | /* Fill in some random data */ |
460 | for (i = 0; i < MAX_BYTES; i++) |
461 | { |
462 | guchar x = 0; |
463 | while (! x) |
464 | x = (guchar)g_rand_int (rand_: randomizer); |
465 | *(guchar*)((guchar*)buffer + sizeof(guchar) * i) = x; |
466 | } |
467 | |
468 | base_stream = g_memory_input_stream_new (); |
469 | stream = G_INPUT_STREAM (g_data_input_stream_new (base_stream)); |
470 | g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (base_stream), data: buffer, MAX_BYTES, NULL); |
471 | |
472 | |
473 | for (i = 0; i < 3; i++) |
474 | { |
475 | int j; |
476 | g_data_input_stream_set_byte_order (G_DATA_INPUT_STREAM (stream), order: i); |
477 | |
478 | for (j = 0; j <= TEST_DATA_UINT64; j++) |
479 | test_data_array (stream, base_stream, buffer, MAX_BYTES, data_type: j, byte_order: i); |
480 | } |
481 | |
482 | g_object_unref (object: base_stream); |
483 | g_object_unref (object: stream); |
484 | g_rand_free (rand_: randomizer); |
485 | g_free (mem: buffer); |
486 | } |
487 | |
488 | |
489 | int |
490 | main (int argc, |
491 | char *argv[]) |
492 | { |
493 | g_test_init (argc: &argc, argv: &argv, NULL); |
494 | |
495 | g_test_add_func (testpath: "/data-input-stream/basic" , test_func: test_basic); |
496 | g_test_add_func (testpath: "/data-input-stream/read-lines-LF" , test_func: test_read_lines_LF); |
497 | g_test_add_func (testpath: "/data-input-stream/read-lines-LF-valid-utf8" , test_func: test_read_lines_LF_valid_utf8); |
498 | g_test_add_func (testpath: "/data-input-stream/read-lines-LF-invalid-utf8" , test_func: test_read_lines_LF_invalid_utf8); |
499 | g_test_add_func (testpath: "/data-input-stream/read-lines-CR" , test_func: test_read_lines_CR); |
500 | g_test_add_func (testpath: "/data-input-stream/read-lines-CR-LF" , test_func: test_read_lines_CR_LF); |
501 | g_test_add_func (testpath: "/data-input-stream/read-lines-any" , test_func: test_read_lines_any); |
502 | g_test_add_func (testpath: "/data-input-stream/read-until" , test_func: test_read_until); |
503 | g_test_add_func (testpath: "/data-input-stream/read-upto" , test_func: test_read_upto); |
504 | g_test_add_func (testpath: "/data-input-stream/read-int" , test_func: test_read_int); |
505 | |
506 | return g_test_run(); |
507 | } |
508 | |