Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
tests.c
00001 /* 00002 * Testing framework for the events library 00003 * 00004 * Copyright (c) 2016 Christopher Haster 00005 * 00006 * Licensed under the Apache License, Version 2.0 (the "License"); 00007 * you may not use this file except in compliance with the License. 00008 * You may obtain a copy of the License at 00009 * 00010 * http://www.apache.org/licenses/LICENSE-2.0 00011 * 00012 * Unless required by applicable law or agreed to in writing, software 00013 * distributed under the License is distributed on an "AS IS" BASIS, 00014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 * See the License for the specific language governing permissions and 00016 * limitations under the License. 00017 */ 00018 #include "equeue.h" 00019 #include <unistd.h> 00020 #include <stdio.h> 00021 #include <setjmp.h> 00022 #include <stdint.h> 00023 #include <stdlib.h> 00024 #include <pthread.h> 00025 00026 00027 // Testing setup 00028 static jmp_buf test_buf; 00029 static int test_line; 00030 static int test_failure; 00031 00032 #define test_assert(test) ({ \ 00033 if (!(test)) { \ 00034 test_line = __LINE__; \ 00035 longjmp(test_buf, 1); \ 00036 } \ 00037 }) 00038 00039 #define test_run(func, ...) ({ \ 00040 printf("%s: ...", #func); \ 00041 fflush(stdout); \ 00042 \ 00043 if (!setjmp(test_buf)) { \ 00044 func(__VA_ARGS__); \ 00045 printf("\r%s: \e[32mpassed\e[0m\n", #func); \ 00046 } else { \ 00047 printf("\r%s: \e[31mfailed\e[0m at line %d\n", #func, test_line); \ 00048 test_failure = true; \ 00049 } \ 00050 }) 00051 00052 00053 // Test functions 00054 void pass_func(void *eh) { 00055 } 00056 00057 void simple_func(void *p) { 00058 (*(int *)p)++; 00059 } 00060 00061 void sloth_func(void *p) { 00062 usleep(10000); 00063 (*(int *)p)++; 00064 } 00065 00066 struct indirect { 00067 int *touched; 00068 uint8_t buffer[7]; 00069 }; 00070 00071 void indirect_func(void *p) { 00072 struct indirect *i = (struct indirect*)p; 00073 (*i->touched)++; 00074 } 00075 00076 struct timing { 00077 unsigned tick; 00078 unsigned delay; 00079 }; 00080 00081 void timing_func(void *p) { 00082 struct timing *timing = (struct timing*)p; 00083 unsigned tick = equeue_tick(); 00084 00085 unsigned t1 = timing->delay; 00086 unsigned t2 = tick - timing->tick; 00087 test_assert(t1 > t2 - 10 && t1 < t2 + 10); 00088 00089 timing->tick = tick; 00090 } 00091 00092 struct fragment { 00093 equeue_t *q; 00094 size_t size; 00095 struct timing timing; 00096 }; 00097 00098 void fragment_func(void *p) { 00099 struct fragment *fragment = (struct fragment*)p; 00100 timing_func(&fragment->timing); 00101 00102 struct fragment *nfragment = equeue_alloc(fragment->q, fragment->size); 00103 test_assert(nfragment); 00104 00105 *nfragment = *fragment; 00106 equeue_event_delay(nfragment, fragment->timing.delay); 00107 00108 int id = equeue_post(nfragment->q, fragment_func, nfragment); 00109 test_assert(id); 00110 } 00111 00112 struct cancel { 00113 equeue_t *q; 00114 int id; 00115 }; 00116 00117 void cancel_func(void *p) { 00118 struct cancel *cancel = (struct cancel *)p; 00119 equeue_cancel(cancel->q, cancel->id); 00120 } 00121 00122 struct nest { 00123 equeue_t *q; 00124 void (*cb)(void *); 00125 void *data; 00126 }; 00127 00128 void nest_func(void *p) { 00129 struct nest *nest = (struct nest *)p; 00130 equeue_call(nest->q, nest->cb, nest->data); 00131 00132 usleep(10000); 00133 } 00134 00135 00136 // Simple call tests 00137 void simple_call_test(void) { 00138 equeue_t q; 00139 int err = equeue_create(&q, 2048); 00140 test_assert(!err); 00141 00142 bool touched = false; 00143 equeue_call(&q, simple_func, &touched); 00144 equeue_dispatch(&q, 0); 00145 test_assert(touched); 00146 00147 equeue_destroy(&q); 00148 } 00149 00150 void simple_call_in_test(void) { 00151 equeue_t q; 00152 int err = equeue_create(&q, 2048); 00153 test_assert(!err); 00154 00155 bool touched = false; 00156 int id = equeue_call_in(&q, 10, simple_func, &touched); 00157 test_assert(id); 00158 00159 equeue_dispatch(&q, 15); 00160 test_assert(touched); 00161 00162 equeue_destroy(&q); 00163 } 00164 00165 void simple_call_every_test(void) { 00166 equeue_t q; 00167 int err = equeue_create(&q, 2048); 00168 test_assert(!err); 00169 00170 bool touched = false; 00171 int id = equeue_call_every(&q, 10, simple_func, &touched); 00172 test_assert(id); 00173 00174 equeue_dispatch(&q, 15); 00175 test_assert(touched); 00176 00177 equeue_destroy(&q); 00178 } 00179 00180 void simple_post_test(void) { 00181 equeue_t q; 00182 int err = equeue_create(&q, 2048); 00183 test_assert(!err); 00184 00185 int touched = false; 00186 struct indirect *i = equeue_alloc(&q, sizeof(struct indirect)); 00187 test_assert(i); 00188 00189 i->touched = &touched; 00190 int id = equeue_post(&q, indirect_func, i); 00191 test_assert(id); 00192 00193 equeue_dispatch(&q, 0); 00194 test_assert(*i->touched); 00195 00196 equeue_destroy(&q); 00197 } 00198 00199 // Misc tests 00200 void destructor_test(void) { 00201 equeue_t q; 00202 int err = equeue_create(&q, 2048); 00203 test_assert(!err); 00204 00205 int touched; 00206 struct indirect *e; 00207 int ids[3]; 00208 00209 touched = 0; 00210 for (int i = 0; i < 3; i++) { 00211 e = equeue_alloc(&q, sizeof(struct indirect)); 00212 test_assert(e); 00213 00214 e->touched = &touched; 00215 equeue_event_dtor(e, indirect_func); 00216 int id = equeue_post(&q, pass_func, e); 00217 test_assert(id); 00218 } 00219 00220 equeue_dispatch(&q, 0); 00221 test_assert(touched == 3); 00222 00223 touched = 0; 00224 for (int i = 0; i < 3; i++) { 00225 e = equeue_alloc(&q, sizeof(struct indirect)); 00226 test_assert(e); 00227 00228 e->touched = &touched; 00229 equeue_event_dtor(e, indirect_func); 00230 ids[i] = equeue_post(&q, pass_func, e); 00231 test_assert(ids[i]); 00232 } 00233 00234 for (int i = 0; i < 3; i++) { 00235 equeue_cancel(&q, ids[i]); 00236 } 00237 00238 equeue_dispatch(&q, 0); 00239 test_assert(touched == 3); 00240 00241 touched = 0; 00242 for (int i = 0; i < 3; i++) { 00243 e = equeue_alloc(&q, sizeof(struct indirect)); 00244 test_assert(e); 00245 00246 e->touched = &touched; 00247 equeue_event_dtor(e, indirect_func); 00248 int id = equeue_post(&q, pass_func, e); 00249 test_assert(id); 00250 } 00251 00252 equeue_destroy(&q); 00253 test_assert(touched == 3); 00254 } 00255 00256 void allocation_failure_test(void) { 00257 equeue_t q; 00258 int err = equeue_create(&q, 2048); 00259 test_assert(!err); 00260 00261 void *p = equeue_alloc(&q, 4096); 00262 test_assert(!p); 00263 00264 for (int i = 0; i < 100; i++) { 00265 p = equeue_alloc(&q, 0); 00266 } 00267 test_assert(!p); 00268 00269 equeue_destroy(&q); 00270 } 00271 00272 void cancel_test(int N) { 00273 equeue_t q; 00274 int err = equeue_create(&q, 2048); 00275 test_assert(!err); 00276 00277 bool touched = false; 00278 int *ids = malloc(N*sizeof(int)); 00279 00280 for (int i = 0; i < N; i++) { 00281 ids[i] = equeue_call(&q, simple_func, &touched); 00282 } 00283 00284 for (int i = N-1; i >= 0; i--) { 00285 equeue_cancel(&q, ids[i]); 00286 } 00287 00288 free(ids); 00289 00290 equeue_dispatch(&q, 0); 00291 test_assert(!touched); 00292 00293 equeue_destroy(&q); 00294 } 00295 00296 void cancel_inflight_test(void) { 00297 equeue_t q; 00298 int err = equeue_create(&q, 2048); 00299 test_assert(!err); 00300 00301 bool touched = false; 00302 00303 int id = equeue_call(&q, simple_func, &touched); 00304 equeue_cancel(&q, id); 00305 00306 equeue_dispatch(&q, 0); 00307 test_assert(!touched); 00308 00309 id = equeue_call(&q, simple_func, &touched); 00310 equeue_cancel(&q, id); 00311 00312 equeue_dispatch(&q, 0); 00313 test_assert(!touched); 00314 00315 struct cancel *cancel = equeue_alloc(&q, sizeof(struct cancel)); 00316 test_assert(cancel); 00317 cancel->q = &q; 00318 cancel->id = 0; 00319 00320 id = equeue_post(&q, cancel_func, cancel); 00321 test_assert(id); 00322 00323 cancel->id = equeue_call(&q, simple_func, &touched); 00324 00325 equeue_dispatch(&q, 0); 00326 test_assert(!touched); 00327 00328 equeue_destroy(&q); 00329 } 00330 00331 void cancel_unnecessarily_test(void) { 00332 equeue_t q; 00333 int err = equeue_create(&q, 2048); 00334 test_assert(!err); 00335 00336 int id = equeue_call(&q, pass_func, 0); 00337 for (int i = 0; i < 5; i++) { 00338 equeue_cancel(&q, id); 00339 } 00340 00341 id = equeue_call(&q, pass_func, 0); 00342 equeue_dispatch(&q, 0); 00343 for (int i = 0; i < 5; i++) { 00344 equeue_cancel(&q, id); 00345 } 00346 00347 bool touched = false; 00348 equeue_call(&q, simple_func, &touched); 00349 for (int i = 0; i < 5; i++) { 00350 equeue_cancel(&q, id); 00351 } 00352 00353 equeue_dispatch(&q, 0); 00354 test_assert(touched); 00355 00356 equeue_destroy(&q); 00357 } 00358 00359 void loop_protect_test(void) { 00360 equeue_t q; 00361 int err = equeue_create(&q, 2048); 00362 test_assert(!err); 00363 00364 bool touched = false; 00365 equeue_call_every(&q, 0, simple_func, &touched); 00366 00367 equeue_dispatch(&q, 0); 00368 test_assert(touched); 00369 00370 touched = false; 00371 equeue_call_every(&q, 1, simple_func, &touched); 00372 00373 equeue_dispatch(&q, 0); 00374 test_assert(touched); 00375 00376 equeue_destroy(&q); 00377 } 00378 00379 void break_test(void) { 00380 equeue_t q; 00381 int err = equeue_create(&q, 2048); 00382 test_assert(!err); 00383 00384 bool touched = false; 00385 equeue_call_every(&q, 0, simple_func, &touched); 00386 00387 equeue_break(&q); 00388 equeue_dispatch(&q, -1); 00389 test_assert(touched); 00390 00391 equeue_destroy(&q); 00392 } 00393 00394 void break_no_windup_test(void) { 00395 equeue_t q; 00396 int err = equeue_create(&q, 2048); 00397 test_assert(!err); 00398 00399 int count = 0; 00400 equeue_call_every(&q, 0, simple_func, &count); 00401 00402 equeue_break(&q); 00403 equeue_break(&q); 00404 equeue_dispatch(&q, -1); 00405 test_assert(count == 1); 00406 00407 count = 0; 00408 equeue_dispatch(&q, 55); 00409 test_assert(count > 1); 00410 00411 equeue_destroy(&q); 00412 } 00413 00414 void period_test(void) { 00415 equeue_t q; 00416 int err = equeue_create(&q, 2048); 00417 test_assert(!err); 00418 00419 int count = 0; 00420 equeue_call_every(&q, 10, simple_func, &count); 00421 00422 equeue_dispatch(&q, 55); 00423 test_assert(count == 5); 00424 00425 equeue_destroy(&q); 00426 } 00427 00428 void nested_test(void) { 00429 equeue_t q; 00430 int err = equeue_create(&q, 2048); 00431 test_assert(!err); 00432 00433 int touched = 0; 00434 struct nest *nest = equeue_alloc(&q, sizeof(struct nest)); 00435 test_assert(nest); 00436 nest->q = &q; 00437 nest->cb = simple_func; 00438 nest->data = &touched; 00439 00440 int id = equeue_post(&q, nest_func, nest); 00441 test_assert(id); 00442 00443 equeue_dispatch(&q, 5); 00444 test_assert(touched == 0); 00445 00446 equeue_dispatch(&q, 5); 00447 test_assert(touched == 1); 00448 00449 touched = 0; 00450 nest = equeue_alloc(&q, sizeof(struct nest)); 00451 test_assert(nest); 00452 nest->q = &q; 00453 nest->cb = simple_func; 00454 nest->data = &touched; 00455 00456 id = equeue_post(&q, nest_func, nest); 00457 test_assert(id); 00458 00459 equeue_dispatch(&q, 20); 00460 test_assert(touched == 1); 00461 00462 equeue_destroy(&q); 00463 } 00464 00465 void sloth_test(void) { 00466 equeue_t q; 00467 int err = equeue_create(&q, 2048); 00468 test_assert(!err); 00469 00470 int touched = 0; 00471 int id = equeue_call(&q, sloth_func, &touched); 00472 test_assert(id); 00473 00474 id = equeue_call_in(&q, 5, simple_func, &touched); 00475 test_assert(id); 00476 00477 id = equeue_call_in(&q, 15, simple_func, &touched); 00478 test_assert(id); 00479 00480 equeue_dispatch(&q, 20); 00481 test_assert(touched == 3); 00482 00483 equeue_destroy(&q); 00484 } 00485 00486 void *multithread_thread(void *p) { 00487 equeue_t *q = (equeue_t *)p; 00488 equeue_dispatch(q, -1); 00489 return 0; 00490 } 00491 00492 void multithread_test(void) { 00493 equeue_t q; 00494 int err = equeue_create(&q, 2048); 00495 test_assert(!err); 00496 00497 int touched = 0; 00498 equeue_call_every(&q, 1, simple_func, &touched); 00499 00500 pthread_t thread; 00501 err = pthread_create(&thread, 0, multithread_thread, &q); 00502 test_assert(!err); 00503 00504 usleep(10000); 00505 equeue_break(&q); 00506 err = pthread_join(thread, 0); 00507 test_assert(!err); 00508 00509 test_assert(touched); 00510 00511 equeue_destroy(&q); 00512 } 00513 00514 void background_func(void *p, int ms) { 00515 *(unsigned *)p = ms; 00516 } 00517 00518 void background_test(void) { 00519 equeue_t q; 00520 int err = equeue_create(&q, 2048); 00521 test_assert(!err); 00522 00523 int id = equeue_call_in(&q, 20, pass_func, 0); 00524 test_assert(id); 00525 00526 unsigned ms; 00527 equeue_background(&q, background_func, &ms); 00528 test_assert(ms == 20); 00529 00530 id = equeue_call_in(&q, 10, pass_func, 0); 00531 test_assert(id); 00532 test_assert(ms == 10); 00533 00534 id = equeue_call(&q, pass_func, 0); 00535 test_assert(id); 00536 test_assert(ms == 0); 00537 00538 equeue_dispatch(&q, 0); 00539 test_assert(ms == 10); 00540 00541 equeue_destroy(&q); 00542 test_assert(ms == -1); 00543 } 00544 00545 void chain_test(void) { 00546 equeue_t q1; 00547 int err = equeue_create(&q1, 2048); 00548 test_assert(!err); 00549 00550 equeue_t q2; 00551 err = equeue_create(&q2, 2048); 00552 test_assert(!err); 00553 00554 equeue_chain(&q2, &q1); 00555 00556 int touched = 0; 00557 00558 int id1 = equeue_call_in(&q1, 20, simple_func, &touched); 00559 int id2 = equeue_call_in(&q2, 20, simple_func, &touched); 00560 test_assert(id1 && id2); 00561 00562 id1 = equeue_call(&q1, simple_func, &touched); 00563 id2 = equeue_call(&q2, simple_func, &touched); 00564 test_assert(id1 && id2); 00565 00566 id1 = equeue_call_in(&q1, 5, simple_func, &touched); 00567 id2 = equeue_call_in(&q2, 5, simple_func, &touched); 00568 test_assert(id1 && id2); 00569 00570 equeue_cancel(&q1, id1); 00571 equeue_cancel(&q2, id2); 00572 00573 id1 = equeue_call_in(&q1, 10, simple_func, &touched); 00574 id2 = equeue_call_in(&q2, 10, simple_func, &touched); 00575 test_assert(id1 && id2); 00576 00577 equeue_dispatch(&q1, 30); 00578 00579 test_assert(touched == 6); 00580 00581 equeue_destroy(&q1); 00582 equeue_destroy(&q2); 00583 } 00584 00585 void unchain_test(void) { 00586 equeue_t q1; 00587 int err = equeue_create(&q1, 2048); 00588 test_assert(!err); 00589 00590 equeue_t q2; 00591 err = equeue_create(&q2, 2048); 00592 test_assert(!err); 00593 00594 equeue_chain(&q2, &q1); 00595 00596 int touched = 0; 00597 int id1 = equeue_call(&q1, simple_func, &touched); 00598 int id2 = equeue_call(&q2, simple_func, &touched); 00599 test_assert(id1 && id2); 00600 00601 equeue_dispatch(&q1, 0); 00602 test_assert(touched == 2); 00603 00604 equeue_chain(&q2, 0); 00605 equeue_chain(&q1, &q2); 00606 00607 id1 = equeue_call(&q1, simple_func, &touched); 00608 id2 = equeue_call(&q2, simple_func, &touched); 00609 test_assert(id1 && id2); 00610 00611 equeue_dispatch(&q2, 0); 00612 test_assert(touched == 4); 00613 00614 equeue_destroy(&q1); 00615 equeue_destroy(&q2); 00616 } 00617 00618 // Barrage tests 00619 void simple_barrage_test(int N) { 00620 equeue_t q; 00621 int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); 00622 test_assert(!err); 00623 00624 for (int i = 0; i < N; i++) { 00625 struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); 00626 test_assert(timing); 00627 00628 timing->tick = equeue_tick(); 00629 timing->delay = (i+1)*100; 00630 equeue_event_delay(timing, timing->delay); 00631 equeue_event_period(timing, timing->delay); 00632 00633 int id = equeue_post(&q, timing_func, timing); 00634 test_assert(id); 00635 } 00636 00637 equeue_dispatch(&q, N*100); 00638 00639 equeue_destroy(&q); 00640 } 00641 00642 void fragmenting_barrage_test(int N) { 00643 equeue_t q; 00644 int err = equeue_create(&q, 00645 2*N*(EQUEUE_EVENT_SIZE+sizeof(struct fragment)+N*sizeof(int))); 00646 test_assert(!err); 00647 00648 for (int i = 0; i < N; i++) { 00649 size_t size = sizeof(struct fragment) + i*sizeof(int); 00650 struct fragment *fragment = equeue_alloc(&q, size); 00651 test_assert(fragment); 00652 00653 fragment->q = &q; 00654 fragment->size = size; 00655 fragment->timing.tick = equeue_tick(); 00656 fragment->timing.delay = (i+1)*100; 00657 equeue_event_delay(fragment, fragment->timing.delay); 00658 00659 int id = equeue_post(&q, fragment_func, fragment); 00660 test_assert(id); 00661 } 00662 00663 equeue_dispatch(&q, N*100); 00664 00665 equeue_destroy(&q); 00666 } 00667 00668 struct ethread { 00669 pthread_t thread; 00670 equeue_t *q; 00671 int ms; 00672 }; 00673 00674 static void *ethread_dispatch(void *p) { 00675 struct ethread *t = (struct ethread*)p; 00676 equeue_dispatch(t->q, t->ms); 00677 return 0; 00678 } 00679 00680 void multithreaded_barrage_test(int N) { 00681 equeue_t q; 00682 int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); 00683 test_assert(!err); 00684 00685 struct ethread t; 00686 t.q = &q; 00687 t.ms = N*100; 00688 err = pthread_create(&t.thread, 0, ethread_dispatch, &t); 00689 test_assert(!err); 00690 00691 for (int i = 0; i < N; i++) { 00692 struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); 00693 test_assert(timing); 00694 00695 timing->tick = equeue_tick(); 00696 timing->delay = (i+1)*100; 00697 equeue_event_delay(timing, timing->delay); 00698 equeue_event_period(timing, timing->delay); 00699 00700 int id = equeue_post(&q, timing_func, timing); 00701 test_assert(id); 00702 } 00703 00704 err = pthread_join(t.thread, 0); 00705 test_assert(!err); 00706 00707 equeue_destroy(&q); 00708 } 00709 00710 struct count_and_queue 00711 { 00712 int p; 00713 equeue_t* q; 00714 }; 00715 00716 void simple_breaker(void *p) { 00717 struct count_and_queue* caq = (struct count_and_queue*)p; 00718 equeue_break(caq->q); 00719 usleep(10000); 00720 caq->p++; 00721 } 00722 00723 void break_request_cleared_on_timeout(void) { 00724 equeue_t q; 00725 int err = equeue_create(&q, 2048); 00726 test_assert(!err); 00727 00728 struct count_and_queue pq; 00729 pq.p = 0; 00730 pq.q = &q; 00731 00732 int id = equeue_call_every(&q, 10, simple_breaker, &pq); 00733 00734 equeue_dispatch(&q, 10); 00735 test_assert(pq.p == 1); 00736 00737 equeue_cancel(&q, id); 00738 00739 int count = 0; 00740 equeue_call_every(&q, 10, simple_func, &count); 00741 00742 equeue_dispatch(&q, 55); 00743 test_assert(count > 1); 00744 00745 equeue_destroy(&q); 00746 } 00747 00748 int main() { 00749 printf("beginning tests...\n"); 00750 00751 test_run(simple_call_test); 00752 test_run(simple_call_in_test); 00753 test_run(simple_call_every_test); 00754 test_run(simple_post_test); 00755 test_run(destructor_test); 00756 test_run(allocation_failure_test); 00757 test_run(cancel_test, 20); 00758 test_run(cancel_inflight_test); 00759 test_run(cancel_unnecessarily_test); 00760 test_run(loop_protect_test); 00761 test_run(break_test); 00762 test_run(break_no_windup_test); 00763 test_run(period_test); 00764 test_run(nested_test); 00765 test_run(sloth_test); 00766 test_run(background_test); 00767 test_run(chain_test); 00768 test_run(unchain_test); 00769 test_run(multithread_test); 00770 test_run(simple_barrage_test, 20); 00771 test_run(fragmenting_barrage_test, 20); 00772 test_run(multithreaded_barrage_test, 20); 00773 test_run(break_request_cleared_on_timeout); 00774 00775 printf("done!\n"); 00776 return test_failure; 00777 }
Generated on Tue Jul 12 2022 12:22:24 by
