#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)) { return; } tsPrintToBuffer("%d\n", i); } static void tsFloatPrinter(Script* sc) { float f; if(sPopFloat(sc, &f)) { return; } tsPrintToBuffer("%.2f\n", f); } static void tsTextPrinter(Script* sc) { SnuviArray* array = sGetArray(sc); if(array == NULL) { return; } for(int i = 0; i < array->realLength; i++) { tsPrintToBuffer("%c", (char)array->data[i].data.intValue); } 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); if(sc->error[0] != '\0') { printf("script '%s' had error on line %d: %s\n", path, sc->line, sc->error); btPrint(sc->code); return; } 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++; Error e; tTokenize(path, &e); if(eHasError(&e)) { puts(e.message); printf("line: %d\n", e.line); printf("path: %s\n", e.paths); return; } ByteCode* bc = cCompile(&e); if(bc == NULL) { puts(e.message); printf("line: %d\n", e.line); printf("path: %s\n", e.paths); 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(dtInt(), tsInt32Printer); tsAddPrinter(dtFloat(), tsFloatPrinter); tsAddPrinter(dtText(), tsTextPrinter); doneTests = 0; allTests = 0; tsAppend(path); tsScanDirectory(); printf("%d / %d tests succeeded\n", doneTests, allTests); }