1. 11
  1.  

  2. 4

    Simple testing frameworks are great, but instead of mixing presentation and testing, you could perhaps emit TAP https://lobste.rs/s/n6y1qt/test_anything_protocol and use existing test harnesses?

    1. 2

      Warning don’t use this from two threads at once. I would have passed around a “test context” that can store the results such as int tt_passes, int tt_fails, etc. Prefixing the macros TT_RUN to avoid potential clashes would have been good too.

      1. 2

        I like single-header unit test frameworks for C. If you’re interested in something with a few more features, I absolutely love Greatest: https://github.com/silentbicycle/greatest.

        1. 1

          We used to use something like:

          /* in testing.h or whatever */
          typedef (int)(*testfunc_t);
          typedef struct { const char* name; testfunc_t test } test_t;
          typedef struct { const char* suiteName; test_t* tests; size_t numTests} test_suite_t;
          
          /* in one or more test files */
          test_t [] myFileTests = [
           { "Test foo", test_foo },
           { "Test foo doesn't assert", test_foo_no_assert},
           /* etc. */
          ];
          size_t myFileTestsCount = sizeof(myFileTests)/(sizeof(test_t);
          
          /* in main.c */
          extern test_t[] myFileTests;
          extern size_t myFileTestsCount;
          
          test_suite suites[] = [
            { "myFile tests", myFileTests, myFileTestsCount }
            /* etc. */
          ];
          size_t numSuites = sizeof(suites) / sizeof(test_suite_t);
          
          /* in main function runner */
          size_t failures = 0;
          size_t testsRun = 0;
          for (size_t i = 0; i < numSuites; i++) {
            printf("=== %s ===\n", suites[i].suiteName);
            for ( size_t j = 0; j < suites[i].numTests; j++ ) {
              testsRun++;
              printf("\t* %s \n", suites[i].tests[j].name);
              if (suites[i].tests[j].test() ) {
                failures++;
              }
            }
          }
          
          printf("Ran %d tests. %d failures.\n", testsRun, failures);
          exit(failures > 0);
          

          EDIT:

          We really need to support code blocks in the markup…