static void test_message_parser_small_blocks(void)
{
	struct message_parser_ctx *parser;
	struct istream *input;
	struct message_part *parts, *parts2;
	struct message_block block;
	unsigned int i, end_of_headers_idx;
	pool_t pool;
	int ret;

	test_begin("message parser in small blocks");
	pool = pool_alloconly_create("message parser", 10240);
	input = test_istream_create(test_msg);

	/* full parsing */
	parser = message_parser_init(pool, input, 0, 0);
	while ((ret = message_parser_parse_next_block(parser, &block)) > 0) ;
	test_assert(ret < 0);
	test_assert(message_parser_deinit(&parser, &parts) == 0);

	/* parsing in small blocks */
	i_stream_seek(input, 0);
	test_istream_set_allow_eof(input, FALSE);

	parser = message_parser_init(pool, input, 0, 0);
	for (i = 1; i <= TEST_MSG_LEN*2+1; i++) {
		test_istream_set_size(input, i/2);
		if (i > TEST_MSG_LEN*2)
			test_istream_set_allow_eof(input, TRUE);
		while ((ret = message_parser_parse_next_block(parser,
							      &block)) > 0) ;
		test_assert((ret == 0 && i <= TEST_MSG_LEN*2) ||
			    (ret < 0 && i > TEST_MSG_LEN*2));
	}
	test_assert(message_parser_deinit(&parser, &parts2) == 0);
	test_assert(msg_parts_cmp(parts, parts2));

	/* parsing in small blocks from preparsed parts */
	i_stream_seek(input, 0);
	test_istream_set_allow_eof(input, FALSE);

	end_of_headers_idx = (strstr(test_msg, "\n-----") - test_msg);
	parser = message_parser_init_from_parts(parts, input, 0,
					MESSAGE_PARSER_FLAG_SKIP_BODY_BLOCK);
	for (i = 1; i <= TEST_MSG_LEN*2+1; i++) {
		test_istream_set_size(input, i/2);
		if (i > TEST_MSG_LEN*2)
			test_istream_set_allow_eof(input, TRUE);
		while ((ret = message_parser_parse_next_block(parser,
							      &block)) > 0) ;
		test_assert((ret == 0 && i/2 <= end_of_headers_idx) ||
			    (ret < 0 && i/2 > end_of_headers_idx));
	}
	test_assert(message_parser_deinit(&parser, &parts2) == 0);
	test_assert(msg_parts_cmp(parts, parts2));

	i_stream_unref(&input);
	pool_unref(&pool);
	test_end();
}
예제 #2
0
static
void test_write_read_v2(void)
{
	test_begin("test_write_read_v2");
	unsigned char payload[IO_BLOCK_SIZE*10];
	const unsigned char *ptr;
	size_t pos = 0, siz;
	random_fill_weak(payload, IO_BLOCK_SIZE*10);

	buffer_t *buf = buffer_create_dynamic(default_pool, sizeof(payload));
	struct ostream *os = o_stream_create_buffer(buf);
	struct ostream *os_2 = o_stream_create_encrypt(os, "aes-256-gcm-sha256", test_v1_kp.pub, IO_STREAM_ENC_INTEGRITY_AEAD);
	o_stream_nsend(os_2, payload, sizeof(payload));
	test_assert(o_stream_nfinish(os_2) == 0);
	if (os_2->stream_errno != 0)
		i_debug("error: %s", o_stream_get_error(os_2));

	o_stream_unref(&os);
	o_stream_unref(&os_2);

	struct istream *is = test_istream_create_data(buf->data, buf->used);
	/* test regression where read fails due to incorrect behaviour
	   when buffer is full before going to decrypt code */
	i_stream_set_max_buffer_size(is, 8192);
	i_stream_read(is);
	struct istream *is_2 = i_stream_create_decrypt(is, test_v1_kp.priv);

	size_t offset = 0;
	test_istream_set_size(is, 0);
	test_istream_set_allow_eof(is, FALSE);
	while(i_stream_read_data(is_2, &ptr, &siz, 0)>=0) {
		if (offset == buf->used)
			test_istream_set_allow_eof(is, TRUE);
		else
			test_istream_set_size(is, ++offset);

		test_assert_idx(pos + siz <= sizeof(payload), pos);
		if (pos + siz > sizeof(payload)) break;
		test_assert_idx(siz == 0 || memcmp(ptr, payload + pos, siz) == 0, pos);
		i_stream_skip(is_2, siz); pos += siz;
	}

	test_assert(is_2->stream_errno == 0);
	if (is_2->stream_errno != 0)
		i_debug("error: %s", i_stream_get_error(is_2));

	i_stream_unref(&is);
	i_stream_unref(&is_2);
	buffer_free(&buf);

	test_end();
}
예제 #3
0
static
void test_write_read_v1_short(void)
{
	test_begin("test_write_read_v1_short");
	unsigned char payload[1];
	const unsigned char *ptr;
	size_t pos = 0, siz;
	random_fill_weak(payload, 1);

	buffer_t *buf = buffer_create_dynamic(default_pool, 64);
	struct ostream *os = o_stream_create_buffer(buf);
	struct ostream *os_2 = o_stream_create_encrypt(os, "<unused>", test_v2_kp.pub, IO_STREAM_ENC_VERSION_1);
	o_stream_nsend(os_2, payload, sizeof(payload));

	if (os_2->stream_errno != 0)
		i_debug("error: %s", o_stream_get_error(os_2));

	test_assert(os_2->stream_errno == 0);
	test_assert(o_stream_nfinish(os_2) == 0);
	test_assert(os_2->stream_errno == 0);

	o_stream_unref(&os);
	o_stream_unref(&os_2);

	struct istream *is = test_istream_create_data(buf->data, buf->used);
	struct istream *is_2 = i_stream_create_decrypt(is, test_v2_kp.priv);

	size_t offset = 0;
	test_istream_set_allow_eof(is, FALSE);
	test_istream_set_size(is, 0);
	while(i_stream_read_data(is_2, &ptr, &siz, 0)>=0) {
		if (offset == buf->used)
			test_istream_set_allow_eof(is, TRUE);
		else
			test_istream_set_size(is, ++offset);

		test_assert_idx(pos + siz <= sizeof(payload), pos);
		if (pos + siz > sizeof(payload)) break;
		test_assert_idx(siz == 0 || memcmp(ptr, payload + pos, siz) == 0, pos);
		i_stream_skip(is_2, siz); pos += siz;
	}

	test_assert(is_2->stream_errno == 0);

	i_stream_unref(&is);
	i_stream_unref(&is_2);
	buffer_free(&buf);

	test_end();
}
예제 #4
0
static void
decode_test(const char *base64_input, const char *output, bool broken_input)
{
	unsigned int base64_input_len = strlen(base64_input);
	struct istream *input_data, *input;
	const unsigned char *data;
	size_t i, size;
	int ret = 0;

	input_data = test_istream_create_data(base64_input, base64_input_len);
	test_istream_set_allow_eof(input_data, FALSE);
	input = i_stream_create_base64_decoder(input_data);

	for (i = 1; i <= base64_input_len; i++) {
		test_istream_set_size(input_data, i);
		while ((ret = i_stream_read(input)) > 0) ;
		if (ret == -1 && broken_input)
			break;
		test_assert(ret == 0);
	}
	if (ret == 0) {
		test_istream_set_allow_eof(input_data, TRUE);
		while ((ret = i_stream_read(input)) > 0) ;
	}
	test_assert(ret == -1);
	test_assert((input->stream_errno == 0 && !broken_input) ||
		    (input->stream_errno == EINVAL && broken_input));

	data = i_stream_get_data(input, &size);
	test_assert(size == strlen(output));
	if (size > 0)
		test_assert(memcmp(data, output, size) == 0);
	i_stream_unref(&input);
	i_stream_unref(&input_data);
}
static void test_istream_binary_converter(void)
{
	struct istream *datainput, *input;
	const unsigned char *data;
	size_t i, size;
	int ret;

	test_begin("istream binary converter");
	datainput = test_istream_create_data(mail_input, sizeof(mail_input));
	test_istream_set_allow_eof(datainput, FALSE);
	input = i_stream_create_binary_converter(datainput);

	for (i = 1; i <= sizeof(mail_input); i++) {
		test_istream_set_size(datainput, i);
		while ((ret = i_stream_read(input)) > 0) ;
		test_assert(ret == 0);
	}
	test_istream_set_allow_eof(datainput, TRUE);
	while ((ret = i_stream_read(input)) > 0) ;
	test_assert(ret == -1);

	data = i_stream_get_data(input, &size);
	test_assert(size == sizeof(mail_output) &&
		    memcmp(data, mail_output, size) == 0);
	i_stream_unref(&input);
	i_stream_unref(&datainput);
	test_end();
}
예제 #6
0
static void test_message_header_parser_partial(void)
{
	struct message_header_parser_ctx *parser;
	struct message_header_line *hdr;
	struct istream *input;
	unsigned int i, max = (strlen(test1_msg)-TEST1_MSG_BODY_LEN)*2;
	string_t *str;
	int ret;

	test_begin("message header parser partial");
	input = test_istream_create(test1_msg);
	test_istream_set_allow_eof(input, FALSE);

	str = t_str_new(max);
	parser = message_parse_header_init(input, NULL, 0);
	for (i = 0; i <= max; i++) {
		test_istream_set_size(input, i/2);
		while ((ret = message_parse_header_next(parser, &hdr)) > 0)
			hdr_write(str, hdr);
		test_assert((ret == 0 && i < max) ||
			    (ret < 0 && i == max));
	}
	message_parse_header_deinit(&parser);

	str_append(str, " body");
	test_assert(strcmp(str_c(str), test1_msg) == 0);
	i_stream_unref(&input);
	test_end();
}
예제 #7
0
static void encode_test(const char *text, unsigned int chars_per_line,
			bool crlf, const char *output)
{
	unsigned int i, text_len = strlen(text);
	struct istream *input, *input_data;
	const unsigned char *data;
	size_t size;
	ssize_t ret;

	input_data = test_istream_create_data(text, text_len);
	test_istream_set_allow_eof(input_data, FALSE);
	input = i_stream_create_base64_encoder(input_data, chars_per_line, crlf);

	for (i = 1; i <= text_len; i++) {
		test_istream_set_size(input_data, i);
		while ((ret = i_stream_read(input)) > 0) ;
		test_assert(ret == 0);
	}
	test_istream_set_allow_eof(input_data, TRUE);
	while ((ret = i_stream_read(input)) > 0) ;
	test_assert(ret == -1);

	data = i_stream_get_data(input, &size);
	test_assert(size == strlen(output) && memcmp(data, output, size) == 0);

	i_stream_unref(&input);
	i_stream_unref(&input_data);
}
예제 #8
0
static void test_istream_tee_blocks(const char *str)
{
	struct istream *test_input, *child_input[CHILD_COUNT];
	struct tee_istream *tee;
	unsigned int i, j;

	test_input = test_istream_create(str);
	test_istream_set_max_buffer_size(test_input, TEST_BUF_SIZE);

	test_begin("istream tee blocks");
	tee = tee_i_stream_create(test_input);
	for (i = 0; i < CHILD_COUNT; i++)
		child_input[i] = tee_i_stream_create_child(tee);

	test_istream_set_allow_eof(test_input, FALSE);
	for (j = 1; j <= 3; j++) {
		test_istream_set_size(test_input, TEST_BUF_SIZE*j);
		for (i = 0; i < CHILD_COUNT; i++) {
			test_assert(i_stream_read(child_input[i]) == TEST_BUF_SIZE);
			i_stream_skip(child_input[i], TEST_BUF_SIZE);
		}
	}
	test_istream_set_allow_eof(test_input, TRUE);
	for (i = 0; i < CHILD_COUNT; i++) {
		test_assert(i_stream_read(child_input[i]) == -1);
		i_stream_unref(&child_input[i]);
	}
	i_stream_unref(&test_input);

	test_end();
}
예제 #9
0
static void test_imap_parser_crlf(void)
{
	static const char *test_input = "foo\r\nx\ry\n";
	struct istream *input;
	struct imap_parser *parser;
	const struct imap_arg *args;
	unsigned int i;
	bool fatal;

	test_begin("imap parser crlf handling");
	input = test_istream_create(test_input);
	parser = imap_parser_create(input, NULL, 1024);

	/* must return -2 until LF is read */
	for (i = 0; test_input[i] != '\n'; i++) {
		test_istream_set_size(input, i+1);
		(void)i_stream_read(input);
		test_assert(imap_parser_read_args(parser, 0, 0, &args) == -2);
	}
	test_istream_set_size(input, i+1);
	(void)i_stream_read(input);
	test_assert(imap_parser_read_args(parser, 0, 0, &args) == 1);
	test_assert(args[0].type == IMAP_ARG_ATOM);
	test_assert(args[1].type == IMAP_ARG_EOL);

	/* CR without LF should fail with error */
	imap_parser_reset(parser);
	i_stream_seek(input, ++i);
	test_istream_set_size(input, ++i);
	(void)i_stream_read(input);
	test_assert(imap_parser_read_args(parser, 0, 0, &args) == -2);
	test_istream_set_size(input, ++i);
	(void)i_stream_read(input);
	test_assert(imap_parser_read_args(parser, 0, 0, &args) == -2);
	test_istream_set_size(input, ++i);
	(void)i_stream_read(input);
	test_assert(imap_parser_read_args(parser, 0, 0, &args) == -1);
	test_assert(strcmp(imap_parser_get_error(parser, &fatal), "CR sent without LF") == 0 && !fatal);

	imap_parser_destroy(&parser);
	i_stream_destroy(&input);
	test_end();
}
예제 #10
0
static
void test_write_read_v1_empty(void)
{
	const unsigned char *ptr;
	size_t siz;
	test_begin("test_write_read_v1_empty");
	buffer_t *buf = buffer_create_dynamic(default_pool, 64);
	struct ostream *os = o_stream_create_buffer(buf);
	struct ostream *os_2 = o_stream_create_encrypt(os, "<unused>", test_v1_kp.pub, IO_STREAM_ENC_VERSION_1);
	test_assert(o_stream_nfinish(os_2) == 0);
	if (os_2->stream_errno != 0)
		i_debug("error: %s", o_stream_get_error(os_2));

	o_stream_unref(&os);
	o_stream_unref(&os_2);
	/* this should've been enough */

	struct istream *is = test_istream_create_data(buf->data, buf->used);
	struct istream *is_2 = i_stream_create_decrypt(is, test_v1_kp.priv);

	/* read should not fail */
	test_istream_set_allow_eof(is, FALSE);
	test_istream_set_size(is, 0);
	size_t offset = 0;
	ssize_t ret;
	while ((ret = i_stream_read_data(is_2, &ptr, &siz, 0)) >= 0) {
		test_assert(ret == 0);
		if (offset == buf->used)
			test_istream_set_allow_eof(is, TRUE);
		else
			test_istream_set_size(is, ++offset);
	};

	test_assert(is_2->stream_errno == 0);
	if (is_2->stream_errno != 0)
		i_debug("error: %s", i_stream_get_error(is_2));
	i_stream_unref(&is);
	i_stream_unref(&is_2);
	buffer_free(&buf);
	test_end();
}
static void test_json_parser_success(bool full_size)
{
	struct json_parser *parser;
	struct istream *input, *jsoninput = NULL;
	enum json_type type;
	const char *value, *error;
	unsigned int i, pos, json_input_len = strlen(json_input);
	int ret = 0;

	test_begin(full_size ? "json parser" : "json parser (nonblocking)");
	input = test_istream_create_data(json_input, json_input_len);
	test_istream_set_allow_eof(input, FALSE);
	parser = json_parser_init(input);

	i = full_size ? json_input_len : 0;
	for (pos = 0; i <= json_input_len; i++) {
		test_istream_set_size(input, i);

		for (;;) {
			value = NULL;
			if (pos < N_ELEMENTS(json_output) &&
			    json_output[pos].type == (enum json_type)TYPE_SKIP) {
				json_parse_skip_next(parser);
				pos++;
				continue;
			} else if (pos == N_ELEMENTS(json_output) ||
				   json_output[pos].type != (enum json_type)TYPE_STREAM) {
				ret = json_parse_next(parser, &type, &value);
			} else {
				ret = jsoninput != NULL ? 1 :
					json_parse_next_stream(parser, &jsoninput);
				if (jsoninput != NULL)
					ret = stream_read_value(&jsoninput, &value);
				type = TYPE_STREAM;
			}
			if (ret <= 0)
				break;

			i_assert(pos < N_ELEMENTS(json_output));
			test_assert(json_output[pos].type == type);
			test_assert(null_strcmp(json_output[pos].value, value) == 0);
			pos++;
		}
		test_assert(ret == 0);
	}
	test_assert(pos == N_ELEMENTS(json_output));
	test_istream_set_allow_eof(input, TRUE);
	test_assert(json_parse_next(parser, &type, &value) == -1);

	i_stream_unref(&input);
	test_assert(json_parser_deinit(&parser, &error) == 0);
	test_end();
}
예제 #12
0
static void test_istream_dot_error(const char *input_str, bool test_bufsize)
{
	struct istream *test_input, *input;
	unsigned int i;
	size_t outsize, input_len;
	uoff_t offset;
	int ret;

	test_input = test_istream_create(input_str);
	input = i_stream_create_dot(test_input, FALSE);

	input_len = strlen(input_str);

	if (!test_bufsize) {
		outsize = 1; i = 0;
		i_stream_set_max_buffer_size(input, outsize);
		test_istream_set_size(test_input, 1);
		while ((ret = i_stream_read(input)) != -1) {
			switch (ret) {
			case -2:
				i_stream_set_max_buffer_size(input, ++outsize);
				offset = test_input->v_offset;
				/* seek one byte backwards so stream gets
				   reset */
				i_stream_seek(test_input, offset - 1);
				/* go back to original position */
				test_istream_set_size(test_input, offset);
				i_stream_skip(test_input, 1);
				/* and finally allow reading one more byte */
				test_istream_set_size(test_input, offset + 1);
				break;
			case 0:
				test_istream_set_size(test_input, ++i);
				break;
			default:
				test_assert(ret > 0);
			}
		}
		test_istream_set_size(test_input, input_len);
		(void)i_stream_read(test_input);
	} else {
		test_istream_set_size(test_input, input_len);
		for (i = 1; i <= input_len; i++) {
			i_stream_set_max_buffer_size(input, i);
			(void)i_stream_read(input);
			(void)i_stream_read(input);
		}
		i_stream_set_max_buffer_size(input, i+1);
		(void)i_stream_read(input);
	}
	test_assert(input->stream_errno == EPIPE);

	i_stream_unref(&test_input);
	i_stream_unref(&input);
}
예제 #13
0
static void
decode_test(const char *qp_input, const char *output, bool broken_input,
	    unsigned int buffer_size)
{
	unsigned int qp_input_len = strlen(qp_input);
	struct istream *input_data, *input;
	const unsigned char *data;
	size_t i, size;
	string_t *str = t_str_new(32);
	int ret = 0;

	input_data = test_istream_create_data(qp_input, qp_input_len);
	test_istream_set_max_buffer_size(input_data, buffer_size);
	test_istream_set_allow_eof(input_data, FALSE);
	input = i_stream_create_qp_decoder(input_data);

	for (i = 1; i <= qp_input_len; i++) {
		test_istream_set_size(input_data, i);
		while ((ret = i_stream_read_more(input, &data, &size)) > 0) {
			str_append_n(str, data, size);
			i_stream_skip(input, size);
		}
		if (ret == -1 && broken_input)
			break;
		test_assert(ret == 0);
	}
	if (ret == 0) {
		test_istream_set_allow_eof(input_data, TRUE);
		while ((ret = i_stream_read_more(input, &data, &size)) > 0) {
			str_append_n(str, data, size);
			i_stream_skip(input, size);
		}
	}
	test_assert(ret == -1);
	test_assert((input->stream_errno == 0 && !broken_input) ||
		    (input->stream_errno == EINVAL && broken_input));

	test_assert(strcmp(str_c(str), output) == 0);
	i_stream_unref(&input);
	i_stream_unref(&input_data);
}
예제 #14
0
static void
test_message_header_parser_long_lines_str(const char *str,
					  unsigned int buffer_size,
					  struct message_size *size_r)
{
	struct message_header_parser_ctx *parser;
	struct message_header_line *hdr;
	struct istream *input;
	unsigned int i, len = strlen(str);

	input = test_istream_create(str);
	test_istream_set_max_buffer_size(input, buffer_size);

	parser = message_parse_header_init(input, size_r, 0);
	for (i = 1; i <= len; i++) {
		test_istream_set_size(input, i);
		while (message_parse_header_next(parser, &hdr) > 0) ;
	}
	message_parse_header_deinit(&parser);
	i_stream_unref(&input);
}
static void test_istream_dot_one(const struct dot_test *test,
				 bool send_last_lf, bool test_bufsize)
{
	struct istream *test_input, *input;
	const unsigned char *data;
	size_t size;
	unsigned int i, outsize, input_len, output_len;
	string_t *str;
	uoff_t offset;
	int ret;

	test_input = test_istream_create(test->input);
	input = i_stream_create_dot(test_input, send_last_lf);

	input_len = strlen(test->input);
	output_len = strlen(test->output);
	if (!send_last_lf &&
	    (test->input[input_len-1] == '\n' ||
	     strstr(test->input, "\n.\n") != NULL ||
	     strstr(test->input, "\n.\r\n") != NULL)) {
		if (test->output[output_len-1] == '\n') {
			output_len--;
			if (output_len > 0 &&
			    test->output[output_len-1] == '\r')
				output_len--;
		}
	}

	str = t_str_new(256);
	if (!test_bufsize) {
		outsize = 1; i = 0;
		i_stream_set_max_buffer_size(input, outsize);
		test_istream_set_size(test_input, 1);
		while ((ret = i_stream_read(input)) != -1) {
			switch (ret) {
			case -2:
				i_stream_set_max_buffer_size(input, ++outsize);
				offset = test_input->v_offset;
				/* seek one byte backwards so stream gets
				   reset */
				i_stream_seek(test_input, offset - 1);
				/* go back to original position */
				test_istream_set_size(test_input, offset);
				i_stream_skip(test_input, 1);
				/* and finally allow reading one more byte */
				test_istream_set_size(test_input, offset + 1);
				break;
			case 0:
				test_istream_set_size(test_input, ++i);
				break;
			default:
				test_assert(ret > 0);

				data = i_stream_get_data(input, &size);
				str_append_n(str, data, size);
				i_stream_skip(input, size);
			}
		}
		test_istream_set_size(test_input, input_len);
		(void)i_stream_read(test_input);
	} else {
		test_istream_set_size(test_input, input_len);
		size = 0;
		for (i = 1; i < output_len; i++) {
			i_stream_set_max_buffer_size(input, i);
			test_assert(i_stream_read(input) == 1);
			test_assert(i_stream_read(input) == -2);
			data = i_stream_get_data(input, &size);
			test_assert(memcmp(data, test->output, size) == 0);
		}
		i_stream_set_max_buffer_size(input, i+2);
		if (size < output_len)
			test_assert(i_stream_read(input) == 1);
		test_assert(i_stream_read(input) == -1);

		data = i_stream_get_data(input, &size);
		str_append_n(str, data, size);
	}
	test_assert(str_len(str) == output_len);
	test_assert(memcmp(str_data(str), test->output, output_len) == 0);

	data = i_stream_get_data(test_input, &size);
	test_assert(size == strlen(test->parent_input));
	test_assert(memcmp(data, test->parent_input, size) == 0);

	i_stream_unref(&test_input);
	i_stream_unref(&input);
}
예제 #16
0
static void test_istream_tee_tailing(const char *str)
{
	struct istream *test_input, *child_input[CHILD_COUNT];
	struct tee_istream *tee;
	unsigned int i, len;

	test_input = test_istream_create(str);
	test_istream_set_max_buffer_size(test_input, TEST_BUF_SIZE);

	test_begin("istream tee tailing");
	tee = tee_i_stream_create(test_input);
	for (i = 0; i < CHILD_COUNT; i++)
		child_input[i] = tee_i_stream_create_child(tee);

	test_istream_set_allow_eof(test_input, FALSE);
	for (len = 1; len < TEST_BUF_SIZE; len++) {
		test_istream_set_size(test_input, len);
		for (i = 0; i < CHILD_COUNT; i++) {
			test_assert(i_stream_read(child_input[i]) == 1);
			test_assert(!tee_i_stream_child_is_waiting(child_input[i]));
			test_assert(i_stream_read(child_input[i]) == 0);
			test_assert(!tee_i_stream_child_is_waiting(child_input[i]));
		}
	}

	test_istream_set_size(test_input, len);
	for (i = 0; i < CHILD_COUNT; i++) {
		test_assert(i_stream_read(child_input[i]) == 1);
		test_assert(i_stream_read(child_input[i]) == -2);
		test_assert(!tee_i_stream_child_is_waiting(child_input[i]));
	}

	for (len++; len <= TEST_STR_LEN; len++) {
		test_istream_set_size(test_input, len);
		for (i = 0; i < CHILD_COUNT; i++) {
			test_assert(i_stream_read(child_input[i]) == -2);
			test_assert(!tee_i_stream_child_is_waiting(child_input[i]));
		}
		for (i = 0; i < CHILD_COUNT-1; i++) {
			i_stream_skip(child_input[i], 1);
			test_assert(i_stream_read(child_input[i]) == 0);
			test_assert(tee_i_stream_child_is_waiting(child_input[i]));
		}
		i_stream_skip(child_input[i], 1);
		for (i = 0; i < CHILD_COUNT; i++) {
			test_assert(i_stream_read(child_input[i]) == 1);
			test_assert(i_stream_read(child_input[i]) == -2);
			test_assert(!tee_i_stream_child_is_waiting(child_input[i]));
		}
	}

	for (i = 0; i < CHILD_COUNT-1; i++) {
		i_stream_skip(child_input[i], 1);
		test_assert(i_stream_read(child_input[i]) == 0);
		test_assert(tee_i_stream_child_is_waiting(child_input[i]));
	}
	i_stream_skip(child_input[i], 1);
	test_assert(i_stream_read(child_input[i]) == 0);
	test_assert(!tee_i_stream_child_is_waiting(child_input[i]));

	test_istream_set_allow_eof(test_input, TRUE);
	for (i = 0; i < CHILD_COUNT; i++) {
		test_assert(i_stream_read(child_input[i]) == -1);
		i_stream_unref(&child_input[i]);
	}
	i_stream_unref(&test_input);

	test_end();
}