145 lines
5.5 KiB
C++
145 lines
5.5 KiB
C++
|
|
// Step 536: Argument Shape Validator (12 tests)
|
||
|
|
|
||
|
|
#include "ArgumentShapeValidator.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-536";
|
||
|
|
c.nodeId = "n-1";
|
||
|
|
c.language = "cpp";
|
||
|
|
c.allowedTargets = {"Function"};
|
||
|
|
c.allowedOps = {"rename", "update", "insert", "extract", "delete"};
|
||
|
|
c.allowedSymbols = {"cursor", "count", "render"};
|
||
|
|
c.forbiddenSymbols = {"unsafeGlobal"};
|
||
|
|
c.expectedDiagnosticsAdd = {"none"};
|
||
|
|
return c;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool hasError(const ArgumentShapeResult& r, const std::string& codePrefix) {
|
||
|
|
for (const auto& e : r.errors) {
|
||
|
|
if (e.find(codePrefix) == 0) return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_valid_rename_args_pass() {
|
||
|
|
TEST(valid_rename_args_pass);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "rename", "cursor",
|
||
|
|
json{{"newName", "cursor2"}});
|
||
|
|
CHECK(r.valid, "valid rename should pass");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_rename_missing_new_name_fails() {
|
||
|
|
TEST(rename_missing_new_name_fails);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "rename", "cursor", json::object());
|
||
|
|
CHECK(hasError(r, "missing_or_invalid_string:newName"), "newName error expected");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_rename_noop_fails() {
|
||
|
|
TEST(rename_noop_fails);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "rename", "cursor",
|
||
|
|
json{{"newName", "cursor"}});
|
||
|
|
CHECK(hasError(r, "rename_noop"), "rename noop should fail");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_update_requires_replacement() {
|
||
|
|
TEST(update_requires_replacement);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "update", "cursor", json::object());
|
||
|
|
CHECK(hasError(r, "missing_or_invalid_string:replacement"), "replacement error expected");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_insert_requires_position_and_insert_text() {
|
||
|
|
TEST(insert_requires_position_and_insert_text);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "insert", "cursor",
|
||
|
|
json{{"insertText", "x"}});
|
||
|
|
CHECK(hasError(r, "missing_or_invalid_string:position"), "position required");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_insert_rejects_invalid_position_enum() {
|
||
|
|
TEST(insert_rejects_invalid_position_enum);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "insert", "cursor",
|
||
|
|
json{{"insertText", "x"}, {"position", "middle"}});
|
||
|
|
CHECK(hasError(r, "invalid_enum:position"), "invalid position enum expected");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_extract_requires_target_and_mode() {
|
||
|
|
TEST(extract_requires_target_and_mode);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "extract", "cursor", json::object());
|
||
|
|
CHECK(hasError(r, "missing_or_invalid_string:target"), "target required");
|
||
|
|
CHECK(hasError(r, "missing_or_invalid_string:mode"), "mode required");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_extract_rejects_invalid_mode() {
|
||
|
|
TEST(extract_rejects_invalid_mode);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "extract", "cursor",
|
||
|
|
json{{"target", "tmp"}, {"mode", "lambda"}});
|
||
|
|
CHECK(hasError(r, "invalid_enum:mode"), "invalid mode expected");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_delete_requires_confirm_bool() {
|
||
|
|
TEST(delete_requires_confirm_bool);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "delete", "cursor", json::object());
|
||
|
|
CHECK(hasError(r, "missing_or_invalid_boolean:confirm"), "confirm required");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_disallowed_operation_fails() {
|
||
|
|
TEST(disallowed_operation_fails);
|
||
|
|
auto c = contract();
|
||
|
|
c.allowedOps = {"rename"};
|
||
|
|
auto r = ArgumentShapeValidator::validate(c, "delete", "cursor", json{{"confirm", true}});
|
||
|
|
CHECK(hasError(r, "op_not_allowed:delete"), "disallowed op should fail");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_disallowed_symbol_fails() {
|
||
|
|
TEST(disallowed_symbol_fails);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "rename", "ghost",
|
||
|
|
json{{"newName", "ghost2"}});
|
||
|
|
CHECK(hasError(r, "symbol_not_allowed:ghost"), "disallowed symbol should fail");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
void test_args_must_be_object() {
|
||
|
|
TEST(args_must_be_object);
|
||
|
|
auto r = ArgumentShapeValidator::validate(contract(), "rename", "cursor", json::array());
|
||
|
|
CHECK(hasError(r, "args_not_object"), "args object requirement expected");
|
||
|
|
PASS();
|
||
|
|
}
|
||
|
|
|
||
|
|
int main() {
|
||
|
|
std::cout << "Step 536: Argument Shape Validator\n";
|
||
|
|
|
||
|
|
test_valid_rename_args_pass(); // 1
|
||
|
|
test_rename_missing_new_name_fails(); // 2
|
||
|
|
test_rename_noop_fails(); // 3
|
||
|
|
test_update_requires_replacement(); // 4
|
||
|
|
test_insert_requires_position_and_insert_text(); // 5
|
||
|
|
test_insert_rejects_invalid_position_enum(); // 6
|
||
|
|
test_extract_requires_target_and_mode(); // 7
|
||
|
|
test_extract_rejects_invalid_mode(); // 8
|
||
|
|
test_delete_requires_confirm_bool(); // 9
|
||
|
|
test_disallowed_operation_fails(); // 10
|
||
|
|
test_disallowed_symbol_fails(); // 11
|
||
|
|
test_args_must_be_object(); // 12
|
||
|
|
|
||
|
|
std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n";
|
||
|
|
return failed == 0 ? 0 : 1;
|
||
|
|
}
|