#include #include #include #include #include #include #include #include "Compiler.h" #include "tokenizer/Tokenizer.h" #include "utils/ByteCodePrinter.h" #include "vm/Script.h" static int doneTests = 0; static int allTests = 0; static char path[PATH_MAX] = {'\0'}; static int pathIndex = 0; #define TEST_BUFFER_LENGTH (1024 * 2) static char testBuffer[TEST_BUFFER_LENGTH]; static int testBufferIndex = 0; static void tsPrintToBuffer(const char* format, ...) { va_list args; va_start(args, format); int leftBytes = TEST_BUFFER_LENGTH - testBufferIndex; testBufferIndex += vsnprintf(testBuffer + testBufferIndex, leftBytes, format, args); if(testBufferIndex > TEST_BUFFER_LENGTH) { testBufferIndex = TEST_BUFFER_LENGTH; } va_end(args); } static void tsIntPrinter(int i) { tsPrintToBuffer("%d\n", i); } static void tsFloatPrinter(float f) { tsPrintToBuffer("%.2f\n", f); } static void tsBoolPrinter(bool b) { tsPrintToBuffer(b ? "true\n" : "false\n"); } static void tsPointerPrinter(Pointer* p) { tsPrintToBuffer("(%d, %d)\n", p->array, p->offset); } static void tsAppend(const char* s) { for(int i = 0; pathIndex < (PATH_MAX - 1) && s[i] != '\0'; i++) { path[pathIndex++] = s[i]; } path[pathIndex] = '\0'; } static int tsEnter(const char* s) { int marker = pathIndex; tsAppend("/"); tsAppend(s); return marker; } static void tsReset(int marker) { path[marker] = '\0'; pathIndex = marker; } static bool tsCompareResults(FILE* file) { for(int i = 0; i < testBufferIndex; i++) { char a = fgetc(file); char b = testBuffer[i]; if(a != b) { printf("error in '%s': expected %c, got:\n%s", path, a, testBuffer + i); return true; } } if(fgetc(file) != EOF) { printf("error in '%s': no full read\n", path); return true; } doneTests++; return false; } static void tsCheckScript(Script* sc) { testBufferIndex = 0; sRun(sc); tsAppend(".out"); FILE* file = fopen(path, "r"); if(file == NULL) { printf("cannot open result file '%s'\n", path); return; } if(tsCompareResults(file)) { btPrint(sc->code); } else if(sc->stackIndex != 0) { printf("%s has non empty stack: %d\n", path, sc->stackIndex); btPrint(sc->code); } fclose(file); } static void tsCheckFile() { allTests++; if(tTokenize(path)) { puts(path); puts(tGetError()); return; } ByteCode* bc = cCompile(); if(bc == NULL) { puts(path); puts(cGetError()); printf("line: %d\n", cGetLine()); return; } Script* sc = sInit(bc); tsCheckScript(sc); sDelete(sc); } static void tsScanDirectory() { DIR* dir = opendir(path); if(dir == NULL) { printf("cannot open '%s': %s\n", path, strerror(errno)); return; } while(true) { struct dirent* e = readdir(dir); if(e == NULL) { return; } else if(strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) { continue; } else if(e->d_type == DT_DIR) { int marker = tsEnter(e->d_name); tsScanDirectory(); tsReset(marker); } else if(e->d_type == DT_REG && strchr(e->d_name, '.') == NULL) { int marker = tsEnter(e->d_name); tsCheckFile(); tsReset(marker); } } if(closedir(dir)) { printf("cannot close '%s': %s\n", path, strerror(errno)); } } void tsStart(const char* path) { sSetIntPrinter(tsIntPrinter); sSetFloatPrinter(tsFloatPrinter); sSetBoolPrinter(tsBoolPrinter); sSetPointerPrinter(tsPointerPrinter); doneTests = 0; allTests = 0; tsAppend(path); tsScanDirectory(); printf("%d / %d tests succeeded\n", doneTests, allTests); }