Replace windows_error with system_error

This commit is contained in:
Victor Zverovich
2021-05-06 09:20:46 -07:00
parent 5238055f40
commit 4b885c8633
7 changed files with 76 additions and 70 deletions

View File

@ -70,3 +70,5 @@ jobs:
- name: Test - name: Test
working-directory: ${{runner.workspace}}/build working-directory: ${{runner.workspace}}/build
run: ctest -C ${{matrix.build_type}} run: ctest -C ${{matrix.build_type}}
env:
CTEST_OUTPUT_ON_FAILURE: True

View File

@ -28,3 +28,5 @@ jobs:
- name: Test - name: Test
working-directory: ${{runner.workspace}}/build working-directory: ${{runner.workspace}}/build
run: ctest -C ${{matrix.build_type}} run: ctest -C ${{matrix.build_type}}
env:
CTEST_OUTPUT_ON_FAILURE: True

View File

@ -54,3 +54,5 @@ jobs:
- name: Test - name: Test
working-directory: ${{runner.workspace}}/build working-directory: ${{runner.workspace}}/build
run: ctest -C ${{matrix.build_type}} run: ctest -C ${{matrix.build_type}}
env:
CTEST_OUTPUT_ON_FAILURE: True

View File

@ -9,10 +9,11 @@
#define FMT_OS_H_ #define FMT_OS_H_
#include <cerrno> #include <cerrno>
#include <clocale> // for locale_t #include <clocale> // locale_t
#include <cstddef> #include <cstddef>
#include <cstdio> #include <cstdio>
#include <cstdlib> // for strtod_l #include <cstdlib> // strtod_l
#include <system_error> // std::system_error
#if defined __APPLE__ || defined(__FreeBSD__) #if defined __APPLE__ || defined(__FreeBSD__)
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X # include <xlocale.h> // for LC_NUMERIC_MASK on OS X
@ -154,45 +155,42 @@ FMT_API void format_windows_error(buffer<char>& out, int error_code,
string_view message) FMT_NOEXCEPT; string_view message) FMT_NOEXCEPT;
} // namespace detail } // namespace detail
/** A Windows error. */ FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
class windows_error : public system_error { format_args args);
private:
FMT_API void init(int error_code, string_view format_str, format_args args);
public: /**
/** \rst
\rst Constructs a :class:`std::system_error` object with the description
Constructs a :class:`fmt::windows_error` object with the description of the form
of the form
.. parsed-literal:: .. parsed-literal::
*<message>*: *<system-message>* *<message>*: *<system-message>*
where *<message>* is the formatted message and *<system-message>* is the where *<message>* is the formatted message and *<system-message>* is the
system message corresponding to the error code. system message corresponding to the error code.
*error_code* is a Windows error code as given by ``GetLastError``. *error_code* is a Windows error code as given by ``GetLastError``.
If *error_code* is not a valid error code such as -1, the system message If *error_code* is not a valid error code such as -1, the system message
will look like "error -1". will look like "error -1".
**Example**:: **Example**::
// This throws a windows_error with the description // This throws a windows_error with the description
// cannot open file 'madeup': The system cannot find the file specified. // cannot open file 'madeup': The system cannot find the file specified.
// or similar (system message may vary). // or similar (system message may vary).
const char *filename = "madeup"; const char *filename = "madeup";
LPOFSTRUCT of = LPOFSTRUCT(); LPOFSTRUCT of = LPOFSTRUCT();
HFILE file = OpenFile(filename, &of, OF_READ); HFILE file = OpenFile(filename, &of, OF_READ);
if (file == HFILE_ERROR) { if (file == HFILE_ERROR) {
throw fmt::windows_error(GetLastError(), throw fmt::windows_error(GetLastError(),
"cannot open file '{}'", filename); "cannot open file '{}'", filename);
} }
\endrst \endrst
*/ */
template <typename... Args> template <typename... Args>
windows_error(int error_code, string_view message, const Args&... args) { std::system_error windows_error(int error_code, string_view message,
init(error_code, message, make_format_args(args...)); const Args&... args) {
} return vwindows_error(error_code, message, make_format_args(args...));
}; }
// Reports a Windows error without throwing an exception. // Reports a Windows error without throwing an exception.
// Can be used to report errors from destructors. // Can be used to report errors from destructors.

View File

@ -100,13 +100,10 @@ int detail::utf16_to_utf8::convert(wstring_view s) {
return 0; return 0;
} }
void windows_error::init(int err_code, string_view format_str, std::system_error vwindows_error(int err_code, string_view format_str,
format_args args) { format_args args) {
error_code_ = err_code; auto ec = std::error_code(err_code, std::system_category());
memory_buffer buffer; throw std::system_error(ec, vformat(format_str, args));
detail::format_windows_error(buffer, err_code, vformat(format_str, args));
std::runtime_error& base = *this;
base = std::runtime_error(to_string(buffer));
} }
void detail::format_windows_error(detail::buffer<char>& out, int error_code, void detail::format_windows_error(detail::buffer<char>& out, int error_code,

View File

@ -20,6 +20,7 @@
using fmt::buffered_file; using fmt::buffered_file;
using fmt::error_code; using fmt::error_code;
using testing::HasSubstr;
#ifdef _WIN32 #ifdef _WIN32
@ -45,14 +46,15 @@ void check_utf_conversion_error(
fmt::basic_string_view<Char> str = fmt::basic_string_view<Char>(0, 1)) { fmt::basic_string_view<Char> str = fmt::basic_string_view<Char>(0, 1)) {
fmt::memory_buffer out; fmt::memory_buffer out;
fmt::detail::format_windows_error(out, ERROR_INVALID_PARAMETER, message); fmt::detail::format_windows_error(out, ERROR_INVALID_PARAMETER, message);
auto error = fmt::system_error(0, ""); out.resize(out.size() - 2); // Remove newline.
auto error = std::system_error(std::error_code());
try { try {
(Converter)(str); (Converter)(str);
} catch (const fmt::system_error& e) { } catch (const std::system_error& e) {
error = e; error = e;
} }
EXPECT_EQ(ERROR_INVALID_PARAMETER, error.error_code()); EXPECT_EQ(ERROR_INVALID_PARAMETER, error.code().value());
EXPECT_EQ(fmt::to_string(out), error.what()); EXPECT_THAT(error.what(), HasSubstr(fmt::to_string(out)));
} }
TEST(util_test, utf16_to_utf8_error) { TEST(util_test, utf16_to_utf8_error) {
@ -69,11 +71,11 @@ TEST(util_test, utf16_to_utf8_convert) {
TEST(os_test, format_windows_error) { TEST(os_test, format_windows_error) {
LPWSTR message = 0; LPWSTR message = 0;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | auto result = FormatMessageW(
FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
0, ERROR_FILE_EXISTS, FORMAT_MESSAGE_IGNORE_INSERTS,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 0, ERROR_FILE_EXISTS, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&message), 0, 0); reinterpret_cast<LPWSTR>(&message), 0, 0);
fmt::detail::utf16_to_utf8 utf8_message(message); fmt::detail::utf16_to_utf8 utf8_message(message);
LocalFree(message); LocalFree(message);
fmt::memory_buffer actual_message; fmt::memory_buffer actual_message;
@ -93,16 +95,14 @@ TEST(os_test, format_long_windows_error) {
// this error code is not available on all Windows platforms and // this error code is not available on all Windows platforms and
// Windows SDKs, so do not fail the test if the error string cannot // Windows SDKs, so do not fail the test if the error string cannot
// be retrieved. // be retrieved.
const int provisioning_not_allowed = int provisioning_not_allowed = 0x80284013L; // TBS_E_PROVISIONING_NOT_ALLOWED
0x80284013L /*TBS_E_PROVISIONING_NOT_ALLOWED*/; auto result = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
FORMAT_MESSAGE_IGNORE_INSERTS, 0, static_cast<DWORD>(provisioning_not_allowed),
0, static_cast<DWORD>(provisioning_not_allowed), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&message), 0, 0);
reinterpret_cast<LPWSTR>(&message), 0, 0) == 0) { EXPECT_NE(result, 0);
return;
}
fmt::detail::utf16_to_utf8 utf8_message(message); fmt::detail::utf16_to_utf8 utf8_message(message);
LocalFree(message); LocalFree(message);
fmt::memory_buffer actual_message; fmt::memory_buffer actual_message;
@ -113,16 +113,17 @@ TEST(os_test, format_long_windows_error) {
} }
TEST(os_test, windows_error) { TEST(os_test, windows_error) {
auto error = fmt::system_error(0, ""); auto error = std::system_error(std::error_code());
try { try {
throw fmt::windows_error(ERROR_FILE_EXISTS, "test {}", "error"); throw fmt::windows_error(ERROR_FILE_EXISTS, "test {}", "error");
} catch (const fmt::system_error& e) { } catch (const std::system_error& e) {
error = e; error = e;
} }
fmt::memory_buffer message; fmt::memory_buffer message;
fmt::detail::format_windows_error(message, ERROR_FILE_EXISTS, "test error"); fmt::detail::format_windows_error(message, ERROR_FILE_EXISTS, "test error");
EXPECT_EQ(to_string(message), error.what()); message.resize(message.size() - 2);
EXPECT_EQ(ERROR_FILE_EXISTS, error.error_code()); EXPECT_THAT(error.what(), HasSubstr(to_string(message)));
EXPECT_EQ(ERROR_FILE_EXISTS, error.code().value());
} }
TEST(os_test, report_windows_error) { TEST(os_test, report_windows_error) {

View File

@ -264,12 +264,16 @@ TEST(file_test, size) {
EXPECT_GE(f.size(), 0); EXPECT_GE(f.size(), 0);
EXPECT_EQ(content.size(), static_cast<unsigned long long>(f.size())); EXPECT_EQ(content.size(), static_cast<unsigned long long>(f.size()));
# ifdef _WIN32 # ifdef _WIN32
fmt::memory_buffer message; auto error_code = std::error_code();
fmt::detail::format_windows_error(message, ERROR_ACCESS_DENIED,
"cannot get file size");
fstat_sim = error; fstat_sim = error;
EXPECT_THROW_MSG(f.size(), fmt::windows_error, fmt::to_string(message)); try {
f.size();
} catch (const std::system_error& e) {
error_code = e.code();
}
fstat_sim = none; fstat_sim = none;
EXPECT_EQ(error_code,
std::error_code(ERROR_ACCESS_DENIED, std::system_category()));
# else # else
f.close(); f.close();
EXPECT_SYSTEM_ERROR(f.size(), EBADF, "cannot get file attributes"); EXPECT_SYSTEM_ERROR(f.size(), EBADF, "cannot get file attributes");