Add PngSuite tests to prevent pngcheck regressions - #53
Conversation
jbowler
left a comment
There was a problem hiding this comment.
I'm reviewing bats as a black box, but based on the "expectations" files this won't work; pngcheck is outputting a compression ratio at the end of the "OK" lines and that is almost certain to change.
The "x" files in PNGSuite also create an issue because the text in pngcheck output for errors is likely to change; maintainers do that.
I think this could be fixed by just checking for "OK" or "ERROR" at the start of the line. The exact output may be wrong but the point of pngcheck is to do a pass/fail and if @svgeesus feels like changing the somewhat abrupt "ERROR" then the CI tests can be changed too :-)
That said pngcheck returns an error code and that is the platinum in the sea of gold; automated testing relies on pngcheck to reliably identify possibly non-conformant (in the PNG sense) images. I guess what I'm saying is that it doesn't matter what it says, what matters is that it fails.
I suggest not checking output, which depends on many things, language for one, but just the return code for each of the PNGSuite images.
|
Just to be clear: I'm intensely critical and over the years I've learned to do this only to people I respect. |
|
@jbowler point taken and I agree with the sentiments expressed.
Very honored for this... 😜 Just doing what we can to help out the community! After some thought (and some time...) instead of BATS I'll rework this PR to use Ceedling which is apparently the leading C testing framework. Its component called "Unity" is a lightweight test library that is quite popular. With Ceedling it would be possible in the future if pngcheck is to be refactored into smaller files that can be unit tested then the framework will allow testing those. So please don't merge this yet, I'll re-push once done. |
Mark the PR as "draft" - see the top right of this page. |
|
Thanks! I wanted to do so earlier but couldn't find the button... |
f4e745a to
437f860
Compare
|
Are your builds all using CMakeLists.txt or are they using the makefiles in some cases? @ctruta, @svgeesus - CMakeLists.txt was only added 6 days ago but it seems to me that the makefiles should all be removed and only CMakeLists.txt used. It's confusing to have two ways of doing the same thing and I didn't see any documentation of what to use. |
|
@jbowler This PR aims to test both CMake and traditional Makefile workflows because this repo was documented to support both approaches. |
437f860 to
7f05096
Compare
|
This is done and all builds/tests now pass across all supported platforms and the two allowed build platforms (CMake and traditional Makefile), including:
There are a few caveats that I couldn't solve:
|
672c368 to
8712f56
Compare
jbowler
left a comment
There was a problem hiding this comment.
The local build picks up the installed pngcheck not the one that is built. I guess that doesn't matter in a Docker but it does for people developing the tests and it's confusing in any case.
|
So far as the github actions are concerned by very basic test of pushing the changes to my own github repo are producing the results I expect; I deliberately introduced errors to make sure I get failures. The results are on the "Actions" tab here: https://github.com/jbowler/pngcheck/actions @svgeesus - I suggest you merge this now. It has adequate documentation for maintenance, although a little familiarity with rubygems helps (I now have sufficient after 30 minutes). The issue with picking up an installed pngcheck doesn't affect the github actions behavior and it's trivial to disable the actions ("workflows") - e.g. I just disabled one of them, "build-makefile". |
Yes, that is an issue that requires foreknowledge, it probably should be documented somewhere clear. The environment variable |
So if I type "cmake", then type "make", then type "make test" I expect PNGCHUNK_EXECUTABLE to end up set appropriately. The use of existing PATH is certainly a bug in Linux, et al. LDD_LIBRARY_PATH has the same problem. I don't know any way of getting round that bug. Life sucks. From a cmake environment (I'd like to see the makefiles die without trace @svgeesus) I don't see why it can't be done; @ctruta (resident cmake expert!) |
|
if the direction is to get rid of Makefiles, we can create a target in CMake to run tests, perhaps linking with CTest. That would certainly make life easier if there’s only one build system. |
f27968a to
c99e2f6
Compare
96e584e to
5c9ef82
Compare
|
This PR is finally ready to go! All tests in our fork are passing across all platforms: There are some caveats I wasn't able to solve in Windows CI, and they are now described in TESTING.md. Reproduced below for convenience. CI troublesWindows CI (windows-2022, windows-11-arm)For some reason, the CMake custom target (in In addition, Windows builds the As a result, the
|
|
This is very useful, but let us sort out PR #52 first, and then we'll move over to this one. |
|
Also, once this lands, I intend to add additional images to test out Third Edition chunks (and even Fourth Edition updates) |
|
Just like PR #52, this one, too, is a very extensive and thorough change, but I would like to make it simpler. I don't mind the history of three commits in #52 (and I also wouldn't mind if you squash those into a single commit, either), but these ones absolutely need to be squashed. Let us integrate #52 first, and then, you can rebase these ones over that, and then we'll proceed with the review. |
That seems over cautious. The pngsuite license is very clear:
Also, copying these in means that others can be added (I have several to add). |
12709fb to
0c822a8
Compare
| $arch = if ("${{ matrix.runner }}" -eq "windows-11-arm") { "arm64" } else { "x64" } | ||
| vcpkg install zlib:$arch-windows | ||
|
|
||
| # CMake builds | ||
| - name: Build with CMake (Ubuntu/macOS) | ||
| if: matrix.os == 'ubuntu' || matrix.os == 'macos' | ||
| # CMake builds using presets | ||
| - name: Build with CMake (macOS) | ||
| if: matrix.os == 'macos' | ||
| run: | | ||
| cmake -B build-cmake \ | ||
| -DCMAKE_BUILD_TYPE=Release \ | ||
| -DPNGCHECK_USE_SYSTEM_ZLIB=ON | ||
| cmake --build build-cmake --config Release | ||
| cmake --preset Debug \ | ||
| -DCMAKE_OSX_ARCHITECTURES=${{ matrix.runner == 'macos-13' && 'x86_64' || 'arm64' }} | ||
| cmake --build build --preset Debug | ||
|
|
||
| - name: Build with CMake (Ubuntu) | ||
| if: matrix.os == 'ubuntu' | ||
| run: | | ||
| cmake --preset Debug | ||
| cmake --build build --preset Debug | ||
|
|
||
| - name: Build with CMake (Windows MSVC) | ||
| if: matrix.os == 'windows' | ||
| run: | | ||
| $arch = if ("${{ matrix.runner }}" -eq "windows-11-arm") { "ARM64" } else { "x64" } | ||
| cmake -B build-cmake -A $arch -DCMAKE_BUILD_TYPE=Release -DPNGCHECK_USE_SYSTEM_ZLIB=ON -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake | ||
| cmake --build build-cmake --config Release | ||
| cmake --preset Debug -A $arch -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake | ||
| cmake --build build --preset Debug | ||
|
|
||
| - name: Build with CMake (Windows MSYS2) | ||
| if: matrix.os == 'windows-msys2' | ||
| shell: msys2 {0} | ||
| run: | | ||
| cmake -B build-cmake \ | ||
| -G "MSYS Makefiles" \ | ||
| -DCMAKE_BUILD_TYPE=Release \ | ||
| -DPNGCHECK_USE_SYSTEM_ZLIB=ON | ||
| cmake --build build-cmake --config Release | ||
| cmake --preset Debug -G "MSYS Makefiles" | ||
| cmake --build build --preset Debug | ||
|
|
||
| # Testing CMake builds | ||
| - name: Test CMake build (MSYS2) | ||
| # Test that the executable works | ||
| - name: Test executable (MSYS2) | ||
| if: matrix.os == 'windows-msys2' | ||
| shell: msys2 {0} | ||
| run: | | ||
| build-cmake/pngcheck.exe -h | ||
| build/Debug/pngcheck.exe -h | ||
|
|
||
| - name: Test CMake build (Windows MSVC) | ||
| # TODO: No idea why MSVC builds at Debug/Debug/pngcheck.exe... | ||
| - name: Test executable (Windows MSVC) | ||
| if: matrix.os == 'windows' | ||
| run: | | ||
| build-cmake/Release/pngcheck.exe -h | ||
| build/Debug/Debug/pngcheck.exe -h | ||
|
|
||
| - name: Test CMake build (Unix/macOS) | ||
| - name: Test executable (Unix/macOS) | ||
| if: matrix.os == 'ubuntu' || matrix.os == 'macos' | ||
| run: | | ||
| ./build-cmake/pngcheck -h | ||
| ./build/Debug/pngcheck -h | ||
|
|
||
| # Artifacts | ||
| # Prepare and upload build artifacts | ||
| - name: Prepare artifacts (MSYS2) | ||
| if: matrix.os == 'windows-msys2' | ||
| shell: msys2 {0} | ||
| run: | | ||
| mkdir -p artifacts | ||
| cp build-cmake/pngcheck.exe artifacts/pngcheck-${{ matrix.name }}-cmake.exe | ||
| cp build/Debug/pngcheck.exe artifacts/pngcheck-${{ matrix.name }}-cmake.exe | ||
| cd artifacts | ||
| sha256sum * > checksums.txt | ||
|
|
||
| - name: Prepare artifacts (Windows MSVC) | ||
| if: matrix.os == 'windows' | ||
| run: | | ||
| mkdir -p artifacts | ||
| cp build-cmake/Release/pngcheck.exe artifacts/pngcheck-${{ matrix.name }}-cmake.exe | ||
| cp build/Debug/Debug/pngcheck.exe artifacts/pngcheck-${{ matrix.name }}-cmake.exe | ||
| cd artifacts | ||
| Get-FileHash -Algorithm SHA256 *.exe | ForEach-Object { "$($_.Hash.ToLower()) $($_.Path | Split-Path -Leaf)" } > checksums.txt | ||
|
|
||
| - name: Prepare artifacts (Unix/macOS) | ||
| if: matrix.os == 'ubuntu' || matrix.os == 'macos' | ||
| run: | | ||
| mkdir -p artifacts | ||
| cp build-cmake/pngcheck artifacts/pngcheck-${{ matrix.name }}-cmake | ||
| cp build/Debug/pngcheck artifacts/pngcheck-${{ matrix.name }}-cmake | ||
| cd artifacts | ||
| if command -v sha256sum >/dev/null 2>&1; then | ||
| sha256sum * > checksums.txt | ||
| elif command -v shasum >/dev/null 2>&1; then | ||
| shasum -a 256 * > checksums.txt | ||
| fi | ||
|
|
||
| - name: Upload artifacts | ||
| - name: Upload build artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: pngcheck-${{ matrix.name }}-cmake | ||
| path: artifacts/ | ||
| retention-days: 30 | ||
|
|
||
| load-test-matrix: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions
| name: Load Test Matrix | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| matrix: ${{ steps.filter-matrix.outputs.matrix }} | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Filter matrix for testing | ||
| id: filter-matrix | ||
| run: | | ||
| # Filter out MSYS2 entries from the matrix for testing | ||
| echo "matrix=$(jq -c '[.[] | select(.os != "windows-msys2")]' matrix.json)" >> $GITHUB_OUTPUT | ||
|
|
||
| test: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions
| name: Test ${{ matrix.name }} | ||
| runs-on: ${{ matrix.runner }} | ||
| needs: [load-test-matrix, build] | ||
|
|
||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| include: ${{ fromJson(needs.load-test-matrix.outputs.matrix) }} | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| submodules: recursive | ||
|
|
||
| # Ubuntu dependencies | ||
| - name: Install dependencies (Ubuntu) | ||
| if: matrix.os == 'ubuntu' | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y cmake build-essential zlib1g-dev | ||
|
|
||
| # macOS dependencies | ||
| - name: Install dependencies (macOS) | ||
| if: matrix.os == 'macos' | ||
| run: | | ||
| # Check if zlib is installed, install if not | ||
| if ! brew list zlib &>/dev/null; then | ||
| brew install zlib | ||
| else | ||
| echo "zlib already installed" | ||
| fi | ||
|
|
||
| # Windows dependencies | ||
| - name: Setup MSVC (Windows) | ||
| if: matrix.os == 'windows' | ||
| uses: microsoft/setup-msbuild@v2 | ||
|
|
||
| - name: Install vcpkg dependencies (Windows) | ||
| if: matrix.os == 'windows' | ||
| run: | | ||
| $arch = if ("${{ matrix.runner }}" -eq "windows-11-arm") { "arm64" } else { "x64" } | ||
| vcpkg install zlib:$arch-windows | ||
|
|
||
| # Download build artifacts from the build job | ||
| - name: Download build artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: pngcheck-${{ matrix.name }}-cmake | ||
| path: artifacts/ | ||
|
|
||
| # Rebuild for testing (needed for CMake test targets) | ||
| - name: Build with CMake (macOS) | ||
| if: matrix.os == 'macos' | ||
| run: | | ||
| cmake --preset Debug \ | ||
| -DCMAKE_OSX_ARCHITECTURES=${{ matrix.runner == 'macos-13' && 'x86_64' || 'arm64' }} | ||
| cmake --build build --preset Debug | ||
|
|
||
| - name: Build with CMake (Ubuntu) | ||
| if: matrix.os == 'ubuntu' | ||
| run: | | ||
| cmake --preset Debug | ||
| cmake --build build --preset Debug | ||
|
|
||
| - name: Build with CMake (Windows MSVC) | ||
| if: matrix.os == 'windows' | ||
| run: | | ||
| $arch = if ("${{ matrix.runner }}" -eq "windows-11-arm") { "ARM64" } else { "x64" } | ||
| cmake --preset Debug -A $arch -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake | ||
| cmake --build build --preset Debug | ||
|
|
||
| # Setup Ruby for testing | ||
| - name: Setup Ruby 3.4 | ||
| uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: '3.4' | ||
| bundler-cache: true | ||
|
|
||
| # Cache PNG suite test files | ||
| - name: Cache PNG suite test files | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: test/fixtures/pngsuite | ||
| key: pngsuite-fixtures-${{ hashFiles('test/generate_expectations.sh') }} | ||
| restore-keys: | | ||
| pngsuite-fixtures- | ||
|
|
||
| # - name: Debug environment with CMake (Windows) | ||
| # if: matrix.os == 'windows' | ||
| # env: | ||
| # PNGCHECK_EXECUTABLE: ${{ github.workspace }}\build\Debug\Debug\pngcheck.exe | ||
| # run: | | ||
| # echo "=== Debug: Windows test execution ===" | ||
| # echo "GITHUB_WORKSPACE: ${{ github.workspace }}" | ||
| # echo "Current directory: $(Get-Location)" | ||
| # echo "Environment variable check:" | ||
| # echo " PNGCHECK_EXECUTABLE = $env:PNGCHECK_EXECUTABLE" | ||
|
|
||
| # echo "Checking if executable exists..." | ||
| # if (Test-Path "$env:PNGCHECK_EXECUTABLE") { | ||
| # echo "✓ Executable found at: $env:PNGCHECK_EXECUTABLE" | ||
| # echo "File info:" | ||
| # Get-Item "$env:PNGCHECK_EXECUTABLE" | Format-List | ||
|
|
||
| # echo "Testing executable directly..." | ||
| # try { | ||
| # & "$env:PNGCHECK_EXECUTABLE" -h | ||
| # echo "✓ Executable runs successfully" | ||
| # } catch { | ||
| # echo "✗ Error running executable: $_" | ||
| # } | ||
| # } else { | ||
| # echo "✗ Executable NOT found at: $env:PNGCHECK_EXECUTABLE" | ||
| # echo "Searching for pngcheck.exe in build directory..." | ||
| # Get-ChildItem -Path "build" -Recurse -Name "pngcheck.exe" -ErrorAction SilentlyContinue | ||
| # } | ||
|
|
||
| # Download PNG test files before running tests | ||
| - name: Download PNG test files (Unix/macOS) | ||
| if: matrix.os == 'ubuntu' || matrix.os == 'macos' | ||
| run: | | ||
| cmake --build build --target pngsuite-download --preset Debug | ||
|
|
||
| # TODO: Unable to fix CMake when using the test/bin/pngcheck-test script on Windows | ||
| # It keeps saying "no such file or directory" when we try to execute the script. | ||
| # Hence we directly run the test/bin/pngcheck-test script. | ||
| - name: Download PNG test files | ||
| if: matrix.os == 'windows' | ||
| env: | ||
| PNGCHECK_EXECUTABLE: ${{ github.workspace }}\build\Debug\Debug\pngcheck.exe | ||
| run: | | ||
| bundle exec ruby test\bin\pngcheck-test download | ||
|
|
||
| # Run tests using CMake targets | ||
| - name: Run tests with CMake (Unix/macOS) | ||
| if: matrix.os == 'ubuntu' || matrix.os == 'macos' | ||
| env: | ||
| PNGCHECK_EXECUTABLE: ${{ github.workspace }}/build/Debug/pngcheck | ||
| run: | | ||
| cmake --build build --target test-all --preset Debug | ||
|
|
||
| # TODO: Unable to fix CMake when using the test/bin/pngcheck-test script on Windows | ||
| # It keeps saying "no such file or directory" when we try to execute the script. | ||
| # Hence we directly run Ceedling. | ||
| - name: Run tests with CMake (Windows) | ||
| if: matrix.os == 'windows' | ||
| env: | ||
| PNGCHECK_EXECUTABLE: ${{ github.workspace }}\build\Debug\Debug\pngcheck.exe | ||
| run: | | ||
| bundle exec ceedling test:all | ||
|
|
||
| # Upload test reports as artifacts | ||
| - name: Upload test reports | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: test-reports-${{ matrix.name }}-cmake | ||
| path: | | ||
| build/artifacts/test/ | ||
| build/logs/ | ||
| *.xml | ||
| *.json | ||
| retention-days: 30 | ||
|
|
||
| # Upload test results for GitHub's test reporting | ||
| - name: Publish Test Results | ||
| if: always() | ||
| uses: dorny/test-reporter@v1 | ||
| with: | ||
| name: Unity Tests (${{ matrix.name }}, CMake) | ||
| path: 'build/artifacts/test/junit_tests_report.xml' | ||
| reporter: java-junit | ||
| fail-on-error: true | ||
|
|
||
| # Upload test results on failure for debugging | ||
| - name: Upload test results on failure | ||
| if: failure() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: test-results-${{ matrix.name }} | ||
| path: | | ||
| test/fixtures/ | ||
| test/expectations/ | ||
| *.log | ||
| retention-days: 7 | ||
|
|
||
| coverage: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions
| name: Coverage report | ||
| runs-on: ubuntu-latest | ||
| needs: build | ||
| if: github.event_name == 'push' || github.event_name == 'pull_request' | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| submodules: recursive | ||
|
|
||
| # Ubuntu dependencies | ||
| - name: Install dependencies | ||
| run: | | ||
| sudo apt-get update | ||
| sudo apt-get install -y cmake build-essential zlib1g-dev | ||
|
|
||
| # Setup Ruby 3.4 for Ceedling | ||
| - name: Setup Ruby 3.4 | ||
| uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: '3.4' | ||
| bundler-cache: true | ||
|
|
||
| # Install gcovr for coverage reporting | ||
| - name: Install gcovr for coverage reporting | ||
| run: | | ||
| pip install gcovr | ||
|
|
||
| # Cache PNG suite test files | ||
| - name: Cache PNG suite test files | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: test/fixtures/pngsuite | ||
| key: pngsuite-fixtures-${{ hashFiles('test/generate_expectations.sh') }} | ||
| restore-keys: | | ||
| pngsuite-fixtures- | ||
|
|
||
| # Build with coverage flags | ||
| - name: Build with coverage | ||
| run: | | ||
| cmake --preset Debug | ||
| cmake --build build --preset Debug | ||
|
|
||
| # Download PNG test files before running coverage tests | ||
| - name: Download PNG test files | ||
| run: | | ||
| cmake --build build --target pngsuite-download --preset Debug | ||
|
|
||
| # Run tests with coverage analysis | ||
| - name: Run tests with coverage | ||
| continue-on-error: true | ||
| run: | | ||
| cmake --build build --target test-coverage --preset Debug | ||
|
|
||
| # Upload coverage report | ||
| - name: Upload coverage report | ||
| if: always() | ||
| continue-on-error: true | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: coverage-report-html | ||
| path: build/artifacts/gcov/ | ||
| retention-days: 30 | ||
|
|
||
| # # Upload coverage to Codecov (optional) | ||
| # - name: Upload coverage to Codecov | ||
| # if: always() | ||
| # continue-on-error: true | ||
| # uses: codecov/codecov-action@v4 | ||
| # with: | ||
| # files: build/artifacts/gcov/coverage.xml | ||
| # fail_ci_if_error: false | ||
| # verbose: true |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions
* Fixes pnggroup#57 Continuous integration tests are implemented for all supported platforms tested on GitHub Actions: * Ubuntu x64/arm64 * macOS x64/arm64 * Windows x64/arm64 * Windows MinGW 32/64 Contributed-by: Ronald Tse (@ronaldtse), Ribose (@riboseinc/@metanorma)
0c822a8 to
32de6f1
Compare
0169aa8 to
3f0cf10
Compare
|
@ctruta @svgeesus this is done! Tests are failing now due to the inability to upload test results. This is because my account (PRs run according to the user's account) has no write access to the pngcheck repository. The identical PR on our fork, where I do have access, is passing: Here are the additional changes beyond the original PR post:
|
|
@ctruta could you review? I want to merge this before adding Third Edition sample files as well. |
| ``` | ||
|
|
||
| ### PNG tests | ||
| 1. Add PNG files to `fixtures/pngsuite/` |
There was a problem hiding this comment.
I assume it would be easy in future to add additional directories under fixtures? I am thinking of the APNG testsuite, and third edition test files, for example.
|
Following up, later-is-better-than-never. @ronaldtse I recall you and I discussing about this being too big of a test matrix. So we landed #52 but now this PR clearly needs an update because many tests are failing. The tests are out of date because they check both the standard (CMake) builds and the legacy (Makefile) builds, and we agreed that we won't be re-enabling the Makefile builds. This PR needed an update back then, and it still needs it now. Are you able to help us out with getting this integrated? |
ctruta
left a comment
There was a problem hiding this comment.
I admit to knowing very little about Unity development, and even less so about Ceedling.
@ronaldtse, can you please clarify the necessity to have this as a test dependency, when (in my opinion) simply enumerating the various platforms and compilers that we want to test with CMake should in fact be sufficient?
|
Thanks again for your effort, @ronaldtse. I agree the PngSuite fixtures are genuinely useful. However, after researching and taking into consideration the maintenance costs involving the Ceedling library, I've decided to implement the test infrastructure using CTest to keep dependencies within the standard C development toolchain. I'm closing this PR, although I will credit your contribution when I add the test fixtures. |
This is a follow-up to #52. (please merge #52 before this, or we could rebase this after the merge of #52)
This PR adds the Bats (Bash Automated Testing System) framework and accompanying tests.NOTE: A detailed description of the test framework and architecture is available in
the TESTING.md file, and here I'm pasting some relevant content from there.
This PR adds a hybrid CMake/Ceedling testing framework for the
pngchecktoensure robust PNG validation across all platforms.
There are 2 categories of tests added:
pngcheckon images from Willem van Schaik's PngSuite of 176 images.The full test suite is run across all test platforms supported in #52 on GitHub Actions.
The test fixtures of PngSuite are pulled in dynamically in order to prevent
licensing issues for this repository.
Testing pngcheck
Introduction
This document describes the comprehensive testing framework for the
pngcheckutility, which uses a hybrid CMake/Ceedling/Unity approach to ensure robust PNG
validation across all platforms.
Architecture
The
test/directory contains the test suite for thepngcheckutility, whichis used to guard against regressions on PNG validation.
The test files are sourced from the PngSuite
collection, which provides a comprehensive set of PNG test files designed to
test the robustness and compliance of PNG processing tools.
The test framework uses Unity C
testing framework with Ceedling
build system to run comprehensive tests against the
pngcheckexecutable.The CMake build infrastructure seamlessly integrates with Ceedling, allowing you
to run tests directly from CMake without needing to manually invoke Ceedling
commands.
Note: The CMake/Ceedling integration architecture follows best practices
adopted from the structure of the
apm32-ceedling-example
repository.
Overview
project.yml)As the Ceedling framework is written in Ruby, the test suite uses a Ruby
command-line tool (
test/bin/pngcheck-test) to manage the test files,expectations, and to run the tests.
Prerequisites
Overview
Installation
CMake: Install from your package manager or download from
cmake.org
Ruby: Install from your package manager or download from
ruby-lang.org
Bundler: Install via RubyGems:
Ceedling: Install via Bundler:
Python: Install from your package manager or download from
python.org
gcovr: Install via pip:
Quick start
Using CMake (Recommended)
Using Ceedling directly
Running tests in CMake
The project integrates CMake with Ceedling tests such that all test targets are
available via CMake. This allows you to run tests without needing to interact
with Ceedling.
Available CMake targets
Test targets
test-allRun all Ceedling tests (alias:
test).The JUnit XML test report gets generated at
build/artifacts/test/junit_tests_report.xml.If Ceedling is not installed, the target provides helpful instructions
on how to install it.
Ceedling is a Ruby-based testing framework, so you need to have Ruby and
Bundler installed. You can install Ceedling using Bundler:
test-verboseRun all tests with verbose output.
test-cleanClean Ceedling test artifacts (alias:
clean-test).test-coverageRun tests with coverage analysis and generate HTML report (requires
gcovr).When
gcovris installed, coverage targets generate both console output andHTML reports in
build/artifacts/gcov/. The HTML report is located atbuild/artifacts/gcov/index.html.Note: Prerequisites need to be satisfied to use this tool (see
prerequisites).
test-pngcheck-cliRun CLI-specific tests only.
test-pngcheck-suiteRun PNG suite tests only.
Targets for test case generation
pngsuite-statusCheck the status of PNG suite test files. Shows which files are present and missing.
pngsuite-downloadDownload PNG test files from the PngSuite collection. This target automaticallydownloads the required PNG files to
test/fixtures/pngsuite/if they aremissing.
Note: This target is automatically run as a dependency oftest-allto ensurePNG files are available before running tests.
generate-pngsuite-expectationsGenerate expected output files for PNG suite tests. This target runs pngcheck
against all PNG files in the suite and captures the expected outputs to
test/expectations/pngsuite/.Use this target when pngcheck behavior changes and you need to update the test
expectations.
generate-pngsuite-testsGenerate the
test/test/test_pngcheck_suite.cfile based on the PNG files andexpectations. This target creates the actual C test functions that will be
executed by the test framework.
CMake presets
The project includes the following CMake presets:
They can be used to configure and build the project easily:
Integration with Ceedling
A two-file approach is used to bridge the CMake build system with Ceedling's
test framework:
CMakeLists.txt- Main CMake configuration file that includes the test subdirectorytest/CMakeLists.txt- CMake configuration for the test suiteThis integration provides the following features:
Instead of needing to manually set the
PNGCHECK_EXECUTABLEenvironmentvariable, the CMake integration automatically locates the built
pngcheckexecutable and sets the environment variable for you.
CMake automatically manages dependencies, ensuring that the
pngcheckexecutable is built before running tests.
The CMake targets provide a consistent interface for running tests across
different platforms, without needing to manually invoke Ceedling commands.
The CMake integration provides clear error messages if dependencies are missing,
such as
ceedlingorgcovr, guiding users to install them.Test structure
Test files
test/support/test_helpers.c- Common test functionstest/support/test_helpers.h- Header for common test functionstest/test/test_pngcheck_cli.c- CLI functionality tests (manual)test/test/test_pngcheck_suite.c- PNG validation tests (auto-generated)Directory layout
Test approach
Tests validate pngcheck behavior using simple prefix matching and exit codes:
This approach focuses on core functionality rather than exact output matching.
CLI tests
Static tests for command-line options:
-h)-v,-q,-t,-p,-c,-7)PNG suite tests
Auto-generated tests using the PngSuite collection:
Note: The PNG suite tests are not committed to the repository due to
licensing considerations. Instead, the test management tool
(
test/bin/pngcheck-test) downloads the PNG files from the PngSuite websitewhen needed. This ensures that the tests remain up-to-date with the latest PNG
suite files.
Test management
The test suite includes a Ruby-based management tool.
Note: Prerequisites need to be satisfied to use this tool (see
prerequisites).
To manage tests, run the Ruby CLI tool:
Adding tests
CLI tests
Edit
test/test_pngcheck_cli.cand use helper functions:PNG tests
fixtures/pngsuite/bundle exec test/bin/pngcheck-test expectationsbundle exec test/bin/pngcheck-test generateTroubleshooting
pngcheck not found: Build with
makeorcmakeMissing PNG files: Runbundle exec test/bin/pngcheck-test downloadRuby issues: Run
bundle installCredits
FYI @jbowler @ctruta @svgeesus