AUDIT / src /lib /__tests__ /runtimeVerifier.test.ts
Arypulka98's picture
feat(audit): deploy full backend cluster node (part 2)
cc11e77 verified
Raw
History Blame Contribute Delete
14.6 kB
/**
* runtimeVerifier.test.ts — S415 test suite
*
* Copre tutti i 5 check di verifyRuntime:
* 1. Entry point esistente
* 2. Import relativi risolti nel VFS
* 3. Dipendenze npm in package.json
* 4. Bilanciamento sintattico (bracket/paren/brace balance)
* 5. Anti-pattern (require() in TS, TODO/FIXME placeholder, JSX senza export default)
*
* + casi edge: VFS vuoto, file non-codice, struttura RuntimeVerifyResult
*/
import { describe, it, expect } from "vitest";
import { verifyRuntime } from "../runtimeVerifier";
// ─── helper ───────────────────────────────────────────────────────────────────
const mkFile = (path: string, content: string) => ({ path, content });
// ─── 1. VFS vuoto ─────────────────────────────────────────────────────────────
describe("verifyRuntime — VFS vuoto", () => {
it("VFS vuoto → ok:true, hasCritical:false, issues:[], passed non vuoto", () => {
const r = verifyRuntime([]);
expect(r.ok).toBe(true);
expect(r.hasCritical).toBe(false);
expect(r.issues).toEqual([]);
expect(r.passed.length).toBeGreaterThan(0);
});
it("VFS vuoto → summary contiene 'VFS'", () => {
const r = verifyRuntime([]);
expect(r.summary.toLowerCase()).toContain("vfs");
});
});
// ─── 2. Entry point check ─────────────────────────────────────────────────────
describe("verifyRuntime — check 1: entry point", () => {
it("src/main.tsx presente → 'Entry point ✓' in passed[]", () => {
const r = verifyRuntime([mkFile("src/main.tsx", "import React from 'react'; export default App;")]);
expect(r.passed.some(p => /entry point/i.test(p))).toBe(true);
expect(r.issues.some(i => i.severity === "error" && /entry/i.test(i.message))).toBe(false);
});
it("src/index.tsx presente → entry point ok", () => {
const r = verifyRuntime([mkFile("src/index.tsx", "export default App;")]);
expect(r.passed.some(p => /entry point/i.test(p))).toBe(true);
});
it("index.html presente → entry point ok", () => {
const r = verifyRuntime([mkFile("index.html", "<html><body></body></html>")]);
expect(r.passed.some(p => /entry point/i.test(p))).toBe(true);
});
it("app.py presente → entry point ok", () => {
const r = verifyRuntime([mkFile("app.py", "from flask import Flask\napp = Flask(__name__)")]);
expect(r.passed.some(p => /entry point/i.test(p))).toBe(true);
});
it("server.js presente → entry point ok", () => {
const r = verifyRuntime([mkFile("server.js", "const express = require('express');")]);
expect(r.passed.some(p => /entry point/i.test(p))).toBe(true);
});
it("solo file utility senza entry point → error severity", () => {
const r = verifyRuntime([
mkFile("src/utils/helper.ts", "export const add = (a: number, b: number) => a + b;"),
mkFile("src/components/Card.tsx", "export function Card() { return <div/>; }"),
]);
const epIssue = r.issues.find(i => i.severity === "error" && /entry/i.test(i.message));
expect(epIssue).toBeDefined();
expect(r.hasCritical).toBe(true);
expect(r.ok).toBe(false);
});
});
// ─── 3. Import relativi check ─────────────────────────────────────────────────
describe("verifyRuntime — check 2: import relativi", () => {
it("import relativo risolto nel VFS → nessun errore import", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "import { useAuth } from './lib/auth';"),
mkFile("src/lib/auth.ts", "export const useAuth = () => {};"),
]);
const importIssues = r.issues.filter(i => i.message.includes("Import non risolto"));
expect(importIssues.length).toBe(0);
});
it("import relativo non nel VFS → errore", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "import { helper } from './utils/missing-file';"),
]);
const importIssue = r.issues.find(i => i.severity === "error" && /import non risolto|missing/i.test(i.message));
expect(importIssue).toBeDefined();
});
it("import di pacchetto npm (non relativo) → nessun import error", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "import React from 'react'; import axios from 'axios';"),
]);
const importIssues = r.issues.filter(i => i.message.includes("Import non risolto"));
expect(importIssues.length).toBe(0);
});
it("import con ../dir risolto correttamente", () => {
const r = verifyRuntime([
mkFile("src/pages/Login.tsx", "import { auth } from '../lib/auth';"),
mkFile("src/lib/auth.ts", "export const auth = {};"),
]);
const importIssues = r.issues.filter(i => i.message.includes("Import non risolto"));
expect(importIssues.length).toBe(0);
});
it("import con extension .tsx esplicita risolto", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "import Button from './components/Button.tsx';"),
mkFile("src/components/Button.tsx", "export default function Button() {}"),
]);
const importIssues = r.issues.filter(i => i.message.includes("Import non risolto"));
expect(importIssues.length).toBe(0);
});
it("import con index.ts → risolto correttamente", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "import { db } from './db';"),
mkFile("src/db/index.ts", "export const db = {};"),
]);
const importIssues = r.issues.filter(i => i.message.includes("Import non risolto"));
expect(importIssues.length).toBe(0);
});
});
// ─── 4. Package.json deps check ───────────────────────────────────────────────
describe("verifyRuntime — check 3: package.json deps", () => {
it("pacchetto dichiarato in dependencies → nessun warning", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "import axios from 'axios';"),
mkFile("package.json", JSON.stringify({ dependencies: { axios: "^1.6.0" } })),
]);
const depIssues = r.issues.filter(i => i.message.toLowerCase().includes("axios"));
expect(depIssues.length).toBe(0);
});
it("pacchetto NON in package.json → warning", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "import moment from 'moment';"),
mkFile("package.json", JSON.stringify({ dependencies: { react: "^18.0.0" } })),
]);
const depIssues = r.issues.filter(i => i.severity === "warning" && i.message.includes("moment"));
expect(depIssues.length).toBeGreaterThan(0);
});
it("pacchetto scoped @scope/pkg in devDeps → nessun warning", () => {
const r = verifyRuntime([
mkFile("src/test.ts", "import { render } from '@testing-library/react';"),
mkFile("package.json", JSON.stringify({ devDependencies: { "@testing-library/react": "^14.0.0" } })),
]);
const depIssues = r.issues.filter(i => i.message.includes("testing-library"));
expect(depIssues.length).toBe(0);
});
it("built-in Node (fs, path, os) → nessun warning", () => {
const r = verifyRuntime([
mkFile("src/server.ts", "import fs from 'fs'; import path from 'path'; import os from 'os';"),
mkFile("package.json", JSON.stringify({ dependencies: {} })),
]);
const builtinIssues = r.issues.filter(i =>
i.severity === "warning" && (
i.message.includes("'fs'") ||
i.message.includes("'path'") ||
i.message.includes("'os'")
)
);
expect(builtinIssues.length).toBe(0);
});
it("senza package.json → dep check skippato", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "import unknownPkg from 'unknown-package-xyz';"),
]);
// Senza package.json il check non può confrontare → nessun false positive
const pkgMissing = r.issues.filter(i => i.message.includes("package.json mancante"));
expect(pkgMissing.length).toBe(0);
});
});
// ─── 5. Syntax balance check ──────────────────────────────────────────────────
describe("verifyRuntime — check 4: bilanciamento sintattico", () => {
it("codice bilanciato → nessun warning sintassi", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "function App() { return (<div><h1>Hello</h1></div>); }"),
]);
const syntaxIssues = r.issues.filter(i =>
i.message.includes("sintattico") || i.message.includes("sbilanciata")
);
expect(syntaxIssues.length).toBe(0);
});
it("4 brace aperte senza chiusura → warning (delta > 2)", () => {
const r = verifyRuntime([
mkFile("src/broken.ts", "function a() { function b() { function c() { function d() { return 1;"),
]);
const syntaxIssues = r.issues.filter(i =>
i.severity === "warning" && (i.message.includes("sintattico") || i.message.includes("sbilanciata"))
);
expect(syntaxIssues.length).toBeGreaterThan(0);
});
it("file .md non analizzato per syntax", () => {
const r = verifyRuntime([
mkFile("README.md", "# {{{ titolo senza chiusura {{{{"),
mkFile("src/main.tsx", "function App() { return <div/>; }"),
]);
const mdIssues = r.issues.filter(i => i.file === "README.md");
expect(mdIssues.length).toBe(0);
});
});
// ─── 6. Anti-pattern check ────────────────────────────────────────────────────
describe("verifyRuntime — check 5: anti-pattern", () => {
it("require() in file .ts → warning", () => {
const r = verifyRuntime([
mkFile("src/lib/db.ts", "const pg = require('pg'); module.exports = { pg };"),
]);
const apIssues = r.issues.filter(i => i.severity === "warning" && i.message.includes("require()"));
expect(apIssues.length).toBeGreaterThan(0);
});
it("require() in file .tsx → warning (TypeScript)", () => {
const r = verifyRuntime([
mkFile("src/App.tsx", "const x = require('something');"),
]);
const apIssues = r.issues.filter(i => i.severity === "warning" && i.message.includes("require()"));
expect(apIssues.length).toBeGreaterThan(0);
});
it("TODO nel commento → warning placeholder", () => {
const r = verifyRuntime([
mkFile("src/service.ts", "// TODO: implementare questa funzione\nexport function doSomething() {}"),
]);
const toDoIssues = r.issues.filter(i => i.severity === "warning" && /placeholder|TODO/i.test(i.message));
expect(toDoIssues.length).toBeGreaterThan(0);
});
it("FIXME nel commento → warning placeholder", () => {
const r = verifyRuntime([
mkFile("src/api.ts", "// FIXME: bug qui\nexport function handler() {}"),
]);
const fixmeIssues = r.issues.filter(i => i.severity === "warning" && /placeholder|FIXME/i.test(i.message));
expect(fixmeIssues.length).toBeGreaterThan(0);
});
it("JSX con tag uppercase (<MyComponent/>) senza export default → warning", () => {
const r = verifyRuntime([
mkFile("src/components/Widget.tsx",
// Tag uppercase = JSX component; nessun export default
"function Widget() { return <MyContainer><MyItem /></MyContainer>; }"
),
]);
const exportIssues = r.issues.filter(i =>
i.severity === "warning" && i.message.includes("export default")
);
expect(exportIssues.length).toBeGreaterThan(0);
});
it("JSX con export default → nessun warning export", () => {
const r = verifyRuntime([
mkFile("src/components/Button.tsx", "function Button() { return <MyBtn/>; }\nexport default Button;"),
]);
const exportIssues = r.issues.filter(i => i.message.includes("export default"));
expect(exportIssues.length).toBe(0);
});
it("codice pulito → 0 anti-pattern warnings", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "import React from 'react';\nexport default function App() { return <div>Hello</div>; }"),
]);
const apIssues = r.issues.filter(i =>
i.severity === "warning" && (
i.message.includes("require()") ||
i.message.includes("TODO") ||
i.message.includes("FIXME")
)
);
expect(apIssues.length).toBe(0);
});
});
// ─── 7. RuntimeVerifyResult — ok / hasCritical / summary / repairHint ─────────
describe("verifyRuntime — struttura RuntimeVerifyResult", () => {
it("senza errori critici → ok:true, hasCritical:false", () => {
const r = verifyRuntime([mkFile("src/main.tsx", "export default function App() { return <div/>; }")]);
if (!r.hasCritical) {
expect(r.ok).toBe(true);
}
});
it("errore critico → ok:false, hasCritical:true", () => {
const r = verifyRuntime([
mkFile("src/main.tsx", "import { missing } from './does-not-exist';"),
]);
if (r.issues.some(i => i.severity === "error")) {
expect(r.hasCritical).toBe(true);
expect(r.ok).toBe(false);
}
});
it("summary è stringa non vuota", () => {
const r = verifyRuntime([mkFile("src/main.tsx", "export default function App() {}")]);
expect(typeof r.summary).toBe("string");
expect(r.summary.length).toBeGreaterThan(0);
});
it("repairHint definita quando hasCritical=true", () => {
const r = verifyRuntime([
mkFile("src/utils/helper.ts", "export const x = 1;"),
]);
if (r.hasCritical) {
expect(r.repairHint).toBeDefined();
expect(r.repairHint!.length).toBeGreaterThan(0);
}
});
it("passed[] contiene stringhe con ✓ quando check superati", () => {
const r = verifyRuntime([mkFile("src/main.tsx", "export default function App() {}")]);
if (r.passed.length > 0) {
expect(r.passed.some(p => p.includes("✓"))).toBe(true);
}
});
it("issues[] — ogni issue ha severity, file, message", () => {
const r = verifyRuntime([
mkFile("src/utils/x.ts", "// TODO: fix this"),
]);
for (const issue of r.issues) {
expect(issue).toHaveProperty("severity");
expect(issue).toHaveProperty("file");
expect(issue).toHaveProperty("message");
expect(["error", "warning", "info"]).toContain(issue.severity);
}
});
});