From 3891b479553b6711e38aec68a8a297b64f928b58 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Tue, 2 Sep 2014 22:43:33 -0400 Subject: [PATCH] Implemented heap-based exceptions and added tests to increase coverage --- Rakefile | 3 +++ source/exn/exn.c | 41 +++++++++++++++++++++++++++++------------ source/exn/exn.h | 2 ++ source/mem/mem.c | 5 ++++- source/rbt/rbt.c | 4 ++-- tests/main.c | 1 + tests/test_buf.c | 2 +- tests/test_exn.c | 29 ++++++++++++++++++++++++++++- tests/test_mem.c | 20 ++++++++++++++++++++ 9 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 tests/test_mem.c diff --git a/Rakefile b/Rakefile index 5c88c39..8f1cd2d 100644 --- a/Rakefile +++ b/Rakefile @@ -69,3 +69,6 @@ end desc "Clean all generated files and directories" task(:clean) { Rscons.clean } +desc "Clobber all generated files and directories" +task(:clobber) { FileUtils.rm_rf('build') } + diff --git a/source/exn/exn.c b/source/exn/exn.c index 95113db..6507d0a 100755 --- a/source/exn/exn.c +++ b/source/exn/exn.c @@ -7,10 +7,20 @@ #include "exn.h" #include -#ifndef EXN_MAX_NUM_HANDLERS -#define EXN_MAX_NUM_HANDLERS (8) +#ifdef TESTING +extern void test_exit(int); +#define exit(status) test_exit(status) #endif +//#ifndef EXN_MAX_NUM_HANDLERS +//#define EXN_MAX_NUM_HANDLERS (8) +//#endif + +typedef struct exn_stack_t { + struct exn_stack_t* p_next; + exn_handler_t handler; +} exn_stack_t; + DEFINE_EXCEPTION(RuntimeException, NULL); DEFINE_EXCEPTION(NullPointerException, &RuntimeException); DEFINE_EXCEPTION(AssertionException, &RuntimeException); @@ -21,8 +31,7 @@ DEFINE_EXCEPTION(SegmentationException, &RuntimeException); static bool Exn_Handled = true; static const exn_t* Exn_Current = NULL; -static int Exn_Num_Handlers = 0; -static exn_handler_t Exn_Handlers[EXN_MAX_NUM_HANDLERS]; +static exn_stack_t* Exn_Handlers = NULL; static void exn_uncaught(const exn_t* p_exn) { (void)p_exn; @@ -30,11 +39,17 @@ static void exn_uncaught(const exn_t* p_exn) { exit(1); } +static void exn_pop(void) { + exn_stack_t* p_prev = Exn_Handlers; + Exn_Handlers = p_prev->p_next; + free(p_prev); +} + void exn_prep(void) { - if((Exn_Num_Handlers+1) > EXN_MAX_NUM_HANDLERS) - exn_throw(&RuntimeException); - Exn_Handlers[Exn_Num_Handlers].state = EXN_BEGIN; - Exn_Num_Handlers++; + exn_stack_t* p_prev = Exn_Handlers; + Exn_Handlers = (exn_stack_t*)malloc(sizeof(exn_stack_t)); + Exn_Handlers->p_next = p_prev; + Exn_Handlers->handler.state = EXN_BEGIN; Exn_Handled = true; } @@ -61,7 +76,7 @@ bool exn_process(void) { break; case EXN_DONE: - Exn_Num_Handlers--; + exn_pop(); ret = false; break; @@ -74,7 +89,7 @@ bool exn_process(void) { } void exn_throw(const exn_t* p_type) { - if (Exn_Num_Handlers == 0) { + if (Exn_Handlers == NULL) { exn_uncaught(Exn_Current); } else { Exn_Current = p_type; @@ -84,7 +99,9 @@ void exn_throw(const exn_t* p_type) { } void exn_rethrow(void) { - Exn_Num_Handlers--; + printf("rethrowing 1 %p\n", Exn_Handlers); + exn_pop(); + printf("rethrowing 2 %p\n", Exn_Handlers); exn_throw(Exn_Current); } @@ -106,7 +123,7 @@ const exn_t* exn_current(void) { } exn_handler_t* exn_handler(void) { - return &(Exn_Handlers[Exn_Num_Handlers-1]); + return (NULL != Exn_Handlers) ? &(Exn_Handlers->handler) : NULL; } void exn_assert(bool expr) { diff --git a/source/exn/exn.h b/source/exn/exn.h index 3c7febb..0ae6a19 100755 --- a/source/exn/exn.h +++ b/source/exn/exn.h @@ -31,6 +31,8 @@ typedef struct { exn_state_t state; } exn_handler_t; +//typedef void (*)(const exn_t* p_exn); + #define DECLARE_EXCEPTION(exname) \ extern const exn_t exname diff --git a/source/mem/mem.c b/source/mem/mem.c index f95dfa3..a0d8731 100644 --- a/source/mem/mem.c +++ b/source/mem/mem.c @@ -36,7 +36,10 @@ block_t* Live_Blocks = NULL; size_t Num_Allocations = 0; #endif -static void summarize_leaks(void) { +#ifndef TESTING +static +#endif +void summarize_leaks(void) { #if (LEAK_DETECT_LEVEL == 2) bool leak_detected = false; block_t* p_curr = Live_Blocks; diff --git a/source/rbt/rbt.c b/source/rbt/rbt.c index b17f3ac..1cc3dbd 100644 --- a/source/rbt/rbt.c +++ b/source/rbt/rbt.c @@ -69,9 +69,9 @@ static rbt_node_t* rbt_lookup_node(rbt_t* tree, rbt_node_t* node, void* value){ rbt_node_t* ret = NULL; if(node){ int c = tree->comp(value, node->contents); - if(c == 0) ret = node; + if (c < 0) ret = rbt_lookup_node(tree, node->left, value); else if(c > 0) ret = rbt_lookup_node(tree, node->right, value); - else if(c < 0) ret = rbt_lookup_node(tree, node->left, value); + else ret = node; } return ret; } diff --git a/tests/main.c b/tests/main.c index cac9be5..50ed8ae 100644 --- a/tests/main.c +++ b/tests/main.c @@ -10,5 +10,6 @@ int main(int argc, char** argv) RUN_TEST_SUITE(String); RUN_TEST_SUITE(RBT); RUN_TEST_SUITE(Exn); + RUN_TEST_SUITE(Mem); return PRINT_TEST_RESULTS(); } diff --git a/tests/test_buf.c b/tests/test_buf.c index 0dab271..9bf736a 100644 --- a/tests/test_buf.c +++ b/tests/test_buf.c @@ -83,7 +83,7 @@ TEST_SUITE(Buffer) { { buf_t* buf = buf_new(3); buf_write( buf, mem_box(0x1234) ); - buf_write( buf, mem_box(0x1235) ); + buf_write( buf, NULL ); buf_write( buf, mem_box(0x1236) ); buf_clear( buf ); CHECK( buf->reads == 0 ); diff --git a/tests/test_exn.c b/tests/test_exn.c index fba5d48..ea3304b 100644 --- a/tests/test_exn.c +++ b/tests/test_exn.c @@ -5,7 +5,16 @@ // File To Test #include "exn.h" -static void test_setup(void) { } +static int Exit_Status = 0; +void test_exit(int status) { + Exit_Status = status; + if (NULL != exn_handler()) + exn_handler()->state = EXN_DONE; +} + +static void test_setup(void) { + Exit_Status = 0; +} //----------------------------------------------------------------------------- // Begin Unit Tests @@ -114,4 +123,22 @@ TEST_SUITE(Exn) { catch(AssertionException) { counter--; } CHECK(counter == -1); } + + //------------------------------------------------------------------------- + // Test extraordinary conditions + //------------------------------------------------------------------------- + TEST(Verify_an_uncaught_exception_terminates_the_program) + { + throw(AssertionException); + CHECK( Exit_Status == 1 ); + } + + TEST(Verify_an_invalid_exception_state_terminates_the_program) + { + try { + exn_handler()->state = EXN_DONE+1; + exn_process(); + } + CHECK( Exit_Status == 1 ); + } } diff --git a/tests/test_mem.c b/tests/test_mem.c new file mode 100644 index 0000000..9bc92e6 --- /dev/null +++ b/tests/test_mem.c @@ -0,0 +1,20 @@ +// Unit Test Framework Includes +#include "test.h" + +// File To Test +#include "mem.h" + +static void test_setup(void) { } + +//----------------------------------------------------------------------------- +// Begin Unit Tests +//----------------------------------------------------------------------------- +TEST_SUITE(Mem) { + TEST(Verify_mem_can_summarize_leaks) + { + void* p_obj = mem_allocate(sizeof(4),NULL); + extern void summarize_leaks(void); + summarize_leaks(); + mem_release( p_obj ); + } +} -- 2.52.0