Coverage for tests / unit / parsers / test_ruff_parser_additional.py: 100%

53 statements  

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

1"""Additional tests for Ruff parser coverage gaps.""" 

2 

3from __future__ import annotations 

4 

5from assertpy import assert_that 

6 

7from lintro.parsers.ruff.ruff_parser import parse_ruff_output 

8 

9 

10def test_parse_ruff_output_plain_json_array() -> None: 

11 """Parse a simple JSON array output into issues list.""" 

12 output = ( 

13 "[\n" 

14 ' {"filename": "a.py", "location": {"row": 1, "column": 2},' 

15 ' "code": "E1", "message": "x"}\n' 

16 "]" 

17 ) 

18 issues = parse_ruff_output(output) 

19 assert_that(len(issues)).is_equal_to(1) 

20 assert_that(issues[0].file.endswith("a.py")).is_true() 

21 

22 

23def test_parse_ruff_output_empty_and_malformed_line_skipped() -> None: 

24 """Skip empty and malformed lines in JSONL output gracefully.""" 

25 jl = ( 

26 "\n\n" # empties ignored 

27 '{"filename":"b.py","location":{"row":2,"column":1},"code":"F","message":"m"}\n' 

28 "not-json\n" # malformed line skipped 

29 ) 

30 issues = parse_ruff_output(jl) 

31 files = [i.file for i in issues] 

32 assert_that(files).contains("b.py") 

33 

34 

35# ============================================================================= 

36# Edge case tests 

37# ============================================================================= 

38 

39 

40def test_parse_ruff_output_unicode_file_path() -> None: 

41 """Handle Unicode characters in file paths.""" 

42 output = ( 

43 '{"filename": "src/código/módulo.py", "location": {"row": 1, "column": 1}, ' 

44 '"code": "E501", "message": "line too long"}' 

45 ) 

46 issues = parse_ruff_output(output) 

47 assert_that(issues).is_length(1) 

48 assert_that(issues[0].file).contains("módulo.py") 

49 

50 

51def test_parse_ruff_output_file_path_with_spaces() -> None: 

52 """Handle file paths with spaces.""" 

53 output = ( 

54 '{"filename": "my project/source files/main.py", ' 

55 '"location": {"row": 5, "column": 10}, "code": "F401", "message": "unused"}' 

56 ) 

57 issues = parse_ruff_output(output) 

58 assert_that(issues).is_length(1) 

59 assert_that(issues[0].file).contains("my project") 

60 

61 

62def test_parse_ruff_output_special_chars_in_message() -> None: 

63 """Handle special characters in error messages.""" 

64 output = ( 

65 '{"filename": "test.py", "location": {"row": 1, "column": 1}, ' 

66 '"code": "E501", "message": "Line contains \\"quotes\\" and <brackets>"}' 

67 ) 

68 issues = parse_ruff_output(output) 

69 assert_that(issues).is_length(1) 

70 assert_that(issues[0].message).contains("quotes") 

71 

72 

73def test_parse_ruff_output_null_values_handled() -> None: 

74 """Handle null values in JSON output gracefully.""" 

75 output = ( 

76 '{"filename": "test.py", "location": {"row": 1, "column": null}, ' 

77 '"code": "E501", "message": "error"}' 

78 ) 

79 issues = parse_ruff_output(output) 

80 # Should either parse with default column or handle gracefully 

81 assert_that(issues).is_length(1) 

82 

83 

84def test_parse_ruff_output_very_long_file_path() -> None: 

85 """Handle very long file paths.""" 

86 long_path = "src/" + "nested/" * 50 + "deep_file.py" 

87 output = ( 

88 f'{{"filename": "{long_path}", "location": {{"row": 1, "column": 1}}, ' 

89 '"code": "E501", "message": "error"}' 

90 ) 

91 issues = parse_ruff_output(output) 

92 assert_that(issues).is_length(1) 

93 assert_that(issues[0].file).contains("deep_file.py") 

94 

95 

96def test_parse_ruff_output_extremely_long_message() -> None: 

97 """Handle extremely long error messages.""" 

98 long_message = "x" * 10000 

99 output = ( 

100 f'{{"filename": "test.py", "location": {{"row": 1, "column": 1}}, ' 

101 f'"code": "E501", "message": "{long_message}"}}' 

102 ) 

103 issues = parse_ruff_output(output) 

104 assert_that(issues).is_length(1) 

105 assert_that(len(issues[0].message)).is_equal_to(10000) 

106 

107 

108def test_parse_ruff_output_zero_line_number() -> None: 

109 """Handle zero line number (edge case).""" 

110 output = ( 

111 '{"filename": "test.py", "location": {"row": 0, "column": 1}, ' 

112 '"code": "E501", "message": "error"}' 

113 ) 

114 issues = parse_ruff_output(output) 

115 assert_that(issues).is_length(1) 

116 assert_that(issues[0].line).is_equal_to(0) 

117 

118 

119def test_parse_ruff_output_negative_column() -> None: 

120 """Handle negative column number gracefully.""" 

121 output = ( 

122 '{"filename": "test.py", "location": {"row": 1, "column": -1}, ' 

123 '"code": "E501", "message": "error"}' 

124 ) 

125 issues = parse_ruff_output(output) 

126 # Should handle gracefully without crashing 

127 assert_that(issues).is_length(1)