Skip to content

Commit 858a9aa

Browse files
committed
unit tests
1 parent 03b98b6 commit 858a9aa

File tree

9 files changed

+373
-12
lines changed

9 files changed

+373
-12
lines changed

.codegen/config.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,21 @@ openai_api_key = ""
55
[repository]
66
organization_name = "codegen-sh"
77
repo_name = "codegen-sdk"
8+
9+
[feature_flags.codebase]
10+
debug = false
11+
verify_graph = false
12+
track_graph = false
13+
method_usages = true
14+
sync_enabled = true
15+
full_range_index = false
16+
ignore_process_errors = true
17+
disable_graph = false
18+
generics = true
19+
20+
[feature_flags.codebase.import_resolution_overrides]
21+
22+
[feature_flags.codebase.typescript]
23+
ts_dependency_manager = false
24+
ts_language_engine = false
25+
v8_ts_engine = false

src/codegen/shared/configs/models.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,21 @@
99

1010

1111
class TypescriptConfig(BaseModel):
12-
ts_dependency_manager: bool = False
13-
ts_language_engine: bool = False
14-
v8_ts_engine: bool = False
12+
ts_dependency_manager: bool | None = None
13+
ts_language_engine: bool | None = None
14+
v8_ts_engine: bool | None = None
1515

1616

1717
class CodebaseFeatureFlags(BaseModel):
18-
debug: bool = False
19-
verify_graph: bool = False
20-
track_graph: bool = False
21-
method_usages: bool = True
22-
sync_enabled: bool = True
23-
full_range_index: bool = False
24-
ignore_process_errors: bool = True
25-
disable_graph: bool = False
26-
generics: bool = True
18+
debug: bool | None = None
19+
verify_graph: bool | None = None
20+
track_graph: bool | None = None
21+
method_usages: bool | None = None
22+
sync_enabled: bool | None = None
23+
full_range_index: bool | None = None
24+
ignore_process_errors: bool | None = None
25+
disable_graph: bool | None = None
26+
generics: bool | None = None
2727
import_resolution_overrides: dict[str, str] = Field(default_factory=lambda: {})
2828
typescript: TypescriptConfig = Field(default_factory=TypescriptConfig)
2929

File renamed without changes.
File renamed without changes.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# Test data
2+
SAMPLE_TOML = """
3+
[secrets]
4+
github_token = "gh_token123"
5+
openai_api_key = "sk-123456"
6+
7+
[repository]
8+
organization_name = "test-org"
9+
repo_name = "test-repo"
10+
11+
[feature_flags.codebase]
12+
debug = true
13+
verify_graph = true
14+
track_graph = false
15+
method_usages = true
16+
sync_enabled = true
17+
full_range_index = false
18+
ignore_process_errors = true
19+
disable_graph = false
20+
generics = true
21+
22+
[feature_flags.codebase.typescript]
23+
ts_dependency_manager = true
24+
ts_language_engine = false
25+
v8_ts_engine = true
26+
27+
[feature_flags.codebase.import_resolution_overrides]
28+
"@org/pkg" = "./local/path"
29+
"""
30+
31+
SAMPLE_CONFIG_DICT = {
32+
"secrets": {
33+
"github_token": "gh_token123",
34+
"openai_api_key": "sk-123456",
35+
},
36+
"repository": {
37+
"organization_name": "test-org",
38+
"repo_name": "test-repo",
39+
},
40+
"feature_flags": {
41+
"codebase": {
42+
"debug": True,
43+
"verify_graph": True,
44+
"track_graph": False,
45+
"method_usages": True,
46+
"sync_enabled": True,
47+
"full_range_index": False,
48+
"ignore_process_errors": True,
49+
"disable_graph": False,
50+
"generics": True,
51+
"typescript": {
52+
"ts_dependency_manager": True,
53+
"ts_language_engine": False,
54+
"v8_ts_engine": True,
55+
},
56+
"import_resolution_overrides": {"@org/pkg": "./local/path"},
57+
}
58+
},
59+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
from unittest.mock import patch
2+
3+
import pytest
4+
5+
from tests.shared.configs.sample_config import SAMPLE_CONFIG_DICT, SAMPLE_TOML
6+
7+
8+
@pytest.fixture
9+
def sample_toml():
10+
"""Return sample TOML configuration string."""
11+
return SAMPLE_TOML
12+
13+
14+
@pytest.fixture
15+
def sample_config_dict():
16+
"""Return sample configuration dictionary."""
17+
return SAMPLE_CONFIG_DICT
18+
19+
20+
@pytest.fixture
21+
def temp_config_file(tmp_path):
22+
"""Create a temporary config file with sample TOML content."""
23+
config_file = tmp_path / "config.toml"
24+
config_file.write_text(SAMPLE_TOML)
25+
return config_file
26+
27+
28+
@pytest.fixture
29+
def invalid_toml_file(tmp_path):
30+
"""Create a temporary file with invalid TOML content."""
31+
invalid_toml = tmp_path / "invalid.toml"
32+
invalid_toml.write_text("invalid = toml [ content")
33+
return invalid_toml
34+
35+
36+
@pytest.fixture
37+
def clean_env():
38+
"""Temporarily clear environment variables and override env file path."""
39+
with patch.dict("os.environ", {}, clear=True):
40+
with patch("codegen.shared.configs.models.Config.model_config", {"env_file": "nonexistent.env"}):
41+
with patch("codegen.shared.configs.models.SecretsConfig.model_config", {"env_file": "nonexistent.env"}):
42+
yield
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
from pathlib import Path
2+
from unittest.mock import patch
3+
4+
import pytest
5+
import tomllib
6+
7+
from codegen.shared.configs.config import (
8+
Config,
9+
_load_from_env,
10+
_load_from_toml,
11+
_merge_configs,
12+
load,
13+
)
14+
from codegen.shared.configs.models import CodebaseFeatureFlags, FeatureFlagsConfig, SecretsConfig
15+
16+
17+
# Test _merge_configs
18+
def test_merge_configs_basic():
19+
base = {"a": 1, "b": 2}
20+
override = {"b": 3, "c": 4}
21+
result = _merge_configs(base, override)
22+
assert result == {"a": 1, "b": 3, "c": 4}
23+
24+
25+
def test_merge_configs_nested():
26+
base = {"feature_flags": {"codebase": {"debug": False, "typescript": {"ts_dependency_manager": False}}}}
27+
override = {"feature_flags": {"codebase": {"debug": True, "typescript": {"ts_language_engine": True}}}}
28+
result = _merge_configs(base, override)
29+
assert result == {"feature_flags": {"codebase": {"debug": True, "typescript": {"ts_dependency_manager": False, "ts_language_engine": True}}}}
30+
31+
32+
def test_merge_configs_none_values():
33+
base = {"secrets": {"github_token": "token1"}}
34+
override = {"secrets": {"github_token": None}}
35+
result = _merge_configs(base, override)
36+
assert result == {"secrets": {"github_token": "token1"}}
37+
38+
39+
def test_merge_configs_empty_string():
40+
base = {"repository": {"organization_name": "org1"}}
41+
override = {"repository": {"organization_name": ""}}
42+
result = _merge_configs(base, override)
43+
assert result == {"repository": {"organization_name": "org1"}}
44+
45+
46+
# Test _load_from_toml
47+
def test_load_from_toml_existing_file(temp_config_file):
48+
config = _load_from_toml(temp_config_file)
49+
assert isinstance(config, Config)
50+
assert config.secrets.github_token == "gh_token123"
51+
assert config.repository.organization_name == "test-org"
52+
assert config.feature_flags.codebase.debug is True
53+
assert config.feature_flags.codebase.typescript.ts_dependency_manager is True
54+
assert config.feature_flags.codebase.import_resolution_overrides == {"@org/pkg": "./local/path"}
55+
56+
57+
@patch("codegen.shared.configs.models.SecretsConfig.model_config", {"env_file": "nonexistent.env"})
58+
def test_load_from_toml_nonexistent_file():
59+
config = _load_from_toml(Path("nonexistent.toml"))
60+
assert isinstance(config, Config)
61+
assert config.secrets.github_token is None
62+
assert config.repository.organization_name is None
63+
assert config.feature_flags.codebase.debug is None
64+
65+
66+
# Test _load_from_env
67+
@patch.dict("os.environ", {"CODEGEN_SECRETS__GITHUB_TOKEN": "env_token", "CODEGEN_SECRETS__OPENAI_API_KEY": "env_key"})
68+
def test_load_from_env():
69+
config = _load_from_env()
70+
assert isinstance(config, Config)
71+
assert config.secrets.github_token == "env_token"
72+
assert config.secrets.openai_api_key == "env_key"
73+
74+
75+
# Test load function
76+
@patch.dict("os.environ", {}, clear=True) # Clear all env vars for this test
77+
@patch("codegen.shared.configs.config._load_from_env")
78+
@patch("codegen.shared.configs.config._load_from_toml")
79+
@patch("codegen.shared.configs.models.SecretsConfig.model_config", {"env_file": None, "env_prefix": "CODEGEN_SECRETS__"})
80+
def test_load_with_both_configs(mock_toml, mock_env):
81+
# Setup mock returns
82+
mock_env.return_value = Config(secrets=SecretsConfig(github_token="env_token"), feature_flags=FeatureFlagsConfig(codebase=CodebaseFeatureFlags(debug=True)))
83+
mock_toml.return_value = Config(secrets={"openai_api_key": "openai_key"}, repository={"organization_name": "codegen-org"})
84+
85+
config = load()
86+
87+
assert isinstance(config, Config)
88+
assert config.secrets.github_token == "env_token"
89+
assert config.secrets.openai_api_key == "openai_key"
90+
assert config.repository.organization_name == "codegen-org"
91+
assert config.feature_flags.codebase.debug is True
92+
93+
94+
@patch("codegen.shared.configs.config._load_from_env")
95+
@patch("codegen.shared.configs.config._load_from_toml")
96+
def test_load_with_custom_path(mock_toml, mock_env):
97+
custom_path = Path("custom/config.toml")
98+
load(config_path=custom_path)
99+
100+
mock_toml.assert_called_once_with(custom_path)
101+
mock_env.assert_called_once()
102+
103+
104+
# Error cases
105+
def test_load_from_toml_invalid_file(invalid_toml_file):
106+
with pytest.raises(tomllib.TOMLDecodeError):
107+
_load_from_toml(invalid_toml_file)
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
from pathlib import Path
2+
3+
from codegen.shared.configs.constants import (
4+
CODEGEN_DIR_NAME,
5+
CODEGEN_REPO_ROOT,
6+
CONFIG_FILENAME,
7+
CONFIG_PATH,
8+
ENV_FILENAME,
9+
ENV_PATH,
10+
)
11+
12+
13+
def test_codegen_repo_root_is_path():
14+
assert isinstance(CODEGEN_REPO_ROOT, Path)
15+
assert CODEGEN_REPO_ROOT.exists()
16+
assert CODEGEN_REPO_ROOT.is_dir()
17+
18+
19+
def test_config_path_construction():
20+
expected_path = CODEGEN_REPO_ROOT / CODEGEN_DIR_NAME / CONFIG_FILENAME
21+
assert CONFIG_PATH == expected_path
22+
assert str(CONFIG_PATH).endswith(f"{CODEGEN_DIR_NAME}/{CONFIG_FILENAME}")
23+
assert CONFIG_PATH.exists()
24+
assert CONFIG_PATH.is_file()
25+
26+
27+
def test_env_path_construction():
28+
expected_path = CODEGEN_REPO_ROOT / "src" / "codegen" / ENV_FILENAME
29+
assert ENV_PATH == expected_path
30+
assert str(ENV_PATH).endswith(f"src/codegen/{ENV_FILENAME}")

0 commit comments

Comments
 (0)