// Name: tests/any/anytest.cpp
// Purpose: Test the wxAny classes
// Author: Jaakko Salli
-// RCS-ID: $Id$
// Copyright: (c) the wxWidgets team
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#include "wx/any.h"
#include "wx/datetime.h"
#include "wx/object.h"
+#include "wx/vector.h"
#include <math.h>
private:
CPPUNIT_TEST_SUITE( wxAnyTestCase );
+ CPPUNIT_TEST( CheckType );
CPPUNIT_TEST( Equality );
CPPUNIT_TEST( As );
CPPUNIT_TEST( GetAs );
CPPUNIT_TEST( Null );
+ CPPUNIT_TEST( wxVariantConversions );
CPPUNIT_TEST( CustomTemplateSpecialization );
+ CPPUNIT_TEST( Misc );
CPPUNIT_TEST_SUITE_END();
+ void CheckType();
void Equality();
void As();
void GetAs();
void Null();
+ void wxVariantConversions();
void CustomTemplateSpecialization();
+ void Misc();
wxDateTime m_testDateTime;
wxAny m_anyWxObjectPtr1;
wxAny m_anyVoidPtr1;
wxAny m_anyDateTime1;
+ wxAny m_anyUniChar1;
wxAny m_anySignedChar2;
wxAny m_anySignedShort2;
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( wxAnyTestCase );
-// also include in it's own registry so that these tests can be run alone
+// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( wxAnyTestCase, "wxAnyTestCase" );
// Let's use a number with first digit after decimal dot less than 5,
// so that we don't have to worry about whether conversion from float
// to int truncates or rounds.
-const double TEST_FLOAT_CONST = 123.456;
+const float TEST_FLOAT_CONST = 123.456f;
+const double TEST_DOUBLE_CONST = 123.456;
const double FEQ_DELTA = 0.001;
m_anyCharString1("abc"),
m_anyWcharString1(L"abc"),
m_anyBool1(true),
- m_anyFloatDouble1((float)TEST_FLOAT_CONST),
- m_anyDoubleDouble1((double)TEST_FLOAT_CONST),
+ m_anyFloatDouble1(TEST_FLOAT_CONST),
+ m_anyDoubleDouble1(TEST_DOUBLE_CONST),
m_anyWxObjectPtr1(dummyWxObjectPointer),
m_anyVoidPtr1(dummyVoidPointer),
m_anyDateTime1(wxDateTime::Now())
m_anyCharString2 = "abc";
m_anyWcharString2 = L"abc";
m_anyBool2 = true;
- m_anyFloatDouble2 = (float)TEST_FLOAT_CONST;
- m_anyDoubleDouble2 = (double)TEST_FLOAT_CONST;
+ m_anyFloatDouble2 = TEST_FLOAT_CONST;
+ m_anyDoubleDouble2 = TEST_DOUBLE_CONST;
m_anyDateTime2 = m_testDateTime;
+ m_anyUniChar1 = wxUniChar('A');
m_anyWxObjectPtr2 = dummyWxObjectPointer;
m_anyVoidPtr2 = dummyVoidPointer;
}
+void wxAnyTestCase::CheckType()
+{
+ wxAny nullAny;
+ CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(nullAny, wxString));
+
+ CPPUNIT_ASSERT(wxANY_CHECK_TYPE(m_anyCharString2, const char*));
+ CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyCharString2, wxString));
+ CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyCharString2, const wchar_t*));
+ CPPUNIT_ASSERT(wxANY_CHECK_TYPE(m_anyWcharString2, const wchar_t*));
+ CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyWcharString2, wxString));
+ CPPUNIT_ASSERT(!wxANY_CHECK_TYPE(m_anyWcharString2, const char*));
+
+ // HasSameType()
+ CPPUNIT_ASSERT( m_anyWcharString1.HasSameType(m_anyWcharString2) );
+ CPPUNIT_ASSERT( !m_anyWcharString1.HasSameType(m_anyBool1) );
+}
+
void wxAnyTestCase::Equality()
{
//
CPPUNIT_ASSERT(wxANY_AS(m_anyWxObjectPtr2, wxObject*)
== dummyWxObjectPointer);
CPPUNIT_ASSERT(wxANY_AS(m_anyVoidPtr2, void*) == dummyVoidPointer);
+
+ // Test sub-type system type compatibility
+ CPPUNIT_ASSERT(m_anySignedShort1.GetType()->
+ IsSameType(m_anySignedLongLong1.GetType()));
+ CPPUNIT_ASSERT(m_anyUnsignedShort1.GetType()->
+ IsSameType(m_anyUnsignedLongLong1.GetType()));
}
void wxAnyTestCase::As()
wxString k = wxANY_AS(m_anyStringString1, wxString);
CPPUNIT_ASSERT(k == "abc");
wxString l = wxANY_AS(m_anyCharString1, wxString);
+ const char* cptr = wxANY_AS(m_anyCharString1, const char*);
CPPUNIT_ASSERT(l == "abc");
+ CPPUNIT_ASSERT(cptr);
wxString m = wxANY_AS(m_anyWcharString1, wxString);
+ const wchar_t* wcptr = wxANY_AS(m_anyWcharString1, const wchar_t*);
+ CPPUNIT_ASSERT(wcptr);
CPPUNIT_ASSERT(m == "abc");
bool n = wxANY_AS(m_anyBool1, bool);
CPPUNIT_ASSERT(n);
+
+ // Make sure the stored float that comes back is -identical-.
+ // So do not use delta comparison here.
float o = wxANY_AS(m_anyFloatDouble1, float);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(o, TEST_FLOAT_CONST, FEQ_DELTA);
+ CPPUNIT_ASSERT_EQUAL(o, TEST_FLOAT_CONST);
+
double p = wxANY_AS(m_anyDoubleDouble1, double);
- CPPUNIT_ASSERT_DOUBLES_EQUAL(p, TEST_FLOAT_CONST, FEQ_DELTA);
+ CPPUNIT_ASSERT_EQUAL(p, TEST_DOUBLE_CONST);
+
+ wxUniChar chr = wxANY_AS(m_anyUniChar1, wxUniChar);
+ CPPUNIT_ASSERT(chr == 'A');
wxDateTime q = wxANY_AS(m_anyDateTime1, wxDateTime);
CPPUNIT_ASSERT(q == m_testDateTime);
wxObject* r = wxANY_AS(m_anyWxObjectPtr1, wxObject*);
// Test dynamic conversion
bool res;
long l = 0;
+ short int si = 0;
unsigned long ul = 0;
wxString s;
// Let's test against float instead of double, since the former
bool b = false;
// Conversions from signed long type
+ // The first check should be enough to make sure that the sub-type system
+ // has not failed.
+ res = m_anySignedLong1.GetAs(&si);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT_EQUAL(si, 15);
res = m_anySignedLong1.GetAs(&ul);
CPPUNIT_ASSERT(res);
- CPPUNIT_ASSERT_EQUAL(ul, static_cast<unsigned long>(15));
+ CPPUNIT_ASSERT_EQUAL(ul, 15UL);
res = m_anySignedLong1.GetAs(&s);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT(s == "15");
res = m_anyDoubleDouble1.GetAs(&s);
CPPUNIT_ASSERT(res);
double d2;
- res = s.ToDouble(&d2);
+ res = s.ToCDouble(&d2);
CPPUNIT_ASSERT(res);
CPPUNIT_ASSERT_DOUBLES_EQUAL(d2, TEST_FLOAT_CONST, FEQ_DELTA);
}
+
//
-// Test user data type specialization of wxAnyValueTypeImpl
+// Test user data type for wxAnyValueTypeImpl specialization
+// any hand-built wxVariantData. Also for inplace allocation
+// sanity checks.
//
+class MyClass;
+
+static wxVector<MyClass*> gs_myClassInstances;
+
class MyClass
{
public:
MyClass( int someValue = 32768 )
{
+ Init();
m_someValue = someValue;
}
+ MyClass( const MyClass& other )
+ {
+ Init();
+ m_someValue = other.m_someValue;
+ }
+ virtual ~MyClass()
+ {
+ for ( size_t i=0; i<gs_myClassInstances.size(); i++ )
+ {
+ if ( gs_myClassInstances[i] == this )
+ {
+ gs_myClassInstances.erase(gs_myClassInstances.begin()+i);
+ }
+ }
+ }
+
+ int GetValue() const
+ {
+ return m_someValue;
+ }
wxString ToString()
{
}
private:
+ void Init()
+ {
+ // We use this for some sanity checking
+ gs_myClassInstances.push_back(this);
+ }
+
int m_someValue;
};
+#if wxUSE_VARIANT
+
+// For testing purposes, create dummy variant data implementation
+// that does not have wxAny conversion code
+class wxMyVariantData : public wxVariantData
+{
+public:
+ wxMyVariantData(const MyClass& value)
+ {
+ m_value = value;
+ }
+
+ virtual bool Eq(wxVariantData& WXUNUSED(data)) const
+ {
+ return false;
+ }
+
+ // What type is it? Return a string name.
+ virtual wxString GetType() const { return "MyClass"; }
+
+ virtual wxVariantData* Clone() const
+ {
+ return new wxMyVariantData(m_value);
+ }
+
+protected:
+ MyClass m_value;
+};
+
+#endif // wxUSE_VARIANT
+
+
+void wxAnyTestCase::wxVariantConversions()
+{
+#if wxUSE_VARIANT
+ //
+ // Test various conversions to and from wxVariant
+ //
+ bool res;
+
+ // Prepare wxVariants
+ wxVariant vLong(123L);
+ wxVariant vString("ABC");
+ wxVariant vDouble(TEST_FLOAT_CONST);
+ wxVariant vBool((bool)true);
+ wxVariant vChar('A');
+#ifdef wxLongLong_t
+ wxVariant vLongLong(wxLongLong(wxLL(0xAABBBBCCCC)));
+ wxVariant vULongLong(wxULongLong(wxULL(123456)));
+#endif
+ wxArrayString arrstr;
+ arrstr.push_back("test string");
+ wxVariant vArrayString(arrstr);
+ wxVariant vDateTime(m_testDateTime);
+ wxVariant vVoidPtr(dummyVoidPointer);
+ wxVariant vCustomType(new wxMyVariantData(MyClass(101)));
+ wxVariant vList;
+
+ vList.NullList();
+ vList.Append(15);
+ vList.Append("abc");
+
+ // Convert to wxAnys, and then back to wxVariants
+ wxVariant variant;
+
+ wxAny any(vLong);
+ CPPUNIT_ASSERT(any == 123L);
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant == 123L);
+
+ // Make sure integer variant has correct type information
+ CPPUNIT_ASSERT(variant.GetLong() == 123);
+ CPPUNIT_ASSERT(variant.GetType() == "long");
+
+ // Unsigned long wxAny should convert to "ulonglong" wxVariant
+ any = 1000UL;
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetType() == "ulonglong");
+ CPPUNIT_ASSERT(variant.GetLong() == 1000);
+
+ any = vString;
+ CPPUNIT_ASSERT(any == "ABC");
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetString() == "ABC");
+
+ // Must be able to build string wxVariant from wxAny built from
+ // string literal
+ any = "ABC";
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetType() == "string");
+ CPPUNIT_ASSERT(variant.GetString() == "ABC");
+ any = L"ABC";
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetType() == "string");
+#if wxUSE_UNICODE
+ CPPUNIT_ASSERT(variant.GetString() == L"ABC");
+#endif
+
+ any = vDouble;
+ double d = wxANY_AS(any, double);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(d, TEST_FLOAT_CONST, FEQ_DELTA);
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT_DOUBLES_EQUAL(variant.GetDouble(),
+ TEST_FLOAT_CONST,
+ FEQ_DELTA);
+
+ any = vBool;
+ CPPUNIT_ASSERT(wxANY_AS(any, bool) == true);
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetBool() == true);
+
+ any = wxAny(vChar);
+ //CPPUNIT_ASSERT(wxANY_AS(any, wxUniChar) == 'A');
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetChar() == 'A');
+
+#ifdef wxLongLong_t
+ any = wxAny(vLongLong);
+ CPPUNIT_ASSERT(any == wxLL(0xAABBBBCCCC));
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetType() == "longlong");
+ CPPUNIT_ASSERT(variant.GetLongLong() == wxLongLong(wxLL(0xAABBBBCCCC)));
+
+#if LONG_MAX == wxINT64_MAX
+ // As a sanity check, test that wxVariant of type 'long' converts
+ // seamlessly to 'longlong' (on some 64-bit systems)
+ any = 0xAABBBBCCCCL;
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(variant.GetLongLong() == wxLongLong(wxLL(0xAABBBBCCCC)));
+#endif
+
+ any = wxAny(vULongLong);
+ CPPUNIT_ASSERT(any == wxLL(123456));
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetType() == "ulonglong");
+ CPPUNIT_ASSERT(variant.GetULongLong() == wxULongLong(wxULL(123456)));
+#endif
+
+ // Cannot test equality for the rest, just test that they convert
+ // back correctly.
+ any = wxAny(vArrayString);
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ wxArrayString arrstr2 = variant.GetArrayString();
+ CPPUNIT_ASSERT(arrstr2 == arrstr);
+
+ any = m_testDateTime;
+ CPPUNIT_ASSERT(wxANY_AS(any, wxDateTime) == m_testDateTime);
+ any = wxAny(vDateTime);
+ CPPUNIT_ASSERT(wxANY_AS(any, wxDateTime) == m_testDateTime);
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant == m_testDateTime);
+
+ any = wxAny(vVoidPtr);
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetVoidPtr() == dummyVoidPointer);
+
+ any = wxAny(vList);
+ CPPUNIT_ASSERT(wxANY_CHECK_TYPE(any, wxAnyList));
+ wxAnyList anyList = wxANY_AS(any, wxAnyList);
+ CPPUNIT_ASSERT(anyList.GetCount() == 2);
+ CPPUNIT_ASSERT(wxANY_AS((*anyList[0]), int) == 15);
+ CPPUNIT_ASSERT(wxANY_AS((*anyList[1]), wxString) == "abc");
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetType() == "list");
+ CPPUNIT_ASSERT(variant.GetCount() == 2);
+ CPPUNIT_ASSERT(variant[0].GetLong() == 15);
+ CPPUNIT_ASSERT(variant[1].GetString() == "abc");
+
+ any = wxAny(vCustomType);
+ CPPUNIT_ASSERT(wxANY_CHECK_TYPE(any, wxVariantData*));
+ res = any.GetAs(&variant);
+ CPPUNIT_ASSERT(res);
+ CPPUNIT_ASSERT(variant.GetType() == "MyClass");
+
+#endif // wxUSE_VARIANT
+}
+
template<>
class wxAnyValueTypeImpl<MyClass> :
public wxAnyValueTypeImplBase<MyClass>
CPPUNIT_ASSERT_EQUAL(str, myObject.ToString());
}
+void wxAnyTestCase::Misc()
+{
+ // Do some (inplace) allocation sanity checks
+ {
+
+ // Do it inside a scope so we can easily test instance count
+ // afterwards
+ MyClass myObject(15);
+ wxAny any = myObject;
+
+ // There must be two instances - first in myObject,
+ // and second copied in any.
+ CPPUNIT_ASSERT_EQUAL(gs_myClassInstances.size(), 2);
+
+ // Check that it is allocated in-place, as supposed
+ if ( sizeof(MyClass) <= WX_ANY_VALUE_BUFFER_SIZE )
+ {
+ // Memory block of the instance second must be inside the any
+ size_t anyBegin = reinterpret_cast<size_t>(&any);
+ size_t anyEnd = anyBegin + sizeof(wxAny);
+ size_t pos = reinterpret_cast<size_t>(gs_myClassInstances[1]);
+ CPPUNIT_ASSERT( pos >= anyBegin );
+ CPPUNIT_ASSERT( pos < anyEnd );
+ }
+
+ wxAny any2 = any;
+ CPPUNIT_ASSERT( wxANY_AS(any2, MyClass).GetValue() == 15 );
+ }
+
+ // Make sure allocations and deallocations match
+ CPPUNIT_ASSERT_EQUAL(gs_myClassInstances.size(), 0);
+}
+
#endif // wxUSE_ANY