• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>(&copy),
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>(&copy),
155             "comparing address in copy against original");
156         check_equal(assign_result, &copy, "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