STATUS: proposal — awaiting confirmation. This document lists candidate tests only. No test framework has been added yet and no test code has been written. Per the task spec, implementation (section 5b) must not start until this plan is explicitly confirmed.
The source tree contains:
- Core library (
src/,include/):Array2D,Data2D,ROI2D,Disp2D,Strain2D,Image2D, the DIC enginencorr.cpp(RGDIC,DIC_analysis*,change_perspective,set_units,strain_analysis, interpolators, nloptimizers), plus the newsession.cpp(in-memory API) andconfig.cpp(+ header-onlyini.h). - Existing harnesses (
test/src/): ad-hoc executables that already exercise parts of the engine —interpolator_test,ncorr_interpolator_test,ncorr_cubic_interpolator_test,ncorr_nloptimizer_test,roi2d_reduce_test,ncorr_test_parity,ncorr_test_verif,ncorr_test_rgdic_verification,ncorr_test_sequential,ncorr_test_parallel,ncorr_test_chain_seam,ncorr_test,proxyncorr. These are standalonemain()s, not a unit-test framework, and mostly dump JSON for external (MATLAB) comparison. - Fixture dataset:
test/examples/ohtcfrp/(12 PNG frames +roi.png) — the lightweight end-to-end fixture referenced by the spec.
The spec offers two options: reuse the existing ad-hoc harness style, or add GoogleTest / Catch2 (which requires explicit approval as a new dependency). Recommendation: add Catch2 v3 via the existing FetchContent pattern (header/single-lib, no system install, matches how nlohmann_json/OpenCV are already fetched). It gives real assertions, test discovery, and CTest integration. If you prefer zero new dependencies, the alternative is a minimal in-tree assertion macro + a CTest registration of pass/fail executables. Please confirm the framework choice before I implement.
ini_parse_basic—key = value, whitespace trimming, returns expected map.ini_parse_comments— full-line#and;comments are skipped; inline comments after unquoted#/;are stripped.ini_parse_quoted_values— single/double quotes preserve spaces and embedded#/;.ini_parse_sections—[section]headers producesection.keyaddressing.ini_parse_crlf— CRLF line endings parse identically to LF.ini_typed_getters—get_int/get_double/get_boolparse valid values; bool accepts true/false/1/0/yes/no/on/off.ini_typed_getters_invalid— non-numeric int/double and bad bool throw with a descriptive message.ini_missing_file—load()of a non-existent path returns false (not throw).config_defaults— a freshConfighas the documented compiled defaults.config_overlay—load_config_fileoverrides only keys present in the file, leaving others at their incoming values.config_key_field_parity— every key inconfig/default.cfgmaps to aConfigfield (guards against silent mismatches).
imagebuffer_valid—valid()/size_bytes()for good and degenerate inputs.session_requires_reference—process_framebeforeset_referencethrowsstd::logic_error.session_rejects_invalid_reference—set_referencewith a null/empty buffer throwsstd::invalid_argument.session_geometry_mismatch— deformed frame of a different size returns an invalidDICResultwith a message (no crash).session_stub_contract— current stub returnsvalid == falseand the "not yet implemented" message (update this test when 3b is implemented).
has_image_extension— accepts png/tif/tiff/bmp/jpg/jpeg (any case), rejects others and length-edge names.natural_less—frame_2 < frame_10; zero-padded names also order correctly.discover_frames_sorted— returns frames in natural order from a temp dir.discover_frames_excludes_reserved— skipsroi.png,ref.png, hidden files, sub-directories, and explicitly named ref/roi basenames.discover_frames_empty— empty folder returns an empty vector.discover_frames_missing_folder— throwsstd::runtime_error.Note: these helpers currently live in
proxyncorr.cpp. Testing them cleanly may require extracting them into a small reader unit (e.g.include/ncorr/frame_reader.h). Flag if you want that refactor in 5b.
image2d_read_grayscale—get_gs()on a known PNG returns values in [0,1] with expected dimensions.image2d_read_missing— constructing from / reading a missing file throwsstd::invalid_argument.image2d_from_mat_roundtrip—from_matthenget_gs()matches the source.imageprocessor_mat_array_roundtrip—array2d_to_mat/mat_to_array2d.
array2d_construct_index— element access,height/width, bounds.array2d_arithmetic—+ - * /, scalar ops, equality.array2d_eye— identity construction.- (Lower priority: this is heavily templated and large; smoke-level coverage.)
interp_nearest_linear— exact recovery of node values; linear midpoint.interp_cubic_keys— reproduces a known cubic polynomial within tolerance.interp_quintic_bspline— round-trip / partition-of-unity property.Existing
interpolator_test/ncorr_cubic_interpolator_testprovide reference behaviour to port into assertions.
subregion_circle_square— generated subregion point sets for CIRCLE/SQUARE at a few radii.rgdic_synthetic_shift—RGDICon a synthetically translated image recovers the known uniform displacement within tolerance (small fixture).
strain_zero_for_rigid_translation— pure translation yields ~0 strain.strain_uniform_field— a synthetic linear displacement field yields the expected constantexx/eyy/exy.
roi_from_mask— threshold mask -> region count and mask round-trip.roi_reduce— port assertions from existingroi2d_reduce_test.roi_update—update(ROI, Disp, INTERP)SKIP_ALL vs SKIP_INVALID behaviour.
set_units_scaling—set_unitsscales displacement by units/pixel.change_perspective_identity— converting and (where applicable) inverting returns a field close to the original on a synthetic case.
pipeline_load_to_dic— loadohtcfrpref + one deformed frame, buildDIC_analysis_input, runDIC_analysis, assert output dimensions and a finite displacement inside the ROI.pipeline_dic_to_strain— feedDIC_analysis_outputintostrain_analysis, assert strain field dimensions and finiteness in-ROI.pipeline_perspective_units—DIC_analysis -> change_perspective -> set_unitschain runs and preserves dimensions.pipeline_sequential_vs_parallel—DIC_analysis_sequentialandDIC_analysis(parallel)agree within tolerance on the same small input.pipeline_config_drives_run— load params from a temp INI, confirm the run uses them (e.g. radius/scalefactor reflected inDIC_analysis_input).pipeline_export_outputs— JSON and binary save/round-trip (save/load) of DIC/strain inputs and outputs to a temp dir.pipeline_session_matches_folder(deferred until 3b implemented) — onceNcorrSession::process_frameis real, assert it matches the folder pipeline on the same frames.
e2e_ohtcfrp_smoke— run the full pipeline (or theproxyncorrexecutable) ontest/examples/ohtcfrpwith a reduced frame count, writing to a temp output dir; assert it exits 0 and produces the expected output files.e2e_ohtcfrp_known_value— at a chosen in-ROI control point on a specific frame, assert the displacement magnitude matches a recorded golden value within tolerance. Action needed: capture the golden value from a trusted run during 5b (or supply one) — please confirm the control point/frame and the acceptable tolerance.- Keep CI-friendly: use 2-3 frames, small scalefactor, no video rendering, no large downloads.
- Framework: Catch2 v3 via FetchContent (recommended) or in-tree minimal asserts + CTest — your call.
- Layout:
test/unit/,test/integration/,test/e2e/, registered withenable_testing()/add_testsoctestruns everything. - Fixtures: reuse
test/examples/ohtcfrp; generate synthetic shifted images in-memory for deterministic unit tests (no new data files). - Tolerances: define a shared
kDispTol/kStrainTol; sub-pixel DIC tests use loose tolerances (e.g. 0.05 px) to stay robust across platforms. - Possible small refactor: extract
discover_frames/has_image_extension/natural_lessinto a reusable header so 1c can test them without compiling all ofproxyncorr.cpp— flag if acceptable.
- Test framework: Catch2 v3 (FetchContent) or in-tree asserts?
- OK to extract the folder-reader helpers into a small unit for testability?
- The e2e golden control point + tolerance (or approve capturing one during 5b).