From 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 20:24:20 +0200 Subject: Adding upstream version 14.2.21. Signed-off-by: Daniel Baumann --- src/seastar/fmt/test/CMakeLists.txt | 204 + .../fmt/test/add-subdirectory-test/CMakeLists.txt | 17 + src/seastar/fmt/test/add-subdirectory-test/main.cc | 6 + src/seastar/fmt/test/assert-test.cc | 22 + src/seastar/fmt/test/chrono-test.cc | 170 + src/seastar/fmt/test/compile-test/CMakeLists.txt | 79 + src/seastar/fmt/test/core-test.cc | 613 + src/seastar/fmt/test/custom-formatter-test.cc | 52 + .../fmt/test/find-package-test/CMakeLists.txt | 17 + src/seastar/fmt/test/find-package-test/main.cc | 6 + src/seastar/fmt/test/format-impl-test.cc | 236 + src/seastar/fmt/test/format-test.cc | 2462 +++ src/seastar/fmt/test/gmock-gtest-all.cc | 11443 +++++++++++ src/seastar/fmt/test/gmock/gmock.h | 14204 +++++++++++++ src/seastar/fmt/test/gtest-extra-test.cc | 413 + src/seastar/fmt/test/gtest-extra.cc | 90 + src/seastar/fmt/test/gtest-extra.h | 161 + src/seastar/fmt/test/gtest/gtest-spi.h | 232 + src/seastar/fmt/test/gtest/gtest.h | 20065 +++++++++++++++++++ src/seastar/fmt/test/header-only-test.cc | 3 + src/seastar/fmt/test/header-only-test2.cc | 3 + src/seastar/fmt/test/locale-test.cc | 34 + src/seastar/fmt/test/mock-allocator.h | 62 + src/seastar/fmt/test/ostream-test.cc | 200 + src/seastar/fmt/test/posix-mock-test.cc | 539 + src/seastar/fmt/test/posix-mock.h | 69 + src/seastar/fmt/test/posix-test.cc | 378 + src/seastar/fmt/test/printf-test.cc | 569 + src/seastar/fmt/test/ranges-test.cc | 87 + src/seastar/fmt/test/test-assert.h | 26 + src/seastar/fmt/test/test-main.cc | 42 + src/seastar/fmt/test/time-test.cc | 68 + src/seastar/fmt/test/util.cc | 44 + src/seastar/fmt/test/util.h | 85 + 34 files changed, 52701 insertions(+) create mode 100644 src/seastar/fmt/test/CMakeLists.txt create mode 100644 src/seastar/fmt/test/add-subdirectory-test/CMakeLists.txt create mode 100644 src/seastar/fmt/test/add-subdirectory-test/main.cc create mode 100644 src/seastar/fmt/test/assert-test.cc create mode 100644 src/seastar/fmt/test/chrono-test.cc create mode 100644 src/seastar/fmt/test/compile-test/CMakeLists.txt create mode 100644 src/seastar/fmt/test/core-test.cc create mode 100644 src/seastar/fmt/test/custom-formatter-test.cc create mode 100644 src/seastar/fmt/test/find-package-test/CMakeLists.txt create mode 100644 src/seastar/fmt/test/find-package-test/main.cc create mode 100644 src/seastar/fmt/test/format-impl-test.cc create mode 100644 src/seastar/fmt/test/format-test.cc create mode 100644 src/seastar/fmt/test/gmock-gtest-all.cc create mode 100644 src/seastar/fmt/test/gmock/gmock.h create mode 100644 src/seastar/fmt/test/gtest-extra-test.cc create mode 100644 src/seastar/fmt/test/gtest-extra.cc create mode 100644 src/seastar/fmt/test/gtest-extra.h create mode 100644 src/seastar/fmt/test/gtest/gtest-spi.h create mode 100644 src/seastar/fmt/test/gtest/gtest.h create mode 100644 src/seastar/fmt/test/header-only-test.cc create mode 100644 src/seastar/fmt/test/header-only-test2.cc create mode 100644 src/seastar/fmt/test/locale-test.cc create mode 100644 src/seastar/fmt/test/mock-allocator.h create mode 100644 src/seastar/fmt/test/ostream-test.cc create mode 100644 src/seastar/fmt/test/posix-mock-test.cc create mode 100644 src/seastar/fmt/test/posix-mock.h create mode 100644 src/seastar/fmt/test/posix-test.cc create mode 100644 src/seastar/fmt/test/printf-test.cc create mode 100644 src/seastar/fmt/test/ranges-test.cc create mode 100644 src/seastar/fmt/test/test-assert.h create mode 100644 src/seastar/fmt/test/test-main.cc create mode 100644 src/seastar/fmt/test/time-test.cc create mode 100644 src/seastar/fmt/test/util.cc create mode 100644 src/seastar/fmt/test/util.h (limited to 'src/seastar/fmt/test') diff --git a/src/seastar/fmt/test/CMakeLists.txt b/src/seastar/fmt/test/CMakeLists.txt new file mode 100644 index 00000000..70e19db7 --- /dev/null +++ b/src/seastar/fmt/test/CMakeLists.txt @@ -0,0 +1,204 @@ +#------------------------------------------------------------------------------ +# Build the google test library + +# We compile Google Test ourselves instead of using pre-compiled libraries. +# See the Google Test FAQ "Why is it not recommended to install a +# pre-compiled copy of Google Test (for example, into /usr/local)?" +# at http://code.google.com/p/googletest/wiki/FAQ for more details. +add_library(gmock STATIC + gmock-gtest-all.cc gmock/gmock.h gtest/gtest.h gtest/gtest-spi.h) +target_compile_definitions(gmock PUBLIC GTEST_HAS_STD_WSTRING=1) +target_include_directories(gmock SYSTEM PUBLIC . gmock gtest) + +find_package(Threads) +if (Threads_FOUND) + target_link_libraries(gmock ${CMAKE_THREAD_LIBS_INIT}) +else () + target_compile_definitions(gmock PUBLIC GTEST_HAS_PTHREAD=0) +endif () + +if (NOT SUPPORTS_VARIADIC_TEMPLATES OR NOT SUPPORTS_INITIALIZER_LIST) + target_compile_definitions(gmock PUBLIC GTEST_LANG_CXX11=0) +endif () + +# Workaround a bug in implementation of variadic templates in MSVC11. +if (MSVC) + target_compile_definitions(gmock PUBLIC _VARIADIC_MAX=10) +endif () + +# GTest doesn't detect with clang. +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + target_compile_definitions(gmock PUBLIC GTEST_USE_OWN_TR1_TUPLE=1) +endif () + +# Silence MSVC tr1 deprecation warning in gmock. +target_compile_definitions(gmock + PUBLIC _SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING=0) + +#------------------------------------------------------------------------------ +# Build the actual library tests + +set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc) +add_library(test-main STATIC ${TEST_MAIN_SRC}) +target_compile_definitions(test-main PUBLIC + FMT_USE_FILE_DESCRIPTORS=$) +target_include_directories(test-main SYSTEM PUBLIC gtest gmock) +target_link_libraries(test-main gmock fmt) + +include(CheckCXXCompilerFlag) + +# Workaround GTest bug https://github.com/google/googletest/issues/705. +check_cxx_compiler_flag( + -fno-delete-null-pointer-checks HAVE_FNO_DELETE_NULL_POINTER_CHECKS) +if (HAVE_FNO_DELETE_NULL_POINTER_CHECKS) + target_compile_options(test-main PUBLIC -fno-delete-null-pointer-checks) +endif () + +# Use less strict pedantic flags for the tests because GMock doesn't compile +# cleanly with -pedantic and -std=c++98. +if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) + #set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wno-long-long -Wno-variadic-macros) +endif () + +function(add_fmt_executable name) + add_executable(${name} ${ARGN}) + if (MINGW) + target_link_libraries(${name} -static-libgcc -static-libstdc++) + endif () +endfunction() + +# Adds a test. +# Usage: add_fmt_test(name srcs...) +function(add_fmt_test name) + add_fmt_executable(${name} ${name}.cc ${ARGN}) + target_link_libraries(${name} test-main) + + # Define if certain C++ features can be used. + target_compile_definitions(${name} PRIVATE + FMT_USE_TYPE_TRAITS=$ + FMT_USE_ENUM_BASE=$) + if (FMT_PEDANTIC) + target_compile_options(${name} PRIVATE ${PEDANTIC_COMPILE_FLAGS}) + endif () + target_include_directories(${name} SYSTEM PUBLIC gtest gmock) + add_test(NAME ${name} COMMAND ${name}) +endfunction() + +add_fmt_test(assert-test) +add_fmt_test(chrono-test) +add_fmt_test(core-test) +add_fmt_test(gtest-extra-test) +add_fmt_test(format-test mock-allocator.h) +if (NOT (MSVC AND BUILD_SHARED_LIBS)) + add_fmt_test(format-impl-test) +endif () +add_fmt_test(locale-test) +add_fmt_test(ostream-test) +add_fmt_test(printf-test) +add_fmt_test(time-test) +add_fmt_test(custom-formatter-test) +add_fmt_test(ranges-test) + +if (HAVE_OPEN) + add_fmt_executable(posix-mock-test + posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC}) + target_include_directories( + posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include) + target_compile_definitions(posix-mock-test PRIVATE FMT_USE_FILE_DESCRIPTORS=1) + target_link_libraries(posix-mock-test gmock) + target_include_directories(posix-mock-test SYSTEM PUBLIC gtest gmock) + if (FMT_PEDANTIC) + target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS}) + endif () + add_test(NAME posix-mock-test COMMAND posix-mock-test) + add_fmt_test(posix-test) +endif () + +add_fmt_executable(header-only-test + header-only-test.cc header-only-test2.cc test-main.cc) +target_link_libraries(header-only-test gmock) +target_include_directories(header-only-test SYSTEM PUBLIC gtest gmock) +if (TARGET fmt-header-only) + target_link_libraries(header-only-test fmt-header-only) +else () + target_include_directories( + header-only-test PRIVATE ${PROJECT_SOURCE_DIR}/include) + target_compile_definitions(header-only-test PRIVATE FMT_HEADER_ONLY=1) +endif () + +# Test that the library can be compiled with exceptions disabled. +# -fno-exception is broken in icc: https://github.com/fmtlib/fmt/issues/822. +if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG) +endif () +if (HAVE_FNO_EXCEPTIONS_FLAG) + add_library(noexception-test ../src/format.cc) + target_include_directories( + noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include) + target_compile_options(noexception-test PRIVATE -fno-exceptions) + if (FMT_PEDANTIC) + target_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS}) + endif () + target_include_directories(noexception-test SYSTEM PUBLIC gtest gmock) +endif () + +message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}") + +if (FMT_PEDANTIC) + # Test that the library compiles without windows.h. + if (CMAKE_SYSTEM_NAME STREQUAL "Windows") + add_library(no-windows-h-test ../src/format.cc) + target_include_directories( + no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}/include) + target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0) + if (FMT_PEDANTIC) + target_compile_options(no-windows-h-test PRIVATE ${PEDANTIC_COMPILE_FLAGS}) + endif () + target_include_directories(no-windows-h-test SYSTEM PUBLIC gtest gmock) + endif () + + add_test(compile-test ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMAKE_CURRENT_SOURCE_DIR}/compile-test" + "${CMAKE_CURRENT_BINARY_DIR}/compile-test" + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-options + "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}" + "-DCXX_STANDARD_FLAG=${CXX_STANDARD_FLAG}" + "-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}" + "-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}") +endif () + +# These tests are disabled on Windows because they take too long. +if (FMT_PEDANTIC AND NOT WIN32) + # Test if the targets are found from the build directory. + add_test(find-package-test ${CMAKE_CTEST_COMMAND} + -C ${CMAKE_BUILD_TYPE} + --build-and-test + "${CMAKE_CURRENT_SOURCE_DIR}/find-package-test" + "${CMAKE_CURRENT_BINARY_DIR}/find-package-test" + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-options + "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}" + "-DFMT_DIR=${PROJECT_BINARY_DIR}" + "-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}" + "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") + + # Test if the targets are found when add_subdirectory is used. + add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND} + -C ${CMAKE_BUILD_TYPE} + --build-and-test + "${CMAKE_CURRENT_SOURCE_DIR}/add-subdirectory-test" + "${CMAKE_CURRENT_BINARY_DIR}/add-subdirectory-test" + --build-generator ${CMAKE_GENERATOR} + --build-makeprogram ${CMAKE_MAKE_PROGRAM} + --build-options + "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}" + "-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}" + "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") +endif () diff --git a/src/seastar/fmt/test/add-subdirectory-test/CMakeLists.txt b/src/seastar/fmt/test/add-subdirectory-test/CMakeLists.txt new file mode 100644 index 00000000..db7054bd --- /dev/null +++ b/src/seastar/fmt/test/add-subdirectory-test/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.1.0) + +project(fmt-test) + +add_subdirectory(../.. fmt) + +add_executable(library-test "main.cc") +target_link_libraries(library-test fmt::fmt) +target_compile_options(library-test PRIVATE ${PEDANTIC_COMPILE_FLAGS}) +target_include_directories(library-test PUBLIC SYSTEM .) + +if (TARGET fmt::fmt-header-only) + add_executable(header-only-test "main.cc") + target_link_libraries(header-only-test fmt::fmt-header-only) + target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS}) + target_include_directories(header-only-test PUBLIC SYSTEM .) +endif () diff --git a/src/seastar/fmt/test/add-subdirectory-test/main.cc b/src/seastar/fmt/test/add-subdirectory-test/main.cc new file mode 100644 index 00000000..f39f377c --- /dev/null +++ b/src/seastar/fmt/test/add-subdirectory-test/main.cc @@ -0,0 +1,6 @@ +#include "fmt/format.h" + +int main(int argc, char** argv) { + for(int i = 0; i < argc; ++i) + fmt::print("{}: {}\n", i, argv[i]); +} diff --git a/src/seastar/fmt/test/assert-test.cc b/src/seastar/fmt/test/assert-test.cc new file mode 100644 index 00000000..8af9b09f --- /dev/null +++ b/src/seastar/fmt/test/assert-test.cc @@ -0,0 +1,22 @@ +// Formatting library for C++ - assertion tests +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include "fmt/core.h" +#include "gtest.h" + +#if GTEST_HAS_DEATH_TEST +# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEBUG_DEATH(statement, regex) +#else +# define EXPECT_DEBUG_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) +#endif + +TEST(AssertTest, Fail) { + EXPECT_DEBUG_DEATH_IF_SUPPORTED( + FMT_ASSERT(false, "don't panic!"), "don't panic!"); +} diff --git a/src/seastar/fmt/test/chrono-test.cc b/src/seastar/fmt/test/chrono-test.cc new file mode 100644 index 00000000..ca25d18c --- /dev/null +++ b/src/seastar/fmt/test/chrono-test.cc @@ -0,0 +1,170 @@ +// Formatting library for C++ - time formatting tests +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include "fmt/chrono.h" +#include "gtest-extra.h" + +#include + +std::tm make_tm() { + auto time = std::tm(); + time.tm_mday = 1; + return time; +} + +std::tm make_hour(int h) { + auto time = make_tm(); + time.tm_hour = h; + return time; +} + +std::tm make_minute(int m) { + auto time = make_tm(); + time.tm_min = m; + return time; +} + +std::tm make_second(int s) { + auto time = make_tm(); + time.tm_sec = s; + return time; +} + +std::string format_tm(const std::tm &time, const char *spec, + const std::locale &loc) { + auto &facet = std::use_facet>(loc); + std::ostringstream os; + os.imbue(loc); + facet.put(os, os, ' ', &time, spec, spec + std::strlen(spec)); + return os.str(); +} + +#define EXPECT_TIME(spec, time, duration) { \ + std::locale loc("ja_JP.utf8"); \ + EXPECT_EQ(format_tm(time, spec, loc), \ + fmt::format(loc, "{:" spec "}", duration)); \ + } + +TEST(ChronoTest, FormatDefault) { + EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42))); + EXPECT_EQ("42as", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42fs", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42ps", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42ns", fmt::format("{}", std::chrono::nanoseconds(42))); + EXPECT_EQ("42µs", fmt::format("{}", std::chrono::microseconds(42))); + EXPECT_EQ("42ms", fmt::format("{}", std::chrono::milliseconds(42))); + EXPECT_EQ("42cs", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42ds", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42))); + EXPECT_EQ("42das", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42hs", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42ks", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42Ms", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42Gs", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42Ts", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42Ps", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42Es", + fmt::format("{}", std::chrono::duration(42))); + EXPECT_EQ("42m", fmt::format("{}", std::chrono::minutes(42))); + EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42))); + EXPECT_EQ("42[15s]", + fmt::format("{}", + std::chrono::duration>(42))); + EXPECT_EQ("42[15/4s]", + fmt::format("{}", + std::chrono::duration>(42))); +} + +TEST(ChronoTest, FormatSpecs) { + EXPECT_EQ("%", fmt::format("{:%%}", std::chrono::seconds(0))); + EXPECT_EQ("\n", fmt::format("{:%n}", std::chrono::seconds(0))); + EXPECT_EQ("\t", fmt::format("{:%t}", std::chrono::seconds(0))); + EXPECT_EQ("00", fmt::format("{:%S}", std::chrono::seconds(0))); + EXPECT_EQ("00", fmt::format("{:%S}", std::chrono::seconds(60))); + EXPECT_EQ("42", fmt::format("{:%S}", std::chrono::seconds(42))); + EXPECT_EQ("01.234", fmt::format("{:%S}", std::chrono::milliseconds(1234))); + EXPECT_EQ("00", fmt::format("{:%M}", std::chrono::minutes(0))); + EXPECT_EQ("00", fmt::format("{:%M}", std::chrono::minutes(60))); + EXPECT_EQ("42", fmt::format("{:%M}", std::chrono::minutes(42))); + EXPECT_EQ("01", fmt::format("{:%M}", std::chrono::seconds(61))); + EXPECT_EQ("00", fmt::format("{:%H}", std::chrono::hours(0))); + EXPECT_EQ("00", fmt::format("{:%H}", std::chrono::hours(24))); + EXPECT_EQ("14", fmt::format("{:%H}", std::chrono::hours(14))); + EXPECT_EQ("01", fmt::format("{:%H}", std::chrono::minutes(61))); + EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(0))); + EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(12))); + EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(24))); + EXPECT_EQ("04", fmt::format("{:%I}", std::chrono::hours(4))); + EXPECT_EQ("02", fmt::format("{:%I}", std::chrono::hours(14))); + EXPECT_EQ("03:25:45", + fmt::format("{:%H:%M:%S}", std::chrono::seconds(12345))); + EXPECT_EQ("03:25", fmt::format("{:%R}", std::chrono::seconds(12345))); + EXPECT_EQ("03:25:45", fmt::format("{:%T}", std::chrono::seconds(12345))); +} + +TEST(ChronoTest, InvalidSpecs) { + auto sec = std::chrono::seconds(0); + EXPECT_THROW_MSG(fmt::format("{:%a}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%A}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%c}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%x}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%Ex}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%X}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%EX}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%D}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%F}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%Ec}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%w}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%u}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%b}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%B}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%z}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%Z}", sec), fmt::format_error, "no date"); + EXPECT_THROW_MSG(fmt::format("{:%q}", sec), fmt::format_error, + "invalid format"); + EXPECT_THROW_MSG(fmt::format("{:%Eq}", sec), fmt::format_error, + "invalid format"); + EXPECT_THROW_MSG(fmt::format("{:%Oq}", sec), fmt::format_error, + "invalid format"); +} + +TEST(ChronoTest, Locale) { + const char *loc_name = "ja_JP.utf8"; + bool has_locale = false; + std::locale loc; + try { + loc = std::locale(loc_name); + has_locale = true; + } catch (const std::runtime_error &) {} + if (!has_locale) { + fmt::print("{} locale is missing.\n", loc_name); + return; + } + EXPECT_TIME("%OH", make_hour(14), std::chrono::hours(14)); + EXPECT_TIME("%OI", make_hour(14), std::chrono::hours(14)); + EXPECT_TIME("%OM", make_minute(42), std::chrono::minutes(42)); + EXPECT_TIME("%OS", make_second(42), std::chrono::seconds(42)); + auto time = make_tm(); + time.tm_hour = 3; + time.tm_min = 25; + time.tm_sec = 45; + auto sec = std::chrono::seconds(12345); + EXPECT_TIME("%r", time, sec); + EXPECT_TIME("%p", time, sec); +} diff --git a/src/seastar/fmt/test/compile-test/CMakeLists.txt b/src/seastar/fmt/test/compile-test/CMakeLists.txt new file mode 100644 index 00000000..75a0c5a5 --- /dev/null +++ b/src/seastar/fmt/test/compile-test/CMakeLists.txt @@ -0,0 +1,79 @@ +# Test if compile errors are produced where necessary. + +cmake_minimum_required(VERSION 3.1.0) + +include(CheckCXXSourceCompiles) +include(CheckCXXCompilerFlag) + +set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../../include) +set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG} ${PEDANTIC_COMPILE_FLAGS}) + +function (generate_source result fragment) + set(${result} " + #define FMT_HEADER_ONLY 1 + #include \"fmt/format.h\" + int main() { + ${fragment} + } + " PARENT_SCOPE) +endfunction () + +function (expect_compile code) + generate_source(source "${code}") + check_cxx_source_compiles("${source}" compiles) + if (NOT compiles) + set(error_msg "Compile error for: ${code}") + endif () + # Unset the CMake cache variable compiles. Otherwise the compile test will + # just use cached information next time it runs. + unset(compiles CACHE) + if (error_msg) + message(FATAL_ERROR ${error_msg}) + endif () +endfunction () + +function (expect_compile_error code) + generate_source(source "${code}") + check_cxx_source_compiles("${source}" compiles) + if (compiles) + set(error_msg "No compile error for: ${code}") + endif () + # Unset the CMake cache variable compiles. Otherwise the compile test will + # just use cached information next time it runs. + unset(compiles CACHE) + if (error_msg) + message(FATAL_ERROR ${error_msg}) + endif () +endfunction () + +# check if the source file skeleton compiles +expect_compile("") + +# Formatting a wide character with a narrow format string is forbidden. +expect_compile_error("fmt::format(\"{}\", L'a');") + +# Formatting a wide string with a narrow format string is forbidden. +expect_compile_error("fmt::format(\"{}\", L\"foo\");") + +# Formatting a narrow string with a wide format string is forbidden because +# mixing UTF-8 with UTF-16/32 can result in an invalid output. +expect_compile_error("fmt::format(L\"{}\", \"foo\");") + +# Formatting a wide string with a narrow format string is forbidden. +expect_compile_error(" + struct S { + operator std::string() const { return std::string(); } + }; + fmt::format(\"{}\", S()); +") + +# Make sure that compiler features detected in the header +# match the features detected in CMake. +if (SUPPORTS_USER_DEFINED_LITERALS) + set(supports_udl 1) +else () + set(supports_udl 0) +endif () +expect_compile("#if FMT_USE_USER_DEFINED_LITERALS != ${supports_udl} + # error + #endif") diff --git a/src/seastar/fmt/test/core-test.cc b/src/seastar/fmt/test/core-test.cc new file mode 100644 index 00000000..fe7583ba --- /dev/null +++ b/src/seastar/fmt/test/core-test.cc @@ -0,0 +1,613 @@ +// Formatting library for C++ - core tests +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test-assert.h" + +#include "gmock.h" + +// Check if fmt/core.h compiles with windows.h included before it. +#ifdef _WIN32 +# include +#endif + +#include "fmt/core.h" + +#undef min +#undef max + +using fmt::basic_format_arg; +using fmt::internal::basic_buffer; +using fmt::internal::value; +using fmt::string_view; + +using testing::_; +using testing::StrictMock; + +namespace { + +struct test_struct {}; + +template +basic_format_arg make_arg(const T &value) { + return fmt::internal::make_arg(value); +} +} // namespace + +FMT_BEGIN_NAMESPACE +template +struct formatter { + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + typedef std::back_insert_iterator> iterator; + + auto format(test_struct, basic_format_context &ctx) + -> decltype(ctx.out()) { + const Char *test = "test"; + return std::copy_n(test, std::strlen(test), ctx.out()); + } +}; +FMT_END_NAMESPACE + +#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470 +TEST(BufferTest, Noncopyable) { + EXPECT_FALSE(std::is_copy_constructible >::value); +#if !FMT_MSC_VER + // std::is_copy_assignable is broken in MSVC2013. + EXPECT_FALSE(std::is_copy_assignable >::value); +#endif +} + +TEST(BufferTest, Nonmoveable) { + EXPECT_FALSE(std::is_move_constructible >::value); +#if !FMT_MSC_VER + // std::is_move_assignable is broken in MSVC2013. + EXPECT_FALSE(std::is_move_assignable >::value); +#endif +} +#endif + +// A test buffer with a dummy grow method. +template +struct test_buffer : basic_buffer { + void grow(std::size_t capacity) { this->set(FMT_NULL, capacity); } +}; + +template +struct mock_buffer : basic_buffer { + MOCK_METHOD1(do_grow, void (std::size_t capacity)); + + void grow(std::size_t capacity) { + this->set(this->data(), capacity); + do_grow(capacity); + } + + mock_buffer() {} + mock_buffer(T *data) { this->set(data, 0); } + mock_buffer(T *data, std::size_t capacity) { this->set(data, capacity); } +}; + +TEST(BufferTest, Ctor) { + { + mock_buffer buffer; + EXPECT_EQ(FMT_NULL, &buffer[0]); + EXPECT_EQ(static_cast(0), buffer.size()); + EXPECT_EQ(static_cast(0), buffer.capacity()); + } + { + int dummy; + mock_buffer buffer(&dummy); + EXPECT_EQ(&dummy, &buffer[0]); + EXPECT_EQ(static_cast(0), buffer.size()); + EXPECT_EQ(static_cast(0), buffer.capacity()); + } + { + int dummy; + std::size_t capacity = std::numeric_limits::max(); + mock_buffer buffer(&dummy, capacity); + EXPECT_EQ(&dummy, &buffer[0]); + EXPECT_EQ(static_cast(0), buffer.size()); + EXPECT_EQ(capacity, buffer.capacity()); + } +} + +struct dying_buffer : test_buffer { + MOCK_METHOD0(die, void()); + ~dying_buffer() { die(); } +}; + +TEST(BufferTest, VirtualDtor) { + typedef StrictMock stict_mock_buffer; + stict_mock_buffer *mock_buffer = new stict_mock_buffer(); + EXPECT_CALL(*mock_buffer, die()); + basic_buffer *buffer = mock_buffer; + delete buffer; +} + +TEST(BufferTest, Access) { + char data[10]; + mock_buffer buffer(data, sizeof(data)); + buffer[0] = 11; + EXPECT_EQ(11, buffer[0]); + buffer[3] = 42; + EXPECT_EQ(42, *(&buffer[0] + 3)); + const basic_buffer &const_buffer = buffer; + EXPECT_EQ(42, const_buffer[3]); +} + +TEST(BufferTest, Resize) { + char data[123]; + mock_buffer buffer(data, sizeof(data)); + buffer[10] = 42; + EXPECT_EQ(42, buffer[10]); + buffer.resize(20); + EXPECT_EQ(20u, buffer.size()); + EXPECT_EQ(123u, buffer.capacity()); + EXPECT_EQ(42, buffer[10]); + buffer.resize(5); + EXPECT_EQ(5u, buffer.size()); + EXPECT_EQ(123u, buffer.capacity()); + EXPECT_EQ(42, buffer[10]); + // Check if resize calls grow. + EXPECT_CALL(buffer, do_grow(124)); + buffer.resize(124); + EXPECT_CALL(buffer, do_grow(200)); + buffer.resize(200); +} + +TEST(BufferTest, Clear) { + test_buffer buffer; + buffer.resize(20); + buffer.resize(0); + EXPECT_EQ(static_cast(0), buffer.size()); + EXPECT_EQ(20u, buffer.capacity()); +} + +TEST(BufferTest, Append) { + char data[15]; + mock_buffer buffer(data, 10); + const char *test = "test"; + buffer.append(test, test + 5); + EXPECT_STREQ(test, &buffer[0]); + EXPECT_EQ(5u, buffer.size()); + buffer.resize(10); + EXPECT_CALL(buffer, do_grow(12)); + buffer.append(test, test + 2); + EXPECT_EQ('t', buffer[10]); + EXPECT_EQ('e', buffer[11]); + EXPECT_EQ(12u, buffer.size()); +} + +TEST(BufferTest, AppendAllocatesEnoughStorage) { + char data[19]; + mock_buffer buffer(data, 10); + const char *test = "abcdefgh"; + buffer.resize(10); + EXPECT_CALL(buffer, do_grow(19)); + buffer.append(test, test + 9); +} + +TEST(ArgTest, FormatArgs) { + fmt::format_args args; + EXPECT_FALSE(args.get(1)); +} + +struct custom_context { + typedef char char_type; + + template + struct formatter_type { + struct type { + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + const char *format(const T &, custom_context& ctx) { + ctx.called = true; + return FMT_NULL; + } + }; + }; + + bool called; + + fmt::format_parse_context parse_context() { + return fmt::format_parse_context(""); + } + void advance_to(const char *) {} +}; + +TEST(ArgTest, MakeValueWithCustomContext) { + test_struct t; + fmt::internal::value arg = + fmt::internal::make_value(t); + custom_context ctx = {false}; + arg.custom.format(&t, ctx); + EXPECT_TRUE(ctx.called); +} + +FMT_BEGIN_NAMESPACE +namespace internal { +template +bool operator==(custom_value lhs, custom_value rhs) { + return lhs.value == rhs.value; +} +} +FMT_END_NAMESPACE + +// Use a unique result type to make sure that there are no undesirable +// conversions. +struct test_result {}; + +template +struct mock_visitor { + template + struct result { typedef test_result type; }; + + mock_visitor() { + ON_CALL(*this, visit(_)).WillByDefault(testing::Return(test_result())); + } + + MOCK_METHOD1_T(visit, test_result (T value)); + MOCK_METHOD0_T(unexpected, void ()); + + test_result operator()(T value) { return visit(value); } + + template + test_result operator()(U) { + unexpected(); + return test_result(); + } +}; + +template +struct visit_type { typedef T Type; }; + +#define VISIT_TYPE(Type_, visit_type_) \ + template <> \ + struct visit_type { typedef visit_type_ Type; } + +VISIT_TYPE(signed char, int); +VISIT_TYPE(unsigned char, unsigned); +VISIT_TYPE(short, int); +VISIT_TYPE(unsigned short, unsigned); + +#if LONG_MAX == INT_MAX +VISIT_TYPE(long, int); +VISIT_TYPE(unsigned long, unsigned); +#else +VISIT_TYPE(long, long long); +VISIT_TYPE(unsigned long, unsigned long long); +#endif + +VISIT_TYPE(float, double); + +#define CHECK_ARG_(Char, expected, value) { \ + testing::StrictMock> visitor; \ + EXPECT_CALL(visitor, visit(expected)); \ + typedef std::back_insert_iterator> iterator; \ + fmt::visit(visitor, \ + make_arg>(value)); \ +} + +#define CHECK_ARG(value, typename_) { \ + typedef decltype(value) value_type; \ + typename_ visit_type::Type expected = value; \ + CHECK_ARG_(char, expected, value) \ + CHECK_ARG_(wchar_t, expected, value) \ +} + +template +class NumericArgTest : public testing::Test {}; + +typedef ::testing::Types< + bool, signed char, unsigned char, signed, unsigned short, + int, unsigned, long, unsigned long, long long, unsigned long long, + float, double, long double> Types; +TYPED_TEST_CASE(NumericArgTest, Types); + +template +typename std::enable_if::value, T>::type test_value() { + return static_cast(42); +} + +template +typename std::enable_if::value, T>::type + test_value() { + return static_cast(4.2); +} + +TYPED_TEST(NumericArgTest, MakeAndVisit) { + CHECK_ARG(test_value(), typename); + CHECK_ARG(std::numeric_limits::min(), typename); + CHECK_ARG(std::numeric_limits::max(), typename); +} + +TEST(ArgTest, CharArg) { + CHECK_ARG_(char, 'a', 'a'); + CHECK_ARG_(wchar_t, L'a', 'a'); + CHECK_ARG_(wchar_t, L'a', L'a'); +} + +TEST(ArgTest, StringArg) { + char str_data[] = "test"; + char *str = str_data; + const char *cstr = str; + CHECK_ARG_(char, cstr, str); + + string_view sref(str); + CHECK_ARG_(char, sref, std::string(str)); +} + +TEST(ArgTest, WStringArg) { + wchar_t str_data[] = L"test"; + wchar_t *str = str_data; + const wchar_t *cstr = str; + + fmt::wstring_view sref(str); + CHECK_ARG_(wchar_t, cstr, str); + CHECK_ARG_(wchar_t, cstr, cstr); + CHECK_ARG_(wchar_t, sref, std::wstring(str)); + CHECK_ARG_(wchar_t, sref, fmt::wstring_view(str)); +} + +TEST(ArgTest, PointerArg) { + void *p = FMT_NULL; + const void *cp = FMT_NULL; + CHECK_ARG_(char, cp, p); + CHECK_ARG_(wchar_t, cp, p); + CHECK_ARG(cp, ); +} + +struct check_custom { + test_result operator()( + fmt::basic_format_arg::handle h) const { + struct test_buffer : fmt::internal::basic_buffer { + char data[10]; + test_buffer() : fmt::internal::basic_buffer(data, 0, 10) {} + void grow(std::size_t) {} + } buffer; + fmt::internal::basic_buffer &base = buffer; + fmt::format_context ctx(std::back_inserter(base), "", fmt::format_args()); + h.format(ctx); + EXPECT_EQ("test", std::string(buffer.data, buffer.size())); + return test_result(); + } +}; + +TEST(ArgTest, CustomArg) { + test_struct test; + typedef mock_visitor::handle> + visitor; + testing::StrictMock v; + EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom())); + fmt::visit(v, make_arg(test)); +} + +TEST(ArgTest, VisitInvalidArg) { + testing::StrictMock< mock_visitor > visitor; + EXPECT_CALL(visitor, visit(_)); + fmt::basic_format_arg arg; + visit(visitor, arg); +} + +TEST(StringViewTest, Length) { + // Test that StringRef::size() returns string length, not buffer size. + char str[100] = "some string"; + EXPECT_EQ(std::strlen(str), string_view(str).size()); + EXPECT_LT(std::strlen(str), sizeof(str)); +} + +// Check string_view's comparison operator. +template