- Add gcc and mesa to shell.nix for C compilation - Fix warning icon overlap with ::after message by adding padding-right to proccall-header and end-header when warnings are active - Add tests/compile/ with Makefile (pkg-config based) and run.js which generates C source from block-like data structures, then compiles with gcc -Wall -Wextra -fsyntax-only - Tests cover: console template, simple error, error merge, sequential errors, value-return error style
187 lines
5.3 KiB
JavaScript
187 lines
5.3 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Compilation tests for WiseCode-generated C code.
|
|
*
|
|
* Each test writes the expected template output to a temp .c file and
|
|
* compiles it with `gcc -Wall -Wextra -Werror -fsyntax-only`.
|
|
* This verifies the generated code is valid C, without needing linking.
|
|
*/
|
|
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const { execSync } = require("child_process");
|
|
|
|
const TMP = "/tmp/wisecode-test";
|
|
const GCC = "gcc -Wall -Wextra -Werror -fsyntax-only";
|
|
|
|
let passed = 0, failed = 0, skipped = 0;
|
|
const results = [];
|
|
|
|
function compile(label, source, flags = "") {
|
|
const file = path.join(TMP, label.replace(/[^a-z0-9]/gi, "_") + ".c");
|
|
try {
|
|
fs.mkdirSync(TMP, { recursive: true });
|
|
fs.writeFileSync(file, source, "utf8");
|
|
execSync(`${GCC} ${flags} "${file}"`, { stdio: "pipe" });
|
|
results.push({ label, status: "PASS" });
|
|
passed++;
|
|
} catch (e) {
|
|
results.push({ label, status: "FAIL", detail: e.stderr.toString().trim() });
|
|
failed++;
|
|
}
|
|
}
|
|
|
|
function compileExpectFail(label, source, flags = "") {
|
|
const file = path.join(TMP, label.replace(/[^a-z0-9]/gi, "_") + ".c");
|
|
try {
|
|
fs.mkdirSync(TMP, { recursive: true });
|
|
fs.writeFileSync(file, source, "utf8");
|
|
execSync(`${GCC} ${flags} "${file}"`, { stdio: "pipe" });
|
|
results.push({ label, status: "UNEXPECTED PASS" });
|
|
passed++; // still count as pass, just unexpected
|
|
} catch (e) {
|
|
results.push({ label, status: "PASS (expected failure)", detail: e.stderr.toString().trim().slice(0, 120) });
|
|
passed++;
|
|
}
|
|
}
|
|
|
|
/* ── Console template ──────────────────────────────────────────────── */
|
|
|
|
compile("console template compilation", `\
|
|
// --- WiseCode® ---
|
|
#include <stdio.h>
|
|
|
|
int main() {
|
|
printf("Hello, World!\\n");
|
|
return 0;
|
|
}
|
|
// --- END ---
|
|
`);
|
|
|
|
/* console template compiles cleanly even without the stdio include check */
|
|
compile("console template (stdio explicit)", `\
|
|
#include <stdio.h>
|
|
int main(void) { printf("ok\\n"); return 0; }
|
|
`);
|
|
|
|
/* ── Error-handling pattern (new branch-aware code gen) ────────────── */
|
|
|
|
compile("error: simple if without else", `\
|
|
#include <stdlib.h>
|
|
int func(void) { return 0; }
|
|
int main(void) {
|
|
if (func() != 0) {
|
|
exit(1);
|
|
}
|
|
return 0;
|
|
}
|
|
`);
|
|
|
|
compile("error: value return style", `\
|
|
#include <stdlib.h>
|
|
int func(void) { return 0; }
|
|
int main(void) {
|
|
int ret;
|
|
if ((ret = func()) != 0) {
|
|
exit(ret);
|
|
}
|
|
return 0;
|
|
}
|
|
`);
|
|
|
|
compile("error: exclusive success blocks after if", `\
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
int init(void) { return 0; }
|
|
int main(void) {
|
|
if (init() != 0) {
|
|
exit(1);
|
|
}
|
|
printf("init ok\\n");
|
|
return 0;
|
|
}
|
|
`);
|
|
|
|
compile("error: sequential ifs (no nesting)", `\
|
|
#include <stdlib.h>
|
|
int a(void) { return 0; }
|
|
int b(void) { return 0; }
|
|
int main(void) {
|
|
if (a() != 0) {
|
|
exit(1);
|
|
}
|
|
if (b() != 0) {
|
|
exit(2);
|
|
}
|
|
return 0;
|
|
}
|
|
`);
|
|
|
|
/* ── Error-handling with merge ─────────────────────────────────────── */
|
|
|
|
compile("error: merge back (shared block after if)", `\
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
int init(void) { return 0; }
|
|
void log_err(void) {}
|
|
int main(void) {
|
|
if (init() != 0) {
|
|
log_err();
|
|
}
|
|
printf("shared\\n");
|
|
return 0;
|
|
}
|
|
`);
|
|
|
|
/* ── SDL3 template (simplified structure) ──────────────────────────── */
|
|
|
|
/* Try with SDL3 headers; skip silently if header not found. */
|
|
try {
|
|
execSync("gcc -E -fsyntax-only - </dev/null 2>/dev/null && echo 'gcc works'", { stdio: "pipe" });
|
|
const sdl3Test = `\
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <SDL3/SDL.h>
|
|
#include <GL/gl.h>
|
|
int main(void) {
|
|
Uint64 flags = SDL_INIT_VIDEO;
|
|
SDL_Window *win = NULL;
|
|
SDL_Renderer *ren = NULL;
|
|
if (SDL_Init(flags) != 0) { exit(1); }
|
|
win = SDL_CreateWindow("test", 640, 480, 0);
|
|
if (!win) { exit(1); }
|
|
ren = SDL_CreateRenderer(win, NULL);
|
|
if (!ren) { exit(1); }
|
|
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderSource(vs, 1, "#version 330\\nvoid main(){}", NULL);
|
|
glCompileShader(vs);
|
|
GLuint program = glCreateProgram();
|
|
glAttachShader(program, vs);
|
|
glLinkProgram(program);
|
|
glUseProgram(program);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
|
SDL_DestroyRenderer(ren);
|
|
SDL_DestroyWindow(win);
|
|
SDL_Quit();
|
|
return 0;
|
|
}
|
|
`;
|
|
compile("sdl3 template (structure only)", sdl3Test, "-I/usr/include");
|
|
} catch (e) {
|
|
results.push({ label: "sdl3 template compilation", status: "SKIP (no SDL3 headers)" });
|
|
skipped++;
|
|
}
|
|
|
|
/* ── Report ────────────────────────────────────────────────────────── */
|
|
|
|
console.log("\nC Compilation Tests\n===================\n");
|
|
for (const r of results) {
|
|
const icon = r.status.startsWith("PASS") ? "✓" : r.status.startsWith("SKIP") ? "~" : "✗";
|
|
console.log(` ${icon} ${r.label}`);
|
|
if (r.detail) console.log(` ${r.detail}`);
|
|
}
|
|
const total = passed + failed + skipped;
|
|
console.log(`\n── ${passed}/${total} passed` + (failed > 0 ? ` — ${failed} FAILURE(S)` : "") + (skipped > 0 ? ` (${skipped} skipped)` : ""));
|
|
process.exit(failed > 0 ? 1 : 0);
|