Step 402: self-host parse coverage for AnnotationValidatorExtended

This commit is contained in:
Bill
2026-02-16 14:59:57 -07:00
parent 02e76576f3
commit 1df56b809f
3 changed files with 287 additions and 0 deletions

View File

@@ -2497,4 +2497,13 @@ target_link_libraries(step401_test PRIVATE
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
add_executable(step402_test tests/step402_test.cpp)
target_include_directories(step402_test PRIVATE src)
target_link_libraries(step402_test PRIVATE
nlohmann_json::nlohmann_json
unofficial::tree-sitter::tree-sitter
tree_sitter_python tree_sitter_cpp tree_sitter_elisp
tree_sitter_javascript tree_sitter_typescript
tree_sitter_java tree_sitter_rust tree_sitter_go)
# Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies)

View File

@@ -0,0 +1,239 @@
// Step 402: Parse AnnotationValidatorExtended.h (12 tests)
// Self-hosting: parse class-heavy validator header with static helpers and casts.
#include <cassert>
#include <filesystem>
#include <iostream>
#include <string>
#include <vector>
#include "AnnotationInference.h"
#include "SelfHostHarness.h"
#include "ast/ClassDeclaration.h"
#include "ast/CppAdvancedNodes.h"
#include "ast/Function.h"
namespace {
std::string resolveHeaderPath() {
const std::vector<std::string> candidates = {
"src/AnnotationValidatorExtended.h",
"editor/src/AnnotationValidatorExtended.h",
"../src/AnnotationValidatorExtended.h",
"../../editor/src/AnnotationValidatorExtended.h"
};
for (const auto& candidate : candidates) {
if (std::filesystem::exists(candidate)) return candidate;
}
return "src/AnnotationValidatorExtended.h";
}
std::string headerPath() {
static const std::string path = resolveHeaderPath();
return path;
}
const ClassDeclaration* findClass(const Module* module, const std::string& name) {
if (!module) return nullptr;
for (auto* clsNode : module->getChildren("classes")) {
auto* cls = static_cast<ClassDeclaration*>(clsNode);
if (cls->name == name) return cls;
}
return nullptr;
}
const Function* findMethod(const ClassDeclaration* cls, const std::string& name) {
if (!cls) return nullptr;
for (auto* methodNode : cls->getChildren("methods")) {
if (methodNode->conceptType == "MethodDeclaration" || methodNode->conceptType == "Function") {
auto* method = static_cast<Function*>(methodNode);
if (method->name == name) return method;
}
}
return nullptr;
}
int countConceptRecursive(const ASTNode* node, const std::string& conceptType) {
if (!node) return 0;
int total = (node->conceptType == conceptType) ? 1 : 0;
for (auto* child : node->allChildren()) {
total += countConceptRecursive(child, conceptType);
}
return total;
}
int countStaticMethods(const ClassDeclaration* cls) {
if (!cls) return 0;
int count = 0;
for (auto* methodNode : cls->getChildren("methods")) {
if (methodNode->conceptType == "MethodDeclaration") {
auto* method = static_cast<MethodDeclaration*>(methodNode);
if (method->isStatic) count++;
}
}
return count;
}
} // namespace
int main() {
int passed = 0;
// Test 1: Parse real validator header file from disk.
{
assert(std::filesystem::exists(headerPath()));
auto result = SelfHostHarness::parseFile(headerPath());
assert(result.parseSuccess);
assert(result.ast != nullptr);
std::cout << "PASS: test 1 — parse real AnnotationValidatorExtended.h file\n";
passed++;
}
// Test 2: AnnotationValidatorExtended class is captured.
{
auto result = SelfHostHarness::parseFile(headerPath());
assert(SelfHostHarness::hasParsedConstruct(
result.ast.get(), "class", "AnnotationValidatorExtended"));
std::cout << "PASS: test 2 — class AnnotationValidatorExtended captured\n";
passed++;
}
// Test 3: Class has parsed method entries.
{
auto result = SelfHostHarness::parseFile(headerPath());
const auto* cls = findClass(result.ast.get(), "AnnotationValidatorExtended");
assert(cls != nullptr);
assert(cls->getChildren("methods").size() >= 3);
std::cout << "PASS: test 3 — class has method entries\n";
passed++;
}
// Test 4: Public validate method signature is captured.
{
auto result = SelfHostHarness::parseFile(headerPath());
const auto* cls = findClass(result.ast.get(), "AnnotationValidatorExtended");
const auto* method = findMethod(cls, "validate");
assert(method != nullptr);
assert(method->getChildren("parameters").size() >= 1);
std::cout << "PASS: test 4 — validate method signature captured\n";
passed++;
}
// Test 5: Private helper methods are captured.
{
auto result = SelfHostHarness::parseFile(headerPath());
const auto* cls = findClass(result.ast.get(), "AnnotationValidatorExtended");
assert(findMethod(cls, "validateNode") != nullptr);
assert(findMethod(cls, "validateAnnotation") != nullptr);
std::cout << "PASS: test 5 — private helper methods captured\n";
passed++;
}
// Test 6: Static helper methods are captured as static methods.
{
auto result = SelfHostHarness::parseFile(headerPath());
const auto* cls = findClass(result.ast.get(), "AnnotationValidatorExtended");
assert(findMethod(cls, "isPowerOf2") != nullptr);
assert(findMethod(cls, "isOneOf") != nullptr);
assert(countStaticMethods(cls) >= 2);
std::cout << "PASS: test 6 — static helper methods parsed\n";
passed++;
}
// Test 7: Self-host expected structure has full coverage.
{
auto result = SelfHostHarness::parseFile(headerPath());
ExpectedStructure expected;
expected.filePath = headerPath();
expected.constructs = {{"class", "AnnotationValidatorExtended"}};
SelfHostHarness::checkExpected(result, expected);
assert(result.totalExpected == 1);
assert(result.totalParsed == 1);
assert(result.totalOpaque == 0);
assert(result.overallCoverage() == 1.0);
std::cout << "PASS: test 7 — expected structure coverage 100%\n";
passed++;
}
// Test 8: static_cast patterns from validator logic are recognized by cast helpers.
{
const std::string expr1 = "static_cast<const BitWidthAnnotation*>(anno)";
const std::string expr2 = "static_cast<const LayoutAnnotation*>(anno)";
assert(detectCastKind(expr1) == "static_cast");
assert(detectCastKind(expr2) == "static_cast");
assert(castRiskLevel(detectCastKind(expr1)) == "low");
std::cout << "PASS: test 8 — static_cast detection helpers match validator patterns\n";
passed++;
}
// Test 9: Inference produces complexity signals on parsed methods.
{
auto result = SelfHostHarness::parseFile(headerPath());
AnnotationInference inf;
auto inferred = inf.inferAll(result.ast.get());
int complexityCount = 0;
for (const auto& item : inferred) {
if (item.annotationType == "ComplexityAnnotation") complexityCount++;
}
assert(complexityCount >= 1);
std::cout << "PASS: test 9 — complexity inference runs on self-host AST\n";
passed++;
}
// Test 10: Targeted class snippet with static helpers parses cleanly.
{
const std::string source = R"(
class ValidatorLite {
public:
static bool ok(int x) { return x > 0; }
static bool positive(int x) { return x >= 0; }
int run(int value) { return value + 1; }
};
)";
auto result = SelfHostHarness::parseSource(source, "validator_lite");
assert(result.parseSuccess);
assert(SelfHostHarness::hasParsedConstruct(result.ast.get(), "class", "ValidatorLite"));
const auto* cls = findClass(result.ast.get(), "ValidatorLite");
assert(cls != nullptr);
assert(countStaticMethods(cls) >= 2);
std::cout << "PASS: test 10 — static helper snippet parse stable\n";
passed++;
}
// Test 11: Coverage report includes real file path and parse status.
{
auto result = SelfHostHarness::parseFile(headerPath());
ExpectedStructure expected;
expected.filePath = headerPath();
expected.constructs = {{"class", "AnnotationValidatorExtended"}};
SelfHostHarness::checkExpected(result, expected);
const std::string report = SelfHostHarness::coverageReport(result);
assert(report.find(headerPath()) != std::string::npos);
assert(report.find("Parse success: yes") != std::string::npos);
assert(report.find("100%") != std::string::npos);
std::cout << "PASS: test 11 — coverage report content checks\n";
passed++;
}
// Test 12: Missing expected constructs are counted as opaque, not fatal.
{
auto result = SelfHostHarness::parseFile(headerPath());
ExpectedStructure expected;
expected.filePath = headerPath();
expected.constructs = {
{"class", "AnnotationValidatorExtended"},
{"function", "definitelyMissingFunction"},
{"class", "DefinitelyMissingClass"}
};
SelfHostHarness::checkExpected(result, expected);
assert(result.totalExpected == 3);
assert(result.totalParsed == 1);
assert(result.totalOpaque == 2);
assert(result.overallCoverage() == (1.0 / 3.0));
std::cout << "PASS: test 12 — graceful degradation via opaque tracking\n";
passed++;
}
std::cout << "\nStep 402 result: " << passed << "/12 tests passed\n";
return (passed == 12) ? 0 : 1;
}

View File

@@ -3496,6 +3496,45 @@ coverage reporting, and graceful degradation on missing expected constructs.
- `editor/src/MCPServer.h` (`1679` > `600`)
- `editor/src/HeadlessAgentRPCHandler.h` (`2623` > `600`)
### Step 402: Parse AnnotationValidatorExtended.h
**Status:** PASS (12/12 tests)
Validated self-hosting parse coverage for a class-heavy production header
(`AnnotationValidatorExtended.h`): class/method extraction, static helper
method recognition, validator-style cast-pattern helper checks, complexity
inference on parsed AST, and graceful degradation accounting.
**Files created:**
- `editor/tests/step402_test.cpp` — 12 tests covering:
1. parse real header file from disk
2. `AnnotationValidatorExtended` class capture
3. class method extraction
4. public `validate` signature capture
5. private helper method capture (`validateNode`, `validateAnnotation`)
6. static helper method parsing (`isPowerOf2`, `isOneOf`)
7. expected-structure 100% coverage
8. validator-style `static_cast` detection helper checks
9. complexity inference execution on parsed AST
10. static-helper class snippet parse stability
11. coverage report content checks
12. graceful degradation via opaque coverage accounting
**Files modified:**
- `editor/CMakeLists.txt``step402_test` target
**Verification run:**
- `step402_test` — PASS (12/12) new step coverage
- `step401_test` — PASS (12/12) regression coverage
- `step400_test` — PASS (12/12) regression coverage
**Architecture gate check:**
- `editor/tests/step402_test.cpp` within test-file size guidance (`239` lines)
- `editor/src/AnnotationValidatorExtended.h` within header-size limit (`349` <= `600`)
- `editor/src/SelfHostHarness.h` remains within header-size limit (`308` <= `600`)
- Legacy oversized headers persist:
- `editor/src/MCPServer.h` (`1679` > `600`)
- `editor/src/HeadlessAgentRPCHandler.h` (`2623` > `600`)
# Roadmap Planning — Sprints 12-25+
## Status: Planning Complete (Sprints 12-19 detailed, 20-25 in roadmap.md)