#include #include #if defined(TEST_TARGET_intl) #include #include #include #else #include "init.h" #include "command.h" #include "unitt.h" #include "kern.h" #include "intl.h" #endif static char pbuff[INTL_PRINT_MAX] = {0}; /************************************************************************************/ /************************************* Unit Test ************************************/ /************************************************************************************/ // #define EXIT_TEST extern uint64_t unitt_clock(void); static intl random_intl() { intl random = INTL_ZERO; for (int i = 0; i < __INTL_U32_PARTS__; i++) { random.u32[i] = rand(); } return random; } static const char* random_format() { const char *format[4] = { "d", "#b", "#o", "#x" }; return format[rand() % 4]; } static int test_convert(void) { for (int i = 0; i < 100; i++) { intl src = random_intl(); intl dst = intl_from(intl_show(src, pbuff, sizeof(pbuff), random_format())); if (!intl_eq(src, dst)) { printf("convert fail: \r\n"); printf("src: %s\r\n", intl_show(src, pbuff, sizeof(pbuff), "x")); printf("dst: %s\r\n", intl_show(dst, pbuff, sizeof(pbuff), "x")); #if defined (EXIT_TEST) exit(0); #endif return UNITT_E_FAIL; } } return UNITT_E_OK; } /* Need config intl as 64bits */ static int test_accuracy(void) { for (int i = 0; i < 1000; i++) { int op = rand() % 10; uint8_t sh = 0; intl a = random_intl(); intl b = random_intl(); intl c = INTL_ZERO; int64_t x = 0; int64_t y = 0; int64_t z = 0; memcpy(&x, &a, sizeof(x)); memcpy(&y, &b, sizeof(y)); /* Skip the division by 0 */ if (op == 3 && y == 0) continue; /* Adjust shift */ if (op == 8 || op == 9) { sh = y; sh %= 64; } if (op == 0) { c = intl_add(a, b); z = x + y; } else if (op == 1) { c = intl_sub(a, b); z = x - y; } else if (op == 2) { c = intl_mul(a, b); z = x * y; } else if (op == 3) { c = intl_div(a, b); z = x / y; } else if (op == 4) { c = intl_mod(a, b); z = x % y; } else if (op == 5) { c = intl_and(a, b); z = x & y; } else if (op == 6) { c = intl_xor(a, b); z = x ^ y; } else if (op == 7) { c = intl_or (a, b); z = x | y; } else if (op == 8) { c = intl_shl(a, sh); z = x << sh; } else if (op == 9) { c = intl_shr(a, sh); z = x >> sh; } if (memcmp(&c, &z, sizeof(z)) != 0) { printf("accuracy fail: %d,%d\r\n", op, sh); printf("c: %s\r\n", intl_show(c, pbuff, sizeof(pbuff), "d")); printf("z: %lld\r\n", z); #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_convert), #if defined (INTL_USE_64BITS) UNITT_TCASE(test_accuracy), #endif }; static UNITT suites[] = { { "intl suite", rand_tests, sizeof(rand_tests) / sizeof(rand_tests[0]) , unitt_clock }, }; UNITT_EXE(suites); } /************************************************************************************/ /************************************* Base Test ************************************/ /************************************************************************************/ void intl_gen_cfg(uint32_t bits, const char *filename) { #define MINBITS 64 #define NEWLINE "\n" // "\r\n" // FILE* output = stdout; // Default output to standard output if (filename != NULL) { output = fopen(filename, "w"); if (output == NULL) { fprintf(stdout, "[ERROR] Failed to open output file"NEWLINE); return; } } /* The number of bits in an intl needs to be an exponent of two */ if ((bits & (bits - 1)) != 0) { fprintf(stdout, "[ERROR] `bits` not a power of 2"NEWLINE); return; } /* Limiting the minimum bit */ if (bits < MINBITS) { fprintf(stdout, "[ERROR] `bits` too small\r\b"); return; } fprintf(output, "/*****************************************************************/"NEWLINE); fprintf(output, "/* Config start */"NEWLINE); fprintf(output, "/*****************************************************************/"NEWLINE); for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1) { if (tb == bits) { fprintf(output, "#define INTL_USE_%uBITS"NEWLINE, tb); } else { fprintf(output, "// #define INTL_USE_%uBITS"NEWLINE, tb); } } fprintf(output, ""NEWLINE); intl temp; for (uint32_t tb = MINBITS; tb <= bits; tb <<= 1) { if (tb == MINBITS) { fprintf(output, "#if defined(INTL_USE_%uBITS)"NEWLINE, tb); } else { fprintf(output, "#elif defined(INTL_USE_%uBITS)"NEWLINE, tb); } uint32_t BIT_PARTS ; /* bits */ uint32_t U32_PARTS ; /* __INTL_BIT_PARTS__ / 32 */ uint32_t U16_PARTS ; /* __INTL_BIT_PARTS__ / 16 */ uint32_t MAX_BIN ; /* __INTL_BIT_PARTS__ + 1 */ uint32_t MAX_DEC ; /* strlen(intl_shl(intl(1), __INTL_BIT_PARTS__ - 1)) + 1 */ uint32_t MAX_HEX ; /* __INTL_BIT_PARTS__ / 4 + 1 */ BIT_PARTS = tb; U32_PARTS = BIT_PARTS >> (5); U16_PARTS = BIT_PARTS >> (4); MAX_BIN = BIT_PARTS + 3; // "0b" + '\0' MAX_DEC = MAX_BIN; // First apply as MAX bin maximum value, and then according to the actual calculation MAX_HEX = (BIT_PARTS >> (2)) + 3; // "0x" + '\0' /* The current configuration is applied */ if (sizeof(temp) == (bits >> 3)) { char buffer[__INTL_P_MAX_BIN__]; MAX_DEC = intl_print(intl_shl(intl(1), BIT_PARTS - 1), buffer, sizeof(buffer), "d") + 1; // '\0' } fprintf(output, "#define __INTL_BIT_PARTS__ %u"NEWLINE, BIT_PARTS); fprintf(output, "#define __INTL_U32_PARTS__ %u"NEWLINE, U32_PARTS); fprintf(output, "#define __INTL_U16_PARTS__ %u"NEWLINE, U16_PARTS); fprintf(output, "#define __INTL_P_MAX_BIN__ %u"NEWLINE, MAX_BIN); fprintf(output, "#define __INTL_P_MAX_DEC__ %u"NEWLINE, MAX_DEC); fprintf(output, "#define __INTL_P_MAX_HEX__ %u"NEWLINE, MAX_HEX); /* __INTL_MAX__ */ fprintf(output, "#define __INTL_MAX__ (intl){.u32={"); for (uint32_t i = 0; i < U32_PARTS; i++) { fprintf(output, "%s,", (i == U32_PARTS-1) ? "0x7FFFFFFF" : "-1"); } fprintf(output, "}}"NEWLINE); /* __INTL_MIN__ */ fprintf(output, "#define __INTL_MIN__ (intl){.u32={"); for (uint32_t i = 0; i < U32_PARTS; i++) { fprintf(output, "%s,", (i == U32_PARTS-1) ? "0x80000000" : "0"); } fprintf(output, "}}"NEWLINE); /* __INTL_ZERO__ */ fprintf(output, "#define __INTL_ZERO__ (intl){.u32={"); for (uint32_t i = 0; i < U32_PARTS; i++) { fprintf(output, "0,"); } fprintf(output, "}}"NEWLINE); } fprintf(output, "#endif"NEWLINE); fprintf(output, "/*****************************************************************/"NEWLINE); fprintf(output, "/* Config end */"NEWLINE); fprintf(output, "/*****************************************************************/"NEWLINE); fprintf(stdout, "\r\n\r\n-------------------------------------------------------------\r\n"NEWLINE); /* The current configuration is not applied */ if (sizeof(temp) != (bits >> 3)) { fprintf(stdout, "[TODO][%s] Apply the current configuration and run it again to get the new `__INTL_P_MAX_DEC__`"NEWLINE, filename); } else { fprintf(stdout, "[INFO][%s] The configuration has been generated, copy it to the `intl_cfg.h` range specified"NEWLINE, filename); } if (filename != NULL) { fclose(output); } } static void test_define(void) { intl a = intl(0); intl b = intl(10); intl c = intl(-10); intl d = intl(0xFF); intl e = intl_from("0"); intl f = intl_from("100"); intl g = intl_from("-100"); intl h = intl_from("123456789123456789123456789"); intl i = intl_from("0b1110000001111100101010100"); intl j = intl_from("0o1236541236763210233642166"); intl k = intl_from("0xF125E3F6D743648EEFFF12356"); intl max = INTL_MAX; intl min = INTL_MIN; intl n0 = INTL_ZERO; } static void test_print(void) { intl a = intl_from("123456789123456789123456789"); printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "dx")); printf("a: %s\r\n", intl_show(INTL_ZERO, pbuff, sizeof(pbuff), "#x")); printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "#o")); printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "#x")); printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "10x")); printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "010x")); printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "-10x")); printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "-010x")); printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#10x")); printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#010x")); printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#-10x")); printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#-010x")); printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#x")); printf("a: %s\r\n", intl_show(intl(123456), pbuff, sizeof(pbuff), "#0x")); printf("a: %s\r\n", intl_show(intl(-123456), pbuff, sizeof(pbuff), "#d")); printf("a: %s\r\n", intl_show(intl(-123456), pbuff, sizeof(pbuff), "#10d")); printf("a: %s\r\n", intl_show(intl(-123456), pbuff, sizeof(pbuff), "-#d")); } static void test_calculate(void) { intl a = intl_from("123456789123456789123456789"); intl b = intl_from("987654321987654321987654321"); printf("a: %s\r\n", intl_show(a, pbuff, sizeof(pbuff), "d")); printf("b: %s\r\n", intl_show(b, pbuff, sizeof(pbuff), "d")); printf("a + b: %s\r\n", intl_show(intl_add(a, b), pbuff, sizeof(pbuff), "d")); printf("a - b: %s\r\n", intl_show(intl_sub(a, b), pbuff, sizeof(pbuff), "d")); printf("a * b: %s\r\n", intl_show(intl_mul(a, b), pbuff, sizeof(pbuff), "d")); printf("b / a: %s\r\n", intl_show(intl_div(a, b), pbuff, sizeof(pbuff), "d")); printf("b %% a: %s\r\n", intl_show(intl_mod(a, b), pbuff, sizeof(pbuff), "d")); printf("a & b: %s\r\n", intl_show(intl_and(a, b), pbuff, sizeof(pbuff), "d")); printf("a | b: %s\r\n", intl_show(intl_or(a, b), pbuff, sizeof(pbuff), "d")); printf("a ^ b: %s\r\n", intl_show(intl_xor(a, b), pbuff, sizeof(pbuff), "d")); printf("~a: %s\r\n", intl_show(intl_not(a), pbuff, sizeof(pbuff), "d")); printf("a << 1: %s\r\n", intl_show(intl_shl(a, 1), pbuff, sizeof(pbuff), "d")); printf("b >> 1: %s\r\n", intl_show(intl_shr(a, 1), pbuff, sizeof(pbuff), "d")); printf("a++: %s\r\n", intl_show(intl_inc(a), pbuff, sizeof(pbuff), "d")); printf("b--: %s\r\n", intl_show(intl_dec(a), pbuff, sizeof(pbuff), "d")); printf("a > b: %d\r\n", intl_gt(a, b)); printf("a >= b: %d\r\n", intl_ge(a, b)); printf("a < b: %d\r\n", intl_lt(a, b)); printf("a <= b: %d\r\n", intl_le(a, b)); printf("a == b: %d\r\n", intl_eq(a, b)); printf("a != b: %d\r\n", intl_ne(a, b)); } static void test_base(void) { // test_define(); // test_print(); test_calculate(); } /************************************************************************************/ /************************************* Command ************************************/ /************************************************************************************/ static void usage(void) { printf( "Usage: intl [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" " Test define function\n" " Calculate string math expression\n" " Generate the intl configuration file code segment, need specify -f -b\n" " Print an intl number\n" " -l Format string, 10d, 08x, ...\n" " -o Operate function, add, sub, mul, div, ...\n" " -n intl number expression\n" " -f File name, temporarily store configuration code segment\n" " -b Maximum number of configured bits\n" " -h Print help\n" " -v Print version\n" " -u [] Unit test period, unit ms, the default is 1000ms\n" "\n" ); } static int test(int argc, char *argv[]) { char *execute = NULL; int ut_period = 1000; char *filename = NULL; int bits = 0; intl n[2] = {INTL_ZERO, INTL_ZERO}; int in = 0; char *op = NULL; char *format = NULL; /* reset getopt */ command_opt_init(); while (1) { int opt = command_getopt(argc, argv, "e:hvu::f:b:n:o:l:"); if (opt == -1) break; switch (opt) { case 'l' : format = command_optarg; break; case 'o' : op = command_optarg; break; case 'n' : if (in < 2) n[in++] = intl_from(command_optarg); break; case 'b' : bits = atoi(command_optarg); break; case 'f' : filename = command_optarg; break; case 'u' : if (command_optarg) ut_period = atoi(command_optarg); break; case 'e' : execute = command_optarg; break; case 'v' : printf("intl version %d.%d.%d\r\n", INTL_V_MAJOR, INTL_V_MINOR, INTL_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_intl) 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, "define")) { test_define(); } else if (!strcmp(execute, "gen")) { intl_gen_cfg(bits, filename); } else if (!strcmp(execute, "cal")) { intl result = INTL_ZERO; if (!strcmp(op, "add")) result = intl_add(n[0], n[1]); else if (!strcmp(op, "sub")) result = intl_sub(n[0], n[1]); else if (!strcmp(op, "mul")) result = intl_mul(n[0], n[1]); else if (!strcmp(op, "div")) result = intl_div(n[0], n[1]); else if (!strcmp(op, "mod")) result = intl_mod(n[0], n[1]); else if (!strcmp(op, "and")) result = intl_and(n[0], n[1]); else if (!strcmp(op, "xor")) result = intl_xor(n[0], n[1]); else if (!strcmp(op, "or")) result = intl_or(n[0], n[1]); else if (!strcmp(op, "shl")) result = intl_shl(n[0], *(uint32_t *)(&n[1])); else if (!strcmp(op, "shr")) result = intl_shr(n[0], *(uint32_t *)(&n[1])); else printf("No such function!\r\n"); printf("result: %s\r\n", intl_show(result, pbuff, sizeof(pbuff), "d")); } else if (!strcmp(execute, "print")) { printf("%s\r\n", intl_show(n[0], pbuff, sizeof(pbuff), format)); } } else { test_base(); } return 0; } /************************************************************************************/ /************************************ Test entry ************************************/ /************************************************************************************/ #if defined(TEST_TARGET_intl) int main(int argc, char *argv[]) { return test(argc, argv); } #else void test_intl(void) { command_export("intl", test); } init_export_app(test_intl); #endif