// // game_dispatch_test.cxx // engine-test // // Created by Sam Jaffe on 7/10/19. // Copyright © 2019 Sam Jaffe. All rights reserved. // #include "game/engine/game_dispatch.hpp" #include #include #include #include #include #include "game/engine/events.hpp" #include "game/engine/scene.hpp" #include "mock_renderer.h" struct mock_scene : engine::scene { mock_scene(std::shared_ptr game) : engine::scene("mock", {0.f, 0.f}, game) {} mock_scene(std::shared_ptr game, math::vec2 dim) : engine::scene("mock2", dim, game) {} MOCK_METHOD1(update, void(float)); MOCK_METHOD0(render, void()); MOCK_METHOD1(handle_key_event, void(engine::event::key_event)); MOCK_METHOD1(handle_mouse_event, void(engine::event::mouse_event)); }; class GameDispatchTest : public testing::Test { protected: void SetUp() override; void TearDown() override; mock_scene & scene() const { return *scene_; } engine::game_dispatch & game() const { return *dispatch_; } std::shared_ptr renderer_; std::shared_ptr dispatch_; std::shared_ptr scene_; }; void GameDispatchTest::SetUp() { env::resize_screen(math::vec2i{{100, 100}}); renderer_.reset(new stub_renderer); dispatch_.reset(new engine::game_dispatch(renderer_)); dispatch_->set_target_fps(env::fps::v60); scene_.reset(new mock_scene(dispatch_)); game().register_scene(scene_); game().activate_scene("mock"); } void GameDispatchTest::TearDown() { scene_.reset(); dispatch_.reset(); renderer_.reset(); } using testing::_; using testing::AnyNumber; using testing::Eq; using testing::Field; using testing::FloatNear; using testing::Ge; using testing::Lt; using testing::Not; TEST_F(GameDispatchTest, ManagerIsFetchedFromRenderer) { EXPECT_THAT(&game().graphics_manager(), Eq(renderer_->manager().get())); } // TODO: Set FPS to a much smaller value for testing purposes (e.g. 512fps) TEST_F(GameDispatchTest, UpdateDispatchesToCurrentScene) { EXPECT_CALL(scene(), update(_)).Times(1); game().update(); } TEST_F(GameDispatchTest, UpdateIsCappedInFrequencyByFPSParam) { auto fps60 = 1.0 / 60.0; EXPECT_CALL(scene(), update(Ge(fps60))).Times(AnyNumber()); EXPECT_CALL(scene(), update(Lt(fps60))).Times(0); for (int i = 0; i < 10; i++) { game().update(); } } TEST_F(GameDispatchTest, FPSCanBeChanged) { game().set_target_fps(env::fps::v120); auto fps120 = 1.0 / 120.0; EXPECT_CALL(scene(), update(Ge(fps120))).Times(AnyNumber()); EXPECT_CALL(scene(), update(Lt(fps120))).Times(0); for (int i = 0; i < 10; i++) { game().update(); } } TEST_F(GameDispatchTest, UpdateHasNoUpperBoundOnTime) { EXPECT_CALL(scene(), update(Ge(0.03))).Times(1); usleep(300000); game().update(); } TEST_F(GameDispatchTest, SetCurrentTimestampOverridesWaiting) { auto fps60 = 1.0 / 60.0; EXPECT_CALL(scene(), update(Ge(0.03))).Times(0); EXPECT_CALL(scene(), update(FloatNear(fps60, 1E-2))).Times(1); usleep(300000); game().set_current_timestamp(); game().update(); } TEST_F(GameDispatchTest, RenderDispatchesToCurrentScene) { EXPECT_CALL(scene(), render()).Times(1); game().render(); } using MouseEventTest = GameDispatchTest; TEST_F(MouseEventTest, DispatchesToCurrentScene) { EXPECT_CALL(scene(), handle_mouse_event(_)).Times(1); game().process_mouse_event({{0.f, 0.f}}, true); } MATCHER(WasPressed, "") { return (arg.type & engine::event::PRESSED_MASK) != 0; } TEST_F(MouseEventTest, CanPressAndRelease) { EXPECT_CALL(scene(), handle_mouse_event(WasPressed())).Times(1); game().process_mouse_event({}, true); EXPECT_CALL(scene(), handle_mouse_event(Not(WasPressed()))).Times(1); game().process_mouse_event({}, false); } TEST_F(MouseEventTest, TranslatesFrameOfRef) { // Resize the scene (not a supported operation) scene_.reset(new mock_scene(dispatch_, {10.f, 10.f})); game().register_scene(scene_); game().activate_scene("mock2"); auto mouse_pos = &engine::event::mouse_event::current_mouse_position; math::vec2 const where{5.f, 5.f}; EXPECT_CALL(scene(), handle_mouse_event(Field(mouse_pos, where))).Times(1); game().process_mouse_event({{50.f, 50.f}}, true); } using KeyEventTest = GameDispatchTest; TEST_F(KeyEventTest, DoesNotDispatchUnmappedKeys) { EXPECT_CALL(scene(), handle_key_event(_)).Times(0); game().process_key_event('A', true); } TEST_F(KeyEventTest, RemapsKeyWhenForwarding) { // TODO: Properly set this instead of using this garbage const_cast(scene().keys()).emplace('A', 'B'); auto key_value = &engine::event::key_event::key; EXPECT_CALL(scene(), handle_key_event(Field(key_value, 'A'))).Times(0); EXPECT_CALL(scene(), handle_key_event(Field(key_value, 'B'))).Times(1); game().process_key_event('A', true); }