File size: 8,958 Bytes
a5784e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
"""
Tests for gui/env_manager.py - Environment file management
"""

import os
import tempfile
from pathlib import Path

import pytest

from gui.env_manager import EnvManager, get_env_manager, reset_env_manager


@pytest.fixture
def temp_env_file():
    """Create a temporary .env file for testing."""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
        f.write("""# Test configuration
PORT=2048
STREAM_PORT=3120
DEBUG_LOGS_ENABLED=true
DEFAULT_TEMPERATURE=1.0
SERVER_LOG_LEVEL=INFO
FUNCTION_CALLING_MODE=auto
""")
        f.flush()
        yield Path(f.name)
    os.unlink(f.name)


@pytest.fixture
def temp_example_file():
    """Create a temporary .env.example file for testing."""
    with tempfile.NamedTemporaryFile(
        mode="w", suffix=".env.example", delete=False
    ) as f:
        f.write("""# Example configuration
PORT=2048
STREAM_PORT=3120
""")
        f.flush()
        yield Path(f.name)
    os.unlink(f.name)


@pytest.fixture
def env_manager(temp_env_file, temp_example_file):
    """Create an EnvManager instance for testing."""
    reset_env_manager()
    return EnvManager(temp_env_file, temp_example_file)


class TestEnvManagerInit:
    """Tests for EnvManager initialization."""

    def test_loads_existing_file(self, env_manager):
        """Test that EnvManager loads existing .env file."""
        assert env_manager.get("PORT") == 2048

    def test_creates_from_example_if_missing(self, temp_example_file):
        """Test creating .env from .env.example if missing."""
        reset_env_manager()
        missing_path = Path(tempfile.gettempdir()) / "nonexistent_test.env"
        if missing_path.exists():
            missing_path.unlink()

        manager = EnvManager(missing_path, temp_example_file)
        assert missing_path.exists()
        assert manager.get("PORT") == 2048
        missing_path.unlink()


class TestEnvManagerGet:
    """Tests for EnvManager.get() method."""

    def test_get_int_value(self, env_manager):
        """Test getting integer values."""
        assert env_manager.get("PORT") == 2048
        assert isinstance(env_manager.get("PORT"), int)

    def test_get_bool_value(self, env_manager):
        """Test getting boolean values."""
        assert env_manager.get("DEBUG_LOGS_ENABLED") is True
        assert isinstance(env_manager.get("DEBUG_LOGS_ENABLED"), bool)

    def test_get_float_value(self, env_manager):
        """Test getting float values."""
        assert env_manager.get("DEFAULT_TEMPERATURE") == 1.0
        assert isinstance(env_manager.get("DEFAULT_TEMPERATURE"), float)

    def test_get_string_value(self, env_manager):
        """Test getting string values."""
        assert env_manager.get("SERVER_LOG_LEVEL") == "INFO"
        assert isinstance(env_manager.get("SERVER_LOG_LEVEL"), str)

    def test_get_choice_value(self, env_manager):
        """Test getting choice values."""
        assert env_manager.get("FUNCTION_CALLING_MODE") == "auto"

    def test_get_missing_returns_default(self, env_manager):
        """Test that missing keys return schema default."""
        # QUOTA_SOFT_LIMIT is in schema but not in our test file
        assert env_manager.get("QUOTA_SOFT_LIMIT") == 850000

    def test_get_raw_value(self, env_manager):
        """Test getting raw string value."""
        raw = env_manager.get_raw("DEBUG_LOGS_ENABLED")
        assert raw == "true"
        assert isinstance(raw, str)


class TestEnvManagerSet:
    """Tests for EnvManager.set() method."""

    def test_set_int_value(self, env_manager):
        """Test setting integer values."""
        env_manager.set("PORT", 3000)
        assert env_manager.get("PORT") == 3000

    def test_set_bool_value(self, env_manager):
        """Test setting boolean values."""
        env_manager.set("DEBUG_LOGS_ENABLED", False)
        assert env_manager.get("DEBUG_LOGS_ENABLED") is False

    def test_set_float_value(self, env_manager):
        """Test setting float values."""
        env_manager.set("DEFAULT_TEMPERATURE", 0.7)
        assert env_manager.get("DEFAULT_TEMPERATURE") == 0.7


class TestEnvManagerDirtyState:
    """Tests for dirty state tracking."""

    def test_initially_not_dirty(self, env_manager):
        """Test that newly loaded manager is not dirty."""
        assert env_manager.is_dirty() is False

    def test_dirty_after_set(self, env_manager):
        """Test that manager becomes dirty after setting a value."""
        env_manager.set("PORT", 9999)
        assert env_manager.is_dirty() is True

    def test_get_modified_keys(self, env_manager):
        """Test getting list of modified keys."""
        env_manager.set("PORT", 9999)
        env_manager.set("STREAM_PORT", 8888)
        modified = env_manager.get_modified_keys()
        assert "PORT" in modified
        assert "STREAM_PORT" in modified


class TestEnvManagerSave:
    """Tests for saving .env file."""

    def test_save_writes_file(self, env_manager, temp_env_file):
        """Test that save writes to file."""
        env_manager.set("PORT", 5000)
        assert env_manager.save() is True

        # Re-read the file
        with open(temp_env_file) as f:
            content = f.read()
        assert "PORT=5000" in content

    def test_save_clears_dirty_state(self, env_manager):
        """Test that save clears dirty state."""
        env_manager.set("PORT", 5000)
        assert env_manager.is_dirty() is True
        env_manager.save()
        assert env_manager.is_dirty() is False


class TestEnvManagerCategories:
    """Tests for category handling."""

    def test_get_category_keys(self, env_manager):
        """Test getting keys by category."""
        server_keys = env_manager.get_category_keys("server")
        assert "PORT" in server_keys
        assert "STREAM_PORT" in server_keys

    def test_get_schema_info(self, env_manager):
        """Test getting schema info for a key."""
        info = env_manager.get_schema_info("PORT")
        assert info is not None
        default, type_hint, description, category = info
        assert default == 2048
        assert type_hint == "int"
        assert category == "server"

    def test_categories_dict_exists(self, env_manager):
        """Test that CATEGORIES dict is defined."""
        assert len(EnvManager.CATEGORIES) > 0
        assert "server" in EnvManager.CATEGORIES
        assert "logging" in EnvManager.CATEGORIES


class TestEnvManagerHotReload:
    """Tests for hot reload functionality."""

    def test_register_callback(self, env_manager):
        """Test registering hot reload callback."""
        callback_called = []

        def callback(modified):
            callback_called.append(modified)

        env_manager.register_hot_reload_callback(callback)
        env_manager.set("PORT", 9999)
        env_manager.trigger_hot_reload()

        assert len(callback_called) == 1
        assert "PORT" in callback_called[0]

    def test_unregister_callback(self, env_manager):
        """Test unregistering hot reload callback."""
        callback_called = []

        def callback(modified):
            callback_called.append(modified)

        env_manager.register_hot_reload_callback(callback)
        env_manager.unregister_hot_reload_callback(callback)
        env_manager.set("PORT", 9999)
        env_manager.trigger_hot_reload()

        assert len(callback_called) == 0

    def test_apply_to_environment(self, env_manager):
        """Test applying settings to os.environ."""
        env_manager.set("PORT", 7777)
        env_manager.apply_to_environment()
        assert os.environ.get("PORT") == "7777"


class TestEnvManagerReset:
    """Tests for reset functionality."""

    def test_reset_to_defaults(self, env_manager):
        """Test resetting all values to defaults."""
        env_manager.set("PORT", 9999)
        env_manager.reset_to_defaults()
        assert env_manager.get("PORT") == 2048

    def test_discard_changes(self, env_manager):
        """Test discarding unsaved changes."""
        original = env_manager.get("PORT")
        env_manager.set("PORT", 9999)
        env_manager.discard_changes()
        assert env_manager.get("PORT") == original


class TestGetEnvManagerSingleton:
    """Tests for singleton pattern."""

    def test_singleton_returns_same_instance(self, temp_env_file, temp_example_file):
        """Test that get_env_manager returns singleton."""
        reset_env_manager()
        manager1 = get_env_manager(temp_env_file, temp_example_file)
        manager2 = get_env_manager()
        assert manager1 is manager2

    def test_reset_clears_singleton(self, temp_env_file, temp_example_file):
        """Test that reset_env_manager clears singleton."""
        reset_env_manager()
        manager1 = get_env_manager(temp_env_file, temp_example_file)
        reset_env_manager()
        manager2 = get_env_manager(temp_env_file, temp_example_file)
        assert manager1 is not manager2