A lot of refactoring

This commit is contained in:
Thomas Lovén 2018-01-09 22:55:51 +01:00
parent 52846ceeac
commit 126ed26b3d
2 changed files with 155 additions and 95 deletions

View File

@ -5,23 +5,7 @@
#include <string.h> #include <string.h>
char *tt_filename; #define TT_FAIL(error, ...) dprintf(tt_pipe[1], "\"%s\" Line %d: %s >> " error "\n", tt_current->filename, __LINE__, tt_current->name, __VA_ARGS__);
char *tt_current_test;
int tt_fd[2];
int tt_color = 1;
#ifndef TT_BUFFER_SIZE
#define TT_BUFFER_SIZE 512
#endif
#define TT_CLR_RED ((tt_color)?"\x1b[31m":"")
#define TT_CLR_GRN ((tt_color)?"\x1b[32m":"")
#define TT_CLR_BLU ((tt_color)?"\x1b[34m":"")
#define TT_CLR_RES ((tt_color)?"\x1b[0m":"")
#define TT_FAIL(error, ...) dprintf(tt_fd[1], "\"%s\" Line %d: %s >> " error "\n", tt_filename, __LINE__, tt_current_test, __VA_ARGS__);
#define ASSERT_EQUAL(type, pf, lhs, rhs) do { \ #define ASSERT_EQUAL(type, pf, lhs, rhs) do { \
@ -31,7 +15,9 @@ int tt_color = 1;
TT_FAIL("Expected <%" pf "> got <%" pf ">", tt_rhs, tt_lhs); \ TT_FAIL("Expected <%" pf "> got <%" pf ">", tt_rhs, tt_lhs); \
return 1; \ return 1; \
} \ } \
return 0; \
}while(0); }while(0);
#define ASSERT_NOT_EQUAL(type, pf, lhs, rhs) do { \ #define ASSERT_NOT_EQUAL(type, pf, lhs, rhs) do { \
type tt_lhs = (type)(lhs); \ type tt_lhs = (type)(lhs); \
type tt_rhs = (type)(rhs); \ type tt_rhs = (type)(rhs); \
@ -39,6 +25,7 @@ int tt_color = 1;
TT_FAIL("Got <%" pf "> but expected anything else", tt_rhs); \ TT_FAIL("Got <%" pf "> but expected anything else", tt_rhs); \
return 1; \ return 1; \
} \ } \
return 0; \
}while(0); }while(0);
#define ASSERT_STRN(lhs, rhs, n) do { \ #define ASSERT_STRN(lhs, rhs, n) do { \
@ -61,6 +48,7 @@ int tt_color = 1;
return 1; \ return 1; \
} \ } \
free(tt_lhs_c); free(tt_rhs_c); \ free(tt_lhs_c); free(tt_rhs_c); \
return 0; \
}while(0); }while(0);
#define ASSERT_EQ_INT(lhs, rhs) ASSERT_EQUAL(int, "d", lhs, rhs) #define ASSERT_EQ_INT(lhs, rhs) ASSERT_EQUAL(int, "d", lhs, rhs)
@ -69,112 +57,184 @@ int tt_color = 1;
#define ASSERT_NEQ_CHR(lhs, rhs) ASSERT_NOT_EQUAL(char, "c", lhs, rhs) #define ASSERT_NEQ_CHR(lhs, rhs) ASSERT_NOT_EQUAL(char, "c", lhs, rhs)
#define ASSERT_EQ_STR(lhs, rhs, n) ASSERT_STRN(lhs, rhs, n) #define ASSERT_EQ_STR(lhs, rhs, n) ASSERT_STRN(lhs, rhs, n)
typedef int (*tt_test)(void);
struct tt_test
{
char *name;
int (*test)(void);
};
struct tt_test *tt_tests;
int tt_test_count = 0;
#define TEST(name) \ #define TEST(name) \
int ttt_##name(); \ int ttt_##name(); \
__attribute__((constructor)) void tttr_##name() { \ __attribute__((constructor)) void tttr_##name() { \
tt_register(#name, ttt_##name); \ tt_register(#name, ttt_##name, __FILE__); \
} \ } \
int ttt_##name() int ttt_##name()
#define BEFORE() void tt_before() #define BEFORE() void tt_before()
#define AFTER() void tt_after() #define AFTER() void tt_after()
void tt_register(char *name, int (*fn)(void))
{
tt_tests = realloc(tt_tests, (tt_test_count+1)*sizeof(struct tt_test));
tt_tests[tt_test_count].name = name;
tt_tests[tt_test_count].test = fn;
tt_test_count++;
}
void __attribute__((weak)) tt_before(void); void __attribute__((weak)) tt_before(void);
void __attribute__((weak)) tt_after(void); void __attribute__((weak)) tt_after(void);
#ifndef TT_BUFFER_SIZE
#define TT_BUFFER_SIZE 512
#endif
struct tt_test
{
char *filename;
char *name;
int (*test)(void);
int status;
char *output;
};
// Global variables
int tt_pipe[2];
int tt_color = 1;
int tt_verbose = 0;
int tt_silent = 0;
struct tt_test *tt_tests;
struct tt_test *tt_current;
int tt_max_name_len = 0;
int tt_test_count = 0;
void tt_register(char *name, int (*fn)(void), char *filename)
{
tt_tests = realloc(tt_tests, (tt_test_count+1)*sizeof(struct tt_test));
struct tt_test *t = &tt_tests[tt_test_count++];
t->filename = filename;
t->name = name;
t->test = fn;
t->status = 1;
t->output = malloc(TT_BUFFER_SIZE);
if(strlen(name) > tt_max_name_len)
tt_max_name_len = strlen(name);
}
#define TT_CLR_RED ((tt_color)?"\x1b[31m":"")
#define TT_CLR_GRN ((tt_color)?"\x1b[32m":"")
#define TT_CLR_YEL ((tt_color)?"\x1b[33m":"")
#define TT_CLR_RES ((tt_color)?"\x1b[0m":"")
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
tt_filename = argv[1];
if(!isatty(1)) tt_color = 0; if(!isatty(1)) tt_color = 0;
int opt;
while((opt = getopt(argc, argv, "vscn")) != -1)
{
switch(opt)
{
case 'v':
tt_verbose = 1;
tt_silent = 0;
break;
case 's':
tt_silent = 1;
tt_verbose = 0;
break;
case 'c':
tt_color = 1;
break;
case 'n':
tt_color = 0;
break;
}
}
char *buffer = malloc(TT_BUFFER_SIZE); int ok = 0;
char **errors = 0; int failed = 0;
int crashed = 0;
if(!tt_silent)
printf("\n%s\n", tt_tests[0].filename);
int failures = 0;
int i = 0; int i = 0;
while(i < tt_test_count) while(i < tt_test_count)
{ {
struct tt_test *test = &tt_tests[i]; tt_current = &tt_tests[i];
fflush(stdout); fflush(stdout);
pipe(tt_fd); pipe(tt_pipe);
int pid; int pid;
tt_current_test = test->name;
if(!(pid = fork())) if(!(pid = fork()))
{ {
close(tt_fd[0]); // Run test
close(tt_pipe[0]);
if(tt_before) tt_before(); if(tt_before) tt_before();
int result = test->test(); int result = tt_current->test();
if(tt_after) tt_after(); if(tt_after) tt_after();
exit(result); exit(result);
} }
close(tt_fd[1]); // Capture test output
close(tt_pipe[1]);
read(tt_pipe[0], tt_current->output, TT_BUFFER_SIZE);
close(tt_pipe[0]);
// Determine if test passed or not
int status; int status;
waitpid(pid, &status, 0); waitpid(pid, &status, 0);
int failed = 0;
if(read(tt_fd[0], buffer, TT_BUFFER_SIZE))
{
failed = 1;
}
close(tt_fd[0]);
if(!WIFEXITED(status)) if(!WIFEXITED(status))
{ {
failed = 1; crashed++;
sprintf(buffer, "\"%s\" >> TEST %s CRASHED\n", tt_filename, tt_current_test); tt_current->status = -1;
} else if(WEXITSTATUS(status)) {
failed++;
tt_current->status = WEXITSTATUS(status);
} else {
ok++;
tt_current->status = 0;
} }
if(failed)
// Output progress
if(tt_verbose)
printf("%3d/%3d %-*s ", i+1, tt_test_count,
tt_max_name_len, tt_current->name);
switch(tt_current->status)
{ {
failures++; case 0:
errors = realloc(errors, failures*sizeof(char *)); if(tt_verbose)
errors[failures-1] = buffer; printf("[%sOK%s]\n", TT_CLR_GRN, TT_CLR_RES);
buffer = malloc(TT_BUFFER_SIZE);
printf("%sF%s", TT_CLR_RED, TT_CLR_RES);
}
else else
{
printf("%s.%s", TT_CLR_GRN, TT_CLR_RES); printf("%s.%s", TT_CLR_GRN, TT_CLR_RES);
break;
case -1:
if(tt_verbose)
printf("[%sCRASHED%s]\n", TT_CLR_RED, TT_CLR_RES);
else
printf("%sC%s", TT_CLR_RED, TT_CLR_RES);
break;
default:
if(tt_verbose)
printf("[%sFAILED%s]\n", TT_CLR_YEL, TT_CLR_RES);
else
printf("%sF%s", TT_CLR_YEL, TT_CLR_RES);
} }
i++; i++;
} }
int retval = failed+crashed;
// Print summary
if(!tt_silent)
{
printf("\n%s", (retval)?TT_CLR_RED:TT_CLR_GRN);
printf("%d tests, %d failures", tt_test_count, retval);
printf("%s\n", TT_CLR_RES);
}
if(retval && tt_silent)
printf("\n"); printf("\n");
printf("Ran %d tests in %s\n", i, tt_filename);
free(buffer); // Print any errors
if(failures)
{
printf("%sFAILED%s (failures=%d)\n", TT_CLR_RED, TT_CLR_RES, failures);
i = 0; i = 0;
printf("%s========================================%s\n", TT_CLR_RED, TT_CLR_RES); while(i < tt_test_count)
while(i < failures)
{ {
printf("%s", errors[i]); if(tt_tests[i].status)
free(errors[i]); printf("%s", tt_tests[i].output);
free(tt_tests[i].output);
i++; i++;
} }
printf("%s========================================%s\n", TT_CLR_RED, TT_CLR_RES);
free(errors);
}
return failures;
return retval;
} }

10
ttest
View File

@ -9,16 +9,15 @@ main()
local files=`find $dir -name "*.tt"` local files=`find $dir -name "*.tt"`
for suite in $files; do for suite in $files; do
test_exec="${suite}est"
test_exec=`mktemp /tmp/tmp.XXXXXX` compiler_output=`cc -x c $suite -o $test_exec -I $dir/include -I toolchain -DTTEST 2>&1`
compiler_output=`cc -x c $suite -o $test_exec -ggdb -I $dir/include -I toolchain -DTTEST 2>&1`
compiler_status=$? compiler_status=$?
echo -e "\x1b[35m$suite\x1b[0m"
if [[ "$compiler_status" -eq "0" ]]; then if [[ "$compiler_status" -eq "0" ]]; then
$test_exec $suite || failures=$(($failures + 1)) $test_exec $@ || failures=$(($failures + 1))
else else
failures=$(($failures + 1)) failures=$(($failures + 1))
echo
echo -e "\x1b[31mCOMPILATION OF SUITE FAILED\x1b[0m" echo -e "\x1b[31mCOMPILATION OF SUITE FAILED\x1b[0m"
echo "$compiler_output" | sed -e 's/\.tt\.c:/\.tt:/' echo "$compiler_output" | sed -e 's/\.tt\.c:/\.tt:/'
fi fi
@ -26,6 +25,7 @@ main()
done done
done done
echo
exit $failures exit $failures
} }