Browse Source

new test system

Kajetan Johannes Hammerle 3 years ago
parent
commit
4859582fdf
10 changed files with 229 additions and 149 deletions
  1. 4 40
      Main.c
  2. 15 3
      Script.c
  3. 5 0
      Script.h
  4. 190 0
      Test.c
  5. 6 0
      Test.h
  6. 1 1
      meson.build
  7. 0 97
      test/Test.cpp
  8. 0 8
      test/Test.h
  9. 4 0
      tests/calc/adding
  10. 4 0
      tests/calc/adding.out

+ 4 - 40
Main.c

@@ -1,44 +1,8 @@
-#include <stdio.h>
-#include <stdlib.h>
+#include "Test.h"
 
-#include "Compiler.h"
-#include "Script.h"
-#include "Tokenizer.h"
-
-int main() {
-    if(tTokenize("../tests/test")) {
-        puts(tGetError());
-        return 0;
-    }
-
-    while(true) {
-        Token token = tReadToken();
-        if(token == T_END) {
-            break;
-        }
-        if(token == T_INT) {
-            int value;
-            tReadInt(&value);
-            printf("> %s %d\n", tGetTokenName(token), value);
-        } else {
-            printf("> %s\n", tGetTokenName(token));
-        }
+int main(int argAmount, const char** args) {
+    if(argAmount >= 2) {
+        tsStart(args[1]);
     }
-    tResetReader();
-
-    int codeLength = 0;
-    unsigned char* code = cCompile(&codeLength);
-    if(code == NULL) {
-        if(cGetError() == NULL) {
-            puts("error not set as it should");
-        } else {
-            puts(cGetError());
-        }
-        return 0;
-    }
-
-    Script* sc = sInit(code, codeLength);
-    sRun(sc);
-    sDelete(sc);
     return 0;
 }

+ 15 - 3
Script.c

@@ -12,6 +12,16 @@ static const char* NOT_PRINTABLE = "cannot print given object";
 static const char* STACK_OVERFLOW = "stack overflow";
 static const char* STACK_UNDERFLOW = "stack underflow";
 
+static bool sPrinter(Object* o) {
+    if(o->type == OT_INT) {
+        printf("%d\n", o->data.intValue);
+        return false;
+    }
+    return true;
+}
+
+static ObjectPrinter printer = sPrinter;
+
 static bool sRead(Script* sc, void* buffer, int length) {
     if(sc->readIndex + length > sc->byteCodeLength) {
         return true;
@@ -78,9 +88,7 @@ void sPrint(Script* sc) {
     if(sPop(sc, &o)) {
         return;
     }
-    if(o.type == OT_INT) {
-        printf("%d\n", o.data.intValue);
-    } else {
+    if(printer(&o)) {
         sc->error = NOT_PRINTABLE;
     }
 }
@@ -120,4 +128,8 @@ void sRun(Script* sc) {
             return;
         }
     }
+}
+
+void sSetPrinter(ObjectPrinter p) {
+    printer = p;
 }

+ 5 - 0
Script.h

@@ -1,6 +1,8 @@
 #ifndef SCRIPT_H
 #define SCRIPT_H
 
+#include <stdbool.h>
+
 #include "Object.h"
 
 #define SCRIPT_STACK_SIZE 50
@@ -19,4 +21,7 @@ void sDelete(Script* sc);
 
 void sRun(Script* sc);
 
+typedef bool (*ObjectPrinter)(Object*);
+void sSetPrinter(ObjectPrinter p);
+
 #endif

+ 190 - 0
Test.c

@@ -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);
+}

+ 6 - 0
Test.h

@@ -0,0 +1,6 @@
+#ifndef TEST_H
+#define TEST_H
+
+void tsStart(const char* path);
+
+#endif

+ 1 - 1
meson.build

@@ -1,6 +1,6 @@
 project('lonely tiger', 'c')
 
-src = ['Main.c', 'Tokenizer.c', 'Compiler.c', 'Utils.c', 'Script.c']
+src = ['Main.c', 'Tokenizer.c', 'Compiler.c', 'Utils.c', 'Script.c', 'Test.c']
 
 executable('lonely_tiger', 
     sources: src,

+ 0 - 97
test/Test.cpp

@@ -1,97 +0,0 @@
-#include <cstring>
-#include <fstream>
-#include <iostream>
-
-#include <dirent.h>
-
-#include "test/Test.h"
-#include "tokenizer/TokenStream.h"
-#include "tokenizer/Tokenizer.h"
-#include "utils/String.h"
-
-static unsigned int done = 0;
-static unsigned int tests = 0;
-
-static bool checkPath(const String& path, const char* ending, bool (*f)(const String&, const String&)) {
-    DIR* dir = opendir(path);
-    if(dir == nullptr) {
-        std::cout << "cannot open '" << path << "': " << strerror(errno) << "\n";
-        return true;
-    }
-    while(true) {
-        struct dirent* entry = readdir(dir);
-        if(entry == nullptr) {
-            break;
-        } else if(strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
-            continue;
-        } else if(entry->d_type == DT_DIR) {
-            checkPath(path + "/" + entry->d_name, ending, f);
-        } else if(entry->d_type == DT_REG && strchr(entry->d_name, '.') == nullptr) {
-            if(f(path + "/" + entry->d_name, path + "/" + entry->d_name + ending)) {
-                return true;
-            }
-        }
-    }
-    if(closedir(dir)) {
-        std::cout << "cannot close '" << path << "': " << strerror(errno) << "\n";
-        return true;
-    }
-    return false;
-}
-
-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;
-}
-
-static void startTokenizerTests(const char* path) {
-    done = 0;
-    tests = 0;
-    checkPath(path, ".tout", testTokenizer);
-    std::cout << done << " / " << tests << " tokenizer tests succeeded\n";
-}
-
-void Test::start(const char* path) {
-    startTokenizerTests(path);
-}

+ 0 - 8
test/Test.h

@@ -1,8 +0,0 @@
-#ifndef TEST_H
-#define TEST_H
-
-namespace Test {
-    void start(const char* path);
-}
-
-#endif

+ 4 - 0
tests/calc/adding

@@ -0,0 +1,4 @@
+print 1;
+print 2 + 3;
+print 3 + 4 + 5;
+print 6 + 7 + 8 + 9;

+ 4 - 0
tests/calc/adding.out

@@ -0,0 +1,4 @@
+1
+5
+12
+30