libpulsar
A modular compiler for the pulsar programming language
Loading...
Searching...
No Matches
test.c
Go to the documentation of this file.
1
8#define _POSIX_C_SOURCE 200809L
9#include <stdio.h>
10#include <stdlib.h>
11#include <ctype.h>
12#include <limits.h>
13#include "util/notmain.h"
14
15#define EXEC "../main"
16
17#define fail(status, ...) \
18 do { \
19 fprintf(stderr, "\033[31;1mabort:\033[m " __VA_ARGS__); \
20 exit(status); \
21 } while (0)
22
23int run_test(int exit_code, const char* filename, const char* folder) {
24 char command[512];
25 snprintf(command, 512, "(" EXEC " %s/%s) &> /dev/null", folder, filename);
26 int status = (system(command) >> 8) & 0xFF;
27 if (status < 0) {
28 perror("system");
29 fail(1, "Could not execute shell command\n");
30 }
31 int result = 0;
32 if (status != exit_code) {
33 printf(" - \033[31;1mfail:\033[m %s", filename);
34 result = 1;
35 } else {
36 printf(" + \033[32;1mpass:\033[m %s", filename);
37 }
38 printf(" (target=%d actual=%d)\n", exit_code, status);
39 return result;
40}
41
42#ifdef test_main
43 #undef test_main
44 #define test_main main
45#endif
46
47int fpeekc(FILE* file) {
48 const int c = fgetc(file);
49 ungetc(c, file);
50 return c;
51}
52
53MAIN(int argc, const char* argv[]) {
54 if (!(argc == 2 || argc == 3)) {
55 fail(1, "use as: %s TESTFILE [TESTFOLDER]\n", argv[0]);
56 }
57 const char* folder = ".";
58 if (argc == 3) {
59 folder = argv[2];
60 }
61
62 FILE* handle = fopen(argv[1], "r");
63 if (handle == NULL) {
64 perror("fopen");
65 fail(1, "Failed to open file for reading\n");
66 }
67
68 int errors = 0;
69 int tests = 0;
70 int exit_code;
71 char filename[PATH_MAX];
72
73 size_t line = 1;
74 int cur;
75 while (!feof(handle) && (cur = fpeekc(handle)) != EOF) {
76 // If the current char is not a digit (i.e. not the start of a test
77 // directive) then we check to make sure its a comment or a newline
78 if (!isdigit(cur)) {
79 // Consume this char
80 fgetc(handle);
81
82 // Here we check if its a comment
83 if (cur == '#') {
84 // Comments that appear in output start with #!
85 if (!feof(handle) && fpeekc(handle) == '!') {
86 // Consume the '!'
87 fgetc(handle);
88
89 // Consume a space afterwards
90 if (!feof(handle) && fpeekc(handle) == ' ') {
91 fgetc(handle);
92 }
93
94 // We print title comments...
95 while (!feof(handle) && cur != '\n') {
96 cur = fgetc(handle);
97 fputc(cur, stdout);
98 }
99 } else {
100 // We discard normal comments starting with #
101 while (!feof(handle) && cur != '\n') {
102 cur = fgetc(handle);
103 }
104 }
105 line++;
106 continue;
107 } else if (cur == '\n') {
108 // Empty newlines ignored
109 line++;
110 continue;
111 } else {
112 // Otherwise its invalid
113 fail(1,
114 "Expected comment or test directive on line %zu, "
115 "received character '%c' instead\n",
116 line, cur);
117 }
118 }
119
120 // Otherwise it's a test directive (or so we assume)
121 if (fscanf(handle, "%d %127s\n", &exit_code, filename) != 2) {
122 perror("fscanf");
123 fail(1, "Failed to parse line %zu\n", line);
124 }
125 line++;
126 tests++;
127 if (run_test(exit_code, filename, folder) != 0) {
128 errors++;
129 }
130 }
131 if (fclose(handle) != 0) {
132 perror("fclose");
133 fail(1, "Failed to close file\n");
134 }
135 if (tests == 0) {
136 return 0;
137 }
138 printf("\nSummary:\n");
139 if (errors == tests) {
140 printf(" - \033[31;1mNone of the %d test(s) passed\033[m\n", tests);
141 return 1;
142 } else if (errors > tests / 2) {
143 printf(
144 " - \033[31;1mLess than half of the tests (%d/%d) passed\033[m\n",
145 tests - errors, tests);
146 return 1;
147 } else if (errors > 0) {
148 printf(" ~ \033[33;1mMost of the tests (%d/%d) passed\033[m\n",
149 tests - errors, tests);
150 return 1;
151 } else {
152 printf(" + \033[32;1mAll %d test(s) passed!\033[m\n", tests);
153 return 0;
154 }
155}
Enables programs to be located in the project directory.
#define MAIN
Defines a main function that should not be treated as a main function unless explicitly desired by th...
Definition notmain.h:15
int run_test(int exit_code, const char *filename, const char *folder)
Definition test.c:23
int fpeekc(FILE *file)
Definition test.c:47
#define EXEC
Definition test.c:15
#define fail(status,...)
Definition test.c:17