summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authoranonymous <local@localhost>2010-06-27 17:13:07 +0000
committeranonymous <local@localhost>2010-06-27 17:13:07 +0000
commit7ca18cb7c08bf92db5946a66e312678c480eb819 (patch)
tree22dfcc5cf05ecad955cd15d9feb952f204a4b32b /test
downloadlibcxxrt-7ca18cb7c08bf92db5946a66e312678c480eb819.tar.gz
libcxxrt-7ca18cb7c08bf92db5946a66e312678c480eb819.tar.bz2
libcxxrt-7ca18cb7c08bf92db5946a66e312678c480eb819.tar.xz
Initial import.
Diffstat (limited to 'test')
-rw-r--r--test/Makefile71
-rw-r--r--test/new.cc16
-rw-r--r--test/test.cc26
-rw-r--r--test/test.h4
-rw-r--r--test/test_exception.cc146
-rw-r--r--test/test_guard.cc24
-rw-r--r--test/test_typeinfo.cc120
7 files changed, 407 insertions, 0 deletions
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..0d0e203
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,71 @@
+OBJECTS = typeinfo.o exception.o dynamic_cast.o terminate.o guard.o
+
+TEST_OBJECTS = test_typeinfo.o test.o test_exception.o new.o test_guard.o
+
+# Needed for building the shared library
+CXXFLAGS = -fPIC
+# Needed for GCC atomic ops to work on x86.
+CXXFLAGS += -march=native
+# This library implements exception handling, so make sure that the compiler
+# emits the correct code
+CXXFLAGS += -fexceptions
+
+# Useful flags for debugging
+CXXFLAGS += -Wall -pedantic -g
+
+# silence warnings about LL suffix (only works with clang / recent GCC):
+#CXXFLAGS += -std=c++0x
+
+# Find the unwind.h header installed from ports
+CPPFLAGS += -I/usr/local/include
+LDFLAGS += -L/usr/local/lib -L. -lpthread -fexceptions
+
+
+
+
+
+all: test libcxxabi.so.1
+
+PRODUCTS = test libcxxabi.so.1 system_test
+
+test: $(TEST_OBJECTS) libcxxabi.so.1
+ @echo
+ @gcc $(CPPFLAGS) $(LDFLAGS) -lcxxabi -o test $(TEST_OBJECTS)
+
+# Fudge the dynamic library search path to include the current directory so
+# that we can run the tests without having to install the .so
+runtest: test
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ./test
+
+# Run the test program in the debugger
+debug: test
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) gdb ./test
+
+# Run the test program with valgrind. Make sure that the output from this has
+# no memory leaks
+valgrind: test
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) valgrind --leak-check=full ./test
+
+# Compile another version of the test program linked against libstdc++, run it,
+# and ensure that both versions pass the same number of tests. Bugs in the
+# unwinding can cause some test not to be executed - this is a quick way of
+# testing that the correct number pass.
+compare: test
+ @$(CXX) $(CXXFLAGS) $(LDFLAGS) $(TEST_OBJECTS) -lstdc++ -o system_test
+ @./system_test 2>&1 | tail -1 > system_test.out
+ @echo Comparing libcxxabi and libstdc++ versions...
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ./test 2>&1 | tail -1 | diff system_test.out -
+
+
+libcxxabi.so.1: $(OBJECTS)
+ @echo Linking $@...
+ @gcc -fexception -shared $(OBJECTS) $(LDFLAGS) -o libcxxabi.so.1 #-lunwind
+
+.cc.o:
+ @echo Compiling $<...
+ @echo $(CXXFLAGS)
+ @$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
+
+clean:
+ @echo Cleaning...
+ @rm -f $(OBJECTS) $(PRODUCTS) $(TEST_OBJECTS) vgcore* *.core
diff --git a/test/new.cc b/test/new.cc
new file mode 100644
index 0000000..73184ea
--- /dev/null
+++ b/test/new.cc
@@ -0,0 +1,16 @@
+#include <stdlib.h>
+
+// Stub (incomplete) implementations to allow testing the library without an
+// STL implementation
+//
+// Note: gcc complains on x86 if this takes a size_t, and on x86-64 if it takes
+// an unsigned int. This is just a stub, so it doesn't matter too much.
+void *operator new(unsigned int s)
+{
+ return malloc(s);
+}
+
+void operator delete(void *o)
+{
+ free(o);
+}
diff --git a/test/test.cc b/test/test.cc
new file mode 100644
index 0000000..13bad95
--- /dev/null
+++ b/test/test.cc
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+static int succeeded;
+static int failed;
+
+void log_test(bool predicate, const char *file, int line, const char *message)
+{
+ if (predicate)
+ {
+ succeeded++;
+ return;
+ }
+ failed++;
+ printf("Test failed: %s:%d: %s\n", file, line, message);
+}
+
+static void log_totals(void)
+{
+ printf("\n%d tests, %d passed, %d failed\n", succeeded+failed, succeeded, failed);
+}
+
+static void __attribute__((constructor)) init(void)
+{
+ atexit(log_totals);
+}
diff --git a/test/test.h b/test/test.h
new file mode 100644
index 0000000..6972b62
--- /dev/null
+++ b/test/test.h
@@ -0,0 +1,4 @@
+
+void log_test(bool predicate, const char *file, int line, const char *message);
+
+#define TEST(p, m) log_test(p, __FILE__, __LINE__, m)
diff --git a/test/test_exception.cc b/test/test_exception.cc
new file mode 100644
index 0000000..2a1be80
--- /dev/null
+++ b/test/test_exception.cc
@@ -0,0 +1,146 @@
+#include "test.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+void log(void* ignored)
+{
+ printf("Cleanup called on %s\n", *(char**)ignored);
+}
+#define CLEANUP\
+ __attribute__((cleanup(log))) __attribute__((unused))\
+ const char *f = __func__;
+
+/**
+ * Simple struct to test throwing.
+ */
+struct foo
+{
+ int i;
+};
+
+struct bar : foo
+{
+ float bar;
+};
+
+
+static int cleanup_count;
+/**
+ * Simple structure declared with a destructor. Destroying this object will
+ * increment cleanup count. The destructor should be called automatically if
+ * an instance of cl is allocated with automatic storage.
+ */
+struct cl
+{
+ int i;
+ ~cl() { fprintf(stderr, "cl destroyed: %d\n", i); cleanup_count++; }
+};
+/**
+ * Test that one cl was destroyed when running the argument.
+ */
+#define TEST_CLEANUP(x) do {\
+ int cleanups = cleanup_count;\
+ { x; }\
+ TEST(cleanup_count == cleanups+1, "Cleanup ran correctly");\
+ } while(0)
+
+int inner(int i)
+{
+ CLEANUP
+ switch (i)
+ {
+ case 0: throw (int)1.0;
+ case 1: throw (float)1.0;
+ case 2: throw (int64_t)1;
+ case 3: { foo f = {2} ; throw f; }
+ case 4: { bar f; f.i = 2 ; f.bar=1 ; throw f; }
+ }
+ return -1;
+}
+
+int outer(int i) throw(float, int, foo)
+{
+ //CLEANUP
+ inner(i);
+ return 1;
+}
+
+static void test_catch(int s)
+{
+ cl c;
+ c.i = 12;
+ fprintf(stderr, "Entering try\n");
+ try
+ {
+ outer(s);
+ }
+ catch(int i)
+ {
+ fprintf(stderr, "Caught int %d!\n", i);
+ TEST(s == 0 && i == 1, "Caught int");
+ return;
+ }
+ catch (float f)
+ {
+ fprintf(stderr, "Caught float %f!\n", f);
+ TEST(s == 1 && f == 1, "Caught float");
+ return;
+ }
+ catch (foo f)
+ {
+ fprintf(stderr, "Caught struct {%d}!\n", f.i);
+ TEST((s == 3 || s == 4) && f.i == 2, "Caught struct");
+ return;
+ }
+ //abort();
+ TEST(0, "Unreachable line reached");
+}
+
+void test_nested1(void)
+{
+ CLEANUP;
+ cl c;
+ c.i = 123;
+ try
+ {
+ outer(0);
+ }
+ catch (int a)
+ {
+ try
+ {
+ TEST(a == 1, "Caught int");
+ outer(1);
+ }
+ catch (float f)
+ {
+ TEST(f == 1, "Caught float inside outer catch block");
+ throw;
+ }
+ }
+}
+
+void test_nested()
+{
+ try
+ {
+ test_nested1();
+ }
+ catch (float f)
+ {
+ fprintf(stderr, "Caught re-thrown float\n");
+ TEST(f == 1, "Caught re-thrown float");
+ }
+}
+void test_exceptions(void)
+{
+ TEST_CLEANUP(test_catch(0));
+ TEST_CLEANUP(test_catch(1));
+ TEST_CLEANUP(test_catch(3));
+ TEST_CLEANUP(test_catch(4));
+ //test_catch(2);
+ TEST_CLEANUP(test_nested());
+
+ //printf("Test: %s\n",
+}
diff --git a/test/test_guard.cc b/test/test_guard.cc
new file mode 100644
index 0000000..baeb0e7
--- /dev/null
+++ b/test/test_guard.cc
@@ -0,0 +1,24 @@
+#include <stdio.h>
+
+static int static_count;
+struct static_struct
+{
+ int i;
+ static_struct()
+ {
+ fprintf(stderr, "Initialized static\n");
+ static_count++;
+ i = 12;
+ };
+};
+
+int init_static(void)
+{
+ static static_struct s;
+ return s.i;
+}
+
+void test_guards(void)
+{
+ init_static();
+}
diff --git a/test/test_typeinfo.cc b/test/test_typeinfo.cc
new file mode 100644
index 0000000..dd5321a
--- /dev/null
+++ b/test/test_typeinfo.cc
@@ -0,0 +1,120 @@
+#include "typeinfo.h"
+#include "test.h"
+#include <stdio.h>
+
+// FIXME: Move this and main() to a different file.
+void test_exceptions();
+
+struct Virt1;
+struct Virt2;
+struct Diamond;
+struct Virt1a;
+struct Virt2a;
+struct Diamond2;
+
+struct Root
+{
+ int test;
+ void * foo;
+ virtual Virt1 *as_v1() { return 0; }
+ virtual Virt2 *as_v2() { return 0; }
+ virtual Diamond *as_diamond() { return 0; }
+ virtual Virt1a *as_v1a() { return 0; }
+ virtual Virt2a *as_v2a() { return 0; }
+ virtual Diamond2 *as_diamond2() { return 0; }
+};
+
+struct Sub1 : public Root
+{
+ double a;
+};
+
+struct Sub2 : public Sub1
+{
+ float ignored;
+};
+
+struct Virt1a : public virtual Root
+{
+ int b;
+ virtual Virt1a *as_v1a() { return this; }
+};
+
+struct Virt2a : public virtual Root
+{
+ int b;
+ virtual Virt2a *as_v2a() { return this; }
+};
+
+struct Virt1 : public virtual Virt1a
+{
+ double a;
+ virtual Virt1 *as_v1() { return this; }
+};
+
+struct Virt2 : public virtual Virt2a
+{
+ double b;
+ virtual Virt2 *as_v2() { return this; }
+};
+
+struct Diamond : public virtual Virt1, public virtual Virt2
+{
+ int c;
+ virtual Diamond *as_diamond() { return this; }
+};
+
+struct Diamond2 : public virtual Virt1a, public virtual Virt2a
+{
+ int c;
+ virtual Diamond2 *as_diamond2() { return this; }
+};
+
+void test_type_info(void)
+{
+ Sub2 sub2;
+ Root root;
+ Virt1 virt1;
+ Diamond diamond;
+ Root *b = &sub2;
+ Root *f = &sub2;
+ Root *s2 = &sub2;
+ Root *b2 = &root;
+ Root *v1 = &virt1;
+ Virt1 *d1 = &diamond;
+ b->test = 12;
+ f->test = 12;
+ b2->test = 12;
+ s2->test = 12;
+ TEST(12 == b->test, "Setting field");
+ b = dynamic_cast<Root*>(f);
+
+ TEST(12 == b->test, "Casting Sub1 to superclass");
+ ((Sub1*)(s2))->a = 12;
+ TEST(12 == dynamic_cast<Sub1*>(s2)->a, "Casting Sub2 -> Sub1");
+
+ v1->as_v1()->a = 12;
+ TEST(12 == dynamic_cast<Virt1*>(v1)->a, "Casting Root (Virt1) -> Virt1");
+
+ d1->as_v1()->test = 12;
+ TEST(12 == d1->as_v2()->test, "Accessing virt2 via vtable method");
+ TEST(12 == dynamic_cast<Virt2*>(d1)->test, "Casting diamond to virt2");
+ TEST(12 == dynamic_cast<Diamond*>(d1)->test, "casting diamond to diamond");
+
+ Diamond2 diamond2;
+ Root *d2 = &diamond2;
+ d2->test = 12;
+ TEST(12 == dynamic_cast<Diamond2*>(d2)->test, "Casting Diamond2 to Diamond2");
+ TEST(12 == dynamic_cast<Virt2a*>(d2)->test, "Casting Diamond2 to Virt2a");
+
+ TEST(0 == dynamic_cast<Sub1*>(b2), "Casting Root to Sub1 (0 expected)");
+}
+
+void test_guards(void);
+int main(void)
+{
+ test_type_info();
+ test_guards();
+ test_exceptions();
+ return 0;
+}