cmake_minimum_required(VERSION 3.20)
project(canon
  VERSION 0.1.0
  DESCRIPTION "Scaffolds C++ projects that follow P1204R0 (Canonical Project Structure)"
  LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

option(BUILD_TESTING "Build canon's tests" ON)

# Everything except main(), so unit tests can link against it.
add_library(canon.core STATIC
  canon/cli.cpp
  canon/cmake.cpp
  canon/executor.cpp
  canon/generate.cpp
  canon/manifest.cpp
  canon/name.cpp
  canon/plan.cpp
  canon/template.cpp
)
target_include_directories(canon.core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
if(NOT MSVC)
  target_compile_options(canon.core PUBLIC -Wall -Wextra -Wpedantic)
endif()

add_executable(canon canon/canon.cpp)
target_link_libraries(canon PRIVATE canon.core)
target_compile_definitions(canon PRIVATE CANON_VERSION="${PROJECT_VERSION}")
install(TARGETS canon)

if(BUILD_TESTING)
  enable_testing()

  # Unit tests live next to the code they test: canon/<unit>.test.cpp.
  foreach(unit cli cmake executor generate manifest name plan template)
    add_executable(canon.${unit}.test canon/${unit}.test.cpp)
    target_link_libraries(canon.${unit}.test PRIVATE canon.core)
    add_test(NAME canon/${unit}.test COMMAND canon.${unit}.test)
  endforeach()

  # Byte-for-byte comparison of scaffolded projects against tests/golden/.
  add_test(NAME tests/golden
    COMMAND ${CMAKE_COMMAND}
      -DCANON=$<TARGET_FILE:canon>
      -DWORK_DIR=${CMAKE_CURRENT_BINARY_DIR}/tests/golden
      -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/golden/check.cmake)

  # Scaffolds each project kind, then configures, builds and tests it.
  add_test(NAME tests/e2e
    COMMAND ${CMAKE_COMMAND}
      -DCANON=$<TARGET_FILE:canon>
      -DWORK_DIR=${CMAKE_CURRENT_BINARY_DIR}/tests/e2e
      -DCXX=${CMAKE_CXX_COMPILER}
      -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/e2e/check.cmake)
  set_tests_properties(tests/e2e PROPERTIES LABELS e2e TIMEOUT 300)
endif()
