File size: 5,309 Bytes
51ff9e5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import os

import pytest

from openhands.core.config.extended_config import ExtendedConfig
from openhands.core.config.openhands_config import OpenHandsConfig
from openhands.core.config.utils import load_from_toml


def test_extended_config_from_dict():
    """Test that ExtendedConfig.from_dict successfully creates an instance.

    This test verifies that the from_dict method correctly creates an instance
    from a dictionary containing arbitrary extra keys.
    """
    data = {'foo': 'bar', 'baz': 123, 'flag': True}
    ext_cfg = ExtendedConfig.from_dict(data)

    # Check that the keys are accessible both as attributes and via __getitem__
    assert ext_cfg.foo == 'bar'
    assert ext_cfg['baz'] == 123
    assert ext_cfg.flag is True
    # Verify the root dictionary contains all keys
    assert ext_cfg.root == data


def test_extended_config_empty():
    """Test that an empty ExtendedConfig can be created and accessed."""
    ext_cfg = ExtendedConfig.from_dict({})
    assert ext_cfg.root == {}

    # Creating directly should also work
    ext_cfg2 = ExtendedConfig({})
    assert ext_cfg2.root == {}


def test_extended_config_str_and_repr():
    """Test that __str__ and __repr__ return the correct string representations.

    This test verifies that the string representations of the ExtendedConfig instance
    include the expected key/value pairs.
    """
    data = {'alpha': 'test', 'beta': 42}
    ext_cfg = ExtendedConfig.from_dict(data)
    string_repr = str(ext_cfg)
    repr_str = repr(ext_cfg)

    # Ensure the representations include our key/value pairs
    assert "alpha='test'" in string_repr
    assert 'beta=42' in string_repr

    # __repr__ should match __str__
    assert string_repr == repr_str


def test_extended_config_getitem_and_getattr():
    """Test that __getitem__ and __getattr__ can be used to access values.

    This test verifies that values in the ExtendedConfig instance can be accessed
    both via attribute access and dictionary-style access.
    """
    data = {'key1': 'value1', 'key2': 2}
    ext_cfg = ExtendedConfig.from_dict(data)

    # Attribute access
    assert ext_cfg.key1 == 'value1'
    # Dictionary-style access
    assert ext_cfg['key2'] == 2


def test_extended_config_invalid_key():
    """Test that accessing a non-existent key via attribute access raises AttributeError."""
    data = {'existing': 'yes'}
    ext_cfg = ExtendedConfig.from_dict(data)

    with pytest.raises(AttributeError):
        _ = ext_cfg.nonexistent

    with pytest.raises(KeyError):
        _ = ext_cfg['nonexistent']


def test_app_config_extended_from_toml(tmp_path: os.PathLike) -> None:
    """Test that the [extended] section in a TOML file is correctly loaded.

    This test verifies that the [extended] section is loaded into OpenHandsConfig.extended
    and that it accepts arbitrary keys.
    """
    # Create a temporary TOML file with multiple sections including [extended]
    config_content = """
[core]
workspace_base = "/tmp/workspace"

[llm]
model = "test-model"
api_key = "toml-api-key"

[extended]
custom1 = "custom_value"
custom2 = 42
llm = "overridden"  # even a key like 'llm' is accepted in extended

[agent]
enable_prompt_extensions = true
"""
    config_file = tmp_path / 'config.toml'
    config_file.write_text(config_content)

    # Load the TOML into the OpenHandsConfig instance
    config = OpenHandsConfig()
    load_from_toml(config, str(config_file))

    # Verify that extended section is applied
    assert config.extended.custom1 == 'custom_value'
    assert config.extended.custom2 == 42
    # Even though 'llm' is defined in extended, it should not affect the main llm config.
    assert config.get_llm_config().model == 'test-model'


def test_app_config_extended_default(tmp_path: os.PathLike) -> None:
    """Test default behavior when no [extended] section exists.

    This test verifies that if there is no [extended] section in the TOML file,
    OpenHandsConfig.extended remains its default (empty) ExtendedConfig.
    """
    config_content = """
[core]
workspace_base = "/tmp/workspace"

[llm]
model = "test-model"
api_key = "toml-api-key"

[agent]
enable_prompt_extensions = true
"""
    config_file = tmp_path / 'config.toml'
    config_file.write_text(config_content)

    config = OpenHandsConfig()
    load_from_toml(config, str(config_file))

    # Extended config should be empty
    assert config.extended.root == {}


def test_app_config_extended_random_keys(tmp_path: os.PathLike) -> None:
    """Test that the extended section accepts arbitrary keys.

    This test verifies that the extended section accepts arbitrary keys,
    including ones not defined in any schema.
    """
    config_content = """
[core]
workspace_base = "/tmp/workspace"

[extended]
random_key = "random_value"
another_key = 3.14
"""
    config_file = tmp_path / 'config.toml'
    config_file.write_text(config_content)

    config = OpenHandsConfig()
    load_from_toml(config, str(config_file))

    # Verify that extended config holds the arbitrary keys with correct values.
    assert config.extended.random_key == 'random_value'
    assert config.extended.another_key == 3.14
    # Verify the root dictionary contains all keys
    assert config.extended.root == {'random_key': 'random_value', 'another_key': 3.14}