Coverage for tests / unit / utils / native_parsers / test_jsonc_comments.py: 100%

92 statements  

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

1"""Tests for strip_jsonc_comments function.""" 

2 

3from __future__ import annotations 

4 

5import json 

6from unittest.mock import patch 

7 

8import pytest 

9from assertpy import assert_that 

10 

11from lintro.utils.jsonc import strip_jsonc_comments as _strip_jsonc_comments 

12 

13 

14def test_strip_jsonc_comments_no_comments() -> None: 

15 """Return unchanged content when no comments are present.""" 

16 content = '{"key": "value", "num": 42}' 

17 result = _strip_jsonc_comments(content) 

18 assert_that(result).is_equal_to(content) 

19 

20 

21def test_strip_jsonc_comments_line_comment() -> None: 

22 """Strip single-line // comments from the end of lines.""" 

23 content = '{"key": "value"} // this is a comment' 

24 result = _strip_jsonc_comments(content) 

25 assert_that(result.strip()).is_equal_to('{"key": "value"}') 

26 

27 

28def test_strip_jsonc_comments_line_comment_on_own_line() -> None: 

29 """Strip full-line // comments appearing at the start of lines.""" 

30 content = '// comment at start\n{"key": "value"}' 

31 result = _strip_jsonc_comments(content) 

32 parsed = json.loads(result) 

33 assert_that(parsed["key"]).is_equal_to("value") 

34 

35 

36def test_strip_jsonc_comments_block_comment() -> None: 

37 """Strip /* */ block comments from content.""" 

38 content = '{"key": /* comment */ "value"}' 

39 result = _strip_jsonc_comments(content) 

40 parsed = json.loads(result) 

41 assert_that(parsed["key"]).is_equal_to("value") 

42 

43 

44def test_strip_jsonc_comments_multiline_block_comment() -> None: 

45 """Strip multi-line /* */ block comments spanning multiple lines.""" 

46 content = '{\n/* this is\na multi-line\ncomment */\n"key": "value"\n}' 

47 result = _strip_jsonc_comments(content) 

48 parsed = json.loads(result) 

49 assert_that(parsed["key"]).is_equal_to("value") 

50 

51 

52@pytest.mark.parametrize( 

53 ("content", "expected_key", "expected_value"), 

54 [ 

55 ( 

56 '{"url": "https://example.com", "pattern": "/* glob */"}', 

57 "url", 

58 "https://example.com", 

59 ), 

60 ( 

61 '{"url": "https://example.com", "pattern": "/* glob */"}', 

62 "pattern", 

63 "/* glob */", 

64 ), 

65 ], 

66 ids=["preserve_url_with_slashes", "preserve_glob_pattern_in_string"], 

67) 

68def test_strip_jsonc_comments_preserve_comment_like_strings( 

69 content: str, 

70 expected_key: str, 

71 expected_value: str, 

72) -> None: 

73 """Preserve // and /* patterns that appear inside string values. 

74 

75 Args: 

76 content: JSONC content with comment-like patterns in strings. 

77 expected_key: Key to check in the parsed result. 

78 expected_value: Expected value for the key. 

79 """ 

80 result = _strip_jsonc_comments(content) 

81 parsed = json.loads(result) 

82 assert_that(parsed[expected_key]).is_equal_to(expected_value) 

83 

84 

85def test_strip_jsonc_comments_escape_sequence_in_string() -> None: 

86 """Handle escaped quotes in strings without treating them as string ends.""" 

87 content = '{"message": "He said \\"hello\\""}' 

88 result = _strip_jsonc_comments(content) 

89 parsed = json.loads(result) 

90 assert_that(parsed["message"]).is_equal_to('He said "hello"') 

91 

92 

93def test_strip_jsonc_comments_backslash_in_string() -> None: 

94 """Handle backslash escape sequences in strings correctly.""" 

95 content = '{"path": "C:\\\\Users\\\\test"}' 

96 result = _strip_jsonc_comments(content) 

97 parsed = json.loads(result) 

98 assert_that(parsed["path"]).is_equal_to("C:\\Users\\test") 

99 

100 

101def test_strip_jsonc_comments_unclosed_block_comment_warning() -> None: 

102 """Warn when a block comment is not properly closed.""" 

103 content = '{"key": "value"} /* unclosed' 

104 with patch("lintro.utils.jsonc.logger") as mock_logger: 

105 _strip_jsonc_comments(content) 

106 mock_logger.warning.assert_called_once() 

107 

108 

109def test_strip_jsonc_comments_empty_content() -> None: 

110 """Handle empty content gracefully by returning empty string.""" 

111 result = _strip_jsonc_comments("") 

112 assert_that(result).is_empty() 

113 

114 

115def test_strip_jsonc_comments_complex_jsonc() -> None: 

116 """Parse complex JSONC with multiple comment types and nested structures.""" 

117 content = """{ 

118 // Configuration 

119 "name": "test", 

120 /* 

121 * Multi-line 

122 * description 

123 */ 

124 "settings": { 

125 "enabled": true // inline comment 

126 } 

127}""" 

128 result = _strip_jsonc_comments(content) 

129 parsed = json.loads(result) 

130 assert_that(parsed["name"]).is_equal_to("test") 

131 assert_that(parsed["settings"]["enabled"]).is_true() 

132 

133 

134def test_strip_jsonc_comments_unicode_content() -> None: 

135 """Handle Unicode characters in JSON content.""" 

136 content = '{"message": "日本語テスト", "emoji": "🚀"}' 

137 result = _strip_jsonc_comments(content) 

138 parsed = json.loads(result) 

139 assert_that(parsed["message"]).is_equal_to("日本語テスト") 

140 assert_that(parsed["emoji"]).is_equal_to("🚀") 

141 

142 

143def test_strip_jsonc_comments_very_long_content() -> None: 

144 """Handle very long JSON content.""" 

145 long_value = "x" * 10000 

146 content = f'{{"key": "{long_value}"}}' 

147 result = _strip_jsonc_comments(content) 

148 parsed = json.loads(result) 

149 assert_that(len(parsed["key"])).is_equal_to(10000) 

150 

151 

152def test_strip_jsonc_comments_nested_comments() -> None: 

153 """Handle nested block comment patterns (only outer is stripped).""" 

154 content = '{"key": "value"} /* outer /* inner */ still comment */' 

155 result = _strip_jsonc_comments(content) 

156 # The inner "/*" should be consumed by the outer comment 

157 assert_that('{"key": "value"}' in result).is_true() 

158 

159 

160def test_strip_jsonc_comments_consecutive_comments() -> None: 

161 """Handle consecutive block comments.""" 

162 content = '/* first */ {"key": "value"} /* second */' 

163 result = _strip_jsonc_comments(content) 

164 parsed = json.loads(result) 

165 assert_that(parsed["key"]).is_equal_to("value") 

166 

167 

168def test_strip_jsonc_comments_mixed_quotes() -> None: 

169 """Handle content with different quote styles in strings.""" 

170 content = ( 

171 """{"single": "has 'single' quotes", "double": "has \\"double\\" quotes"}""" 

172 ) 

173 result = _strip_jsonc_comments(content) 

174 parsed = json.loads(result) 

175 assert_that(parsed["single"]).contains("single") 

176 

177 

178def test_strip_jsonc_comments_only_whitespace() -> None: 

179 """Handle content that is only whitespace.""" 

180 result = _strip_jsonc_comments(" \n\t \n ") 

181 assert_that(result.strip()).is_empty() 

182 

183 

184def test_strip_jsonc_comments_deeply_nested_json() -> None: 

185 """Handle deeply nested JSON structures.""" 

186 content = '{"a": {"b": {"c": {"d": {"e": "deep"}}}}} // comment' 

187 result = _strip_jsonc_comments(content) 

188 parsed = json.loads(result) 

189 assert_that(parsed["a"]["b"]["c"]["d"]["e"]).is_equal_to("deep")