├── .travis.yml ├── LICENSE ├── Makefile ├── README.rst ├── arrayqueue.c ├── arrayqueue.h ├── package.json └── tests ├── CuTest.c ├── CuTest.h ├── make-tests.sh └── test_arrayqueue.c /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | script: 3 | - make 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, 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 = -Itests -I. -g -O2 -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 arrayqueue.o tests/test_arrayqueue.c tests/CuTest.c main.c 13 | $(CC) $(CCFLAGS) -o $@ $^ 14 | ./test 15 | gcov main.c test_arrayqueue.c arrayqueue.c 16 | 17 | arrayqueue.o: arrayqueue.c 18 | $(CC) $(CCFLAGS) -c -o $@ $^ 19 | 20 | clean: 21 | rm -f main.c arrayqueue.o test $(GCOV_OUTPUT) 22 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. image:: https://travis-ci.org/willemt/arrayqueue.png 2 | :target: https://travis-ci.org/willemt/arrayqueue 3 | 4 | What? 5 | ----- 6 | A queue that uses an array instead of a linked list. 7 | 8 | Benefits of using an array: 9 | 10 | * helps prevent unnecessary malloc/free calls you'll usually find in a linked list implementation 11 | * reduces the likelihood of cache misses 12 | -------------------------------------------------------------------------------- /arrayqueue.c: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Copyright (c) 2014, Willem-Hendrik Thiart 4 | * Use of this source code is governed by a BSD-style license that can be 5 | * found in the LICENSE file. 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "arrayqueue.h" 13 | 14 | void aqueue_init(arrayqueue_t* me, size_t size, size_t m_size) 15 | { 16 | me->m_size = m_size; 17 | me->size = size; 18 | me->count = 0; 19 | me->back = me->front = 0; 20 | } 21 | 22 | void* aqueue_array(arrayqueue_t* me) 23 | { 24 | return (void*)me + sizeof(arrayqueue_t); 25 | } 26 | 27 | arrayqueue_t* aqueue_new(size_t size, size_t m_size) 28 | { 29 | arrayqueue_t *me = malloc(aqueue_sizeof(size, m_size)); 30 | 31 | if (!me) 32 | return NULL; 33 | 34 | aqueue_init(me, size, m_size); 35 | 36 | return me; 37 | } 38 | 39 | size_t aqueue_sizeof(size_t size, size_t m_size) 40 | { 41 | return sizeof(arrayqueue_t) + size * m_size; 42 | } 43 | 44 | int aqueue_is_empty(const arrayqueue_t * me) 45 | { 46 | return 0 == me->count; 47 | } 48 | 49 | int aqueue_is_full(arrayqueue_t * me) 50 | { 51 | return me->size == me->count; 52 | } 53 | 54 | static arrayqueue_t* __ensurecapacity(arrayqueue_t * me) 55 | { 56 | if (me->count < me->size) 57 | return me; 58 | 59 | arrayqueue_t *new = malloc(aqueue_sizeof(me->size * 2, me->m_size)); 60 | 61 | size_t ii, jj; 62 | for (ii = 0, jj = me->front; ii < me->count; ii++, jj++) 63 | { 64 | if (jj == me->size) 65 | jj = 0; 66 | memcpy(aqueue_array(new) + ii * me->m_size, aqueue_array(me) + jj * me->m_size, 67 | me->m_size); 68 | } 69 | 70 | new->m_size = me->m_size; 71 | new->size = me->size * 2; 72 | new->front = 0; 73 | new->count = new->back = me->count; 74 | free(me); 75 | return new; 76 | } 77 | 78 | void *aqueue_peek(arrayqueue_t * me) 79 | { 80 | if (aqueue_is_empty(me)) 81 | return NULL; 82 | return aqueue_array(me) + me->front * me->m_size; 83 | } 84 | 85 | int aqueue_poll(arrayqueue_t * me) 86 | { 87 | if (aqueue_is_empty(me)) 88 | return -1; 89 | 90 | me->front++; 91 | if (me->size == me->front) 92 | me->front = 0; 93 | me->count--; 94 | return 0; 95 | } 96 | 97 | int aqueue_offerensure(arrayqueue_t **me_ptr, void *item) 98 | { 99 | if (NULL == (*me_ptr = __ensurecapacity(*me_ptr))) 100 | return -1; 101 | 102 | arrayqueue_t* me = *me_ptr; 103 | 104 | memcpy(aqueue_array(me) + me->back * me->m_size, item, me->m_size); 105 | me->count++; 106 | me->back++; 107 | 108 | if (!aqueue_is_full(me) && me->size == me->back) 109 | me->back = 0; 110 | return 0; 111 | } 112 | 113 | int aqueue_offer(arrayqueue_t *me, void *item) 114 | { 115 | if (aqueue_is_full(me)) 116 | return -1; 117 | 118 | memcpy(aqueue_array(me) + me->back * me->m_size, item, me->m_size); 119 | me->count++; 120 | me->back++; 121 | 122 | if (me->size == me->back) 123 | me->back = 0; 124 | return 0; 125 | } 126 | 127 | void aqueue_empty(arrayqueue_t * me) 128 | { 129 | me->front = me->back = me->count = 0; 130 | } 131 | 132 | void aqueue_free(arrayqueue_t * me) 133 | { 134 | free(me); 135 | } 136 | 137 | int aqueue_count(const arrayqueue_t * me) 138 | { 139 | return me->count; 140 | } 141 | 142 | int aqueue_size(const arrayqueue_t * me) 143 | { 144 | return me->count; 145 | } 146 | 147 | void* aqueue_get_from_idx(arrayqueue_t * me, int idx) 148 | { 149 | return aqueue_array(me) + ((me->front + idx) % me->size) * me->m_size; 150 | } 151 | 152 | int aqueue_iter_has_next(arrayqueue_t* me, arrayqueue_iter_t* iter) 153 | { 154 | if (iter->current == (int)me->back) 155 | return 0; 156 | return 1; 157 | } 158 | 159 | void *aqueue_iter_next(arrayqueue_t* me, arrayqueue_iter_t* iter) 160 | { 161 | if (!aqueue_iter_has_next(me, iter)) 162 | return NULL; 163 | 164 | if (iter->current == (int)me->size) 165 | iter->current = 0; 166 | 167 | void* item = aqueue_array(me) + iter->current * me->m_size; 168 | 169 | iter->current++; 170 | 171 | return item; 172 | } 173 | 174 | int aqueue_iter_has_next_reverse(arrayqueue_t* me, 175 | arrayqueue_iter_t* iter) 176 | { 177 | int end = me->front - 1; 178 | 179 | if (end < 0) 180 | end = me->size - 1; 181 | 182 | if (iter->current == end) 183 | return 0; 184 | 185 | return 1; 186 | } 187 | 188 | void *aqueue_iter_next_reverse(arrayqueue_t* me, 189 | arrayqueue_iter_t* iter) 190 | { 191 | if (!aqueue_iter_has_next_reverse(me, iter)) 192 | return NULL; 193 | 194 | void* val = aqueue_array(me) + iter->current * me->m_size; 195 | 196 | iter->current--; 197 | if (iter->current < 0) 198 | iter->current = me->size - 1; 199 | return val; 200 | } 201 | 202 | void aqueue_iter_reverse(arrayqueue_t* me, arrayqueue_iter_t* iter) 203 | { 204 | iter->current = me->back - 1; 205 | if (iter->current < 0) 206 | iter->current = me->size - 1; 207 | } 208 | 209 | void aqueue_iter(arrayqueue_t * me, arrayqueue_iter_t * iter) 210 | { 211 | iter->current = me->front; 212 | } 213 | -------------------------------------------------------------------------------- /arrayqueue.h: -------------------------------------------------------------------------------- 1 | #ifndef ARRAYqueue_H 2 | #define ARRAYqueue_H 3 | 4 | typedef struct 5 | { 6 | size_t m_size; /* size of member */ 7 | size_t size; /* size of array */ 8 | size_t count; /* the amount of items in the array */ 9 | size_t front, back; /* position of the queue */ 10 | } arrayqueue_t; 11 | 12 | typedef struct 13 | { 14 | int current; 15 | } arrayqueue_iter_t; 16 | 17 | /** 18 | * Create a new data structure and initialise it 19 | * 20 | * malloc()s space 21 | * 22 | * @param[in] size Initial size of queue 23 | * @return initialised queue */ 24 | arrayqueue_t* aqueue_new(size_t size, size_t m_size); 25 | 26 | /** 27 | * Create a new data structure and initialise it. 28 | * 29 | * No malloc()s are performed. 30 | * 31 | * @param[in] size Initial size of queue 32 | * @return initialised queue */ 33 | void aqueue_init(arrayqueue_t* qu, size_t size, size_t m_size); 34 | 35 | /** 36 | * @return number of bytes needed for a queue of this size. */ 37 | size_t aqueue_sizeof(size_t size, size_t m_size); 38 | 39 | /** 40 | * Is the queue empty? 41 | * 42 | * @return 1 if empty; otherwise 0 */ 43 | int aqueue_is_empty(const arrayqueue_t * qu); 44 | 45 | /** 46 | * @return oldest item in this queue. */ 47 | void *aqueue_peek(arrayqueue_t * qu); 48 | 49 | /** 50 | * Remove oldest item from queue. 51 | * 52 | * @return 0 on sucess; -1 on failure */ 53 | int aqueue_poll(arrayqueue_t * qu); 54 | 55 | /** 56 | * Add item 57 | * 58 | * Ensures that the queue can hold the item. 59 | * 60 | * NOTE: 61 | * malloc() possibly called. 62 | * The queue pointer will be changed if the queu needs to be enlarged. 63 | * 64 | * @param[in/out] qu_ptr Pointer to the queue. Changed when queue is enlarged. 65 | * @param[in] item The item to be added 66 | * @return 0 on success; -1 on failure */ 67 | int aqueue_offerensure(arrayqueue_t ** qu_ptr, void *item); 68 | 69 | /** 70 | * Add item 71 | * 72 | * An error will occur if there isn't enough space for this item. 73 | * 74 | * NOTE: 75 | * no malloc()s called. 76 | * 77 | * @param[in] item The item to be added 78 | * @return 0 on success; -1 on error */ 79 | int aqueue_offer(arrayqueue_t * qu, void *item); 80 | 81 | /** 82 | * Empty the queue */ 83 | void aqueue_empty(arrayqueue_t * qu); 84 | 85 | void aqueue_free(arrayqueue_t * qu); 86 | 87 | /** 88 | * @return number of items */ 89 | int aqueue_count(const arrayqueue_t * qu); 90 | 91 | int aqueue_size(const arrayqueue_t * qu); 92 | 93 | int aqueue_iter_has_next(arrayqueue_t* qu, arrayqueue_iter_t* iter); 94 | 95 | void *aqueue_iter_next(arrayqueue_t* qu, arrayqueue_iter_t* iter); 96 | 97 | int aqueue_iter_has_next_reverse(arrayqueue_t* qu, arrayqueue_iter_t* iter); 98 | 99 | void *aqueue_iter_next_reverse(arrayqueue_t* qu, arrayqueue_iter_t* iter); 100 | 101 | void aqueue_iter_reverse(arrayqueue_t* qu, arrayqueue_iter_t* iter); 102 | 103 | void aqueue_iter(arrayqueue_t * qu, arrayqueue_iter_t * iter); 104 | 105 | #endif /* ARRAYqueue_H */ 106 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arrayqueue", 3 | "version": "0.0.1", 4 | "repo": "willemt/arrayqueue", 5 | "description": "Queue implemented using an array", 6 | "keywords": ["queue"], 7 | "license": "BSD", 8 | "src": ["arrayqueue.c", "arrayqueue.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_arrayqueue.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "CuTest.h" 9 | 10 | #include "arrayqueue.h" 11 | 12 | void TestarrayQueue_new_is_empty( 13 | CuTest * tc 14 | ) 15 | { 16 | void *qu = aqueue_new(10, 1); 17 | CuAssertTrue(tc, aqueue_is_empty(qu)); 18 | aqueue_free(qu); 19 | } 20 | 21 | void TestarrayQueue_offer_adds_new_item( 22 | CuTest * tc 23 | ) 24 | { 25 | char *item = "testitem"; 26 | void *qu = aqueue_new(10, 8); 27 | 28 | aqueue_offer(qu, item); 29 | CuAssertTrue(tc, 1 == aqueue_count(qu)); 30 | aqueue_free(qu); 31 | } 32 | 33 | void TestarrayQueue_cannot_offer_over_capacity( 34 | CuTest * tc 35 | ) 36 | { 37 | char *item = "testitem"; 38 | void *qu = aqueue_new(1, 8); 39 | 40 | aqueue_offer(qu, item); 41 | CuAssertTrue(tc, -1 == aqueue_offer(qu, item)); 42 | CuAssertTrue(tc, 1 == aqueue_count(qu)); 43 | aqueue_free(qu); 44 | } 45 | 46 | void TestarrayQueue_peek_gets_head( 47 | CuTest * tc 48 | ) 49 | { 50 | char *item1 = "testitem1"; 51 | char *item2 = "testitem2"; 52 | void *qu = aqueue_new(10, 9); 53 | 54 | aqueue_offer(qu, item1); 55 | aqueue_offer(qu, item2); 56 | CuAssertTrue(tc, 0 == strncmp(item1, aqueue_peek(qu), 9)); 57 | aqueue_free(qu); 58 | } 59 | 60 | void TestarrayQueue_empty_empties_queue( 61 | CuTest * tc 62 | ) 63 | { 64 | char *item = "testitem"; 65 | void *qu = aqueue_new(10, 8); 66 | 67 | aqueue_offer(qu, item); 68 | aqueue_empty(qu); 69 | CuAssertTrue(tc, 0 == aqueue_count(qu)); 70 | CuAssertTrue(tc, aqueue_is_empty(qu)); 71 | aqueue_free(qu); 72 | } 73 | 74 | void TestarrayQueue_cant_poll_with_no_contents( 75 | CuTest * tc 76 | ) 77 | { 78 | char *item = "testitem"; 79 | void *qu = aqueue_new(10, 8); 80 | aqueue_offer(qu, item); 81 | CuAssertTrue(tc, 0 == strncmp(item, aqueue_peek(qu), 8)); 82 | CuAssertTrue(tc, 0 == aqueue_poll(qu)); 83 | CuAssertTrue(tc, 0 == aqueue_count(qu)); 84 | aqueue_free(qu); 85 | } 86 | 87 | void TestarrayQueue_offer_and_poll_item( 88 | CuTest * tc 89 | ) 90 | { 91 | char *item = "testitem"; 92 | void *qu = aqueue_new(10, 8); 93 | 94 | aqueue_offer(qu, item); 95 | CuAssertTrue(tc, 0 == strncmp(item, aqueue_peek(qu), 8)); 96 | CuAssertTrue(tc, 0 == aqueue_poll(qu)); 97 | aqueue_free(qu); 98 | } 99 | 100 | void TestarrayQueue_fifo( 101 | CuTest * tc 102 | ) 103 | { 104 | char *item = "testitem1", *item2 = "testitem2"; 105 | void *qu = aqueue_new(10, 9); 106 | 107 | aqueue_offer(qu, item); 108 | aqueue_offer(qu, item2); 109 | CuAssertTrue(tc, 0 == strncmp(item, aqueue_peek(qu), 9)); 110 | CuAssertTrue(tc, 0 == aqueue_poll(qu)); 111 | CuAssertTrue(tc, 0 == strncmp(item2, aqueue_peek(qu), 9)); 112 | CuAssertTrue(tc, 0 == aqueue_poll(qu)); 113 | aqueue_free(qu); 114 | } 115 | 116 | void TestarrayQueue_poll_offer_past_boundary( 117 | CuTest * tc 118 | ) 119 | { 120 | char *item1 = "testitem1"; 121 | char *item2 = "testitem2"; 122 | char *item3 = "testitem3"; 123 | void *qu = aqueue_new(2, 9); 124 | 125 | aqueue_offer(qu, item1); 126 | aqueue_offer(qu, item2); 127 | CuAssertTrue(tc, 0 == strncmp(item1, aqueue_peek(qu), 9)); 128 | CuAssertTrue(tc, 0 == aqueue_poll(qu)); 129 | CuAssertTrue(tc, 0 == strncmp(item2, aqueue_peek(qu), 9)); 130 | aqueue_offer(qu, item3); 131 | CuAssertTrue(tc, 0 == strncmp(item2, aqueue_peek(qu), 9)); 132 | CuAssertTrue(tc, 0 == aqueue_poll(qu)); 133 | CuAssertTrue(tc, 0 == strncmp(item3, aqueue_peek(qu), 9)); 134 | CuAssertTrue(tc, 0 == aqueue_poll(qu)); 135 | aqueue_free(qu); 136 | } 137 | 138 | void TestarrayQueue_offerensure_ensures_capacity( 139 | CuTest * tc 140 | ) 141 | { 142 | char *item = "testitem"; 143 | arrayqueue_t *qu = aqueue_new(1, 8); 144 | 145 | CuAssertTrue(tc, 0 == aqueue_offerensure(&qu, item)); 146 | CuAssertTrue(tc, 1 == aqueue_count(qu)); 147 | CuAssertTrue(tc, 1 == aqueue_size(qu)); 148 | CuAssertTrue(tc, 0 == aqueue_offerensure(&qu, item)); 149 | CuAssertTrue(tc, 2 == aqueue_count(qu)); 150 | CuAssertTrue(tc, 2 == aqueue_size(qu)); 151 | aqueue_free(qu); 152 | } 153 | 154 | void TestarrayQueue_iterator_iterates( 155 | CuTest * tc 156 | ) 157 | { 158 | char *item = "testitem"; 159 | char *item2 = "TESTITEM"; 160 | arrayqueue_t *qu = aqueue_new(1, 8); 161 | 162 | CuAssertTrue(tc, 0 == aqueue_offerensure(&qu, item)); 163 | CuAssertTrue(tc, 0 == aqueue_offerensure(&qu, item2)); 164 | 165 | arrayqueue_iter_t iter; 166 | aqueue_iter(qu, &iter); 167 | CuAssertTrue(tc, 1 == aqueue_iter_has_next(qu, &iter)); 168 | CuAssertTrue(tc, 0 == strncmp(item, aqueue_iter_next(qu, &iter), 8)); 169 | CuAssertTrue(tc, 1 == aqueue_iter_has_next(qu, &iter)); 170 | CuAssertTrue(tc, 0 == strncmp(item2, aqueue_iter_next(qu, &iter), 8)); 171 | CuAssertTrue(tc, 0 == aqueue_iter_has_next(qu, &iter)); 172 | aqueue_free(qu); 173 | } 174 | --------------------------------------------------------------------------------