#include #include #include #include #include #include #include #include "Compiler.h" #include "tokenizer/Tokenizer.h" #include "utils/ByteCodePrinter.h" #include "utils/Functions.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 tsInt32Printer(Script* sc) { int32 i; if(sPopInt32(sc, &i)) { tsPrintToBuffer("%d\n", i); } } static void tsInt64Printer(Script* sc) { int64 i; if(sPopInt64(sc, &i)) { tsPrintToBuffer("%ld\n", i); } } static void tsFloatPrinter(Script* sc) { float f; if(sPopFloat(sc, &f)) { tsPrintToBuffer("%.2f\n", f); } } static void tsBoolPrinter(Script* sc) { bool b; if(sPopBool(sc, &b)) { tsPrintToBuffer(b ? "true\n" : "false\n"); } } static void tsTextPrinter(Script* sc) { Pointer p; if(sPopPointer(sc, &p)) { int32 length; if(sGetPointerLength(sc, &p, &length)) { return; } for(int i = 0; i < length; i++) { int32* ip = sCheckAddress(sc, &p, sizeof(int32)); tsPrintToBuffer("%c", (char)*ip); p.offset += sizeof(int32); } tsPrintToBuffer("\n"); } } 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()); printf("line: %d\n", tGetLine()); 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)); } } static void tsAddPrinter(DataType in, ScriptFunction sf) { Function f; gfInit(&f, "test", dtVoid(), sf); gfAddArgument(&f, in); gfsAdd(&f); } void tsStart(const char* path) { tsAddPrinter(dtConst(dtInt32()), tsInt32Printer); tsAddPrinter(dtConst(dtInt64()), tsInt64Printer); tsAddPrinter(dtConst(dtFloat()), tsFloatPrinter); tsAddPrinter(dtConst(dtBool()), tsBoolPrinter); tsAddPrinter(dtConst(dtText()), tsTextPrinter); doneTests = 0; allTests = 0; tsAppend(path); tsScanDirectory(); printf("%d / %d tests succeeded\n", doneTests, allTests); }