#include #include #include #include #include #include #include #include #include #include #include #include "../../common/test_helpers_catch2.h" using namespace yams::vector; using Catch::Matchers::StartsWith; namespace { EmbeddingConfig make_cfg(size_t dim = 256) { EmbeddingConfig cfg; cfg.backend = EmbeddingConfig::Backend::Simeon; cfg.backend_is_resolved = true; cfg.embedding_dim = dim; cfg.normalize_embeddings = true; cfg.max_sequence_length = 512; return cfg; } } // namespace TEST_CASE("SimeonBackend initializes and reports its dimension", "[vector][simeon]") { auto backend = makeSimeonBackend(make_cfg(384)); REQUIRE(backend != nullptr); REQUIRE(backend->isAvailable()); REQUIRE(backend->initialize()); REQUIRE(backend->isInitialized()); REQUIRE(backend->getEmbeddingDimension() == 384u); REQUIRE(backend->getBackendName() == "Simeon"); } TEST_CASE("SimeonBackend fixed hash profile exposes the frozen retrieval space", "[vector][simeon][identity]") { auto cfg = make_cfg(1024); cfg.simeon_encoder_profile = EmbeddingConfig::SimeonEncoderProfile::FixedHash384; auto backend = makeSimeonBackend(cfg); REQUIRE(backend != nullptr); REQUIRE(backend->initialize()); CHECK(backend->getEmbeddingDimension() == 384u); CHECK(backend->getEmbeddingSpaceIdentity() == "simeon-v1-384"); CHECK(simeonEmbeddingSpaceIdentity(cfg) == "simeon-v1-384"); } TEST_CASE("SimeonBackend produces deterministic, unit-norm embeddings", "[vector][simeon]") { auto backend = makeSimeonBackend(make_cfg(256)); REQUIRE(backend->initialize()); const std::string text = "The quick brown fox jumps over the lazy dog."; auto r1 = backend->generateEmbedding(text); auto r2 = backend->generateEmbedding(text); REQUIRE(r1); REQUIRE(r2); REQUIRE(r1.value().size() == 256u); REQUIRE(r1.value() == r2.value()); double acc = 0.0; for (float f : r1.value()) acc += static_cast(f) * static_cast(f); REQUIRE(std::fabs(std::sqrt(acc) - 1.0) < 1e-4); } TEST_CASE("SimeonBackend batch matches per-item encoding", "[vector][simeon]") { auto backend = makeSimeonBackend(make_cfg(128)); REQUIRE(backend->initialize()); const std::vector texts = {"alpha bravo charlie", "delta echo foxtrot", "golf hotel india"}; auto per = std::vector>{}; for (const auto& t : texts) { auto r = backend->generateEmbedding(t); REQUIRE(r); per.push_back(std::move(r).value()); } auto batch = backend->generateEmbeddings(std::span(texts)); REQUIRE(batch); REQUIRE(batch.value().size() == per.size()); for (size_t i = 0; i < per.size(); ++i) { REQUIRE(batch.value()[i] == per[i]); } } TEST_CASE("EmbeddingGenerator trusts typed backend over ambient environment", "[vector][simeon][config]") { yams::test::ScopedEnvVar backend{"YAMS_EMBED_BACKEND", std::string{"daemon"}}; EmbeddingConfig cfg; cfg.backend = EmbeddingConfig::Backend::Simeon; cfg.embedding_dim = 384; cfg.normalize_embeddings = true; EmbeddingGenerator gen(cfg); REQUIRE(gen.initialize()); REQUIRE(gen.getBackendName() == "Simeon"); REQUIRE(gen.getEmbeddingDimension() == 384u); auto v = gen.generateEmbedding("hello world"); REQUIRE(v.size() == 384u); } TEST_CASE("EmbeddingGenerator selects Simeon when configured directly", "[vector][simeon]") { EmbeddingConfig cfg; cfg.backend = EmbeddingConfig::Backend::Simeon; cfg.backend_is_resolved = true; cfg.embedding_dim = 128; cfg.normalize_embeddings = true; EmbeddingGenerator gen(cfg); REQUIRE(gen.initialize()); REQUIRE(gen.getBackendName() == "Simeon"); REQUIRE(gen.getEmbeddingDimension() == 128u); } TEST_CASE("EmbeddingGenerator moved-from observers report neutral state", "[vector][embedding-generator][move][catch2]") { EmbeddingGenerator source(make_cfg(128)); EmbeddingGenerator destination(std::move(source)); CHECK_FALSE(source.isInitialized()); CHECK((source.estimateTokenCount("moved-from") == 0)); CHECK((source.getLastError().empty())); CHECK_FALSE(source.hasError()); CHECK((destination.getConfig().embedding_dim == 128)); } TEST_CASE("EmbeddingGenerator maps OnnxRuntime config to Daemon path", "[vector][daemon]") { EmbeddingConfig cfg; cfg.backend = EmbeddingConfig::Backend::OnnxRuntime; cfg.backend_is_resolved = true; EmbeddingGenerator gen(cfg); REQUIRE_THAT(gen.getBackendName(), StartsWith("Daemon")); } TEST_CASE("EmbeddingGenerator maps legacy Hybrid config to Daemon path", "[vector][daemon]") { EmbeddingConfig cfg; cfg.backend = EmbeddingConfig::Backend::Hybrid; cfg.backend_is_resolved = true; EmbeddingGenerator gen(cfg); REQUIRE_THAT(gen.getBackendName(), StartsWith("Daemon")); } TEST_CASE("EmbeddingGenerator selects Daemon when configured directly", "[vector][daemon]") { EmbeddingConfig cfg; cfg.backend = EmbeddingConfig::Backend::Daemon; cfg.backend_is_resolved = true; EmbeddingGenerator gen(cfg); REQUIRE_THAT(gen.getBackendName(), StartsWith("Daemon")); }