diff options
author | anonymous <local@localhost> | 2010-06-27 17:13:07 +0000 |
---|---|---|
committer | anonymous <local@localhost> | 2010-06-27 17:13:07 +0000 |
commit | 7ca18cb7c08bf92db5946a66e312678c480eb819 (patch) | |
tree | 22dfcc5cf05ecad955cd15d9feb952f204a4b32b /test | |
download | libcxxrt-7ca18cb7c08bf92db5946a66e312678c480eb819.tar.gz libcxxrt-7ca18cb7c08bf92db5946a66e312678c480eb819.tar.bz2 libcxxrt-7ca18cb7c08bf92db5946a66e312678c480eb819.tar.xz |
Initial import.
Diffstat (limited to 'test')
-rw-r--r-- | test/Makefile | 71 | ||||
-rw-r--r-- | test/new.cc | 16 | ||||
-rw-r--r-- | test/test.cc | 26 | ||||
-rw-r--r-- | test/test.h | 4 | ||||
-rw-r--r-- | test/test_exception.cc | 146 | ||||
-rw-r--r-- | test/test_guard.cc | 24 | ||||
-rw-r--r-- | test/test_typeinfo.cc | 120 |
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 = ⋄ + 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; +} |