1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/any/anytest.cpp
3 // Purpose: Test the wxAny classes
4 // Author: Jaakko Salli
6 // Copyright: (c) the wxWidgets team
7 // Licence: wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
19 #include "wx/datetime.h"
20 #include "wx/object.h"
24 // ----------------------------------------------------------------------------
26 // ----------------------------------------------------------------------------
28 class wxAnyTestCase
: public CppUnit::TestCase
34 CPPUNIT_TEST_SUITE( wxAnyTestCase
);
35 CPPUNIT_TEST( Equality
);
37 CPPUNIT_TEST( GetAs
);
39 CPPUNIT_TEST( wxVariantConversions
);
40 CPPUNIT_TEST( CustomTemplateSpecialization
);
41 CPPUNIT_TEST_SUITE_END();
47 void wxVariantConversions();
48 void CustomTemplateSpecialization();
50 wxDateTime m_testDateTime
;
52 wxAny m_anySignedChar1
;
53 wxAny m_anySignedShort1
;
54 wxAny m_anySignedInt1
;
55 wxAny m_anySignedLong1
;
56 wxAny m_anySignedLongLong1
;
57 wxAny m_anyUnsignedChar1
;
58 wxAny m_anyUnsignedShort1
;
59 wxAny m_anyUnsignedInt1
;
60 wxAny m_anyUnsignedLong1
;
61 wxAny m_anyUnsignedLongLong1
;
62 wxAny m_anyStringString1
;
63 wxAny m_anyCharString1
;
64 wxAny m_anyWcharString1
;
66 wxAny m_anyFloatDouble1
;
67 wxAny m_anyDoubleDouble1
;
68 wxAny m_anyWxObjectPtr1
;
73 wxAny m_anySignedChar2
;
74 wxAny m_anySignedShort2
;
75 wxAny m_anySignedInt2
;
76 wxAny m_anySignedLong2
;
77 wxAny m_anySignedLongLong2
;
78 wxAny m_anyUnsignedChar2
;
79 wxAny m_anyUnsignedShort2
;
80 wxAny m_anyUnsignedInt2
;
81 wxAny m_anyUnsignedLong2
;
82 wxAny m_anyUnsignedLongLong2
;
83 wxAny m_anyStringString2
;
84 wxAny m_anyCharString2
;
85 wxAny m_anyWcharString2
;
87 wxAny m_anyFloatDouble2
;
88 wxAny m_anyDoubleDouble2
;
89 wxAny m_anyWxObjectPtr2
;
93 DECLARE_NO_COPY_CLASS(wxAnyTestCase
)
96 // register in the unnamed registry so that these tests are run by default
97 CPPUNIT_TEST_SUITE_REGISTRATION( wxAnyTestCase
);
99 // also include in it's own registry so that these tests can be run alone
100 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( wxAnyTestCase
, "wxAnyTestCase" );
102 // Let's use a number with first digit after decimal dot less than 5,
103 // so that we don't have to worry about whether conversion from float
104 // to int truncates or rounds.
105 const double TEST_FLOAT_CONST
= 123.456;
107 const double FEQ_DELTA
= 0.001;
109 wxObject
* dummyWxObjectPointer
= reinterpret_cast<wxObject
*>(1234);
110 void* dummyVoidPointer
= reinterpret_cast<void*>(1234);
114 // Test both 'creation' methods
115 wxAnyTestCase::wxAnyTestCase()
116 : m_anySignedChar1((signed char)15),
117 m_anySignedShort1((signed short)15),
118 m_anySignedInt1((signed int)15),
119 m_anySignedLong1((signed long)15),
121 m_anySignedLongLong1((wxLongLong_t
)15),
123 m_anyUnsignedChar1((unsigned char)15),
124 m_anyUnsignedShort1((unsigned short)15),
125 m_anyUnsignedInt1((unsigned int)15),
126 m_anyUnsignedLong1((unsigned long)15),
128 m_anyUnsignedLongLong1((wxULongLong_t
)15),
130 m_anyStringString1(wxString("abc")),
131 m_anyCharString1("abc"),
132 m_anyWcharString1(L
"abc"),
134 m_anyFloatDouble1((float)TEST_FLOAT_CONST
),
135 m_anyDoubleDouble1((double)TEST_FLOAT_CONST
),
136 m_anyWxObjectPtr1(dummyWxObjectPointer
),
137 m_anyVoidPtr1(dummyVoidPointer
),
138 m_anyDateTime1(wxDateTime::Now())
140 m_testDateTime
= wxDateTime::Now();
141 m_anySignedChar2
= (signed char)15;
142 m_anySignedShort2
= (signed short)15;
143 m_anySignedInt2
= (signed int)15;
144 m_anySignedLong2
= (signed long)15;
146 m_anySignedLongLong2
= (wxLongLong_t
)15;
148 m_anyUnsignedChar2
= (unsigned char)15;
149 m_anyUnsignedShort2
= (unsigned short)15;
150 m_anyUnsignedInt2
= (unsigned int)15;
151 m_anyUnsignedLong2
= (unsigned long)15;
153 m_anyUnsignedLongLong2
= (wxULongLong_t
)15;
155 m_anyStringString2
= wxString("abc");
156 m_anyCharString2
= "abc";
157 m_anyWcharString2
= L
"abc";
159 m_anyFloatDouble2
= (float)TEST_FLOAT_CONST
;
160 m_anyDoubleDouble2
= (double)TEST_FLOAT_CONST
;
161 m_anyDateTime2
= m_testDateTime
;
162 m_anyUniChar1
= wxUniChar('A');
163 m_anyWxObjectPtr2
= dummyWxObjectPointer
;
164 m_anyVoidPtr2
= dummyVoidPointer
;
167 void wxAnyTestCase::Equality()
170 // Currently this should work
171 CPPUNIT_ASSERT(m_anyUnsignedLong1
== 15L);
172 CPPUNIT_ASSERT(m_anyUnsignedLong1
!= 30L);
173 CPPUNIT_ASSERT(m_anyUnsignedLong1
== 15UL);
174 CPPUNIT_ASSERT(m_anyUnsignedLong1
!= 30UL);
175 CPPUNIT_ASSERT(m_anyStringString1
== wxString("abc"));
176 CPPUNIT_ASSERT(m_anyStringString1
!= wxString("ABC"));
177 CPPUNIT_ASSERT(m_anyStringString1
== "abc");
178 CPPUNIT_ASSERT(m_anyStringString1
!= "ABC");
179 CPPUNIT_ASSERT(m_anyStringString1
== L
"abc");
180 CPPUNIT_ASSERT(m_anyStringString1
!= L
"ABC");
181 CPPUNIT_ASSERT(m_anyBool1
== true);
182 CPPUNIT_ASSERT(m_anyBool1
!= false);
183 CPPUNIT_ASSERT_DOUBLES_EQUAL(wxANY_AS(m_anyFloatDouble1
, double),
184 wxANY_AS(m_anyDoubleDouble1
, double),
186 CPPUNIT_ASSERT_DOUBLES_EQUAL(wxANY_AS(m_anyFloatDouble1
, double),
189 CPPUNIT_ASSERT(wxANY_AS(m_anyWxObjectPtr1
, wxObject
*)
190 == dummyWxObjectPointer
);
191 CPPUNIT_ASSERT(wxANY_AS(m_anyVoidPtr1
, void*) == dummyVoidPointer
);
193 CPPUNIT_ASSERT(m_anySignedLong2
== 15);
194 CPPUNIT_ASSERT(m_anyStringString2
== wxString("abc"));
195 CPPUNIT_ASSERT(m_anyStringString2
== "abc");
196 CPPUNIT_ASSERT(m_anyStringString2
== L
"abc");
197 CPPUNIT_ASSERT(m_anyBool2
== true);
198 CPPUNIT_ASSERT_DOUBLES_EQUAL(wxANY_AS(m_anyFloatDouble2
, double),
199 wxANY_AS(m_anyDoubleDouble2
, double),
201 CPPUNIT_ASSERT_DOUBLES_EQUAL(wxANY_AS(m_anyFloatDouble2
, double),
204 CPPUNIT_ASSERT(wxANY_AS(m_anyWxObjectPtr2
, wxObject
*)
205 == dummyWxObjectPointer
);
206 CPPUNIT_ASSERT(wxANY_AS(m_anyVoidPtr2
, void*) == dummyVoidPointer
);
208 // Test sub-type system type compatibility
209 CPPUNIT_ASSERT(m_anySignedShort1
.GetType()->
210 IsSameType(m_anySignedLongLong1
.GetType()));
211 CPPUNIT_ASSERT(m_anyUnsignedShort1
.GetType()->
212 IsSameType(m_anyUnsignedLongLong1
.GetType()));
215 void wxAnyTestCase::As()
218 // Test getting C++ data from wxAny without dynamic conversion
219 signed char a
= wxANY_AS(m_anySignedChar1
, signed char);
220 CPPUNIT_ASSERT(a
== (signed int)15);
221 signed short b
= wxANY_AS(m_anySignedShort1
, signed short);
222 CPPUNIT_ASSERT(b
== (signed int)15);
223 signed int c
= wxANY_AS(m_anySignedInt1
, signed int);
224 CPPUNIT_ASSERT(c
== (signed int)15);
225 signed long d
= wxANY_AS(m_anySignedLong1
, signed long);
226 CPPUNIT_ASSERT(d
== (signed int)15);
228 wxLongLong_t e
= wxANY_AS(m_anySignedLongLong1
, wxLongLong_t
);
229 CPPUNIT_ASSERT(e
== (signed int)15);
231 unsigned char f
= wxANY_AS(m_anyUnsignedChar1
, unsigned char);
232 CPPUNIT_ASSERT(f
== (unsigned int)15);
233 unsigned short g
= wxANY_AS(m_anyUnsignedShort1
, unsigned short);
234 CPPUNIT_ASSERT(g
== (unsigned int)15);
235 unsigned int h
= wxANY_AS(m_anyUnsignedInt1
, unsigned int);
236 CPPUNIT_ASSERT(h
== (unsigned int)15);
237 unsigned long i
= wxANY_AS(m_anyUnsignedLong1
, unsigned long);
238 CPPUNIT_ASSERT(i
== (unsigned int)15);
240 wxULongLong_t j
= wxANY_AS(m_anyUnsignedLongLong1
, wxULongLong_t
);
241 CPPUNIT_ASSERT(j
== (unsigned int)15);
243 wxString k
= wxANY_AS(m_anyStringString1
, wxString
);
244 CPPUNIT_ASSERT(k
== "abc");
245 wxString l
= wxANY_AS(m_anyCharString1
, wxString
);
246 CPPUNIT_ASSERT(l
== "abc");
247 wxString m
= wxANY_AS(m_anyWcharString1
, wxString
);
248 CPPUNIT_ASSERT(m
== "abc");
249 bool n
= wxANY_AS(m_anyBool1
, bool);
251 float o
= wxANY_AS(m_anyFloatDouble1
, float);
252 CPPUNIT_ASSERT_DOUBLES_EQUAL(o
, TEST_FLOAT_CONST
, FEQ_DELTA
);
253 double p
= wxANY_AS(m_anyDoubleDouble1
, double);
254 CPPUNIT_ASSERT_DOUBLES_EQUAL(p
, TEST_FLOAT_CONST
, FEQ_DELTA
);
255 wxUniChar chr
= wxANY_AS(m_anyUniChar1
, wxUniChar
);
256 CPPUNIT_ASSERT(chr
== 'A');
257 wxDateTime q
= wxANY_AS(m_anyDateTime1
, wxDateTime
);
258 CPPUNIT_ASSERT(q
== m_testDateTime
);
259 wxObject
* r
= wxANY_AS(m_anyWxObjectPtr1
, wxObject
*);
260 CPPUNIT_ASSERT(r
== dummyWxObjectPointer
);
261 void* s
= wxANY_AS(m_anyVoidPtr1
, void*);
262 CPPUNIT_ASSERT(s
== dummyVoidPointer
);
265 void wxAnyTestCase::Null()
268 CPPUNIT_ASSERT(a
.IsNull());
270 CPPUNIT_ASSERT(a
== -127);
272 CPPUNIT_ASSERT(a
.IsNull());
275 void wxAnyTestCase::GetAs()
278 // Test dynamic conversion
282 unsigned long ul
= 0;
284 // Let's test against float instead of double, since the former
285 // is not the native underlying type the code converts to, but
286 // should still work, all the same.
290 // Conversions from signed long type
291 // The first check should be enough to make sure that the sub-type system
293 res
= m_anySignedLong1
.GetAs(&si
);
295 CPPUNIT_ASSERT_EQUAL(si
, 15);
296 res
= m_anySignedLong1
.GetAs(&ul
);
298 CPPUNIT_ASSERT_EQUAL(ul
, 15UL);
299 res
= m_anySignedLong1
.GetAs(&s
);
301 CPPUNIT_ASSERT(s
== "15");
302 res
= m_anySignedLong1
.GetAs(&f
);
304 CPPUNIT_ASSERT_DOUBLES_EQUAL(f
, 15.0, FEQ_DELTA
);
305 res
= m_anySignedLong1
.GetAs(&b
);
307 CPPUNIT_ASSERT(b
== true);
309 // Conversions from unsigned long type
310 res
= m_anyUnsignedLong1
.GetAs(&l
);
312 CPPUNIT_ASSERT(l
== static_cast<signed long>(15));
313 res
= m_anyUnsignedLong1
.GetAs(&s
);
315 CPPUNIT_ASSERT(s
== "15");
316 res
= m_anyUnsignedLong1
.GetAs(&f
);
318 CPPUNIT_ASSERT_DOUBLES_EQUAL(f
, 15.0, FEQ_DELTA
);
319 res
= m_anyUnsignedLong1
.GetAs(&b
);
321 CPPUNIT_ASSERT(b
== true);
323 // Conversions from default "abc" string to other types
325 CPPUNIT_ASSERT(!m_anyStringString1
.GetAs(&l
));
326 CPPUNIT_ASSERT(!m_anyStringString1
.GetAs(&ul
));
327 CPPUNIT_ASSERT(!m_anyStringString1
.GetAs(&f
));
328 CPPUNIT_ASSERT(!m_anyStringString1
.GetAs(&b
));
330 // Let's test some other conversions from string that should work.
334 res
= anyString
.GetAs(&l
);
336 CPPUNIT_ASSERT(l
== static_cast<signed long>(15));
337 res
= anyString
.GetAs(&ul
);
339 CPPUNIT_ASSERT_EQUAL(ul
, static_cast<unsigned long>(15));
340 res
= anyString
.GetAs(&f
);
342 CPPUNIT_ASSERT_DOUBLES_EQUAL(f
, 15.0, FEQ_DELTA
);
344 res
= anyString
.GetAs(&b
);
346 CPPUNIT_ASSERT(b
== true);
348 res
= anyString
.GetAs(&b
);
350 CPPUNIT_ASSERT(b
== false);
352 // Conversions from bool type
353 res
= m_anyBool1
.GetAs(&l
);
355 CPPUNIT_ASSERT(l
== static_cast<signed long>(1));
356 res
= m_anyBool1
.GetAs(&ul
);
358 CPPUNIT_ASSERT_EQUAL(ul
, static_cast<unsigned long>(1));
359 res
= m_anyBool1
.GetAs(&s
);
361 CPPUNIT_ASSERT(s
== "true");
362 CPPUNIT_ASSERT(!m_anyBool1
.GetAs(&f
));
364 // Conversions from floating point type
365 res
= m_anyDoubleDouble1
.GetAs(&l
);
367 CPPUNIT_ASSERT(l
== static_cast<signed long>(123));
368 res
= m_anyDoubleDouble1
.GetAs(&ul
);
370 CPPUNIT_ASSERT_EQUAL(ul
, static_cast<unsigned long>(123));
371 res
= m_anyDoubleDouble1
.GetAs(&s
);
374 res
= s
.ToDouble(&d2
);
376 CPPUNIT_ASSERT_DOUBLES_EQUAL(d2
, TEST_FLOAT_CONST
, FEQ_DELTA
);
381 // Test user data type for wxAnyValueTypeImpl specialization
382 // any hand-built wxVariantData
388 MyClass( int someValue
= 32768 )
390 m_someValue
= someValue
;
395 return wxString::Format("%i", m_someValue
);
405 // For testing purposes, create dummy variant data implementation
406 // that does not have wxAny conversion code
407 class wxMyVariantData
: public wxVariantData
410 wxMyVariantData(const MyClass
& value
)
415 virtual bool Eq(wxVariantData
& WXUNUSED(data
)) const
420 // What type is it? Return a string name.
421 virtual wxString
GetType() const { return "MyClass"; }
423 virtual wxVariantData
* Clone() const
425 return new wxMyVariantData(m_value
);
432 #endif // wxUSE_VARIANT
435 void wxAnyTestCase::wxVariantConversions()
439 // Test various conversions to and from wxVariant
443 // Prepare wxVariants
444 wxVariant
vLong(123L);
445 wxVariant
vString("ABC");
446 wxVariant
vDouble(TEST_FLOAT_CONST
);
447 wxVariant
vBool((bool)true);
448 wxVariant
vChar('A');
450 wxVariant
vLongLong(wxLongLong(wxLL(0xAABBBBCCCC)));
451 wxVariant
vULongLong(wxULongLong(wxULL(123456)));
453 wxArrayString arrstr
;
454 arrstr
.push_back("test string");
455 wxVariant
vArrayString(arrstr
);
456 wxVariant
vDateTime(m_testDateTime
);
457 wxVariant
vVoidPtr(dummyVoidPointer
);
458 wxVariant
vCustomType(new wxMyVariantData(MyClass(101)));
465 // Convert to wxAnys, and then back to wxVariants
469 CPPUNIT_ASSERT(any
== 123L);
470 res
= any
.GetAs(&variant
);
472 CPPUNIT_ASSERT(variant
== 123L);
474 // Make sure integer variant has correct type information
475 CPPUNIT_ASSERT(variant
.GetLong() == 123);
476 CPPUNIT_ASSERT(variant
.GetType() == "long");
478 // Unsigned long wxAny should convert to "ulonglong" wxVariant
480 res
= any
.GetAs(&variant
);
482 CPPUNIT_ASSERT(variant
.GetType() == "ulonglong");
483 CPPUNIT_ASSERT(variant
.GetLong() == 1000);
486 CPPUNIT_ASSERT(any
== "ABC");
487 res
= any
.GetAs(&variant
);
489 CPPUNIT_ASSERT(variant
.GetString() == "ABC");
492 double d
= wxANY_AS(any
, double);
493 CPPUNIT_ASSERT_DOUBLES_EQUAL(d
, TEST_FLOAT_CONST
, FEQ_DELTA
);
494 res
= any
.GetAs(&variant
);
496 CPPUNIT_ASSERT_DOUBLES_EQUAL(variant
.GetDouble(),
501 CPPUNIT_ASSERT(wxANY_AS(any
, bool) == true);
502 res
= any
.GetAs(&variant
);
504 CPPUNIT_ASSERT(variant
.GetBool() == true);
507 //CPPUNIT_ASSERT(wxANY_AS(any, wxUniChar) == 'A');
508 res
= any
.GetAs(&variant
);
510 CPPUNIT_ASSERT(variant
.GetChar() == 'A');
513 any
= wxAny(vLongLong
);
514 CPPUNIT_ASSERT(any
== wxLL(0xAABBBBCCCC));
515 res
= any
.GetAs(&variant
);
517 CPPUNIT_ASSERT(variant
.GetType() == "longlong");
518 CPPUNIT_ASSERT(variant
.GetLongLong() == wxLongLong(wxLL(0xAABBBBCCCC)));
520 #if LONG_MAX == wxINT64_MAX
521 // As a sanity check, test that wxVariant of type 'long' converts
522 // seamlessly to 'longlong' (on some 64-bit systems)
524 res
= any
.GetAs(&variant
);
525 CPPUNIT_ASSERT(variant
.GetLongLong() == wxLongLong(wxLL(0xAABBBBCCCC)));
528 any
= wxAny(vULongLong
);
529 CPPUNIT_ASSERT(any
== wxLL(123456));
530 res
= any
.GetAs(&variant
);
532 CPPUNIT_ASSERT(variant
.GetType() == "ulonglong");
533 CPPUNIT_ASSERT(variant
.GetULongLong() == wxULongLong(wxULL(123456)));
536 // Cannot test equality for the rest, just test that they convert
538 any
= wxAny(vArrayString
);
539 res
= any
.GetAs(&variant
);
541 wxArrayString arrstr2
= variant
.GetArrayString();
542 CPPUNIT_ASSERT(arrstr2
== arrstr
);
544 any
= m_testDateTime
;
545 CPPUNIT_ASSERT(wxANY_AS(any
, wxDateTime
) == m_testDateTime
);
546 any
= wxAny(vDateTime
);
547 CPPUNIT_ASSERT(wxANY_AS(any
, wxDateTime
) == m_testDateTime
);
548 res
= any
.GetAs(&variant
);
550 CPPUNIT_ASSERT(variant
== m_testDateTime
);
552 any
= wxAny(vVoidPtr
);
553 res
= any
.GetAs(&variant
);
555 CPPUNIT_ASSERT(variant
.GetVoidPtr() == dummyVoidPointer
);
558 CPPUNIT_ASSERT(wxANY_CHECK_TYPE(any
, wxAnyList
));
559 wxAnyList anyList
= wxANY_AS(any
, wxAnyList
);
560 CPPUNIT_ASSERT(anyList
.GetCount() == 2);
561 CPPUNIT_ASSERT(wxANY_AS((*anyList
[0]), int) == 15);
562 CPPUNIT_ASSERT(wxANY_AS((*anyList
[1]), wxString
) == "abc");
563 res
= any
.GetAs(&variant
);
565 CPPUNIT_ASSERT(variant
.GetType() == "list");
566 CPPUNIT_ASSERT(variant
.GetCount() == 2);
567 CPPUNIT_ASSERT(variant
[0].GetLong() == 15);
568 CPPUNIT_ASSERT(variant
[1].GetString() == "abc");
570 any
= wxAny(vCustomType
);
571 CPPUNIT_ASSERT(wxANY_CHECK_TYPE(any
, wxVariantData
*));
572 res
= any
.GetAs(&variant
);
574 CPPUNIT_ASSERT(variant
.GetType() == "MyClass");
576 #endif // wxUSE_VARIANT
580 class wxAnyValueTypeImpl
<MyClass
> :
581 public wxAnyValueTypeImplBase
<MyClass
>
583 WX_DECLARE_ANY_VALUE_TYPE(wxAnyValueTypeImpl
<MyClass
>)
585 wxAnyValueTypeImpl() :
586 wxAnyValueTypeImplBase
<MyClass
>() { }
587 virtual ~wxAnyValueTypeImpl() { }
589 virtual bool ConvertValue(const wxAnyValueBuffer
& src
,
590 wxAnyValueType
* dstType
,
591 wxAnyValueBuffer
& dst
) const
593 MyClass value
= GetValue(src
);
595 if ( wxANY_VALUE_TYPE_CHECK_TYPE(dstType
, wxString
) )
597 wxString s
= value
.ToString();
598 wxAnyValueTypeImpl
<wxString
>::SetValue(s
, dst
);
608 // Following must be placed somewhere in your source code
609 WX_IMPLEMENT_ANY_VALUE_TYPE(wxAnyValueTypeImpl
<MyClass
>)
611 void wxAnyTestCase::CustomTemplateSpecialization()
613 // Do only a minimal CheckType() test, as dynamic type conversion already
617 wxAny any
= myObject
;
619 CPPUNIT_ASSERT( wxANY_CHECK_TYPE(any
, MyClass
) );
620 MyClass myObject2
= wxANY_AS(any
, MyClass
);
621 wxUnusedVar(myObject2
);
624 res
= any
.GetAs(&str
);
626 CPPUNIT_ASSERT_EQUAL(str
, myObject
.ToString());