├── .travis.yml ├── LICENSE ├── Makefile ├── README.rst ├── heap.c ├── heap.h ├── package.json └── tests ├── CuTest.c ├── CuTest.h ├── make-tests.sh └── test_heap.c /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | script: 3 | - make 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Willem-Hendrik Thiart 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * The names of its contributors may not be used to endorse or promote 12 | products derived from this software without specific prior written 13 | permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL WILLEM-HENDRIK THIART BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GCOV_OUTPUT = *.gcda *.gcno *.gcov 2 | GCOV_CCFLAGS = -fprofile-arcs -ftest-coverage 3 | CC = gcc 4 | CCFLAGS = -I. -Itests -g -Wall -Werror -W -fno-omit-frame-pointer -fno-common -fsigned-char $(GCOV_CCFLAGS) 5 | 6 | 7 | all: test 8 | 9 | main.c: 10 | sh tests/make-tests.sh tests/test_*.c > main.c 11 | 12 | test: main.c heap.o tests/test_heap.c tests/CuTest.c main.c 13 | $(CC) $(CCFLAGS) -o $@ $^ 14 | ./test 15 | gcov heap.c 16 | 17 | heap.o: heap.c 18 | $(CC) $(CCFLAGS) -c -o $@ $^ 19 | 20 | clean: 21 | rm -f main.c heap.o $(GCOV_OUTPUT) 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. image:: https://travis-ci.org/willemt/heap.png 2 | :target: https://travis-ci.org/willemt/heap 3 | 4 | What? 5 | ----- 6 | A heap abstract data type implemented within an array. 7 | 8 | Written in C with a BSD license. 9 | 10 | How does it work? 11 | ----------------- 12 | To see the module in action check out: 13 | 14 | * Unit tests within test_heap.c 15 | 16 | Example usage 17 | ------------- 18 | http://github.com/willemt/YABTorrent/blob/master/src/bt_selector_rarestfirst.c 19 | 20 | Building 21 | -------- 22 | $make 23 | -------------------------------------------------------------------------------- /heap.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "heap.h" 8 | 9 | #define DEFAULT_CAPACITY 13 10 | 11 | struct heap_s 12 | { 13 | /* size of array */ 14 | unsigned int size; 15 | /* items within heap */ 16 | unsigned int count; 17 | /** user data */ 18 | const void *udata; 19 | int (*cmp) (const void *, const void *, const void *); 20 | void * array[]; 21 | }; 22 | 23 | size_t heap_sizeof(unsigned int size) 24 | { 25 | return sizeof(heap_t) + size * sizeof(void *); 26 | } 27 | 28 | static int __child_left(const int idx) 29 | { 30 | return idx * 2 + 1; 31 | } 32 | 33 | static int __child_right(const int idx) 34 | { 35 | return idx * 2 + 2; 36 | } 37 | 38 | static int __parent(const int idx) 39 | { 40 | return (idx - 1) / 2; 41 | } 42 | 43 | void heap_init(heap_t* h, 44 | int (*cmp) (const void *, 45 | const void *, 46 | const void *udata), 47 | const void *udata, 48 | unsigned int size 49 | ) 50 | { 51 | h->cmp = cmp; 52 | h->udata = udata; 53 | h->size = size; 54 | h->count = 0; 55 | } 56 | 57 | heap_t *heap_new(int (*cmp) (const void *, 58 | const void *, 59 | const void *udata), 60 | const void *udata) 61 | { 62 | heap_t *h = malloc(heap_sizeof(DEFAULT_CAPACITY)); 63 | 64 | if (!h) 65 | return NULL; 66 | 67 | heap_init(h, cmp, udata, DEFAULT_CAPACITY); 68 | 69 | return h; 70 | } 71 | 72 | void heap_free(heap_t * h) 73 | { 74 | free(h); 75 | } 76 | 77 | /** 78 | * @return a new heap on success; NULL otherwise */ 79 | static heap_t* __ensurecapacity(heap_t * h) 80 | { 81 | if (h->count < h->size) 82 | return h; 83 | 84 | h->size *= 2; 85 | 86 | return realloc(h, heap_sizeof(h->size)); 87 | } 88 | 89 | static void __swap(heap_t * h, const int i1, const int i2) 90 | { 91 | void *tmp = h->array[i1]; 92 | 93 | h->array[i1] = h->array[i2]; 94 | h->array[i2] = tmp; 95 | } 96 | 97 | static int __pushup(heap_t * h, unsigned int idx) 98 | { 99 | /* 0 is the root node */ 100 | while (0 != idx) 101 | { 102 | int parent = __parent(idx); 103 | 104 | /* we are smaller than the parent */ 105 | if (h->cmp(h->array[idx], h->array[parent], h->udata) < 0) 106 | return -1; 107 | else 108 | __swap(h, idx, parent); 109 | 110 | idx = parent; 111 | } 112 | 113 | return idx; 114 | } 115 | 116 | static void __pushdown(heap_t * h, unsigned int idx) 117 | { 118 | while (1) 119 | { 120 | unsigned int childl, childr, child; 121 | 122 | childl = __child_left(idx); 123 | childr = __child_right(idx); 124 | 125 | if (childr >= h->count) 126 | { 127 | /* can't pushdown any further */ 128 | if (childl >= h->count) 129 | return; 130 | 131 | child = childl; 132 | } 133 | /* find biggest child */ 134 | else if (h->cmp(h->array[childl], h->array[childr], h->udata) < 0) 135 | child = childr; 136 | else 137 | child = childl; 138 | 139 | /* idx is smaller than child */ 140 | if (h->cmp(h->array[idx], h->array[child], h->udata) < 0) 141 | { 142 | __swap(h, idx, child); 143 | idx = child; 144 | /* bigger than the biggest child, we stop, we win */ 145 | } 146 | else 147 | return; 148 | } 149 | } 150 | 151 | static void __heap_offerx(heap_t * h, void *item) 152 | { 153 | h->array[h->count] = item; 154 | 155 | /* ensure heap properties */ 156 | __pushup(h, h->count++); 157 | } 158 | 159 | int heap_offerx(heap_t * h, void *item) 160 | { 161 | if (h->count == h->size) 162 | return -1; 163 | __heap_offerx(h, item); 164 | return 0; 165 | } 166 | 167 | int heap_offer(heap_t ** h, void *item) 168 | { 169 | if (NULL == (*h = __ensurecapacity(*h))) 170 | return -1; 171 | 172 | __heap_offerx(*h, item); 173 | return 0; 174 | } 175 | 176 | void *heap_poll(heap_t * h) 177 | { 178 | if (0 == heap_count(h)) 179 | return NULL; 180 | 181 | void *item = h->array[0]; 182 | 183 | h->array[0] = h->array[h->count - 1]; 184 | h->count--; 185 | 186 | if (h->count > 1) 187 | __pushdown(h, 0); 188 | 189 | return item; 190 | } 191 | 192 | void *heap_peek(const heap_t * h) 193 | { 194 | if (0 == heap_count(h)) 195 | return NULL; 196 | 197 | return h->array[0]; 198 | } 199 | 200 | void heap_clear(heap_t * h) 201 | { 202 | h->count = 0; 203 | } 204 | 205 | /** 206 | * @return item's index on the heap's array; otherwise -1 */ 207 | static int __item_get_idx(const heap_t * h, const void *item) 208 | { 209 | unsigned int idx; 210 | 211 | for (idx = 0; idx < h->count; idx++) 212 | if (0 == h->cmp(h->array[idx], item, h->udata)) 213 | return idx; 214 | 215 | return -1; 216 | } 217 | 218 | void *heap_remove_item(heap_t * h, const void *item) 219 | { 220 | int idx = __item_get_idx(h, item); 221 | 222 | if (idx == -1) 223 | return NULL; 224 | 225 | /* swap the item we found with the last item on the heap */ 226 | void *ret_item = h->array[idx]; 227 | h->array[idx] = h->array[h->count - 1]; 228 | h->array[h->count - 1] = NULL; 229 | 230 | h->count -= 1; 231 | 232 | /* ensure heap property */ 233 | __pushup(h, idx); 234 | 235 | return ret_item; 236 | } 237 | 238 | int heap_contains_item(const heap_t * h, const void *item) 239 | { 240 | return __item_get_idx(h, item) != -1; 241 | } 242 | 243 | int heap_count(const heap_t * h) 244 | { 245 | return h->count; 246 | } 247 | 248 | int heap_size(const heap_t * h) 249 | { 250 | return h->size; 251 | } 252 | 253 | /*--------------------------------------------------------------79-characters-*/ 254 | -------------------------------------------------------------------------------- /heap.h: -------------------------------------------------------------------------------- 1 | #ifndef HEAP_H 2 | #define HEAP_H 3 | 4 | typedef struct heap_s heap_t; 5 | 6 | /** 7 | * Create new heap and initialise it. 8 | * 9 | * malloc()s space for heap. 10 | * 11 | * @param[in] cmp Callback used to get an item's priority 12 | * @param[in] udata User data passed through to cmp callback 13 | * @return initialised heap */ 14 | heap_t *heap_new(int (*cmp) (const void *, 15 | const void *, 16 | const void *udata), 17 | const void *udata); 18 | 19 | /** 20 | * Initialise heap. Use memory passed by user. 21 | * 22 | * No malloc()s are performed. 23 | * 24 | * @param[in] cmp Callback used to get an item's priority 25 | * @param[in] udata User data passed through to cmp callback 26 | * @param[in] size Initial size of the heap's array */ 27 | void heap_init(heap_t* h, 28 | int (*cmp) (const void *, 29 | const void *, 30 | const void *udata), 31 | const void *udata, 32 | unsigned int size); 33 | 34 | void heap_free(heap_t * hp); 35 | 36 | /** 37 | * Add item 38 | * 39 | * Ensures that the data structure can hold the item. 40 | * 41 | * NOTE: 42 | * realloc() possibly called. 43 | * The heap pointer will be changed if the heap needs to be enlarged. 44 | * 45 | * @param[in/out] hp_ptr Pointer to the heap. Changed when heap is enlarged. 46 | * @param[in] item The item to be added 47 | * @return 0 on success; -1 on failure */ 48 | int heap_offer(heap_t **hp_ptr, void *item); 49 | 50 | /** 51 | * Add item 52 | * 53 | * An error will occur if there isn't enough space for this item. 54 | * 55 | * NOTE: 56 | * no malloc()s called. 57 | * 58 | * @param[in] item The item to be added 59 | * @return 0 on success; -1 on error */ 60 | int heap_offerx(heap_t * hp, void *item); 61 | 62 | /** 63 | * Remove the item with the top priority 64 | * 65 | * @return top item */ 66 | void *heap_poll(heap_t * hp); 67 | 68 | /** 69 | * @return top item of the heap */ 70 | void *heap_peek(const heap_t * hp); 71 | 72 | /** 73 | * Clear all items 74 | * 75 | * NOTE: 76 | * Does not free items. 77 | * Only use if item memory is managed outside of heap */ 78 | void heap_clear(heap_t * hp); 79 | 80 | /** 81 | * @return number of items in heap */ 82 | int heap_count(const heap_t * hp); 83 | 84 | /** 85 | * @return size of array */ 86 | int heap_size(const heap_t * hp); 87 | 88 | /** 89 | * @return number of bytes needed for a heap of this size. */ 90 | size_t heap_sizeof(unsigned int size); 91 | 92 | /** 93 | * Remove item 94 | * 95 | * @param[in] item The item that is to be removed 96 | * @return item to be removed; NULL if item does not exist */ 97 | void *heap_remove_item(heap_t * hp, const void *item); 98 | 99 | /** 100 | * Test membership of item 101 | * 102 | * @param[in] item The item to test 103 | * @return 1 if the heap contains this item; otherwise 0 */ 104 | int heap_contains_item(const heap_t * hp, const void *item); 105 | 106 | #endif /* HEAP_H */ 107 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "heap", 3 | "version": "0.0.1", 4 | "repo": "willemt/heap", 5 | "description": "Heap priority queued", 6 | "keywords": ["heap", "priority queue", "queue"], 7 | "license": "BSD", 8 | "src": ["heap.c", "heap.h"] 9 | } 10 | -------------------------------------------------------------------------------- /tests/CuTest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "CuTest.h" 9 | 10 | /*-------------------------------------------------------------------------* 11 | * CuStr 12 | *-------------------------------------------------------------------------*/ 13 | 14 | char* CuStrAlloc(int size) 15 | { 16 | char* newStr = (char*) malloc( sizeof(char) * (size) ); 17 | return newStr; 18 | } 19 | 20 | char* CuStrCopy(const char* old) 21 | { 22 | int len = strlen(old); 23 | char* newStr = CuStrAlloc(len + 1); 24 | strcpy(newStr, old); 25 | return newStr; 26 | } 27 | 28 | /*-------------------------------------------------------------------------* 29 | * CuString 30 | *-------------------------------------------------------------------------*/ 31 | 32 | void CuStringInit(CuString* str) 33 | { 34 | str->length = 0; 35 | str->size = STRING_MAX; 36 | str->buffer = (char*) malloc(sizeof(char) * str->size); 37 | str->buffer[0] = '\0'; 38 | } 39 | 40 | CuString* CuStringNew(void) 41 | { 42 | CuString* str = (CuString*) malloc(sizeof(CuString)); 43 | str->length = 0; 44 | str->size = STRING_MAX; 45 | str->buffer = (char*) malloc(sizeof(char) * str->size); 46 | str->buffer[0] = '\0'; 47 | return str; 48 | } 49 | 50 | void CuStringResize(CuString* str, int newSize) 51 | { 52 | str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); 53 | str->size = newSize; 54 | } 55 | 56 | void CuStringAppend(CuString* str, const char* text) 57 | { 58 | int length; 59 | 60 | if (text == NULL) { 61 | text = "NULL"; 62 | } 63 | 64 | length = strlen(text); 65 | if (str->length + length + 1 >= str->size) 66 | CuStringResize(str, str->length + length + 1 + STRING_INC); 67 | str->length += length; 68 | strcat(str->buffer, text); 69 | } 70 | 71 | void CuStringAppendChar(CuString* str, char ch) 72 | { 73 | char text[2]; 74 | text[0] = ch; 75 | text[1] = '\0'; 76 | CuStringAppend(str, text); 77 | } 78 | 79 | void CuStringAppendFormat(CuString* str, const char* format, ...) 80 | { 81 | va_list argp; 82 | char buf[HUGE_STRING_LEN]; 83 | va_start(argp, format); 84 | vsprintf(buf, format, argp); 85 | va_end(argp); 86 | CuStringAppend(str, buf); 87 | } 88 | 89 | void CuStringInsert(CuString* str, const char* text, int pos) 90 | { 91 | int length = strlen(text); 92 | if (pos > str->length) 93 | pos = str->length; 94 | if (str->length + length + 1 >= str->size) 95 | CuStringResize(str, str->length + length + 1 + STRING_INC); 96 | memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1); 97 | str->length += length; 98 | memcpy(str->buffer + pos, text, length); 99 | } 100 | 101 | /*-------------------------------------------------------------------------* 102 | * CuTest 103 | *-------------------------------------------------------------------------*/ 104 | 105 | void CuTestInit(CuTest* t, const char* name, TestFunction function) 106 | { 107 | t->name = CuStrCopy(name); 108 | t->failed = 0; 109 | t->ran = 0; 110 | t->message = NULL; 111 | t->function = function; 112 | t->jumpBuf = NULL; 113 | } 114 | 115 | CuTest* CuTestNew(const char* name, TestFunction function) 116 | { 117 | CuTest* tc = CU_ALLOC(CuTest); 118 | CuTestInit(tc, name, function); 119 | return tc; 120 | } 121 | 122 | void CuTestRun(CuTest* tc) 123 | { 124 | printf(" running %s\n", tc->name); 125 | 126 | jmp_buf buf; 127 | tc->jumpBuf = &buf; 128 | if (setjmp(buf) == 0) 129 | { 130 | tc->ran = 1; 131 | (tc->function)(tc); 132 | } 133 | tc->jumpBuf = 0; 134 | } 135 | 136 | static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) 137 | { 138 | char buf[HUGE_STRING_LEN]; 139 | 140 | sprintf(buf, "%s:%d: ", file, line); 141 | CuStringInsert(string, buf, 0); 142 | 143 | tc->failed = 1; 144 | tc->message = string->buffer; 145 | if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0); 146 | } 147 | 148 | void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) 149 | { 150 | CuString string; 151 | 152 | CuStringInit(&string); 153 | if (message2 != NULL) 154 | { 155 | CuStringAppend(&string, message2); 156 | CuStringAppend(&string, ": "); 157 | } 158 | CuStringAppend(&string, message); 159 | CuFailInternal(tc, file, line, &string); 160 | } 161 | 162 | void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) 163 | { 164 | if (condition) return; 165 | CuFail_Line(tc, file, line, NULL, message); 166 | } 167 | 168 | void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 169 | const char* expected, const char* actual) 170 | { 171 | CuString string; 172 | if ((expected == NULL && actual == NULL) || 173 | (expected != NULL && actual != NULL && 174 | strcmp(expected, actual) == 0)) 175 | { 176 | return; 177 | } 178 | 179 | CuStringInit(&string); 180 | if (message != NULL) 181 | { 182 | CuStringAppend(&string, message); 183 | CuStringAppend(&string, ": "); 184 | } 185 | CuStringAppend(&string, "expected <"); 186 | CuStringAppend(&string, expected); 187 | CuStringAppend(&string, "> but was <"); 188 | CuStringAppend(&string, actual); 189 | CuStringAppend(&string, ">"); 190 | CuFailInternal(tc, file, line, &string); 191 | } 192 | 193 | void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 194 | int expected, int actual) 195 | { 196 | char buf[STRING_MAX]; 197 | if (expected == actual) return; 198 | sprintf(buf, "expected <%d> but was <%d>", expected, actual); 199 | CuFail_Line(tc, file, line, message, buf); 200 | } 201 | 202 | void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 203 | double expected, double actual, double delta) 204 | { 205 | char buf[STRING_MAX]; 206 | if (fabs(expected - actual) <= delta) return; 207 | sprintf(buf, "expected <%lf> but was <%lf>", expected, actual); 208 | CuFail_Line(tc, file, line, message, buf); 209 | } 210 | 211 | void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, 212 | void* expected, void* actual) 213 | { 214 | char buf[STRING_MAX]; 215 | if (expected == actual) return; 216 | sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual); 217 | CuFail_Line(tc, file, line, message, buf); 218 | } 219 | 220 | 221 | /*-------------------------------------------------------------------------* 222 | * CuSuite 223 | *-------------------------------------------------------------------------*/ 224 | 225 | void CuSuiteInit(CuSuite* testSuite) 226 | { 227 | testSuite->count = 0; 228 | testSuite->failCount = 0; 229 | } 230 | 231 | CuSuite* CuSuiteNew(void) 232 | { 233 | CuSuite* testSuite = CU_ALLOC(CuSuite); 234 | CuSuiteInit(testSuite); 235 | return testSuite; 236 | } 237 | 238 | void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) 239 | { 240 | assert(testSuite->count < MAX_TEST_CASES); 241 | testSuite->list[testSuite->count] = testCase; 242 | testSuite->count++; 243 | } 244 | 245 | void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) 246 | { 247 | int i; 248 | for (i = 0 ; i < testSuite2->count ; ++i) 249 | { 250 | CuTest* testCase = testSuite2->list[i]; 251 | CuSuiteAdd(testSuite, testCase); 252 | } 253 | } 254 | 255 | void CuSuiteRun(CuSuite* testSuite) 256 | { 257 | int i; 258 | for (i = 0 ; i < testSuite->count ; ++i) 259 | { 260 | CuTest* testCase = testSuite->list[i]; 261 | CuTestRun(testCase); 262 | if (testCase->failed) { testSuite->failCount += 1; } 263 | } 264 | } 265 | 266 | void CuSuiteSummary(CuSuite* testSuite, CuString* summary) 267 | { 268 | int i; 269 | for (i = 0 ; i < testSuite->count ; ++i) 270 | { 271 | CuTest* testCase = testSuite->list[i]; 272 | CuStringAppend(summary, testCase->failed ? "F" : "."); 273 | } 274 | CuStringAppend(summary, "\n\n"); 275 | } 276 | 277 | void CuSuiteDetails(CuSuite* testSuite, CuString* details) 278 | { 279 | int i; 280 | int failCount = 0; 281 | 282 | if (testSuite->failCount == 0) 283 | { 284 | int passCount = testSuite->count - testSuite->failCount; 285 | const char* testWord = passCount == 1 ? "test" : "tests"; 286 | CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord); 287 | } 288 | else 289 | { 290 | if (testSuite->failCount == 1) 291 | CuStringAppend(details, "There was 1 failure:\n"); 292 | else 293 | CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount); 294 | 295 | for (i = 0 ; i < testSuite->count ; ++i) 296 | { 297 | CuTest* testCase = testSuite->list[i]; 298 | if (testCase->failed) 299 | { 300 | failCount++; 301 | CuStringAppendFormat(details, "%d) %s: %s\n", 302 | failCount, testCase->name, testCase->message); 303 | } 304 | } 305 | CuStringAppend(details, "\n!!!FAILURES!!!\n"); 306 | 307 | CuStringAppendFormat(details, "Runs: %d ", testSuite->count); 308 | CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount); 309 | CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount); 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /tests/CuTest.h: -------------------------------------------------------------------------------- 1 | #ifndef CU_TEST_H 2 | #define CU_TEST_H 3 | 4 | #include 5 | #include 6 | 7 | /* CuString */ 8 | 9 | char* CuStrAlloc(int size); 10 | char* CuStrCopy(const char* old); 11 | 12 | #define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE))) 13 | 14 | #define HUGE_STRING_LEN 8192 15 | #define STRING_MAX 256 16 | #define STRING_INC 256 17 | 18 | typedef struct 19 | { 20 | int length; 21 | int size; 22 | char* buffer; 23 | } CuString; 24 | 25 | void CuStringInit(CuString* str); 26 | CuString* CuStringNew(void); 27 | void CuStringRead(CuString* str, const char* path); 28 | void CuStringAppend(CuString* str, const char* text); 29 | void CuStringAppendChar(CuString* str, char ch); 30 | void CuStringAppendFormat(CuString* str, const char* format, ...); 31 | void CuStringInsert(CuString* str, const char* text, int pos); 32 | void CuStringResize(CuString* str, int newSize); 33 | 34 | /* CuTest */ 35 | 36 | typedef struct CuTest CuTest; 37 | 38 | typedef void (*TestFunction)(CuTest *); 39 | 40 | struct CuTest 41 | { 42 | const char* name; 43 | TestFunction function; 44 | int failed; 45 | int ran; 46 | const char* message; 47 | jmp_buf *jumpBuf; 48 | }; 49 | 50 | void CuTestInit(CuTest* t, const char* name, TestFunction function); 51 | CuTest* CuTestNew(const char* name, TestFunction function); 52 | void CuTestRun(CuTest* tc); 53 | 54 | /* Internal versions of assert functions -- use the public versions */ 55 | void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message); 56 | void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition); 57 | void CuAssertStrEquals_LineMsg(CuTest* tc, 58 | const char* file, int line, const char* message, 59 | const char* expected, const char* actual); 60 | void CuAssertIntEquals_LineMsg(CuTest* tc, 61 | const char* file, int line, const char* message, 62 | int expected, int actual); 63 | void CuAssertDblEquals_LineMsg(CuTest* tc, 64 | const char* file, int line, const char* message, 65 | double expected, double actual, double delta); 66 | void CuAssertPtrEquals_LineMsg(CuTest* tc, 67 | const char* file, int line, const char* message, 68 | void* expected, void* actual); 69 | 70 | /* public assert functions */ 71 | 72 | #define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms)) 73 | #define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond)) 74 | #define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond)) 75 | 76 | #define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) 77 | #define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) 78 | #define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) 79 | #define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) 80 | #define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl)) 81 | #define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl)) 82 | #define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) 83 | #define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) 84 | 85 | #define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL)) 86 | #define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL)) 87 | 88 | /* CuSuite */ 89 | 90 | #define MAX_TEST_CASES 1024 91 | 92 | #define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST)) 93 | 94 | typedef struct 95 | { 96 | int count; 97 | CuTest* list[MAX_TEST_CASES]; 98 | int failCount; 99 | 100 | } CuSuite; 101 | 102 | 103 | void CuSuiteInit(CuSuite* testSuite); 104 | CuSuite* CuSuiteNew(void); 105 | void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase); 106 | void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2); 107 | void CuSuiteRun(CuSuite* testSuite); 108 | void CuSuiteSummary(CuSuite* testSuite, CuString* summary); 109 | void CuSuiteDetails(CuSuite* testSuite, CuString* details); 110 | 111 | #endif /* CU_TEST_H */ 112 | -------------------------------------------------------------------------------- /tests/make-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Auto generate single AllTests file for CuTest. 4 | # Searches through all *.c files in the current directory. 5 | # Prints to stdout. 6 | # Author: Asim Jalis 7 | # Date: 01/08/2003 8 | 9 | FILES=$1 10 | 11 | #if test $# -eq 0 ; then FILES=*.c ; else FILES=$* ; fi 12 | 13 | echo ' 14 | 15 | /* This is auto-generated code. Edit at your own peril. */ 16 | #include 17 | #include "CuTest.h" 18 | 19 | ' 20 | 21 | cat $FILES | grep '^void Test' | 22 | sed -e 's/(.*$//' \ 23 | -e 's/$/(CuTest*);/' \ 24 | -e 's/^/extern /' 25 | 26 | echo \ 27 | ' 28 | 29 | void RunAllTests(void) 30 | { 31 | CuString *output = CuStringNew(); 32 | CuSuite* suite = CuSuiteNew(); 33 | 34 | ' 35 | cat $FILES | grep '^void Test' | 36 | sed -e 's/^void //' \ 37 | -e 's/(.*$//' \ 38 | -e 's/^/ SUITE_ADD_TEST(suite, /' \ 39 | -e 's/$/);/' 40 | 41 | echo \ 42 | ' 43 | CuSuiteRun(suite); 44 | CuSuiteSummary(suite, output); 45 | CuSuiteDetails(suite, output); 46 | printf("%s\\n", output->buffer); 47 | } 48 | 49 | int main() 50 | { 51 | RunAllTests(); 52 | return 0; 53 | } 54 | ' 55 | -------------------------------------------------------------------------------- /tests/test_heap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "CuTest.h" 8 | 9 | #include "heap.h" 10 | 11 | static int __uint_compare( 12 | const void *e1, 13 | const void *e2, 14 | const void *udata __attribute__((__unused__)) 15 | ) 16 | { 17 | const int *i1 = e1; 18 | 19 | const int *i2 = e2; 20 | 21 | return *i2 - *i1; 22 | } 23 | 24 | void TestHeap_new_results_in_empty_heap( 25 | CuTest * tc 26 | ) 27 | { 28 | heap_t *hp = heap_new(NULL, NULL); 29 | 30 | CuAssertTrue(tc, 0 == heap_count(hp)); 31 | } 32 | 33 | void TestHeap_offer_accepts_null_item( 34 | CuTest * tc 35 | ) 36 | { 37 | heap_t *hp = heap_new(__uint_compare, NULL); 38 | 39 | heap_offer(&hp, NULL); 40 | CuAssertTrue(tc, 1 == heap_count(hp)); 41 | } 42 | 43 | void TestHeap_offerx_accepts_null_item( 44 | CuTest * tc 45 | ) 46 | { 47 | heap_t *hp = heap_new(__uint_compare, NULL); 48 | 49 | CuAssertTrue(tc, 0 == heap_offerx(hp, NULL)); 50 | CuAssertTrue(tc, 1 == heap_count(hp)); 51 | } 52 | 53 | void TestHeap_offer_adds_new_item( 54 | CuTest * tc 55 | ) 56 | { 57 | int val = 10; 58 | 59 | heap_t *hp = heap_new(__uint_compare, NULL); 60 | 61 | heap_offer(&hp, &val); 62 | CuAssertTrue(tc, 1 == heap_count(hp)); 63 | } 64 | 65 | void TestHeap_poll_on_empty_heap_returns_null( 66 | CuTest * tc 67 | ) 68 | { 69 | heap_t *hp = heap_new(__uint_compare, NULL); 70 | 71 | CuAssertTrue(tc, NULL == heap_poll(hp)); 72 | } 73 | 74 | void TestHeap_poll_removes_item( 75 | CuTest * tc 76 | ) 77 | { 78 | int val = 10; 79 | 80 | int *res; 81 | 82 | heap_t *hp = heap_new(__uint_compare, NULL); 83 | 84 | heap_offer(&hp, &val); 85 | res = heap_poll(hp); 86 | 87 | CuAssertTrue(tc, 0 == heap_count(hp)); 88 | CuAssertTrue(tc, res == &val); 89 | } 90 | 91 | void TestHeap_poll_removes_best_item( 92 | CuTest * tc 93 | ) 94 | { 95 | int vals[10] = { 9, 2, 5, 7, 4, 6, 3, 8, 1 }; 96 | int ii; 97 | 98 | heap_t *hp = heap_new(__uint_compare, NULL); 99 | 100 | for (ii = 0; ii < 9; ii++) 101 | heap_offer(&hp, &vals[ii]); 102 | CuAssertTrue(tc, 9 == heap_count(hp)); 103 | 104 | for (ii = 0; ii < 9; ii++) 105 | { 106 | int *res; 107 | 108 | res = heap_poll(hp); 109 | CuAssertTrue(tc, *res == ii + 1); 110 | } 111 | CuAssertTrue(tc, 0 == heap_count(hp)); 112 | 113 | heap_free(hp); 114 | } 115 | 116 | void TestHeap_remove_item_using_cmp_callback_works( 117 | CuTest * tc 118 | ) 119 | { 120 | heap_t *hp = heap_new(__uint_compare, NULL); 121 | 122 | int vals[10] = { 9, 2, 5, 7, 4, 6, 3, 8, 1 }; 123 | int ii; 124 | 125 | for (ii = 0; ii < 9; ii++) 126 | heap_offer(&hp, &vals[ii]); 127 | 128 | int *item = heap_remove_item(hp, &vals[0]); 129 | 130 | CuAssertTrue(tc, *item == 9); 131 | 132 | heap_free(hp); 133 | } 134 | 135 | void TestHeap_remove_item_using_cmp_callback_returns_null_for_missing_item( 136 | CuTest * tc 137 | ) 138 | { 139 | heap_t *hp = heap_new(__uint_compare, NULL); 140 | 141 | int vals[10] = { 9, 2, 5, 7, 4, 6, 3, 8, 1 }; 142 | int ii; 143 | 144 | for (ii = 1; ii < 9; ii++) 145 | heap_offer(&hp, &vals[ii]); 146 | 147 | CuAssertTrue(tc, NULL == heap_remove_item(hp, &vals[0])); 148 | 149 | heap_free(hp); 150 | } 151 | 152 | void TestHeap_contains_item_using_cmp_callback_works( 153 | CuTest * tc 154 | ) 155 | { 156 | int vals[10] = { 9, 2, 5, 7, 4, 6, 3, 8, 1 }; 157 | int ii; 158 | 159 | heap_t *hp = heap_new(__uint_compare, NULL); 160 | 161 | for (ii = 0; ii < 9; ii++) 162 | heap_offer(&hp, &vals[ii]); 163 | 164 | CuAssertTrue(tc, 1 == heap_contains_item(hp, &vals[2])); 165 | CuAssertTrue(tc, 1 == heap_contains_item(hp, &vals[1])); 166 | CuAssertTrue(tc, 1 == heap_contains_item(hp, &vals[0])); 167 | 168 | heap_free(hp); 169 | } 170 | 171 | void TestHeap_clear_removes_all_items( 172 | CuTest * tc 173 | ) 174 | { 175 | int vals[10] = { 9, 2, 5, 7, 4, 6, 3, 8, 1 }; 176 | int ii; 177 | 178 | heap_t *hp = heap_new(__uint_compare, NULL); 179 | 180 | for (ii = 0; ii < 9; ii++) 181 | heap_offer(&hp, &vals[ii]); 182 | 183 | heap_clear(hp); 184 | 185 | CuAssertTrue(tc, 0 == heap_count(hp)); 186 | CuAssertTrue(tc, 0 == heap_contains_item(hp, &vals[2])); 187 | CuAssertTrue(tc, 0 == heap_contains_item(hp, &vals[1])); 188 | CuAssertTrue(tc, 0 == heap_contains_item(hp, &vals[0])); 189 | 190 | heap_free(hp); 191 | } 192 | 193 | void TestHeap_peek_returns_null_if_heap_is_empty( 194 | CuTest * tc 195 | ) 196 | { 197 | heap_t *hp = heap_new(__uint_compare, NULL); 198 | 199 | CuAssertTrue(tc, NULL == heap_peek(hp)); 200 | 201 | heap_free(hp); 202 | } 203 | 204 | void TestHeap_peek_gets_best_item( 205 | CuTest * tc 206 | ) 207 | { 208 | int ii; 209 | int vals[10] = { 9, 2, 5, 7, 4, 6, 3, 8, 1 }; 210 | 211 | heap_t *hp = heap_new(__uint_compare, NULL); 212 | 213 | for (ii = 0; ii < 9; ii++) 214 | heap_offer(&hp, &vals[ii]); 215 | 216 | CuAssertTrue(tc, 1 == *(int*)heap_peek(hp)); 217 | 218 | heap_free(hp); 219 | } 220 | 221 | void TestHeap_offer_ensures_capacity_is_sufficient( 222 | CuTest * tc 223 | ) 224 | { 225 | heap_t *hp; 226 | int vals[3] = { 1, 2, 3 }; 227 | 228 | hp = malloc(heap_sizeof(1)); 229 | heap_init(hp, __uint_compare, NULL, 1); 230 | 231 | heap_offer(&hp, &vals[0]); 232 | CuAssertTrue(tc, NULL != hp); 233 | CuAssertTrue(tc, 1 == heap_size(hp)); 234 | heap_offer(&hp, &vals[1]); 235 | CuAssertTrue(tc, NULL != hp); 236 | CuAssertTrue(tc, 2 == heap_size(hp)); 237 | heap_offer(&hp, &vals[2]); 238 | CuAssertTrue(tc, NULL != hp); 239 | CuAssertTrue(tc, 4 == heap_size(hp)); 240 | CuAssertTrue(tc, 3 == heap_count(hp)); 241 | heap_free(hp); 242 | } 243 | 244 | void TestHeap_doubling_capacity_retains_items( 245 | CuTest * tc 246 | ) 247 | { 248 | int vals[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; 249 | int ii; 250 | 251 | heap_t *hp = heap_new(__uint_compare, NULL); 252 | 253 | for (ii = 0; ii < 15; ii++) 254 | heap_offer(&hp, &vals[ii]); 255 | 256 | CuAssertTrue(tc, 1 == heap_contains_item(hp, &vals[0])); 257 | 258 | heap_free(hp); 259 | } 260 | 261 | void TestHeap_offerx_fails_if_not_enough_capacity( 262 | CuTest * tc 263 | ) 264 | { 265 | heap_t *hp; 266 | int vals[3] = { 1, 2, 3 }; 267 | 268 | hp = alloca(heap_sizeof(2)); 269 | heap_init(hp, __uint_compare, NULL, 2); 270 | 271 | CuAssertTrue(tc, 0 == heap_offerx(hp, &vals[0])); 272 | CuAssertTrue(tc, 0 == heap_offerx(hp, &vals[1])); 273 | CuAssertTrue(tc, -1 == heap_offerx(hp, &vals[2])); 274 | CuAssertTrue(tc, 2 == heap_count(hp)); 275 | CuAssertTrue(tc, 0 == heap_contains_item(hp, &vals[2])); 276 | } 277 | --------------------------------------------------------------------------------