]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-mail: Add tests for message-size functions
authorMarkus Valentin <markus.valentin@open-xchange.com>
Fri, 6 Nov 2020 10:47:18 +0000 (11:47 +0100)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Tue, 1 Dec 2020 14:37:12 +0000 (14:37 +0000)
Integrate testing of header and body size to existing tests and add new
tests specifically for message-size.

src/lib-mail/Makefile.am
src/lib-mail/test-message-header-parser.c
src/lib-mail/test-message-parser.c
src/lib-mail/test-message-size.c [new file with mode: 0644]

index 9127cccff8fc8ed3d56a7d0ad48176729e8b6819..f260694f18c6a54858d1eb851762f47bac45b18e 100644 (file)
@@ -106,6 +106,7 @@ test_programs = \
        test-message-part \
        test-message-part-serialize \
        test-message-search \
+       test-message-size \
        test-message-snippet \
        test-ostream-dot \
        test-qp-decoder \
@@ -196,6 +197,10 @@ test_message_search_SOURCES = test-message-search.c
 test_message_search_LDADD = $(test_libs) ../lib-charset/libcharset.la
 test_message_search_DEPENDENCIES = $(test_deps) ../lib-charset/libcharset.la
 
+test_message_size_SOURCES = test-message-size.c
+test_message_size_LDADD = $(test_libs)
+test_message_size_DEPENDENCIES = $(test_deps)
+
 test_message_snippet_SOURCES = test-message-snippet.c
 test_message_snippet_LDADD = $(test_message_decoder_LDADD)
 test_message_snippet_DEPENDENCIES = $(test_deps)
index 7362f6c630394853b552d2db7871ac9ffba60a63..a9fea89a5c3e537ee18d95c91fe303c8009f3c9a 100644 (file)
@@ -132,8 +132,9 @@ static void test_message_header_parser(void)
                MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE;
        enum message_header_parser_flags hdr_flags;
        struct message_header_parser_ctx *parser;
-       struct message_size hdr_size;
+       struct message_size hdr_size, hdr_size2;
        struct istream *input;
+       bool has_nuls;
 
        test_begin("message header parser");
        input = test_istream_create(test1_msg);
@@ -143,7 +144,14 @@ static void test_message_header_parser(void)
                parser = message_parse_header_init(input, &hdr_size, hdr_flags);
                test_message_header_parser_one(parser, hdr_flags);
                message_parse_header_deinit(&parser);
+               i_stream_seek(input, 0);
+               message_get_header_size(input, &hdr_size2, &has_nuls);
        }
+
+       test_assert(!has_nuls);
+       test_assert(hdr_size.physical_size == hdr_size2.physical_size);
+       test_assert(hdr_size.virtual_size == hdr_size2.virtual_size);
+       test_assert(hdr_size.lines == hdr_size2.lines);
        test_assert(hdr_size.physical_size == strlen(test1_msg)-TEST1_MSG_BODY_LEN);
        test_assert(hdr_size.virtual_size == strlen(test1_msg) - TEST1_MSG_BODY_LEN + 4);
 
@@ -199,13 +207,15 @@ static void test_message_header_parser_partial(void)
 static void
 test_message_header_parser_long_lines_str(const char *str,
                                          unsigned int buffer_size,
-                                         struct message_size *size_r)
+                                         struct message_size *size_r,
+                                         struct message_size *size_2_r)
 {
        struct message_header_parser_ctx *parser;
        struct message_header_line *hdr;
        struct istream *input;
        unsigned int i;
        size_t len = strlen(str);
+       bool has_nuls;
 
        input = test_istream_create(str);
        test_istream_set_max_buffer_size(input, buffer_size);
@@ -216,6 +226,12 @@ test_message_header_parser_long_lines_str(const char *str,
                while (message_parse_header_next(parser, &hdr) > 0) ;
        }
        message_parse_header_deinit(&parser);
+       i_stream_seek(input, 0);
+       /* Buffer must be +1 for message_get_header_size as it's using
+          i_stream_read_bytes which does not work with lower buffersize
+          because it returns -2 (input buffer full) if 2 bytes are wanted. */
+       test_istream_set_max_buffer_size(input, buffer_size+1);
+       message_get_header_size(input, size_2_r, &has_nuls);
        i_stream_unref(&input);
 }
 
@@ -223,21 +239,25 @@ static void test_message_header_parser_long_lines(void)
 {
        static const char *lf_str = "1234567890: 345\n\n";
        static const char *crlf_str = "1234567890: 345\r\n\r\n";
-       struct message_size hdr_size;
+       struct message_size hdr_size, hdr_size2;
        size_t i, len;
 
        test_begin("message header parser long lines");
        len = strlen(lf_str);
        for (i = 2; i < len; i++) {
-               test_message_header_parser_long_lines_str(lf_str, i, &hdr_size);
+               test_message_header_parser_long_lines_str(lf_str, i, &hdr_size, &hdr_size2);
                test_assert(hdr_size.physical_size == len);
                test_assert(hdr_size.virtual_size == len + 2);
+               test_assert(hdr_size.virtual_size == hdr_size2.virtual_size);
+               test_assert(hdr_size.physical_size == hdr_size2.physical_size);
        }
        len = strlen(crlf_str);
        for (i = 3; i < len; i++) {
-               test_message_header_parser_long_lines_str(crlf_str, i, &hdr_size);
+               test_message_header_parser_long_lines_str(crlf_str, i, &hdr_size, &hdr_size2);
                test_assert(hdr_size.physical_size == len);
                test_assert(hdr_size.virtual_size == len);
+               test_assert(hdr_size.virtual_size == hdr_size2.virtual_size);
+               test_assert(hdr_size.physical_size == hdr_size2.physical_size);
        }
        test_end();
 }
index b99fc74dd161612d8582b7848e7654df8252edb2..8c5a3404f10bdfee7a9b3da346a334d8aebc0428 100644 (file)
@@ -5,6 +5,7 @@
 #include "istream.h"
 #include "message-parser.h"
 #include "message-part-data.h"
+#include "message-size.h"
 #include "test-common.h"
 
 static const char test_msg[] =
@@ -202,6 +203,33 @@ static void test_message_parser_stop_early(void)
        test_end();
 }
 
+static void test_message_parser_get_sizes(struct istream *input,
+                                         struct message_size *body_size_r,
+                                         struct message_size *header_size_r,
+                                         bool expect_has_nuls)
+{
+       bool has_nuls;
+       i_zero(body_size_r);
+       i_zero(header_size_r);
+
+       message_get_header_size(input, header_size_r, &has_nuls);
+       test_assert(has_nuls == expect_has_nuls);
+       message_get_body_size(input, body_size_r, &has_nuls);
+       test_assert(has_nuls == expect_has_nuls);
+}
+
+static void test_message_parser_assert_sizes(const struct message_part *part,
+                                            const struct message_size *body_size,
+                                            const struct message_size *header_size)
+{
+       test_assert(part->header_size.lines == header_size->lines);
+       test_assert(part->header_size.physical_size == header_size->physical_size);
+       test_assert(part->header_size.virtual_size == header_size->virtual_size);
+       test_assert(part->body_size.lines == body_size->lines);
+       test_assert(part->body_size.physical_size == body_size->physical_size);
+       test_assert(part->body_size.virtual_size == body_size->virtual_size);
+}
+
 static void test_message_parser_truncated_mime_headers(void)
 {
 static const char input_msg[] =
@@ -217,6 +245,7 @@ static const char input_msg[] =
 "--:foo--\n";
        struct istream *input;
        struct message_part *parts, *part;
+       struct message_size body_size, header_size;
        pool_t pool;
 
        test_begin("message parser truncated mime headers");
@@ -225,6 +254,9 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &set_empty, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+       test_message_parser_get_sizes(input, &body_size, &header_size, FALSE);
+
        test_assert((parts->flags & MESSAGE_PART_FLAG_MULTIPART) != 0);
        test_assert(parts->children_count == 4);
        test_assert(parts->header_size.lines == 2);
@@ -233,6 +265,8 @@ static const char input_msg[] =
        test_assert(parts->body_size.lines == 8);
        test_assert(parts->body_size.physical_size == 112);
        test_assert(parts->body_size.virtual_size == 112+7);
+       test_message_parser_assert_sizes(parts, &body_size, &header_size);
+
        test_assert(parts->children->physical_pos == 55);
        test_assert(parts->children->header_size.physical_size == 0);
        test_assert(parts->children->body_size.physical_size == 0);
@@ -276,6 +310,7 @@ static const char input_msg[] =
 "--a\n\n";
        struct istream *input;
        struct message_part *parts;
+       struct message_size body_size, header_size;
        pool_t pool;
 
        test_begin("message parser truncated mime headers 2");
@@ -284,6 +319,9 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &set_empty, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+       test_message_parser_get_sizes(input, &body_size, &header_size, FALSE);
+
        test_assert(parts->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
        test_assert(parts->children_count == 2);
        test_assert(parts->header_size.lines == 2);
@@ -292,6 +330,7 @@ static const char input_msg[] =
        test_assert(parts->body_size.lines == 8);
        test_assert(parts->body_size.physical_size == 86);
        test_assert(parts->body_size.virtual_size == 86+8);
+       test_message_parser_assert_sizes(parts, &body_size, &header_size);
 
        test_assert(parts->children->children_count == 0);
        test_assert(parts->children->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
@@ -397,6 +436,7 @@ static const char input_msg[] =
 "body\n";
        struct istream *input;
        struct message_part *parts;
+       struct message_size body_size, header_size;
        pool_t pool;
 
        test_begin("message parser duplicate mime boundary");
@@ -405,6 +445,9 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &set_empty, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+       test_message_parser_get_sizes(input, &body_size, &header_size, FALSE);
+
        test_assert(parts->children_count == 2);
        test_assert(parts->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
        test_assert(parts->header_size.lines == 2);
@@ -413,6 +456,8 @@ static const char input_msg[] =
        test_assert(parts->body_size.lines == 7);
        test_assert(parts->body_size.physical_size == 84);
        test_assert(parts->body_size.virtual_size == 84+7);
+       test_message_parser_assert_sizes(parts, &body_size, &header_size);
+
        test_assert(parts->children->children_count == 1);
        test_assert(parts->children->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
        test_assert(parts->children->physical_pos == 49);
@@ -452,6 +497,7 @@ static const char input_msg[] =
 "body\n";
        struct istream *input;
        struct message_part *parts;
+       struct message_size body_size, header_size;
        pool_t pool;
 
        test_begin("message parser garbage suffix mime boundary");
@@ -460,6 +506,9 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &set_empty, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+       test_message_parser_get_sizes(input, &body_size, &header_size, FALSE);
+
        test_assert(parts->children_count == 2);
        test_assert(parts->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
        test_assert(parts->header_size.lines == 2);
@@ -468,6 +517,8 @@ static const char input_msg[] =
        test_assert(parts->body_size.lines == 7);
        test_assert(parts->body_size.physical_size == 86);
        test_assert(parts->body_size.virtual_size == 86+7);
+       test_message_parser_assert_sizes(parts, &body_size, &header_size);
+
        test_assert(parts->children->children_count == 1);
        test_assert(parts->children->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
        test_assert(parts->children->physical_pos == 50);
@@ -554,6 +605,8 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &set_empty, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+
        test_assert(parts->children_count == 2);
        test_assert(parts->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
        test_assert(parts->header_size.lines == 2);
@@ -602,6 +655,7 @@ static const char input_msg[] =
 "--a--\n\n";
        struct istream *input;
        struct message_part *parts, *part;
+       struct message_size body_size, header_size;
        pool_t pool;
 
        test_begin("message parser continuing truncated mime boundary");
@@ -610,6 +664,9 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &set_empty, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+       test_message_parser_get_sizes(input, &body_size, &header_size, FALSE);
+
        part = parts;
        test_assert(part->children_count == 3);
        test_assert(part->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
@@ -619,6 +676,7 @@ static const char input_msg[] =
        test_assert(part->body_size.lines == 9);
        test_assert(part->body_size.physical_size == 112);
        test_assert(part->body_size.virtual_size == 112+9);
+       test_message_parser_assert_sizes(part, &body_size, &header_size);
 
        part = parts->children;
        test_assert(part->children_count == 0);
@@ -679,6 +737,7 @@ static const char input_msg[] =
 "body2\n";
        struct istream *input;
        struct message_part *parts;
+       struct message_size body_size, header_size;
        pool_t pool;
 
        test_begin("message parser continuing mime boundary reverse");
@@ -687,6 +746,9 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &set_empty, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+       test_message_parser_get_sizes(input, &body_size, &header_size, FALSE);
+
        test_assert(parts->children_count == 3);
        test_assert(parts->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
        test_assert(parts->header_size.lines == 2);
@@ -695,6 +757,8 @@ static const char input_msg[] =
        test_assert(parts->body_size.lines == 11);
        test_assert(parts->body_size.physical_size == 121);
        test_assert(parts->body_size.virtual_size == 121+11);
+       test_message_parser_assert_sizes(parts, &body_size, &header_size);
+
        test_assert(parts->children->children_count == 1);
        test_assert(parts->children->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
        test_assert(parts->children->physical_pos == 51);
@@ -790,6 +854,7 @@ static const char input_msg[] =
 "4444\n";
        struct istream *input;
        struct message_part *parts, *part;
+       struct message_size body_size, header_size;
        pool_t pool;
 
        test_begin("message parser long mime boundary");
@@ -798,6 +863,9 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &set_empty, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+       test_message_parser_get_sizes(input, &body_size, &header_size, FALSE);
+
        part = parts;
        test_assert(part->children_count == 6);
        test_assert(part->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
@@ -807,6 +875,7 @@ static const char input_msg[] =
        test_assert(part->body_size.lines == 22);
        test_assert(part->body_size.physical_size == 871);
        test_assert(part->body_size.virtual_size == 871+22);
+       test_message_parser_assert_sizes(part, &body_size, &header_size);
 
        part = parts->children;
        test_assert(part->children_count == 5);
@@ -871,6 +940,7 @@ static const char input_msg[] =
        };
        struct istream *input;
        struct message_part *parts, *part;
+       struct message_size body_size, header_size;
        pool_t pool;
 
        test_begin("message parser mime part nested limit");
@@ -879,6 +949,9 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &parser_set, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+       test_message_parser_get_sizes(input, &body_size, &header_size, FALSE);
+
        part = parts;
        test_assert(part->children_count == 2);
        test_assert(part->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
@@ -888,6 +961,7 @@ static const char input_msg[] =
        test_assert(part->body_size.lines == 15);
        test_assert(part->body_size.physical_size == 148);
        test_assert(part->body_size.virtual_size == 148+15);
+       test_message_parser_assert_sizes(part, &body_size, &header_size);
 
        part = parts->children;
        test_assert(part->children_count == 0);
@@ -930,6 +1004,7 @@ static const char input_msg[] =
        };
        struct istream *input;
        struct message_part *parts, *part;
+       struct message_size body_size, header_size;
        pool_t pool;
 
        test_begin("message parser mime part nested limit rfc822");
@@ -938,6 +1013,9 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &parser_set, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+       test_message_parser_get_sizes(input, &body_size, &header_size, FALSE);
+
        part = parts;
        test_assert(part->children_count == 1);
        test_assert(part->flags == (MESSAGE_PART_FLAG_MESSAGE_RFC822 | MESSAGE_PART_FLAG_IS_MIME));
@@ -947,6 +1025,7 @@ static const char input_msg[] =
        test_assert(part->body_size.lines == 5);
        test_assert(part->body_size.physical_size == 58);
        test_assert(part->body_size.virtual_size == 58+5);
+       test_message_parser_assert_sizes(part, &body_size, &header_size);
 
        part = parts->children;
        test_assert(part->children_count == 0);
@@ -989,6 +1068,7 @@ static const char input_msg[] =
        };
        struct istream *input;
        struct message_part *parts, *part;
+       struct message_size body_size, header_size;
        pool_t pool;
 
        test_begin("message parser mime part limit");
@@ -997,6 +1077,9 @@ static const char input_msg[] =
 
        test_assert(message_parse_stream(pool, input, &parser_set, FALSE, &parts) < 0);
 
+       i_stream_seek(input, 0);
+       test_message_parser_get_sizes(input, &body_size, &header_size, FALSE);
+
        part = parts;
        test_assert(part->children_count == 3);
        test_assert(part->flags == (MESSAGE_PART_FLAG_MULTIPART | MESSAGE_PART_FLAG_IS_MIME));
@@ -1006,6 +1089,7 @@ static const char input_msg[] =
        test_assert(part->body_size.lines == 15);
        test_assert(part->body_size.physical_size == 148);
        test_assert(part->body_size.virtual_size == 148+15);
+       test_message_parser_assert_sizes(part, &body_size, &header_size);
 
        part = parts->children;
        test_assert(part->children_count == 2);
diff --git a/src/lib-mail/test-message-size.c b/src/lib-mail/test-message-size.c
new file mode 100644 (file)
index 0000000..4342c27
--- /dev/null
@@ -0,0 +1,159 @@
+/* Copyright (c) 2020 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "istream.h"
+#include "message-size.h"
+#include "test-common.h"
+
+static const char test_msg[] =
+"Return-Path: <test@example.org>\n"
+"Subject: Hello world\n"
+"From: Test User <test@example.org>\n"
+"To: Another User <test2@example.org>\n"
+"Message-Id: <1.2.3.4@example>\n"
+"Mime-Version: 1.0\n"
+"Date: Sun, 23 May 2007 04:58:08 +0300\n"
+"Content-Type: multipart/signed; micalg=pgp-sha1;\n"
+"      protocol=\"application/pgp-signature\";\n"
+"      boundary=\"=-GNQXLhuj24Pl1aCkk4/d\"\n"
+"\n"
+"--=-GNQXLhuj24Pl1aCkk4/d\n"
+"Content-Type: text/plain\n"
+"Content-Transfer-Encoding: quoted-printable\n"
+"\n"
+"There was a day=20\n"
+"a happy=20day\n"
+"\n"
+"--=-GNQXLhuj24Pl1aCkk4/d\n"
+"Content-Type: application/pgp-signature; name=signature.asc\n"
+"\n"
+"-----BEGIN PGP SIGNATURE-----\n"
+"Version: GnuPG v1.2.4 (GNU/Linux)\n"
+"\n"
+"invalid\n"
+"-----END PGP SIGNATURE-----\n"
+"\n"
+"--=-GNQXLhuj24Pl1aCkk4/d--\n"
+"\n"
+"\n";
+
+static const char test_msg_with_nuls[] =
+"Return-Path: <test@example.org>\n"
+"Subject: Hello world\n"
+"From: Test User <test@example.org>\n"
+"To: Another User <test2@example.org>\n"
+"Message-Id: <1.2.3.4@example>\n"
+"Mime-Version: 1.0\0\n"
+"Date: Sun, 23 May 2007 04:58:08 +0300\n"
+"Content-Type: multipart/signed; micalg=pgp-sha1;\n"
+"      protocol=\"application/pgp-signature\";\n"
+"      boundary=\"=-GNQXLhuj24Pl1aCkk4/d\"\n"
+"\n"
+"--=-GNQXLhuj24Pl1aCkk4/d\n"
+"\n"
+"Content-Type: text/plain\n"
+"Content-Transfer-Encoding: quoted-printable\n"
+"\n"
+"There was\0 a day=20\n"
+"a happy=20day\n"
+"\n"
+"--=-GNQXLhuj24Pl1aCkk4/d\n"
+"Content-Type: application/pgp-signature; name=signature.asc\n"
+"\n"
+"-----BEGIN PGP SIGNATURE-----\n"
+"Version: GnuPG v1.2.4 (GNU/Linux)\n"
+"\n"
+"inva\0lid\n"
+"-----END PGP SIGNATURE-----\n"
+"\n"
+"--=-GNQXLhuj24Pl1aCkk4/d--\n"
+"\n"
+"\n";
+
+struct test_case {
+       const char *test_name;
+       const char *message;
+       bool has_nuls;
+       unsigned int body_newlines;
+       unsigned int header_newlines;
+       unsigned int message_len;
+       unsigned int header_len;
+};
+static const struct test_case test_cases[] = {
+       {
+               .test_name = "message size",
+               .message = test_msg,
+               .has_nuls = FALSE,
+               .body_newlines = 19,
+               .header_newlines = 11,
+               .message_len = sizeof(test_msg)-1,
+               .header_len = 335,
+       },
+       {
+               .test_name = "message size with nuls",
+               .message = test_msg_with_nuls,
+               .has_nuls = TRUE,
+               .body_newlines = 20,
+               .header_newlines = 11,
+               .message_len = sizeof(test_msg_with_nuls)-1,
+               .header_len = 336,
+       },
+};
+
+static void test_message_size(void)
+{
+       struct istream *input;
+       struct message_size body_size, header_size;
+       bool has_nuls;
+       bool last_cr;
+       unsigned int i;
+
+       for (i = 0; i < N_ELEMENTS(test_cases); i++) {
+               test_begin(test_cases[i].test_name);
+               input = i_stream_create_from_data(test_cases[i].message,
+                                                 test_cases[i].message_len);
+
+               /* Read physical_size */
+               message_get_header_size(input, &header_size, &has_nuls);
+               test_assert_idx(has_nuls == test_cases[i].has_nuls, i);
+               test_assert_idx(input->v_offset == test_cases[i].header_len, i);
+               message_get_body_size(input, &body_size, &has_nuls);
+               test_assert_idx(has_nuls == test_cases[i].has_nuls, i);
+               test_assert_idx(input->v_offset  - body_size.physical_size ==
+                               test_cases[i].header_len, i);
+               test_assert_idx(body_size.physical_size + header_size.physical_size ==
+                               test_cases[i].message_len, i);
+
+               /* Test last_cr handling */
+               i_stream_seek(input, 0);
+               message_skip_virtual(input, 0, &last_cr);
+               test_assert_idx(!last_cr, i);
+               message_skip_virtual(input, header_size.virtual_size-1, &last_cr);
+               test_assert_idx(last_cr, i);
+               message_skip_virtual(input, 2, &last_cr);
+               test_assert_idx(!last_cr, i);
+
+               /* Skipped header size so read body again */
+               message_get_body_size(input, &body_size, &has_nuls);
+               test_assert_idx(has_nuls == test_cases[i].has_nuls, i);
+               test_assert_idx(input->v_offset  - body_size.physical_size ==
+                               test_cases[i].header_len, i);
+               test_assert_idx(body_size.physical_size + test_cases[i].body_newlines ==
+                               body_size.virtual_size, i);
+               test_assert_idx(body_size.virtual_size + header_size.virtual_size -
+                               test_cases[i].body_newlines - test_cases[i].header_newlines ==
+                               test_cases[i].message_len, i);
+
+               i_stream_unref(&input);
+               test_end();
+       }
+}
+
+int main(void)
+{
+       static void (*const test_functions[])(void) = {
+               test_message_size,
+               NULL
+       };
+       return test_run(test_functions);
+}