WIP: Move boilerplate application code to external lib.
Overview --- - Added: External dependency on IOCore - Removed: - Application.hpp, Application.cpp - debuginnfo.hpp,debuginfo.cpp - Exception.hpp,Exception.cpp - types/legible_ctypes.hpp - All references to Boost and execinfo/backtrace. Additionally: --- - .clang-format: Switch to modified WebKit code style - .clang-tidy: Tweak style for Constexpr statements - .clangd: Re-enable IWYU include directory insertion & analysis CMakeLists.txt: - Replace manual CMake conditionals with prepackaged functions from my custom cmake/BuildProperties.cmake CMake module. - Bump project version - Set project-wide dir variables - Add and use CPM Package Manager - Add reference to my IOCore application framework library using CPM - Remove references to backtrace generation. Now using IOCore - Comment out app and demo subdirectories for now. cmake/BuildProperties.cmake: - Move in-source build detection, set project-wide environment variables, and other configuration tasks to specific CMake functions in a custom CMake module. cmake/CPM.cmake: Imported from the CPM Project under MIT License - Copyright (c) Lars Melchior and contributors demo/Phong.hpp,demo/Phong.cpp: - Use new method names. (untested, never compiled) include/Component.hpp: Unused, Untested changes Work #28
This commit is contained in:
parent
89e90aaa5e
commit
42af043b3f
@ -4,31 +4,23 @@ Language: Cpp
|
||||
|
||||
IndentWidth: 8
|
||||
UseTab: AlignWithSpaces
|
||||
ColumnLimit: 80
|
||||
AccessModifierOffset: -6
|
||||
AlwaysBreakAfterReturnType: None
|
||||
BinPackArguments: true
|
||||
ColumnLimit: 81
|
||||
AccessModifierOffset: -4
|
||||
BinPackParameters: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
PenaltyReturnTypeOnItsOwnLine: 50
|
||||
ContinuationIndentWidth: 4
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
PackConstructorInitializers: CurrentLine
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AlignAfterOpenBracket: Align
|
||||
DerivePointerAlignment: False
|
||||
PointerAlignment: Left
|
||||
ReferenceAlignment: Pointer
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
FixNamespaceComments: Yes
|
||||
NamespaceIndentation: Inner
|
||||
AlignAfterOpenBracket: BlockIndent
|
||||
|
||||
MaxEmptyLinesToKeep: 1
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
|
||||
#BreakBeforeBraces: Custom
|
||||
BreakBeforeBraces: WebKit
|
||||
#BraceWrapping:
|
||||
# AfterCaseLabel: false
|
||||
# AfterClass: true
|
||||
# AfterControlStatement: Always
|
||||
# AfterControlStatement: MultiLine
|
||||
# AfterEnum: false
|
||||
# AfterFunction: true
|
||||
# AfterNamespace: false
|
||||
@ -45,4 +37,5 @@ KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
# SplitEmptyFunction: true
|
||||
# SplitEmptyRecord: false
|
||||
# SplitEmptyNamespace: true
|
||||
#
|
||||
---
|
||||
|
@ -12,7 +12,7 @@ CheckOptions:
|
||||
- { key: readability-function-cognitive-complexity.IgnoreMacros, value: true }
|
||||
|
||||
# Minimum Variable Length
|
||||
- { key: readability-identifier-length.MinimumVariableLength, value: 3 }
|
||||
- { key: readability-identifier-length.MinimumVariableNameLength, value: 3 }
|
||||
- { key: readability-identifier-length.IgnoredVariableNames, value: "^(i|j|n|x|y|z|it)$" }
|
||||
|
||||
# Minimum Parameter Length
|
||||
@ -46,10 +46,10 @@ CheckOptions:
|
||||
value: '' }
|
||||
- { key: readability-identifier-naming.TypeTemplateParameterCase,
|
||||
value: CamelCase }
|
||||
- { key: readability-identifier-naming.TypeTemplateParameterIgnoredRegexp, value: "^T$" }
|
||||
|
||||
# TypeAlias Rules
|
||||
- { key: readability-identifier-naming.TypeAliasCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.TypeAliasTemplateCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.TypeAliasIgnoredRegexp,
|
||||
value: '.*_t|string|.*_string' }
|
||||
|
||||
@ -71,7 +71,7 @@ CheckOptions:
|
||||
|
||||
# Constant Expression
|
||||
- { key: readability-identifier-naming.ConstexprVariablePrefix, value: 'k' }
|
||||
- { key: readability-identifier-naming.ConstexprVariableCase, value: Camelcase }
|
||||
- { key: readability-identifier-naming.ConstexprVariableCase, value: Camel_Snake_Case }
|
||||
|
||||
- { key: readability-identifier-naming.ConstexprFunctionCase, value: Camel_Snake_Case }
|
||||
- { key: readability-identifier-naming.ConstexprMethodCase, value: Camel_Snake_Case }
|
||||
|
6
.clangd
6
.clangd
@ -1,3 +1,9 @@
|
||||
#.clangd
|
||||
CompileFlags:
|
||||
Add: [-DCLANGD, -DVIM_LSP=1]
|
||||
|
||||
Diagnostics:
|
||||
UnusedIncludes: Strict
|
||||
MissingIncludes: Strict
|
||||
Includes:
|
||||
IgnoreHeader: types\.hpp
|
||||
|
252
CMakeLists.txt
252
CMakeLists.txt
@ -1,88 +1,122 @@
|
||||
cmake_minimum_required(VERSION 3.26)
|
||||
|
||||
# Prevent in-source builds
|
||||
if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
message(FATAL_ERROR "Source and build directories cannot be the same.")
|
||||
endif()
|
||||
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
|
||||
cmake_policy(SET CMP0135 NEW)
|
||||
endif()
|
||||
|
||||
# Check if this CMakeFile is being built as part of a FetchContent CMake
|
||||
# dependency download.
|
||||
if (NOT DEFINED PROJECT_NAME)
|
||||
# When this package is included as a subproject, save some time by skipping
|
||||
# the unit test build and execution.
|
||||
# To override this, set -DENABLE_TESTS=true when you call CMake
|
||||
option(ENABLE_TESTS "Build and run unit tests" ON)
|
||||
else()
|
||||
option(ENABLE_TESTS "Build and run unit tests" OFF)
|
||||
endif()
|
||||
option(CI_BUILD "Defines a C preprocessor macro used to disable some code paths in CI servers" OFF)
|
||||
# Additional paths to search for custom and third-party CMake modules
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
include(BuildProperties)
|
||||
|
||||
prevent_in_source_build()
|
||||
disable_deprecated_features()
|
||||
|
||||
# When this package is included as a subproject, there's no need to
|
||||
# build and run the unit-tests.
|
||||
# Sets -DBUILD_TESTING to false by default if this is a third-party lib build
|
||||
# This check must appear before project()
|
||||
disable_tests_if_subproject()
|
||||
|
||||
project(Elemental
|
||||
VERSION 0.0.1
|
||||
VERSION 0.0.2
|
||||
LANGUAGES C CXX
|
||||
# Save this for later:
|
||||
# HOMEPAGE_URL <URL>
|
||||
DESCRIPTION "A simple top-down strategy game"
|
||||
)
|
||||
include(CPM)
|
||||
|
||||
# Custom CMake Defines / Command-line options
|
||||
option(USE_SYSTEM_CATCH2
|
||||
"Do not download & compile catch2 library for unit tests"
|
||||
ON
|
||||
)
|
||||
SET(${PROJECT_NAME}_CMAKE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
SET(${PROJECT_NAME}_INCLUDE_DIRS ${IOCore_CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
if (CI_BUILD)
|
||||
add_compile_definitions(-DCI_BUILD=1)
|
||||
endif()
|
||||
|
||||
if( NOT CMAKE_BUILD_TYPE )
|
||||
SET( CMAKE_BUILD_TYPE Debug )
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Disable non-portable GNU compiler extensions
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# Check if ccache is installed and enable CMake integration
|
||||
# if found. This will speed up repeated builds.
|
||||
find_program(CCACHE_PATH ccache)
|
||||
if(ccache_path)
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_PATH})
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_PATH})
|
||||
endif(ccache_path)
|
||||
|
||||
if (USE_SYSTEM_CATCH2)
|
||||
message(CHECK_START "Detecting System Catch2 ")
|
||||
find_package(Catch2 3 QUIET)
|
||||
|
||||
if(TARGET Catch2::Catch2)
|
||||
message(CHECK_PASS "found target Catch2::Catch2")
|
||||
else()
|
||||
message(CHECK_FAIL "not found")
|
||||
set(USE_SYSTEM_CATCH2 OFF)
|
||||
message(STATUS "USE_SYSTEM_CATCH2=OFF")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux"))
|
||||
option(USE_BOOST_STACKTRACE "Use Boost::stacktrace for stack traces" OFF)
|
||||
option(USE_EXECINFO_STACKTRACE "Use BSD/UNIX execinfo for stack traces" ON)
|
||||
else()
|
||||
option(USE_BOOST_STACKTRACE "Use Boost::stacktrace for stack traces" ON)
|
||||
option(USE_EXECINFO_STACKTRACE "Use BSD/UNIX execinfo for stack traces" OFF)
|
||||
endif()
|
||||
|
||||
option(USE_CCACHE
|
||||
[=[Use ccache compiler cache to speed up builds.
|
||||
Enabled by default if ccache is found]=]
|
||||
ON
|
||||
)
|
||||
|
||||
# enable compile_commands.json generation for clangd
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS On)
|
||||
|
||||
IF( NOT CMAKE_BUILD_TYPE )
|
||||
SET( CMAKE_BUILD_TYPE Debug )
|
||||
ENDIF()
|
||||
|
||||
set(CMAKE_C_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# Disable GNU compiler extensions
|
||||
set(CMAKE_C_EXTENSIONS OFF)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# Search for the code caching compiler wrapper, ccache and enable it
|
||||
# if found. This will speed up repeated builds.
|
||||
if (USE_CCACHE)
|
||||
message(CHECK_START "Detecting cacche")
|
||||
|
||||
find_program(CCACHE_PATH ccache)
|
||||
if(CCACHE_PATH)
|
||||
message(CHECK_PASS("found"))
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_PATH})
|
||||
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ${CCACHE_PATH})
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MESSAGE_INDENT " ")
|
||||
message(STATUS "(set -DUSE_CCACHE=Off to disable)")
|
||||
list(POP_BACK CMAKE_MESSAGE_INDENT)
|
||||
endif()
|
||||
|
||||
if (BUILD_TESTING)
|
||||
CPMFindPackage(NAME Catch2
|
||||
GITHUB_REPOSITORY catchorg/Catch2
|
||||
VERSION 3.4.0
|
||||
OPTIONS
|
||||
"CATCH_DEVELOPMENT_BUILD OFF"
|
||||
"CATCH_BUILD_TESTING OFF"
|
||||
)
|
||||
CPMFindPackage(NAME FakeIt
|
||||
GITHUB_REPOSITORY eranpeer/FakeIt
|
||||
GIT_TAG 2.4.0
|
||||
OPTIONS
|
||||
"BUILD_TESTINGING OFF"
|
||||
)
|
||||
|
||||
if (TARGET Catch2)
|
||||
set_target_properties(Catch2 PROPERTIES
|
||||
CXX_STANDARD 20
|
||||
)
|
||||
endif()
|
||||
if (TARGET Catch2WithMain)
|
||||
set_target_properties(Catch2WithMain PROPERTIES
|
||||
CXX_STANDARD 20
|
||||
)
|
||||
endif()
|
||||
|
||||
if (Catch2_ADDED)
|
||||
list(APPEND CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras)
|
||||
else()
|
||||
if (Catch2_DIR)
|
||||
list(APPEND CMAKE_MODULE_PATH ${Catch2_DIR})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
CPMAddPackage(NAME IOCore
|
||||
GIT_REPOSITORY "file://${CMAKE_CURRENT_SOURCE_DIR}/../IOCore"
|
||||
#GIT_TAG HEAD
|
||||
#GIT_REPOSITORY "https://gitea.beniquez.me/sdaveb/IOCore.git"
|
||||
GIT_TAG v0.2.10
|
||||
OPTIONS
|
||||
"BUILD_SHARED_LIBS OFF"
|
||||
"BUILD_TESTING OFF"
|
||||
)
|
||||
|
||||
# Set output directories for build targets
|
||||
set_artifact_dir(${CMAKE_BINARY_DIR}/out)
|
||||
|
||||
# Initialize FetchContent
|
||||
include(FetchContent)
|
||||
include(CheckIncludeFile)
|
||||
@ -96,12 +130,13 @@ find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(SDL2 REQUIRED IMPORTED_TARGET sdl2)
|
||||
pkg_check_modules(SDL2_IMAGE REQUIRED IMPORTED_TARGET SDL2_image)
|
||||
pkg_check_modules(SDL2_GFX REQUIRED IMPORTED_TARGET SDL2_gfx)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(NLOHMANN_JSON "nlohmann_json >= 3.11.2" REQUIRED)
|
||||
|
||||
SET(SDL2_COMBINED_INCLUDE_DIRS "")
|
||||
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_INCLUDE_DIRS})
|
||||
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIRS})
|
||||
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_GFX_INCLUDE_DIRS})
|
||||
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_INCLUDE_DIRS})
|
||||
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_IMAGE_INCLUDE_DIRS})
|
||||
list(APPEND SDL2_COMBINED_INCLUDE_DIRS ${SDL2_GFX_INCLUDE_DIRS})
|
||||
|
||||
list(REMOVE_DUPLICATES SDL2_COMBINED_INCLUDE_DIRS)
|
||||
|
||||
@ -111,98 +146,25 @@ set(SDL2_COMBINED_LINK_DEPS
|
||||
PkgConfig::SDL2_GFX
|
||||
)
|
||||
|
||||
if (USE_EXECINFO_STACKTRACE AND (NOT USE_BOOST_STACKTRACE))
|
||||
CHECK_INCLUDE_FILE("execinfo.h" HAVE_EXECINFO_H)
|
||||
|
||||
if (HAVE_EXECINFO_H)
|
||||
add_definitions(-DHAVE_EXECINFO_H=1)
|
||||
endif()
|
||||
|
||||
find_library(LIB_EXEC_INFO
|
||||
NAMES execinfo # Specify the library name without the 'lib' prefix or file extension
|
||||
HINTS /usr/lib /usr/local/lib # Optional hint for the library location
|
||||
)
|
||||
if (LIB_EXEC_INFO)
|
||||
message(STATUS "Found libexecinfo: ${LIB_EXEC_INFO}")
|
||||
set(STACKTRACE_DEP_LIBS ${LIB_EXEC_INFO})
|
||||
endif()
|
||||
elseif((NOT USE_EXECINFO_STACKTRACE) AND USE_BOOST_STACKTRACE)
|
||||
set(Boost_USE_STATIC_LIBS OFF)
|
||||
set(Boost_USE_STATIC_RUNTIME OFF) # Do not require static C++ runtime
|
||||
set(Boost_USE_MULTITHREADED ON)
|
||||
find_package(Boost 1.82.0 COMPONENTS system filesystem REQUIRED)
|
||||
|
||||
|
||||
if (Boost_FOUND)
|
||||
add_definitions(-DBOOST_STACKTRACER=1)
|
||||
add_definitions(-DBOOST_STACKTRACE_USE_ADDR2LINE=1)
|
||||
|
||||
include_directories(${Boost_INCLUDE_DIRS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ENABLE_TESTS)
|
||||
if (NOT USE_SYSTEM_CATCH2)
|
||||
FetchContent_Declare(
|
||||
Catch2
|
||||
URL https://github.com/catchorg/Catch2/archive/refs/tags/v3.4.0.zip
|
||||
URL_HASH MD5=c426e77d4ee0055410bc930182959ae5
|
||||
)
|
||||
FetchContent_MakeAvailable(Catch2)
|
||||
endif()
|
||||
|
||||
FetchContent_Declare(
|
||||
FakeIt
|
||||
URL https://github.com/eranpeer/FakeIt/archive/refs/tags/2.4.0.zip
|
||||
URL_HASH MD5=72e4ce7f1c0de97074d2d5b517753286
|
||||
)
|
||||
FetchContent_MakeAvailable(FakeIt)
|
||||
|
||||
if (TARGET Catch2::Catch2)
|
||||
set_target_properties(Catch2::Catch2 PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
)
|
||||
endif()
|
||||
|
||||
if (TARGET Catch2::Catch2WithMain)
|
||||
set_target_properties(Catch2::Catch2WithMain PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
)
|
||||
endif()
|
||||
if (TARGET FakeIt::FakeIt-catch)
|
||||
set(FakeIt_INCLUDE_DIRS "${FakeIt_SOURCE_DIR}/single_header/catch")
|
||||
endif()
|
||||
|
||||
list(APPEND cmake_module_path ${Catch2_source_dir}/extras)
|
||||
endif()
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_definitions(-DDEBUG=1)
|
||||
endif()
|
||||
|
||||
# Set output directories for build targets
|
||||
set(OUTPUT_DIR ${CMAKE_BINARY_DIR}/out)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR}/bin)
|
||||
|
||||
# Include directories
|
||||
#include_directories(${CMAKE_SOURCE_DIR}/src)
|
||||
include_directories(${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
include_directories(${Elemental_CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
# Add a target to copy application resource files to the build dir
|
||||
add_custom_target(copy_assets
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${OUTPUT_DIR}/share/data
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${Elemental_ARTIFACT_DIR}/share/data
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_LIST_DIR}/data ${CMAKE_BINARY_DIR}/tests/data
|
||||
)
|
||||
|
||||
# Add subdirectories
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(demo)
|
||||
add_subdirectory(apps)
|
||||
#add_subdirectory(demo)
|
||||
#add_subdirectory(apps)
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
|
46
cmake/BuildProperties.cmake
Normal file
46
cmake/BuildProperties.cmake
Normal file
@ -0,0 +1,46 @@
|
||||
# BuildProperties.cmake
|
||||
# Copyright (c) 2024 Saul D Beniquez
|
||||
# License: MIT
|
||||
#
|
||||
# This module defines a function prevent_in_source_build() that prevents in-source builds
|
||||
# and sets a policy for CMake version 3.24.0 and above.
|
||||
|
||||
function(prevent_in_source_build)
|
||||
# Prevent in-source builds
|
||||
if (CMAKE_BINARY_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
message(FATAL_ERROR "Source and build directories cannot be the same.")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(set_artifact_dir path)
|
||||
# Set local variable, not necessary to be parent scope since it's not used outside this function
|
||||
set(ARTIFACT_DIR "${path}")
|
||||
|
||||
# Set project-specific artifact directory in parent scope
|
||||
set(${PROJECT_NAME}_ARTIFACT_DIR "${path}" PARENT_SCOPE)
|
||||
|
||||
# Set output directories in parent scope using the provided path directly
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${path}/lib" PARENT_SCOPE)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${path}/lib" PARENT_SCOPE)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${path}/bin" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
|
||||
function(disable_deprecated_features)
|
||||
# Use new timestamp behavior when extracting files archives
|
||||
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0")
|
||||
cmake_policy(SET CMP0135 NEW)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(disable_tests_if_subproject)
|
||||
if (NOT DEFINED PROJECT_NAME)
|
||||
option(BUILD_TESTING "Build and run unit tests" ON)
|
||||
else()
|
||||
option(BUILD_TESTING "Build and run unit tests" OFF)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
# vim: ts=4 sts=4 sw=4 noet :
|
24
cmake/CPM.cmake
Normal file
24
cmake/CPM.cmake
Normal file
@ -0,0 +1,24 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors
|
||||
|
||||
set(CPM_DOWNLOAD_VERSION 0.38.7)
|
||||
set(CPM_HASH_SUM "83e5eb71b2bbb8b1f2ad38f1950287a057624e385c238f6087f94cdfc44af9c5")
|
||||
|
||||
if(CPM_SOURCE_CACHE)
|
||||
set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||
elseif(DEFINED ENV{CPM_SOURCE_CACHE})
|
||||
set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||
else()
|
||||
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
|
||||
endif()
|
||||
|
||||
# Expand relative path. This is important if the provided path contains a tilde (~)
|
||||
get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE)
|
||||
|
||||
file(DOWNLOAD
|
||||
https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
|
||||
${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM}
|
||||
)
|
||||
|
||||
include(${CPM_DOWNLOAD_LOCATION})
|
@ -59,23 +59,11 @@ Phong::run() -> int
|
||||
{
|
||||
this->is_running = true;
|
||||
try {
|
||||
LoopRegulator frame_regulator(60_Hz);
|
||||
|
||||
this->running_threads["simulation_thread"] =
|
||||
std::thread([this]() { this->simulation_thread_loop(); });
|
||||
|
||||
while (this->is_running) {
|
||||
frame_regulator.startUpdate();
|
||||
this->video_renderer.clearScreen();
|
||||
|
||||
this->event_emitter.pollEvents();
|
||||
|
||||
auto cycle_delay_ms = frame_regulator.delay();
|
||||
print_cycle_rate(cycle_delay_ms, "frame delay");
|
||||
video_renderer.flip();
|
||||
}
|
||||
|
||||
this->is_running = false;
|
||||
this->event_and_rendering_loop();
|
||||
|
||||
/* threading clean-up:
|
||||
* wait for all child threads to finish */
|
||||
@ -142,6 +130,25 @@ Phong::Phong()
|
||||
this->event_emitter.pollEvents();
|
||||
}
|
||||
|
||||
void
|
||||
Phong::event_and_rendering_loop()
|
||||
{
|
||||
LoopRegulator frame_regulator(60_Hz);
|
||||
|
||||
do {
|
||||
frame_regulator.startUpdate();
|
||||
this->video_renderer.clearScreen();
|
||||
|
||||
this->event_emitter.pollEvents();
|
||||
|
||||
auto cycle_delay_ms = frame_regulator.delay();
|
||||
print_cycle_rate(cycle_delay_ms, "frame delay");
|
||||
video_renderer.flip();
|
||||
} while (this->is_running);
|
||||
|
||||
this->is_running = false;
|
||||
}
|
||||
|
||||
void
|
||||
Phong::simulation_thread_loop()
|
||||
{
|
||||
@ -150,7 +157,7 @@ Phong::simulation_thread_loop()
|
||||
do {
|
||||
loop_regulator.startUpdate();
|
||||
|
||||
this->event_emitter.transmitEvents();
|
||||
this->event_emitter.sendEvents();
|
||||
|
||||
auto cycle_delay_ms = loop_regulator.delay();
|
||||
print_cycle_rate(cycle_delay_ms);
|
||||
|
@ -65,6 +65,8 @@ class Phong
|
||||
bool is_running{ false };
|
||||
|
||||
Dictionary<std::thread> running_threads;
|
||||
|
||||
void event_and_rendering_loop();
|
||||
void simulation_thread_loop();
|
||||
|
||||
IRenderer& video_renderer;
|
||||
|
@ -1,58 +0,0 @@
|
||||
/* Application.hpp
|
||||
* Copyright © 2023 Saul D. Beniquez
|
||||
* License: Mozilla Public License v. 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
* v.2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
* obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "IApplication.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace elemental {
|
||||
class Application : public IApplication // NOLINT
|
||||
{
|
||||
public:
|
||||
~Application() override = default;
|
||||
|
||||
auto init(int argc, c::const_string argv[], c::const_string envp[])
|
||||
-> void override;
|
||||
|
||||
auto run() -> int override = 0;
|
||||
|
||||
[[nodiscard]] inline auto getArguments() const
|
||||
-> const std::vector<std::string>& override
|
||||
{
|
||||
return this->arguments;
|
||||
}
|
||||
[[nodiscard]] inline auto getEnvironment() const
|
||||
-> const Dictionary<const std::string>& override
|
||||
{
|
||||
return this->environment_variables;
|
||||
}
|
||||
|
||||
protected:
|
||||
Application();
|
||||
Application(const IApplication&) = delete;
|
||||
Application(IApplication&&) = delete;
|
||||
auto operator=(const IApplication&) -> Application& = delete;
|
||||
auto operator=(IApplication&&) -> Application& = delete;
|
||||
|
||||
void read_arguments(int argc, c::const_string argv[]);
|
||||
void create_env_dictionary(c::const_string envp[]);
|
||||
|
||||
std::vector<std::string> arguments;
|
||||
Dictionary<const std::string> environment_variables;
|
||||
};
|
||||
|
||||
} // namespace elemental
|
||||
|
||||
// clang-format off
|
||||
// vim: set foldmethod=syntax textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
@ -19,6 +19,7 @@ struct Component
|
||||
{
|
||||
public:
|
||||
using TypeInfo = std::type_index;
|
||||
|
||||
// using EntityId = unsigned int;
|
||||
using InstanceID = unsigned int;
|
||||
|
||||
@ -26,11 +27,11 @@ struct Component
|
||||
|
||||
virtual ~Component() = default;
|
||||
|
||||
inline auto getInstanceId() const -> InstanceID { return instance_id; }
|
||||
auto getInstanceId() const -> InstanceID { return instance_id; }
|
||||
virtual auto getTypeIndex() -> TypeInfo = 0;
|
||||
|
||||
template<typename T_>
|
||||
inline static auto isChildClass() -> bool
|
||||
static auto isChildClass() -> bool
|
||||
{
|
||||
static_assert(std::is_base_of_v<Component, T_>,
|
||||
"T must be a derived class of Component");
|
||||
@ -52,7 +53,7 @@ struct Component
|
||||
static unsigned int next_instance_id;
|
||||
};
|
||||
|
||||
inline unsigned int Component::next_instance_id = 0;
|
||||
unsigned int Component::next_instance_id = 0;
|
||||
|
||||
} // namespace elemental
|
||||
// clang-format off
|
||||
|
@ -1,84 +0,0 @@
|
||||
/* exceptions.hpp
|
||||
* Copyright © 2020 Saul D. Beniquez
|
||||
* License: Mozilla Public License v. 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#define ASSERT(condition) \
|
||||
if (condition == false) { \
|
||||
elemental::assert_impl(#condition); \
|
||||
}
|
||||
|
||||
#define ASSERT_MSG(condition, msg) \
|
||||
if (condition == false) { \
|
||||
elemental::assert_impl(#condition, msg); \
|
||||
}
|
||||
|
||||
namespace elemental {
|
||||
|
||||
class Exception : public std::exception
|
||||
{
|
||||
|
||||
public:
|
||||
Exception(c::const_string message = kDEFAULT_ERROR);
|
||||
Exception(std::string message);
|
||||
|
||||
Exception(const elemental::Exception& other) = default;
|
||||
Exception(const std::exception& inner);
|
||||
|
||||
auto operator=(const Exception&) -> Exception& = delete;
|
||||
|
||||
auto what() const noexcept -> const char* override;
|
||||
auto stacktrace() const noexcept -> const std::string&;
|
||||
|
||||
constexpr static auto kDEFAULT_ERROR = "An exception has ocurred!";
|
||||
|
||||
protected:
|
||||
void build_what_message(c::const_string class_name = "",
|
||||
c::const_string optional_data = "");
|
||||
|
||||
private:
|
||||
std::string error_message;
|
||||
std::string what_message;
|
||||
std::string stack_trace;
|
||||
|
||||
std::exception_ptr inner_exception_ptr;
|
||||
};
|
||||
|
||||
struct NotImplementedException : public Exception
|
||||
{
|
||||
NotImplementedException() : Exception("Method not implemented") {}
|
||||
~NotImplementedException() override = default;
|
||||
};
|
||||
|
||||
void inline assert_impl(c::const_string failed_condition,
|
||||
c::const_string assert_reason = "")
|
||||
{
|
||||
std::stringstream assert_buffer;
|
||||
assert_buffer << failed_condition << " is false!";
|
||||
|
||||
if (std::strlen(assert_reason) > 0) {
|
||||
assert_buffer << std::endl
|
||||
<< "\tassert_resion: " << assert_reason;
|
||||
}
|
||||
assert_buffer << std::flush;
|
||||
throw Exception(assert_buffer.str());
|
||||
}
|
||||
} // namespace elemental
|
||||
// clang-format off
|
||||
// vim: set foldmethod=marker foldmarker=\{,\} textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
@ -16,8 +16,7 @@
|
||||
#include <fstream>
|
||||
|
||||
namespace elemental {
|
||||
enum class CreateDirs : bool
|
||||
{
|
||||
enum class CreateDirs : bool {
|
||||
Default = false,
|
||||
Disable = false,
|
||||
Disabled = false,
|
||||
@ -25,29 +24,29 @@ enum class CreateDirs : bool
|
||||
Enabled = true
|
||||
};
|
||||
|
||||
class FileResource
|
||||
{
|
||||
public:
|
||||
FileResource(const std::filesystem::path& file_path,
|
||||
CreateDirs mode = CreateDirs::Default);
|
||||
class FileResource {
|
||||
public:
|
||||
FileResource(
|
||||
const std::filesystem::path& file_path,
|
||||
CreateDirs mode = CreateDirs::Default
|
||||
);
|
||||
|
||||
virtual ~FileResource() = default;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
std::filesystem::path file_path;
|
||||
};
|
||||
|
||||
struct UnreachablePathException : public Exception
|
||||
{
|
||||
inline UnreachablePathException(const std::filesystem::path& path)
|
||||
: Exception("Unreachable path or directory")
|
||||
, unreachable_path(path)
|
||||
struct UnreachablePathException : public IOCore::Exception {
|
||||
UnreachablePathException(const std::filesystem::path& path)
|
||||
: Exception("Unreachable path or directory"), unreachable_path(path)
|
||||
{
|
||||
this->build_what_message("elemental::UnreachablePathException",
|
||||
path.c_str());
|
||||
this->build_what_message(
|
||||
"elemental::UnreachablePathException", path.c_str()
|
||||
);
|
||||
}
|
||||
|
||||
auto inline what() const noexcept -> const char* override
|
||||
auto what() const noexcept -> const char* override
|
||||
{
|
||||
return Exception::what();
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
/* IApplication.hpp
|
||||
* Copyright © 2023 Saul D. Beniquez
|
||||
* License: Mozilla Public License v. 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
* v.2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
* obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace elemental {
|
||||
|
||||
struct IApplication;
|
||||
using IApplicationRef = std::reference_wrapper<IApplication>;
|
||||
|
||||
class IApplication
|
||||
{
|
||||
public:
|
||||
virtual ~IApplication() = default;
|
||||
|
||||
virtual auto init(int argc, c::const_string argv[],
|
||||
c::const_string envp[]) -> void = 0;
|
||||
virtual auto run() -> int = 0;
|
||||
|
||||
[[nodiscard]] virtual auto getArguments() const
|
||||
-> const std::vector<std::string>& = 0;
|
||||
[[nodiscard]] virtual auto getEnvironment() const
|
||||
-> const Dictionary<const std::string>& = 0;
|
||||
|
||||
protected:
|
||||
IApplication() {}
|
||||
};
|
||||
|
||||
} // namespace elemental
|
||||
|
||||
// clang-format off
|
||||
// vim: set foldmethod=syntax textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
@ -18,14 +18,12 @@ struct IDrawable
|
||||
{
|
||||
virtual ~IDrawable(){};
|
||||
|
||||
inline void Draw(Position& pos)
|
||||
{
|
||||
this->Draw(Area{ pos.x, pos.y, 0, 0 });
|
||||
}
|
||||
virtual void Draw(const Area& rect) = 0;
|
||||
virtual void draw(const Rectangle& rect) = 0;
|
||||
|
||||
void draw(Position2D& pos) { this->draw(Rectangle{ pos.x, pos.y }); }
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace elemental
|
||||
|
||||
// clang-format off
|
||||
// vim: set foldmethod=syntax textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
||||
|
@ -24,8 +24,8 @@ struct IEventSource
|
||||
, private INonCopyable
|
||||
{
|
||||
~IEventSource() override = default;
|
||||
virtual auto pollEvents() -> void = 0;
|
||||
virtual auto transmitEvents() -> void = 0;
|
||||
virtual void pollEvents() = 0;
|
||||
virtual void sendEvents() = 0;
|
||||
|
||||
protected:
|
||||
explicit IEventSource(InputDevices device_flags) {}
|
||||
|
@ -41,10 +41,7 @@ class JsonConfigFile : public FileResource
|
||||
config_json = value;
|
||||
}
|
||||
|
||||
inline auto getJsonData() -> nlohmann::json&
|
||||
{
|
||||
return this->config_json;
|
||||
};
|
||||
auto getJsonData() -> nlohmann::json& { return this->config_json; };
|
||||
|
||||
protected:
|
||||
nlohmann::json config_json;
|
||||
|
@ -52,23 +52,23 @@ namespace elemental {
|
||||
* automatically manage resource SDL resources. */
|
||||
struct SdlResourceDeleter
|
||||
{
|
||||
inline auto operator()(SDL_Window* window_ptr) -> void
|
||||
auto operator()(SDL_Window* window_ptr) -> void
|
||||
{
|
||||
SDL_DestroyWindow(window_ptr);
|
||||
}
|
||||
inline auto operator()(SDL_Renderer* renderer_ptr) -> void
|
||||
auto operator()(SDL_Renderer* renderer_ptr) -> void
|
||||
{
|
||||
SDL_DestroyRenderer(renderer_ptr);
|
||||
}
|
||||
inline auto operator()(SDL_Surface* surface_ptr) -> void
|
||||
auto operator()(SDL_Surface* surface_ptr) -> void
|
||||
{
|
||||
SDL_FreeSurface(surface_ptr);
|
||||
}
|
||||
inline auto operator()(SDL_Texture* texture_ptr) -> void
|
||||
auto operator()(SDL_Texture* texture_ptr) -> void
|
||||
{
|
||||
SDL_DestroyTexture(texture_ptr);
|
||||
}
|
||||
inline auto operator()(SDL_Joystick* joystick_ptr) -> void
|
||||
auto operator()(SDL_Joystick* joystick_ptr) -> void
|
||||
{
|
||||
SDL_JoystickClose(joystick_ptr);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ namespace elemental {
|
||||
class SdlEventSource : public IEventSource
|
||||
{
|
||||
TEST_INSPECTABLE(SdlEventSource);
|
||||
|
||||
public:
|
||||
using Mutex = std::mutex;
|
||||
using MutexLock = std::lock_guard<Mutex>;
|
||||
@ -39,8 +40,8 @@ class SdlEventSource : public IEventSource
|
||||
|
||||
~SdlEventSource() override = default;
|
||||
|
||||
auto pollEvents() -> void override;
|
||||
auto transmitEvents() -> void override;
|
||||
void pollEvents() override;
|
||||
void sendEvents() override;
|
||||
|
||||
protected:
|
||||
std::queue<SDL_Event> event_queue;
|
||||
|
@ -12,34 +12,33 @@ namespace elemental {
|
||||
|
||||
namespace platform {
|
||||
|
||||
enum platform_t
|
||||
{ // NOLINTBEGIN
|
||||
kUNKNOWN = 0b0000,
|
||||
kWINDOWS = 0b0001,
|
||||
kUNIX = 0b0100,
|
||||
kLINUX = 0b0101,
|
||||
kFREEBSD = 0b0110,
|
||||
kMACOS = 0b0111
|
||||
}; // NOLINTEND
|
||||
enum platform_t { // NOLINTBEGIN
|
||||
kUNKNOWN = 0b0000,
|
||||
kWINDOWS = 0b0001,
|
||||
kUNIX = 0b0100,
|
||||
kLINUX = 0b0101,
|
||||
kFREEBSD = 0b0110,
|
||||
kMACOS = 0b0111
|
||||
}; // NOLINTEND
|
||||
|
||||
#ifdef __linux__
|
||||
static const platform_t kCurrentPlatform = kLINUX;
|
||||
static const platform_t kCurrentPlatform = kLINUX;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
static const platform_t kCurrentPlatform = kWINDOWS;
|
||||
static const platform_t kCurrentPlatform = kWINDOWS;
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
static const platform_t kCurrentPlatform = kMACOS;
|
||||
static const platform_t kCurrentPlatform = kMACOS;
|
||||
#endif
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
static const platform_t kCurrentPlatform = kFREEBSD;
|
||||
static const platform_t kCurrentPlatform = kFREEBSD;
|
||||
#endif
|
||||
|
||||
// I don't own any AIX, Solaris, HP-UX, or pure Darwin systems, sorry :)
|
||||
// To be added at a later date.
|
||||
// I don't own any AIX, Solaris, HP-UX, or pure Darwin systems, sorry :)
|
||||
// To be added at a later date.
|
||||
|
||||
}; // namespace platform
|
||||
} // namespace elemental
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "types/containers.hpp"
|
||||
#include "types/errors.hpp"
|
||||
#include "types/legible_ctypes.hpp"
|
||||
// #include "types/legible_ctypes.hpp"
|
||||
#include "types/pointers.hpp"
|
||||
|
||||
// clang-format off
|
||||
|
@ -1,23 +0,0 @@
|
||||
/* containers.hpp
|
||||
* Copyright © 2024 Saul D. Beniquez
|
||||
* License: Mozilla Public License v. 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
* v.2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
* obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace elemental {
|
||||
|
||||
/// \brief Convenience for std::map objects where the key is always a string.
|
||||
template<typename TValueT>
|
||||
using Dictionary = std::unordered_map<std::string, TValueT>;
|
||||
} // namespace elemental
|
||||
|
||||
// clang-format off
|
||||
// vim: set foldmethod=syntax textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
@ -1,24 +0,0 @@
|
||||
/* legible_ctypes.hpp
|
||||
* Copyright © 2023-2024 Saul D. Beniquez
|
||||
* License: Mozilla Public License v. 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
* v.2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
* obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
/*! \name Aliases for C-types that are unclear.
|
||||
* The C type char* does not immediately scream "STRING", and
|
||||
* socket libraries return `int`, rather than a typedef socket_fd_t. */
|
||||
namespace elemental::c {
|
||||
using string = char*;
|
||||
using const_string = const char*;
|
||||
using count_t = size_t;
|
||||
} // namespace elemental::c
|
||||
|
||||
// clang-format off
|
||||
// vim: set foldmethod=syntax textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
@ -32,22 +32,15 @@ using Resolution = Area;
|
||||
|
||||
struct Rectangle
|
||||
{
|
||||
union
|
||||
{
|
||||
Point position;
|
||||
struct
|
||||
{
|
||||
uint32_t x, y;
|
||||
};
|
||||
};
|
||||
union
|
||||
{
|
||||
Area size;
|
||||
struct
|
||||
{
|
||||
uint32_t width, height;
|
||||
};
|
||||
};
|
||||
Point position;
|
||||
Area size;
|
||||
|
||||
uint32_t& x = position.x;
|
||||
uint32_t& y = position.y;
|
||||
|
||||
uint32_t& width = size.width;
|
||||
uint32_t& height = size.height;
|
||||
|
||||
SERIALIZABLE(Rectangle, position, size);
|
||||
};
|
||||
|
||||
|
@ -1,75 +0,0 @@
|
||||
/* Application.cpp
|
||||
* Copyright © 2023 Saul D. Beniquez
|
||||
* License: Mozilla Public License v. 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
* v.2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
* obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "Exception.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace elemental;
|
||||
|
||||
void
|
||||
Application::init(int argc, c::const_string argv[], c::const_string envp[])
|
||||
{
|
||||
if (argv == nullptr || envp == nullptr) {
|
||||
std::string problem = (argv == nullptr) ? "argv " : "envp ";
|
||||
auto message = "Cannot instantiate the application class "
|
||||
"with null " +
|
||||
problem + "parameter";
|
||||
|
||||
auto fatal_exception = std::logic_error(message);
|
||||
throw elemental::Exception(fatal_exception);
|
||||
}
|
||||
|
||||
this->read_arguments(argc, argv);
|
||||
this->create_env_dictionary(envp);
|
||||
}
|
||||
|
||||
Application::Application()
|
||||
: IApplication()
|
||||
, arguments()
|
||||
, environment_variables()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Application::read_arguments(int argc, c::const_string argv[])
|
||||
{
|
||||
for (c::count_t index = 0; index < argc; ++index) {
|
||||
this->arguments.emplace_back(argv[index]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Application::create_env_dictionary(c::const_string envp[])
|
||||
{
|
||||
for (c::count_t num = 0; envp[num] != nullptr; ++num) {
|
||||
auto encoded_pair = std::string_view(envp[num]);
|
||||
|
||||
size_t equal_character_pos;
|
||||
auto not_found = encoded_pair.npos;
|
||||
|
||||
equal_character_pos = encoded_pair.find('=');
|
||||
if (equal_character_pos != not_found) {
|
||||
auto key = std::string(
|
||||
encoded_pair.substr(0, equal_character_pos));
|
||||
auto val = std::string(
|
||||
encoded_pair.substr(equal_character_pos + 1));
|
||||
|
||||
this->environment_variables.insert(
|
||||
std::make_pair(key, val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
// vim: set foldmethod=marker foldmarker=#region,#endregion textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
@ -1,14 +1,11 @@
|
||||
# Define the library 'engine'
|
||||
set(ELEMENTAL_SOURCES
|
||||
debuginfo.cpp
|
||||
Exception.cpp
|
||||
Application.cpp
|
||||
SdlRenderer.cpp
|
||||
LoopRegulator.cpp
|
||||
Observable.cpp
|
||||
SdlEventSource.cpp
|
||||
FileResource.cpp
|
||||
JsonConfigFile.cpp
|
||||
LoopRegulator.cpp
|
||||
Observable.cpp
|
||||
SdlRenderer.cpp
|
||||
SdlEventSource.cpp
|
||||
paths.cpp
|
||||
)
|
||||
|
||||
@ -21,14 +18,16 @@ target_include_directories(elemental SYSTEM BEFORE
|
||||
|
||||
# Add a target to copy this project's header files to the build dir
|
||||
add_custom_target(include_files
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/include ${OUTPUT_DIR}/include
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${Elemental_CMAKE_SOURCE_DIR}/include ${Elemental_ARTIFACT_DIR}/include
|
||||
)
|
||||
add_dependencies(elemental include_files)
|
||||
|
||||
set(ELEMENTAL_LINK_DEPS
|
||||
IOCore::IOCoreStatic
|
||||
Threads::Threads
|
||||
${SDL2_COMBINED_LINK_DEPS}
|
||||
${STACKTRACE_DEP_LIBS}
|
||||
${NLOHMANN_JSON_LIBS}
|
||||
)
|
||||
|
||||
# Add additional link options for boost::stacktrace
|
||||
@ -40,16 +39,4 @@ endif()
|
||||
# Also get the same dependencies.
|
||||
target_link_libraries(elemental PUBLIC ${ELEMENTAL_LINK_DEPS})
|
||||
|
||||
#if (ENABLE_TESTS)
|
||||
# if (USE_BOOST_STACKTRACE)
|
||||
# target_link_options(elemental-testing PUBLIC -rdynamic)
|
||||
# endif()
|
||||
# target_link_libraries(elemental-testing PUBLIC ${ELEMENTAL_LINK_DEPS})
|
||||
#
|
||||
# # Define a preprocessor flag to enable helper code for unit-testing
|
||||
# # This flag will propagate to programs that link to this library (PUBLIC)
|
||||
# #target_compile_definitions(elemental-testing PUBLIC -DUNIT_TEST=1)
|
||||
#
|
||||
#endif()
|
||||
|
||||
# vim: ts=4 sw=4 noet foldmethod=indent :
|
||||
|
@ -1,121 +0,0 @@
|
||||
/* exceptions.hpp
|
||||
* Copyright © 2020 Saul D. Beniquez
|
||||
* License: Mozilla Public License v. 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "Exception.hpp"
|
||||
|
||||
#include "sys/debuginfo.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
using elemental::Exception;
|
||||
|
||||
constexpr unsigned kDEFAULT_STACKFRAMES_TO_STRIP = 3;
|
||||
|
||||
// Helper classes and functions. #region
|
||||
|
||||
Exception::Exception(c::const_string error_message)
|
||||
: std::exception()
|
||||
, error_message(error_message)
|
||||
, what_message()
|
||||
, stack_trace(elemental::generate_stacktrace(kDEFAULT_STACKFRAMES_TO_STRIP))
|
||||
, inner_exception_ptr()
|
||||
{
|
||||
build_what_message();
|
||||
}
|
||||
|
||||
Exception::Exception(std::string error_message)
|
||||
: std::exception()
|
||||
, error_message(std::move(error_message))
|
||||
, what_message()
|
||||
, stack_trace(elemental::generate_stacktrace(kDEFAULT_STACKFRAMES_TO_STRIP))
|
||||
, inner_exception_ptr()
|
||||
{
|
||||
build_what_message();
|
||||
}
|
||||
|
||||
Exception::Exception(const std::exception& inner)
|
||||
: std::exception(inner)
|
||||
, error_message(inner.what())
|
||||
, what_message()
|
||||
, inner_exception_ptr(std::make_exception_ptr(&inner))
|
||||
, stack_trace(elemental::generate_stacktrace(kDEFAULT_STACKFRAMES_TO_STRIP))
|
||||
{
|
||||
build_what_message();
|
||||
}
|
||||
|
||||
auto
|
||||
Exception::what() const noexcept -> const char*
|
||||
{
|
||||
return this->what_message.c_str();
|
||||
}
|
||||
|
||||
auto
|
||||
Exception::stacktrace() const noexcept -> const std::string&
|
||||
{
|
||||
return this->stack_trace;
|
||||
}
|
||||
|
||||
auto
|
||||
prepend_tabs_to_lines(const std::string& input) -> std::string
|
||||
{
|
||||
std::ostringstream results_buffer;
|
||||
std::istringstream input_buffer(input);
|
||||
|
||||
// Function to add a tab character before each line
|
||||
auto add_tab_before_line = [&results_buffer](const std::string& line) {
|
||||
results_buffer << '\t' << line << '\n';
|
||||
};
|
||||
|
||||
// Process each line and add a tab character before it
|
||||
std::string line;
|
||||
while (std::getline(input_buffer, line)) {
|
||||
add_tab_before_line(line);
|
||||
}
|
||||
|
||||
return results_buffer.str();
|
||||
}
|
||||
void
|
||||
Exception::build_what_message(c::const_string class_name,
|
||||
c::const_string optional_data)
|
||||
{
|
||||
|
||||
std::string my_name(class_name);
|
||||
std::stringstream buffer;
|
||||
|
||||
if (my_name.empty()) {
|
||||
my_name = "elemental::Exception";
|
||||
};
|
||||
|
||||
std::string indented_stacktrace =
|
||||
prepend_tabs_to_lines(this->stack_trace);
|
||||
|
||||
buffer << my_name << "::what(): { " << std::endl
|
||||
<< "\terror: " << error_message.c_str() << std::endl;
|
||||
|
||||
if (std::strlen(optional_data) > 0) {
|
||||
buffer << "\tdata: " << optional_data << std::endl;
|
||||
}
|
||||
|
||||
buffer << "\tstack_trace: " << std::endl
|
||||
<< indented_stacktrace << std::endl
|
||||
<< "};" << std::endl;
|
||||
|
||||
this->what_message = buffer.str().c_str();
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
// vim: set foldmethod=marker foldmarker=\{,\} textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
@ -39,14 +39,15 @@ FileResource::FileResource(const fs::path& file_path, CreateDirs mode)
|
||||
|
||||
if (fs::exists(file_path) == false) {
|
||||
std::ofstream file_stream(
|
||||
file_path, std::ios::out | std::ios::trunc);
|
||||
file_path, std::ios::out | std::ios::trunc
|
||||
);
|
||||
file_stream.flush();
|
||||
file_stream.close();
|
||||
}
|
||||
} catch (elemental::Exception&) {
|
||||
} catch (IOCore::Exception&) {
|
||||
throw;
|
||||
} catch (std::exception& exception) {
|
||||
throw Exception(exception);
|
||||
throw IOCore::Exception(exception);
|
||||
}
|
||||
};
|
||||
// clang-format off
|
||||
|
@ -26,14 +26,12 @@ namespace fs = std::filesystem;
|
||||
namespace {
|
||||
static std::stringstream error_buffer;
|
||||
|
||||
enum IndentMode : int
|
||||
{
|
||||
enum IndentMode : int {
|
||||
Compact = -1,
|
||||
NewlinesOnly = 0,
|
||||
Ident = 1,
|
||||
};
|
||||
enum AsciiMode : bool
|
||||
{
|
||||
enum AsciiMode : bool {
|
||||
Default = false,
|
||||
Raw = false,
|
||||
IgnoreUnicode = false,
|
||||
@ -50,8 +48,7 @@ JsonConfigFile::JsonConfigFile(const fs::path& file_path, CreateDirs mode)
|
||||
|
||||
JsonConfigFile::~JsonConfigFile() = default;
|
||||
|
||||
auto
|
||||
JsonConfigFile::read() -> nlohmann::json&
|
||||
auto JsonConfigFile::read() -> nlohmann::json&
|
||||
{
|
||||
try {
|
||||
std::ifstream file_stream(file_path);
|
||||
@ -61,27 +58,26 @@ JsonConfigFile::read() -> nlohmann::json&
|
||||
error_buffer
|
||||
<< "Error opening JsonConfigFile for reading: "
|
||||
<< file_path << std::endl;
|
||||
throw Exception(error_buffer.str());
|
||||
throw IOCore::Exception(error_buffer.str());
|
||||
}
|
||||
|
||||
// If the file is empty, do not try to open it and parse JSON
|
||||
if (file_stream.peek() != std::ifstream::traits_type::eof()) {
|
||||
file_stream >> config_json;
|
||||
}
|
||||
} catch (elemental::Exception& except) {
|
||||
} catch (IOCore::Exception& except) {
|
||||
throw;
|
||||
} catch (const std::exception& e) {
|
||||
error_buffer.str("");
|
||||
error_buffer << "JsonConfigFile::Read() error" << std::endl
|
||||
<< e.what() << std::flush;
|
||||
throw Exception(error_buffer.str());
|
||||
throw IOCore::Exception(error_buffer.str());
|
||||
}
|
||||
|
||||
return this->config_json;
|
||||
}
|
||||
|
||||
void
|
||||
JsonConfigFile::write()
|
||||
void JsonConfigFile::write()
|
||||
{
|
||||
try {
|
||||
std::ofstream file_stream(file_path);
|
||||
@ -90,24 +86,26 @@ JsonConfigFile::write()
|
||||
error_buffer << "Error opening JsonConfigFile "
|
||||
"for writing: "
|
||||
<< file_path << std::endl;
|
||||
throw Exception(error_buffer.str());
|
||||
throw IOCore::Exception(error_buffer.str());
|
||||
}
|
||||
|
||||
file_stream
|
||||
<< config_json.dump(
|
||||
IndentMode::Ident, '\t', AsciiMode::IgnoreUnicode,
|
||||
nlohmann::json::error_handler_t::replace)
|
||||
<< std::endl;
|
||||
file_stream << config_json.dump(
|
||||
IndentMode::Ident,
|
||||
'\t',
|
||||
AsciiMode::IgnoreUnicode,
|
||||
nlohmann::json::error_handler_t::replace
|
||||
)
|
||||
<< std::endl;
|
||||
|
||||
return;
|
||||
} catch (elemental::Exception& except) {
|
||||
} catch (IOCore::Exception& except) {
|
||||
throw;
|
||||
} catch (const std::exception& e) {
|
||||
|
||||
error_buffer.str("");
|
||||
error_buffer << "JSonConfigFile::Save() error: " << std::endl
|
||||
<< e.what() << std::flush;
|
||||
throw Exception(error_buffer.str());
|
||||
throw IOCore::Exception(error_buffer.str());
|
||||
}
|
||||
}
|
||||
} // namespace elemental::configuration
|
||||
|
@ -74,7 +74,7 @@ SdlEventSource::pollEvents() -> void
|
||||
}
|
||||
|
||||
auto
|
||||
SdlEventSource::transmitEvents() -> void
|
||||
SdlEventSource::sendEvents() -> void
|
||||
{
|
||||
auto thread_lock = MutexLock(this->mutex);
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "util/debug.hpp"
|
||||
|
||||
#include "types/input.hpp"
|
||||
#include "types/rendering.hpp"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
@ -30,11 +31,10 @@ namespace {
|
||||
std::stringstream error_buffer;
|
||||
} // namespace
|
||||
|
||||
#define HANDLE_SDL_ERROR(what) \
|
||||
error_buffer.str(""); \
|
||||
error_buffer << what << ", SDL Error:" << SDL_GetError() \
|
||||
<< std::flush; \
|
||||
throw elemental::Exception(error_buffer.str());
|
||||
#define HANDLE_SDL_ERROR(what) \
|
||||
error_buffer.str(""); \
|
||||
error_buffer << what << ", SDL Error:" << SDL_GetError() << std::flush; \
|
||||
throw IOCore::Exception(error_buffer.str());
|
||||
|
||||
SdlRenderer::~SdlRenderer()
|
||||
{
|
||||
@ -43,20 +43,20 @@ SdlRenderer::~SdlRenderer()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SdlRenderer::init(RendererSettings& settings)
|
||||
void SdlRenderer::init(RendererSettings& settings)
|
||||
{
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_TIMER | SDL_INIT_VIDEO) < 0) {
|
||||
HANDLE_SDL_ERROR("Could not initialize video subsystem");
|
||||
}
|
||||
if (kError == IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF |
|
||||
IMG_INIT_WEBP)) {
|
||||
if (kError ==
|
||||
IMG_Init(
|
||||
IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF | IMG_INIT_WEBP
|
||||
)) {
|
||||
error_buffer.str("");
|
||||
error_buffer
|
||||
<< "Could not initialize SDL_Image: IMG_INIT() == 0"
|
||||
<< std::flush;
|
||||
throw elemental::Exception(error_buffer.str());
|
||||
error_buffer << "Could not initialize SDL_Image: IMG_INIT() == 0"
|
||||
<< std::flush;
|
||||
throw IOCore::Exception(error_buffer.str());
|
||||
}
|
||||
int window_xpos, window_ypos, window_width, window_height, res_width,
|
||||
res_height;
|
||||
@ -81,21 +81,28 @@ SdlRenderer::init(RendererSettings& settings)
|
||||
sdl_flags |= SDL_WINDOW_FULLSCREEN;
|
||||
}
|
||||
|
||||
this->sdl_window_ptr =
|
||||
SDL_CreateWindow(window_title.c_str(), window_xpos, window_ypos,
|
||||
window_width, window_height, sdl_flags);
|
||||
this->sdl_window_ptr = SDL_CreateWindow(
|
||||
window_title.c_str(),
|
||||
window_xpos,
|
||||
window_ypos,
|
||||
window_width,
|
||||
window_height,
|
||||
sdl_flags
|
||||
);
|
||||
if (nullptr == this->sdl_window_ptr) {
|
||||
HANDLE_SDL_ERROR("Could not create SDL_Window");
|
||||
}
|
||||
|
||||
this->sdl_renderer_ptr = SDL_CreateRenderer(this->sdl_window_ptr, 0,
|
||||
SDL_RENDERER_ACCELERATED);
|
||||
this->sdl_renderer_ptr = SDL_CreateRenderer(
|
||||
this->sdl_window_ptr, 0, SDL_RENDERER_ACCELERATED
|
||||
);
|
||||
if (nullptr == this->sdl_renderer_ptr) {
|
||||
HANDLE_SDL_ERROR("Could not initialize SDL_Renderer");
|
||||
}
|
||||
|
||||
if (SDL_RenderSetLogicalSize(this->sdl_renderer_ptr, res_width,
|
||||
res_height)) {
|
||||
if (SDL_RenderSetLogicalSize(
|
||||
this->sdl_renderer_ptr, res_width, res_height
|
||||
)) {
|
||||
|
||||
HANDLE_SDL_ERROR("Could not set SDL_Renderer LogicalSize");
|
||||
}
|
||||
@ -103,8 +110,7 @@ SdlRenderer::init(RendererSettings& settings)
|
||||
this->is_initialized = true;
|
||||
}
|
||||
|
||||
void
|
||||
SdlRenderer::deactivate()
|
||||
void SdlRenderer::deactivate()
|
||||
{
|
||||
DBG_PRINT("SdlRenderer::Deactivate called!");
|
||||
if (this->sdl_window_ptr != nullptr) {
|
||||
@ -117,30 +123,28 @@ SdlRenderer::deactivate()
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
this->is_initialized = false;
|
||||
}
|
||||
auto
|
||||
SdlRenderer::isInitialized() -> bool
|
||||
auto SdlRenderer::isInitialized() -> bool
|
||||
{
|
||||
return this->is_initialized;
|
||||
};
|
||||
|
||||
auto
|
||||
SdlRenderer::getResolution() -> Resolution
|
||||
auto SdlRenderer::getResolution() -> Resolution
|
||||
{
|
||||
int width, height;
|
||||
|
||||
/* SDL does not seem to catch this condition sometimes */
|
||||
ASSERT(this->sdl_renderer_ptr.get() != nullptr)
|
||||
|
||||
if (kError == SDL_GetRendererOutputSize(this->sdl_renderer_ptr.get(),
|
||||
&width, &height)) {
|
||||
if (kError == SDL_GetRendererOutputSize(
|
||||
this->sdl_renderer_ptr.get(), &width, &height
|
||||
)) {
|
||||
HANDLE_SDL_ERROR("Could not get Renderer output size");
|
||||
}
|
||||
|
||||
return { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
|
||||
}
|
||||
|
||||
auto
|
||||
SdlRenderer::getWindowSize() -> Area
|
||||
auto SdlRenderer::getWindowSize() -> Area
|
||||
{
|
||||
int width, height;
|
||||
|
||||
@ -156,8 +160,7 @@ SdlRenderer::getWindowSize() -> Area
|
||||
return { static_cast<uint32_t>(width), static_cast<uint32_t>(height) };
|
||||
}
|
||||
|
||||
void
|
||||
SdlRenderer::clearScreen()
|
||||
void SdlRenderer::clearScreen()
|
||||
{
|
||||
ASSERT(this->sdl_renderer_ptr != nullptr);
|
||||
|
||||
@ -168,8 +171,7 @@ SdlRenderer::clearScreen()
|
||||
HANDLE_SDL_ERROR("Call to SDL_RenderClear failed!");
|
||||
}
|
||||
}
|
||||
void
|
||||
SdlRenderer::flip()
|
||||
void SdlRenderer::flip()
|
||||
{
|
||||
ASSERT(this->sdl_renderer_ptr != nullptr);
|
||||
|
||||
@ -178,33 +180,32 @@ SdlRenderer::flip()
|
||||
}
|
||||
|
||||
/*! \todo convert this to a private method, used internally to wrap SDL_Blit */
|
||||
void
|
||||
SdlRenderer::blit(std::shared_ptr<void> image_data, Rectangle& placement)
|
||||
void SdlRenderer::blit(std::shared_ptr<void> image_data, Rectangle& placement)
|
||||
{
|
||||
ASSERT(this->sdl_renderer_ptr != nullptr);
|
||||
ASSERT(image_data.get() != nullptr);
|
||||
|
||||
try {
|
||||
auto to_draw =
|
||||
std::static_pointer_cast<SDL_Texture>(image_data);
|
||||
auto to_draw = std::static_pointer_cast<SDL_Texture>(image_data);
|
||||
auto position = fromRectangle<SDL_Rect>(placement);
|
||||
|
||||
if (kError == SDL_RenderCopy(this->sdl_renderer_ptr.get(),
|
||||
to_draw.get(), nullptr,
|
||||
&position)) {
|
||||
if (kError == SDL_RenderCopy(
|
||||
this->sdl_renderer_ptr.get(),
|
||||
to_draw.get(),
|
||||
nullptr,
|
||||
&position
|
||||
)) {
|
||||
HANDLE_SDL_ERROR("SDL_RenderCopy failed.");
|
||||
}
|
||||
} catch (Exception& thrown_exception) {
|
||||
} catch (IOCore::Exception& thrown_exception) {
|
||||
throw;
|
||||
} catch (std::exception& thrown_exception) {
|
||||
throw Exception(thrown_exception);
|
||||
throw IOCore::Exception(thrown_exception);
|
||||
}
|
||||
}
|
||||
|
||||
SdlRenderer::SdlRenderer()
|
||||
: IRenderer()
|
||||
, sdl_window_ptr(nullptr)
|
||||
, sdl_renderer_ptr(nullptr)
|
||||
: IRenderer(), sdl_window_ptr(nullptr), sdl_renderer_ptr(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1,146 +0,0 @@
|
||||
/* debuginfo.h
|
||||
* Copyright © 2020-2023 Saul D. Beniquez
|
||||
* License: Mozilla Public License v. 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "sys/debuginfo.hpp"
|
||||
#include "sys/platform.hpp"
|
||||
|
||||
#if !defined(BOOST_STACKTRACER)
|
||||
#if defined(HAVE_EXECINFO_H)
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#include <cxxabi.h>
|
||||
#else
|
||||
#include <boost/stacktrace.hpp>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace elemental {
|
||||
namespace {
|
||||
|
||||
// Extracts the mangled symbol from a string like <func_name+0x34>
|
||||
auto extract_mangled_symbol(const std::string& input) -> std::string
|
||||
{
|
||||
std::string result;
|
||||
bool inside_angle_brackets = false;
|
||||
|
||||
for (char c : input) {
|
||||
if (c == '<') {
|
||||
inside_angle_brackets = true;
|
||||
continue;
|
||||
}
|
||||
if (c == '>') {
|
||||
inside_angle_brackets = false;
|
||||
continue;
|
||||
}
|
||||
if (c == '+') {
|
||||
break;
|
||||
}
|
||||
|
||||
if (inside_angle_brackets) {
|
||||
result += c;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// There are a lot of C and platform-specific hacks contained within
|
||||
// I am sorry. 🤡
|
||||
auto
|
||||
generate_stacktrace(unsigned short framesToRemove) -> std::string
|
||||
{
|
||||
using namespace elemental::platform;
|
||||
|
||||
std::stringstream buffer;
|
||||
|
||||
#ifndef BOOST_STACKTRACER
|
||||
void* callstack[128];
|
||||
int i, frames = backtrace(callstack, 128);
|
||||
char** strs = backtrace_symbols(callstack, frames);
|
||||
|
||||
size_t columns_to_print = 0;
|
||||
|
||||
// preconfigure column length for certain platforms
|
||||
if (platform::kCurrentPlatform == kFREEBSD) {
|
||||
columns_to_print = 2;
|
||||
} else if (platform::kCurrentPlatform == kMACOS) {
|
||||
columns_to_print = 4;
|
||||
}
|
||||
|
||||
if (framesToRemove == frames) {
|
||||
framesToRemove = 0;
|
||||
}
|
||||
|
||||
for (i = framesToRemove; i < frames; ++i) {
|
||||
std::string word;
|
||||
std::stringstream line_stream(strs[i]);
|
||||
std::vector<std::string> wordlist;
|
||||
|
||||
// Create a list of words for this stack trace line
|
||||
while (line_stream >> word) {
|
||||
if (columns_to_print != 0 &&
|
||||
(word.find('<') != word.npos &&
|
||||
word.find('>') != word.npos)) {
|
||||
auto extracted_symbol =
|
||||
extract_mangled_symbol(word);
|
||||
word = extracted_symbol;
|
||||
}
|
||||
wordlist.push_back(word);
|
||||
}
|
||||
// if columns_to_print is still 0, assign it to the list length
|
||||
// It is only pre-configured for certain platforms, see above
|
||||
if (!columns_to_print) {
|
||||
columns_to_print = wordlist.size();
|
||||
}
|
||||
// Process the extracted words one at a time and format the
|
||||
// stack trace string
|
||||
for (unsigned pos = 0; pos < columns_to_print; ++pos) {
|
||||
auto word = wordlist[pos];
|
||||
int status;
|
||||
|
||||
char* demangled_symbol = abi::__cxa_demangle(
|
||||
word.c_str(), nullptr, nullptr, &status);
|
||||
|
||||
if (status == 0) {
|
||||
buffer << demangled_symbol << '\t';
|
||||
std::free(demangled_symbol);
|
||||
} else {
|
||||
buffer << word << '\t';
|
||||
}
|
||||
}
|
||||
buffer << std::endl;
|
||||
}
|
||||
std::free(strs);
|
||||
#else
|
||||
buffer << boost::stacktrace::stacktrace() << std::flush;
|
||||
#endif
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
void
|
||||
print_cmdline(int argc, const char* argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
std::cout << "Command-line received" << std::endl;
|
||||
for (i = 0; i < argc; ++i)
|
||||
std::cout << argv[i] << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
} // namespace elemental
|
||||
|
||||
// clang-format off
|
||||
// vim: set foldmethod=syntax foldminlines=10 textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
||||
|
@ -7,10 +7,8 @@
|
||||
* obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "types/legible_ctypes.hpp"
|
||||
|
||||
#include "Exception.hpp"
|
||||
#include "sys/paths.hpp"
|
||||
#include "Exception.hpp"
|
||||
#include "sys/platform.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
@ -25,8 +23,7 @@
|
||||
namespace fs = std::filesystem;
|
||||
namespace elemental::paths {
|
||||
|
||||
auto
|
||||
get_home() -> fs::path
|
||||
auto get_home() -> fs::path
|
||||
{
|
||||
c::string result;
|
||||
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
@ -37,8 +34,7 @@ get_home() -> fs::path
|
||||
return result;
|
||||
}
|
||||
|
||||
auto
|
||||
get_app_config_root() -> fs::path
|
||||
auto get_app_config_root() -> fs::path
|
||||
{
|
||||
fs::path result;
|
||||
|
||||
@ -55,44 +51,41 @@ get_app_config_root() -> fs::path
|
||||
result = getenv("APPDATA");
|
||||
break;
|
||||
default:
|
||||
throw NotImplementedException();
|
||||
throw IOCore::NotImplementedException();
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
auto
|
||||
expand_path(const fs::path& location) -> fs::path
|
||||
auto expand_path(const fs::path& location) -> fs::path
|
||||
{
|
||||
try {
|
||||
fs::path result(location.root_path());
|
||||
|
||||
for (auto path_iter = location.begin();
|
||||
path_iter != location.end(); ++path_iter) {
|
||||
path_iter != location.end();
|
||||
++path_iter) {
|
||||
std::string token(path_iter->string());
|
||||
c::string env_val;
|
||||
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
if (token == "~" || token == "$HOME") {
|
||||
env_val = getenv("HOME");
|
||||
result =
|
||||
result / (env_val ? std::string(env_val)
|
||||
: std::string(""));
|
||||
result = result / (env_val ? std::string(env_val)
|
||||
: std::string(""));
|
||||
} else if (token[0] == '$') {
|
||||
// remove the $ from the varaible
|
||||
token = token.substr(1, token.length());
|
||||
env_val = getenv(token.c_str());
|
||||
result =
|
||||
result / (env_val ? std::string(env_val)
|
||||
: std::string(""));
|
||||
result = result / (env_val ? std::string(env_val)
|
||||
: std::string(""));
|
||||
} else {
|
||||
#elif defined(__WIN32__)
|
||||
if (token[0] == '%' && token[token.length()] == '%') {
|
||||
// Remove the % around the varaible
|
||||
token = token.substr(1, token.length() - 1);
|
||||
env_val = getenv(token.c_str());
|
||||
result =
|
||||
result / (env_val ? std::string(env_val)
|
||||
: std::string(""));
|
||||
result = result / (env_val ? std::string(env_val)
|
||||
: std::string(""));
|
||||
|
||||
} else {
|
||||
#endif
|
||||
@ -100,10 +93,10 @@ expand_path(const fs::path& location) -> fs::path
|
||||
}
|
||||
}
|
||||
return fs::canonical(result);
|
||||
} catch (elemental::Exception& e) {
|
||||
} catch (IOCore::Exception& e) {
|
||||
throw e;
|
||||
} catch (std::exception& e) {
|
||||
throw Exception(e);
|
||||
throw IOCore::Exception(e);
|
||||
}
|
||||
}
|
||||
} // namespace elemental::paths
|
||||
|
@ -1,61 +0,0 @@
|
||||
/* Application.test.cpp
|
||||
* Copyright © 2023 Saul D. Beniquez
|
||||
* License: Mozilla Public License v. 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
* v.2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
* obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "Application.hpp"
|
||||
#include "Exception.hpp"
|
||||
|
||||
#include "test-utils/common.hpp"
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
namespace {
|
||||
struct SimulatedLaunch
|
||||
{
|
||||
static const char* argv[];
|
||||
static const char* env[];
|
||||
};
|
||||
inline const char* SimulatedLaunch::argv[] = { "param1", "param2", "param3" };
|
||||
inline const char* SimulatedLaunch::env[] = {
|
||||
"PATH=/usr/bin", "VAR2=TWO", "REQUEST_URI=markdown?msg=hello-world",
|
||||
nullptr
|
||||
};
|
||||
} // namespace
|
||||
|
||||
BEGIN_TEST_SUITE("elemental::Application")
|
||||
{
|
||||
using namespace elemental;
|
||||
struct IDerivedApplication : public Application
|
||||
{
|
||||
auto run() -> int override { return 0; }
|
||||
};
|
||||
struct TestFixture
|
||||
{
|
||||
TestFixture() : derived_app(), app(derived_app) {}
|
||||
|
||||
IDerivedApplication derived_app;
|
||||
IApplication& app;
|
||||
};
|
||||
|
||||
FIXTURE_TEST("elemental::Application - Init method populates "
|
||||
"Arguments list and Environment dictionary")
|
||||
{
|
||||
app.init(3, SimulatedLaunch::argv, SimulatedLaunch::env);
|
||||
|
||||
CHECK(app.getArguments().size() == 3);
|
||||
CHECK(app.getArguments()[0] == "param1");
|
||||
CHECK(app.getArguments()[1] == "param2");
|
||||
CHECK(app.getArguments()[2] == "param3");
|
||||
|
||||
CHECK(app.getEnvironment().at("PATH") == "/usr/bin");
|
||||
CHECK(app.getEnvironment().at("VAR2") == "TWO");
|
||||
CHECK(app.getEnvironment().at("REQUEST_URI") ==
|
||||
"markdown?msg=hello-world");
|
||||
};
|
||||
}
|
||||
// clang-format off
|
||||
// vim: set foldmethod=marker foldmarker=#region,#endregion textwidth=80 ts=8 sts=0 sw=8 noexpandtab ft=cpp.doxygen :
|
@ -1,9 +1,7 @@
|
||||
# Define the executable 'test-runner'
|
||||
set(test-runner_SOURCES
|
||||
runtime.test.cpp
|
||||
Exception.test.cpp
|
||||
Singleton.template.test.cpp
|
||||
Application.test.cpp
|
||||
IRenderer.test.cpp
|
||||
LoopRegulator.test.cpp
|
||||
sdl/SdlRenderer.test.cpp
|
||||
@ -19,7 +17,7 @@ add_executable(test-runner
|
||||
${test-runner_SOURCES}
|
||||
)
|
||||
|
||||
set_target_properties(test-runner PROPERTIES EXCLUDE_FROM_ALL 0)
|
||||
set_target_properties(test-runner PROPERTIES EXCLUDE_FROM_ALL 1)
|
||||
|
||||
target_compile_definitions(test-runner PRIVATE
|
||||
-DUNIT_TEST=1
|
||||
@ -56,7 +54,7 @@ PRIVATE
|
||||
|
||||
# Set output directories for build targets
|
||||
set_target_properties(test-runner PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${OUTPUT_DIR}/tests"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${Elemental_ARTIFACT_DIR}/tests"
|
||||
)
|
||||
# extras: catch2 ctest integration.
|
||||
# add catch2's ctest cmake module and register the tests defined by mdml-tests
|
||||
|
@ -1,135 +0,0 @@
|
||||
/* exceptions-test.cpp
|
||||
* Copyright © 2023 Saul D. Beniquez
|
||||
* License: Mozilla Public License v. 2.0
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
* v.2.0. If a copy of the MPL was not distributed with this file, You can
|
||||
* obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "Exception.hpp"
|
||||
|
||||
#include "test-utils/common.hpp"
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <catch2/matchers/catch_matchers_string.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace Match = Catch::Matchers;
|
||||
using Catch::CaseSensitive;
|
||||
|
||||
void
|
||||
throw_wrapped_stl_exception()
|
||||
{
|
||||
auto local = std::logic_error("This is a stack variable");
|
||||
|
||||
throw elemental::Exception(local);
|
||||
}
|
||||
|
||||
BEGIN_TEST_SUITE("elemental::Exception")
|
||||
{
|
||||
auto throw_an_exception = []() {
|
||||
throw elemental::Exception("An error occurred!!");
|
||||
};
|
||||
|
||||
TEST("elemental::Exception - Can throw new exception type")
|
||||
{
|
||||
REQUIRE_THROWS(throw_an_exception());
|
||||
}
|
||||
|
||||
TEST("elemental::Exception - Can construct exception various ways")
|
||||
{
|
||||
SECTION("1. Blank constructor")
|
||||
{
|
||||
elemental::Exception obj;
|
||||
}
|
||||
SECTION("2a. With cstring parameter")
|
||||
{
|
||||
elemental::Exception obj("Sample Error");
|
||||
}
|
||||
SECTION("2b. With std::string parameter")
|
||||
{
|
||||
elemental::Exception obj(std::string("Sample Error"));
|
||||
}
|
||||
|
||||
SECTION("3. With STL exception")
|
||||
{
|
||||
elemental::Exception obj(
|
||||
std::runtime_error("Sample Error"));
|
||||
}
|
||||
SECTION("4. With destroyed stack")
|
||||
{
|
||||
auto nested_function_call = []() {
|
||||
throw_wrapped_stl_exception();
|
||||
};
|
||||
try {
|
||||
nested_function_call();
|
||||
} catch (std::exception& e) {
|
||||
REQUIRE_THAT(e.what(),
|
||||
Match::ContainsSubstring(
|
||||
"This is a stack variable"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST("elemental::Exception::what() - message reflects error")
|
||||
{
|
||||
|
||||
SECTION("1. Unspecified error or exception")
|
||||
{
|
||||
elemental::Exception obj;
|
||||
|
||||
REQUIRE_THAT(obj.what(),
|
||||
Match::ContainsSubstring(
|
||||
elemental::Exception::kDEFAULT_ERROR,
|
||||
CaseSensitive::Yes));
|
||||
}
|
||||
|
||||
SECTION("2. custom error or exception")
|
||||
{
|
||||
constexpr auto kTEST_MESSAGE = "This is a test.";
|
||||
elemental::Exception test_object_one(kTEST_MESSAGE);
|
||||
elemental::Exception test_object_two(
|
||||
std::logic_error("Makes no sense"));
|
||||
SECTION(" a: what() does not contain default message")
|
||||
{
|
||||
REQUIRE_THAT(
|
||||
test_object_one.what(),
|
||||
!Match::ContainsSubstring(
|
||||
elemental::Exception::kDEFAULT_ERROR));
|
||||
}
|
||||
SECTION(" b: what() displays custom message")
|
||||
{
|
||||
REQUIRE_THAT(
|
||||
test_object_one.what(),
|
||||
Match::ContainsSubstring(kTEST_MESSAGE));
|
||||
}
|
||||
SECTION(" c: what() contains inner exception message")
|
||||
{
|
||||
REQUIRE_THAT(
|
||||
test_object_two.what(),
|
||||
Match::ContainsSubstring("Makes no sense"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST("elemental::Exception::what() - contains stacktrace with Catch2 "
|
||||
"runtime method names")
|
||||
{
|
||||
elemental::Exception test_object("Test");
|
||||
SECTION(" a: what() does not contain default message")
|
||||
{
|
||||
REQUIRE_THAT(
|
||||
test_object.what(),
|
||||
Match::ContainsSubstring("Catch::RunContext"));
|
||||
SUCCEED(test_object.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
// vim: set foldmethod=syntax textwidth=80 ts=4 sts=0 sw=4 noexpandtab ft=cpp.doxygen :
|
@ -12,7 +12,6 @@
|
||||
#include "Exception.hpp"
|
||||
|
||||
#include "sys/debuginfo.hpp"
|
||||
#include "types/legible_ctypes.hpp"
|
||||
#include "util/debug.hpp"
|
||||
|
||||
#include "test-utils/common.hpp"
|
||||
@ -36,37 +35,37 @@ constexpr c::const_string kNON_EXISTENT_PATH = "/hades/tmp/dne/file.json";
|
||||
BEGIN_TEST_SUITE("elemental::JsonConfigFile")
|
||||
{
|
||||
namespace { // Test fixtures
|
||||
struct SampleFileGenerator
|
||||
struct SampleFileGenerator {
|
||||
SampleFileGenerator()
|
||||
{
|
||||
SampleFileGenerator()
|
||||
{
|
||||
if (!fs::exists(kINPUT_FILE_PATH)) {
|
||||
std::ofstream f(kINPUT_FILE_PATH,
|
||||
std::ios::out |
|
||||
std::ios::trunc);
|
||||
f << R"({"key1": "value1", "key2": "value2"})"
|
||||
<< std::endl;
|
||||
f.close();
|
||||
}
|
||||
if (!fs::exists(kINPUT_FILE_PATH)) {
|
||||
std::ofstream f(
|
||||
kINPUT_FILE_PATH,
|
||||
std::ios::out | std::ios::trunc
|
||||
);
|
||||
f << R"({"key1": "value1", "key2": "value2"})"
|
||||
<< std::endl;
|
||||
f.close();
|
||||
}
|
||||
~SampleFileGenerator()
|
||||
{
|
||||
try {
|
||||
if (fs::exists(kINPUT_FILE_PATH)) {
|
||||
fs::remove(kINPUT_FILE_PATH);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
DBG_PRINT(e.what());
|
||||
}
|
||||
~SampleFileGenerator()
|
||||
{
|
||||
try {
|
||||
if (fs::exists(kINPUT_FILE_PATH)) {
|
||||
fs::remove(kINPUT_FILE_PATH);
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
DBG_PRINT(e.what());
|
||||
}
|
||||
};
|
||||
using TestFixture = SampleFileGenerator;
|
||||
}
|
||||
};
|
||||
using TestFixture = SampleFileGenerator;
|
||||
} // namespace
|
||||
|
||||
TEST("elemental::nlohmann::json is serializablable like "
|
||||
"std::map<std::string,std::string>")
|
||||
{
|
||||
elemental::Dictionary<std::string> test_data;
|
||||
IOCore::Dictionary<std::string> test_data;
|
||||
nlohmann::json jsonified;
|
||||
|
||||
test_data["one"] = "1";
|
||||
@ -92,8 +91,10 @@ BEGIN_TEST_SUITE("elemental::JsonConfigFile")
|
||||
SECTION("JsonConfigFile w/ invalid path throws exception")
|
||||
{
|
||||
|
||||
REQUIRE_THROWS_AS(JsonConfigFile(kNON_EXISTENT_PATH),
|
||||
elemental::UnreachablePathException);
|
||||
REQUIRE_THROWS_AS(
|
||||
JsonConfigFile(kNON_EXISTENT_PATH),
|
||||
elemental::UnreachablePathException
|
||||
);
|
||||
}
|
||||
}
|
||||
FIXTURE_TEST("JsonConfigFile::Read")
|
||||
@ -113,9 +114,9 @@ BEGIN_TEST_SUITE("elemental::JsonConfigFile")
|
||||
SECTION("JsonConfigFile::Read w/ bad file throws exception")
|
||||
{
|
||||
if (!fs::exists(kBADFILE_PATH)) {
|
||||
std::ofstream f(kBADFILE_PATH);
|
||||
f << R"({"Hello World"})" << std::endl;
|
||||
f.close();
|
||||
std::ofstream fileout(kBADFILE_PATH);
|
||||
fileout << R"({"Hello World"})" << std::endl;
|
||||
fileout.close();
|
||||
}
|
||||
REQUIRE_THROWS_AS(
|
||||
[&]() {
|
||||
@ -124,7 +125,8 @@ BEGIN_TEST_SUITE("elemental::JsonConfigFile")
|
||||
|
||||
bad_config.read();
|
||||
}(),
|
||||
Exception);
|
||||
IOCore::Exception
|
||||
);
|
||||
}
|
||||
if (fs::exists(kBADFILE_PATH)) {
|
||||
fs::remove(kBADFILE_PATH);
|
||||
@ -148,34 +150,37 @@ BEGIN_TEST_SUITE("elemental::JsonConfigFile")
|
||||
|
||||
resulting_file >> jobject;
|
||||
auto written_data =
|
||||
jobject.get<elemental::Dictionary<std::string>>();
|
||||
jobject.get<IOCore::Dictionary<std::string>>();
|
||||
|
||||
REQUIRE(written_data["one"] == test_data["one"]);
|
||||
REQUIRE(written_data["resolution"] ==
|
||||
test_data["resolution"]);
|
||||
REQUIRE(
|
||||
written_data["resolution"] == test_data["resolution"]
|
||||
);
|
||||
REQUIRE(written_data["Hello"] == test_data["Hello"]);
|
||||
}
|
||||
fs::remove(kINPUT_FILE_PATH);
|
||||
}
|
||||
|
||||
FIXTURE_TEST(
|
||||
"JsonConfigFile::Get<T>() basically wraps nlohmann::json::get<T>()")
|
||||
"JsonConfigFile::Get<T>() basically wraps nlohmann::json::get<T>()"
|
||||
)
|
||||
{
|
||||
auto config_file = JsonConfigFile(kINPUT_FILE_PATH);
|
||||
auto& json_data = config_file.getJsonData();
|
||||
|
||||
config_file.read();
|
||||
auto obtained_data =
|
||||
config_file.get<elemental::Dictionary<std::string>>();
|
||||
config_file.get<IOCore::Dictionary<std::string>>();
|
||||
|
||||
REQUIRE(obtained_data["key1"] == "value1");
|
||||
REQUIRE(obtained_data["key2"] == "value2");
|
||||
}
|
||||
FIXTURE_TEST(
|
||||
"JsonConfigFile::Set() basically wraps nlohmann::json::operator=()")
|
||||
"JsonConfigFile::Set() basically wraps nlohmann::json::operator=()"
|
||||
)
|
||||
{
|
||||
auto config_file = JsonConfigFile(kINPUT_FILE_PATH);
|
||||
elemental::Dictionary<std::string> test_data;
|
||||
IOCore::Dictionary<std::string> test_data;
|
||||
|
||||
test_data["one"] = "1";
|
||||
test_data["resolution"] = "1280x720";
|
||||
|
@ -7,10 +7,8 @@
|
||||
* obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "types/legible_ctypes.hpp"
|
||||
|
||||
#include "Exception.hpp"
|
||||
#include "sys/paths.hpp"
|
||||
#include "Exception.hpp"
|
||||
#include "sys/platform.hpp"
|
||||
|
||||
#include "test-utils/common.hpp"
|
||||
@ -39,8 +37,10 @@ BEGIN_TEST_SUITE("elemental::paths")
|
||||
{
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
fs::path app_config_root = get_app_config_root();
|
||||
REQUIRE(app_config_root ==
|
||||
(get_home() / "Library" / "Application Support"));
|
||||
REQUIRE(
|
||||
app_config_root ==
|
||||
(get_home() / "Library" / "Application Support")
|
||||
);
|
||||
#elif defined(__unix__)
|
||||
|
||||
fs::path appConfigRoot = get_app_config_root();
|
||||
@ -56,24 +56,29 @@ BEGIN_TEST_SUITE("elemental::paths")
|
||||
|
||||
using namespace elemental::paths;
|
||||
|
||||
elemental::c::string home_var = getenv("HOME");
|
||||
elemental::c::string user_name = getenv("USER");
|
||||
c::string home_var = getenv("HOME");
|
||||
c::string user_name = getenv("USER");
|
||||
SECTION("resolves home directory")
|
||||
{
|
||||
|
||||
if (home_var) {
|
||||
REQUIRE(expand_path("~") ==
|
||||
fs::canonical(home_var));
|
||||
REQUIRE(expand_path("$HOME") ==
|
||||
fs::canonical(home_var));
|
||||
REQUIRE(
|
||||
expand_path("~") == fs::canonical(home_var)
|
||||
);
|
||||
REQUIRE(
|
||||
expand_path("$HOME") ==
|
||||
fs::canonical(home_var)
|
||||
);
|
||||
}
|
||||
}
|
||||
SECTION("substitutes other variables")
|
||||
{
|
||||
if ((home_var && user_name) &&
|
||||
(std::string(home_var) != "/")) {
|
||||
REQUIRE(expand_path("~/../$USER") ==
|
||||
fs::canonical(home_var));
|
||||
REQUIRE(
|
||||
expand_path("~/../$USER") ==
|
||||
fs::canonical(home_var)
|
||||
);
|
||||
}
|
||||
}
|
||||
#if !defined(__unix__) && !(defined(__APPLE__) && defined(__MACH__))
|
||||
|
@ -36,7 +36,7 @@ PRIVATE
|
||||
|
||||
# Set output directories for build targetsk
|
||||
set_target_properties(SDL_test-runner PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${OUTPUT_DIR}/tests"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${Elemental_ARTIFACT_DIR}/tests"
|
||||
)
|
||||
|
||||
add_dependencies(ctest
|
||||
|
@ -121,7 +121,7 @@ BEGIN_TEST_SUITE("elemental::SdlEventSource")
|
||||
event_queue_ref.push(input);
|
||||
}
|
||||
|
||||
test_object.transmitEvents();
|
||||
test_object.sendEvents();
|
||||
|
||||
REQUIRE(recorder.received.size() > 0);
|
||||
|
||||
|
@ -22,21 +22,13 @@
|
||||
|
||||
namespace elemental {
|
||||
|
||||
struct SdlEventSimulator
|
||||
{
|
||||
enum KeyDir
|
||||
{
|
||||
Up = 0,
|
||||
Right,
|
||||
Down,
|
||||
Left
|
||||
};
|
||||
struct SdlEventSimulator {
|
||||
enum KeyDir { Up = 0, Right, Down, Left };
|
||||
|
||||
static inline auto eventFromScancode(SDL_Scancode scancode) -> SDL_Event
|
||||
{
|
||||
SDL_Event event{ .key = {
|
||||
.type = SDL_KEYDOWN,
|
||||
.keysym = { .scancode = scancode } } };
|
||||
SDL_Event event{ .key = { .type = SDL_KEYDOWN,
|
||||
.keysym = { .scancode = scancode } } };
|
||||
return event;
|
||||
}
|
||||
|
||||
@ -104,18 +96,17 @@ struct SdlEventSimulator
|
||||
}
|
||||
}; // #endregion
|
||||
|
||||
struct SdlTestFixture
|
||||
{
|
||||
struct SdlTestFixture {
|
||||
std::stringstream buffer;
|
||||
|
||||
SdlTestFixture() : buffer()
|
||||
{
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_EVENTS) != kSuccess) {
|
||||
if (SDL_InitSubSystem(SDL_INIT_EVENTS) != IOCore::kSuccess) {
|
||||
buffer << "SDL Could not initialize; SDL_Error: "
|
||||
<< SDL_GetError();
|
||||
throw elemental::Exception(buffer.str());
|
||||
throw IOCore::Exception(buffer.str());
|
||||
}
|
||||
SDL_PumpEvents();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user