]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | ||
b32b8144 | 11 | #include <boost/any.hpp> |
7c673cae FG |
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 | ||
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(); | |
b32b8144 | 44 | void test_addressof(); |
7c673cae FG |
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 }, | |
b32b8144 FG |
60 | { "testing with vectors", test_vectors }, |
61 | { "class with operator&()", test_addressof } | |
7c673cae FG |
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 | ||
75 | copy_counter() {} | |
76 | copy_counter(const copy_counter&) { ++count; } | |
77 | copy_counter& operator=(const copy_counter&) { ++count; return *this; } | |
78 | 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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
279 | const std::string& returning_string1() | |
280 | { | |
281 | static const std::string ret("foo"); | |
282 | return ret; | |
283 | } | |
284 | ||
285 | std::string returning_string2() | |
286 | { | |
287 | static const std::string ret("foo"); | |
288 | return ret; | |
289 | } | |
290 | ||
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 | ||
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 | |
345 | boost::any makeVec() | |
346 | { | |
347 | return std::vector<int>(100 /*size*/, 7 /*value*/); | |
348 | } | |
349 | ||
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 | ||
b32b8144 FG |
362 | } |
363 | ||
364 | template<typename T> | |
365 | class class_with_address_op { | |
366 | public: | |
367 | class_with_address_op(const T* p) | |
368 | : ptr(p) | |
369 | {} | |
370 | ||
f67539c2 | 371 | const T** operator &() { |
b32b8144 FG |
372 | return &ptr; |
373 | } | |
374 | ||
375 | const T* get() const { | |
376 | return ptr; | |
377 | } | |
378 | ||
379 | private: | |
380 | const T* ptr; | |
381 | }; | |
382 | ||
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 | } | |
7c673cae FG |
396 | |
397 | } | |
398 | ||
399 | // Copyright Kevlin Henney, 2000, 2001. All rights reserved. | |
92f5a8d4 | 400 | // Copyright Antony Polukhin, 2013-2019. |
7c673cae FG |
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 | // |