Improve NativeFileStream
* Expose native file descriptor/handle to be able to use native APIs like POSIX sendfile() * Fix using Boost.Iostreams under Windows * Make it compile * Workaround issue with append flag
This commit is contained in:
parent
e8d829cadd
commit
5bed21c9d2
|
@ -127,12 +127,93 @@ struct NativeFileParams {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \class NativeFileStream::FileBuffer
|
||||||
|
* \brief The NativeFileStream::FileBuffer class holds an std::basic_streambuf<char> object obtained from a file path or a native file descriptor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Constructs a new FileBuffer object taking ownership of \a buffer.
|
||||||
|
*/
|
||||||
|
NativeFileStream::FileBuffer::FileBuffer(std::basic_streambuf<char> *buffer)
|
||||||
|
: buffer(buffer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Opens a file buffer from the specified \a path.
|
||||||
|
* \remarks See NativeFileStream::open() for remarks on how \a path must be encoded.
|
||||||
|
*/
|
||||||
|
NativeFileStream::FileBuffer::FileBuffer(const string &path, ios_base::openmode openMode)
|
||||||
|
{
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
// convert path to UTF-16
|
||||||
|
const auto widePath(makeWidePath(path));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// compute native params
|
||||||
|
const NativeFileParams nativeParams(openMode);
|
||||||
|
|
||||||
|
// open native file handle or descriptor
|
||||||
|
#ifdef CPP_UTILITIES_USE_GNU_CXX_STDIO_FILEBUF
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
descriptor = _wopen(widePath.get(), nativeParams.openMode, nativeParams.permissions);
|
||||||
|
if (descriptor == -1) {
|
||||||
|
throw std::ios_base::failure("_wopen failed");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
descriptor = ::open(path.data(), nativeParams.openFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (descriptor == -1) {
|
||||||
|
throw std::ios_base::failure("open failed");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
buffer = make_unique<StreamBuffer>(descriptor, openMode);
|
||||||
|
#else // CPP_UTILITIES_USE_BOOST_IOSTREAMS
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
handle = CreateFileW(widePath.get(), nativeParams.access, nativeParams.shareMode, nullptr, nativeParams.creation, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
if (handle == INVALID_HANDLE_VALUE) {
|
||||||
|
throw std::ios_base::failure("CreateFileW failed");
|
||||||
|
}
|
||||||
|
buffer = make_unique<StreamBuffer>(handle, boost::iostreams::close_handle);
|
||||||
|
// if we wanted to open assign the descriptor as well: descriptor = _open_osfhandle(reinterpret_cast<intptr_t>(handle), nativeParams.flags);
|
||||||
|
#else
|
||||||
|
descriptor = ::open(path.data(), nativeParams.openFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||||
|
if (descriptor == -1) {
|
||||||
|
throw std::ios_base::failure("open failed");
|
||||||
|
}
|
||||||
|
buffer = make_unique<StreamBuffer>(descriptor, boost::iostreams::close_handle);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Opens a file buffer from the specified \a fileDescriptor.
|
||||||
|
* \remarks
|
||||||
|
* The specified \a openMode is only used when using __gnu_cxx::stdio_filebuf<char> and must be in accordance with how \a fileDescriptor
|
||||||
|
* has been opened.
|
||||||
|
*/
|
||||||
|
NativeFileStream::FileBuffer::FileBuffer(int fileDescriptor, ios_base::openmode openMode)
|
||||||
|
: descriptor(fileDescriptor)
|
||||||
|
{
|
||||||
|
#ifdef CPP_UTILITIES_USE_GNU_CXX_STDIO_FILEBUF
|
||||||
|
buffer = make_unique<StreamBuffer>(descriptor, openMode);
|
||||||
|
#else // CPP_UTILITIES_USE_BOOST_IOSTREAMS
|
||||||
|
CPP_UTILITIES_UNUSED(openMode)
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
handle = reinterpret_cast<Handle>(_get_osfhandle(descriptor));
|
||||||
|
buffer = make_unique<StreamBuffer>(handle, boost::iostreams::close_handle);
|
||||||
|
#else
|
||||||
|
buffer = make_unique<StreamBuffer>(descriptor, boost::iostreams::close_handle);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Constructs a new NativeFileStream which is initially closed.
|
* \brief Constructs a new NativeFileStream which is initially closed.
|
||||||
*/
|
*/
|
||||||
NativeFileStream::NativeFileStream()
|
NativeFileStream::NativeFileStream()
|
||||||
: iostream(new StreamBuffer)
|
: iostream(new StreamBuffer)
|
||||||
, m_filebuf(rdbuf())
|
, m_data(rdbuf())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,9 +221,13 @@ NativeFileStream::NativeFileStream()
|
||||||
* \brief Moves the NativeFileStream.
|
* \brief Moves the NativeFileStream.
|
||||||
*/
|
*/
|
||||||
NativeFileStream::NativeFileStream(NativeFileStream &&other)
|
NativeFileStream::NativeFileStream(NativeFileStream &&other)
|
||||||
: iostream(other.m_filebuf.release())
|
: iostream(other.m_data.buffer.release())
|
||||||
, m_filebuf(rdbuf())
|
, m_data(rdbuf())
|
||||||
{
|
{
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
m_data.handle = other.m_data.handle;
|
||||||
|
#endif
|
||||||
|
m_data.descriptor = other.m_data.descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -155,9 +240,9 @@ NativeFileStream::~NativeFileStream()
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns whether the file is open.
|
* \brief Returns whether the file is open.
|
||||||
*/
|
*/
|
||||||
bool NativeFileStream::is_open() const
|
bool NativeFileStream::isOpen() const
|
||||||
{
|
{
|
||||||
return m_filebuf && static_cast<const StreamBuffer *>(m_filebuf.get())->is_open();
|
return m_data.buffer && static_cast<const StreamBuffer *>(m_data.buffer.get())->is_open();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -175,7 +260,7 @@ bool NativeFileStream::is_open() const
|
||||||
*/
|
*/
|
||||||
void NativeFileStream::open(const string &path, ios_base::openmode openMode)
|
void NativeFileStream::open(const string &path, ios_base::openmode openMode)
|
||||||
{
|
{
|
||||||
setFileBuffer(makeFileBuffer(path, openMode));
|
setData(FileBuffer(path, openMode), openMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -187,7 +272,7 @@ void NativeFileStream::open(const string &path, ios_base::openmode openMode)
|
||||||
*/
|
*/
|
||||||
void NativeFileStream::open(int fileDescriptor, ios_base::openmode openMode)
|
void NativeFileStream::open(int fileDescriptor, ios_base::openmode openMode)
|
||||||
{
|
{
|
||||||
setFileBuffer(makeFileBuffer(fileDescriptor, openMode));
|
setData(FileBuffer(fileDescriptor, openMode), openMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -195,96 +280,28 @@ void NativeFileStream::open(int fileDescriptor, ios_base::openmode openMode)
|
||||||
*/
|
*/
|
||||||
void NativeFileStream::close()
|
void NativeFileStream::close()
|
||||||
{
|
{
|
||||||
if (m_filebuf) {
|
if (m_data.buffer) {
|
||||||
static_cast<StreamBuffer *>(m_filebuf.get())->close();
|
static_cast<StreamBuffer *>(m_data.buffer.get())->close();
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
m_data.handle = nullptr;
|
||||||
|
#endif
|
||||||
|
m_data.descriptor = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Internally called to assign the \a buffer taking. Takes ownership over \a buffer.
|
* \brief Internally called to assign the buffer, file descriptor and handle.
|
||||||
*/
|
*/
|
||||||
void NativeFileStream::setFileBuffer(std::unique_ptr<std::basic_streambuf<char>> buffer)
|
void NativeFileStream::setData(FileBuffer data, std::ios_base::openmode openMode)
|
||||||
{
|
{
|
||||||
rdbuf(buffer.get());
|
rdbuf(data.buffer.get());
|
||||||
m_filebuf = std::move(buffer);
|
m_data = std::move(data);
|
||||||
}
|
m_openMode = openMode;
|
||||||
|
#if defined(PLATFORM_WINDOWS) && defined(CPP_UTILITIES_USE_BOOST_IOSTREAMS)
|
||||||
/*!
|
// workaround append flag dysfunctioning
|
||||||
* \brief \brief Internally called by open().
|
if (m_openMode & ios_base::app) {
|
||||||
*/
|
seekp(0, ios_base::end);
|
||||||
std::unique_ptr<std::basic_streambuf<char>> NativeFileStream::makeFileBuffer(const string &path, ios_base::openmode openMode)
|
|
||||||
{
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
|
||||||
// convert path to UTF-16
|
|
||||||
const auto widePath(makeWidePath(path));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// compute native params
|
|
||||||
const NativeFileParams nativeParams(openMode);
|
|
||||||
|
|
||||||
#ifdef CPP_UTILITIES_USE_GNU_CXX_STDIO_FILEBUF
|
|
||||||
// open file handle to initialize stdio_filebuf
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
|
||||||
const int fileHandle = _wopen(widePath.get(), nativeParams.openMode, nativeParams.permissions);
|
|
||||||
if (fileHandle == -1) {
|
|
||||||
throw std::ios_base::failure("_wopen failed");
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
const auto fileHandle = fopen(path.data(), nativeParams.openMode.data());
|
|
||||||
if (!fileHandle) {
|
|
||||||
throw std::ios_base::failure("fopen failed");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return make_unique<StreamBuffer>(fileHandle, openMode);
|
|
||||||
|
|
||||||
#else // CPP_UTILITIES_USE_BOOST_IOSTREAMS
|
|
||||||
// create raw file descriptor to initialize boost::iostreams::file_descriptor
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
|
||||||
const auto fileDescriptor
|
|
||||||
= CreateFileW(widePath.get(), nativeParams.access, nativeParams.shareMode, nullptr, nativeParams.creation, FILE_ATTRIBUTE_NORMAL);
|
|
||||||
if (fileDescriptor == INVALID_HANDLE_VALUE) {
|
|
||||||
throw std::ios_base::failure("CreateFileW failed");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
const auto fileDescriptor = ::open(path.data(), nativeParams.openFlags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
||||||
if (fileDescriptor == -1) {
|
|
||||||
throw std::ios_base::failure("open failed");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return make_unique<StreamBuffer>(fileDescriptor, boost::iostreams::close_handle);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Internally called by open().
|
|
||||||
*/
|
|
||||||
std::unique_ptr<std::basic_streambuf<char>> NativeFileStream::makeFileBuffer(int fileDescriptor, ios_base::openmode openMode)
|
|
||||||
{
|
|
||||||
// compute native params
|
|
||||||
const NativeFileParams nativeParams(openMode);
|
|
||||||
|
|
||||||
#ifdef CPP_UTILITIES_USE_GNU_CXX_STDIO_FILEBUF
|
|
||||||
// open file handle to initialize stdio_filebuf
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
|
||||||
const auto fileHandle = _get_osfhandle(fileDescriptor);
|
|
||||||
if (fileHandle == -1) {
|
|
||||||
throw std::ios_base::failure("_get_osfhandle failed");
|
|
||||||
}
|
|
||||||
const auto osFileHandle = _open_osfhandle(fileHandle, nativeParams.flags);
|
|
||||||
if (osFileHandle == -1) {
|
|
||||||
throw std::ios_base::failure("_open_osfhandle failed");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
const auto fileHandle = fdopen(fileDescriptor, nativeParams.openMode.data());
|
|
||||||
if (!fileHandle) {
|
|
||||||
throw std::ios_base::failure("fdopen failed");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return make_unique<StreamBuffer>(fileDescriptor, openMode);
|
|
||||||
|
|
||||||
#else // CPP_UTILITIES_USE_BOOST_IOSTREAMS
|
|
||||||
// initialize boost::iostreams::file_descriptor from the specified fileDescriptor
|
|
||||||
return make_unique<StreamBuffer>(fileDescriptor, boost::iostreams::close_handle);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,6 +318,7 @@ std::unique_ptr<wchar_t[]> NativeFileStream::makeWidePath(const std::string &pat
|
||||||
}
|
}
|
||||||
return std::move(widePath.first);
|
return std::move(widePath.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -17,6 +17,21 @@ namespace CppUtilities {
|
||||||
|
|
||||||
class CPP_UTILITIES_EXPORT NativeFileStream : public std::iostream {
|
class CPP_UTILITIES_EXPORT NativeFileStream : public std::iostream {
|
||||||
public:
|
public:
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
using Handle = void *;
|
||||||
|
#endif
|
||||||
|
struct CPP_UTILITIES_EXPORT FileBuffer {
|
||||||
|
FileBuffer(std::basic_streambuf<char> *buffer);
|
||||||
|
FileBuffer(const std::string &path, ios_base::openmode openMode);
|
||||||
|
FileBuffer(int fileDescriptor, ios_base::openmode openMode);
|
||||||
|
|
||||||
|
std::unique_ptr<std::basic_streambuf<char>> buffer;
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
Handle handle = nullptr;
|
||||||
|
#endif
|
||||||
|
int descriptor = -1;
|
||||||
|
};
|
||||||
|
|
||||||
NativeFileStream();
|
NativeFileStream();
|
||||||
NativeFileStream(const std::string &path, std::ios_base::openmode openMode);
|
NativeFileStream(const std::string &path, std::ios_base::openmode openMode);
|
||||||
NativeFileStream(int fileDescriptor, std::ios_base::openmode openMode);
|
NativeFileStream(int fileDescriptor, std::ios_base::openmode openMode);
|
||||||
|
@ -24,34 +39,70 @@ public:
|
||||||
~NativeFileStream();
|
~NativeFileStream();
|
||||||
|
|
||||||
bool is_open() const;
|
bool is_open() const;
|
||||||
|
bool isOpen() const;
|
||||||
void open(const std::string &path, std::ios_base::openmode openMode);
|
void open(const std::string &path, std::ios_base::openmode openMode);
|
||||||
void open(int fileDescriptor, std::ios_base::openmode openMode);
|
void open(int fileDescriptor, std::ios_base::openmode openMode);
|
||||||
void close();
|
void close();
|
||||||
|
int fileDescriptor();
|
||||||
static std::unique_ptr<std::basic_streambuf<char>> makeFileBuffer(const std::string &path, ios_base::openmode openMode);
|
|
||||||
static std::unique_ptr<std::basic_streambuf<char>> makeFileBuffer(int fileDescriptor, ios_base::openmode openMode);
|
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
Handle fileHandle();
|
||||||
static std::unique_ptr<wchar_t[]> makeWidePath(const std::string &path);
|
static std::unique_ptr<wchar_t[]> makeWidePath(const std::string &path);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setFileBuffer(std::unique_ptr<std::basic_streambuf<char>> buffer);
|
void setData(FileBuffer data, std::ios_base::openmode openMode);
|
||||||
|
|
||||||
std::unique_ptr<std::basic_streambuf<char>> m_filebuf;
|
FileBuffer m_data;
|
||||||
|
std::ios_base::openmode m_openMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Constructs a new NativeFileStream. The specified \a path is supposed to be UTF-8 encoded.
|
||||||
|
*/
|
||||||
inline NativeFileStream::NativeFileStream(const std::string &path, ios_base::openmode openMode)
|
inline NativeFileStream::NativeFileStream(const std::string &path, ios_base::openmode openMode)
|
||||||
: NativeFileStream()
|
: NativeFileStream()
|
||||||
{
|
{
|
||||||
open(path, openMode);
|
open(path, openMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Constructs a new NativeFileStream. The specified \a fileDescriptor is either a POSIX file descriptor or a Windows CRT file descriptor.
|
||||||
|
*/
|
||||||
inline NativeFileStream::NativeFileStream(int fileDescriptor, ios_base::openmode openMode)
|
inline NativeFileStream::NativeFileStream(int fileDescriptor, ios_base::openmode openMode)
|
||||||
: NativeFileStream()
|
: NativeFileStream()
|
||||||
{
|
{
|
||||||
open(fileDescriptor, openMode);
|
open(fileDescriptor, openMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the native POSIX or Windows CRT file descriptor.
|
||||||
|
* \remarks Might not be populated if only a Windows file handle is used.
|
||||||
|
*/
|
||||||
|
inline int NativeFileStream::fileDescriptor()
|
||||||
|
{
|
||||||
|
return m_data.descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
|
/*!
|
||||||
|
* \brief Returns the native Windows file handle.
|
||||||
|
* \remarks Might not be populated if only a Windows CRT file descriptor is used.
|
||||||
|
*/
|
||||||
|
inline NativeFileStream::Handle NativeFileStream::fileHandle()
|
||||||
|
{
|
||||||
|
return m_data.handle;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns whether the file is open.
|
||||||
|
* \remarks Same as NativeFileStream::isOpen(); provided for API compatibility with std::fstream.
|
||||||
|
*/
|
||||||
|
inline bool NativeFileStream::is_open() const
|
||||||
|
{
|
||||||
|
return isOpen();
|
||||||
|
}
|
||||||
|
|
||||||
#else // CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
|
#else // CPP_UTILITIES_USE_NATIVE_FILE_BUFFER
|
||||||
|
|
||||||
using NativeFileStream = std::fstream;
|
using NativeFileStream = std::fstream;
|
||||||
|
|
|
@ -411,6 +411,11 @@ void IoTests::testNativeFileStream()
|
||||||
CPPUNIT_ASSERT(!fileStream.is_open());
|
CPPUNIT_ASSERT(!fileStream.is_open());
|
||||||
fileStream.open(txtFilePath, ios_base::in);
|
fileStream.open(txtFilePath, ios_base::in);
|
||||||
CPPUNIT_ASSERT(fileStream.is_open());
|
CPPUNIT_ASSERT(fileStream.is_open());
|
||||||
|
#if defined(PLATFORM_WINDOWS) && defined(CPP_UTILITIES_USE_BOOST_IOSTREAMS)
|
||||||
|
CPPUNIT_ASSERT(fileStream.fileHandle() != nullptr);
|
||||||
|
#else
|
||||||
|
CPPUNIT_ASSERT(fileStream.fileDescriptor() != -1);
|
||||||
|
#endif
|
||||||
CPPUNIT_ASSERT_EQUAL(static_cast<char>(fileStream.get()), 'f');
|
CPPUNIT_ASSERT_EQUAL(static_cast<char>(fileStream.get()), 'f');
|
||||||
fileStream.seekg(0, ios_base::end);
|
fileStream.seekg(0, ios_base::end);
|
||||||
CPPUNIT_ASSERT_EQUAL(fileStream.tellg(), static_cast<NativeFileStream::pos_type>(47));
|
CPPUNIT_ASSERT_EQUAL(fileStream.tellg(), static_cast<NativeFileStream::pos_type>(47));
|
||||||
|
@ -421,10 +426,10 @@ void IoTests::testNativeFileStream()
|
||||||
CPPUNIT_FAIL("expected exception");
|
CPPUNIT_FAIL("expected exception");
|
||||||
} catch (const std::ios_base::failure &failure) {
|
} catch (const std::ios_base::failure &failure) {
|
||||||
#ifdef PLATFORM_WINDOWS
|
#ifdef PLATFORM_WINDOWS
|
||||||
#ifdef CPP_UTILITIES_USE_GNU_CXX_STDIO_FILEBUF
|
#ifdef CPP_UTILITIES_USE_BOOST_IOSTREAMS
|
||||||
CPPUNIT_ASSERT_EQUAL("_wopen failed: iostream error"s, string(failure.what()));
|
|
||||||
#else // CPP_UTILITIES_USE_BOOST_IOSTREAMS
|
|
||||||
CPPUNIT_ASSERT_EQUAL("CreateFileW failed: iostream error"s, string(failure.what()));
|
CPPUNIT_ASSERT_EQUAL("CreateFileW failed: iostream error"s, string(failure.what()));
|
||||||
|
#else
|
||||||
|
CPPUNIT_ASSERT_EQUAL("_wopen failed: iostream error"s, string(failure.what()));
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
CPPUNIT_ASSERT_EQUAL("open failed: iostream error"s, string(failure.what()));
|
CPPUNIT_ASSERT_EQUAL("open failed: iostream error"s, string(failure.what()));
|
||||||
|
@ -452,7 +457,9 @@ void IoTests::testNativeFileStream()
|
||||||
} catch (const std::ios_base::failure &failure) {
|
} catch (const std::ios_base::failure &failure) {
|
||||||
#ifndef PLATFORM_WINDOWS
|
#ifndef PLATFORM_WINDOWS
|
||||||
TESTUTILS_ASSERT_LIKE(
|
TESTUTILS_ASSERT_LIKE(
|
||||||
"expected error message", "(fdopen failed|failed reading: Bad file descriptor): iostream error"s, string(failure.what()));
|
"expected error message", "(basic_ios::clear|failed reading: Bad file descriptor): iostream error"s, string(failure.what()));
|
||||||
|
#else
|
||||||
|
CPP_UTILITIES_UNUSED(failure)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
fileStream.clear();
|
fileStream.clear();
|
||||||
|
|
Loading…
Reference in New Issue