diff --git a/docs/c_parser/c_parser_architecture.md b/docs/c_parser/c_parser_architecture.md index 69487893a..31d1dd789 100644 --- a/docs/c_parser/c_parser_architecture.md +++ b/docs/c_parser/c_parser_architecture.md @@ -77,8 +77,8 @@ Implemented now: rejected until semantic conversion exists. - Focused partial CLI/API, declaration/function, diagnostic color, project include/index, raw lexer/directive, project golden, error golden, and JSON - schema tests are active while corpus, semantic, and `.pyi` roadmap tests - remain skipped. + schema tests are active. Remaining parser-suite skips are limited to the + pinned corpus roadmap and compiler-preprocessed `.i`/`#line` behavior. - `tests/data/c/` contains general fixtures modeled after the Fortran general fixture themes, additional C-specific API shapes, fatal diagnostic inputs, and real-world cJSON/jsmn/tinyexpr/linmath/NanoSVG/stb inputs whose partial diff --git a/docs/c_parser/c_parser_cli_workflow.md b/docs/c_parser/c_parser_cli_workflow.md index 89feb83c6..82492c585 100644 --- a/docs/c_parser/c_parser_cli_workflow.md +++ b/docs/c_parser/c_parser_cli_workflow.md @@ -57,6 +57,8 @@ member placement and flexible union members produce `parser_status: "partial"`. C parse diagnostics, currently including unsupported K&R-style function definitions and invalid primitive-specifier combinations such as `unsigned float`, honor `--no-color` and `NO_COLOR=1`. +Active CLI regression tests also verify that `--debug-traceback` and +`C_PARSER_DEBUG=1` re-raise fatal C parse errors for debugging. Function definitions do not store executable body text; they preserve a direct `start` location and `end` location from the signature start through the closing brace. Compatible repeated top-level declarations are merged; diff --git a/docs/c_parser/c_parser_implementation_checklist.md b/docs/c_parser/c_parser_implementation_checklist.md index 07e0c62e5..3d6def3f3 100644 --- a/docs/c_parser/c_parser_implementation_checklist.md +++ b/docs/c_parser/c_parser_implementation_checklist.md @@ -372,16 +372,19 @@ Scope: - [x] Keep the skipped C suite separate from existing Fortran tests. - [x] Keep Fortran tests green whenever C tests are unskipped. -### Skipped Roadmap Test Files +### Roadmap And Active Test Files - [x] Create `tests/parser/c/README.md` with the staged unskip policy. -- [x] Create `tests/parser/c/test_c_public_entrypoints.py`. -- [x] Create `tests/parser/c/test_c_cli.py`. +- [x] Consolidate implemented public API roadmap coverage into + `tests/parser/c/test_c_public_api_skeleton.py`. +- [x] Consolidate implemented CLI roadmap coverage into + `tests/parser/c/test_c_cli_skeleton.py`. - [x] Create `tests/parser/c/test_c_lexer_preprocessor.py`. - [x] Create `tests/parser/c/test_c_declarations_and_declarators.py`. - [x] Create `tests/parser/c/test_c_functions.py`. - [x] Create `tests/parser/c/test_c_structs_unions_enums_typedefs.py`. -- [x] Create `tests/parser/c/test_c_project_includes.py`. +- [x] Consolidate implemented project/include roadmap coverage into + `tests/parser/c/test_c_project_resolution.py`. - [x] Create `tests/semantics/test_c_semantic_readiness.py` or equivalent semantic-layer coverage for C wrappability once that layer exists. - [x] Create `tests/parser/c/test_c_fixture_suite.py`. diff --git a/docs/c_parser/c_parser_reference.md b/docs/c_parser/c_parser_reference.md index 99271bdd7..3bb75398f 100644 --- a/docs/c_parser/c_parser_reference.md +++ b/docs/c_parser/c_parser_reference.md @@ -466,8 +466,8 @@ Test families should mirror the Fortran parser: - error fixture/golden tests - corpus parse-only tests -The C test area now contains both unskipped partial-parser/raw-metadata tests -and skipped roadmap tests under `tests/parser/c/`. The active tests cover +The C test area now contains active partial-parser/raw-metadata tests plus +narrowly scoped roadmap skips under `tests/parser/c/`. The active tests cover public entrypoints, empty model serialization, CLI discovery, JSON/output-file behavior, unsupported C stages, comment stripping, line-continuation folding, top-level splitting, include collection, simple macro collection, macro-shaped @@ -476,13 +476,15 @@ macro-dependency metadata, project include/index behavior, simple declarations, variables, typedefs, top-level redeclaration diagnostics, recursive declarator composition, aggregate definitions, members, enums, simple function prototypes/definitions, function-definition start/end locations, JSON golden -serialization, and fatal diagnostic goldens. The `json` regression inputs +serialization, fatal diagnostic goldens, and project-level callback typedef +resolution. The `json` regression inputs intentionally retain recoverable diagnostics from unsupported constructs; they -do not claim complete library parsing. Corpus, semantic, and `.pyi` roadmap -tests remain skipped until their matching implementation branches land. Future -implementation -branches should unskip only the tests for the capability they implement, then -merge those branches back into `c-parser/main`. +do not claim complete library parsing. Remaining parser-suite skips cover the +pinned/provenanced corpus target and compiler-preprocessed `.i`/`#line` +behavior; golden inventory checks also skip deliberately while update mode is +rewriting their baselines. Future implementation branches should activate only +the tests for the capability they implement, then merge those branches back +into `c-parser/main`. ### Declaration Coverage Boundary diff --git a/tests/parser/c/README.md b/tests/parser/c/README.md index b081101c0..b11d76c76 100644 --- a/tests/parser/c/README.md +++ b/tests/parser/c/README.md @@ -1,7 +1,7 @@ # C Parser Tests This directory contains active tests for the implemented partial C parser and -skipped roadmap tests for later parser, corpus, semantic, and `.pyi` work. +narrowly scoped skipped tests for genuinely deferred input/corpus work. Unskip tests one capability at a time on a short-lived `c-parser/*` branch, then merge only into `c-parser/main`. @@ -10,11 +10,22 @@ Guidelines: - keep these tests separate from the Fortran parser tests - keep wrap-readiness tests under `tests/semantics`, not under parser tests -- do not import `c_parser` at module import time while the suite is skipped -- unskip the smallest useful group of tests with each implementation branch +- do not import `c_parser` at module import time while a roadmap test is skipped +- activate or remove roadmap tests once matching active coverage lands - add fixtures and goldens only when the corresponding schema is stable - keep cJSON as the first real-world corpus target once corpus tests start +## Intentional Skips + +The normal parser test run retains skips only for the pinned/provenanced +cJSON corpus roadmap and compiler-preprocessed `.i`/`#line` behavior, which +are not implemented yet. CLI, public API, and current project-resolution +coverage are active. + +When `C_PARSER_UPDATE_GOLDENS=1` is set, golden inventory checks are skipped +while their corresponding comparison tests rewrite the expected output. Those +update-mode skips are workflow behavior, not unsupported parser input. + ## Parser Goldens Active parser goldens cover grouped projects from `tests/data/c/general/`, diff --git a/tests/parser/c/test_c_cli.py b/tests/parser/c/test_c_cli.py deleted file mode 100644 index 3eaed19a7..000000000 --- a/tests/parser/c/test_c_cli.py +++ /dev/null @@ -1,190 +0,0 @@ -# -*- coding: utf-8 -*- -"""Planned C parser CLI tests. - -These tests mirror the Fortran CLI coverage but stay skipped until the C CLI -skeleton exists. Unskip one test group at a time as the explicit C mode lands. -""" - -import json -import os -import subprocess -import sys -from pathlib import Path - -import pytest - -pytestmark = pytest.mark.skip( - reason="C parser CLI roadmap tests; unskip with the matching C CLI implementation branch." -) - - -def test_cli_help_shows_explicit_c_language_mode(): - cmd = [sys.executable, "-m", "x2py", "--help"] - - res = subprocess.run(cmd, capture_output=True, text=True, check=True) - - assert "--language" in res.stdout - assert "c" in res.stdout - - -def test_cli_c_parse_human_tree_output_for_header(tmp_path: Path): - header = tmp_path / "api.h" - header.write_text("int add(int a, int b);\n", encoding="utf-8") - cmd = [sys.executable, "-m", "x2py", str(header), "--language", "c", "--parse"] - - res = subprocess.run(cmd, capture_output=True, text=True, check=True) - - assert f"File: {header}" in res.stdout - assert "Language: c" in res.stdout - assert "Functions: 1" in res.stdout - assert "add" in res.stdout - - -def test_cli_c_parse_json_stdout_for_header(tmp_path: Path): - header = tmp_path / "api.h" - header.write_text("int add(int a, int b);\n", encoding="utf-8") - cmd = [sys.executable, "-m", "x2py", str(header), "--language", "c", "--parse", "--json"] - - res = subprocess.run(cmd, capture_output=True, text=True, check=True) - payload = json.loads(res.stdout) - - assert payload[str(header)]["language"] == "c" - assert payload[str(header)]["functions"][0]["name"] == "add" - - -def test_cli_c_parse_json_out_writes_file_and_suppresses_stdout(tmp_path: Path): - header = tmp_path / "api.h" - output = tmp_path / "report.json" - header.write_text("double scale(double x);\n", encoding="utf-8") - cmd = [ - sys.executable, - "-m", - "x2py", - str(header), - "--language", - "c", - "--parse", - "--json", - "--out", - str(output), - ] - - res = subprocess.run(cmd, capture_output=True, text=True, check=True) - payload = json.loads(output.read_text(encoding="utf-8")) - - assert res.stdout == "" - assert payload[str(header)]["functions"][0]["name"] == "scale" - - -def test_cli_c_wrap_readiness_is_rejected_until_semantic_conversion_exists(tmp_path: Path): - header = tmp_path / "api.h" - header.write_text("int add(int a, int b);\n", encoding="utf-8") - cmd = [ - sys.executable, - "-m", - "x2py", - str(header), - "--language", - "c", - "--parse", - "--wrap-readiness", - ] - - res = subprocess.run(cmd, capture_output=True, text=True) - - assert res.returncode != 0 - assert "semantic" in res.stderr.lower() - assert "not supported" in res.stderr.lower() - - -def test_cli_c_rejects_fortran_only_flags_with_clear_error(tmp_path: Path): - header = tmp_path / "api.h" - header.write_text("int add(int a, int b);\n", encoding="utf-8") - cmd = [sys.executable, "-m", "x2py", str(header), "--language", "c", "--parse", "--show-vars"] - - res = subprocess.run(cmd, capture_output=True, text=True) - - assert res.returncode != 0 - assert "show-vars" in res.stderr - assert "C" in res.stderr - - -def test_cli_c_semantics_is_rejected_until_phase_10(tmp_path: Path): - header = tmp_path / "api.h" - header.write_text("int add(int a, int b);\n", encoding="utf-8") - cmd = [sys.executable, "-m", "x2py", str(header), "--language", "c", "--semantics"] - - res = subprocess.run(cmd, capture_output=True, text=True) - - assert res.returncode != 0 - assert "not supported" in res.stderr.lower() - - -def test_cli_c_pyi_is_rejected_until_phase_11(tmp_path: Path): - header = tmp_path / "api.h" - header.write_text("int add(int a, int b);\n", encoding="utf-8") - cmd = [sys.executable, "-m", "x2py", str(header), "--language", "c", "--pyi"] - - res = subprocess.run(cmd, capture_output=True, text=True) - - assert res.returncode != 0 - assert "not supported" in res.stderr.lower() - - -def test_cli_c_no_color_formats_parse_errors_without_ansi(tmp_path: Path): - header = tmp_path / "bad.h" - header.write_text("int broken(;\n", encoding="utf-8") - cmd = [sys.executable, "-m", "x2py", str(header), "--language", "c", "--parse", "--no-color"] - - res = subprocess.run(cmd, capture_output=True, text=True) - - assert res.returncode == 1 - assert "\033[" not in res.stderr - assert "error[" in res.stderr - - -def test_cli_c_debug_traceback_reraises_parse_errors(tmp_path: Path): - header = tmp_path / "bad.h" - header.write_text("int broken(;\n", encoding="utf-8") - cmd = [ - sys.executable, - "-m", - "x2py", - str(header), - "--language", - "c", - "--parse", - "--debug-traceback", - ] - - res = subprocess.run(cmd, capture_output=True, text=True) - - assert res.returncode == 1 - assert "Traceback" in res.stderr - assert "CParseError" in res.stderr - - -def test_cli_c_debug_env_reraises_parse_errors(tmp_path: Path): - header = tmp_path / "bad.h" - header.write_text("int broken(;\n", encoding="utf-8") - cmd = [sys.executable, "-m", "x2py", str(header), "--language", "c", "--parse"] - - res = subprocess.run( - cmd, - capture_output=True, - text=True, - env={**os.environ, "C_PARSER_DEBUG": "1"}, - ) - - assert res.returncode == 1 - assert "Traceback" in res.stderr - - -def test_cli_without_language_keeps_fortran_default_behavior(): - fixture = Path(__file__).resolve().parents[2] / "data" / "fortran" / "general" / "basic_subroutine.f90" - cmd = [sys.executable, "-m", "x2py", str(fixture), "--parse"] - - res = subprocess.run(cmd, capture_output=True, text=True, check=True) - - assert "subroutine add1" in res.stdout - assert "Language: c" not in res.stdout diff --git a/tests/parser/c/test_c_cli_skeleton.py b/tests/parser/c/test_c_cli_skeleton.py index 4fa6e7b5c..5145e8bfa 100644 --- a/tests/parser/c/test_c_cli_skeleton.py +++ b/tests/parser/c/test_c_cli_skeleton.py @@ -210,6 +210,44 @@ def test_cli_c_invalid_primitive_specifier_sequence_is_fatal(tmp_path: Path): assert "\x1b[" not in res.stderr +def test_cli_c_debug_traceback_reraises_parse_errors(tmp_path: Path): + header = tmp_path / "invalid_specifiers.h" + header.write_text("unsigned float value;\n", encoding="utf-8") + cmd = [ + sys.executable, + "-m", + "x2py", + str(header), + "--language", + "c", + "--parse", + "--debug-traceback", + ] + + res = subprocess.run(cmd, capture_output=True, text=True) + + assert res.returncode == 1 + assert "Traceback" in res.stderr + assert "CParseError" in res.stderr + + +def test_cli_c_debug_env_reraises_parse_errors(tmp_path: Path): + header = tmp_path / "invalid_specifiers.h" + header.write_text("unsigned float value;\n", encoding="utf-8") + cmd = [sys.executable, "-m", "x2py", str(header), "--language", "c", "--parse"] + + res = subprocess.run( + cmd, + capture_output=True, + text=True, + env={**os.environ, "C_PARSER_DEBUG": "1"}, + ) + + assert res.returncode == 1 + assert "Traceback" in res.stderr + assert "CParseError" in res.stderr + + def test_cli_without_language_keeps_fortran_default_behavior(): fixture = Path(__file__).resolve().parents[2] / "data" / "fortran" / "general" / "basic_subroutine.f90" cmd = [sys.executable, "-m", "x2py", str(fixture), "--parse"] diff --git a/tests/parser/c/test_c_functions.py b/tests/parser/c/test_c_functions.py index 0df4a83e4..9131d368e 100644 --- a/tests/parser/c/test_c_functions.py +++ b/tests/parser/c/test_c_functions.py @@ -129,19 +129,19 @@ def test_function_parameter_preserves_declaration_and_adjusts_to_callback_pointe assert parsed.functions[0].type.parameter_types[0] is callback.type -@pytest.mark.skip(reason="function pointer typedef resolution is not implemented yet.") -def test_callback_typedef_parameter_links_to_typedef_signature(): - from c_parser import CFunctionType, CTypedef, parse_c_file +def test_project_resolves_callback_typedef_parameter_to_typedef_signature(): + from c_parser import CFunctionType, CTypedef, parse_c_project - parsed = parse_c_file( - """ + project = parse_c_project( + { + "callback_typedef.h": """ typedef int (*compare_fn)(const void *a, const void *b); void sort_items(void *items, compare_fn compare); -""", - filename="callback_typedef.h", +""" + } ) - referenced = parsed.functions[0].parameters[1].type + referenced = project.functions["sort_items"].parameters[1].type assert isinstance(referenced, CTypedef) assert isinstance(referenced.type.components[1], CFunctionType) diff --git a/tests/parser/c/test_c_project_includes.py b/tests/parser/c/test_c_project_includes.py deleted file mode 100644 index c592b3554..000000000 --- a/tests/parser/c/test_c_project_includes.py +++ /dev/null @@ -1,99 +0,0 @@ -# -*- coding: utf-8 -*- -"""Planned C project parsing, include graph, and cross-file resolution tests.""" - -from pathlib import Path - -import pytest - -pytestmark = pytest.mark.skip( - reason="C parser project roadmap tests; unskip with include/project resolution implementation." -) - - -def test_parse_c_project_accepts_directory_and_discovers_c_h_and_i_files(tmp_path: Path): - from c_parser import parse_c_project - - (tmp_path / "api.h").write_text("int add(int a, int b);\n", encoding="utf-8") - (tmp_path / "api.c").write_text('#include "api.h"\nint add(int a, int b) { return a + b; }\n', encoding="utf-8") - (tmp_path / "generated.i").write_text("int generated(void);\n", encoding="utf-8") - - project = parse_c_project(tmp_path) - - assert set(project.files) == {"api.h", "api.c", "generated.i"} - - -def test_project_include_graph_tracks_local_and_system_includes(tmp_path: Path): - from c_parser import parse_c_project - - (tmp_path / "api.h").write_text("#include \nint run(size_t n);\n", encoding="utf-8") - (tmp_path / "api.c").write_text('#include "api.h"\n', encoding="utf-8") - - project = parse_c_project(tmp_path) - - assert project.include_graph["api.c"] == {"api.h"} - assert project.system_includes["api.h"] == {"stddef.h"} - - -def test_project_resolves_typedefs_across_headers_and_sources(tmp_path: Path): - from c_parser import parse_c_project - - (tmp_path / "types.h").write_text("typedef unsigned long api_size;\n", encoding="utf-8") - (tmp_path / "api.h").write_text('#include "types.h"\napi_size count(void);\n', encoding="utf-8") - - project = parse_c_project(tmp_path) - - assert project.functions["count"].result_type.type is project.typedefs["api_size"].type - - -def test_project_resolves_struct_tags_across_includes(tmp_path: Path): - from c_parser import parse_c_project - - (tmp_path / "types.h").write_text("struct state { int id; };\n", encoding="utf-8") - (tmp_path / "api.h").write_text('#include "types.h"\nvoid step(struct state *s);\n', encoding="utf-8") - - project = parse_c_project(tmp_path) - - param_type = project.functions["step"].parameters[0].type - assert param_type.components[-1] is project.structs["state"] - assert param_type.components[-1].members[0].name == "id" - - -def test_include_guards_do_not_duplicate_symbols(tmp_path: Path): - from c_parser import parse_c_project - - (tmp_path / "types.h").write_text( - """ -#ifndef TYPES_H -#define TYPES_H -typedef int api_int; -#endif -""", - encoding="utf-8", - ) - (tmp_path / "a.h").write_text('#include "types.h"\napi_int a(void);\n', encoding="utf-8") - (tmp_path / "b.h").write_text('#include "types.h"\napi_int b(void);\n', encoding="utf-8") - - project = parse_c_project(tmp_path) - - assert list(project.typedefs).count("api_int") == 1 - - -def test_duplicate_global_function_symbols_report_project_diagnostic(tmp_path: Path): - from c_parser import CParseError, parse_c_project - - (tmp_path / "a.h").write_text("int work(void);\n", encoding="utf-8") - (tmp_path / "b.h").write_text("double work(double x);\n", encoding="utf-8") - - with pytest.raises(CParseError, match="Duplicate symbol 'work'"): - parse_c_project(tmp_path) - - -def test_header_source_pairing_links_matching_stems(tmp_path: Path): - from c_parser import parse_c_project - - (tmp_path / "solver.h").write_text("int solve(void);\n", encoding="utf-8") - (tmp_path / "solver.c").write_text('#include "solver.h"\nint solve(void) { return 0; }\n', encoding="utf-8") - - project = parse_c_project(tmp_path) - - assert project.header_source_pairs["solver.h"] == {"solver.c"} diff --git a/tests/parser/c/test_c_project_resolution.py b/tests/parser/c/test_c_project_resolution.py index d7244c737..709977fd0 100644 --- a/tests/parser/c/test_c_project_resolution.py +++ b/tests/parser/c/test_c_project_resolution.py @@ -3,6 +3,8 @@ from pathlib import Path +import pytest + def test_project_include_graph_tracks_local_system_missing_and_cycles(tmp_path: Path): from c_parser import parse_c_project @@ -39,6 +41,20 @@ def test_project_resolves_quoted_includes_through_include_dirs(tmp_path: Path): assert project.unresolved_includes[str(api)] == set() +@pytest.mark.skip( + reason="Directory discovery of preprocessed .i inputs is deferred with preprocessed mode." +) +def test_parse_c_project_directory_discovers_preprocessed_i_files(tmp_path: Path): + from c_parser import parse_c_project + + (tmp_path / "api.c").write_text("int from_source(void);\n", encoding="utf-8") + (tmp_path / "generated.i").write_text("int generated(void);\n", encoding="utf-8") + + project = parse_c_project(tmp_path) + + assert set(project.files) == {"api.c", "generated.i"} + + def test_project_indexes_functions_by_file_and_enum_constants(tmp_path: Path): from c_parser import parse_c_project diff --git a/tests/parser/c/test_c_public_api_skeleton.py b/tests/parser/c/test_c_public_api_skeleton.py index 0cc8b54e9..8e2d4f603 100644 --- a/tests/parser/c/test_c_public_api_skeleton.py +++ b/tests/parser/c/test_c_public_api_skeleton.py @@ -218,6 +218,16 @@ def test_public_c_parser_entrypoints_do_not_include_parser_side_readiness(): assert not hasattr(c_parser, "assess_c_wrap_readiness") +def test_c_parser_instance_entrypoints_match_public_functions(): + from c_parser import CParser, parse_c_file, parse_c_project + + source = "int answer(void);\n" + parser = CParser() + + assert parser.visit_file(source, filename="api.h") == parse_c_file(source, filename="api.h") + assert parser.visit_project({"api.h": source}) == parse_c_project({"api.h": source}) + + def test_c_parse_error_attributes_and_diagnostic_formatting(): from c_parser import CParseError diff --git a/tests/parser/c/test_c_public_entrypoints.py b/tests/parser/c/test_c_public_entrypoints.py deleted file mode 100644 index 593776f46..000000000 --- a/tests/parser/c/test_c_public_entrypoints.py +++ /dev/null @@ -1,87 +0,0 @@ -# -*- coding: utf-8 -*- -"""Planned public C parser entrypoint tests.""" - -from pathlib import Path - -import pytest - -pytestmark = pytest.mark.skip( - reason="C parser public API roadmap tests; unskip with public API implementation." -) - - -def test_parse_c_file_accepts_inline_header_source(): - from c_parser import parse_c_file - - parsed = parse_c_file("int add(int a, int b);\n", filename="inline.h") - - assert parsed.filename == "inline.h" - assert parsed.language == "c" - assert [fn.name for fn in parsed.functions] == ["add"] - - -def test_parse_c_file_accepts_path_input_and_preserves_filename(tmp_path: Path): - from c_parser import parse_c_file - - header = tmp_path / "api.h" - header.write_text("double scale(double x);\n", encoding="utf-8") - - parsed = parse_c_file(header) - - assert parsed.filename == str(header) - assert parsed.functions[0].name == "scale" - - -def test_parse_c_file_accepts_empty_translation_unit(): - from c_parser import parse_c_file - - parsed = parse_c_file("\n/* intentionally empty */\n", filename="empty.c") - - assert parsed.filename == "empty.c" - assert parsed.functions == [] - assert parsed.diagnostics == [] - - -def test_parse_c_project_accepts_mapping_sources(): - from c_parser import parse_c_project - - project = parse_c_project( - { - "types.h": "typedef int api_int;\n", - "api.h": '#include "types.h"\napi_int answer(void);\n', - } - ) - - assert "types.h" in project.files - assert "api.h" in project.files - assert "answer" in project.functions - - -def test_parse_c_project_accepts_directory_input(tmp_path: Path): - from c_parser import parse_c_project - - (tmp_path / "api.h").write_text("int add(int a, int b);\n", encoding="utf-8") - (tmp_path / "api.c").write_text('#include "api.h"\nint add(int a, int b) { return a + b; }\n', encoding="utf-8") - - project = parse_c_project(tmp_path) - - assert set(project.files) == {"api.h", "api.c"} - assert "add" in project.functions - - -def test_c_parser_instance_entrypoints_match_public_functions(): - from c_parser import CParser, parse_c_file, parse_c_project - - source = "int answer(void);\n" - parser = CParser() - - assert parser.visit_file(source, filename="api.h") == parse_c_file(source, filename="api.h") - assert parser.visit_project({"api.h": source}) == parse_c_project({"api.h": source}) - - -def test_public_c_parser_entrypoints_do_not_include_parser_side_readiness(): - import c_parser - - assert hasattr(c_parser, "parse_c_file") - assert hasattr(c_parser, "parse_c_project") - assert not hasattr(c_parser, "assess_c_wrap_readiness")