From 1c1e7f8d510f0c0cd45826e6838e4ad79831f3c7 Mon Sep 17 00:00:00 2001 From: cdemeyer-teachx Date: Thu, 14 Aug 2025 10:19:03 +0900 Subject: [PATCH] Google Tests --- LICENSE | 21 ++++++++ cmake/PokemonSimConfig.cmake.in | 14 ++++++ cmake/modules/CompilerWarnings.cmake | 22 ++++++++ cmake/modules/StaticAnalysis.cmake | 20 ++++++++ cmake/packaging/DEB.cmake | 5 ++ cmake/packaging/RPM.cmake | 4 ++ examples/CMakeLists.txt | 26 ++++++++++ include/pokemon_battle_sim.h | 37 ++++++++++++++ src/CMakeLists.txt | 41 +++++++++++++++ src/placeholder.cpp | 44 ++++++++++++++++ test_all.sh | 8 +++ tests/CMakeLists.txt | 75 ++++++++++++++++++++++++++++ tests/README.md | 43 +++++++++++++++- tests/integration/CMakeLists.txt | 18 +++++++ tests/integration/main.cpp | 11 ++++ tests/unit/CMakeLists.txt | 9 ++++ tests/unit/core/CMakeLists.txt | 18 +++++++ tests/unit/core/test_example.cpp | 75 ++++++++++++++++++++++++++++ tests/unit/main.cpp | 11 ++++ 19 files changed, 500 insertions(+), 2 deletions(-) create mode 100644 LICENSE create mode 100644 cmake/PokemonSimConfig.cmake.in create mode 100644 cmake/modules/CompilerWarnings.cmake create mode 100644 cmake/modules/StaticAnalysis.cmake create mode 100644 cmake/packaging/DEB.cmake create mode 100644 cmake/packaging/RPM.cmake create mode 100644 examples/CMakeLists.txt create mode 100644 include/pokemon_battle_sim.h create mode 100644 src/CMakeLists.txt create mode 100644 src/placeholder.cpp create mode 100755 test_all.sh create mode 100644 tests/CMakeLists.txt create mode 100644 tests/integration/CMakeLists.txt create mode 100644 tests/integration/main.cpp create mode 100644 tests/unit/CMakeLists.txt create mode 100644 tests/unit/core/CMakeLists.txt create mode 100644 tests/unit/core/test_example.cpp create mode 100644 tests/unit/main.cpp diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9fc9d5f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Pokemon Battle Engine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/cmake/PokemonSimConfig.cmake.in b/cmake/PokemonSimConfig.cmake.in new file mode 100644 index 0000000..a46102e --- /dev/null +++ b/cmake/PokemonSimConfig.cmake.in @@ -0,0 +1,14 @@ +@PACKAGE_INIT@ + +# Pokemon Battle Simulator CMake Configuration +set(PokemonSim_VERSION "@PROJECT_VERSION@") + +# Set up import targets +include("${CMAKE_CURRENT_LIST_DIR}/PokemonSimTargets.cmake") + +# Set up variables for consumers +set(PokemonSim_LIBRARIES PokemonSim::pokemon_battle_sim) +set(PokemonSim_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@") + +# Check required components +check_required_components(PokemonSim) diff --git a/cmake/modules/CompilerWarnings.cmake b/cmake/modules/CompilerWarnings.cmake new file mode 100644 index 0000000..6f6071a --- /dev/null +++ b/cmake/modules/CompilerWarnings.cmake @@ -0,0 +1,22 @@ +# Compiler warnings configuration +function(set_project_warnings) + option(WARNINGS_AS_ERRORS "Treat compiler warnings as errors" ON) + + if(MSVC) + add_compile_options( + /W4 + /permissive- + $<$:/WX> + ) + else() + add_compile_options( + -Wall + -Wextra + -Wpedantic + -Wshadow + -Wconversion + -Wsign-conversion + $<$:-Werror> + ) + endif() +endfunction() diff --git a/cmake/modules/StaticAnalysis.cmake b/cmake/modules/StaticAnalysis.cmake new file mode 100644 index 0000000..8f9fdd2 --- /dev/null +++ b/cmake/modules/StaticAnalysis.cmake @@ -0,0 +1,20 @@ +# Static analysis tools configuration +function(enable_static_analysis) + # Find clang-tidy + find_program(CLANG_TIDY_EXE NAMES clang-tidy) + if(CLANG_TIDY_EXE) + set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_EXE} PARENT_SCOPE) + message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}") + else() + message(STATUS "clang-tidy not found") + endif() + + # Find cppcheck + find_program(CPPCHECK_EXE NAMES cppcheck) + if(CPPCHECK_EXE) + set(CMAKE_CXX_CPPCHECK ${CPPCHECK_EXE} PARENT_SCOPE) + message(STATUS "cppcheck found: ${CPPCHECK_EXE}") + else() + message(STATUS "cppcheck not found") + endif() +endfunction() diff --git a/cmake/packaging/DEB.cmake b/cmake/packaging/DEB.cmake new file mode 100644 index 0000000..9469c1d --- /dev/null +++ b/cmake/packaging/DEB.cmake @@ -0,0 +1,5 @@ +# DEB packaging configuration +set(CPACK_DEB_COMPONENT_INSTALL ON) +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Pokemon Sim Team") +set(CPACK_DEBIAN_PACKAGE_SECTION "games") +set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") diff --git a/cmake/packaging/RPM.cmake b/cmake/packaging/RPM.cmake new file mode 100644 index 0000000..e4e6212 --- /dev/null +++ b/cmake/packaging/RPM.cmake @@ -0,0 +1,4 @@ +# RPM packaging configuration +set(CPACK_RPM_COMPONENT_INSTALL ON) +set(CPACK_RPM_PACKAGE_GROUP "Games") +set(CPACK_RPM_PACKAGE_LICENSE "MIT") diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..f9deeb8 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,26 @@ +# Examples CMakeLists.txt + +# Collect all example source files +file(GLOB_RECURSE EXAMPLE_SOURCES "*.cpp" "*.cc" "*.cxx") + +# Create example executables +foreach(EXAMPLE_SOURCE ${EXAMPLE_SOURCES}) + get_filename_component(EXAMPLE_NAME ${EXAMPLE_SOURCE} NAME_WE) + add_executable(${EXAMPLE_NAME} ${EXAMPLE_SOURCE}) + + # Link with our library + target_link_libraries(${EXAMPLE_NAME} + PRIVATE + PokemonSim::pokemon_battle_sim + ) + + # Include directories + target_include_directories(${EXAMPLE_NAME} + PRIVATE + ${CMAKE_SOURCE_DIR}/include + ) +endforeach() + +# Example of adding examples manually: +# add_executable(battle_example battle_example.cpp) +# target_link_libraries(battle_example PRIVATE PokemonSim::pokemon_battle_sim) diff --git a/include/pokemon_battle_sim.h b/include/pokemon_battle_sim.h new file mode 100644 index 0000000..cc14a15 --- /dev/null +++ b/include/pokemon_battle_sim.h @@ -0,0 +1,37 @@ +// Pokemon Battle Engine Header +// This is a placeholder header for the Pokemon Battle Engine library + +#ifndef POKEMON_BATTLE_SIM_H +#define POKEMON_BATTLE_SIM_H + +#include + +namespace PokemonSim { + +// Forward declarations +class Pokemon; + +// Pokemon class +class Pokemon { +public: + Pokemon(const std::string& name, int health = 100); + ~Pokemon() = default; + + // Getters + std::string getName() const; + int getHealth() const; + + // Setters + void setHealth(int health); + +private: + std::string name_; + int health_; +}; + +// Battle simulation function +bool simulateBattle(Pokemon& pokemon1, Pokemon& pokemon2); + +} // namespace PokemonSim + +#endif // POKEMON_BATTLE_SIM_H diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..82a73eb --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,41 @@ +# Source files CMakeLists.txt + +# Collect all source files +file(GLOB_RECURSE SOURCES "*.cpp" "*.cc" "*.cxx") +file(GLOB_RECURSE HEADERS "*.h" "*.hpp" "*.hxx") + +# Create the main library +add_library(pokemon_battle_sim ${SOURCES} ${HEADERS}) + +# Set library properties +set_target_properties(pokemon_battle_sim PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} +) + +# Include directories +target_include_directories(pokemon_battle_sim + PUBLIC + $ + $ + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +# Link dependencies +target_link_libraries(pokemon_battle_sim + PRIVATE + Threads::Threads +) + +# Create an alias for consistency +add_library(PokemonSim::pokemon_battle_sim ALIAS pokemon_battle_sim) + +# Export the target +install(TARGETS pokemon_battle_sim + EXPORT PokemonSimTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) diff --git a/src/placeholder.cpp b/src/placeholder.cpp new file mode 100644 index 0000000..6327c28 --- /dev/null +++ b/src/placeholder.cpp @@ -0,0 +1,44 @@ +// Placeholder source file for Pokemon Battle Engine +// This file is temporary and will be replaced with actual implementation + +#include "pokemon_battle_sim.h" +#include +#include + +namespace PokemonSim { + +// Pokemon class method implementations +Pokemon::Pokemon(const std::string& name, int health) + : name_(name), health_(health) {} + +std::string Pokemon::getName() const { + return name_; +} + +int Pokemon::getHealth() const { + return health_; +} + +void Pokemon::setHealth(int health) { + health_ = health; +} + +// Placeholder battle function +bool simulateBattle(Pokemon& pokemon1, Pokemon& pokemon2) { + // Simple battle simulation for testing + while (pokemon1.getHealth() > 0 && pokemon2.getHealth() > 0) { + // Pokemon 1 attacks Pokemon 2 + int damage = 10; // Fixed damage for now + pokemon2.setHealth(pokemon2.getHealth() - damage); + + if (pokemon2.getHealth() <= 0) { + return true; // Pokemon 1 wins + } + + // Pokemon 2 attacks Pokemon 1 + pokemon1.setHealth(pokemon1.getHealth() - damage); + } + return false; // Pokemon 2 wins or tie +} + +} // namespace PokemonSim diff --git a/test_all.sh b/test_all.sh new file mode 100755 index 0000000..bcf5f99 --- /dev/null +++ b/test_all.sh @@ -0,0 +1,8 @@ +# Configure the project +cmake -B build -S . + +# Build the project (includes tests) +cmake --build build + +# Run all tests +cmake --build build --target test \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..19cd4b5 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,75 @@ +# Tests CMakeLists.txt +include(FetchContent) + +# Download and configure Google Test +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/v1.14.0.zip + DOWNLOAD_EXTRACT_TIMESTAMP TRUE +) + +# Prevent overriding the parent project's compiler/linker on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Make Google Test available +FetchContent_MakeAvailable(googletest) + +# Include Google Test modules +include(GoogleTest) + +# Create test executable for unit tests +add_executable(unit_tests + unit/main.cpp +) + +# Link with Google Test and our library +target_link_libraries(unit_tests + PRIVATE + GTest::gtest_main + GTest::gmock_main + PokemonSim::pokemon_battle_sim +) + +# Set up test discovery +gtest_discover_tests(unit_tests + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + PROPERTIES + LABELS "unit" +) + +# Create test executable for integration tests +add_executable(integration_tests + integration/main.cpp +) + +# Link with Google Test and our library +target_link_libraries(integration_tests + PRIVATE + GTest::gtest_main + GTest::gmock_main + PokemonSim::pokemon_battle_sim +) + +# Set up test discovery +gtest_discover_tests(integration_tests + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + PROPERTIES + LABELS "integration" +) + +# Include directories for tests +target_include_directories(unit_tests + PRIVATE + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/src +) + +target_include_directories(integration_tests + PRIVATE + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/src +) + +# Add test subdirectories +add_subdirectory(unit) +add_subdirectory(integration) diff --git a/tests/README.md b/tests/README.md index f4e9774..3527902 100644 --- a/tests/README.md +++ b/tests/README.md @@ -38,10 +38,49 @@ tests/ ## Testing Framework -- **Google Test (gtest)**: Primary testing framework -- **Google Mock (gmock)**: For mocking dependencies +- **Google Test (gtest)**: Primary testing framework - automatically downloaded via FetchContent +- **Google Mock (gmock)**: For mocking dependencies - included with Google Test - **Test Coverage**: Aim for >90% code coverage - **Continuous Integration**: Tests run on every commit +- **Version**: Google Test v1.14.0 + +## Running Tests + +### Build and Run + +```bash +# Configure and build +cmake -B build -S . +cmake --build build + +# Run all tests +cmake --build build --target test + +# Run specific test types +cd build && ctest -L unit # Unit tests only +cd build && ctest -L integration # Integration tests only + +# Run with verbose output +cd build && ctest -V +``` + +### Test Structure (Now Implemented) + +``` +tests/ +├── unit/ # Unit tests for individual components +│ ├── main.cpp # Unit test entry point +│ ├── CMakeLists.txt # Unit test build config +│ └── core/ # Core system tests +│ ├── CMakeLists.txt +│ └── test_example.cpp # Example test (ready to run) +├── integration/ # Integration tests +│ ├── main.cpp # Integration test entry point +│ └── CMakeLists.txt # Integration test build config +├── fixtures/ # Test data and fixtures +├── helpers/ # Test helper utilities +└── CMakeLists.txt # Main test build configuration +``` ## Test Categories diff --git a/tests/integration/CMakeLists.txt b/tests/integration/CMakeLists.txt new file mode 100644 index 0000000..5f48fba --- /dev/null +++ b/tests/integration/CMakeLists.txt @@ -0,0 +1,18 @@ +# Integration tests CMakeLists.txt + +# Collect all test source files +file(GLOB_RECURSE INTEGRATION_TEST_SOURCES "*.cpp" "*.cc" "*.cxx") + +# Remove main.cpp from the sources list if it exists +list(REMOVE_ITEM INTEGRATION_TEST_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") + +# Add integration test sources to the integration_tests executable +if(INTEGRATION_TEST_SOURCES) + target_sources(integration_tests PRIVATE ${INTEGRATION_TEST_SOURCES}) +endif() + +# Example of how to add specific test files: +# target_sources(integration_tests PRIVATE +# test_battle_integration.cpp +# test_full_game_flow.cpp +# ) diff --git a/tests/integration/main.cpp b/tests/integration/main.cpp new file mode 100644 index 0000000..affb354 --- /dev/null +++ b/tests/integration/main.cpp @@ -0,0 +1,11 @@ +#include + +// Main test runner for integration tests +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + // Set up any global test configuration here + // Integration tests might need different setup than unit tests + + return RUN_ALL_TESTS(); +} diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt new file mode 100644 index 0000000..6ef7709 --- /dev/null +++ b/tests/unit/CMakeLists.txt @@ -0,0 +1,9 @@ +# Unit tests CMakeLists.txt + +# Add unit test subdirectories +add_subdirectory(core) + +# You can add more unit test subdirectories here as needed: +# add_subdirectory(math) +# add_subdirectory(utils) +# add_subdirectory(battle) diff --git a/tests/unit/core/CMakeLists.txt b/tests/unit/core/CMakeLists.txt new file mode 100644 index 0000000..6c5301d --- /dev/null +++ b/tests/unit/core/CMakeLists.txt @@ -0,0 +1,18 @@ +# Core unit tests CMakeLists.txt + +# Collect all test source files +file(GLOB_RECURSE CORE_TEST_SOURCES "*.cpp" "*.cc" "*.cxx") + +# Remove main.cpp from the sources list if it exists +list(REMOVE_ITEM CORE_TEST_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") + +# Add core test sources to the unit_tests executable +if(CORE_TEST_SOURCES) + target_sources(unit_tests PRIVATE ${CORE_TEST_SOURCES}) +endif() + +# Example of how to add specific test files: +# target_sources(unit_tests PRIVATE +# test_example.cpp +# test_another_example.cpp +# ) diff --git a/tests/unit/core/test_example.cpp b/tests/unit/core/test_example.cpp new file mode 100644 index 0000000..09d8d2b --- /dev/null +++ b/tests/unit/core/test_example.cpp @@ -0,0 +1,75 @@ +#include + +// Example test case demonstrating Google Test usage +class ExampleTest : public ::testing::Test { +protected: + void SetUp() override { + // Set up test fixtures here + } + + void TearDown() override { + // Clean up test fixtures here + } +}; + +// Basic assertion test +TEST_F(ExampleTest, BasicAssertions) { + // Basic equality assertions + EXPECT_EQ(2 + 2, 4); + EXPECT_NE(2 + 2, 5); + + // Boolean assertions + EXPECT_TRUE(true); + EXPECT_FALSE(false); + + // String assertions + EXPECT_STREQ("hello", "hello"); + EXPECT_STRNE("hello", "world"); +} + +// Test with parameters +TEST(ParameterizedTest, Addition) { + EXPECT_EQ(1 + 1, 2); + EXPECT_EQ(10 + 5, 15); + EXPECT_EQ(-1 + 1, 0); +} + +// Test that demonstrates failure (using TEST_F to match the fixture) +TEST_F(ExampleTest, ThisWillFail) { + // This test will fail to demonstrate the failure output + // EXPECT_EQ(2 + 2, 5); // Uncomment this line to see a failing test +} + +// Example of how you might test a Pokemon battle simulator component +// This demonstrates testing the placeholder implementation we created +#include "pokemon_battle_sim.h" + +TEST(PokemonTest, PokemonCreation) { + PokemonSim::Pokemon pikachu("Pikachu", 100); + + // Test basic properties + EXPECT_EQ(pikachu.getName(), "Pikachu"); + EXPECT_EQ(pikachu.getHealth(), 100); +} + +TEST(PokemonTest, PokemonHealthModification) { + PokemonSim::Pokemon charizard("Charizard", 150); + + EXPECT_EQ(charizard.getHealth(), 150); + + charizard.setHealth(100); + EXPECT_EQ(charizard.getHealth(), 100); +} + +TEST(PokemonTest, BattleSimulation) { + PokemonSim::Pokemon pokemon1("Pokemon1", 50); + PokemonSim::Pokemon pokemon2("Pokemon2", 30); + + // Pokemon1 should win because it has more health + bool result = PokemonSim::simulateBattle(pokemon1, pokemon2); + EXPECT_TRUE(result); // Pokemon1 wins + + // Both Pokemon should have taken damage + EXPECT_LT(pokemon1.getHealth(), 50); + EXPECT_LE(pokemon2.getHealth(), 0); +} diff --git a/tests/unit/main.cpp b/tests/unit/main.cpp new file mode 100644 index 0000000..60360d1 --- /dev/null +++ b/tests/unit/main.cpp @@ -0,0 +1,11 @@ +#include + +// Main test runner for unit tests +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + + // Set up any global test configuration here + // For example, you can set test filters, output format, etc. + + return RUN_ALL_TESTS(); +}