Skip to content

Commit 65dc908

Browse files
committed
Improve testing and output
1 parent a70a3db commit 65dc908

6 files changed

Lines changed: 182 additions & 50 deletions

File tree

CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,17 @@ enable_testing()
1111

1212
add_subdirectory(src)
1313

14+
if(BUILD_TESTING)
15+
add_subdirectory(test)
16+
# Ensure invoking the test target compiles the app first
17+
if(TARGET test)
18+
add_dependencies(test masp)
19+
endif()
20+
# Provide a convenient 'check' target that builds and runs tests
21+
add_custom_target(check
22+
COMMAND ${CMAKE_CTEST_COMMAND} -C $<CONFIG> --output-on-failure
23+
DEPENDS masp
24+
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
25+
)
26+
endif()
1427

cmake/RunMaspAndCompare.cmake

Lines changed: 0 additions & 40 deletions
This file was deleted.

src/CMakeLists.txt

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,4 @@ if(MINGW)
6262
target_link_libraries(masp PRIVATE gnurx)
6363
endif()
6464

65-
# Tests
66-
if(BUILD_TESTING)
67-
add_test(NAME masp_vu1Triangle
68-
COMMAND ${CMAKE_COMMAND}
69-
-Dmasp_exe=$<TARGET_FILE:masp>
70-
-Dsrc=${CMAKE_SOURCE_DIR}/test/vu1Triangle.vcl
71-
-Dexpected=${CMAKE_SOURCE_DIR}/test/vu1Triangle.vcl_masp
72-
-Dout=${CMAKE_BINARY_DIR}/test_outputs/vu1Triangle.vcl_masp
73-
-P ${CMAKE_SOURCE_DIR}/cmake/RunMaspAndCompare.cmake)
74-
endif()
65+
# Tests are defined in test/CMakeLists.txt

test/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# C unit tests
2+
add_subdirectory(unit)
3+
4+

test/unit/CMakeLists.txt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Minimal C unit test that calls masp's main in-process to avoid CLI parsing issues
2+
3+
add_executable(test_masp_cli
4+
${CMAKE_SOURCE_DIR}/test/unit/test_masp_cli.c
5+
${CMAKE_SOURCE_DIR}/src/hash.c
6+
${CMAKE_SOURCE_DIR}/src/macro.c
7+
${CMAKE_SOURCE_DIR}/src/sb.c
8+
${CMAKE_SOURCE_DIR}/src/compat.c
9+
)
10+
11+
target_include_directories(test_masp_cli PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src)
12+
13+
target_compile_definitions(test_masp_cli PRIVATE
14+
SRC_DIR="${CMAKE_SOURCE_DIR}"
15+
BUILD_DIR="${CMAKE_BINARY_DIR}"
16+
PACKAGE_VERSION="test"
17+
REPORT_BUGS_TO="ci"
18+
LOCALEDIR=""
19+
)
20+
21+
add_test(NAME masp_cli_unit COMMAND test_masp_cli)
22+
23+
# Windows (MinGW) needs POSIX regex library (libgnurx)
24+
if(MINGW)
25+
target_link_libraries(test_masp_cli PRIVATE gnurx)
26+
endif()
27+
28+

test/unit/test_masp_cli.c

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <sys/stat.h>
5+
#include <errno.h>
6+
#ifdef _WIN32
7+
#include <direct.h>
8+
#define MKDIR(p) _mkdir(p)
9+
#else
10+
#include <sys/types.h>
11+
#include <unistd.h>
12+
#include <sys/wait.h>
13+
#define MKDIR(p) mkdir((p), 0777)
14+
#endif
15+
16+
#ifndef SRC_DIR
17+
#define SRC_DIR "."
18+
#endif
19+
#ifndef BUILD_DIR
20+
#define BUILD_DIR "."
21+
#endif
22+
23+
// Avoid symbol clash: rename masp main before including the implementation
24+
#define main masp_program_main
25+
#include "../../src/masp.c"
26+
#undef main
27+
28+
static int files_equal(const char *a, const char *b) {
29+
FILE *fa = fopen(a, "rb");
30+
FILE *fb = fopen(b, "rb");
31+
if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return 0; }
32+
int eq = 1;
33+
const size_t BUFSZ = 8192;
34+
unsigned char *ba = (unsigned char*)malloc(BUFSZ);
35+
unsigned char *bb = (unsigned char*)malloc(BUFSZ);
36+
if (!ba || !bb) { eq = 0; goto done; }
37+
size_t ra, rb;
38+
do {
39+
ra = fread(ba, 1, BUFSZ, fa);
40+
rb = fread(bb, 1, BUFSZ, fb);
41+
if (ra != rb || memcmp(ba, bb, ra) != 0) { eq = 0; break; }
42+
} while (ra > 0 && rb > 0);
43+
done:
44+
if (ba) free(ba);
45+
if (bb) free(bb);
46+
fclose(fa);
47+
fclose(fb);
48+
return eq;
49+
}
50+
51+
static int run_vu1Triangle(void) {
52+
char out_path[1024];
53+
char src_path[1024];
54+
char expected_path[1024];
55+
char out_dir[1024];
56+
snprintf(out_path, sizeof(out_path), "%s/test_outputs/masp_vu1Triangle.unit.out", BUILD_DIR);
57+
snprintf(src_path, sizeof(src_path), "%s/test/vu1Triangle.vcl", SRC_DIR);
58+
snprintf(expected_path, sizeof(expected_path), "%s/test/vu1Triangle.vcl_masp", SRC_DIR);
59+
60+
// Ensure output directory exists (CI may not have it yet)
61+
snprintf(out_dir, sizeof(out_dir), "%s/test_outputs", BUILD_DIR);
62+
if (MKDIR(out_dir) != 0 && errno != EEXIST) {
63+
fprintf(stderr, "Failed to create output dir: %s (errno=%d)\n", out_dir, errno);
64+
return 1;
65+
}
66+
67+
int rc = 0;
68+
#if defined(__unix__)
69+
const char *force_inproc = getenv("MASP_TEST_INPROC");
70+
if (!force_inproc || strcmp(force_inproc, "1") != 0) {
71+
// Prefer a clean subprocess exec on UNIX to avoid sanitizer/locale clashes on CI
72+
char masp_path[1024];
73+
snprintf(masp_path, sizeof(masp_path), "%s/src/masp", BUILD_DIR);
74+
pid_t pid = fork();
75+
if (pid == 0) {
76+
const char *argvp[] = { masp_path, "-p", "-s", "-c", ";", "-o", out_path, "--", src_path, NULL };
77+
execv(masp_path, (char* const*)argvp);
78+
_exit(127);
79+
} else if (pid > 0) {
80+
int status = 0;
81+
if (waitpid(pid, &status, 0) < 0) {
82+
perror("waitpid");
83+
return 1;
84+
}
85+
if (!WIFEXITED(status)) {
86+
fprintf(stderr, "masp subprocess terminated abnormally\n");
87+
return 1;
88+
}
89+
rc = WEXITSTATUS(status);
90+
} else {
91+
perror("fork");
92+
return 1;
93+
}
94+
} else
95+
#endif
96+
{
97+
const char *argv0[] = {
98+
"masp",
99+
"-p",
100+
"-s",
101+
"-c", ";",
102+
"-o", out_path,
103+
"--", src_path,
104+
NULL
105+
};
106+
int argc = 9;
107+
rc = masp_program_main(argc, (char**)argv0);
108+
}
109+
if (rc != 0) {
110+
fprintf(stderr, "masp_program_main returned %d\n", rc);
111+
return 1;
112+
}
113+
struct stat st;
114+
if (stat(out_path, &st) != 0) {
115+
fprintf(stderr, "Output file not created: %s\n", out_path);
116+
return 1;
117+
}
118+
if (!files_equal(out_path, expected_path)) {
119+
fprintf(stderr, "Output differs from expected: %s\n", out_path);
120+
return 1;
121+
}
122+
return 0;
123+
}
124+
125+
int main(void) {
126+
int failures = 0;
127+
failures += run_vu1Triangle();
128+
if (failures) {
129+
fprintf(stderr, "Unit tests failed: %d\n", failures);
130+
return 1;
131+
}
132+
printf("All unit tests passed.\n");
133+
return 0;
134+
}
135+
136+

0 commit comments

Comments
 (0)