+///////////////////////////////////////////////////////////////////////////////
+// Name: tests/hashes/hashes.cpp
+// Purpose: wxArray unit test
+// Author: Vadim Zeitlin, Mattia Barbon
+// Created: 2004-05-16
+// RCS-ID: $Id$
+// Copyright: (c) 2004 Vadim Zeitlin, Mattia Barbon
+///////////////////////////////////////////////////////////////////////////////
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+ #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif // WX_PRECOMP
+
+#include "wx/hash.h"
+#include "wx/hashmap.h"
+#include "wx/hashset.h"
+
+#include "wx/cppunit.h"
+
+// --------------------------------------------------------------------------
+// helper class for typed/untyped wxHashTable
+// --------------------------------------------------------------------------
+
+struct Foo
+{
+ Foo(int n_) { n = n_; count++; }
+ ~Foo() { count--; }
+
+ int n;
+
+ static size_t count;
+};
+
+size_t Foo::count = 0;
+
+struct FooObject : public wxObject
+{
+ FooObject(int n_) { n = n_; count++; }
+ ~FooObject() { count--; }
+
+ int n;
+
+ static size_t count;
+};
+
+size_t FooObject::count = 0;
+
+// --------------------------------------------------------------------------
+// test class
+// --------------------------------------------------------------------------
+
+class HashesTestCase : public CppUnit::TestCase
+{
+public:
+ HashesTestCase() { }
+
+private:
+ CPPUNIT_TEST_SUITE( HashesTestCase );
+ CPPUNIT_TEST( wxHashTableTest );
+ CPPUNIT_TEST( wxUntypedHashTableDeleteContents );
+ CPPUNIT_TEST( wxTypedHashTableTest );
+ CPPUNIT_TEST( wxHashMapTest );
+ CPPUNIT_TEST( wxHashSetTest );
+ CPPUNIT_TEST_SUITE_END();
+
+ void wxHashTableTest();
+ void wxUntypedHashTableDeleteContents();
+ void wxTypedHashTableTest();
+ void wxHashMapTest();
+ void wxHashSetTest();
+
+ DECLARE_NO_COPY_CLASS(HashesTestCase)
+};
+
+// register in the unnamed registry so that these tests are run by default
+CPPUNIT_TEST_SUITE_REGISTRATION( HashesTestCase );
+
+// also include in it's own registry so that these tests can be run alone
+CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( HashesTestCase, "HashesTestCase" );
+
+void HashesTestCase::wxHashTableTest()
+{
+ const int COUNT = 100;
+
+ {
+ wxHashTable hash(wxKEY_INTEGER, 10), hash2(wxKEY_STRING);
+ wxObject o;
+ int i;
+
+ for ( i = 0; i < COUNT; ++i )
+ hash.Put(i, &o + i);
+
+ hash.BeginFind();
+ wxHashTable::compatibility_iterator it = hash.Next();
+ i = 0;
+
+ while (it)
+ {
+ ++i;
+ it = hash.Next();
+ }
+
+ CPPUNIT_ASSERT( i == COUNT );
+
+ for ( i = 99; i >= 0; --i )
+ CPPUNIT_ASSERT( hash.Get(i) == &o + i );
+
+ for ( i = 0; i < COUNT; ++i )
+ hash.Put(i, &o + i + 20);
+
+ for ( i = 99; i >= 0; --i )
+ CPPUNIT_ASSERT( hash.Get(i) == &o + i);
+
+ for ( i = 0; i < COUNT/2; ++i )
+ CPPUNIT_ASSERT( hash.Delete(i) == &o + i);
+
+ for ( i = COUNT/2; i < COUNT; ++i )
+ CPPUNIT_ASSERT( hash.Get(i) == &o + i);
+
+ for ( i = 0; i < COUNT/2; ++i )
+ CPPUNIT_ASSERT( hash.Get(i) == &o + i + 20);
+
+ for ( i = 0; i < COUNT/2; ++i )
+ CPPUNIT_ASSERT( hash.Delete(i) == &o + i + 20);
+
+ for ( i = 0; i < COUNT/2; ++i )
+ CPPUNIT_ASSERT( hash.Get(i) == NULL);
+
+ hash2.Put(_T("foo"), &o + 1);
+ hash2.Put(_T("bar"), &o + 2);
+ hash2.Put(_T("baz"), &o + 3);
+
+ CPPUNIT_ASSERT(hash2.Get(_T("moo")) == NULL);
+ CPPUNIT_ASSERT(hash2.Get(_T("bar")) == &o + 2);
+
+ hash2.Put(_T("bar"), &o + 0);
+
+ CPPUNIT_ASSERT(hash2.Get(_T("bar")) == &o + 2);
+ }
+
+ // and now some corner-case testing; 3 and 13 hash to the same bucket
+ {
+ wxHashTable hash(wxKEY_INTEGER, 10);
+ wxObject dummy;
+
+ hash.Put(3, &dummy);
+ hash.Delete(3);
+
+ CPPUNIT_ASSERT(hash.Get(3) == NULL);
+
+ hash.Put(3, &dummy);
+ hash.Put(13, &dummy);
+ hash.Delete(3);
+
+ CPPUNIT_ASSERT(hash.Get(3) == NULL);
+
+ hash.Delete(13);
+
+ CPPUNIT_ASSERT(hash.Get(13) == NULL);
+
+ hash.Put(3, &dummy);
+ hash.Put(13, &dummy);
+ hash.Delete(13);
+
+ CPPUNIT_ASSERT(hash.Get(13) == NULL);
+
+ hash.Delete(3);
+
+ CPPUNIT_ASSERT(hash.Get(3) == NULL);
+ }
+
+ // test for key + value access (specifically that supplying either
+ // wrong key or wrong value returns NULL)
+ {
+ wxHashTable hash(wxKEY_INTEGER, 10);
+ wxObject dummy;
+
+ hash.Put(3, 7, &dummy + 7);
+ hash.Put(4, 8, &dummy + 8);
+
+ CPPUNIT_ASSERT(hash.Get(7) == NULL);
+ CPPUNIT_ASSERT(hash.Get(3, 7) == &dummy + 7);
+ CPPUNIT_ASSERT(hash.Get(4) == NULL);
+ CPPUNIT_ASSERT(hash.Get(3) == NULL);
+ CPPUNIT_ASSERT(hash.Get(8) == NULL);
+ CPPUNIT_ASSERT(hash.Get(8, 4) == NULL);
+
+ CPPUNIT_ASSERT(hash.Delete(7) == NULL);
+ CPPUNIT_ASSERT(hash.Delete(3) == NULL);
+ CPPUNIT_ASSERT(hash.Delete(3, 7) == &dummy + 7);
+ }
+
+}
+
+void HashesTestCase::wxUntypedHashTableDeleteContents()
+{
+ // need a nested scope for destruction
+ {
+ wxHashTable hash;
+ hash.DeleteContents(true);
+
+ CPPUNIT_ASSERT( hash.GetCount() == 0 );
+ CPPUNIT_ASSERT( FooObject::count == 0 );
+
+ static const int hashTestData[] =
+ {
+ 0, 1, 17, -2, 2, 4, -4, 345, 3, 3, 2, 1,
+ };
+
+ size_t n;
+ for ( n = 0; n < WXSIZEOF(hashTestData); n++ )
+ {
+ hash.Put(hashTestData[n], n, new FooObject(n));
+ }
+
+ CPPUNIT_ASSERT( hash.GetCount() == WXSIZEOF(hashTestData) );
+ CPPUNIT_ASSERT( FooObject::count == WXSIZEOF(hashTestData) );
+
+ // delete from hash without deleting object
+ FooObject* foo = (FooObject*)hash.Delete(0l);
+
+ CPPUNIT_ASSERT( FooObject::count == WXSIZEOF(hashTestData) );
+ delete foo;
+ CPPUNIT_ASSERT( FooObject::count == WXSIZEOF(hashTestData) - 1 );
+ }
+
+ // hash destroyed
+ CPPUNIT_ASSERT( FooObject::count == 0 );
+}
+
+#if WXWIN_COMPATIBILITY_2_4
+WX_DECLARE_LIST(Foo, wxListFoos);
+#endif
+
+WX_DECLARE_HASH(Foo, wxListFoos, wxHashFoos);
+
+#if WXWIN_COMPATIBILITY_2_4
+#include "wx/listimpl.cpp"
+WX_DEFINE_LIST(wxListFoos);
+#endif
+
+void HashesTestCase::wxTypedHashTableTest()
+{
+ // need a nested scope for destruction
+ {
+ wxHashFoos hash;
+ hash.DeleteContents(true);
+
+ CPPUNIT_ASSERT( hash.GetCount() == 0 );
+ CPPUNIT_ASSERT( Foo::count == 0 );
+
+ static const int hashTestData[] =
+ {
+ 0, 1, 17, -2, 2, 4, -4, 345, 3, 3, 2, 1,
+ };
+
+ size_t n;
+ for ( n = 0; n < WXSIZEOF(hashTestData); n++ )
+ {
+ hash.Put(hashTestData[n], n, new Foo(n));
+ }
+
+ CPPUNIT_ASSERT( hash.GetCount() == WXSIZEOF(hashTestData) );
+ CPPUNIT_ASSERT( Foo::count == WXSIZEOF(hashTestData) );
+
+ for ( n = 0; n < WXSIZEOF(hashTestData); n++ )
+ {
+ Foo *foo = hash.Get(hashTestData[n], n);
+
+ CPPUNIT_ASSERT( foo != NULL );
+ CPPUNIT_ASSERT( foo->n == (int)n );
+ }
+
+ // element not in hash
+ CPPUNIT_ASSERT( hash.Get(1234) == NULL );
+ CPPUNIT_ASSERT( hash.Get(1, 0) == NULL );
+
+ // delete from hash without deleting object
+ Foo* foo = hash.Delete(0);
+
+ CPPUNIT_ASSERT( Foo::count == WXSIZEOF(hashTestData) );
+ delete foo;
+ CPPUNIT_ASSERT( Foo::count == WXSIZEOF(hashTestData) - 1 );
+ }
+
+ // hash destroyed
+ CPPUNIT_ASSERT( Foo::count == 0 );
+}
+
+void HashesTestCase::wxHashMapTest()
+{
+}
+
+void HashesTestCase::wxHashSetTest()
+{
+}