[libcxx-commits] [libcxx] f8bed13 - [libc++][format] Adds new test macros.
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jan 18 08:01:34 PST 2023
Author: Mark de Wever
Date: 2023-01-18T17:01:27+01:00
New Revision: f8bed136942190d7e50854d74248243c8103d2b1
URL: https://github.com/llvm/llvm-project/commit/f8bed136942190d7e50854d74248243c8103d2b1
DIFF: https://github.com/llvm/llvm-project/commit/f8bed136942190d7e50854d74248243c8103d2b1.diff
LOG: [libc++][format] Adds new test macros.
These macros make it easier to log additional information. This is
useful for formatting tests. It also properly disables additional
information when locales are disabled in libc++.
Reviewed By: #libc, ldionne
Differential Revision: https://reviews.llvm.org/D140651
Added:
libcxx/test/support/assert_macros.h
Modified:
libcxx/test/std/utilities/format/format.functions/escaped_output.ascii.pass.cpp
libcxx/test/std/utilities/format/format.functions/escaped_output.unicode.pass.cpp
libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
libcxx/test/std/utilities/format/format.functions/format.pass.cpp
libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
libcxx/test/std/utilities/format/format.tuple/format.functions.format.pass.cpp
libcxx/test/std/utilities/format/format.tuple/format.functions.vformat.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/test/std/utilities/format/format.functions/escaped_output.ascii.pass.cpp b/libcxx/test/std/utilities/format/format.functions/escaped_output.ascii.pass.cpp
index 4145385678874..329124fe5130b 100644
--- a/libcxx/test/std/utilities/format/format.functions/escaped_output.ascii.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/escaped_output.ascii.pass.cpp
@@ -24,6 +24,7 @@
#include "test_macros.h"
#include "make_string.h"
#include "test_format_string.h"
+#include "assert_macros.h"
#ifndef TEST_HAS_NO_LOCALIZATION
# include <iostream>
@@ -35,19 +36,9 @@ auto test_format = []<class CharT, class... Args>(
std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
{
std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...);
-#ifndef TEST_HAS_NO_LOCALIZATION
- if (out != expected) {
- if constexpr (std::same_as<CharT, char>)
- std::cerr << "\nFormat string " << fmt.get() << "\nExpected output " << expected << "\nActual output "
- << out << '\n';
-# ifndef TEST_HAS_NO_WIDE_CHARACTERS
- else
- std::wcerr << L"\nFormat string " << fmt.get() << L"\nExpected output " << expected << L"\nActual output "
- << out << L'\n';
-# endif // TEST_HAS_NO_WIDE_CHARACTERS
- }
-#endif // TEST_HAS_NO_LOCALIZATION
- assert(out == expected);
+ TEST_REQUIRE(out == expected,
+ test_concat_message(
+ "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
}
#ifndef TEST_HAS_NO_LOCALIZATION
{
diff --git a/libcxx/test/std/utilities/format/format.functions/escaped_output.unicode.pass.cpp b/libcxx/test/std/utilities/format/format.functions/escaped_output.unicode.pass.cpp
index 351491940cc0e..c940bcb7be959 100644
--- a/libcxx/test/std/utilities/format/format.functions/escaped_output.unicode.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/escaped_output.unicode.pass.cpp
@@ -30,6 +30,7 @@
#include "test_macros.h"
#include "make_string.h"
#include "test_format_string.h"
+#include "assert_macros.h"
#ifndef TEST_HAS_NO_LOCALIZATION
# include <iostream>
@@ -41,19 +42,9 @@ auto test_format = []<class CharT, class... Args>(
std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
{
std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...);
-#ifndef TEST_HAS_NO_LOCALIZATION
- if (out != expected) {
- if constexpr (std::same_as<CharT, char>)
- std::cerr << "\nFormat string " << fmt.get() << "\nExpected output " << expected << "\nActual output "
- << out << '\n';
-# ifndef TEST_HAS_NO_WIDE_CHARACTERS
- else
- std::wcerr << L"\nFormat string " << fmt.get() << L"\nExpected output " << expected << L"\nActual output "
- << out << L'\n';
-# endif // TEST_HAS_NO_WIDE_CHARACTERS
- }
-#endif // TEST_HAS_NO_LOCALIZATION
- assert(out == expected);
+ TEST_REQUIRE(out == expected,
+ test_concat_message(
+ "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
}
#ifndef TEST_HAS_NO_LOCALIZATION
{
diff --git a/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
index 76d4b35f90cfc..ab34558ab3524 100644
--- a/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format.locale.pass.cpp
@@ -27,16 +27,16 @@
#include "format_tests.h"
#include "string_literal.h"
#include "test_format_string.h"
+#include "assert_macros.h"
auto test =
[]<class CharT, class... Args>(
std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) constexpr {
std::basic_string<CharT> out = std::format(std::locale(), fmt, std::forward<Args>(args)...);
- if constexpr (std::same_as<CharT, char>)
- if (out != expected)
- std::cerr << "\nFormat string " << fmt.get() << "\nExpected output " << expected << "\nActual output "
- << out << '\n';
- assert(out == expected);
+ TEST_REQUIRE(
+ out == expected,
+ test_concat_message(
+ "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, Args&&...) {
diff --git a/libcxx/test/std/utilities/format/format.functions/format.pass.cpp b/libcxx/test/std/utilities/format/format.functions/format.pass.cpp
index 271007803af8d..ca9d1d9036422 100644
--- a/libcxx/test/std/utilities/format/format.functions/format.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/format.pass.cpp
@@ -29,23 +29,16 @@
#include "format_tests.h"
#include "string_literal.h"
#include "test_format_string.h"
-
-#ifndef TEST_HAS_NO_LOCALIZATION
-# include <iostream>
-# include <type_traits>
-#endif
+#include "assert_macros.h"
auto test =
[]<class CharT, class... Args>(
std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) constexpr {
std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...);
-#ifndef TEST_HAS_NO_LOCALIZATION
- if constexpr (std::same_as<CharT, char>)
- if (out != expected)
- std::cerr << "\nFormat string " << fmt.get() << "\nExpected output " << expected << "\nActual output "
- << out << '\n';
-#endif
- assert(out == expected);
+ TEST_REQUIRE(
+ out == expected,
+ test_concat_message(
+ "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, Args&&...) {
diff --git a/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp b/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
index 7f3f195af3d2a..86d56daa18d56 100644
--- a/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp
@@ -93,6 +93,7 @@
#include "format_tests.h"
#include "string_literal.h"
#include "test_format_string.h"
+#include "assert_macros.h"
#define STR(S) MAKE_STRING(CharT, S)
#define SV(S) MAKE_STRING_VIEW(CharT, S)
@@ -127,11 +128,9 @@ void test(std::basic_string_view<CharT> expected, test_format_string<CharT, Args
// *** format ***
{
std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...);
- if constexpr (std::same_as<CharT, char>)
- if (out != expected)
- std::cerr << "\nFormat string " << fmt.get() << "\nExpected output " << expected << "\nActual output "
- << out << '\n';
- assert(out == expected);
+ TEST_REQUIRE(out == expected,
+ test_concat_message(
+ "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
}
// *** vformat ***
{
diff --git a/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
index 11bf67f064904..90c56df423fcf 100644
--- a/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/vformat.locale.pass.cpp
@@ -23,11 +23,14 @@
#include "test_macros.h"
#include "format_tests.h"
#include "string_literal.h"
+#include "assert_macros.h"
auto test = []<class CharT, class... Args>(
std::basic_string_view<CharT> expected, std::basic_string_view<CharT> fmt, Args&&... args) constexpr {
std::basic_string<CharT> out = std::vformat(std::locale(), fmt, std::make_format_args<context_t<CharT>>(args...));
- assert(out == expected);
+ TEST_REQUIRE(
+ out == expected,
+ test_concat_message("\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
auto test_exception =
@@ -37,10 +40,13 @@ auto test_exception =
[[maybe_unused]] Args&&... args) {
#ifndef TEST_HAS_NO_EXCEPTIONS
try {
- (void)std::vformat(std::locale(), fmt, std::make_format_args<context_t<CharT>>(args...));
- assert(false);
+ TEST_IGNORE_NODISCARD std::vformat(std::locale(), fmt, std::make_format_args<context_t<CharT>>(args...));
+ TEST_FAIL(test_concat_message("\nFormat string ", fmt, "\nDidn't throw an exception.\n"));
} catch ([[maybe_unused]] const std::format_error& e) {
- LIBCPP_ASSERT(e.what() == what);
+ TEST_LIBCPP_REQUIRE(
+ e.what() == what,
+ test_concat_message(
+ "\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
return;
}
assert(false);
diff --git a/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp b/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
index d1156158b2695..236d83ec1e7b7 100644
--- a/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.functions/vformat.pass.cpp
@@ -22,11 +22,14 @@
#include "test_macros.h"
#include "format_tests.h"
#include "string_literal.h"
+#include "assert_macros.h"
auto test = []<class CharT, class... Args>(
std::basic_string_view<CharT> expected, std::basic_string_view<CharT> fmt, Args&&... args) constexpr {
std::basic_string<CharT> out = std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...));
- assert(out == expected);
+ TEST_REQUIRE(
+ out == expected,
+ test_concat_message("\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
auto test_exception =
@@ -37,9 +40,13 @@ auto test_exception =
#ifndef TEST_HAS_NO_EXCEPTIONS
try {
TEST_IGNORE_NODISCARD std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...));
- assert(false);
+ TEST_FAIL(test_concat_message("\nFormat string ", fmt, "\nDidn't throw an exception.\n"));
} catch ([[maybe_unused]] const std::format_error& e) {
- LIBCPP_ASSERT(e.what() == what);
+ TEST_LIBCPP_REQUIRE(
+ e.what() == what,
+ test_concat_message(
+ "\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
+
return;
}
assert(false);
diff --git a/libcxx/test/std/utilities/format/format.tuple/format.functions.format.pass.cpp b/libcxx/test/std/utilities/format/format.tuple/format.functions.format.pass.cpp
index 72f8430792ff0..d6f9bd376849c 100644
--- a/libcxx/test/std/utilities/format/format.tuple/format.functions.format.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.tuple/format.functions.format.pass.cpp
@@ -30,22 +30,14 @@
#include "format.functions.tests.h"
#include "test_format_string.h"
#include "test_macros.h"
-
-#ifndef TEST_HAS_NO_LOCALIZATION
-# include <iostream>
-# include <concepts>
-#endif
+#include "assert_macros.h"
auto test = []<class CharT, class... Args>(
std::basic_string_view<CharT> expected, test_format_string<CharT, Args...> fmt, Args&&... args) {
std::basic_string<CharT> out = std::format(fmt, std::forward<Args>(args)...);
-#ifndef TEST_HAS_NO_LOCALIZATION
- if constexpr (std::same_as<CharT, char>)
- if (out != expected)
- std::cerr << "\nFormat string " << fmt.get() << "\nExpected output " << expected << "\nActual output " << out
- << '\n';
-#endif // TEST_HAS_NO_LOCALIZATION
- assert(out == expected);
+ TEST_REQUIRE(
+ out == expected,
+ test_concat_message("\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
auto test_exception = []<class CharT, class... Args>(std::string_view, std::basic_string_view<CharT>, Args&&...) {
diff --git a/libcxx/test/std/utilities/format/format.tuple/format.functions.vformat.pass.cpp b/libcxx/test/std/utilities/format/format.tuple/format.functions.vformat.pass.cpp
index 7c9540c2db3a8..68531341c7124 100644
--- a/libcxx/test/std/utilities/format/format.tuple/format.functions.vformat.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.tuple/format.functions.vformat.pass.cpp
@@ -29,22 +29,14 @@
#include "test_macros.h"
#include "format.functions.tests.h"
-
-#ifndef TEST_HAS_NO_LOCALIZATION
-# include <iostream>
-# include <concepts>
-#endif
+#include "assert_macros.h"
auto test = []<class CharT, class... Args>(
std::basic_string_view<CharT> expected, std::basic_string_view<CharT> fmt, Args&&... args) {
std::basic_string<CharT> out = std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...));
-#ifndef TEST_HAS_NO_LOCALIZATION
- if constexpr (std::same_as<CharT, char>)
- if (out != expected)
- std::cerr << "\nFormat string " << fmt << "\nExpected output " << expected << "\nActual output " << out
- << '\n';
-#endif // TEST_HAS_NO_LOCALIZATION
- assert(out == expected);
+ TEST_REQUIRE(
+ out == expected,
+ test_concat_message("\nFormat string ", fmt, "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
auto test_exception =
@@ -55,22 +47,13 @@ auto test_exception =
#ifndef TEST_HAS_NO_EXCEPTIONS
try {
TEST_IGNORE_NODISCARD std::vformat(fmt, std::make_format_args<context_t<CharT>>(args...));
-# if !defined(TEST_HAS_NO_LOCALIZATION)
- if constexpr (std::same_as<CharT, char>)
- std::cerr << "\nFormat string " << fmt << "\nDidn't throw an exception.\n";
-# endif // !defined(TEST_HAS_NO_LOCALIZATION
- assert(false);
+ TEST_FAIL(test_concat_message("\nFormat string ", fmt, "\nDidn't throw an exception.\n"));
} catch ([[maybe_unused]] const std::format_error& e) {
-# if defined(_LIBCPP_VERSION)
-# if !defined(TEST_HAS_NO_LOCALIZATION)
- if constexpr (std::same_as<CharT, char>) {
- if (e.what() != what)
- std::cerr << "\nFormat string " << fmt << "\nExpected exception " << what << "\nActual exception "
- << e.what() << '\n';
- }
-# endif // !defined(TEST_HAS_NO_LOCALIZATION
- assert(e.what() == what);
-# endif // defined(_LIBCPP_VERSION)
+ TEST_LIBCPP_REQUIRE(
+ e.what() == what,
+ test_concat_message(
+ "\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
+
return;
}
assert(false);
diff --git a/libcxx/test/support/assert_macros.h b/libcxx/test/support/assert_macros.h
new file mode 100644
index 0000000000000..5d5d810446306
--- /dev/null
+++ b/libcxx/test/support/assert_macros.h
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef TEST_SUPPORT_ASSERT_MACROS_H
+#define TEST_SUPPORT_ASSERT_MACROS_H
+
+// Contains a set of validation macros.
+//
+// Note these test were added after C++20 was well supported by the compilers
+// used. To make the implementation simple the macros require C++20 or newer.
+// It's not expected that existing tests start to use these new macros.
+//
+// These macros are an alternative to using assert. The
diff erences are:
+// - The assert message isn't localized.
+// - It's possible to log additional information. This is useful when the
+// function asserting is a helper function. In these cases the assertion
+// failure contains to little information to find the issue. For example, in
+// the format functions, the really useful information is the actual output,
+// the expected output, and the format string used. These macros allow
+// logging additional arguments.
+
+#include "test_macros.h"
+
+#include <cstdio>
+#include <cstdlib>
+
+#ifndef TEST_HAS_NO_LOCALIZATION
+# include <sstream>
+#endif
+
+#if TEST_STD_VER > 17
+
+# ifndef TEST_HAS_NO_LOCALIZATION
+template <class T>
+concept test_char_streamable = requires(T&& value) { std::stringstream{} << std::forward<T>(value); };
+# endif
+
+// If possible concatenates message for the assertion function, else returns a
+// default message. Not being able to stream is not considered and error. For
+// example, streaming to std::wcerr doesn't work properly in the CI. Therefore
+// the formatting tests should only stream to std::string_string.
+template <class... Args>
+std::string test_concat_message([[maybe_unused]] Args&&... args) {
+# ifndef TEST_HAS_NO_LOCALIZATION
+ if constexpr ((test_char_streamable<Args> && ...)) {
+ std::stringstream sstr;
+ ((sstr << std::forward<Args>(args)), ...);
+ return sstr.str();
+ } else
+# endif
+ return "Message discarded since it can't be streamed to std::cerr.\n";
+}
+
+#endif // TEST_STD_VER > 17
+
+// Logs the error and calls exit.
+//
+// It shows a generic assert like message including a custom message. This
+// message should end with a newline.
+[[noreturn]] void test_log_error(const char* condition, const char* file, int line, std::string&& message) {
+ const char* msg = condition ? "Assertion failure: " : "Unconditional failure:";
+ std::fprintf(stderr, "%s%s %s %d\n%s", msg, condition, file, line, message.c_str());
+ exit(EXIT_FAILURE);
+}
+
+inline void test_fail(const char* file, int line, std::string&& message) {
+ test_log_error("", file, line, std::move(message));
+}
+
+inline void test_require(bool condition, const char* condition_str, const char* file, int line, std::string&& message) {
+ if (condition)
+ return;
+
+ test_log_error(condition_str, file, line, std::move(message));
+}
+
+inline void test_libcpp_require(
+ [[maybe_unused]] bool condition,
+ [[maybe_unused]] const char* condition_str,
+ [[maybe_unused]] const char* file,
+ [[maybe_unused]] int line,
+ [[maybe_unused]] std::string&& message) {
+#if defined(_LIBCPP_VERSION)
+ test_require(condition, condition_str, file, line, std::move(message));
+#endif
+}
+
+// assert(false) replacement
+#define TEST_FAIL(MSG) ::test_fail(__FILE__, __LINE__, MSG)
+
+// assert replacement.
+#define TEST_REQUIRE(CONDITION, MSG) ::test_require(CONDITION, #CONDITION, __FILE__, __LINE__, MSG)
+
+// LIBCPP_ASSERT replacement
+//
+// This requirement is only tested when the test suite is used for libc++.
+// This allows checking libc++ specific requirements, for example the error
+// messages of exceptions.
+#define TEST_LIBCPP_REQUIRE(CONDITION, MSG) ::test_libcpp_require(CONDITION, #CONDITION, __FILE__, __LINE__, MSG)
+
+#endif // TEST_SUPPORT_ASSERT_MACROS_H
More information about the libcxx-commits
mailing list