from pathlib import Path import re ROOT = Path(__file__).resolve().parents[1] def read(path: Path) -> str: return path.read_text(encoding="utf-8") def doxygen_assignments(text: str) -> dict[str, str]: assignments = {} for line in text.splitlines(): match = re.fullmatch(r"\s*([A-Z][A-Z0-9_]*)\s*=\s*(.*?)\s*", line) if match is not None: assignments[match.group(1)] = match.group(2) return assignments def test_p_style_001_cpp_style_and_doxygen_tooling_contract(): required_paths = ( ROOT / ".clang-format", ROOT / ".clang-tidy", ROOT / "Doxyfile", ) missing_paths = [path.name for path in required_paths if not path.is_file()] assert not missing_paths, f"missing C++ policy files: {missing_paths}" clang_format = read(ROOT / ".clang-format") for setting in ( "BasedOnStyle: Google", "IndentWidth: 2", "ColumnLimit: 80", ): assert setting in clang_format clang_tidy = read(ROOT / ".clang-tidy") for setting in ( "-std=c++17", "readability-identifier-naming", "readability-identifier-naming.ClassCase: CamelCase", "readability-identifier-naming.StructCase: CamelCase", "readability-identifier-naming.EnumCase: CamelCase", "readability-identifier-naming.TypeAliasCase: CamelCase", "readability-identifier-naming.FunctionCase: CamelCase", "readability-identifier-naming.MethodCase: CamelCase", "readability-identifier-naming.VariableCase: lower_case", "readability-identifier-naming.ParameterCase: lower_case", "readability-identifier-naming.LocalVariableCase: lower_case", "readability-identifier-naming.PrivateMemberCase: lower_case", "readability-identifier-naming.PrivateMemberSuffix: _", "readability-identifier-naming.ProtectedMemberCase: lower_case", "readability-identifier-naming.ProtectedMemberSuffix: _", "readability-identifier-naming.PublicMemberCase: lower_case", "readability-identifier-naming.ConstantCase: CamelCase", "readability-identifier-naming.ConstantPrefix: k", "readability-identifier-naming.EnumConstantCase: CamelCase", "readability-identifier-naming.EnumConstantPrefix: k", "readability-identifier-naming.NamespaceCase: lower_case", "readability-identifier-naming.MacroDefinitionCase: UPPER_CASE", ): assert setting in clang_tidy doxyfile = doxygen_assignments(read(ROOT / "Doxyfile")) assert doxyfile["INPUT"].split() == ["include", "src"] assert doxyfile["EXCLUDE"].split() == ["tests"] assert doxyfile["WARN_AS_ERROR"] == "YES" assert doxyfile["OUTPUT_DIRECTORY"] == ".harness/doxygen" assert doxyfile["HTML_OUTPUT"] == "html" gitignore_lines = read(ROOT / ".gitignore").splitlines() assert ".harness/doxygen/" in gitignore_lines cmake = read(ROOT / "CMakeLists.txt") assert "find_package(Doxygen QUIET)" in cmake doxygen_block = re.search( r"if\(Doxygen_FOUND\)(?P.*?)endif\(\)", cmake, re.DOTALL ) assert doxygen_block is not None assert "add_custom_target(fesa_docs" in doxygen_block.group("body") assert "Doxyfile" in doxygen_block.group("body") assert re.search(r"add_custom_target\(fesa_docs\s+ALL\b", cmake) is None