# tests/cgal/CMakeLists.txt
#
# CGAL-dependent test target.  Only built when -DWITH_CGAL=ON.
# Requires Boost (find_package(Boost REQUIRED) is called in the root CMakeLists).
#
# Run with:
#   cmake -S code -B build -DWITH_CGAL=ON
#   cmake --build build --target conformallab_cgal_tests
#   ctest --test-dir build -R cgal

add_executable(conformallab_cgal_tests
    # ── Phase 3a: mesh infrastructure ──────────────────────────────────────
    test_conformal_mesh.cpp

    # ── Phase 3b: HyperIdealFunctional ─────────────────────────────────────
    test_hyper_ideal_functional.cpp

    # ── Phase 3c + 3e: SphericalFunctional + gauge-fix ────────────────────
    test_spherical_functional.cpp

    # ── Phase 3d: EuclideanCyclicFunctional ───────────────────────────────
    test_euclidean_functional.cpp

    # ── Phase 3f: Hessians (cotangent Laplacian, spherical + Euclidean) ───
    test_euclidean_hessian.cpp
    test_spherical_hessian.cpp

    # ── Phase 9b: Hyper-ideal Hessian — block-FD vs full-FD validation ───
    #    Verifies the O(F·36) block-local Hessian agrees with the
    #    O(F·n) full-FD baseline.  Java upstream has no Hessian at all
    #    (HyperIdealFunctional.hasHessian() returns false) — both
    #    variants are conformallab++ extensions beyond the port.
    test_hyper_ideal_hessian.cpp

    # ── Phase 4a: Newton solver ────────────────────────────────────────────
    test_newton_solver.cpp

    # ── Phase 4b: Mesh I/O (CGAL::IO) ─────────────────────────────────────
    test_mesh_io.cpp

    # ── Phase 4c: End-to-end pipeline + user examples ─────────────────────
    test_pipeline.cpp

    # ── Phase 5: Layout / embedding + serialization ────────────────────────
    test_layout.cpp

    # ── Phase 6: Gauss–Bonnet, cut graph, exact trilateration, normalisation
    test_phase6.cpp

    # ── Phase 7: Java-parity layout — MobiusMap, priority BFS, halfedge_uv,
    #             period matrix, fundamental domain, tiling
    test_phase7.cpp

    # ── Java parity: geometry utility tests ──────────────────────────────────
    #    Ported from CuttinUtilityTest, UnwrapUtilityTest,
    #    ConvergenceUtilityTests, HomologyTest.  All tests active —
    #    the v0.7.0 genus-2 homology stub was implemented in Phase 7
    #    (HomologyGenerators.Genus2_FourCutEdges, brezel2.obj).
    test_geometry_utils.cpp

    # ── Scalability smoke tests ────────────────────────────────────────────────
    #    Newton convergence on large real-world meshes (cathead, brezel, brezel2).
    #    Assert correctness only (< 30 iterations, ||G|| < 1e-8).
    #    Wall-clock time is printed for documentation but NOT asserted,
    #    so the tests remain stable on slow CI hardware (Raspberry Pi ARM64).
    test_scalability_smoke.cpp

    # ── Phase 8 MVP: new CGAL-style public API ────────────────────────────────
    #    First client of Conformal_map_traits.h + Discrete_conformal_map.h.
    #    Acceptance probe before Phase 9a (Inversive-Distance) lands.
    test_cgal_traits_mvp.cpp

    # ── Phase 9a.1: CPEuclideanFunctional (BPS 2010 circle packing) ──────────
    #    Face-based circle-packing functional ported from
    #    CPEuclideanFunctional.java.  Reference: Bobenko-Pinkall-Springborn 2010.
    test_cp_euclidean_functional.cpp

    # ── Phase 9a.2: InversiveDistance (Luo 2004 + Glickenstein 2011) ─────────
    #    Vertex-based inversive-distance circle-packing functional.  No Java
    #    reference; implemented from the literature.  Cross-validated against
    #    EuclideanCyclicFunctional at the natural initial geometry (u = 0).
    test_inversive_distance_functional.cpp

    # ── Phase 9a: Newton solvers for the two new circle-packing functionals ──
    #    Convergence tests for newton_cp_euclidean (analytic Hessian) and
    #    newton_inversive_distance (FD Hessian).
    test_newton_phase9a.cpp

    # ── Tier-3 Java cross-validation: Lawson square-tiled HyperIdeal ─────────
    #    Low-level half-edge genus-2 generator + golden-vector convergence.
    test_lawson_hyperideal.cpp

    # ── Phase 8b-Lite: CGAL entry wrappers for the 4 non-Euclidean modes ─────
    #    Spherical, HyperIdeal, CircleP-Euclidean, Inversive-Distance via
    #    <CGAL/Discrete_*.h> public API + Conformal_layout.h wrapper.
    test_cgal_phase8b_lite.cpp
)

target_include_directories(conformallab_cgal_tests SYSTEM PRIVATE
    ${CMAKE_SOURCE_DIR}/deps/eigen-3.4.0
    ${CMAKE_SOURCE_DIR}/deps/CGAL-6.1.1/include
    ${CMAKE_SOURCE_DIR}/deps/single_includes
    ${Boost_INCLUDE_DIRS}
)

target_include_directories(conformallab_cgal_tests PRIVATE
    ${CMAKE_SOURCE_DIR}/include
)

target_compile_definitions(conformallab_cgal_tests PRIVATE
    CGAL_DISABLE_GMP
    CGAL_DISABLE_MPFR
    # Data directory — absolute path to code/data/ at build time.
    # Used by tests that load real mesh files (cathead.obj, brezel2.obj, …).
    CONFORMALLAB_DATA_DIR="${CMAKE_SOURCE_DIR}/data"
)

# Suppress warnings from CGAL/Boost headers
target_compile_options(conformallab_cgal_tests PRIVATE
    $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-Wno-unused-parameter>
)

# Fast test-build mode (lever #10): -O0 -g overrides the inherited
# Release-mode -O3 + -DNDEBUG.  Applies only to this test target.
if(CONFORMALLAB_FAST_TEST_BUILD)
    target_compile_options(conformallab_cgal_tests PRIVATE
        $<$<CXX_COMPILER_ID:GNU,Clang,AppleClang>:-O0 -g -UNDEBUG>
    )
endif()

target_link_libraries(conformallab_cgal_tests PRIVATE GTest::gtest_main)

# ── Compile-time speed-up: precompiled headers ───────────────────────────────
#
# The CGAL+Eigen template soup dominates every TU in this target:
# measured at 5.9 s per minimal "include <CGAL/Discrete_conformal_map.h>"
# TU on Apple M1.  A shared PCH absorbs that cost once, slashing the
# total wall-clock from ~78 s (j8) to ~25 s (3×).
#
# Opt-out with -DCONFORMALLAB_USE_PCH=OFF if the PCH itself misbehaves
# (e.g. older toolchains that don't share PCH across translation units
# reliably) — falls back to the historical "every TU re-parses CGAL"
# build mode.
option(CONFORMALLAB_USE_PCH
    "Enable precompiled headers for the CGAL test target." ON)

if(CONFORMALLAB_USE_PCH)
    # Per-target Unity Build property takes precedence over the global
    # CMAKE_UNITY_BUILD; honour CONFORMALLAB_DEV_BUILD's preference here
    # so `-DCONFORMALLAB_DEV_BUILD=ON` truly turns Unity Build off for
    # incremental-rebuild workflows.
    if(NOT CONFORMALLAB_DEV_BUILD)
        set_target_properties(conformallab_cgal_tests PROPERTIES
            # Unity-builds amortise the per-TU CGAL+Eigen header cost
            # across several tests in the same compile.  Batch size 4
            # keeps gtest's TEST(...) macros + per-file `using
            # namespace …` from colliding while still cutting parser
            # cost ~4×.
            UNITY_BUILD ON
            UNITY_BUILD_MODE BATCH
            UNITY_BUILD_BATCH_SIZE 4)
    endif()

    target_precompile_headers(conformallab_cgal_tests PRIVATE
        # CGAL headers that every test transitively includes.
        <CGAL/Surface_mesh.h>
        <CGAL/Simple_cartesian.h>
        <CGAL/Kernel_traits.h>
        <CGAL/boost/graph/iterator.h>
        <CGAL/Polygon_mesh_processing/triangulate_faces.h>

        # Eigen blocks that drive the slowest template instantiations
        # (SelfAdjointEigenSolver<Matrix<2,2>>, ColPivHouseholderQR<
        # Matrix<complex,3,3>>, sparse Cholesky + QR fallback).
        <Eigen/Dense>
        <Eigen/Sparse>
        <Eigen/SparseCholesky>
        <Eigen/SparseQR>

        # GoogleTest itself; every test includes it.
        <gtest/gtest.h>

        # std headers that appear in every test.
        <vector>
        <string>
        <cmath>
        <complex>
    )
endif()

include(GoogleTest)
gtest_discover_tests(conformallab_cgal_tests
    TEST_PREFIX "cgal."
    DISCOVERY_TIMEOUT 60
)
