yams/tests/integration/cli/grep_path_tree_catch2_test.cpp

154 lines
6 KiB
C++

// Integration tests for grep --path-tree CLI flag
// Phase 3, Step 4: Tests for CLI integration
#include <catch2/catch_test_macros.hpp>
// removed: yams/app/cli.h (header no longer exists)
#include <filesystem>
#include <memory>
#include <sstream>
#include <string>
#include <yams/metadata/connection_pool.h>
#include <yams/metadata/metadata_repository.h>
#include <yams/metadata/migration.h>
using namespace yams;
using namespace yams::metadata;
struct GrepPathTreeIntegrationTest {
GrepPathTreeIntegrationTest() {
testDir_ = std::filesystem::temp_directory_path() / "yams_grep_path_tree_integration";
std::filesystem::create_directories(testDir_);
dbPath_ = testDir_ / "yams.db";
// Initialize repository with test data
ConnectionPoolConfig poolCfg;
poolCfg.minConnections = 1;
poolCfg.maxConnections = 2;
pool_ = std::make_unique<ConnectionPool>(dbPath_.string(), poolCfg);
auto initRes = pool_->initialize();
REQUIRE(initRes.has_value());
repository_ = std::make_shared<MetadataRepository>(*pool_);
// Run migrations
auto connRes = pool_->acquire();
REQUIRE(connRes.has_value());
auto& db = **connRes.value();
yams::metadata::MigrationManager mgr(db);
mgr.registerMigrations(yams::metadata::YamsMetadataMigrations::getAllMigrations());
auto initRes2 = mgr.initialize();
REQUIRE(initRes2.has_value());
auto migrate = mgr.migrate();
REQUIRE(migrate.has_value());
// Seed test data
seedTestDocuments();
}
~GrepPathTreeIntegrationTest() {
repository_.reset();
pool_.reset();
std::error_code ec;
std::filesystem::remove_all(testDir_, ec);
}
void seedTestDocuments() {
// Create documents with path tree structure
std::vector<std::tuple<std::string, std::string, std::vector<float>>> docs = {
{"/project/src/main.cpp", "HASH001", {1.0F, 2.0F, 3.0F}},
{"/project/src/utils.cpp", "HASH002", {1.5F, 2.5F, 3.5F}},
{"/project/tests/test_main.cpp", "HASH003", {5.0F, 6.0F, 7.0F}},
{"/project/docs/README.md", "HASH004", {9.0F, 10.0F, 11.0F}},
};
for (const auto& [path, hash, embedding] : docs) {
DocumentInfo doc;
doc.sha256Hash = hash;
doc.filePath = path;
doc.mimeType = "text/plain";
doc.fileSize = 100;
auto now = std::chrono::time_point_cast<std::chrono::seconds>(
std::chrono::system_clock::now());
doc.indexedTime = std::chrono::time_point_cast<std::chrono::seconds>(now);
doc.modifiedTime = std::chrono::time_point_cast<std::chrono::seconds>(now);
doc.createdTime = std::chrono::time_point_cast<std::chrono::seconds>(now);
auto insertRes = repository_->insertDocument(doc);
REQUIRE(insertRes.has_value());
doc.id = insertRes.value();
// Build path tree with embeddings
auto upsertRes = repository_->upsertPathTreeForDocument(
doc, doc.id, true, std::span<const float>(embedding.data(), embedding.size()));
REQUIRE(upsertRes.has_value());
}
}
std::filesystem::path testDir_;
std::filesystem::path dbPath_;
std::unique_ptr<ConnectionPool> pool_;
std::shared_ptr<MetadataRepository> repository_;
};
// TODO: These tests are stubs for Phase 3, Step 4
// Once grep_command.cpp is wired to call RetrievalService with PathTreeOptions,
// these tests will exercise the full CLI → Service → Repository flow
TEST_CASE_METHOD(GrepPathTreeIntegrationTest, "GrepWithPathTreeFlagParsesCorrectly",
"[integration][greppathtreeintegrationtest]") {
// This test verifies that the --path-tree flag is parsed without error
// Expected behavior: CLI should accept the flag and pass it to the service layer
// TODO: Once grep_command.cpp calls rsvc.grep(..., PathTreeOptions{...}),
// this test should verify that PathTreeOptions.enabled = true when flag is set
SKIP("CLI wiring pending - Phase 3, Step 3");
}
TEST_CASE_METHOD(GrepPathTreeIntegrationTest, "GrepPathTreeReturnsChildNodes",
"[integration][greppathtreeintegrationtest]") {
// Test: yams grep --path-tree --paths "/project/src" should return child nodes
// Expected: main.cpp and utils.cpp (2 docs under /project/src)
// TODO: Implement once service layer returns synthetic matches with matchType="path_tree"
SKIP("Service implementation pending");
}
TEST_CASE_METHOD(GrepPathTreeIntegrationTest, "GrepPathTreeShowsDocCounts",
"[integration][greppathtreeintegrationtest]") {
// Test: Path-tree results should include doc counts in output
// Expected: Each child node shows its doc_count
SKIP("Service implementation pending");
}
TEST_CASE_METHOD(GrepPathTreeIntegrationTest, "GrepPathTreeFallbackModeWorks",
"[integration][greppathtreeintegrationtest]") {
// Test: --path-tree mode=fallback should try path-tree first, fallback to normal grep
// Expected: If path-tree query returns empty, normal grep runs
SKIP("Service implementation pending");
}
TEST_CASE_METHOD(GrepPathTreeIntegrationTest, "GrepPathTreePreferredModeSkipsFallback",
"[integration][greppathtreeintegrationtest]") {
// Test: --path-tree mode=preferred should only use path-tree, no fallback
// Expected: If path-tree returns empty, command returns empty (no normal grep)
SKIP("Service implementation pending");
}
TEST_CASE_METHOD(GrepPathTreeIntegrationTest, "GrepPathTreeLimitsChildren",
"[integration][greppathtreeintegrationtest]") {
// Test: childLimit parameter should cap number of children returned
// Expected: Only top N children by doc_count
SKIP("Service implementation pending");
}
// NOTE: To run these tests when Phase 3 is complete:
// 1. Remove GTEST_SKIP() calls
// 2. Add actual CLI invocation or service calls
// 3. Verify output format matches expected synthetic GrepResponse structure