Sprint 42-45: stabilize modeling tools and implement context, validation, and metrics MCP tooling (Steps 669-688)
This commit is contained in:
203
editor/tests/step675_test.cpp
Normal file
203
editor/tests/step675_test.cpp
Normal file
@@ -0,0 +1,203 @@
|
||||
// Step 675: ContextSliceAssembler (12 tests)
|
||||
|
||||
#include "ContextSliceAssembler.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
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; }
|
||||
|
||||
static fs::path makeTempDir(const std::string& suffix) {
|
||||
fs::path dir = fs::temp_directory_path() / ("whetstone_step675_" + suffix);
|
||||
std::error_code ec;
|
||||
fs::remove_all(dir, ec);
|
||||
fs::create_directories(dir, ec);
|
||||
return dir;
|
||||
}
|
||||
|
||||
static void writeFile(const fs::path& p, const std::string& content) {
|
||||
std::error_code ec;
|
||||
fs::create_directories(p.parent_path(), ec);
|
||||
std::ofstream out(p);
|
||||
out << content;
|
||||
}
|
||||
|
||||
static std::string sourceText() {
|
||||
return "int alpha() {\n"
|
||||
" return 1;\n"
|
||||
"}\n"
|
||||
"class Demo {\n"
|
||||
"public:\n"
|
||||
" void run() {}\n"
|
||||
"};\n"
|
||||
"int beta() {\n"
|
||||
" return 2;\n"
|
||||
"}\n";
|
||||
}
|
||||
|
||||
void t1() {
|
||||
TEST(empty_requests_returns_empty_result);
|
||||
WorkspaceFileIndex idx;
|
||||
auto out = ContextSliceAssembler::assemble({}, idx);
|
||||
CHECK(out.empty(), "expected empty");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t2() {
|
||||
TEST(named_symbol_found_returns_correct_lines);
|
||||
auto dir = makeTempDir("t2");
|
||||
auto f = dir / "demo.cpp";
|
||||
writeFile(f, sourceText());
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
SliceRequest req{f.string(), "alpha", 0, 40};
|
||||
auto out = ContextSliceAssembler::assemble({req}, idx);
|
||||
CHECK(out.size() == 1, "expected one slice");
|
||||
CHECK(out[0].found, "symbol should be found");
|
||||
CHECK(out[0].content.find("int alpha()") != std::string::npos, "missing alpha");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t3() {
|
||||
TEST(unknown_symbol_returns_head_fallback);
|
||||
auto dir = makeTempDir("t3");
|
||||
auto f = dir / "demo.cpp";
|
||||
writeFile(f, sourceText());
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
auto out = ContextSliceAssembler::assemble({{f.string(), "missing_symbol", 0, 2}}, idx);
|
||||
CHECK(out.size() == 1, "expected one slice");
|
||||
CHECK(!out[0].found, "found should be false");
|
||||
CHECK(out[0].content.find("int alpha()") != std::string::npos, "fallback head missing");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t4() {
|
||||
TEST(line_range_returns_correct_lines);
|
||||
auto dir = makeTempDir("t4");
|
||||
auto f = dir / "demo.cpp";
|
||||
writeFile(f, sourceText());
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
auto out = ContextSliceAssembler::assemble({{f.string(), "", 2, 2}}, idx);
|
||||
CHECK(out.size() == 1, "expected one slice");
|
||||
CHECK(out[0].lineStart == 2 && out[0].lineEnd == 3, "line range mismatch");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t5() {
|
||||
TEST(content_non_empty_on_success);
|
||||
auto dir = makeTempDir("t5");
|
||||
auto f = dir / "demo.cpp";
|
||||
writeFile(f, sourceText());
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
auto out = ContextSliceAssembler::assemble({{f.string(), "beta", 0, 40}}, idx);
|
||||
CHECK(!out.empty(), "slice missing");
|
||||
CHECK(!out[0].content.empty(), "content empty");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t6() {
|
||||
TEST(found_false_when_symbol_missing);
|
||||
auto dir = makeTempDir("t6");
|
||||
auto f = dir / "demo.cpp";
|
||||
writeFile(f, sourceText());
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
auto out = ContextSliceAssembler::assemble({{f.string(), "zzz", 0, 1}}, idx);
|
||||
CHECK(out.size() == 1, "slice missing");
|
||||
CHECK(!out[0].found, "should be false");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t7() {
|
||||
TEST(multiple_requests_all_processed);
|
||||
auto dir = makeTempDir("t7");
|
||||
auto f = dir / "demo.cpp";
|
||||
writeFile(f, sourceText());
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
std::vector<SliceRequest> reqs = {
|
||||
{f.string(), "alpha", 0, 40},
|
||||
{f.string(), "beta", 0, 40},
|
||||
{f.string(), "", 1, 1}
|
||||
};
|
||||
auto out = ContextSliceAssembler::assemble(reqs, idx);
|
||||
CHECK(out.size() == 3, "expected 3 slices");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t8() {
|
||||
TEST(head_fallback_respects_head_lines);
|
||||
auto dir = makeTempDir("t8");
|
||||
auto f = dir / "demo.cpp";
|
||||
writeFile(f, sourceText());
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
auto out = ContextSliceAssembler::assemble({{f.string(), "none", 0, 1}}, idx);
|
||||
CHECK(out.size() == 1, "slice missing");
|
||||
CHECK(out[0].lineEnd == 1, "headLines not respected");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t9() {
|
||||
TEST(function_body_slice_includes_closing_brace);
|
||||
auto dir = makeTempDir("t9");
|
||||
auto f = dir / "demo.cpp";
|
||||
writeFile(f, sourceText());
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
auto out = ContextSliceAssembler::assemble({{f.string(), "alpha", 0, 40}}, idx);
|
||||
CHECK(out.size() == 1, "slice missing");
|
||||
CHECK(out[0].content.find("}") != std::string::npos, "closing brace not included");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t10() {
|
||||
TEST(class_slice_includes_closing_brace);
|
||||
auto dir = makeTempDir("t10");
|
||||
auto f = dir / "demo.cpp";
|
||||
writeFile(f, sourceText());
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
auto out = ContextSliceAssembler::assemble({{f.string(), "Demo", 0, 40}}, idx);
|
||||
CHECK(out.size() == 1, "slice missing");
|
||||
CHECK(out[0].content.find("};") != std::string::npos, "class close not included");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t11() {
|
||||
TEST(file_path_preserved_in_result);
|
||||
auto dir = makeTempDir("t11");
|
||||
auto f = dir / "demo.cpp";
|
||||
writeFile(f, sourceText());
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
auto out = ContextSliceAssembler::assemble({{f.string(), "alpha", 0, 40}}, idx);
|
||||
CHECK(out.size() == 1, "slice missing");
|
||||
CHECK(out[0].filePath == f.string(), "path not preserved");
|
||||
PASS();
|
||||
}
|
||||
|
||||
void t12() {
|
||||
TEST(slice_content_is_substring_of_source);
|
||||
auto dir = makeTempDir("t12");
|
||||
auto f = dir / "demo.cpp";
|
||||
const std::string src = sourceText();
|
||||
writeFile(f, src);
|
||||
auto idx = WorkspaceFileIndex::build(dir.string());
|
||||
auto out = ContextSliceAssembler::assemble({{f.string(), "beta", 0, 40}}, idx);
|
||||
CHECK(out.size() == 1, "slice missing");
|
||||
CHECK(src.find(out[0].content.substr(0, std::min<size_t>(10, out[0].content.size()))) != std::string::npos,
|
||||
"slice content not from source");
|
||||
PASS();
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::cout << "Step 675: ContextSliceAssembler\n";
|
||||
t1(); t2(); t3(); t4(); t5(); t6();
|
||||
t7(); t8(); t9(); t10(); t11(); t12();
|
||||
std::cout << "\nResults: " << passed << "/" << (passed + failed) << " passed\n";
|
||||
return failed == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user