xref: /freebsd/contrib/kyua/utils/format/formatter_test.cpp (revision ec0ea6efa1ad229d75c394c1a9b9cac33af2b1d3)
1 // Copyright 2010 The Kyua Authors.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 //   notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 //   notice, this list of conditions and the following disclaimer in the
12 //   documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 //   may be used to endorse or promote products derived from this software
15 //   without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #include "utils/format/formatter.hpp"
30 
31 #include <ostream>
32 
33 #include <atf-c++.hpp>
34 
35 #include "utils/format/exceptions.hpp"
36 #include "utils/format/macros.hpp"
37 
38 namespace format = utils::format;
39 
40 
41 namespace {
42 
43 
44 /// Wraps an integer in a C++ class.
45 ///
46 /// This custom type exists to ensure that we can feed arbitrary objects that
47 /// support operator<< to the formatter;
48 class int_wrapper {
49     /// The wrapped integer.
50     int _value;
51 
52 public:
53     /// Constructs a new wrapper.
54     ///
55     /// \param value_ The value to wrap.
56     int_wrapper(const int value_) : _value(value_)
57     {
58     }
59 
60     /// Returns the wrapped value.
61     ///
62     /// \return An integer.
63     int
64     value(void) const
65     {
66         return _value;
67     }
68 };
69 
70 
71 /// Writes a wrapped integer into an output stream.
72 ///
73 /// \param output The output stream into which to place the integer.
74 /// \param wrapper The wrapped integer.
75 ///
76 /// \return The output stream.
77 std::ostream&
78 operator<<(std::ostream& output, const int_wrapper& wrapper)
79 {
80     return (output << wrapper.value());
81 }
82 
83 
84 }  // anonymous namespace
85 
86 
87 /// Calls ATF_REQUIRE_EQ on an expected string and a formatter.
88 ///
89 /// This is pure syntactic sugar to avoid calling the str() method on all the
90 /// individual tests below, which results in very long lines that require
91 /// wrapping and clutter readability.
92 ///
93 /// \param expected The expected string generated by the formatter.
94 /// \param formatter The formatter to test.
95 #define EQ(expected, formatter) ATF_REQUIRE_EQ(expected, (formatter).str())
96 
97 
98 ATF_TEST_CASE_WITHOUT_HEAD(no_fields);
99 ATF_TEST_CASE_BODY(no_fields)
100 {
101     EQ("Plain string", F("Plain string"));
102 }
103 
104 
105 ATF_TEST_CASE_WITHOUT_HEAD(one_field);
106 ATF_TEST_CASE_BODY(one_field)
107 {
108     EQ("foo", F("%sfoo") % "");
109     EQ(" foo", F("%sfoo") % " ");
110     EQ("foo ", F("foo %s") % "");
111     EQ("foo bar", F("foo %s") % "bar");
112     EQ("foo bar baz", F("foo %s baz") % "bar");
113     EQ("foo %s %s", F("foo %s %s") % "%s" % "%s");
114 }
115 
116 
117 ATF_TEST_CASE_WITHOUT_HEAD(many_fields);
118 ATF_TEST_CASE_BODY(many_fields)
119 {
120     EQ("", F("%s%s") % "" % "");
121     EQ("foo", F("%s%s%s") % "" % "foo" % "");
122     EQ("some 5 text", F("%s %s %s") % "some" % 5 % "text");
123     EQ("f%s 5 text", F("%s %s %s") % "f%s" % 5 % "text");
124 }
125 
126 
127 ATF_TEST_CASE_WITHOUT_HEAD(escape);
128 ATF_TEST_CASE_BODY(escape)
129 {
130     EQ("%", F("%%"));
131     EQ("% %", F("%% %%"));
132     EQ("%% %%", F("%%%% %%%%"));
133 
134     EQ("foo %", F("foo %%"));
135     EQ("foo bar %", F("foo %s %%") % "bar");
136     EQ("foo % bar", F("foo %% %s") % "bar");
137 
138     EQ("foo %%", F("foo %s") % "%%");
139     EQ("foo a%%b", F("foo a%sb") % "%%");
140     EQ("foo a%%b", F("foo %s") % "a%%b");
141 
142     EQ("foo % bar %%", F("foo %% %s %%%%") % "bar");
143 }
144 
145 
146 ATF_TEST_CASE_WITHOUT_HEAD(extra_args_error);
147 ATF_TEST_CASE_BODY(extra_args_error)
148 {
149     using format::extra_args_error;
150 
151     ATF_REQUIRE_THROW(extra_args_error, F("foo") % "bar");
152     ATF_REQUIRE_THROW(extra_args_error, F("foo %%") % "bar");
153     ATF_REQUIRE_THROW(extra_args_error, F("foo %s") % "bar" % "baz");
154     ATF_REQUIRE_THROW(extra_args_error, F("foo %s") % "%s" % "bar");
155     ATF_REQUIRE_THROW(extra_args_error, F("%s foo %s") % "bar" % "baz" % "foo");
156 
157     try {
158         F("foo %s %s") % "bar" % "baz" % "something extra";
159         fail("extra_args_error not raised");
160     } catch (const extra_args_error& e) {
161         ATF_REQUIRE_EQ("foo %s %s", e.format());
162         ATF_REQUIRE_EQ("something extra", e.arg());
163     }
164 }
165 
166 
167 ATF_TEST_CASE_WITHOUT_HEAD(format__class);
168 ATF_TEST_CASE_BODY(format__class)
169 {
170     EQ("foo bar", F("%s") % std::string("foo bar"));
171     EQ("3", F("%s") % int_wrapper(3));
172 }
173 
174 
175 ATF_TEST_CASE_WITHOUT_HEAD(format__pointer);
176 ATF_TEST_CASE_BODY(format__pointer)
177 {
178     EQ("0xcafebabe", F("%s") % reinterpret_cast< void* >(0xcafebabe));
179     EQ("foo bar", F("%s") % "foo bar");
180 }
181 
182 
183 ATF_TEST_CASE_WITHOUT_HEAD(format__bool);
184 ATF_TEST_CASE_BODY(format__bool)
185 {
186     EQ("true", F("%s") % true);
187     EQ("false", F("%s") % false);
188 }
189 
190 
191 ATF_TEST_CASE_WITHOUT_HEAD(format__char);
192 ATF_TEST_CASE_BODY(format__char)
193 {
194     EQ("Z", F("%s") % 'Z');
195 }
196 
197 
198 ATF_TEST_CASE_WITHOUT_HEAD(format__float);
199 ATF_TEST_CASE_BODY(format__float)
200 {
201     EQ("3", F("%s") % 3.0);
202     EQ("3.0", F("%.1s") % 3.0);
203     EQ("3.0", F("%0.1s") % 3.0);
204     EQ("  15.600", F("%8.3s") % 15.6);
205     EQ("01.52", F("%05.2s") % 1.52);
206 }
207 
208 
209 ATF_TEST_CASE_WITHOUT_HEAD(format__int);
210 ATF_TEST_CASE_BODY(format__int)
211 {
212     EQ("3", F("%s") % 3);
213     EQ("3", F("%0s") % 3);
214     EQ(" -123", F("%5s") % -123);
215     EQ("00078", F("%05s") % 78);
216 }
217 
218 
219 ATF_TEST_CASE_WITHOUT_HEAD(format__error);
220 ATF_TEST_CASE_BODY(format__error)
221 {
222     using format::bad_format_error;
223 
224     ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("%"));
225     ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("f%"));
226     ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("f%%%"));
227     ATF_REQUIRE_THROW_RE(bad_format_error, "Trailing %", F("ab %s cd%") % "cd");
228 
229     ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid width", F("%1bs"));
230 
231     ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%.s"));
232     ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%0.s"));
233     ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%123.s"));
234     ATF_REQUIRE_THROW_RE(bad_format_error, "Invalid precision", F("%.12bs"));
235 
236     ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%c") % 'Z');
237     ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%d") % 5);
238     ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%.1f") % 3);
239     ATF_REQUIRE_THROW_RE(bad_format_error, "Unterminated", F("%d%s") % 3 % "a");
240 
241     try {
242         F("foo %s%") % "bar";
243         fail("bad_format_error not raised");
244     } catch (const bad_format_error& e) {
245         ATF_REQUIRE_EQ("foo %s%", e.format());
246     }
247 }
248 
249 
250 ATF_INIT_TEST_CASES(tcs)
251 {
252     ATF_ADD_TEST_CASE(tcs, no_fields);
253     ATF_ADD_TEST_CASE(tcs, one_field);
254     ATF_ADD_TEST_CASE(tcs, many_fields);
255     ATF_ADD_TEST_CASE(tcs, escape);
256     ATF_ADD_TEST_CASE(tcs, extra_args_error);
257 
258     ATF_ADD_TEST_CASE(tcs, format__class);
259     ATF_ADD_TEST_CASE(tcs, format__pointer);
260     ATF_ADD_TEST_CASE(tcs, format__bool);
261     ATF_ADD_TEST_CASE(tcs, format__char);
262     ATF_ADD_TEST_CASE(tcs, format__float);
263     ATF_ADD_TEST_CASE(tcs, format__int);
264     ATF_ADD_TEST_CASE(tcs, format__error);
265 }
266