Skip to content

Commit 68316f3

Browse files
committed
Add check_test_files.py tool to detect and fix double newline endings in test files
- Create check_test_files.py with list and fix functionality - Update tools/README.md with new tool documentation - Support --fix flag for automatic repair - Support --verbose flag for detailed output
1 parent f1a5c1f commit 68316f3

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed

tools/README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Developer tools for checking, validating, and generating project content.
1010
|----------|------|---------|
1111
| **Checking** | [`check_solutions.py`](#check_solutionspy) | Validate solution file architecture compliance |
1212
| | [`run_format_tests.py`](#run_format_testspy) | Run format unit tests |
13+
| | [`check_test_files.py`](#check_test_filespy) | Check and fix test files with double newline endings |
1314
| **Generation** | [`generate_mindmaps.py`](#generate_mindmapspy) | Rule-based mind map generation |
1415
| | [`generate_mindmaps_ai.py`](#generate_mindmaps_aipy) | AI-powered mind map generation |
1516
| | [`generate_pattern_docs.py`](#generate_pattern_docspy) | Pattern documentation generation |
@@ -43,6 +44,7 @@ python tools/generate_pattern_docs.py
4344
tools/
4445
├── README.md # This file
4546
├── check_solutions.py # Solution file checker
47+
├── check_test_files.py # Test file format checker/fixer
4648
├── run_format_tests.py # Format test runner
4749
├── run_format_tests.bat/.sh # Format test scripts
4850
@@ -131,6 +133,33 @@ tools\run_format_tests.bat # Windows
131133
tools/run_format_tests.sh # Linux/Mac
132134
```
133135

136+
### `check_test_files.py`
137+
138+
Check and fix double newline ending errors in test files under `tests/` directory.
139+
140+
Checks all `.in` and `.out` files to find files ending with two newlines (`\n\n`).
141+
142+
```bash
143+
python tools/check_test_files.py # List problematic files
144+
python tools/check_test_files.py --fix # List and auto-fix
145+
python tools/check_test_files.py --verbose # Show detailed info
146+
```
147+
148+
**Features:**
149+
- List all test files ending with two newlines
150+
- Auto-fix: Remove extra newline, keep only one
151+
152+
**Example Output:**
153+
```
154+
Found 3 files ending with two newlines:
155+
156+
tests/0977_squares_of_a_sorted_array_1.in
157+
tests/0977_squares_of_a_sorted_array_1.out
158+
tests/0142_linked_list_cycle_ii_1.in
159+
160+
Tip: Use --fix to automatically fix these issues.
161+
```
162+
134163
---
135164

136165
## 🧠 Mind Map Generation

tools/check_test_files.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Check and fix double newline ending errors in test files under tests/ directory.
4+
5+
Checks all .in and .out files to find files ending with two newlines (\n\n).
6+
7+
Features:
8+
1. List problematic files
9+
2. Fix these files (remove extra newline)
10+
11+
Exit Codes:
12+
- 0: All files OK or fix successful
13+
- 1: Errors found but not fixed
14+
15+
Usage:
16+
python tools/check_test_files.py # List problematic files
17+
python tools/check_test_files.py --fix # List and fix
18+
python tools/check_test_files.py --verbose # Show detailed info
19+
"""
20+
import sys
21+
from pathlib import Path
22+
from typing import List
23+
24+
25+
PROJECT_ROOT = Path(__file__).parent.parent
26+
TESTS_DIR = PROJECT_ROOT / "tests"
27+
28+
29+
def check_file(file_path: Path) -> bool:
30+
"""
31+
Check if file ends with two newlines.
32+
33+
Returns:
34+
True if file ends with \n\n (problematic)
35+
False if file is OK
36+
"""
37+
try:
38+
with open(file_path, 'rb') as f:
39+
data = f.read()
40+
# Check if ends with \n\n
41+
return data.endswith(b'\n\n')
42+
except Exception as e:
43+
print(f"Error: Cannot read file {file_path}: {e}", file=sys.stderr)
44+
return False
45+
46+
47+
def fix_file(file_path: Path) -> bool:
48+
"""
49+
Fix file: remove extra newline at end, keep only one.
50+
51+
Returns:
52+
True if fix successful
53+
False if fix failed
54+
"""
55+
try:
56+
with open(file_path, 'rb') as f:
57+
data = f.read()
58+
59+
# If ends with \n\n, remove one \n
60+
if data.endswith(b'\n\n'):
61+
# Remove last \n
62+
fixed_data = data[:-1]
63+
64+
with open(file_path, 'wb') as f:
65+
f.write(fixed_data)
66+
return True
67+
return False
68+
except Exception as e:
69+
print(f"Error: Cannot fix file {file_path}: {e}", file=sys.stderr)
70+
return False
71+
72+
73+
def find_test_files() -> List[Path]:
74+
"""Find all .in and .out test files."""
75+
if not TESTS_DIR.exists():
76+
print(f"Error: tests directory does not exist: {TESTS_DIR}", file=sys.stderr)
77+
return []
78+
79+
test_files = []
80+
for ext in ['.in', '.out']:
81+
test_files.extend(TESTS_DIR.glob(f'*{ext}'))
82+
83+
return sorted(test_files)
84+
85+
86+
def main():
87+
"""Main function."""
88+
# Parse arguments
89+
fix_mode = '--fix' in sys.argv or '-f' in sys.argv
90+
verbose = '--verbose' in sys.argv or '-v' in sys.argv
91+
92+
# Find all test files
93+
test_files = find_test_files()
94+
95+
if not test_files:
96+
print("No test files found.")
97+
return 0
98+
99+
if verbose:
100+
print(f"Checking {len(test_files)} test files...")
101+
102+
# Check files
103+
problematic_files = []
104+
for file_path in test_files:
105+
if check_file(file_path):
106+
problematic_files.append(file_path)
107+
108+
# Show results
109+
if not problematic_files:
110+
print("✓ All test files are OK (no double newline endings).")
111+
return 0
112+
113+
print(f"\nFound {len(problematic_files)} files ending with two newlines:\n")
114+
for file_path in problematic_files:
115+
rel_path = file_path.relative_to(PROJECT_ROOT)
116+
print(f" {rel_path}")
117+
118+
# Fix mode
119+
if fix_mode:
120+
print(f"\nFixing {len(problematic_files)} files...")
121+
fixed_count = 0
122+
failed_count = 0
123+
124+
for file_path in problematic_files:
125+
if fix_file(file_path):
126+
fixed_count += 1
127+
if verbose:
128+
rel_path = file_path.relative_to(PROJECT_ROOT)
129+
print(f" ✓ Fixed: {rel_path}")
130+
else:
131+
failed_count += 1
132+
rel_path = file_path.relative_to(PROJECT_ROOT)
133+
print(f" ✗ Fix failed: {rel_path}", file=sys.stderr)
134+
135+
print(f"\nFix complete: {fixed_count} succeeded, {failed_count} failed")
136+
return 0 if failed_count == 0 else 1
137+
else:
138+
print("\nTip: Use --fix to automatically fix these issues.")
139+
return 1
140+
141+
142+
if __name__ == '__main__':
143+
sys.exit(main())
144+

0 commit comments

Comments
 (0)