BA / Mbed OS BaBoRo1
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers tests.c Source File

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 }