Coverage for tests / unit / parsers / base_parser / test_safe_parse.py: 98%

47 statements  

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

1"""Tests for safe_parse_items function.""" 

2 

3from __future__ import annotations 

4 

5from dataclasses import dataclass 

6from unittest.mock import patch 

7 

8from assertpy import assert_that 

9 

10from lintro.parsers.base_issue import BaseIssue 

11from lintro.parsers.base_parser import safe_parse_items 

12 

13 

14@dataclass 

15class TestIssue(BaseIssue): 

16 """Simple test issue for safe_parse_items tests.""" 

17 

18 pass 

19 

20 

21def test_safe_parse_items_success() -> None: 

22 """Parse all valid items successfully.""" 

23 items: list[object] = [{"file": "a.py", "line": 1}, {"file": "b.py", "line": 2}] 

24 

25 def parse_func(item: dict[str, object]) -> TestIssue: 

26 # Values are validated at runtime; use explicit type checks for mypy 

27 line_val = item["line"] 

28 line = line_val if isinstance(line_val, int) else 0 

29 return TestIssue(file=str(item["file"]), line=line) 

30 

31 results: list[TestIssue] = safe_parse_items(items, parse_func, "test_tool") 

32 assert_that(results).is_length(2) 

33 assert_that(results[0].file).is_equal_to("a.py") 

34 

35 

36def test_safe_parse_items_skips_non_dict() -> None: 

37 """Skip non-dictionary items.""" 

38 items: list[object] = [{"file": "a.py"}, "not_a_dict", 123] 

39 

40 def parse_func(item: dict[str, object]) -> TestIssue: 

41 return TestIssue(file=str(item.get("file", ""))) 

42 

43 with patch("lintro.parsers.base_parser.logger"): 

44 results: list[TestIssue] = safe_parse_items(items, parse_func, "test_tool") 

45 assert_that(results).is_length(1) 

46 

47 

48def test_safe_parse_items_handles_parse_errors() -> None: 

49 """Continue parsing after encountering errors.""" 

50 items: list[object] = [{"file": "a.py"}, {"bad": "data"}, {"file": "c.py"}] 

51 

52 def parse_func(item: dict[str, object]) -> TestIssue | None: 

53 if "file" not in item: 

54 raise KeyError("file") 

55 return TestIssue(file=str(item["file"])) 

56 

57 with patch("lintro.parsers.base_parser.logger"): 

58 results: list[TestIssue] = safe_parse_items(items, parse_func, "test_tool") 

59 assert_that(results).is_length(2) 

60 

61 

62def test_safe_parse_items_skips_none_results() -> None: 

63 """Skip items where parse function returns None.""" 

64 items: list[object] = [{"file": "a.py"}, {"skip": True}, {"file": "c.py"}] 

65 

66 def parse_func(item: dict[str, object]) -> TestIssue | None: 

67 if item.get("skip"): 

68 return None 

69 return TestIssue(file=str(item.get("file", ""))) 

70 

71 results: list[TestIssue] = safe_parse_items(items, parse_func, "test_tool") 

72 assert_that(results).is_length(2) 

73 

74 

75def test_safe_parse_items_empty_list() -> None: 

76 """Handle empty items list.""" 

77 

78 def parse_func(item: dict[str, object]) -> TestIssue: 

79 return TestIssue(file=str(item.get("file", ""))) 

80 

81 results: list[TestIssue] = safe_parse_items([], parse_func, "test_tool") 

82 assert_that(results).is_empty()