[libcxx-commits] [libcxx] Add test case for xsgetn in basic_filebuf (PR #167937)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Nov 17 16:07:15 PST 2025
https://github.com/Sterling-Augustine updated https://github.com/llvm/llvm-project/pull/167937
>From a7ddd924414f512a853b04d96d5102dc8df3aa50 Mon Sep 17 00:00:00 2001
From: Sterling Augustine <saugustine at google.com>
Date: Thu, 13 Nov 2025 11:38:36 -0800
Subject: [PATCH 1/2] Add test case for xsgetn in basic_filebuf
This is the promised follow-up to #167779. It simply adds a test case.
---
.../fstreams/ifstream.members/xsgetn.pass.cpp | 72 +++++++++++++++++++
.../fstreams/ifstream.members/xsgetn.test.dat | 1 +
2 files changed, 73 insertions(+)
create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
create mode 100644 libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.test.dat
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
new file mode 100644
index 0000000000000..ec555ea4d259b
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// FILE_DEPENDENCIES: xsgetn.test.dat
+
+// <fstream>
+
+// template <class charT, class traits = char_traits<charT> >
+// class basic_ifstream
+
+// streamsize xsgetn(char_type*, streamsize) override;
+
+// This isn't a required override by the standard, but most implementations override it, since it allows for
+// significantly improved performance in some cases. All of this code is required to work, so this isn't a libc++
+// extension
+
+#include <cassert>
+#include <fstream>
+
+#include "test_macros.h"
+
+int main(int, char**) {
+ {
+ char buffer[10];
+ std::ifstream fs("xsgetn.test.dat");
+ std::filebuf* fb = fs.rdbuf();
+ fb->pubsetbuf(buffer, 10);
+
+ // Ensure that the buffer is set up
+ assert(fb->sgetc() == 't');
+
+ std::string str(5, '\0');
+
+ { // Check that a read smaller than the buffer works fine
+ assert(fb->sgetn(str.data(), 5) == 5);
+ assert(str == "this ");
+ }
+ { // Check that reading up to the buffer end works fine
+ assert(fb->sgetn(str.data(), 5) == 5);
+ assert(str == "is so");
+ }
+ { // Check that reading from an empty buffer, but more than the buffer can hold works fine
+ str.resize(12);
+ assert(fb->sgetn(str.data(), 12) == 12);
+ assert(str == "me random da");
+ }
+ { // Check that reading from a non-empty buffer, and more than the buffer can hold works fine
+ // Fill the buffer up
+ str.resize(2);
+ assert(fb->sgetn(str.data(), 2) == 2);
+ assert(str == "ta");
+
+ // Do the actual check
+ str.resize(12);
+ assert(fb->sgetn(str.data(), 12) == 12);
+ assert(str == " to be able ");
+ }
+ { // Check that trying to read more than the file size works fine
+ str.resize(30);
+ assert(fb->sgetn(str.data(), 30) == 24);
+ str.resize(24);
+ assert(str == "to test buffer behaviour");
+ }
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.test.dat b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.test.dat
new file mode 100644
index 0000000000000..06d663b9bf23d
--- /dev/null
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.test.dat
@@ -0,0 +1 @@
+this is some random data to be able to test buffer behaviour
\ No newline at end of file
>From c328003e09bd74873dc1edccc4217a8791857655 Mon Sep 17 00:00:00 2001
From: Sterling Augustine <saugustine at google.com>
Date: Mon, 17 Nov 2025 16:06:03 -0800
Subject: [PATCH 2/2] Fix scoping. Use vectors for buffers.
Writing data to a buffer obtained by data() is undefined behavior. Fix that.
---
.../fstreams/ifstream.members/xsgetn.pass.cpp | 81 ++++++++++---------
1 file changed, 41 insertions(+), 40 deletions(-)
diff --git a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
index ec555ea4d259b..9438679823d50 100644
--- a/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
+++ b/libcxx/test/std/input.output/file.streams/fstreams/ifstream.members/xsgetn.pass.cpp
@@ -15,57 +15,58 @@
// streamsize xsgetn(char_type*, streamsize) override;
-// This isn't a required override by the standard, but most implementations override it, since it allows for
-// significantly improved performance in some cases. All of this code is required to work, so this isn't a libc++
-// extension
+// This isn't a required override by the standard, but most implementations
+// override it, since it allows for significantly improved performance in some
+// cases. All of this code is required to work, so this isn't a libc++ extension
#include <cassert>
#include <fstream>
+#include <vector>
#include "test_macros.h"
int main(int, char**) {
- {
- char buffer[10];
- std::ifstream fs("xsgetn.test.dat");
- std::filebuf* fb = fs.rdbuf();
- fb->pubsetbuf(buffer, 10);
+ std::vector<char> stream_buffer(10);
+ std::ifstream fs("xsgetn.test.dat");
+ std::filebuf* fb = fs.rdbuf();
+ fb->pubsetbuf(stream_buffer.data(), 10);
- // Ensure that the buffer is set up
- assert(fb->sgetc() == 't');
+ // Ensure that the buffer is set up
+ assert(fb->sgetc() == 't');
- std::string str(5, '\0');
+ std::vector<char> test_buffer(5);
+ test_buffer[0] = '\0';
- { // Check that a read smaller than the buffer works fine
- assert(fb->sgetn(str.data(), 5) == 5);
- assert(str == "this ");
- }
- { // Check that reading up to the buffer end works fine
- assert(fb->sgetn(str.data(), 5) == 5);
- assert(str == "is so");
- }
- { // Check that reading from an empty buffer, but more than the buffer can hold works fine
- str.resize(12);
- assert(fb->sgetn(str.data(), 12) == 12);
- assert(str == "me random da");
- }
- { // Check that reading from a non-empty buffer, and more than the buffer can hold works fine
- // Fill the buffer up
- str.resize(2);
- assert(fb->sgetn(str.data(), 2) == 2);
- assert(str == "ta");
+ { // Check that a read smaller than the buffer works fine
+ assert(fb->sgetn(test_buffer.data(), 5) == 5);
+ assert(std::string(test_buffer.data()) == "this ");
+ }
+ { // Check that reading up to the buffer end works fine
+ assert(fb->sgetn(test_buffer.data(), 5) == 5);
+ assert(std::string(test_buffer.data(), 5) == "is so");
+ }
+ { // Check that reading from an empty buffer, but more than the buffer can
+ // hold works fine
+ test_buffer.resize(12);
+ assert(fb->sgetn(test_buffer.data(), 12) == 12);
+ assert(std::string(test_buffer.data(), 12) == "me random da");
+ }
+ { // Check that reading from a non-empty buffer, and more than the buffer can
+ // hold works fine Fill the buffer up
+ test_buffer.resize(2);
+ assert(fb->sgetn(test_buffer.data(), 2) == 2);
+ assert(std::string(test_buffer.data(), 2) == "ta");
- // Do the actual check
- str.resize(12);
- assert(fb->sgetn(str.data(), 12) == 12);
- assert(str == " to be able ");
- }
- { // Check that trying to read more than the file size works fine
- str.resize(30);
- assert(fb->sgetn(str.data(), 30) == 24);
- str.resize(24);
- assert(str == "to test buffer behaviour");
- }
+ // Do the actual check
+ test_buffer.resize(12);
+ assert(fb->sgetn(test_buffer.data(), 12) == 12);
+ assert(std::string(test_buffer.data(), 12) == " to be able ");
+ }
+ { // Check that trying to read more than the file size works fine
+ test_buffer.resize(30);
+ assert(fb->sgetn(test_buffer.data(), 30) == 24);
+ test_buffer.resize(24);
+ assert(std::string(test_buffer.data(), 24) == "to test buffer behaviour");
}
return 0;
More information about the libcxx-commits
mailing list