cmake_minimum_required(VERSION 3.8...3.19)

set(test_sources
  action_add_guard.cpp
  action_add_state.cpp
  action_apply_1.cpp
  action_apply_2.cpp
  action_apply_3.cpp
  action_change_action_and_state.cpp
  action_change_action_and_states.cpp
  action_change_control.cpp
  action_change_rule.cpp
  action_change_state.cpp
  action_change_states.cpp
  action_check_consume.cpp
  action_check_depth.cpp
  action_control_action.cpp
  action_enable_disable.cpp
  action_limit_consume.cpp
  action_match_lazy.cpp
  action_match_text.cpp
  action_match_typed_state.cpp
  apply_mode.cpp
  ascii_any.cpp
  ascii_chars.cpp
  ascii_classes.cpp
  ascii_ellipsis.cpp
  ascii_eol.cpp
  ascii_eolf.cpp
  ascii_identifier.cpp
  ascii_ione.cpp
  ascii_istring.cpp
  ascii_keyword.cpp
  ascii_not_ione.cpp
  ascii_not_one.cpp
  ascii_not_range.cpp
  ascii_not_ranges.cpp
  ascii_one.cpp
  ascii_range.cpp
  ascii_ranges.cpp
  ascii_shebang.cpp
  ascii_string.cpp
  ascii_three.cpp
  ascii_two.cpp
  base_empty.cpp
  base_exceptions.cpp
  base_result.cpp
  base_setup.cpp
  control_apply_typed_state.cpp
  control_input_control.cpp
  control_remove_first_state.cpp
  control_remove_first_states.cpp
  control_remove_last_states.cpp
  control_reverse_states.cpp
  control_rewind_control.cpp
  control_rewind_state_control.cpp
  control_rotate_states.cpp
  control_shuffle_states.cpp
  control_state_control.cpp
  control_unwind.cpp
  count_position.cpp
  debug_analyze.cpp
  debug_analyze_traits_enum.cpp
  debug_contains.cpp
  debug_coverage.cpp
  debug_print.cpp
  debug_trace_1.cpp
  debug_trace_2.cpp
  debug_trace_3.cpp
  debug_trace_4.cpp
  debug_visit.cpp
  demangle.cpp
  deprecated_alphabet.cpp
  deprecated_if_then.cpp
  deprecated_integer.cpp
  deprecated_integer_convert.cpp
  deprecated_integer_match.cpp
  deprecated_integer_maximum.cpp
  deprecated_rep_one_min_max.cpp
  deprecated_rep_string.cpp
  deprecated_unescape.cpp
  enable_control.cpp
  error_message_1.cpp
  error_message_2.cpp
  error_message_3.cpp
  example_escaped.cpp
  example_fp.cpp
  example_http.cpp
  example_ipv4.cpp
  example_ipv6.cpp
  example_iri.cpp
  example_json.cpp
  example_json_pointer.cpp
  example_lua53.cpp
  example_proto3.cpp
  example_semver2.cpp
  example_uri.cpp
  extra_charconv.cpp
  extra_dispatch.cpp
  extra_nested_exceptions.cpp
  extra_parse_tree.cpp
  extra_parse_tree_to_dot.cpp
  extra_raw_string.cpp
  extra_record.cpp
  extra_type_to_string.cpp
  extra_unescape.cpp
  icu_utf16_base.cpp
  icu_utf32_base.cpp
  icu_utf8_base.cpp
  include.cpp
  input_action_input.cpp
  input_argv_input.cpp
  input_file_input.cpp
  input_mmap_input.cpp
  input_read_input.cpp
  input_with_depth.cpp
  input_with_offset.cpp
  input_with_source.cpp
  int16_general.cpp
  int32_general.cpp
  int64_general.cpp
  int8_general.cpp
  internal_any.cpp
  internal_argv_input.cpp
  internal_ascii_utility.cpp
  internal_base_inputs.cpp
  internal_char_scan_traits.cpp
  internal_constexpr.cpp
  internal_copy_input.cpp
  internal_data_and_size.cpp
  internal_endian.cpp
  internal_extract_position.cpp
  internal_file_input.cpp
  internal_file_mapper.cpp
  internal_get_eol_rule_char.cpp
  internal_inputs_lines.cpp
  internal_integer_bswap.cpp
  internal_integer_size.cpp
  internal_lazy_inputs.cpp
  internal_lazy_scan_traits.cpp
  internal_mmap_input.cpp
  internal_peek_ascii.cpp
  internal_peek_data.cpp
  internal_peek_direct.cpp
  internal_peek_endian16.cpp
  internal_peek_endian8.cpp
  internal_peek_masked.cpp
  internal_peek_member.cpp
  internal_peek_signed.cpp
  internal_peek_unsigned.cpp
  internal_peek_utf16.cpp
  internal_peek_utf32.cpp
  internal_peek_utf8.cpp
  internal_read_file_stdio.cpp
  internal_read_input.cpp
  internal_rematch_input.cpp
  internal_resize_uninitialized.cpp
  internal_set_stack_guard.cpp
  internal_stream_to_string.cpp
  internal_text_inputs.cpp
  internal_text_rule_traits.cpp
  internal_text_scan_traits.cpp
  internal_type_traits.cpp
  internal_unhex_utility.cpp
  internal_unwind_guard.cpp
  internal_utf32_to_utf8.cpp
  internal_utf8_append.cpp
  internal_utf_one.cpp
  internal_value_list_concat.cpp
  internal_vector_stack_guard.cpp
  internal_view_input.cpp
  member_general.cpp
  normal_apply_rule.cpp
  parse_error.cpp
  pegtl_string_t.cpp
  rewind_mode.cpp
  rewind_mode_required.cpp
  rule_action.cpp
  rule_apply.cpp
  rule_apply0.cpp
  rule_ascii_many.cpp
  rule_at.cpp
  rule_bof.cpp
  rule_bol.cpp
  rule_consume.cpp
  rule_control.cpp
  rule_disable.cpp
  rule_enable.cpp
  rule_eof.cpp
  rule_everything.cpp
  rule_failure.cpp
  rule_function.cpp
  rule_if_apply.cpp
  rule_if_must.cpp
  rule_if_must_else.cpp
  rule_if_then_else.cpp
  rule_invert.cpp
  rule_list.cpp
  rule_list_must.cpp
  rule_list_tail.cpp
  rule_minus.cpp
  rule_must.cpp
  rule_nested.cpp
  rule_not_at.cpp
  rule_opt.cpp
  rule_opt_must.cpp
  rule_pad.cpp
  rule_pad_opt.cpp
  rule_partial.cpp
  rule_plus.cpp
  rule_raise.cpp
  rule_rematch.cpp
  rule_rep.cpp
  rule_rep_max.cpp
  rule_rep_min.cpp
  rule_rep_min_max.cpp
  rule_rep_opt.cpp
  rule_restart.cpp
  rule_separated.cpp
  rule_separated_pad.cpp
  rule_seq.cpp
  rule_source.cpp
  rule_sor.cpp
  rule_star.cpp
  rule_star_must.cpp
  rule_star_partial.cpp
  rule_star_strict.cpp
  rule_state.cpp
  rule_strict.cpp
  rule_success.cpp
  rule_try_catch_raise_nested.cpp
  rule_try_catch_return_false.cpp
  rule_unordered.cpp
  rule_until.cpp
  rule_utf8_string.cpp
  stream_analyze_traits.cpp
  stream_alloc_buffer.cpp
  stream_array_buffer.cpp
  stream_cstream_input.cpp
  stream_cstring_input.cpp
  stream_discard_input.cpp
  stream_endless_input.cpp
  stream_istream_input.cpp
  stream_iterator_input.cpp
  stream_rule_discard.cpp
  stream_rule_is_stream.cpp
  stream_rule_prefetch.cpp
  stream_rule_require.cpp
  stream_stream_input_base.cpp
  stream_text_stream_input.cpp
  text_position.cpp
  type_list.cpp
  uint16_general.cpp
  uint32_general.cpp
  uint64_general.cpp
  uint8_general.cpp
  unaligned_access.cpp
  utf16_general.cpp
  utf32_general.cpp
  utf8_general.cpp
)

# file(GLOB ...) is used to validate the above list of test_sources
file(GLOB glob_test_sources RELATIVE ${CMAKE_CURRENT_LIST_DIR} *.cpp)

foreach(testsourcefile ${test_sources})
  if(${testsourcefile} IN_LIST glob_test_sources)
    list(REMOVE_ITEM glob_test_sources ${testsourcefile})
  else()
    message(SEND_ERROR "File ${testsourcefile} is missing from src/test")
  endif()

  get_filename_component(exename pegtl-test-${testsourcefile} NAME_WE)
  add_executable(${exename} ${testsourcefile})
  target_link_libraries(${exename} PRIVATE taocpp::pegtl)
  set_target_properties(${exename} PROPERTIES
    CXX_STANDARD 17
    CXX_STANDARD_REQUIRED ON
    CXX_EXTENSIONS OFF
  )
  if(MSVC)
    target_compile_options(${exename} PRIVATE /W4 /WX /utf-8 /bigobj)
  else()
    target_compile_options(${exename} PRIVATE -pedantic -Wall -Wextra -Wshadow -Werror)
    if(MINGW)
      target_compile_options(${exename} PRIVATE -Wa,-mbig-obj)
    endif()
  endif()
  if(ANDROID)
    add_test(NAME ${exename} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} "-DANDROID_NDK=${ANDROID_NDK}" "-DTEST_RESOURCES_DIR=${CMAKE_SOURCE_DIR}" "-DTEST_RESOURCES=src/test/data;src/test/file_data.txt;Makefile" "-DUNITTEST=${exename}" -P ${CMAKE_CURRENT_SOURCE_DIR}/ExecuteOnAndroid.cmake)
  else()
    # FIXME: Windows 2022 Clang results in segfault when running for some tests
    if(CMAKE_SYSTEM_VERSION VERSION_EQUAL "10.0.20348" AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
      if("${exename}" MATCHES "pegtl-test-position" OR "${exename}" MATCHES "pegtl-test-rule_try_catch_raise_nested")
        message(WARNING "FIXME: Skipping test ${exename} on Windows Clang due to segfault.")
        continue()
      endif()
    endif()
    add_test(NAME ${exename} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} COMMAND ${exename})
  endif()
endforeach()

if(glob_test_sources)
  foreach(ignored_source_file ${glob_test_sources})
    message(SEND_ERROR "File ${ignored_source_file} in src/test is ignored")
  endforeach()
endif()
