test: add comprehensive unit tests for core modules #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Test and Coverage | ||
| on: | ||
| pull_request: | ||
| branches: [ main, master ] | ||
| push: | ||
| branches: [ main, master ] | ||
| jobs: | ||
| test-coverage: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| submodules: recursive | ||
| - name: Install dependencies | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y build-essential cmake lcov | ||
| - name: Configure CMake with coverage | ||
| run: | | ||
| mkdir -p build | ||
| cd build | ||
| cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="--coverage -g -O0" -DCMAKE_C_FLAGS="--coverage -g -O0" -DGGML_NATIVE=OFF | ||
| - name: Build | ||
| run: | | ||
| cd build | ||
| make -j$(nproc) | ||
| - name: Run tests | ||
| run: | | ||
| cd build | ||
| ctest --output-on-failure --parallel $(nproc) | ||
| - name: Generate coverage report | ||
| run: | | ||
| cd build | ||
| lcov --capture --directory . --output-file coverage.info | ||
| lcov --remove coverage.info '/usr/*' '*/build/*' '*/ggml/src/*' '*/vendor/*' --output-file coverage_filtered.info | ||
| lcov --list coverage_filtered.info | ||
| - name: Check coverage thresholds | ||
| run: | | ||
| cd build | ||
| python3 -c " | ||
| import sys | ||
| import re | ||
| def parse_lcov_summary(filename): | ||
| with open(filename, 'r') as f: | ||
| content = f.read() | ||
| # Extract summary from lcov --list output | ||
| lines_match = re.search(r'Total:\s*\|\s*(\d+)\s*\|\s*(\d+)\s*\|\s*([\d.]+)%', content) | ||
| functions_match = re.search(r'Functions:\s*(\d+)\s*of\s*(\d+)\s*\(([\d.]+)%\)', content) | ||
| if lines_match: | ||
| lines_hit = int(lines_match.group(2)) | ||
| lines_total = int(lines_match.group(1)) | ||
| line_coverage = float(lines_match.group(3)) | ||
| else: | ||
| line_coverage = 0.0 | ||
| if functions_match: | ||
| func_coverage = float(functions_match.group(3)) | ||
| else: | ||
| func_coverage = 0.0 | ||
| return line_coverage, func_coverage | ||
| # Check if coverage meets thresholds | ||
| try: | ||
| # Run lcov --list and capture output | ||
| import subprocess | ||
| result = subprocess.run(['lcov', '--list', 'coverage_filtered.info'], | ||
| capture_output=True, text=True, check=True) | ||
| # Parse coverage from output | ||
| lines = result.stdout.split('\n') | ||
| line_coverage = 0.0 | ||
| func_coverage = 0.0 | ||
| for line in lines: | ||
| if 'Total:' in line and '|' in line: | ||
| parts = line.split('|') | ||
| if len(parts) >= 4: | ||
| coverage_str = parts[3].strip().replace('%', '') | ||
| try: | ||
| line_coverage = float(coverage_str) | ||
| except: | ||
| pass | ||
| elif 'functions..' in line: | ||
| match = re.search(r'(\d+\.\d+)%', line) | ||
| if match: | ||
| func_coverage = float(match.group(1)) | ||
| print(f'Line coverage: {line_coverage:.1f}%') | ||
| print(f'Function coverage: {func_coverage:.1f}%') | ||
| # Check thresholds | ||
| min_coverage = 95.0 | ||
| if line_coverage < min_coverage: | ||
| print(f'ERROR: Line coverage {line_coverage:.1f}% is below threshold {min_coverage}%') | ||
| sys.exit(1) | ||
| if func_coverage < min_coverage: | ||
| print(f'ERROR: Function coverage {func_coverage:.1f}% is below threshold {min_coverage}%') | ||
| sys.exit(1) | ||
| print(f'SUCCESS: Coverage meets thresholds (≥{min_coverage}%)') | ||
| except Exception as e: | ||
| print(f'Error checking coverage: {e}') | ||
| # For now, don't fail the build on coverage parsing errors | ||
| # sys.exit(1) | ||
| " | ||
| - name: Upload coverage reports | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: coverage-report | ||
| path: | | ||
| build/coverage.info | ||
| build/coverage_filtered.info | ||
| if: always() | ||
| - name: Generate HTML coverage report | ||
| run: | | ||
| cd build | ||
| genhtml coverage_filtered.info --output-directory coverage_html | ||
| if: always() | ||
| - name: Upload HTML coverage report | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: coverage-html | ||
| path: build/coverage_html/ | ||
| if: always() | ||