"""Pure-function tests for hardware warning checks — zero mocking needed.""" from unittest.mock import patch from local_deep_research.web.warning_checks.hardware import ( LOCAL_PROVIDERS, check_high_context, check_legacy_server_config, check_model_mismatch, ) class TestLocalProviders: """Verify the LOCAL_PROVIDERS constant.""" def test_contains_expected_providers(self): assert LOCAL_PROVIDERS == frozenset({"ollama", "llamacpp", "lmstudio"}) def test_is_frozenset(self): assert isinstance(LOCAL_PROVIDERS, frozenset) class TestCheckHighContext: """Tests for check_high_context.""" def test_warns_local_provider_above_8192(self): result = check_high_context("ollama", 16384, dismissed=False) assert result is not None assert result["type"] == "high_context" assert "16,384" in result["message"] def test_no_warning_at_8192(self): assert check_high_context("ollama", 8192, dismissed=False) is None def test_no_warning_below_8192(self): assert check_high_context("ollama", 4096, dismissed=False) is None def test_no_warning_non_local_provider(self): assert check_high_context("openai", 32000, dismissed=False) is None def test_no_warning_when_dismissed(self): assert check_high_context("ollama", 16384, dismissed=True) is None def test_all_local_providers_trigger(self): for provider in LOCAL_PROVIDERS: result = check_high_context(provider, 16384, dismissed=False) assert result is not None, f"{provider} should trigger warning" def test_warns_at_boundary_8193(self): """8193 is just above the 8192 threshold — should trigger.""" result = check_high_context("ollama", 8193, dismissed=False) assert result is not None assert result["type"] == "high_context" def test_context_size_in_message(self): result = check_high_context("ollama", 16384, dismissed=False) assert "16,384" in result["message"] def test_warning_dict_has_all_required_keys(self): result = check_high_context("ollama", 16384, dismissed=False) assert set(result.keys()) == { "type", "icon", "title", "message", "dismissKey", "actionUrl", "actionLabel", } def test_dismiss_key(self): result = check_high_context("ollama", 16384, dismissed=False) assert result["dismissKey"] == "app.warnings.dismiss_high_context" def test_warning_dict_has_action_link(self): result = check_high_context("ollama", 16384, dismissed=False) assert result["actionUrl"] == "/metrics/context-overflow" assert result["actionLabel"] == "View context metrics" class TestCheckModelMismatch: """Tests for check_model_mismatch.""" def test_warns_70b_model_high_context(self): result = check_model_mismatch( "ollama", "llama3.1:70b", 16384, dismissed=False ) assert result is not None assert result["type"] == "model_mismatch" def test_case_insensitive_70b(self): result = check_model_mismatch( "ollama", "Mixtral-70B-v2", 16384, dismissed=False ) assert result is not None def test_no_warning_small_model(self): result = check_model_mismatch( "ollama", "llama3:8b", 16384, dismissed=False ) assert result is None def test_no_warning_empty_model(self): result = check_model_mismatch("ollama", "", 16384, dismissed=False) assert result is None def test_no_warning_non_local_provider(self): result = check_model_mismatch( "openai", "gpt-4-70b-fake", 16384, dismissed=False ) assert result is None def test_no_warning_at_boundary_8192(self): """Context exactly at 8192 should NOT trigger (uses <=).""" result = check_model_mismatch( "ollama", "llama3.1:70b", 8192, dismissed=False ) assert result is None def test_warns_at_boundary_8193(self): """Context at 8193 is just above the threshold — should trigger.""" result = check_model_mismatch( "ollama", "llama3.1:70b", 8193, dismissed=False ) assert result is not None assert result["type"] == "model_mismatch" def test_no_warning_low_context(self): result = check_model_mismatch( "ollama", "llama3.1:70b", 4096, dismissed=False ) assert result is None def test_no_warning_when_dismissed(self): result = check_model_mismatch( "ollama", "llama3.1:70b", 16384, dismissed=True ) assert result is None def test_model_name_in_message(self): result = check_model_mismatch( "ollama", "deepseek-r1:70b", 16384, dismissed=False ) assert "deepseek-r1:70b" in result["message"] def test_context_value_in_message(self): result = check_model_mismatch( "ollama", "llama3.1:70b", 32000, dismissed=False ) assert "32,000" in result["message"] def test_warning_dict_has_all_required_keys(self): result = check_model_mismatch( "ollama", "llama3.1:70b", 16384, dismissed=False ) assert set(result.keys()) == { "type", "icon", "title", "message", "dismissKey", "actionUrl", "actionLabel", } def test_no_warning_none_model(self): """None model should not crash — treated as falsy like empty string.""" result = check_model_mismatch("ollama", None, 16384, dismissed=False) assert result is None def test_dismiss_key(self): result = check_model_mismatch( "ollama", "llama3.1:70b", 16384, dismissed=False ) assert result["dismissKey"] == "app.warnings.dismiss_model_mismatch" def test_warning_dict_has_action_link(self): result = check_model_mismatch( "ollama", "llama3.1:70b", 16384, dismissed=False ) assert result["actionUrl"] == "/metrics/context-overflow" assert result["actionLabel"] == "View context metrics" class TestCheckLegacyServerConfig: """Tests for check_legacy_server_config.""" def test_no_warning_when_dismissed(self, tmp_path): config_file = tmp_path / "server_config.json" config_file.write_text('{"port": 9999}', encoding="utf-8") with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): assert check_legacy_server_config(dismissed=True) is None def test_no_warning_when_file_missing(self, tmp_path): config_file = tmp_path / "server_config.json" with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): assert check_legacy_server_config(dismissed=False) is None def test_no_warning_when_all_defaults(self, tmp_path): """File exists but all values match defaults — no warning.""" import json from local_deep_research.web.server_config import _DEFAULTS config_file = tmp_path / "server_config.json" config_file.write_text(json.dumps(_DEFAULTS), encoding="utf-8") with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): assert check_legacy_server_config(dismissed=False) is None def test_no_warning_when_empty_object(self, tmp_path): """Empty JSON object has no customizations — no warning.""" config_file = tmp_path / "server_config.json" config_file.write_text("{}", encoding="utf-8") with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): assert check_legacy_server_config(dismissed=False) is None def test_warns_when_non_default_value(self, tmp_path): """File has a customized value — should warn.""" config_file = tmp_path / "server_config.json" config_file.write_text('{"port": 9999}', encoding="utf-8") with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): result = check_legacy_server_config(dismissed=False) assert result is not None assert result["type"] == "legacy_server_config" assert result["dismissKey"] == "app.warnings.dismiss_legacy_config" assert set(result.keys()) == { "type", "icon", "title", "message", "dismissKey", } def test_warns_when_unrecognized_keys(self, tmp_path): """File has unrecognized keys — should warn.""" config_file = tmp_path / "server_config.json" config_file.write_text('{"custom_thing": true}', encoding="utf-8") with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): result = check_legacy_server_config(dismissed=False) assert result is not None assert result["type"] == "legacy_server_config" def test_no_warning_on_malformed_json(self, tmp_path): """Malformed JSON should not crash — just return None.""" config_file = tmp_path / "server_config.json" config_file.write_text("not valid json", encoding="utf-8") with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): assert check_legacy_server_config(dismissed=False) is None def test_no_warning_on_non_dict_json(self, tmp_path): """JSON array instead of object should not crash — just return None.""" config_file = tmp_path / "server_config.json" config_file.write_text("[1, 2, 3]", encoding="utf-8") with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): assert check_legacy_server_config(dismissed=False) is None def test_warns_with_partial_defaults_and_one_custom(self, tmp_path): """Mix of default and non-default values — should warn on the mismatch.""" import json config_file = tmp_path / "server_config.json" config_file.write_text( json.dumps({"host": "0.0.0.0", "port": 5000, "debug": True}), encoding="utf-8", ) with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): result = check_legacy_server_config(dismissed=False) assert result is not None assert result["type"] == "legacy_server_config" def test_warns_unrecognized_keys_with_default_recognized(self, tmp_path): """All recognized keys match defaults but an unknown key exists — should warn.""" import json from local_deep_research.web.server_config import _DEFAULTS data = dict(_DEFAULTS) data["unknown"] = "val" config_file = tmp_path / "server_config.json" config_file.write_text(json.dumps(data), encoding="utf-8") with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): result = check_legacy_server_config(dismissed=False) assert result is not None assert result["type"] == "legacy_server_config" def test_warns_when_value_is_none(self, tmp_path): """null value differs from default — should warn.""" config_file = tmp_path / "server_config.json" config_file.write_text('{"port": null}', encoding="utf-8") with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): result = check_legacy_server_config(dismissed=False) assert result is not None assert result["type"] == "legacy_server_config" def test_warns_when_type_differs_from_default(self, tmp_path): """String '5000' != int 5000 — strict comparison should catch this.""" config_file = tmp_path / "server_config.json" config_file.write_text('{"port": "5000"}', encoding="utf-8") with patch( "local_deep_research.web.server_config.get_server_config_path", return_value=config_file, ): result = check_legacy_server_config(dismissed=False) assert result is not None assert result["type"] == "legacy_server_config"