446 lines
15 KiB
C
446 lines
15 KiB
C
|
/* ----------------------------------------------------------------------------
|
||
|
* -- _____ ______ _____ -
|
||
|
* -- |_ _| | ____|/ ____| -
|
||
|
* -- | | _ __ | |__ | (___ Institute of Embedded Systems -
|
||
|
* -- | | | '_ \| __| \___ \ Zuercher Hochschule Winterthur -
|
||
|
* -- _| |_| | | | |____ ____) | (University of Applied Sciences) -
|
||
|
* -- |_____|_| |_|______|_____/ 8401 Winterthur, Switzerland -
|
||
|
* ----------------------------------------------------------------------------
|
||
|
*/
|
||
|
/**
|
||
|
* @file
|
||
|
* @brief Test suite for the given package.
|
||
|
*/
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <sys/wait.h>
|
||
|
#include <time.h>
|
||
|
#include <assert.h>
|
||
|
#include <CUnit/Basic.h>
|
||
|
#include "test_utils.h"
|
||
|
#include "model.h"
|
||
|
|
||
|
#ifndef TARGET // must be given by the make file --> see test target
|
||
|
#error missing TARGET define
|
||
|
#endif
|
||
|
|
||
|
/// @brief alias for EXIT_SUCCESS
|
||
|
#define OK EXIT_SUCCESS
|
||
|
/// @brief alias for EXIT_FAILURE
|
||
|
#define FAIL EXIT_FAILURE
|
||
|
|
||
|
/// @brief The name of the STDOUT text file.
|
||
|
#define OUTFILE "stdout.txt"
|
||
|
/// @brief The name of the STDERR text file.
|
||
|
#define ERRFILE "stderr.txt"
|
||
|
|
||
|
#define TRACE_INDENT "\n " ///< allow for better stdout formatting in case of error
|
||
|
|
||
|
// setup & cleanup
|
||
|
static int setup(void)
|
||
|
{
|
||
|
remove_file_if_exists(OUTFILE);
|
||
|
remove_file_if_exists(ERRFILE);
|
||
|
return 0; // success
|
||
|
}
|
||
|
|
||
|
static int teardown(void)
|
||
|
{
|
||
|
// Do nothing.
|
||
|
// Especially: do not remove result files - they are removed in int setup(void) *before* running a test.
|
||
|
return 0; // success
|
||
|
}
|
||
|
|
||
|
// test utils
|
||
|
static void init_model(model_t *instance, int act)
|
||
|
{
|
||
|
if (act) printf(TRACE_INDENT "init_model:... ");
|
||
|
model_init(instance);
|
||
|
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||
|
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||
|
if (act) printf("%zd/%zd ", row, col);
|
||
|
CU_ASSERT_EQUAL_FATAL(instance->board[row][col], model_state_none);
|
||
|
}
|
||
|
}
|
||
|
if (act) printf(TRACE_INDENT);
|
||
|
}
|
||
|
|
||
|
static void print_board(model_state_t board[MODEL_SIZE][MODEL_SIZE])
|
||
|
{
|
||
|
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||
|
printf("{ ");
|
||
|
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||
|
printf("%d ", board[row][col]);
|
||
|
}
|
||
|
printf("} ");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// tests
|
||
|
static void test_model_init(void)
|
||
|
{
|
||
|
// check void model_init(model_t *instance);
|
||
|
|
||
|
// arrange
|
||
|
model_t model;
|
||
|
// act & assert
|
||
|
init_model(&model, 1);
|
||
|
}
|
||
|
|
||
|
static void test_model_get_state(void)
|
||
|
{
|
||
|
// check: model_state_t model_get_state(model_t *instance, model_pos_t pos);
|
||
|
|
||
|
{
|
||
|
// arrange
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "initial state:... ");
|
||
|
print_board(model.board);
|
||
|
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||
|
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||
|
printf("%zd/%zd ", row, col);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_get_state(&model, model_pos(row, col)), model_state_none);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
{
|
||
|
// arrange
|
||
|
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||
|
{ model_state_none, model_state_a, model_state_b },
|
||
|
{ model_state_a, model_state_b, model_state_none },
|
||
|
{ model_state_b, model_state_none, model_state_a },
|
||
|
};
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
memcpy(model.board, board, sizeof(board));
|
||
|
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "modified state:... ");
|
||
|
print_board(model.board);
|
||
|
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||
|
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||
|
printf("%zd/%zd ", row, col);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_get_state(&model, model_pos(row, col)), board[row][col]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
printf(TRACE_INDENT);
|
||
|
}
|
||
|
|
||
|
static void test_model_get_winner(void)
|
||
|
{
|
||
|
// check: model_state_t model_get_winner(model_t *instance);
|
||
|
|
||
|
{
|
||
|
// arrange
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "initial no winner:... ");
|
||
|
print_board(model.board);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_get_winner(&model), model_state_none);
|
||
|
}
|
||
|
{
|
||
|
// arrange
|
||
|
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||
|
{ model_state_none, model_state_a, model_state_b },
|
||
|
{ model_state_a, model_state_b, model_state_none },
|
||
|
{ model_state_b, model_state_none, model_state_a },
|
||
|
};
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
memcpy(model.board, board, sizeof(board));
|
||
|
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "winner:... ");
|
||
|
print_board(model.board);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_get_winner(&model), model_state_b);
|
||
|
}
|
||
|
printf(TRACE_INDENT);
|
||
|
}
|
||
|
|
||
|
static void test_model_can_move(void)
|
||
|
{
|
||
|
// check: int model_can_move(model_t *instance);
|
||
|
|
||
|
{
|
||
|
// arrange
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "initial can move:... ");
|
||
|
print_board(model.board);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_can_move(&model), 1);
|
||
|
}
|
||
|
{
|
||
|
// arrange
|
||
|
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||
|
{ model_state_none, model_state_a, model_state_a },
|
||
|
{ model_state_a, model_state_b, model_state_none },
|
||
|
{ model_state_b, model_state_none, model_state_b },
|
||
|
};
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
memcpy(model.board, board, sizeof(board));
|
||
|
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "can move while not yet done nor win:... ");
|
||
|
print_board(model.board);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_can_move(&model), 1);
|
||
|
}
|
||
|
{
|
||
|
// arrange
|
||
|
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||
|
{ model_state_none, model_state_a, model_state_b },
|
||
|
{ model_state_a, model_state_b, model_state_none },
|
||
|
{ model_state_b, model_state_none, model_state_a },
|
||
|
};
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
memcpy(model.board, board, sizeof(board));
|
||
|
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "cannot move after win:... ");
|
||
|
print_board(model.board);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_can_move(&model), 0);
|
||
|
}
|
||
|
{
|
||
|
// arrange
|
||
|
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||
|
{ model_state_b, model_state_a, model_state_a },
|
||
|
{ model_state_a, model_state_b, model_state_b },
|
||
|
{ model_state_b, model_state_a, model_state_a },
|
||
|
};
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
memcpy(model.board, board, sizeof(board));
|
||
|
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "cannot move when all done:... ");
|
||
|
print_board(model.board);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_can_move(&model), 0);
|
||
|
}
|
||
|
printf(TRACE_INDENT);
|
||
|
}
|
||
|
|
||
|
static void test_model_move(void)
|
||
|
{
|
||
|
// check: int model_move(model_t *instance, model_pos_t pos, model_state_t state);
|
||
|
|
||
|
{
|
||
|
// arrange
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "initial move:... ");
|
||
|
print_board(model.board);
|
||
|
model_pos_t pos_a = model_pos(0, 0);
|
||
|
printf("%zd/%zd ", pos_a.row, pos_a.col);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_a, model_state_a), 1);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_a, model_state_a), 0);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_a, model_state_b), 0);
|
||
|
model_pos_t pos_b = model_pos(2, 2);
|
||
|
printf("%zd/%zd ", pos_b.row, pos_b.col);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_b, model_state_b), 1);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_b, model_state_b), 0);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos_b, model_state_a), 0);
|
||
|
}
|
||
|
{
|
||
|
// arrange
|
||
|
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||
|
{ model_state_none, model_state_a, model_state_a },
|
||
|
{ model_state_a, model_state_b, model_state_none },
|
||
|
{ model_state_b, model_state_none, model_state_b },
|
||
|
};
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
memcpy(model.board, board, sizeof(board));
|
||
|
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "can move while not yet done nor win:... ");
|
||
|
print_board(model.board);
|
||
|
model_pos_t pos = model_pos(2, 1);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_a), 1);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_a), 0);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_b), 0);
|
||
|
}
|
||
|
{
|
||
|
// arrange
|
||
|
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||
|
{ model_state_none, model_state_a, model_state_b },
|
||
|
{ model_state_a, model_state_b, model_state_none },
|
||
|
{ model_state_b, model_state_none, model_state_a },
|
||
|
};
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
memcpy(model.board, board, sizeof(board));
|
||
|
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "cannot move after win:... ");
|
||
|
print_board(model.board);
|
||
|
model_pos_t pos = model_pos(2, 1);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_a), 0);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_b), 0);
|
||
|
}
|
||
|
{
|
||
|
// arrange
|
||
|
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||
|
{ model_state_b, model_state_a, model_state_a },
|
||
|
{ model_state_a, model_state_b, model_state_b },
|
||
|
{ model_state_b, model_state_a, model_state_a },
|
||
|
};
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
memcpy(model.board, board, sizeof(board));
|
||
|
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "cannot move when all done:... ");
|
||
|
print_board(model.board);
|
||
|
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||
|
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||
|
model_pos_t pos = model_pos(row, col);
|
||
|
printf("%zd/%zd ", row, col);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_a), 0);
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, pos, model_state_b), 0);
|
||
|
}
|
||
|
}
|
||
|
CU_ASSERT_EQUAL_FATAL(model_can_move(&model), 0);
|
||
|
}
|
||
|
printf(TRACE_INDENT);
|
||
|
}
|
||
|
|
||
|
static void test_model_get_win_line(void)
|
||
|
{
|
||
|
// check: model_line_t model_get_win_line(model_t *instance);
|
||
|
|
||
|
{
|
||
|
// arrange
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "initial no winner:... ");
|
||
|
print_board(model.board);
|
||
|
model_line_t no_win = model_get_win_line(&model);
|
||
|
CU_ASSERT_EQUAL_FATAL(no_win.dir, model_dir_none);
|
||
|
}
|
||
|
{
|
||
|
// arrange
|
||
|
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||
|
{ model_state_none, model_state_a, model_state_a },
|
||
|
{ model_state_a, model_state_b, model_state_none },
|
||
|
{ model_state_b, model_state_none, model_state_b },
|
||
|
};
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
memcpy(model.board, board, sizeof(board));
|
||
|
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "no winner while not yet done nor win:... ");
|
||
|
print_board(model.board);
|
||
|
model_line_t no_win = model_get_win_line(&model);
|
||
|
CU_ASSERT_EQUAL_FATAL(no_win.dir, model_dir_none);
|
||
|
}
|
||
|
{
|
||
|
// arrange
|
||
|
static const model_state_t board[MODEL_SIZE][MODEL_SIZE] = {
|
||
|
{ model_state_b, model_state_a, model_state_a },
|
||
|
{ model_state_a, model_state_b, model_state_b },
|
||
|
{ model_state_b, model_state_a, model_state_a },
|
||
|
};
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
memcpy(model.board, board, sizeof(board));
|
||
|
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "no winner when all done:... ");
|
||
|
print_board(model.board);
|
||
|
model_line_t no_win = model_get_win_line(&model);
|
||
|
CU_ASSERT_EQUAL_FATAL(no_win.dir, model_dir_none);
|
||
|
}
|
||
|
{
|
||
|
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||
|
// arrange
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, model_pos(row, col), model_state_a), 1);
|
||
|
}
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "row winner:... ");
|
||
|
print_board(model.board);
|
||
|
model_line_t win = model_get_win_line(&model);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.dir, model_dir_h);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.start.row, row);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.start.col, 0);
|
||
|
}
|
||
|
}
|
||
|
{
|
||
|
for(size_t col = 0; col < MODEL_SIZE; col++) {
|
||
|
// arrange
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
for(size_t row = 0; row < MODEL_SIZE; row++) {
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, model_pos(row, col), model_state_a), 1);
|
||
|
}
|
||
|
// act & assert
|
||
|
printf(TRACE_INDENT "column winner:... ");
|
||
|
print_board(model.board);
|
||
|
model_line_t win = model_get_win_line(&model);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.dir, model_dir_v);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.start.row, 0);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.start.col, col);
|
||
|
}
|
||
|
}
|
||
|
{
|
||
|
printf(TRACE_INDENT "diagonal left-right winner:... ");
|
||
|
// arrange
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
for(size_t i = 0; i < MODEL_SIZE; i++) {
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, model_pos(i, i), model_state_a), 1);
|
||
|
}
|
||
|
// act & assert
|
||
|
print_board(model.board);
|
||
|
model_line_t win = model_get_win_line(&model);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.dir, model_dir_d);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.start.row, 0);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.start.col, 0);
|
||
|
}
|
||
|
{
|
||
|
printf(TRACE_INDENT "diagonal right-left winner:... ");
|
||
|
// arrange
|
||
|
model_t model;
|
||
|
init_model(&model, 0);
|
||
|
for(size_t i = 0; i < MODEL_SIZE; i++) {
|
||
|
CU_ASSERT_EQUAL_FATAL(model_move(&model, model_pos(MODEL_SIZE - 1 - i, i), model_state_a), 1);
|
||
|
}
|
||
|
// act & assert
|
||
|
print_board(model.board);
|
||
|
model_line_t win = model_get_win_line(&model);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.dir, model_dir_d);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.start.row, 0);
|
||
|
CU_ASSERT_EQUAL_FATAL(win.start.col, MODEL_SIZE - 1);
|
||
|
}
|
||
|
printf(TRACE_INDENT);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @brief Registers and runs the tests.
|
||
|
* @returns success (0) or one of the CU_ErrorCode (>0)
|
||
|
*/
|
||
|
int main(void)
|
||
|
{
|
||
|
// setup, run, teardown
|
||
|
TestMainBasic("lab test", setup, teardown
|
||
|
, test_model_init
|
||
|
, test_model_get_state
|
||
|
, test_model_get_winner
|
||
|
, test_model_can_move
|
||
|
, test_model_move
|
||
|
, test_model_get_win_line
|
||
|
);
|
||
|
}
|