Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-07 10:15:35

0001 /*
0002     Copyright (C) 2021 Daniel Schultz
0003     Copyright (C) 2023, 2024 Albin Ahlbäck
0004 
0005     This file is part of FLINT.
0006 
0007     FLINT is free software: you can redistribute it and/or modify it under
0008     the terms of the GNU Lesser General Public License (LGPL) as published
0009     by the Free Software Foundation; either version 3 of the License, or
0010     (at your option) any later version.  See <https://www.gnu.org/licenses/>.
0011 */
0012 
0013 #ifndef TEST_HELPERS_H
0014 #define TEST_HELPERS_H
0015 
0016 #include <time.h> /* clock */
0017 #include <string.h> /* strlen, strcmp, strncmp */
0018 #include <stdlib.h> /* strtol */
0019 #include <limits.h> /* LONG_MIN */
0020 #include "templates.h"
0021 #include "flint.h"
0022 
0023 #if FLINT_WANT_PRETTY_TESTS
0024 # define _RED "\033[0;31m"
0025 # define _RED_B "\033[1;31m"
0026 # define _GREEN "\033[0;32m"
0027 # define _GREEN_B "\033[1;32m"
0028 # define _YELLOW "\033[0;33m"
0029 # define _YELLOW_B "\033[1;33m"
0030 # define _RESET "\033[0m"
0031 #else
0032 # define _RED
0033 # define _RED_B
0034 # define _GREEN
0035 # define _GREEN_B
0036 # define _YELLOW
0037 # define _YELLOW_B
0038 # define _RESET
0039 #endif
0040 
0041 /* easy way to test a condition in test code */
0042 #define FLINT_TEST(e)                                   \
0043     do {                                                \
0044         if (!(e))                                       \
0045         {                                               \
0046             flint_throw(FLINT_ERROR, "test %s FAILED\n%s:%d", #e, __FILE__, __LINE__); \
0047         }                                               \
0048     } while (0)
0049 
0050 /* test function macro *******************************************************/
0051 
0052 typedef struct
0053 {
0054     int (* test_function)(void);
0055     char * name;
0056 }
0057 test_struct;
0058 
0059 #define TEST_FUNCTION(label) { CAT(test, label), #label }
0060 
0061 #define TEST_FUNCTION_START(label, state)               \
0062 int CAT(test, label)(void)                              \
0063 {                                                       \
0064     double FLINT_SET_BUT_UNUSED(_start_time_), FLINT_SET_BUT_UNUSED(_end_time_); \
0065     char _test_io_string_[128] = #label "                                                        "; \
0066     const int _label_len_ = sizeof(#label) - 1;         \
0067     puts(#label "...");                                 \
0068     FLINT_TEST_INIT(state);                             \
0069     _start_time_ = clock();
0070 
0071 #define TEST_GR_FUNCTION_START(label, state, count_success, count_domain, count_unable) \
0072 int CAT(test, label)(void)                              \
0073 {                                                       \
0074     slong count_success = 0, count_unable = 0, count_domain = 0; \
0075     double FLINT_SET_BUT_UNUSED(_start_time_), FLINT_SET_BUT_UNUSED(_end_time_); \
0076     char _test_io_string_[128] = #label "                                                        "; \
0077     const int _label_len_ = sizeof(#label) - 1;         \
0078     puts(#label "...");                                 \
0079     FLINT_TEST_INIT(state);                             \
0080     _start_time_ = clock();
0081 
0082 #define TEST_TEMPLATE_FUNCTION_START(T, label, state)   \
0083 int TEMPLATE3(test, T, label)(void)                     \
0084 {                                                       \
0085     double FLINT_SET_BUT_UNUSED(_start_time_), FLINT_SET_BUT_UNUSED(_end_time_); \
0086     char _test_io_string_[128] = TEMPLATE_STR(T) "_" #label "                                                      "; \
0087     const int _label_len_ = sizeof(TEMPLATE_STR(T) "_" #label) - 1; \
0088     puts(TEMPLATE_STR(T) "_" #label "...");             \
0089     FLINT_TEST_INIT(state);                             \
0090     _start_time_ = clock();
0091 
0092 #define TEST_TEMPLATE2_FUNCTION_START(T, label1, label2, state)\
0093 int TEMPLATE5(test, T, label1, T, label2)(void)         \
0094 {                                                       \
0095     double FLINT_SET_BUT_UNUSED(_start_time_), FLINT_SET_BUT_UNUSED(_end_time_); \
0096     char _test_io_string_[128] = TEMPLATE_STR(T) "_" #label1 "_" TEMPLATE_STR(T) "_" #label2 "                                                  "; \
0097     const int _label_len_ = sizeof(TEMPLATE_STR(T) "_" #label1 "_" TEMPLATE_STR(T) "_" #label2) - 1; \
0098     puts(TEMPLATE_STR(T) "_" #label1 "_" TEMPLATE_STR(T) "_" #label2 "..."); \
0099     FLINT_TEST_INIT(state);                             \
0100     _start_time_ = clock();
0101 
0102 #define TEST_FUNCTION_END(state)                        \
0103     _end_time_ = clock();                               \
0104     FLINT_TEST_CLEAR(state);                            \
0105     if (_label_len_ < 48)                               \
0106         printf("%.48s%6.2f   (" _GREEN_B "PASS" _RESET ")\n", \
0107                 _test_io_string_,                       \
0108                 (_end_time_ - _start_time_) / CLOCKS_PER_SEC); \
0109     else                                                \
0110         printf("%.*s\n%54.2f   (" _GREEN_B "PASS" _RESET ")\n", \
0111                 _label_len_, _test_io_string_,          \
0112                 (_end_time_ - _start_time_) / CLOCKS_PER_SEC); \
0113     return 0;                                           \
0114 }
0115 
0116 #define TEST_GR_FUNCTION_END(state, count_success, count_domain, count_unable) \
0117     _end_time_ = clock();                               \
0118     FLINT_TEST_CLEAR(state);                            \
0119     printf("%.*s\n  "                                   \
0120             "%5" _WORD_FMT "d success, "                \
0121             "%5" _WORD_FMT "d domain, "                 \
0122             "%5" _WORD_FMT "d unable"                   \
0123             "%11.2f   "                                 \
0124             "(" _GREEN_B "PASS" _RESET ")\n",           \
0125             _label_len_, _test_io_string_,              \
0126             count_success, count_domain, count_unable,  \
0127             (_end_time_ - _start_time_) / CLOCKS_PER_SEC); \
0128     return 0;                                           \
0129 }
0130 
0131 #define TEST_FUNCTION_END_SKIPPED(state)                \
0132     FLINT_TEST_CLEAR(state);                            \
0133     if (_label_len_ < 54)                               \
0134         printf("%.*s(" _YELLOW_B "SKIPPED" _RESET ")\n", \
0135                 54, _test_io_string_);                  \
0136     else                                                \
0137         printf("%.*s\n%*s(" _YELLOW_B "SKIPPED" _RESET ")\n", \
0138                 _label_len_, _test_io_string_,          \
0139                 54, "");                                \
0140     return 0;                                           \
0141 }
0142 
0143 #define TEST_FUNCTION_FAIL(...)                         \
0144 do                                                      \
0145 {                                                       \
0146     _end_time_ = clock();                               \
0147     if (_label_len_ < 48)                               \
0148         printf("%.48s%6.2f   (" _RED_B "FAIL" _RESET ")\n", \
0149                 _test_io_string_,                       \
0150                 (_end_time_ - _start_time_) / CLOCKS_PER_SEC); \
0151     else                                                \
0152         printf("%.*s\n%54.2f   (" _RED_B "FAIL" _RESET ")\n", \
0153                 _label_len_, _test_io_string_,          \
0154                 (_end_time_ - _start_time_) / CLOCKS_PER_SEC); \
0155     flint_printf(__VA_ARGS__);                          \
0156     return 1;                                           \
0157 } while (0)
0158 
0159 #define TEST_MAIN(tests)                                                    \
0160 int                                                                         \
0161 main(int argc, char ** argv)                                                \
0162 {                                                                           \
0163     char numthreads_str[] = "--numthreads=";                                \
0164     char thread_str[] = "--thread=";                                        \
0165     size_t numthreads_str_len = sizeof(numthreads_str) / sizeof(char) - 1;  \
0166     size_t thread_str_len = sizeof(thread_str) / sizeof(char) - 1;          \
0167     long int numthreads, thread;                                            \
0168     int ix, ix_max, numtests;                                               \
0169                                                                             \
0170     numtests = sizeof(tests) / sizeof(test_struct);                         \
0171                                                                             \
0172     /* If no arguments was put in, simply run all tests. */                 \
0173     if (argc < 2)                                                           \
0174     {                                                                       \
0175         for (ix = 0; ix < numtests; ix++)                                   \
0176             if ((tests)[ix].test_function())                                \
0177                 flint_abort();                                              \
0178                                                                             \
0179         return 0;                                                           \
0180     }                                                                       \
0181                                                                             \
0182     /* If no options not specified, then run the set of functions specified */\
0183     if (argv[1][0] != '-' && argv[1][1] != '-')                             \
0184     {                                                                       \
0185         int jx;                                                             \
0186                                                                             \
0187         for (jx = 1; jx < argc; jx++)                                       \
0188         {                                                                   \
0189             for (ix = 0; ix < numtests; ix++)                               \
0190             {                                                               \
0191                 /* If argument equals to test name, run it */               \
0192                 if (strcmp(argv[jx], (tests)[ix].name) == 0)                \
0193                 {                                                           \
0194                     if ((tests)[ix].test_function())                        \
0195                         flint_abort();                                      \
0196                     break;                                                  \
0197                 }                                                           \
0198             }                                                               \
0199                                                                             \
0200             if (ix == numtests)                                             \
0201             {                                                               \
0202                 flint_throw(FLINT_ERROR, "Could not find test function for %s\n", argv[jx]); \
0203             }                                                               \
0204         }                                                                   \
0205                                                                             \
0206         return 0;                                                           \
0207     }                                                                       \
0208                                                                             \
0209     /* If the length of first argument is less or equal to the the length of\
0210      * "--numthreads=" or that the first argument does not start with       \
0211      * "--numthreads=", then exit. */                                       \
0212     if (strlen(argv[1]) <= numthreads_str_len                               \
0213         || strncmp(argv[1], numthreads_str, numthreads_str_len) != 0)       \
0214     {                                                                       \
0215         printf("Invalid first option, must be --numthreads=NUM.\n");        \
0216         return 1;                                                           \
0217     }                                                                       \
0218                                                                             \
0219     /* Parse the argument. An invalid argument is either returned as LONG_MIN,\
0220      * LONG_MAX or 0. Moreover, we require the argument to be strictly positive.\
0221      * If the argument is invalid or non-positive, exit. */                 \
0222     numthreads = strtol(argv[1] + numthreads_str_len, NULL, 10);            \
0223     if (numthreads == LONG_MAX || numthreads <= 0)                          \
0224     {                                                                       \
0225         printf("Invalid parameter for option --numthreads=NUM.\n");         \
0226         return 1;                                                           \
0227     }                                                                       \
0228                                                                             \
0229     /* Same goes here as for the first argument */                          \
0230     if (strlen(argv[2]) <= thread_str_len                                   \
0231         || strncmp(argv[2], thread_str, thread_str_len) != 0)               \
0232     {                                                                       \
0233         printf("Invalid second option, must be --thread=NUM.\n");           \
0234         return 1;                                                           \
0235     }                                                                       \
0236                                                                             \
0237     /* Same goes here as for the first argument, with the addition that the \
0238      * parameter for this option must be less or equal to the previous argument. */\
0239     thread = strtol(argv[2] + thread_str_len, NULL, 10);                    \
0240     if (thread == LONG_MAX || thread <= 0 || thread > numthreads)           \
0241     {                                                                       \
0242         printf("Invalid parameter for option --thread=NUM.\n");             \
0243         return 1;                                                           \
0244     }                                                                       \
0245                                                                             \
0246     /* We split the tests into `numthreads_par' partitions, and run the     \
0247      * `thread_par'-th partition. */                                        \
0248     ix = (thread - 1) * ((numtests + numthreads - 1) / numthreads);         \
0249     ix_max = FLINT_MIN(thread * ((numtests + numthreads - 1) / numthreads), numtests);\
0250     for (; ix < ix_max; ix++)                                               \
0251         if ((tests)[ix].test_function())                                    \
0252             flint_abort();                                                  \
0253                                                                             \
0254     return 0;                                                               \
0255 }
0256 
0257 #endif