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 period_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, 10, simple_func, &count); 00401 00402 equeue_dispatch(&q, 55); 00403 test_assert(count == 5); 00404 00405 equeue_destroy(&q); 00406 } 00407 00408 void nested_test(void) { 00409 equeue_t q; 00410 int err = equeue_create(&q, 2048); 00411 test_assert(!err); 00412 00413 int touched = 0; 00414 struct nest *nest = equeue_alloc(&q, sizeof(struct nest)); 00415 test_assert(nest); 00416 nest->q = &q; 00417 nest->cb = simple_func; 00418 nest->data = &touched; 00419 00420 int id = equeue_post(&q, nest_func, nest); 00421 test_assert(id); 00422 00423 equeue_dispatch(&q, 5); 00424 test_assert(touched == 0); 00425 00426 equeue_dispatch(&q, 5); 00427 test_assert(touched == 1); 00428 00429 touched = 0; 00430 nest = equeue_alloc(&q, sizeof(struct nest)); 00431 test_assert(nest); 00432 nest->q = &q; 00433 nest->cb = simple_func; 00434 nest->data = &touched; 00435 00436 id = equeue_post(&q, nest_func, nest); 00437 test_assert(id); 00438 00439 equeue_dispatch(&q, 20); 00440 test_assert(touched == 1); 00441 00442 equeue_destroy(&q); 00443 } 00444 00445 void sloth_test(void) { 00446 equeue_t q; 00447 int err = equeue_create(&q, 2048); 00448 test_assert(!err); 00449 00450 int touched = 0; 00451 int id = equeue_call(&q, sloth_func, &touched); 00452 test_assert(id); 00453 00454 id = equeue_call_in(&q, 5, simple_func, &touched); 00455 test_assert(id); 00456 00457 id = equeue_call_in(&q, 15, simple_func, &touched); 00458 test_assert(id); 00459 00460 equeue_dispatch(&q, 20); 00461 test_assert(touched == 3); 00462 00463 equeue_destroy(&q); 00464 } 00465 00466 void *multithread_thread(void *p) { 00467 equeue_t *q = (equeue_t *)p; 00468 equeue_dispatch(q, -1); 00469 return 0; 00470 } 00471 00472 void multithread_test(void) { 00473 equeue_t q; 00474 int err = equeue_create(&q, 2048); 00475 test_assert(!err); 00476 00477 int touched = 0; 00478 equeue_call_every(&q, 1, simple_func, &touched); 00479 00480 pthread_t thread; 00481 err = pthread_create(&thread, 0, multithread_thread, &q); 00482 test_assert(!err); 00483 00484 usleep(10000); 00485 equeue_break(&q); 00486 err = pthread_join(thread, 0); 00487 test_assert(!err); 00488 00489 test_assert(touched); 00490 00491 equeue_destroy(&q); 00492 } 00493 00494 void background_func(void *p, int ms) { 00495 *(unsigned *)p = ms; 00496 } 00497 00498 void background_test(void) { 00499 equeue_t q; 00500 int err = equeue_create(&q, 2048); 00501 test_assert(!err); 00502 00503 int id = equeue_call_in(&q, 20, pass_func, 0); 00504 test_assert(id); 00505 00506 unsigned ms; 00507 equeue_background(&q, background_func, &ms); 00508 test_assert(ms == 20); 00509 00510 id = equeue_call_in(&q, 10, pass_func, 0); 00511 test_assert(id); 00512 test_assert(ms == 10); 00513 00514 id = equeue_call(&q, pass_func, 0); 00515 test_assert(id); 00516 test_assert(ms == 0); 00517 00518 equeue_dispatch(&q, 0); 00519 test_assert(ms == 10); 00520 00521 equeue_destroy(&q); 00522 test_assert(ms == -1); 00523 } 00524 00525 void chain_test(void) { 00526 equeue_t q1; 00527 int err = equeue_create(&q1, 2048); 00528 test_assert(!err); 00529 00530 equeue_t q2; 00531 err = equeue_create(&q2, 2048); 00532 test_assert(!err); 00533 00534 equeue_chain(&q2, &q1); 00535 00536 int touched = 0; 00537 00538 int id1 = equeue_call_in(&q1, 20, simple_func, &touched); 00539 int id2 = equeue_call_in(&q2, 20, simple_func, &touched); 00540 test_assert(id1 && id2); 00541 00542 id1 = equeue_call(&q1, simple_func, &touched); 00543 id2 = equeue_call(&q2, simple_func, &touched); 00544 test_assert(id1 && id2); 00545 00546 id1 = equeue_call_in(&q1, 5, simple_func, &touched); 00547 id2 = equeue_call_in(&q2, 5, simple_func, &touched); 00548 test_assert(id1 && id2); 00549 00550 equeue_cancel(&q1, id1); 00551 equeue_cancel(&q2, id2); 00552 00553 id1 = equeue_call_in(&q1, 10, simple_func, &touched); 00554 id2 = equeue_call_in(&q2, 10, simple_func, &touched); 00555 test_assert(id1 && id2); 00556 00557 equeue_dispatch(&q1, 30); 00558 00559 test_assert(touched == 6); 00560 00561 equeue_destroy(&q1); 00562 equeue_destroy(&q2); 00563 } 00564 00565 void unchain_test(void) { 00566 equeue_t q1; 00567 int err = equeue_create(&q1, 2048); 00568 test_assert(!err); 00569 00570 equeue_t q2; 00571 err = equeue_create(&q2, 2048); 00572 test_assert(!err); 00573 00574 equeue_chain(&q2, &q1); 00575 00576 int touched = 0; 00577 int id1 = equeue_call(&q1, simple_func, &touched); 00578 int id2 = equeue_call(&q2, simple_func, &touched); 00579 test_assert(id1 && id2); 00580 00581 equeue_dispatch(&q1, 0); 00582 test_assert(touched == 2); 00583 00584 equeue_chain(&q2, 0); 00585 equeue_chain(&q1, &q2); 00586 00587 id1 = equeue_call(&q1, simple_func, &touched); 00588 id2 = equeue_call(&q2, simple_func, &touched); 00589 test_assert(id1 && id2); 00590 00591 equeue_dispatch(&q2, 0); 00592 test_assert(touched == 4); 00593 00594 equeue_destroy(&q1); 00595 equeue_destroy(&q2); 00596 } 00597 00598 // Barrage tests 00599 void simple_barrage_test(int N) { 00600 equeue_t q; 00601 int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); 00602 test_assert(!err); 00603 00604 for (int i = 0; i < N; i++) { 00605 struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); 00606 test_assert(timing); 00607 00608 timing->tick = equeue_tick(); 00609 timing->delay = (i+1)*100; 00610 equeue_event_delay(timing, timing->delay); 00611 equeue_event_period(timing, timing->delay); 00612 00613 int id = equeue_post(&q, timing_func, timing); 00614 test_assert(id); 00615 } 00616 00617 equeue_dispatch(&q, N*100); 00618 00619 equeue_destroy(&q); 00620 } 00621 00622 void fragmenting_barrage_test(int N) { 00623 equeue_t q; 00624 int err = equeue_create(&q, 00625 2*N*(EQUEUE_EVENT_SIZE+sizeof(struct fragment)+N*sizeof(int))); 00626 test_assert(!err); 00627 00628 for (int i = 0; i < N; i++) { 00629 size_t size = sizeof(struct fragment) + i*sizeof(int); 00630 struct fragment *fragment = equeue_alloc(&q, size); 00631 test_assert(fragment); 00632 00633 fragment->q = &q; 00634 fragment->size = size; 00635 fragment->timing.tick = equeue_tick(); 00636 fragment->timing.delay = (i+1)*100; 00637 equeue_event_delay(fragment, fragment->timing.delay); 00638 00639 int id = equeue_post(&q, fragment_func, fragment); 00640 test_assert(id); 00641 } 00642 00643 equeue_dispatch(&q, N*100); 00644 00645 equeue_destroy(&q); 00646 } 00647 00648 struct ethread { 00649 pthread_t thread; 00650 equeue_t *q; 00651 int ms; 00652 }; 00653 00654 static void *ethread_dispatch(void *p) { 00655 struct ethread *t = (struct ethread*)p; 00656 equeue_dispatch(t->q, t->ms); 00657 return 0; 00658 } 00659 00660 void multithreaded_barrage_test(int N) { 00661 equeue_t q; 00662 int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); 00663 test_assert(!err); 00664 00665 struct ethread t; 00666 t.q = &q; 00667 t.ms = N*100; 00668 err = pthread_create(&t.thread, 0, ethread_dispatch, &t); 00669 test_assert(!err); 00670 00671 for (int i = 0; i < N; i++) { 00672 struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); 00673 test_assert(timing); 00674 00675 timing->tick = equeue_tick(); 00676 timing->delay = (i+1)*100; 00677 equeue_event_delay(timing, timing->delay); 00678 equeue_event_period(timing, timing->delay); 00679 00680 int id = equeue_post(&q, timing_func, timing); 00681 test_assert(id); 00682 } 00683 00684 err = pthread_join(t.thread, 0); 00685 test_assert(!err); 00686 00687 equeue_destroy(&q); 00688 } 00689 00690 00691 int main() { 00692 printf("beginning tests...\n"); 00693 00694 test_run(simple_call_test); 00695 test_run(simple_call_in_test); 00696 test_run(simple_call_every_test); 00697 test_run(simple_post_test); 00698 test_run(destructor_test); 00699 test_run(allocation_failure_test); 00700 test_run(cancel_test, 20); 00701 test_run(cancel_inflight_test); 00702 test_run(cancel_unnecessarily_test); 00703 test_run(loop_protect_test); 00704 test_run(break_test); 00705 test_run(period_test); 00706 test_run(nested_test); 00707 test_run(sloth_test); 00708 test_run(background_test); 00709 test_run(chain_test); 00710 test_run(unchain_test); 00711 test_run(multithread_test); 00712 test_run(simple_barrage_test, 20); 00713 test_run(fragmenting_barrage_test, 20); 00714 test_run(multithreaded_barrage_test, 20); 00715 00716 printf("done!\n"); 00717 return test_failure; 00718 }
Generated on Tue Jul 12 2022 13:31:35 by
