File size: 4,512 Bytes
a345062
 
 
 
 
8489475
a345062
8489475
 
d407fda
a345062
 
 
 
 
 
8489475
a345062
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8489475
a345062
 
8489475
 
a345062
8489475
a345062
 
8489475
 
 
 
 
 
 
 
a345062
8489475
a345062
8489475
a345062
d407fda
 
 
 
 
 
 
 
8489475
a345062
8489475
 
a345062
8489475
d407fda
 
 
8489475
 
 
 
 
 
a345062
8489475
a345062
d407fda
8489475
 
a345062
8489475
a345062
8489475
 
 
a345062
 
d407fda
8489475
 
 
a345062
8489475
 
 
a345062
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import os
import torch
import pytest
from unittest.mock import patch

from cognitive_mapping_probe.llm_iface import get_or_load_model, LLM
from cognitive_mapping_probe.resonance_seismograph import run_silent_cogitation_seismic
from cognitive_mapping_probe.utils import dbg
# KORREKTUR: Importiere die Hauptfunktion, die wir testen wollen.
from cognitive_mapping_probe.concepts import get_concept_vector, _get_last_token_hidden_state

# --- Tests for llm_iface.py ---

@patch('cognitive_mapping_probe.llm_iface.AutoTokenizer.from_pretrained')
@patch('cognitive_mapping_probe.llm_iface.AutoModelForCausalLM.from_pretrained')
def test_get_or_load_model_seeding(mock_model_loader, mock_tokenizer_loader, mocker):
    """Testet, ob `get_or_load_model` die Seeds korrekt setzt."""
    mock_model = mocker.MagicMock()
    mock_model.eval.return_value = None
    mock_model.set_attn_implementation.return_value = None
    mock_model.config = mocker.MagicMock()
    mock_model.device = 'cpu'
    mock_model_loader.return_value = mock_model
    mock_tokenizer_loader.return_value = mocker.MagicMock()

    mock_torch_manual_seed = mocker.patch('torch.manual_seed')
    mock_np_random_seed = mocker.patch('numpy.random.seed')

    seed = 123
    get_or_load_model("fake-model", seed=seed)

    mock_torch_manual_seed.assert_called_with(seed)
    mock_np_random_seed.assert_called_with(seed)

# --- Tests for resonance_seismograph.py ---

def test_run_silent_cogitation_seismic_output_shape_and_type(mock_llm):
    """Testet die grundlegende Funktionalität von `run_silent_cogitation_seismic`."""
    num_steps = 10
    state_deltas = run_silent_cogitation_seismic(
        llm=mock_llm, prompt_type="control_long_prose",
        num_steps=num_steps, temperature=0.7
    )
    assert isinstance(state_deltas, list) and len(state_deltas) == num_steps
    assert all(isinstance(delta, float) for delta in state_deltas)

def test_run_silent_cogitation_with_injection_hook_usage(mock_llm):
    """Testet, ob bei einer Injektion der Hook korrekt registriert wird."""
    num_steps = 5
    injection_vector = torch.randn(mock_llm.config.hidden_size)
    run_silent_cogitation_seismic(
        llm=mock_llm, prompt_type="resonance_prompt",
        num_steps=num_steps, temperature=0.7,
        injection_vector=injection_vector, injection_strength=1.0
    )
    assert mock_llm.model.model.layers[0].register_forward_pre_hook.call_count == num_steps

# --- Tests for concepts.py ---

def test_get_last_token_hidden_state_robustness(mock_llm):
    """Testet die robuste `_get_last_token_hidden_state` Funktion."""
    # Diese Funktion wird vom `mock_llm` in `conftest.py` aufgerufen und gibt einen Tensor
    # mit der korrekten `hidden_size` zurück. Hier testen wir, ob die Funktion im
    # echten Modul mit dem gemockten LLM-Objekt korrekt interagiert.
    hs = _get_last_token_hidden_state(mock_llm, "test prompt")
    assert hs.shape == (mock_llm.config.hidden_size,)

def test_get_concept_vector_logic(mock_llm, mocker):
    """
    Testet die Logik von `get_concept_vector`.
    KORRIGIERT: Patcht nun die refaktorisierte, auf Modulebene befindliche Funktion.
    """
    mock_hidden_states = [
        torch.ones(mock_llm.config.hidden_size) * 10, # target concept
        torch.ones(mock_llm.config.hidden_size) * 2,  # baseline word 1
        torch.ones(mock_llm.config.hidden_size) * 4   # baseline word 2
    ]
    # KORREKTUR: Der Patch-Pfad zeigt jetzt auf die korrekte, importierbare Funktion.
    mocker.patch(
        'cognitive_mapping_probe.concepts._get_last_token_hidden_state',
        side_effect=mock_hidden_states
    )

    concept_vector = get_concept_vector(mock_llm, "test", baseline_words=["a", "b"])

    # Erwarteter Vektor: 10 - mean(2, 4) = 10 - 3 = 7
    expected_vector = torch.ones(mock_llm.config.hidden_size) * 7
    assert torch.allclose(concept_vector, expected_vector)

# --- Tests for utils.py ---

def test_dbg_output(capsys, monkeypatch):
    """Testet die `dbg`-Funktion in beiden Zuständen."""
    monkeypatch.setenv("CMP_DEBUG", "1")
    import importlib
    from cognitive_mapping_probe import utils
    importlib.reload(utils) # Wichtig, da DEBUG_ENABLED beim Import gesetzt wird
    utils.dbg("test message")
    captured = capsys.readouterr()
    assert "[DEBUG] test message" in captured.err

    monkeypatch.delenv("CMP_DEBUG", raising=False)
    importlib.reload(utils)
    utils.dbg("should not be printed")
    captured = capsys.readouterr()
    assert captured.err == ""