tests
This commit is contained in:
parent
218ee65e67
commit
ef7b492b24
8 changed files with 355 additions and 18 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -62,3 +62,5 @@ src/high_score.txt
|
|||
src/build/high_score.txt
|
||||
code-samples/frogger/project.md
|
||||
dvi/
|
||||
gcov_report/
|
||||
build/
|
||||
|
|
|
|||
39
src/Makefile
39
src/Makefile
|
|
@ -36,25 +36,17 @@ BINDIR = $(PREFIX)/bin
|
|||
|
||||
all: $(TARGET)
|
||||
|
||||
$(LIB_TETRIS): $(TETRIS_OBJ)
|
||||
mkdir -p $(BUILDDIR)
|
||||
ar rcs $@ $^
|
||||
|
||||
$(TARGET): $(LIB_TETRIS) $(CLI_OBJ)
|
||||
$(CC) $(CLI_OBJ) -L$(BUILDDIR) -ltetris -o $@ $(LDFLAGS)
|
||||
|
||||
brick_game/tetris/%.o: brick_game/tetris/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
gui/cli/%.o: gui/cli/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
run: $(TARGET)
|
||||
./$(TARGET)
|
||||
|
||||
install: $(TARGET)
|
||||
mkdir -p $(BINDIR)
|
||||
install -m 755 $(TARGET) $(BINDIR)/tetris
|
||||
@echo "installed $(BINDIR)/tetris"
|
||||
|
||||
uninstall:
|
||||
rm -f $(BINDIR)/tetris
|
||||
@echo "uninstalled $(BINDIR)/tetris"
|
||||
|
||||
clean:
|
||||
rm -rf $(CLI_OBJ) $(TETRIS_OBJ) $(TARGET) $(LIB_TETRIS) $(TEST_TARGET)
|
||||
|
|
@ -70,11 +62,12 @@ gcov_report: LDFLAGS += --coverage
|
|||
gcov_report: clean test
|
||||
@mkdir -p $(GCOV_DIR)
|
||||
gcov $(TETRIS_SRC) -o $(TETRISDIR)
|
||||
lcov --capture --directory . --output-file $(GCOV_DIR)/coverage.info
|
||||
lcov --remove $(GCOV_DIR)/coverage.info '/usr/*' '*/nix/store/*' -o $(GCOV_DIR)/coverage.info
|
||||
lcov --capture --directory $(TETRISDIR) --output-file $(GCOV_DIR)/coverage.info --ignore-errors unused
|
||||
lcov --extract $(GCOV_DIR)/coverage.info '*/brick_game/tetris/*' -o $(GCOV_DIR)/coverage.info --ignore-errors unused
|
||||
genhtml $(GCOV_DIR)/coverage.info --output-directory $(GCOV_DIR)
|
||||
mv *.gcov $(GCOV_DIR)/ 2>/dev/null || true
|
||||
@mv *.gcov $(GCOV_DIR)/ 2>/dev/null || true
|
||||
@echo "Report: $(GCOV_DIR)/index.html"
|
||||
xdg-open $(GCOV_DIR)/index.html
|
||||
|
||||
dvi:
|
||||
@mkdir -p $(DVI_DIR)
|
||||
|
|
@ -92,9 +85,6 @@ dvi:
|
|||
dist: clean
|
||||
tar -czf tetris.tar.gz Makefile $(TETRISDIR) $(CLIDIR) $(TESTDIR) README.md doc.md
|
||||
|
||||
run: $(TARGET)
|
||||
./$(TARGET)
|
||||
|
||||
style:
|
||||
@if [ -f .clang-format ]; then \
|
||||
clang-format -n $(TETRIS_SRC) $(CLI_SRC); \
|
||||
|
|
@ -109,4 +99,17 @@ format:
|
|||
echo ".clang-format not found"; \
|
||||
fi
|
||||
|
||||
$(LIB_TETRIS): $(TETRIS_OBJ)
|
||||
mkdir -p $(BUILDDIR)
|
||||
ar rcs $@ $^
|
||||
|
||||
$(TARGET): $(LIB_TETRIS) $(CLI_OBJ)
|
||||
$(CC) $(CLI_OBJ) -L$(BUILDDIR) -ltetris -o $@ $(LDFLAGS)
|
||||
|
||||
brick_game/tetris/%.o: brick_game/tetris/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
gui/cli/%.o: gui/cli/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
-include $(TETRIS_OBJ:.o=.d) $(CLI_OBJ:.o=.d)
|
||||
|
|
|
|||
77
src/test/test_collision.c
Normal file
77
src/test/test_collision.c
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include <check.h>
|
||||
#include "test_helper.h"
|
||||
|
||||
START_TEST(test_collision_bottom) {
|
||||
test_setup();
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
state->curr.y = FIELD_HEIGHT;
|
||||
state->curr.x = 5;
|
||||
state->curr.mtrx[0][0] = 1;
|
||||
|
||||
ck_assert_int_eq(check_collision(), 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_collision_left) {
|
||||
test_setup();
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
state->curr.x = -1;
|
||||
state->curr.y = 5;
|
||||
state->curr.mtrx[0][0] = 1;
|
||||
|
||||
ck_assert_int_eq(check_collision(), 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_collision_right) {
|
||||
test_setup();
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
state->curr.x = FIELD_WIDTH;
|
||||
state->curr.y = 5;
|
||||
state->curr.mtrx[0][0] = 1;
|
||||
|
||||
ck_assert_int_eq(check_collision(), 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_collision_placed_block) {
|
||||
test_setup();
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
state->field[10][5] = 2;
|
||||
state->curr.y = 10;
|
||||
state->curr.x = 5;
|
||||
state->curr.mtrx[0][0] = 1;
|
||||
|
||||
ck_assert_int_eq(check_collision(), 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_no_collision) {
|
||||
test_setup();
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
state->curr.y = 5;
|
||||
state->curr.x = 5;
|
||||
state->curr.mtrx[0][0] = 1;
|
||||
|
||||
ck_assert_int_eq(check_collision(), 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite* collision_suite(void) {
|
||||
Suite* s = suite_create("Collision");
|
||||
TCase* tc = tcase_create("Core");
|
||||
|
||||
tcase_add_test(tc, test_collision_bottom);
|
||||
tcase_add_test(tc, test_collision_left);
|
||||
tcase_add_test(tc, test_collision_right);
|
||||
tcase_add_test(tc, test_collision_placed_block);
|
||||
tcase_add_test(tc, test_no_collision);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
return s;
|
||||
}
|
||||
57
src/test/test_figures.c
Normal file
57
src/test/test_figures.c
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#include <check.h>
|
||||
#include "test_helper.h"
|
||||
|
||||
START_TEST(test_generate_figure) {
|
||||
generate_next_figure();
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
ck_assert(state->next.sprite >= I && state->next.sprite < FIGURE_COUNT);
|
||||
ck_assert_int_eq(state->next.rotation, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_all_shapes_exist) {
|
||||
for (int sprite = I; sprite < FIGURE_COUNT; sprite++) {
|
||||
for (int rotation = 0; rotation < 4; rotation++) {
|
||||
const int (*shape)[4] = get_figure_shape(sprite, rotation);
|
||||
ck_assert_ptr_nonnull(shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_i_figure_horizontal) {
|
||||
const int (*shape)[4] = get_figure_shape(I, 0);
|
||||
|
||||
int count = 0;
|
||||
for (int j = 0; j < 4; j++) {
|
||||
if (shape[1][j]) count++;
|
||||
}
|
||||
ck_assert_int_eq(count, 4);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_o_figure_unchanged) {
|
||||
const int (*s1)[4] = get_figure_shape(O, 0);
|
||||
const int (*s2)[4] = get_figure_shape(O, 2);
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
ck_assert_int_eq(s1[i][j], s2[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite* figures_suite(void) {
|
||||
Suite* s = suite_create("Figures");
|
||||
TCase* tc = tcase_create("Core");
|
||||
|
||||
tcase_add_test(tc, test_generate_figure);
|
||||
tcase_add_test(tc, test_all_shapes_exist);
|
||||
tcase_add_test(tc, test_i_figure_horizontal);
|
||||
tcase_add_test(tc, test_o_figure_unchanged);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
return s;
|
||||
}
|
||||
39
src/test/test_helper.h
Normal file
39
src/test/test_helper.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef TEST_HELPER_H
|
||||
#define TEST_HELPER_H
|
||||
|
||||
#include "../brick_game/tetris/01_automato.h"
|
||||
|
||||
// Хелпер для очистки поля
|
||||
static inline void clear_test_field(void) {
|
||||
GameState_t* state = get_game_state();
|
||||
for (int i = 0; i < FIELD_HEIGHT; i++)
|
||||
for (int j = 0; j < FIELD_WIDTH; j++)
|
||||
state->field[i][j] = 0;
|
||||
}
|
||||
|
||||
// Хелпер для очистки матрицы фигуры
|
||||
static inline void clear_figure_matrix(void) {
|
||||
GameState_t* state = get_game_state();
|
||||
for (int i = 0; i < 4; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
state->curr.mtrx[i][j] = 0;
|
||||
}
|
||||
|
||||
// Хелпер для заполнения линии
|
||||
static inline void fill_line(int row) {
|
||||
GameState_t* state = get_game_state();
|
||||
for (int j = 0; j < FIELD_WIDTH; j++) {
|
||||
state->field[row][j] = 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup функция (вызывается перед каждым тестом)
|
||||
static inline void test_setup(void) {
|
||||
GameState_t* state = get_game_state();
|
||||
clear_test_field();
|
||||
state->info->score = 0;
|
||||
state->info->level = 1;
|
||||
state->info->speed = 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
77
src/test/test_lines.c
Normal file
77
src/test/test_lines.c
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
#include <check.h>
|
||||
#include "test_helper.h"
|
||||
|
||||
START_TEST(test_clear_one_line) {
|
||||
test_setup();
|
||||
fill_line(FIELD_HEIGHT - 1);
|
||||
|
||||
clear_lines();
|
||||
|
||||
ck_assert_int_eq(get_game_state()->info->score, 100);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_clear_two_lines) {
|
||||
test_setup();
|
||||
fill_line(FIELD_HEIGHT - 1);
|
||||
fill_line(FIELD_HEIGHT - 2);
|
||||
|
||||
clear_lines();
|
||||
|
||||
ck_assert_int_eq(get_game_state()->info->score, 300);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_clear_three_lines) {
|
||||
test_setup();
|
||||
fill_line(FIELD_HEIGHT - 1);
|
||||
fill_line(FIELD_HEIGHT - 2);
|
||||
fill_line(FIELD_HEIGHT - 3);
|
||||
|
||||
clear_lines();
|
||||
|
||||
ck_assert_int_eq(get_game_state()->info->score, 700);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_clear_four_lines) {
|
||||
test_setup();
|
||||
fill_line(FIELD_HEIGHT - 1);
|
||||
fill_line(FIELD_HEIGHT - 2);
|
||||
fill_line(FIELD_HEIGHT - 3);
|
||||
fill_line(FIELD_HEIGHT - 4);
|
||||
|
||||
clear_lines();
|
||||
|
||||
ck_assert_int_eq(get_game_state()->info->score, 1500);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_incomplete_line) {
|
||||
test_setup();
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
// Не полная линия
|
||||
for (int j = 0; j < FIELD_WIDTH - 1; j++) {
|
||||
state->field[FIELD_HEIGHT - 1][j] = 2;
|
||||
}
|
||||
|
||||
clear_lines();
|
||||
|
||||
ck_assert_int_eq(state->info->score, 0);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite* lines_suite(void) {
|
||||
Suite* s = suite_create("ClearLines");
|
||||
TCase* tc = tcase_create("Core");
|
||||
|
||||
tcase_add_test(tc, test_clear_one_line);
|
||||
tcase_add_test(tc, test_clear_two_lines);
|
||||
tcase_add_test(tc, test_clear_three_lines);
|
||||
tcase_add_test(tc, test_clear_four_lines);
|
||||
tcase_add_test(tc, test_incomplete_line);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
return s;
|
||||
}
|
||||
20
src/test/test_main.c
Normal file
20
src/test/test_main.c
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include <check.h>
|
||||
|
||||
// Объявления Suite из других файлов
|
||||
Suite* collision_suite(void);
|
||||
Suite* lines_suite(void);
|
||||
Suite* figures_suite(void);
|
||||
Suite* score_suite(void);
|
||||
|
||||
int main(void) {
|
||||
SRunner* sr = srunner_create(collision_suite());
|
||||
srunner_add_suite(sr, lines_suite());
|
||||
srunner_add_suite(sr, figures_suite());
|
||||
srunner_add_suite(sr, score_suite());
|
||||
|
||||
srunner_run_all(sr, CK_VERBOSE);
|
||||
int failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
return (failed == 0) ? 0 : 1;
|
||||
}
|
||||
62
src/test/test_score.c
Normal file
62
src/test/test_score.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include <check.h>
|
||||
#include "test_helper.h"
|
||||
|
||||
START_TEST(test_level_up) {
|
||||
test_setup();
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
// Набираем 700 очков
|
||||
fill_line(FIELD_HEIGHT - 1);
|
||||
clear_lines(); // +100
|
||||
|
||||
fill_line(FIELD_HEIGHT - 1);
|
||||
fill_line(FIELD_HEIGHT - 2);
|
||||
clear_lines(); // +300 = 400
|
||||
|
||||
fill_line(FIELD_HEIGHT - 1);
|
||||
fill_line(FIELD_HEIGHT - 2);
|
||||
clear_lines(); // +300 = 700
|
||||
|
||||
ck_assert_int_eq(state->info->level, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_max_level) {
|
||||
test_setup();
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
state->info->score = 10000;
|
||||
fill_line(FIELD_HEIGHT - 1);
|
||||
clear_lines();
|
||||
|
||||
ck_assert_int_le(state->info->level, 10);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_high_score_save) {
|
||||
save_high_score(9999);
|
||||
ck_assert_int_eq(load_high_score(), 9999);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_game_over_top) {
|
||||
test_setup();
|
||||
GameState_t* state = get_game_state();
|
||||
|
||||
state->field[0][5] = 2;
|
||||
ck_assert_int_eq(is_game_over(), 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite* score_suite(void) {
|
||||
Suite* s = suite_create("Score");
|
||||
TCase* tc = tcase_create("Core");
|
||||
|
||||
tcase_add_test(tc, test_level_up);
|
||||
tcase_add_test(tc, test_max_level);
|
||||
tcase_add_test(tc, test_high_score_save);
|
||||
tcase_add_test(tc, test_game_over_top);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
return s;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue