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