Cover format_to, format_to_n truncation, write failure, and
large writes that exceed the internal buffer. These paths
were previously untested.
libstdc++-v3/ChangeLog:
* testsuite/std/format/functions/format_to_ostreambuf.cc: New test.
Signed-off-by: Anlai Lu <[email protected]>
---
.../format/functions/format_to_ostreambuf.cc | 244 ++++++++++++++++++
1 file changed, 244 insertions(+)
create mode 100644
libstdc++-v3/testsuite/std/format/functions/format_to_ostreambuf.cc
diff --git
a/libstdc++-v3/testsuite/std/format/functions/format_to_ostreambuf.cc
b/libstdc++-v3/testsuite/std/format/functions/format_to_ostreambuf.cc
new file mode 100644
index 000000000..4fc8e7597
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/format/functions/format_to_ostreambuf.cc
@@ -0,0 +1,244 @@
+// { dg-do run { target c++20 } }
+
+#include <format>
+#include <sstream>
+#include <string>
+#include <testsuite_hooks.h>
+
+template<std::streamsize BufSize>
+struct ShortWriteStreambuf : std::streambuf
+{
+ std::string data;
+
+ std::streamsize
+ xsputn(const char_type* s, std::streamsize n) override
+ {
+ std::streamsize limit = std::max<std::streamsize>(0, BufSize -
data.size());
+ std::streamsize to_write = std::min(n, limit);
+ if (to_write > 0)
+ data.append(s, to_write);
+ return to_write;
+ }
+
+ int_type
+ overflow(int_type c) override
+ {
+ if (data.size() < BufSize)
+ {
+ data.push_back(traits_type::to_char_type(c));
+ return c;
+ }
+ return traits_type::eof();
+ }
+};
+
+void
+test_format_to()
+{
+ {
+ std::ostringstream os;
+ std::format_to(std::ostreambuf_iterator<char>(os), "{}", 42);
+ VERIFY( os.str() == "42" );
+ }
+
+ {
+ std::ostringstream os;
+ std::string big(800, 'y');
+ std::format_to(std::ostreambuf_iterator<char>(os), "{}", big);
+ VERIFY( os.str() == big );
+ }
+
+ {
+ std::ostringstream os;
+ std::string part(700, 'P');
+ std::format_to(std::ostreambuf_iterator<char>(os),
+ "{}{}{}", part, part, part);
+ VERIFY( os.str() == std::string(2100, 'P') );
+ }
+
+ {
+ std::ostringstream os;
+ std::string body(400, 'B');
+ std::format_to(std::ostreambuf_iterator<char>(os),
+ "header-{}-footer", body);
+ VERIFY( os.str() == "header-" + std::string(400, 'B') + "-footer" );
+ }
+}
+
+void
+test_format_to_n()
+{
+ {
+ std::ostringstream os;
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 3, "{}", "hello");
+ VERIFY( res.size == 5 );
+ VERIFY( os.str() == "hel" );
+ }
+
+ {
+ std::ostringstream os;
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 10, "{}", std::string(100, 'x'));
+ VERIFY( res.size == 100 );
+ VERIFY( os.str() == std::string(10, 'x') );
+ }
+
+ {
+ std::ostringstream os;
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 10, "{}", std::string(1000, 'x'));
+ VERIFY( res.size == 1000 );
+ VERIFY( os.str() == std::string(10, 'x') );
+ }
+
+ {
+ std::ostringstream os;
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 256, "{}", std::string(1000, 'x'));
+ VERIFY( res.size == 1000 );
+ VERIFY( os.str() == std::string(256, 'x') );
+ }
+
+ {
+ std::ostringstream os;
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 257, "{}", std::string(1000, 'x'));
+ VERIFY( res.size == 1000 );
+ VERIFY( os.str() == std::string(257, 'x') );
+ }
+
+ {
+ std::ostringstream os;
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 8, "{}{}{}", "AAAA", "BBBB", "CCCC");
+ VERIFY( res.size == 12 );
+ VERIFY( os.str() == "AAAABBBB" );
+ }
+
+ {
+ std::ostringstream os;
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 2, "{}{}", "AAAA", "BBBB");
+ VERIFY( res.size == 8 );
+ VERIFY( os.str() == "AA" );
+ }
+
+ {
+ std::ostringstream os;
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 8, "{}{}", "AAAA", "BBBB");
+ VERIFY( res.size == 8 );
+ VERIFY( os.str() == "AAAABBBB" );
+ }
+}
+
+void
+test_format_to_n_padding()
+{
+ {
+ std::ostringstream os;
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 3, "{:>10}", "hello");
+ VERIFY( res.size == 10 );
+ VERIFY( os.str().size() == 3 );
+ }
+
+ {
+ std::ostringstream os;
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 3, "{:.5}", std::string(100, 'z'));
+ VERIFY( res.size == 5 );
+ VERIFY( os.str() == std::string(3, 'z') );
+ }
+}
+
+void
+test_format_to_n_prefilled()
+{
+ // Pre-filled ostringstream: after seekp(0) the streambuf has a put
+ // area pointing into existing data. This exercises the
+ // _M_use_put_area code path combined with format_to_n truncation.
+ {
+ std::string init(100, 'Z');
+ std::ostringstream os(init);
+ os.seekp(0);
+ auto res = std::format_to_n(std::ostreambuf_iterator<char>(os),
+ 5, "{}", "1234567890");
+ VERIFY( res.size == 10 );
+ VERIFY( os.str() == "12345ZZZZZ" + std::string(90, 'Z') );
+ }
+}
+
+void
+test_write_failure()
+{
+ const std::string payload(20, 'Z');
+
+ {
+ ShortWriteStreambuf<20> buf;
+ auto it = std::ostreambuf_iterator<char>(&buf);
+ auto res = std::format_to(it, "{}", payload);
+ VERIFY( !res.failed() );
+ VERIFY( buf.data == std::string(20, 'Z') );
+ }
+
+ {
+ ShortWriteStreambuf<19> buf;
+ auto it = std::ostreambuf_iterator<char>(&buf);
+ auto res = std::format_to(it, "{}", payload);
+ VERIFY( res.failed() );
+ VERIFY( buf.data == std::string(19, 'Z') );
+ }
+
+ {
+ ShortWriteStreambuf<10> buf;
+ auto it = std::ostreambuf_iterator<char>(&buf);
+ auto res = std::format_to_n(it, 10, "{}", payload);
+ VERIFY( !res.out.failed() );
+ VERIFY( res.size == 20 );
+ VERIFY( buf.data == std::string(10, 'Z') );
+ }
+
+ {
+ ShortWriteStreambuf<10> buf;
+ auto it = std::ostreambuf_iterator<char>(&buf);
+ auto res = std::format_to_n(it, 11, "{}", payload);
+ VERIFY( res.out.failed() );
+ VERIFY( res.size == 20 );
+ VERIFY( buf.data == std::string(10, 'Z') );
+ }
+
+ {
+ ShortWriteStreambuf<100> buf;
+ auto it = std::ostreambuf_iterator<char>(&buf);
+ auto res = std::format_to(it, "{}", std::string(300, 'Y'));
+ VERIFY( res.failed() );
+ VERIFY( buf.data.size() <= 100 );
+ }
+ // format_to_n after write failure: size must still be the total
+ // number of characters that would have been produced.
+ {
+ ShortWriteStreambuf<50> buf;
+ auto it = std::ostreambuf_iterator<char>(&buf);
+ auto res = std::format_to_n(it, 100,
+ "{}{}{}",
+ std::string(20, 'A'),
+ std::string(30, 'B'),
+ std::string(40, 'C'));
+ // The first two arguments fill the buffer (20 + 30 == 50).
+ // The third argument (40 C's) triggers write failure and the
+ // remaining chars must still be counted in res.size.
+ VERIFY( res.out.failed() );
+ VERIFY( res.size == 90 );
+ }
+}
+
+int main()
+{
+ test_format_to();
+ test_format_to_n();
+ test_format_to_n_padding();
+ test_format_to_n_prefilled();
+ test_write_failure();
+}
--
2.34.1