#include #include #include #include #include #include #include #if defined(TEST_TARGET_calculate) #include #include #include #else #include "init.h" #include "command.h" #include "unitt.h" #include "calculate.h" #include "kern.h" #endif /************************************************************************************/ /************************************* Unit Test ************************************/ /************************************************************************************/ // #define EXIT_TEST extern uint64_t unitt_clock(void); typedef union { uint64_t int_; double double_; } doubel_ut; extern uint64_t unitt_clock(void); // #define EXIT_TEST static char expbuffer[1000]; static double random_double() { doubel_ut random; for (int i = 0; i < 8; i++) { random.int_ <<= 8; random.int_ |= rand() & 0xFF; } #if 0 if (isnan(random.double_)) random.double_ = 1.0; else if (isinf(random.double_)) { if (random.double_ > 0) random.double_ = 2.0; else random.double_ = -2.0; } else if (random.double_ == 0.0) random.double_ = 1.0; #else uint64_t temp = random.int_; random.double_ = (double)temp / 100; #endif return random.double_; } static int double_eq(double a, double b) { double epsilon = 1e-6; doubel_ut a1 = {.double_ = a}, b1 = {.double_ = b}; if (a1.int_ == b1.int_) return 1; if (isnan(a) && isnan(b)) return 1; if (isinf(a) && isinf(b)) return 1; if (fabs(a - b) < epsilon) return 1; return 0; } static int test_add(void) { for (int i = 0; i < 100; i++) { double a, b; doubel_ut r1 = {.int_ = 0}, r2 = {.int_ = 0}; a = random_double(); b = random_double(); snprintf(expbuffer, sizeof(expbuffer), "%lf + %lf", a, b); r1.double_ = calculate(expbuffer); r2.double_ = a + b; if (!double_eq(r1.double_, r2.double_)) { printf("add fail: \r\nexpert: \r\n%llu | %lf \r\nactual: \r\n%llu | %lf \r\n", r2.int_, r2.double_, r1.int_, r1.double_); #if defined (EXIT_TEST) exit(0); #endif return UNITT_E_FAIL; } } return UNITT_E_OK; } static int test_sub(void) { for (int i = 0; i < 100; i++) { double a, b; doubel_ut r1 = {.int_ = 0}, r2 = {.int_ = 0}; a = random_double(); b = random_double(); snprintf(expbuffer, sizeof(expbuffer), "%lf - %lf", a, b); r1.double_ = calculate(expbuffer); r2.double_ = a - b; if (!double_eq(r1.double_, r2.double_)) { printf("sub fail: \r\nexpert: \r\n%llu | %lf \r\nactual: \r\n%llu | %lf \r\n", r2.int_, r2.double_, r1.int_, r1.double_); #if defined (EXIT_TEST) exit(0); #endif return UNITT_E_FAIL; } } return UNITT_E_OK; } static int test_mul(void) { for (int i = 0; i < 100; i++) { double a, b; doubel_ut r1 = {.int_ = 0}, r2 = {.int_ = 0}; a = random_double(); b = random_double(); snprintf(expbuffer, sizeof(expbuffer), "%lf * %lf", a, b); r1.double_ = calculate(expbuffer); r2.double_ = a * b; if (!double_eq(r1.double_, r2.double_)) { printf("mul fail: \r\nexpert: \r\n%llu | %lf \r\nactual: \r\n%llu | %lf \r\n", r2.int_, r2.double_, r1.int_, r1.double_); #if defined (EXIT_TEST) exit(0); #endif return UNITT_E_FAIL; } } return UNITT_E_OK; } static int test_div(void) { for (int i = 0; i < 100; i++) { double a, b; doubel_ut r1 = {.int_ = 0}, r2 = {.int_ = 0}; a = random_double(); b = random_double(); snprintf(expbuffer, sizeof(expbuffer), "%lf / %lf", a, b); r1.double_ = calculate(expbuffer); r2.double_ = a / b; if (!double_eq(r1.double_, r2.double_)) { printf("div fail: \r\nexpert: \r\n%llu | %lf \r\nactual: \r\n%llu | %lf \r\n", r2.int_, r2.double_, r1.int_, r1.double_); #if defined (EXIT_TEST) exit(0); #endif return UNITT_E_FAIL; } } return UNITT_E_OK; } static void unitt_task(void) { static UNITT_TCASE rand_tests[] = { UNITT_TCASE(test_add), UNITT_TCASE(test_sub), UNITT_TCASE(test_mul), UNITT_TCASE(test_div), }; static UNITT suites[] = { { "calculate suite", rand_tests, sizeof(rand_tests) / sizeof(rand_tests[0]) , unitt_clock }, }; UNITT_EXE(suites); } /************************************************************************************/ /************************************* Base Test ************************************/ /************************************************************************************/ static void ls(void) { const char *name = NULL; int fargc = 0; double value = 0; while (name = calculate_ls_const(&value)) { printf("- %s<%lf>\r\n", name, value); } while (name = calculate_ls_func(&fargc)) { printf("- %s(%d)\r\n", name, fargc); } } static int command_calculate(const char *expression) { double r = NAN; if (!expression) return 0; r = calculate(expression); if (fabs(floor(r) - r) <= DBL_EPSILON && fabs(r) < 1.0e60) printf("%.0lf\r\n", r); else if (fabs(r) < 1.0e-6 || fabs(r) > 1.0e9) printf("%e\r\n", r); else { char p[64]; int len = 0; len = sprintf(p, "%lf", r); while (len > 0 && p[len-1] == '0' && p[len-2] != '.') {p[--len] = 0;} printf("%s\r\n", p); } return 1; } static double factorial(double n) { if (n < 1) return 1; return n * factorial(n - 1); } static void test_base(void) { const char *expression[] = { " ( 99 * 3 ) ", " min (12, 3)", "sin ( 11 / 2 * Pi ) + 100 ", }; for (int i = 0; i < sizeof(expression) / sizeof(expression[0]); i++) { printf("cal: %s = %lf\r\n", expression[i], calculate(expression[i])); } } static void test_export(void) { int ret = 0; ret = calculate_function("fac", factorial, 1); printf("export func '%s' ret<%d>\r\n", "fac", ret); ret = calculate_constant("K", 1024); printf("export const '%s' ret<%d>\r\n", "K", ret); ls(); } /************************************************************************************/ /************************************* Command ************************************/ /************************************************************************************/ static void usage(void) { printf( "Usage: calculate [opt] [arg] ...\n" "\n" "options:\n" " -e Specifies the function to execute, the default is the test\n" " Test base function\n" " Unit test\n" " Calculate string math expression\n" " Test base export function\n" " -h Print help\n" " -v Print version\n" " -u [] Unit test period, unit ms, the default is 1000ms\n" " -c Calculation expression\n" " -l Lists the currently supported calculation functions and constants\n" "\n" ); } static int test(int argc, char *argv[]) { char *execute = NULL; int ut_period = 1000; char *expression = NULL; /* reset getopt */ command_opt_init(); while (1) { int opt = command_getopt(argc, argv, "e:hvu::lc:"); if (opt == -1) break; switch (opt) { case 'c' : expression = command_optarg; break; case 'l' : ls(); return 0; case 'u' : if (command_optarg) ut_period = atoi(command_optarg); break; case 'e' : execute = command_optarg; break; case 'v' : printf("calculate version %d.%d.%d\r\n", CALCULATE_V_MAJOR, CALCULATE_V_MINOR, CALCULATE_V_PATCH); return 0; case '?': printf("Unknown option `%c`\r\n", command_optopt); return -1; case 'h' : default: usage(); return 0; } } if (execute) { if (!strcmp(execute, "base")) { test_base(); } else if (!strcmp(execute, "ut")) { srand((unsigned int)time(NULL)); #if defined(TEST_TARGET_calculate) while (1) { unitt_task(); usleep(1000 * ut_period); } #else printf("create task %d\r\n", task_create(ut_period, unitt_task)); #endif } else if (!strcmp(execute, "cal")) { if (expression) { command_calculate(expression); } else { printf("Use the -c option to specify the evaluated expression!\r\n"); } } else if (!strcmp(execute, "export")) { test_export(); } } else { test_base(); } return 0; } /************************************************************************************/ /************************************ Test entry ************************************/ /************************************************************************************/ #if defined(TEST_TARGET_calculate) int main(int argc, char *argv[]) { return test(argc, argv); } #else void test_calculate(void) { command_export("calculate", test); // command("calculate"); // command("calculate -e ut"); // command("calculate -e cal -c 1+2"); // command("calculate -e export"); } init_export_app(test_calculate); #endif