|
@@ -0,0 +1,190 @@
|
|
|
+#include <dirent.h>
|
|
|
+#include <errno.h>
|
|
|
+#include <stdbool.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+
|
|
|
+#include "Compiler.h"
|
|
|
+#include "Script.h"
|
|
|
+#include "Tokenizer.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 tsAddBufferIndex(int length) {
|
|
|
+ testBufferIndex += length;
|
|
|
+ if(testBufferIndex > TEST_BUFFER_LENGTH) {
|
|
|
+ testBufferIndex = TEST_BUFFER_LENGTH;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static bool tsPrinter(Object* o) {
|
|
|
+ if(testBufferIndex >= TEST_BUFFER_LENGTH) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if(o->type == OT_INT) {
|
|
|
+ int leftBytes = TEST_BUFFER_LENGTH - testBufferIndex;
|
|
|
+ tsAddBufferIndex(snprintf(testBuffer + testBufferIndex, leftBytes, "%d\n", o->data.intValue));
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+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 void 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(fgetc(file) != EOF) {
|
|
|
+ printf("error in '%s': no full read\n", path);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ doneTests++;
|
|
|
+}
|
|
|
+
|
|
|
+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;
|
|
|
+ }
|
|
|
+ tsCompareResults(file);
|
|
|
+ fclose(file);
|
|
|
+}
|
|
|
+
|
|
|
+static void tsCheckFile() {
|
|
|
+ allTests++;
|
|
|
+ if(tTokenize(path)) {
|
|
|
+ puts(tGetError());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ int codeLength;
|
|
|
+ unsigned char* code = cCompile(&codeLength);
|
|
|
+ if(code == NULL) {
|
|
|
+ if(cGetError() == NULL) {
|
|
|
+ printf("'%s' has error but none was set\n", path);
|
|
|
+ } else {
|
|
|
+ puts(cGetError());
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Script* sc = sInit(code, codeLength);
|
|
|
+ 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 String readLine(std::ifstream& f) {
|
|
|
+ String s;
|
|
|
+ while(true) {
|
|
|
+ char c = f.get();
|
|
|
+ if(!f.good() || c == '\n') {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ s += c;
|
|
|
+ }
|
|
|
+ return s;
|
|
|
+}
|
|
|
+
|
|
|
+static bool testTokenizer(const String& input, const String& output) {
|
|
|
+ tests++;
|
|
|
+ std::ifstream oStream;
|
|
|
+ oStream.open(output);
|
|
|
+ if(!oStream.good()) {
|
|
|
+ std::cout << "cannot open file '" << output << "'\n";
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ TokenStream tokenStream;
|
|
|
+ if(Tokenizer::tokenize(tokenStream, input)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ while(true) {
|
|
|
+ String expected = readLine(oStream);
|
|
|
+ if(expected.getLength() == 0) {
|
|
|
+ break;
|
|
|
+ } else if(!tokenStream.hasToken()) {
|
|
|
+ std::cout << "error in '" << input << "\n'out of tokens\n";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ String buffer = tokenStream.nextTokenString();
|
|
|
+ if(strchr(buffer, '\n') != nullptr) {
|
|
|
+ expected += '\n';
|
|
|
+ expected += readLine(oStream);
|
|
|
+ }
|
|
|
+ if(strcmp(buffer, expected) != 0) {
|
|
|
+ std::cout << "error in '" << input << "\n'" << buffer << "' should be '" << expected << "'\n";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ done++;
|
|
|
+ return false;
|
|
|
+}*/
|
|
|
+
|
|
|
+void tsStart(const char* path) {
|
|
|
+ sSetPrinter(tsPrinter);
|
|
|
+ doneTests = 0;
|
|
|
+ allTests = 0;
|
|
|
+ tsAppend(path);
|
|
|
+ tsScanDirectory();
|
|
|
+ printf("%d / %d tests succeeded\n", doneTests, allTests);
|
|
|
+}
|