Files
wehub-resource-sync 41cb1c0170
OpenSSF Scorecard / scorecard (push) Failing after 0s
DCO / dco (push) Failing after 0s
CodeQL SAST / analyze (push) Failing after 1s
Deploy Pages / deploy (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:28:05 +08:00

371 lines
18 KiB
C

/*
* test_grammar_regression.c — Per-language extraction regression net.
*
* Guards against silent extraction breakage when vendored tree-sitter grammars
* are refreshed. Every CBM_LANG_* enum is exercised: a minimal sample is
* extracted and checked for (a) no crash (non-NULL result) and (b) a
* catastrophic-break floor (defs >= min_defs) plus, for confident cases,
* expected definition names. A future grammar upgrade that renames/removes the
* node types extraction depends on (e.g. the fwcd kotlin `name`-field drop that
* produced 0 defs) fails this suite loudly.
*
* min_defs convention: code languages use >=1 (a sample with a function/type
* must yield at least one def); data/config/markup languages use 0 (the check
* is "parses without crashing"). Tighten a row's min_defs to lock in a count.
*/
#include "test_framework.h"
#include "cbm.h"
#include "grammar_cases.h"
static int reg_has_def_any(CBMFileResult *r, const char *name) {
for (int i = 0; i < r->defs.count; i++) {
if (strcmp(r->defs.items[i].name, name) == 0)
return 1;
}
return 0;
}
static CBMFileResult *extract(const char *src, CBMLanguage lang, const char *proj,
const char *path) {
return cbm_extract_file(src, (int)strlen(src), lang, proj, path, 0, NULL, NULL);
}
const GrammarCase CBM_GRAMMAR_CASES[] = {
/* ── LSP-backed / mainstream code languages (expect named defs) ── */
{"go",
CBM_LANG_GO,
"a.go",
"package m\nfunc Foo() {}\nfunc Bar() int { return 0 }\n",
2,
{"Foo", "Bar", NULL}},
{"c",
CBM_LANG_C,
"a.c",
"int foo(void){return 0;}\nint bar(void){return 1;}\n",
2,
{"foo", "bar", NULL}},
{"cpp", CBM_LANG_CPP, "a.cpp", "struct A {};\nint foo(){return 0;}\n", 2, {"A", "foo", NULL}},
{"cuda",
CBM_LANG_CUDA,
"a.cu",
"__global__ void foo(){}\nint bar(){return 0;}\n",
1,
{"bar", NULL}},
{"python",
CBM_LANG_PYTHON,
"a.py",
"def foo():\n pass\nclass A:\n pass\n",
2,
{"foo", "A", NULL}},
{"javascript",
CBM_LANG_JAVASCRIPT,
"a.js",
"function foo(){}\nclass A{}\n",
2,
{"foo", "A", NULL}},
{"typescript",
CBM_LANG_TYPESCRIPT,
"a.ts",
"function foo(): number { return 1; }\nclass A {}\n",
2,
{"foo", "A", NULL}},
{"tsx", CBM_LANG_TSX, "a.tsx", "function foo(): number { return 1; }\n", 1, {"foo", NULL}},
{"java", CBM_LANG_JAVA, "A.java", "class A {\n void foo() {}\n}\n", 2, {"A", "foo", NULL}},
{"kotlin", CBM_LANG_KOTLIN, "a.kt", "fun foo() {}\nclass A\n", 2, {"foo", "A", NULL}},
{"rust", CBM_LANG_RUST, "a.rs", "fn foo() {}\nstruct A;\n", 2, {"foo", "A", NULL}},
{"ruby", CBM_LANG_RUBY, "a.rb", "def foo\nend\nclass A\nend\n", 2, {"foo", "A", NULL}},
{"php", CBM_LANG_PHP, "a.php", "<?php\nfunction foo() {}\nclass A {}\n", 2, {"foo", "A", NULL}},
{"c_sharp",
CBM_LANG_CSHARP,
"A.cs",
"class A {\n void Foo() {}\n}\n",
2,
{"A", "Foo", NULL}},
{"bash",
CBM_LANG_BASH,
"a.sh",
"foo() {\n echo hi\n}\nbar() {\n foo\n}\n",
2,
{"foo", "bar", NULL}},
{"zsh", CBM_LANG_ZSH, "a.zsh", "foo() {\n echo hi\n}\nbar() {\n foo\n}\n", 1, {"foo", NULL}},
{"lua",
CBM_LANG_LUA,
"a.lua",
"function foo() end\nfunction bar() end\n",
2,
{"foo", "bar", NULL}},
{"luau", CBM_LANG_LUAU, "a.luau", "function foo() end\nfunction bar() end\n", 1, {"foo", NULL}},
{"perl", CBM_LANG_PERL, "a.pl", "sub foo {}\nsub bar {}\n", 2, {"foo", "bar", NULL}},
{"dart", CBM_LANG_DART, "a.dart", "class A {}\nvoid foo() {}\n", 2, {"A", "foo", NULL}},
{"swift", CBM_LANG_SWIFT, "a.swift", "func foo() {}\nclass A {}\n", 2, {"foo", "A", NULL}},
{"scala", CBM_LANG_SCALA, "a.scala", "object A {\n def foo() = 1\n}\n", 1, {"A", NULL}},
{"gdscript", CBM_LANG_GDSCRIPT, "a.gd", "func foo():\n pass\n", 1, {"foo", NULL}},
{"groovy", CBM_LANG_GROOVY, "a.groovy", "class A {\n def foo() {}\n}\n", 1, {"A", NULL}},
{"zig", CBM_LANG_ZIG, "a.zig", "fn foo() void {}\nfn bar() void {}\n", 1, {"foo", NULL}},
{"solidity",
CBM_LANG_SOLIDITY,
"a.sol",
"contract A {\n function foo() public {}\n}\n",
1,
{"A", NULL}},
{"tcl", CBM_LANG_TCL, "a.tcl", "proc foo {} {}\nproc bar {} {}\n", 1, {"foo", NULL}},
{"powershell",
CBM_LANG_POWERSHELL,
"a.ps1",
"function Get-Foo {\n}\nfunction Get-Bar {\n}\n",
1,
{"Get-Foo", NULL}},
{"r", CBM_LANG_R, "a.R", "foo <- function() {}\nbar <- function() {}\n", 1, {"foo", NULL}},
{"julia", CBM_LANG_JULIA, "a.jl", "function foo() end\nstruct A end\n", 1, {"foo", NULL}},
{"matlab",
CBM_LANG_MATLAB,
"a.m",
"function foo()\nend\nfunction bar()\nend\n",
1,
{"foo", NULL}},
/* ── code languages: catastrophic-break floor only (>=1), names vary by grammar ── */
{"ada", CBM_LANG_ADA, "a.adb", "procedure Foo is\nbegin\n null;\nend Foo;\n", 1, {NULL}},
{"agda", CBM_LANG_AGDA, "a.agda", "module M where\nfoo : Set\nfoo = Set\n", 0, {NULL}},
{"apex", CBM_LANG_APEX, "A.cls", "public class A {\n void foo() {}\n}\n", 1, {NULL}},
{"awk",
CBM_LANG_AWK,
"a.awk",
"function foo() { print 1 }\nfunction bar() { print 2 }\n",
1,
{NULL}},
{"cairo", CBM_LANG_CAIRO, "a.cairo", "fn foo() {}\nfn bar() {}\n", 1, {NULL}},
{"clojure", CBM_LANG_CLOJURE, "a.clj", "(defn foo [] 1)\n(defn bar [] 2)\n", 1, {NULL}},
{"commonlisp",
CBM_LANG_COMMONLISP,
"a.lisp",
"(defun foo () 1)\n(defun bar () 2)\n",
1,
{NULL}},
{"emacslisp", CBM_LANG_EMACSLISP, "a.el", "(defun foo () 1)\n(defun bar () 2)\n", 1, {NULL}},
{"crystal", CBM_LANG_CRYSTAL, "a.cr", "def foo\nend\nclass A\nend\n", 1, {NULL}},
{"d", CBM_LANG_DLANG, "a.d", "void foo() {}\nvoid bar() {}\n", 1, {NULL}},
{"elixir", CBM_LANG_ELIXIR, "a.ex", "defmodule A do\n def foo do\n end\nend\n", 1, {NULL}},
{"erlang", CBM_LANG_ERLANG, "a.erl", "-module(a).\nfoo() -> ok.\nbar() -> ok.\n", 1, {NULL}},
{"fennel", CBM_LANG_FENNEL, "a.fnl", "(fn foo [] 1)\n(fn bar [] 2)\n", 1, {NULL}},
{"fish", CBM_LANG_FISH, "a.fish", "function foo\n echo hi\nend\n", 1, {NULL}},
{"fortran", CBM_LANG_FORTRAN, "a.f90", "subroutine foo()\nend subroutine\n", 1, {NULL}},
{"fsharp", CBM_LANG_FSHARP, "a.fs", "let foo () = 1\nlet bar () = 2\n", 1, {NULL}},
{"gleam", CBM_LANG_GLEAM, "a.gleam", "pub fn foo() { 1 }\npub fn bar() { 2 }\n", 1, {NULL}},
{"glsl", CBM_LANG_GLSL, "a.glsl", "void foo() {}\nvoid main() {}\n", 1, {NULL}},
{"hare", CBM_LANG_HARE, "a.ha", "fn foo() void = void;\nfn bar() void = void;\n", 1, {NULL}},
{"haskell", CBM_LANG_HASKELL, "a.hs", "foo :: Int\nfoo = 1\n", 1, {NULL}},
{"hlsl", CBM_LANG_HLSL, "a.hlsl", "void foo() {}\nvoid bar() {}\n", 1, {NULL}},
{"ispc", CBM_LANG_ISPC, "a.ispc", "void foo() {}\nvoid bar() {}\n", 1, {NULL}},
{"objc", CBM_LANG_OBJC, "a.m", "@implementation A\n- (void)foo {}\n@end\n", 0, {NULL}},
{"ocaml", CBM_LANG_OCAML, "a.ml", "let foo () = 1\nlet bar () = 2\n", 1, {NULL}},
{"odin", CBM_LANG_ODIN, "a.odin", "foo :: proc() {}\nbar :: proc() {}\n", 1, {NULL}},
{"pascal", CBM_LANG_PASCAL, "a.pas", "procedure Foo;\nbegin\nend;\n", 1, {NULL}},
{"pony",
CBM_LANG_PONY,
"a.pony",
"actor Main\n fun foo(): U32 => 1\n",
2,
{"Main", "foo", NULL}},
{"purescript", CBM_LANG_PURESCRIPT, "a.purs", "foo :: Int\nfoo = 1\n", 0, {NULL}},
{"racket", CBM_LANG_RACKET, "a.rkt", "(define (foo) 1)\n(define (bar) 2)\n", 1, {NULL}},
{"rescript", CBM_LANG_RESCRIPT, "a.res", "let foo = () => 1\nlet bar = () => 2\n", 1, {NULL}},
{"scheme", CBM_LANG_SCHEME, "a.scm", "(define (foo) 1)\n(define (bar) 2)\n", 1, {NULL}},
{"slang", CBM_LANG_SLANG, "a.slang", "void foo() {}\nvoid bar() {}\n", 1, {NULL}},
{"squirrel", CBM_LANG_SQUIRREL, "a.nut", "function foo() {}\nfunction bar() {}\n", 1, {NULL}},
{"starlark",
CBM_LANG_STARLARK,
"a.bzl",
"def foo():\n pass\ndef bar():\n pass\n",
1,
{NULL}},
{"sway", CBM_LANG_SWAY, "a.sw", "fn foo() {}\nfn bar() {}\n", 1, {NULL}},
{"teal",
CBM_LANG_TEAL,
"a.tl",
"local function foo() end\nlocal function bar() end\n",
1,
{NULL}},
{"vimscript", CBM_LANG_VIMSCRIPT, "a.vim", "function! Foo()\nendfunction\n", 1, {NULL}},
{"elm", CBM_LANG_ELM, "a.elm", "module M exposing (..)\nfoo = 1\n", 0, {NULL}},
{"func", CBM_LANG_FUNC, "a.fc", "() foo() {\n}\n", 0, {NULL}},
{"lean", CBM_LANG_LEAN, "a.lean", "def foo : Nat := 1\ndef bar : Nat := 2\n", 0, {NULL}},
{"move",
CBM_LANG_MOVE,
"a.move",
"module 0x1::m {\n public fun foo() {}\n}\n",
1,
{"foo", NULL}},
{"mojo",
CBM_LANG_MOJO,
"a.mojo",
"fn foo() -> Int:\n return 1\n\nstruct A:\n fn bar(self) -> Int:\n return foo()\n",
2,
{"foo", "A", NULL}},
{"smali",
CBM_LANG_SMALI,
"A.smali",
".class public LA;\n.super Ljava/lang/Object;\n.method public foo()V\n.end method\n",
2,
{"foo", NULL}},
{"systemverilog",
CBM_LANG_SYSTEMVERILOG,
"a.sv",
"module m;\n function int foo(); return 0; endfunction\nendmodule\n",
0,
{NULL}},
{"verilog", CBM_LANG_VERILOG, "a.v", "module m;\nendmodule\n", 0, {NULL}},
{"vhdl", CBM_LANG_VHDL, "a.vhd", "entity foo is\nend foo;\n", 0, {NULL}},
{"wgsl", CBM_LANG_WGSL, "a.wgsl", "fn foo() {}\nfn bar() {}\n", 1, {NULL}},
{"tlaplus", CBM_LANG_TLAPLUS, "a.tla", "---- MODULE M ----\nFoo == 1\n====\n", 0, {NULL}},
{"llvm", CBM_LANG_LLVM_IR, "a.ll", "define void @foo() {\n ret void\n}\n", 0, {NULL}},
{"tablegen", CBM_LANG_TABLEGEN, "a.td", "def Foo {}\n", 0, {NULL}},
{"puppet", CBM_LANG_PUPPET, "a.pp", "class foo {\n}\n", 0, {NULL}},
/* ── first-party / self-maintained grammars ── */
{"assembly", CBM_LANG_ASSEMBLY, "a.s", ".global foo\nfoo:\n ret\n", 0, {NULL}},
{"nasm", CBM_LANG_NASM, "a.asm", "global foo\nfoo:\n ret\n", 0, {NULL}},
{"cfml", CBM_LANG_CFML, "a.cfm", "<cffunction name=\"foo\"></cffunction>\n", 0, {NULL}},
{"cfscript", CBM_LANG_CFSCRIPT, "a.cfc", "component {\n function foo() {}\n}\n", 0, {NULL}},
{"cobol",
CBM_LANG_COBOL,
"a.cob",
" IDENTIFICATION DIVISION.\n PROGRAM-ID. FOO.\n PROCEDURE DIVISION.\n "
" MAIN-PARA.\n STOP RUN.\n",
1,
{"FOO", NULL}},
{"janet", CBM_LANG_JANET, "a.janet", "(defn foo [] 1)\n(defn bar [] 2)\n", 0, {NULL}},
{"magma", CBM_LANG_MAGMA, "a.magma", "function foo()\n return 1;\nend function;\n", 0, {NULL}},
{"qml", CBM_LANG_QML, "a.qml", "import QtQuick\nItem {\n function foo() {}\n}\n", 0, {NULL}},
{"wolfram", CBM_LANG_WOLFRAM, "a.wl", "foo[x_] := x + 1\n", 0, {NULL}},
{"pine", CBM_LANG_PINE, "a.pine", "foo() =>\n 1\n", 0, {NULL}},
{"form", CBM_LANG_FORM, "a.frm", "Symbol x;\nLocal F = x;\n", 0, {NULL}},
{"protobuf",
CBM_LANG_PROTOBUF,
"a.proto",
"syntax = \"proto3\";\n\nmessage Foo {\n int32 id = 1;\n}\n",
1,
{"Foo", NULL}},
{"soql", CBM_LANG_SOQL, "a.soql", "SELECT Id FROM Account\n", 0, {NULL}},
{"sosl", CBM_LANG_SOSL, "a.sosl", "FIND {test} IN ALL FIELDS\n", 0, {NULL}},
{"dotenv", CBM_LANG_DOTENV, "a.env", "FOO=bar\nBAZ=qux\n", 0, {NULL}},
/* ── data / config / markup / template languages (no-crash floor) ── */
{"json", CBM_LANG_JSON, "a.json", "{\"a\": 1, \"b\": [2, 3]}\n", 0, {NULL}},
{"json5", CBM_LANG_JSON5, "a.json5", "{a: 1, b: 2}\n", 0, {NULL}},
{"jsonnet", CBM_LANG_JSONNET, "a.jsonnet", "{ a: 1, b: 2 }\n", 0, {NULL}},
{"jsdoc", CBM_LANG_JSDOC, "a.jsdoc", "/** @param {number} x */\n", 0, {NULL}},
{"yaml", CBM_LANG_YAML, "a.yaml", "a: 1\nb:\n - 2\n - 3\n", 0, {NULL}},
{"k8s", CBM_LANG_K8S, "a.yaml", "apiVersion: v1\nkind: Pod\n", 0, {NULL}},
{"kustomize", CBM_LANG_KUSTOMIZE, "kustomization.yaml", "resources:\n - a.yaml\n", 0, {NULL}},
{"toml", CBM_LANG_TOML, "a.toml", "[section]\nkey = 1\n", 0, {NULL}},
{"ini", CBM_LANG_INI, "a.ini", "[section]\nkey=1\n", 0, {NULL}},
{"csv", CBM_LANG_CSV, "a.csv", "a,b,c\n1,2,3\n", 0, {NULL}},
{"sql", CBM_LANG_SQL, "a.sql", "CREATE TABLE t (id INT);\nSELECT * FROM t;\n", 0, {NULL}},
{"xml", CBM_LANG_XML, "a.xml", "<root><child>x</child></root>\n", 0, {NULL}},
{"html", CBM_LANG_HTML, "a.html", "<html><body><p>hi</p></body></html>\n", 0, {NULL}},
{"css", CBM_LANG_CSS, "a.css", "a { color: red; }\n.x { width: 1px; }\n", 0, {NULL}},
{"scss", CBM_LANG_SCSS, "a.scss", "$c: red;\na { color: $c; }\n", 0, {NULL}},
{"markdown", CBM_LANG_MARKDOWN, "a.md", "# Title\n\nSome text.\n", 0, {NULL}},
{"rst", CBM_LANG_RST, "a.rst", "Title\n=====\n\ntext\n", 0, {NULL}},
{"dockerfile", CBM_LANG_DOCKERFILE, "Dockerfile", "FROM alpine\nRUN echo hi\n", 0, {NULL}},
{"makefile", CBM_LANG_MAKEFILE, "Makefile", "all:\n\techo hi\n", 0, {NULL}},
{"cmake", CBM_LANG_CMAKE, "CMakeLists.txt", "function(foo)\nendfunction()\n", 0, {NULL}},
{"meson", CBM_LANG_MESON, "meson.build", "project('x', 'c')\n", 0, {NULL}},
{"gn", CBM_LANG_GN, "a.gn", "executable(\"foo\") {\n}\n", 0, {NULL}},
{"just", CBM_LANG_JUST, "justfile", "foo:\n\techo hi\n", 0, {NULL}},
{"hcl", CBM_LANG_HCL, "a.hcl", "resource \"x\" \"y\" {\n a = 1\n}\n", 0, {NULL}},
{"nix", CBM_LANG_NIX, "a.nix", "{ foo = 1; bar = 2; }\n", 0, {NULL}},
{"gomod", CBM_LANG_GOMOD, "go.mod", "module example.com/x\n\ngo 1.21\n", 0, {NULL}},
{"gotemplate", CBM_LANG_GOTEMPLATE, "a.tmpl", "{{ if .X }}{{ .Y }}{{ end }}\n", 0, {NULL}},
{"graphql", CBM_LANG_GRAPHQL, "a.graphql", "type Foo {\n id: ID\n}\n", 0, {NULL}},
{"prisma", CBM_LANG_PRISMA, "a.prisma", "model Foo {\n id Int @id\n}\n", 0, {NULL}},
{"thrift", CBM_LANG_THRIFT, "a.thrift", "service Foo {\n void ping()\n}\n", 0, {NULL}},
{"capnp", CBM_LANG_CAPNP, "a.capnp", "struct Foo {\n id @0 :Int32;\n}\n", 0, {NULL}},
{"smithy",
CBM_LANG_SMITHY,
"a.smithy",
"namespace example\n\nstructure Foo {\n id: Integer\n}\n",
1,
{"Foo", NULL}},
{"wit",
CBM_LANG_WIT,
"a.wit",
"interface i {\n record r { x: u32 }\n enum e { a, b }\n f: func() -> u32;\n}\n",
3,
{"r", "e", "f", NULL}},
{"kdl", CBM_LANG_KDL, "a.kdl", "node \"x\" {\n}\n", 0, {NULL}},
{"ron", CBM_LANG_RON, "a.ron", "(a: 1, b: 2)\n", 0, {NULL}},
{"nickel", CBM_LANG_NICKEL, "a.ncl", "{ foo = 1, bar = 2 }\n", 0, {NULL}},
{"pkl", CBM_LANG_PKL, "a.pkl", "foo = 1\nbar = 2\n", 0, {NULL}},
{"bicep", CBM_LANG_BICEP, "a.bicep", "param foo string\n", 0, {NULL}},
{"bitbake", CBM_LANG_BITBAKE, "a.bb", "DESCRIPTION = \"x\"\n", 0, {NULL}},
{"beancount", CBM_LANG_BEANCOUNT, "a.beancount", "2020-01-01 open Assets:Cash\n", 0, {NULL}},
{"bibtex", CBM_LANG_BIBTEX, "a.bib", "@article{key,\n title = {X}\n}\n", 0, {NULL}},
{"po", CBM_LANG_PO, "a.po", "msgid \"x\"\nmsgstr \"y\"\n", 0, {NULL}},
{"diff", CBM_LANG_DIFF, "a.diff", "--- a\n+++ b\n@@ -1 +1 @@\n-x\n+y\n", 0, {NULL}},
{"regex", CBM_LANG_REGEX, "a.re", "(foo|bar)+\n", 0, {NULL}},
{"requirements",
CBM_LANG_REQUIREMENTS,
"requirements.txt",
"flask==1.0\nrequests>=2\n",
0,
{NULL}},
{"properties", CBM_LANG_PROPERTIES, "a.properties", "foo=1\nbar=2\n", 0, {NULL}},
{"gitignore", CBM_LANG_GITIGNORE, ".gitignore", "*.o\nbuild/\n", 0, {NULL}},
{"gitattributes", CBM_LANG_GITATTRIBUTES, ".gitattributes", "*.c text\n", 0, {NULL}},
{"sshconfig", CBM_LANG_SSHCONFIG, "config", "Host x\n HostName y\n", 0, {NULL}},
{"hyprlang", CBM_LANG_HYPRLANG, "a.conf", "general {\n gaps_in = 5\n}\n", 0, {NULL}},
{"kconfig", CBM_LANG_KCONFIG, "Kconfig", "config FOO\n bool \"foo\"\n", 0, {NULL}},
{"linkerscript", CBM_LANG_LINKERSCRIPT, "a.ld", "SECTIONS {\n .text : {}\n}\n", 0, {NULL}},
{"devicetree", CBM_LANG_DEVICETREE, "a.dts", "/dts-v1/;\n/ {\n};\n", 0, {NULL}},
{"jinja2", CBM_LANG_JINJA2, "a.j2", "{% if x %}{{ y }}{% endif %}\n", 0, {NULL}},
{"liquid", CBM_LANG_LIQUID, "a.liquid", "{% if x %}{{ y }}{% endif %}\n", 0, {NULL}},
{"blade", CBM_LANG_BLADE, "a.blade.php", "@if($x)\n{{ $y }}\n@endif\n", 0, {NULL}},
{"vue", CBM_LANG_VUE, "a.vue", "<template><div></div></template>\n", 0, {NULL}},
{"svelte", CBM_LANG_SVELTE, "a.svelte", "<script>let x = 1;</script>\n<p>{x}</p>\n", 0, {NULL}},
{"astro", CBM_LANG_ASTRO, "a.astro", "---\nconst x = 1;\n---\n<div>{x}</div>\n", 0, {NULL}},
{"templ", CBM_LANG_TEMPL, "a.templ", "templ foo() {\n <div></div>\n}\n", 0, {NULL}},
{"typst", CBM_LANG_TYPST, "a.typ", "= Title\n\nsome text\n", 0, {NULL}},
{"mermaid", CBM_LANG_MERMAID, "a.mmd", "graph TD\n A --> B\n", 0, {NULL}},
};
const size_t CBM_GRAMMAR_CASES_COUNT = sizeof(CBM_GRAMMAR_CASES) / sizeof(CBM_GRAMMAR_CASES[0]);
TEST(grammar_regression_all) {
int failures = 0;
size_t n = CBM_GRAMMAR_CASES_COUNT;
for (size_t i = 0; i < n; i++) {
const GrammarCase *c = &CBM_GRAMMAR_CASES[i];
CBMFileResult *r = extract(c->src, c->lang, "reg", c->path);
if (!r) {
fprintf(stderr, " [REG] %-14s extract returned NULL\n", c->name);
failures++;
continue;
}
if (r->defs.count < c->min_defs) {
fprintf(stderr, " [REG] %-14s defs=%d < min=%d (extraction regression?)\n", c->name,
r->defs.count, c->min_defs);
failures++;
}
for (int e = 0; c->expect[e]; e++) {
if (!reg_has_def_any(r, c->expect[e])) {
fprintf(stderr, " [REG] %-14s missing def '%s' (defs=%d)\n", c->name, c->expect[e],
r->defs.count);
failures++;
}
}
cbm_free_result(r);
}
if (failures > 0) {
fprintf(stderr, " [REG] %d grammar-regression check(s) failed across %zu languages\n",
failures, n);
}
ASSERT_EQ(failures, 0);
PASS();
}
void suite_grammar_regression(void) {
RUN_TEST(grammar_regression_all);
}