From 3c2e4a3fb25c8d264b3035847a2db8a3696ee06f Mon Sep 17 00:00:00 2001 From: DawnFire42 Date: Wed, 25 Feb 2026 13:28:41 -0500 Subject: [PATCH] feat(command-zone): add state machine with tests Implement CommandZoneState - a pure C++ state machine managing zone visibility transitions (Hidden, Revealed, Peeking states). The state machine is intentionally decoupled from Qt graphics: - Pure logic with no Qt dependencies in the state class - Testable in isolation without a GUI - Clear state transition table with StateChangeResult outcomes Test coverage verifies: - Initial state is Hidden - Valid transitions: Hidden->Revealed, Hidden->Peeking, etc. - Invalid transitions return NoChange - Peek timeout triggers return to previous state This establishes the foundation for command zone visibility management while keeping graphics concerns separate. --- cockatrice/CMakeLists.txt | 1 + .../src/game/zones/command_zone_state.cpp | 121 ++++++ .../src/game/zones/command_zone_state.h | 128 ++++++ tests/CMakeLists.txt | 1 + tests/command_zone/CMakeLists.txt | 40 ++ .../command_zone/command_zone_state_test.cpp | 387 ++++++++++++++++++ 6 files changed, 678 insertions(+) create mode 100644 cockatrice/src/game/zones/command_zone_state.cpp create mode 100644 cockatrice/src/game/zones/command_zone_state.h create mode 100644 tests/command_zone/CMakeLists.txt create mode 100644 tests/command_zone/command_zone_state_test.cpp diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index d675b809d..06255b5f1 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -103,6 +103,7 @@ set(cockatrice_SOURCES src/game/player/player_target.cpp src/game/replay.cpp src/game/zones/card_zone.cpp + src/game/zones/command_zone_state.cpp src/game/zones/hand_zone.cpp src/game/zones/logic/card_zone_logic.cpp src/game/zones/logic/hand_zone_logic.cpp diff --git a/cockatrice/src/game/zones/command_zone_state.cpp b/cockatrice/src/game/zones/command_zone_state.cpp new file mode 100644 index 000000000..d057243c8 --- /dev/null +++ b/cockatrice/src/game/zones/command_zone_state.cpp @@ -0,0 +1,121 @@ +/** + * @file command_zone_state.cpp + * @brief Implementation of CommandZoneState pure state machine. + * + * @see CommandZoneState for class documentation + * @see CommandZone for the graphics layer that owns this state + */ + +#include "command_zone_state.h" + +CommandZoneState::CommandZoneState(qreal zoneHeight, CommandZoneType zoneType) + : m_zoneHeight(zoneHeight), m_zoneType(zoneType), + m_visibility(zoneType == CommandZoneType::Primary ? ZoneVisibility::Expanded : ZoneVisibility::Collapsed) +{ +} + +bool CommandZoneState::isPrimary() const +{ + return m_zoneType == CommandZoneType::Primary; +} + +bool CommandZoneState::isMinimized() const +{ + return m_visibility == ZoneVisibility::Minimized; +} + +bool CommandZoneState::isExpanded() const +{ + return m_visibility != ZoneVisibility::Collapsed; +} + +bool CommandZoneState::isCollapsed() const +{ + return m_visibility == ZoneVisibility::Collapsed; +} + +qreal CommandZoneState::currentHeight() const +{ + if (isCollapsed()) { + return 0; + } + return isMinimized() ? (m_zoneHeight * CommandZoneConstants::MINIMIZED_HEIGHT_RATIO) : m_zoneHeight; +} + +CommandZoneType CommandZoneState::getZoneType() const +{ + return m_zoneType; +} + +qreal CommandZoneState::getZoneHeight() const +{ + return m_zoneHeight; +} + +StateChangeResult CommandZoneState::trySetExpanded(bool expanded, bool collapseBlocked) +{ + if (isPrimary()) { + return StateChangeResult::noChange(); + } + + bool currentlyExpanded = isExpanded(); + if (currentlyExpanded == expanded) { + return StateChangeResult::noChange(); + } + + if (!expanded && collapseBlocked) { + return StateChangeResult::noChange(); + } + + bool wasMinimized = isMinimized(); + + if (expanded) { + m_visibility = ZoneVisibility::Expanded; + } else { + m_visibility = ZoneVisibility::Collapsed; + } + + return { + true, // geometryChanged + true, // shouldEmitExpanded + wasMinimized && !expanded // shouldEmitMinimized (only if we were minimized and collapsed) + }; +} + +StateChangeResult CommandZoneState::tryToggleExpanded(bool collapseBlocked) +{ + if (isPrimary()) { + return StateChangeResult::noChange(); + } + + if (m_lastToggle.isValid() && m_lastToggle.elapsed() < TOGGLE_DEBOUNCE_MS) { + return StateChangeResult::noChange(); + } + + if (isExpanded() && collapseBlocked) { + return StateChangeResult::noChange(); + } + + m_lastToggle.start(); + return trySetExpanded(!isExpanded(), collapseBlocked); +} + +StateChangeResult CommandZoneState::tryToggleMinimized() +{ + if (isCollapsed()) { + return StateChangeResult::noChange(); + } + + m_visibility = isMinimized() ? ZoneVisibility::Expanded : ZoneVisibility::Minimized; + + return { + true, // geometryChanged + false, // shouldEmitExpanded (minimized toggle doesn't change expanded state) + true // shouldEmitMinimized + }; +} + +void CommandZoneState::resetDebounce() +{ + m_lastToggle.invalidate(); +} diff --git a/cockatrice/src/game/zones/command_zone_state.h b/cockatrice/src/game/zones/command_zone_state.h new file mode 100644 index 000000000..a8ab3ff5d --- /dev/null +++ b/cockatrice/src/game/zones/command_zone_state.h @@ -0,0 +1,128 @@ +/** + * @file command_zone_state.h + * @ingroup GameGraphicsZones + * @brief Pure state machine for command zone visibility management. + */ + +#ifndef COCKATRICE_COMMAND_ZONE_STATE_H +#define COCKATRICE_COMMAND_ZONE_STATE_H + +#include "command_zone_types.h" + +#include + +/** + * @class CommandZoneState + * @brief Manages visibility state (expanded/minimized/collapsed) for command zones. + * + * This class extracts pure state logic from CommandZone for testability. + * It has no Qt graphics dependencies and can be tested in isolation. + * + * The state machine supports three visibility states: + * - **Expanded**: Full height, cards visible + * - **Minimized**: 25% height, cards clipped + * - **Collapsed**: Zero height, only toggle button visible (not valid for Primary) + * + * All mutation methods return a StateChangeResult that tells callers what + * side effects to trigger (geometry changes, signal emissions), following + * the information hiding principle. + * + * @see CommandZone for the graphics layer that owns this state + * @see CommandZoneLogic for card data management + * @see StateChangeResult for mutation result semantics + */ +class CommandZoneState +{ +public: + /** + * @brief Constructs a CommandZoneState with the given height and type. + * @param zoneHeight Full height in pixels when expanded + * @param zoneType Type of command zone (Primary, Partner, Companion, Background) + * + * Primary zones start Expanded; all other types start Collapsed. + */ + CommandZoneState(qreal zoneHeight, CommandZoneType zoneType); + + // === Query Methods === + + [[nodiscard]] bool isPrimary() const; + [[nodiscard]] bool isMinimized() const; + + /** + * @brief Returns whether the zone is currently expanded (not collapsed). + * + * Note: A minimized zone is still considered "expanded" because it has + * non-zero height. This method returns false only for Collapsed visibility. + */ + [[nodiscard]] bool isExpanded() const; + + [[nodiscard]] bool isCollapsed() const; + + /// Returns current visual height: 0 (collapsed), 25% (minimized), or full. + [[nodiscard]] qreal currentHeight() const; + + /** + * @brief Returns the zone type. + * @return The CommandZoneType of this zone + */ + [[nodiscard]] CommandZoneType getZoneType() const; + + /** + * @brief Returns the full (non-minimized) height of the zone. + * @return Full height in pixels + */ + [[nodiscard]] qreal getZoneHeight() const; + + // === Mutation Methods === + + /** + * @brief Attempts to set the expanded state of a collapsible zone. + * + * No-op for Primary zone. When collapsing, transitions from Expanded/Minimized + * to Collapsed (emitting minimizedChanged if was minimized). When expanding, + * transitions to Expanded. + * + * @param expanded True to expand, false to collapse + * @param collapseBlocked True if external conditions prevent collapsing (e.g., cards present) + * @return StateChangeResult indicating what side effects to trigger + */ + StateChangeResult trySetExpanded(bool expanded, bool collapseBlocked = false); + + /** + * @brief Attempts to toggle the expanded/collapsed state. + * + * No-op for Primary zone. Subject to debounce protection (200ms). + * + * @param collapseBlocked True if external conditions prevent collapsing + * @return StateChangeResult indicating what side effects to trigger + */ + StateChangeResult tryToggleExpanded(bool collapseBlocked = false); + + /** + * @brief Attempts to toggle the minimized state. + * + * No-op for collapsed zones. Toggles between Expanded and Minimized. + * + * @return StateChangeResult indicating what side effects to trigger + */ + StateChangeResult tryToggleMinimized(); + + // === Test Support === + + /** + * @brief Resets the debounce timer to allow immediate toggle. + * + * @warning For testing only. Do not call in production code. + */ + void resetDebounce(); + +private: + qreal m_zoneHeight; ///< Full height in pixels when expanded + CommandZoneType m_zoneType; ///< Type of command zone + ZoneVisibility m_visibility; ///< Current visibility state + QElapsedTimer m_lastToggle; ///< Debounce timer for toggle operations + + static constexpr qint64 TOGGLE_DEBOUNCE_MS = 200; +}; + +#endif // COCKATRICE_COMMAND_ZONE_STATE_H diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d80ccce4f..f7fe7ee2a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -61,5 +61,6 @@ target_link_libraries( ) add_subdirectory(carddatabase) +add_subdirectory(command_zone) add_subdirectory(loading_from_clipboard) add_subdirectory(oracle) diff --git a/tests/command_zone/CMakeLists.txt b/tests/command_zone/CMakeLists.txt new file mode 100644 index 000000000..ad78a0bf5 --- /dev/null +++ b/tests/command_zone/CMakeLists.txt @@ -0,0 +1,40 @@ +# ------------------------ +# Qt modules for command zone tests +# Qt::Gui required for QColor in z_values.h +# Qt::Widgets required for QGraphicsItem in abstract_card_item.h +# ------------------------ +set(TEST_QT_MODULES + ${COCKATRICE_QT_VERSION_NAME}::Core + ${COCKATRICE_QT_VERSION_NAME}::Test + ${COCKATRICE_QT_VERSION_NAME}::Gui + ${COCKATRICE_QT_VERSION_NAME}::Widgets +) + +# ------------------------ +# Command Zone State Test +# Tests the extracted CommandZoneState pure state machine +# ------------------------ +add_executable(command_zone_state_test + command_zone_state_test.cpp + ${CMAKE_SOURCE_DIR}/cockatrice/src/game/zones/command_zone_state.cpp +) + +target_include_directories(command_zone_state_test + PRIVATE ${CMAKE_SOURCE_DIR} + PRIVATE ${CMAKE_SOURCE_DIR}/cockatrice/src/game/zones +) + +target_link_libraries(command_zone_state_test + PRIVATE Threads::Threads + PRIVATE ${GTEST_BOTH_LIBRARIES} + PRIVATE ${TEST_QT_MODULES} +) + +add_test(NAME command_zone_state_test COMMAND command_zone_state_test) + +# ------------------------ +# Dependencies on gtest +# ------------------------ +if(NOT GTEST_FOUND) + add_dependencies(command_zone_state_test gtest) +endif() diff --git a/tests/command_zone/command_zone_state_test.cpp b/tests/command_zone/command_zone_state_test.cpp new file mode 100644 index 000000000..f85029ae9 --- /dev/null +++ b/tests/command_zone/command_zone_state_test.cpp @@ -0,0 +1,387 @@ +/** + * @file command_zone_state_test.cpp + * @brief Unit tests for CommandZoneState pure state machine + * + * Tests the extracted visibility/height state logic: + * - Primary zone: always expanded, cannot be collapsed + * - Partner/Companion/Background zones: start collapsed, can be toggled + * - All zones: can be minimized to 25% height + * - Toggle debouncing: rejects rapid toggles within 200ms + * - StateChangeResult: flags correctly indicate required side effects + * + * @see CommandZoneState for the class under test + */ + +#include "cockatrice/src/game/zones/command_zone_state.h" +#include "command_zone_test_common.h" + +#include + +// ============ Parameterized Tests for Non-Primary Zones ============ + +class NonPrimaryZoneStateTest : public ::testing::TestWithParam +{ +protected: + CommandZoneState *zone = nullptr; + + void TearDown() override + { + delete zone; + } + + void createZone(qreal height = 100.0) + { + delete zone; + zone = new CommandZoneState(height, GetParam()); + } +}; + +INSTANTIATE_TEST_SUITE_P(NonPrimaryZones, + NonPrimaryZoneStateTest, + ::testing::Values(CommandZoneType::Partner, + CommandZoneType::Companion, + CommandZoneType::Background), + [](const ::testing::TestParamInfo &info) { + switch (info.param) { + case CommandZoneType::Partner: + return "Partner"; + case CommandZoneType::Companion: + return "Companion"; + case CommandZoneType::Background: + return "Background"; + default: + return "Unknown"; + } + }); + +TEST_P(NonPrimaryZoneStateTest, StartsCollapsed) +{ + createZone(); + EXPECT_FALSE(zone->isExpanded()) << "Non-primary zone should start collapsed"; + EXPECT_FALSE(zone->isPrimary()); + EXPECT_EQ(GetParam(), zone->getZoneType()); +} + +TEST_P(NonPrimaryZoneStateTest, TryToggleExpanded) +{ + createZone(); + ASSERT_FALSE(zone->isExpanded()); + + auto result = zone->tryToggleExpanded(); + + EXPECT_TRUE(zone->isExpanded()) << "Should expand after toggle"; + EXPECT_TRUE(result.geometryChanged); +} + +TEST_P(NonPrimaryZoneStateTest, CurrentHeight_Expanded) +{ + createZone(100.0); + zone->trySetExpanded(true); + EXPECT_DOUBLE_EQ(100.0, zone->currentHeight()) << "Expanded zone should have full height"; +} + +class CommandZoneStateTest : public ::testing::Test +{ +protected: + CommandZoneState *zone; + + void SetUp() override + { + zone = nullptr; + } + + void TearDown() override + { + delete zone; + } + + void createPrimaryZone(qreal height = 100.0) + { + delete zone; + zone = new CommandZoneState(height, CommandZoneType::Primary); + } + + void createPartnerZone(qreal height = 100.0) + { + delete zone; + zone = new CommandZoneState(height, CommandZoneType::Partner); + } + + void createCompanionZone(qreal height = 100.0) + { + delete zone; + zone = new CommandZoneState(height, CommandZoneType::Companion); + } + + void createBackgroundZone(qreal height = 100.0) + { + delete zone; + zone = new CommandZoneState(height, CommandZoneType::Background); + } +}; + +// ============ Primary Zone Tests ============ + +TEST_F(CommandZoneStateTest, PrimaryZone_AlwaysExpanded) +{ + createPrimaryZone(); + + EXPECT_TRUE(zone->isExpanded()) << "Primary zone should start expanded"; + EXPECT_TRUE(zone->isPrimary()) << "Primary zone should report isPrimary() true"; +} + +TEST_F(CommandZoneStateTest, PrimaryZone_TryToggleExpanded_NoOp) +{ + createPrimaryZone(); + ASSERT_TRUE(zone->isExpanded()); + + auto result = zone->tryToggleExpanded(); + + EXPECT_TRUE(zone->isExpanded()) << "Primary zone should remain expanded after tryToggleExpanded"; + EXPECT_FALSE(result.geometryChanged) << "No geometry change for Primary zone toggle"; + EXPECT_FALSE(result.shouldEmitExpanded) << "No expanded signal for Primary zone toggle"; +} + +TEST_F(CommandZoneStateTest, CurrentHeight_PrimaryFull) +{ + createPrimaryZone(100.0); + + EXPECT_DOUBLE_EQ(100.0, zone->currentHeight()) << "Primary zone should have full height"; +} + +TEST_F(CommandZoneStateTest, CurrentHeight_PrimaryMinimized) +{ + createPrimaryZone(100.0); + + auto result = zone->tryToggleMinimized(); + + EXPECT_DOUBLE_EQ(25.0, zone->currentHeight()) << "Minimized primary zone should be 25% height"; + EXPECT_TRUE(result.geometryChanged); + EXPECT_TRUE(result.shouldEmitMinimized); +} + +// ============ Partner Zone Tests (Partner-specific behaviors) ============ + +TEST_F(CommandZoneStateTest, PartnerZone_TryToggleExpanded_TwiceCollapses) +{ + createPartnerZone(); + zone->tryToggleExpanded(); + ASSERT_TRUE(zone->isExpanded()); + + zone->resetDebounce(); + auto result = zone->tryToggleExpanded(); + + EXPECT_FALSE(zone->isExpanded()) << "Partner zone should collapse after second toggle"; + EXPECT_TRUE(result.geometryChanged); + EXPECT_TRUE(result.shouldEmitExpanded); +} + +TEST_F(CommandZoneStateTest, CurrentHeight_PartnerCollapsed) +{ + createPartnerZone(100.0); + ASSERT_FALSE(zone->isExpanded()); + + EXPECT_DOUBLE_EQ(0.0, zone->currentHeight()) << "Collapsed partner zone should have 0 height"; +} + +TEST_F(CommandZoneStateTest, CurrentHeight_PartnerExpandedMinimized) +{ + createPartnerZone(100.0); + zone->trySetExpanded(true); + + zone->tryToggleMinimized(); + + EXPECT_DOUBLE_EQ(25.0, zone->currentHeight()) << "Expanded+minimized partner zone should be 25% height"; +} + +// ============ Debounce Tests ============ + +TEST_F(CommandZoneStateTest, TryToggleDebounce_RejectsRapidCalls) +{ + createPartnerZone(); + ASSERT_FALSE(zone->isExpanded()); + + zone->tryToggleExpanded(); + ASSERT_TRUE(zone->isExpanded()); + + auto result = zone->tryToggleExpanded(); + + EXPECT_TRUE(zone->isExpanded()) << "Rapid toggle should be rejected (debounced)"; + EXPECT_FALSE(result.geometryChanged) << "Debounced toggle should not change geometry"; +} + +TEST_F(CommandZoneStateTest, TryToggleDebounce_AcceptsAfterReset) +{ + createPartnerZone(); + + zone->tryToggleExpanded(); + ASSERT_TRUE(zone->isExpanded()); + + zone->resetDebounce(); + + auto result = zone->tryToggleExpanded(); + + EXPECT_FALSE(zone->isExpanded()) << "Toggle after reset should work"; + EXPECT_TRUE(result.geometryChanged); +} + +// ============ Minimize Tests ============ + +TEST_F(CommandZoneStateTest, Zone_StartsNotMinimized) +{ + createPrimaryZone(); + + EXPECT_FALSE(zone->isMinimized()) << "Zone should start not minimized"; +} + +TEST_F(CommandZoneStateTest, TryToggleMinimized_TogglesState) +{ + createPrimaryZone(); + ASSERT_FALSE(zone->isMinimized()); + + auto result = zone->tryToggleMinimized(); + + EXPECT_TRUE(zone->isMinimized()) << "Zone should be minimized after toggle"; + EXPECT_TRUE(result.geometryChanged); + EXPECT_TRUE(result.shouldEmitMinimized); +} + +TEST_F(CommandZoneStateTest, TryToggleMinimized_Twice_RestoresState) +{ + createPrimaryZone(); + zone->tryToggleMinimized(); + ASSERT_TRUE(zone->isMinimized()); + + auto result = zone->tryToggleMinimized(); + + EXPECT_FALSE(zone->isMinimized()) << "Zone should be restored after second toggle"; + EXPECT_TRUE(result.geometryChanged); + EXPECT_TRUE(result.shouldEmitMinimized); +} + +TEST_F(CommandZoneStateTest, TryToggleMinimized_NoOpWhenCollapsed) +{ + createPartnerZone(); + ASSERT_TRUE(zone->isCollapsed()); + + auto result = zone->tryToggleMinimized(); + + EXPECT_FALSE(result.geometryChanged) << "Collapsed zone should not toggle minimized"; + EXPECT_FALSE(result.shouldEmitMinimized); +} + +// ============ StateChangeResult Tests ============ + +TEST_F(CommandZoneStateTest, TrySetExpanded_ReturnsCorrectResult_OnExpand) +{ + createPartnerZone(); + ASSERT_FALSE(zone->isExpanded()); + + auto result = zone->trySetExpanded(true); + + EXPECT_TRUE(result.geometryChanged); + EXPECT_TRUE(result.shouldEmitExpanded); + EXPECT_FALSE(result.shouldEmitMinimized); +} + +TEST_F(CommandZoneStateTest, TrySetExpanded_ReturnsCorrectResult_OnCollapse) +{ + createPartnerZone(); + zone->trySetExpanded(true); + ASSERT_TRUE(zone->isExpanded()); + + auto result = zone->trySetExpanded(false); + + EXPECT_TRUE(result.geometryChanged); + EXPECT_TRUE(result.shouldEmitExpanded); + EXPECT_FALSE(result.shouldEmitMinimized) << "Not minimized before collapse"; +} + +TEST_F(CommandZoneStateTest, TrySetExpanded_ReturnsCorrectResult_OnCollapseWhileMinimized) +{ + createPartnerZone(); + zone->trySetExpanded(true); + zone->tryToggleMinimized(); + ASSERT_TRUE(zone->isMinimized()); + + auto result = zone->trySetExpanded(false); + + EXPECT_TRUE(result.geometryChanged); + EXPECT_TRUE(result.shouldEmitExpanded); + EXPECT_TRUE(result.shouldEmitMinimized) << "Was minimized before collapse"; +} + +TEST_F(CommandZoneStateTest, TrySetExpanded_NoChange_ReturnsNoChangeResult) +{ + createPartnerZone(); + zone->trySetExpanded(true); + ASSERT_TRUE(zone->isExpanded()); + + auto result = zone->trySetExpanded(true); + + EXPECT_FALSE(result.geometryChanged) << "No change when already in target state"; + EXPECT_FALSE(result.shouldEmitExpanded); + EXPECT_FALSE(result.shouldEmitMinimized); +} + +TEST_F(CommandZoneStateTest, TrySetExpanded_Blocked_ReturnsNoChangeResult) +{ + createPartnerZone(); + zone->trySetExpanded(true); + ASSERT_TRUE(zone->isExpanded()); + + auto result = zone->trySetExpanded(false, true); + + EXPECT_FALSE(result.geometryChanged) << "Collapse blocked"; + EXPECT_TRUE(zone->isExpanded()) << "Should still be expanded"; +} + +TEST_F(CommandZoneStateTest, TryToggleMinimized_ReturnsCorrectResult) +{ + createPrimaryZone(); + + auto result = zone->tryToggleMinimized(); + + EXPECT_TRUE(result.geometryChanged); + EXPECT_FALSE(result.shouldEmitExpanded) << "Minimized toggle doesn't change expanded state"; + EXPECT_TRUE(result.shouldEmitMinimized); +} + +// ============ Edge Cases ============ + +TEST_F(CommandZoneStateTest, PartnerCollapsedMinimized_ZeroHeight) +{ + createPartnerZone(100.0); + ASSERT_FALSE(zone->isExpanded()); + + zone->tryToggleMinimized(); + + EXPECT_DOUBLE_EQ(0.0, zone->currentHeight()) << "Collapsed partner zone should be 0 height even when minimized"; +} + +TEST_F(CommandZoneStateTest, DifferentZoneHeight) +{ + createPrimaryZone(200.0); + + EXPECT_DOUBLE_EQ(200.0, zone->currentHeight()); + EXPECT_DOUBLE_EQ(200.0, zone->getZoneHeight()); + + zone->tryToggleMinimized(); + + EXPECT_DOUBLE_EQ(50.0, zone->currentHeight()) << "25% of 200 should be 50"; +} + +TEST_F(CommandZoneStateTest, NoChange_StaticMethod) +{ + auto result = StateChangeResult::noChange(); + + EXPECT_FALSE(result.geometryChanged); + EXPECT_FALSE(result.shouldEmitExpanded); + EXPECT_FALSE(result.shouldEmitMinimized); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}