diff --git a/include/platformstl/filesystem/FILE_stream.hpp b/include/platformstl/filesystem/FILE_stream.hpp index d30fd1b2..5710ce5d 100644 --- a/include/platformstl/filesystem/FILE_stream.hpp +++ b/include/platformstl/filesystem/FILE_stream.hpp @@ -4,11 +4,11 @@ * Purpose: Facade for the standard C Streams API. * * Created: 31st May 2009 - * Updated: 20th March 2025 + * Updated: 23rd September 2026 * * Home: http://stlsoft.org/ * - * Copyright (c) 2019-2025, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems * Copyright (c) 2009-2019, Matthew Wilson and Synesis Software * All rights reserved. * @@ -53,8 +53,8 @@ #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_MAJOR 2 # define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_MINOR 1 -# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_REVISION 5 -# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_EDIT 28 +# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_REVISION 6 +# define PLATFORMSTL_VER_PLATFORMSTL_FILESYSTEM_HPP_FILE_STREAM_EDIT 29 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ @@ -270,12 +270,31 @@ class FILE_stream_base return write_text_(ps, cch); } + /// [DEPRECATED] Writes \c cb bytes from the memory block pointed to by + /// \c pv to the underlying file stream. + /// + /// \deprecated Use write_binary() instead + /// + /// \exception X Thrown in \c cb bytes cannot be written to the + /// underlying stream + STLSOFT_DEPRECATED_("write(void const*, size_t) is deprecated and will be removed from a future version of STLSoft; use write_binary() instead") + class_type& write(void const* pv, size_type cb) + { + return write_binary(pv, cb); + } + /// Writes \c cb bytes from the memory block pointed to by \c pv to the /// underlying file stream. /// + /// \note Every byte is written, including embedded NULs. Character + /// overloads of write() stop at the first NUL. Newline + /// translation follows the stream's open mode, so open with + /// "wb" when the stored bytes must match the memory + /// block. + /// /// \exception X Thrown in \c cb bytes cannot be written to the /// underlying stream - class_type& write(void const* pv, size_type cb) + class_type& write_binary(void const* pv, size_type cb) { return write_bytes_(pv, cb); } diff --git a/test/component/platformstl/CMakeLists.txt b/test/component/platformstl/CMakeLists.txt index ead898a4..9fc02d09 100644 --- a/test/component/platformstl/CMakeLists.txt +++ b/test/component/platformstl/CMakeLists.txt @@ -1,3 +1,4 @@ # SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten add_subdirectory(diagnostics) +add_subdirectory(filesystem) add_subdirectory(system) diff --git a/test/component/platformstl/filesystem/CMakeLists.txt b/test/component/platformstl/filesystem/CMakeLists.txt new file mode 100644 index 00000000..477a88a9 --- /dev/null +++ b/test/component/platformstl/filesystem/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +add_subdirectory(test.component.platformstl.filesystem.file_lines) diff --git a/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/CMakeLists.txt b/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/CMakeLists.txt new file mode 100644 index 00000000..bb50f424 --- /dev/null +++ b/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/CMakeLists.txt @@ -0,0 +1,2 @@ +# SIS:AUTO_GENERATED: Remove this line if you edit the file, otherwise it will be overwritten +define_automated_test_program(test.component.platformstl.filesystem.file_lines entry.cpp) diff --git a/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/entry.cpp b/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/entry.cpp new file mode 100644 index 00000000..9628b986 --- /dev/null +++ b/test/component/platformstl/filesystem/test.component.platformstl.filesystem.file_lines/entry.cpp @@ -0,0 +1,283 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test.component.platformstl.filesystem.file_lines/entry.cpp + * + * Purpose: Component-tests for `platformstl::file_lines`. + * + * Created: 23rd September 2026 + * Updated: 23rd September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +/* ///////////////////////////////////// + * test component header file include(s) + */ + +#include + +/* ///////////////////////////////////// + * general includes + */ + +/* xTests header files */ +#include +#include +#include + +/* STLSoft header files */ +#include +#include + +/* Standard C header files */ +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * forward declarations + */ + +namespace { + + void TEST_EMPTY_FILE(); + void TEST_FILE_WITH_ONE_LINE_UNTERMINATED(); + void TEST_FILE_WITH_ONE_LINE_TERMINATED(); + void TEST_FILE_WITH_THREE_LINES(); + void TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CRLF(); + void TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CRLF(); + void TEST_FILE_WITH_CONSECUTIVE_CRLF_GIVES_EMPTY_LINE(); + void TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CR(); + void TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CR(); + void TEST_FILE_WITH_CONSECUTIVE_CR_GIVES_EMPTY_LINE(); + void TEST_FILE_CONTAINING_NUL_CHARACTER_THROWS(); +} // anonymous namespace + + +/* ///////////////////////////////////////////////////////////////////////// + * main() + */ + +int main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.component.platformstl.filesystem.file_lines", verbosity)) + { + XTESTS_RUN_CASE(TEST_EMPTY_FILE); + XTESTS_RUN_CASE(TEST_FILE_WITH_ONE_LINE_UNTERMINATED); + XTESTS_RUN_CASE(TEST_FILE_WITH_ONE_LINE_TERMINATED); + XTESTS_RUN_CASE(TEST_FILE_WITH_THREE_LINES); + XTESTS_RUN_CASE(TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CRLF); + XTESTS_RUN_CASE(TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CRLF); + XTESTS_RUN_CASE(TEST_FILE_WITH_CONSECUTIVE_CRLF_GIVES_EMPTY_LINE); + XTESTS_RUN_CASE(TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CR); + XTESTS_RUN_CASE(TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CR); + XTESTS_RUN_CASE(TEST_FILE_WITH_CONSECUTIVE_CR_GIVES_EMPTY_LINE); + XTESTS_RUN_CASE_THAT_THROWS(TEST_FILE_CONTAINING_NUL_CHARACTER_THROWS, platformstl::invalid_file_type_exception); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////////////////////////////////////////////////// + * test function implementations + */ + +namespace { + + using ::xtests::cpp::util::temp_file; + + +void TEST_EMPTY_FILE() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + platformstl::file_lines lines(f.c_str()); + + TEST_INT_EQ(0u, lines.size()); +} + +void TEST_FILE_WITH_ONE_LINE_UNTERMINATED() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "w"); + + stm.write("abc"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(1u, lines.size())); + TEST_MS_EQ("abc", lines[0]); +} + +void TEST_FILE_WITH_ONE_LINE_TERMINATED() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "w"); + + stm.write_line("abc"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(1u, lines.size())); + TEST_MS_EQ("abc", lines[0]); +} + +void TEST_FILE_WITH_THREE_LINES() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "w"); + + stm.write_line("abc"); + stm.write("\nghi"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(3u, lines.size())); + TEST_MS_EQ("abc", lines[0]); + TEST_MS_EQ("", lines[1]); + TEST_MS_EQ("ghi", lines[2]); +} + +void TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CRLF() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\r\n"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(1u, lines.size())); + TEST_MS_EQ("abc", lines[0]); +} + +void TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CRLF() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\r\ndef\r\nghi\r\n"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(3u, lines.size())); + TEST_MS_EQ("abc", lines[0]); + TEST_MS_EQ("def", lines[1]); + TEST_MS_EQ("ghi", lines[2]); +} + +void TEST_FILE_WITH_CONSECUTIVE_CRLF_GIVES_EMPTY_LINE() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\r\n\r\nghi"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(3u, lines.size())); + TEST_MS_EQ("abc", lines[0]); + TEST_MS_EQ("", lines[1]); + TEST_MS_EQ("ghi", lines[2]); +} + +void TEST_FILE_WITH_ONE_LINE_TERMINATED_BY_CR() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\r"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(1u, lines.size())); + TEST_MS_EQ("abc", lines[0]); +} + +void TEST_FILE_WITH_THREE_LINES_SEPARATED_BY_CR() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\rdef\rghi\r"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(3u, lines.size())); + TEST_MS_EQ("abc", lines[0]); + TEST_MS_EQ("def", lines[1]); + TEST_MS_EQ("ghi", lines[2]); +} + +void TEST_FILE_WITH_CONSECUTIVE_CR_GIVES_EMPTY_LINE() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write("abc\r\rghi"); + } + + platformstl::file_lines lines(f.c_str()); + + REQUIRE(TEST_INT_EQ(3u, lines.size())); + TEST_MS_EQ("abc", lines[0]); + TEST_MS_EQ("", lines[1]); + TEST_MS_EQ("ghi", lines[2]); +} + +void TEST_FILE_CONTAINING_NUL_CHARACTER_THROWS() +{ + temp_file f(temp_file::DeleteOnClose | temp_file::EmptyOnOpen | temp_file::CloseOnOpen); + + { + char const contents[] = { 'a', 'b', 'c', '\0', 'd', 'e', 'f' }; + platformstl::FILE_stream stm(f.c_str(), "wb"); + + stm.write_binary(contents, sizeof(contents)); + } + + platformstl::file_lines lines(f.c_str()); +} +} // anonymous namespace + + +/* ///////////////////////////// end of file //////////////////////////// */ +