#include "test_macros.h"
#include "make_string.h"
#include "test_format_string.h"
+#include "assert_macros.h"
#ifndef TEST_HAS_NO_LOCALIZATION
# include <iostream>
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
{
#include "test_macros.h"
#include "make_string.h"
#include "test_format_string.h"
+#include "assert_macros.h"
#ifndef TEST_HAS_NO_LOCALIZATION
# include <iostream>
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
{
#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&&...) {
#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&&...) {
#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)
// *** 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 ***
{
#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 =
[[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);
#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 =
#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);
#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&&...) {
#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 =
#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);
--- /dev/null
+//===----------------------------------------------------------------------===//
+//
+// 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 differences 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