diff --git a/.gitignore b/.gitignore index d250e2019542fe420edbfcd807e80ca8094e72f2..72f4c9edb56add14c46828468683b3d2a31b7559 100644 --- a/.gitignore +++ b/.gitignore @@ -58,4 +58,4 @@ desktop.ini # binary file puissance4 -test_board \ No newline at end of file +test_puissance4 \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 15bb36541ef4f40367b0dd50e969fc0c3dc7a3cb..4a0093ae7c56991ef88deb8184369a88bf92af38 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,33 +12,27 @@ build: - echo "Compiling project..." - make clean - make puissance4 + - make test_puissance4 artifacts: paths: - puissance4 + - test_puissance4 -test_2players: +testbest: stage: test script: - - echo "Running 2players tests..." - - make -C testbed/2players + - echo "Running testbest..." + - make tests + dependencies: + - build -test_rand_ai: +test_unit: stage: test script: - - echo "Running rand_ai tests..." - - make -C testbed/rand_ai - -test_smart_ai: - stage: test - script: - - echo "Running smart_ai tests..." - - make -C testbed/smart_ai - -test_board: - stage: test - script: - - echo "Running board tests..." - - make tests_board + - echo "Running unit tests..." + - make run_unit_tests + dependencies: + - build clean: stage: clean diff --git a/Makefile b/Makefile index 727325a4aba71a99ddd63bece287b12c0d560cc7..50b3ac0398a1148930f1d55e13b23766b78e9ee4 100644 --- a/Makefile +++ b/Makefile @@ -1,51 +1,50 @@ -CC:=gcc -CFLAGS = -g -Wall -Wextra -Wpedantic -LDLIBS = -lm -LDFLAGS = -fsanitize=address -fsanitize=leak +CC := gcc +CFLAGS := -g -Wall -Wextra -Wpedantic +LDLIBS := -lm +LDFLAGS := -fsanitize=address -fsanitize=leak puissance4: puissance4.o src/board.o src/computer.o src/game.o $(CC) $(CFLAGS) $^ -o $@ $(LDLIBS) $(LDFLAGS) -board.o: src/board.h -game.o: src/game.h src/computer.h -computer.o: src/computer.h src/board.h -puissance4.o: puissance4.h src/game.h src/board.h +test_puissance4: src/test_puissance4.o src/test_board.o src/test_game.o src/test_computer.o src/board.o src/computer.o src/game.o + $(CC) $(CFLAGS) $^ -o $@ $(LDLIBS) $(LDFLAGS) -clean: - @echo "this rule must clean everything up (including candidate files in testbed)" - $(MAKE) -C testbed clean - $(RM) -rf puissance4 *.o tests_game tests_board tests_computer +puissance4.o: puissance4.c puissance4.h src/game.h src/board.h + $(CC) $(CFLAGS) -c $< -o $@ -run: puissance4 - ./$< 3 5 6 +src/board.o: src/board.c src/board.h + $(CC) $(CFLAGS) -c $< -o $@ -tests: puissance4 - $(MAKE) -C testbed +src/computer.o: src/computer.c src/computer.h src/board.h + $(CC) $(CFLAGS) -c $< -o $@ + +src/game.o: src/game.c src/game.h src/computer.h src/board.h + $(CC) $(CFLAGS) -c $< -o $@ -tests_2players: puissance4 - $(MAKE) -C testbed/2players +src/test_puissance4.o: src/test_puissance4.c src/test_puissance4.h src/test_board.h src/test_game.h src/test_computer.h + $(CC) $(CFLAGS) -c $< -o $@ -tests_rand_ai: puissance4 - $(MAKE) -C testbed/rand_ai +src/test_board.o: src/test_board.c src/test_board.h src/board.h + $(CC) $(CFLAGS) -c $< -o $@ -tests_smart_ai: puissance4 - $(MAKE) -C testbed/smart_ai +src/test_game.o: src/test_game.c src/test_game.h src/board.h src/computer.h + $(CC) $(CFLAGS) -c $< -o $@ -tests_game: src/test_game.o src/board.o src/game.o src/computer.o - $(CC) $(CFLAGS) $^ -o tests_game $(LDLIBS) $(LDFLAGS) - ./tests_game +src/test_computer.o: src/test_computer.c src/test_computer.h src/board.h src/computer.h + $(CC) $(CFLAGS) -c $< -o $@ -tests_board: src/test_board.o src/board.o - $(CC) $(CFLAGS) $^ -o tests_board $(LDLIBS) $(LDFLAGS) - ./tests_board +clean: + $(MAKE) -C testbed clean + $(RM) -rf puissance4 test_puissance4 *.o src/*.o + +run: puissance4 + ./$< 3 5 6 -tests_computer: src/test_computer.o src/computer.o src/board.o src/game.o - $(CC) $(CFLAGS) $^ -o tests_computer $(LDLIBS) $(LDFLAGS) - ./tests_computer +run_unit_tests: test_puissance4 + ./$< -run_tests: tests_game tests_board tests_computer - @echo "Running all tests..." - ./tests_game - ./tests_board - ./tests_computer - @echo "All tests executed successfully." \ No newline at end of file +run_all_tests: test_puissance4 tests + ./$< + +tests: puissance4 + $(MAKE) -C testbed diff --git a/src/test_board.c b/src/test_board.c index 5e351ae08b21cc5c71f69632abf2f51983e9ac33..5ef77225edb1abb15554c4bef7fd9cee0c407999 100644 --- a/src/test_board.c +++ b/src/test_board.c @@ -1,23 +1,4 @@ -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#include <string.h> -#include "board.h" - -#define GREEN "\033[1;32m" -#define RED "\033[1;31m" -#define RESET "\033[0m" - -void test_destroy_board(); -void test_fill_board(); -void test_create_board(); - -int main() { - test_create_board(); - test_fill_board(); - test_destroy_board(); - return EXIT_SUCCESS; -} +#include "test_board.h" void test_destroy_board() { int rows = 6; @@ -29,7 +10,7 @@ void test_destroy_board() { } fill_board(rows, cols, board); - assert(destroy_board(rows, board) == EXIT_SUCCESS); + assert(destroy_board(rows, board) == EXIT_SUCCESS && RED "test_destroy_board: FAILED\n" RESET); printf(GREEN "test_destroy_board: PASSED\n" RESET); } @@ -37,10 +18,10 @@ void test_create_board() { int rows = 6; int cols = 7; int** board = create_board(rows, cols); - assert(board != NULL && "Board creation failed"); + assert(board != NULL && RED "Board creation failed\n" RESET); for (int i = 0; i < rows; i++) { - assert(board[i] != NULL && "Row allocation failed"); + assert(board[i] != NULL && RED "Row allocation failed\n" RESET); } printf(GREEN "test_create_board: PASSED\n" RESET); @@ -51,13 +32,13 @@ void test_fill_board() { int rows = 6; int cols = 7; int** board = create_board(rows, cols); - assert(board != NULL && "Board creation failed"); + assert(board != NULL && RED "Board creation failed\n" RESET); fill_board(rows, cols, board); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { - assert(board[i][j] == EMPTY); + assert(board[i][j] == EMPTY && RED "test_fill_board: FAILED at board[%d][%d]\n" RESET); } } diff --git a/src/test_board.h b/src/test_board.h new file mode 100644 index 0000000000000000000000000000000000000000..ec5ccd3dd7841478daae904f3fcd10ad07053f88 --- /dev/null +++ b/src/test_board.h @@ -0,0 +1,11 @@ +#ifndef _TEST_BOARD_H_ +#define _TEST_BOARD_H_ + +#include "board.h" +#include "test_puissance4.h" + +void test_destroy_board(); +void test_fill_board(); +void test_create_board(); + +#endif diff --git a/src/test_computer.c b/src/test_computer.c index 63a111d38d9fb2c1342d6db62edc0a1ea707f0aa..35e71226c33d0581d9a251cfe044d46293ee87b0 100644 --- a/src/test_computer.c +++ b/src/test_computer.c @@ -1,47 +1,20 @@ -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include "computer.h" -#include "game.h" - -int** setup_board(int rows, int cols, int default_value) { - int** board = create_board(rows, cols); - if (board == NULL) { - fprintf(stderr, "Error: Unable to allocate memory for the board.\n"); - exit(EXIT_FAILURE); - } - - for (int i = 0; i < rows; i++) { - for (int j = 0; j < cols; j++) { - board[i][j] = default_value; - } - } - - return board; -} - -void reset_board(int rows, int cols, int** board) { - for (int i = 0; i < rows; i++) { - for (int j = 0; j < cols; j++) { - board[i][j] = EMPTY; - } - } -} +#include "test_computer.h" void test_is_column_full() { int rows = 6, cols = 7; int** board = setup_board(rows, cols, EMPTY); // An empty column should not be considered full - assert(is_column_full(1, rows, board) == false); + assert(is_column_full(1, rows, board) == false && RED "test_is_column_full: FAILED - column should not be full\n" RESET); // Fill a column completely and test again for (int i = 0; i < rows; i++) { board[i][0] = PLAYER1; } - assert(is_column_full(1, rows, board) == true); + assert(is_column_full(1, rows, board) == true && RED "test_is_column_full: FAILED - column should be full\n" RESET); destroy_board(rows, board); + printf(GREEN "test_is_column_full: PASSED\n" RESET); } void test_select_smart_column() { @@ -53,16 +26,17 @@ void test_select_smart_column() { board[4][0] = PLAYER2; board[3][0] = PLAYER2; - assert(select_smart_column(cols, rows, board) == 1); + assert(select_smart_column(cols, rows, board) == 1 && RED "test_select_smart_column: FAILED - AI should select column 1\n" RESET); reset_board(rows, cols, board); // Simulate a situation where the player can win on the next move board[5][1] = PLAYER1; board[4][1] = PLAYER1; board[3][1] = PLAYER1; - assert(select_smart_column(cols, rows, board) == 2); + assert(select_smart_column(cols, rows, board) == 2 && RED "test_select_smart_column: FAILED - Player should select column 2\n" RESET); destroy_board(rows, board); + printf(GREEN "test_select_smart_column: PASSED\n" RESET); } void test_select_random_column() { @@ -72,7 +46,7 @@ void test_select_random_column() { // Select a random column on an empty board int col = select_random_column(cols, rows, board); - assert(col == 2); // The expected value based on the random seed + assert(col == 2 && RED "test_select_random_column: FAILED - Expected column 2\n" RESET); // Fill all columns except one for (int j = 0; j < cols - 1; j++) { @@ -83,17 +57,8 @@ void test_select_random_column() { // The AI should select the only non-full column, which is column 7 (the last one) col = select_random_column(cols, rows, board); - assert(col == 7); // The last remaining column + assert(col == 7 && RED "test_select_random_column: FAILED - Expected column 7\n" RESET); destroy_board(rows, board); -} - - -int main() { - test_is_column_full(); - test_select_smart_column(); - test_select_random_column(); - - printf("All computer tests passed successfully.\n"); - return EXIT_SUCCESS; + printf(GREEN "test_select_random_column: PASSED\n" RESET); } diff --git a/src/test_computer.h b/src/test_computer.h new file mode 100644 index 0000000000000000000000000000000000000000..550fc924314224b094078a6000601808c59a5c15 --- /dev/null +++ b/src/test_computer.h @@ -0,0 +1,12 @@ +#ifndef _TEST_COMPUTER_H_ +#define _TEST_COMPUTER_H_ + +#include "computer.h" +#include "game.h" +#include "test_puissance4.h" + +void test_is_column_full(); +void test_select_smart_column(); +void test_select_random_column(); + +#endif diff --git a/src/test_game.c b/src/test_game.c index 3cd6b996ae61696cbc15c3eac97b2fc91b94ad1a..7f2ec445c382acd8ca3b8e738a015e0a9c767bee 100644 --- a/src/test_game.c +++ b/src/test_game.c @@ -1,23 +1,4 @@ -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include "game.h" - -int** setup_board(int rows, int cols, int default_value) { - int** board = create_board(rows, cols); - if (board == NULL) { - fprintf(stderr, "Error: Unable to allocate memory for the board.\n"); - exit(EXIT_FAILURE); - } - - for (int i = 0; i < rows; i++) { - for (int j = 0; j < cols; j++) { - board[i][j] = default_value; - } - } - - return board; -} +#include "test_game.h" void test_place_token() { int rows = 6, cols = 7; @@ -26,15 +7,16 @@ void test_place_token() { // Player1 struct coordinate coord = { 2, 3 }; place_token(0, coord, board); - assert(board[2][3] == PLAYER1); + assert(board[2][3] == PLAYER1 && RED "test_place_token: FAILED - Expected PLAYER1 at board[2][3]\n" RESET); // Player2 coord.x = 4; coord.y = 5; place_token(1, coord, board); - assert(board[4][5] == PLAYER2); + assert(board[4][5] == PLAYER2 && RED "test_place_token: FAILED - Expected PLAYER2 at board[4][5]\n" RESET); destroy_board(rows, board); + printf(GREEN "test_place_token: PASSED\n" RESET); } void test_find_empty_slot() { @@ -44,31 +26,34 @@ void test_find_empty_slot() { // Search for an empty slot in a column board[5][2] = PLAYER1; struct coordinate coord = find_empty_slot(2, rows, board); - assert(coord.x == 4 && coord.y == 2); + assert(coord.x == 4 && coord.y == 2 && RED "test_find_empty_slot: FAILED - Expected coord (4, 2)\n" RESET); // Search for an empty slot in a column with multiple tokens board[4][2] = PLAYER2; coord = find_empty_slot(2, rows, board); - assert(coord.x == 3 && coord.y == 2); + assert(coord.x == 3 && coord.y == 2 && RED "test_find_empty_slot: FAILED - Expected coord (3, 2)\n" RESET); destroy_board(rows, board); + printf(GREEN "test_find_empty_slot: PASSED\n" RESET); } void test_is_valid_column() { int cols = 7; - assert(is_valid_column(1, cols) == true); - assert(is_valid_column(7, cols) == true); + assert(is_valid_column(1, cols) == true && RED "test_is_valid_column: FAILED - Column 1 should be valid\n" RESET); + assert(is_valid_column(7, cols) == true && RED "test_is_valid_column: FAILED - Column 7 should be valid\n" RESET); - assert(is_valid_column(0, cols) == false); - assert(is_valid_column(8, cols) == false); + assert(is_valid_column(0, cols) == false && RED "test_is_valid_column: FAILED - Column 0 should be invalid\n" RESET); + assert(is_valid_column(8, cols) == false && RED "test_is_valid_column: FAILED - Column 8 should be invalid\n" RESET); + printf(GREEN "test_is_valid_column: PASSED\n" RESET); } void test_is_board_full() { int rows = 6, cols = 7; - assert(is_board_full(41, rows, cols) == true); // Full board - assert(is_board_full(40, rows, cols) == false); // Not full board + assert(is_board_full(41, rows, cols) == true && RED "test_is_board_full: FAILED - Board should be full\n" RESET); + assert(is_board_full(40, rows, cols) == false && RED "test_is_board_full: FAILED - Board should not be full\n" RESET); + printf(GREEN "test_is_board_full: PASSED\n" RESET); } void test_does_player_win() { @@ -81,7 +66,7 @@ void test_does_player_win() { board[5][2] = PLAYER1; board[5][3] = PLAYER1; struct coordinate coord = { 5, 3 }; - assert(does_player_win(coord, rows, cols, board) == true); + assert(does_player_win(coord, rows, cols, board) == true && RED "test_does_player_win: FAILED - Horizontal win should be detected\n" RESET); // Test vertical win fill_board(rows, cols, board); @@ -91,7 +76,7 @@ void test_does_player_win() { board[2][2] = PLAYER2; coord.x = 2; coord.y = 2; - assert(does_player_win(coord, rows, cols, board) == true); + assert(does_player_win(coord, rows, cols, board) == true && RED "test_does_player_win: FAILED - Vertical win should be detected\n" RESET); // Test diagonal win (left to right) fill_board(rows, cols, board); @@ -101,7 +86,7 @@ void test_does_player_win() { board[2][3] = PLAYER1; coord.x = 2; coord.y = 3; - assert(does_player_win(coord, rows, cols, board) == true); + assert(does_player_win(coord, rows, cols, board) == true && RED "test_does_player_win: FAILED - Left-to-right diagonal win should be detected\n" RESET); // Test diagonal win (right to left) fill_board(rows, cols, board); @@ -111,18 +96,8 @@ void test_does_player_win() { board[2][0] = PLAYER2; coord.x = 2; coord.y = 0; - assert(does_player_win(coord, rows, cols, board) == true); + assert(does_player_win(coord, rows, cols, board) == true && RED "test_does_player_win: FAILED - Right-to-left diagonal win should be detected\n" RESET); destroy_board(rows, board); + printf(GREEN "test_does_player_win: PASSED\n" RESET); } - -int main() { - test_place_token(); - test_find_empty_slot(); - test_is_valid_column(); - test_is_board_full(); - test_does_player_win(); - - printf("All tests passed successfully.\n"); - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/src/test_game.h b/src/test_game.h new file mode 100644 index 0000000000000000000000000000000000000000..47e4b2b36f6c79a3576f37cd953afb14b45b5bfd --- /dev/null +++ b/src/test_game.h @@ -0,0 +1,14 @@ +#ifndef _TEST_GAME_H_ +#define _TEST_GAME_H_ + +#include "computer.h" +#include "game.h" +#include "test_puissance4.h" + +void test_place_token(); +void test_find_empty_slot(); +void test_is_valid_column(); +void test_is_board_full(); +void test_does_player_win(); + +#endif diff --git a/src/test_puissance4.c b/src/test_puissance4.c new file mode 100644 index 0000000000000000000000000000000000000000..74004d565109255c37f16d046f25584f29fd5b15 --- /dev/null +++ b/src/test_puissance4.c @@ -0,0 +1,47 @@ +#include "test_puissance4.h" + +int main() { + // game.h + test_create_board(); + test_fill_board(); + test_destroy_board(); + + // computer.h + test_is_column_full(); + test_select_smart_column(); + test_select_random_column(); + + // board.h + test_place_token(); + test_find_empty_slot(); + test_is_valid_column(); + test_is_board_full(); + test_does_player_win(); + + printf(GREEN "All tests passed successfully!\n" RESET); + return EXIT_SUCCESS; +} + +int** setup_board(int rows, int cols, int default_value) { + int** board = create_board(rows, cols); + if (board == NULL) { + fprintf(stderr, "Error: Unable to allocate memory for the board.\n"); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + board[i][j] = default_value; + } + } + + return board; +} + +void reset_board(int rows, int cols, int** board) { + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + board[i][j] = EMPTY; + } + } +} diff --git a/src/test_puissance4.h b/src/test_puissance4.h new file mode 100644 index 0000000000000000000000000000000000000000..0b1a9300202ad820477ee55bd704b6b217c6c2b2 --- /dev/null +++ b/src/test_puissance4.h @@ -0,0 +1,21 @@ +#ifndef _TEST_PUSSIANCE4_h_ +#define _TEST_PUSSIANCE4_h_ + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <string.h> + +#include "../puissance4.h" +#include "test_board.h" +#include "test_game.h" +#include "test_computer.h" + +#define GREEN "\033[1;32m" +#define RED "\033[1;31m" +#define RESET "\033[0m" + +int** setup_board(int rows, int cols, int default_value); +void reset_board(int rows, int cols, int** board); + +#endif diff --git a/test_puissance4.c b/test_puissance4.c deleted file mode 100644 index f63ff0d35fc96b59d6337277ac1545b4fb711c68..0000000000000000000000000000000000000000 --- a/test_puissance4.c +++ /dev/null @@ -1,36 +0,0 @@ -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#include "puissance4.h" - -#define GREEN "\033[1;32m" -#define RED "\033[1;31m" -#define RESET "\033[0m" - -void test_is_valid_game_mode(); -void test_is_valid_board_size(); - -int main() { - test_is_valid_game_mode(); - test_is_valid_board_size(); - return EXIT_SUCCESS; -} - -void test_is_valid_game_mode() { - assert(is_valid_game_mode(1) == true); - assert(is_valid_game_mode(2) == true); - assert(is_valid_game_mode(3) == true); - assert(is_valid_game_mode(0) == false); - assert(is_valid_game_mode(4) == false); - assert(is_valid_game_mode(-1) == false); - printf(GREEN "test_is_valid_game_mode: PASSED\n" RESET); -} - -void test_is_valid_board_size() { - assert(is_valid_board_size(4, 4) == true); - assert(is_valid_board_size(6, 7) == true); - assert(is_valid_board_size(3, 4) == false); - assert(is_valid_board_size(4, 3) == false); - assert(is_valid_board_size(2, 2) == false); - printf(GREEN "test_is_valid_board_size: PASSED\n" RESET); -} \ No newline at end of file