| 1 | // Boost.Range library |
| 2 | // |
| 3 | // Copyright Neil Groves 2014. Use, modification and |
| 4 | // distribution is subject to the Boost Software License, Version |
| 5 | // 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
| 6 | // http://www.boost.org/LICENSE_1_0.txt) |
| 7 | // |
| 8 | // For more information, see http://www.boost.org/libs/range/ |
| 9 | // |
| 10 | #include <boost/range/adaptor/formatted.hpp> |
| 11 | #include <boost/cstdint.hpp> |
| 12 | #include <boost/test/test_tools.hpp> |
| 13 | #include <boost/test/unit_test.hpp> |
| 14 | #include <iostream> |
| 15 | #include <string> |
| 16 | #include <sstream> |
| 17 | #include <vector> |
| 18 | |
| 19 | namespace boost_range_test |
| 20 | { |
| 21 | namespace |
| 22 | { |
| 23 | |
| 24 | template<typename T> |
| 25 | std::string make_string(T x) |
| 26 | { |
| 27 | std::ostringstream result; |
| 28 | result << x; |
| 29 | return result.str(); |
| 30 | } |
| 31 | |
| 32 | template<typename T1, typename T2> |
| 33 | std::string make_string(T1 x, T2 y) |
| 34 | { |
| 35 | std::ostringstream result; |
| 36 | result << x << y; |
| 37 | return result.str(); |
| 38 | } |
| 39 | |
| 40 | std::string reference_result(const std::vector<boost::int32_t>& v, |
| 41 | const std::string& separator, |
| 42 | const std::string& prefix, |
| 43 | const std::string& postfix) |
| 44 | { |
| 45 | std::ostringstream out; |
| 46 | out << prefix; |
| 47 | if (!v.empty()) |
| 48 | { |
| 49 | out << v.at(n: 0); |
| 50 | std::vector<boost::int32_t>::const_iterator it = v.begin(); |
| 51 | for (++it; it != v.end(); ++it) |
| 52 | { |
| 53 | out << separator << *it; |
| 54 | } |
| 55 | } |
| 56 | out << postfix; |
| 57 | |
| 58 | return out.str(); |
| 59 | } |
| 60 | |
| 61 | void test_formatted_0args_impl(const std::vector<boost::int32_t>& v) |
| 62 | { |
| 63 | std::ostringstream out1; |
| 64 | out1 << '[' << (v | boost::adaptors::formatted()) << ']'; |
| 65 | BOOST_CHECK_EQUAL(out1.str(), reference_result(v, "," , "[{" , "}]" )); |
| 66 | |
| 67 | std::ostringstream out2; |
| 68 | out2 << '[' << boost::adaptors::format(rng: v) << ']'; |
| 69 | BOOST_CHECK_EQUAL(out2.str(), reference_result(v, "," , "[{" , "}]" )); |
| 70 | |
| 71 | std::ostringstream out3; |
| 72 | out3 << (v | boost::adaptors::formatted()); |
| 73 | BOOST_CHECK_EQUAL(out3.str(), reference_result(v, "," , "{" , "}" )); |
| 74 | |
| 75 | std::ostringstream out4; |
| 76 | out4 << boost::adaptors::format(rng: v); |
| 77 | BOOST_CHECK_EQUAL(out4.str(), reference_result(v, "," , "{" , "}" )); |
| 78 | } |
| 79 | |
| 80 | template<typename Sep> |
| 81 | void test_formatted_1arg_impl( |
| 82 | const std::vector<boost::int32_t>& v, |
| 83 | const Sep& sep) |
| 84 | { |
| 85 | const std::string ref_sep = make_string(sep); |
| 86 | std::ostringstream out1; |
| 87 | out1 << '[' << (v | boost::adaptors::formatted(sep)) << ']'; |
| 88 | |
| 89 | BOOST_CHECK_EQUAL(out1.str(), reference_result(v, ref_sep, "[{" , "}]" )); |
| 90 | |
| 91 | std::ostringstream out2; |
| 92 | out2 << '[' << boost::adaptors::format(v, sep) << ']'; |
| 93 | BOOST_CHECK_EQUAL(out2.str(), reference_result(v, ref_sep, "[{" , "}]" )); |
| 94 | |
| 95 | std::ostringstream out3; |
| 96 | out3 << (v | boost::adaptors::formatted(sep)); |
| 97 | BOOST_CHECK_EQUAL(out3.str(), reference_result(v, ref_sep, "{" , "}" )); |
| 98 | |
| 99 | std::ostringstream out4; |
| 100 | out4 << boost::adaptors::format(v, sep); |
| 101 | BOOST_CHECK_EQUAL(out4.str(), reference_result(v, ref_sep, "{" , "}" )); |
| 102 | } |
| 103 | |
| 104 | void test_formatted_1arg_impl(const std::vector<boost::int32_t>& v) |
| 105 | { |
| 106 | test_formatted_1arg_impl(v, sep: ','); |
| 107 | test_formatted_1arg_impl(v, sep: ' '); |
| 108 | test_formatted_1arg_impl<const char[3]>(v, sep: ":?" ); |
| 109 | } |
| 110 | |
| 111 | template<typename Sep, typename Prefix> |
| 112 | void test_formatted_2args_impl( |
| 113 | const std::vector<boost::int32_t>& v, |
| 114 | const Sep& sep, |
| 115 | const Prefix& prefix |
| 116 | ) |
| 117 | { |
| 118 | const std::string ref_sep = make_string(sep); |
| 119 | |
| 120 | std::ostringstream out1; |
| 121 | out1 << '[' << (v | boost::adaptors::formatted(sep, prefix)) << ']'; |
| 122 | BOOST_CHECK_EQUAL( |
| 123 | out1.str(), |
| 124 | reference_result(v, ref_sep, make_string('[', prefix), "}]" )); |
| 125 | |
| 126 | std::ostringstream out2; |
| 127 | out2 << '[' << boost::adaptors::format(v, sep, prefix) << ']'; |
| 128 | BOOST_CHECK_EQUAL( |
| 129 | out2.str(), |
| 130 | reference_result(v, ref_sep, make_string('[', prefix), "}]" )); |
| 131 | |
| 132 | std::ostringstream out3; |
| 133 | out3 << (v | boost::adaptors::formatted(sep, prefix)); |
| 134 | BOOST_CHECK_EQUAL( |
| 135 | out3.str(), |
| 136 | reference_result(v, ref_sep, make_string(prefix), "}" )); |
| 137 | |
| 138 | std::ostringstream out4; |
| 139 | out4 << boost::adaptors::format(v, sep, prefix); |
| 140 | BOOST_CHECK_EQUAL( |
| 141 | out4.str(), |
| 142 | reference_result(v, ref_sep, make_string(prefix), "}" )); |
| 143 | } |
| 144 | |
| 145 | void test_formatted_2args_impl(const std::vector<boost::int32_t>& v) |
| 146 | { |
| 147 | test_formatted_2args_impl(v, sep: ',', prefix: '{'); |
| 148 | test_formatted_2args_impl(v, sep: ':', prefix: '('); |
| 149 | test_formatted_2args_impl<char, const char[3]>(v, sep: ',', prefix: "{!" ); |
| 150 | test_formatted_2args_impl<const char[3], char>(v, sep: "#$" , prefix: '{'); |
| 151 | test_formatted_2args_impl<const char[3], const char[3]>(v, sep: "#$" , prefix: "{!" ); |
| 152 | } |
| 153 | |
| 154 | template<typename Sep, typename Prefix, typename Postfix> |
| 155 | void test_formatted_3args_impl( |
| 156 | const std::vector<boost::int32_t>& v, |
| 157 | const Sep& sep, |
| 158 | const Prefix& prefix, |
| 159 | const Postfix& postfix |
| 160 | ) |
| 161 | { |
| 162 | const std::string ref_sep = make_string(sep); |
| 163 | |
| 164 | std::ostringstream out1; |
| 165 | out1 << '[' << (v | boost::adaptors::formatted(sep, prefix, postfix)) |
| 166 | << ']'; |
| 167 | BOOST_CHECK_EQUAL( |
| 168 | out1.str(), |
| 169 | reference_result(v, ref_sep, make_string('[', prefix), |
| 170 | make_string(postfix, ']'))); |
| 171 | } |
| 172 | |
| 173 | void test_formatted_3args_impl(const std::vector<boost::int32_t>& v) |
| 174 | { |
| 175 | test_formatted_3args_impl(v, sep: ',', prefix: '{', postfix: '}'); |
| 176 | test_formatted_3args_impl(v, sep: ':', prefix: '(', postfix: ')'); |
| 177 | test_formatted_3args_impl<char, char, const char[3]>(v, sep: ',', prefix: '{', postfix: "!}" ); |
| 178 | test_formatted_3args_impl<char, const char[3], char>(v, sep: ',', prefix: "{!" , postfix: '}'); |
| 179 | test_formatted_3args_impl<const char[3], char, char>(v, sep: "#$" , prefix: '{', postfix: '}'); |
| 180 | test_formatted_3args_impl< |
| 181 | const char[3], const char[3], const char[3] |
| 182 | >(v, sep: "#$" , prefix: "{!" , postfix: "!}" ); |
| 183 | } |
| 184 | |
| 185 | void test_formatted_impl(const std::vector<boost::int32_t>& v) |
| 186 | { |
| 187 | test_formatted_0args_impl(v); |
| 188 | test_formatted_1arg_impl(v); |
| 189 | test_formatted_2args_impl(v); |
| 190 | test_formatted_3args_impl(v); |
| 191 | } |
| 192 | |
| 193 | void test_formatted1() |
| 194 | { |
| 195 | std::vector<boost::int32_t> v; |
| 196 | for (boost::int32_t i = 0; i < 10; ++i) |
| 197 | v.push_back(x: i); |
| 198 | |
| 199 | test_formatted_impl(v); |
| 200 | } |
| 201 | |
| 202 | void test_formatted2() |
| 203 | { |
| 204 | std::vector<boost::int32_t> v; |
| 205 | v.push_back(x: 3); |
| 206 | |
| 207 | test_formatted_impl(v); |
| 208 | } |
| 209 | |
| 210 | void test_formatted3() |
| 211 | { |
| 212 | std::vector<boost::int32_t> v; |
| 213 | |
| 214 | test_formatted_impl(v); |
| 215 | } |
| 216 | |
| 217 | void test_formatted4() |
| 218 | { |
| 219 | std::vector<boost::int32_t> v; |
| 220 | for (boost::int32_t i = 0; i < 5; ++i) |
| 221 | v.push_back(x: i); |
| 222 | |
| 223 | test_formatted_impl(v); |
| 224 | } |
| 225 | |
| 226 | struct udt_separator |
| 227 | { |
| 228 | }; |
| 229 | |
| 230 | template<typename Char, typename Traits> |
| 231 | inline std::basic_ostream<Char,Traits>& |
| 232 | operator<<(std::basic_ostream<Char,Traits>& out, udt_separator) |
| 233 | { |
| 234 | return out << "[sep]" ; |
| 235 | } |
| 236 | |
| 237 | void test_formatted5() |
| 238 | { |
| 239 | std::vector<boost::int32_t> v; |
| 240 | for (boost::int32_t i = 0; i < 5; ++i) |
| 241 | v.push_back(x: i); |
| 242 | |
| 243 | std::ostringstream out1; |
| 244 | out1 << (v | boost::adaptors::formatted(sep: udt_separator())); |
| 245 | BOOST_CHECK_EQUAL(out1.str(), "{0[sep]1[sep]2[sep]3[sep]4}" ); |
| 246 | |
| 247 | std::ostringstream out2; |
| 248 | out2 << boost::adaptors::format(rng: v, sep: udt_separator()); |
| 249 | BOOST_CHECK_EQUAL(out2.str(), "{0[sep]1[sep]2[sep]3[sep]4}" ); |
| 250 | } |
| 251 | |
| 252 | // This test is already covered by the more complex code above. This |
| 253 | // code duplicates coverage to ensure that char literal arrays are handled |
| 254 | // correctly. I was particularly concerned that my test code above may pass |
| 255 | // erroneously by decaying a char literal to a pointer. This function makes |
| 256 | // it very plain that character literal strings work. |
| 257 | void test_formatted_empty() |
| 258 | { |
| 259 | std::vector<boost::int32_t> v; |
| 260 | |
| 261 | std::ostringstream out1; |
| 262 | out1 << (v | boost::adaptors::formatted()); |
| 263 | BOOST_CHECK_EQUAL(out1.str(), "{}" ); |
| 264 | |
| 265 | std::ostringstream out2; |
| 266 | out2 << boost::adaptors::format(rng: v); |
| 267 | BOOST_CHECK_EQUAL(out2.str(), "{}" ); |
| 268 | |
| 269 | std::ostringstream out3; |
| 270 | out3 << (v | boost::adaptors::formatted(sep: ',')); |
| 271 | BOOST_CHECK_EQUAL(out3.str(), "{}" ); |
| 272 | |
| 273 | std::ostringstream out4; |
| 274 | out4 << boost::adaptors::format(rng: v, sep: ','); |
| 275 | BOOST_CHECK_EQUAL(out4.str(), "{}" ); |
| 276 | |
| 277 | std::ostringstream out5; |
| 278 | out5 << (v | boost::adaptors::formatted(sep: "#$" )); |
| 279 | BOOST_CHECK_EQUAL(out5.str(), "{}" ); |
| 280 | |
| 281 | std::ostringstream out6; |
| 282 | out6 << boost::adaptors::format(rng: v, sep: "#$" ); |
| 283 | BOOST_CHECK_EQUAL(out6.str(), "{}" ); |
| 284 | |
| 285 | std::ostringstream out7; |
| 286 | out7 << (v | boost::adaptors::formatted(sep: "" , prefix: "12" , postfix: "34" )); |
| 287 | BOOST_CHECK_EQUAL(out7.str(), "1234" ); |
| 288 | |
| 289 | std::ostringstream out8; |
| 290 | out8 << boost::adaptors::format(rng: v, sep: "" , prefix: "12" , postfix: "34" ); |
| 291 | BOOST_CHECK_EQUAL(out8.str(), "1234" ); |
| 292 | } |
| 293 | |
| 294 | } // anonymous namespace |
| 295 | } // namespace boost_range_test |
| 296 | |
| 297 | boost::unit_test::test_suite* init_unit_test_suite(int, char*[] ) |
| 298 | { |
| 299 | boost::unit_test::test_suite* test = |
| 300 | BOOST_TEST_SUITE( "Boost.Range formatted test suite" ); |
| 301 | |
| 302 | test->add(BOOST_TEST_CASE(&boost_range_test::test_formatted1)); |
| 303 | test->add(BOOST_TEST_CASE(&boost_range_test::test_formatted2)); |
| 304 | test->add(BOOST_TEST_CASE(&boost_range_test::test_formatted3)); |
| 305 | test->add(BOOST_TEST_CASE(&boost_range_test::test_formatted4)); |
| 306 | test->add(BOOST_TEST_CASE(&boost_range_test::test_formatted5)); |
| 307 | |
| 308 | test->add(BOOST_TEST_CASE(&boost_range_test::test_formatted_empty)); |
| 309 | |
| 310 | return test; |
| 311 | } |
| 312 | |