1 // Copyright 2012 Google Inc. 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/text/operations.ipp" 30 31 #include <iostream> 32 #include <set> 33 #include <string> 34 #include <vector> 35 36 #include <atf-c++.hpp> 37 38 #include "utils/text/exceptions.hpp" 39 40 namespace text = utils::text; 41 42 43 namespace { 44 45 46 /// Tests text::refill() on an input string with a range of widths. 47 /// 48 /// \param expected The expected refilled paragraph. 49 /// \param input The input paragraph to be refilled. 50 /// \param first_width The first width to validate. 51 /// \param last_width The last width to validate (inclusive). 52 static void 53 refill_test(const char* expected, const char* input, 54 const std::size_t first_width, const std::size_t last_width) 55 { 56 for (std::size_t width = first_width; width <= last_width; ++width) { 57 const std::vector< std::string > lines = text::split(expected, '\n'); 58 std::cout << "Breaking at width " << width << '\n'; 59 ATF_REQUIRE_EQ(expected, text::refill_as_string(input, width)); 60 ATF_REQUIRE(lines == text::refill(input, width)); 61 } 62 } 63 64 65 } // anonymous namespace 66 67 68 ATF_TEST_CASE_WITHOUT_HEAD(quote__empty); 69 ATF_TEST_CASE_BODY(quote__empty) 70 { 71 ATF_REQUIRE_EQ("''", text::quote("", '\'')); 72 ATF_REQUIRE_EQ("##", text::quote("", '#')); 73 } 74 75 76 ATF_TEST_CASE_WITHOUT_HEAD(quote__no_escaping); 77 ATF_TEST_CASE_BODY(quote__no_escaping) 78 { 79 ATF_REQUIRE_EQ("'Some text\"'", text::quote("Some text\"", '\'')); 80 ATF_REQUIRE_EQ("#Another'string#", text::quote("Another'string", '#')); 81 } 82 83 84 ATF_TEST_CASE_WITHOUT_HEAD(quote__some_escaping); 85 ATF_TEST_CASE_BODY(quote__some_escaping) 86 { 87 ATF_REQUIRE_EQ("'Some\\'text'", text::quote("Some'text", '\'')); 88 ATF_REQUIRE_EQ("#Some\\#text#", text::quote("Some#text", '#')); 89 90 ATF_REQUIRE_EQ("'More than one\\' quote\\''", 91 text::quote("More than one' quote'", '\'')); 92 ATF_REQUIRE_EQ("'Multiple quotes \\'\\'\\' together'", 93 text::quote("Multiple quotes ''' together", '\'')); 94 95 ATF_REQUIRE_EQ("'\\'escape at the beginning'", 96 text::quote("'escape at the beginning", '\'')); 97 ATF_REQUIRE_EQ("'escape at the end\\''", 98 text::quote("escape at the end'", '\'')); 99 } 100 101 102 ATF_TEST_CASE_WITHOUT_HEAD(refill__empty); 103 ATF_TEST_CASE_BODY(refill__empty) 104 { 105 ATF_REQUIRE_EQ(1, text::refill("", 0).size()); 106 ATF_REQUIRE(text::refill("", 0)[0].empty()); 107 ATF_REQUIRE_EQ("", text::refill_as_string("", 0)); 108 109 ATF_REQUIRE_EQ(1, text::refill("", 10).size()); 110 ATF_REQUIRE(text::refill("", 10)[0].empty()); 111 ATF_REQUIRE_EQ("", text::refill_as_string("", 10)); 112 } 113 114 115 ATF_TEST_CASE_WITHOUT_HEAD(refill__no_changes); 116 ATF_TEST_CASE_BODY(refill__no_changes) 117 { 118 std::vector< std::string > exp_lines; 119 exp_lines.push_back("foo bar\nbaz"); 120 121 ATF_REQUIRE(exp_lines == text::refill("foo bar\nbaz", 12)); 122 ATF_REQUIRE_EQ("foo bar\nbaz", text::refill_as_string("foo bar\nbaz", 12)); 123 124 ATF_REQUIRE(exp_lines == text::refill("foo bar\nbaz", 18)); 125 ATF_REQUIRE_EQ("foo bar\nbaz", text::refill_as_string("foo bar\nbaz", 80)); 126 } 127 128 129 ATF_TEST_CASE_WITHOUT_HEAD(refill__break_one); 130 ATF_TEST_CASE_BODY(refill__break_one) 131 { 132 refill_test("only break the\nfirst line", "only break the first line", 133 14, 19); 134 } 135 136 137 ATF_TEST_CASE_WITHOUT_HEAD(refill__break_one__not_first_word); 138 ATF_TEST_CASE_BODY(refill__break_one__not_first_word) 139 { 140 refill_test("first-long-word\nother\nwords", "first-long-word other words", 141 6, 10); 142 refill_test("first-long-word\nother words", "first-long-word other words", 143 11, 20); 144 refill_test("first-long-word other\nwords", "first-long-word other words", 145 21, 26); 146 refill_test("first-long-word other words", "first-long-word other words", 147 27, 28); 148 } 149 150 151 ATF_TEST_CASE_WITHOUT_HEAD(refill__break_many); 152 ATF_TEST_CASE_BODY(refill__break_many) 153 { 154 refill_test("this is a long\nparagraph to be\nsplit into\npieces", 155 "this is a long paragraph to be split into pieces", 156 15, 15); 157 } 158 159 160 ATF_TEST_CASE_WITHOUT_HEAD(refill__cannot_break); 161 ATF_TEST_CASE_BODY(refill__cannot_break) 162 { 163 refill_test("this-is-a-long-string", "this-is-a-long-string", 5, 5); 164 165 refill_test("this is\na-string-with-long-words", 166 "this is a-string-with-long-words", 10, 10); 167 } 168 169 170 ATF_TEST_CASE_WITHOUT_HEAD(refill__preserve_whitespace); 171 ATF_TEST_CASE_BODY(refill__preserve_whitespace) 172 { 173 refill_test("foo bar baz ", "foo bar baz ", 80, 80); 174 refill_test("foo \n bar", "foo bar", 5, 5); 175 176 std::vector< std::string > exp_lines; 177 exp_lines.push_back("foo \n"); 178 exp_lines.push_back(" bar"); 179 ATF_REQUIRE(exp_lines == text::refill("foo \n bar", 5)); 180 ATF_REQUIRE_EQ("foo \n\n bar", text::refill_as_string("foo \n bar", 5)); 181 } 182 183 184 ATF_TEST_CASE_WITHOUT_HEAD(join__empty); 185 ATF_TEST_CASE_BODY(join__empty) 186 { 187 std::vector< std::string > lines; 188 ATF_REQUIRE_EQ("", text::join(lines, " ")); 189 } 190 191 192 ATF_TEST_CASE_WITHOUT_HEAD(join__one); 193 ATF_TEST_CASE_BODY(join__one) 194 { 195 std::vector< std::string > lines; 196 lines.push_back("first line"); 197 ATF_REQUIRE_EQ("first line", text::join(lines, "*")); 198 } 199 200 201 ATF_TEST_CASE_WITHOUT_HEAD(join__several); 202 ATF_TEST_CASE_BODY(join__several) 203 { 204 std::vector< std::string > lines; 205 lines.push_back("first abc"); 206 lines.push_back("second"); 207 lines.push_back("and last line"); 208 ATF_REQUIRE_EQ("first abc second and last line", text::join(lines, " ")); 209 ATF_REQUIRE_EQ("first abc***second***and last line", 210 text::join(lines, "***")); 211 } 212 213 214 ATF_TEST_CASE_WITHOUT_HEAD(join__unordered); 215 ATF_TEST_CASE_BODY(join__unordered) 216 { 217 std::set< std::string > lines; 218 lines.insert("first"); 219 lines.insert("second"); 220 const std::string joined = text::join(lines, " "); 221 ATF_REQUIRE(joined == "first second" || joined == "second first"); 222 } 223 224 225 ATF_TEST_CASE_WITHOUT_HEAD(split__empty); 226 ATF_TEST_CASE_BODY(split__empty) 227 { 228 std::vector< std::string > words = text::split("", ' '); 229 std::vector< std::string > exp_words; 230 ATF_REQUIRE(exp_words == words); 231 } 232 233 234 ATF_TEST_CASE_WITHOUT_HEAD(split__one); 235 ATF_TEST_CASE_BODY(split__one) 236 { 237 std::vector< std::string > words = text::split("foo", ' '); 238 std::vector< std::string > exp_words; 239 exp_words.push_back("foo"); 240 ATF_REQUIRE(exp_words == words); 241 } 242 243 244 ATF_TEST_CASE_WITHOUT_HEAD(split__several__simple); 245 ATF_TEST_CASE_BODY(split__several__simple) 246 { 247 std::vector< std::string > words = text::split("foo bar baz", ' '); 248 std::vector< std::string > exp_words; 249 exp_words.push_back("foo"); 250 exp_words.push_back("bar"); 251 exp_words.push_back("baz"); 252 ATF_REQUIRE(exp_words == words); 253 } 254 255 256 ATF_TEST_CASE_WITHOUT_HEAD(split__several__delimiters); 257 ATF_TEST_CASE_BODY(split__several__delimiters) 258 { 259 std::vector< std::string > words = text::split("XfooXXbarXXXbazXX", 'X'); 260 std::vector< std::string > exp_words; 261 exp_words.push_back(""); 262 exp_words.push_back("foo"); 263 exp_words.push_back(""); 264 exp_words.push_back("bar"); 265 exp_words.push_back(""); 266 exp_words.push_back(""); 267 exp_words.push_back("baz"); 268 exp_words.push_back(""); 269 exp_words.push_back(""); 270 ATF_REQUIRE(exp_words == words); 271 } 272 273 274 ATF_TEST_CASE_WITHOUT_HEAD(to_type__ok__bool); 275 ATF_TEST_CASE_BODY(to_type__ok__bool) 276 { 277 ATF_REQUIRE( text::to_type< bool >("true")); 278 ATF_REQUIRE(!text::to_type< bool >("false")); 279 } 280 281 282 ATF_TEST_CASE_WITHOUT_HEAD(to_type__ok__numerical); 283 ATF_TEST_CASE_BODY(to_type__ok__numerical) 284 { 285 ATF_REQUIRE_EQ(12, text::to_type< int >("12")); 286 ATF_REQUIRE_EQ(18745, text::to_type< int >("18745")); 287 ATF_REQUIRE_EQ(-12345, text::to_type< int >("-12345")); 288 289 ATF_REQUIRE_EQ(12.0, text::to_type< double >("12")); 290 ATF_REQUIRE_EQ(12.5, text::to_type< double >("12.5")); 291 } 292 293 294 ATF_TEST_CASE_WITHOUT_HEAD(to_type__ok__string); 295 ATF_TEST_CASE_BODY(to_type__ok__string) 296 { 297 // While this seems redundant, having this particular specialization that 298 // does nothing allows callers to delegate work to to_type without worrying 299 // about the particular type being converted. 300 ATF_REQUIRE_EQ("", text::to_type< std::string >("")); 301 ATF_REQUIRE_EQ(" abcd ", text::to_type< std::string >(" abcd ")); 302 } 303 304 305 ATF_TEST_CASE_WITHOUT_HEAD(to_type__empty); 306 ATF_TEST_CASE_BODY(to_type__empty) 307 { 308 ATF_REQUIRE_THROW(text::value_error, text::to_type< int >("")); 309 } 310 311 312 ATF_TEST_CASE_WITHOUT_HEAD(to_type__invalid__bool); 313 ATF_TEST_CASE_BODY(to_type__invalid__bool) 314 { 315 ATF_REQUIRE_THROW(text::value_error, text::to_type< bool >("")); 316 ATF_REQUIRE_THROW(text::value_error, text::to_type< bool >("true ")); 317 ATF_REQUIRE_THROW(text::value_error, text::to_type< bool >("foo")); 318 } 319 320 321 ATF_TEST_CASE_WITHOUT_HEAD(to_type__invalid__numerical); 322 ATF_TEST_CASE_BODY(to_type__invalid__numerical) 323 { 324 ATF_REQUIRE_THROW(text::value_error, text::to_type< int >(" 3")); 325 ATF_REQUIRE_THROW(text::value_error, text::to_type< int >("3 ")); 326 ATF_REQUIRE_THROW(text::value_error, text::to_type< int >("3a")); 327 ATF_REQUIRE_THROW(text::value_error, text::to_type< int >("a3")); 328 } 329 330 331 ATF_INIT_TEST_CASES(tcs) 332 { 333 ATF_ADD_TEST_CASE(tcs, quote__empty); 334 ATF_ADD_TEST_CASE(tcs, quote__no_escaping); 335 ATF_ADD_TEST_CASE(tcs, quote__some_escaping); 336 337 ATF_ADD_TEST_CASE(tcs, refill__empty); 338 ATF_ADD_TEST_CASE(tcs, refill__no_changes); 339 ATF_ADD_TEST_CASE(tcs, refill__break_one); 340 ATF_ADD_TEST_CASE(tcs, refill__break_one__not_first_word); 341 ATF_ADD_TEST_CASE(tcs, refill__break_many); 342 ATF_ADD_TEST_CASE(tcs, refill__cannot_break); 343 ATF_ADD_TEST_CASE(tcs, refill__preserve_whitespace); 344 345 ATF_ADD_TEST_CASE(tcs, join__empty); 346 ATF_ADD_TEST_CASE(tcs, join__one); 347 ATF_ADD_TEST_CASE(tcs, join__several); 348 ATF_ADD_TEST_CASE(tcs, join__unordered); 349 350 ATF_ADD_TEST_CASE(tcs, split__empty); 351 ATF_ADD_TEST_CASE(tcs, split__one); 352 ATF_ADD_TEST_CASE(tcs, split__several__simple); 353 ATF_ADD_TEST_CASE(tcs, split__several__delimiters); 354 355 ATF_ADD_TEST_CASE(tcs, to_type__ok__bool); 356 ATF_ADD_TEST_CASE(tcs, to_type__ok__numerical); 357 ATF_ADD_TEST_CASE(tcs, to_type__ok__string); 358 ATF_ADD_TEST_CASE(tcs, to_type__empty); 359 ATF_ADD_TEST_CASE(tcs, to_type__invalid__bool); 360 ATF_ADD_TEST_CASE(tcs, to_type__invalid__numerical); 361 } 362