Fri Aug 29 10:50:46 2008 Google Inc. <opensource@google.com>
authorstewartamiles <stewartamiles@40f4469a-5155-0410-be90-2de3f0bae501>
Fri, 29 Aug 2008 17:58:06 +0000 (17:58 +0000)
committerstewartamiles <stewartamiles@40f4469a-5155-0410-be90-2de3f0bae501>
Fri, 29 Aug 2008 17:58:06 +0000 (17:58 +0000)
* cmockery: version 0.11
* Made it possible to specify executable, library and object output
  directories.

git-svn-id: http://cmockery.googlecode.com/svn/trunk@5 40f4469a-5155-0410-be90-2de3f0bae501

ChangeLog
configure
configure.ac
src/cmockery.c
windows/makefile

index 37b1921b33c10271171d4e85db9adafc41b76274..2a3b6074e9a426df18a3819eb8a1f670a06dcd67 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+Fri Aug 29 10:50:46 2008  Google Inc. <opensource@google.com>
+
+       * cmockery: version 0.11
+       * Made it possible to specify executable, library and object output 
+         directories.
+
 Tue Aug 26 10:18:02 2008  Google Inc. <opensource@google.com>
 
        * cmockery: initial release:
index 9a05aa21b74a50e1a2f976498e068b9c832c81c6..934d9d2bbfabf8da41488c038c5d5e979699fc27 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for cmockery 0.1.
+# Generated by GNU Autoconf 2.59 for cmockery 0.11.
 #
 # Report bugs to <opensource@google.com>.
 #
@@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='cmockery'
 PACKAGE_TARNAME='cmockery'
-PACKAGE_VERSION='0.1'
-PACKAGE_STRING='cmockery 0.1'
+PACKAGE_VERSION='0.11'
+PACKAGE_STRING='cmockery 0.11'
 PACKAGE_BUGREPORT='opensource@google.com'
 
 ac_unique_file="README"
@@ -954,7 +954,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures cmockery 0.1 to adapt to many kinds of systems.
+\`configure' configures cmockery 0.11 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1020,7 +1020,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of cmockery 0.1:";;
+     short | recursive ) echo "Configuration of cmockery 0.11:";;
    esac
   cat <<\_ACEOF
 
@@ -1163,7 +1163,7 @@ fi
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-cmockery configure 0.1
+cmockery configure 0.11
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1177,7 +1177,7 @@ cat >&5 <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by cmockery $as_me 0.1, which was
+It was created by cmockery $as_me 0.11, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1823,7 +1823,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='cmockery'
- VERSION='0.1'
+ VERSION='0.11'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -22247,7 +22247,7 @@ _ASBOX
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by cmockery $as_me 0.1, which was
+This file was extended by cmockery $as_me 0.11, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -22310,7 +22310,7 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-cmockery config.status 0.1
+cmockery config.status 0.11
 configured by $0, generated by GNU Autoconf 2.59,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
index 32667f4a5cf835cfe38c0ce5997ccd100411b2d8..b5fee28cb4fe8c3a4404af5a811942c7d14b352d 100644 (file)
@@ -9,7 +9,7 @@
 # make sure we're interpreted by some minimal autoconf
 AC_PREREQ(2.57)
 
-AC_INIT(cmockery, 0.1, opensource@google.com)
+AC_INIT(cmockery, 0.11, opensource@google.com)
 # The argument here is just something that should be in the current directory
 # (for sanity checking)
 AC_CONFIG_SRCDIR(README)
index 9d25a1599fb39145a13ef4ca23ee619dce59b8eb..0287a4691e11be521af08aec1e7cfcb6d9feb27e 100755 (executable)
-/*\r
- * Copyright 2008 Google Inc.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-#include <malloc.h>\r
-#include <setjmp.h>\r
-#ifndef _WIN32\r
-#include <signal.h>\r
-#endif // !_WIN32\r
-#include <stdarg.h>\r
-#include <stddef.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#ifdef _WIN32\r
-#include <windows.h>\r
-#endif // _WIN32\r
-#include <cmockery.h>\r
-\r
-#ifdef _WIN32\r
-#define vsnprintf _vsnprintf\r
-#endif // _WIN32\r
-\r
-// Size of guard bytes around dynamically allocated blocks.\r
-#define MALLOC_GUARD_SIZE 16\r
-// Pattern used to initialize guard blocks.\r
-#define MALLOC_GUARD_PATTERN 0xEF\r
-// Pattern used to initialize memory allocated with test_malloc().\r
-#define MALLOC_ALLOC_PATTERN 0xBA\r
-#define MALLOC_FREE_PATTERN 0xCD\r
-// Alignment of allocated blocks.  NOTE: This must be base2.\r
-#define MALLOC_ALIGNMENT sizeof(size_t)\r
-\r
-// Printf formatting for source code locations.\r
-#define SOURCE_LOCATION_FORMAT "%s:%d"\r
-\r
-// Calculates the number of elements in an array.\r
-#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))\r
-\r
-// Doubly linked list node.\r
-typedef struct ListNode {\r
-       const void *value;\r
-       int refcount;\r
-       struct ListNode *next;\r
-       struct ListNode *prev;\r
-} ListNode;\r
-\r
-// Debug information for malloc().\r
-typedef struct MallocBlockInfo {\r
-       void* block;              // Address of the block returned by malloc().\r
-       size_t allocated_size;    // Total size of the allocated block.\r
-       size_t size;              // Request block size.\r
-       SourceLocation location;  // Where the block was allocated.\r
-       ListNode node;            // Node within list of all allocated blocks.\r
-} MallocBlockInfo;\r
-\r
-// State of each test.\r
-typedef struct TestState {\r
-       const ListNode *check_point; // Check point of the test if there's a \r
-                                    // setup function.\r
-       void *state;                 // State associated with the test.\r
-} TestState;\r
-\r
-// Determines whether two values are the same.\r
-typedef int (*EqualityFunction)(const void *left, const void *right);\r
-\r
-// Value of a symbol and the place it was declared.\r
-typedef struct SymbolValue {\r
-       SourceLocation location;\r
-       const void* value;\r
-} SymbolValue;\r
-\r
-/* Contains a list of values for a symbol.\r
- * NOTE: Each structure referenced by symbol_values_list_head must have a \r
- * SourceLocation as its' first member.\r
- */\r
-typedef struct SymbolMapValue {\r
-       const char *symbol_name;\r
-       ListNode symbol_values_list_head;\r
-} SymbolMapValue;\r
-\r
-// Used by list_free() to deallocate values referenced by list nodes.\r
-typedef void (*CleanupListValue)(const void *value, void *cleanup_value_data);\r
-\r
-// Structure used to check the range of integer types.\r
-typedef struct CheckIntegerRange {\r
-       CheckParameterEvent event;\r
-       int minimum;\r
-       int maximum;\r
-} CheckIntegerRange;\r
-\r
-// Structure used to check whether an integer value is in a set.\r
-typedef struct CheckIntegerSet {\r
-       CheckParameterEvent event;\r
-       const void **set;\r
-       size_t size_of_set;\r
-} CheckIntegerSet;\r
-\r
-/* Used to check whether a parameter matches the area of memory referenced by \r
- * this structure.  */\r
-typedef struct CheckMemoryData {\r
-       CheckParameterEvent event;\r
-       const void *memory;\r
-       size_t size;\r
-} CheckMemoryData;\r
-\r
-static ListNode* list_initialize(ListNode * const node);\r
-static ListNode* list_add(ListNode * const head, ListNode *new_node);\r
-static ListNode* list_add_value(ListNode * const head, const void *value,\r
-                                     const int count);\r
-static ListNode* list_remove(\r
-    ListNode * const node, const CleanupListValue cleanup_value,\r
-    void * const cleanup_value_data);\r
-static void list_remove_free(\r
-    ListNode * const node, const CleanupListValue cleanup_value,\r
-    void * const cleanup_value_data);\r
-static int list_empty(const ListNode * const head);\r
-static int list_find(\r
-    ListNode * const head, const void *value,\r
-    const EqualityFunction equal_func, ListNode **output);\r
-static int list_first(ListNode * const head, ListNode **output);\r
-static ListNode* list_free(\r
-    ListNode * const head, const CleanupListValue cleanup_value, \r
-    void * const cleanup_value_data);\r
-\r
-static void add_symbol_value(\r
-    ListNode * const symbol_map_head, const char * const symbol_names[], \r
-    const size_t number_of_symbol_names, const void* value, const int count);\r
-static int get_symbol_value(\r
-    ListNode * const symbol_map_head, const char * const symbol_names[], \r
-    const size_t number_of_symbol_names, void **output);\r
-static void free_value(const void *value, void *cleanup_value_data);\r
-static void free_symbol_map_value(\r
-    const void *value, void *cleanup_value_data);\r
-static void remove_always_return_values(ListNode * const map_head,\r
-                                        const size_t number_of_symbol_names);\r
-static int check_for_leftover_values(\r
-    const ListNode * const map_head, const char * const error_message,\r
-    const size_t number_of_symbol_names);\r
-// This must be called at the beginning of a test to initialize some data\r
-// structures.\r
-static void initialize_testing(const char *test_name);\r
-// This must be called at the end of a test to free() allocated structures.\r
-static void teardown_testing(const char *test_name);\r
-\r
-\r
-// Keeps track of the calling context returned by setenv() so that the fail()\r
-// method can jump out of a test.\r
-static jmp_buf global_run_test_env;\r
-static int global_running_test = 0;\r
-\r
-// Keeps track of the calling context returned by setenv() so that\r
-// mock_assert() can optionally jump back to expect_assert_failure().\r
-jmp_buf global_expect_assert_env;\r
-int global_expecting_assert = 0;\r
-\r
-// Keeps a map of the values that functions will have to return to provide\r
-// mocked interfaces.\r
-static ListNode global_function_result_map_head;\r
-// Location of the last mock value returned was declared.\r
-static SourceLocation global_last_mock_value_location;\r
-\r
-/* Keeps a map of the values that functions expect as parameters to their \r
- * mocked interfaces. */\r
-static ListNode global_function_parameter_map_head;\r
-// Location of last parameter value checked was declared.\r
-static SourceLocation global_last_parameter_location;\r
-\r
-// List of all currently allocated blocks.\r
-static ListNode global_allocated_blocks;\r
-\r
-#ifndef _WIN32\r
-// Signals caught by exception_handler().\r
-static const int exception_signals[] = {\r
-       SIGFPE,\r
-       SIGILL,\r
-       SIGSEGV,\r
-       SIGBUS,\r
-       SIGSYS,\r
-};\r
-\r
-// Default signal functions that should be restored after a test is complete.\r
-typedef void (*SignalFunction)(int signal);\r
-static SignalFunction default_signal_functions[\r
-    ARRAY_LENGTH(exception_signals)];\r
-\r
-#else // _WIN32\r
-\r
-// The default exception filter.\r
-static LPTOP_LEVEL_EXCEPTION_FILTER previous_exception_filter;\r
-\r
-// Fatal exceptions.\r
-typedef struct ExceptionCodeInfo {\r
-       DWORD code;\r
-       const char* description;\r
-} ExceptionCodeInfo;\r
-\r
-#define EXCEPTION_CODE_INFO(exception_code) {exception_code, #exception_code}\r
-\r
-static const ExceptionCodeInfo exception_codes[] = {\r
-       EXCEPTION_CODE_INFO(EXCEPTION_ACCESS_VIOLATION),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_ARRAY_BOUNDS_EXCEEDED),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_DATATYPE_MISALIGNMENT),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_FLT_DENORMAL_OPERAND),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_FLT_DIVIDE_BY_ZERO),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_FLT_INEXACT_RESULT),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_FLT_INVALID_OPERATION),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_FLT_OVERFLOW),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_FLT_STACK_CHECK),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_FLT_UNDERFLOW),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_GUARD_PAGE),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_ILLEGAL_INSTRUCTION),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_INT_DIVIDE_BY_ZERO),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_INT_OVERFLOW),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_INVALID_DISPOSITION),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_INVALID_HANDLE),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_IN_PAGE_ERROR),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_NONCONTINUABLE_EXCEPTION),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_PRIV_INSTRUCTION),\r
-       EXCEPTION_CODE_INFO(EXCEPTION_STACK_OVERFLOW),\r
-};\r
-#endif // !_WIN32\r
-\r
-\r
-// Exit the currently executing test.\r
-static void exit_test(const int quit_application) {\r
-       if (global_running_test) {\r
-               longjmp(global_run_test_env, 1);\r
-       } else if (quit_application) {\r
-               exit(-1);\r
-       }\r
-}\r
-\r
-\r
-// Initialize a SourceLocation structure.\r
-static void initialize_source_location(SourceLocation * const location) {\r
-       assert_true(location);\r
-       location->file = NULL;\r
-       location->line = 0;\r
-}\r
-\r
-\r
-// Determine whether a source location is currently set.\r
-static int source_location_is_set(const SourceLocation * const location) {\r
-       assert_true(location);\r
-       return location->file && location->line;\r
-}\r
-\r
-\r
-// Set a source location.\r
-static void set_source_location(\r
-    SourceLocation * const location, const char * const file, \r
-    const int line) {\r
-       assert_true(location);\r
-       location->file = file;\r
-       location->line = line;\r
-}\r
-\r
-\r
-// Create function results and expected parameter lists.\r
-void initialize_testing(const char *test_name) {\r
-       list_initialize(&global_function_result_map_head);\r
-       initialize_source_location(&global_last_mock_value_location);\r
-       list_initialize(&global_function_parameter_map_head);\r
-       initialize_source_location(&global_last_parameter_location);\r
-}\r
-\r
-\r
-void fail_if_leftover_values(const char *test_name) {\r
-       int error_occurred = 0;\r
-       remove_always_return_values(&global_function_result_map_head, 1);\r
-       if (check_for_leftover_values(\r
-               &global_function_result_map_head,\r
-               "%s() has remaining non-returned values.\n", 1)) {\r
-               error_occurred = 1;\r
-       }\r
-\r
-       remove_always_return_values(&global_function_parameter_map_head, 2);\r
-       if (check_for_leftover_values(\r
-               &global_function_parameter_map_head,\r
-               "%s parameter still has values that haven't been checked.\n", 2)) {\r
-               error_occurred = 1;\r
-       }\r
-       if (error_occurred) {\r
-               exit_test(1);\r
-       }\r
-}\r
-\r
-\r
-void teardown_testing(const char *test_name) {\r
-       list_free(&global_function_result_map_head, free_symbol_map_value, \r
-                 (void*)0);\r
-       initialize_source_location(&global_last_mock_value_location);\r
-       list_free(&global_function_parameter_map_head, free_symbol_map_value,\r
-                 (void*)1);\r
-       initialize_source_location(&global_last_parameter_location);\r
-}\r
-\r
-// Initialize a list node.\r
-static ListNode* list_initialize(ListNode * const node) {\r
-       node->value = NULL;\r
-       node->next = node;\r
-       node->prev = node;\r
-       node->refcount = 1;\r
-       return node;\r
-}\r
-\r
-\r
-/* Adds a value at the tail of a given list. \r
- * The node referencing the value is allocated from the heap. */\r
-static ListNode* list_add_value(ListNode * const head, const void *value,\r
-                                     const int refcount) {\r
-       ListNode * const new_node = (ListNode*)malloc(sizeof(ListNode));\r
-       assert_true(head);\r
-       assert_true(value);\r
-       new_node->value = value;\r
-       new_node->refcount = refcount;\r
-       return list_add(head, new_node);\r
-}\r
-\r
-\r
-// Add new_node to the end of the list.\r
-static ListNode* list_add(ListNode * const head, ListNode *new_node) {\r
-       assert_true(head);\r
-       assert_true(new_node);\r
-       new_node->next = head;\r
-       new_node->prev = head->prev;\r
-       head->prev->next = new_node;\r
-       head->prev = new_node;\r
-       return new_node;\r
-}\r
-\r
-\r
-// Remove a node from a list.\r
-static ListNode* list_remove(\r
-        ListNode * const node, const CleanupListValue cleanup_value,\r
-        void * const cleanup_value_data) {\r
-       assert_true(node);\r
-       node->prev->next = node->next;\r
-       node->next->prev = node->prev;\r
-       if (cleanup_value) {\r
-               cleanup_value(node->value, cleanup_value_data);\r
-       }\r
-       return node;\r
-}\r
-\r
-\r
-/* Remove a list node from a list and free the node. */\r
-static void list_remove_free(\r
-        ListNode * const node, const CleanupListValue cleanup_value,\r
-        void * const cleanup_value_data) {\r
-       assert_true(node);\r
-       free(list_remove(node, cleanup_value, cleanup_value_data));\r
-}\r
-\r
-\r
-/* Frees memory kept by a linked list\r
- * The cleanup_value function is called for every "value" field of nodes in the\r
- * list, except for the head.  In addition to each list value, \r
- * cleanup_value_data is passed to each call to cleanup_value.  The head\r
- * of the list is not deallocated.\r
- */\r
-static ListNode* list_free(\r
-        ListNode * const head, const CleanupListValue cleanup_value, \r
-        void * const cleanup_value_data) {\r
-       assert_true(head);\r
-       while (!list_empty(head)) {\r
-               list_remove_free(head->next, cleanup_value, cleanup_value_data);\r
-       }\r
-       return head;\r
-}\r
-\r
-\r
-// Determine whether a list is empty.\r
-static int list_empty(const ListNode * const head) {\r
-       assert_true(head);\r
-       return head->next == head;\r
-}\r
-\r
-\r
-/* Find a value in the list using the equal_func to compare each node with the\r
- * value. \r
- */\r
-static int list_find(ListNode * const head, const void *value, \r
-                     const EqualityFunction equal_func, ListNode **output) {\r
-       ListNode *current;\r
-       assert_true(head);\r
-       for (current = head->next; current != head; current = current->next) {\r
-               if (equal_func(current->value, value)) {\r
-                       *output = current;\r
-                       return 1;\r
-               }\r
-       }\r
-       return 0;\r
-}\r
-\r
-// Returns the first node of a list\r
-static int list_first(ListNode * const head, ListNode **output) {\r
-       ListNode *target_node;\r
-       assert_true(head);\r
-       if (list_empty(head)) {\r
-               return 0;\r
-       }\r
-       target_node = head->next;\r
-       *output = target_node;\r
-       return 1;\r
-}\r
-\r
-\r
-// Deallocate a value referenced by a list.\r
-static void free_value(const void *value, void *cleanup_value_data) {\r
-       assert_true(value);\r
-       free((void*)value);\r
-}\r
-\r
-\r
-// Releases memory associated to a symbol_map_value.\r
-static void free_symbol_map_value(const void *value, \r
-                                  void *cleanup_value_data) {\r
-       SymbolMapValue * const map_value = (SymbolMapValue*)value;\r
-       const unsigned int children = (unsigned int)cleanup_value_data;\r
-       assert_true(value);\r
-       list_free(&map_value->symbol_values_list_head, \r
-                 children ? free_symbol_map_value : free_value, \r
-                 (void*)(children - 1));\r
-       free(map_value);\r
-}\r
-\r
-\r
-/* Determine whether a symbol name referenced by a symbol_map_value\r
- * matches the specified function name. */\r
-static int symbol_names_match(const void *map_value, const void *symbol) {\r
-       return !strcmp(((SymbolMapValue*)map_value)->symbol_name, \r
-                   (const char*)symbol);\r
-}\r
-\r
-\r
-/* Adds a value to the queue of values associated with the given\r
- * hierarchy of symbols.  It's assumed value is allocated from the heap.\r
- */\r
-static void add_symbol_value(ListNode * const symbol_map_head,\r
-                             const char * const symbol_names[],\r
-                             const size_t number_of_symbol_names,\r
-                             const void* value, const int refcount) {\r
-       const char* symbol_name;\r
-       ListNode *target_node;\r
-       SymbolMapValue *target_map_value;\r
-       assert_true(symbol_map_head);\r
-       assert_true(symbol_names);\r
-       assert_true(number_of_symbol_names);\r
-       symbol_name = symbol_names[0];\r
-\r
-       if (!list_find(symbol_map_head, symbol_name, symbol_names_match, \r
-                      &target_node)) {\r
-               SymbolMapValue * const new_symbol_map_value =\r
-                   malloc(sizeof(*new_symbol_map_value));\r
-               new_symbol_map_value->symbol_name = symbol_name;\r
-               list_initialize(&new_symbol_map_value->symbol_values_list_head);\r
-               target_node = list_add_value(symbol_map_head, new_symbol_map_value,\r
-                                                 1);\r
-       }\r
-\r
-       target_map_value = (SymbolMapValue*)target_node->value;\r
-       if (number_of_symbol_names == 1) {\r
-                       list_add_value(&target_map_value->symbol_values_list_head,\r
-                                           value, refcount);\r
-       } else {\r
-               add_symbol_value(&target_map_value->symbol_values_list_head,\r
-                                &symbol_names[1], number_of_symbol_names - 1, value,\r
-                                refcount);\r
-       }\r
-}\r
-\r
-\r
-/* Gets the next value associated with the given hierarchy of symbols. \r
- * The value is returned as an output parameter with the function returning the\r
- * node's old refcount value if a value is found, 0 otherwise.\r
- * This means that a return value of 1 indicates the node was just removed from\r
- * the list.\r
- */\r
-static int get_symbol_value(\r
-        ListNode * const head, const char * const symbol_names[], \r
-        const size_t number_of_symbol_names, void **output) {\r
-       const char* symbol_name;\r
-       ListNode *target_node;\r
-       assert_true(head);\r
-       assert_true(symbol_names);\r
-       assert_true(number_of_symbol_names);\r
-       assert_true(output);\r
-       symbol_name = symbol_names[0];\r
-\r
-       if (list_find(head, symbol_name, symbol_names_match, &target_node)) {\r
-               SymbolMapValue *map_value;\r
-               ListNode *child_list;\r
-               int return_value = 0;\r
-               assert_true(target_node);\r
-               assert_true(target_node->value);\r
-\r
-               map_value = (SymbolMapValue*)target_node->value;\r
-               child_list = &map_value->symbol_values_list_head;\r
-\r
-               if (number_of_symbol_names == 1) {\r
-                       ListNode *value_node = NULL;\r
-                       return_value = list_first(child_list, &value_node);\r
-                       assert_true(return_value);\r
-                       *output = (void*) value_node->value;\r
-                       return_value = value_node->refcount;\r
-                       if (--value_node->refcount == 0) {\r
-                               list_remove_free(value_node, NULL, NULL);\r
-                       }\r
-               } else {\r
-                       return_value = get_symbol_value(\r
-                           child_list, &symbol_names[1], number_of_symbol_names - 1, \r
-                           output);\r
-               }\r
-               if (list_empty(child_list)) {\r
-                       list_remove_free(target_node, free_symbol_map_value, (void*)0);\r
-               }\r
-               return return_value;\r
-       } else {\r
-               print_error("No entries for symbol %s.\n", symbol_name);\r
-       }\r
-       return 0;\r
-}\r
-\r
-\r
-/* Traverse down a tree of symbol values and remove the first symbol value\r
- * in each branch that has a refcount < -1 (i.e should always be returned\r
- * and has been returned at least once).\r
- */\r
-static void remove_always_return_values(ListNode * const map_head,\r
-                                        const size_t number_of_symbol_names) {\r
-       ListNode *current;\r
-       assert_true(map_head);\r
-       assert_true(number_of_symbol_names);\r
-       current = map_head->next;\r
-       while (current != map_head) {\r
-               SymbolMapValue * const value = (SymbolMapValue*)current->value;\r
-               ListNode * const next = current->next;\r
-               ListNode *child_list;\r
-               assert_true(value);\r
-               child_list = &value->symbol_values_list_head;\r
-\r
-               if (!list_empty(child_list)) {\r
-                       if (number_of_symbol_names == 1) {\r
-                               ListNode * const child_node = child_list->next;\r
-                               // If this item has been returned more than once, free it.\r
-                               if (child_node->refcount < -1) {\r
-                                       list_remove_free(child_node, free_value, NULL);\r
-                               }\r
-                       } else {\r
-                               remove_always_return_values(child_list,\r
-                                                           number_of_symbol_names - 1);\r
-                       }\r
-               }\r
-\r
-               if (list_empty(child_list)) {\r
-                       list_remove_free(current, free_value, NULL);\r
-               }\r
-               current = next;\r
-       }\r
-}\r
-\r
-/* Checks if there are any leftover values set up by the test that were never\r
- * retrieved through execution, and fail the test if that is the case.\r
- */\r
-static int check_for_leftover_values(\r
-        const ListNode * const map_head, const char * const error_message,\r
-        const size_t number_of_symbol_names) {\r
-       const ListNode *current;\r
-       int symbols_with_leftover_values = 0;\r
-       assert_true(map_head);\r
-       assert_true(number_of_symbol_names);\r
-\r
-       for (current = map_head->next; current != map_head; \r
-            current = current->next) {\r
-               const SymbolMapValue * const value = \r
-                   (SymbolMapValue*)current->value;\r
-               const ListNode *child_list;\r
-               assert_true(value);\r
-               child_list = &value->symbol_values_list_head;\r
-\r
-               if (!list_empty(child_list)) {\r
-                       if (number_of_symbol_names == 1) {\r
-                               const ListNode *child_node;\r
-                               print_error(error_message, value->symbol_name);\r
-                               print_error("  Remaining item(s) declared at...\n");\r
-\r
-                               for (child_node = child_list->next; child_node != child_list;\r
-                                    child_node = child_node->next) {\r
-                                       const SourceLocation * const location = child_node->value;\r
-                                       print_error("    " SOURCE_LOCATION_FORMAT "\n",\r
-                                                   location->file, location->line);\r
-                               }\r
-                       } else {\r
-                               print_error("%s.", value->symbol_name);\r
-                               check_for_leftover_values(child_list, error_message,\r
-                                                         number_of_symbol_names - 1);\r
-                       }\r
-                       symbols_with_leftover_values ++;\r
-               }\r
-       }\r
-       return symbols_with_leftover_values;\r
-}\r
-\r
-\r
-// Get the next return value for the specified mock function.\r
-void* _mock(const char * const function, const char* const file, \r
-            const int line) {\r
-       void *result;\r
-       const int rc = get_symbol_value(&global_function_result_map_head, \r
-                                       &function, 1, &result);\r
-       if (rc) {\r
-               SymbolValue * const symbol = result;\r
-               void * const value = (void*)symbol->value;\r
-               global_last_mock_value_location = symbol->location;\r
-               if (rc == 1) {\r
-                       free(symbol);\r
-               }\r
-               return value;\r
-       } else {\r
-               print_error("ERROR: " SOURCE_LOCATION_FORMAT " - Could not get value "\r
-                           "to mock function %s\n", file, line, function);\r
-               if (source_location_is_set(&global_last_mock_value_location)) {\r
-                       print_error("Previously returned mock value was declared at "\r
-                                   SOURCE_LOCATION_FORMAT "\n", \r
-                                   global_last_mock_value_location.file, \r
-                                   global_last_mock_value_location.line);\r
-               } else {\r
-                       print_error("There were no previously returned mock values for "\r
-                                   "this test.\n");\r
-               }\r
-               exit_test(1);\r
-       }\r
-       return NULL;\r
-}\r
-\r
-\r
-// Add a return value for the specified mock function name.\r
-void _will_return(const char * const function_name, const char * const file, \r
-                  const int line, const void* const value, const int count) {\r
-       SymbolValue * const return_value = malloc(sizeof(*return_value));\r
-       assert_true(count > 0);\r
-       return_value->value = value;\r
-       set_source_location(&return_value->location, file, line);\r
-       add_symbol_value(&global_function_result_map_head, &function_name, 1,\r
-                        return_value, count);\r
-}\r
-\r
-\r
-/* Add a custom parameter checking function.  If the event parameter is NULL\r
- * the event structure is allocated internally by this function.  If event\r
- * parameter is provided it must be allocated on the heap and doesn't need to\r
- * be deallocated by the caller.\r
- */\r
-void _expect_check(\r
-        const char* const function, const char* const parameter, \r
-        const char* const file, const int line,\r
-        const CheckParameterValue check_function, void * const check_data,\r
-        CheckParameterEvent * const event, const int count) {\r
-       CheckParameterEvent * const check = \r
-           event ? event : malloc(sizeof(*check));\r
-       const char* symbols[] = {function, parameter};\r
-       check->parameter_name = parameter;\r
-       check->check_value = check_function;\r
-       check->check_value_data = check_data;\r
-       set_source_location(&check->location, file, line); \r
-       add_symbol_value(&global_function_parameter_map_head, symbols, 2, check,\r
-                        count);\r
-}\r
-\r
-\r
-/* Returns 1 if the specified values are equal.  If the values are not equal\r
- * an error is displayed and 0 is returned. */\r
-static int values_equal_display_error(const void* const left,\r
-                                      const void* const right) {\r
-       const int equal = left == right;\r
-       if (!equal) {\r
-               print_error("0x%x != 0x%x\n", left, right);\r
-       }\r
-       return equal;\r
-}\r
-\r
-/* Returns 1 if the specified values are not equal.  If the values are equal\r
- * an error is displayed and 0 is returned. */\r
-static int values_not_equal_display_error(const void* const left,\r
-                                          const void* const right) {\r
-       const int not_equal = left != right;\r
-       if (!not_equal) {\r
-               print_error("0x%x == 0x%x\n", left, right);\r
-       }\r
-       return not_equal;\r
-}\r
-\r
-\r
-/* Determine whether value is contained within check_integer_set.\r
- * If invert is 0 and the value is in the set 1 is returned, otherwise 0 is\r
- * returned and an error is displayed.  If invert is 1 and the value is not \r
- * in the set 1 is returned, otherwise 0 is returned and an error is \r
- * displayed. */\r
-static int value_in_set_display_error(\r
-        const void *value, const CheckIntegerSet * const check_integer_set,\r
-        const int invert) {\r
-       int succeeded = invert;\r
-       assert_true(check_integer_set);\r
-       {\r
-               const void ** const set = check_integer_set->set;\r
-               const size_t size_of_set = check_integer_set->size_of_set; \r
-               size_t i;\r
-               for (i = 0; i < size_of_set; i++) {\r
-                       if (set[i] == value) {\r
-                               if (invert) {\r
-                                       succeeded = 0;\r
-                               }\r
-                               break;\r
-                       }\r
-               }\r
-               if (succeeded) {\r
-                       return 1;\r
-               }\r
-               print_error("%d is %sin the set (", value, invert ? "" : "not ");\r
-               for (i = 0; i < size_of_set; i++) {\r
-                       print_error("%d, ", set[i]);\r
-               }\r
-               print_error(")\n");\r
-       }\r
-       return 0;\r
-}\r
-\r
-\r
-/* Determine whether a value is within the specified range.  If the value is\r
- * within the specified range 1 is returned.  If the value isn't within the \r
- * specified range an error is displayed and 0 is returned. */\r
-static int integer_in_range_display_error(\r
-        const int value, const int range_min, const int range_max) {\r
-       if (value >= range_min && value <= range_max) {\r
-               return 1;\r
-       }\r
-       print_error("%d is not within the range %d-%d\n", value, range_min, \r
-                   range_max);\r
-       return 0;\r
-}\r
-\r
-\r
-/* Determine whether a value is within the specified range.  If the value\r
- * is not within the range 1 is returned.  If the value is within the \r
- * specified range an error is displayed and zero is returned. */\r
-static int integer_not_in_range_display_error(\r
-        const int value, const int range_min, const int range_max) {\r
-       if (value < range_min || value > range_max) {\r
-               return 1;\r
-       }\r
-       print_error("%d is within the range %d-%d\n", value, range_min,\r
-                   range_max);\r
-       return 0;\r
-}\r
-\r
-\r
-/* Determine whether the specified strings are equal.  If the strings are equal\r
- * 1 is returned.  If they're not equal an error is displayed and 0 is \r
- * returned. */\r
-static int string_equal_display_error(\r
-        const char * const left, const char * const right) {\r
-       if (strcmp(left, right) == 0) {\r
-               return 1;\r
-       }\r
-       print_error("\"%s\" != \"%s\"\n", left, right);\r
-       return 0;\r
-}\r
-\r
-\r
-/* Determine whether the specified strings are equal.  If the strings are not \r
- * equal 1 is returned.  If they're not equal an error is displayed and 0 is \r
- * returned */\r
-static int string_not_equal_display_error(\r
-        const char * const left, const char * const right) {\r
-       if (strcmp(left, right) != 0) {\r
-               return 1;\r
-       }\r
-       print_error("\"%s\" == \"%s\"\n", left, right);\r
-       return 0;\r
-}\r
-\r
-\r
-/* Determine whether the specified areas of memory are equal.  If they're equal\r
- * 1 is returned otherwise an error is displayed and 0 is returned. */\r
-static int memory_equal_display_error(const char* a, const char* b,\r
-                                      const size_t size) {\r
-       int differences = 0;\r
-       size_t i;\r
-       for (i = 0; i < size; i++) {\r
-               const char l = a[i];\r
-               const char r = b[i];\r
-               if (l != r) {\r
-                       print_error("difference at offset %d 0x%02x 0x%02x\n", i, l, r);\r
-                       differences ++;\r
-               }\r
-       }\r
-       if (differences) {\r
-               print_error("%d bytes of 0x%08x and 0x%08x differ\n", differences,\r
-                           a, b);\r
-               return 0;\r
-       }\r
-       return 1;\r
-}\r
-\r
-\r
-/* Determine whether the specified areas of memory are not equal.  If they're \r
- * not equal 1 is returned otherwise an error is displayed and 0 is \r
- * returned. */\r
-static int memory_not_equal_display_error(const char* a, const char* b,\r
-                                          const size_t size) {\r
-       int same = 0;\r
-       size_t i;\r
-       for (i = 0; i < size; i++) {\r
-               const char l = a[i];\r
-               const char r = b[i];\r
-               if (l == r) {\r
-                       print_error("equal at offset %d 0x%02x 0x%02x\n", i, l, r);\r
-                       same ++;\r
-               }\r
-       }\r
-       if (same) {\r
-               print_error("%d bytes of 0x%08x and 0x%08x the same\n", same,\r
-                           a, b);\r
-               return 0;\r
-       }\r
-       return 1;\r
-}\r
-\r
-\r
-// CheckParameterValue callback to check whether a value is within a set.\r
-static int check_in_set(const void *value, void *check_value_data) {\r
-       return value_in_set_display_error(value, \r
-           (CheckIntegerSet*)check_value_data, 0);\r
-}\r
-\r
-\r
-// CheckParameterValue callback to check whether a value isn't within a set.\r
-static int check_not_in_set(const void *value, void *check_value_data) {\r
-       return value_in_set_display_error(value, \r
-           (CheckIntegerSet*)check_value_data, 1);\r
-}\r
-\r
-\r
-/* Create the callback data for check_in_set() or check_not_in_set() and \r
- * register a check event. */\r
-static void expect_set(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line, const void *values[],\r
-        const size_t number_of_values, \r
-        const CheckParameterValue check_function, const int count) {\r
-       CheckIntegerSet * const check_integer_set =\r
-           malloc(sizeof(*check_integer_set) + \r
-                  (sizeof(values[0]) * number_of_values));\r
-       void ** const set = (void**)(check_integer_set + 1);\r
-       assert_true(values);\r
-       assert_true(number_of_values);\r
-       memcpy(set, values, number_of_values * sizeof(values[0]));\r
-       check_integer_set->set = (const void**)set;\r
-       _expect_check(function, parameter, file, line, check_function,\r
-                     check_integer_set, &check_integer_set->event, count);\r
-}\r
-\r
-\r
-// Add an event to check whether a value is in a set.\r
-void _expect_in_set(\r
-        const char* const function, const char* const parameter, \r
-        const char* const file, const int line, const void *values[], \r
-        const size_t number_of_values, const int count) {\r
-       expect_set(function, parameter, file, line, values, number_of_values,\r
-                  check_in_set, count);\r
-}\r
-\r
-\r
-// Add an event to check whether a value isn't in a set.\r
-void _expect_not_in_set(\r
-        const char* const function, const char* const parameter, \r
-        const char* const file, const int line, const void *values[], \r
-        const size_t number_of_values, const int count) {\r
-       expect_set(function, parameter, file, line, values, number_of_values,\r
-                  check_not_in_set, count);\r
-}\r
-\r
-\r
-// CheckParameterValue callback to check whether a value is within a range.\r
-static int check_in_range(const void *value, void *check_value_data) {\r
-       CheckIntegerRange * const check_integer_range = check_value_data;\r
-       assert_true(check_value_data);\r
-       return integer_in_range_display_error(\r
-           (int)value, check_integer_range->minimum,\r
-           check_integer_range->maximum);\r
-}\r
-\r
-\r
-// CheckParameterValue callback to check whether a value is not within a range.\r
-static int check_not_in_range(const void *value, void *check_value_data) {\r
-       CheckIntegerRange * const check_integer_range = check_value_data;\r
-       assert_true(check_value_data);\r
-       return integer_not_in_range_display_error(\r
-           (int)value, check_integer_range->minimum,\r
-           check_integer_range->maximum);\r
-}\r
-\r
-\r
-/* Create the callback data for check_in_range() or check_not_in_range() and \r
- * register a check event. */\r
-static void expect_range(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line,\r
-        const int minimum, const int maximum,\r
-        const CheckParameterValue check_function, const int count) {\r
-       CheckIntegerRange * const check_integer_range =\r
-           malloc(sizeof(*check_integer_range));\r
-       check_integer_range->minimum = minimum;\r
-       check_integer_range->maximum = maximum;\r
-       _expect_check(function, parameter, file, line, check_function,\r
-                     check_integer_range, &check_integer_range->event, count);\r
-}\r
-\r
-\r
-// Add an event to determine whether a parameter is within a range.\r
-void _expect_in_range(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line,\r
-        const int minimum, const int maximum, const int count) {\r
-       expect_range(function, parameter, file, line, minimum, maximum,\r
-                    check_in_range, count);\r
-}\r
-\r
-\r
-// Add an event to determine whether a parameter is not within a range.\r
-void _expect_not_in_range(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line,\r
-        const int minimum, const int maximum, const int count) {\r
-       expect_range(function, parameter, file, line, minimum, maximum,\r
-                    check_not_in_range, count);\r
-}\r
-\r
-\r
-/* CheckParameterValue callback to check whether a value is equal to an \r
- * expected value. */\r
-static int check_value(const void *value, void *check_value_data) {\r
-       return values_equal_display_error(value, check_value_data);\r
-}\r
-\r
-\r
-// Add an event to check a parameter equals an expected value.\r
-void _expect_value(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line, const void* const value,\r
-        const int count) {\r
-       _expect_check(function, parameter, file, line, check_value, \r
-                     (void*)value, NULL, count);\r
-}\r
-\r
-\r
-/* CheckParameterValue callback to check whether a value is not equal to an \r
- * expected value. */\r
-static int check_not_value(const void *value, void *check_value_data) {\r
-       return values_not_equal_display_error(value, check_value_data);\r
-}\r
-\r
-\r
-// Add an event to check a parameter is not equal to an expected value.\r
-void _expect_not_value(\r
-        const char* const function, const char* const parameter, \r
-        const char* const file, const int line, const void* const value,\r
-        const int count) {\r
-       _expect_check(function, parameter, file, line, check_not_value,\r
-                     (void*)value, NULL, count);\r
-}\r
-\r
-\r
-// CheckParameterValue callback to check whether a parameter equals a string.\r
-static int check_string(const void * value, void *check_value_data) {\r
-       return string_equal_display_error(value, check_value_data);\r
-}\r
-\r
-\r
-// Add an event to check whether a parameter is equal to a string.\r
-void _expect_string(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line, const char* string,\r
-        const int count) {\r
-       _expect_check(function, parameter, file, line, check_string, (void*)string,\r
-                     NULL, count);\r
-}\r
-\r
-\r
-/* CheckParameterValue callback to check whether a parameter is not equals to \r
- * a string. */\r
-static int check_not_string(const void * value, void *check_value_data) {\r
-       return string_not_equal_display_error(value, check_value_data);\r
-}\r
-\r
-\r
-// Add an event to check whether a parameter is not equal to a string.\r
-void _expect_not_string(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line, const char* string,\r
-        const int count) {\r
-       _expect_check(function, parameter, file, line, check_not_string,\r
-                     (void*)string, NULL, count);\r
-}\r
-\r
-/* CheckParameterValue callback to check whether a parameter equals an area of\r
- * memory. */\r
-static int check_memory(const void* value, void *check_value_data) {\r
-       CheckMemoryData * const check = (CheckMemoryData*)check_value_data;\r
-       assert_true(check);\r
-       return memory_equal_display_error(value, check->memory, check->size);\r
-}\r
-\r
-\r
-/* Create the callback data for check_memory() or check_not_memory() and \r
- * register a check event. */\r
-static void expect_memory_setup(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line,\r
-        const void * const memory, const size_t size,\r
-        const CheckParameterValue check_function, const int count) {\r
-       CheckMemoryData * const check_data = malloc(sizeof(*check_data) + size);\r
-       void * const mem = (void*)(check_data + 1);\r
-       assert_true(memory);\r
-       assert_true(size);\r
-       memcpy(mem, memory, size);\r
-       check_data->memory = mem;\r
-       check_data->size = size;\r
-       _expect_check(function, parameter, file, line, check_function,\r
-                     check_data, &check_data->event, count);\r
-}\r
-\r
-\r
-// Add an event to check whether a parameter matches an area of memory.\r
-void _expect_memory(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line, const void* const memory,\r
-        const size_t size, const int count) {\r
-       expect_memory_setup(function, parameter, file, line, memory, size,\r
-                           check_memory, count);\r
-}\r
-\r
-\r
-/* CheckParameterValue callback to check whether a parameter is not equal to\r
- * an area of memory. */\r
-static int check_not_memory(const void* value, void *check_value_data) {\r
-       CheckMemoryData * const check = (CheckMemoryData*)check_value_data;\r
-       assert_true(check);\r
-       return memory_not_equal_display_error(value, check->memory, check->size);\r
-}\r
-\r
-\r
-// Add an event to check whether a parameter doesn't match an area of memory.\r
-void _expect_not_memory(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line, const void* const memory, \r
-        const size_t size, const int count) {\r
-       expect_memory_setup(function, parameter, file, line, memory, size,\r
-                           check_not_memory, count);\r
-}\r
-\r
-\r
-// CheckParameterValue callback that always returns 1.\r
-static int check_any(const void *value, void *check_value_data) {\r
-       return 1;\r
-}\r
-\r
-\r
-// Add an event to allow any value for a parameter.\r
-void _expect_any(\r
-        const char* const function, const char* const parameter,\r
-        const char* const file, const int line, const int count) {\r
-       _expect_check(function, parameter, file, line, check_any, NULL, NULL, \r
-                     count);\r
-}\r
-\r
-\r
-void _check_expected(\r
-        const char * const function_name, const char * const parameter_name,\r
-        const char* file, const int line, const void* value) {\r
-       void *result;\r
-       const char* symbols[] = {function_name, parameter_name};\r
-       const int rc = get_symbol_value(&global_function_parameter_map_head, \r
-                                       symbols, 2, &result);\r
-       if (rc) {\r
-               CheckParameterEvent * const check = (CheckParameterEvent*)result;\r
-               int check_succeeded;\r
-               global_last_parameter_location = check->location;\r
-               check_succeeded = check->check_value(value, check->check_value_data);\r
-               if (rc == 1) {\r
-                       free(check);\r
-               }\r
-               if (!check_succeeded) {\r
-                       print_error("ERROR: Check of parameter %s, function %s failed\n"\r
-                                   "Expected parameter declared at " \r
-                                   SOURCE_LOCATION_FORMAT "\n",\r
-                                   parameter_name, function_name,\r
-                                   global_last_parameter_location.file, \r
-                                   global_last_parameter_location.line);\r
-                       _fail(file, line); \r
-               }\r
-       } else {\r
-               print_error("ERROR: " SOURCE_LOCATION_FORMAT " - Could not get value "\r
-                           "to check parameter %s of function %s\n", file, line, \r
-                           parameter_name, function_name);\r
-               if (source_location_is_set(&global_last_parameter_location)) {\r
-                       print_error("Previously declared parameter value was declared at "\r
-                                   SOURCE_LOCATION_FORMAT "\n", \r
-                                   global_last_parameter_location.file, \r
-                                   global_last_parameter_location.line);\r
-               } else {\r
-                       print_error("There were no previously declared parameter values "\r
-                                   "for this test.\n");\r
-               }\r
-               exit_test(1);\r
-       }\r
-}\r
-\r
-\r
-// Replacement for assert.\r
-void mock_assert(const int result, const char* const expression, \r
-                 const char* const file, const int line) {\r
-       if (!result) {\r
-               if (global_expecting_assert) {\r
-                       longjmp(global_expect_assert_env, (int)expression);\r
-               } else {\r
-                       print_error("ASSERT: %s\n", expression);\r
-                       _fail(file, line);\r
-               }\r
-       }\r
-}\r
-\r
-\r
-void _assert_true(const int result, const char * const expression, \r
-                  const char * const file, const int line) {\r
-       if (!result) {\r
-               print_error("%s\n", expression);\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-void _assert_int_equal(const int a, const int b, const char * const file, \r
-                       const int line) {\r
-       if (!values_equal_display_error((void*)a, (void*)b)) {\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-\r
-void _assert_int_not_equal(const int a, const int b, const char * const file, \r
-                           const int line) {\r
-       if (!values_not_equal_display_error((void*)a, (void*)b)) {\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-\r
-void _assert_string_equal(const char * const a, const char * const b, \r
-                          const char * const file, const int line) {\r
-       if (!string_equal_display_error(a, b)) {\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-\r
-void _assert_string_not_equal(const char * const a, const char * const b, \r
-                              const char *file, const int line) {\r
-       if (!string_not_equal_display_error(a, b)) {\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-\r
-void _assert_memory_equal(const void * const a, const void * const b, \r
-                          const size_t size, const char* const file, \r
-                          const int line) {\r
-       if (!memory_equal_display_error((const char*)a, (const char*)b, size)) {\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-\r
-void _assert_memory_not_equal(const void * const a, const void * const b,\r
-                              const size_t size, const char* const file, \r
-                              const int line) {\r
-       if (!memory_not_equal_display_error((const char*)a, (const char*)b, \r
-                                           size)) {\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-\r
-void _assert_in_range(const int value, const int minimum, const int maximum,\r
-                      const char* const file, const int line) {\r
-       if (!integer_in_range_display_error(value, minimum, maximum)) {\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-void _assert_not_in_range(const int value, const int minimum,\r
-                          const int maximum, const char* const file, \r
-                          const int line) {\r
-       if (!integer_not_in_range_display_error(value, minimum, maximum)) {\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-void _assert_in_set(const void* const value, const void *values[],\r
-                    const size_t number_of_values, const char* const file,\r
-                    const int line) {\r
-       CheckIntegerSet check_integer_set;\r
-       check_integer_set.set = values;\r
-       check_integer_set.size_of_set = number_of_values;\r
-       if (!value_in_set_display_error(value, &check_integer_set, 0)) {\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-void _assert_not_in_set(const void* const value, const void *values[],\r
-                        const size_t number_of_values, const char* const file,\r
-                        const int line) {\r
-       CheckIntegerSet check_integer_set;\r
-       check_integer_set.set = values;\r
-       check_integer_set.size_of_set = number_of_values;\r
-       if (!value_in_set_display_error(value, &check_integer_set, 1)) {\r
-               _fail(file, line);\r
-       }\r
-}\r
-\r
-\r
-// Get the list of allocated blocks.\r
-static ListNode* get_allocated_blocks_list() {\r
-       // If it initialized, initialize the list of allocated blocks.\r
-       if (!global_allocated_blocks.value) {\r
-               list_initialize(&global_allocated_blocks);\r
-               global_allocated_blocks.value = (void*)1;\r
-       }\r
-       return &global_allocated_blocks;\r
-}\r
-\r
-// Use the real malloc in this function.\r
-#undef malloc\r
-void* _test_malloc(const size_t size, const char* file, const int line) {\r
-       char* ptr;\r
-       MallocBlockInfo *block_info;\r
-       ListNode * const block_list = get_allocated_blocks_list();\r
-       const size_t allocate_size = size + (MALLOC_GUARD_SIZE * 2) + \r
-           sizeof(*block_info) + MALLOC_ALIGNMENT;\r
-       char* const block = (char*)malloc(allocate_size);\r
-       assert_true(block);\r
-\r
-       // Calculate the returned address.\r
-       ptr = (char*)(((size_t)block + MALLOC_GUARD_SIZE + sizeof(*block_info) +\r
-                     MALLOC_ALIGNMENT) & ~(MALLOC_ALIGNMENT - 1));\r
-\r
-       // Initialize the guard blocks.\r
-       memset(ptr - MALLOC_GUARD_SIZE, MALLOC_GUARD_PATTERN, MALLOC_GUARD_SIZE);\r
-       memset(ptr + size, MALLOC_GUARD_PATTERN, MALLOC_GUARD_SIZE);\r
-       memset(ptr, MALLOC_ALLOC_PATTERN, size);\r
-\r
-       block_info = (MallocBlockInfo*)(ptr - (MALLOC_GUARD_SIZE +\r
-                                                sizeof(*block_info)));\r
-       set_source_location(&block_info->location, file, line);\r
-       block_info->allocated_size = allocate_size;\r
-       block_info->size = size;\r
-       block_info->block = block;\r
-       block_info->node.value = block_info;\r
-       list_add(block_list, &block_info->node);\r
-       return ptr;\r
-}\r
-#define malloc test_malloc\r
-\r
-\r
-void* _test_calloc(const size_t number_of_elements, const size_t size, \r
-                   const char* file, const int line) {\r
-       void* const ptr = _test_malloc(number_of_elements * size, file, line);\r
-       if (ptr) {\r
-               memset(ptr, 0, number_of_elements * size);\r
-       }\r
-       return ptr;\r
-}\r
-\r
-\r
-// Use the real free in this function.\r
-#undef free\r
-void _test_free(void* const ptr, const char* file, const int line) {\r
-       unsigned int i;\r
-       char *block = (char*)ptr;\r
-       MallocBlockInfo *block_info;\r
-       _assert_true((int)ptr, "ptr", file, line);\r
-       block_info = (MallocBlockInfo*)(block - (MALLOC_GUARD_SIZE +\r
-                                                  sizeof(*block_info)));\r
-       // Check the guard blocks.\r
-       {\r
-               char *guards[2] = {block - MALLOC_GUARD_SIZE,\r
-                                  block + block_info->size};\r
-               for (i = 0; i < ARRAY_LENGTH(guards); i++) {\r
-                       unsigned int j;\r
-                       char * const guard = guards[i];\r
-                       for (j = 0; j < MALLOC_GUARD_SIZE; j++) {\r
-                               const char diff = guard[j] - MALLOC_GUARD_PATTERN;\r
-                               if (diff) {\r
-                                       print_error(\r
-                                           "Guard block of 0x%08x size=%d allocated by "\r
-                                           SOURCE_LOCATION_FORMAT " at 0x%08x is corrupt\n", \r
-                                           (size_t)ptr, block_info->size,\r
-                                           block_info->location.file, block_info->location.line, \r
-                                           (size_t)&guard[j]);\r
-                                       _fail(file, line);\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       list_remove(&block_info->node, NULL, NULL);\r
-\r
-       block = block_info->block;\r
-       memset(block, MALLOC_FREE_PATTERN, block_info->allocated_size);\r
-       free(block);\r
-}\r
-#define free test_free\r
-\r
-\r
-// Crudely checkpoint the current heap state.\r
-static const ListNode* check_point_allocated_blocks() {\r
-       return get_allocated_blocks_list()->prev;\r
-}\r
-\r
-\r
-/* Display the blocks allocated after the specified check point.  This\r
- * function returns the number of blocks displayed. */\r
-static int display_allocated_blocks(const ListNode * const check_point) {\r
-       const ListNode * const head = get_allocated_blocks_list();\r
-       const ListNode *node;\r
-       int allocated_blocks = 0;\r
-       assert_true(check_point);\r
-       assert_true(check_point->next);\r
-\r
-       for (node = check_point->next; node != head; node = node->next) {\r
-               const MallocBlockInfo * const block_info = node->value;\r
-               assert_true(block_info);\r
-\r
-               if (!allocated_blocks) {\r
-                       print_error("Blocks allocated...\n");\r
-               }\r
-               print_error("  0x%08x : " SOURCE_LOCATION_FORMAT "\n",\r
-                           block_info->block, block_info->location.file,\r
-                           block_info->location.line);\r
-               allocated_blocks ++;\r
-       }\r
-       return allocated_blocks;\r
-}\r
-\r
-\r
-// Free all blocks allocated after the specified check point.\r
-static void free_allocated_blocks(const ListNode * const check_point) {\r
-       const ListNode * const head = get_allocated_blocks_list();\r
-       const ListNode *node;\r
-       assert_true(check_point);\r
-\r
-       node = check_point->next;\r
-       assert_true(node);\r
-\r
-       while (node != head) {\r
-               MallocBlockInfo * const block_info = (MallocBlockInfo*)node->value;\r
-               node = node->next;\r
-               free((char*)block_info + sizeof(*block_info) + MALLOC_GUARD_SIZE);\r
-       }\r
-}\r
-\r
-\r
-// Fail if any any blocks are allocated after the specified check point.\r
-static void fail_if_blocks_allocated(const ListNode * const check_point,\r
-                                     const char * const test_name) {\r
-       const int allocated_blocks = display_allocated_blocks(check_point);\r
-       if (allocated_blocks) {\r
-               free_allocated_blocks(check_point);\r
-               print_error("ERROR: %s leaked %d block(s)\n", test_name, \r
-                           allocated_blocks);\r
-               exit_test(1);\r
-       }\r
-}\r
-\r
-\r
-void _fail(const char * const file, const int line) {\r
-       print_error("ERROR: " SOURCE_LOCATION_FORMAT " Failure!\n", file, line);\r
-       exit_test(1);\r
-}\r
-\r
-\r
-#ifndef _WIN32\r
-static void exception_handler(int sig) {\r
-       print_error("%s\n", strsignal(sig));\r
-       exit_test(1);\r
-}\r
-\r
-#else // _WIN32\r
-\r
-static LONG WINAPI exception_filter(EXCEPTION_POINTERS *exception_pointers) {\r
-       EXCEPTION_RECORD * const exception_record =\r
-           exception_pointers->ExceptionRecord;\r
-       const DWORD code = exception_record->ExceptionCode;\r
-       unsigned int i;\r
-       for (i = 0; i < ARRAY_LENGTH(exception_codes); i++) {\r
-               const ExceptionCodeInfo * const code_info = &exception_codes[i];\r
-               if (code == code_info->code) {\r
-                       static int shown_debug_message = 0;\r
-                       fflush(stdout);\r
-                       print_error("%s occurred at 0x%08x.\n", code_info->description,\r
-                                   exception_record->ExceptionAddress);\r
-                       if (!shown_debug_message) {\r
-                               print_error(\r
-                                   "\n"\r
-                                   "To debug in Visual Studio...\n"\r
-                                   "1. Select menu item File->Open Project\n"\r
-                                   "2. Change 'Files of type' to 'Executable Files'\n"\r
-                                   "3. Open this executable.\n"\r
-                                   "4. Select menu item Debug->Start\n"\r
-                                   "\n"\r
-                                   "Alternatively, set the environment variable \n"\r
-                                   "UNIT_TESTING_DEBUG to 1 and rebuild this executable, \n"\r
-                                   "then click 'Debug' in the popup dialog box.\n"\r
-                                   "\n");\r
-                               shown_debug_message = 1;\r
-                       }\r
-                       exit_test(0);\r
-                       return EXCEPTION_EXECUTE_HANDLER;\r
-               }\r
-       }\r
-       return EXCEPTION_CONTINUE_SEARCH;\r
-}\r
-#endif // !_WIN32\r
-\r
-\r
-// Standard output and error print methods.\r
-void vprint_message(const char* const format, va_list args) {\r
-       char buffer[1024];\r
-       vsnprintf(buffer, sizeof(buffer), format, args);\r
-       printf(buffer);\r
-#ifdef _WIN32\r
-       OutputDebugString(buffer);\r
-#endif // _WIN32\r
-}\r
-\r
-\r
-void vprint_error(const char* const format, va_list args) {\r
-       char buffer[1024];\r
-       vsnprintf(buffer, sizeof(buffer), format, args);\r
-       fprintf(stderr, buffer);\r
-#ifdef _WIN32\r
-       OutputDebugString(buffer);\r
-#endif // _WIN32\r
-}\r
-\r
-\r
-void print_message(const char* const format, ...) {\r
-       va_list args;\r
-       va_start(args, format);\r
-       vprint_message(format, args);\r
-       va_end(args);\r
-}\r
-\r
-\r
-void print_error(const char* const format, ...) {\r
-       va_list args;\r
-       va_start(args, format);\r
-       vprint_error(format, args);\r
-       va_end(args);\r
-}\r
-\r
-\r
-int _run_test(\r
-        const char * const function_name,  const UnitTestFunction Function, \r
-        void ** const state, const UnitTestFunctionType function_type,\r
-        const void* const heap_check_point) {\r
-       const ListNode * const check_point = heap_check_point ? \r
-           heap_check_point : check_point_allocated_blocks();\r
-       void *current_state = NULL;\r
-       int rc = 1;\r
-       int handle_exceptions = 1;\r
-#ifdef _WIN32\r
-       handle_exceptions = !IsDebuggerPresent();\r
-#endif // _WIN32\r
-#if UNIT_TESTING_DEBUG\r
-       handle_exceptions = 0;\r
-#endif // UNIT_TESTING_DEBUG\r
-\r
-       if (handle_exceptions) {\r
-#ifndef _WIN32\r
-               unsigned int i;\r
-               for (i = 0; i < ARRAY_LENGTH(exception_signals); i++) {\r
-                       default_signal_functions[i] = signal(\r
-                           exception_signals[i], exception_handler);\r
-               }\r
-#else // _WIN32\r
-               previous_exception_filter = SetUnhandledExceptionFilter(\r
-                   exception_filter);\r
-#endif // !_WIN32\r
-       }\r
-\r
-       if (function_type == UNIT_TEST_FUNCTION_TYPE_TEST) {\r
-               print_message("%s: Starting test\n", function_name);\r
-       }\r
-       initialize_testing(function_name);\r
-       global_running_test = 1;\r
-       if (setjmp(global_run_test_env) == 0) {\r
-               Function(state ? state : &current_state);\r
-               fail_if_leftover_values(function_name);\r
-\r
-               /* If this is a setup function then ignore any allocated blocks\r
-                * only ensure they're deallocated on tear down. */\r
-               if (function_type != UNIT_TEST_FUNCTION_TYPE_SETUP) {\r
-                       fail_if_blocks_allocated(check_point, function_name);\r
-               }\r
-\r
-               global_running_test = 0;\r
-\r
-               if (function_type == UNIT_TEST_FUNCTION_TYPE_TEST) {\r
-                       print_message("%s: Test completed successfully.\n", function_name);\r
-               }\r
-               rc = 0;\r
-       } else {\r
-               global_running_test = 0;\r
-               print_message("%s: Test failed.\n", function_name);\r
-       }\r
-       teardown_testing(function_name);\r
-\r
-       if (handle_exceptions) {\r
-#ifndef _WIN32\r
-               unsigned int i;\r
-               for (i = 0; i < ARRAY_LENGTH(exception_signals); i++) {\r
-                       signal(exception_signals[i], default_signal_functions[i]);\r
-               }\r
-#else // _WIN32\r
-               if (previous_exception_filter) {\r
-                       SetUnhandledExceptionFilter(previous_exception_filter);\r
-                       previous_exception_filter = NULL;\r
-               }\r
-#endif // !_WIN32\r
-       }\r
-\r
-       return rc;\r
-}\r
-\r
-\r
-int _run_tests(const UnitTest * const tests, const size_t number_of_tests) {\r
-       // Whether to execute the next test.\r
-       int run_next_test = 1;\r
-       // Whether the previous test failed.\r
-       int previous_test_failed = 0;\r
-       // Check point of the heap state.\r
-       const ListNode * const check_point = check_point_allocated_blocks();\r
-       // Current test being executed.\r
-       size_t current_test = 0;\r
-       // Number of tests executed.\r
-       size_t tests_executed = 0;\r
-       // Number of failed tests.\r
-       size_t total_failed = 0;\r
-       // Number of setup functions.\r
-       size_t setups = 0;\r
-       // Number of teardown functions.\r
-       size_t teardowns = 0;\r
-       /* A stack of test states.  A state is pushed on the stack\r
-        * when a test setup occurs and popped on tear down. */\r
-       TestState* test_states = malloc(number_of_tests * sizeof(*test_states));\r
-       size_t number_of_test_states = 0;\r
-       // Names of the tests that failed.\r
-       const char** failed_names = malloc(number_of_tests * \r
-                                          sizeof(*failed_names));\r
-       void **current_state = NULL;\r
-\r
-       while (current_test < number_of_tests) {\r
-               const ListNode *test_check_point = NULL;\r
-               TestState *current_TestState;\r
-               const UnitTest * const test = &tests[current_test++];\r
-               if (!test->function) {\r
-                       continue;\r
-               }\r
-\r
-               switch (test->function_type) {\r
-               case UNIT_TEST_FUNCTION_TYPE_TEST:\r
-                       run_next_test = 1;\r
-                       break;\r
-               case UNIT_TEST_FUNCTION_TYPE_SETUP: {\r
-                       // Checkpoint the heap before the setup.\r
-                       current_TestState = &test_states[number_of_test_states++];\r
-                       current_TestState->check_point = check_point_allocated_blocks();\r
-                       test_check_point = current_TestState->check_point;\r
-                       current_state = &current_TestState->state;\r
-                       *current_state = NULL;\r
-                       run_next_test = 1;\r
-                       setups ++;\r
-                       break;\r
-               }\r
-               case UNIT_TEST_FUNCTION_TYPE_TEARDOWN:\r
-                       // Check the heap based on the last setup checkpoint.\r
-                       assert_true(number_of_test_states);\r
-                       current_TestState = &test_states[--number_of_test_states];\r
-                       test_check_point = current_TestState->check_point;\r
-                       current_state = &current_TestState->state;\r
-                       teardowns ++;\r
-                       break;\r
-               default:\r
-                       print_error("Invalid unit test function type %d\n",\r
-                                   test->function_type);\r
-                       exit_test(1);\r
-                       break;\r
-               }\r
-\r
-               if (run_next_test) {\r
-                       int failed = _run_test(test->name, test->function, current_state,\r
-                                              test->function_type, test_check_point);\r
-                       if (failed) {\r
-                               failed_names[total_failed] = test->name;\r
-                       }\r
-\r
-                       switch (test->function_type) {\r
-                       case UNIT_TEST_FUNCTION_TYPE_TEST:\r
-                               previous_test_failed = failed;\r
-                               total_failed += failed;\r
-                               tests_executed ++;\r
-                               break;\r
-\r
-                       case UNIT_TEST_FUNCTION_TYPE_SETUP:\r
-                               if (failed) {\r
-                                       total_failed ++;\r
-                                       tests_executed ++;\r
-                                       // Skip forward until the next test or setup function.\r
-                                       run_next_test = 0;\r
-                               }\r
-                               previous_test_failed = 0;\r
-                               break;\r
-\r
-                       case UNIT_TEST_FUNCTION_TYPE_TEARDOWN:\r
-                               // If this test failed.\r
-                               if (failed && !previous_test_failed) {\r
-                                       total_failed ++;\r
-                               }\r
-                               break;\r
-                       default:\r
-                               assert_false("BUG: shouldn't be here!");\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-\r
-       if (total_failed) {\r
-               size_t i;\r
-               print_error("%d out of %d tests failed!\n", total_failed, \r
-                           tests_executed);\r
-               for (i = 0; i < total_failed; i++) {\r
-                       print_error("    %s\n", failed_names[i]);\r
-               }\r
-       } else {\r
-               print_message("All %d tests passed\n", tests_executed);\r
-       }\r
-\r
-       if (number_of_test_states) {\r
-               print_error("Mismatched number of setup %d and teardown %d "\r
-                           "functions\n", setups, teardowns);\r
-               total_failed = -1;\r
-       }\r
-\r
-       free(test_states);\r
-       free((void*)failed_names);\r
-\r
-       fail_if_blocks_allocated(check_point, "run_tests");\r
-       return total_failed;\r
-}\r
+/*
+ * Copyright 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <malloc.h>
+#include <setjmp.h>
+#ifndef _WIN32
+#include <signal.h>
+#endif // !_WIN32
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <windows.h>
+#endif // _WIN32
+#include <cmockery.h>
+
+#ifdef _WIN32
+#define vsnprintf _vsnprintf
+#endif // _WIN32
+
+// Size of guard bytes around dynamically allocated blocks.
+#define MALLOC_GUARD_SIZE 16
+// Pattern used to initialize guard blocks.
+#define MALLOC_GUARD_PATTERN 0xEF
+// Pattern used to initialize memory allocated with test_malloc().
+#define MALLOC_ALLOC_PATTERN 0xBA
+#define MALLOC_FREE_PATTERN 0xCD
+// Alignment of allocated blocks.  NOTE: This must be base2.
+#define MALLOC_ALIGNMENT sizeof(size_t)
+
+// Printf formatting for source code locations.
+#define SOURCE_LOCATION_FORMAT "%s:%d"
+
+// Calculates the number of elements in an array.
+#define ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))
+
+// Doubly linked list node.
+typedef struct ListNode {
+       const void *value;
+       int refcount;
+       struct ListNode *next;
+       struct ListNode *prev;
+} ListNode;
+
+// Debug information for malloc().
+typedef struct MallocBlockInfo {
+       void* block;              // Address of the block returned by malloc().
+       size_t allocated_size;    // Total size of the allocated block.
+       size_t size;              // Request block size.
+       SourceLocation location;  // Where the block was allocated.
+       ListNode node;            // Node within list of all allocated blocks.
+} MallocBlockInfo;
+
+// State of each test.
+typedef struct TestState {
+       const ListNode *check_point; // Check point of the test if there's a 
+                                    // setup function.
+       void *state;                 // State associated with the test.
+} TestState;
+
+// Determines whether two values are the same.
+typedef int (*EqualityFunction)(const void *left, const void *right);
+
+// Value of a symbol and the place it was declared.
+typedef struct SymbolValue {
+       SourceLocation location;
+       const void* value;
+} SymbolValue;
+
+/* Contains a list of values for a symbol.
+ * NOTE: Each structure referenced by symbol_values_list_head must have a 
+ * SourceLocation as its' first member.
+ */
+typedef struct SymbolMapValue {
+       const char *symbol_name;
+       ListNode symbol_values_list_head;
+} SymbolMapValue;
+
+// Used by list_free() to deallocate values referenced by list nodes.
+typedef void (*CleanupListValue)(const void *value, void *cleanup_value_data);
+
+// Structure used to check the range of integer types.
+typedef struct CheckIntegerRange {
+       CheckParameterEvent event;
+       int minimum;
+       int maximum;
+} CheckIntegerRange;
+
+// Structure used to check whether an integer value is in a set.
+typedef struct CheckIntegerSet {
+       CheckParameterEvent event;
+       const void **set;
+       size_t size_of_set;
+} CheckIntegerSet;
+
+/* Used to check whether a parameter matches the area of memory referenced by 
+ * this structure.  */
+typedef struct CheckMemoryData {
+       CheckParameterEvent event;
+       const void *memory;
+       size_t size;
+} CheckMemoryData;
+
+static ListNode* list_initialize(ListNode * const node);
+static ListNode* list_add(ListNode * const head, ListNode *new_node);
+static ListNode* list_add_value(ListNode * const head, const void *value,
+                                     const int count);
+static ListNode* list_remove(
+    ListNode * const node, const CleanupListValue cleanup_value,
+    void * const cleanup_value_data);
+static void list_remove_free(
+    ListNode * const node, const CleanupListValue cleanup_value,
+    void * const cleanup_value_data);
+static int list_empty(const ListNode * const head);
+static int list_find(
+    ListNode * const head, const void *value,
+    const EqualityFunction equal_func, ListNode **output);
+static int list_first(ListNode * const head, ListNode **output);
+static ListNode* list_free(
+    ListNode * const head, const CleanupListValue cleanup_value, 
+    void * const cleanup_value_data);
+
+static void add_symbol_value(
+    ListNode * const symbol_map_head, const char * const symbol_names[], 
+    const size_t number_of_symbol_names, const void* value, const int count);
+static int get_symbol_value(
+    ListNode * const symbol_map_head, const char * const symbol_names[], 
+    const size_t number_of_symbol_names, void **output);
+static void free_value(const void *value, void *cleanup_value_data);
+static void free_symbol_map_value(
+    const void *value, void *cleanup_value_data);
+static void remove_always_return_values(ListNode * const map_head,
+                                        const size_t number_of_symbol_names);
+static int check_for_leftover_values(
+    const ListNode * const map_head, const char * const error_message,
+    const size_t number_of_symbol_names);
+// This must be called at the beginning of a test to initialize some data
+// structures.
+static void initialize_testing(const char *test_name);
+// This must be called at the end of a test to free() allocated structures.
+static void teardown_testing(const char *test_name);
+
+
+// Keeps track of the calling context returned by setenv() so that the fail()
+// method can jump out of a test.
+static jmp_buf global_run_test_env;
+static int global_running_test = 0;
+
+// Keeps track of the calling context returned by setenv() so that
+// mock_assert() can optionally jump back to expect_assert_failure().
+jmp_buf global_expect_assert_env;
+int global_expecting_assert = 0;
+
+// Keeps a map of the values that functions will have to return to provide
+// mocked interfaces.
+static ListNode global_function_result_map_head;
+// Location of the last mock value returned was declared.
+static SourceLocation global_last_mock_value_location;
+
+/* Keeps a map of the values that functions expect as parameters to their 
+ * mocked interfaces. */
+static ListNode global_function_parameter_map_head;
+// Location of last parameter value checked was declared.
+static SourceLocation global_last_parameter_location;
+
+// List of all currently allocated blocks.
+static ListNode global_allocated_blocks;
+
+#ifndef _WIN32
+// Signals caught by exception_handler().
+static const int exception_signals[] = {
+       SIGFPE,
+       SIGILL,
+       SIGSEGV,
+       SIGBUS,
+       SIGSYS,
+};
+
+// Default signal functions that should be restored after a test is complete.
+typedef void (*SignalFunction)(int signal);
+static SignalFunction default_signal_functions[
+    ARRAY_LENGTH(exception_signals)];
+
+#else // _WIN32
+
+// The default exception filter.
+static LPTOP_LEVEL_EXCEPTION_FILTER previous_exception_filter;
+
+// Fatal exceptions.
+typedef struct ExceptionCodeInfo {
+       DWORD code;
+       const char* description;
+} ExceptionCodeInfo;
+
+#define EXCEPTION_CODE_INFO(exception_code) {exception_code, #exception_code}
+
+static const ExceptionCodeInfo exception_codes[] = {
+       EXCEPTION_CODE_INFO(EXCEPTION_ACCESS_VIOLATION),
+       EXCEPTION_CODE_INFO(EXCEPTION_ARRAY_BOUNDS_EXCEEDED),
+       EXCEPTION_CODE_INFO(EXCEPTION_DATATYPE_MISALIGNMENT),
+       EXCEPTION_CODE_INFO(EXCEPTION_FLT_DENORMAL_OPERAND),
+       EXCEPTION_CODE_INFO(EXCEPTION_FLT_DIVIDE_BY_ZERO),
+       EXCEPTION_CODE_INFO(EXCEPTION_FLT_INEXACT_RESULT),
+       EXCEPTION_CODE_INFO(EXCEPTION_FLT_INVALID_OPERATION),
+       EXCEPTION_CODE_INFO(EXCEPTION_FLT_OVERFLOW),
+       EXCEPTION_CODE_INFO(EXCEPTION_FLT_STACK_CHECK),
+       EXCEPTION_CODE_INFO(EXCEPTION_FLT_UNDERFLOW),
+       EXCEPTION_CODE_INFO(EXCEPTION_GUARD_PAGE),
+       EXCEPTION_CODE_INFO(EXCEPTION_ILLEGAL_INSTRUCTION),
+       EXCEPTION_CODE_INFO(EXCEPTION_INT_DIVIDE_BY_ZERO),
+       EXCEPTION_CODE_INFO(EXCEPTION_INT_OVERFLOW),
+       EXCEPTION_CODE_INFO(EXCEPTION_INVALID_DISPOSITION),
+       EXCEPTION_CODE_INFO(EXCEPTION_INVALID_HANDLE),
+       EXCEPTION_CODE_INFO(EXCEPTION_IN_PAGE_ERROR),
+       EXCEPTION_CODE_INFO(EXCEPTION_NONCONTINUABLE_EXCEPTION),
+       EXCEPTION_CODE_INFO(EXCEPTION_PRIV_INSTRUCTION),
+       EXCEPTION_CODE_INFO(EXCEPTION_STACK_OVERFLOW),
+};
+#endif // !_WIN32
+
+
+// Exit the currently executing test.
+static void exit_test(const int quit_application) {
+       if (global_running_test) {
+               longjmp(global_run_test_env, 1);
+       } else if (quit_application) {
+               exit(-1);
+       }
+}
+
+
+// Initialize a SourceLocation structure.
+static void initialize_source_location(SourceLocation * const location) {
+       assert_true(location);
+       location->file = NULL;
+       location->line = 0;
+}
+
+
+// Determine whether a source location is currently set.
+static int source_location_is_set(const SourceLocation * const location) {
+       assert_true(location);
+       return location->file && location->line;
+}
+
+
+// Set a source location.
+static void set_source_location(
+    SourceLocation * const location, const char * const file, 
+    const int line) {
+       assert_true(location);
+       location->file = file;
+       location->line = line;
+}
+
+
+// Create function results and expected parameter lists.
+void initialize_testing(const char *test_name) {
+       list_initialize(&global_function_result_map_head);
+       initialize_source_location(&global_last_mock_value_location);
+       list_initialize(&global_function_parameter_map_head);
+       initialize_source_location(&global_last_parameter_location);
+}
+
+
+void fail_if_leftover_values(const char *test_name) {
+       int error_occurred = 0;
+       remove_always_return_values(&global_function_result_map_head, 1);
+       if (check_for_leftover_values(
+               &global_function_result_map_head,
+               "%s() has remaining non-returned values.\n", 1)) {
+               error_occurred = 1;
+       }
+
+       remove_always_return_values(&global_function_parameter_map_head, 2);
+       if (check_for_leftover_values(
+               &global_function_parameter_map_head,
+               "%s parameter still has values that haven't been checked.\n", 2)) {
+               error_occurred = 1;
+       }
+       if (error_occurred) {
+               exit_test(1);
+       }
+}
+
+
+void teardown_testing(const char *test_name) {
+       list_free(&global_function_result_map_head, free_symbol_map_value, 
+                 (void*)0);
+       initialize_source_location(&global_last_mock_value_location);
+       list_free(&global_function_parameter_map_head, free_symbol_map_value,
+                 (void*)1);
+       initialize_source_location(&global_last_parameter_location);
+}
+
+// Initialize a list node.
+static ListNode* list_initialize(ListNode * const node) {
+       node->value = NULL;
+       node->next = node;
+       node->prev = node;
+       node->refcount = 1;
+       return node;
+}
+
+
+/* Adds a value at the tail of a given list. 
+ * The node referencing the value is allocated from the heap. */
+static ListNode* list_add_value(ListNode * const head, const void *value,
+                                     const int refcount) {
+       ListNode * const new_node = (ListNode*)malloc(sizeof(ListNode));
+       assert_true(head);
+       assert_true(value);
+       new_node->value = value;
+       new_node->refcount = refcount;
+       return list_add(head, new_node);
+}
+
+
+// Add new_node to the end of the list.
+static ListNode* list_add(ListNode * const head, ListNode *new_node) {
+       assert_true(head);
+       assert_true(new_node);
+       new_node->next = head;
+       new_node->prev = head->prev;
+       head->prev->next = new_node;
+       head->prev = new_node;
+       return new_node;
+}
+
+
+// Remove a node from a list.
+static ListNode* list_remove(
+        ListNode * const node, const CleanupListValue cleanup_value,
+        void * const cleanup_value_data) {
+       assert_true(node);
+       node->prev->next = node->next;
+       node->next->prev = node->prev;
+       if (cleanup_value) {
+               cleanup_value(node->value, cleanup_value_data);
+       }
+       return node;
+}
+
+
+/* Remove a list node from a list and free the node. */
+static void list_remove_free(
+        ListNode * const node, const CleanupListValue cleanup_value,
+        void * const cleanup_value_data) {
+       assert_true(node);
+       free(list_remove(node, cleanup_value, cleanup_value_data));
+}
+
+
+/* Frees memory kept by a linked list
+ * The cleanup_value function is called for every "value" field of nodes in the
+ * list, except for the head.  In addition to each list value, 
+ * cleanup_value_data is passed to each call to cleanup_value.  The head
+ * of the list is not deallocated.
+ */
+static ListNode* list_free(
+        ListNode * const head, const CleanupListValue cleanup_value, 
+        void * const cleanup_value_data) {
+       assert_true(head);
+       while (!list_empty(head)) {
+               list_remove_free(head->next, cleanup_value, cleanup_value_data);
+       }
+       return head;
+}
+
+
+// Determine whether a list is empty.
+static int list_empty(const ListNode * const head) {
+       assert_true(head);
+       return head->next == head;
+}
+
+
+/* Find a value in the list using the equal_func to compare each node with the
+ * value. 
+ */
+static int list_find(ListNode * const head, const void *value, 
+                     const EqualityFunction equal_func, ListNode **output) {
+       ListNode *current;
+       assert_true(head);
+       for (current = head->next; current != head; current = current->next) {
+               if (equal_func(current->value, value)) {
+                       *output = current;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+// Returns the first node of a list
+static int list_first(ListNode * const head, ListNode **output) {
+       ListNode *target_node;
+       assert_true(head);
+       if (list_empty(head)) {
+               return 0;
+       }
+       target_node = head->next;
+       *output = target_node;
+       return 1;
+}
+
+
+// Deallocate a value referenced by a list.
+static void free_value(const void *value, void *cleanup_value_data) {
+       assert_true(value);
+       free((void*)value);
+}
+
+
+// Releases memory associated to a symbol_map_value.
+static void free_symbol_map_value(const void *value, 
+                                  void *cleanup_value_data) {
+       SymbolMapValue * const map_value = (SymbolMapValue*)value;
+       const unsigned int children = (unsigned int)cleanup_value_data;
+       assert_true(value);
+       list_free(&map_value->symbol_values_list_head, 
+                 children ? free_symbol_map_value : free_value, 
+                 (void*)(children - 1));
+       free(map_value);
+}
+
+
+/* Determine whether a symbol name referenced by a symbol_map_value
+ * matches the specified function name. */
+static int symbol_names_match(const void *map_value, const void *symbol) {
+       return !strcmp(((SymbolMapValue*)map_value)->symbol_name, 
+                   (const char*)symbol);
+}
+
+
+/* Adds a value to the queue of values associated with the given
+ * hierarchy of symbols.  It's assumed value is allocated from the heap.
+ */
+static void add_symbol_value(ListNode * const symbol_map_head,
+                             const char * const symbol_names[],
+                             const size_t number_of_symbol_names,
+                             const void* value, const int refcount) {
+       const char* symbol_name;
+       ListNode *target_node;
+       SymbolMapValue *target_map_value;
+       assert_true(symbol_map_head);
+       assert_true(symbol_names);
+       assert_true(number_of_symbol_names);
+       symbol_name = symbol_names[0];
+
+       if (!list_find(symbol_map_head, symbol_name, symbol_names_match, 
+                      &target_node)) {
+               SymbolMapValue * const new_symbol_map_value =
+                   malloc(sizeof(*new_symbol_map_value));
+               new_symbol_map_value->symbol_name = symbol_name;
+               list_initialize(&new_symbol_map_value->symbol_values_list_head);
+               target_node = list_add_value(symbol_map_head, new_symbol_map_value,
+                                                 1);
+       }
+
+       target_map_value = (SymbolMapValue*)target_node->value;
+       if (number_of_symbol_names == 1) {
+                       list_add_value(&target_map_value->symbol_values_list_head,
+                                           value, refcount);
+       } else {
+               add_symbol_value(&target_map_value->symbol_values_list_head,
+                                &symbol_names[1], number_of_symbol_names - 1, value,
+                                refcount);
+       }
+}
+
+
+/* Gets the next value associated with the given hierarchy of symbols. 
+ * The value is returned as an output parameter with the function returning the
+ * node's old refcount value if a value is found, 0 otherwise.
+ * This means that a return value of 1 indicates the node was just removed from
+ * the list.
+ */
+static int get_symbol_value(
+        ListNode * const head, const char * const symbol_names[], 
+        const size_t number_of_symbol_names, void **output) {
+       const char* symbol_name;
+       ListNode *target_node;
+       assert_true(head);
+       assert_true(symbol_names);
+       assert_true(number_of_symbol_names);
+       assert_true(output);
+       symbol_name = symbol_names[0];
+
+       if (list_find(head, symbol_name, symbol_names_match, &target_node)) {
+               SymbolMapValue *map_value;
+               ListNode *child_list;
+               int return_value = 0;
+               assert_true(target_node);
+               assert_true(target_node->value);
+
+               map_value = (SymbolMapValue*)target_node->value;
+               child_list = &map_value->symbol_values_list_head;
+
+               if (number_of_symbol_names == 1) {
+                       ListNode *value_node = NULL;
+                       return_value = list_first(child_list, &value_node);
+                       assert_true(return_value);
+                       *output = (void*) value_node->value;
+                       return_value = value_node->refcount;
+                       if (--value_node->refcount == 0) {
+                               list_remove_free(value_node, NULL, NULL);
+                       }
+               } else {
+                       return_value = get_symbol_value(
+                           child_list, &symbol_names[1], number_of_symbol_names - 1, 
+                           output);
+               }
+               if (list_empty(child_list)) {
+                       list_remove_free(target_node, free_symbol_map_value, (void*)0);
+               }
+               return return_value;
+       } else {
+               print_error("No entries for symbol %s.\n", symbol_name);
+       }
+       return 0;
+}
+
+
+/* Traverse down a tree of symbol values and remove the first symbol value
+ * in each branch that has a refcount < -1 (i.e should always be returned
+ * and has been returned at least once).
+ */
+static void remove_always_return_values(ListNode * const map_head,
+                                        const size_t number_of_symbol_names) {
+       ListNode *current;
+       assert_true(map_head);
+       assert_true(number_of_symbol_names);
+       current = map_head->next;
+       while (current != map_head) {
+               SymbolMapValue * const value = (SymbolMapValue*)current->value;
+               ListNode * const next = current->next;
+               ListNode *child_list;
+               assert_true(value);
+               child_list = &value->symbol_values_list_head;
+
+               if (!list_empty(child_list)) {
+                       if (number_of_symbol_names == 1) {
+                               ListNode * const child_node = child_list->next;
+                               // If this item has been returned more than once, free it.
+                               if (child_node->refcount < -1) {
+                                       list_remove_free(child_node, free_value, NULL);
+                               }
+                       } else {
+                               remove_always_return_values(child_list,
+                                                           number_of_symbol_names - 1);
+                       }
+               }
+
+               if (list_empty(child_list)) {
+                       list_remove_free(current, free_value, NULL);
+               }
+               current = next;
+       }
+}
+
+/* Checks if there are any leftover values set up by the test that were never
+ * retrieved through execution, and fail the test if that is the case.
+ */
+static int check_for_leftover_values(
+        const ListNode * const map_head, const char * const error_message,
+        const size_t number_of_symbol_names) {
+       const ListNode *current;
+       int symbols_with_leftover_values = 0;
+       assert_true(map_head);
+       assert_true(number_of_symbol_names);
+
+       for (current = map_head->next; current != map_head; 
+            current = current->next) {
+               const SymbolMapValue * const value = 
+                   (SymbolMapValue*)current->value;
+               const ListNode *child_list;
+               assert_true(value);
+               child_list = &value->symbol_values_list_head;
+
+               if (!list_empty(child_list)) {
+                       if (number_of_symbol_names == 1) {
+                               const ListNode *child_node;
+                               print_error(error_message, value->symbol_name);
+                               print_error("  Remaining item(s) declared at...\n");
+
+                               for (child_node = child_list->next; child_node != child_list;
+                                    child_node = child_node->next) {
+                                       const SourceLocation * const location = child_node->value;
+                                       print_error("    " SOURCE_LOCATION_FORMAT "\n",
+                                                   location->file, location->line);
+                               }
+                       } else {
+                               print_error("%s.", value->symbol_name);
+                               check_for_leftover_values(child_list, error_message,
+                                                         number_of_symbol_names - 1);
+                       }
+                       symbols_with_leftover_values ++;
+               }
+       }
+       return symbols_with_leftover_values;
+}
+
+
+// Get the next return value for the specified mock function.
+void* _mock(const char * const function, const char* const file, 
+            const int line) {
+       void *result;
+       const int rc = get_symbol_value(&global_function_result_map_head, 
+                                       &function, 1, &result);
+       if (rc) {
+               SymbolValue * const symbol = result;
+               void * const value = (void*)symbol->value;
+               global_last_mock_value_location = symbol->location;
+               if (rc == 1) {
+                       free(symbol);
+               }
+               return value;
+       } else {
+               print_error("ERROR: " SOURCE_LOCATION_FORMAT " - Could not get value "
+                           "to mock function %s\n", file, line, function);
+               if (source_location_is_set(&global_last_mock_value_location)) {
+                       print_error("Previously returned mock value was declared at "
+                                   SOURCE_LOCATION_FORMAT "\n", 
+                                   global_last_mock_value_location.file, 
+                                   global_last_mock_value_location.line);
+               } else {
+                       print_error("There were no previously returned mock values for "
+                                   "this test.\n");
+               }
+               exit_test(1);
+       }
+       return NULL;
+}
+
+
+// Add a return value for the specified mock function name.
+void _will_return(const char * const function_name, const char * const file, 
+                  const int line, const void* const value, const int count) {
+       SymbolValue * const return_value = malloc(sizeof(*return_value));
+       assert_true(count > 0);
+       return_value->value = value;
+       set_source_location(&return_value->location, file, line);
+       add_symbol_value(&global_function_result_map_head, &function_name, 1,
+                        return_value, count);
+}
+
+
+/* Add a custom parameter checking function.  If the event parameter is NULL
+ * the event structure is allocated internally by this function.  If event
+ * parameter is provided it must be allocated on the heap and doesn't need to
+ * be deallocated by the caller.
+ */
+void _expect_check(
+        const char* const function, const char* const parameter, 
+        const char* const file, const int line,
+        const CheckParameterValue check_function, void * const check_data,
+        CheckParameterEvent * const event, const int count) {
+       CheckParameterEvent * const check = 
+           event ? event : malloc(sizeof(*check));
+       const char* symbols[] = {function, parameter};
+       check->parameter_name = parameter;
+       check->check_value = check_function;
+       check->check_value_data = check_data;
+       set_source_location(&check->location, file, line); 
+       add_symbol_value(&global_function_parameter_map_head, symbols, 2, check,
+                        count);
+}
+
+
+/* Returns 1 if the specified values are equal.  If the values are not equal
+ * an error is displayed and 0 is returned. */
+static int values_equal_display_error(const void* const left,
+                                      const void* const right) {
+       const int equal = left == right;
+       if (!equal) {
+               print_error("0x%x != 0x%x\n", left, right);
+       }
+       return equal;
+}
+
+/* Returns 1 if the specified values are not equal.  If the values are equal
+ * an error is displayed and 0 is returned. */
+static int values_not_equal_display_error(const void* const left,
+                                          const void* const right) {
+       const int not_equal = left != right;
+       if (!not_equal) {
+               print_error("0x%x == 0x%x\n", left, right);
+       }
+       return not_equal;
+}
+
+
+/* Determine whether value is contained within check_integer_set.
+ * If invert is 0 and the value is in the set 1 is returned, otherwise 0 is
+ * returned and an error is displayed.  If invert is 1 and the value is not 
+ * in the set 1 is returned, otherwise 0 is returned and an error is 
+ * displayed. */
+static int value_in_set_display_error(
+        const void *value, const CheckIntegerSet * const check_integer_set,
+        const int invert) {
+       int succeeded = invert;
+       assert_true(check_integer_set);
+       {
+               const void ** const set = check_integer_set->set;
+               const size_t size_of_set = check_integer_set->size_of_set; 
+               size_t i;
+               for (i = 0; i < size_of_set; i++) {
+                       if (set[i] == value) {
+                               if (invert) {
+                                       succeeded = 0;
+                               }
+                               break;
+                       }
+               }
+               if (succeeded) {
+                       return 1;
+               }
+               print_error("%d is %sin the set (", value, invert ? "" : "not ");
+               for (i = 0; i < size_of_set; i++) {
+                       print_error("%d, ", set[i]);
+               }
+               print_error(")\n");
+       }
+       return 0;
+}
+
+
+/* Determine whether a value is within the specified range.  If the value is
+ * within the specified range 1 is returned.  If the value isn't within the 
+ * specified range an error is displayed and 0 is returned. */
+static int integer_in_range_display_error(
+        const int value, const int range_min, const int range_max) {
+       if (value >= range_min && value <= range_max) {
+               return 1;
+       }
+       print_error("%d is not within the range %d-%d\n", value, range_min, 
+                   range_max);
+       return 0;
+}
+
+
+/* Determine whether a value is within the specified range.  If the value
+ * is not within the range 1 is returned.  If the value is within the 
+ * specified range an error is displayed and zero is returned. */
+static int integer_not_in_range_display_error(
+        const int value, const int range_min, const int range_max) {
+       if (value < range_min || value > range_max) {
+               return 1;
+       }
+       print_error("%d is within the range %d-%d\n", value, range_min,
+                   range_max);
+       return 0;
+}
+
+
+/* Determine whether the specified strings are equal.  If the strings are equal
+ * 1 is returned.  If they're not equal an error is displayed and 0 is 
+ * returned. */
+static int string_equal_display_error(
+        const char * const left, const char * const right) {
+       if (strcmp(left, right) == 0) {
+               return 1;
+       }
+       print_error("\"%s\" != \"%s\"\n", left, right);
+       return 0;
+}
+
+
+/* Determine whether the specified strings are equal.  If the strings are not 
+ * equal 1 is returned.  If they're not equal an error is displayed and 0 is 
+ * returned */
+static int string_not_equal_display_error(
+        const char * const left, const char * const right) {
+       if (strcmp(left, right) != 0) {
+               return 1;
+       }
+       print_error("\"%s\" == \"%s\"\n", left, right);
+       return 0;
+}
+
+
+/* Determine whether the specified areas of memory are equal.  If they're equal
+ * 1 is returned otherwise an error is displayed and 0 is returned. */
+static int memory_equal_display_error(const char* a, const char* b,
+                                      const size_t size) {
+       int differences = 0;
+       size_t i;
+       for (i = 0; i < size; i++) {
+               const char l = a[i];
+               const char r = b[i];
+               if (l != r) {
+                       print_error("difference at offset %d 0x%02x 0x%02x\n", i, l, r);
+                       differences ++;
+               }
+       }
+       if (differences) {
+               print_error("%d bytes of 0x%08x and 0x%08x differ\n", differences,
+                           a, b);
+               return 0;
+       }
+       return 1;
+}
+
+
+/* Determine whether the specified areas of memory are not equal.  If they're 
+ * not equal 1 is returned otherwise an error is displayed and 0 is 
+ * returned. */
+static int memory_not_equal_display_error(const char* a, const char* b,
+                                          const size_t size) {
+       int same = 0;
+       size_t i;
+       for (i = 0; i < size; i++) {
+               const char l = a[i];
+               const char r = b[i];
+               if (l == r) {
+                       print_error("equal at offset %d 0x%02x 0x%02x\n", i, l, r);
+                       same ++;
+               }
+       }
+       if (same) {
+               print_error("%d bytes of 0x%08x and 0x%08x the same\n", same,
+                           a, b);
+               return 0;
+       }
+       return 1;
+}
+
+
+// CheckParameterValue callback to check whether a value is within a set.
+static int check_in_set(const void *value, void *check_value_data) {
+       return value_in_set_display_error(value, 
+           (CheckIntegerSet*)check_value_data, 0);
+}
+
+
+// CheckParameterValue callback to check whether a value isn't within a set.
+static int check_not_in_set(const void *value, void *check_value_data) {
+       return value_in_set_display_error(value, 
+           (CheckIntegerSet*)check_value_data, 1);
+}
+
+
+/* Create the callback data for check_in_set() or check_not_in_set() and 
+ * register a check event. */
+static void expect_set(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line, const void *values[],
+        const size_t number_of_values, 
+        const CheckParameterValue check_function, const int count) {
+       CheckIntegerSet * const check_integer_set =
+           malloc(sizeof(*check_integer_set) + 
+                  (sizeof(values[0]) * number_of_values));
+       void ** const set = (void**)(check_integer_set + 1);
+       assert_true(values);
+       assert_true(number_of_values);
+       memcpy(set, values, number_of_values * sizeof(values[0]));
+       check_integer_set->set = (const void**)set;
+       _expect_check(function, parameter, file, line, check_function,
+                     check_integer_set, &check_integer_set->event, count);
+}
+
+
+// Add an event to check whether a value is in a set.
+void _expect_in_set(
+        const char* const function, const char* const parameter, 
+        const char* const file, const int line, const void *values[], 
+        const size_t number_of_values, const int count) {
+       expect_set(function, parameter, file, line, values, number_of_values,
+                  check_in_set, count);
+}
+
+
+// Add an event to check whether a value isn't in a set.
+void _expect_not_in_set(
+        const char* const function, const char* const parameter, 
+        const char* const file, const int line, const void *values[], 
+        const size_t number_of_values, const int count) {
+       expect_set(function, parameter, file, line, values, number_of_values,
+                  check_not_in_set, count);
+}
+
+
+// CheckParameterValue callback to check whether a value is within a range.
+static int check_in_range(const void *value, void *check_value_data) {
+       CheckIntegerRange * const check_integer_range = check_value_data;
+       assert_true(check_value_data);
+       return integer_in_range_display_error(
+           (int)value, check_integer_range->minimum,
+           check_integer_range->maximum);
+}
+
+
+// CheckParameterValue callback to check whether a value is not within a range.
+static int check_not_in_range(const void *value, void *check_value_data) {
+       CheckIntegerRange * const check_integer_range = check_value_data;
+       assert_true(check_value_data);
+       return integer_not_in_range_display_error(
+           (int)value, check_integer_range->minimum,
+           check_integer_range->maximum);
+}
+
+
+/* Create the callback data for check_in_range() or check_not_in_range() and 
+ * register a check event. */
+static void expect_range(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line,
+        const int minimum, const int maximum,
+        const CheckParameterValue check_function, const int count) {
+       CheckIntegerRange * const check_integer_range =
+           malloc(sizeof(*check_integer_range));
+       check_integer_range->minimum = minimum;
+       check_integer_range->maximum = maximum;
+       _expect_check(function, parameter, file, line, check_function,
+                     check_integer_range, &check_integer_range->event, count);
+}
+
+
+// Add an event to determine whether a parameter is within a range.
+void _expect_in_range(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line,
+        const int minimum, const int maximum, const int count) {
+       expect_range(function, parameter, file, line, minimum, maximum,
+                    check_in_range, count);
+}
+
+
+// Add an event to determine whether a parameter is not within a range.
+void _expect_not_in_range(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line,
+        const int minimum, const int maximum, const int count) {
+       expect_range(function, parameter, file, line, minimum, maximum,
+                    check_not_in_range, count);
+}
+
+
+/* CheckParameterValue callback to check whether a value is equal to an 
+ * expected value. */
+static int check_value(const void *value, void *check_value_data) {
+       return values_equal_display_error(value, check_value_data);
+}
+
+
+// Add an event to check a parameter equals an expected value.
+void _expect_value(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line, const void* const value,
+        const int count) {
+       _expect_check(function, parameter, file, line, check_value, 
+                     (void*)value, NULL, count);
+}
+
+
+/* CheckParameterValue callback to check whether a value is not equal to an 
+ * expected value. */
+static int check_not_value(const void *value, void *check_value_data) {
+       return values_not_equal_display_error(value, check_value_data);
+}
+
+
+// Add an event to check a parameter is not equal to an expected value.
+void _expect_not_value(
+        const char* const function, const char* const parameter, 
+        const char* const file, const int line, const void* const value,
+        const int count) {
+       _expect_check(function, parameter, file, line, check_not_value,
+                     (void*)value, NULL, count);
+}
+
+
+// CheckParameterValue callback to check whether a parameter equals a string.
+static int check_string(const void * value, void *check_value_data) {
+       return string_equal_display_error(value, check_value_data);
+}
+
+
+// Add an event to check whether a parameter is equal to a string.
+void _expect_string(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line, const char* string,
+        const int count) {
+       _expect_check(function, parameter, file, line, check_string, (void*)string,
+                     NULL, count);
+}
+
+
+/* CheckParameterValue callback to check whether a parameter is not equals to 
+ * a string. */
+static int check_not_string(const void * value, void *check_value_data) {
+       return string_not_equal_display_error(value, check_value_data);
+}
+
+
+// Add an event to check whether a parameter is not equal to a string.
+void _expect_not_string(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line, const char* string,
+        const int count) {
+       _expect_check(function, parameter, file, line, check_not_string,
+                     (void*)string, NULL, count);
+}
+
+/* CheckParameterValue callback to check whether a parameter equals an area of
+ * memory. */
+static int check_memory(const void* value, void *check_value_data) {
+       CheckMemoryData * const check = (CheckMemoryData*)check_value_data;
+       assert_true(check);
+       return memory_equal_display_error(value, check->memory, check->size);
+}
+
+
+/* Create the callback data for check_memory() or check_not_memory() and 
+ * register a check event. */
+static void expect_memory_setup(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line,
+        const void * const memory, const size_t size,
+        const CheckParameterValue check_function, const int count) {
+       CheckMemoryData * const check_data = malloc(sizeof(*check_data) + size);
+       void * const mem = (void*)(check_data + 1);
+       assert_true(memory);
+       assert_true(size);
+       memcpy(mem, memory, size);
+       check_data->memory = mem;
+       check_data->size = size;
+       _expect_check(function, parameter, file, line, check_function,
+                     check_data, &check_data->event, count);
+}
+
+
+// Add an event to check whether a parameter matches an area of memory.
+void _expect_memory(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line, const void* const memory,
+        const size_t size, const int count) {
+       expect_memory_setup(function, parameter, file, line, memory, size,
+                           check_memory, count);
+}
+
+
+/* CheckParameterValue callback to check whether a parameter is not equal to
+ * an area of memory. */
+static int check_not_memory(const void* value, void *check_value_data) {
+       CheckMemoryData * const check = (CheckMemoryData*)check_value_data;
+       assert_true(check);
+       return memory_not_equal_display_error(value, check->memory, check->size);
+}
+
+
+// Add an event to check whether a parameter doesn't match an area of memory.
+void _expect_not_memory(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line, const void* const memory, 
+        const size_t size, const int count) {
+       expect_memory_setup(function, parameter, file, line, memory, size,
+                           check_not_memory, count);
+}
+
+
+// CheckParameterValue callback that always returns 1.
+static int check_any(const void *value, void *check_value_data) {
+       return 1;
+}
+
+
+// Add an event to allow any value for a parameter.
+void _expect_any(
+        const char* const function, const char* const parameter,
+        const char* const file, const int line, const int count) {
+       _expect_check(function, parameter, file, line, check_any, NULL, NULL, 
+                     count);
+}
+
+
+void _check_expected(
+        const char * const function_name, const char * const parameter_name,
+        const char* file, const int line, const void* value) {
+       void *result;
+       const char* symbols[] = {function_name, parameter_name};
+       const int rc = get_symbol_value(&global_function_parameter_map_head, 
+                                       symbols, 2, &result);
+       if (rc) {
+               CheckParameterEvent * const check = (CheckParameterEvent*)result;
+               int check_succeeded;
+               global_last_parameter_location = check->location;
+               check_succeeded = check->check_value(value, check->check_value_data);
+               if (rc == 1) {
+                       free(check);
+               }
+               if (!check_succeeded) {
+                       print_error("ERROR: Check of parameter %s, function %s failed\n"
+                                   "Expected parameter declared at " 
+                                   SOURCE_LOCATION_FORMAT "\n",
+                                   parameter_name, function_name,
+                                   global_last_parameter_location.file, 
+                                   global_last_parameter_location.line);
+                       _fail(file, line); 
+               }
+       } else {
+               print_error("ERROR: " SOURCE_LOCATION_FORMAT " - Could not get value "
+                           "to check parameter %s of function %s\n", file, line, 
+                           parameter_name, function_name);
+               if (source_location_is_set(&global_last_parameter_location)) {
+                       print_error("Previously declared parameter value was declared at "
+                                   SOURCE_LOCATION_FORMAT "\n", 
+                                   global_last_parameter_location.file, 
+                                   global_last_parameter_location.line);
+               } else {
+                       print_error("There were no previously declared parameter values "
+                                   "for this test.\n");
+               }
+               exit_test(1);
+       }
+}
+
+
+// Replacement for assert.
+void mock_assert(const int result, const char* const expression, 
+                 const char* const file, const int line) {
+       if (!result) {
+               if (global_expecting_assert) {
+                       longjmp(global_expect_assert_env, (int)expression);
+               } else {
+                       print_error("ASSERT: %s\n", expression);
+                       _fail(file, line);
+               }
+       }
+}
+
+
+void _assert_true(const int result, const char * const expression, 
+                  const char * const file, const int line) {
+       if (!result) {
+               print_error("%s\n", expression);
+               _fail(file, line);
+       }
+}
+
+void _assert_int_equal(const int a, const int b, const char * const file, 
+                       const int line) {
+       if (!values_equal_display_error((void*)a, (void*)b)) {
+               _fail(file, line);
+       }
+}
+
+
+void _assert_int_not_equal(const int a, const int b, const char * const file, 
+                           const int line) {
+       if (!values_not_equal_display_error((void*)a, (void*)b)) {
+               _fail(file, line);
+       }
+}
+
+
+void _assert_string_equal(const char * const a, const char * const b, 
+                          const char * const file, const int line) {
+       if (!string_equal_display_error(a, b)) {
+               _fail(file, line);
+       }
+}
+
+
+void _assert_string_not_equal(const char * const a, const char * const b, 
+                              const char *file, const int line) {
+       if (!string_not_equal_display_error(a, b)) {
+               _fail(file, line);
+       }
+}
+
+
+void _assert_memory_equal(const void * const a, const void * const b, 
+                          const size_t size, const char* const file, 
+                          const int line) {
+       if (!memory_equal_display_error((const char*)a, (const char*)b, size)) {
+               _fail(file, line);
+       }
+}
+
+
+void _assert_memory_not_equal(const void * const a, const void * const b,
+                              const size_t size, const char* const file, 
+                              const int line) {
+       if (!memory_not_equal_display_error((const char*)a, (const char*)b, 
+                                           size)) {
+               _fail(file, line);
+       }
+}
+
+
+void _assert_in_range(const int value, const int minimum, const int maximum,
+                      const char* const file, const int line) {
+       if (!integer_in_range_display_error(value, minimum, maximum)) {
+               _fail(file, line);
+       }
+}
+
+void _assert_not_in_range(const int value, const int minimum,
+                          const int maximum, const char* const file, 
+                          const int line) {
+       if (!integer_not_in_range_display_error(value, minimum, maximum)) {
+               _fail(file, line);
+       }
+}
+
+void _assert_in_set(const void* const value, const void *values[],
+                    const size_t number_of_values, const char* const file,
+                    const int line) {
+       CheckIntegerSet check_integer_set;
+       check_integer_set.set = values;
+       check_integer_set.size_of_set = number_of_values;
+       if (!value_in_set_display_error(value, &check_integer_set, 0)) {
+               _fail(file, line);
+       }
+}
+
+void _assert_not_in_set(const void* const value, const void *values[],
+                        const size_t number_of_values, const char* const file,
+                        const int line) {
+       CheckIntegerSet check_integer_set;
+       check_integer_set.set = values;
+       check_integer_set.size_of_set = number_of_values;
+       if (!value_in_set_display_error(value, &check_integer_set, 1)) {
+               _fail(file, line);
+       }
+}
+
+
+// Get the list of allocated blocks.
+static ListNode* get_allocated_blocks_list() {
+       // If it initialized, initialize the list of allocated blocks.
+       if (!global_allocated_blocks.value) {
+               list_initialize(&global_allocated_blocks);
+               global_allocated_blocks.value = (void*)1;
+       }
+       return &global_allocated_blocks;
+}
+
+// Use the real malloc in this function.
+#undef malloc
+void* _test_malloc(const size_t size, const char* file, const int line) {
+       char* ptr;
+       MallocBlockInfo *block_info;
+       ListNode * const block_list = get_allocated_blocks_list();
+       const size_t allocate_size = size + (MALLOC_GUARD_SIZE * 2) + 
+           sizeof(*block_info) + MALLOC_ALIGNMENT;
+       char* const block = (char*)malloc(allocate_size);
+       assert_true(block);
+
+       // Calculate the returned address.
+       ptr = (char*)(((size_t)block + MALLOC_GUARD_SIZE + sizeof(*block_info) +
+                     MALLOC_ALIGNMENT) & ~(MALLOC_ALIGNMENT - 1));
+
+       // Initialize the guard blocks.
+       memset(ptr - MALLOC_GUARD_SIZE, MALLOC_GUARD_PATTERN, MALLOC_GUARD_SIZE);
+       memset(ptr + size, MALLOC_GUARD_PATTERN, MALLOC_GUARD_SIZE);
+       memset(ptr, MALLOC_ALLOC_PATTERN, size);
+
+       block_info = (MallocBlockInfo*)(ptr - (MALLOC_GUARD_SIZE +
+                                                sizeof(*block_info)));
+       set_source_location(&block_info->location, file, line);
+       block_info->allocated_size = allocate_size;
+       block_info->size = size;
+       block_info->block = block;
+       block_info->node.value = block_info;
+       list_add(block_list, &block_info->node);
+       return ptr;
+}
+#define malloc test_malloc
+
+
+void* _test_calloc(const size_t number_of_elements, const size_t size, 
+                   const char* file, const int line) {
+       void* const ptr = _test_malloc(number_of_elements * size, file, line);
+       if (ptr) {
+               memset(ptr, 0, number_of_elements * size);
+       }
+       return ptr;
+}
+
+
+// Use the real free in this function.
+#undef free
+void _test_free(void* const ptr, const char* file, const int line) {
+       unsigned int i;
+       char *block = (char*)ptr;
+       MallocBlockInfo *block_info;
+       _assert_true((int)ptr, "ptr", file, line);
+       block_info = (MallocBlockInfo*)(block - (MALLOC_GUARD_SIZE +
+                                                  sizeof(*block_info)));
+       // Check the guard blocks.
+       {
+               char *guards[2] = {block - MALLOC_GUARD_SIZE,
+                                  block + block_info->size};
+               for (i = 0; i < ARRAY_LENGTH(guards); i++) {
+                       unsigned int j;
+                       char * const guard = guards[i];
+                       for (j = 0; j < MALLOC_GUARD_SIZE; j++) {
+                               const char diff = guard[j] - MALLOC_GUARD_PATTERN;
+                               if (diff) {
+                                       print_error(
+                                           "Guard block of 0x%08x size=%d allocated by "
+                                           SOURCE_LOCATION_FORMAT " at 0x%08x is corrupt\n", 
+                                           (size_t)ptr, block_info->size,
+                                           block_info->location.file, block_info->location.line, 
+                                           (size_t)&guard[j]);
+                                       _fail(file, line);
+                               }
+                       }
+               }
+       }
+       list_remove(&block_info->node, NULL, NULL);
+
+       block = block_info->block;
+       memset(block, MALLOC_FREE_PATTERN, block_info->allocated_size);
+       free(block);
+}
+#define free test_free
+
+
+// Crudely checkpoint the current heap state.
+static const ListNode* check_point_allocated_blocks() {
+       return get_allocated_blocks_list()->prev;
+}
+
+
+/* Display the blocks allocated after the specified check point.  This
+ * function returns the number of blocks displayed. */
+static int display_allocated_blocks(const ListNode * const check_point) {
+       const ListNode * const head = get_allocated_blocks_list();
+       const ListNode *node;
+       int allocated_blocks = 0;
+       assert_true(check_point);
+       assert_true(check_point->next);
+
+       for (node = check_point->next; node != head; node = node->next) {
+               const MallocBlockInfo * const block_info = node->value;
+               assert_true(block_info);
+
+               if (!allocated_blocks) {
+                       print_error("Blocks allocated...\n");
+               }
+               print_error("  0x%08x : " SOURCE_LOCATION_FORMAT "\n",
+                           block_info->block, block_info->location.file,
+                           block_info->location.line);
+               allocated_blocks ++;
+       }
+       return allocated_blocks;
+}
+
+
+// Free all blocks allocated after the specified check point.
+static void free_allocated_blocks(const ListNode * const check_point) {
+       const ListNode * const head = get_allocated_blocks_list();
+       const ListNode *node;
+       assert_true(check_point);
+
+       node = check_point->next;
+       assert_true(node);
+
+       while (node != head) {
+               MallocBlockInfo * const block_info = (MallocBlockInfo*)node->value;
+               node = node->next;
+               free((char*)block_info + sizeof(*block_info) + MALLOC_GUARD_SIZE);
+       }
+}
+
+
+// Fail if any any blocks are allocated after the specified check point.
+static void fail_if_blocks_allocated(const ListNode * const check_point,
+                                     const char * const test_name) {
+       const int allocated_blocks = display_allocated_blocks(check_point);
+       if (allocated_blocks) {
+               free_allocated_blocks(check_point);
+               print_error("ERROR: %s leaked %d block(s)\n", test_name, 
+                           allocated_blocks);
+               exit_test(1);
+       }
+}
+
+
+void _fail(const char * const file, const int line) {
+       print_error("ERROR: " SOURCE_LOCATION_FORMAT " Failure!\n", file, line);
+       exit_test(1);
+}
+
+
+#ifndef _WIN32
+static void exception_handler(int sig) {
+       print_error("%s\n", strsignal(sig));
+       exit_test(1);
+}
+
+#else // _WIN32
+
+static LONG WINAPI exception_filter(EXCEPTION_POINTERS *exception_pointers) {
+       EXCEPTION_RECORD * const exception_record =
+           exception_pointers->ExceptionRecord;
+       const DWORD code = exception_record->ExceptionCode;
+       unsigned int i;
+       for (i = 0; i < ARRAY_LENGTH(exception_codes); i++) {
+               const ExceptionCodeInfo * const code_info = &exception_codes[i];
+               if (code == code_info->code) {
+                       static int shown_debug_message = 0;
+                       fflush(stdout);
+                       print_error("%s occurred at 0x%08x.\n", code_info->description,
+                                   exception_record->ExceptionAddress);
+                       if (!shown_debug_message) {
+                               print_error(
+                                   "\n"
+                                   "To debug in Visual Studio...\n"
+                                   "1. Select menu item File->Open Project\n"
+                                   "2. Change 'Files of type' to 'Executable Files'\n"
+                                   "3. Open this executable.\n"
+                                   "4. Select menu item Debug->Start\n"
+                                   "\n"
+                                   "Alternatively, set the environment variable \n"
+                                   "UNIT_TESTING_DEBUG to 1 and rebuild this executable, \n"
+                                   "then click 'Debug' in the popup dialog box.\n"
+                                   "\n");
+                               shown_debug_message = 1;
+                       }
+                       exit_test(0);
+                       return EXCEPTION_EXECUTE_HANDLER;
+               }
+       }
+       return EXCEPTION_CONTINUE_SEARCH;
+}
+#endif // !_WIN32
+
+
+// Standard output and error print methods.
+void vprint_message(const char* const format, va_list args) {
+       char buffer[1024];
+       vsnprintf(buffer, sizeof(buffer), format, args);
+       printf(buffer);
+#ifdef _WIN32
+       OutputDebugString(buffer);
+#endif // _WIN32
+}
+
+
+void vprint_error(const char* const format, va_list args) {
+       char buffer[1024];
+       vsnprintf(buffer, sizeof(buffer), format, args);
+       fprintf(stderr, buffer);
+#ifdef _WIN32
+       OutputDebugString(buffer);
+#endif // _WIN32
+}
+
+
+void print_message(const char* const format, ...) {
+       va_list args;
+       va_start(args, format);
+       vprint_message(format, args);
+       va_end(args);
+}
+
+
+void print_error(const char* const format, ...) {
+       va_list args;
+       va_start(args, format);
+       vprint_error(format, args);
+       va_end(args);
+}
+
+
+int _run_test(
+        const char * const function_name,  const UnitTestFunction Function, 
+        void ** const state, const UnitTestFunctionType function_type,
+        const void* const heap_check_point) {
+       const ListNode * const check_point = heap_check_point ? 
+           heap_check_point : check_point_allocated_blocks();
+       void *current_state = NULL;
+       int rc = 1;
+       int handle_exceptions = 1;
+#ifdef _WIN32
+       handle_exceptions = !IsDebuggerPresent();
+#endif // _WIN32
+#if UNIT_TESTING_DEBUG
+       handle_exceptions = 0;
+#endif // UNIT_TESTING_DEBUG
+
+       if (handle_exceptions) {
+#ifndef _WIN32
+               unsigned int i;
+               for (i = 0; i < ARRAY_LENGTH(exception_signals); i++) {
+                       default_signal_functions[i] = signal(
+                           exception_signals[i], exception_handler);
+               }
+#else // _WIN32
+               previous_exception_filter = SetUnhandledExceptionFilter(
+                   exception_filter);
+#endif // !_WIN32
+       }
+
+       if (function_type == UNIT_TEST_FUNCTION_TYPE_TEST) {
+               print_message("%s: Starting test\n", function_name);
+       }
+       initialize_testing(function_name);
+       global_running_test = 1;
+       if (setjmp(global_run_test_env) == 0) {
+               Function(state ? state : &current_state);
+               fail_if_leftover_values(function_name);
+
+               /* If this is a setup function then ignore any allocated blocks
+                * only ensure they're deallocated on tear down. */
+               if (function_type != UNIT_TEST_FUNCTION_TYPE_SETUP) {
+                       fail_if_blocks_allocated(check_point, function_name);
+               }
+
+               global_running_test = 0;
+
+               if (function_type == UNIT_TEST_FUNCTION_TYPE_TEST) {
+                       print_message("%s: Test completed successfully.\n", function_name);
+               }
+               rc = 0;
+       } else {
+               global_running_test = 0;
+               print_message("%s: Test failed.\n", function_name);
+       }
+       teardown_testing(function_name);
+
+       if (handle_exceptions) {
+#ifndef _WIN32
+               unsigned int i;
+               for (i = 0; i < ARRAY_LENGTH(exception_signals); i++) {
+                       signal(exception_signals[i], default_signal_functions[i]);
+               }
+#else // _WIN32
+               if (previous_exception_filter) {
+                       SetUnhandledExceptionFilter(previous_exception_filter);
+                       previous_exception_filter = NULL;
+               }
+#endif // !_WIN32
+       }
+
+       return rc;
+}
+
+
+int _run_tests(const UnitTest * const tests, const size_t number_of_tests) {
+       // Whether to execute the next test.
+       int run_next_test = 1;
+       // Whether the previous test failed.
+       int previous_test_failed = 0;
+       // Check point of the heap state.
+       const ListNode * const check_point = check_point_allocated_blocks();
+       // Current test being executed.
+       size_t current_test = 0;
+       // Number of tests executed.
+       size_t tests_executed = 0;
+       // Number of failed tests.
+       size_t total_failed = 0;
+       // Number of setup functions.
+       size_t setups = 0;
+       // Number of teardown functions.
+       size_t teardowns = 0;
+       /* A stack of test states.  A state is pushed on the stack
+        * when a test setup occurs and popped on tear down. */
+       TestState* test_states = malloc(number_of_tests * sizeof(*test_states));
+       size_t number_of_test_states = 0;
+       // Names of the tests that failed.
+       const char** failed_names = malloc(number_of_tests * 
+                                          sizeof(*failed_names));
+       void **current_state = NULL;
+
+       while (current_test < number_of_tests) {
+               const ListNode *test_check_point = NULL;
+               TestState *current_TestState;
+               const UnitTest * const test = &tests[current_test++];
+               if (!test->function) {
+                       continue;
+               }
+
+               switch (test->function_type) {
+               case UNIT_TEST_FUNCTION_TYPE_TEST:
+                       run_next_test = 1;
+                       break;
+               case UNIT_TEST_FUNCTION_TYPE_SETUP: {
+                       // Checkpoint the heap before the setup.
+                       current_TestState = &test_states[number_of_test_states++];
+                       current_TestState->check_point = check_point_allocated_blocks();
+                       test_check_point = current_TestState->check_point;
+                       current_state = &current_TestState->state;
+                       *current_state = NULL;
+                       run_next_test = 1;
+                       setups ++;
+                       break;
+               }
+               case UNIT_TEST_FUNCTION_TYPE_TEARDOWN:
+                       // Check the heap based on the last setup checkpoint.
+                       assert_true(number_of_test_states);
+                       current_TestState = &test_states[--number_of_test_states];
+                       test_check_point = current_TestState->check_point;
+                       current_state = &current_TestState->state;
+                       teardowns ++;
+                       break;
+               default:
+                       print_error("Invalid unit test function type %d\n",
+                                   test->function_type);
+                       exit_test(1);
+                       break;
+               }
+
+               if (run_next_test) {
+                       int failed = _run_test(test->name, test->function, current_state,
+                                              test->function_type, test_check_point);
+                       if (failed) {
+                               failed_names[total_failed] = test->name;
+                       }
+
+                       switch (test->function_type) {
+                       case UNIT_TEST_FUNCTION_TYPE_TEST:
+                               previous_test_failed = failed;
+                               total_failed += failed;
+                               tests_executed ++;
+                               break;
+
+                       case UNIT_TEST_FUNCTION_TYPE_SETUP:
+                               if (failed) {
+                                       total_failed ++;
+                                       tests_executed ++;
+                                       // Skip forward until the next test or setup function.
+                                       run_next_test = 0;
+                               }
+                               previous_test_failed = 0;
+                               break;
+
+                       case UNIT_TEST_FUNCTION_TYPE_TEARDOWN:
+                               // If this test failed.
+                               if (failed && !previous_test_failed) {
+                                       total_failed ++;
+                               }
+                               break;
+                       default:
+                               assert_false("BUG: shouldn't be here!");
+                               break;
+                       }
+               }
+       }
+
+       if (total_failed) {
+               size_t i;
+               print_error("%d out of %d tests failed!\n", total_failed, 
+                           tests_executed);
+               for (i = 0; i < total_failed; i++) {
+                       print_error("    %s\n", failed_names[i]);
+               }
+       } else {
+               print_message("All %d tests passed\n", tests_executed);
+       }
+
+       if (number_of_test_states) {
+               print_error("Mismatched number of setup %d and teardown %d "
+                           "functions\n", setups, teardowns);
+               total_failed = -1;
+       }
+
+       free(test_states);
+       free((void*)failed_names);
+
+       fail_if_blocks_allocated(check_point, "run_tests");
+       return total_failed;
+}
index 0395bba1559030a5f8f8b41bcd75a8fb885a516f..8cb7bb2b1be9a8b8bec7bafe86435a5e04835076 100644 (file)
-#\r
-# Copyright 2008 Google Inc.\r
-#\r
-# Licensed under the Apache License, Version 2.0 (the "License");\r
-# you may not use this file except in compliance with the License.\r
-# You may obtain a copy of the License at\r
-# \r
-# http://www.apache.org/licenses/LICENSE-2.0\r
-# \r
-# Unless required by applicable law or agreed to in writing, software\r
-# distributed under the License is distributed on an "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-# See the License for the specific language governing permissions and\r
-# limitations under the License.\r
-#\r
-# Microsoft Windows namke file which builds the cmockery library and example \r
-# applications.\r
-#\r
-# To use this makefile...\r
-# Select Start->Run and run "cmd.exe" to open the command line.\r
-# Run "vsvars.bat" located in Microsoft Visual Studio's directory.\r
-# Run "nmake" to build the cmockery library and example applications.\r
-# Run "nmake clean" to delete all files built by this makefile.\r
-\r
-LIBRARY_SOURCE_DIRECTORY=..\src\r
-EXAMPLE_SOURCE_DIRECTORY=..\src\example\r
-\r
-CFLAGS=/nologo /c /D_WIN32_WINNT=0x501 /I$(LIBRARY_SOURCE_DIRECTORY)\google \\r
-       /I$(EXAMPLE_SOURCE_DIRECTORY)\r
-CC_COMMAND=$(CC) $(CFLAGS) $(**) /Fo$(@)\r
-CC_COMMAND_UNIT_TEST=$(CC_COMMAND) /DUNIT_TESTING=1\r
-\r
-LIBLINKFLAGS=/NOLOGO /MACHINE:x86 /SUBSYSTEM:console\r
-\r
-LIBRARY_ARCHIVER=lib.exe\r
-LIBFLAGS=$(LIBLINKFLAGS)\r
-LIB_COMMAND=$(LIBRARY_ARCHIVER) $(LIBFLAGS) $(**) /OUT:$(@)\r
-\r
-LINK=link.exe\r
-LFLAGS=$(LIBLINKFLAGS) libcmt.lib kernel32.lib /NODEFAULTLIB:libc.lib\r
-LINK_COMMAND=$(LINK) $(LFLAGS) $(**) /OUT:$(@)\r
-\r
-.SUFFIXES: .exe .lib .obj .c\r
-\r
-all: cmockery.lib calculator.exe calculator_test.exe allocate_module_test.exe \\r
-       assert_macro_test.exe customer_database_test.exe key_value_test.exe \\r
-       product_database_test.exe run_tests.exe\r
-\r
-clean:\r
-       -cmd /c "@for %A in (\\r
-               cmockery.lib cmockery.obj \\r
-               calculator.exe calculator.obj \\r
-               calculator_test.exe calculator_test.obj \\r
-                       calculator_test-calculator.obj \\r
-               allocate_module_test.exe allocate_module_test.obj \\r
-                       allocate_module.obj \\r
-               assert_macro_test.exe assert_macro_test.obj \\r
-                       assert_macro.obj \\r
-               customer_database_test.exe customer_database_test.obj \\r
-                       customer_database.obj \\r
-               key_value_test.exe key_value_test.obj key_value.obj \\r
-               product_database_test.exe product_database_test.obj \\r
-                       product_database.obj \\r
-               run_tests.exe run_tests.obj) do @del %A 2>NUL"\r
-\r
-# Rules for the cmockery library.\r
-cmockery.lib: cmockery.obj\r
-cmockery.obj: $(LIBRARY_SOURCE_DIRECTORY)\cmockery.c\r
-\r
-# Rules for the calculator application.\r
-calculator.exe: calculator.obj\r
-\r
-calculator.obj: $(EXAMPLE_SOURCE_DIRECTORY)\calculator.c\r
-       $(CC_COMMAND)\r
-\r
-# Rules for the calculator test application.\r
-calculator_test.exe: calculator_test.obj calculator_test-calculator.obj \\r
-                     cmockery.lib\r
-       $(LINK_COMMAND)\r
-\r
-calculator_test.obj: $(EXAMPLE_SOURCE_DIRECTORY)\calculator_test.c\r
-\r
-calculator_test-calculator.obj: $(EXAMPLE_SOURCE_DIRECTORY)\calculator.c\r
-       $(CC_COMMAND_UNIT_TEST)\r
-\r
-# Sample code applications.\r
-allocate_module_test.exe: allocate_module_test.obj allocate_module.obj \\r
-               cmockery.lib\r
-       $(LINK_COMMAND)\r
-\r
-allocate_module_test.obj: $(EXAMPLE_SOURCE_DIRECTORY)\allocate_module_test.c\r
-allocate_module.obj: $(EXAMPLE_SOURCE_DIRECTORY)\allocate_module.c\r
-\r
-assert_macro_test.exe: assert_macro_test.obj assert_macro.obj \\r
-               cmockery.lib\r
-       $(LINK_COMMAND)\r
-\r
-assert_macro_test.obj: $(EXAMPLE_SOURCE_DIRECTORY)\assert_macro_test.c\r
-assert_macro.obj: $(EXAMPLE_SOURCE_DIRECTORY)\assert_macro.c\r
-\r
-customer_database_test.exe: customer_database_test.obj customer_database.obj \\r
-               cmockery.lib\r
-       $(LINK_COMMAND)\r
-\r
-customer_database_test.obj: \\r
-               $(EXAMPLE_SOURCE_DIRECTORY)\customer_database_test.c\r
-customer_database.obj: $(EXAMPLE_SOURCE_DIRECTORY)\customer_database.c\r
-\r
-key_value_test.exe: key_value_test.obj key_value.obj \\r
-               cmockery.lib\r
-       $(LINK_COMMAND)\r
-\r
-key_value_test.obj: $(EXAMPLE_SOURCE_DIRECTORY)\key_value_test.c\r
-key_value.obj: $(EXAMPLE_SOURCE_DIRECTORY)\key_value.c\r
-\r
-product_database_test.exe: product_database_test.obj product_database.obj \\r
-               cmockery.lib\r
-       $(LINK_COMMAND)\r
-\r
-product_database_test.obj: $(EXAMPLE_SOURCE_DIRECTORY)\product_database_test.c\r
-product_database.obj: $(EXAMPLE_SOURCE_DIRECTORY)\product_database.c\r
-\r
-run_tests.exe: run_tests.obj cmockery.lib\r
-       $(LINK_COMMAND)\r
-\r
-run_tests.obj: $(EXAMPLE_SOURCE_DIRECTORY)\run_tests.c\r
-\r
-# Inference rules.\r
-.obj.exe:\r
-       $(LINK_COMMAND)\r
-\r
-.obj.lib:\r
-       $(LIB_COMMAND)\r
-\r
-{$(LIBRARY_SOURCE_DIRECTORY)\}.c{}.obj:\r
-       $(CC_COMMAND)\r
-\r
-{$(EXAMPLE_SOURCE_DIRECTORY)\}.c{}.obj:\r
-       $(CC_COMMAND_UNIT_TEST)\r
+#
+# Copyright 2008 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+# http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Microsoft Windows namke file which builds the cmockery library and example 
+# applications.
+#
+# To use this makefile...
+# Select Start->Run and run "cmd.exe" to open the command line.
+# Run "vsvars.bat" located in Microsoft Visual Studio's directory.
+# Run "nmake" to build the cmockery library and example applications.
+# Run "nmake clean" to delete all files built by this makefile.
+
+# Target directories.
+!IFNDEF EXECUTABLE_DIR
+EXECUTABLE_DIR=.
+!ENDIF # EXECUTABLE_DIR
+
+!IFNDEF LIBRARY_DIR
+LIBRARY_DIR=.
+!ENDIF # LIBRARY_DIR
+
+!IFNDEF OBJECT_DIR
+OBJECT_DIR=.
+!ENDIF # OBJECT_DIR
+
+# Source directories.
+LIBRARY_SOURCE_DIRECTORY=..\src
+EXAMPLE_SOURCE_DIRECTORY=..\src\example
+
+# Compiler flags and commands.
+CFLAGS=/nologo /c /D_WIN32_WINNT=0x501 /I$(LIBRARY_SOURCE_DIRECTORY)\google \
+       /I$(EXAMPLE_SOURCE_DIRECTORY)
+CC_COMMAND=$(CC) $(CFLAGS) $(**) /Fo$(@)
+CC_COMMAND_UNIT_TEST=$(CC_COMMAND) /DUNIT_TESTING=1
+
+LIBLINKFLAGS=/NOLOGO /MACHINE:x86 /SUBSYSTEM:console
+
+# Library archiver flags and command.
+LIBRARY_ARCHIVER=lib.exe
+LIBFLAGS=$(LIBLINKFLAGS)
+LIB_COMMAND=$(LIBRARY_ARCHIVER) $(LIBFLAGS) $(**) /OUT:$(@)
+
+# Linker flags and command. 
+LINK=link.exe
+LFLAGS=$(LIBLINKFLAGS) libcmt.lib kernel32.lib /NODEFAULTLIB:libc.lib
+LINK_COMMAND=$(LINK) $(LFLAGS) $(**) /OUT:$(@)
+
+.SUFFIXES: .exe .lib .obj .c
+
+all: $(EXECUTABLE_DIR) $(LIBRARY_DIR) $(OBJECT_DIR) \
+       $(LIBRARY_DIR)\cmockery.lib examples
+
+$(EXECUTABLE_DIR):
+       mkdir $@
+
+!IF "$(LIBRARY_DIR)" != "$(EXECUTABLE_DIR)"
+$(LIBRARY_DIR):
+       mkdir $*
+!ENDIF
+
+!IF "$(OBJECT_DIR)" != "$(LIBRARY_DIR)" && \
+       "$(OBJECT_DIR)" != "$(EXECUTABLE_DIR)"
+$(OBJECT_DIR):
+       mkdir $@
+!ENDIF
+
+examples: \
+       $(EXECUTABLE_DIR)\calculator.exe \
+       $(EXECUTABLE_DIR)\calculator_test.exe \
+       $(EXECUTABLE_DIR)\allocate_module_test.exe \
+       $(EXECUTABLE_DIR)\assert_macro_test.exe \
+       $(EXECUTABLE_DIR)\customer_database_test.exe \
+       $(EXECUTABLE_DIR)\key_value_test.exe \
+       $(EXECUTABLE_DIR)\product_database_test.exe \
+       $(EXECUTABLE_DIR)\run_tests.exe
+
+clean:
+       -cmd /c "@for %A in (\
+               $(LIBRARY_DIR)\cmockery.lib \
+                       $(OBJECT_DIR)\cmockery.obj \
+               $(EXECUTABLE_DIR)\calculator.exe \
+                       $(OBJECT_DIR)\calculator.obj \
+               $(EXECUTABLE_DIR)\calculator_test.exe \
+                       $(OBJECT_DIR)\calculator_test.obj \
+                       $(OBJECT_DIR)\calculator_test-calculator.obj \
+               $(EXECUTABLE_DIR)\allocate_module_test.exe \
+                       $(OBJECT_DIR)\allocate_module_test.obj \
+                       $(OBJECT_DIR)\allocate_module.obj \
+               $(EXECUTABLE_DIR)\assert_macro_test.exe \
+                       $(OBJECT_DIR)\assert_macro_test.obj \
+                       $(OBJECT_DIR)\assert_macro.obj \
+               $(EXECUTABLE_DIR)\customer_database_test.exe \
+                       $(OBJECT_DIR)\customer_database_test.obj \
+                       $(OBJECT_DIR)\customer_database.obj \
+               $(EXECUTABLE_DIR)\key_value_test.exe \
+                       $(OBJECT_DIR)\key_value_test.obj \
+                       $(OBJECT_DIR)\key_value.obj \
+               $(EXECUTABLE_DIR)\product_database_test.exe \
+                       $(OBJECT_DIR)\product_database_test.obj \
+                       $(OBJECT_DIR)\product_database.obj \
+               $(EXECUTABLE_DIR)\run_tests.exe \
+                       $(OBJECT_DIR)\run_tests.obj) do @del %A 2>NUL"
+       -rmdir $(EXECUTABLE_DIR) $(OBJECT_DIR) $(LIBRARY_DIR) 2>NUL
+
+# Rules for the cmockery library.
+$(LIBRARY_DIR)\cmockery.lib: $(OBJECT_DIR)\cmockery.obj
+$(OBJECT_DIR)\cmockery.obj: $(LIBRARY_SOURCE_DIRECTORY)\cmockery.c
+
+# Rules for the calculator application.
+$(EXECUTABLE_DIR)\calculator.exe: $(OBJECT_DIR)\calculator.obj
+
+$(OBJECT_DIR)\calculator.obj: $(EXAMPLE_SOURCE_DIRECTORY)\calculator.c
+       $(CC_COMMAND)
+
+# Rules for the calculator test application.
+$(EXECUTABLE_DIR)\calculator_test.exe: \
+               $(OBJECT_DIR)\calculator_test.obj \
+               $(OBJECT_DIR)\calculator_test-calculator.obj \
+               $(LIBRARY_DIR)\cmockery.lib
+       $(LINK_COMMAND)
+
+$(OBJECT_DIR)\calculator_test.obj: \
+       $(EXAMPLE_SOURCE_DIRECTORY)\calculator_test.c
+
+$(OBJECT_DIR)\calculator_test-calculator.obj: \
+       $(EXAMPLE_SOURCE_DIRECTORY)\calculator.c
+       $(CC_COMMAND_UNIT_TEST)
+
+# Sample code applications.
+$(EXECUTABLE_DIR)\allocate_module_test.exe: \
+               $(OBJECT_DIR)\allocate_module_test.obj \
+               $(OBJECT_DIR)\allocate_module.obj \
+               $(LIBRARY_DIR)\cmockery.lib
+       $(LINK_COMMAND)
+
+$(OBJECT_DIR)\allocate_module_test.obj: \
+       $(EXAMPLE_SOURCE_DIRECTORY)\allocate_module_test.c
+$(OBJECT_DIR)\allocate_module.obj: \
+       $(EXAMPLE_SOURCE_DIRECTORY)\allocate_module.c
+
+$(EXECUTABLE_DIR)\assert_macro_test.exe: \
+               $(OBJECT_DIR)\assert_macro_test.obj \
+               $(OBJECT_DIR)\assert_macro.obj \
+               $(LIBRARY_DIR)\cmockery.lib
+       $(LINK_COMMAND)
+
+$(OBJECT_DIR)\assert_macro_test.obj: \
+       $(EXAMPLE_SOURCE_DIRECTORY)\assert_macro_test.c
+$(OBJECT_DIR)\assert_macro.obj: $(EXAMPLE_SOURCE_DIRECTORY)\assert_macro.c
+
+$(EXECUTABLE_DIR)\customer_database_test.exe: \
+               $(OBJECT_DIR)\customer_database_test.obj \
+               $(OBJECT_DIR)\customer_database.obj \
+               $(LIBRARY_DIR)\cmockery.lib
+       $(LINK_COMMAND)
+
+$(OBJECT_DIR)\customer_database_test.obj: \
+       $(EXAMPLE_SOURCE_DIRECTORY)\customer_database_test.c
+$(OBJECT_DIR)\customer_database.obj: \
+       $(EXAMPLE_SOURCE_DIRECTORY)\customer_database.c
+
+$(EXECUTABLE_DIR)\key_value_test.exe: \
+               $(OBJECT_DIR)\key_value_test.obj \
+               $(OBJECT_DIR)\key_value.obj \
+               $(LIBRARY_DIR)\cmockery.lib
+       $(LINK_COMMAND)
+
+$(OBJECT_DIR)\key_value_test.obj: $(EXAMPLE_SOURCE_DIRECTORY)\key_value_test.c
+$(OBJECT_DIR)\key_value.obj: $(EXAMPLE_SOURCE_DIRECTORY)\key_value.c
+
+$(EXECUTABLE_DIR)\product_database_test.exe: \
+               $(OBJECT_DIR)\product_database_test.obj \
+               $(OBJECT_DIR)\product_database.obj \
+               $(LIBRARY_DIR)\cmockery.lib
+       $(LINK_COMMAND)
+
+$(OBJECT_DIR)\product_database_test.obj: \
+       $(EXAMPLE_SOURCE_DIRECTORY)\product_database_test.c
+$(OBJECT_DIR)\product_database.obj: \
+       $(EXAMPLE_SOURCE_DIRECTORY)\product_database.c
+
+$(EXECUTABLE_DIR)\run_tests.exe: \
+               $(OBJECT_DIR)\run_tests.obj $(LIBRARY_DIR)\cmockery.lib
+       $(LINK_COMMAND)
+
+$(OBJECT_DIR)\run_tests.obj: $(EXAMPLE_SOURCE_DIRECTORY)\run_tests.c
+
+# Inference rules.
+{$(OBJECT_DIR)\}.obj{$(EXECUTABLE_DIR)\}.exe:
+       $(LINK_COMMAND)
+
+{$(OBJECT_DIR)\}.obj{$(LIBRARY_DIR)\}.lib:
+       $(LIB_COMMAND)
+
+{$(LIBRARY_SOURCE_DIRECTORY)\}.c{$(OBJECT_DIR)\}.obj:
+       $(CC_COMMAND)
+
+{$(EXAMPLE_SOURCE_DIRECTORY)\}.c{$(OBJECT_DIR)\}.obj:
+       $(CC_COMMAND_UNIT_TEST)