]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - test.c
Remove trailing whitespace
[xonotic/gmqcc.git] / test.c
diff --git a/test.c b/test.c
index 631f5e3fb0b942a2024f1a1ab4d008a453d5fc3a..2ede2ae2c14c2ed4a2607da768f6138324e37a20 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
@@ -210,7 +210,7 @@ int task_pclose(FILE **handles) {
  *                  This will perform compilation and execution
  *              -fail
  *                  This will perform compilation, but requires
- *                  the compilation to fail in order to succeed.   
+ *                  the compilation to fail in order to succeed.
  *
  *          This must be provided, this tag is NOT optional.
  *
@@ -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)
@@ -315,7 +316,7 @@ bool task_template_generate(task_template_t *tmpl, char tag, const char *file, s
     if (strchr(value, '\n'))
         *strrchr(value, '\n')='\0';
     else /* cppcheck: possible nullpointer dereference */
-        abort();
+        exit(EXIT_FAILURE);
 
     /*
      * Now allocate and set the actual value for the specific tag. Which
@@ -328,11 +329,14 @@ bool task_template_generate(task_template_t *tmpl, char tag, const char *file, s
         /*
          * Create some padding for the description to align the
          * printing of the rules file.
-         */  
+         */
         if ((desclen = strlen(tmpl->description)) > pad[0])
             pad[0] = desclen;
     }
 
+    if ((filelen = strlen(file)) > pad[2])
+        pad[2] = filelen;
+
     return true;
 }
 
@@ -428,7 +432,7 @@ bool task_template_parse(const char *file, task_template_t *tmpl, FILE *fp, size
                 if (strrchr(value, '\n'))
                     *strrchr(value, '\n')='\0';
                 else /* cppcheck: possible null pointer dereference */
-                    abort();
+                    exit(EXIT_FAILURE);
 
                 vec_push(tmpl->comparematch, util_strdup(value));
 
@@ -493,7 +497,7 @@ task_template_t *task_template_compile(const char *file, const char *dir, size_t
     /*
      * Create some padding for the printing to align the
      * printing of the rules file to the console.
-     */  
+     */
     if ((filepadd = strlen(fullfile)) > pad[1])
         pad[1] = filepadd;
 
@@ -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) {
@@ -827,7 +859,7 @@ void task_destroy(void) {
         /*
          * Only remove the log files if the test actually compiled otherwise
          * forget about it (or if it didn't compile, and the procedure type
-         * was set to -fail (meaning it shouldn't compile) .. stil remove) 
+         * was set to -fail (meaning it shouldn't compile) .. stil remove)
          */
         if (task_tasks[i].compiled || !strcmp(task_tasks[i].tmpl->proceduretype, "-fail")) {
             if (remove(task_tasks[i].stdoutlogfile))
@@ -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;
@@ -923,7 +972,7 @@ bool task_execute(task_template_t *tmpl, char ***line) {
             /*
              * Copy to output vector for diagnostics if execution match
              * fails.
-             */  
+             */
             vec_push(*line, data);
 
             /* reset */
@@ -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
@@ -958,7 +1022,7 @@ void task_schedualize(size_t *pad) {
     for (; i < vec_size(task_tasks); i++) {
         memset(space[1], 0, sizeof(space[1]));
         snprintf(space[1], sizeof(space[1]), "%d", (int)(i + 1));
-        
+
         con_out("test #%u %*s", i + 1, strlen(space[0]) - strlen(space[1]), "");
 
         util_debug("TEST", "executing task: %d: %s\n", i, task_tasks[i].tmpl->description);
@@ -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
@@ -985,8 +1050,6 @@ void task_schedualize(size_t *pad) {
                 task_tasks[i].compiled = false;
                 execute                = false;
             }
-
-            fs_file_flush(task_tasks[i].stdoutlog);
         }
         while (fs_file_getline(&data, &size, task_tasks[i].runhandles[2]) != EOF) {
             /*
@@ -1003,40 +1066,51 @@ void task_schedualize(size_t *pad) {
             }
 
             fs_file_puts (task_tasks[i].stderrlog, data);
-            fs_file_flush(task_tasks[i].stdoutlog);
         }
 
         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;
         }
 
         /*
          * 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)"
             );
 
             /*
@@ -1044,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)
             );
@@ -1052,25 +1126,25 @@ 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]);
             }
 
             /*
              * Print the non-expected out (since we are simply not expecting it)
              * This will help track down bugs in template files that fail to match
              * something.
-             */  
+             */
             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)]
                     );
                 }
             }
-                    
+
 
             for (j = 0; j < vec_size(match); j++)
                 mem_d(match[j]);
@@ -1081,12 +1155,13 @@ 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)
+
         );
     }
     mem_d(data);
@@ -1110,17 +1185,18 @@ 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
     };
 
     /*
      * If the default definition file isn't set to anything.  We will
      * use the default_defs here, which is "defs.qc"
-     */   
+     */
     if (!defs) {
         defs = default_defs;
     }
-        
+
 
     task_precleanup(curdir);
     if (!task_propagate(curdir, pad, defs)) {