Testing

OpenMeta treats metadata parsing as security-sensitive code. Tests and fuzzing are part of the expected workflow for parser changes.

Unit tests (GoogleTest)

cmake -S . -B build-tests -G Ninja -DCMAKE_BUILD_TYPE=Debug \
  -DCMAKE_PREFIX_PATH=/mnt/f/UBSd -DOPENMETA_BUILD_TESTS=ON
cmake --build build-tests
ctest --test-dir build-tests --output-on-failure

If your test dependencies were built against libc++ (common with Clang), configure OpenMeta with -DOPENMETA_USE_LIBCXX=ON.

If CTest-launched external tools need a custom runtime lookup path for that standard library, configure -DOPENMETA_TEST_RUNTIME_LIBRARY_PATH=/path/to/runtime-libs. OpenMeta applies it as LD_LIBRARY_PATH on Linux and DYLD_LIBRARY_PATH on macOS.

Fuzzing

libFuzzer targets (Clang):

cmake -S . -B build-fuzz -G Ninja -DCMAKE_BUILD_TYPE=Debug -DOPENMETA_BUILD_FUZZERS=ON
cmake --build build-fuzz
ASAN_OPTIONS=detect_leaks=0 ./build-fuzz/openmeta_fuzz_exif_tiff_decode -max_total_time=60

Corpus runs

If you pass corpus directories to libFuzzer, it treats the first directory as the main corpus and may add/reduce files there. To avoid modifying your seed corpus, use an empty output directory first:

mkdir -p build-fuzz/_corpus_out
ASAN_OPTIONS=detect_leaks=0 ./build-fuzz/openmeta_fuzz_container_scan \
  build-fuzz/_corpus_out \
  /path/to/seed-corpus-a /path/to/seed-corpus-b \
  -runs=1000

Public in-tree seed corpus:

mkdir -p build-fuzz/_corpus_out
ASAN_OPTIONS=detect_leaks=0 ./build-fuzz/openmeta_fuzz_container_scan \
  build-fuzz/_corpus_out \
  tests/fuzz/corpus/container_scan \
  -runs=1000

The container_scan seed set includes BMFF iloc method-2 relation cases (valid v1 iref mapping, missing mapping, out-of-range extent_index, and idx_size=0 reference mismatch).

FuzzTest targets (when available):

cmake -S . -B build-fuzztest -G Ninja -DCMAKE_BUILD_TYPE=Debug \
  -DCMAKE_PREFIX_PATH=/mnt/f/UBSd -DOPENMETA_BUILD_FUZZTEST=ON -DOPENMETA_FUZZTEST_FUZZING_MODE=ON
cmake --build build-fuzztest
ASAN_OPTIONS=detect_leaks=0 ./build-fuzztest/openmeta_fuzztest_metastore --fuzz_for=10s

CLI smoke gates

Public-tree smoke targets (self-contained, no external corpus required):

cmake --build build-tests --target openmeta_gate_metavalidate_smoke
ctest --test-dir build-tests -R openmeta_cli_metavalidate_smoke --output-on-failure
cmake --build build-tests --target openmeta_gate_metaread_safe_text_smoke

These gates provide fast regression checks for safe-output and validation behavior. Corpus-scale compare/baseline gates are expected to run in project CI or release validation workflows.

Transfer release gate

The stronger transfer release gate rolls up the main transfer-focused unit suite and the public transfer smoke coverage into one named check.

  • In a non-Python test tree it runs:

    • MetadataTransferApi.*

    • XmpDump.*

    • ExrAdapter.*

    • DngSdkAdapter.*

    • openmeta_cli_metatransfer_smoke

  • In a Python-enabled test tree it also runs:

    • openmeta_python_transfer_probe_smoke

    • openmeta_python_metatransfer_edit_smoke

cmake --build build-tests --target openmeta_gate_transfer_release
ctest --test-dir build-tests -R openmeta_transfer_release_gate --output-on-failure

The external image-usability gate can also use existing BMFF target files when local tools cannot create them: OPENMETA_BMFF_HEIF_TEST_TARGET, OPENMETA_BMFF_AVIF_TEST_TARGET, and OPENMETA_BMFF_CR3_TEST_TARGET. Configured targets exercise the ICC property, XMP item, MakerNote, and EXIF image-property transfer/read-back paths. For real configured targets, the gate infers target-owned image dimensions, channel count, bit depth, sample format, and photometric layout before transfer, so it does not intentionally write mismatched image geometry. The configured XMP assertion is based on OpenMeta’s BMFF summary; ExifTool title validation is also applied for formats where ExifTool exposes the generic BMFF XMP item. ExifTool is also used for BMFF EXIF/ICC reader checks when available. If the local oiiotool build cannot decode a configured BMFF target after rewrite, OPENMETA_FFMPEG_EXECUTABLE can provide the decode fallback.

ExifTool is an optional external validation tool in these tests, not an OpenMeta runtime dependency. Keep it patched when running validation against untrusted files. This matters especially on macOS, where older ExifTool releases have had metadata-write command-injection issues in their own platform-specific tooling.

The public GitHub Actions workflow .github/workflows/ci.yml runs two Linux variants of these public release gates:

  • self-contained non-Python, non-DNG-SDK

  • Python-enabled, non-DNG-SDK, with nanobind installed into the CI interpreter via pip

Read release gate

The read release gate rolls up the main self-contained decode, scan, and interop-adapter suites into one named check. It includes coverage such as:

  • ContainerScan.*

  • ContainerPayload.*

  • ExifTiffDecode.*

  • SimpleMetaRead.*

  • XmpDecodeTest.*

  • JumbfDecode.*

  • OcioAdapter.*

  • ValidateFile.*

cmake --build build-tests --target openmeta_gate_read_release
ctest --test-dir build-tests -R openmeta_read_release_gate --output-on-failure

CLI release gate

The CLI release gate rolls up the self-contained public CLI smokes that are not already part of the transfer gate:

  • openmeta_cli_metaread_safe_text_smoke

  • openmeta_cli_metaread_photoshop_irb_smoke

  • openmeta_cli_metavalidate_smoke

  • openmeta_cli_numeric_parse_smoke

cmake --build build-tests --target openmeta_gate_cli_release
ctest --test-dir build-tests -R openmeta_cli_release_gate --output-on-failure

Interop adapter tests

Adapter-focused tests in the public tree:

cmake --build build-tests --target openmeta_tests
./build-tests/openmeta_tests --gtest_filter='InteropExport.*:OcioAdapter.*:ExrAdapter.*'
./build-tests/openmeta_tests --gtest_filter='CrwCiffDecode.*'

These tests cover:

  • alias/spec name-policy behavior in InteropExport,

  • flat host-style naming plus OCIO/EXR adapter export stability,

  • CRW/CIFF derived EXIF mapping for legacy Canon RAW.