1 // what: unit tests for variant type boost::any
2 // who: contributed by Kevlin Henney
3 // when: July 2001, 2013, 2014
4 // where: tested with BCC 5.5, MSVC 6.0, and g++ 2.95
5
6 #include <cstdlib>
7 #include <string>
8 #include <vector>
9 #include <utility>
10
11 #include <boost/any.hpp>
12 #include "test.hpp"
13
14 namespace any_tests
15 {
16 typedef test<const char *, void (*)()> test_case;
17 typedef const test_case * test_case_iterator;
18
19 extern const test_case_iterator begin, end;
20 }
21
main()22 int main()
23 {
24 using namespace any_tests;
25 tester<test_case_iterator> test_suite(begin, end);
26 return test_suite() ? EXIT_SUCCESS : EXIT_FAILURE;
27 }
28
29 namespace any_tests // test suite
30 {
31 void test_default_ctor();
32 void test_converting_ctor();
33 void test_copy_ctor();
34 void test_copy_assign();
35 void test_converting_assign();
36 void test_bad_cast();
37 void test_swap();
38 void test_null_copying();
39 void test_cast_to_reference();
40 void test_with_array();
41 void test_with_func();
42 void test_clear();
43 void test_vectors();
44 void test_addressof();
45
46 const test_case test_cases[] =
47 {
48 { "default construction", test_default_ctor },
49 { "single argument construction", test_converting_ctor },
50 { "copy construction", test_copy_ctor },
51 { "copy assignment operator", test_copy_assign },
52 { "converting assignment operator", test_converting_assign },
53 { "failed custom keyword cast", test_bad_cast },
54 { "swap member function", test_swap },
55 { "copying operations on a null", test_null_copying },
56 { "cast to reference types", test_cast_to_reference },
57 { "storing an array inside", test_with_array },
58 { "implicit cast of returned value",test_with_func },
59 { "clear() methods", test_clear },
60 { "testing with vectors", test_vectors },
61 { "class with operator&()", test_addressof }
62 };
63
64 const test_case_iterator begin = test_cases;
65 const test_case_iterator end =
66 test_cases + (sizeof test_cases / sizeof *test_cases);
67
68
69
70 struct copy_counter
71 {
72
73 public:
74
copy_counterany_tests::copy_counter75 copy_counter() {}
copy_counterany_tests::copy_counter76 copy_counter(const copy_counter&) { ++count; }
operator =any_tests::copy_counter77 copy_counter& operator=(const copy_counter&) { ++count; return *this; }
get_countany_tests::copy_counter78 static int get_count() { return count; }
79
80 private:
81
82 static int count;
83
84 };
85
86 int copy_counter::count = 0;
87 }
88
89 namespace any_tests // test definitions
90 {
91 using namespace boost;
92
test_default_ctor()93 void test_default_ctor()
94 {
95 const any value;
96
97 check_true(value.empty(), "empty");
98 check_null(any_cast<int>(&value), "any_cast<int>");
99 check_equal(value.type(), boost::typeindex::type_id<void>(), "type");
100 }
101
test_converting_ctor()102 void test_converting_ctor()
103 {
104 std::string text = "test message";
105 any value = text;
106
107 check_false(value.empty(), "empty");
108 check_equal(value.type(), boost::typeindex::type_id<std::string>(), "type");
109 check_null(any_cast<int>(&value), "any_cast<int>");
110 check_non_null(any_cast<std::string>(&value), "any_cast<std::string>");
111 check_equal(
112 any_cast<std::string>(value), text,
113 "comparing cast copy against original text");
114 check_unequal(
115 any_cast<std::string>(&value), &text,
116 "comparing address in copy against original text");
117 }
118
test_copy_ctor()119 void test_copy_ctor()
120 {
121 std::string text = "test message";
122 any original = text, copy = original;
123
124 check_false(copy.empty(), "empty");
125 check_equal(boost::typeindex::type_index(original.type()), copy.type(), "type");
126 check_equal(
127 any_cast<std::string>(original), any_cast<std::string>(copy),
128 "comparing cast copy against original");
129 check_equal(
130 text, any_cast<std::string>(copy),
131 "comparing cast copy against original text");
132 check_unequal(
133 any_cast<std::string>(&original),
134 any_cast<std::string>(©),
135 "comparing address in copy against original");
136 }
137
test_copy_assign()138 void test_copy_assign()
139 {
140 std::string text = "test message";
141 any original = text, copy;
142 any * assign_result = &(copy = original);
143
144 check_false(copy.empty(), "empty");
145 check_equal(boost::typeindex::type_index(original.type()), copy.type(), "type");
146 check_equal(
147 any_cast<std::string>(original), any_cast<std::string>(copy),
148 "comparing cast copy against cast original");
149 check_equal(
150 text, any_cast<std::string>(copy),
151 "comparing cast copy against original text");
152 check_unequal(
153 any_cast<std::string>(&original),
154 any_cast<std::string>(©),
155 "comparing address in copy against original");
156 check_equal(assign_result, ©, "address of assignment result");
157 }
158
test_converting_assign()159 void test_converting_assign()
160 {
161 std::string text = "test message";
162 any value;
163 any * assign_result = &(value = text);
164
165 check_false(value.empty(), "type");
166 check_equal(value.type(), boost::typeindex::type_id<std::string>(), "type");
167 check_null(any_cast<int>(&value), "any_cast<int>");
168 check_non_null(any_cast<std::string>(&value), "any_cast<std::string>");
169 check_equal(
170 any_cast<std::string>(value), text,
171 "comparing cast copy against original text");
172 check_unequal(
173 any_cast<std::string>(&value),
174 &text,
175 "comparing address in copy against original text");
176 check_equal(assign_result, &value, "address of assignment result");
177 }
178
test_bad_cast()179 void test_bad_cast()
180 {
181 std::string text = "test message";
182 any value = text;
183
184 TEST_CHECK_THROW(
185 any_cast<const char *>(value),
186 bad_any_cast,
187 "any_cast to incorrect type");
188 }
189
test_swap()190 void test_swap()
191 {
192 std::string text = "test message";
193 any original = text, swapped;
194 std::string * original_ptr = any_cast<std::string>(&original);
195 any * swap_result = &original.swap(swapped);
196
197 check_true(original.empty(), "empty on original");
198 check_false(swapped.empty(), "empty on swapped");
199 check_equal(swapped.type(), boost::typeindex::type_id<std::string>(), "type");
200 check_equal(
201 text, any_cast<std::string>(swapped),
202 "comparing swapped copy against original text");
203 check_non_null(original_ptr, "address in pre-swapped original");
204 check_equal(
205 original_ptr,
206 any_cast<std::string>(&swapped),
207 "comparing address in swapped against original");
208 check_equal(swap_result, &original, "address of swap result");
209
210 any copy1 = copy_counter();
211 any copy2 = copy_counter();
212 int count = copy_counter::get_count();
213 swap(copy1, copy2);
214 check_equal(count, copy_counter::get_count(), "checking that free swap doesn't make any copies.");
215 }
216
test_null_copying()217 void test_null_copying()
218 {
219 const any null;
220 any copied = null, assigned;
221 assigned = null;
222
223 check_true(null.empty(), "empty on null");
224 check_true(copied.empty(), "empty on copied");
225 check_true(assigned.empty(), "empty on copied");
226 }
227
test_cast_to_reference()228 void test_cast_to_reference()
229 {
230 any a(137);
231 const any b(a);
232
233 int & ra = any_cast<int &>(a);
234 int const & ra_c = any_cast<int const &>(a);
235 int volatile & ra_v = any_cast<int volatile &>(a);
236 int const volatile & ra_cv = any_cast<int const volatile&>(a);
237
238 check_true(
239 &ra == &ra_c && &ra == &ra_v && &ra == &ra_cv,
240 "cv references to same obj");
241
242 int const & rb_c = any_cast<int const &>(b);
243 int const volatile & rb_cv = any_cast<int const volatile &>(b);
244
245 check_true(&rb_c == &rb_cv, "cv references to copied const obj");
246 check_true(&ra != &rb_c, "copies hold different objects");
247
248 ++ra;
249 int incremented = any_cast<int>(a);
250 check_true(incremented == 138, "increment by reference changes value");
251
252 TEST_CHECK_THROW(
253 any_cast<char &>(a),
254 bad_any_cast,
255 "any_cast to incorrect reference type");
256
257 TEST_CHECK_THROW(
258 any_cast<const char &>(b),
259 bad_any_cast,
260 "any_cast to incorrect const reference type");
261 }
262
test_with_array()263 void test_with_array()
264 {
265 any value1("Char array");
266 any value2;
267 value2 = "Char array";
268
269 check_false(value1.empty(), "type");
270 check_false(value2.empty(), "type");
271
272 check_equal(value1.type(), boost::typeindex::type_id<const char*>(), "type");
273 check_equal(value2.type(), boost::typeindex::type_id<const char*>(), "type");
274
275 check_non_null(any_cast<const char*>(&value1), "any_cast<const char*>");
276 check_non_null(any_cast<const char*>(&value2), "any_cast<const char*>");
277 }
278
returning_string1()279 const std::string& returning_string1()
280 {
281 static const std::string ret("foo");
282 return ret;
283 }
284
returning_string2()285 std::string returning_string2()
286 {
287 static const std::string ret("foo");
288 return ret;
289 }
290
test_with_func()291 void test_with_func()
292 {
293 std::string s;
294 s = any_cast<std::string>(returning_string1());
295 s = any_cast<const std::string&>(returning_string1());
296
297 s = any_cast<std::string>(returning_string2());
298 s = any_cast<const std::string&>(returning_string2());
299
300 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
301 #if !defined(__INTEL_COMPILER) && !defined(__ICL) && (!defined(_MSC_VER) || _MSC_VER != 1600)
302 // Intel compiler thinks that it must choose the `any_cast(const any&)` function
303 // instead of the `any_cast(const any&&)`.
304 // Bug was not reported because of missing premier support account + annoying
305 // registrations requirements.
306
307 // MSVC-10 had a bug:
308 //
309 // any.hpp(291) : error C2440: 'return' : cannot convert.
310 // Conversion loses qualifiers
311 // any_test.cpp(304) : see reference to function template instantiation
312 //
313 // This issue was fixed in MSVC-11.
314
315 s = any_cast<std::string&&>(returning_string1());
316 #endif
317
318 s = any_cast<std::string&&>(returning_string2());
319 #endif
320 }
321
322
test_clear()323 void test_clear()
324 {
325 std::string text = "test message";
326 any value = text;
327
328 check_false(value.empty(), "empty");
329
330 value.clear();
331 check_true(value.empty(), "non-empty after clear");
332
333 value.clear();
334 check_true(value.empty(), "non-empty after second clear");
335
336 value = text;
337 check_false(value.empty(), "empty");
338
339 value.clear();
340 check_true(value.empty(), "non-empty after clear");
341 }
342
343 // Following tests cover the case from #9462
344 // https://svn.boost.org/trac/boost/ticket/9462
makeVec()345 boost::any makeVec()
346 {
347 return std::vector<int>(100 /*size*/, 7 /*value*/);
348 }
349
test_vectors()350 void test_vectors()
351 {
352 const std::vector<int>& vec = boost::any_cast<std::vector<int> >(makeVec());
353 check_equal(vec.size(), 100u, "size of vector extracted from boost::any");
354 check_equal(vec.back(), 7, "back value of vector extracted from boost::any");
355 check_equal(vec.front(), 7, "front value of vector extracted from boost::any");
356
357 std::vector<int> vec1 = boost::any_cast<std::vector<int> >(makeVec());
358 check_equal(vec1.size(), 100u, "size of second vector extracted from boost::any");
359 check_equal(vec1.back(), 7, "back value of second vector extracted from boost::any");
360 check_equal(vec1.front(), 7, "front value of second vector extracted from boost::any");
361
362 }
363
364 template<typename T>
365 class class_with_address_op {
366 public:
class_with_address_op(const T * p)367 class_with_address_op(const T* p)
368 : ptr(p)
369 {}
370
operator &()371 const T** operator &() {
372 return &ptr;
373 }
374
get() const375 const T* get() const {
376 return ptr;
377 }
378
379 private:
380 const T* ptr;
381 };
382
test_addressof()383 void test_addressof()
384 {
385 int val = 10;
386 const int* ptr = &val;
387 class_with_address_op<int> obj(ptr);
388 boost::any test_val(obj);
389
390 class_with_address_op<int> returned_obj = boost::any_cast<class_with_address_op<int> >(test_val);
391 check_equal(&val, returned_obj.get(), "any_cast incorrectly works with type that has operator&(): addresses differ");
392
393 check_true(!!boost::any_cast<class_with_address_op<int> >(&test_val), "any_cast incorrectly works with type that has operator&()");
394 check_equal(boost::unsafe_any_cast<class_with_address_op<int> >(&test_val)->get(), ptr, "unsafe_any_cast incorrectly works with type that has operator&()");
395 }
396
397 }
398
399 // Copyright Kevlin Henney, 2000, 2001. All rights reserved.
400 // Copyright Antony Polukhin, 2013-2019.
401 //
402 // Distributed under the Boost Software License, Version 1.0. (See
403 // accompanying file LICENSE_1_0.txt or copy at
404 // http://www.boost.org/LICENSE_1_0.txt)
405 //
406