Fix crash when auto-sizing a wxDataViewCtrl column.
[wxWidgets.git] / tests / any / anytest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/any/anytest.cpp
3 // Purpose: Test the wxAny classes
4 // Author: Jaakko Salli
5 // Copyright: (c) the wxWidgets team
6 // Licence: wxWindows licence
7 ///////////////////////////////////////////////////////////////////////////////
8
9 #include "testprec.h"
10
11 #ifdef __BORLANDC__
12 # pragma hdrstop
13 #endif
14
15 #if wxUSE_ANY
16
17 #include "wx/any.h"
18 #include "wx/datetime.h"
19 #include "wx/object.h"
20 #include "wx/vector.h"
21
22 #include <math.h>
23
24 // ----------------------------------------------------------------------------
25 // test class
26 // ----------------------------------------------------------------------------
27
28 class wxAnyTestCase : public CppUnit::TestCase
29 {
30 public:
31 wxAnyTestCase();
32
33 private:
34 CPPUNIT_TEST_SUITE( wxAnyTestCase );
35 CPPUNIT_TEST( CheckType );
36 CPPUNIT_TEST( Equality );
37 CPPUNIT_TEST( As );
38 CPPUNIT_TEST( GetAs );
39 CPPUNIT_TEST( Null );
40 CPPUNIT_TEST( wxVariantConversions );
41 CPPUNIT_TEST( CustomTemplateSpecialization );
42 CPPUNIT_TEST( Misc );
43 CPPUNIT_TEST_SUITE_END();
44
45 void CheckType();
46 void Equality();
47 void As();
48 void GetAs();
49 void Null();
50 void wxVariantConversions();
51 void CustomTemplateSpecialization();
52 void Misc();
53
54 wxDateTime m_testDateTime;
55
56 wxAny m_anySignedChar1;
57 wxAny m_anySignedShort1;
58 wxAny m_anySignedInt1;
59 wxAny m_anySignedLong1;
60 wxAny m_anySignedLongLong1;
61 wxAny m_anyUnsignedChar1;
62 wxAny m_anyUnsignedShort1;
63 wxAny m_anyUnsignedInt1;
64 wxAny m_anyUnsignedLong1;
65 wxAny m_anyUnsignedLongLong1;
66 wxAny m_anyStringString1;
67 wxAny m_anyCharString1;
68 wxAny m_anyWcharString1;
69 wxAny m_anyBool1;
70 wxAny m_anyFloatDouble1;
71 wxAny m_anyDoubleDouble1;
72 wxAny m_anyWxObjectPtr1;
73 wxAny m_anyVoidPtr1;
74 wxAny m_anyDateTime1;
75 wxAny m_anyUniChar1;
76
77 wxAny m_anySignedChar2;
78 wxAny m_anySignedShort2;
79 wxAny m_anySignedInt2;
80 wxAny m_anySignedLong2;
81 wxAny m_anySignedLongLong2;
82 wxAny m_anyUnsignedChar2;
83 wxAny m_anyUnsignedShort2;
84 wxAny m_anyUnsignedInt2;
85 wxAny m_anyUnsignedLong2;
86 wxAny m_anyUnsignedLongLong2;
87 wxAny m_anyStringString2;
88 wxAny m_anyCharString2;
89 wxAny m_anyWcharString2;
90 wxAny m_anyBool2;
91 wxAny m_anyFloatDouble2;
92 wxAny m_anyDoubleDouble2;
93 wxAny m_anyWxObjectPtr2;
94 wxAny m_anyVoidPtr2;
95 wxAny m_anyDateTime2;
96
97 DECLARE_NO_COPY_CLASS(wxAnyTestCase)
98 };
99
100 // register in the unnamed registry so that these tests are run by default
101 CPPUNIT_TEST_SUITE_REGISTRATION( wxAnyTestCase );
102
103 // also include in its own registry so that these tests can be run alone
104 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( wxAnyTestCase, "wxAnyTestCase" );
105
106 // Let's use a number with first digit after decimal dot less than 5,
107 // so that we don't have to worry about whether conversion from float
108 // to int truncates or rounds.
109 const float TEST_FLOAT_CONST = 123.456f;
110 const double TEST_DOUBLE_CONST = 123.456;
111
112 const double FEQ_DELTA = 0.001;
113
114 wxObject* dummyWxObjectPointer = reinterpret_cast<wxObject*>(1234);
115 void* dummyVoidPointer = reinterpret_cast<void*>(1234);
116
117
118 //
119 // Test both 'creation' methods
120 wxAnyTestCase::wxAnyTestCase()
121 : m_anySignedChar1((signed char)15),
122 m_anySignedShort1((signed short)15),
123 m_anySignedInt1((signed int)15),
124 m_anySignedLong1((signed long)15),
125 #ifdef wxLongLong_t
126 m_anySignedLongLong1((wxLongLong_t)15),
127 #endif
128 m_anyUnsignedChar1((unsigned char)15),
129 m_anyUnsignedShort1((unsigned short)15),
130 m_anyUnsignedInt1((unsigned int)15),
131 m_anyUnsignedLong1((unsigned long)15),
132 #ifdef wxLongLong_t
133 m_anyUnsignedLongLong1((wxULongLong_t)15),
134 #endif
135 m_anyStringString1(wxString("abc")),
136 m_anyCharString1("abc"),
137 m_anyWcharString1(L"abc"),
138 m_anyBool1(true),
139 m_anyFloatDouble1(TEST_FLOAT_CONST),
140 m_anyDoubleDouble1(TEST_DOUBLE_CONST),
141 m_anyWxObjectPtr1(dummyWxObjectPointer),
142 m_anyVoidPtr1(dummyVoidPointer),
143 m_anyDateTime1(wxDateTime::Now())
144 {
145 m_testDateTime = wxDateTime::Now();
146 m_anySignedChar2 = (signed char)15;
147 m_anySignedShort2 = (signed short)15;
148 m_anySignedInt2 = (signed int)15;
149 m_anySignedLong2 = (signed long)15;
150 #ifdef wxLongLong_t
151 m_anySignedLongLong2 = (wxLongLong_t)15;
152 #endif
153 m_anyUnsignedChar2 = (unsigned char)15;
154 m_anyUnsignedShort2 = (unsigned short)15;
155 m_anyUnsignedInt2 = (unsigned int)15;
156 m_anyUnsignedLong2 = (unsigned long)15;
157 #ifdef wxLongLong_t
158 m_anyUnsignedLongLong2 = (wxULongLong_t)15;
159 #endif
160 m_anyStringString2 = wxString("abc");
161 m_anyCharString2 = "abc";
162 m_anyWcharString2 = L"abc";
163 m_anyBool2 = true;
164 m_anyFloatDouble2 = TEST_FLOAT_CONST;
165 m_anyDoubleDouble2 = TEST_DOUBLE_CONST;
166 m_anyDateTime2 = m_testDateTime;
167 m_anyUniChar1 = wxUniChar('A');
168 m_anyWxObjectPtr2 = dummyWxObjectPointer;
169 m_anyVoidPtr2 = dummyVoidPointer;
170 }
171
172 void wxAnyTestCase::CheckType()
173 {
174 wxAny nullAny;
175 CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(nullAny, wxString));
176
177 CPPUNIT_ASSERT(wxANY_CHECK_TYPE(m_anyCharString2, const char*));
178 CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyCharString2, wxString));
179 CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyCharString2, const wchar_t*));
180 CPPUNIT_ASSERT(wxANY_CHECK_TYPE(m_anyWcharString2, const wchar_t*));
181 CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyWcharString2, wxString));
182 CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyWcharString2, const char*));
183
184 // HasSameType()
185 CPPUNIT_ASSERT( m_anyWcharString1.HasSameType(m_anyWcharString2) );
186 CPPUNIT_ASSERT( !m_anyWcharString1.HasSameType(m_anyBool1) );
187 }
188
189 void wxAnyTestCase::Equality()
190 {
191 //
192 // Currently this should work
193 CPPUNIT_ASSERT(m_anyUnsignedLong1 == 15L);
194 CPPUNIT_ASSERT(m_anyUnsignedLong1 != 30L);
195 CPPUNIT_ASSERT(m_anyUnsignedLong1 == 15UL);
196 CPPUNIT_ASSERT(m_anyUnsignedLong1 != 30UL);
197 CPPUNIT_ASSERT(m_anyStringString1 == wxString("abc"));
198 CPPUNIT_ASSERT(m_anyStringString1 != wxString("ABC"));
199 CPPUNIT_ASSERT(m_anyStringString1 == "abc");
200 CPPUNIT_ASSERT(m_anyStringString1 != "ABC");
201 CPPUNIT_ASSERT(m_anyStringString1 == L"abc");
202 CPPUNIT_ASSERT(m_anyStringString1 != L"ABC");
203 CPPUNIT_ASSERT(m_anyBool1 == true);
204 CPPUNIT_ASSERT(m_anyBool1 != false);
205 CPPUNIT_ASSERT_DOUBLES_EQUAL(wxANY_AS(m_anyFloatDouble1, double),
206 wxANY_AS(m_anyDoubleDouble1, double),
207 FEQ_DELTA);
208 CPPUNIT_ASSERT_DOUBLES_EQUAL(wxANY_AS(m_anyFloatDouble1, double),
209 TEST_FLOAT_CONST,
210 FEQ_DELTA);
211 CPPUNIT_ASSERT(wxANY_AS(m_anyWxObjectPtr1, wxObject*)
212 == dummyWxObjectPointer);
213 CPPUNIT_ASSERT(wxANY_AS(m_anyVoidPtr1, void*) == dummyVoidPointer);
214
215 CPPUNIT_ASSERT(m_anySignedLong2 == 15);
216 CPPUNIT_ASSERT(m_anyStringString2 == wxString("abc"));
217 CPPUNIT_ASSERT(m_anyStringString2 == "abc");
218 CPPUNIT_ASSERT(m_anyStringString2 == L"abc");
219 CPPUNIT_ASSERT(m_anyBool2 == true);
220 CPPUNIT_ASSERT_DOUBLES_EQUAL(wxANY_AS(m_anyFloatDouble2, double),
221 wxANY_AS(m_anyDoubleDouble2, double),
222 FEQ_DELTA);
223 CPPUNIT_ASSERT_DOUBLES_EQUAL(wxANY_AS(m_anyFloatDouble2, double),
224 TEST_FLOAT_CONST,
225 FEQ_DELTA);
226 CPPUNIT_ASSERT(wxANY_AS(m_anyWxObjectPtr2, wxObject*)
227 == dummyWxObjectPointer);
228 CPPUNIT_ASSERT(wxANY_AS(m_anyVoidPtr2, void*) == dummyVoidPointer);
229
230 // Test sub-type system type compatibility
231 CPPUNIT_ASSERT(m_anySignedShort1.GetType()->
232 IsSameType(m_anySignedLongLong1.GetType()));
233 CPPUNIT_ASSERT(m_anyUnsignedShort1.GetType()->
234 IsSameType(m_anyUnsignedLongLong1.GetType()));
235 }
236
237 void wxAnyTestCase::As()
238 {
239 //
240 // Test getting C++ data from wxAny without dynamic conversion
241 signed char a = wxANY_AS(m_anySignedChar1, signed char);
242 CPPUNIT_ASSERT(a == (signed int)15);
243 signed short b = wxANY_AS(m_anySignedShort1, signed short);
244 CPPUNIT_ASSERT(b == (signed int)15);
245 signed int c = wxANY_AS(m_anySignedInt1, signed int);
246 CPPUNIT_ASSERT(c == (signed int)15);
247 signed long d = wxANY_AS(m_anySignedLong1, signed long);
248 CPPUNIT_ASSERT(d == (signed int)15);
249 #ifdef wxLongLong_t
250 wxLongLong_t e = wxANY_AS(m_anySignedLongLong1, wxLongLong_t);
251 CPPUNIT_ASSERT(e == (signed int)15);
252 #endif
253 unsigned char f = wxANY_AS(m_anyUnsignedChar1, unsigned char);
254 CPPUNIT_ASSERT(f == (unsigned int)15);
255 unsigned short g = wxANY_AS(m_anyUnsignedShort1, unsigned short);
256 CPPUNIT_ASSERT(g == (unsigned int)15);
257 unsigned int h = wxANY_AS(m_anyUnsignedInt1, unsigned int);
258 CPPUNIT_ASSERT(h == (unsigned int)15);
259 unsigned long i = wxANY_AS(m_anyUnsignedLong1, unsigned long);
260 CPPUNIT_ASSERT(i == (unsigned int)15);
261 #ifdef wxLongLong_t
262 wxULongLong_t j = wxANY_AS(m_anyUnsignedLongLong1, wxULongLong_t);
263 CPPUNIT_ASSERT(j == (unsigned int)15);
264 #endif
265 wxString k = wxANY_AS(m_anyStringString1, wxString);
266 CPPUNIT_ASSERT(k == "abc");
267 wxString l = wxANY_AS(m_anyCharString1, wxString);
268 const char* cptr = wxANY_AS(m_anyCharString1, const char*);
269 CPPUNIT_ASSERT(l == "abc");
270 CPPUNIT_ASSERT(cptr);
271 wxString m = wxANY_AS(m_anyWcharString1, wxString);
272 const wchar_t* wcptr = wxANY_AS(m_anyWcharString1, const wchar_t*);
273 CPPUNIT_ASSERT(wcptr);
274 CPPUNIT_ASSERT(m == "abc");
275 bool n = wxANY_AS(m_anyBool1, bool);
276 CPPUNIT_ASSERT(n);
277
278 // Make sure the stored float that comes back is -identical-.
279 // So do not use delta comparison here.
280 float o = wxANY_AS(m_anyFloatDouble1, float);
281 CPPUNIT_ASSERT_EQUAL(o, TEST_FLOAT_CONST);
282
283 double p = wxANY_AS(m_anyDoubleDouble1, double);
284 CPPUNIT_ASSERT_EQUAL(p, TEST_DOUBLE_CONST);
285
286 wxUniChar chr = wxANY_AS(m_anyUniChar1, wxUniChar);
287 CPPUNIT_ASSERT(chr == 'A');
288 wxDateTime q = wxANY_AS(m_anyDateTime1, wxDateTime);
289 CPPUNIT_ASSERT(q == m_testDateTime);
290 wxObject* r = wxANY_AS(m_anyWxObjectPtr1, wxObject*);
291 CPPUNIT_ASSERT(r == dummyWxObjectPointer);
292 void* s = wxANY_AS(m_anyVoidPtr1, void*);
293 CPPUNIT_ASSERT(s == dummyVoidPointer);
294 }
295
296 void wxAnyTestCase::Null()
297 {
298 wxAny a;
299 CPPUNIT_ASSERT(a.IsNull());
300 a = -127;
301 CPPUNIT_ASSERT(a == -127);
302 a.MakeNull();
303 CPPUNIT_ASSERT(a.IsNull());
304 }
305
306 void wxAnyTestCase::GetAs()
307 {
308 //
309 // Test dynamic conversion
310 bool res;
311 long l = 0;
312 short int si = 0;
313 unsigned long ul = 0;
314 wxString s;
315 // Let's test against float instead of double, since the former
316 // is not the native underlying type the code converts to, but
317 // should still work, all the same.
318 float f = 0.0;
319 bool b = false;
320
321 // Conversions from signed long type
322 // The first check should be enough to make sure that the sub-type system
323 // has not failed.
324 res = m_anySignedLong1.GetAs(&si);
325 CPPUNIT_ASSERT(res);
326 CPPUNIT_ASSERT_EQUAL(si, 15);
327 res = m_anySignedLong1.GetAs(&ul);
328 CPPUNIT_ASSERT(res);
329 CPPUNIT_ASSERT_EQUAL(ul, 15UL);
330 res = m_anySignedLong1.GetAs(&s);
331 CPPUNIT_ASSERT(res);
332 CPPUNIT_ASSERT(s == "15");
333 res = m_anySignedLong1.GetAs(&f);
334 CPPUNIT_ASSERT(res);
335 CPPUNIT_ASSERT_DOUBLES_EQUAL(f, 15.0, FEQ_DELTA);
336 res = m_anySignedLong1.GetAs(&b);
337 CPPUNIT_ASSERT(res);
338 CPPUNIT_ASSERT(b == true);
339
340 // Conversions from unsigned long type
341 res = m_anyUnsignedLong1.GetAs(&l);
342 CPPUNIT_ASSERT(res);
343 CPPUNIT_ASSERT(l == static_cast<signed long>(15));
344 res = m_anyUnsignedLong1.GetAs(&s);
345 CPPUNIT_ASSERT(res);
346 CPPUNIT_ASSERT(s == "15");
347 res = m_anyUnsignedLong1.GetAs(&f);
348 CPPUNIT_ASSERT(res);
349 CPPUNIT_ASSERT_DOUBLES_EQUAL(f, 15.0, FEQ_DELTA);
350 res = m_anyUnsignedLong1.GetAs(&b);
351 CPPUNIT_ASSERT(res);
352 CPPUNIT_ASSERT(b == true);
353
354 // Conversions from default "abc" string to other types
355 // should not work.
356 CPPUNIT_ASSERT(!m_anyStringString1.GetAs(&l));
357 CPPUNIT_ASSERT(!m_anyStringString1.GetAs(&ul));
358 CPPUNIT_ASSERT(!m_anyStringString1.GetAs(&f));
359 CPPUNIT_ASSERT(!m_anyStringString1.GetAs(&b));
360
361 // Let's test some other conversions from string that should work.
362 wxAny anyString;
363
364 anyString = "15";
365 res = anyString.GetAs(&l);
366 CPPUNIT_ASSERT(res);
367 CPPUNIT_ASSERT(l == static_cast<signed long>(15));
368 res = anyString.GetAs(&ul);
369 CPPUNIT_ASSERT(res);
370 CPPUNIT_ASSERT_EQUAL(ul, static_cast<unsigned long>(15));
371 res = anyString.GetAs(&f);
372 CPPUNIT_ASSERT(res);
373 CPPUNIT_ASSERT_DOUBLES_EQUAL(f, 15.0, FEQ_DELTA);
374 anyString = "TRUE";
375 res = anyString.GetAs(&b);
376 CPPUNIT_ASSERT(res);
377 CPPUNIT_ASSERT(b == true);
378 anyString = "0";
379 res = anyString.GetAs(&b);
380 CPPUNIT_ASSERT(res);
381 CPPUNIT_ASSERT(b == false);
382
383 // Conversions from bool type
384 res = m_anyBool1.GetAs(&l);
385 CPPUNIT_ASSERT(res);
386 CPPUNIT_ASSERT(l == static_cast<signed long>(1));
387 res = m_anyBool1.GetAs(&ul);
388 CPPUNIT_ASSERT(res);
389 CPPUNIT_ASSERT_EQUAL(ul, static_cast<unsigned long>(1));
390 res = m_anyBool1.GetAs(&s);
391 CPPUNIT_ASSERT(res);
392 CPPUNIT_ASSERT(s == "true");
393 CPPUNIT_ASSERT(!m_anyBool1.GetAs(&f));
394
395 // Conversions from floating point type
396 res = m_anyDoubleDouble1.GetAs(&l);
397 CPPUNIT_ASSERT(res);
398 CPPUNIT_ASSERT(l == static_cast<signed long>(123));
399 res = m_anyDoubleDouble1.GetAs(&ul);
400 CPPUNIT_ASSERT(res);
401 CPPUNIT_ASSERT_EQUAL(ul, static_cast<unsigned long>(123));
402 res = m_anyDoubleDouble1.GetAs(&s);
403 CPPUNIT_ASSERT(res);
404 double d2;
405 res = s.ToCDouble(&d2);
406 CPPUNIT_ASSERT(res);
407 CPPUNIT_ASSERT_DOUBLES_EQUAL(d2, TEST_FLOAT_CONST, FEQ_DELTA);
408 }
409
410
411 //
412 // Test user data type for wxAnyValueTypeImpl specialization
413 // any hand-built wxVariantData. Also for inplace allocation
414 // sanity checks.
415 //
416
417 class MyClass;
418
419 static wxVector<MyClass*> gs_myClassInstances;
420
421 class MyClass
422 {
423 public:
424 MyClass( int someValue = 32768 )
425 {
426 Init();
427 m_someValue = someValue;
428 }
429 MyClass( const MyClass& other )
430 {
431 Init();
432 m_someValue = other.m_someValue;
433 }
434 virtual ~MyClass()
435 {
436 for ( size_t i=0; i<gs_myClassInstances.size(); i++ )
437 {
438 if ( gs_myClassInstances[i] == this )
439 {
440 gs_myClassInstances.erase(gs_myClassInstances.begin()+i);
441 }
442 }
443 }
444
445 int GetValue() const
446 {
447 return m_someValue;
448 }
449
450 wxString ToString()
451 {
452 return wxString::Format("%i", m_someValue);
453 }
454
455 private:
456 void Init()
457 {
458 // We use this for some sanity checking
459 gs_myClassInstances.push_back(this);
460 }
461
462 int m_someValue;
463 };
464
465
466 #if wxUSE_VARIANT
467
468 // For testing purposes, create dummy variant data implementation
469 // that does not have wxAny conversion code
470 class wxMyVariantData : public wxVariantData
471 {
472 public:
473 wxMyVariantData(const MyClass& value)
474 {
475 m_value = value;
476 }
477
478 virtual bool Eq(wxVariantData& WXUNUSED(data)) const
479 {
480 return false;
481 }
482
483 // What type is it? Return a string name.
484 virtual wxString GetType() const { return "MyClass"; }
485
486 virtual wxVariantData* Clone() const
487 {
488 return new wxMyVariantData(m_value);
489 }
490
491 protected:
492 MyClass m_value;
493 };
494
495 #endif // wxUSE_VARIANT
496
497
498 void wxAnyTestCase::wxVariantConversions()
499 {
500 #if wxUSE_VARIANT
501 //
502 // Test various conversions to and from wxVariant
503 //
504 bool res;
505
506 // Prepare wxVariants
507 wxVariant vLong(123L);
508 wxVariant vString("ABC");
509 wxVariant vDouble(TEST_FLOAT_CONST);
510 wxVariant vBool((bool)true);
511 wxVariant vChar('A');
512 #ifdef wxLongLong_t
513 wxVariant vLongLong(wxLongLong(wxLL(0xAABBBBCCCC)));
514 wxVariant vULongLong(wxULongLong(wxULL(123456)));
515 #endif
516 wxArrayString arrstr;
517 arrstr.push_back("test string");
518 wxVariant vArrayString(arrstr);
519 wxVariant vDateTime(m_testDateTime);
520 wxVariant vVoidPtr(dummyVoidPointer);
521 wxVariant vCustomType(new wxMyVariantData(MyClass(101)));
522 wxVariant vList;
523
524 vList.NullList();
525 vList.Append(15);
526 vList.Append("abc");
527
528 // Convert to wxAnys, and then back to wxVariants
529 wxVariant variant;
530
531 wxAny any(vLong);
532 CPPUNIT_ASSERT(any == 123L);
533 res = any.GetAs(&variant);
534 CPPUNIT_ASSERT(res);
535 CPPUNIT_ASSERT(variant == 123L);
536
537 // Make sure integer variant has correct type information
538 CPPUNIT_ASSERT(variant.GetLong() == 123);
539 CPPUNIT_ASSERT(variant.GetType() == "long");
540
541 // Unsigned long wxAny should convert to "ulonglong" wxVariant
542 any = 1000UL;
543 res = any.GetAs(&variant);
544 CPPUNIT_ASSERT(res);
545 CPPUNIT_ASSERT(variant.GetType() == "ulonglong");
546 CPPUNIT_ASSERT(variant.GetLong() == 1000);
547
548 any = vString;
549 CPPUNIT_ASSERT(any == "ABC");
550 res = any.GetAs(&variant);
551 CPPUNIT_ASSERT(res);
552 CPPUNIT_ASSERT(variant.GetString() == "ABC");
553
554 // Must be able to build string wxVariant from wxAny built from
555 // string literal
556 any = "ABC";
557 res = any.GetAs(&variant);
558 CPPUNIT_ASSERT(res);
559 CPPUNIT_ASSERT(variant.GetType() == "string");
560 CPPUNIT_ASSERT(variant.GetString() == "ABC");
561 any = L"ABC";
562 res = any.GetAs(&variant);
563 CPPUNIT_ASSERT(res);
564 CPPUNIT_ASSERT(variant.GetType() == "string");
565 #if wxUSE_UNICODE
566 CPPUNIT_ASSERT(variant.GetString() == L"ABC");
567 #endif
568
569 any = vDouble;
570 double d = wxANY_AS(any, double);
571 CPPUNIT_ASSERT_DOUBLES_EQUAL(d, TEST_FLOAT_CONST, FEQ_DELTA);
572 res = any.GetAs(&variant);
573 CPPUNIT_ASSERT(res);
574 CPPUNIT_ASSERT_DOUBLES_EQUAL(variant.GetDouble(),
575 TEST_FLOAT_CONST,
576 FEQ_DELTA);
577
578 any = vBool;
579 CPPUNIT_ASSERT(wxANY_AS(any, bool) == true);
580 res = any.GetAs(&variant);
581 CPPUNIT_ASSERT(res);
582 CPPUNIT_ASSERT(variant.GetBool() == true);
583
584 any = wxAny(vChar);
585 //CPPUNIT_ASSERT(wxANY_AS(any, wxUniChar) == 'A');
586 res = any.GetAs(&variant);
587 CPPUNIT_ASSERT(res);
588 CPPUNIT_ASSERT(variant.GetChar() == 'A');
589
590 #ifdef wxLongLong_t
591 any = wxAny(vLongLong);
592 CPPUNIT_ASSERT(any == wxLL(0xAABBBBCCCC));
593 res = any.GetAs(&variant);
594 CPPUNIT_ASSERT(res);
595 CPPUNIT_ASSERT(variant.GetType() == "longlong");
596 CPPUNIT_ASSERT(variant.GetLongLong() == wxLongLong(wxLL(0xAABBBBCCCC)));
597
598 #if LONG_MAX == wxINT64_MAX
599 // As a sanity check, test that wxVariant of type 'long' converts
600 // seamlessly to 'longlong' (on some 64-bit systems)
601 any = 0xAABBBBCCCCL;
602 res = any.GetAs(&variant);
603 CPPUNIT_ASSERT(variant.GetLongLong() == wxLongLong(wxLL(0xAABBBBCCCC)));
604 #endif
605
606 any = wxAny(vULongLong);
607 CPPUNIT_ASSERT(any == wxLL(123456));
608 res = any.GetAs(&variant);
609 CPPUNIT_ASSERT(res);
610 CPPUNIT_ASSERT(variant.GetType() == "ulonglong");
611 CPPUNIT_ASSERT(variant.GetULongLong() == wxULongLong(wxULL(123456)));
612 #endif
613
614 // Cannot test equality for the rest, just test that they convert
615 // back correctly.
616 any = wxAny(vArrayString);
617 res = any.GetAs(&variant);
618 CPPUNIT_ASSERT(res);
619 wxArrayString arrstr2 = variant.GetArrayString();
620 CPPUNIT_ASSERT(arrstr2 == arrstr);
621
622 any = m_testDateTime;
623 CPPUNIT_ASSERT(wxANY_AS(any, wxDateTime) == m_testDateTime);
624 any = wxAny(vDateTime);
625 CPPUNIT_ASSERT(wxANY_AS(any, wxDateTime) == m_testDateTime);
626 res = any.GetAs(&variant);
627 CPPUNIT_ASSERT(res);
628 CPPUNIT_ASSERT(variant == m_testDateTime);
629
630 any = wxAny(vVoidPtr);
631 res = any.GetAs(&variant);
632 CPPUNIT_ASSERT(res);
633 CPPUNIT_ASSERT(variant.GetVoidPtr() == dummyVoidPointer);
634
635 any = wxAny(vList);
636 CPPUNIT_ASSERT(wxANY_CHECK_TYPE(any, wxAnyList));
637 wxAnyList anyList = wxANY_AS(any, wxAnyList);
638 CPPUNIT_ASSERT(anyList.GetCount() == 2);
639 CPPUNIT_ASSERT(wxANY_AS((*anyList[0]), int) == 15);
640 CPPUNIT_ASSERT(wxANY_AS((*anyList[1]), wxString) == "abc");
641 res = any.GetAs(&variant);
642 CPPUNIT_ASSERT(res);
643 CPPUNIT_ASSERT(variant.GetType() == "list");
644 CPPUNIT_ASSERT(variant.GetCount() == 2);
645 CPPUNIT_ASSERT(variant[0].GetLong() == 15);
646 CPPUNIT_ASSERT(variant[1].GetString() == "abc");
647
648 any = wxAny(vCustomType);
649 CPPUNIT_ASSERT(wxANY_CHECK_TYPE(any, wxVariantData*));
650 res = any.GetAs(&variant);
651 CPPUNIT_ASSERT(res);
652 CPPUNIT_ASSERT(variant.GetType() == "MyClass");
653
654 #endif // wxUSE_VARIANT
655 }
656
657 template<>
658 class wxAnyValueTypeImpl<MyClass> :
659 public wxAnyValueTypeImplBase<MyClass>
660 {
661 WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl<MyClass>)
662 public:
663 wxAnyValueTypeImpl() :
664 wxAnyValueTypeImplBase<MyClass>() { }
665 virtual ~wxAnyValueTypeImpl() { }
666
667 virtual bool ConvertValue(const wxAnyValueBuffer& src,
668 wxAnyValueType* dstType,
669 wxAnyValueBuffer& dst) const
670 {
671 MyClass value = GetValue(src);
672
673 if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType, wxString) )
674 {
675 wxString s = value.ToString();
676 wxAnyValueTypeImpl<wxString>::SetValue(s, dst);
677 }
678 else
679 return false;
680
681 return true;
682 }
683 };
684
685 //
686 // Following must be placed somewhere in your source code
687 WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl<MyClass>)
688
689 void wxAnyTestCase::CustomTemplateSpecialization()
690 {
691 // Do only a minimal CheckType() test, as dynamic type conversion already
692 // uses it a lot.
693 bool res;
694 MyClass myObject;
695 wxAny any = myObject;
696
697 CPPUNIT_ASSERT( wxANY_CHECK_TYPE(any, MyClass) );
698 MyClass myObject2 = wxANY_AS(any, MyClass);
699 wxUnusedVar(myObject2);
700
701 wxString str;
702 res = any.GetAs(&str);
703 CPPUNIT_ASSERT(res);
704 CPPUNIT_ASSERT_EQUAL(str, myObject.ToString());
705 }
706
707 void wxAnyTestCase::Misc()
708 {
709 // Do some (inplace) allocation sanity checks
710 {
711
712 // Do it inside a scope so we can easily test instance count
713 // afterwards
714 MyClass myObject(15);
715 wxAny any = myObject;
716
717 // There must be two instances - first in myObject,
718 // and second copied in any.
719 CPPUNIT_ASSERT_EQUAL(gs_myClassInstances.size(), 2);
720
721 // Check that it is allocated in-place, as supposed
722 if ( sizeof(MyClass) <= WX_ANY_VALUE_BUFFER_SIZE )
723 {
724 // Memory block of the instance second must be inside the any
725 size_t anyBegin = reinterpret_cast<size_t>(&any);
726 size_t anyEnd = anyBegin + sizeof(wxAny);
727 size_t pos = reinterpret_cast<size_t>(gs_myClassInstances[1]);
728 CPPUNIT_ASSERT( pos >= anyBegin );
729 CPPUNIT_ASSERT( pos < anyEnd );
730 }
731
732 wxAny any2 = any;
733 CPPUNIT_ASSERT( wxANY_AS(any2, MyClass).GetValue() == 15 );
734 }
735
736 // Make sure allocations and deallocations match
737 CPPUNIT_ASSERT_EQUAL(gs_myClassInstances.size(), 0);
738 }
739
740 #endif // wxUSE_ANY
741