File indexing completed on 2026-08-12 08:24:57
0001 """
0002 Unit tests for CLI helper functions (_helpers.py).
0003
0004 Tests config type detection, parameter counting, and formatting utilities.
0005 """
0006
0007 import pytest
0008 from aid2e.cli._helpers import (
0009 detect_config_type,
0010 count_parameters,
0011 extract_description_data,
0012 )
0013
0014
0015 class TestConfigTypeDetection:
0016 """Test automatic configuration type detection."""
0017
0018 def test_detect_full_config(self):
0019 """Full config has both problem and optimizer."""
0020 data = {
0021 "problem": {"name": "test"},
0022 "optimizer": {"name": "test"}
0023 }
0024 assert detect_config_type(data) == "full"
0025
0026 def test_detect_problem_only(self):
0027 """Problem-only config has problem but no optimizer."""
0028 data = {"problem": {"name": "test"}}
0029 assert detect_config_type(data) == "problem"
0030
0031 def test_detect_optimizer_only(self):
0032 """Optimizer-only config has optimizer but no problem."""
0033 data = {"optimizer": {"name": "test"}}
0034 assert detect_config_type(data) == "optimizer"
0035
0036 def test_detect_design_with_design_space(self):
0037 """Design config has design_space key."""
0038 data = {"design_space": {"design_parameters": {}}}
0039 assert detect_config_type(data) == "design"
0040
0041 def test_detect_design_with_design_parameters(self):
0042 """Design config can have design_parameters key directly."""
0043 data = {"design_parameters": {}}
0044 assert detect_config_type(data) == "design"
0045
0046 def test_detect_unknown_config(self):
0047 """Unknown config type when no recognizable keys."""
0048 data = {"random": "data"}
0049 assert detect_config_type(data) == "unknown"
0050
0051 def test_detect_empty_config(self):
0052 """Empty config is unknown."""
0053 data = {}
0054 assert detect_config_type(data) == "unknown"
0055
0056
0057 class TestParameterCounting:
0058 """Test parameter counting across groups."""
0059
0060 def test_count_single_group(self):
0061 """Count parameters in single group."""
0062 params = {
0063 "group1": {
0064 "parameters": {
0065 "x1": {"value": 0.5},
0066 "x2": {"value": 1.0}
0067 }
0068 }
0069 }
0070 assert count_parameters(params) == 2
0071
0072 def test_count_multiple_groups(self):
0073 """Count parameters across multiple groups."""
0074 params = {
0075 "group1": {
0076 "parameters": {
0077 "x1": {"value": 0.5},
0078 "x2": {"value": 1.0}
0079 }
0080 },
0081 "group2": {
0082 "parameters": {
0083 "y1": {"value": 2.0},
0084 "y2": {"value": 3.0},
0085 "y3": {"value": 4.0}
0086 }
0087 }
0088 }
0089 assert count_parameters(params) == 5
0090
0091 def test_count_empty_groups(self):
0092 """Count zero when groups have no parameters."""
0093 params = {
0094 "group1": {"parameters": {}},
0095 "group2": {"parameters": {}}
0096 }
0097 assert count_parameters(params) == 0
0098
0099 def test_count_missing_parameters_key(self):
0100 """Handle groups without 'parameters' key."""
0101 params = {
0102 "group1": {"parameters": {"x1": {}}},
0103 "group2": {"other_key": "value"}
0104 }
0105 assert count_parameters(params) == 1
0106
0107 def test_count_empty_dict(self):
0108 """Count zero for empty dict."""
0109 assert count_parameters({}) == 0
0110
0111
0112 class TestDescriptionExtraction:
0113 """Test structured description extraction for JSON/YAML output."""
0114
0115 def test_extract_full_config_description(self):
0116 """Extract description from full config."""
0117 data = {
0118 "problem": {
0119 "name": "Test Problem",
0120 "type": "toy",
0121 "objectives": [{"name": "f1"}, {"name": "f2"}]
0122 },
0123 "optimizer": {
0124 "name": "ax",
0125 "parameters": {"n_iterations": 50}
0126 }
0127 }
0128 result = extract_description_data(data, "full")
0129
0130 assert result["type"] == "full"
0131 assert result["summary"]["problem_name"] == "Test Problem"
0132 assert result["summary"]["problem_type"] == "toy"
0133 assert result["summary"]["optimizer"] == "ax"
0134 assert result["summary"]["n_iterations"] == 50
0135 assert result["summary"]["n_objectives"] == 2
0136
0137 def test_extract_problem_description(self):
0138 """Extract description from problem config."""
0139 data = {
0140 "problem": {
0141 "name": "Test Problem",
0142 "type": "custom",
0143 "objectives": [{"name": "f1"}]
0144 }
0145 }
0146 result = extract_description_data(data, "problem")
0147
0148 assert result["type"] == "problem"
0149 assert result["summary"]["name"] == "Test Problem"
0150 assert result["summary"]["type"] == "custom"
0151 assert result["summary"]["n_objectives"] == 1
0152
0153 def test_extract_optimizer_description(self):
0154 """Extract description from optimizer config."""
0155 data = {
0156 "optimizer": {
0157 "name": "ax",
0158 "type": "Bayesian",
0159 "parameters": {"n_iterations": 100}
0160 }
0161 }
0162 result = extract_description_data(data, "optimizer")
0163
0164 assert result["type"] == "optimizer"
0165 assert result["summary"]["name"] == "ax"
0166 assert result["summary"]["optimizer"] == "ax"
0167 assert result["summary"]["n_iterations"] == 100
0168
0169 def test_extract_design_description(self):
0170 """Extract description from canonical design config."""
0171 data = {
0172 "design_space": {
0173 "design_parameters": {
0174 "group1": {
0175 "parameters": {"x1": {}, "x2": {}}
0176 },
0177 "group2": {
0178 "parameters": {"y1": {}}
0179 }
0180 },
0181 "parameter_constraints": [
0182 {"name": "c1"},
0183 {"name": "c2"}
0184 ]
0185 }
0186 }
0187 result = extract_description_data(data, "design")
0188
0189 assert result["type"] == "design"
0190 assert result["summary"]["n_parameters"] == 3
0191 assert result["summary"]["n_constraints"] == 2
0192 assert set(result["summary"]["groups"]) == {"group1", "group2"}
0193
0194 def test_extract_with_parameter_constraints_key(self):
0195 """Handle canonical parameter_constraints key."""
0196 data = {
0197 "design_space": {
0198 "design_parameters": {
0199 "group1": {"parameters": {"x1": {}}}
0200 },
0201 "parameter_constraints": [{"name": "c1"}]
0202 }
0203 }
0204 result = extract_description_data(data, "design")
0205 assert result["summary"]["n_constraints"] == 1