Overhaul tests
1. Adds a `libdevilution_so` target when tests are enabled. 2. Each test file is now a separate binary target linked against `libdevilutionx_so` (can now run tests in parallel). 3. Tests are now defined in a separate `test/CMakeLists.txt` file. 4. Building the tests is now controlled by the standard `BUILD_TESTING` option (defined by CTest). 5. Tests are now built by default. 6. On CI, test errors are now reported. Also: * `.clang-format`: Enable SortIncludes in tests * `path_test.cpp`: Fix -Wsign-compare
This commit is contained in:
parent
f5d8f513cb
commit
076b0c0c05
52 changed files with 657 additions and 601 deletions
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
- run: apt update -y
|
||||
- run: apt install -y g++ libsdl2-dev libbz2-dev git rpm wget smpq
|
||||
- run: apt install -y -t 'stretch-backports*' cmake libsodium-dev libpng-dev
|
||||
- run: cmake -S. -Bbuild .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DCPACK=ON -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- run: cmake --build build -j 2 --target package
|
||||
- store_artifacts: {path: ./build/devilutionx, destination: devilutionx_linux_x86_64}
|
||||
- run: Packaging/nix/LinuxReleasePackaging.sh
|
||||
|
|
@ -25,9 +25,9 @@ jobs:
|
|||
- checkout
|
||||
- run: apt-get update -y
|
||||
- run: apt-get install -y cmake curl g++ git lcov libgtest-dev libgmock-dev libfmt-dev libsdl2-dev libsodium-dev libpng-dev libbz2-dev
|
||||
- run: cmake -S. -Bbuild -DRUN_TESTS=ON -DENABLE_CODECOVERAGE=ON
|
||||
- run: cmake -S. -Bbuild -DENABLE_CODECOVERAGE=ON
|
||||
- run: cmake --build build -j 2
|
||||
- run: cmake --build build -j 2 --target test
|
||||
- run: cd build && ctest --output-on-failure
|
||||
- run: bash <(curl -s https://codecov.io/bash)
|
||||
environment:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
working_directory: ~/repo
|
||||
steps:
|
||||
- checkout
|
||||
- run: /opt/devkitpro/portlibs/switch/bin/aarch64-none-elf-cmake -S. -Bbuild .. -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
- run: /opt/devkitpro/portlibs/switch/bin/aarch64-none-elf-cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
- run: cmake --build build -j 2
|
||||
- store_artifacts: {path: ./build/devilutionx.nro, destination: devilutionx.nro}
|
||||
3ds:
|
||||
|
|
|
|||
2
.github/workflows/Linux_x86.yml
vendored
2
.github/workflows/Linux_x86.yml
vendored
|
|
@ -32,7 +32,7 @@ jobs:
|
|||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/linux_i386.toolchain.cmake
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DCPACK=ON -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/linux_i386.toolchain.cmake
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}
|
||||
|
|
|
|||
2
.github/workflows/Linux_x86_64_SDL1.yml
vendored
2
.github/workflows/Linux_x86_64_SDL1.yml
vendored
|
|
@ -31,7 +31,7 @@ jobs:
|
|||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}
|
||||
run: cmake -S. -Bbuild .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DUSE_SDL1=ON -DDISCORD_INTEGRATION=ON
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DCPACK=ON -DUSE_SDL1=ON -DDISCORD_INTEGRATION=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}
|
||||
|
|
|
|||
2
.github/workflows/MacOSX.yml
vendored
2
.github/workflows/MacOSX.yml
vendored
|
|
@ -39,7 +39,7 @@ jobs:
|
|||
# access regardless of the host operating system
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}
|
||||
run: cmake -S. -Bbuild -DMACOSX_STANDALONE_APP_BUNDLE=ON -DDISCORD_INTEGRATION=ON
|
||||
run: cmake -S. -Bbuild -DBUILD_TESTING=OFF -DMACOSX_STANDALONE_APP_BUNDLE=ON -DDISCORD_INTEGRATION=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}
|
||||
|
|
|
|||
2
.github/workflows/Windows_x64.yml
vendored
2
.github/workflows/Windows_x64.yml
vendored
|
|
@ -26,7 +26,7 @@ jobs:
|
|||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc64.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON -DDISCORD_INTEGRATION=ON
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc64.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON -DDISCORD_INTEGRATION=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}
|
||||
|
|
|
|||
2
.github/workflows/Windows_x86.yml
vendored
2
.github/workflows/Windows_x86.yml
vendored
|
|
@ -26,7 +26,7 @@ jobs:
|
|||
- name: Configure CMake
|
||||
shell: bash
|
||||
working-directory: ${{github.workspace}}
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON -DDISCORD_INTEGRATION=ON
|
||||
run: cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=OFF -DCPACK=ON -DCMAKE_TOOLCHAIN_FILE=../CMake/platforms/mingwcc.toolchain.cmake -DDEVILUTIONX_SYSTEM_BZIP2=OFF -DDEVILUTIONX_STATIC_LIBSODIUM=ON -DDISCORD_INTEGRATION=ON
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{github.workspace}}
|
||||
|
|
|
|||
14
3rdParty/googletest/CMakeLists.txt
vendored
Normal file
14
3rdParty/googletest/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
include(functions/FetchContent_MakeAvailableExcludeFromAll)
|
||||
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
|
||||
URL_HASH MD5=0a912f72cbe9d4e2c976e49219433cb1
|
||||
)
|
||||
|
||||
set(INSTALL_GTEST OFF)
|
||||
|
||||
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
FetchContent_MakeAvailable(googletest)
|
||||
|
|
@ -29,8 +29,8 @@ if (Gettext_FOUND)
|
|||
set_source_files_properties("${_gmo_file}" PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources
|
||||
XCODE_EXPLICIT_FILE_TYPE compiled)
|
||||
add_dependencies(${BIN_TARGET} "${_lang_target}")
|
||||
target_sources(${BIN_TARGET} PRIVATE "${_gmo_file}")
|
||||
add_dependencies(libdevilutionx "${_lang_target}")
|
||||
target_sources(libdevilutionx PRIVATE "${_gmo_file}")
|
||||
endif()
|
||||
|
||||
if(VITA)
|
||||
|
|
@ -160,7 +160,7 @@ if(APPLE)
|
|||
set_source_files_properties("${src}" PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION "Resources/${_asset_dir}"
|
||||
XCODE_EXPLICIT_FILE_TYPE compiled)
|
||||
target_sources(${BIN_TARGET} PRIVATE "${src}")
|
||||
target_sources(libdevilutionx PRIVATE "${src}")
|
||||
endforeach()
|
||||
else()
|
||||
# Copy assets to the build assets subdirectory. This serves two purposes:
|
||||
|
|
@ -195,9 +195,9 @@ else()
|
|||
DEPENDS ${DEVILUTIONX_OUTPUT_ASSETS_FILES} ${devilutionx_lang_targets} ${devilutionx_lang_files}
|
||||
VERBATIM)
|
||||
add_custom_target(devilutionx_mpq DEPENDS "${DEVILUTIONX_MPQ}")
|
||||
add_dependencies(${BIN_TARGET} devilutionx_mpq)
|
||||
add_dependencies(libdevilutionx devilutionx_mpq)
|
||||
else()
|
||||
add_custom_target(devilutionx_copied_assets DEPENDS ${DEVILUTIONX_OUTPUT_ASSETS_FILES} ${devilutionx_lang_targets})
|
||||
add_dependencies(${BIN_TARGET} devilutionx_copied_assets)
|
||||
add_dependencies(libdevilutionx devilutionx_copied_assets)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -135,3 +135,12 @@ endif()
|
|||
if(DISCORD_INTEGRATION)
|
||||
add_subdirectory(3rdParty/discord)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
dependency_options("googletest" DEVILUTIONX_SYSTEM_GOOGLETEST ON DEVILUTIONX_STATIC_GOOGLETEST)
|
||||
if(DEVILUTIONX_SYSTEM_GOOGLETEST)
|
||||
find_package(GTest REQUIRED)
|
||||
else()
|
||||
add_subdirectory(3rdParty/googletest)
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -10,6 +10,6 @@ endif()
|
|||
if(USE_GETTEXT_FROM_VCPKG)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "translations")
|
||||
endif()
|
||||
if(RUN_TESTS)
|
||||
if(BUILD_TESTING)
|
||||
list(APPEND VCPKG_MANIFEST_FEATURES "tests")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
set(BUILD_TESTING OFF)
|
||||
set(ASAN OFF)
|
||||
set(UBSAN OFF)
|
||||
set(NONET ON)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
# General build options.
|
||||
set(BUILD_TESTING OFF)
|
||||
set(VIRTUAL_GAMEPAD ON)
|
||||
|
||||
# Disable all system dependencies.
|
||||
|
|
|
|||
|
|
@ -1,26 +1,27 @@
|
|||
set(NONET ON)
|
||||
set(PREFILL_PLAYER_NAME ON)
|
||||
set(HAS_KBCTRL 1)
|
||||
set(LTO ON)
|
||||
set(DIST ON)
|
||||
set(DEBUG OFF)
|
||||
set(ASAN OFF)
|
||||
set(UBSAN OFF)
|
||||
set(KBCTRL_BUTTON_DPAD_LEFT SDLK_LEFT)
|
||||
set(KBCTRL_BUTTON_DPAD_RIGHT SDLK_RIGHT)
|
||||
set(KBCTRL_BUTTON_DPAD_UP SDLK_UP)
|
||||
set(KBCTRL_BUTTON_DPAD_DOWN SDLK_DOWN)
|
||||
set(KBCTRL_BUTTON_X SDLK_i)
|
||||
set(KBCTRL_BUTTON_Y SDLK_u)
|
||||
set(KBCTRL_BUTTON_B SDLK_k)
|
||||
set(KBCTRL_BUTTON_A SDLK_j)
|
||||
set(KBCTRL_BUTTON_RIGHTSHOULDER SDLK_l)
|
||||
set(KBCTRL_BUTTON_LEFTSHOULDER SDLK_h)
|
||||
set(KBCTRL_BUTTON_AXIS_TRIGGERLEFT SDLK_y)
|
||||
set(KBCTRL_BUTTON_AXIS_TRIGGERRIGHT SDLK_o)
|
||||
set(KBCTRL_BUTTON_LEFTSTICK SDLK_PAGEUP)
|
||||
set(KBCTRL_BUTTON_RIGHTSTICK SDLK_PAGEDOWN)
|
||||
set(KBCTRL_BUTTON_START SDLK_RETURN)
|
||||
set(KBCTRL_BUTTON_BACK SDLK_SPACE)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
set(BUILD_TESTING OFF)
|
||||
set(NONET ON)
|
||||
set(PREFILL_PLAYER_NAME ON)
|
||||
set(HAS_KBCTRL 1)
|
||||
set(LTO ON)
|
||||
set(DIST ON)
|
||||
set(DEBUG OFF)
|
||||
set(ASAN OFF)
|
||||
set(UBSAN OFF)
|
||||
set(KBCTRL_BUTTON_DPAD_LEFT SDLK_LEFT)
|
||||
set(KBCTRL_BUTTON_DPAD_RIGHT SDLK_RIGHT)
|
||||
set(KBCTRL_BUTTON_DPAD_UP SDLK_UP)
|
||||
set(KBCTRL_BUTTON_DPAD_DOWN SDLK_DOWN)
|
||||
set(KBCTRL_BUTTON_X SDLK_i)
|
||||
set(KBCTRL_BUTTON_Y SDLK_u)
|
||||
set(KBCTRL_BUTTON_B SDLK_k)
|
||||
set(KBCTRL_BUTTON_A SDLK_j)
|
||||
set(KBCTRL_BUTTON_RIGHTSHOULDER SDLK_l)
|
||||
set(KBCTRL_BUTTON_LEFTSHOULDER SDLK_h)
|
||||
set(KBCTRL_BUTTON_AXIS_TRIGGERLEFT SDLK_y)
|
||||
set(KBCTRL_BUTTON_AXIS_TRIGGERRIGHT SDLK_o)
|
||||
set(KBCTRL_BUTTON_LEFTSTICK SDLK_PAGEUP)
|
||||
set(KBCTRL_BUTTON_RIGHTSTICK SDLK_PAGEDOWN)
|
||||
set(KBCTRL_BUTTON_START SDLK_RETURN)
|
||||
set(KBCTRL_BUTTON_BACK SDLK_SPACE)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
# General build options.
|
||||
set(BUILD_TESTING OFF)
|
||||
set(VIRTUAL_GAMEPAD ON)
|
||||
|
||||
# Disable all system dependencies.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#General compilation options
|
||||
set(ASAN OFF)
|
||||
set(UBSAN OFF)
|
||||
set(BUILD_TESTING OFF)
|
||||
set(DEVILUTIONX_SYSTEM_LIBSODIUM OFF)
|
||||
set(DEVILUTIONX_SYSTEM_LIBFMT OFF)
|
||||
set(DEVILUTIONX_STATIC_LIBSODIUM ON)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/switch")
|
|||
|
||||
set(ASAN OFF)
|
||||
set(UBSAN OFF)
|
||||
set(BUILD_TESTING OFF)
|
||||
|
||||
set(DEVILUTIONX_SYSTEM_LIBSODIUM OFF)
|
||||
set(DISABLE_ZERO_TIER ON)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
set(ASAN OFF)
|
||||
set(UBSAN OFF)
|
||||
set(BUILD_TESTING OFF)
|
||||
set(DISABLE_ZERO_TIER ON)
|
||||
set(PREFILL_PLAYER_NAME ON)
|
||||
add_definitions("-DMO_LANG_DIR=\"app0:/\"")
|
||||
|
|
|
|||
|
|
@ -38,8 +38,9 @@ option(TSAN "Enable thread sanitizer (not compatible with ASAN=ON)" OFF)
|
|||
DEBUG_OPTION(DEBUG "Enable debug mode in engine")
|
||||
option(GPERF "Build with GPerfTools profiler" OFF)
|
||||
cmake_dependent_option(GPERF_HEAP_FIRST_GAME_ITERATION "Save heap profile of the first game iteration" OFF "GPERF" OFF)
|
||||
option(BUILD_TESTING "Build tests." ON)
|
||||
option(DISABLE_LTO "Disable link-time optimization (by default enabled in release mode)" OFF)
|
||||
option(PIE "Generate position-independent code" OFF)
|
||||
cmake_dependent_option(PIE "Generate position-independent code" OFF "BUILD_TESTING" ON)
|
||||
option(MACOSX_STANDALONE_APP_BUNDLE "Generate a portable app bundle to use on other devices (requires sudo)" OFF)
|
||||
option(USE_SDL1 "Use SDL1.2 instead of SDL2" OFF)
|
||||
option(NONET "Disable network support" OFF)
|
||||
|
|
@ -47,8 +48,7 @@ cmake_dependent_option(DISABLE_TCP "Disable TCP multiplayer option" OFF "NOT NON
|
|||
cmake_dependent_option(DISABLE_ZERO_TIER "Disable ZeroTier multiplayer option" OFF "NOT NONET" ON)
|
||||
cmake_dependent_option(PACKET_ENCRYPTION "Encrypt network packets" ON "NOT NONET" OFF)
|
||||
option(NOSOUND "Disable sound support" OFF)
|
||||
option(RUN_TESTS "Build and run tests" OFF)
|
||||
option(ENABLE_CODECOVERAGE "Instrument code for code coverage (only enabled with RUN_TESTS)" OFF)
|
||||
option(ENABLE_CODECOVERAGE "Instrument code for code coverage (only enabled with BUILD_TESTING)" OFF)
|
||||
option(DISCORD_INTEGRATION "Build with Discord SDK for rich presence support" OFF)
|
||||
|
||||
option(DISABLE_STREAMING_MUSIC "Disable streaming music (to work around broken platform implementations)" OFF)
|
||||
|
|
@ -58,10 +58,6 @@ mark_as_advanced(DISABLE_STREAMING_SOUNDS)
|
|||
option(STREAM_ALL_AUDIO "Stream all the audio. For extremely RAM-constrained platforms.")
|
||||
mark_as_advanced(STREAM_ALL_AUDIO)
|
||||
|
||||
if(PIE)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
|
||||
endif()
|
||||
|
||||
if(TSAN)
|
||||
set(ASAN OFF)
|
||||
endif()
|
||||
|
|
@ -117,6 +113,12 @@ else()
|
|||
endif()
|
||||
set(PROJECT_VERSION_WITH_SUFFIX "${PROJECT_VERSION}$<$<CONFIG:Debug>:-${VERSION_SUFFIX}>")
|
||||
|
||||
# This built-in CMake module adds a BUILD_TESTING option (ON by default).
|
||||
# Must be included in the top-level `CMakeLists.txt` after calling `project`.
|
||||
# Because we must include `VcPkgManifestFeatures` before the `project` call,
|
||||
# we add a BUILD_TESTING option ourselves above as well.
|
||||
include(CTest)
|
||||
|
||||
# Platform definitions can override options and we want `cmake_dependent_option` to see the effects,
|
||||
# so ideally we would include Platforms.cmake before definining the options.
|
||||
#
|
||||
|
|
@ -126,6 +128,17 @@ set(PROJECT_VERSION_WITH_SUFFIX "${PROJECT_VERSION}$<$<CONFIG:Debug>:-${VERSION_
|
|||
include(Platforms)
|
||||
|
||||
# Recalculate the dependent options after including the Platforms:
|
||||
if(BUILD_TESTING)
|
||||
# For tests, we build a libdevilutionx.so shared library.
|
||||
# When this libdevilutionx.so is linked against certain static libraries,
|
||||
# they must be compiled with `-fPIC`.
|
||||
set(PIE ON)
|
||||
endif()
|
||||
|
||||
if(PIE)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
|
||||
endif()
|
||||
|
||||
if(NONET)
|
||||
set(DISABLE_TCP ON)
|
||||
set(DISABLE_ZERO_TIER ON)
|
||||
|
|
@ -415,33 +428,6 @@ if(DISCORD_INTEGRATION)
|
|||
)
|
||||
endif()
|
||||
|
||||
if(RUN_TESTS)
|
||||
set(devilutionxtest_SRCS
|
||||
test/appfat_test.cpp
|
||||
test/automap_test.cpp
|
||||
test/control_test.cpp
|
||||
test/cursor_test.cpp
|
||||
test/codec_test.cpp
|
||||
test/dead_test.cpp
|
||||
test/diablo_test.cpp
|
||||
test/drlg_l1_test.cpp
|
||||
test/effects_test.cpp
|
||||
test/file_util_test.cpp
|
||||
test/inv_test.cpp
|
||||
test/lighting_test.cpp
|
||||
test/main.cpp
|
||||
test/missiles_test.cpp
|
||||
test/pack_test.cpp
|
||||
test/path_test.cpp
|
||||
test/player_test.cpp
|
||||
test/quests_test.cpp
|
||||
test/random_test.cpp
|
||||
test/scrollrt_test.cpp
|
||||
test/stores_test.cpp
|
||||
test/writehero_test.cpp
|
||||
test/animationinfo_test.cpp)
|
||||
endif()
|
||||
|
||||
add_library(libdevilutionx OBJECT ${libdevilutionx_SRCS})
|
||||
if(ANDROID)
|
||||
add_library(${BIN_TARGET} SHARED Source/main.cpp)
|
||||
|
|
@ -457,6 +443,20 @@ else()
|
|||
endif()
|
||||
target_link_libraries(${BIN_TARGET} PRIVATE libdevilutionx)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
if(ENABLE_CODECOVERAGE)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
message(WARNING "Codecoverage not supported with MSVC")
|
||||
else()
|
||||
target_compile_options(libdevilutionx PUBLIC --coverage)
|
||||
target_link_options(libdevilutionx PUBLIC --coverage)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
target_compile_definitions(libdevilutionx PRIVATE _DVL_EXPORTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
# Use file GENERATE instead of configure_file because configure_file
|
||||
# does not support generator expressions.
|
||||
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
|
|
@ -475,31 +475,6 @@ file(GENERATE OUTPUT ${CONFIG_PATH} CONTENT
|
|||
#define PROJECT_VERSION_PATCH ${PROJECT_VERSION_PATCH}
|
||||
")
|
||||
|
||||
if(RUN_TESTS)
|
||||
add_executable(devilutionx-tests WIN32 MACOSX_BUNDLE ${devilutionxtest_SRCS})
|
||||
include(CTest)
|
||||
include(GoogleTest)
|
||||
find_package(GTest REQUIRED)
|
||||
add_definitions(-DRUN_TESTS)
|
||||
target_include_directories(devilutionx-tests PRIVATE ${GTEST_INCLUDE_DIRS})
|
||||
target_link_libraries(devilutionx-tests PRIVATE libdevilutionx)
|
||||
target_link_libraries(devilutionx-tests PRIVATE ${GTEST_LIBRARIES})
|
||||
target_include_directories(devilutionx-tests PRIVATE 3rdParty/PicoSHA2)
|
||||
if(ENABLE_CODECOVERAGE)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
message(WARNING "Codecoverage not supported with MSVC")
|
||||
else()
|
||||
target_compile_options(devilutionx-tests PRIVATE -fprofile-arcs -ftest-coverage)
|
||||
target_compile_options(libdevilutionx PRIVATE -fprofile-arcs -ftest-coverage)
|
||||
target_compile_options(${BIN_TARGET} PRIVATE -fprofile-arcs -ftest-coverage)
|
||||
target_link_options(devilutionx-tests PRIVATE -fprofile-arcs)
|
||||
target_link_options(libdevilutionx PRIVATE -fprofile-arcs)
|
||||
target_link_options(${BIN_TARGET} PRIVATE -fprofile-arcs)
|
||||
endif()
|
||||
endif()
|
||||
gtest_add_tests(devilutionx-tests "" AUTO)
|
||||
endif()
|
||||
|
||||
if(DISCORD_INTEGRATION)
|
||||
target_compile_definitions(libdevilutionx PRIVATE DISCORD)
|
||||
target_link_libraries(libdevilutionx PRIVATE discord discord_game_sdk)
|
||||
|
|
@ -559,6 +534,7 @@ foreach(
|
|||
DISABLE_ZERO_TIER
|
||||
DISABLE_STREAMING_MUSIC
|
||||
DISABLE_STREAMING_SOUNDS
|
||||
BUILD_TESTING
|
||||
GPERF
|
||||
GPERF_HEAP_MAIN
|
||||
GPERF_HEAP_FIRST_GAME_ITERATION
|
||||
|
|
|
|||
|
|
@ -1,148 +1,112 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Debug-UnitTests",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"cmakeCommandArgs": "-DRUN_TESTS=ON",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Debug-SDL1",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"cmakeCommandArgs": "-DUSE_SDL1=ON",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"cmakeCommandArgs": "-DCPACK=ON",
|
||||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x86-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"intelliSenseMode": "windows-msvc-x86",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x86-Debug-UnitTests",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"intelliSenseMode": "windows-msvc-x86",
|
||||
"cmakeCommandArgs": "-DRUN_TESTS=ON",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x86-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"cmakeCommandArgs": "-DCPACK=ON",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"intelliSenseMode": "windows-msvc-x86",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Debug-WSL-GCC",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"cmakeExecutable": "cmake",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "linux_x64" ],
|
||||
"wslPath": "${defaultWSLPath}",
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Debug-SDL1",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"cmakeCommandArgs": "-DUSE_SDL1=ON",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"cmakeCommandArgs": "-DCPACK=ON",
|
||||
"inheritEnvironments": [ "msvc_x64" ],
|
||||
"intelliSenseMode": "windows-msvc-x64",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x86-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"intelliSenseMode": "windows-msvc-x86",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x86-Release",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"cmakeCommandArgs": "-DCPACK=ON",
|
||||
"inheritEnvironments": [ "msvc_x86" ],
|
||||
"intelliSenseMode": "windows-msvc-x86",
|
||||
"enableClangTidyCodeAnalysis": true,
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "x64-Debug-WSL-GCC",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${workspaceRoot}\\build\\${name}",
|
||||
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
|
||||
"cmakeExecutable": "cmake",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "linux_x64" ],
|
||||
"wslPath": "${defaultWSLPath}",
|
||||
"variables": [
|
||||
{
|
||||
"name": "DISCORD_INTEGRATION",
|
||||
"value": "True",
|
||||
"type": "BOOL"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ cmake_configure() {
|
|||
cmake -S. -B"$BUILD_DIR" \
|
||||
"-DTARGET_PLATFORM=$TARGET" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="${TOOLCHAIN}/usr/share/buildroot/toolchainfile.cmake" \
|
||||
-DBUILD_TESTING=OFF \
|
||||
-DDEVILUTIONX_SYSTEM_LIBSODIUM=OFF \
|
||||
-DDEVILUTIONX_SYSTEM_BZIP2=OFF \
|
||||
-DSTACK_PROTECTOR=OFF \
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "engine/displacement.hpp"
|
||||
#include "engine/point.hpp"
|
||||
#include "gendung.h"
|
||||
#include "utils/attributes.h"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
|
|
@ -28,17 +29,17 @@ enum MapExplorationType : uint8_t {
|
|||
};
|
||||
|
||||
/** Specifies whether the automap is enabled. */
|
||||
extern bool AutomapActive;
|
||||
extern DVL_API_FOR_TEST bool AutomapActive;
|
||||
/** Tracks the explored areas of the map. */
|
||||
extern uint8_t AutomapView[DMAXX][DMAXY];
|
||||
/** Specifies the scale of the automap. */
|
||||
extern int AutoMapScale;
|
||||
extern Displacement AutomapOffset;
|
||||
extern int AmLine64;
|
||||
extern int AmLine32;
|
||||
extern int AmLine16;
|
||||
extern int AmLine8;
|
||||
extern int AmLine4;
|
||||
extern DVL_API_FOR_TEST int AutoMapScale;
|
||||
extern DVL_API_FOR_TEST Displacement AutomapOffset;
|
||||
extern DVL_API_FOR_TEST int AmLine64;
|
||||
extern DVL_API_FOR_TEST int AmLine32;
|
||||
extern DVL_API_FOR_TEST int AmLine16;
|
||||
extern DVL_API_FOR_TEST int AmLine8;
|
||||
extern DVL_API_FOR_TEST int AmLine4;
|
||||
|
||||
/**
|
||||
* @brief Initializes the automap.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "panels/ui_panels.hpp"
|
||||
#include "spelldat.h"
|
||||
#include "spells.h"
|
||||
#include "utils/attributes.h"
|
||||
#include "utils/stdcompat/optional.hpp"
|
||||
#include "utils/stdcompat/string_view.hpp"
|
||||
#include "utils/ui_fwd.h"
|
||||
|
|
@ -38,7 +39,7 @@ extern bool lvlbtndown;
|
|||
extern int dropGoldValue;
|
||||
extern bool drawmanaflag;
|
||||
extern bool chrbtnactive;
|
||||
extern int pnumlines;
|
||||
extern DVL_API_FOR_TEST int pnumlines;
|
||||
extern UiFlags InfoColor;
|
||||
extern char tempstr[256];
|
||||
extern int sbooktab;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "towners.h"
|
||||
#include "track.h"
|
||||
#include "trigs.h"
|
||||
#include "utils/attributes.h"
|
||||
#include "utils/language.h"
|
||||
|
||||
namespace devilution {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "engine.h"
|
||||
#include "engine/cel_sprite.hpp"
|
||||
#include "miniwin/miniwin.h"
|
||||
#include "utils/attributes.h"
|
||||
#include "utils/stdcompat/optional.hpp"
|
||||
|
||||
namespace devilution {
|
||||
|
|
@ -31,16 +32,16 @@ enum cursor_id : uint8_t {
|
|||
CURSOR_FIRSTITEM,
|
||||
};
|
||||
|
||||
extern Size cursSize;
|
||||
extern DVL_API_FOR_TEST Size cursSize;
|
||||
extern int pcursmonst;
|
||||
extern Size icursSize28;
|
||||
extern Size icursSize;
|
||||
extern DVL_API_FOR_TEST Size icursSize28;
|
||||
extern DVL_API_FOR_TEST Size icursSize;
|
||||
extern int8_t pcursinvitem;
|
||||
extern int8_t pcursitem;
|
||||
extern int8_t pcursobj;
|
||||
extern int8_t pcursplr;
|
||||
extern Point cursPosition;
|
||||
extern int pcurs;
|
||||
extern DVL_API_FOR_TEST int pcurs;
|
||||
|
||||
void InitCursor();
|
||||
void FreeCursor();
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
#include "utils/endian.hpp"
|
||||
|
||||
#include "controls/keymapper.hpp"
|
||||
#ifdef _DEBUG
|
||||
#include "monstdat.h"
|
||||
#endif
|
||||
#include "gendung.h"
|
||||
#include "init.h"
|
||||
#include "utils/attributes.h"
|
||||
#include "utils/endian.hpp"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
|
|
@ -61,21 +61,21 @@ extern dungeon_type gnLevelTypeTbl[NUMLEVELS];
|
|||
extern Point MousePosition;
|
||||
extern bool gbRunGame;
|
||||
extern bool gbRunGameResult;
|
||||
extern bool zoomflag;
|
||||
extern DVL_API_FOR_TEST bool zoomflag;
|
||||
extern bool gbProcessPlayers;
|
||||
extern bool gbLoadGame;
|
||||
extern bool cineflag;
|
||||
extern int force_redraw;
|
||||
/* These are defined in fonts.h */
|
||||
extern void FontsCleanup();
|
||||
extern int PauseMode;
|
||||
extern DVL_API_FOR_TEST int PauseMode;
|
||||
extern bool gbNestArt;
|
||||
extern bool gbBard;
|
||||
extern bool gbBarbarian;
|
||||
/**
|
||||
* @brief Don't show Messageboxes or other user-interaction. Needed for UnitTests.
|
||||
*/
|
||||
extern bool gbQuietMode;
|
||||
extern DVL_API_FOR_TEST bool gbQuietMode;
|
||||
extern clicktype sgbMouseDown;
|
||||
extern uint16_t gnTickDelay;
|
||||
extern char gszProductName[64];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#ifdef RUN_TESTS
|
||||
#ifdef BUILD_TESTING
|
||||
#include <ostream>
|
||||
#endif
|
||||
|
||||
|
|
@ -153,7 +153,7 @@ struct Point {
|
|||
return std::max<int>(offset.deltaX, offset.deltaY);
|
||||
}
|
||||
|
||||
#ifdef RUN_TESTS
|
||||
#ifdef BUILD_TESTING
|
||||
/**
|
||||
* @brief Format points nicely in test failure messages
|
||||
* @param stream output stream, expected to have overloads for int and char*
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "engine/cel_sprite.hpp"
|
||||
#include "engine/point.hpp"
|
||||
#include "scrollrt.h"
|
||||
#include "utils/attributes.h"
|
||||
#include "utils/enum_traits.h"
|
||||
#include "utils/stdcompat/optional.hpp"
|
||||
|
||||
|
|
@ -165,7 +166,7 @@ extern std::array<bool, MAXTILES + 1> nBlockTable;
|
|||
/**
|
||||
* List of path blocking dPieces
|
||||
*/
|
||||
extern std::array<bool, MAXTILES + 1> nSolidTable;
|
||||
extern DVL_API_FOR_TEST std::array<bool, MAXTILES + 1> nSolidTable;
|
||||
/**
|
||||
* List of transparent dPieces
|
||||
*/
|
||||
|
|
@ -180,7 +181,7 @@ extern Point dminPosition;
|
|||
/** Specifies the maximum X,Y-coordinates of the map. */
|
||||
extern Point dmaxPosition;
|
||||
/** Specifies the active dungeon type of the current game. */
|
||||
extern dungeon_type leveltype;
|
||||
extern DVL_API_FOR_TEST dungeon_type leveltype;
|
||||
/** Specifies the active dungeon level of the current game. */
|
||||
extern uint8_t currlevel;
|
||||
extern bool setlevel;
|
||||
|
|
@ -196,12 +197,12 @@ extern char TransVal;
|
|||
/** Specifies the active transparency indices. */
|
||||
extern bool TransList[256];
|
||||
/** Contains the piece IDs of each tile on the map. */
|
||||
extern int dPiece[MAXDUNX][MAXDUNY];
|
||||
extern DVL_API_FOR_TEST int dPiece[MAXDUNX][MAXDUNY];
|
||||
/** Specifies the dungeon piece information for a given coordinate and block number. */
|
||||
extern MICROS dpiece_defs_map_2[MAXDUNX][MAXDUNY];
|
||||
/** Specifies the transparency at each coordinate of the map. */
|
||||
extern int8_t dTransVal[MAXDUNX][MAXDUNY];
|
||||
extern char dLight[MAXDUNX][MAXDUNY];
|
||||
extern DVL_API_FOR_TEST char dLight[MAXDUNX][MAXDUNY];
|
||||
extern char dPreLight[MAXDUNX][MAXDUNY];
|
||||
/** Holds various information about dungeon tiles, @see DungeonFlag */
|
||||
extern DungeonFlag dFlags[MAXDUNX][MAXDUNY];
|
||||
|
|
@ -220,9 +221,9 @@ extern int16_t dMonster[MAXDUNX][MAXDUNY];
|
|||
* dDead[x][y] & 0x1F - index of dead
|
||||
* dDead[x][y] >> 0x5 - direction
|
||||
*/
|
||||
extern int8_t dCorpse[MAXDUNX][MAXDUNY];
|
||||
extern DVL_API_FOR_TEST int8_t dCorpse[MAXDUNX][MAXDUNY];
|
||||
/** Contains the object numbers (objects array indices) of the map. */
|
||||
extern char dObject[MAXDUNX][MAXDUNY];
|
||||
extern DVL_API_FOR_TEST char dObject[MAXDUNX][MAXDUNY];
|
||||
/** Contains the item numbers (items array indices) of the map. */
|
||||
extern int8_t dItem[MAXDUNX][MAXDUNY];
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "miniwin/miniwin.h"
|
||||
#include "mpq/mpq_reader.hpp"
|
||||
#include "utils/attributes.h"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
|
|
@ -15,9 +16,9 @@ extern std::optional<MpqArchive> hellfire_mpq;
|
|||
extern WNDPROC CurrentProc;
|
||||
extern std::optional<MpqArchive> spawn_mpq;
|
||||
extern std::optional<MpqArchive> diabdat_mpq;
|
||||
extern bool gbIsSpawn;
|
||||
extern bool gbIsHellfire;
|
||||
extern bool gbVanilla;
|
||||
extern DVL_API_FOR_TEST bool gbIsSpawn;
|
||||
extern DVL_API_FOR_TEST bool gbIsHellfire;
|
||||
extern DVL_API_FOR_TEST bool gbVanilla;
|
||||
extern bool forceHellfire;
|
||||
extern std::optional<MpqArchive> hfmonk_mpq;
|
||||
extern std::optional<MpqArchive> hfbard_mpq;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "engine.h"
|
||||
#include "engine/point.hpp"
|
||||
#include "miniwin/miniwin.h"
|
||||
#include "utils/attributes.h"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
|
|
@ -45,7 +46,7 @@ extern uint8_t ActiveLights[MAXLIGHTS];
|
|||
extern int ActiveLightCount;
|
||||
extern char LightsMax;
|
||||
extern std::array<uint8_t, LIGHTSIZE> LightTables;
|
||||
extern bool DisableLighting;
|
||||
extern DVL_API_FOR_TEST bool DisableLighting;
|
||||
extern bool UpdateLighting;
|
||||
|
||||
void DoLighting(Point position, int nRadius, int Lnum);
|
||||
|
|
@ -74,8 +75,8 @@ void lighting_color_cycling();
|
|||
|
||||
/* rdata */
|
||||
|
||||
extern const int8_t CrawlTable[2749];
|
||||
extern const int CrawlNum[19];
|
||||
extern DVL_API_FOR_TEST const int8_t CrawlTable[2749];
|
||||
extern DVL_API_FOR_TEST const int CrawlNum[19];
|
||||
extern const uint8_t VisionCrawlTable[23][30];
|
||||
|
||||
} // namespace devilution
|
||||
|
|
|
|||
|
|
@ -6,11 +6,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "player.h"
|
||||
#include "utils/attributes.h"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
extern bool gbIsHellfireSaveGame;
|
||||
extern uint8_t giNumberOfLevels;
|
||||
extern DVL_API_FOR_TEST bool gbIsHellfireSaveGame;
|
||||
extern DVL_API_FOR_TEST uint8_t giNumberOfLevels;
|
||||
|
||||
void RemoveInvalidItem(Item &pItem);
|
||||
_item_indexes RemapItemIdxFromDiablo(_item_indexes i);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <cstdint>
|
||||
|
||||
#include "msg.h"
|
||||
#include "utils/attributes.h"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
|
|
@ -37,7 +38,7 @@ extern BYTE gbActivePlayers;
|
|||
extern bool gbGameDestroyed;
|
||||
extern GameData sgGameInitInfo;
|
||||
extern bool gbSelectProvider;
|
||||
extern bool gbIsMultiplayer;
|
||||
extern DVL_API_FOR_TEST bool gbIsMultiplayer;
|
||||
extern char szPlayerName[128];
|
||||
extern bool PublicGame;
|
||||
extern BYTE gbDeltaSender;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "player.h"
|
||||
#include "utils/attributes.h"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
|
|
@ -15,7 +16,7 @@ extern uint32_t gdwTurnsInTransit;
|
|||
extern uintptr_t glpMsgTbl[MAX_PLRS];
|
||||
extern uint32_t gdwLargestMsgSize;
|
||||
extern uint32_t gdwNormalMsgSize;
|
||||
extern float gfProgressToNextGameTick; // the progress as a fraction (0.0f to 1.0f) in time to the next game tick
|
||||
extern DVL_API_FOR_TEST float gfProgressToNextGameTick; // the progress as a fraction (0.0f to 1.0f) in time to the next game tick
|
||||
extern int last_tick;
|
||||
|
||||
void nthread_terminate_game(const char *pszFcn);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "monster.h"
|
||||
#include "objdat.h"
|
||||
#include "textdat.h"
|
||||
#include "utils/attributes.h"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
|
|
@ -230,7 +231,7 @@ struct Object {
|
|||
}
|
||||
};
|
||||
|
||||
extern Object Objects[MAXOBJECTS];
|
||||
extern DVL_API_FOR_TEST Object Objects[MAXOBJECTS];
|
||||
extern int AvailableObjects[MAXOBJECTS];
|
||||
extern int ActiveObjects[MAXOBJECTS];
|
||||
extern int ActiveObjectCount;
|
||||
|
|
|
|||
|
|
@ -545,7 +545,7 @@ std::optional<Point> FindClosestValidPosition(const std::function<bool(Point)> &
|
|||
return {};
|
||||
}
|
||||
|
||||
#ifdef RUN_TESTS
|
||||
#ifdef BUILD_TESTING
|
||||
int TestPathGetHeuristicCost(Point startPosition, Point destinationPosition)
|
||||
{
|
||||
return GetHeuristicCost(startPosition, destinationPosition);
|
||||
|
|
|
|||
|
|
@ -3813,7 +3813,7 @@ void PlayDungMsgs()
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef RUN_TESTS
|
||||
#ifdef BUILD_TESTING
|
||||
bool TestPlayerDoGotHit(int pnum)
|
||||
{
|
||||
return DoGotHit(pnum);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "multi.h"
|
||||
#include "path.h"
|
||||
#include "spelldat.h"
|
||||
#include "utils/attributes.h"
|
||||
#include "utils/enum_traits.h"
|
||||
|
||||
namespace devilution {
|
||||
|
|
@ -614,9 +615,9 @@ struct Player {
|
|||
}
|
||||
};
|
||||
|
||||
extern int MyPlayerId;
|
||||
extern Player *MyPlayer;
|
||||
extern Player Players[MAX_PLRS];
|
||||
extern DVL_API_FOR_TEST int MyPlayerId;
|
||||
extern DVL_API_FOR_TEST Player *MyPlayer;
|
||||
extern DVL_API_FOR_TEST Player Players[MAX_PLRS];
|
||||
extern bool MyPlayerIsDead;
|
||||
extern int BlockBonuses[enum_size<HeroClass>::value];
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "monster.h"
|
||||
#include "objdat.h"
|
||||
#include "textdat.h"
|
||||
#include "utils/attributes.h"
|
||||
#include "utils/stdcompat/optional.hpp"
|
||||
|
||||
namespace devilution {
|
||||
|
|
@ -73,7 +74,7 @@ struct QuestData {
|
|||
|
||||
extern bool QuestLogIsOpen;
|
||||
extern std::optional<CelSprite> pQLogCel;
|
||||
extern Quest Quests[MAXQUESTS];
|
||||
extern DVL_API_FOR_TEST Quest Quests[MAXQUESTS];
|
||||
extern Point ReturnLvlPosition;
|
||||
extern dungeon_type ReturnLevelType;
|
||||
extern int ReturnLevel;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "control.h"
|
||||
#include "engine.h"
|
||||
#include "engine/cel_sprite.hpp"
|
||||
#include "utils/attributes.h"
|
||||
#include "utils/stdcompat/optional.hpp"
|
||||
|
||||
namespace devilution {
|
||||
|
|
@ -77,11 +78,11 @@ extern std::optional<CelSprite> pSTextSlidCels;
|
|||
extern talk_id stextflag;
|
||||
|
||||
/** Current index into storehidx/storehold */
|
||||
extern int storenumh;
|
||||
extern DVL_API_FOR_TEST int storenumh;
|
||||
/** Map of inventory items being presented in the store */
|
||||
extern char storehidx[48];
|
||||
/** Copies of the players items as presented in the store */
|
||||
extern Item storehold[48];
|
||||
extern DVL_API_FOR_TEST Item storehold[48];
|
||||
|
||||
/** Temporary item used to generate gold piles by various function */
|
||||
extern Item golditem;
|
||||
|
|
|
|||
|
|
@ -31,3 +31,14 @@
|
|||
#else
|
||||
#define DVL_ATTRIBUTE_HOT
|
||||
#endif
|
||||
|
||||
// Any global data used by tests must be marked with `DVL_API_FOR_TEST`.
|
||||
#if defined(_MSC_VER) && defined(BUILD_TESTING)
|
||||
#ifdef _DVL_EXPORTING
|
||||
#define DVL_API_FOR_TEST __declspec(dllexport)
|
||||
#else
|
||||
#define DVL_API_FOR_TEST __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define DVL_API_FOR_TEST
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "utils/attributes.h"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
extern Uint16 gnScreenWidth;
|
||||
extern Uint16 gnScreenHeight;
|
||||
extern Uint16 gnViewportHeight;
|
||||
extern DVL_API_FOR_TEST Uint16 gnScreenWidth;
|
||||
extern DVL_API_FOR_TEST Uint16 gnScreenHeight;
|
||||
extern DVL_API_FOR_TEST Uint16 gnViewportHeight;
|
||||
|
||||
Uint16 GetScreenWidth();
|
||||
Uint16 GetScreenHeight();
|
||||
|
|
|
|||
|
|
@ -5,6 +5,6 @@ AllowShortFunctionsOnASingleLine: None
|
|||
PointerAlignment: Right
|
||||
TabWidth: 4
|
||||
UseTab: ForIndentation
|
||||
SortIncludes: false
|
||||
SortIncludes: true
|
||||
NamespaceIndentation: None
|
||||
FixNamespaceComments: true
|
||||
|
|
|
|||
44
test/CMakeLists.txt
Normal file
44
test/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
include(GoogleTest)
|
||||
|
||||
add_library(libdevilutionx_so SHARED)
|
||||
target_link_libraries(libdevilutionx_so PUBLIC libdevilutionx)
|
||||
target_include_directories(libdevilutionx_so INTERFACE "${DevilutionX_SOURCE_DIR}/Source")
|
||||
set_target_properties(libdevilutionx_so PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
|
||||
add_library(test_main STATIC main.cpp)
|
||||
target_link_libraries(test_main PRIVATE libdevilutionx_so ${GTEST_LIBRARIES})
|
||||
target_include_directories(test_main PRIVATE ${GTEST_INCLUDE_DIRS})
|
||||
|
||||
set(tests
|
||||
animationinfo_test
|
||||
appfat_test
|
||||
automap_test
|
||||
codec_test
|
||||
control_test
|
||||
cursor_test
|
||||
dead_test
|
||||
diablo_test
|
||||
drlg_l1_test
|
||||
effects_test
|
||||
file_util_test
|
||||
inv_test
|
||||
lighting_test
|
||||
missiles_test
|
||||
pack_test
|
||||
path_test
|
||||
player_test
|
||||
quests_test
|
||||
random_test
|
||||
scrollrt_test
|
||||
stores_test
|
||||
writehero_test
|
||||
)
|
||||
|
||||
foreach(test_target ${tests})
|
||||
add_executable(${test_target} "${test_target}.cpp")
|
||||
gtest_discover_tests(${test_target})
|
||||
target_link_libraries(${test_target} PRIVATE libdevilutionx_so ${GTEST_LIBRARIES} test_main)
|
||||
target_include_directories(${test_target} PRIVATE ${GTEST_INCLUDE_DIRS})
|
||||
endforeach()
|
||||
|
||||
target_include_directories(writehero_test PRIVATE ../3rdParty/PicoSHA2)
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "nthread.h"
|
||||
#include "engine/animationinfo.h"
|
||||
#include "nthread.h"
|
||||
|
||||
using namespace devilution;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "utils/file_util.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@ TEST(Lighting, CrawlTables)
|
|||
for (unsigned i = (uint8_t)CrawlTable[cr - 1]; i > 0; i--, cr += 2) {
|
||||
int dx = x + CrawlTable[cr];
|
||||
int dy = y + CrawlTable[cr + 1];
|
||||
sprintf(tempstr, "location %i:%i added twice.", dx - 20, dy - 20);
|
||||
EXPECT_EQ(added[dx][dy], false) << tempstr;
|
||||
EXPECT_EQ(added[dx][dy], false) << "location " << i << ":" << j << " added twice";
|
||||
added[dx][dy] = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -29,8 +28,7 @@ TEST(Lighting, CrawlTables)
|
|||
continue;
|
||||
if ((i == -18 && j == -18) || (i == -18 && j == 18) || (i == 18 && j == -18) || (i == 18 && j == 18))
|
||||
continue; // Limit of the crawl table rage
|
||||
sprintf(tempstr, "while checking location %i:%i.", i, j);
|
||||
EXPECT_EQ(false, true) << tempstr;
|
||||
EXPECT_EQ(false, true) << "while checking location " << i << ":" << j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "diablo.h"
|
||||
#include "utils/paths.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
// Disable error dialogs.
|
||||
devilution::gbQuietMode = true;
|
||||
|
||||
// Let the tests find `devilutionx.mpq` or `assets/`.
|
||||
devilution::paths::SetAssetsPath(devilution::paths::BasePath() + "../assets");
|
||||
devilution::paths::SetBasePath(devilution::paths::BasePath() + "..");
|
||||
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <cstdint>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "pack.h"
|
||||
#include "utils/paths.h"
|
||||
|
||||
using namespace devilution;
|
||||
namespace devilution {
|
||||
namespace {
|
||||
|
||||
static void ComparePackedItems(const ItemPack &item1, const ItemPack &item2)
|
||||
{
|
||||
|
|
@ -327,7 +329,7 @@ const TestItemStruct DiabloItems[] = {
|
|||
// clang-format on
|
||||
};
|
||||
|
||||
TEST(pack, UnPackItem_diablo)
|
||||
TEST(PackTest, UnPackItem_diablo)
|
||||
{
|
||||
Item id;
|
||||
ItemPack is;
|
||||
|
|
@ -348,7 +350,7 @@ TEST(pack, UnPackItem_diablo)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(pack, UnPackItem_diablo_unique_bug)
|
||||
TEST(PackTest, UnPackItem_diablo_unique_bug)
|
||||
{
|
||||
ItemPack pkItemBug = { 6, 911, 14, 5, 60, 60, 0, 0, 0, 0 }; // Veil of Steel - with morph bug
|
||||
ItemPack pkItem = { 6, 655, 14, 5, 60, 60, 0, 0, 0, 0 }; // Veil of Steel - fixed
|
||||
|
|
@ -398,7 +400,7 @@ const TestItemStruct SpawnItems[] = {
|
|||
// clang-format on
|
||||
};
|
||||
|
||||
TEST(pack, UnPackItem_spawn)
|
||||
TEST(PackTest, UnPackItem_spawn)
|
||||
{
|
||||
Item id;
|
||||
ItemPack is;
|
||||
|
|
@ -442,7 +444,7 @@ const TestItemStruct DiabloMPItems[] = {
|
|||
// clang-format on
|
||||
};
|
||||
|
||||
TEST(pack, UnPackItem_diablo_multiplayer)
|
||||
TEST(PackTest, UnPackItem_diablo_multiplayer)
|
||||
{
|
||||
Item id;
|
||||
ItemPack is;
|
||||
|
|
@ -651,7 +653,7 @@ const TestItemStruct HellfireItems[] = {
|
|||
// clang-format on
|
||||
};
|
||||
|
||||
TEST(pack, UnPackItem_hellfire)
|
||||
TEST(PackTest, UnPackItem_hellfire)
|
||||
{
|
||||
Item id;
|
||||
ItemPack is;
|
||||
|
|
@ -673,7 +675,7 @@ TEST(pack, UnPackItem_hellfire)
|
|||
}
|
||||
}
|
||||
|
||||
TEST(pack, UnPackItem_diablo_strip_hellfire_items)
|
||||
TEST(PackTest, UnPackItem_diablo_strip_hellfire_items)
|
||||
{
|
||||
ItemPack is = { 1478792102, 259, 92, 0, 0, 0, 0, 0, 0, 0 }; // Scroll of Search
|
||||
Item id;
|
||||
|
|
@ -687,7 +689,7 @@ TEST(pack, UnPackItem_diablo_strip_hellfire_items)
|
|||
ASSERT_EQ(id._itype, ItemType::None);
|
||||
}
|
||||
|
||||
TEST(pack, UnPackItem_empty)
|
||||
TEST(PackTest, UnPackItem_empty)
|
||||
{
|
||||
ItemPack is = { 0, 0, 0xFFFF, 0, 0, 0, 0, 0, 0, 0 };
|
||||
Item id;
|
||||
|
|
@ -697,7 +699,7 @@ TEST(pack, UnPackItem_empty)
|
|||
ASSERT_EQ(id._itype, ItemType::None);
|
||||
}
|
||||
|
||||
TEST(pack, PackItem_empty)
|
||||
TEST(PackTest, PackItem_empty)
|
||||
{
|
||||
ItemPack is;
|
||||
Item id = {};
|
||||
|
|
@ -706,7 +708,9 @@ TEST(pack, PackItem_empty)
|
|||
|
||||
PackItem(is, id);
|
||||
|
||||
ASSERT_EQ(is.idx, 0xFFFF);
|
||||
// Copy the value out before comparing to avoid loading a misaligned address.
|
||||
const auto idx = is.idx;
|
||||
ASSERT_EQ(idx, 0xFFFF);
|
||||
}
|
||||
|
||||
static void compareGold(const ItemPack &is, int iCurs)
|
||||
|
|
@ -715,7 +719,9 @@ static void compareGold(const ItemPack &is, int iCurs)
|
|||
UnPackItem(is, id, false);
|
||||
ASSERT_EQ(id._iCurs, iCurs);
|
||||
ASSERT_EQ(id.IDidx, IDI_GOLD);
|
||||
ASSERT_EQ(id._ivalue, is.wValue);
|
||||
// Copy the value out before comparing to avoid loading a misaligned address.
|
||||
const auto wvalue = is.wValue;
|
||||
ASSERT_EQ(id._ivalue, wvalue);
|
||||
ASSERT_EQ(id._itype, ItemType::Gold);
|
||||
ASSERT_EQ(id._iClass, ICLASS_GOLD);
|
||||
|
||||
|
|
@ -724,25 +730,25 @@ static void compareGold(const ItemPack &is, int iCurs)
|
|||
ComparePackedItems(is, is2);
|
||||
}
|
||||
|
||||
TEST(pack, UnPackItem_gold_small)
|
||||
TEST(PackTest, UnPackItem_gold_small)
|
||||
{
|
||||
ItemPack is = { 0, 0, IDI_GOLD, 0, 0, 0, 0, 0, 1000, 0 };
|
||||
compareGold(is, ICURS_GOLD_SMALL);
|
||||
}
|
||||
|
||||
TEST(pack, UnPackItem_gold_medium)
|
||||
TEST(PackTest, UnPackItem_gold_medium)
|
||||
{
|
||||
ItemPack is = { 0, 0, IDI_GOLD, 0, 0, 0, 0, 0, 1001, 0 };
|
||||
compareGold(is, ICURS_GOLD_MEDIUM);
|
||||
}
|
||||
|
||||
TEST(pack, UnPackItem_gold_large)
|
||||
TEST(PackTest, UnPackItem_gold_large)
|
||||
{
|
||||
ItemPack is = { 0, 0, IDI_GOLD, 0, 0, 0, 0, 0, 2500, 0 };
|
||||
compareGold(is, ICURS_GOLD_LARGE);
|
||||
}
|
||||
|
||||
TEST(pack, UnPackItem_ear)
|
||||
TEST(PackTest, UnPackItem_ear)
|
||||
{
|
||||
ItemPack is = { 1633955154, 17509, 23, 111, 103, 117, 101, 68, 19843, 0 };
|
||||
Item id;
|
||||
|
|
@ -755,3 +761,6 @@ TEST(pack, UnPackItem_ear)
|
|||
PackItem(is2, id);
|
||||
ComparePackedItems(is, is2);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace devilution
|
||||
|
|
|
|||
|
|
@ -1,275 +1,275 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "path.h"
|
||||
|
||||
// The following headers are included to access globals used in functions that have not been isolated yet.
|
||||
#include "gendung.h"
|
||||
#include "objects.h"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
extern int TestPathGetHeuristicCost(Point startPosition, Point destinationPosition);
|
||||
|
||||
TEST(PathTest, Heuristics)
|
||||
{
|
||||
constexpr Point source { 25, 32 };
|
||||
Point destination = source;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 0) << "Wrong cost for travelling to the same tile";
|
||||
|
||||
destination = source + Direction::NorthEast;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
|
||||
destination = source + Direction::SouthEast;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
|
||||
destination = source + Direction::SouthWest;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
|
||||
destination = source + Direction::NorthWest;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
|
||||
|
||||
destination = source + Direction::North;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
|
||||
destination = source + Direction::East;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
|
||||
destination = source + Direction::South;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
|
||||
destination = source + Direction::West;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
|
||||
destination = source + Direction::SouthWest + Direction::SouthEast; // Effectively the same as Direction::South
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
|
||||
|
||||
destination = source + Direction::NorthEast + Direction::North;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 6) << "Wrong cost for travelling to a { 2, 1 } offset";
|
||||
destination = source + Direction::SouthEast + Direction::SouthEast;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to a { 2, 0 } offset";
|
||||
}
|
||||
|
||||
TEST(PathTest, Solid)
|
||||
{
|
||||
dPiece[5][5] = 0;
|
||||
nSolidTable[0] = true;
|
||||
EXPECT_TRUE(IsTileSolid({ 5, 5 })) << "Solid in-bounds tiles are solid";
|
||||
EXPECT_FALSE(IsTileNotSolid({ 5, 5 })) << "IsTileNotSolid returns the inverse of IsTileSolid for in-bounds tiles";
|
||||
|
||||
dPiece[6][6] = 1;
|
||||
nSolidTable[1] = false;
|
||||
EXPECT_FALSE(IsTileSolid({ 6, 6 })) << "Non-solid in-bounds tiles are not solid";
|
||||
EXPECT_TRUE(IsTileNotSolid({ 6, 6 })) << "IsTileNotSolid returns the inverse of IsTileSolid for in-bounds tiles";
|
||||
|
||||
EXPECT_FALSE(IsTileSolid({ -1, 1 })) << "Out of bounds tiles are not solid"; // this reads out of bounds in the current code and may fail unexpectedly
|
||||
EXPECT_FALSE(IsTileNotSolid({ -1, 1 })) << "Out of bounds tiles are also not not solid";
|
||||
}
|
||||
|
||||
TEST(PathTest, SolidPieces)
|
||||
{
|
||||
dPiece[0][0] = 0;
|
||||
dPiece[0][1] = 0;
|
||||
dPiece[1][0] = 0;
|
||||
dPiece[1][1] = 0;
|
||||
nSolidTable[0] = false;
|
||||
EXPECT_TRUE(path_solid_pieces({ 0, 0 }, { 1, 1 })) << "A step in open space is free of solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 1, 1 }, { 0, 0 })) << "A step in open space is free of solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 1, 0 }, { 0, 1 })) << "A step in open space is free of solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 0, 1 }, { 1, 0 })) << "A step in open space is free of solid pieces";
|
||||
|
||||
nSolidTable[1] = true;
|
||||
dPiece[1][0] = 1;
|
||||
EXPECT_TRUE(path_solid_pieces({ 0, 1 }, { 1, 0 })) << "Can path to a destination which is solid";
|
||||
EXPECT_TRUE(path_solid_pieces({ 1, 0 }, { 0, 1 })) << "Can path from a starting position which is solid";
|
||||
EXPECT_TRUE(path_solid_pieces({ 0, 1 }, { 1, 1 })) << "Stepping in a cardinal direction ignores solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 1, 0 }, { 1, 1 })) << "Stepping in a cardinal direction ignores solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 0, 0 }, { 1, 0 })) << "Stepping in a cardinal direction ignores solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 1, 1 }, { 1, 0 })) << "Stepping in a cardinal direction ignores solid pieces";
|
||||
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 0 }, { 1, 1 })) << "Can't cut a solid corner";
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 1 }, { 0, 0 })) << "Can't cut a solid corner";
|
||||
dPiece[0][1] = 1;
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 0 }, { 1, 1 })) << "Can't walk through the boundary between two corners";
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 1 }, { 0, 0 })) << "Can't walk through the boundary between two corners";
|
||||
dPiece[1][0] = 0;
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 0 }, { 1, 1 })) << "Can't cut a solid corner";
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 1 }, { 0, 0 })) << "Can't cut a solid corner";
|
||||
dPiece[0][1] = 0;
|
||||
|
||||
dPiece[0][0] = 1;
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 0 }, { 0, 1 })) << "Can't cut a solid corner";
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 1 }, { 1, 0 })) << "Can't cut a solid corner";
|
||||
dPiece[1][1] = 1;
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 0 }, { 0, 1 })) << "Can't walk through the boundary between two corners";
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 1 }, { 1, 0 })) << "Can't walk through the boundary between two corners";
|
||||
dPiece[0][0] = 0;
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 0 }, { 0, 1 })) << "Can't cut a solid corner";
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 1 }, { 1, 0 })) << "Can't cut a solid corner";
|
||||
dPiece[1][1] = 0;
|
||||
}
|
||||
|
||||
void CheckPath(Point startPosition, Point destinationPosition, std::vector<int8_t> expectedSteps)
|
||||
{
|
||||
static int8_t pathSteps[MAX_PATH_LENGTH];
|
||||
auto pathLength = FindPath([](Point) { return true; }, startPosition, destinationPosition, pathSteps);
|
||||
|
||||
EXPECT_EQ(pathLength, expectedSteps.size()) << "Wrong path length for a path from " << startPosition << " to " << destinationPosition;
|
||||
// Die early if the wrong path length is returned as we don't want to read oob in expectedSteps
|
||||
ASSERT_LE(pathLength, expectedSteps.size()) << "Path is longer than expected.";
|
||||
|
||||
for (auto i = 0; i < pathLength; i++) {
|
||||
EXPECT_EQ(pathSteps[i], expectedSteps[i]) << "Path step " << i << " differs from expectation for a path from "
|
||||
<< startPosition << " to " << destinationPosition; // this shouldn't be a requirement but...
|
||||
|
||||
// Path directions are all jacked up compared to the Direction enum. Most consumers have their own mapping definition
|
||||
// startPosition += Direction { path[i] - 1 };
|
||||
}
|
||||
// Given that we can't really make any assumptions about how the path is actually used.
|
||||
// EXPECT_EQ(startPosition, destinationPosition) << "Path doesn't lead to destination";
|
||||
}
|
||||
|
||||
TEST(PathTest, FindPath)
|
||||
{
|
||||
CheckPath({ 8, 8 }, { 8, 8 }, {});
|
||||
|
||||
// Traveling in cardinal directions is the only way to get a first step in a cardinal direction
|
||||
CheckPath({ 8, 8 }, { 8, 6 }, { 1, 1 });
|
||||
CheckPath({ 8, 8 }, { 6, 8 }, { 2, 2 });
|
||||
CheckPath({ 8, 8 }, { 10, 8 }, { 3, 3 });
|
||||
CheckPath({ 8, 8 }, { 8, 10 }, { 4, 4 });
|
||||
|
||||
// Otherwise pathing biases along diagonals and the diagonal steps will always be first
|
||||
CheckPath({ 8, 8 }, { 5, 6 }, { 5, 5, 2 });
|
||||
CheckPath({ 8, 8 }, { 4, 4 }, { 5, 5, 5, 5 });
|
||||
CheckPath({ 8, 8 }, { 12, 20 }, { 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 4, 4 });
|
||||
}
|
||||
|
||||
TEST(PathTest, Walkable)
|
||||
{
|
||||
dPiece[5][5] = 0;
|
||||
nSolidTable[0] = true; // Doing this manually to save running through the code in gendung.cpp
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 })) << "Tile which is marked as solid should be considered blocked";
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 }, true)) << "Solid non-door tiles remain unwalkable when ignoring doors";
|
||||
|
||||
nSolidTable[0] = false;
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 })) << "Non-solid tiles are walkable";
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 }, true)) << "Non-solid tiles remain walkable when ignoring doors";
|
||||
|
||||
dObject[5][5] = 1;
|
||||
Objects[0]._oSolidFlag = true;
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 })) << "Tile occupied by a solid object is unwalkable";
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 }, true)) << "Tile occupied by a solid non-door object are unwalkable when ignoring doors";
|
||||
|
||||
Objects[0]._otype = _object_id::OBJ_L1LDOOR;
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 })) << "Tile occupied by a door which is marked as solid should be considered blocked";
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 }, true)) << "Tile occupied by a door is considered walkable when ignoring doors";
|
||||
|
||||
Objects[0]._oSolidFlag = false;
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 })) << "Tile occupied by an open door is walkable";
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 }, true)) << "Tile occupied by a door is considered walkable when ignoring doors";
|
||||
|
||||
nSolidTable[0] = true;
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 })) << "Solid tiles occupied by an open door remain unwalkable";
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 }, true)) << "Solid tiles occupied by an open door become walkable when ignoring doors";
|
||||
}
|
||||
|
||||
TEST(PathTest, FindClosest)
|
||||
{
|
||||
{
|
||||
std::array<std::array<int, 101>, 101> searchedTiles {};
|
||||
|
||||
std::optional<Point> nearPosition = FindClosestValidPosition(
|
||||
[&searchedTiles](Point testPosition) {
|
||||
searchedTiles[testPosition.x][testPosition.y]++;
|
||||
return false;
|
||||
},
|
||||
{ 50, 50 }, 0, 50);
|
||||
|
||||
EXPECT_FALSE(nearPosition) << "Searching with no valid tiles should return an empty optional";
|
||||
|
||||
for (int x = 0; x < searchedTiles.size(); x++) {
|
||||
for (int y = 0; y < searchedTiles[x].size(); y++) {
|
||||
if (IsAnyOf(x, 0, 100) && IsAnyOf(y, 0, 100)) {
|
||||
EXPECT_EQ(searchedTiles[x][y], 0) << "Extreme corners should be skipped due to the inset/rounded search space";
|
||||
} else {
|
||||
EXPECT_EQ(searchedTiles[x][y], 1) << "Position " << Point { x, y } << " should have been searched exactly once";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::array<std::array<int, 5>, 5> searchedTiles {};
|
||||
|
||||
std::optional<Point> nearPosition = FindClosestValidPosition(
|
||||
[&searchedTiles](Point testPosition) {
|
||||
searchedTiles[testPosition.x][testPosition.y]++;
|
||||
return false;
|
||||
},
|
||||
{ 2, 2 }, 1, 2);
|
||||
|
||||
EXPECT_FALSE(nearPosition) << "Still shouldn't find a valid position with no valid tiles";
|
||||
|
||||
for (int x = 0; x < searchedTiles.size(); x++) {
|
||||
for (int y = 0; y < searchedTiles[x].size(); y++) {
|
||||
if (Point { x, y } == Point { 2, 2 }) {
|
||||
EXPECT_EQ(searchedTiles[x][y], 0) << "The starting tile should be skipped with a min radius of 1";
|
||||
} else if (IsAnyOf(x, 0, 4) && IsAnyOf(y, 0, 4)) {
|
||||
EXPECT_EQ(searchedTiles[x][y], 0) << "Corners should be skipped";
|
||||
} else {
|
||||
EXPECT_EQ(searchedTiles[x][y], 1) << "All tiles in range should be searched exactly once";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::array<std::array<int, 3>, 3> searchedTiles {};
|
||||
|
||||
std::optional<Point> nearPosition = FindClosestValidPosition(
|
||||
[&searchedTiles](Point testPosition) {
|
||||
searchedTiles[testPosition.x][testPosition.y]++;
|
||||
return false;
|
||||
},
|
||||
{ 1, 1 }, 0, 0);
|
||||
|
||||
EXPECT_FALSE(nearPosition) << "Searching with no valid tiles should return an empty optional";
|
||||
|
||||
for (int x = 0; x < searchedTiles.size(); x++) {
|
||||
for (int y = 0; y < searchedTiles[x].size(); y++) {
|
||||
if (Point { x, y } == Point { 1, 1 }) {
|
||||
EXPECT_EQ(searchedTiles[x][y], 1) << "Only the starting tile should be searched with max radius 0";
|
||||
} else {
|
||||
EXPECT_EQ(searchedTiles[x][y], 0) << "Position " << Point { x, y } << " should not have been searched";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::array<std::array<int, 7>, 7> searchedTiles {};
|
||||
|
||||
std::optional<Point> nearPosition = FindClosestValidPosition(
|
||||
[&searchedTiles](Point testPosition) {
|
||||
searchedTiles[testPosition.x][testPosition.y]++;
|
||||
return false;
|
||||
},
|
||||
{ 3, 3 }, 3, 3);
|
||||
|
||||
EXPECT_FALSE(nearPosition) << "Searching with no valid tiles should return an empty optional";
|
||||
|
||||
for (int x = 0; x < searchedTiles.size(); x++) {
|
||||
for (int y = 0; y < searchedTiles[x].size(); y++) {
|
||||
if ((IsAnyOf(x, 1, 5) && IsAnyOf(y, 1, 5)) // inset corners
|
||||
|| (IsAnyOf(x, 0, 6) && IsNoneOf(y, 0, 6)) // left/right sides
|
||||
|| (IsNoneOf(x, 0, 6) && IsAnyOf(y, 0, 6)) // top/bottom sides
|
||||
) {
|
||||
EXPECT_EQ(searchedTiles[x][y], 1) << "Searching with a fixed radius should make a square with inset corners";
|
||||
} else {
|
||||
EXPECT_EQ(searchedTiles[x][y], 0) << "Position " << Point { x, y } << " should not have been searched";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::optional<Point> nearPosition = FindClosestValidPosition(
|
||||
[](Point testPosition) {
|
||||
return true;
|
||||
},
|
||||
{ 50, 50 }, 21, 50);
|
||||
|
||||
EXPECT_EQ(*nearPosition, (Point { 50, 50 } + Displacement { 0, 21 })) << "First candidate position with a minimum radius should be at {0, +y}";
|
||||
}
|
||||
}
|
||||
} // namespace devilution
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "path.h"
|
||||
|
||||
// The following headers are included to access globals used in functions that have not been isolated yet.
|
||||
#include "gendung.h"
|
||||
#include "objects.h"
|
||||
|
||||
namespace devilution {
|
||||
|
||||
extern int TestPathGetHeuristicCost(Point startPosition, Point destinationPosition);
|
||||
|
||||
TEST(PathTest, Heuristics)
|
||||
{
|
||||
constexpr Point source { 25, 32 };
|
||||
Point destination = source;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 0) << "Wrong cost for travelling to the same tile";
|
||||
|
||||
destination = source + Direction::NorthEast;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
|
||||
destination = source + Direction::SouthEast;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
|
||||
destination = source + Direction::SouthWest;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
|
||||
destination = source + Direction::NorthWest;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 2) << "Wrong cost for travelling to horizontal/vertical adjacent tile";
|
||||
|
||||
destination = source + Direction::North;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
|
||||
destination = source + Direction::East;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
|
||||
destination = source + Direction::South;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
|
||||
destination = source + Direction::West;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
|
||||
destination = source + Direction::SouthWest + Direction::SouthEast; // Effectively the same as Direction::South
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to diagonally adjacent tile";
|
||||
|
||||
destination = source + Direction::NorthEast + Direction::North;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 6) << "Wrong cost for travelling to a { 2, 1 } offset";
|
||||
destination = source + Direction::SouthEast + Direction::SouthEast;
|
||||
EXPECT_EQ(TestPathGetHeuristicCost(source, destination), 4) << "Wrong cost for travelling to a { 2, 0 } offset";
|
||||
}
|
||||
|
||||
TEST(PathTest, Solid)
|
||||
{
|
||||
dPiece[5][5] = 0;
|
||||
nSolidTable[0] = true;
|
||||
EXPECT_TRUE(IsTileSolid({ 5, 5 })) << "Solid in-bounds tiles are solid";
|
||||
EXPECT_FALSE(IsTileNotSolid({ 5, 5 })) << "IsTileNotSolid returns the inverse of IsTileSolid for in-bounds tiles";
|
||||
|
||||
dPiece[6][6] = 1;
|
||||
nSolidTable[1] = false;
|
||||
EXPECT_FALSE(IsTileSolid({ 6, 6 })) << "Non-solid in-bounds tiles are not solid";
|
||||
EXPECT_TRUE(IsTileNotSolid({ 6, 6 })) << "IsTileNotSolid returns the inverse of IsTileSolid for in-bounds tiles";
|
||||
|
||||
EXPECT_FALSE(IsTileSolid({ -1, 1 })) << "Out of bounds tiles are not solid"; // this reads out of bounds in the current code and may fail unexpectedly
|
||||
EXPECT_FALSE(IsTileNotSolid({ -1, 1 })) << "Out of bounds tiles are also not not solid";
|
||||
}
|
||||
|
||||
TEST(PathTest, SolidPieces)
|
||||
{
|
||||
dPiece[0][0] = 0;
|
||||
dPiece[0][1] = 0;
|
||||
dPiece[1][0] = 0;
|
||||
dPiece[1][1] = 0;
|
||||
nSolidTable[0] = false;
|
||||
EXPECT_TRUE(path_solid_pieces({ 0, 0 }, { 1, 1 })) << "A step in open space is free of solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 1, 1 }, { 0, 0 })) << "A step in open space is free of solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 1, 0 }, { 0, 1 })) << "A step in open space is free of solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 0, 1 }, { 1, 0 })) << "A step in open space is free of solid pieces";
|
||||
|
||||
nSolidTable[1] = true;
|
||||
dPiece[1][0] = 1;
|
||||
EXPECT_TRUE(path_solid_pieces({ 0, 1 }, { 1, 0 })) << "Can path to a destination which is solid";
|
||||
EXPECT_TRUE(path_solid_pieces({ 1, 0 }, { 0, 1 })) << "Can path from a starting position which is solid";
|
||||
EXPECT_TRUE(path_solid_pieces({ 0, 1 }, { 1, 1 })) << "Stepping in a cardinal direction ignores solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 1, 0 }, { 1, 1 })) << "Stepping in a cardinal direction ignores solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 0, 0 }, { 1, 0 })) << "Stepping in a cardinal direction ignores solid pieces";
|
||||
EXPECT_TRUE(path_solid_pieces({ 1, 1 }, { 1, 0 })) << "Stepping in a cardinal direction ignores solid pieces";
|
||||
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 0 }, { 1, 1 })) << "Can't cut a solid corner";
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 1 }, { 0, 0 })) << "Can't cut a solid corner";
|
||||
dPiece[0][1] = 1;
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 0 }, { 1, 1 })) << "Can't walk through the boundary between two corners";
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 1 }, { 0, 0 })) << "Can't walk through the boundary between two corners";
|
||||
dPiece[1][0] = 0;
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 0 }, { 1, 1 })) << "Can't cut a solid corner";
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 1 }, { 0, 0 })) << "Can't cut a solid corner";
|
||||
dPiece[0][1] = 0;
|
||||
|
||||
dPiece[0][0] = 1;
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 0 }, { 0, 1 })) << "Can't cut a solid corner";
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 1 }, { 1, 0 })) << "Can't cut a solid corner";
|
||||
dPiece[1][1] = 1;
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 0 }, { 0, 1 })) << "Can't walk through the boundary between two corners";
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 1 }, { 1, 0 })) << "Can't walk through the boundary between two corners";
|
||||
dPiece[0][0] = 0;
|
||||
EXPECT_FALSE(path_solid_pieces({ 1, 0 }, { 0, 1 })) << "Can't cut a solid corner";
|
||||
EXPECT_FALSE(path_solid_pieces({ 0, 1 }, { 1, 0 })) << "Can't cut a solid corner";
|
||||
dPiece[1][1] = 0;
|
||||
}
|
||||
|
||||
void CheckPath(Point startPosition, Point destinationPosition, std::vector<int8_t> expectedSteps)
|
||||
{
|
||||
static int8_t pathSteps[MAX_PATH_LENGTH];
|
||||
auto pathLength = FindPath([](Point) { return true; }, startPosition, destinationPosition, pathSteps);
|
||||
|
||||
EXPECT_EQ(pathLength, expectedSteps.size()) << "Wrong path length for a path from " << startPosition << " to " << destinationPosition;
|
||||
// Die early if the wrong path length is returned as we don't want to read oob in expectedSteps
|
||||
ASSERT_LE(pathLength, expectedSteps.size()) << "Path is longer than expected.";
|
||||
|
||||
for (auto i = 0; i < pathLength; i++) {
|
||||
EXPECT_EQ(pathSteps[i], expectedSteps[i]) << "Path step " << i << " differs from expectation for a path from "
|
||||
<< startPosition << " to " << destinationPosition; // this shouldn't be a requirement but...
|
||||
|
||||
// Path directions are all jacked up compared to the Direction enum. Most consumers have their own mapping definition
|
||||
// startPosition += Direction { path[i] - 1 };
|
||||
}
|
||||
// Given that we can't really make any assumptions about how the path is actually used.
|
||||
// EXPECT_EQ(startPosition, destinationPosition) << "Path doesn't lead to destination";
|
||||
}
|
||||
|
||||
TEST(PathTest, FindPath)
|
||||
{
|
||||
CheckPath({ 8, 8 }, { 8, 8 }, {});
|
||||
|
||||
// Traveling in cardinal directions is the only way to get a first step in a cardinal direction
|
||||
CheckPath({ 8, 8 }, { 8, 6 }, { 1, 1 });
|
||||
CheckPath({ 8, 8 }, { 6, 8 }, { 2, 2 });
|
||||
CheckPath({ 8, 8 }, { 10, 8 }, { 3, 3 });
|
||||
CheckPath({ 8, 8 }, { 8, 10 }, { 4, 4 });
|
||||
|
||||
// Otherwise pathing biases along diagonals and the diagonal steps will always be first
|
||||
CheckPath({ 8, 8 }, { 5, 6 }, { 5, 5, 2 });
|
||||
CheckPath({ 8, 8 }, { 4, 4 }, { 5, 5, 5, 5 });
|
||||
CheckPath({ 8, 8 }, { 12, 20 }, { 7, 7, 7, 7, 4, 4, 4, 4, 4, 4, 4, 4 });
|
||||
}
|
||||
|
||||
TEST(PathTest, Walkable)
|
||||
{
|
||||
dPiece[5][5] = 0;
|
||||
nSolidTable[0] = true; // Doing this manually to save running through the code in gendung.cpp
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 })) << "Tile which is marked as solid should be considered blocked";
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 }, true)) << "Solid non-door tiles remain unwalkable when ignoring doors";
|
||||
|
||||
nSolidTable[0] = false;
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 })) << "Non-solid tiles are walkable";
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 }, true)) << "Non-solid tiles remain walkable when ignoring doors";
|
||||
|
||||
dObject[5][5] = 1;
|
||||
Objects[0]._oSolidFlag = true;
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 })) << "Tile occupied by a solid object is unwalkable";
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 }, true)) << "Tile occupied by a solid non-door object are unwalkable when ignoring doors";
|
||||
|
||||
Objects[0]._otype = _object_id::OBJ_L1LDOOR;
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 })) << "Tile occupied by a door which is marked as solid should be considered blocked";
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 }, true)) << "Tile occupied by a door is considered walkable when ignoring doors";
|
||||
|
||||
Objects[0]._oSolidFlag = false;
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 })) << "Tile occupied by an open door is walkable";
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 }, true)) << "Tile occupied by a door is considered walkable when ignoring doors";
|
||||
|
||||
nSolidTable[0] = true;
|
||||
EXPECT_FALSE(IsTileWalkable({ 5, 5 })) << "Solid tiles occupied by an open door remain unwalkable";
|
||||
EXPECT_TRUE(IsTileWalkable({ 5, 5 }, true)) << "Solid tiles occupied by an open door become walkable when ignoring doors";
|
||||
}
|
||||
|
||||
TEST(PathTest, FindClosest)
|
||||
{
|
||||
{
|
||||
std::array<std::array<int, 101>, 101> searchedTiles {};
|
||||
|
||||
std::optional<Point> nearPosition = FindClosestValidPosition(
|
||||
[&searchedTiles](Point testPosition) {
|
||||
searchedTiles[testPosition.x][testPosition.y]++;
|
||||
return false;
|
||||
},
|
||||
{ 50, 50 }, 0, 50);
|
||||
|
||||
EXPECT_FALSE(nearPosition) << "Searching with no valid tiles should return an empty optional";
|
||||
|
||||
for (size_t x = 0; x < searchedTiles.size(); x++) {
|
||||
for (size_t y = 0; y < searchedTiles[x].size(); y++) {
|
||||
if ((x == 0 || x == 100) && (y == 0 || y == 100)) {
|
||||
EXPECT_EQ(searchedTiles[x][y], 0) << "Extreme corners should be skipped due to the inset/rounded search space";
|
||||
} else {
|
||||
EXPECT_EQ(searchedTiles[x][y], 1) << "Position " << x << " " << y << " should have been searched exactly once";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::array<std::array<int, 5>, 5> searchedTiles {};
|
||||
|
||||
std::optional<Point> nearPosition = FindClosestValidPosition(
|
||||
[&searchedTiles](Point testPosition) {
|
||||
searchedTiles[testPosition.x][testPosition.y]++;
|
||||
return false;
|
||||
},
|
||||
{ 2, 2 }, 1, 2);
|
||||
|
||||
EXPECT_FALSE(nearPosition) << "Still shouldn't find a valid position with no valid tiles";
|
||||
|
||||
for (size_t x = 0; x < searchedTiles.size(); x++) {
|
||||
for (size_t y = 0; y < searchedTiles[x].size(); y++) {
|
||||
if (x == 2 && y == 2) {
|
||||
EXPECT_EQ(searchedTiles[x][y], 0) << "The starting tile should be skipped with a min radius of 1";
|
||||
} else if ((x == 0 || x == 4) && (y == 0 || y == 4)) {
|
||||
EXPECT_EQ(searchedTiles[x][y], 0) << "Corners should be skipped";
|
||||
} else {
|
||||
EXPECT_EQ(searchedTiles[x][y], 1) << "All tiles in range should be searched exactly once";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::array<std::array<int, 3>, 3> searchedTiles {};
|
||||
|
||||
std::optional<Point> nearPosition = FindClosestValidPosition(
|
||||
[&searchedTiles](Point testPosition) {
|
||||
searchedTiles[testPosition.x][testPosition.y]++;
|
||||
return false;
|
||||
},
|
||||
{ 1, 1 }, 0, 0);
|
||||
|
||||
EXPECT_FALSE(nearPosition) << "Searching with no valid tiles should return an empty optional";
|
||||
|
||||
for (size_t x = 0; x < searchedTiles.size(); x++) {
|
||||
for (size_t y = 0; y < searchedTiles[x].size(); y++) {
|
||||
if (x == 1 && y == 1) {
|
||||
EXPECT_EQ(searchedTiles[x][y], 1) << "Only the starting tile should be searched with max radius 0";
|
||||
} else {
|
||||
EXPECT_EQ(searchedTiles[x][y], 0) << "Position " << x << " " << y << " should not have been searched";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::array<std::array<int, 7>, 7> searchedTiles {};
|
||||
|
||||
std::optional<Point> nearPosition = FindClosestValidPosition(
|
||||
[&searchedTiles](Point testPosition) {
|
||||
searchedTiles[testPosition.x][testPosition.y]++;
|
||||
return false;
|
||||
},
|
||||
{ 3, 3 }, 3, 3);
|
||||
|
||||
EXPECT_FALSE(nearPosition) << "Searching with no valid tiles should return an empty optional";
|
||||
|
||||
for (size_t x = 0; x < searchedTiles.size(); x++) {
|
||||
for (size_t y = 0; y < searchedTiles[x].size(); y++) {
|
||||
if (((x == 1 || x == 5) && (y == 1 || y == 5)) // inset corners
|
||||
|| ((x == 0 || x == 6) && y != 0 && y != 6) // left/right sides
|
||||
|| (x != 0 && x != 6 && (y == 0 || y == 6)) // top/bottom sides
|
||||
) {
|
||||
EXPECT_EQ(searchedTiles[x][y], 1) << "Searching with a fixed radius should make a square with inset corners";
|
||||
} else {
|
||||
EXPECT_EQ(searchedTiles[x][y], 0) << "Position " << x << " " << y << " should not have been searched";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
std::optional<Point> nearPosition = FindClosestValidPosition(
|
||||
[](Point testPosition) {
|
||||
return true;
|
||||
},
|
||||
{ 50, 50 }, 21, 50);
|
||||
|
||||
EXPECT_EQ(*nearPosition, (Point { 50, 50 } + Displacement { 0, 21 })) << "First candidate position with a minimum radius should be at {0, +y}";
|
||||
}
|
||||
}
|
||||
} // namespace devilution
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "player.h"
|
||||
#include "items.h"
|
||||
#include "player.h"
|
||||
|
||||
using namespace devilution;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "quests.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
#include "player_test.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <gtest/gtest.h>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <picosha2.h>
|
||||
|
||||
#include "loadsave.h"
|
||||
#include "pack.h"
|
||||
#include "pfile.h"
|
||||
#include "utils/paths.h"
|
||||
|
||||
#include "picosha2.h"
|
||||
|
||||
using namespace devilution;
|
||||
|
||||
int spelldat_vanilla[] = {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ _DEPS = ['asio', 'libmpq', 'libsmackerdec',
|
|||
|
||||
# These dependencies are not vendored by default.
|
||||
# Run with `--fully_vendored` to include them.
|
||||
_DEPS_NOT_VENDORED_BY_DEFAULT = ['sdl2', 'sdl_image',
|
||||
_DEPS_NOT_VENDORED_BY_DEFAULT = ['googletest', 'sdl2', 'sdl_image',
|
||||
'libpng', 'libfmt', 'bzip2', 'libsodium']
|
||||
|
||||
_ROOT_DIR = pathlib.Path(__file__).resolve().parent.parent
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue