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 00562 // Barrage tests 00563 void simple_barrage_test(int N) { 00564 equeue_t q; 00565 int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); 00566 test_assert(!err); 00567 00568 for (int i = 0; i < N; i++) { 00569 struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); 00570 test_assert(timing); 00571 00572 timing->tick = equeue_tick(); 00573 timing->delay = (i+1)*100; 00574 equeue_event_delay(timing, timing->delay); 00575 equeue_event_period(timing, timing->delay); 00576 00577 int id = equeue_post(&q, timing_func, timing); 00578 test_assert(id); 00579 } 00580 00581 equeue_dispatch(&q, N*100); 00582 00583 equeue_destroy(&q); 00584 } 00585 00586 void fragmenting_barrage_test(int N) { 00587 equeue_t q; 00588 int err = equeue_create(&q, 00589 2*N*(EQUEUE_EVENT_SIZE+sizeof(struct fragment)+N*sizeof(int))); 00590 test_assert(!err); 00591 00592 for (int i = 0; i < N; i++) { 00593 size_t size = sizeof(struct fragment) + i*sizeof(int); 00594 struct fragment *fragment = equeue_alloc(&q, size); 00595 test_assert(fragment); 00596 00597 fragment->q = &q; 00598 fragment->size = size; 00599 fragment->timing.tick = equeue_tick(); 00600 fragment->timing.delay = (i+1)*100; 00601 equeue_event_delay(fragment, fragment->timing.delay); 00602 00603 int id = equeue_post(&q, fragment_func, fragment); 00604 test_assert(id); 00605 } 00606 00607 equeue_dispatch(&q, N*100); 00608 00609 equeue_destroy(&q); 00610 } 00611 00612 struct ethread { 00613 pthread_t thread; 00614 equeue_t *q; 00615 int ms; 00616 }; 00617 00618 static void *ethread_dispatch(void *p) { 00619 struct ethread *t = (struct ethread*)p; 00620 equeue_dispatch(t->q, t->ms); 00621 return 0; 00622 } 00623 00624 void multithreaded_barrage_test(int N) { 00625 equeue_t q; 00626 int err = equeue_create(&q, N*(EQUEUE_EVENT_SIZE+sizeof(struct timing))); 00627 test_assert(!err); 00628 00629 struct ethread t; 00630 t.q = &q; 00631 t.ms = N*100; 00632 err = pthread_create(&t.thread, 0, ethread_dispatch, &t); 00633 test_assert(!err); 00634 00635 for (int i = 0; i < N; i++) { 00636 struct timing *timing = equeue_alloc(&q, sizeof(struct timing)); 00637 test_assert(timing); 00638 00639 timing->tick = equeue_tick(); 00640 timing->delay = (i+1)*100; 00641 equeue_event_delay(timing, timing->delay); 00642 equeue_event_period(timing, timing->delay); 00643 00644 int id = equeue_post(&q, timing_func, timing); 00645 test_assert(id); 00646 } 00647 00648 err = pthread_join(t.thread, 0); 00649 test_assert(!err); 00650 00651 equeue_destroy(&q); 00652 } 00653 00654 00655 int main() { 00656 printf("beginning tests...\n"); 00657 00658 test_run(simple_call_test); 00659 test_run(simple_call_in_test); 00660 test_run(simple_call_every_test); 00661 test_run(simple_post_test); 00662 test_run(destructor_test); 00663 test_run(allocation_failure_test); 00664 test_run(cancel_test, 20); 00665 test_run(cancel_inflight_test); 00666 test_run(cancel_unnecessarily_test); 00667 test_run(loop_protect_test); 00668 test_run(break_test); 00669 test_run(period_test); 00670 test_run(nested_test); 00671 test_run(sloth_test); 00672 test_run(background_test); 00673 test_run(chain_test); 00674 test_run(multithread_test); 00675 test_run(simple_barrage_test, 20); 00676 test_run(fragmenting_barrage_test, 20); 00677 test_run(multithreaded_barrage_test, 20); 00678 00679 printf("done!\n"); 00680 return test_failure; 00681 }
Generated on Tue Jul 12 2022 17:34:58 by
1.7.2