Coverage for tests / unit / utils / test_native_parsers.py: 100%

49 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-04-03 18:53 +0000

1"""Unit tests for native_parsers.py error handling.""" 

2 

3from __future__ import annotations 

4 

5from pathlib import Path 

6from unittest.mock import mock_open, patch 

7 

8from assertpy import assert_that 

9 

10from lintro.utils.native_parsers import _load_json_config, _load_native_tool_config 

11 

12# ============================================================================= 

13# _load_json_config - Error Handling 

14# ============================================================================= 

15 

16 

17def test_load_json_config_parse_error_logs_warning(tmp_path: Path) -> None: 

18 """Verify JSON parse error logs warning with details. 

19 

20 Args: 

21 tmp_path: Pytest temporary directory fixture. 

22 """ 

23 config_file = tmp_path / "bad.json" 

24 config_file.write_text("{ invalid json }") 

25 

26 with patch("lintro.utils.native_parsers.logger") as mock_logger: 

27 result = _load_json_config(config_file) 

28 

29 assert_that(result).is_equal_to({}) 

30 mock_logger.warning.assert_called_once() 

31 warning_msg = mock_logger.warning.call_args[0][0] 

32 assert_that(warning_msg).contains("Failed to parse JSON config") 

33 assert_that(warning_msg).contains(str(config_file)) 

34 

35 

36def test_load_json_config_file_not_found_logs_debug(tmp_path: Path) -> None: 

37 """Verify missing file logs debug message. 

38 

39 Args: 

40 tmp_path: Pytest temporary directory fixture. 

41 """ 

42 missing_file = tmp_path / "missing.json" 

43 

44 with patch("lintro.utils.native_parsers.logger") as mock_logger: 

45 result = _load_json_config(missing_file) 

46 

47 assert_that(result).is_equal_to({}) 

48 mock_logger.debug.assert_called_once() 

49 debug_msg = mock_logger.debug.call_args[0][0] 

50 assert_that(debug_msg).contains("Config file not found") 

51 

52 

53def test_load_json_config_valid_returns_dict(tmp_path: Path) -> None: 

54 """Verify valid JSON returns parsed dict. 

55 

56 Args: 

57 tmp_path: Pytest temporary directory fixture. 

58 """ 

59 config_file = tmp_path / "valid.json" 

60 config_file.write_text('{"key": "value"}') 

61 

62 result = _load_json_config(config_file) 

63 

64 assert_that(result).is_equal_to({"key": "value"}) 

65 

66 

67def test_load_json_config_non_dict_returns_empty(tmp_path: Path) -> None: 

68 """Verify non-dict JSON returns empty dict. 

69 

70 Args: 

71 tmp_path: Pytest temporary directory fixture. 

72 """ 

73 config_file = tmp_path / "array.json" 

74 config_file.write_text('["item1", "item2"]') 

75 

76 result = _load_json_config(config_file) 

77 

78 assert_that(result).is_equal_to({}) 

79 

80 

81# ============================================================================= 

82# _load_native_tool_config - YAML Parse Errors (yamllint) 

83# ============================================================================= 

84 

85 

86def test_load_yamllint_config_yaml_error_logs_warning() -> None: 

87 """Verify YAML parse error for yamllint config logs warning.""" 

88 with ( 

89 patch("lintro.utils.native_parsers.Path.exists", return_value=True), 

90 patch( 

91 "builtins.open", 

92 mock_open(read_data="invalid: yaml: content: ["), 

93 ), 

94 patch("lintro.utils.native_parsers.yaml") as mock_yaml, 

95 patch("lintro.utils.native_parsers.logger") as mock_logger, 

96 ): 

97 # Make yaml.YAMLError available for isinstance check 

98 mock_yaml.YAMLError = type("YAMLError", (Exception,), {}) 

99 mock_yaml.safe_load.side_effect = mock_yaml.YAMLError("bad yaml") 

100 

101 result = _load_native_tool_config("yamllint") 

102 

103 assert_that(result).is_equal_to({}) 

104 mock_logger.warning.assert_called() 

105 

106 

107def test_load_yamllint_config_os_error_returns_empty() -> None: 

108 """Verify OS error reading yamllint config returns empty dict.""" 

109 with ( 

110 patch("lintro.utils.native_parsers.Path.exists", return_value=True), 

111 patch("builtins.open", side_effect=OSError("Permission denied")), 

112 patch("lintro.utils.native_parsers.yaml") as mock_yaml, 

113 ): 

114 mock_yaml.YAMLError = type("YAMLError", (Exception,), {}) 

115 

116 result = _load_native_tool_config("yamllint") 

117 

118 # OS errors should return empty dict gracefully 

119 assert_that(result).is_equal_to({}) 

120 

121 

122# ============================================================================= 

123# _load_native_tool_config - Markdownlint Parse Errors 

124# ============================================================================= 

125 

126 

127def test_load_markdownlint_missing_config_returns_empty() -> None: 

128 """Verify missing markdownlint config returns empty dict.""" 

129 with patch("lintro.utils.native_parsers.Path.exists", return_value=False): 

130 result = _load_native_tool_config("markdownlint") 

131 assert_that(result).is_equal_to({})