]> de.git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - test.c
Fixes
[xonotic/gmqcc.git] / test.c
diff --git a/test.c b/test.c
index ebd7bfa89c97310674a5ebde1c4bab6e73da3f8d..107140e5cc7697f4a7e5e346e7334f12dd7a53cb 100644 (file)
--- a/test.c
+++ b/test.c
@@ -176,8 +176,8 @@ int task_pclose(FILE **handles) {
     }
 #endif /*! _WIN32 */
 
-#define TASK_COMPILE 0
-#define TASK_EXECUTE 1
+#define TASK_COMPILE    0
+#define TASK_EXECUTE    1
 /*
  * Task template system:
  *  templates are rules for a specific test, used to create a "task" that
@@ -269,6 +269,7 @@ typedef struct {
  */
 bool task_template_generate(task_template_t *tmpl, char tag, const char *file, size_t line, char *value, size_t *pad) {
     size_t desclen = 0;
+    size_t filelen = 0;
     char **destval = NULL;
 
     if (!tmpl)
@@ -333,6 +334,9 @@ bool task_template_generate(task_template_t *tmpl, char tag, const char *file, s
             pad[0] = desclen;
     }
 
+    if ((filelen = strlen(file)) > pad[2])
+        pad[2] = filelen;
+
     return true;
 }
 
@@ -563,7 +567,13 @@ task_template_t *task_template_compile(const char *file, const char *dir, size_t
             con_err("template compile warning: %s erroneous tag `E:` when only failing\n", file);
         if (tmpl->comparematch)
             con_err("template compile warning: %s erroneous tag `M:` when only failing\n", file);
-        goto success;
+    } else if (!strcmp(tmpl->proceduretype, "-pp")) {
+        if (tmpl->executeflags)
+            con_err("template compile warning: %s erroneous tag `E:` when only preprocessing\n", file);
+        if (!tmpl->comparematch) {
+            con_err("template compile error: %s missing `M:` tag (use `$null` for exclude)\n", file);
+            goto failure;
+        }
     } else {
         con_err("template compile error: %s invalid procedure type: %s\n", file, tmpl->proceduretype);
         goto failure;
@@ -644,10 +654,10 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
     char             buffer[4096];
     size_t           found = 0;
 
-    dir = opendir(curdir);
+    dir = fs_dir_open(curdir);
 
-    while ((files = readdir(dir))) {
-        snprintf(buffer,   sizeof(buffer), "%s/%s", curdir, files->d_name);
+    while ((files = fs_dir_read(dir))) {
+        snprintf(buffer, sizeof(buffer), "%s/%s", curdir, files->d_name);
 
         if (stat(buffer, &directory) == -1) {
             con_err("internal error: stat failed, aborting\n");
@@ -679,7 +689,8 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
              * Generate a temportary file name for the output binary
              * so we don't trample over an existing one.
              */
-            tmpl->tempfilename = tempnam(curdir, "TMPDAT");
+            tmpl->tempfilename = NULL;
+            util_asprintf(&tmpl->tempfilename, "%s/TMPDAT.%s", curdir, files->d_name);
 
             /*
              * Additional QCFLAGS enviroment variable may be used
@@ -693,45 +704,66 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
              * which will be refered to with a handle in the task for
              * reading the data from the pipe.
              */
-            if (qcflags) {
-                if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
-                    snprintf(buf, sizeof(buf), "%s %s/%s %s %s -o %s",
-                        task_bins[TASK_COMPILE],
-                        curdir,
-                        tmpl->sourcefile,
-                        qcflags,
-                        tmpl->compileflags,
-                        tmpl->tempfilename
-                    );
+            if (strcmp(tmpl->proceduretype, "-pp")) {
+                if (qcflags) {
+                    if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
+                        snprintf(buf, sizeof(buf), "%s %s/%s %s %s -o %s",
+                            task_bins[TASK_COMPILE],
+                            curdir,
+                            tmpl->sourcefile,
+                            qcflags,
+                            tmpl->compileflags,
+                            tmpl->tempfilename
+                        );
+                    } else {
+                        snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s %s -o %s",
+                            task_bins[TASK_COMPILE],
+                            curdir,
+                            defs,
+                            curdir,
+                            tmpl->sourcefile,
+                            qcflags,
+                            tmpl->compileflags,
+                            tmpl->tempfilename
+                        );
+                    }
                 } else {
-                    snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s %s -o %s",
-                        task_bins[TASK_COMPILE],
-                        curdir,
-                        defs,
-                        curdir,
-                        tmpl->sourcefile,
-                        qcflags,
-                        tmpl->compileflags,
-                        tmpl->tempfilename
-                    );
+                    if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
+                        snprintf(buf, sizeof(buf), "%s %s/%s %s -o %s",
+                            task_bins[TASK_COMPILE],
+                            curdir,
+                            tmpl->sourcefile,
+                            tmpl->compileflags,
+                            tmpl->tempfilename
+                        );
+                    } else {
+                        snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s -o %s",
+                            task_bins[TASK_COMPILE],
+                            curdir,
+                            defs,
+                            curdir,
+                            tmpl->sourcefile,
+                            tmpl->compileflags,
+                            tmpl->tempfilename
+                        );
+                    }
                 }
             } else {
+                /* Preprocessing (qcflags mean shit all here we don't allow them) */
                 if (tmpl->testflags && !strcmp(tmpl->testflags, "-no-defs")) {
-                    snprintf(buf, sizeof(buf), "%s %s/%s %s -o %s",
+                    snprintf(buf, sizeof(buf), "%s -E %s/%s -o %s",
                         task_bins[TASK_COMPILE],
                         curdir,
                         tmpl->sourcefile,
-                        tmpl->compileflags,
                         tmpl->tempfilename
                     );
                 } else {
-                    snprintf(buf, sizeof(buf), "%s %s/%s %s/%s %s -o %s",
+                    snprintf(buf, sizeof(buf), "%s -E %s/%s %s/%s -o %s",
                         task_bins[TASK_COMPILE],
                         curdir,
                         defs,
                         curdir,
                         tmpl->sourcefile,
-                        tmpl->compileflags,
                         tmpl->tempfilename
                     );
                 }
@@ -777,7 +809,7 @@ bool task_propagate(const char *curdir, size_t *pad, const char *defs) {
         found
     );
 
-    closedir(dir);
+    fs_dir_close(dir);
     return success;
 }
 
@@ -790,9 +822,9 @@ void task_precleanup(const char *curdir) {
     struct dirent   *files;
     char             buffer[4096];
 
-    dir = opendir(curdir);
+    dir = fs_dir_open(curdir);
 
-    while ((files = readdir(dir))) {
+    while ((files = fs_dir_read(dir))) {
         if (strstr(files->d_name, "TMP")     ||
             strstr(files->d_name, ".stdout") ||
             strstr(files->d_name, ".stderr"))
@@ -805,7 +837,7 @@ void task_precleanup(const char *curdir) {
         }
     }
 
-    closedir(dir);
+    fs_dir_close(dir);
 }
 
 void task_destroy(void) {
@@ -854,40 +886,50 @@ void task_destroy(void) {
 /*
  * This executes the QCVM task for a specificly compiled progs.dat
  * using the template passed into it for call-flags and user defined
- * messages.
+ * messages IF the procedure type is -execute, otherwise it matches
+ * the preprocessor output. 
  */
-bool task_execute(task_template_t *tmpl, char ***line) {
+bool task_trymatch(task_template_t *tmpl, char ***line) {
     bool     success = true;
     FILE    *execute;
     char     buffer[4096];
     memset  (buffer,0,sizeof(buffer));
 
-    /*
-     * Drop the execution flags for the QCVM if none where
-     * actually specified.
-     */
-    if (!strcmp(tmpl->executeflags, "$null")) {
-        snprintf(buffer,  sizeof(buffer), "%s %s",
-            task_bins[TASK_EXECUTE],
-            tmpl->tempfilename
+    if (strcmp(tmpl->proceduretype, "-pp")) {
+        /*
+         * Drop the execution flags for the QCVM if none where
+         * actually specified.
+         */
+        if (!strcmp(tmpl->executeflags, "$null")) {
+            snprintf(buffer,  sizeof(buffer), "%s %s",
+                task_bins[TASK_EXECUTE],
+                tmpl->tempfilename
+            );
+        } else {
+            snprintf(buffer,  sizeof(buffer), "%s %s %s",
+                task_bins[TASK_EXECUTE],
+                tmpl->executeflags,
+                tmpl->tempfilename
+            );
+        }
+
+        util_debug("TEST", "executing qcvm: `%s` [%s]\n",
+            tmpl->description,
+            buffer
         );
+
+        execute = popen(buffer, "r");
+        if (!execute)
+            return false;
     } else {
-        snprintf(buffer,  sizeof(buffer), "%s %s %s",
-            task_bins[TASK_EXECUTE],
-            tmpl->executeflags,
-            tmpl->tempfilename
-        );
+        /*
+         * we're preprocessing, which means we need to read int
+         * the produced file and do some really weird shit.
+         */
+        if (!(execute = fs_file_open(tmpl->tempfilename, "r")))
+            return false;
     }
 
-    util_debug("TEST", "executing qcvm: `%s` [%s]\n",
-        tmpl->description,
-        buffer
-    );
-
-    execute = popen(buffer, "r");
-    if (!execute)
-        return false;
-
     /*
      * Now lets read the lines and compare them to the matches we expect
      * and handle accordingly.
@@ -913,6 +955,13 @@ bool task_execute(task_template_t *tmpl, char ***line) {
             if  (strrchr(data, '\n'))
                 *strrchr(data, '\n') = '\0';
 
+            /*
+             * If data is just null now, that means the line was an empty
+             * one and for that, we just ignore it.
+             */
+            if (!*data)
+                continue;
+
             if (vec_size(tmpl->comparematch) > compare) {
                 if (strcmp(data, tmpl->comparematch[compare++]))
                     success = false;
@@ -933,10 +982,25 @@ bool task_execute(task_template_t *tmpl, char ***line) {
         mem_d(data);
         data = NULL;
     }
-    pclose(execute);
+
+    if (strcmp(tmpl->proceduretype, "-pp"))
+        pclose(execute);
+    else
+        fs_file_close(execute);
+
     return success;
 }
 
+const char *task_type(task_template_t *tmpl) {
+    if (!strcmp(tmpl->proceduretype, "-pp"))
+        return "type: preprocessor";
+    if (!strcmp(tmpl->proceduretype, "-execute"))
+        return "type: execution";
+    if (!strcmp(tmpl->proceduretype, "-compile"))
+        return "type: compile";
+    return "type: fail";
+}
+
 /*
  * This schedualizes all tasks and actually runs them individually
  * this is generally easy for just -compile variants.  For compile and
@@ -966,7 +1030,8 @@ void task_schedualize(size_t *pad) {
          * Generate a task from thin air if it requires execution in
          * the QCVM.
          */
-        execute = !!(!strcmp(task_tasks[i].tmpl->proceduretype, "-execute"));
+        execute = !! (!strcmp(task_tasks[i].tmpl->proceduretype, "-execute")) ||
+                     (!strcmp(task_tasks[i].tmpl->proceduretype, "-pp"));
 
         /*
          * We assume it compiled before we actually compiled :).  On error
@@ -1004,21 +1069,23 @@ void task_schedualize(size_t *pad) {
         }
 
         if (!task_tasks[i].compiled && strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
-            con_err("failure: `%s` (failed to compile) see %s.stdout and %s.stderr [%s]\n",
+            con_out("failure:   `%s` %*s %*s\n",
                 task_tasks[i].tmpl->description,
-                task_tasks[i].tmpl->tempfilename,
-                task_tasks[i].tmpl->tempfilename,
-                task_tasks[i].tmpl->rulesfile
+                (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
+                task_tasks[i].tmpl->rulesfile,
+                (pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen("(failed to compile)") - pad[2]),
+                "(failed to compile)"
             );
             continue;
         }
 
         if (!execute) {
-            con_out("succeeded: `%s` %*s\n",
+            con_out("succeeded: `%s` %*s %*s\n",
                 task_tasks[i].tmpl->description,
-                (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) +
-                (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
-                task_tasks[i].tmpl->rulesfile
+                (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
+                task_tasks[i].tmpl->rulesfile,
+                (pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen(task_type(task_tasks[i].tmpl)) - pad[2]),
+                task_type(task_tasks[i].tmpl)
                 
             );
             continue;
@@ -1026,14 +1093,24 @@ void task_schedualize(size_t *pad) {
 
         /*
          * If we made it here that concludes the task is to be executed
-         * in the virtual machine.
+         * in the virtual machine (or the preprocessor output needs to
+         * be matched). 
          */
-        if (!task_execute(task_tasks[i].tmpl, &match)) {
+        if (!task_trymatch(task_tasks[i].tmpl, &match)) {
             size_t d = 0;
 
-            con_err("failure: `%s` (invalid results from execution) [%s]\n",
+            con_out("failure:   `%s` %*s %*s\n",
                 task_tasks[i].tmpl->description,
-                task_tasks[i].tmpl->rulesfile
+                (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
+                task_tasks[i].tmpl->rulesfile,
+                (pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen(
+                    (strcmp(task_tasks[i].tmpl->proceduretype, "-pp"))
+                        ? "(invalid results from execution)"
+                        : "(invalid results from preprocessing)"
+                ) - pad[2]),
+                (strcmp(task_tasks[i].tmpl->proceduretype, "-pp"))
+                    ? "(invalid results from execution)"
+                    : "(invalid results from preprocessing)"
             );
 
             /*
@@ -1041,7 +1118,7 @@ void task_schedualize(size_t *pad) {
              * handler for the all the given matches in the template file and
              * what was actually returned from executing.
              */
-            con_err("    Expected From %u Matches: (got %u Matches)\n",
+            con_out("    Expected From %u Matches: (got %u Matches)\n",
                 vec_size(task_tasks[i].tmpl->comparematch),
                 vec_size(match)
             );
@@ -1049,10 +1126,10 @@ void task_schedualize(size_t *pad) {
                 char  *select = task_tasks[i].tmpl->comparematch[d];
                 size_t length = 40 - strlen(select);
 
-                con_err("        Expected: \"%s\"", select);
+                con_out("        Expected: \"%s\"", select);
                 while (length --)
-                    con_err(" ");
-                con_err("| Got: \"%s\"\n", (d >= vec_size(match)) ? "<<nothing else to compare>>" : match[d]);
+                    con_out(" ");
+                con_out("| Got: \"%s\"\n", (d >= vec_size(match)) ? "<<nothing else to compare>>" : match[d]);
             }
 
             /*
@@ -1062,7 +1139,7 @@ void task_schedualize(size_t *pad) {
              */  
             if (vec_size(match) > vec_size(task_tasks[i].tmpl->comparematch)) {
                 for (d = 0; d < vec_size(match) - vec_size(task_tasks[i].tmpl->comparematch); d++) {
-                    con_err("        Expected: Nothing                                   | Got: \"%s\"\n",
+                    con_out("        Expected: Nothing                                   | Got: \"%s\"\n",
                         match[d + vec_size(task_tasks[i].tmpl->comparematch)]
                     );
                 }
@@ -1078,11 +1155,12 @@ void task_schedualize(size_t *pad) {
             mem_d(match[j]);
         vec_free(match);
 
-        con_out("succeeded: `%s` %*s\n",
+        con_out("succeeded: `%s` %*s %*s\n",
             task_tasks[i].tmpl->description,
-            (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) +
-            (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
-            task_tasks[i].tmpl->rulesfile
+            (pad[0] + pad[1] - strlen(task_tasks[i].tmpl->description)) + (strlen(task_tasks[i].tmpl->rulesfile) - pad[1]),
+            task_tasks[i].tmpl->rulesfile,
+            (pad[1] + pad[2] - strlen(task_tasks[i].tmpl->rulesfile)) + (strlen(task_type(task_tasks[i].tmpl))- pad[2]),
+            task_type(task_tasks[i].tmpl)
             
         );
     }
@@ -1107,7 +1185,8 @@ GMQCC_WARN bool test_perform(const char *curdir, const char *defs) {
     static const char *default_defs = "defs.qh";
 
     size_t pad[] = {
-        0, 0
+        /* test ### [succeed/fail]: `description`      [tests/template.tmpl]     [type] */
+                    0,                                 0,                        0
     };
 
     /*