Add unit tests for encryption functionality and integration tests #22
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: CI | |
| on: | |
| push: | |
| branches: [main, develop] | |
| pull_request: | |
| branches: [main] | |
| jobs: | |
| build-and-test: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| build_type: [Debug, Release] | |
| include: | |
| - os: ubuntu-latest | |
| cc: clang | |
| cxx: clang++ | |
| - os: macos-latest | |
| cc: clang | |
| cxx: clang++ | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install dependencies (Ubuntu) | |
| if: matrix.os == 'ubuntu-latest' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y build-essential cmake clang-format clang-tidy libzstd-dev libsodium-dev | |
| - name: Install dependencies (macOS) | |
| if: matrix.os == 'macos-latest' | |
| run: | | |
| brew install clang-format zstd libsodium || true | |
| # cmake is already available on macOS runners | |
| - name: Set up environment | |
| run: | | |
| echo "CC=${{ matrix.cc }}" >> $GITHUB_ENV | |
| echo "CXX=${{ matrix.cxx }}" >> $GITHUB_ENV | |
| - name: Configure CMake | |
| run: | | |
| cmake -B build \ | |
| -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \ | |
| -DCMAKE_C_COMPILER=${{ matrix.cc }} \ | |
| -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} \ | |
| -DBFC_WITH_ZSTD=ON \ | |
| -DBFC_WITH_SODIUM=ON | |
| - name: Build | |
| run: cmake --build build --config ${{ matrix.build_type }} -j$(nproc 2>/dev/null || sysctl -n hw.ncpu) | |
| - name: Run tests | |
| if: matrix.build_type == 'Debug' | |
| run: | | |
| cd build | |
| ctest --output-on-failure --parallel $(nproc 2>/dev/null || sysctl -n hw.ncpu) | |
| - name: Test CLI functionality | |
| run: | | |
| # Create test data | |
| mkdir -p test_data | |
| echo "Hello World" > test_data/hello.txt | |
| echo "Goodbye" > test_data/bye.txt | |
| mkdir -p test_data/subdir | |
| echo "Nested file" > test_data/subdir/nested.txt | |
| # Test CLI workflow | |
| ./build/bin/bfc create test.bfc test_data/ | |
| ./build/bin/bfc list test.bfc | |
| ./build/bin/bfc info test.bfc | |
| ./build/bin/bfc verify test.bfc | |
| ./build/bin/bfc verify --deep test.bfc | |
| # Test compression functionality | |
| ./build/bin/bfc create -c zstd test_compressed.bfc test_data/ | |
| ./build/bin/bfc info test_compressed.bfc test_data/hello.txt | |
| ./build/bin/bfc verify test_compressed.bfc | |
| # Test different compression levels | |
| ./build/bin/bfc create -c zstd -l 1 test_fast.bfc test_data/ | |
| ./build/bin/bfc create -c zstd -l 6 test_balanced.bfc test_data/ | |
| ./build/bin/bfc info test_balanced.bfc test_data/hello.txt | |
| # Test extraction | |
| mkdir -p extract_test | |
| cd extract_test | |
| ../build/bin/bfc extract ../test.bfc | |
| # Verify extracted files | |
| [ -f hello.txt ] && echo "hello.txt extracted" | |
| [ -f bye.txt ] && echo "bye.txt extracted" | |
| [ -f subdir/nested.txt ] && echo "nested.txt extracted" | |
| cd .. | |
| rm -rf extract_test | |
| # Test encryption functionality | |
| echo "Testing encryption features..." | |
| ./build/bin/bfc create -e testpassword123 test_encrypted.bfc test_data/ | |
| ./build/bin/bfc info test_encrypted.bfc | |
| ./build/bin/bfc info test_encrypted.bfc test_data/hello.txt | grep -i encrypt | |
| # Test encrypted extraction | |
| mkdir -p extract_encrypted | |
| cd extract_encrypted | |
| ../build/bin/bfc extract -p testpassword123 ../test_encrypted.bfc | |
| # Verify extracted files from encrypted container | |
| [ -f hello.txt ] && echo "hello.txt extracted from encrypted container" | |
| [ -f bye.txt ] && echo "bye.txt extracted from encrypted container" | |
| [ -f subdir/nested.txt ] && echo "nested.txt extracted from encrypted container" | |
| cd .. | |
| rm -rf extract_encrypted | |
| # Test wrong password failure | |
| mkdir -p extract_fail_test | |
| cd extract_fail_test | |
| ! ../build/bin/bfc extract -p wrongpassword ../test_encrypted.bfc && echo "Correctly failed with wrong password" | |
| cd .. | |
| rm -rf extract_fail_test | |
| # Test key file encryption | |
| echo -n "0123456789abcdef0123456789abcdef" > test.key | |
| ./build/bin/bfc create -k test.key test_keyfile.bfc test_data/ | |
| ./build/bin/bfc info test_keyfile.bfc | grep -i encrypt | |
| mkdir -p extract_keyfile | |
| cd extract_keyfile | |
| ../build/bin/bfc extract -K ../test.key ../test_keyfile.bfc | |
| [ -f hello.txt ] && echo "hello.txt extracted with key file" | |
| cd .. | |
| rm -rf extract_keyfile | |
| # Test encryption with compression | |
| echo "This is a larger test file with enough content to be compressed by zstd compression algorithm." > test_data/large.txt | |
| ./build/bin/bfc create -e testpass -c zstd test_enc_comp.bfc test_data/ | |
| ./build/bin/bfc info test_enc_comp.bfc test_data/large.txt | grep -i encrypt | |
| ./build/bin/bfc info test_enc_comp.bfc test_data/large.txt | grep -i zstd | |
| # Clean up | |
| rm -rf test.bfc test_data test_compressed.bfc test_fast.bfc test_balanced.bfc | |
| rm -rf test_encrypted.bfc test_keyfile.bfc test_enc_comp.bfc test.key | |
| - name: Run benchmarks | |
| run: | | |
| cd build/benchmarks | |
| ./benchmark_crc32c | |
| # Run compression benchmark (quick test) | |
| timeout 60s ./benchmark_compress || gtimeout 60s ./benchmark_compress || echo "Compression benchmark completed or timed out" | |
| # Run with timeout (different commands for Linux vs macOS) | |
| if command -v timeout >/dev/null 2>&1; then | |
| timeout 30s ./benchmark_writer || true | |
| timeout 30s ./benchmark_reader || true | |
| elif command -v gtimeout >/dev/null 2>&1; then | |
| gtimeout 30s ./benchmark_writer || true | |
| gtimeout 30s ./benchmark_reader || true | |
| else | |
| # macOS without coreutils - run without timeout | |
| echo "Running benchmarks without timeout on macOS..." | |
| ./benchmark_writer & | |
| WRITER_PID=$! | |
| sleep 10 && kill $WRITER_PID 2>/dev/null || true | |
| wait $WRITER_PID 2>/dev/null || true | |
| ./benchmark_reader & | |
| READER_PID=$! | |
| sleep 10 && kill $READER_PID 2>/dev/null || true | |
| wait $READER_PID 2>/dev/null || true | |
| fi | |
| - name: Check code formatting (Ubuntu Debug only) | |
| if: matrix.os == 'ubuntu-latest' && matrix.build_type == 'Debug' | |
| run: | | |
| find src include tests examples -name "*.c" -o -name "*.h" | xargs clang-format --dry-run --Werror | |
| coverage: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y build-essential cmake lcov bc libzstd-dev libsodium-dev | |
| - name: Configure CMake with coverage | |
| run: | | |
| cmake -B build \ | |
| -DCMAKE_BUILD_TYPE=Debug \ | |
| -DBFC_COVERAGE=ON \ | |
| -DBFC_WITH_ZSTD=ON \ | |
| -DBFC_WITH_SODIUM=ON \ | |
| -DBFC_BUILD_BENCHMARKS=OFF \ | |
| -DCMAKE_C_FLAGS="--coverage -fprofile-arcs -ftest-coverage" | |
| - name: Build | |
| run: cmake --build build -j$(nproc) | |
| - name: Run tests | |
| run: | | |
| cd build | |
| ctest --output-on-failure | |
| - name: Generate coverage report | |
| run: | | |
| cd build | |
| lcov --capture --directory . --output-file coverage.info \ | |
| --rc branch_coverage=1 \ | |
| --ignore-errors deprecated,unsupported,unused | |
| lcov --remove coverage.info \ | |
| '*/tests/*' \ | |
| --output-file coverage_filtered.info \ | |
| --rc branch_coverage=1 \ | |
| --ignore-errors deprecated,unsupported,unused | |
| lcov --list coverage_filtered.info \ | |
| --rc branch_coverage=1 \ | |
| --ignore-errors deprecated,unsupported,unused | |
| - name: Check coverage thresholds | |
| run: | | |
| cd build | |
| # Generate summary and check thresholds | |
| lcov --summary coverage_filtered.info \ | |
| --rc branch_coverage=1 \ | |
| --ignore-errors deprecated,unsupported,unused > coverage_summary.txt 2>&1 | |
| # Extract coverage percentages | |
| LINE_COV=$(grep "lines" coverage_summary.txt | grep -o '[0-9]\+\.[0-9]\+%' | head -1 | sed 's/%//') | |
| FUNC_COV=$(grep "functions" coverage_summary.txt | grep -o '[0-9]\+\.[0-9]\+%' | head -1 | sed 's/%//') | |
| BRANCH_COV=$(grep "branches" coverage_summary.txt | grep -o '[0-9]\+\.[0-9]\+%' | head -1 | sed 's/%//') | |
| echo "Coverage Summary:" | |
| echo "Lines: ${LINE_COV}%" | |
| echo "Functions: ${FUNC_COV}%" | |
| echo "Branches: ${BRANCH_COV}%" | |
| # Set coverage threshold based on current achievable coverage | |
| THRESHOLD=72 | |
| # Check thresholds using bc for floating point comparison | |
| if command -v bc >/dev/null 2>&1; then | |
| LINE_FAIL=$(echo "${LINE_COV} < ${THRESHOLD}" | bc -l) | |
| FUNC_FAIL=$(echo "${FUNC_COV} < 95" | bc -l) # High threshold for functions | |
| if [ "${LINE_FAIL}" = "1" ]; then | |
| echo "ERROR: Line coverage ${LINE_COV}% is below threshold ${THRESHOLD}%" | |
| exit 1 | |
| fi | |
| if [ "${FUNC_FAIL}" = "1" ]; then | |
| echo "ERROR: Function coverage ${FUNC_COV}% is below threshold 95%" | |
| exit 1 | |
| fi | |
| echo "All coverage thresholds met!" | |
| else | |
| echo "bc not available, skipping threshold checks" | |
| fi | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v3 | |
| with: | |
| file: build/coverage_filtered.info | |
| fail_ci_if_error: false | |
| static-analysis: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y build-essential cmake clang-tidy cppcheck libzstd-dev libsodium-dev | |
| - name: Configure CMake | |
| run: cmake -B build -DCMAKE_BUILD_TYPE=Debug -DBFC_WITH_ZSTD=ON -DBFC_WITH_SODIUM=ON | |
| - name: Run clang-tidy | |
| run: | | |
| cd build | |
| run-clang-tidy -p . ../src/ || true | |
| - name: Run cppcheck | |
| run: | | |
| cppcheck --enable=all --inconclusive --xml --xml-version=2 \ | |
| --suppress=missingIncludeSystem \ | |
| --suppress=unmatchedSuppression \ | |
| src/ include/ 2> cppcheck.xml || true | |
| # Show results (non-blocking) | |
| cat cppcheck.xml | |
| security: | |
| runs-on: ubuntu-latest | |
| # Add permissions for security scanning | |
| permissions: | |
| contents: read | |
| security-events: write | |
| actions: read | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Run CodeQL Analysis | |
| uses: github/codeql-action/init@v3 | |
| with: | |
| languages: cpp | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y build-essential cmake libzstd-dev libsodium-dev | |
| - name: Build for CodeQL | |
| run: | | |
| cmake -B build -DCMAKE_BUILD_TYPE=Release -DBFC_WITH_ZSTD=ON -DBFC_WITH_SODIUM=ON -DBFC_BUILD_BENCHMARKS=OFF | |
| cmake --build build | |
| - name: Perform CodeQL Analysis | |
| uses: github/codeql-action/analyze@v3 | |
| documentation: | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'push' && github.ref == 'refs/heads/main' | |
| # Add permissions for GitHub Pages | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| # Environment for GitHub Pages deployment | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Install dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y doxygen graphviz | |
| - name: Generate documentation | |
| run: | | |
| # Create Doxygen config if it doesn't exist | |
| if [ ! -f Doxyfile ]; then | |
| doxygen -g | |
| sed -i 's/PROJECT_NAME = "My Project"/PROJECT_NAME = "BFC"/' Doxyfile | |
| sed -i 's/INPUT =/INPUT = include\/ src\/ README.md/' Doxyfile | |
| sed -i 's/RECURSIVE = NO/RECURSIVE = YES/' Doxyfile | |
| sed -i 's/GENERATE_HTML = YES/GENERATE_HTML = YES/' Doxyfile | |
| sed -i 's/OUTPUT_DIRECTORY =/OUTPUT_DIRECTORY = docs/' Doxyfile | |
| fi | |
| doxygen Doxyfile | |
| - name: Setup Pages | |
| uses: actions/configure-pages@v4 | |
| - name: Upload artifact | |
| uses: actions/upload-pages-artifact@v3 | |
| with: | |
| path: docs/html | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v4 |