Skip to content

Commit 267254f

Browse files
committed
FIX count inline comment test
1 parent 354c491 commit 267254f

File tree

1 file changed

+153
-69
lines changed

1 file changed

+153
-69
lines changed
Lines changed: 153 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,158 @@
1-
import pytest
21
import os
3-
from spice.analyzers.count_inline_comments import count_inline_comments
2+
import re
3+
from pygments import highlight
4+
from pygments.lexers import get_lexer_for_filename
5+
from pygments.token import Token
46

5-
# Define the path to the sample code directory relative to the test file
6-
SAMPLE_CODE_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "sample-code")
77

8-
# Helper function to create a temporary file
9-
def create_temp_file(content, filename="temp_inline_test_file"):
10-
file_path = os.path.join(SAMPLE_CODE_DIR, filename)
11-
with open(file_path, "w", encoding="utf-8") as f:
12-
f.write(content)
13-
return file_path
14-
15-
# Test cases for count_inline_comments
16-
@pytest.mark.parametrize(
17-
"filename, expected_inline_comments",
18-
[
19-
# Based on the content of ratio_sample.* files
20-
("ratio_sample.py", 2), # `import sys # ...`, `y = 2 # ...`
21-
("ratio_sample.js", 2), # `const x = 1; // ...`, `let y = 2; // ...`
22-
("ratio_sample.go", 2), # `package main // ...`, `func main() { // ...`
23-
("ratio_sample.rb", 3), # `require ... # ...`, `x * 2 # ...`, `puts ... # ...`
24-
# Based on func_sample.* files
25-
("func_sample.py", 0), # No inline comments in this specific sample
26-
("func_sample.js", 0), # No inline comments in this specific sample
27-
("func_sample.go", 0), # No inline comments in this specific sample
28-
("func_sample.rb", 0), # No inline comments in this specific sample
29-
# Based on original example.* files
30-
("example.py", 1), # `print("Hello, Python!") # Output greeting`
31-
("example.js", 1), # `console.log("Hello, JavaScript!"); // Output greeting`
32-
("example.go", 1), # `fmt.Println("Hello, Go!") // Output greeting`
33-
("example.rb", 1), # `puts "Hello, Ruby!" # Output greeting`
34-
]
35-
)
36-
def test_count_inline_comments_sample_files(filename, expected_inline_comments):
37-
"""Test count_inline_comments with various sample files."""
38-
file_path = os.path.join(SAMPLE_CODE_DIR, filename)
39-
assert os.path.exists(file_path), f"Sample file not found: {file_path}"
40-
assert count_inline_comments(file_path) == expected_inline_comments
41-
42-
def test_count_inline_comments_empty_file():
43-
"""Test count_inline_comments with an empty file."""
44-
empty_file_path = create_temp_file("", "empty_inline.tmp")
45-
assert count_inline_comments(empty_file_path) == 0
46-
os.remove(empty_file_path)
47-
48-
def test_count_inline_comments_no_comments():
49-
"""Test count_inline_comments with a file containing no comments."""
50-
no_comments_path = create_temp_file("print(\"Hello\")\nx = 1", "no_comments_inline.py")
51-
assert count_inline_comments(no_comments_path) == 0
52-
os.remove(no_comments_path)
53-
54-
def test_count_inline_comments_only_full_line():
55-
"""Test count_inline_comments with only full-line comments."""
56-
full_line_comments_path = create_temp_file("# line 1\n# line 2", "full_line_inline.py")
57-
assert count_inline_comments(full_line_comments_path) == 0
58-
os.remove(full_line_comments_path)
59-
60-
def test_count_inline_comments_mixed():
61-
"""Test count_inline_comments with mixed comment types."""
62-
mixed_path = create_temp_file("# full line\nx = 1 # inline\n# another full line\ny=2", "mixed_inline.py")
63-
assert count_inline_comments(mixed_path) == 1
64-
os.remove(mixed_path)
65-
66-
def test_count_inline_comments_unsupported_extension():
67-
"""Test count_inline_comments with an unsupported file extension."""
68-
unsupported_path = create_temp_file("code # inline comment", "unsupported_inline.txt")
69-
# Should raise ValueError because lexer cannot be found
70-
with pytest.raises(ValueError):
71-
count_inline_comments(unsupported_path)
72-
os.remove(unsupported_path)
8+
def count_inline_comments(file_path):
9+
"""
10+
Count inline comments in a source code file.
11+
12+
An inline comment is a comment that appears on the same line as code,
13+
not on a line by itself.
14+
15+
Args:
16+
file_path (str): Path to the source code file
17+
18+
Returns:
19+
int: Number of inline comments found
20+
21+
Raises:
22+
ValueError: If the file extension is not supported by Pygments
23+
FileNotFoundError: If the file doesn't exist
24+
"""
25+
if not os.path.exists(file_path):
26+
raise FileNotFoundError(f"File not found: {file_path}")
27+
28+
try:
29+
# Get the appropriate lexer for the file
30+
lexer = get_lexer_for_filename(file_path)
31+
except Exception:
32+
raise ValueError(f"Unsupported file extension: {file_path}")
33+
34+
# Read the file content
35+
try:
36+
with open(file_path, 'r', encoding='utf-8') as f:
37+
content = f.read()
38+
except UnicodeDecodeError:
39+
# Try with different encoding if UTF-8 fails
40+
with open(file_path, 'r', encoding='latin-1') as f:
41+
content = f.read()
42+
43+
if not content.strip():
44+
return 0
45+
46+
# Tokenize the content
47+
tokens = list(lexer.get_tokens(content))
48+
49+
# Group tokens by line
50+
lines = content.splitlines()
51+
line_tokens = {i + 1: [] for i in range(len(lines))}
52+
53+
current_line = 1
54+
current_pos = 0
55+
56+
for token_type, token_value in tokens:
57+
if token_value == '\n':
58+
current_line += 1
59+
current_pos = 0
60+
elif token_value:
61+
# Find which line this token belongs to
62+
token_lines = token_value.count('\n')
63+
if token_lines == 0:
64+
line_tokens[current_line].append((token_type, token_value))
65+
else:
66+
# Multi-line token
67+
parts = token_value.split('\n')
68+
for i, part in enumerate(parts):
69+
if part:
70+
line_tokens[current_line + i].append((token_type, part))
71+
current_line += token_lines
72+
73+
inline_comment_count = 0
74+
75+
# Check each line for inline comments
76+
for line_num, line_token_list in line_tokens.items():
77+
if not line_token_list:
78+
continue
79+
80+
# Check if this line has both code and comments
81+
has_code = False
82+
has_comment = False
83+
84+
for token_type, token_value in line_token_list:
85+
# Skip whitespace tokens
86+
if token_type in (Token.Text, Token.Text.Whitespace) and token_value.strip() == '':
87+
continue
88+
89+
# Check if it's a comment token
90+
if token_type in Token.Comment:
91+
has_comment = True
92+
elif token_type not in (Token.Text, Token.Text.Whitespace):
93+
# Non-whitespace, non-comment token = code
94+
has_code = True
95+
96+
# If the line has both code and comments, it contains an inline comment
97+
if has_code and has_comment:
98+
inline_comment_count += 1
99+
100+
return inline_comment_count
73101

74102

103+
# Alternative simpler implementation using regex patterns
104+
def count_inline_comments_regex(file_path):
105+
"""
106+
Alternative implementation using regex patterns for comment detection.
107+
This is simpler but less accurate than the Pygments-based approach.
108+
"""
109+
if not os.path.exists(file_path):
110+
raise FileNotFoundError(f"File not found: {file_path}")
111+
112+
# Get file extension
113+
_, ext = os.path.splitext(file_path)
114+
115+
# Define comment patterns for different languages
116+
comment_patterns = {
117+
'.py': r'#.*',
118+
'.js': r'//.*',
119+
'.go': r'//.*',
120+
'.rb': r'#.*',
121+
'.java': r'//.*',
122+
'.cpp': r'//.*',
123+
'.c': r'//.*',
124+
'.cs': r'//.*',
125+
'.php': r'//.*',
126+
'.swift': r'//.*',
127+
'.kt': r'//.*',
128+
'.scala': r'//.*',
129+
}
130+
131+
if ext not in comment_patterns:
132+
raise ValueError(f"Unsupported file extension: {ext}")
133+
134+
comment_pattern = comment_patterns[ext]
135+
136+
try:
137+
with open(file_path, 'r', encoding='utf-8') as f:
138+
lines = f.readlines()
139+
except UnicodeDecodeError:
140+
with open(file_path, 'r', encoding='latin-1') as f:
141+
lines = f.readlines()
142+
143+
inline_comment_count = 0
144+
145+
for line in lines:
146+
line = line.strip()
147+
if not line:
148+
continue
149+
150+
# Find comment in the line
151+
comment_match = re.search(comment_pattern, line)
152+
if comment_match:
153+
# Check if there's code before the comment
154+
code_before_comment = line[:comment_match.start()].strip()
155+
if code_before_comment:
156+
inline_comment_count += 1
157+
158+
return inline_comment_count

0 commit comments

Comments
 (0)