diff --git a/source/general/game_state/player.cpp b/source/general/game_state/player.cpp index bde37b8f817c860699ba403b8f80770c2a39d2a9..3eca22239337707cd0643b58574fd391f536b565 100644 --- a/source/general/game_state/player.cpp +++ b/source/general/game_state/player.cpp @@ -94,11 +94,12 @@ void player::setup_round(std::string& err) { _player_hand->setup_round(err); } -// based on how many points the dealer has, chooses to call won_round, lost_round or draw round +// Based on how many points the dealer has, chooses to call won_round or draw_round. +// We do not need lose_round since the bet will just not be returned to the player +// and it is set to 0 in setup_round(). void player::wrap_up_round(int dealer_points, std::string& err) { int player_points = _player_hand->get_points(err); if(player_points > 21 || (player_points < dealer_points && dealer_points <= 21)){ - this->lost_round(); return; } if(player_points > dealer_points || dealer_points > 21) { @@ -139,10 +140,6 @@ void player::won_round() { //_bet_size->set_value(0); } -void player::lost_round() { - //_bet_size->set_value(0); -} - void player::draw_round() { int winnings = this->get_bet_size(); int holdings = this->get_money(); diff --git a/source/general/game_state/player.hpp b/source/general/game_state/player.hpp index a60529ccc3b532639063fbe8ffac46a575e6af0f..e5bebd54207162331b5daf3cf182ec9cb4efe05a 100644 --- a/source/general/game_state/player.hpp +++ b/source/general/game_state/player.hpp @@ -10,7 +10,6 @@ #include "../serialization/unique_serializable.h" #include "../serialization/serializable_value.h" -//TODO: flag access function for finished turn //TODO: hit implemented in game_state, also set flag if over 21 class player : public unique_serializable { @@ -54,22 +53,21 @@ public: bool has_finished_turn() const noexcept; hand* get_hand() const noexcept; std::string get_player_name() const noexcept; - void set_finished_turn(); - bool is_broke(); + void set_finished_turn(); //TODO + bool is_broke(); //TODO #ifdef BLACKJACK_SERVER // state update functions - void wrap_up_round(int dealer_points, std::string& err); - void setup_round(std::string& err); + void wrap_up_round(int dealer_points, std::string& err); //TODO + void setup_round(std::string& err); //TODO // player actions (probably not needed) - bool make_bet(int bet_size, std::string &err); + bool make_bet(int bet_size, std::string &err); //TODO // helper functions for game_state // helper functions to calculate winnings - void won_round(); - void lost_round(); - void draw_round(); + void won_round(); //TODO + void draw_round(); //TODO #endif diff --git a/unit-tests/card.cpp b/unit-tests/card.cpp index 6dfad54aa7c2d5eaa9f3a527cb54617d12c8bcd0..20eb89152c241462c04be516d249061091cd0be8 100644 --- a/unit-tests/card.cpp +++ b/unit-tests/card.cpp @@ -2,3 +2,30 @@ // Created by Flavia Taras on 24.05.22. // +#include "gtest/gtest.h" +#include "../source/general/exceptions/BlackjackException.hpp" +#include "../source/general/game_state/card.hpp" +#include "../source/general/serialization/json_utils.h" + +// Serialization and subsequent deserialization must yield the same object +TEST(CardTest, SerializationEquality) { + card card_send(2, 3); + rapidjson::Document* json_send = card_send.to_json(); + std::string message = json_utils::to_string(json_send); + delete json_send; + + rapidjson::Document json_received = rapidjson::Document(rapidjson::kObjectType); + json_received.Parse(message.c_str()); + card* card_received = card::from_json(json_received); + EXPECT_EQ(card_send.get_id(), card_received->get_id()); + EXPECT_EQ(card_send.get_value(), card_received->get_value()); + EXPECT_EQ(card_send.get_suit(), card_received->get_suit()); + delete card_received; +} + +// Deserializing an invalid string must throw a BlackjackException +TEST(CardTest, SerializationException) { + rapidjson::Document json = rapidjson::Document(rapidjson::kObjectType); + json.Parse("not json"); + EXPECT_THROW(card::from_json(json), BlackjackException); +} diff --git a/unit-tests/hand.cpp b/unit-tests/hand.cpp index 7fe7b1832ccaf13971339ce3e13ec15631d31d74..bb16d91101910b58cdd27dd70604fcd16fe6232d 100644 --- a/unit-tests/hand.cpp +++ b/unit-tests/hand.cpp @@ -2,12 +2,13 @@ // Created by Flavia Taras on 20.05.22. // -//TODO: check the get_points function in many different ways with different amounts of aces and stuff //TODO try to get extra cards when you already have over 21 points //TODO: adding the same card more than the number of decks in a shoe should not work #include "gtest/gtest.h" #include "../source/general/game_state/hand.hpp" +#include "../source/general/exceptions/BlackjackException.hpp" +#include "../source/general/serialization/json_utils.h" /* A test fixture allows to reuse the same configuration of objects for all @@ -25,7 +26,7 @@ class HandTest : public ::testing::Test { protected: virtual void SetUp() { - cards.resize(8); //TODO: do we need this... rather just declare a shoe... + cards.resize(14); for (int i = 1; i < 14; ++i) { for (int j = 0; j < 5; ++j) { cards[i].push_back(new card(i, j)); @@ -94,7 +95,6 @@ TEST_F(HandTest, ScoreOneFaceCard) { EXPECT_EQ(10, player_hand.get_points(err)); } -//TODO: do we even test for this? // The score of an empty hand must be zero TEST_F(HandTest, ScoreNoCards) { EXPECT_EQ(0, player_hand.get_points(err)); @@ -316,4 +316,33 @@ TEST_F(HandTest, IsOver21TrueWithAce) { player_hand.add_card(cards[13][0], err); player_hand.add_card(cards[5][0], err); EXPECT_TRUE(player_hand.is_over_21(err)); +} + +// Serialization and subsequent deserialization must yield the same object +TEST_F(HandTest, SerializationEquality) { + //std::vector<card*> hand_cards = {cards[1][0], cards[2][0], cards[9][0]}; + //hand hand_send(); + player_hand.add_card(cards[2][0], err); + player_hand.add_card(cards[7][0], err); + player_hand.add_card(cards[9][0], err); + rapidjson::Document* json_send = player_hand.to_json(); + std::string message = json_utils::to_string(json_send); + delete json_send; + + rapidjson::Document json_received = rapidjson::Document(rapidjson::kObjectType); + json_received.Parse(message.c_str()); + hand* hand_received = hand::from_json(json_received); + EXPECT_EQ(player_hand.get_id(), hand_received->get_id()); + for (int i = 0; i < player_hand.get_cards().size(); ++i) { + EXPECT_EQ(player_hand.get_cards()[i]->get_value(), hand_received->get_cards()[i]->get_value()); + EXPECT_EQ(player_hand.get_cards()[i]->get_suit(), hand_received->get_cards()[i]->get_suit()); + } + delete hand_received; +} + +// Deserializing an invalid string must throw a BlackjackException +TEST_F(HandTest, SerializationException) { + rapidjson::Document json = rapidjson::Document(rapidjson::kObjectType); + json.Parse("not json"); + EXPECT_THROW(hand::from_json(json), BlackjackException); } \ No newline at end of file diff --git a/unit-tests/player.cpp b/unit-tests/player.cpp index 6dfad54aa7c2d5eaa9f3a527cb54617d12c8bcd0..82909acc7902e2ad1c4ae1b8e864071550a8f857 100644 --- a/unit-tests/player.cpp +++ b/unit-tests/player.cpp @@ -2,3 +2,169 @@ // Created by Flavia Taras on 24.05.22. // +#include "gtest/gtest.h" +#include "../source/general/game_state/player.hpp" +#include "../source/general/exceptions/BlackjackException.hpp" +#include "../source/general/serialization/json_utils.h" + + +/* A test fixture allows to reuse the same configuration of objects for all + * tests in a test suite. The name of the fixture must match the test suite. + * + * For each test defined with TEST_F(), googletest will create a fresh test + * fixture at runtime, immediately initialize it via SetUp(), run the test, + * clean up by calling TearDown(), and then delete the test fixture. + * Note that different tests in the same test suite have different test fixture + * objects, and googletest always deletes a test fixture before it creates the + * next one. googletest does not reuse the same test fixture for multiple + * tests. Any changes one test makes to the fixture do not affect other tests. + */ + +class PlayerTest : public ::testing::Test { + +protected: + virtual void SetUp() { + cards.resize(14); + for (int i = 1; i < 14; ++i) { + for (int j = 0; j < 4; ++j) { + cards[i].push_back(new card(i, j)); + } + } + } + + /* Any object and subroutine declared here can be accessed in the tests */ + + std::vector<std::vector<card*>> cards; + player player; + std::string player_name; + int bet_size = 0; + int money = 100; + bool finished_turn = false; + hand player_hand; + std::string err; +}; + +// If the player has finished their turn, the corresponding flag attribute has to be set +TEST_F(PlayerTest, SetFinishedTurn) { + player.set_finished_turn(); + EXPECT_TRUE(player.has_finished_turn()); +} + +// After initialization a player must not be broke +TEST_F(PlayerTest, IsBrokeFalse) { + EXPECT_EQ(money, player.get_money()); + EXPECT_FALSE(player.is_broke()); +} + +// A player with no money should be broke +// TODO how to set the money of a player to 0 so that I can check this +TEST_F(PlayerTest, IsBrokeTrue) { + EXPECT_TRUE(player_hand.add_card(cards[1][0], err)); + EXPECT_TRUE(player_hand.add_card(cards[3][0], err)); + EXPECT_TRUE(player_hand.add_card(cards[13][0], err)); + std::vector<card*> expected_hand = {cards[1][0], cards[3][0], cards[13][0]}; + EXPECT_EQ(expected_hand, player_hand.get_cards()); +} + +// TODO one of these for a broke player +// When starting a new round only the finished_round flag and the bet_size have to be reset +TEST_F(PlayerTest, SetupRound) { + player_name = player.get_player_name(); + money = player.get_money(); + player_hand.setup_round(err); + player.setup_round(err); + EXPECT_EQ(bet_size, player.get_bet_size()); + EXPECT_EQ(money, player.get_money()); + EXPECT_EQ(player_hand, player.get_hand()); + EXPECT_EQ(player_name, player.get_player_name()); + EXPECT_FALSE(player.has_finished_turn()); +} + +// After winning a round, the new amount of money has to be computed +// and nothing else changes +TEST_F(PlayerTest, WonRound) { + bet_size = player.get_bet_size(); + money = player.get_money(); + player_name = player.get_player_name(); + int money_new = bet_size * 2 + money; + ASSERT_TRUE(player.has_finished_turn()); + player.won_round(); + EXPECT_EQ(bet_size, player.get_bet_size()); + EXPECT_EQ(money_new, player.get_money()); + EXPECT_EQ(player_hand, player.get_hand()); + EXPECT_EQ(player_name, player.get_player_name()); +} + +// After a draw round, the bet is returned to the player and nothing else changes +TEST_F(PlayerTest, DrawRound) { + bet_size = player.get_bet_size(); + money = player.get_money(); + player_name = player.get_player_name(); + int money_new = bet_size + money; + ASSERT_TRUE(player.has_finished_turn()); + player.draw_round(); + EXPECT_EQ(bet_size, player.get_bet_size()); + EXPECT_EQ(money_new, player.get_money()); + EXPECT_EQ(player_hand, player.get_hand()); + EXPECT_EQ(player_name, player.get_player_name()); + EXPECT_FALSE(player.has_finished_turn()); +} + +// todo +// After a draw round, the bet is returned to the player and nothing else changes +TEST_F(PlayerTest, MakeBetHalf) { + player_name = player.get_player_name(); + EXPECT_TRUE(player.make_bet(50, err)); + EXPECT_EQ(50, player.get_bet_size()); + EXPECT_EQ(50, player.get_money()); + EXPECT_EQ(player_hand, player.get_hand()); + EXPECT_EQ(player_name, player.get_player_name()); + EXPECT_FALSE(player.has_finished_turn()); +} + +// After a draw round, the bet is returned to the player and nothing else changes +TEST_F(PlayerTest, MakeBetAllMoney) { + player_name = player.get_player_name(); + EXPECT_TRUE(player.make_bet(100, err)); + EXPECT_EQ(100, player.get_bet_size()); + EXPECT_EQ(0, player.get_money()); + EXPECT_EQ(player_hand, player.get_hand()); + EXPECT_EQ(player_name, player.get_player_name()); + EXPECT_FALSE(player.has_finished_turn()); +} + +// After a draw round, the bet is returned to the player and nothing else changes +TEST_F(PlayerTest, MakeBetMoneyOver) { + player_name = player.get_player_name(); + EXPECT_FALSE(player.make_bet(200, err)); + EXPECT_EQ(0, player.get_bet_size()); + EXPECT_EQ(100, player.get_money()); + EXPECT_EQ(player_hand, player.get_hand()); + EXPECT_EQ(player_name, player.get_player_name()); + EXPECT_FALSE(player.has_finished_turn()); +} + +// After a draw round, the bet is returned to the player and nothing else changes +TEST_F(PlayerTest, MakeBetNegative) { + player_name = player.get_player_name(); + EXPECT_FALSE(player.make_bet(-2, err)); + EXPECT_EQ(0, player.get_bet_size()); + EXPECT_EQ(100, player.get_money()); + EXPECT_EQ(player_hand, player.get_hand()); + EXPECT_EQ(player_name, player.get_player_name()); + EXPECT_FALSE(player.has_finished_turn()); +} + +/* +// When starting a new round only the finished_round flag and the bet_size have to be reset +TEST_F(PlayerTest, WrapupRound) { + player_name = player.get_player_name(); + money = player.get_money(); + player_hand.setup_round(err); + player.setup_round(err); + EXPECT_EQ(bet_size, player.get_bet_size()); + EXPECT_EQ(money, player.get_money()); + EXPECT_EQ(player_hand, player.get_hand()); + EXPECT_EQ(player_name, player.get_player_name()); + EXPECT_FALSE(player.has_finished_turn()); +}*/