#!/usr/bin/env python3 """ Replace printf with DEBUG_ macros in test files. """ import os import re import sys def add_debug_include(content): """Add #include \"../lib/debug_config.h\" if not present.""" if '#include "../lib/debug_config.h"' in content: return content # Find position after last #include lines = content.split('\n') new_lines = [] include_added = False for line in lines: new_lines.append(line) if line.strip().startswith('#include') and not include_added: # Add our include after the last #include block # Check if next line is not #include pass # Simpler: insert after first #include line that includes something from ../lib or ../src # Actually, just insert after the first #include line for i, line in enumerate(lines): if line.strip().startswith('#include'): # Insert after this line lines.insert(i + 1, '#include "../lib/debug_config.h"') break return '\n'.join(lines) def add_debug_init(content): """Add debug initialization at the beginning of main().""" if 'debug_config_init();' in content: return content # Find int main() { pattern = r'int main\s*\(\s*\)\s*\{' match = re.search(pattern, content) if not match: return content start = match.end() # Insert after the opening brace # Find the next newline after brace newline_pos = content.find('\n', start) if newline_pos == -1: return content insertion_point = newline_pos + 1 init_code = '\n debug_config_init();\n debug_set_level(DEBUG_LEVEL_TRACE);\n debug_set_categories(DEBUG_CATEGORY_ALL);\n' content = content[:insertion_point] + init_code + content[insertion_point:] return content def determine_category(filename, line): """Determine debug category based on filename and line content.""" filename_lower = filename.lower() if 'crypto' in filename_lower: return 'DEBUG_CATEGORY_CRYPTO' elif 'etcp' in filename_lower: return 'DEBUG_CATEGORY_ETCP' elif 'memory' in filename_lower: return 'DEBUG_CATEGORY_MEMORY' elif 'u_async' in filename_lower: return 'DEBUG_CATEGORY_UASYNC' elif 'll_queue' in filename_lower: return 'DEBUG_CATEGORY_LL_QUEUE' elif 'config' in filename_lower: return 'DEBUG_CATEGORY_CONFIG' else: return 'DEBUG_CATEGORY_ALL' def determine_level(line): """Determine debug level based on line content.""" line_lower = line.lower() if '❌' in line or 'error' in line_lower or 'failed' in line_lower: return 'DEBUG_ERROR' elif 'warn' in line_lower: return 'DEBUG_WARN' elif '✅' in line_lower or 'success' in line_lower or 'passed' in line_lower: return 'DEBUG_INFO' elif '[debug]' in line_lower: return 'DEBUG_DEBUG' elif 'info' in line_lower: return 'DEBUG_INFO' else: return 'DEBUG_INFO' def replace_printf(content, filename): """Replace printf calls with DEBUG_ macros.""" # Pattern to match printf("...", ...); # Simple approach: replace line by line lines = content.split('\n') new_lines = [] i = 0 while i < len(lines): line = lines[i] stripped = line.strip() # Check for printf if stripped.startswith('printf('): # Extract format string and arguments # Simple regex to capture printf("format", args); match = re.match(r'printf\("([^"]*)"\s*,?(.*)\);', stripped) if match: fmt = match.group(1) args = match.group(2).strip() # Remove ❌ and ✅ symbols fmt = fmt.replace('❌', '').replace('✅', '').strip() # Determine category and level category = determine_category(filename, line) level = determine_level(line) # Build new macro call if args: new_line = line.replace(stripped, f'{level}({category}, "{fmt}", {args});') else: new_line = line.replace(stripped, f'{level}({category}, "{fmt}");') new_lines.append(new_line) # Check if next line is fflush(stdout); if i + 1 < len(lines) and 'fflush(stdout);' in lines[i + 1]: i += 1 # Skip fflush line else: # Keep original if pattern doesn't match new_lines.append(line) elif stripped.startswith('fprintf(') and 'stderr' in stripped: # Replace fprintf(stderr, ...) with DEBUG_ERROR match = re.match(r'fprintf\s*\(\s*stderr\s*,\s*"([^"]*)"\s*,?(.*)\);', stripped) if match: fmt = match.group(1) args = match.group(2).strip() category = determine_category(filename, line) new_line = line.replace(stripped, f'DEBUG_ERROR({category}, "{fmt}", {args});') new_lines.append(new_line) else: new_lines.append(line) else: new_lines.append(line) i += 1 return '\n'.join(new_lines) def process_file(filepath): """Process a single file.""" print(f"Processing {filepath}") with open(filepath, 'r') as f: content = f.read() original = content # Step 1: Add debug include content = add_debug_include(content) # Step 2: Add debug initialization in main() content = add_debug_init(content) # Step 3: Replace printf calls content = replace_printf(content, os.path.basename(filepath)) if content != original: with open(filepath, 'w') as f: f.write(content) print(f" Updated {filepath}") else: print(f" No changes needed") def main(): test_dir = 'tests' for root, dirs, files in os.walk(test_dir): for file in files: if file.endswith('.c'): filepath = os.path.join(root, file) process_file(filepath) if __name__ == '__main__': main()