mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-01 14:10:06 +00:00
Improve POSIX API detection
This commit is contained in:
parent
2145a7bdcc
commit
dcde089b4e
@ -135,10 +135,8 @@ endif ()
|
|||||||
|
|
||||||
include(CheckSymbolExists)
|
include(CheckSymbolExists)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
check_symbol_exists(open io.h HAVE_OPEN)
|
|
||||||
check_symbol_exists(_strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
|
check_symbol_exists(_strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
|
||||||
else ()
|
else ()
|
||||||
check_symbol_exists(open fcntl.h HAVE_OPEN)
|
|
||||||
check_symbol_exists(strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
|
check_symbol_exists(strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
@ -152,13 +150,9 @@ endfunction()
|
|||||||
|
|
||||||
# Define the fmt library, its includes and the needed defines.
|
# Define the fmt library, its includes and the needed defines.
|
||||||
add_headers(FMT_HEADERS chrono.h color.h compile.h core.h format.h format-inl.h
|
add_headers(FMT_HEADERS chrono.h color.h compile.h core.h format.h format-inl.h
|
||||||
locale.h ostream.h printf.h ranges.h
|
locale.h ostream.h posix.h printf.h ranges.h
|
||||||
safe-duration-cast.h)
|
safe-duration-cast.h)
|
||||||
set(FMT_SOURCES src/format.cc)
|
set(FMT_SOURCES src/format.cc src/posix.cc)
|
||||||
if (HAVE_OPEN)
|
|
||||||
add_headers(FMT_HEADERS posix.h)
|
|
||||||
set(FMT_SOURCES ${FMT_SOURCES} src/posix.cc)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
|
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
|
||||||
add_library(fmt::fmt ALIAS fmt)
|
add_library(fmt::fmt ALIAS fmt)
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <fcntl.h> // for O_RDONLY
|
|
||||||
#include <clocale> // for locale_t
|
#include <clocale> // for locale_t
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib> // for strtod_l
|
#include <cstdlib> // for strtod_l
|
||||||
@ -27,6 +26,13 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
#if FMT_HAS_INCLUDE("fcntl.h")
|
||||||
|
# include <fcntl.h> // for O_RDONLY
|
||||||
|
# define FMT_USE_FCNTL 1
|
||||||
|
#else
|
||||||
|
# define FMT_USE_FCNTL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FMT_POSIX
|
#ifndef FMT_POSIX
|
||||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
// Fix warnings about deprecated symbols.
|
// Fix warnings about deprecated symbols.
|
||||||
@ -176,6 +182,7 @@ class buffered_file {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if FMT_USE_FCNTL
|
||||||
// A file. Closed file is represented by a file object with descriptor -1.
|
// A file. Closed file is represented by a file object with descriptor -1.
|
||||||
// Methods that are not declared with FMT_NOEXCEPT may throw
|
// Methods that are not declared with FMT_NOEXCEPT may throw
|
||||||
// fmt::system_error in case of failure. Note that some errors such as
|
// fmt::system_error in case of failure. Note that some errors such as
|
||||||
@ -258,6 +265,7 @@ class file {
|
|||||||
|
|
||||||
// Returns the memory page size.
|
// Returns the memory page size.
|
||||||
long getpagesize();
|
long getpagesize();
|
||||||
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
#ifdef FMT_LOCALE
|
#ifdef FMT_LOCALE
|
||||||
// A "C" numeric locale.
|
// A "C" numeric locale.
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
#include "fmt/posix.h"
|
#include "fmt/posix.h"
|
||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
|
#if FMT_USE_FCNTL
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
@ -39,8 +41,8 @@
|
|||||||
# ifdef __MINGW32__
|
# ifdef __MINGW32__
|
||||||
# define _SH_DENYNO 0x40
|
# define _SH_DENYNO 0x40
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
#ifdef fileno
|
#ifdef fileno
|
||||||
# undef fileno
|
# undef fileno
|
||||||
@ -94,6 +96,7 @@ int buffered_file::fileno() const {
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FMT_USE_FCNTL
|
||||||
file::file(cstring_view path, int oflag) {
|
file::file(cstring_view path, int oflag) {
|
||||||
int mode = S_IRUSR | S_IWUSR;
|
int mode = S_IRUSR | S_IWUSR;
|
||||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
@ -230,4 +233,5 @@ long getpagesize() {
|
|||||||
return size;
|
return size;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif // FMT_USE_FCNTL
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
@ -47,8 +47,6 @@ target_compile_definitions(gmock
|
|||||||
|
|
||||||
set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
|
set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
|
||||||
add_library(test-main STATIC ${TEST_MAIN_SRC})
|
add_library(test-main STATIC ${TEST_MAIN_SRC})
|
||||||
target_compile_definitions(test-main PUBLIC
|
|
||||||
FMT_USE_FILE_DESCRIPTORS=$<BOOL:${HAVE_OPEN}>)
|
|
||||||
target_include_directories(test-main SYSTEM PUBLIC gtest gmock)
|
target_include_directories(test-main SYSTEM PUBLIC gtest gmock)
|
||||||
target_link_libraries(test-main gmock fmt)
|
target_link_libraries(test-main gmock fmt)
|
||||||
|
|
||||||
@ -113,7 +111,7 @@ add_fmt_test(custom-formatter-test)
|
|||||||
add_fmt_test(ranges-test)
|
add_fmt_test(ranges-test)
|
||||||
add_fmt_test(scan-test)
|
add_fmt_test(scan-test)
|
||||||
|
|
||||||
if (HAVE_OPEN AND NOT MSVC_BUILD_STATIC)
|
if (NOT MSVC_BUILD_STATIC)
|
||||||
add_fmt_executable(posix-mock-test
|
add_fmt_executable(posix-mock-test
|
||||||
posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC})
|
posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC})
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
|
@ -1819,7 +1819,7 @@ TEST(FormatIntTest, FormatInt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, Print) {
|
TEST(FormatTest, Print) {
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FCNTL
|
||||||
EXPECT_WRITE(stdout, fmt::print("Don't {}!", "panic"), "Don't panic!");
|
EXPECT_WRITE(stdout, fmt::print("Don't {}!", "panic"), "Don't panic!");
|
||||||
EXPECT_WRITE(stderr, fmt::print(stderr, "Don't {}!", "panic"),
|
EXPECT_WRITE(stderr, fmt::print(stderr, "Don't {}!", "panic"),
|
||||||
"Don't panic!");
|
"Don't panic!");
|
||||||
|
@ -74,14 +74,6 @@ TEST_F(SingleEvaluationTest, FailedEXPECT_SYSTEM_ERROR) {
|
|||||||
EXPECT_EQ(s_ + 1, p_);
|
EXPECT_EQ(s_ + 1, p_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that when EXPECT_WRITE fails, it evaluates its message argument
|
|
||||||
// exactly once.
|
|
||||||
TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) {
|
|
||||||
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), p_++),
|
|
||||||
"01234");
|
|
||||||
EXPECT_EQ(s_ + 1, p_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests that assertion arguments are evaluated exactly once.
|
// Tests that assertion arguments are evaluated exactly once.
|
||||||
TEST_F(SingleEvaluationTest, ExceptionTests) {
|
TEST_F(SingleEvaluationTest, ExceptionTests) {
|
||||||
// successful EXPECT_THROW_MSG
|
// successful EXPECT_THROW_MSG
|
||||||
@ -163,6 +155,15 @@ TEST_F(SingleEvaluationTest, SystemErrorTests) {
|
|||||||
EXPECT_EQ(4, b_);
|
EXPECT_EQ(4, b_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FMT_USE_FCNTL
|
||||||
|
// Tests that when EXPECT_WRITE fails, it evaluates its message argument
|
||||||
|
// exactly once.
|
||||||
|
TEST_F(SingleEvaluationTest, FailedEXPECT_WRITE) {
|
||||||
|
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), p_++),
|
||||||
|
"01234");
|
||||||
|
EXPECT_EQ(s_ + 1, p_);
|
||||||
|
}
|
||||||
|
|
||||||
// Tests that assertion arguments are evaluated exactly once.
|
// Tests that assertion arguments are evaluated exactly once.
|
||||||
TEST_F(SingleEvaluationTest, WriteTests) {
|
TEST_F(SingleEvaluationTest, WriteTests) {
|
||||||
// successful EXPECT_WRITE
|
// successful EXPECT_WRITE
|
||||||
@ -187,6 +188,24 @@ TEST_F(SingleEvaluationTest, WriteTests) {
|
|||||||
EXPECT_EQ(2, b_);
|
EXPECT_EQ(2, b_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests EXPECT_WRITE.
|
||||||
|
TEST(ExpectTest, EXPECT_WRITE) {
|
||||||
|
EXPECT_WRITE(stdout, do_nothing(), "");
|
||||||
|
EXPECT_WRITE(stdout, std::printf("test"), "test");
|
||||||
|
EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test");
|
||||||
|
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("that"), "this"),
|
||||||
|
"Expected: this\n"
|
||||||
|
" Actual: that");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StreamingAssertionsTest, EXPECT_WRITE) {
|
||||||
|
EXPECT_WRITE(stdout, std::printf("test"), "test") << "unexpected failure";
|
||||||
|
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), "other")
|
||||||
|
<< "expected failure",
|
||||||
|
"expected failure");
|
||||||
|
}
|
||||||
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
// Tests that the compiler will not complain about unreachable code in the
|
// Tests that the compiler will not complain about unreachable code in the
|
||||||
// EXPECT_THROW_MSG macro.
|
// EXPECT_THROW_MSG macro.
|
||||||
TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
|
TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) {
|
||||||
@ -280,16 +299,6 @@ TEST(ExpectTest, EXPECT_SYSTEM_ERROR) {
|
|||||||
format_system_error(EDOM, "test")));
|
format_system_error(EDOM, "test")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests EXPECT_WRITE.
|
|
||||||
TEST(ExpectTest, EXPECT_WRITE) {
|
|
||||||
EXPECT_WRITE(stdout, do_nothing(), "");
|
|
||||||
EXPECT_WRITE(stdout, std::printf("test"), "test");
|
|
||||||
EXPECT_WRITE(stderr, std::fprintf(stderr, "test"), "test");
|
|
||||||
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("that"), "this"),
|
|
||||||
"Expected: this\n"
|
|
||||||
" Actual: that");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) {
|
TEST(StreamingAssertionsTest, EXPECT_THROW_MSG) {
|
||||||
EXPECT_THROW_MSG(throw_exception(), std::exception, "test")
|
EXPECT_THROW_MSG(throw_exception(), std::exception, "test")
|
||||||
<< "unexpected failure";
|
<< "unexpected failure";
|
||||||
@ -308,20 +317,13 @@ TEST(StreamingAssertionsTest, EXPECT_SYSTEM_ERROR) {
|
|||||||
"expected failure");
|
"expected failure");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(StreamingAssertionsTest, EXPECT_WRITE) {
|
|
||||||
EXPECT_WRITE(stdout, std::printf("test"), "test") << "unexpected failure";
|
|
||||||
EXPECT_NONFATAL_FAILURE(EXPECT_WRITE(stdout, std::printf("test"), "other")
|
|
||||||
<< "expected failure",
|
|
||||||
"expected failure");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(UtilTest, FormatSystemError) {
|
TEST(UtilTest, FormatSystemError) {
|
||||||
fmt::memory_buffer out;
|
fmt::memory_buffer out;
|
||||||
fmt::format_system_error(out, EDOM, "test message");
|
fmt::format_system_error(out, EDOM, "test message");
|
||||||
EXPECT_EQ(to_string(out), format_system_error(EDOM, "test message"));
|
EXPECT_EQ(to_string(out), format_system_error(EDOM, "test message"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FCNTL
|
||||||
|
|
||||||
using fmt::buffered_file;
|
using fmt::buffered_file;
|
||||||
using fmt::error_code;
|
using fmt::error_code;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include "gtest-extra.h"
|
#include "gtest-extra.h"
|
||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FCNTL
|
||||||
|
|
||||||
using fmt::file;
|
using fmt::file;
|
||||||
|
|
||||||
|
@ -10,16 +10,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "gmock.h"
|
#include "gmock.h"
|
||||||
|
#include "fmt/posix.h"
|
||||||
#include "fmt/core.h"
|
|
||||||
|
|
||||||
#ifndef FMT_USE_FILE_DESCRIPTORS
|
|
||||||
# define FMT_USE_FILE_DESCRIPTORS 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
|
||||||
# include "fmt/posix.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
|
#define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \
|
||||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||||
@ -65,7 +56,7 @@ std::string format_system_error(int error_code, fmt::string_view message);
|
|||||||
EXPECT_THROW_MSG(statement, fmt::system_error, \
|
EXPECT_THROW_MSG(statement, fmt::system_error, \
|
||||||
format_system_error(error_code, message))
|
format_system_error(error_code, message))
|
||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FCNTL
|
||||||
|
|
||||||
// Captures file output by redirecting it to a pipe.
|
// Captures file output by redirecting it to a pipe.
|
||||||
// The output it can handle is limited by the pipe capacity.
|
// The output it can handle is limited by the pipe capacity.
|
||||||
@ -151,7 +142,9 @@ std::string read(fmt::file& f, std::size_t count);
|
|||||||
# define EXPECT_READ(file, expected_content) \
|
# define EXPECT_READ(file, expected_content) \
|
||||||
EXPECT_EQ(expected_content, read(file, std::strlen(expected_content)))
|
EXPECT_EQ(expected_content, read(file, std::strlen(expected_content)))
|
||||||
|
|
||||||
#endif // FMT_USE_FILE_DESCRIPTORS
|
#else
|
||||||
|
# define EXPECT_WRITE(file, statement, expected_output) SUCCEED()
|
||||||
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
template <typename Mock> struct ScopedMock : testing::StrictMock<Mock> {
|
template <typename Mock> struct ScopedMock : testing::StrictMock<Mock> {
|
||||||
ScopedMock() { Mock::instance = this; }
|
ScopedMock() { Mock::instance = this; }
|
||||||
|
@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
using fmt::buffered_file;
|
using fmt::buffered_file;
|
||||||
using fmt::error_code;
|
using fmt::error_code;
|
||||||
using fmt::file;
|
|
||||||
|
|
||||||
using testing::_;
|
using testing::_;
|
||||||
using testing::Return;
|
using testing::Return;
|
||||||
@ -198,6 +197,9 @@ static void write_file(fmt::cstring_view filename, fmt::string_view content) {
|
|||||||
f.print("{}", content);
|
f.print("{}", content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FMT_USE_FCNTL
|
||||||
|
using fmt::file;
|
||||||
|
|
||||||
TEST(UtilTest, GetPageSize) {
|
TEST(UtilTest, GetPageSize) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SYSTEM_INFO si = {};
|
SYSTEM_INFO si = {};
|
||||||
@ -429,6 +431,7 @@ TEST(BufferedFileTest, FilenoNoRetry) {
|
|||||||
EXPECT_EQ(2, fileno_count);
|
EXPECT_EQ(2, fileno_count);
|
||||||
fileno_count = 0;
|
fileno_count = 0;
|
||||||
}
|
}
|
||||||
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
struct TestMock {
|
struct TestMock {
|
||||||
static TestMock* instance;
|
static TestMock* instance;
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
|
|
||||||
using fmt::buffered_file;
|
using fmt::buffered_file;
|
||||||
using fmt::error_code;
|
using fmt::error_code;
|
||||||
|
|
||||||
|
#if FMT_USE_FCNTL
|
||||||
|
|
||||||
using fmt::file;
|
using fmt::file;
|
||||||
|
|
||||||
// Checks if the file is open by reading one character from it.
|
// Checks if the file is open by reading one character from it.
|
||||||
@ -376,3 +379,4 @@ TEST(LocaleTest, Strtod) {
|
|||||||
EXPECT_EQ(start + 3, ptr);
|
EXPECT_EQ(start + 3, ptr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif // FMT_USE_FCNTL
|
@ -477,7 +477,7 @@ enum E { A = 42 };
|
|||||||
|
|
||||||
TEST(PrintfTest, Enum) { EXPECT_PRINTF("42", "%d", A); }
|
TEST(PrintfTest, Enum) { EXPECT_PRINTF("42", "%d", A); }
|
||||||
|
|
||||||
#if FMT_USE_FILE_DESCRIPTORS
|
#if FMT_USE_FCNTL
|
||||||
TEST(PrintfTest, Examples) {
|
TEST(PrintfTest, Examples) {
|
||||||
const char* weekday = "Thursday";
|
const char* weekday = "Thursday";
|
||||||
const char* month = "August";
|
const char* month = "August";
|
||||||
|
@ -33,11 +33,17 @@ std::string get_system_error(int error_code) {
|
|||||||
const char* const FILE_CONTENT = "Don't panic!";
|
const char* const FILE_CONTENT = "Don't panic!";
|
||||||
|
|
||||||
fmt::buffered_file open_buffered_file(FILE** fp) {
|
fmt::buffered_file open_buffered_file(FILE** fp) {
|
||||||
|
#if FMT_USE_FCNTL
|
||||||
fmt::file read_end, write_end;
|
fmt::file read_end, write_end;
|
||||||
fmt::file::pipe(read_end, write_end);
|
fmt::file::pipe(read_end, write_end);
|
||||||
write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT));
|
write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT));
|
||||||
write_end.close();
|
write_end.close();
|
||||||
fmt::buffered_file f = read_end.fdopen("r");
|
fmt::buffered_file f = read_end.fdopen("r");
|
||||||
if (fp) *fp = f.get();
|
if (fp) *fp = f.get();
|
||||||
|
#else
|
||||||
|
fmt::buffered_file f("test-file", "w");
|
||||||
|
fputs(FILE_CONTENT, f.get());
|
||||||
|
if (fp) *fp = f.get();
|
||||||
|
#endif
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user