|
| 1 | +#!/usr/bin/env python3 |
| 2 | +""" |
| 3 | +error_messages ユニットテスト |
| 4 | +============================= |
| 5 | +
|
| 6 | +config/error_messages.py のユニットテスト。 |
| 7 | +各エラーメッセージ生成関数の動作を検証: |
| 8 | +- invalid_level_message |
| 9 | +- unknown_level_message |
| 10 | +- config_key_missing_message |
| 11 | +- config_invalid_value_message |
| 12 | +- config_section_missing_message |
| 13 | +- initialization_failed_message |
| 14 | +- file_not_found_message |
| 15 | +- invalid_json_message |
| 16 | +- directory_not_found_message |
| 17 | +""" |
| 18 | + |
| 19 | +from pathlib import Path |
| 20 | + |
| 21 | +import pytest |
| 22 | + |
| 23 | +from config.error_messages import ( |
| 24 | + config_invalid_value_message, |
| 25 | + config_key_missing_message, |
| 26 | + config_section_missing_message, |
| 27 | + directory_not_found_message, |
| 28 | + file_not_found_message, |
| 29 | + initialization_failed_message, |
| 30 | + invalid_json_message, |
| 31 | + invalid_level_message, |
| 32 | + unknown_level_message, |
| 33 | +) |
| 34 | + |
| 35 | + |
| 36 | +# ============================================================================= |
| 37 | +# TestInvalidLevelMessage |
| 38 | +# ============================================================================= |
| 39 | + |
| 40 | + |
| 41 | +class TestInvalidLevelMessage: |
| 42 | + """invalid_level_messageのテスト""" |
| 43 | + |
| 44 | + @pytest.mark.unit |
| 45 | + def test_without_valid_levels(self): |
| 46 | + """有効レベルなしのメッセージ""" |
| 47 | + result = invalid_level_message("invalid_level") |
| 48 | + assert result == "Invalid level: 'invalid_level'" |
| 49 | + |
| 50 | + @pytest.mark.unit |
| 51 | + def test_with_valid_levels(self): |
| 52 | + """有効レベルありのメッセージ""" |
| 53 | + valid = ["weekly", "monthly", "annual"] |
| 54 | + result = invalid_level_message("bad", valid) |
| 55 | + assert "Invalid level: 'bad'" in result |
| 56 | + assert "weekly" in result |
| 57 | + assert "monthly" in result |
| 58 | + assert "annual" in result |
| 59 | + |
| 60 | + @pytest.mark.unit |
| 61 | + def test_with_single_valid_level(self): |
| 62 | + """単一の有効レベル""" |
| 63 | + result = invalid_level_message("bad", ["weekly"]) |
| 64 | + assert "Invalid level: 'bad'" in result |
| 65 | + assert "weekly" in result |
| 66 | + |
| 67 | + @pytest.mark.unit |
| 68 | + def test_with_empty_valid_levels(self): |
| 69 | + """空の有効レベルリスト""" |
| 70 | + result = invalid_level_message("bad", []) |
| 71 | + # 空リストはFalsyなので、valid_levelsなしと同じ扱い |
| 72 | + assert result == "Invalid level: 'bad'" |
| 73 | + |
| 74 | + @pytest.mark.unit |
| 75 | + def test_with_none_valid_levels(self): |
| 76 | + """None の有効レベル""" |
| 77 | + result = invalid_level_message("bad", None) |
| 78 | + assert result == "Invalid level: 'bad'" |
| 79 | + |
| 80 | + @pytest.mark.unit |
| 81 | + def test_special_characters_in_level(self): |
| 82 | + """特殊文字を含むレベル名""" |
| 83 | + result = invalid_level_message("level<script>") |
| 84 | + assert "level<script>" in result |
| 85 | + |
| 86 | + |
| 87 | +# ============================================================================= |
| 88 | +# TestUnknownLevelMessage |
| 89 | +# ============================================================================= |
| 90 | + |
| 91 | + |
| 92 | +class TestUnknownLevelMessage: |
| 93 | + """unknown_level_messageのテスト""" |
| 94 | + |
| 95 | + @pytest.mark.unit |
| 96 | + def test_basic_message(self): |
| 97 | + """基本的なメッセージ""" |
| 98 | + result = unknown_level_message("unknown") |
| 99 | + assert result == "Unknown level: 'unknown'" |
| 100 | + |
| 101 | + @pytest.mark.unit |
| 102 | + def test_empty_level(self): |
| 103 | + """空のレベル名""" |
| 104 | + result = unknown_level_message("") |
| 105 | + assert result == "Unknown level: ''" |
| 106 | + |
| 107 | + @pytest.mark.unit |
| 108 | + def test_level_with_spaces(self): |
| 109 | + """スペースを含むレベル名""" |
| 110 | + result = unknown_level_message("weekly level") |
| 111 | + assert "weekly level" in result |
| 112 | + |
| 113 | + |
| 114 | +# ============================================================================= |
| 115 | +# TestConfigKeyMissingMessage |
| 116 | +# ============================================================================= |
| 117 | + |
| 118 | + |
| 119 | +class TestConfigKeyMissingMessage: |
| 120 | + """config_key_missing_messageのテスト""" |
| 121 | + |
| 122 | + @pytest.mark.unit |
| 123 | + def test_basic_message(self): |
| 124 | + """基本的なメッセージ""" |
| 125 | + result = config_key_missing_message("loops_path") |
| 126 | + assert result == "Required configuration key missing: 'loops_path'" |
| 127 | + |
| 128 | + @pytest.mark.unit |
| 129 | + def test_nested_key(self): |
| 130 | + """ネストされたキー名""" |
| 131 | + result = config_key_missing_message("paths.loops_dir") |
| 132 | + assert "paths.loops_dir" in result |
| 133 | + |
| 134 | + |
| 135 | +# ============================================================================= |
| 136 | +# TestConfigInvalidValueMessage |
| 137 | +# ============================================================================= |
| 138 | + |
| 139 | + |
| 140 | +class TestConfigInvalidValueMessage: |
| 141 | + """config_invalid_value_messageのテスト""" |
| 142 | + |
| 143 | + @pytest.mark.unit |
| 144 | + def test_with_string_value(self): |
| 145 | + """文字列値の場合""" |
| 146 | + result = config_invalid_value_message("threshold", "int", "five") |
| 147 | + assert "threshold" in result |
| 148 | + assert "expected int" in result |
| 149 | + assert "str" in result |
| 150 | + |
| 151 | + @pytest.mark.unit |
| 152 | + def test_with_int_value(self): |
| 153 | + """整数値の場合""" |
| 154 | + result = config_invalid_value_message("path", "str", 123) |
| 155 | + assert "path" in result |
| 156 | + assert "expected str" in result |
| 157 | + assert "int" in result |
| 158 | + |
| 159 | + @pytest.mark.unit |
| 160 | + def test_with_list_value(self): |
| 161 | + """リスト値の場合""" |
| 162 | + result = config_invalid_value_message("count", "int", [1, 2, 3]) |
| 163 | + assert "count" in result |
| 164 | + assert "list" in result |
| 165 | + |
| 166 | + @pytest.mark.unit |
| 167 | + def test_with_none_value(self): |
| 168 | + """None値の場合""" |
| 169 | + result = config_invalid_value_message("required", "str", None) |
| 170 | + assert "required" in result |
| 171 | + assert "NoneType" in result |
| 172 | + |
| 173 | + |
| 174 | +# ============================================================================= |
| 175 | +# TestConfigSectionMissingMessage |
| 176 | +# ============================================================================= |
| 177 | + |
| 178 | + |
| 179 | +class TestConfigSectionMissingMessage: |
| 180 | + """config_section_missing_messageのテスト""" |
| 181 | + |
| 182 | + @pytest.mark.unit |
| 183 | + def test_basic_message(self): |
| 184 | + """基本的なメッセージ""" |
| 185 | + result = config_section_missing_message("paths") |
| 186 | + assert result == "'paths' section missing in config.json" |
| 187 | + |
| 188 | + @pytest.mark.unit |
| 189 | + def test_levels_section(self): |
| 190 | + """levelsセクション""" |
| 191 | + result = config_section_missing_message("levels") |
| 192 | + assert "'levels' section missing" in result |
| 193 | + |
| 194 | + |
| 195 | +# ============================================================================= |
| 196 | +# TestInitializationFailedMessage |
| 197 | +# ============================================================================= |
| 198 | + |
| 199 | + |
| 200 | +class TestInitializationFailedMessage: |
| 201 | + """initialization_failed_messageのテスト""" |
| 202 | + |
| 203 | + @pytest.mark.unit |
| 204 | + def test_with_value_error(self): |
| 205 | + """ValueError の場合""" |
| 206 | + error = ValueError("invalid value") |
| 207 | + result = initialization_failed_message("ConfigLoader", error) |
| 208 | + assert "Failed to initialize ConfigLoader" in result |
| 209 | + assert "invalid value" in result |
| 210 | + |
| 211 | + @pytest.mark.unit |
| 212 | + def test_with_file_not_found_error(self): |
| 213 | + """FileNotFoundError の場合""" |
| 214 | + error = FileNotFoundError("config.json not found") |
| 215 | + result = initialization_failed_message("DigestConfig", error) |
| 216 | + assert "Failed to initialize DigestConfig" in result |
| 217 | + assert "config.json not found" in result |
| 218 | + |
| 219 | + @pytest.mark.unit |
| 220 | + def test_with_generic_exception(self): |
| 221 | + """一般的なException""" |
| 222 | + error = Exception("unknown error") |
| 223 | + result = initialization_failed_message("Component", error) |
| 224 | + assert "Failed to initialize Component" in result |
| 225 | + |
| 226 | + |
| 227 | +# ============================================================================= |
| 228 | +# TestFileNotFoundMessage |
| 229 | +# ============================================================================= |
| 230 | + |
| 231 | + |
| 232 | +class TestFileNotFoundMessage: |
| 233 | + """file_not_found_messageのテスト""" |
| 234 | + |
| 235 | + @pytest.mark.unit |
| 236 | + def test_with_path_object(self): |
| 237 | + """Pathオブジェクトの場合""" |
| 238 | + path = Path("/tmp/missing.json") |
| 239 | + result = file_not_found_message(path) |
| 240 | + assert "File not found:" in result |
| 241 | + assert "missing.json" in result |
| 242 | + |
| 243 | + @pytest.mark.unit |
| 244 | + def test_with_relative_path(self): |
| 245 | + """相対パスの場合""" |
| 246 | + path = Path("config/config.json") |
| 247 | + result = file_not_found_message(path) |
| 248 | + assert "config.json" in result |
| 249 | + |
| 250 | + @pytest.mark.unit |
| 251 | + def test_with_windows_path(self): |
| 252 | + """Windowsパスの場合""" |
| 253 | + path = Path("C:/Users/test/file.json") |
| 254 | + result = file_not_found_message(path) |
| 255 | + assert "file.json" in result |
| 256 | + |
| 257 | + |
| 258 | +# ============================================================================= |
| 259 | +# TestInvalidJsonMessage |
| 260 | +# ============================================================================= |
| 261 | + |
| 262 | + |
| 263 | +class TestInvalidJsonMessage: |
| 264 | + """invalid_json_messageのテスト""" |
| 265 | + |
| 266 | + @pytest.mark.unit |
| 267 | + def test_with_decode_error(self): |
| 268 | + """デコードエラーの場合""" |
| 269 | + path = Path("/tmp/bad.json") |
| 270 | + error = ValueError("Expecting property name enclosed in double quotes") |
| 271 | + result = invalid_json_message(path, error) |
| 272 | + assert "Invalid JSON" in result |
| 273 | + assert "bad.json" in result |
| 274 | + assert "double quotes" in result |
| 275 | + |
| 276 | + @pytest.mark.unit |
| 277 | + def test_path_included_in_message(self): |
| 278 | + """パスがメッセージに含まれる""" |
| 279 | + path = Path("/data/config.json") |
| 280 | + error = Exception("parse error") |
| 281 | + result = invalid_json_message(path, error) |
| 282 | + assert "config.json" in result |
| 283 | + |
| 284 | + |
| 285 | +# ============================================================================= |
| 286 | +# TestDirectoryNotFoundMessage |
| 287 | +# ============================================================================= |
| 288 | + |
| 289 | + |
| 290 | +class TestDirectoryNotFoundMessage: |
| 291 | + """directory_not_found_messageのテスト""" |
| 292 | + |
| 293 | + @pytest.mark.unit |
| 294 | + def test_basic_message(self): |
| 295 | + """基本的なメッセージ""" |
| 296 | + path = Path("/tmp/missing_dir") |
| 297 | + result = directory_not_found_message(path) |
| 298 | + assert "Directory not found:" in result |
| 299 | + assert "missing_dir" in result |
| 300 | + |
| 301 | + @pytest.mark.unit |
| 302 | + def test_with_nested_path(self): |
| 303 | + """ネストされたパス""" |
| 304 | + path = Path("/data/Digests/1_Weekly") |
| 305 | + result = directory_not_found_message(path) |
| 306 | + assert "1_Weekly" in result |
0 commit comments