option(NEOSPICE_DEBUG_COMPARE "Print margin diagnostics from compare functions" OFF)
if(NEOSPICE_DEBUG_COMPARE)
    add_compile_definitions(NEOSPICE_DEBUG_COMPARE)
endif()

include(FetchContent)

FetchContent_Declare(
    googletest
    URL https://github.com/google/googletest/archive/refs/tags/v1.14.0.tar.gz
    URL_HASH SHA256=8ad598c73ad796e0d8280b082cebd82a630d73e73cd3c70057938a6501bba5d7
)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)

include(GoogleTest)


add_executable(neospice_tests
    unit/test_matrix.cpp
    unit/test_amd.cpp
    unit/test_btf.cpp
    unit/test_neo_solver.cpp
    unit/test_amd_lu.cpp
    unit/test_solver_select.cpp
    unit/test_resistor.cpp
    unit/test_vsource.cpp
    unit/test_isource.cpp
    unit/test_capacitor.cpp
    unit/test_inductor.cpp
    unit/test_gear.cpp
    unit/test_timestep.cpp
    unit/test_diode.cpp
    unit/test_circuit.cpp
    unit/test_convergence.cpp
    unit/test_node_classify.cpp
    unit/test_gain_homotopy.cpp
    unit/test_tokenizer.cpp
    unit/test_parser.cpp
    unit/test_ako.cpp
    unit/test_parser_mosfet.cpp
    unit/test_transient.cpp
    unit/test_ac.cpp
    unit/test_comparator.cpp
    unit/test_oscillator_comparator.cpp
    unit/test_api.cpp
    unit/test_sim_status.cpp
    unit/test_sim_status_enriched.cpp
    unit/test_raw_writer.cpp
    unit/test_ngspice_compare.cpp
    unit/test_bsim4v7_ucb_setup.cpp
    unit/test_bsim4v7_shim_load_fields.cpp
    unit/test_device_state_interface.cpp
    unit/test_bsim4v7_shim_matrix.cpp
    unit/test_bsim4v7_ucb_load.cpp
    unit/test_circuit_state_allocation.cpp
    unit/test_circuit_state_rotation.cpp
    unit/test_newton_init_mode_flip.cpp
    unit/test_bsim4v7_niintegrate.cpp
    unit/test_sim_options_temp_plumbing.cpp
    unit/test_internal_nodes.cpp
    unit/test_bsim4v7_ac.cpp
    unit/test_bsim4v7_trunc.cpp
    unit/test_bsim4v7_cvtest.cpp
    unit/test_bsim4v7_query.cpp
    unit/test_vcvs.cpp
    unit/test_vccs.cpp
    unit/test_ccvs.cpp
    unit/test_cccs.cpp
    unit/test_dc_sweep.cpp
    unit/test_save_filter.cpp
    unit/test_expression.cpp
    unit/test_expression_random.cpp
    unit/test_subcircuit.cpp
    unit/test_subcircuit_expand.cpp
    unit/test_include.cpp
    unit/test_lib.cpp
    unit/test_pdk_integration.cpp
    unit/test_bjt.cpp
    unit/test_coupled_inductor.cpp
    unit/test_tline.cpp
    unit/test_ltra.cpp
    unit/test_jfet.cpp
    unit/test_switch.cpp
    unit/test_noise.cpp
    unit/test_noise_flicker.cpp
    unit/test_noise_temp.cpp
    unit/test_bjt_jfet_noise.cpp
    unit/test_bsim4v7_noise.cpp
    unit/test_fourier.cpp
    unit/test_measure.cpp
    unit/test_output.cpp
    unit/test_options.cpp
    unit/test_nonlinear_sources.cpp
    unit/test_bordodynov_parser.cpp
    unit/test_asrc.cpp
    unit/test_ths4131.cpp
    unit/test_tf.cpp
    unit/test_sens.cpp
    unit/test_pz.cpp
    unit/test_step.cpp
    unit/test_ringing.cpp
    unit/test_introspection.cpp
    unit/test_handles.cpp
    unit/test_circuit_typed.cpp
    unit/test_circuit_semiconductor.cpp
    unit/test_measure_utils.cpp
    unit/test_kicad_lm358_ns.cpp
    unit/test_kicad_bc547a.cpp
    unit/test_kicad_opa1632.cpp
    unit/test_api_integration.cpp
    unit/test_node_damping.cpp
    unit/test_dead_node_pin.cpp
    unit/test_true_gmin.cpp
    unit/test_reorder_pivot.cpp
    unit/test_topology.cpp
    unit/test_src_fact.cpp
    unit/test_adaptive_ptc.cpp
    framework/ngspice_runner.cpp
    framework/comparator.cpp
)

target_link_directories(neospice_tests PRIVATE ${NGSPICE_LIBRARY_DIRS})
target_link_libraries(neospice_tests PRIVATE
    gtest_main
    neospice_lib
    ${NGSPICE_LIBRARIES}
)

target_include_directories(neospice_tests PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${NGSPICE_INCLUDE_DIRS}
)

target_compile_definitions(neospice_tests PRIVATE
    TEST_CIRCUITS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/circuits"
)

gtest_discover_tests(neospice_tests)

# Per-device comparison tests
add_subdirectory(devices/asrc)
add_subdirectory(devices/bjt)
add_subdirectory(devices/bsim3)
add_subdirectory(devices/bsim4v7)
add_subdirectory(devices/dio)
add_subdirectory(devices/hfet1)
add_subdirectory(devices/hfet2)
add_subdirectory(devices/ltra)
add_subdirectory(devices/mes)
add_subdirectory(devices/mos1)
add_subdirectory(devices/mos2)
add_subdirectory(devices/jfet2)
add_subdirectory(devices/mos3)
add_subdirectory(devices/mos9)
add_subdirectory(devices/vbic)
add_subdirectory(devices/bsim3v32)
add_subdirectory(devices/hisim2)
add_subdirectory(devices/hisimhv)
add_subdirectory(devices/bsimsoi)
add_subdirectory(devices/vdmos)

# Performance benchmarks (requires: apt install libngspice0-dev)
add_executable(bench_ths4131
    bench/bench_ths4131.cpp
)

target_link_directories(bench_ths4131 PRIVATE ${NGSPICE_LIBRARY_DIRS})
target_link_libraries(bench_ths4131 PRIVATE neospice_lib ${NGSPICE_LIBRARIES})
target_include_directories(bench_ths4131 PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR} ${NGSPICE_INCLUDE_DIRS})
target_compile_definitions(bench_ths4131 PRIVATE
    TEST_CIRCUITS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/circuits"
)

add_executable(bench_comprehensive
    bench/bench_comprehensive.cpp
)
target_link_directories(bench_comprehensive PRIVATE ${NGSPICE_LIBRARY_DIRS})
target_link_libraries(bench_comprehensive PRIVATE neospice_lib ${NGSPICE_LIBRARIES})
target_include_directories(bench_comprehensive PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR} ${NGSPICE_INCLUDE_DIRS})
target_compile_definitions(bench_comprehensive PRIVATE
    TEST_CIRCUITS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/circuits"
)

add_executable(bench_tlv3201
    bench/bench_tlv3201.cpp
    framework/ngspice_runner.cpp
    framework/comparator.cpp
)
target_link_directories(bench_tlv3201 PRIVATE ${NGSPICE_LIBRARY_DIRS})
target_link_libraries(bench_tlv3201 PRIVATE neospice_lib ${NGSPICE_LIBRARIES})
target_include_directories(bench_tlv3201 PRIVATE
    ${CMAKE_CURRENT_SOURCE_DIR} ${NGSPICE_INCLUDE_DIRS})
target_compile_definitions(bench_tlv3201 PRIVATE
    TEST_CIRCUITS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/circuits"
)

add_executable(debug_tlv3201
    bench/debug_tlv3201.cpp
)
target_link_libraries(debug_tlv3201 PRIVATE neospice_lib)
target_include_directories(debug_tlv3201 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(debug_tlv3201 PRIVATE
    TEST_CIRCUITS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/circuits"
)

add_executable(bench_neo_solver
    bench/bench_neo_solver.cpp
)
target_link_libraries(bench_neo_solver PRIVATE neospice_lib)
target_include_directories(bench_neo_solver PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

# Solver-throughput benchmark: measures solve time isolated from parse time on
# large, scalable in-memory circuits. neospice-only (no ngspice dependency).
# Not registered with ctest -- benchmarks must not gate CI.
add_executable(bench_solver_throughput
    bench/bench_solver_throughput.cpp
)
target_link_libraries(bench_solver_throughput PRIVATE neospice_lib)
target_include_directories(bench_solver_throughput PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(bench_solver_throughput PRIVATE
    TEST_CIRCUITS_DIR="${CMAKE_CURRENT_SOURCE_DIR}/circuits"
)

# Ordering spike: measures LU fill (natural vs neospice's amd_ordering) and a
# representative no-pivot factor-time estimate vs the production Markowitz
# solver. neospice-only, not registered with ctest (a measurement spike).
# amd.cpp/btf.cpp are now part of neospice_lib, so link the lib (do NOT
# recompile core/amd.cpp here to avoid duplicate-symbol/ODR issues).
add_executable(bench_ordering_spike
    bench/bench_ordering_spike.cpp
)
target_link_libraries(bench_ordering_spike PRIVATE neospice_lib)
target_include_directories(bench_ordering_spike PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
