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
38namespace format = utils::format;
39
40
41namespace {
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;
48class int_wrapper {
49    /// The wrapped integer.
50    int _value;
51
52public:
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.
77std::ostream&
78operator<<(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
98ATF_TEST_CASE_WITHOUT_HEAD(no_fields);
99ATF_TEST_CASE_BODY(no_fields)
100{
101    EQ("Plain string", F("Plain string"));
102}
103
104
105ATF_TEST_CASE_WITHOUT_HEAD(one_field);
106ATF_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
117ATF_TEST_CASE_WITHOUT_HEAD(many_fields);
118ATF_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
127ATF_TEST_CASE_WITHOUT_HEAD(escape);
128ATF_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
146ATF_TEST_CASE_WITHOUT_HEAD(extra_args_error);
147ATF_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
167ATF_TEST_CASE_WITHOUT_HEAD(format__class);
168ATF_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
175ATF_TEST_CASE_WITHOUT_HEAD(format__pointer);
176ATF_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
183ATF_TEST_CASE_WITHOUT_HEAD(format__bool);
184ATF_TEST_CASE_BODY(format__bool)
185{
186    EQ("true", F("%s") % true);
187    EQ("false", F("%s") % false);
188}
189
190
191ATF_TEST_CASE_WITHOUT_HEAD(format__char);
192ATF_TEST_CASE_BODY(format__char)
193{
194    EQ("Z", F("%s") % 'Z');
195}
196
197
198ATF_TEST_CASE_WITHOUT_HEAD(format__float);
199ATF_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
209ATF_TEST_CASE_WITHOUT_HEAD(format__int);
210ATF_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
219ATF_TEST_CASE_WITHOUT_HEAD(format__error);
220ATF_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
250ATF_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