|
1 | 1 | """Tests for feature flags functionality.""" |
2 | 2 |
|
| 3 | +import pytest |
| 4 | + |
3 | 5 | from comfy_api.feature_flags import ( |
4 | 6 | get_connection_feature, |
5 | 7 | supports_feature, |
6 | 8 | get_server_features, |
| 9 | + CLI_FEATURE_FLAG_REGISTRY, |
7 | 10 | SERVER_FEATURE_FLAGS, |
| 11 | + _coerce_flag_value, |
| 12 | + _parse_cli_feature_flags, |
8 | 13 | ) |
9 | 14 |
|
10 | 15 |
|
@@ -96,3 +101,83 @@ def test_empty_feature_flags_dict(self): |
96 | 101 | result = get_connection_feature(sockets_metadata, "sid1", "any_feature") |
97 | 102 | assert result is False |
98 | 103 | assert supports_feature(sockets_metadata, "sid1", "any_feature") is False |
| 104 | + |
| 105 | + |
| 106 | +class TestCoerceFlagValue: |
| 107 | + """Test suite for _coerce_flag_value.""" |
| 108 | + |
| 109 | + def test_registered_bool_true(self): |
| 110 | + assert _coerce_flag_value("show_signin_button", "true") is True |
| 111 | + assert _coerce_flag_value("show_signin_button", "True") is True |
| 112 | + |
| 113 | + def test_registered_bool_false(self): |
| 114 | + assert _coerce_flag_value("show_signin_button", "false") is False |
| 115 | + assert _coerce_flag_value("show_signin_button", "FALSE") is False |
| 116 | + |
| 117 | + def test_unregistered_key_stays_string(self): |
| 118 | + assert _coerce_flag_value("unknown_flag", "true") == "true" |
| 119 | + assert _coerce_flag_value("unknown_flag", "42") == "42" |
| 120 | + |
| 121 | + def test_bool_typo_raises(self): |
| 122 | + """Strict bool: typos like 'ture' or 'yes' must raise so the flag can be dropped.""" |
| 123 | + with pytest.raises(ValueError): |
| 124 | + _coerce_flag_value("show_signin_button", "ture") |
| 125 | + with pytest.raises(ValueError): |
| 126 | + _coerce_flag_value("show_signin_button", "yes") |
| 127 | + with pytest.raises(ValueError): |
| 128 | + _coerce_flag_value("show_signin_button", "1") |
| 129 | + with pytest.raises(ValueError): |
| 130 | + _coerce_flag_value("show_signin_button", "") |
| 131 | + |
| 132 | + def test_failed_int_coercion_raises(self, monkeypatch): |
| 133 | + """Malformed values for typed flags must raise; caller decides what to do.""" |
| 134 | + monkeypatch.setitem( |
| 135 | + CLI_FEATURE_FLAG_REGISTRY, |
| 136 | + "test_int_flag", |
| 137 | + {"type": "int", "default": 0, "description": "test"}, |
| 138 | + ) |
| 139 | + with pytest.raises(ValueError): |
| 140 | + _coerce_flag_value("test_int_flag", "not_a_number") |
| 141 | + |
| 142 | + |
| 143 | +class TestParseCliFeatureFlags: |
| 144 | + """Test suite for _parse_cli_feature_flags.""" |
| 145 | + |
| 146 | + def test_single_flag(self, monkeypatch): |
| 147 | + monkeypatch.setattr("comfy_api.feature_flags.args", type("Args", (), {"feature_flag": ["show_signin_button=true"]})()) |
| 148 | + result = _parse_cli_feature_flags() |
| 149 | + assert result == {"show_signin_button": True} |
| 150 | + |
| 151 | + def test_missing_equals_defaults_to_true(self, monkeypatch): |
| 152 | + """Bare flag without '=' is treated as the string 'true' (and coerced if registered).""" |
| 153 | + monkeypatch.setattr("comfy_api.feature_flags.args", type("Args", (), {"feature_flag": ["show_signin_button", "valid=1"]})()) |
| 154 | + result = _parse_cli_feature_flags() |
| 155 | + assert result == {"show_signin_button": True, "valid": "1"} |
| 156 | + |
| 157 | + def test_empty_key_skipped(self, monkeypatch): |
| 158 | + monkeypatch.setattr("comfy_api.feature_flags.args", type("Args", (), {"feature_flag": ["=value", "valid=1"]})()) |
| 159 | + result = _parse_cli_feature_flags() |
| 160 | + assert result == {"valid": "1"} |
| 161 | + |
| 162 | + def test_invalid_bool_value_dropped(self, monkeypatch, caplog): |
| 163 | + """A typo'd bool value must be dropped entirely, not silently set to False |
| 164 | + and not stored as a raw string. A warning must be logged.""" |
| 165 | + monkeypatch.setattr( |
| 166 | + "comfy_api.feature_flags.args", |
| 167 | + type("Args", (), {"feature_flag": ["show_signin_button=ture", "valid=1"]})(), |
| 168 | + ) |
| 169 | + with caplog.at_level("WARNING"): |
| 170 | + result = _parse_cli_feature_flags() |
| 171 | + assert result == {"valid": "1"} |
| 172 | + assert "show_signin_button" not in result |
| 173 | + assert any("show_signin_button" in r.message and "drop" in r.message.lower() for r in caplog.records) |
| 174 | + |
| 175 | + |
| 176 | +class TestCliFeatureFlagRegistry: |
| 177 | + """Test suite for the CLI feature flag registry.""" |
| 178 | + |
| 179 | + def test_registry_entries_have_required_fields(self): |
| 180 | + for key, info in CLI_FEATURE_FLAG_REGISTRY.items(): |
| 181 | + assert "type" in info, f"{key} missing 'type'" |
| 182 | + assert "default" in info, f"{key} missing 'default'" |
| 183 | + assert "description" in info, f"{key} missing 'description'" |
0 commit comments