#define DST_SIZE 512
-#define NORMALIZE(src, expected) \
- char dst[sizeof(expected)]; \
+#define NORMALIZE(src) \
JSIdentifierCtxTest ident_ctx; \
JSNormalizer norm(ident_ctx, DEPTH, MAX_TEMPLATE_NESTNIG); \
- auto ret = norm.normalize(src, sizeof(src), dst, sizeof(dst)); \
+ auto ret = norm.normalize(src, sizeof(src)); \
const char* ptr = norm.get_src_next(); \
- int act_len = norm.get_dst_next() - dst;
+ auto result = norm.get_script(); \
+ char* dst = result.first; \
+ int act_len = result.second; \
#define VALIDATE(src, expected) \
CHECK(ret == JSTokenizer::SCRIPT_CONTINUE); \
CHECK((ptr - src) == sizeof(src)); \
CHECK(act_len == sizeof(expected) - 1); \
- CHECK(!memcmp(dst, expected, act_len));
+ CHECK(!memcmp(dst, expected, act_len)); \
+ delete[] dst;
#define VALIDATE_FAIL(src, expected, ret_code, ptr_offset) \
CHECK(ret == ret_code); \
CHECK((ptr - src) == ptr_offset); \
CHECK(act_len == sizeof(expected) - 1); \
- CHECK(!memcmp(dst, expected, act_len));
+ CHECK(!memcmp(dst, expected, act_len)); \
+ delete[] dst;
+
#define NORMALIZE_L(src, src_len, dst, dst_len, depth, ret, ptr, len) \
{ \
JSIdentifierCtxTest ident_ctx; \
JSNormalizer norm(ident_ctx, depth, MAX_TEMPLATE_NESTNIG); \
- ret = norm.normalize(src, src_len, dst, dst_len); \
+ ret = norm.normalize(src, src_len); \
ptr = norm.get_src_next(); \
- len = norm.get_dst_next() - dst; \
+ auto result = norm.get_script(); \
+ char* dptr = result.first; \
+ len = result.second; \
+ REQUIRE(len == dst_len); \
+ memcpy(dst, dptr, dst_len); \
+ delete[] dptr; \
}
#define DO(src, slen, dst, dlen) \
{ \
- auto ret = norm.normalize(src, slen, dst, dlen); \
+ auto ret = norm.normalize(src, slen); \
CHECK(ret == JSTokenizer::SCRIPT_CONTINUE); \
auto nsrc = norm.get_src_next(); \
- auto ndst = norm.get_dst_next(); \
+ auto result = norm.get_script(); \
+ char* ptr = result.first; \
+ int act_len = result.second; \
REQUIRE(nsrc - src == slen); \
- REQUIRE(ndst - dst == dlen); \
+ REQUIRE(act_len == dlen); \
+ memcpy(dst, ptr, dlen); \
+ delete[] ptr; \
}
#define TRY(src, slen, dst, dlen, rexp) \
{ \
- auto ret = norm.normalize(src, slen, dst, dlen); \
+ auto ret = norm.normalize(src, slen); \
CHECK(ret == rexp); \
- auto ndst = norm.get_dst_next(); \
- REQUIRE(ndst - dst == dlen); \
+ auto result = norm.get_script(); \
+ char* ptr = result.first; \
+ int act_len = result.second; \
+ REQUIRE(act_len == dlen); \
+ memcpy(dst, ptr, dlen); \
+ delete[] ptr; \
}
#define CLOSE() \
{ \
const char end[] = "</script>"; \
- char dst[DST_SIZE]; \
- auto ret = norm.normalize(end, sizeof(end) - 1, dst, sizeof(dst) - 1); \
+ auto ret = norm.normalize(end, sizeof(end) - 1); \
CHECK(ret == JSTokenizer::SCRIPT_ENDED); \
}
{
SECTION("test_case_0 - mixed identifiers and comments")
{
- NORMALIZE(clamav_buf0, clamav_expected0);
+ NORMALIZE(clamav_buf0);
VALIDATE(clamav_buf0, clamav_expected0);
}
SECTION("test_case_1 - escaped unicode in identifier")
{
- NORMALIZE(clamav_buf1, clamav_expected1);
+ NORMALIZE(clamav_buf1);
VALIDATE(clamav_buf1, clamav_expected1);
}
SECTION("test_case_2 - accumulated string assignment")
{
- NORMALIZE(clamav_buf2, clamav_expected2);
+ NORMALIZE(clamav_buf2);
VALIDATE(clamav_buf2, clamav_expected2);
}
SECTION("test_case_3 - percent-encoded string")
{
- NORMALIZE(clamav_buf3, clamav_expected3);
+ NORMALIZE(clamav_buf3);
VALIDATE(clamav_buf3, clamav_expected3);
}
SECTION("test_case_4 - percent-encoded string")
{
- NORMALIZE(clamav_buf4, clamav_expected4);
+ NORMALIZE(clamav_buf4);
VALIDATE(clamav_buf4, clamav_expected4);
}
SECTION("test_case_5 - obfuscated script")
{
- NORMALIZE(clamav_buf5, clamav_expected5);
+ NORMALIZE(clamav_buf5);
VALIDATE(clamav_buf5, clamav_expected5);
}
SECTION("test_case_6 - obfuscated script")
{
- NORMALIZE(clamav_buf6, clamav_expected6);
+ NORMALIZE(clamav_buf6);
VALIDATE(clamav_buf6, clamav_expected6);
}
SECTION("test_case_7 - single quotes string")
{
- NORMALIZE(clamav_buf7, clamav_expected7);
+ NORMALIZE(clamav_buf7);
VALIDATE(clamav_buf7, clamav_expected7);
}
SECTION("test_case_8 - double quotes string")
{
- NORMALIZE(clamav_buf8, clamav_expected8);
+ NORMALIZE(clamav_buf8);
VALIDATE(clamav_buf8, clamav_expected8);
}
SECTION("test_case_9 - obfuscated script")
{
- NORMALIZE(clamav_buf9, clamav_expected9);
+ NORMALIZE(clamav_buf9);
VALIDATE(clamav_buf9, clamav_expected9);
}
SECTION("test_case_10 - obfuscated script")
{
- NORMALIZE(clamav_buf10, clamav_expected10);
+ NORMALIZE(clamav_buf10);
VALIDATE(clamav_buf10, clamav_expected10);
}
SECTION("test_case_11 - integer literal")
{
- NORMALIZE(clamav_buf11, clamav_expected11);
+ NORMALIZE(clamav_buf11);
VALIDATE(clamav_buf11, clamav_expected11);
}
SECTION("test_case_12 - escaped unicode in string literal")
{
- NORMALIZE(clamav_buf12, clamav_expected12);
+ NORMALIZE(clamav_buf12);
VALIDATE(clamav_buf12, clamav_expected12);
}
// FIXIT-L this should be revisited
SECTION("test_case_13 - invalid escape sequence")
{
- NORMALIZE(clamav_buf13, clamav_expected13);
+ NORMALIZE(clamav_buf13);
VALIDATE(clamav_buf13, clamav_expected13);
}
SECTION("test_case_14 - EOF in the middle of string literal")
{
- NORMALIZE(clamav_buf14, clamav_expected14);
+ NORMALIZE(clamav_buf14);
// trailing \0 is included as a part of the string
// to utilize available macros we alter the read length
act_len -= 1;
{
SECTION("whitespaces and special characters")
{
- NORMALIZE(all_patterns_buf0, all_patterns_expected0);
+ NORMALIZE(all_patterns_buf0);
VALIDATE(all_patterns_buf0, all_patterns_expected0);
}
SECTION("comments")
{
- NORMALIZE(all_patterns_buf1, all_patterns_expected1);
+ NORMALIZE(all_patterns_buf1);
VALIDATE(all_patterns_buf1, all_patterns_expected1);
}
SECTION("directives")
const char expected1[] = "\"use strict\";var a=1;";
const char expected2[] = "var a=1 'use strict';";
- char dst0[sizeof(expected0)];
- char dst1[sizeof(expected1)];
- char dst2[sizeof(expected0)];
- char dst3[sizeof(expected1)];
- char dst4[sizeof(expected2)];
+ char dst0[sizeof(expected0) - 1];
+ char dst1[sizeof(expected1) - 1];
+ char dst2[sizeof(expected0) - 1];
+ char dst3[sizeof(expected1) - 1];
+ char dst4[sizeof(expected2) - 1];
int ret0, ret1, ret2, ret3, ret4;
const char *ptr0, *ptr1, *ptr2, *ptr3, *ptr4;
}
SECTION("punctuators")
{
- NORMALIZE(all_patterns_buf2, all_patterns_expected2);
+ NORMALIZE(all_patterns_buf2);
VALIDATE(all_patterns_buf2, all_patterns_expected2);
}
SECTION("keywords")
{
- NORMALIZE(all_patterns_buf3, all_patterns_expected3);
+ NORMALIZE(all_patterns_buf3);
VALIDATE(all_patterns_buf3, all_patterns_expected3);
}
SECTION("literals")
{
- NORMALIZE(all_patterns_buf4, all_patterns_expected4);
+ NORMALIZE(all_patterns_buf4);
VALIDATE(all_patterns_buf4, all_patterns_expected4);
}
SECTION("identifiers")
{
- NORMALIZE(all_patterns_buf5, all_patterns_expected5);
+ NORMALIZE(all_patterns_buf5);
VALIDATE(all_patterns_buf5, all_patterns_expected5);
}
SECTION("template literals")
{
- NORMALIZE(all_patterns_buf6, all_patterns_expected6);
+ NORMALIZE(all_patterns_buf6);
VALIDATE(all_patterns_buf6, all_patterns_expected6);
}
}
{
SECTION("variables")
{
- NORMALIZE(syntax_cases_buf0, syntax_cases_expected0);
+ NORMALIZE(syntax_cases_buf0);
VALIDATE(syntax_cases_buf0, syntax_cases_expected0);
}
SECTION("operators")
{
- NORMALIZE(syntax_cases_buf1, syntax_cases_expected1);
+ NORMALIZE(syntax_cases_buf1);
VALIDATE(syntax_cases_buf1, syntax_cases_expected1);
}
SECTION("arithmetic and logical operators")
{
- NORMALIZE(syntax_cases_buf2, syntax_cases_expected2);
+ NORMALIZE(syntax_cases_buf2);
VALIDATE(syntax_cases_buf2, syntax_cases_expected2);
}
SECTION("complex object")
{
- NORMALIZE(syntax_cases_buf3, syntax_cases_expected3);
+ NORMALIZE(syntax_cases_buf3);
VALIDATE(syntax_cases_buf3, syntax_cases_expected3);
}
SECTION("arrays")
{
- NORMALIZE(syntax_cases_buf4, syntax_cases_expected4);
+ NORMALIZE(syntax_cases_buf4);
VALIDATE(syntax_cases_buf4, syntax_cases_expected4);
}
SECTION("loops")
{
- NORMALIZE(syntax_cases_buf5, syntax_cases_expected5);
+ NORMALIZE(syntax_cases_buf5);
VALIDATE(syntax_cases_buf5, syntax_cases_expected5);
}
SECTION("if-else and switch statements")
{
- NORMALIZE(syntax_cases_buf6, syntax_cases_expected6);
+ NORMALIZE(syntax_cases_buf6);
VALIDATE(syntax_cases_buf6, syntax_cases_expected6);
}
SECTION("try-catch statements")
{
- NORMALIZE(syntax_cases_buf7, syntax_cases_expected7);
+ NORMALIZE(syntax_cases_buf7);
VALIDATE(syntax_cases_buf7, syntax_cases_expected7);
}
SECTION("functions and promises")
{
- NORMALIZE(syntax_cases_buf8, syntax_cases_expected8);
+ NORMALIZE(syntax_cases_buf8);
VALIDATE(syntax_cases_buf8, syntax_cases_expected8);
}
SECTION("regex-division ambiguity")
{
- NORMALIZE(syntax_cases_buf9, syntax_cases_expected9);
+ NORMALIZE(syntax_cases_buf9);
VALIDATE(syntax_cases_buf9, syntax_cases_expected9);
}
SECTION("regex on a new line")
{
- NORMALIZE(syntax_cases_buf10, syntax_cases_expected10);
+ NORMALIZE(syntax_cases_buf10);
VALIDATE(syntax_cases_buf10, syntax_cases_expected10);
}
SECTION("string and regex literals ambiguity with escaped sentinel chars")
{
- NORMALIZE(syntax_cases_buf11, syntax_cases_expected11);
+ NORMALIZE(syntax_cases_buf11);
VALIDATE(syntax_cases_buf11, syntax_cases_expected11);
}
SECTION("escaped LF and CR chars in literals")
{
- NORMALIZE(syntax_cases_buf12, syntax_cases_expected12);
+ NORMALIZE(syntax_cases_buf12);
VALIDATE(syntax_cases_buf12, syntax_cases_expected12);
}
SECTION("regex after keyword")
{
- NORMALIZE(syntax_cases_buf13, syntax_cases_expected13);
+ NORMALIZE(syntax_cases_buf13);
VALIDATE(syntax_cases_buf13, syntax_cases_expected13);
}
SECTION("white space between '+'<-->'++' and '-'<-->'--'")
{
- NORMALIZE(syntax_cases_buf14, syntax_cases_expected14);
+ NORMALIZE(syntax_cases_buf14);
VALIDATE(syntax_cases_buf14, syntax_cases_expected14);
}
SECTION("template literals")
{
- NORMALIZE(syntax_cases_buf22, syntax_cases_expected22);
+ NORMALIZE(syntax_cases_buf22);
VALIDATE(syntax_cases_buf22, syntax_cases_expected22);
}
}
{
SECTION("LS chars within literal")
{
- NORMALIZE(syntax_cases_buf15, syntax_cases_expected15);
+ NORMALIZE(syntax_cases_buf15);
VALIDATE_FAIL(syntax_cases_buf15, syntax_cases_expected15, JSTokenizer::BAD_TOKEN, 25);
}
SECTION("PS chars within literal")
{
- NORMALIZE(syntax_cases_buf21, syntax_cases_expected21);
+ NORMALIZE(syntax_cases_buf21);
VALIDATE_FAIL(syntax_cases_buf21, syntax_cases_expected21, JSTokenizer::BAD_TOKEN, 25);
}
SECTION("explicit LF within literal")
{
- NORMALIZE(syntax_cases_buf16, syntax_cases_expected16);
+ NORMALIZE(syntax_cases_buf16);
VALIDATE_FAIL(syntax_cases_buf16, syntax_cases_expected16, JSTokenizer::BAD_TOKEN, 23);
}
SECTION("explicit CR within literal")
{
- NORMALIZE(syntax_cases_buf17, syntax_cases_expected17);
+ NORMALIZE(syntax_cases_buf17);
VALIDATE_FAIL(syntax_cases_buf17, syntax_cases_expected17, JSTokenizer::BAD_TOKEN, 23);
}
SECTION("escaped LF-CR sequence within literal")
{
- NORMALIZE(syntax_cases_buf18, syntax_cases_expected18);
+ NORMALIZE(syntax_cases_buf18);
VALIDATE_FAIL(syntax_cases_buf18, syntax_cases_expected18, JSTokenizer::BAD_TOKEN, 25);
}
SECTION("escaped LF within regex literal")
{
- NORMALIZE(syntax_cases_buf19, syntax_cases_expected19);
+ NORMALIZE(syntax_cases_buf19);
VALIDATE_FAIL(syntax_cases_buf19, syntax_cases_expected19, JSTokenizer::BAD_TOKEN, 23);
}
SECTION("escaped CR-LF within regex literal")
{
- NORMALIZE(syntax_cases_buf20, syntax_cases_expected20);
+ NORMALIZE(syntax_cases_buf20);
VALIDATE_FAIL(syntax_cases_buf20, syntax_cases_expected20, JSTokenizer::BAD_TOKEN, 23);
}
}
{
SECTION("exceeding template literal limit")
{
- NORMALIZE(syntax_cases_buf23, syntax_cases_expected23);
+ NORMALIZE(syntax_cases_buf23);
VALIDATE_FAIL(syntax_cases_buf23, syntax_cases_expected23,
JSTokenizer::TEMPLATE_NESTING_OVERFLOW, 15);
}
"var c = 3 ;\n";
const int ptr_offset = 33;
const char expected[] = "var a=1;var b=2;";
- char dst[sizeof(expected)];
+ char dst[sizeof(expected) - 1];
int act_len;
const char* ptr;
int ret;
const char src[] = "var abc = 123;\n\r";
const char src2[] = "var foo = 321;\n\r";
const char expected[] = "var abc";
- char dst[sizeof(src)];
- int act_len;
const char* ptr;
int ret;
JSIdentifierCtxTest ident_ctx;
JSNormalizer norm(ident_ctx, 7, MAX_TEMPLATE_NESTNIG);
- ret = norm.normalize(src, sizeof(src), dst, sizeof(dst));
+ ret = norm.normalize(src, sizeof(src));
ptr = norm.get_src_next();
- act_len = norm.get_dst_next() - dst;
+ auto res1 = norm.get_script();
+ char* dst1 = res1.first;
+ int act_len1 = res1.second;
CHECK(ret == JSTokenizer::EOS);
CHECK(ptr == src + 7);
- CHECK(act_len == sizeof(expected) - 1);
- CHECK(!memcmp(dst, expected, act_len));
+ CHECK(act_len1 == sizeof(expected) - 1);
+ CHECK(!memcmp(dst1, expected, act_len1));
+ delete[] dst1;
- ret = norm.normalize(src2, sizeof(src2), dst, sizeof(dst));
+ ret = norm.normalize(src2, sizeof(src2));
ptr = norm.get_src_next();
- act_len = norm.get_dst_next() - dst;
+ auto res2 = norm.get_script();
+ char* dst2 = res2.first;
+ int act_len2 = res2.second;
CHECK(ret == JSTokenizer::EOS);
CHECK(ptr == src2 + sizeof(src2));
- CHECK(act_len == 0);
- }
- SECTION("dst size is less then src size")
- {
- const char src[] = "var abc = 123;\n\r";
- const char expected[sizeof(src)] = "var abc";
- char dst[7];
- int act_len;
- const char* ptr;
- int ret;
-
- NORMALIZE_L(src, sizeof(src), dst, sizeof(dst), DEPTH, ret, ptr, act_len);
-
- CHECK(ret == JSTokenizer::SCRIPT_CONTINUE);
- CHECK(ptr == src + sizeof(src));
- CHECK(act_len == 7); // size of normalized src
- CHECK(!memcmp(dst, expected, sizeof(dst)));
+ CHECK(act_len2 == 0);
+ delete[] dst2;
}
}
{
SECTION("explicit open tag - simple")
{
- NORMALIZE(unexpected_tag_buf0, unexpected_tag_expected0);
+ NORMALIZE(unexpected_tag_buf0);
VALIDATE_FAIL(unexpected_tag_buf0, unexpected_tag_expected0, JSTokenizer::OPENING_TAG, 18);
}
SECTION("explicit open tag - complex")
{
- NORMALIZE(unexpected_tag_buf1, unexpected_tag_expected1);
+ NORMALIZE(unexpected_tag_buf1);
VALIDATE_FAIL(unexpected_tag_buf1, unexpected_tag_expected1, JSTokenizer::OPENING_TAG, 18);
}
SECTION("open tag within literal - start")
{
- NORMALIZE(unexpected_tag_buf2, unexpected_tag_expected2);
+ NORMALIZE(unexpected_tag_buf2);
VALIDATE_FAIL(unexpected_tag_buf2, unexpected_tag_expected2, JSTokenizer::OPENING_TAG, 29);
}
SECTION("open tag within literal - mid")
{
- NORMALIZE(unexpected_tag_buf3, unexpected_tag_expected3);
+ NORMALIZE(unexpected_tag_buf3);
VALIDATE_FAIL(unexpected_tag_buf3, unexpected_tag_expected3, JSTokenizer::OPENING_TAG, 39);
}
SECTION("open tag within literal - end")
{
- NORMALIZE(unexpected_tag_buf4, unexpected_tag_expected4);
+ NORMALIZE(unexpected_tag_buf4);
VALIDATE_FAIL(unexpected_tag_buf4, unexpected_tag_expected4, JSTokenizer::OPENING_TAG, 39);
}
SECTION("close tag within literal - start")
{
- NORMALIZE(unexpected_tag_buf5, unexpected_tag_expected5);
+ NORMALIZE(unexpected_tag_buf5);
VALIDATE_FAIL(unexpected_tag_buf5, unexpected_tag_expected5, JSTokenizer::CLOSING_TAG, 31);
}
SECTION("close tag within literal - mid")
{
- NORMALIZE(unexpected_tag_buf6, unexpected_tag_expected6);
+ NORMALIZE(unexpected_tag_buf6);
VALIDATE_FAIL(unexpected_tag_buf6, unexpected_tag_expected6, JSTokenizer::CLOSING_TAG, 41);
}
SECTION("close tag within literal - end")
{
- NORMALIZE(unexpected_tag_buf7, unexpected_tag_expected7);
+ NORMALIZE(unexpected_tag_buf7);
VALIDATE_FAIL(unexpected_tag_buf7, unexpected_tag_expected7, JSTokenizer::CLOSING_TAG, 41);
}
SECTION("open tag within literal - escaped")
{
- NORMALIZE(unexpected_tag_buf8, unexpected_tag_expected8);
+ NORMALIZE(unexpected_tag_buf8);
VALIDATE_FAIL(unexpected_tag_buf8, unexpected_tag_expected8, JSTokenizer::OPENING_TAG, 40);
}
SECTION("close tag within literal - escaped")
{
- NORMALIZE(unexpected_tag_buf9, unexpected_tag_expected9);
+ NORMALIZE(unexpected_tag_buf9);
VALIDATE(unexpected_tag_buf9, unexpected_tag_expected9);
}
SECTION("open tag within single-line comment - start")
{
- NORMALIZE(unexpected_tag_buf10, unexpected_tag_expected10);
+ NORMALIZE(unexpected_tag_buf10);
VALIDATE_FAIL(unexpected_tag_buf10, unexpected_tag_expected10, JSTokenizer::OPENING_TAG, 20);
}
SECTION("open tag within single-line comment - mid")
{
- NORMALIZE(unexpected_tag_buf11, unexpected_tag_expected11);
+ NORMALIZE(unexpected_tag_buf11);
VALIDATE_FAIL(unexpected_tag_buf11, unexpected_tag_expected11, JSTokenizer::OPENING_TAG, 30);
}
SECTION("open tag within single-line comment - end")
{
- NORMALIZE(unexpected_tag_buf12, unexpected_tag_expected12);
+ NORMALIZE(unexpected_tag_buf12);
VALIDATE_FAIL(unexpected_tag_buf12, unexpected_tag_expected12, JSTokenizer::OPENING_TAG, 30);
}
SECTION("open tag within multi-line comment - start")
{
- NORMALIZE(unexpected_tag_buf13, unexpected_tag_expected13);
+ NORMALIZE(unexpected_tag_buf13);
VALIDATE_FAIL(unexpected_tag_buf13, unexpected_tag_expected13, JSTokenizer::OPENING_TAG, 20);
}
SECTION("open tag within multi-line comment - mid")
{
- NORMALIZE(unexpected_tag_buf14, unexpected_tag_expected14);
+ NORMALIZE(unexpected_tag_buf14);
VALIDATE_FAIL(unexpected_tag_buf14, unexpected_tag_expected14, JSTokenizer::OPENING_TAG, 30);
}
SECTION("open tag within multi-line comment - end")
{
- NORMALIZE(unexpected_tag_buf15, unexpected_tag_expected15);
+ NORMALIZE(unexpected_tag_buf15);
VALIDATE_FAIL(unexpected_tag_buf15, unexpected_tag_expected15, JSTokenizer::OPENING_TAG, 30);
}
SECTION("close tag within single-line comment - start")
{
- NORMALIZE(unexpected_tag_buf16, unexpected_tag_expected16);
+ NORMALIZE(unexpected_tag_buf16);
VALIDATE_FAIL(unexpected_tag_buf16, unexpected_tag_expected16, JSTokenizer::CLOSING_TAG, 22);
}
SECTION("close tag within single-line comment - mid")
{
- NORMALIZE(unexpected_tag_buf17, unexpected_tag_expected17);
+ NORMALIZE(unexpected_tag_buf17);
VALIDATE_FAIL(unexpected_tag_buf17, unexpected_tag_expected17, JSTokenizer::CLOSING_TAG, 34);
}
SECTION("close tag within single-line comment - end")
{
- NORMALIZE(unexpected_tag_buf18, unexpected_tag_expected18);
+ NORMALIZE(unexpected_tag_buf18);
VALIDATE_FAIL(unexpected_tag_buf18, unexpected_tag_expected18, JSTokenizer::CLOSING_TAG, 32);
}
SECTION("close tag within multi-line comment - start")
{
- NORMALIZE(unexpected_tag_buf19, unexpected_tag_expected19);
+ NORMALIZE(unexpected_tag_buf19);
VALIDATE_FAIL(unexpected_tag_buf19, unexpected_tag_expected19, JSTokenizer::CLOSING_TAG, 22);
}
SECTION("close tag within multi-line comment - mid")
{
- NORMALIZE(unexpected_tag_buf20, unexpected_tag_expected20);
+ NORMALIZE(unexpected_tag_buf20);
VALIDATE_FAIL(unexpected_tag_buf20, unexpected_tag_expected20, JSTokenizer::CLOSING_TAG, 32);
}
SECTION("close tag within multi-line comment - end")
{
- NORMALIZE(unexpected_tag_buf21, unexpected_tag_expected21);
+ NORMALIZE(unexpected_tag_buf21);
VALIDATE_FAIL(unexpected_tag_buf21, unexpected_tag_expected21, JSTokenizer::CLOSING_TAG, 32);
}
SECTION("multiple patterns - not matched")
{
- NORMALIZE(unexpected_tag_buf22, unexpected_tag_expected22);
+ NORMALIZE(unexpected_tag_buf22);
VALIDATE(unexpected_tag_buf22, unexpected_tag_expected22);
}
SECTION("multiple patterns - matched")
{
- NORMALIZE(unexpected_tag_buf23, unexpected_tag_expected23);
+ NORMALIZE(unexpected_tag_buf23);
VALIDATE_FAIL(unexpected_tag_buf23, unexpected_tag_expected23, JSTokenizer::OPENING_TAG, 65);
}
SECTION("mixed lower and upper case")
{
- NORMALIZE(unexpected_tag_buf24, unexpected_tag_expected24);
+ NORMALIZE(unexpected_tag_buf24);
VALIDATE_FAIL(unexpected_tag_buf24, unexpected_tag_expected24, JSTokenizer::OPENING_TAG, 39);
}
}
};
BENCHMARK("whitespaces - 65535 bytes")
{
- return normalizer.normalize(src_ws, src_ws_len, dst, DEPTH);
+ normalizer.rewind_output();
+ return normalizer.normalize(src_ws, src_ws_len);
};
BENCHMARK("block comment - 65535 bytes")
{
- return normalizer.normalize(src_bcomm, src_bcomm_len, dst, DEPTH);
+ normalizer.rewind_output();
+ return normalizer.normalize(src_bcomm, src_bcomm_len);
};
BENCHMARK("double quotes string - 65535 bytes")
{
- return normalizer.normalize(src_dqstr, src_dqstr_len, dst, DEPTH);
+ normalizer.rewind_output();
+ return normalizer.normalize(src_dqstr, src_dqstr_len);
};
constexpr size_t depth_8k = 8192;
};
BENCHMARK("whitespaces - 8192 bytes")
{
- return normalizer.normalize(src_ws_8k, src_ws_len_8k, dst, DEPTH);
+ normalizer.rewind_output();
+ return normalizer.normalize(src_ws_8k, src_ws_len_8k);
};
BENCHMARK("block comment - 8192 bytes")
{
- return normalizer.normalize(src_bcomm_8k, src_bcomm_len_8k, dst, DEPTH);
+ normalizer.rewind_output();
+ return normalizer.normalize(src_bcomm_8k, src_bcomm_len_8k);
};
BENCHMARK("double quotes string - 8192 bytes")
{
- return normalizer.normalize(src_dqstr_8k, src_dqstr_len_8k, dst, DEPTH);
+ normalizer.rewind_output();
+ return normalizer.normalize(src_dqstr_8k, src_dqstr_len_8k);
};
}
const char* src = input.c_str();
size_t src_len = input.size();
- char dst[DEPTH];
-
JSIdentifierCtxTest ident_ctx_mock;
JSNormalizer normalizer_wo_ident(ident_ctx_mock, UNLIM_DEPTH, MAX_TEMPLATE_NESTNIG);
BENCHMARK("without substitution")
{
- return normalizer_wo_ident.normalize(src, src_len, dst, DEPTH);
+ normalizer_wo_ident.rewind_output();
+ return normalizer_wo_ident.normalize(src, src_len);
};
JSIdentifierCtx ident_ctx(DEPTH);
BENCHMARK("with substitution")
{
- return normalizer_w_ident.normalize(src, src_len, dst, DEPTH);
+ normalizer_w_ident.rewind_output();
+ return normalizer_w_ident.normalize(src, src_len);
};
}
#endif // BENCHMARK_TEST
-
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2021-2021 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "catch/catch.hpp"
+
+#include <cstring>
+#include <iostream>
+#include <vector>
+
+#include "utils/streambuf.h"
+
+using namespace snort;
+using namespace std;
+
+#define ACT_SIZE 1024
+#define EXP_SIZE 4096
+
+#define EXP_AVAIL1(b, exp, len, off) \
+ { \
+ auto avail = (b).in_avail(); \
+ CHECK(avail == (len) - (off)); \
+ \
+ char act[ACT_SIZE]; \
+ auto n = (b).sgetn(act, (len)); \
+ REQUIRE(n == (len) - (off)); \
+ CHECK(!memcmp((exp) + (off), act, n)); \
+ }
+
+#define EXP_AVAIL2(b, exp, len, off, len_1c) \
+ { \
+ auto avail = (b).in_avail(); \
+ if ((off) < (len_1c)) \
+ CHECK(avail == (len_1c) - (off)); \
+ else \
+ CHECK(avail == (len) - (off)); \
+ \
+ char act[ACT_SIZE]; \
+ auto n = (b).sgetn(act, (len)); \
+ REQUIRE(n == (len) - (off)); \
+ CHECK(!memcmp((exp) + (off), act, n)); \
+ }
+
+#define EXP_AVAILn(b, exp, len, off) \
+ { \
+ char act[ACT_SIZE]; \
+ auto n = (b).sgetn(act, (len)); \
+ REQUIRE(n == (len) - (off)); \
+ CHECK(!memcmp((exp) + (off), act, n)); \
+ }
+
+#define EXP_RES(b, exp, exp_len, exp_mem_size) \
+ { \
+ streamsize act_len; \
+ char* act = (b).release_data(act_len); \
+ \
+ CHECK((exp_mem_size) == act_len); \
+ REQUIRE((exp_len) <= act_len); \
+ CHECK(!memcmp((exp), act, (exp_len))); \
+ delete[] act; \
+ }
+
+#define EXP_IN(s, exp, act, len) \
+ { \
+ CHECK(true == (s).good()); \
+ REQUIRE((len) == (s).tellg()); \
+ CHECK(!memcmp((exp), (act), (len))); \
+ }
+
+#define EOF_IN(s, exp, act, len) \
+ { \
+ CHECK(true == (s).eof()); \
+ (s).clear(); \
+ REQUIRE((len) == (s).tellg()); \
+ CHECK(!memcmp((exp), (act), (len))); \
+ }
+
+#define EXP_OUT(s, exp, exp_len) \
+ { \
+ CHECK(false == (s).fail()); \
+ CHECK(false == (s).bad()); \
+ (s).clear(); \
+ CHECK((exp_len) == (s).tellp()); \
+ \
+ ostreambuf_infl* b = reinterpret_cast<ostreambuf_infl*>((s).rdbuf()); \
+ streamsize act_len; \
+ char* act = b->release_data(act_len); \
+ \
+ REQUIRE((exp_len) == act_len); \
+ CHECK(!memcmp((exp), act, (exp_len))); \
+ delete[] act; \
+ }
+
+#define EOF_OUT(s, exp, exp_len) \
+ { \
+ CHECK(true == (s).fail()); \
+ CHECK(true == (s).bad()); \
+ (s).clear(); \
+ CHECK((exp_len) == (s).tellp()); \
+ \
+ ostreambuf_infl* b = reinterpret_cast<ostreambuf_infl*>((s).rdbuf()); \
+ streamsize act_len; \
+ char* act = b->release_data(act_len); \
+ \
+ REQUIRE((exp_len) == act_len); \
+ CHECK(!memcmp((exp), act, (exp_len))); \
+ delete[] act; \
+ }
+
+TEST_CASE("input buffer - basic one source", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ char dat[] = "Early bird gets a corn.";
+
+ SECTION("no data")
+ {
+ istreambuf_glue b;
+
+ int avail_1 = b.in_avail();
+ int c = b.sgetc();
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c == EOF);
+ CHECK(avail_1 == -1);
+ CHECK(avail_2 == -1);
+ CHECK(off_b == -1);
+ CHECK(off_c == -1);
+ CHECK(off_e == -1);
+ }
+
+ SECTION("get char")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat, len);
+
+ int avail_1 = b.in_avail();
+ int c = b.sgetc();
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c == 'E');
+ CHECK(avail_1 == len);
+ CHECK(avail_2 == len);
+ CHECK(off_b == 0);
+ CHECK(off_c == 0);
+ CHECK(off_e == len);
+ }
+
+ SECTION("get char and bump")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat, len);
+
+ int avail_1 = b.in_avail();
+ int c = b.sbumpc();
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c == 'E');
+ CHECK(avail_1 == len);
+ CHECK(avail_2 == len - 1);
+ CHECK(off_b == 0);
+ CHECK(off_c == 1);
+ CHECK(off_e == len);
+ }
+
+ SECTION("advance and get char")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat, len);
+
+ int avail_1 = b.in_avail();
+ int c = b.snextc();
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c == 'a');
+ CHECK(avail_1 == len);
+ CHECK(avail_2 == len - 1);
+ CHECK(off_b == 0);
+ CHECK(off_c == 1);
+ CHECK(off_e == len);
+ }
+
+ SECTION("get chars")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat, len);
+
+ int avail_1 = b.in_avail();
+ int nread_1 = b.sgetn(act, 10);
+ int avail_2 = b.in_avail();
+ int nread_2 = b.sgetn(act + 10, 10);
+ int avail_3 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(nread_1 == 10);
+ CHECK(nread_2 == 10);
+ CHECK(avail_1 == len);
+ CHECK(avail_2 == len - 10);
+ CHECK(avail_3 == len - 20);
+ CHECK(off_b == 0);
+ CHECK(off_c == 20);
+ CHECK(off_e == len);
+ CHECK(!memcmp(exp, act, 20));
+ }
+
+ SECTION("get chars EOF")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat, len);
+
+ int avail_1 = b.in_avail();
+ int nread_1 = b.sgetn(act, 10);
+ int avail_2 = b.in_avail();
+ int nread_2 = b.sgetn(act + 10, 10);
+ int avail_3 = b.in_avail();
+ int nread_3 = b.sgetn(act + 20, 10);
+ int avail_4 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(nread_1 == 10);
+ CHECK(nread_2 == 10);
+ CHECK(nread_3 == 3);
+ CHECK(avail_1 == len);
+ CHECK(avail_2 == len - 10);
+ CHECK(avail_3 == len - 20);
+ CHECK(avail_4 == 0);
+ CHECK(off_b == 0);
+ CHECK(off_c == 23);
+ CHECK(off_e == len);
+ CHECK(!memcmp(exp, act, len));
+ }
+
+ SECTION("put char back")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat, len);
+
+ int off_o = b.pubseekoff(5, ios_base::beg, ios_base::in);
+ int avail_1 = b.in_avail();
+ int c = b.sungetc();
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c == 'y');
+ CHECK(avail_1 == len - 5);
+ CHECK(avail_2 == len - 4);
+ CHECK(off_o == 5);
+ CHECK(off_b == 0);
+ CHECK(off_c == 4);
+ CHECK(off_e == len);
+ }
+
+ SECTION("put another char back")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat, len);
+
+ int off_o = b.pubseekoff(5, ios_base::beg, ios_base::in);
+ int avail_1 = b.in_avail();
+ int c1 = b.sputbackc(' ');
+ int c2 = b.sputbackc('y');
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c1 == -1);
+ CHECK(c2 == 'y');
+ CHECK(avail_1 == len - 5);
+ CHECK(avail_2 == len - 4);
+ CHECK(off_o == 5);
+ CHECK(off_b == 0);
+ CHECK(off_c == 4);
+ CHECK(off_e == len);
+ }
+}
+
+TEST_CASE("input buffer - basic two sources", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ char dat1[] = "Early bird";
+ char dat2[] = " gets a corn.";
+ const int dat1_len = strlen(dat1);
+ const int dat2_len = strlen(dat2);
+
+ SECTION("get char")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ int avail_1 = b.in_avail();
+ int c = b.sgetc();
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c == 'E');
+ CHECK(avail_1 == dat1_len);
+ CHECK(avail_2 == dat1_len);
+ CHECK(off_b == 0);
+ CHECK(off_c == 0);
+ CHECK(off_e == len);
+ }
+
+ SECTION("get char and bump")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ int avail_1 = b.in_avail();
+ int c = b.sbumpc();
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c == 'E');
+ CHECK(avail_1 == dat1_len);
+ CHECK(avail_2 == dat1_len - 1);
+ CHECK(off_b == 0);
+ CHECK(off_c == 1);
+ CHECK(off_e == len);
+ }
+
+ SECTION("advance and get char")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ int avail_1 = b.in_avail();
+ int c = b.snextc();
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c == 'a');
+ CHECK(avail_1 == dat1_len);
+ CHECK(avail_2 == dat1_len - 1);
+ CHECK(off_b == 0);
+ CHECK(off_c == 1);
+ CHECK(off_e == len);
+ }
+
+ SECTION("get chars")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ int avail_1 = b.in_avail();
+ int nread_1 = b.sgetn(act, 10);
+ int avail_2 = b.in_avail();
+ int nread_2 = b.sgetn(act + 10, 10);
+ int avail_3 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(nread_1 == 10);
+ CHECK(nread_2 == 10);
+ CHECK(avail_1 == dat1_len);
+ CHECK(avail_2 == len - 10);
+ CHECK(avail_3 == len - 20);
+ CHECK(off_b == 0);
+ CHECK(off_c == 20);
+ CHECK(off_e == len);
+ CHECK(!memcmp(exp, act, 20));
+ }
+
+ SECTION("get chars EOF")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ int avail_1 = b.in_avail();
+ int nread_1 = b.sgetn(act, 10);
+ int avail_2 = b.in_avail();
+ int nread_2 = b.sgetn(act + 10, 10);
+ int avail_3 = b.in_avail();
+ int nread_3 = b.sgetn(act + 20, 10);
+ int avail_4 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(nread_1 == 10);
+ CHECK(nread_2 == 10);
+ CHECK(nread_3 == 3);
+ CHECK(avail_1 == dat1_len);
+ CHECK(avail_2 == len - 10);
+ CHECK(avail_3 == len - 20);
+ CHECK(avail_4 == 0);
+ CHECK(off_b == 0);
+ CHECK(off_c == 23);
+ CHECK(off_e == len);
+ CHECK(!memcmp(exp, act, len));
+ }
+
+ SECTION("put char back")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ int off_o = b.pubseekoff(5, ios_base::beg, ios_base::in);
+ int avail_1 = b.in_avail();
+ int c = b.sungetc();
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c == 'y');
+ CHECK(avail_1 == dat1_len - 5);
+ CHECK(avail_2 == dat1_len - 4);
+ CHECK(off_o == 5);
+ CHECK(off_b == 0);
+ CHECK(off_c == 4);
+ CHECK(off_e == len);
+ }
+
+ SECTION("put another char back")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ int off_o = b.pubseekoff(5, ios_base::beg, ios_base::in);
+ int avail_1 = b.in_avail();
+ int c1 = b.sputbackc(' ');
+ int c2 = b.sputbackc('y');
+ int avail_2 = b.in_avail();
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(c1 == -1);
+ CHECK(c2 == 'y');
+ CHECK(avail_1 == dat1_len - 5);
+ CHECK(avail_2 == dat1_len - 4);
+ CHECK(off_o == 5);
+ CHECK(off_b == 0);
+ CHECK(off_c == 4);
+ CHECK(off_e == len);
+ }
+}
+
+TEST_CASE("input buffer - buffer management", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ char dat[] = "Early bird gets a corn.";
+ char dat1[] = "Early ";
+ char dat2[] = "bird ";
+ char dat3[] = "gets ";
+ char dat4[] = "a corn.";
+ const int dat1_len = strlen(dat1);
+ const int dat2_len = strlen(dat2);
+ const int dat3_len = strlen(dat3);
+ const int dat4_len = strlen(dat4);
+
+ SECTION("sync")
+ {
+ istreambuf_glue b1, b2;
+
+ b1.pubsetbuf(dat, len);
+ b2.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ int r1 = b1.pubsync();
+ int r2 = b2.pubsync();
+
+ CHECK(r1 == -1);
+ CHECK(r2 == -1);
+ }
+
+ SECTION("chain of buffers")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(nullptr, 0);
+
+ b.pubsetbuf(dat1, dat1_len);
+ EXP_AVAILn(b, exp, dat1_len, 0);
+ b.pubsetbuf(dat2, dat2_len);
+ EXP_AVAILn(b, exp + dat1_len, dat2_len, 0);
+
+ b.pubsetbuf(nullptr, 0);
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+ EXP_AVAILn(b, exp, dat1_len + dat2_len, 0);
+ b.pubsetbuf(dat3, dat3_len)->pubsetbuf(dat4, dat4_len);
+ EXP_AVAILn(b, exp + dat1_len + dat2_len, dat3_len + dat4_len, 0);
+
+ b.pubsetbuf(nullptr, 0);
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len)
+ ->pubsetbuf(dat3, dat3_len)->pubsetbuf(dat4, dat4_len);
+ EXP_AVAILn(b, exp, len, 0);
+ }
+}
+
+TEST_CASE("input buffer - offset one source", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ const int len1d3 = strlen(exp) * 1 / 3;
+ const int len2d3 = len - len1d3;
+ char dat[] = "Early bird gets a corn.";
+
+ SECTION("no data")
+ {
+ istreambuf_glue b;
+
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+
+ CHECK(off_b == -1);
+ CHECK(off_c == -1);
+ CHECK(off_e == -1);
+ }
+
+ SECTION("wrong argument")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat, len);
+
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::out);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::out);
+ int off_a = b.pubseekoff(0, static_cast<std::ios_base::seekdir>(0x5a5a), ios_base::in);
+
+ CHECK(off_b == -1);
+ CHECK(off_c == -1);
+ CHECK(off_e == -1);
+ CHECK(off_a == -1);
+ }
+
+ SECTION("begin")
+ {
+ istreambuf_glue b;
+ int off;
+
+ b.pubsetbuf(dat, len);
+
+ off = b.pubseekoff(0 - len - len, ios_base::beg, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 + len + len, ios_base::beg, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 - 1, ios_base::beg, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 + 1, ios_base::beg, ios_base::in);
+ CHECK(off == 1);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 + len1d3, ios_base::beg, ios_base::in);
+ CHECK(off == len1d3);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 + len2d3, ios_base::beg, ios_base::in);
+ CHECK(off == len2d3);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 + len - 1, ios_base::beg, ios_base::in);
+ CHECK(off == len - 1);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 + len, ios_base::beg, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+ }
+
+ SECTION("end")
+ {
+ istreambuf_glue b;
+ int off;
+
+ b.pubsetbuf(dat, len);
+
+ off = b.pubseekoff(0 - len - len, ios_base::end, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 + len + len, ios_base::end, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0, ios_base::end, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 - 1, ios_base::end, ios_base::in);
+ CHECK(off == len - 1);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 + 1, ios_base::end, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 - len1d3, ios_base::end, ios_base::in);
+ CHECK(off == len2d3);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 - len2d3, ios_base::end, ios_base::in);
+ CHECK(off == len1d3);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 - len + 1, ios_base::end, ios_base::in);
+ CHECK(off == 1);
+ EXP_AVAIL1(b, exp, len, off);
+
+ off = b.pubseekoff(0 - len, ios_base::end, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL1(b, exp, len, off);
+ }
+
+ SECTION("current 1/3")
+ {
+ istreambuf_glue b;
+ int off;
+
+ b.pubsetbuf(dat, len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 - len - len, ios_base::cur, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len + len, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ CHECK(off == len1d3);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 - 1, ios_base::cur, ios_base::in);
+ CHECK(off == len1d3 - 1);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + 1, ios_base::cur, ios_base::in);
+ CHECK(off == len1d3 + 1);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len1d3, ios_base::cur, ios_base::in);
+ CHECK(off == len1d3 + len1d3);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len2d3, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+ }
+
+ SECTION("current 2/3")
+ {
+ istreambuf_glue b;
+ int off;
+
+ b.pubsetbuf(dat, len);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 - len - len, ios_base::cur, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len + len, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ CHECK(off == len2d3);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 - 1, ios_base::cur, ios_base::in);
+ CHECK(off == len2d3 - 1);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + 1, ios_base::cur, ios_base::in);
+ CHECK(off == len2d3 + 1);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len1d3, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len2d3, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL1(b, exp, len, off);
+ }
+}
+
+TEST_CASE("input buffer - offset two sources", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ const int len1d3 = strlen(exp) * 1 / 3;
+ const int len2d3 = len - len1d3;
+ char dat1[] = "Early bird";
+ char dat2[] = " gets a corn.";
+ const int dat1_len = strlen(dat1);
+ const int dat2_len = strlen(dat2);
+
+ SECTION("wrong buffer")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::out);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::out);
+
+ CHECK(off_b == -1);
+ CHECK(off_c == -1);
+ CHECK(off_e == -1);
+ }
+
+ SECTION("begin")
+ {
+ istreambuf_glue b;
+ int off;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ off = b.pubseekoff(0 - len - len, ios_base::beg, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 + len + len, ios_base::beg, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 - 1, ios_base::beg, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 + 1, ios_base::beg, ios_base::in);
+ CHECK(off == 1);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 + len1d3, ios_base::beg, ios_base::in);
+ CHECK(off == len1d3);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 + len2d3, ios_base::beg, ios_base::in);
+ CHECK(off == len2d3);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 + len - 1, ios_base::beg, ios_base::in);
+ CHECK(off == len - 1);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 + len, ios_base::beg, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+ }
+
+ SECTION("end")
+ {
+ istreambuf_glue b;
+ int off;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ off = b.pubseekoff(0 - len - len, ios_base::end, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 + len + len, ios_base::end, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0, ios_base::end, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 - 1, ios_base::end, ios_base::in);
+ CHECK(off == len - 1);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 + 1, ios_base::end, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 - len1d3, ios_base::end, ios_base::in);
+ CHECK(off == len2d3);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 - len2d3, ios_base::end, ios_base::in);
+ CHECK(off == len1d3);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 - len + 1, ios_base::end, ios_base::in);
+ CHECK(off == 1);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ off = b.pubseekoff(0 - len, ios_base::end, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+ }
+
+ SECTION("current 1/3")
+ {
+ istreambuf_glue b;
+ int off;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 - len - len, ios_base::cur, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len + len, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ CHECK(off == len1d3);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 - 1, ios_base::cur, ios_base::in);
+ CHECK(off == len1d3 - 1);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + 1, ios_base::cur, ios_base::in);
+ CHECK(off == len1d3 + 1);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len1d3, ios_base::cur, ios_base::in);
+ CHECK(off == len1d3 + len1d3);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len2d3, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+ }
+
+ SECTION("current 2/3")
+ {
+ istreambuf_glue b;
+ int off;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 - len - len, ios_base::cur, ios_base::in);
+ CHECK(off == 0);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len + len, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ CHECK(off == len2d3);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 - 1, ios_base::cur, ios_base::in);
+ CHECK(off == len2d3 - 1);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + 1, ios_base::cur, ios_base::in);
+ CHECK(off == len2d3 + 1);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len1d3, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len2d3, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+
+ b.pubseekoff(len2d3, ios_base::beg, ios_base::in);
+ off = b.pubseekoff(0 + len, ios_base::cur, ios_base::in);
+ CHECK(off == len);
+ EXP_AVAIL2(b, exp, len, off, dat1_len);
+ }
+}
+
+TEST_CASE("input buffer - positioning one source", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ const int len1d3 = strlen(exp) * 1 / 3;
+ const int len2d3 = len - len1d3;
+ char dat[] = "Early bird gets a corn.";
+
+ SECTION("no data")
+ {
+ istreambuf_glue b;
+
+ int pos_c = b.pubseekpos(len / 2, ios_base::in);
+ int pos_b = b.pubseekpos(0, ios_base::in);
+ int pos_e = b.pubseekpos(len, ios_base::in);
+
+ CHECK(pos_b == -1);
+ CHECK(pos_c == -1);
+ CHECK(pos_e == -1);
+ }
+
+ SECTION("wrong buffer")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat, len);
+
+ int pos_c = b.pubseekpos(len / 2, ios_base::out);
+ int pos_b = b.pubseekpos(0, ios_base::out);
+ int pos_e = b.pubseekpos(len, ios_base::out);
+
+ CHECK(pos_b == -1);
+ CHECK(pos_c == -1);
+ CHECK(pos_e == -1);
+ }
+
+ SECTION("out of range")
+ {
+ istreambuf_glue b;
+ int pos;
+
+ b.pubsetbuf(dat, len);
+
+ pos = b.pubseekpos(0 - len, ios_base::in);
+ CHECK(pos == 0);
+ EXP_AVAIL1(b, exp, len, pos);
+
+ pos = b.pubseekpos(len + len, ios_base::in);
+ CHECK(pos == len);
+ EXP_AVAIL1(b, exp, len, pos);
+ }
+
+ SECTION("on the edge")
+ {
+ istreambuf_glue b;
+ int pos;
+
+ b.pubsetbuf(dat, len);
+
+ pos = b.pubseekpos(0, ios_base::in);
+ CHECK(pos == 0);
+ EXP_AVAIL1(b, exp, len, pos);
+
+ pos = b.pubseekpos(0 - 1, ios_base::in);
+ CHECK(pos == 0);
+ EXP_AVAIL1(b, exp, len, pos);
+
+ pos = b.pubseekpos(0 + 1, ios_base::in);
+ CHECK(pos == 1);
+ EXP_AVAIL1(b, exp, len, pos);
+
+ pos = b.pubseekpos(len, ios_base::in);
+ CHECK(pos == len);
+ EXP_AVAIL1(b, exp, len, pos);
+
+ pos = b.pubseekpos(len - 1, ios_base::in);
+ CHECK(pos == len - 1);
+ EXP_AVAIL1(b, exp, len, pos);
+
+ pos = b.pubseekpos(len + 1, ios_base::in);
+ CHECK(pos == len);
+ EXP_AVAIL1(b, exp, len, pos);
+ }
+
+ SECTION("in range")
+ {
+ istreambuf_glue b;
+ int pos;
+
+ b.pubsetbuf(dat, len);
+
+ pos = b.pubseekpos(len1d3, ios_base::in);
+ CHECK(pos == len1d3);
+ EXP_AVAIL1(b, exp, len, pos);
+
+ pos = b.pubseekpos(len2d3, ios_base::in);
+ CHECK(pos == len2d3);
+ EXP_AVAIL1(b, exp, len, pos);
+ }
+}
+
+TEST_CASE("input buffer - positioning two sources", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ const int len1d3 = strlen(exp) * 1 / 3;
+ const int len2d3 = len - len1d3;
+ char dat1[] = "Early bird";
+ char dat2[] = " gets a corn.";
+ const int dat1_len = strlen(dat1);
+ const int dat2_len = strlen(dat2);
+
+ SECTION("wrong buffer")
+ {
+ istreambuf_glue b;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ int pos_c = b.pubseekpos(len / 2, ios_base::out);
+ int pos_b = b.pubseekpos(0, ios_base::out);
+ int pos_e = b.pubseekpos(len, ios_base::out);
+
+ CHECK(pos_b == -1);
+ CHECK(pos_c == -1);
+ CHECK(pos_e == -1);
+ }
+
+ SECTION("out of range")
+ {
+ istreambuf_glue b;
+ int pos;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ pos = b.pubseekpos(0 - len, ios_base::in);
+ CHECK(pos == 0);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(len + len, ios_base::in);
+ CHECK(pos == len);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+ }
+
+ SECTION("on the edge")
+ {
+ istreambuf_glue b;
+ int pos;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ pos = b.pubseekpos(0, ios_base::in);
+ CHECK(pos == 0);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(0 - 1, ios_base::in);
+ CHECK(pos == 0);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(0 + 1, ios_base::in);
+ CHECK(pos == 1);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(len, ios_base::in);
+ CHECK(pos == len);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(len - 1, ios_base::in);
+ CHECK(pos == len - 1);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(len + 1, ios_base::in);
+ CHECK(pos == len);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+ }
+
+ SECTION("in range")
+ {
+ istreambuf_glue b;
+ int pos;
+
+ b.pubsetbuf(dat1, dat1_len)->pubsetbuf(dat2, dat2_len);
+
+ pos = b.pubseekpos(len1d3, ios_base::in);
+ CHECK(pos == len1d3);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(len2d3, ios_base::in);
+ CHECK(pos == len2d3);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(dat1_len, ios_base::in);
+ CHECK(pos == dat1_len);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(dat1_len + 1, ios_base::in);
+ CHECK(pos == dat1_len + 1);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(dat1_len - 1, ios_base::in);
+ CHECK(pos == dat1_len - 1);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(dat1_len + 2, ios_base::in);
+ CHECK(pos == dat1_len + 2);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+
+ pos = b.pubseekpos(dat1_len - 2, ios_base::in);
+ CHECK(pos == dat1_len - 2);
+ EXP_AVAIL2(b, exp, len, pos, dat1_len);
+ }
+}
+
+TEST_CASE("input stream - one source", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ char dat[] = "Early bird gets a corn.";
+
+ SECTION("no data")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ s.read(act, sizeof(act));
+
+ CHECK(true == s.eof());
+ CHECK(-1 == s.tellg());
+ s.clear();
+ CHECK(-1 == s.tellg());
+ }
+
+ SECTION("equal")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ b.pubsetbuf(dat, len);
+ s.read(act, len);
+
+ EXP_IN(s, exp, act, len);
+ }
+
+ SECTION("partial read")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ b.pubsetbuf(dat, len);
+ s.read(act + 0, 1);
+ s.read(act + 1, 2);
+ s.read(act + 3, 3);
+ s.read(act + 6, 4);
+
+ EXP_IN(s, exp, act, 10);
+
+ s.read(act + 10, len - 10);
+
+ EXP_IN(s, exp, act, len);
+ }
+
+ SECTION("EOF")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ b.pubsetbuf(dat, 10);
+ s.read(act, len);
+
+ EOF_IN(s, exp, act, 10);
+ }
+}
+
+TEST_CASE("input stream - two sources", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ char dat1[] = "Early bird";
+ char dat2[] = " gets a corn.";
+
+ SECTION("equal")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ b.pubsetbuf(dat1, strlen(dat1))->pubsetbuf(dat2, strlen(dat2));
+ s.read(act, len);
+
+ EXP_IN(s, exp, act, len);
+ }
+
+ SECTION("partial read")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ b.pubsetbuf(dat1, strlen(dat1))->pubsetbuf(dat2, strlen(dat2));
+ s.read(act + 0, 1);
+ s.read(act + 1, 2);
+ s.read(act + 3, 3);
+ s.read(act + 6, 4);
+
+ EXP_IN(s, exp, act, 10);
+
+ s.read(act + 10, len - 10);
+
+ EXP_IN(s, exp, act, len);
+ }
+
+ SECTION("EOF")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ b.pubsetbuf(dat1, strlen(dat1))->pubsetbuf(dat2, 1);
+ s.read(act, len);
+
+ EOF_IN(s, exp, act, 11);
+ }
+}
+
+TEST_CASE("input stream - last chunk offset", "[Stream buffers]")
+{
+ SECTION("no data")
+ {
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ CHECK(0 == b.last_chunk_offset());
+
+ s.read(act, 1);
+ CHECK(0 == b.last_chunk_offset());
+ }
+
+ SECTION("single buffer")
+ {
+ char dat1[] = "01234567";
+
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ CHECK(0 == b.last_chunk_offset());
+
+ b.pubsetbuf(dat1, strlen(dat1));
+ CHECK(0 == b.last_chunk_offset());
+
+ s.read(act, 1);
+ CHECK(1 == b.last_chunk_offset());
+
+ s.read(act, 2);
+ CHECK(3 == b.last_chunk_offset());
+
+ s.read(act, 5);
+ CHECK(8 == b.last_chunk_offset());
+
+ s.read(act, 1);
+ CHECK(8 == b.last_chunk_offset());
+ }
+
+ SECTION("two buffers")
+ {
+ char dat1[] = "0123";
+ char dat2[] = "4567";
+
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ CHECK(0 == b.last_chunk_offset());
+
+ b.pubsetbuf(dat1, strlen(dat1))->pubsetbuf(dat2, strlen(dat2));
+ CHECK(0 == b.last_chunk_offset());
+
+ s.read(act, 1);
+ CHECK(0 == b.last_chunk_offset());
+
+ s.read(act, 1);
+ CHECK(0 == b.last_chunk_offset());
+
+ s.read(act, 4);
+ CHECK(2 == b.last_chunk_offset());
+
+ s.read(act, 2);
+ CHECK(4 == b.last_chunk_offset());
+
+ s.read(act, 1);
+ CHECK(4 == b.last_chunk_offset());
+ }
+
+ SECTION("three buffers")
+ {
+ char dat1[] = "0123";
+ char dat2[] = "4567";
+ char dat3[] = "89+*";
+
+ char act[ACT_SIZE];
+ istreambuf_glue b;
+ istream s(&b);
+
+ CHECK(0 == b.last_chunk_offset());
+
+ b.pubsetbuf(dat1, strlen(dat1))->pubsetbuf(dat2, strlen(dat2))->pubsetbuf(dat3, strlen(dat3));
+ CHECK(0 == b.last_chunk_offset());
+
+ s.read(act, 3);
+ CHECK(0 == b.last_chunk_offset());
+
+ s.read(act, 3);
+ CHECK(0 == b.last_chunk_offset());
+
+ s.read(act, 3);
+ CHECK(1 == b.last_chunk_offset());
+
+ s.read(act, 3);
+ CHECK(4 == b.last_chunk_offset());
+
+ s.read(act, 1);
+ CHECK(4 == b.last_chunk_offset());
+ }
+}
+
+TEST_CASE("output buffer - basic", "[Stream buffers]")
+{
+ const char exp[EXP_SIZE] = "ABC";
+
+ SECTION("no input")
+ {
+ const char* n = "";
+ const int l = strlen(n);
+
+ ostreambuf_infl b;
+
+ EXP_RES(b, n, l, 0);
+ }
+
+ SECTION("put char")
+ {
+ ostreambuf_infl b;
+
+ int c = b.sputc('A');
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::out);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::out);
+
+ CHECK(c == 'A');
+ CHECK(off_b == 0);
+ CHECK(off_c == 1);
+ CHECK(off_e == 256);
+
+ EXP_RES(b, exp, 1, 256);
+ }
+
+ SECTION("put two chars")
+ {
+ ostreambuf_infl b;
+
+ int c1 = b.sputc('A');
+ int off_1 = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ int c2 = b.sputc('B');
+ int off_2 = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::out);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::out);
+
+ CHECK(c1 == 'A');
+ CHECK(c2 == 'B');
+ CHECK(off_b == 0);
+ CHECK(off_1 == 1);
+ CHECK(off_2 == 2);
+ CHECK(off_e == 256);
+
+ EXP_RES(b, exp, 2, 256);
+ }
+
+ SECTION("extend buffer")
+ {
+ ostreambuf_infl b;
+
+ int c1 = b.sputc('A');
+ int off_1 = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::out);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::out);
+ int c2 = b.sputc('Z');
+ int off_2 = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ int off_z = b.pubseekoff(0, ios_base::end, ios_base::out);
+
+ CHECK(c1 == 'A');
+ CHECK(c2 == 'Z');
+ CHECK(off_b == 0);
+ CHECK(off_1 == 1);
+ CHECK(off_2 == 257);
+ CHECK(off_e == 256);
+ CHECK(off_z == 768);
+ }
+
+ SECTION("put sequence of chars")
+ {
+ ostreambuf_infl b;
+ const int len = sizeof(exp);
+
+ int n = b.sputn(exp, len);
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::out);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::out);
+
+ CHECK(n == len);
+ CHECK(off_b == 0);
+ CHECK(off_c == len);
+ CHECK(off_e == 4096);
+
+ EXP_RES(b, exp, len, 4096);
+ }
+
+ SECTION("continue sequence")
+ {
+ ostreambuf_infl b;
+ const int len = sizeof(exp) - 1;
+
+ int c1 = b.sputc('A');
+ int n = b.sputn(exp, len);
+ int c2 = b.sputc('Z');
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::out);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::out);
+
+ CHECK(n == len);
+ CHECK(c1 == 'A');
+ CHECK(c2 == 'Z');
+ CHECK(off_b == 0);
+ CHECK(off_c == len + 2);
+ CHECK(off_e == 4096 + 512);
+ }
+}
+
+TEST_CASE("output buffer - buffer management", "[Stream buffers]")
+{
+ char dat1[] = "0123";
+ char dat2[] = "4567";
+ char dat3[] = "89";
+ char dat4[] = "-+";
+ const int dat1_len = strlen(dat1);
+ const int dat2_len = strlen(dat2);
+ const int dat3_len = strlen(dat3);
+ const int dat4_len = strlen(dat4);
+
+ SECTION("sync")
+ {
+ ostreambuf_infl b;
+
+ char* buf = new char[dat1_len];
+ memcpy(buf, dat1, dat1_len);
+ b.pubsetbuf(buf, dat1_len);
+
+ int r = b.pubsync();
+ CHECK(r == -1);
+ }
+
+ SECTION("changing buffer")
+ {
+ ostreambuf_infl b;
+ const int s1 = 128;
+ const int s2 = 256;
+ const int s3 = 32;
+ const int s4 = 64;
+
+ b.pubsetbuf(new char[s1], s1);
+ b.sputn(dat1, dat1_len);
+ EXP_RES(b, dat1, dat1_len, dat1_len);
+
+ b.pubsetbuf(new char[s2], s2);
+ b.sputn(dat2, dat2_len);
+ EXP_RES(b, dat2, dat2_len, dat2_len);
+
+ b.pubsetbuf(new char[s3], s3);
+ b.sputn(dat3, dat3_len);
+ EXP_RES(b, dat3, dat3_len, dat3_len);
+
+ b.pubsetbuf(new char[s4], s4);
+ b.sputn(dat4, dat4_len);
+ EXP_RES(b, dat4, dat4_len, dat4_len);
+ }
+}
+
+TEST_CASE("output buffer - positioning", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ const int len1d3 = strlen(exp) * 1 / 3;
+ const int len2d3 = len - len1d3;
+
+ SECTION("no data")
+ {
+ ostreambuf_infl b;
+
+ int pos_c = b.pubseekpos(len / 2, ios_base::out);
+ int pos_b = b.pubseekpos(0, ios_base::out);
+ int pos_e = b.pubseekpos(len, ios_base::out);
+
+ CHECK(pos_b == 0);
+ CHECK(pos_c == 0);
+ CHECK(pos_e == 0);
+ }
+
+ SECTION("wrong buffer")
+ {
+ ostreambuf_infl b;
+
+ b.pubsetbuf(new char[len], len);
+
+ int pos_c = b.pubseekpos(len / 2, ios_base::in);
+ int pos_b = b.pubseekpos(0, ios_base::in);
+ int pos_e = b.pubseekpos(len, ios_base::in);
+
+ CHECK(pos_b == -1);
+ CHECK(pos_c == -1);
+ CHECK(pos_e == -1);
+ }
+
+ SECTION("out of range")
+ {
+ ostreambuf_infl b;
+ int pos;
+
+ b.pubsetbuf(new char[len], len);
+ b.sputn(exp, len);
+
+ pos = b.pubseekpos(0 - len, ios_base::out);
+ CHECK(pos == 0);
+ EXP_RES(b, exp, 0, 0);
+
+ b.pubsetbuf(new char[len], len);
+ b.sputn(exp, len);
+
+ pos = b.pubseekpos(len + len, ios_base::out);
+ CHECK(pos == len);
+ EXP_RES(b, exp, len, len);
+ }
+
+ SECTION("on the edge")
+ {
+ ostreambuf_infl b;
+ int pos;
+
+ b.pubsetbuf(new char[len], len);
+ b.sputn(exp, len);
+
+ pos = b.pubseekpos(0 - 1, ios_base::out);
+ CHECK(pos == 0);
+ pos = b.pubseekpos(0 + 1, ios_base::out);
+ CHECK(pos == 1);
+ pos = b.pubseekpos(len, ios_base::out);
+ CHECK(pos == len);
+ pos = b.pubseekpos(len - 1, ios_base::out);
+ CHECK(pos == len - 1);
+ pos = b.pubseekpos(len + 1, ios_base::out);
+ CHECK(pos == len);
+
+ pos = b.pubseekpos(0, ios_base::out);
+ CHECK(pos == 0);
+ EXP_RES(b, exp, 0, 0);
+ }
+
+ SECTION("in range")
+ {
+ ostreambuf_infl b;
+ int pos;
+
+ b.pubsetbuf(new char[len], len);
+ b.sputn(exp, len);
+
+ pos = b.pubseekpos(len1d3, ios_base::out);
+ CHECK(pos == len1d3);
+ pos = b.pubseekpos(len2d3, ios_base::out);
+ CHECK(pos == len2d3);
+ }
+}
+
+TEST_CASE("output buffer - offset", "[Stream buffers]")
+{
+ const char* exp = "Early bird gets a corn.";
+ const int len = strlen(exp);
+ const int len1d3 = strlen(exp) * 1 / 3;
+ const int len2d3 = len - len1d3;
+
+ SECTION("no data")
+ {
+ ostreambuf_infl b;
+
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::out);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::out);
+
+ CHECK(off_b == 0);
+ CHECK(off_c == 0);
+ CHECK(off_e == 0);
+ }
+
+ SECTION("wrong buffer")
+ {
+ ostreambuf_infl b;
+
+ b.pubsetbuf(new char[len], len);
+
+ int off_c = b.pubseekoff(0, ios_base::cur, ios_base::in);
+ int off_b = b.pubseekoff(0, ios_base::beg, ios_base::in);
+ int off_e = b.pubseekoff(0, ios_base::end, ios_base::in);
+ int off_a = b.pubseekoff(0, static_cast<std::ios_base::seekdir>(0x5a5a), ios_base::out);
+
+ CHECK(off_b == -1);
+ CHECK(off_c == -1);
+ CHECK(off_e == -1);
+ CHECK(off_a == -1);
+ }
+
+ SECTION("begin")
+ {
+ ostreambuf_infl b;
+ int off;
+
+ b.pubsetbuf(new char[len], len);
+ b.sputn(exp, len);
+
+ off = b.pubseekoff(0 - len - len, ios_base::beg, ios_base::out);
+ CHECK(off == 0);
+
+ off = b.pubseekoff(0 + len + len, ios_base::beg, ios_base::out);
+ CHECK(off == len);
+
+ off = b.pubseekoff(0 - 1, ios_base::beg, ios_base::out);
+ CHECK(off == 0);
+
+ off = b.pubseekoff(0 + 1, ios_base::beg, ios_base::out);
+ CHECK(off == 1);
+
+ off = b.pubseekoff(0 + len1d3, ios_base::beg, ios_base::out);
+ CHECK(off == len1d3);
+
+ off = b.pubseekoff(0 + len2d3, ios_base::beg, ios_base::out);
+ CHECK(off == len2d3);
+
+ off = b.pubseekoff(0 + len - 1, ios_base::beg, ios_base::out);
+ CHECK(off == len - 1);
+
+ off = b.pubseekoff(0 + len, ios_base::beg, ios_base::out);
+ CHECK(off == len);
+
+ off = b.pubseekoff(0, ios_base::beg, ios_base::out);
+ CHECK(off == 0);
+ EXP_RES(b, exp, 0, 0);
+ b.sputn(exp, len);
+ EXP_RES(b, exp, len, len);
+ }
+
+ SECTION("end")
+ {
+ const char* exp_alt = "Early bird gets a corn!";
+
+ ostreambuf_infl b;
+ int off;
+
+ b.pubsetbuf(new char[len], len);
+ b.sputn(exp, len);
+
+ off = b.pubseekoff(0 - len - len, ios_base::end, ios_base::out);
+ CHECK(off == 0);
+
+ off = b.pubseekoff(0 + len + len, ios_base::end, ios_base::out);
+ CHECK(off == len);
+
+ off = b.pubseekoff(0, ios_base::end, ios_base::out);
+ CHECK(off == len);
+
+ off = b.pubseekoff(0 - 1, ios_base::end, ios_base::out);
+ CHECK(off == len - 1);
+
+ off = b.pubseekoff(0 + 1, ios_base::end, ios_base::out);
+ CHECK(off == len);
+
+ off = b.pubseekoff(0 - len1d3, ios_base::end, ios_base::out);
+ CHECK(off == len2d3);
+
+ off = b.pubseekoff(0 - len2d3, ios_base::end, ios_base::out);
+ CHECK(off == len1d3);
+
+ off = b.pubseekoff(0 - len + 1, ios_base::end, ios_base::out);
+ CHECK(off == 1);
+
+ off = b.pubseekoff(0 - len, ios_base::end, ios_base::out);
+ CHECK(off == 0);
+
+ b.pubsetbuf(new char[len], len);
+ b.sputn(exp, len);
+ off = b.pubseekoff(- 1, ios_base::end, ios_base::out);
+ CHECK(off == len - 1);
+ b.sputn("!", 1);
+ off = b.pubseekoff(0, ios_base::end, ios_base::out);
+ CHECK(off == len);
+ EXP_RES(b, exp_alt, len, len);
+ }
+
+ SECTION("current")
+ {
+ const char* exp_alt = "Early birds get a worm.";
+ const char* ovr_alt = "s get a worm.";
+ int off_alt = strlen(ovr_alt);
+
+ ostreambuf_infl b;
+ int off;
+
+ b.pubsetbuf(new char[len], len);
+ b.sputn(exp, len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::out);
+ off = b.pubseekoff(0 - len - len, ios_base::cur, ios_base::out);
+ CHECK(off == 0);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::out);
+ off = b.pubseekoff(0 + len + len, ios_base::cur, ios_base::out);
+ CHECK(off == len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::out);
+ off = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ CHECK(off == len1d3);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::out);
+ off = b.pubseekoff(0 - 1, ios_base::cur, ios_base::out);
+ CHECK(off == len1d3 - 1);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::out);
+ off = b.pubseekoff(0 + 1, ios_base::cur, ios_base::out);
+ CHECK(off == len1d3 + 1);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::out);
+ off = b.pubseekoff(0 + len1d3, ios_base::cur, ios_base::out);
+ CHECK(off == len1d3 + len1d3);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::out);
+ off = b.pubseekoff(0 + len2d3, ios_base::cur, ios_base::out);
+ CHECK(off == len);
+
+ b.pubseekoff(len1d3, ios_base::beg, ios_base::out);
+ off = b.pubseekoff(0 + len, ios_base::cur, ios_base::out);
+ CHECK(off == len);
+
+ b.pubsetbuf(new char[len], len);
+ b.sputn(exp, len);
+ b.pubseekoff(- off_alt, ios_base::end, ios_base::out);
+ off = b.pubseekoff(0, ios_base::cur, ios_base::out);
+ CHECK(off == len - off_alt);
+ b.sputn(ovr_alt, off_alt);
+ off = b.pubseekoff(0, ios_base::end, ios_base::out);
+ CHECK(off == len);
+ EXP_RES(b, exp_alt, len, len);
+ }
+}
+
+TEST_CASE("output stream - basic", "[Stream buffers]")
+{
+ SECTION("no input")
+ {
+ const char* exp = "";
+ const int exp_len = strlen(exp);
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ EXP_OUT(s, exp, exp_len);
+ }
+
+ SECTION("1 byte input")
+ {
+ const char* src = "A";
+ const int src_len = strlen(src);
+ const char* exp = "A";
+ const int exp_len = strlen(exp);
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ s.write(src, src_len);
+
+ EXP_OUT(s, exp, exp_len);
+ }
+
+ SECTION("8 bytes input")
+ {
+ const char* src = "12345678";
+ const int src_len = strlen(src);
+ const char* exp = "12345678";
+ const int exp_len = strlen(exp);
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ s.write(src, src_len);
+
+ EXP_OUT(s, exp, exp_len);
+ }
+
+ SECTION("partial write")
+ {
+ const char* src = "12345678";
+ const int src_len = strlen(src);
+ const char* exp = "12345678";
+ const int exp_len = strlen(exp);
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ for (const char* c = src; c < src + src_len; ++c)
+ s.write(c, 1);
+
+ EXP_OUT(s, exp, exp_len);
+ }
+}
+
+TEST_CASE("output stream - reserved size", "[Stream buffers]")
+{
+ SECTION("no input")
+ {
+ const char* exp = "";
+ const int exp_len = strlen(exp);
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ b.reserve(32);
+
+ EXP_OUT(s, exp, exp_len);
+ }
+
+ SECTION("1 byte input")
+ {
+ const char* src = "A";
+ const int src_len = strlen(src);
+ const char* exp = "A";
+ const int exp_len = strlen(exp);
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ b.reserve(32);
+ s.write(src, src_len);
+
+ EXP_OUT(s, exp, exp_len);
+ }
+
+ SECTION("8 bytes input")
+ {
+ const char* src = "12345678";
+ const int src_len = strlen(src);
+ const char* exp = "12345678";
+ const int exp_len = strlen(exp);
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ b.reserve(32);
+ s.write(src, src_len);
+
+ EXP_OUT(s, exp, exp_len);
+ }
+
+ SECTION("partial write")
+ {
+ const char* src = "12345678";
+ const int src_len = strlen(src);
+ const char* exp = "12345678";
+ const int exp_len = strlen(exp);
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ b.reserve(32);
+ for (const char* c = src; c < src + src_len; ++c)
+ s.write(c, 1);
+
+ EXP_OUT(s, exp, exp_len);
+ }
+}
+
+TEST_CASE("output stream - large data", "[Stream buffers]")
+{
+ const int len = 1 << 21;
+ const int plen = 1 << 12;
+ vector<char> chars;
+
+ chars.reserve(len);
+ for (char& c : chars)
+ c = rand();
+
+ SECTION("0 bytes reserved")
+ {
+ const char* src = chars.data();
+ const char* exp = chars.data();
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ for (int i = 0; i < len; i += plen, src += plen)
+ s.write(src, plen);
+
+ EOF_OUT(s, exp, 1 << 20);
+ }
+
+ SECTION("2^10 bytes reserved")
+ {
+ const char* src = chars.data();
+ const char* exp = chars.data();
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ b.reserve(1 << 10);
+ for (int i = 0; i < len; i += plen, src += plen)
+ s.write(src, plen);
+
+ EOF_OUT(s, exp, 1 << 20);
+ }
+
+ SECTION("2^18 bytes reserved")
+ {
+ const char* src = chars.data();
+ const char* exp = chars.data();
+
+ ostreambuf_infl b;
+ ostream s(&b);
+
+ b.reserve(1 << 18);
+ for (int i = 0; i < len; i += plen, src += plen)
+ s.write(src, plen);
+
+ EOF_OUT(s, exp, 1 << 20);
+ }
+}