diff options
author | coreglitch <mail@s3f.ru> | 2020-10-10 13:32:06 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-10 13:32:06 +0300 |
commit | 176e608c6de18734a5bc4094f5e0fa72a776f0ac (patch) | |
tree | f438f22c853f6d43cd13c476bf668551bd0ab070 /applications/tests | |
parent | aa3ac5b2424f930baf331eef285ed3bfc6c65741 (diff) |
Add minunit test framework (#168)
* add minunit tests
* fix logging
* ignore unexisting time service on embedded targets
* fix warning, issue with printf
* add exitcode
* migrate to printf
* indicate test by leds
* add testing description
* redesigned minunit tests to allow testing in separate files
* add test step for local target
* add failure test
* add restore test_check
* testing description
Co-authored-by: rusdacent <rusdacentx0x08@gmail.com>
Co-authored-by: DrZlo13 <who.just.the.doctor@gmail.com>
Diffstat (limited to 'applications/tests')
-rw-r--r-- | applications/tests/furi_record_test.c | 88 | ||||
-rw-r--r-- | applications/tests/furiac_test.c | 14 | ||||
-rw-r--r-- | applications/tests/minunit.h | 562 | ||||
-rw-r--r-- | applications/tests/minunit_test.c | 77 | ||||
-rw-r--r-- | applications/tests/minunit_vars.h | 15 | ||||
-rw-r--r-- | applications/tests/minunit_vars_ex.h | 15 | ||||
-rw-r--r-- | applications/tests/test_index.c | 78 |
7 files changed, 741 insertions, 108 deletions
diff --git a/applications/tests/furi_record_test.c b/applications/tests/furi_record_test.c index f59d5c62..b8d0b66f 100644 --- a/applications/tests/furi_record_test.c +++ b/applications/tests/furi_record_test.c @@ -22,10 +22,10 @@ void pipe_record_cb(const void* value, size_t size, void* ctx) { pipe_record_value = *((uint8_t*)value); } -bool test_furi_pipe_record(FuriRecordSubscriber* log) { +bool test_furi_pipe_record() { // 1. create pipe record if(!furi_create("test/pipe", NULL, 0)) { - fuprintf(log, "cannot create record\n"); + printf("cannot create record\n"); return false; } @@ -33,27 +33,27 @@ bool test_furi_pipe_record(FuriRecordSubscriber* log) { FuriRecordSubscriber* pipe_record = furi_open("test/pipe", false, false, pipe_record_cb, NULL, NULL); if(pipe_record == NULL) { - fuprintf(log, "cannot open record\n"); + printf("cannot open record\n"); return false; } const uint8_t WRITE_VALUE = 1; // 3. write data if(!furi_write(pipe_record, &WRITE_VALUE, sizeof(uint8_t))) { - fuprintf(log, "cannot write to record\n"); + printf("cannot write to record\n"); return false; } // 4. check that subscriber get data if(pipe_record_value != WRITE_VALUE) { - fuprintf(log, "wrong value (get %d, write %d)\n", pipe_record_value, WRITE_VALUE); + printf("wrong value (get %d, write %d)\n", pipe_record_value, WRITE_VALUE); return false; } // 5. try to read, get error uint8_t read_value = 0; if(furi_read(pipe_record, &read_value, sizeof(uint8_t))) { - fuprintf(log, "reading from pipe record not allowed\n"); + printf("reading from pipe record not allowed\n"); return false; } @@ -62,7 +62,7 @@ bool test_furi_pipe_record(FuriRecordSubscriber* log) { // 7. try to write, get error if(furi_write(pipe_record, &WRITE_VALUE, sizeof(uint8_t))) { - fuprintf(log, "writing to closed record not allowed\n"); + printf("writing to closed record not allowed\n"); return false; } @@ -87,11 +87,11 @@ void holding_record_cb(const void* value, size_t size, void* ctx) { holding_record_value = *((uint8_t*)value); } -bool test_furi_holding_data(FuriRecordSubscriber* log) { +bool test_furi_holding_data() { // 1. Create holding record uint8_t holder = 0; if(!furi_create("test/holding", (void*)&holder, sizeof(holder))) { - fuprintf(log, "cannot create record\n"); + printf("cannot create record\n"); return false; } @@ -99,43 +99,43 @@ bool test_furi_holding_data(FuriRecordSubscriber* log) { FuriRecordSubscriber* holding_record = furi_open("test/holding", false, false, holding_record_cb, NULL, NULL); if(holding_record == NULL) { - fuprintf(log, "cannot open record\n"); + printf("cannot open record\n"); return false; } const uint8_t WRITE_VALUE = 1; // 3. write data if(!furi_write(holding_record, &WRITE_VALUE, sizeof(uint8_t))) { - fuprintf(log, "cannot write to record\n"); + printf("cannot write to record\n"); return false; } // 4. check that subscriber get data if(holding_record_value != WRITE_VALUE) { - fuprintf(log, "wrong sub value (get %d, write %d)\n", holding_record_value, WRITE_VALUE); + printf("wrong sub value (get %d, write %d)\n", holding_record_value, WRITE_VALUE); return false; } // 5. Read and check data uint8_t read_value = 0; if(!furi_read(holding_record, &read_value, sizeof(uint8_t))) { - fuprintf(log, "cannot read from record\n"); + printf("cannot read from record\n"); return false; } if(read_value != WRITE_VALUE) { - fuprintf(log, "wrong read value (get %d, write %d)\n", read_value, WRITE_VALUE); + printf("wrong read value (get %d, write %d)\n", read_value, WRITE_VALUE); return false; } // 6. Try to write/read wrong size of data if(furi_write(holding_record, &WRITE_VALUE, 100)) { - fuprintf(log, "overflowed write not allowed\n"); + printf("overflowed write not allowed\n"); return false; } if(furi_read(holding_record, &read_value, 100)) { - fuprintf(log, "overflowed read not allowed\n"); + printf("overflowed read not allowed\n"); return false; } @@ -159,12 +159,10 @@ typedef struct { } ConcurrentValue; void furi_concurent_app(void* p) { - FuriRecordSubscriber* log = (FuriRecordSubscriber*)p; - FuriRecordSubscriber* holding_record = furi_open("test/concurrent", false, false, NULL, NULL, NULL); if(holding_record == NULL) { - fuprintf(log, "cannot open record\n"); + printf("cannot open record\n"); furiac_exit(NULL); } @@ -172,7 +170,7 @@ void furi_concurent_app(void* p) { ConcurrentValue* value = (ConcurrentValue*)furi_take(holding_record); if(value == NULL) { - fuprintf(log, "cannot take record\n"); + printf("cannot take record\n"); furi_give(holding_record); furiac_exit(NULL); } @@ -190,11 +188,11 @@ void furi_concurent_app(void* p) { furiac_exit(NULL); } -bool test_furi_concurrent_access(FuriRecordSubscriber* log) { +bool test_furi_concurrent_access() { // 1. Create holding record ConcurrentValue holder = {.a = 0, .b = 0}; if(!furi_create("test/concurrent", (void*)&holder, sizeof(ConcurrentValue))) { - fuprintf(log, "cannot create record\n"); + printf("cannot create record\n"); return false; } @@ -202,19 +200,19 @@ bool test_furi_concurrent_access(FuriRecordSubscriber* log) { FuriRecordSubscriber* holding_record = furi_open("test/concurrent", false, false, NULL, NULL, NULL); if(holding_record == NULL) { - fuprintf(log, "cannot open record\n"); + printf("cannot open record\n"); return false; } // 3. Create second app for interact with it - FuriApp* second_app = furiac_start(furi_concurent_app, "furi concurent app", (void*)log); + FuriApp* second_app = furiac_start(furi_concurent_app, "furi concurent app", NULL); // 4. multiply ConcurrentValue::a for(size_t i = 0; i < 4; i++) { ConcurrentValue* value = (ConcurrentValue*)furi_take(holding_record); if(value == NULL) { - fuprintf(log, "cannot take record\n"); + printf("cannot take record\n"); furi_give(holding_record); return false; } @@ -232,12 +230,12 @@ bool test_furi_concurrent_access(FuriRecordSubscriber* log) { delay(50); if(second_app->handler != NULL) { - fuprintf(log, "second app still alive\n"); + printf("second app still alive\n"); return false; } if(holder.a != holder.b) { - fuprintf(log, "broken integrity: a=%d, b=%d\n", holder.a, holder.b); + printf("broken integrity: a=%d, b=%d\n", holder.a, holder.b); return false; } @@ -252,7 +250,7 @@ TEST: non-existent data TODO: implement this test */ -bool test_furi_nonexistent_data(FuriRecordSubscriber* log) { +bool test_furi_nonexistent_data() { return true; } @@ -310,11 +308,9 @@ void mute_record_state_cb(FlipperRecordState state, void* ctx) { } void furi_mute_parent_app(void* p) { - FuriRecordSubscriber* log = (FuriRecordSubscriber*)p; - // 1. Create pipe record if(!furi_create("test/mute", NULL, 0)) { - fuprintf(log, "cannot create record\n"); + printf("cannot create record\n"); furiac_exit(NULL); } @@ -322,7 +318,7 @@ void furi_mute_parent_app(void* p) { FuriRecordSubscriber* watch_handler = furi_open("test/mute", false, false, mute_record_cb, NULL, NULL); if(watch_handler == NULL) { - fuprintf(log, "cannot open watch handler\n"); + printf("cannot open watch handler\n"); furiac_exit(NULL); } @@ -332,9 +328,9 @@ void furi_mute_parent_app(void* p) { } } -bool test_furi_mute_algorithm(FuriRecordSubscriber* log) { +bool test_furi_mute_algorithm() { // 1. Create "parent" application: - FuriApp* parent_app = furiac_start(furi_mute_parent_app, "parent app", (void*)log); + FuriApp* parent_app = furiac_start(furi_mute_parent_app, "parent app", NULL); delay(2); // wait creating record @@ -342,7 +338,7 @@ bool test_furi_mute_algorithm(FuriRecordSubscriber* log) { FuriRecordSubscriber* handler_a = furi_open("test/mute", false, false, NULL, mute_record_state_cb, NULL); if(handler_a == NULL) { - fuprintf(log, "cannot open handler A\n"); + printf("cannot open handler A\n"); return false; } @@ -350,25 +346,25 @@ bool test_furi_mute_algorithm(FuriRecordSubscriber* log) { // Try to write data to A and check subscriber if(!furi_write(handler_a, &test_counter, sizeof(uint8_t))) { - fuprintf(log, "write to A failed\n"); + printf("write to A failed\n"); return false; } if(mute_last_value != test_counter) { - fuprintf(log, "value A mismatch: %d vs %d\n", mute_last_value, test_counter); + printf("value A mismatch: %d vs %d\n", mute_last_value, test_counter); return false; } // 3. Open handler B: solo=true, no_mute=true, NULL subscriber. FuriRecordSubscriber* handler_b = furi_open("test/mute", true, true, NULL, NULL, NULL); if(handler_b == NULL) { - fuprintf(log, "cannot open handler B\n"); + printf("cannot open handler B\n"); return false; } // Check A state cb get FlipperRecordStateMute. if(mute_last_state != FlipperRecordStateMute) { - fuprintf(log, "A state is not FlipperRecordStateMute: %d\n", mute_last_state); + printf("A state is not FlipperRecordStateMute: %d\n", mute_last_state); return false; } @@ -376,12 +372,12 @@ bool test_furi_mute_algorithm(FuriRecordSubscriber* log) { // Try to write data to A and check that subscriber get no data. (muted) if(furi_write(handler_a, &test_counter, sizeof(uint8_t))) { - fuprintf(log, "A not muted\n"); + printf("A not muted\n"); return false; } if(mute_last_value == test_counter) { - fuprintf(log, "value A must be muted\n"); + printf("value A must be muted\n"); return false; } @@ -389,19 +385,19 @@ bool test_furi_mute_algorithm(FuriRecordSubscriber* log) { // Try to write data to B and check that subscriber get data. if(!furi_write(handler_b, &test_counter, sizeof(uint8_t))) { - fuprintf(log, "write to B failed\n"); + printf("write to B failed\n"); return false; } if(mute_last_value != test_counter) { - fuprintf(log, "value B mismatch: %d vs %d\n", mute_last_value, test_counter); + printf("value B mismatch: %d vs %d\n", mute_last_value, test_counter); return false; } // 4. Open hadler C: solo=true, no_mute=false, NULL subscriber. FuriRecordSubscriber* handler_c = furi_open("test/mute", true, false, NULL, NULL, NULL); if(handler_c == NULL) { - fuprintf(log, "cannot open handler C\n"); + printf("cannot open handler C\n"); return false; } @@ -412,7 +408,7 @@ bool test_furi_mute_algorithm(FuriRecordSubscriber* log) { // 5. Open handler D: solo=false, no_mute=false, NULL subscriber. FuriRecordSubscriber* handler_d = furi_open("test/mute", false, false, NULL, NULL, NULL); if(handler_d == NULL) { - fuprintf(log, "cannot open handler D\n"); + printf("cannot open handler D\n"); return false; } @@ -428,7 +424,7 @@ bool test_furi_mute_algorithm(FuriRecordSubscriber* log) { // 7. Exit "parent application" if(!furiac_kill(parent_app)) { - fuprintf(log, "kill parent_app fail\n"); + printf("kill parent_app fail\n"); return false; } diff --git a/applications/tests/furiac_test.c b/applications/tests/furiac_test.c index f9cdc201..05eaaeae 100644 --- a/applications/tests/furiac_test.c +++ b/applications/tests/furiac_test.c @@ -23,26 +23,26 @@ void create_kill_app(void* p) { } } -bool test_furi_ac_create_kill(FuriRecordSubscriber* log) { +bool test_furi_ac_create_kill() { uint8_t counter = 0; uint8_t value_a = counter; FuriApp* widget = furiac_start(create_kill_app, "create_kill_app", (void*)&counter); if(widget == NULL) { - fuprintf(log, "create widget fail\n"); + printf("create widget fail\n"); return false; } delay(10); if(!furiac_kill(widget)) { - fuprintf(log, "kill widget fail\n"); + printf("kill widget fail\n"); return false; } if(value_a == counter) { - fuprintf(log, "counter unchanged\n"); + printf("counter unchanged\n"); return false; } @@ -51,7 +51,7 @@ bool test_furi_ac_create_kill(FuriRecordSubscriber* log) { delay(10); if(value_a != counter) { - fuprintf(log, "counter changes after kill (counter = %d vs %d)\n", value_a, counter); + printf("counter changes after kill (counter = %d vs %d)\n", value_a, counter); return false; } @@ -111,7 +111,7 @@ void task_b(void* p) { furiac_exit(p); } -bool test_furi_ac_switch_exit(FuriRecordSubscriber* log) { +bool test_furi_ac_switch_exit() { // init sequence TestSwitchSequence seq; seq.count = 0; @@ -124,7 +124,7 @@ bool test_furi_ac_switch_exit(FuriRecordSubscriber* log) { seq.sequence[seq.count] = '\0'; if(strcmp(seq.sequence, "ABA/") != 0) { - fuprintf(log, "wrong sequence: %s\n", seq.sequence); + printf("wrong sequence: %s\n", seq.sequence); return false; } diff --git a/applications/tests/minunit.h b/applications/tests/minunit.h new file mode 100644 index 00000000..c90a7454 --- /dev/null +++ b/applications/tests/minunit.h @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2012 David SiƱuela Pastor, siu.4coders@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef MINUNIT_MINUNIT_H +#define MINUNIT_MINUNIT_H + +#ifdef __cplusplus + extern "C" { +#endif + +#if defined(_WIN32) +#include <Windows.h> +#if defined(_MSC_VER) && _MSC_VER < 1900 + #define snprintf _snprintf + #define __func__ __FUNCTION__ +#endif + +#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) + +/* Change POSIX C SOURCE version for pure c99 compilers */ +#if !defined(_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 200112L +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif + +#include <unistd.h> /* POSIX flags */ +#include <time.h> /* clock_gettime(), time() */ +#include <sys/time.h> /* gethrtime(), gettimeofday() */ +#include <sys/resource.h> +#include <sys/times.h> +#include <string.h> + +#if defined(__MACH__) && defined(__APPLE__) +#include <mach/mach.h> +#include <mach/mach_time.h> +#endif + +#if __GNUC__ >= 5 && !defined(__STDC_VERSION__) +#define __func__ __extension__ __FUNCTION__ +#endif + +#else + +// #error "Unable to define timers for an unknown OS." + +#endif + +#include <stdio.h> +#include <math.h> + +/* Maximum length of last message */ +#define MINUNIT_MESSAGE_LEN 1024 +/* Accuracy with which floats are compared */ +#define MINUNIT_EPSILON 1E-12 + +#include "minunit_vars_ex.h" + +/* Test setup and teardown function pointers */ +static void (*minunit_setup)(void) = NULL; +static void (*minunit_teardown)(void) = NULL; + +/* Definitions */ +#define MU_TEST(method_name) static void method_name(void) +#define MU_TEST_SUITE(suite_name) static void suite_name(void) + +#define MU__SAFE_BLOCK(block) do {\ + block\ +} while(0) + +/* Run test suite and unset setup and teardown functions */ +#define MU_RUN_SUITE(suite_name) MU__SAFE_BLOCK(\ + suite_name();\ + minunit_setup = NULL;\ + minunit_teardown = NULL;\ +) + +/* Configure setup and teardown functions */ +#define MU_SUITE_CONFIGURE(setup_fun, teardown_fun) MU__SAFE_BLOCK(\ + minunit_setup = setup_fun;\ + minunit_teardown = teardown_fun;\ +) + +/* Test runner */ +#define MU_RUN_TEST(test) MU__SAFE_BLOCK(\ + if (minunit_real_timer==0 && minunit_proc_timer==0) {\ + minunit_real_timer = mu_timer_real();\ + minunit_proc_timer = mu_timer_cpu();\ + }\ + if (minunit_setup) (*minunit_setup)();\ + minunit_status = 0;\ + test();\ + minunit_run++;\ + if (minunit_status) {\ + minunit_fail++;\ + printf("F");\ + printf("\n%s\n", minunit_last_message);\ + }\ + fflush(stdout);\ + if (minunit_teardown) (*minunit_teardown)();\ +) + +/* Report */ +#define MU_REPORT() MU__SAFE_BLOCK(\ + double minunit_end_real_timer;\ + double minunit_end_proc_timer;\ + printf("\n\n%d tests, %d assertions, %d failures\n", minunit_run, minunit_assert, minunit_fail);\ + minunit_end_real_timer = mu_timer_real();\ + minunit_end_proc_timer = mu_timer_cpu();\ + printf("\nFinished in %.8f seconds (real) %.8f seconds (proc)\n\n",\ + minunit_end_real_timer - minunit_real_timer,\ + minunit_end_proc_timer - minunit_proc_timer);\ +) +#define MU_EXIT_CODE minunit_fail + +/* Assertions */ +#define mu_check(test) MU__SAFE_BLOCK(\ + minunit_assert++;\ + if (!(test)) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, #test);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_fail(message) MU__SAFE_BLOCK(\ + minunit_assert++;\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, message);\ + minunit_status = 1;\ + return;\ +) + +#define mu_assert(test, message) MU__SAFE_BLOCK(\ + minunit_assert++;\ + if (!(test)) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %s", __func__, __FILE__, __LINE__, message);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_int_eq(expected, result) MU__SAFE_BLOCK(\ + int minunit_tmp_e;\ + int minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (expected);\ + minunit_tmp_r = (result);\ + if (minunit_tmp_e != minunit_tmp_r) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %d expected but was %d", __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_int_not_eq(expected, result) MU__SAFE_BLOCK(\ + int minunit_tmp_e;\ + int minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (expected);\ + minunit_tmp_r = (result);\ + if (minunit_tmp_e == minunit_tmp_r) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: expected different results but both were %d", __func__, __FILE__, __LINE__, minunit_tmp_e);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_int_greater_than(val, result) MU__SAFE_BLOCK(\ + int minunit_tmp_e;\ + int minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (val);\ + minunit_tmp_r = (result);\ + if (val >= minunit_tmp_r) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %d <= %d", __func__, __FILE__, __LINE__, minunit_tmp_r, minunit_tmp_e);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_int_less_than(val, result) MU__SAFE_BLOCK(\ + int minunit_tmp_e;\ + int minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (val);\ + minunit_tmp_r = (result);\ + if (val <= minunit_tmp_r) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %d >= %d", __func__, __FILE__, __LINE__, minunit_tmp_r, minunit_tmp_e);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_int_between(expected_lower, expected_upper, result) MU__SAFE_BLOCK(\ + int minunit_tmp_e;\ + int minunit_tmp_m;\ + int minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (expected_lower);\ + minunit_tmp_m = (expected_upper);\ + minunit_tmp_r = (result);\ + if (result < minunit_tmp_e || result > minunit_tmp_m) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %d was not between (inclusive) %d and %d", __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r, minunit_tmp_m);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_int_in(expected, array_length, result) MU__SAFE_BLOCK(\ + int minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_r = (result);\ + int t = 0;\ + int i;\ + for (i = 0; i < array_length; i++) {\ + if (expected[i] == minunit_tmp_r)\ + t = 1;\ + }\ + if (t == 0) {\ + char tmp[500] = {0};\ + tmp[0] = '[';\ + for (i = 0; i < array_length; i++) {\ + sprintf(tmp + strlen(tmp), "%d, ", expected[i]);\ + }\ + int len = strlen(tmp);\ + tmp[len - 2] = ']';\ + tmp[len - 1] = '\0';\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: expected to be one of %s but was %d", __func__, __FILE__, __LINE__, tmp, minunit_tmp_r);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_double_eq(expected, result) MU__SAFE_BLOCK(\ + double minunit_tmp_e;\ + double minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (expected);\ + minunit_tmp_r = (result);\ + if (fabs(minunit_tmp_e-minunit_tmp_r) > MINUNIT_EPSILON) {\ + int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON);\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %.*g expected but was %.*g", __func__, __FILE__, __LINE__, minunit_significant_figures, minunit_tmp_e, minunit_significant_figures, minunit_tmp_r);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_double_greater_than(val, result) MU__SAFE_BLOCK(\ + double minunit_tmp_e;\ + double minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (val);\ + minunit_tmp_r = (result);\ + if (val >= minunit_tmp_r) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %f <= %f", __func__, __FILE__, __LINE__, minunit_tmp_r, minunit_tmp_e);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_double_less_than(val, result) MU__SAFE_BLOCK(\ + double minunit_tmp_e;\ + double minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (val);\ + minunit_tmp_r = (result);\ + if (val <= minunit_tmp_r) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %f >= %f", __func__, __FILE__, __LINE__, minunit_tmp_r, minunit_tmp_e);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_double_between(expected_lower, expected_upper, result) MU__SAFE_BLOCK(\ + double minunit_tmp_e;\ + double minunit_tmp_m;\ + double minunit_tmp_r;\ + minunit_assert++;\ + minunit_tmp_e = (expected_lower);\ + minunit_tmp_m = (expected_upper);\ + minunit_tmp_r = (result);\ + if (result < minunit_tmp_e || result > minunit_tmp_m) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: %f was not between (inclusive) %f and %f", __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r, minunit_tmp_m);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_string_eq(expected, result) MU__SAFE_BLOCK(\ + const char* minunit_tmp_e = expected;\ + const char* minunit_tmp_r = result;\ + minunit_assert++;\ + if (!minunit_tmp_e) {\ + minunit_tmp_e = "<null pointer>";\ + }\ + if (!minunit_tmp_r) {\ + minunit_tmp_r = "<null pointer>";\ + }\ + if(strcmp(minunit_tmp_e, minunit_tmp_r)) {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: '%s' expected but was '%s'", __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r);\ + minunit_status = 1;\ + return;\ + } else {\ + printf(".");\ + }\ +) + +#define mu_assert_null(result) MU__SAFE_BLOCK(\ + minunit_assert++;\ + if (result == NULL) {\ + printf(".");\ + } else {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: Expected result was not NULL", __func__, __FILE__, __LINE__);\ + minunit_status = 1;\ + return;\ + }\ +) + +#define mu_assert_not_null(result) MU__SAFE_BLOCK(\ + minunit_assert++;\ + if (result != NULL) {\ + printf(".");\ + } else {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: Expected result was not NULL", __func__, __FILE__, __LINE__);\ + minunit_status = 1;\ + return;\ + }\ +) + +#define mu_assert_pointers_eq(pointer1, pointer2) MU__SAFE_BLOCK(\ + minunit_assert++;\ + if (pointer1 == pointer2) {\ + printf(".");\ + } else {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: Expected the pointers to point to the same memory location", __func__, __FILE__, __LINE__);\ + minunit_status = 1;\ + return;\ + }\ +) + +#define mu_assert_pointers_not_eq(pointer1, pointer2) MU__SAFE_BLOCK(\ + minunit_assert++;\ + if (pointer1 != pointer2) {\ + printf(".");\ + } else {\ + snprintf(minunit_last_message, MINUNIT_MESSAGE_LEN, "%s failed:\n\t%s:%d: Expected the pointers to point to the same memory location", __func__, __FILE__, __LINE__);\ + minunit_status = 1;\ + return;\ + }\ +) + +/* + * The following two functions were written by David Robert Nadeau + * from http://NadeauSoftware.com/ and distributed under the + * Creative Commons Attribution 3.0 Unported License + */ + +/** + * Returns the real time, in seconds, or -1.0 if an error occurred. + * + * Time is measured since an arbitrary and OS-dependent start time. + * The returned real time is only useful for computing an elapsed time + * between two calls to this function. + */ +static double mu_timer_real(void) +{ +#if defined(_WIN32) + /* Windows 2000 and later. ---------------------------------- */ + LARGE_INTEGER Time; + LARGE_INTEGER Frequency; + + QueryPerformanceFrequency(&Frequency); + QueryPerformanceCounter(&Time); + + Time.QuadPart *= 1000000; + Time.QuadPart /= Frequency.QuadPart; + + return (double)Time.QuadPart / 1000000.0; + +#elif (defined(__hpux) || defined(hpux)) || ((defined(__sun__) || defined(__sun) || defined(sun)) && (defined(__SVR4) || defined(__svr4__))) + /* HP-UX, Solaris. ------------------------------------------ */ + return (double)gethrtime( ) / 1000000000.0; + +#elif defined(__MACH__) && defined(__APPLE__) + /* OSX. ----------------------------------------------------- */ + static double timeConvert = 0.0; + if ( timeConvert == 0.0 ) + { + mach_timebase_info_data_t timeBase; + (void)mach_timebase_info( &timeBase ); + timeConvert = (double)timeBase.numer / + (double)timeBase.denom / + 1000000000.0; + } + return (double)mach_absolute_time( ) * timeConvert; + +#elif defined(_POSIX_VERSION) + /* POSIX. --------------------------------------------------- */ + struct timeval tm; +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) + { + struct timespec ts; +#if defined(CLOCK_MONOTONIC_PRECISE) + /* BSD. --------------------------------------------- */ + const clockid_t id = CLOCK_MONOTONIC_PRECISE; +#elif defined(CLOCK_MONOTONIC_RAW) + /* Linux. ------------------------------------------- */ + const clockid_t id = CLOCK_MONOTONIC_RAW; +#elif defined(CLOCK_HIGHRES) + /* Solaris. ----------------------------------------- */ + const clockid_t id = CLOCK_HIGHRES; +#elif defined(CLOCK_MONOTONIC) + /* AIX, BSD, Linux, POSIX, Solaris. ----------------- */ + const clockid_t id = CLOCK_MONOTONIC; +#elif defined(CLOCK_REALTIME) + /* AIX, BSD, HP-UX, Linux, POSIX. ------------------- */ + const clockid_t id = CLOCK_REALTIME; +#else + const clockid_t id = (clockid_t)-1; /* Unknown. */ +#endif /* CLOCK_* */ + if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) + return (double)ts.tv_sec + + (double)ts.tv_nsec / 1000000000.0; + /* Fall thru. */ + } +#endif /* _POSIX_TIMERS */ + + /* AIX, BSD, Cygwin, HP-UX, Linux, OSX, POSIX, Solaris. ----- */ + gettimeofday( &tm, NULL ); + return (double)tm.tv_sec + (double)tm.tv_usec / 1000000.0; +#else + return -1.0; /* Failed. */ +#endif +} + +/** + * Returns the amount of CPU time used by the current process, + * in seconds, or -1.0 if an error occurred. + */ +static double mu_timer_cpu(void) +{ +#if defined(_WIN32) + /* Windows -------------------------------------------------- */ + FILETIME createTime; + FILETIME exitTime; + FILETIME kernelTime; + FILETIME userTime; + + /* This approach has a resolution of 1/64 second. Unfortunately, Windows' API does not offer better */ + if ( GetProcessTimes( GetCurrentProcess( ), + &createTime, &exitTime, &kernelTime, &userTime ) != 0 ) + { + ULARGE_INTEGER userSystemTime; + memcpy(&userSystemTime, &userTime, sizeof(ULARGE_INTEGER)); + return (double)userSystemTime.QuadPart / 10000000.0; + } + +#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) + /* AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris --------- */ + +#if defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0) + /* Prefer high-res POSIX timers, when available. */ + { + clockid_t id; + struct timespec ts; +#if _POSIX_CPUTIME > 0 + /* Clock ids vary by OS. Query the id, if possible. */ + if ( clock_getcpuclockid( 0, &id ) == -1 ) +#endif +#if defined(CLOCK_PROCESS_CPUTIME_ID) + /* Use known clock id for AIX, Linux, or Solaris. */ + id = CLOCK_PROCESS_CPUTIME_ID; +#elif defined(CLOCK_VIRTUAL) + /* Use known clock id for BSD or HP-UX. */ + id = CLOCK_VIRTUAL; +#else + id = (clockid_t)-1; +#endif + if ( id != (clockid_t)-1 && clock_gettime( id, &ts ) != -1 ) + return (double)ts.tv_sec + + (double)ts.tv_nsec / 1000000000.0; + } +#endif + +#if defined(RUSAGE_SELF) + { + struct rusage rusage; + if ( getrusage( RUSAGE_SELF, &rusage ) != -1 ) + return (double)rusage.ru_utime.tv_sec + + (double)rusage.ru_utime.tv_usec / 1000000.0; + } +#endif + +#if defined(_SC_CLK_TCK) + { + const double ticks = (double)sysconf( _SC_CLK_TCK ); + struct tms tms; + if ( times( &tms ) != (clock_t)-1 ) + return (double)tms.tms_utime / ticks; + } +#endif + +#if defined(CLOCKS_PER_SEC) + { + clock_t cl = clock( ); + if ( cl != (clock_t)-1 ) + return (double)cl / (double)CLOCKS_PER_SEC; + } +#endif + +#endif + + return -1; /* Failed. */ +} + +#ifdef __cplusplus +} +#endif + +#endif /* MINUNIT_MINUNIT_H */
\ No newline at end of file diff --git a/applications/tests/minunit_test.c b/applications/tests/minunit_test.c new file mode 100644 index 00000000..62e0da37 --- /dev/null +++ b/applications/tests/minunit_test.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include "flipper.h" +#include "log.h" +#include "minunit_vars.h" +#include "minunit.h" + +bool test_furi_ac_create_kill(); +bool test_furi_ac_switch_exit(); +bool test_furi_pipe_record(); +bool test_furi_holding_data(); +bool test_furi_concurrent_access(); +bool test_furi_nonexistent_data(); +bool test_furi_mute_algorithm(); + +static int foo = 0; + +void test_setup(void) { + foo = 7; +} + +void test_teardown(void) { + /* Nothing */ +} + +MU_TEST(test_check) { + mu_check(foo != 6); +} + +MU_TEST(mu_test_furi_ac_create_kill) { + mu_assert_int_eq(test_furi_ac_create_kill(), true); +} + +MU_TEST(mu_test_furi_ac_switch_exit) { + mu_assert_int_eq(test_furi_ac_switch_exit(), true); +} + +MU_TEST(mu_test_furi_pipe_record) { + mu_assert_int_eq(test_furi_pipe_record(), true); +} + +MU_TEST(mu_test_furi_holding_data) { + mu_assert_int_eq(test_furi_holding_data(), true); +} + +MU_TEST(mu_test_furi_concurrent_access) { + mu_assert_int_eq(test_furi_concurrent_access(), true); +} + +MU_TEST(mu_test_furi_nonexistent_data) { + mu_assert_int_eq(test_furi_nonexistent_data(), true); +} + +/* +MU_TEST(mu_test_furi_mute_algorithm) { + mu_assert_int_eq(test_furi_mute_algorithm(test_log), true); +} +*/ + +MU_TEST_SUITE(test_suite) { + MU_SUITE_CONFIGURE(&test_setup, &test_teardown); + + MU_RUN_TEST(test_check); + MU_RUN_TEST(mu_test_furi_ac_create_kill); + MU_RUN_TEST(mu_test_furi_ac_switch_exit); + MU_RUN_TEST(mu_test_furi_pipe_record); + MU_RUN_TEST(mu_test_furi_holding_data); + MU_RUN_TEST(mu_test_furi_concurrent_access); + MU_RUN_TEST(mu_test_furi_nonexistent_data); + // MU_RUN_TEST(mu_test_furi_mute_algorithm); +} + +int run_minunit() { + MU_RUN_SUITE(test_suite); + MU_REPORT(); + + return MU_EXIT_CODE; +}
\ No newline at end of file diff --git a/applications/tests/minunit_vars.h b/applications/tests/minunit_vars.h new file mode 100644 index 00000000..7ef5f825 --- /dev/null +++ b/applications/tests/minunit_vars.h @@ -0,0 +1,15 @@ +#pragma once +#include "minunit.h" + +/* Misc. counters */ +int minunit_run = 0; +int minunit_assert = 0; +int minunit_fail = 0; +int minunit_status = 0; + +/* Timers */ +double minunit_real_timer = 0; +double minunit_proc_timer = 0; + +/* Last message */ +char minunit_last_message[MINUNIT_MESSAGE_LEN];
\ No newline at end of file diff --git a/applications/tests/minunit_vars_ex.h b/applications/tests/minunit_vars_ex.h new file mode 100644 index 00000000..e2743d1c --- /dev/null +++ b/applications/tests/minunit_vars_ex.h @@ -0,0 +1,15 @@ +#pragma once +#include "minunit.h" + +/* Misc. counters */ +extern int minunit_run; +extern int minunit_assert; +extern int minunit_fail; +extern int minunit_status; + +/* Timers */ +extern double minunit_real_timer; +extern double minunit_proc_timer; + +/* Last message */ +extern char minunit_last_message[MINUNIT_MESSAGE_LEN];
\ No newline at end of file diff --git a/applications/tests/test_index.c b/applications/tests/test_index.c index 9c970a38..c15985ce 100644 --- a/applications/tests/test_index.c +++ b/applications/tests/test_index.c @@ -4,70 +4,38 @@ // #include "flipper-core.h" TODO: Rust build disabled -bool test_furi_ac_create_kill(FuriRecordSubscriber* log); -bool test_furi_ac_switch_exit(FuriRecordSubscriber* log); - -bool test_furi_pipe_record(FuriRecordSubscriber* log); -bool test_furi_holding_data(FuriRecordSubscriber* log); -bool test_furi_concurrent_access(FuriRecordSubscriber* log); -bool test_furi_nonexistent_data(FuriRecordSubscriber* log); -bool test_furi_mute_algorithm(FuriRecordSubscriber* log); +int run_minunit(); void flipper_test_app(void* p) { - FuriRecordSubscriber* log = get_default_log(); + // create pins + GpioPin red = {.pin = LED_RED_Pin, .port = LED_RED_GPIO_Port}; + GpioPin green = {.pin = LED_GREEN_Pin, .port = LED_GREEN_GPIO_Port}; + GpioPin blue = {.pin = LED_BLUE_Pin, .port = LED_BLUE_GPIO_Port}; - if(test_furi_ac_create_kill(log)) { - fuprintf(log, "[TEST] test_furi_ac_create_kill PASSED\n"); - } else { - fuprintf(log, "[TEST] test_furi_ac_create_kill FAILED\n"); - } - - if(test_furi_ac_switch_exit(log)) { - fuprintf(log, "[TEST] test_furi_ac_switch_exit PASSED\n"); - } else { - fuprintf(log, "[TEST] test_furi_ac_switch_exit FAILED\n"); - } + // configure pins + pinMode(red, GpioModeOpenDrain); + pinMode(green, GpioModeOpenDrain); + pinMode(blue, GpioModeOpenDrain); - if(test_furi_pipe_record(log)) { - fuprintf(log, "[TEST] test_furi_pipe_record PASSED\n"); - } else { - fuprintf(log, "[TEST] test_furi_pipe_record FAILED\n"); - } + digitalWrite(red, HIGH); + digitalWrite(green, HIGH); + digitalWrite(blue, LOW); - if(test_furi_holding_data(log)) { - fuprintf(log, "[TEST] test_furi_holding_data PASSED\n"); - } else { - fuprintf(log, "[TEST] test_furi_holding_data FAILED\n"); - } - - if(test_furi_concurrent_access(log)) { - fuprintf(log, "[TEST] test_furi_concurrent_access PASSED\n"); - } else { - fuprintf(log, "[TEST] test_furi_concurrent_access FAILED\n"); - } - - if(test_furi_nonexistent_data(log)) { - fuprintf(log, "[TEST] test_furi_nonexistent_data PASSED\n"); - } else { - fuprintf(log, "[TEST] test_furi_nonexistent_data FAILED\n"); - } - - if(test_furi_mute_algorithm(log)) { - fuprintf(log, "[TEST] test_furi_mute_algorithm PASSED\n"); - } else { - fuprintf(log, "[TEST] test_furi_mute_algorithm FAILED\n"); - } + uint32_t exitcode = run_minunit(); - /* - TODO: Rust build disabled - if(add(1, 2) == 3) { - fuprintf(log, "[TEST] Rust add PASSED\n"); + if(exitcode == 0) { + // test passed + digitalWrite(red, HIGH); + digitalWrite(green, LOW); + digitalWrite(blue, HIGH); } else { - fuprintf(log, "[TEST] Rust add FAILED\n"); + // test failed + digitalWrite(red, LOW); + digitalWrite(green, HIGH); + digitalWrite(blue, HIGH); } - rust_uart_write(); - */ + set_exitcode(exitcode); furiac_exit(NULL); }
\ No newline at end of file |