119 lines
5.1 KiB
C
119 lines
5.1 KiB
C
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "state_presenter.h"
|
|
|
|
static void set_board(board_t *board) {
|
|
memset(board, 0, sizeof(*board));
|
|
board->cells[0] = CELL_SHIP;
|
|
board->cells[1] = CELL_MISS;
|
|
board->cells[2] = CELL_HIT;
|
|
board->cells[99] = CELL_SHIP;
|
|
}
|
|
|
|
static const char *board_start(const char *json, uint8_t board) {
|
|
const char *first = strstr(json, "\"boards\":[\"");
|
|
assert(first != NULL);
|
|
first += strlen("\"boards\":[\"");
|
|
return board == 0U ? first : first + kBoardCellCount + 3U;
|
|
}
|
|
|
|
static void assert_hidden(const char *json, uint8_t board) {
|
|
const char *cells = board_start(json, board);
|
|
for (uint8_t index = 0; index < kBoardCellCount; ++index) assert(cells[index] != '1');
|
|
}
|
|
|
|
static void test_role_views_and_golden_schema(void) {
|
|
game_state_t state = {0};
|
|
state.game_id = 42U;
|
|
state.version = 9U;
|
|
state.phase = PHASE_IN_PROGRESS;
|
|
state.mode = MODE_HUMAN;
|
|
state.current_player = 1U;
|
|
state.winner = kPlayerCapacity;
|
|
set_board(&state.boards[0]);
|
|
set_board(&state.boards[1]);
|
|
char output[kStateMessageCapacity] = {0};
|
|
size_t written = 0;
|
|
|
|
assert(state_presenter_write(&state, ROLE_PLAYER_1, output, sizeof(output), &written));
|
|
assert(written == strlen(output));
|
|
assert(strstr(output, "{\"type\":\"state\",\"version\":9,\"gameId\":42,\"phase\":\"in_progress\",\"mode\":\"human\",\"viewer\":\"player1\",\"turn\":\"player2\",\"players\":[\"\",\"\"],\"boards\":[\"") == output);
|
|
assert(board_start(output, 0)[0] == '1' && board_start(output, 0)[1] == '2' && board_start(output, 0)[2] == '3');
|
|
assert_hidden(output, 1);
|
|
assert(strstr(output, "\"players\":[\"\",\"\"]") != NULL);
|
|
|
|
assert(state_presenter_write(&state, ROLE_PLAYER_2, output, sizeof(output), &written));
|
|
assert_hidden(output, 0);
|
|
assert(board_start(output, 1)[0] == '1');
|
|
|
|
assert(state_presenter_write(&state, ROLE_SPECTATOR, output, sizeof(output), &written));
|
|
assert_hidden(output, 0);
|
|
assert_hidden(output, 1);
|
|
assert(board_start(output, 0)[1] == '2' && board_start(output, 1)[2] == '3');
|
|
assert(strstr(output, "\"winner\":null,\"statistics\":[[0,0,0,0],[0,0,0,0]]") != NULL);
|
|
}
|
|
|
|
static void test_finished_and_failure_are_safe(void) {
|
|
game_state_t state = {0};
|
|
state.game_id = UINT32_MAX;
|
|
state.version = UINT32_MAX;
|
|
state.phase = PHASE_FINISHED;
|
|
state.mode = MODE_BOT;
|
|
state.current_player = 0U;
|
|
set_board(&state.boards[0]);
|
|
set_board(&state.boards[1]);
|
|
char output[kStateMessageCapacity] = {0};
|
|
size_t written = 0;
|
|
assert(state_presenter_write(&state, ROLE_SPECTATOR, output, sizeof(output), &written));
|
|
assert(written < sizeof(output));
|
|
assert(board_start(output, 0)[0] == '1' && board_start(output, 1)[99] == '1');
|
|
|
|
game_lifecycle_t lifecycle = {0};
|
|
lifecycle.game.state = state;
|
|
lifecycle.game.state.phase = PHASE_REMATCH_WAIT;
|
|
lifecycle.game.state.mode = MODE_HUMAN;
|
|
lifecycle.game.state.winner = 1U;
|
|
lifecycle.game.state.statistics[0] = (match_statistics_t){.shots = 9U, .hits = 4U, .misses = 5U, .ships_sunk = 2U};
|
|
lifecycle.game.state.statistics[1] = (match_statistics_t){.shots = 8U, .hits = 5U, .misses = 3U, .ships_sunk = 3U};
|
|
lifecycle.sessions.entries[0] = (session_t){.occupied = true, .role = ROLE_PLAYER_1, .name = "Алиса"};
|
|
lifecycle.sessions.entries[1] = (session_t){.occupied = true, .role = ROLE_PLAYER_2, .name = "Борис"};
|
|
lifecycle.cumulative[0].wins = UINT16_MAX;
|
|
lifecycle.cumulative[1].wins = UINT16_MAX;
|
|
assert(state_presenter_write_lifecycle(&lifecycle, ROLE_SPECTATOR, output, sizeof(output), &written));
|
|
assert(written < sizeof(output));
|
|
assert(strstr(output, "\"winner\":1,\"statistics\":[[9,4,5,2],[8,5,3,3]]") != NULL);
|
|
assert(strstr(output, "\"players\":[\"Алиса\",\"Борис\"]") != NULL);
|
|
|
|
memset(lifecycle.sessions.entries[0].name, 'A', kDisplayNameBytes);
|
|
memset(lifecycle.sessions.entries[1].name, 'B', kDisplayNameBytes);
|
|
lifecycle.sessions.entries[0].name[kDisplayNameBytes] = '\0';
|
|
lifecycle.sessions.entries[1].name[kDisplayNameBytes] = '\0';
|
|
assert(state_presenter_write_lifecycle(&lifecycle, ROLE_SPECTATOR, output, sizeof(output), &written));
|
|
assert(written < sizeof(output));
|
|
|
|
lifecycle.game.state.statistics[0] = (match_statistics_t){UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT8_MAX};
|
|
lifecycle.game.state.statistics[1] = (match_statistics_t){UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT8_MAX};
|
|
assert(state_presenter_write_lifecycle(&lifecycle, ROLE_SPECTATOR, output, sizeof(output), &written));
|
|
assert(written < sizeof(output));
|
|
|
|
state.boards[0].ships[0] = (ship_t){.x = 2U, .y = 0U, .length = 1U, .hits = 1U, .horizontal = true};
|
|
assert(state_presenter_write(&state, ROLE_SPECTATOR, output, sizeof(output), &written));
|
|
assert(board_start(output, 0)[2] == '4');
|
|
|
|
char unchanged[16];
|
|
memset(unchanged, 'X', sizeof(unchanged));
|
|
size_t failure_written = 99U;
|
|
assert(!state_presenter_write(&state, ROLE_PLAYER_1, unchanged, sizeof(unchanged), &failure_written));
|
|
assert(failure_written == 0U);
|
|
for (size_t index = 0; index < sizeof(unchanged); ++index) assert(unchanged[index] == 'X');
|
|
}
|
|
|
|
int main(void) {
|
|
test_role_views_and_golden_schema();
|
|
test_finished_and_failure_are_safe();
|
|
puts("state presenter tests passed");
|
|
return 0;
|
|
}
|