Skip to content

elm/test_elm.cpp

Unit tests for Phase 7 ELM classes. More...

Functions

Name
TEST(RoleELM , Process_LoadedEngine_ReturnsResponse )
TEST(RoleELM , Process_NotLoaded_ReturnsError )
TEST(RoleELM , GetName_ReturnsCorrectName )
TEST(RoleELM , GetRole_ReturnsConfiguredRole )
TEST(RoleELM , IsLoaded_InitiallyFalse )
TEST(RoleELM , Process_NullEngine_ReturnsError )
TEST(DomainELM , Process_SharedBackbone_ReturnsResponse )
TEST(DomainELM , Process_NoEngine_ReturnsError )
TEST(DomainELM , GetRole_ReturnsConfiguredRole )
TEST(DomainELM , IsLoaded_InitiallyFalse )
TEST(DomainELM , GetName_ReturnsCorrectName )
TEST(DomainELM , Load_EmptyPath_UsesSharedEngine )
TEST(SpecialistAdapter , Process_DelegatesToSpecialist )
TEST(SpecialistAdapter , GetConfidence_ReflectsSpecialist )
TEST(ELMChainBuilder , Build_HighNumericDensity_ReturnsMathChain )
TEST(ELMChainBuilder , Build_CodeSyntax_ReturnsPlannerCodeChain )
TEST(ELMChainBuilder , Build_LowComplexity_ReturnsSingleStep )
TEST(ELMChainBuilder , Build_HighComplexity_ReturnsFullChain )
TEST(ELMChainBuilder , Build_Default_ReturnsPrimaryDraft )
TEST(GroundingELM , Process_KnowledgeLoaded_ReturnsAugmentedOutput )
TEST(ToolSupportELM , Process_ReturnsInputUnchanged_ConfidenceZero )
TEST(ToolSupportELM , IsLoaded_AlwaysFalse )

Detailed Description

Unit tests for Phase 7 ELM classes.

Date: 2026-07-16

Functions Documentation

function TEST

TEST(
    RoleELM ,
    Process_LoadedEngine_ReturnsResponse 
)

function TEST

TEST(
    RoleELM ,
    Process_NotLoaded_ReturnsError 
)

function TEST

TEST(
    RoleELM ,
    GetName_ReturnsCorrectName 
)

function TEST

TEST(
    RoleELM ,
    GetRole_ReturnsConfiguredRole 
)

function TEST

TEST(
    RoleELM ,
    IsLoaded_InitiallyFalse 
)

function TEST

TEST(
    RoleELM ,
    Process_NullEngine_ReturnsError 
)

function TEST

TEST(
    DomainELM ,
    Process_SharedBackbone_ReturnsResponse 
)

function TEST

TEST(
    DomainELM ,
    Process_NoEngine_ReturnsError 
)

function TEST

TEST(
    DomainELM ,
    GetRole_ReturnsConfiguredRole 
)

function TEST

TEST(
    DomainELM ,
    IsLoaded_InitiallyFalse 
)

function TEST

TEST(
    DomainELM ,
    GetName_ReturnsCorrectName 
)

function TEST

TEST(
    DomainELM ,
    Load_EmptyPath_UsesSharedEngine 
)

function TEST

TEST(
    SpecialistAdapter ,
    Process_DelegatesToSpecialist 
)

function TEST

TEST(
    SpecialistAdapter ,
    GetConfidence_ReflectsSpecialist 
)

function TEST

TEST(
    ELMChainBuilder ,
    Build_HighNumericDensity_ReturnsMathChain 
)

function TEST

TEST(
    ELMChainBuilder ,
    Build_CodeSyntax_ReturnsPlannerCodeChain 
)

function TEST

TEST(
    ELMChainBuilder ,
    Build_LowComplexity_ReturnsSingleStep 
)

function TEST

TEST(
    ELMChainBuilder ,
    Build_HighComplexity_ReturnsFullChain 
)

function TEST

TEST(
    ELMChainBuilder ,
    Build_Default_ReturnsPrimaryDraft 
)

function TEST

TEST(
    GroundingELM ,
    Process_KnowledgeLoaded_ReturnsAugmentedOutput 
)

function TEST

TEST(
    ToolSupportELM ,
    Process_ReturnsInputUnchanged_ConfidenceZero 
)

function TEST

TEST(
    ToolSupportELM ,
    IsLoaded_AlwaysFalse 
)

Source code

#include "elm/role_elm.hpp"
#include "elm/domain_elm.hpp"
#include "elm/specialist_adapter.hpp"
#include "elm/grounding_elm.hpp"
#include "elm/tool_support_elm.hpp"
#include "elm/elm_chain_builder.hpp"
#include "core/engine/inference_engine.hpp"
#include "specialists/i_specialist.hpp"
#include "knowledge/knowledge_retrieval.hpp"
#include "knowledge/context_injection.hpp"
#include "knowledge/fact_validation.hpp"
#include <gtest/gtest.h>
#include <functional>
#include <memory>
#include <string>

using namespace sgns::neoswarm;

// -----------------------------------------------------------------------
// Mock inference engine — returns prompt + "[response]" with perplexity=1.0
// (verbatim copy of mock pattern from test/specialists/test_grammar_specialist.cpp)
// -----------------------------------------------------------------------
namespace
{
    class MockEngine : public core::InferenceEngine
    {
        public:
        outcome::result<InferenceResponse> Infer( const Task& task ) override
        {
            InferenceResponse resp;
            resp.m_output = task.m_prompt + " [response]";
            resp.m_perplexity = 1.0f;
            resp.m_success = true;
            resp.m_taskId = task.m_id;
            return outcome::success( resp );
        }

        outcome::result<void> StreamInfer( const Task&,
                                            std::function<void( const std::string& )> ) override
        {
            return outcome::success();
        }

        outcome::result<void> LoadModel( const std::string& ) override
        {
            return outcome::success();
        }

        bool IsLoaded() const override
        {
            return true;
        }

        std::string BackendName() const override
        {
            return "mock";
        }
    };

    class FailingMockEngine : public core::InferenceEngine
    {
        public:
        outcome::result<InferenceResponse> Infer( const Task& ) override
        {
            return outcome::failure( Error::InferenceFailed );
        }
        outcome::result<void> StreamInfer( const Task&,
                                            std::function<void( const std::string& )> ) override
        {
            return outcome::failure( Error::InferenceFailed );
        }
        outcome::result<void> LoadModel( const std::string& ) override
        {
            return outcome::failure( Error::ModelLoadFailed );
        }
        bool IsLoaded() const override
        {
            return false;
        }
        std::string BackendName() const override
        {
            return "mock";
        }
    };

    class MockSpecialist : public specialists::ISpecialist
    {
        public:
        std::string GetName() const override
        {
            return "MockSpecialist";
        }
        bool IsLoaded() const override
        {
            return m_loaded;
        }
        outcome::result<void> Load( const std::string& ) override
        {
            m_loaded = true;
            return outcome::success();
        }
        outcome::result<std::string> Process( const std::string& input ) override
        {
            m_lastConf = 0.9f;
            return outcome::success( input + " [specialized]" );
        }
        float GetConfidence() const override
        {
            return m_lastConf;
        }

        private:
        bool m_loaded = false;
        float m_lastConf = 0.0f;
    };

} // namespace

// -----------------------------------------------------------------------
// RoleELM tests
// -----------------------------------------------------------------------

TEST( RoleELM, Process_LoadedEngine_ReturnsResponse )
{
    auto engine = std::make_shared<MockEngine>();
    elm::RoleELM elm( ELMRole::Verifier, engine );
    ASSERT_TRUE( elm.Load( "dummy" ).has_value() );
    ASSERT_TRUE( elm.IsLoaded() );

    ELMContext ctx;
    ctx.m_originalTask = "test task";
    auto result = elm.Process( "input text", ctx );
    ASSERT_TRUE( result.has_value() );
    EXPECT_NE( result.value().find( "input" ), std::string::npos );
    EXPECT_GT( elm.GetConfidence(), 0.0f );
}

TEST( RoleELM, Process_NotLoaded_ReturnsError )
{
    auto engine = std::make_shared<MockEngine>();
    elm::RoleELM elm( ELMRole::Verifier, engine );

    ELMContext ctx;
    auto result = elm.Process( "hello world", ctx );
    ASSERT_FALSE( result.has_value() );
    EXPECT_EQ( result.error(), Error::NotLoaded );
    EXPECT_FLOAT_EQ( elm.GetConfidence(), 0.0f );
}

TEST( RoleELM, GetName_ReturnsCorrectName )
{
    auto engine = std::make_shared<MockEngine>();
    elm::RoleELM planner( ELMRole::Planner, engine );
    EXPECT_EQ( planner.GetName(), "Planner" );

    elm::RoleELM verifier( ELMRole::Verifier, engine );
    EXPECT_EQ( verifier.GetName(), "Verifier" );
}

TEST( RoleELM, GetRole_ReturnsConfiguredRole )
{
    auto engine = std::make_shared<MockEngine>();
    elm::RoleELM elm( ELMRole::Arbiter, engine );
    EXPECT_EQ( elm.GetRole(), ELMRole::Arbiter );
}

TEST( RoleELM, IsLoaded_InitiallyFalse )
{
    elm::RoleELM elm( ELMRole::Refiner, nullptr );
    EXPECT_FALSE( elm.IsLoaded() );
}

TEST( RoleELM, Process_NullEngine_ReturnsError )
{
    elm::RoleELM elm( ELMRole::PrimaryDraft, nullptr );

    ELMContext ctx;
    auto result = elm.Process( "hello", ctx );
    ASSERT_FALSE( result.has_value() );
    EXPECT_EQ( result.error(), Error::NotLoaded );
    EXPECT_FLOAT_EQ( elm.GetConfidence(), 0.0f );
}

// -----------------------------------------------------------------------
// DomainELM tests
// -----------------------------------------------------------------------

TEST( DomainELM, Process_SharedBackbone_ReturnsResponse )
{
    auto engine = std::make_shared<MockEngine>();
    elm::DomainELM elm( ELMRole::Code, engine );
    ASSERT_TRUE( elm.Load( "" ).has_value() );
    ASSERT_TRUE( elm.IsLoaded() );

    ELMContext ctx;
    ctx.m_originalTask = "write a function";
    auto result = elm.Process( "int main()", ctx );
    ASSERT_TRUE( result.has_value() );
    EXPECT_NE( result.value().find( "int main" ), std::string::npos );
    EXPECT_GT( elm.GetConfidence(), 0.0f );
}

TEST( DomainELM, Process_NoEngine_ReturnsError )
{
    elm::DomainELM elm( ELMRole::Code, nullptr );

    ELMContext ctx;
    auto result = elm.Process( "some code", ctx );
    ASSERT_FALSE( result.has_value() );
    EXPECT_EQ( result.error(), Error::NotLoaded );
    EXPECT_FLOAT_EQ( elm.GetConfidence(), 0.0f );
}

TEST( DomainELM, GetRole_ReturnsConfiguredRole )
{
    auto engine = std::make_shared<MockEngine>();
    elm::DomainELM elm( ELMRole::Math, engine );
    EXPECT_EQ( elm.GetRole(), ELMRole::Math );
}

TEST( DomainELM, IsLoaded_InitiallyFalse )
{
    elm::DomainELM elm( ELMRole::Science, nullptr );
    EXPECT_FALSE( elm.IsLoaded() );
}

TEST( DomainELM, GetName_ReturnsCorrectName )
{
    auto engine = std::make_shared<MockEngine>();
    elm::DomainELM codeElm( ELMRole::Code, engine );
    EXPECT_EQ( codeElm.GetName(), "Code" );

    elm::DomainELM mathElm( ELMRole::Math, engine );
    EXPECT_EQ( mathElm.GetName(), "Math" );
}

TEST( DomainELM, Load_EmptyPath_UsesSharedEngine )
{
    auto engine = std::make_shared<MockEngine>();
    elm::DomainELM elm( ELMRole::Science, engine );
    auto result = elm.Load( "" );
    ASSERT_TRUE( result.has_value() );
    EXPECT_TRUE( elm.IsLoaded() );
}

// -----------------------------------------------------------------------
// SpecialistAdapter tests
// -----------------------------------------------------------------------

TEST( SpecialistAdapter, Process_DelegatesToSpecialist )
{
    auto specialist = std::make_shared<MockSpecialist>();
    elm::SpecialistAdapter adapter( specialist, ELMRole::Refiner, "RefinerAdapter" );

    ELMContext ctx;
    auto result = adapter.Process( "input", ctx );
    ASSERT_TRUE( result.has_value() );
    EXPECT_EQ( result.value(), "input [specialized]" );
}

TEST( SpecialistAdapter, GetConfidence_ReflectsSpecialist )
{
    auto specialist = std::make_shared<MockSpecialist>();
    elm::SpecialistAdapter adapter( specialist, ELMRole::Refiner, "RefinerAdapter" );

    ELMContext ctx;
    auto result = adapter.Process( "x", ctx );
    ASSERT_TRUE( result.has_value() );
    EXPECT_FLOAT_EQ( adapter.GetConfidence(), 0.9f );
}

// -----------------------------------------------------------------------
// ELMChainBuilder tests
// -----------------------------------------------------------------------

namespace
{
    RouteDecision MakeDecision()
    {
        RouteDecision d;
        d.m_target = RouteTarget::CoreOnly;
        d.confidence_ = 0.9f;
        d.m_reasoning = "test";
        d.m_mode = ExecutionMode::ElmAssisted;
        return d;
    }
} // namespace

TEST( ELMChainBuilder, Build_HighNumericDensity_ReturnsMathChain )
{
    elm::ELMChainBuilder builder;
    auto decision = MakeDecision();

    PromptFeatures features;
    features.numeric_density_ = 0.5f;

    auto chain = builder.Build( decision, features );
    EXPECT_EQ( chain.m_steps.size(), 2u );
    EXPECT_EQ( chain.m_steps[0].m_role, ELMRole::Math );
    EXPECT_FALSE( chain.m_reasoning.empty() );
}

TEST( ELMChainBuilder, Build_CodeSyntax_ReturnsPlannerCodeChain )
{
    elm::ELMChainBuilder builder;
    auto decision = MakeDecision();

    PromptFeatures features;
    features.has_code_syntax_ = true;

    auto chain = builder.Build( decision, features );
    EXPECT_EQ( chain.m_steps.size(), 2u );
    EXPECT_EQ( chain.m_steps[0].m_role, ELMRole::Planner );
    EXPECT_TRUE( chain.m_steps[1].m_domain.has_value() );
    EXPECT_EQ( chain.m_steps[1].m_domain.value(), "code" );
    EXPECT_FALSE( chain.m_reasoning.empty() );
}

TEST( ELMChainBuilder, Build_LowComplexity_ReturnsSingleStep )
{
    elm::ELMChainBuilder builder;
    auto decision = MakeDecision();

    PromptFeatures features;
    features.complexity_ = 1.0f;

    auto chain = builder.Build( decision, features );
    EXPECT_EQ( chain.m_steps.size(), 1u );
    EXPECT_EQ( chain.m_steps[0].m_role, ELMRole::PrimaryDraft );
    EXPECT_FALSE( chain.m_reasoning.empty() );
}

TEST( ELMChainBuilder, Build_HighComplexity_ReturnsFullChain )
{
    elm::ELMChainBuilder builder;
    auto decision = MakeDecision();

    PromptFeatures features;
    features.complexity_ = 6.0f;

    auto chain = builder.Build( decision, features );
    EXPECT_EQ( chain.m_steps.size(), 4u );
    EXPECT_EQ( chain.m_steps[3].m_role, ELMRole::Refiner );
    EXPECT_FALSE( chain.m_reasoning.empty() );
}

TEST( ELMChainBuilder, Build_Default_ReturnsPrimaryDraft )
{
    elm::ELMChainBuilder builder;
    auto decision = MakeDecision();

    PromptFeatures features;

    auto chain = builder.Build( decision, features );
    EXPECT_EQ( chain.m_steps.size(), 1u );
    EXPECT_EQ( chain.m_steps[0].m_role, ELMRole::PrimaryDraft );
    EXPECT_FALSE( chain.m_reasoning.empty() );
}

// -----------------------------------------------------------------------
// GroundingELM tests
// -----------------------------------------------------------------------

TEST( GroundingELM, Process_KnowledgeLoaded_ReturnsAugmentedOutput )
{
    auto knowledge = std::make_shared<knowledge::KnowledgeRetrieval>();
    ASSERT_TRUE( knowledge->Load().has_value() );
    ASSERT_TRUE( knowledge->IsLoaded() );

    auto engine = std::make_shared<MockEngine>();
    auto contextInj = std::make_unique<knowledge::ContextInjection>();
    auto factVal = std::make_unique<knowledge::FactValidation>( knowledge );

    elm::GroundingELM elm( engine, knowledge, std::move( contextInj ), std::move( factVal ) );
    ASSERT_TRUE( elm.Load( "" ).has_value() );
    ASSERT_TRUE( elm.IsLoaded() );

    ELMContext ctx;
    auto result = elm.Process( "speed of light", ctx );
    ASSERT_TRUE( result.has_value() );
    EXPECT_FALSE( result.value().empty() );
    EXPECT_GT( elm.GetConfidence(), 0.0f );
}

// -----------------------------------------------------------------------
// ToolSupportELM tests
// -----------------------------------------------------------------------

TEST( ToolSupportELM, Process_ReturnsInputUnchanged_ConfidenceZero )
{
    elm::ToolSupportELM elm;

    ELMContext ctx;
    auto result = elm.Process( "any", ctx );
    ASSERT_TRUE( result.has_value() );
    EXPECT_EQ( result.value(), "any" );
    EXPECT_FLOAT_EQ( elm.GetConfidence(), 0.0f );
}

TEST( ToolSupportELM, IsLoaded_AlwaysFalse )
{
    elm::ToolSupportELM elm;
    EXPECT_FALSE( elm.IsLoaded() );
}

Updated on 2026-10-09 at 03:59:42 +0000