summaryrefslogtreecommitdiff
path: root/tests/test_cpp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_cpp.cc')
-rw-r--r--tests/test_cpp.cc277
1 files changed, 277 insertions, 0 deletions
diff --git a/tests/test_cpp.cc b/tests/test_cpp.cc
new file mode 100644
index 0000000..75fd366
--- /dev/null
+++ b/tests/test_cpp.cc
@@ -0,0 +1,277 @@
+/****************************************************************************
+Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+
+THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+
+Permission is hereby granted to use or copy this program for any
+purpose, provided the above notices are retained on all copies.
+Permission to modify the code and to distribute modified code is
+granted, provided the above notices are retained, and a notice that
+the code was modified is included with the above copyright notice.
+****************************************************************************
+Last modified on Mon Jul 10 21:06:03 PDT 1995 by ellis
+ modified on December 20, 1994 7:27 pm PST by boehm
+
+usage: test_cpp number-of-iterations
+
+This program tries to test the specific C++ functionality provided by
+gc_c++.h that isn't tested by the more general test routines of the
+collector.
+
+A recommended value for number-of-iterations is 10, which will take a
+few minutes to complete.
+
+***************************************************************************/
+
+#include "gc_cpp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __GNUC__
+# include "new_gc_alloc.h"
+#else
+# include "gc_alloc.h"
+#endif
+extern "C" {
+#include "private/gc_priv.h"
+}
+#ifdef MSWIN32
+# include <windows.h>
+#endif
+#ifdef GC_NAME_CONFLICT
+# define USE_GC UseGC
+ struct foo * GC;
+#else
+# define USE_GC GC
+#endif
+
+
+#define my_assert( e ) \
+ if (! (e)) { \
+ GC_printf1( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \
+ __LINE__ ); \
+ exit( 1 ); }
+
+
+class A {public:
+ /* An uncollectable class. */
+
+ A( int iArg ): i( iArg ) {}
+ void Test( int iArg ) {
+ my_assert( i == iArg );}
+ int i;};
+
+
+class B: public gc, public A {public:
+ /* A collectable class. */
+
+ B( int j ): A( j ) {}
+ ~B() {
+ my_assert( deleting );}
+ static void Deleting( int on ) {
+ deleting = on;}
+ static int deleting;};
+
+int B::deleting = 0;
+
+
+class C: public gc_cleanup, public A {public:
+ /* A collectable class with cleanup and virtual multiple inheritance. */
+
+ C( int levelArg ): A( levelArg ), level( levelArg ) {
+ nAllocated++;
+ if (level > 0) {
+ left = new C( level - 1 );
+ right = new C( level - 1 );}
+ else {
+ left = right = 0;}}
+ ~C() {
+ this->A::Test( level );
+ nFreed++;
+ my_assert( level == 0 ?
+ left == 0 && right == 0 :
+ level == left->level + 1 && level == right->level + 1 );
+ left = right = 0;
+ level = -123456;}
+ static void Test() {
+ my_assert( nFreed <= nAllocated && nFreed >= .8 * nAllocated );}
+
+ static int nFreed;
+ static int nAllocated;
+ int level;
+ C* left;
+ C* right;};
+
+int C::nFreed = 0;
+int C::nAllocated = 0;
+
+
+class D: public gc {public:
+ /* A collectable class with a static member function to be used as
+ an explicit clean-up function supplied to ::new. */
+
+ D( int iArg ): i( iArg ) {
+ nAllocated++;}
+ static void CleanUp( void* obj, void* data ) {
+ D* self = (D*) obj;
+ nFreed++;
+ my_assert( self->i == (int) (long) data );}
+ static void Test() {
+ my_assert( nFreed >= .8 * nAllocated );}
+
+ int i;
+ static int nFreed;
+ static int nAllocated;};
+
+int D::nFreed = 0;
+int D::nAllocated = 0;
+
+
+class E: public gc_cleanup {public:
+ /* A collectable class with clean-up for use by F. */
+
+ E() {
+ nAllocated++;}
+ ~E() {
+ nFreed++;}
+
+ static int nFreed;
+ static int nAllocated;};
+
+int E::nFreed = 0;
+int E::nAllocated = 0;
+
+
+class F: public E {public:
+ /* A collectable class with clean-up, a base with clean-up, and a
+ member with clean-up. */
+
+ F() {
+ nAllocated++;}
+ ~F() {
+ nFreed++;}
+ static void Test() {
+ my_assert( nFreed >= .8 * nAllocated );
+ my_assert( 2 * nFreed == E::nFreed );}
+
+ E e;
+ static int nFreed;
+ static int nAllocated;};
+
+int F::nFreed = 0;
+int F::nAllocated = 0;
+
+
+long Disguise( void* p ) {
+ return ~ (long) p;}
+
+void* Undisguise( long i ) {
+ return (void*) ~ i;}
+
+
+#ifdef MSWIN32
+int APIENTRY WinMain(
+ HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int cmdShow )
+{
+ int argc;
+ char* argv[ 3 ];
+
+ for (argc = 1; argc < sizeof( argv ) / sizeof( argv[ 0 ] ); argc++) {
+ argv[ argc ] = strtok( argc == 1 ? cmd : 0, " \t" );
+ if (0 == argv[ argc ]) break;}
+
+#else
+# ifdef MACOS
+ int main() {
+# else
+ int main( int argc, char* argv[] ) {
+# endif
+#endif
+
+# if defined(MACOS) // MacOS
+ char* argv_[] = {"test_cpp", "10"}; // doesn't
+ argv = argv_; // have a
+ argc = sizeof(argv_)/sizeof(argv_[0]); // commandline
+# endif
+ int i, iters, n;
+# if !defined(MACOS)
+# ifdef __GNUC__
+ int *x = (int *)gc_alloc::allocate(sizeof(int));
+# else
+ int *x = (int *)alloc::allocate(sizeof(int));
+# endif
+
+ *x = 29;
+ x -= 3;
+# endif
+ if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
+ GC_printf0( "usage: test_cpp number-of-iterations\n" );
+ exit( 1 );}
+
+ for (iters = 1; iters <= n; iters++) {
+ GC_printf1( "Starting iteration %d\n", iters );
+
+ /* Allocate some uncollectable As and disguise their pointers.
+ Later we'll check to see if the objects are still there. We're
+ checking to make sure these objects really are uncollectable. */
+ long as[ 1000 ];
+ long bs[ 1000 ];
+ for (i = 0; i < 1000; i++) {
+ as[ i ] = Disguise( new (NoGC) A( i ) );
+ bs[ i ] = Disguise( new (NoGC) B( i ) );}
+
+ /* Allocate a fair number of finalizable Cs, Ds, and Fs.
+ Later we'll check to make sure they've gone away. */
+ for (i = 0; i < 1000; i++) {
+ C* c = new C( 2 );
+ C c1( 2 ); /* stack allocation should work too */
+ D* d = ::new (USE_GC, D::CleanUp, (void*)(long)i) D( i );
+ F* f = new F;
+ if (0 == i % 10) delete c;}
+
+ /* Allocate a very large number of collectable As and Bs and
+ drop the references to them immediately, forcing many
+ collections. */
+ for (i = 0; i < 1000000; i++) {
+ A* a = new (USE_GC) A( i );
+ B* b = new B( i );
+ b = new (USE_GC) B( i );
+ if (0 == i % 10) {
+ B::Deleting( 1 );
+ delete b;
+ B::Deleting( 0 );}
+# ifdef FINALIZE_ON_DEMAND
+ GC_invoke_finalizers();
+# endif
+ }
+
+ /* Make sure the uncollectable As and Bs are still there. */
+ for (i = 0; i < 1000; i++) {
+ A* a = (A*) Undisguise( as[ i ] );
+ B* b = (B*) Undisguise( bs[ i ] );
+ a->Test( i );
+ delete a;
+ b->Test( i );
+ B::Deleting( 1 );
+ delete b;
+ B::Deleting( 0 );
+# ifdef FINALIZE_ON_DEMAND
+ GC_invoke_finalizers();
+# endif
+
+ }
+
+ /* Make sure most of the finalizable Cs, Ds, and Fs have
+ gone away. */
+ C::Test();
+ D::Test();
+ F::Test();}
+
+# if !defined(__GNUC__) && !defined(MACOS)
+ my_assert (29 == x[3]);
+# endif
+ GC_printf0( "The test appears to have succeeded.\n" );
+ return( 0 );}
+
+