diff options
Diffstat (limited to 'src/lib/test-istream-concat.c')
-rw-r--r-- | src/lib/test-istream-concat.c | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/src/lib/test-istream-concat.c b/src/lib/test-istream-concat.c new file mode 100644 index 0000000..5e80cfa --- /dev/null +++ b/src/lib/test-istream-concat.c @@ -0,0 +1,254 @@ +/* Copyright (c) 2009-2018 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "istream-private.h" +#include "istream-concat.h" + +#include <fcntl.h> +#include <unistd.h> + +#define TEST_MAX_ISTREAM_COUNT 10 +#define TEST_MAX_ISTREAM_SIZE 1024 +#define TEST_MAX_BUFFER_SIZE 128 + +static void test_istream_concat_one(unsigned int buffer_size) +{ + static const char *input_string = "xyz"; +#define STREAM_COUNT 5 +#define STREAM_BYTES 3 + struct istream *streams[STREAM_COUNT+1]; + struct istream *input; + const unsigned char *data; + size_t size; + unsigned int i, j; + + for (i = 0; i < STREAM_COUNT; i++) { + streams[i] = test_istream_create(input_string); + test_istream_set_allow_eof(streams[i], TRUE); + test_istream_set_size(streams[i], 0); + } + streams[i] = NULL; + + input = i_stream_create_concat(streams); + for (i = 0; i/STREAM_BYTES < STREAM_COUNT; i++) { + test_istream_set_size(streams[i/STREAM_BYTES], (i%STREAM_BYTES) + 1); + test_assert(i_stream_read(input) == 1); + if (i < buffer_size) { + data = i_stream_get_data(input, &size); + test_assert(size == i+1); + } else { + i_stream_skip(input, 1); + data = i_stream_get_data(input, &size); + test_assert(size == buffer_size); + } + for (j = 0; j < size; j++) { + test_assert((char)data[j] == input_string[(input->v_offset + j) % STREAM_BYTES]); + } + test_assert(i_stream_read(input) <= 0); + } + test_assert(i_stream_read(input) == -1); + i_stream_skip(input, i_stream_get_data_size(input)); + i_stream_unref(&input); + + for (i = 0; i < STREAM_COUNT; i++) { + test_assert(streams[i]->eof && streams[i]->stream_errno == 0); + i_stream_unref(&streams[i]); + } +} + +static bool test_istream_concat_random(void) +{ + struct istream **streams, *concat, **limits = NULL; + const unsigned char *data; + unsigned char *w_data; + size_t size = 0; + unsigned int i, j, offset, stream_count, data_len, simult; + + stream_count = i_rand_minmax(2, TEST_MAX_ISTREAM_COUNT + 2 - 1); + streams = t_new(struct istream *, stream_count + 1); + for (i = 0, offset = 0; i < stream_count; i++) { + data_len = i_rand_minmax(1, TEST_MAX_ISTREAM_SIZE); + w_data = t_malloc_no0(data_len); + for (j = 0; j < data_len; j++) + w_data[j] = (offset++) & 0xff; + streams[i] = test_istream_create_data(w_data, data_len); + test_istream_set_allow_eof(streams[i], TRUE); + } + streams[i] = NULL; + i_assert(offset > 0); + + concat = i_stream_create_concat(streams); + i_stream_set_max_buffer_size(concat, TEST_MAX_BUFFER_SIZE); + + simult = i_rand_limit(TEST_MAX_ISTREAM_COUNT); + if (simult > 0) { + limits = t_new(struct istream *, simult); + for (i = 0; i < simult; i++) + limits[i] = i_stream_create_limit(concat, UOFF_T_MAX); + } + + for (i = 0; i < 1000; i++) { + struct istream *input = (simult == 0) ? concat : limits[i_rand_limit(simult)]; + if (i_rand_limit(3) == 0) { + i_stream_seek(input, i_rand_limit(offset)); + } else { + ssize_t ret = i_stream_read(input); + size = i_stream_get_data_size(input); + if (ret == -2) { + test_assert(size >= TEST_MAX_BUFFER_SIZE); + } else if (input->v_offset + size != offset) { + test_assert(ret > 0); + test_assert(input->v_offset + ret <= offset); + i_stream_skip(input, i_rand_limit(ret)); + + data = i_stream_get_data(input, &size); + for (j = 0; j < size; j++) { + test_assert(data[j] == (input->v_offset + j) % 256); + } + } + } + if (test_has_failed()) + break; + } + for (i = 0; i < stream_count; i++) + i_stream_unref(&streams[i]); + for (i = 0; i < simult; i++) + i_stream_unref(&limits[i]); + i_stream_unref(&concat); + return !test_has_failed(); +} + +static void test_istream_concat_seek_end(void) +{ + test_begin("istream concat seek end"); + + struct istream *streams[] = { + test_istream_create("s1"), + test_istream_create("s2"), + NULL + }; + struct istream *input = i_stream_create_concat(streams); + i_stream_unref(&streams[0]); + i_stream_unref(&streams[1]); + + i_stream_seek(input, 4); + test_assert(i_stream_read(input) == -1); + i_stream_unref(&input); + + test_end(); +} + +static void test_istream_concat_early_end(void) +{ + struct istream *input, *streams[2]; + + test_begin("istream concat early end"); + + streams[0] = test_istream_create("stream"); + test_istream_set_size(streams[0], 3); + test_istream_set_allow_eof(streams[0], FALSE); + streams[1] = NULL; + + input = i_stream_create_concat(streams); + test_assert(i_stream_read(input) == 3); + test_istream_set_size(streams[0], 5); + test_assert(i_stream_read(input) == 2); + i_stream_skip(input, 5); + i_stream_unref(&input); + + test_assert(streams[0]->v_offset == 5); + i_stream_unref(&streams[0]); + + test_end(); +} + +static void test_istream_concat_snapshot(void) +{ + struct istream *input; + const unsigned char *data; + size_t size; + + test_begin("istream concat snapshot"); + + struct istream *test_istreams[] = { + test_istream_create("abcdefghijklmnopqrst"), + test_istream_create("ABCDEFGHIJKLMNOPQRSTUVWXY"), + test_istream_create("!\"#$%&'()*+,-./01234567890:;<="), + NULL + }; + + input = i_stream_create_concat(test_istreams); + for (unsigned int i = 0; test_istreams[i] != NULL; i++) { + struct istream *tmp_istream = test_istreams[i]; + i_stream_unref(&tmp_istream); + } + + test_istream_set_size(test_istreams[0], 20); + test_istream_set_size(test_istreams[1], 0); + test_istream_set_size(test_istreams[2], 0); + + /* first stream */ + test_istream_set_allow_eof(test_istreams[0], FALSE); + test_assert(i_stream_read_data(input, &data, &size, 0) == 1); + test_assert(size == 20); + test_assert(memcmp(data, "abcdefghijklmnopqrst", 20) == 0); + + /* partially skip */ + i_stream_skip(input, 12); + + /* second stream */ + test_assert(i_stream_read_data(input, &data, &size, 10) == 0); + test_assert(size == 8); + test_istream_set_allow_eof(test_istreams[0], TRUE); + test_istream_set_size(test_istreams[0], 0); + test_assert(i_stream_read_data(input, &data, &size, 10) == 0); + test_assert(size == 8); + test_istream_set_size(test_istreams[1], 10); + test_assert(i_stream_read_data(input, &data, &size, 10) == 1); + test_assert(size == 18); + test_istream_set_allow_eof(test_istreams[1], FALSE); + test_assert(i_stream_read(input) == 0); + test_istream_set_size(test_istreams[1], 25); + test_istream_set_allow_eof(test_istreams[1], TRUE); + test_assert(i_stream_read_data(input, &data, &size, 30) == 1); + test_assert(size == 33); + test_assert(memcmp(data, "mnopqrst" + "ABCDEFGHIJKLMNOPQRSTUVWXY", 33) == 0); + + /* partially skip */ + i_stream_skip(input, 12); + + /* third stream */ + test_istream_set_size(test_istreams[2], 0); + test_assert(i_stream_read(input) == 0); + test_istream_set_size(test_istreams[2], 30); + test_assert(i_stream_read_data(input, &data, &size, 25) == 1); + test_assert(size == 51); + test_assert(memcmp(data, "EFGHIJKLMNOPQRSTUVWXY" + "!\"#$%&'()*+,-./01234567890:;<=", 51) == 0); + + i_stream_unref(&input); + test_end(); +} + +void test_istream_concat(void) +{ + unsigned int i; + + test_begin("istream concat"); + for (i = 1; i < STREAM_BYTES*STREAM_COUNT; i++) { + test_istream_concat_one(i); + } + test_end(); + + test_begin("istream concat random"); + for (i = 0; i < 100; i++) T_BEGIN { + if(!test_istream_concat_random()) + i = 101; /* don't break a T_BEGIN */ + } T_END; + test_end(); + + test_istream_concat_seek_end(); + test_istream_concat_early_end(); + test_istream_concat_snapshot(); +} |