Files
whetstone_DSL/editor/tests/step535_test.cpp

164 lines
5.7 KiB
C++

// Step 535: Symbol Selector API (12 tests)
#include "SymbolSelectorAPI.h"
#include <iostream>
static int passed = 0, failed = 0;
#define TEST(name) { std::cout << " " << #name << "... "; }
#define PASS() { std::cout << "PASS\n"; ++passed; }
#define FAIL(msg) { std::cout << "FAIL: " << msg << "\n"; ++failed; }
#define CHECK(cond, msg) if (!(cond)) { FAIL(msg); return; } else {}
static TaskitemContract contract() {
TaskitemContract c;
c.id = "ti-535";
c.nodeId = "n-1";
c.language = "cpp";
c.allowedTargets = {"Function"};
c.allowedOps = {"rename"};
c.allowedSymbols = {"render", "EditorState", "value", "MAX_COUNT", "std", "fieldA"};
c.forbiddenSymbols = {"unsafeGlobal"};
c.expectedDiagnosticsAdd = {"none"};
return c;
}
static ScopeSnapshot richScope() {
ScopeSnapshot s;
s.supported = true;
s.candidates = {
{"render", "Function", 2},
{"EditorState", "Type", 0},
{"value", "Variable", 3},
{"MAX_COUNT", "Constant", 0},
{"std", "Namespace", 0},
{"fieldA", "Field", 2},
{"unsafeGlobal", "Variable", 0}
};
return s;
}
void test_supported_scope_returns_candidates() {
TEST(supported_scope_returns_candidates);
auto r = SymbolSelectorAPI::select(contract(), richScope());
CHECK(r.supported, "scope should be supported");
CHECK(!r.candidates.empty(), "candidates expected");
PASS();
}
void test_unsupported_scope_returns_not_supported() {
TEST(unsupported_scope_returns_not_supported);
ScopeSnapshot s;
s.supported = false;
auto r = SymbolSelectorAPI::select(contract(), s);
CHECK(!r.supported, "unsupported scope expected");
CHECK(r.candidates.empty(), "no candidates expected");
PASS();
}
void test_forbidden_symbols_are_not_returned() {
TEST(forbidden_symbols_are_not_returned);
auto r = SymbolSelectorAPI::select(contract(), richScope());
for (const auto& c : r.candidates) {
CHECK(c.name != "unsafeGlobal", "forbidden symbol should be excluded");
}
PASS();
}
void test_contract_allowed_symbols_only() {
TEST(contract_allowed_symbols_only);
auto c = contract();
c.allowedSymbols = {"render"};
auto r = SymbolSelectorAPI::select(c, richScope());
CHECK(r.candidates.size() == 1, "only one symbol should remain");
CHECK(r.candidates[0].name == "render", "render should remain");
PASS();
}
void test_function_category_filter() {
TEST(function_category_filter);
auto r = SymbolSelectorAPI::select(contract(), richScope(), {"function"});
CHECK(r.candidates.size() == 1, "one function expected");
CHECK(r.candidates[0].name == "render", "render should match function category");
PASS();
}
void test_type_category_filter() {
TEST(type_category_filter);
auto r = SymbolSelectorAPI::select(contract(), richScope(), {"type"});
CHECK(r.candidates.size() == 1, "one type expected");
CHECK(r.candidates[0].name == "EditorState", "type category mismatch");
PASS();
}
void test_field_category_filter() {
TEST(field_category_filter);
auto r = SymbolSelectorAPI::select(contract(), richScope(), {"field"});
CHECK(r.candidates.size() == 1, "one field expected");
CHECK(r.candidates[0].name == "fieldA", "field category mismatch");
PASS();
}
void test_module_category_filter() {
TEST(module_category_filter);
auto r = SymbolSelectorAPI::select(contract(), richScope(), {"module"});
CHECK(r.candidates.size() == 1, "one module expected");
CHECK(r.candidates[0].name == "std", "module category mismatch");
PASS();
}
void test_constant_category_filter() {
TEST(constant_category_filter);
auto r = SymbolSelectorAPI::select(contract(), richScope(), {"constant"});
CHECK(r.candidates.size() == 1, "one constant expected");
CHECK(r.candidates[0].name == "MAX_COUNT", "constant category mismatch");
PASS();
}
void test_multiple_category_filter() {
TEST(multiple_category_filter);
auto r = SymbolSelectorAPI::select(contract(), richScope(), {"function", "type"});
CHECK(r.candidates.size() == 2, "two category matches expected");
PASS();
}
void test_candidates_sorted_by_scope_depth_then_name() {
TEST(candidates_sorted_by_scope_depth_then_name);
auto r = SymbolSelectorAPI::select(contract(), richScope());
CHECK(r.candidates.size() >= 2, "at least two candidates required");
CHECK(r.candidates[0].scopeDepth >= r.candidates[1].scopeDepth,
"depth sort expected");
PASS();
}
void test_duplicate_symbol_names_are_deduped() {
TEST(duplicate_symbol_names_are_deduped);
auto s = richScope();
s.candidates.push_back({"value", "Variable", 1});
auto r = SymbolSelectorAPI::select(contract(), s);
int count = 0;
for (const auto& c : r.candidates) if (c.name == "value") ++count;
CHECK(count == 1, "duplicate symbol names should dedupe");
PASS();
}
int main() {
std::cout << "Step 535: Symbol Selector API\n";
test_supported_scope_returns_candidates(); // 1
test_unsupported_scope_returns_not_supported(); // 2
test_forbidden_symbols_are_not_returned(); // 3
test_contract_allowed_symbols_only(); // 4
test_function_category_filter(); // 5
test_type_category_filter(); // 6
test_field_category_filter(); // 7
test_module_category_filter(); // 8
test_constant_category_filter(); // 9
test_multiple_category_filter(); // 10
test_candidates_sorted_by_scope_depth_then_name(); // 11
test_duplicate_symbol_names_are_deduped(); // 12
std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n";
return failed == 0 ? 0 : 1;
}