Files
firmware/test/test_chirpy/test_main.cpp
Jonathan Bennett 8d1fbbf55f Snake! (#10936)
* Snake!

* Add spiLock to snake score saving

* Check fixes

* More careful locking

* WIP: Big Display Node

* Update src/graphics/HUB75Display.cpp

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Add HUB75 Native

* Add Tetris game module with core logic and UI integration

- Implement TetrisGame class for game logic, including piece movement, rotation, and line clearing.
- Create TetrisModule class to manage game state, input handling, and rendering on OLED display.
- Introduce high score tracking with persistence and optional mesh broadcasting.
- Define UI states for title, playing, paused, game over, and high scores.
- Implement input handling for game controls and state transitions.
- Add rendering functions for the game board, high scores, and title screen.

* feat(snake): add snake graphics and update display logic in SnakeModule

* Prompt for Initials for Tetris, too

* refactor games module

* Games refactor

* hub75 native double buffer

* Games tuning

* Make joystick repeat events on held button

* Add clouds and colors

* Fix breakout and more color

* difficulty tuning

* trunk

* refactor game announcements, etc

* Scale chirpy gravity as game speed increases

* Portduino, check for hub75 display before reading in hub75 options

* Final(?) games tuning

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Properly ignore input when games screen not shown

* Fail gracefully when HUB75 is selected but not supported.

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Ixitxachitl <kramerfm@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-16 18:35:33 -05:00

101 lines
2.7 KiB
C++

#include "TestUtil.h"
#include "modules/games/ChirpyRunner.h"
#include <unity.h>
// Pure-logic tests for ChirpyRunnerGame: initial state, jump lifts Chirpy off the ground,
// obstacles spawn and a collision ends the run, and a dead game is inert. No device globals.
static const uint32_t kSeed = 0xC0FFEEu;
void test_reset_initialState()
{
ChirpyRunnerGame game;
game.reset(kSeed);
TEST_ASSERT_TRUE(game.isPlaying());
TEST_ASSERT_EQUAL_UINT32(0, game.score());
TEST_ASSERT_TRUE(game.onGround());
TEST_ASSERT_EQUAL_INT16(ChirpyRunnerGame::GROUND_Y - ChirpyRunnerGame::CHIRPY_H, game.chirpyY());
}
void test_jump_liftsChirpy()
{
ChirpyRunnerGame game;
game.reset(kSeed);
const int16_t groundY = game.chirpyY();
game.jump();
game.step();
TEST_ASSERT_FALSE(game.onGround());
TEST_ASSERT_TRUE(game.chirpyY() < groundY); // rose above the ground rest position
}
void test_jump_ignoredWhileAirborne()
{
ChirpyRunnerGame game;
game.reset(kSeed);
game.jump();
game.step();
const int16_t yAfterFirst = game.chirpyY();
// A second jump mid-air must not re-launch: after another step Chirpy keeps descending toward
// the ground under gravity rather than shooting back up.
game.jump();
game.step();
// Not asserting exact physics, only that we're still airborne and moving as one arc, not reset.
TEST_ASSERT_FALSE(game.onGround());
(void)yAfterFirst;
}
void test_obstacleSpawnsAndCollisionEndsGame()
{
ChirpyRunnerGame game;
game.reset(kSeed);
// One step spawns the first obstacle.
game.step();
bool any = false;
for (uint8_t i = 0; i < ChirpyRunnerGame::obstacleSlots(); i++)
any = any || game.obstacleActive(i);
TEST_ASSERT_TRUE(any);
// Never jumping, an obstacle must reach grounded Chirpy and end the run.
int steps = 0;
while (game.isPlaying() && steps < 2000) {
game.step();
steps++;
}
TEST_ASSERT_FALSE(game.isPlaying());
}
void test_deadGame_stepIsNoOp()
{
ChirpyRunnerGame game;
game.reset(kSeed);
int steps = 0;
while (game.isPlaying() && steps < 2000) {
game.step();
steps++;
}
TEST_ASSERT_FALSE(game.isPlaying());
const uint32_t scoreBefore = game.score();
TEST_ASSERT_FALSE(game.step()); // stays dead, no further change
TEST_ASSERT_EQUAL_UINT32(scoreBefore, game.score());
}
void setUp(void) {}
void tearDown(void) {}
extern "C" {
void setup()
{
initializeTestEnvironment();
UNITY_BEGIN();
RUN_TEST(test_reset_initialState);
RUN_TEST(test_jump_liftsChirpy);
RUN_TEST(test_jump_ignoredWhileAirborne);
RUN_TEST(test_obstacleSpawnsAndCollisionEndsGame);
RUN_TEST(test_deadGame_stepIsNoOp);
exit(UNITY_END());
}
void loop() {}
}