import libs = libglaze%lib{glaze}
import eigen = Eigen%lib{Eigen}
import sqlite = libsqlite3%lib{sqlite3}

define csv: file
csv{*}: extension = csv

define toml: file
toml{*}: extension = toml

define yaml: file
yaml{*}: extension = yml

# Unit tests.
#
exe{*}:
{
  test = true
  install = false
}

# skip: erlang (sys-lib), lib_test (annoying setup), streaming_view_rejection
#       and wrapper_rejection (compile-failure tests).
#
# note: this skips nested tests (eg. networking_tests/*/) for no other reason
#       than to avoid dealing with every single nuance in the CMake setup.
for [dir_path] d: tests/{*_test*/ \
                          -eetf_test/ \
                          -lib_test/ \
                        } \
                  tests/{*_formats/ \
                          -custom_formats/ \
                        } \
                  tests/{ \
                          *_conformance/ \
                          *_parsing/ \
                          *_performance/ \
                          *_repe/ \
                          reflection/ \
                          inplace_vector/ \
                        }
{
  n = $string($leaf($d))
  # beve_test.cpp is replaced by a patched copy (see below).
  for t: tests/$n/cxx{* -beve_test}
  {
    tn = $name($t)
    # Name targets '<subdir>-<name>' unless identical
    if ("$n" != "$tn")
      e = $n-$tn
    else
      e = $n
    exe{$e}: ut/hxx{ut} tests/hxx{*} tests/$n/hxx{*} tests/$n/cxx{$tn} \
                 tests/$n/{json csv toml yaml}{**} $libs testscript

    enabled = true

    switch $e: path.match
    {
      case 'p2996_test'
      {
        # Requires C++26 reflection.
        enabled = false
      }
      case 'yaml_conformance-yaml_conformance_data'
      {
        # Requires external test-suite,
        # (see tests/yaml_conformance/CMakeLists.txt)
        enabled = false
      }
      case 'jsonrpc_test'
      {
        # libc++ 21+ fails std::expected equality with recursive constraint
        # satisfaction (P3379R0, same as GCC bug 119714).
        enabled = ($cxx.stdlib != 'libc++' || $cxx.version.major < 21)
      }
      case 'cbor_test' | 'msgpack_test'
      {
        # Clang with libstdc++ rejects the std::variant of incomplete types
        # used by the ambiguous nest tests.
        enabled = ($cxx.id.type != 'clang' || $cxx.stdlib != 'libstdc++')
      }
    }
    ./: exe{$e}: include = $enabled
  }
}

# roundtrip
for [string] f : json beve
{
  n = roundtrip
  t = $(n)-$(f)_test
  ./: exe{$t}: ut/hxx{ut} tests/$n/json{**} tests/$n/obj{$t} testscript
  tests/$n/obj{$t}: ut/hxx{ut} tests/$n/hxx{*} tests/$n/cxx{*} $libs
  {
    cxx.poptions += "-I$src_base" "-DGLZ_TEST_FORMAT=glz::$string.ucase($f)"
  }
  tests/$n/obj{$t}: ut/hxx{ut} tests/$n/hxx{*} tests/$n/cxx{*} $libs
}

# beve_test (patched copy of tests/beve_test/beve_test.cpp,
# see beve_test.cpp.patch)
./: exe{beve_test}: ut/hxx{ut} tests/hxx{*} tests/beve_test/hxx{*} cxx{beve_test} \
                    tests/beve_test/{json csv toml yaml}{**} $libs testscript

# custom_formats (single executable, eetf_custom requires erlang)
./: exe{custom_formats}: ut/hxx{ut} tests/hxx{*} tests/custom_formats/hxx{*} \
                         tests/custom_formats/cxx{* -eetf_custom} $libs testscript

# eigen_test
exe{eigen_test}: $eigen

# sqlite_test
exe{jsonb_sqlite_test}: $sqlite

# simple_float_test, int_parsing (slow)
exe{simple_float_test int_parsing *_perf_* *_performance}: test = false

# disable performance tests
exe{*_perf_* *_performance}: test = false

# Build options.
#
cxx.poptions += "-I$src_base" "-I$src_base/tests"

for [dir_path] d : {tests/*_test/}
{
  td = [path] $path.posix_representation($src_base/$d)
  n = $name($d)
  tests/$n/obj{**}: \
    cxx.poptions += \
      "-DGLZ_TEST_DIRECTORY=\"$path.posix_string($td)\""
}

# tests requiring certain compiler features
if ($cxx.id != 'msvc')
{
  for [dir_path] d : tests/{ \
                       buffer_pool_test \
                       exceptions_test \
                       json_test \
                       json_performance \
                       inplace_vector \
                       int_parsing \
                       networking_tests \
                       threading_test \
                     }
  {
    tests/$name($d)/obj{**}: cxx.coptions += -fexceptions
  }
}

# The following translation units are exceptionally heavy to compile (deep
# constexpr/template instantiation) and are serialized so they never run
# concurrently with other compile/link jobs, avoiding the OOM observed on
# cppget.org building 9.0.0 (enum_test.cpp was the TU being compiled when the
# kernel OOM-killer fired, with reflection.cpp - the heaviest file in the same
# directory - still compiling alongside it per the preceding log lines). The
# rest are every other target across all of tests/ that upstream itself flags
# with -Wa,-mbig-obj in tests/*/CMakeLists.txt (a proxy for a TU generating
# enough symbols to need the extended object format), for targets this
# package actually builds (eetf_test, example_json and jmespath carry the
# same flag upstream but aren't built here). Where a directory has a sibling
# deliberately kept small (eg. front_hash_test split out of json_reflection_test
# to work around a GCC bug with large TUs), only the flagged file is named
# explicitly rather than the whole directory.
#
tests/reflection/obj{enum_test reflection}: cc.serialize = true
for [dir_path] d: tests/{*_conformance/ *_performance/}
{
  tests/$name($d)/obj{**}: cc.serialize = true
}
tests/json_test/obj{json_test json_variant_support_test}: cc.serialize = true
tests/yaml_test/obj{**}: cc.serialize = true
tests/csv_test/obj{csv_test}: cc.serialize = true
tests/exceptions_test/obj{**}: cc.serialize = true
tests/int_parsing/obj{**}: cc.serialize = true
tests/json_reflection_test/obj{json_reflection_test}: cc.serialize = true
tests/threading_test/obj{**}: cc.serialize = true
tests/toml_reader_test/obj{**}: cc.serialize = true
tests/toml_test/obj{toml_test}: cc.serialize = true
tests/inplace_vector/obj{**}: cc.serialize = true

# Common build options.
#
# See: ../../upstream/tests/CMakeLists.txt
switch $cxx.id: path.match, $cxx.target.system: path.match
{
  case 'gcc' | 'clang*'
  {
    # See: https://github.com/microsoft/STL/issues/4349
    if($cxx.target.system != 'win32-msvc')
      cxx.coptions += -fno-rtti

    cxx.coptions += \
      -fno-exceptions \
      -Wno-missing-braces
  }
  case 'msvc' | 'msvc-clang', 'win32-msvc'
  {
    cxx.coptions += \
      /permissive- \
      /bigobj \
      /GR- \
      /wd4244 \
      /wd4459 \
      /wd4805 \
      /Zc:lambda \
      /Zc:preprocessor
  }
}

if ($cxx.target.system == 'win32-msvc')
{
  cxx.coptions += \
    -DNOMINMAX \
    -D_CRT_SECURE_NO_WARNINGS \
    -D_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS \
    -DWIN32_LEAN_AND_MEAN
}

if ($cxx.id == 'gcc' && $cxx.target.system == 'mingw32')
  cxx.coptions += -Wa,-mbig-obj

# GCC's flow-based warnings misfire (with optimization) on the writers that the
# tests instantiate with small fixed-size buffers.
#
if ($cxx.id == 'gcc')
{
  cxx.coptions += \
    -Wno-array-bounds \
    -Wno-restrict \
    -Wno-stringop-overflow \
    -Wno-stringop-overread \
    -Wno-maybe-uninitialized
}

# MinGW libstdc++ lacks std::from_chars/to_chars for std::float128_t, which
# json_test only exercises when __STDCPP_FLOAT128_T__ is defined.
#
if ($cxx.target.system == 'mingw32')
  tests/json_test/obj{**}: cxx.poptions += -U__STDCPP_FLOAT128_T__
