Skip to content

Commit 3e1924c

Browse files
committed
testing: code improvements
Signed-off-by: IonutMuthi <[email protected]>
1 parent dc5546d commit 3e1924c

File tree

5 files changed

+446
-380
lines changed

5 files changed

+446
-380
lines changed

tools/testing/file_filters.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#!/usr/bin/env python3
2+
"""
3+
File Filters Module
4+
Handles file and content filtering logic for test environment setup.
5+
6+
This module provides functionality for:
7+
- Component-based file filtering
8+
- RBP-based content filtering
9+
- New test detection and filtering
10+
- Helper functions for filtering decisions
11+
"""
12+
13+
from rst_parser import parse_rst_structure, rebuild_rst_file
14+
15+
16+
def _should_include_file(test_file, component_filter, new_uids):
17+
"""Determine if file should be included based on filters."""
18+
# Include files from specified components
19+
if test_file['component'] in component_filter:
20+
return True
21+
22+
# Include files containing new tests (bypass component filter)
23+
if new_uids and any(test['uid'] in new_uids for test in test_file['tests']):
24+
return True
25+
26+
# Include only top-level index files, not component-specific ones
27+
if 'index.rst' in test_file['relative_path']:
28+
path_parts = test_file['relative_path'].split('/')
29+
# Include plugins/index.rst, general/index.rst but not plugins/m2k/index.rst
30+
return len(path_parts) == 2 and path_parts[1] == 'index.rst'
31+
32+
return False
33+
34+
35+
def filter_by_component(test_files, component_filter, new_uids=None):
36+
"""Simple file-level filtering by component, with new-since support."""
37+
if not component_filter:
38+
return test_files
39+
40+
return [tf for tf in test_files
41+
if _should_include_file(tf, component_filter, new_uids)]
42+
43+
44+
def _should_include_test(test, rbp_filter, new_uids):
45+
"""Determine if test should be included based on filters."""
46+
# Include if it's a new test (always)
47+
if new_uids and test['uid'] in new_uids:
48+
return True
49+
50+
# Include if matches RBP filter
51+
if rbp_filter and test['rbp'] in rbp_filter:
52+
return True
53+
54+
# Include if no filters specified
55+
if not rbp_filter and not new_uids:
56+
return True
57+
58+
return False
59+
60+
61+
def _extract_all_uids(test_files):
62+
"""Extract all UIDs from test files efficiently."""
63+
return {test['uid'] for file_info in test_files
64+
for test in file_info['tests']
65+
if test['uid'] != 'MISSING'}
66+
67+
68+
def filter_rst_content(file_path, rbp_filter, new_uids=None):
69+
"""Parse RST file and keep only tests matching RBP filter or new tests."""
70+
71+
with open(file_path, 'r', encoding='utf-8') as f:
72+
content = f.read()
73+
74+
# Split into header + test sections
75+
structure = parse_rst_structure(content)
76+
77+
# Filter tests by RBP or new-since
78+
filtered_tests = [test for test in structure['tests']
79+
if _should_include_test(test, rbp_filter, new_uids)]
80+
81+
# Reconstruct file
82+
return rebuild_rst_file(structure['header'], filtered_tests)

tools/testing/file_operations.py

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/usr/bin/env python3
2+
"""
3+
File Operations Module
4+
Handles file copying operations and index file management.
5+
6+
This module provides functionality for:
7+
- Copying test files with or without modification
8+
- Managing index file toctree entries
9+
- Component tracking for copied files
10+
- RST content-level filtering and file operations
11+
"""
12+
13+
import os
14+
import shutil
15+
import re
16+
from file_filters import filter_rst_content
17+
18+
19+
def get_copied_components(filtered_files):
20+
"""Track which components were actually copied."""
21+
copied_components = set()
22+
for tf in filtered_files:
23+
if tf['component'] not in ['other', 'general']:
24+
copied_components.add(tf['component'])
25+
return copied_components
26+
27+
28+
def extract_component_from_toctree_entry(entry):
29+
"""Extract component name from toctree entry."""
30+
# " adc/index" → "adc"
31+
# " core/hp_tests" → "core"
32+
entry = entry.strip()
33+
if '/' in entry:
34+
return entry.split('/')[0]
35+
return entry
36+
37+
38+
def filter_index_content(file_path, copied_components):
39+
"""Filter toctree entries in index files based on copied components."""
40+
41+
with open(file_path, 'r', encoding='utf-8') as f:
42+
content = f.read()
43+
44+
# Find toctree section
45+
toctree_pattern = r'(\.\. toctree::\n(?:\s+:[^\n]+\n)*\s*\n)(.*?)(\n\n|\.\.|$)'
46+
match = re.search(toctree_pattern, content, re.DOTALL)
47+
48+
if not match:
49+
return content # No toctree found
50+
51+
header = match.group(1)
52+
entries = match.group(2)
53+
footer = content[match.end():]
54+
55+
# Filter toctree entries
56+
filtered_entries = []
57+
for line in entries.split('\n'):
58+
if line.strip():
59+
# Extract component from entry like "adc/index" → "adc"
60+
component = extract_component_from_toctree_entry(line)
61+
if component in copied_components:
62+
filtered_entries.append(line)
63+
64+
# Reconstruct content
65+
before_toctree = content[:match.start()]
66+
new_entries = '\n'.join(filtered_entries)
67+
68+
return f"{before_toctree}{header}{new_entries}\n{footer}"
69+
70+
71+
def copy_files_unchanged(test_files, dest_dir, component_filter=None):
72+
"""Copy files without content modification."""
73+
copied_count = 0
74+
copied_components = get_copied_components(test_files) if component_filter else None
75+
76+
for test_file in test_files:
77+
src_path = test_file['file_path']
78+
dest_path = os.path.join(dest_dir, test_file['relative_path'])
79+
80+
# Create destination directory
81+
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
82+
83+
# Filter index files when component filtering is active
84+
if component_filter and 'index.rst' in test_file['relative_path']:
85+
filtered_content = filter_index_content(src_path, copied_components)
86+
with open(dest_path, 'w', encoding='utf-8') as f:
87+
f.write(filtered_content)
88+
else:
89+
# Copy file unchanged
90+
shutil.copy2(src_path, dest_path)
91+
92+
copied_count += 1
93+
94+
return copied_count
95+
96+
97+
def filter_by_rbp_content(test_files, rbp_filter, dest_dir, component_filter=None, new_uids=None):
98+
"""Content-level filtering: modify files to keep only specified RBP tests or new tests."""
99+
if not rbp_filter and not new_uids:
100+
# No filters - copy files as-is
101+
return copy_files_unchanged(test_files, dest_dir, component_filter)
102+
103+
copied_count = 0
104+
copied_components = get_copied_components(test_files) if component_filter else None
105+
106+
# Filter active - parse and modify content
107+
for test_file in test_files:
108+
dest_path = os.path.join(dest_dir, test_file['relative_path'])
109+
110+
# Create destination directory
111+
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
112+
113+
if test_file['tests']: # File contains tests
114+
filtered_content = filter_rst_content(test_file['file_path'], rbp_filter, new_uids)
115+
with open(dest_path, 'w', encoding='utf-8') as f:
116+
f.write(filtered_content)
117+
elif component_filter and 'index.rst' in test_file['relative_path']:
118+
# Filter index files when component filtering is active
119+
filtered_content = filter_index_content(test_file['file_path'], copied_components)
120+
with open(dest_path, 'w', encoding='utf-8') as f:
121+
f.write(filtered_content)
122+
else: # File has no tests (index, docs, etc.)
123+
shutil.copy2(test_file['file_path'], dest_path)
124+
125+
copied_count += 1
126+
127+
return copied_count

tools/testing/git_operations.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Git Operations Module
4+
Handles git repository operations and new test detection.
5+
6+
This module provides functionality for:
7+
- Git repository validation and operations
8+
- Extracting test files from specific git versions
9+
- Detecting new tests between versions
10+
"""
11+
12+
import os
13+
import subprocess
14+
import tempfile
15+
import shutil
16+
from rst_parser import scan_test_files
17+
18+
19+
def get_git_root():
20+
"""Get the git repository root directory."""
21+
try:
22+
result = subprocess.run(['git', 'rev-parse', '--show-toplevel'],
23+
capture_output=True, check=True, text=True)
24+
return result.stdout.strip()
25+
except subprocess.CalledProcessError:
26+
return None
27+
28+
29+
def validate_git_repository():
30+
"""Ensure we're in a git repository."""
31+
return get_git_root() is not None
32+
33+
34+
def git_tag_exists(tag_name):
35+
"""Check if a git tag exists."""
36+
git_root = get_git_root()
37+
if not git_root:
38+
return False
39+
40+
try:
41+
result = subprocess.run(['git', 'tag', '-l', tag_name],
42+
cwd=git_root, capture_output=True, check=True, text=True)
43+
return tag_name in result.stdout.strip().split('\n')
44+
except subprocess.CalledProcessError:
45+
return False
46+
47+
48+
def detect_new_tests(baseline_version):
49+
"""Detect new test UIDs since baseline version."""
50+
git_root = get_git_root()
51+
if not git_root:
52+
raise RuntimeError("Not in a git repository")
53+
54+
temp_dir = tempfile.mkdtemp()
55+
56+
try:
57+
# Extract docs/tests directory at baseline version from git root
58+
cmd = ['git', 'archive', baseline_version, 'docs/tests']
59+
with subprocess.Popen(cmd, cwd=git_root, stdout=subprocess.PIPE) as git_proc:
60+
subprocess.run(['tar', '-x', '-C', temp_dir],
61+
stdin=git_proc.stdout, check=True)
62+
63+
# Scan extracted files for UIDs
64+
baseline_tests_dir = os.path.join(temp_dir, 'docs', 'tests')
65+
if not os.path.exists(baseline_tests_dir):
66+
raise FileNotFoundError(f"docs/tests not found in {baseline_version}")
67+
68+
baseline_files = scan_test_files(baseline_tests_dir)
69+
70+
baseline_uids = set()
71+
for file_info in baseline_files:
72+
for test in file_info['tests']:
73+
if test['uid'] != 'MISSING':
74+
baseline_uids.add(test['uid'])
75+
76+
print(f"Baseline version {baseline_version}: {len(baseline_uids)} tests")
77+
return baseline_uids
78+
79+
except Exception as e:
80+
print(f"Error extracting baseline UIDs: {e}")
81+
raise
82+
finally:
83+
shutil.rmtree(temp_dir)

0 commit comments

Comments
 (0)