Branch data Line data Source code
1 : : // Copyright (c) 2024-present The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #include <util/string.h>
6 : :
7 : : #include <boost/test/unit_test.hpp>
8 : : #include <test/util/setup_common.h>
9 : :
10 : : using namespace util;
11 : :
12 : : BOOST_AUTO_TEST_SUITE(util_string_tests)
13 : :
14 : : // Helper to allow compile-time sanity checks while providing the number of
15 : : // args directly. Normally PassFmt<sizeof...(Args)> would be used.
16 : : template <unsigned NumArgs>
17 : 28 : inline void PassFmt(util::ConstevalFormatString<NumArgs> fmt)
18 : : {
19 : : // This was already executed at compile-time, but is executed again at run-time to avoid -Wunused.
20 : 28 : decltype(fmt)::Detail_CheckNumFormatSpecifiers(fmt.fmt);
21 : 28 : }
22 : : template <unsigned WrongNumArgs>
23 : 12 : inline void FailFmtWithError(std::string_view wrong_fmt, std::string_view error)
24 : : {
25 [ + - - + : 24 : BOOST_CHECK_EXCEPTION(util::ConstevalFormatString<WrongNumArgs>::Detail_CheckNumFormatSpecifiers(wrong_fmt), const char*, HasReason(error));
- - - - -
+ + - + -
+ - ]
26 : 12 : }
27 : :
28 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(ConstevalFormatString_NumSpec)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
29 : : {
30 : 1 : PassFmt<0>("");
31 : 1 : PassFmt<0>("%%");
32 : 1 : PassFmt<1>("%s");
33 : 1 : PassFmt<0>("%%s");
34 : 1 : PassFmt<0>("s%%");
35 : 1 : PassFmt<1>("%%%s");
36 : 1 : PassFmt<1>("%s%%");
37 : 1 : PassFmt<0>(" 1$s");
38 : 1 : PassFmt<1>("%1$s");
39 : 1 : PassFmt<1>("%1$s%1$s");
40 : 1 : PassFmt<2>("%2$s");
41 : 1 : PassFmt<2>("%2$s 4$s %2$s");
42 : 1 : PassFmt<129>("%129$s 999$s %2$s");
43 : 1 : PassFmt<1>("%02d");
44 : 1 : PassFmt<1>("%+2s");
45 : 1 : PassFmt<1>("%.6i");
46 : 1 : PassFmt<1>("%5.2f");
47 : 1 : PassFmt<1>("%#x");
48 : 1 : PassFmt<1>("%1$5i");
49 : 1 : PassFmt<1>("%1$-5i");
50 : 1 : PassFmt<1>("%1$.5i");
51 : : // tinyformat accepts almost any "type" spec, even '%', or '_', or '\n'.
52 : 1 : PassFmt<1>("%123%");
53 : 1 : PassFmt<1>("%123%s");
54 : 1 : PassFmt<1>("%_");
55 : 1 : PassFmt<1>("%\n");
56 : :
57 : : // The `*` specifier behavior is unsupported and can lead to runtime
58 : : // errors when used in a ConstevalFormatString. Please refer to the
59 : : // note in the ConstevalFormatString docs.
60 : 1 : PassFmt<1>("%*c");
61 : 1 : PassFmt<2>("%2$*3$d");
62 : 1 : PassFmt<1>("%.*f");
63 : :
64 : 1 : auto err_mix{"Format specifiers must be all positional or all non-positional!"};
65 : 1 : FailFmtWithError<1>("%s%1$s", err_mix);
66 : :
67 : 1 : auto err_num{"Format specifier count must match the argument count!"};
68 : 1 : FailFmtWithError<1>("", err_num);
69 : 1 : FailFmtWithError<0>("%s", err_num);
70 : 1 : FailFmtWithError<2>("%s", err_num);
71 : 1 : FailFmtWithError<0>("%1$s", err_num);
72 : 1 : FailFmtWithError<2>("%1$s", err_num);
73 : :
74 : 1 : auto err_0_pos{"Positional format specifier must have position of at least 1"};
75 : 1 : FailFmtWithError<1>("%$s", err_0_pos);
76 : 1 : FailFmtWithError<1>("%$", err_0_pos);
77 : 1 : FailFmtWithError<0>("%0$", err_0_pos);
78 : 1 : FailFmtWithError<0>("%0$s", err_0_pos);
79 : :
80 : 1 : auto err_term{"Format specifier incorrectly terminated by end of string"};
81 : 1 : FailFmtWithError<1>("%", err_term);
82 : 1 : FailFmtWithError<1>("%1$", err_term);
83 : 1 : }
84 : :
85 : : BOOST_AUTO_TEST_SUITE_END()
|