Files
whetstone_DSL/editor/tests/step1970_test.cpp
Bill a410c9c756 Sprint 288: LibrarySymbolAdvisor (steps 1968-1972)
Specific API symbol recommendation layer. Five new headers:
- LibrarySymbolRecord: functionName/signature/usagePattern/caveats
- LibrarySymbolCatalog: multi-symbol registry per (library, domain)
- LSPSymbolExtractor: parses LSP JSON into LibrarySymbolRecords
- LibrarySymbolAdvisor: ranked symbols for (library, domain) alphabetically
- Sprint288IntegrationSummary: CUDA+nlohmann catalog; cublasSgemm+json::parse verified

25/25 tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 10:11:23 -07:00

98 lines
3.6 KiB
C++

// Step 1970: LSPSymbolExtractor
//
// t1: parses valid JSON into correct records
// t2: functionName and signature populated from JSON
// t3: caveats array parsed correctly
// t4: returns error for invalid JSON
// t5: empty symbols array produces empty records; missing name skipped
#include "LSPSymbolExtractor.h"
#include <iostream>
#include <string>
namespace ws = whetstone;
static int p = 0, f = 0;
#define T(n) { std::cout << " " << #n << "... "; }
#define P() { std::cout << "PASS\n"; ++p; }
#define F(m) { std::cout << "FAIL: " << m << "\n"; ++f; }
#define C(c, m) if (!(c)) { F(m); return; }
// Use named delimiter to avoid R"(...)"-terminator collision with JSON content.
static const std::string CUBLAS_JSON = R"JSON({
"symbols": [
{"name": "cublasSgemm", "signature": "cublasStatus_t cublasSgemm(...)", "usage": "cublasSgemm(handle, ...)"},
{"name": "cublasDgemm", "signature": "cublasStatus_t cublasDgemm(...)"}
]
})JSON";
void t1() {
T(parses_valid_json_into_records);
ws::LSPSymbolExtractor ex;
auto res = ex.extract("cublas", "compute.matrix", CUBLAS_JSON);
C(res.success, "success");
C(res.error.empty(), "no error");
C(res.records.size() == 2, "2 records parsed");
C(res.records[0].libraryId == "cublas", "libraryId set");
C(res.records[0].operationDomain == "compute.matrix", "domain set");
P();
}
void t2() {
T(functionName_and_signature_populated);
ws::LSPSymbolExtractor ex;
auto res = ex.extract("cublas", "compute.matrix", CUBLAS_JSON);
C(res.records[0].functionName == "cublasSgemm", "first functionName");
C(res.records[0].signature.find("cublasSgemm") != std::string::npos, "first signature");
C(res.records[0].usagePattern.find("handle") != std::string::npos, "usagePattern");
C(res.records[1].functionName == "cublasDgemm", "second functionName");
P();
}
void t3() {
T(caveats_array_parsed);
const std::string json = R"JSON({"symbols": [
{"name": "myFunc", "signature": "void myFunc()",
"caveats": ["must-call-init-first", "not-thread-safe"]}
]})JSON";
ws::LSPSymbolExtractor ex;
auto res = ex.extract("mylib", "mydom", json);
C(res.success, "success");
C(res.records.size() == 1, "1 record");
C(res.records[0].caveats.size() == 2, "2 caveats");
C(res.records[0].caveats[0] == "must-call-init-first", "first caveat");
P();
}
void t4() {
T(returns_error_for_invalid_json);
ws::LSPSymbolExtractor ex;
auto res = ex.extract("lib", "dom", "{ not valid json !!!");
C(!res.success, "failure for invalid json");
C(!res.error.empty(), "error message set");
C(res.records.empty(), "no records on error");
// Missing symbols key
auto res2 = ex.extract("lib", "dom", R"JSON({"other": []})JSON");
C(!res2.success, "failure for missing symbols key");
P();
}
void t5() {
T(empty_symbols_and_missing_name_skipped);
ws::LSPSymbolExtractor ex;
auto res = ex.extract("lib", "dom", R"JSON({"symbols": []})JSON");
C(res.success, "success for empty array");
C(res.records.empty(), "no records for empty array");
// Symbol with empty name skipped
auto res2 = ex.extract("lib", "dom", R"JSON({"symbols": [{"name": "", "signature": "sig"}]})JSON");
C(res2.success, "success");
C(res2.records.empty(), "empty-name record skipped");
P();
}
int main() {
std::cout << "Step 1970: LSPSymbolExtractor\n";
t1(); t2(); t3(); t4(); t5();
std::cout << "\n" << p << "/" << (p + f) << " passed\n";
return f > 0 ? 1 : 0;
}