diff --git a/CMakeLists.txt b/CMakeLists.txt index 78cea40..a16f545 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,5 @@ cmake_minimum_required(VERSION 3.1...3.28) -enable_testing() - project( Template VERSION 0.1.0 @@ -9,28 +7,37 @@ project( set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -add_subdirectory(src/cppunit) -add_subdirectory(src/prep) +# GoogleTest requires at least C++14 +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +enable_testing() + +add_subdirectory(src/modules) + +add_executable(main src/main.cc) +add_executable(test_validation src/test_validation.cc) +add_library(validation src/validation.cc src/validation.hh) +target_link_libraries(main PUBLIC validation) +target_link_libraries(validation PRIVATE modules) -add_executable(main src/main.cpp) -add_library(lib src/lib.cpp src/lib.hh) -target_link_libraries(main PUBLIC lib) -target_link_libraries(lib PUBLIC prepLib) target_include_directories(main PUBLIC "${PROJECT_BINARY_DIR}" - "${PROJECT_SOURCE_DIR}/prep") -target_include_directories(lib PUBLIC "${PROJECT_BINARY_DIR}" - "${PROJECT_SOURCE_DIR}/prep") + "${PROJECT_SOURCE_DIR}/modules") + +target_include_directories( + test_validation PUBLIC "${PROJECT_BINARY_DIR}" + "${PROJECT_SOURCE_DIR}/modules") include(FetchContent) FetchContent_Declare( googletest - URL https://github.com/google/googletest/archive/5376968f6948923e2411081fd9372e71a59d8e77.zip + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip ) +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt + ON + CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) -add_executable(runtests src/test.cpp) -target_link_libraries(runtests PUBLIC lib gtest gtest_main) -target_include_directories(runtests PUBLIC "${PROJECT_BINARY_DIR}") - include(GoogleTest) -gtest_discover_tests(runtests) +target_link_libraries(test_validation PRIVATE GTest::gtest_main) +gtest_discover_tests(test_validation) diff --git a/README-lv.md b/README-lv.md index fa62eb2..f68fda5 100644 --- a/README-lv.md +++ b/README-lv.md @@ -5,20 +5,21 @@ ## Projekts Šis ir vienkāršs C++ projekts, kas ietver funkciju mūsu kolēģiem -testēšanai. Funkcija (t.i., galvenā funkcija un tajā izmantotās apakšfunkcijas) -atrodas `lib.cpp`. +testēšanai. Funkcija, t.i., apakšfunkcijas, kuru nepieciešams testēt +atrodas `validation.cc`. ## Papildu bibliotēkas un izpildāmā programma -Mūsu bibliotēka `prep` ir saistīta ar datu sagatavošanu pirms funkcijas -izsaukuma. `test.cpp` ir viens testa fails, kurā būs mūsu kolēģu testi -un mūsu pašu izstrādes testi. GTest tiek izmantots testiem. +Direktorija `modules` ir saistīta ar datu sagatavošanu pirms funkcijas +izsaukuma. `test_validation.cc` ir viens testa fails, kas satur testus. +[GTest](https://github.com/google/googletest) tiek izmantots testiem. ## Lietojums ## Kompilācija uz Linux un MacOS -Kompilācijai operētājsistēmā Linux ir nepieciešams cmake un CXX kompilators (e.g., g++). +Kompilācijai operētājsistēmā Linux ir nepieciešams cmake un +CXX kompilators (e.g., g++). ### MacOS @@ -59,10 +60,15 @@ make ### Windows un/vai VSCode -Uzstādiet [CMake](https://cmake.org/download/) un VSCode [CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) paplašinājumu. +Uzstādiet [CMake](https://cmake.org/download/) un VSCode +[CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) +paplašinājumu. -- Atveriet projektu kā saknes direktoriju VSCode. -- Izvēlaties **View->Command palete...** vai `Ctrl+Shift+P` un palaidiet `CMake: Build`. +- Atveriet projektu kā saknes direktoriju + VSCode. +- Izvēlaties **View->Command palete...** vai + `Ctrl+Shift+P` un palaidiet `CMake: Build`. -Rezultātā iegūtie binārie faili ir `build/main` - programma un `build/runtests`, lai -palaistu punktos norādītos testus iekš `test.cpp`. +Rezultātā iegūtie binārie faili ir `build/main` -- programma un +`build/test_validation`, lai palaistu norādītos testus +no `test_validation.cc` faila. diff --git a/README.md b/README.md index da1f4c4..27c19c2 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,14 @@ ## Project This is a simple C++ project that includes the function for our colleagues to -test. The function (i.e., the main function and the subfunctions used in it) is -located in `lib.cpp`. +test. The function (i.e., the subfunctions that are used in main function) is +located in `validation.cc`. ## Additional libraries and executable -Our library `prep` is concerned with preparation of data prior to the function -call. `test.cpp` is a single test file that will contain the tests of our colleagues -and our own development tests. GTest is used for tests. +Directory `modules` is concerned with preparation of data prior to the function +call. `test_validation.cc` is a single test file that contain the tests. +[GTest](https://github.com/google/googletest) is used for tests. ## Usage @@ -61,9 +61,12 @@ make ### Windows and/or VSCode -Install [CMake](https://cmake.org/download/) and VSCode [CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) extension. +Install [CMake](https://cmake.org/download/) and VSCode +[CMake Tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cmake-tools) +extension. - Open project as root in VSCode. - Press **View->Command palette...** or `Ctrl+Shift+P` and run `CMake: Build`. -Resulting binaries are `build/main` -- the program and `build/runtests` to run tests specified in `test.cpp`. +Resulting binaries are `build/main` -- the program and `build/test_validation` +to run tests specified in `test_validation.cc`. diff --git a/src/cppunit/CMakeLists.txt b/src/cppunit/CMakeLists.txt deleted file mode 100644 index 3e8a2ba..0000000 --- a/src/cppunit/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_library(cppunit cppunit.cpp cppunit.hh) diff --git a/src/cppunit/cppunit.cpp b/src/cppunit/cppunit.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/src/cppunit/cppunit.hh b/src/cppunit/cppunit.hh deleted file mode 100644 index ba51b1c..0000000 --- a/src/cppunit/cppunit.hh +++ /dev/null @@ -1,83 +0,0 @@ - -#ifndef CPPUNIT_H -#define CPPUNIT_H - -// Required headers, or just use #include -#include -#include -#include -#include -#include - -// CPlusPlusUnit - C++ Unit testing TDD framework (github.com/cppunit/cppunit) -class Cppunit { - public: -#define CHECK(a, b) check(a, b, #a, #b, __FILE__, __LINE__, __FUNCTION__); -#define CHECKT(a) check(a, true, #a, "true", __FILE__, __LINE__, __FUNCTION__); -#define CHECKS(a, b) check(a, b, #a, #b, __FILE__, __LINE__, __FUNCTION__); - typedef const std::string &cs; - int checks, fails; - std::ostringstream serr; - std::istringstream *in; - - Cppunit() { - checks = fails = 0; - } - - void test_cin(cs s) { - in = new std::istringstream(s); - std::cin.rdbuf(in->rdbuf()); - } - - void fail_hdr(cs stra, cs strb, cs file, int line, cs func) { - serr << "==================================================" << std::endl; - serr << "FAIL: " << func << std::endl; - serr << "--------------------------------------------------" << std::endl; - serr << "File \"" << file << "\", line " << line << " in " << func << std::endl; - serr << " Checking " << stra << " == " << strb << std::endl; - } - - template void check(T a, T b, cs stra, cs strb, cs file, int line, cs func) { - checks++; - if (a == b) { - std::cout << "."; - return; - } - fails++; - std::cout << "F"; - fail_hdr(stra, strb, file, line, func); - serr << " Error: \"" << a << "\" ! = \"" << b << "\"" << std::endl << std::endl; - } - - virtual void single_test() { - } - - virtual void test_list() { - single_test(); - } - - double dclock() { - return double(clock()) / CLOCKS_PER_SEC; - } - - int status() { - std::cout << std::endl; - if (fails) std::cout << serr.str(); - std::cout << "--------------------------------------------------" << std::endl; - std::cout << "Ran " << checks << " checks in " << dclock() << "s" << std::endl << std::endl; - if (fails) - std::cout << "FAILED (failures=" << fails << ")"; - else - std::cout << "OK" << std::endl; - return fails > 0; - } - - int run() { - std::streambuf *ocin = std::cin.rdbuf(); - test_list(); - std::cin.rdbuf(ocin); - return status(); - } -}; - -#endif // CPPUNIT_H diff --git a/src/lib.cpp b/src/lib.cpp deleted file mode 100644 index 3b103d4..0000000 --- a/src/lib.cpp +++ /dev/null @@ -1,98 +0,0 @@ -#include "lib.hh" - -#include "prep/prep.hh" - -#include -#include -#include - -enum VALIDATION_STATUS { - PLAYER_NOT_IN_ROOM, - NO_TARGET_PLAYER_SPECIFIED, - ROOM_NOT_IN_PROGRESS, - ACTION_DOES_NOT_BELONG_TO_ROLE, - ACTION_PROHIBITED, - NO_ACTOR, - NO_ACTION, - NO_ROLE, - NO_ROOM, - NO_RELATED_EVENTS, - ACTION_VALID, -}; - -void run() { - const Action kill = Action("kill", true); - const Action heal = Action("heal", true); - const Action vote = Action("vote", true); - Role role1({vote, kill, heal}); - Role role2({heal}); - Event event1 = Event("Event 1", 1710087355, 1, true, {}, {}); - Event event2 = Event("Event 2", 1710087363, 1, true, {kill}, {}); - Event event3 = Event("Event 3", 1710087369, 1, true, {}, {kill}); - std::vector relatedEvents({event2, event3}); - Player player1 = Player(69, "player1", role1, PlayerStatus::ALIVE); - Player player2 = Player(420, "player2", role1, PlayerStatus::ALIVE); - Room room1(1, "Room 1", 1710087364, RoomStatus::IN_PROGRESS, {player1, player2}); - Room room2(2, "Room 2", 1710087384, RoomStatus::ENDED, {}); - int actionValidated = validateAction(&player1, &kill, &room1, &relatedEvents, &player2); - printf("The action validation result is %u\n", actionValidated); -} - -int validateAction( - Player *actor, const Action *action, Room *room, std::vector *relatedEvents, Player *target = nullptr) { - if (!actor) { - return NO_ACTOR; - } - if (!action) { - return NO_ACTION; - } - if (!room) { - return NO_ROOM; - } - if (!relatedEvents) { - return NO_RELATED_EVENTS; - } - if (!playerBelongsToRoom(actor, room)) { - return PLAYER_NOT_IN_ROOM; - } - if (action->hasTarget && !target) { - return NO_TARGET_PLAYER_SPECIFIED; - } - if (room->status != RoomStatus::IN_PROGRESS) { - return ROOM_NOT_IN_PROGRESS; - } - Role *role = &actor->role; - if (!role) { - return NO_ROLE; - } - if (!actionBelongsToRole(role, action)) { - return ACTION_DOES_NOT_BELONG_TO_ROLE; - } - if (!isActionAllowed(action, relatedEvents)) { - return ACTION_PROHIBITED; - } - return ACTION_VALID; -} - -bool playerBelongsToRoom(Player *player, Room *room) { - return std::find(room->players.begin(), room->players.end(), *player) != room->players.end(); -} - -bool actionBelongsToRole(Role *role, const Action *action) { - return std::find(role->actions.begin(), role->actions.end(), *action) != role->actions.end(); -} - -bool isActionAllowed(const Action *action, std::vector *relevantEvents) { - // actions are disabled by default - bool allowed = false; - std::sort(relevantEvents->begin(), relevantEvents->end()); - for (auto &event : *relevantEvents) { - if (std::find(event.prohibits.begin(), event.prohibits.end(), *action) != event.prohibits.end()) { - allowed = false; - } - if (std::find(event.allows.begin(), event.allows.end(), *action) != event.allows.end()) { - allowed = true; - } - } - return allowed; -} diff --git a/src/lib.hh b/src/lib.hh deleted file mode 100644 index 547d50f..0000000 --- a/src/lib.hh +++ /dev/null @@ -1,8 +0,0 @@ -#include "prep/prep.hh" - -void run(); - -bool playerBelongsToRoom(Player *player, Room *room); -bool actionBelongsToRole(Role *role, const Action *action); -bool isActionAllowed(const Action *action, std::vector *relevantEvents); -int validateAction(Player *actor, const Action *action, Room *room, std::vector *relatedEvents, Player *target); diff --git a/src/main.cc b/src/main.cc new file mode 100644 index 0000000..4aef986 --- /dev/null +++ b/src/main.cc @@ -0,0 +1,24 @@ +#include "./validation.hh" + +#include +#include + +int main(int argc, char *argv[]) { + const Action kill = Action("kill", true); + const Action heal = Action("heal", true); + const Action vote = Action("vote", true); + Role role1({vote, kill, heal}); + Role role2({heal}); + Event event1 = Event("Event 1", 1710087355, 1, true, {}, {}); + Event event2 = Event("Event 2", 1710087363, 1, true, {kill}, {}); + Event event3 = Event("Event 3", 1710087369, 1, true, {}, {kill}); + std::vector relatedEvents({event2, event3}); + Player player1 = Player(69, "player1", role1, PlayerStatus::Alive); + Player player2 = Player(420, "player2", role1, PlayerStatus::Alive); + Room room1(1, "Room 1", 1710087364, RoomStatus::InProgress, {player1, player2}); + Room room2(2, "Room 2", 1710087384, RoomStatus::Ended, {}); + ValidationStatus validated_action = validate_action(&player1, &kill, &room1, &relatedEvents, &player2); + std::string validated_action_str = ValidationStatusUtils::to_string(validated_action); + printf("The validation result is \"%s\"\n", validated_action_str.c_str()); + return EXIT_SUCCESS; +} diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index 81a2ad1..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,8 +0,0 @@ -#include "lib.hh" - -#include - -int main(int argc, char *argv[]) { - run(); - return EXIT_SUCCESS; -} diff --git a/src/modules/CMakeLists.txt b/src/modules/CMakeLists.txt new file mode 100644 index 0000000..84ae806 --- /dev/null +++ b/src/modules/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library( + modules + action.cc + action.hh + event.cc + event.hh + player.cc + player.hh + role.cc + role.hh + room.cc + room.hh + time.cc + time.hh) diff --git a/src/modules/action.cc b/src/modules/action.cc new file mode 100644 index 0000000..b698933 --- /dev/null +++ b/src/modules/action.cc @@ -0,0 +1,12 @@ +#include "./action.hh" + +#include + +Action::Action(std::string name, bool has_target) { + this->name = name; + this->has_target = has_target; +} + +bool Action::operator==(const Action &other) const { + return this->name == other.name; +} diff --git a/src/modules/action.hh b/src/modules/action.hh new file mode 100644 index 0000000..51f298b --- /dev/null +++ b/src/modules/action.hh @@ -0,0 +1,10 @@ +#pragma once +#include + +struct Action { + std::string name; + bool has_target; + + Action(std::string name, bool has_target); + bool operator==(const Action &other) const; +}; diff --git a/src/modules/event.cc b/src/modules/event.cc new file mode 100644 index 0000000..d6e6950 --- /dev/null +++ b/src/modules/event.cc @@ -0,0 +1,48 @@ +#include "./event.hh" + +#include "./action.hh" +#include "./time.hh" + +#include +#include +#include + +Event::Event(std::string title, + uint32_t created_at, + uint32_t night_number, + bool is_visible, + std::vector prohibits, + std::vector allows): + title(title), + created_at(create_utc_timestamp(created_at)), + night_number(night_number), + is_visible(is_visible), + prohibits(prohibits), + allows(allows) { +} + +Event::Event(std::string title, + uint32_t created_at, + uint32_t night_number, + bool is_visible, + std::initializer_list prohibits, + std::initializer_list allows): + title(title), + created_at(create_utc_timestamp(created_at)), + night_number(night_number), + is_visible(is_visible), + prohibits(prohibits), + allows(allows) { +} + +bool Event::operator<(const Event &right) const { + return this->created_at < right.created_at; +} + +bool Event::operator==(const Event &right) const { + return this->created_at == right.created_at; +} + +bool Event::operator>(const Event &right) const { + return this->created_at > right.created_at; +} diff --git a/src/modules/event.hh b/src/modules/event.hh new file mode 100644 index 0000000..675f538 --- /dev/null +++ b/src/modules/event.hh @@ -0,0 +1,41 @@ +#pragma once + +#include "./action.hh" + +#include +#include +#include +#include +#include + +enum class EventType { + PhaseChange, + EventAction, + RoomStateChange, + PlayerStateChange, +}; + +struct Event { + std::string title; + std::tm *created_at; + uint32_t night_number; + bool is_visible; + std::vector prohibits; + std::vector allows; + bool operator<(const Event &other) const; + bool operator==(const Event &other) const; + bool operator>(const Event &other) const; + + Event(std::string title, + uint32_t created_at, + uint32_t night_number, + bool is_visible, + std::vector prohibits, + std::vector allows); + Event(std::string title, + uint32_t created_at, + uint32_t night_number, + bool is_visible, + std::initializer_list prohibits, + std::initializer_list allows); +}; diff --git a/src/modules/player.cc b/src/modules/player.cc new file mode 100644 index 0000000..6f98124 --- /dev/null +++ b/src/modules/player.cc @@ -0,0 +1,16 @@ +#include "./player.hh" + +#include "./role.hh" + +#include + +Player::Player(uint32_t id, std::string username, Role role, PlayerStatus status): + id(id), + username(username), + role(role), + status(status) { +} + +bool Player::operator==(const Player &other) const { + return this->id == other.id; +} diff --git a/src/modules/player.hh b/src/modules/player.hh new file mode 100644 index 0000000..7d9e09c --- /dev/null +++ b/src/modules/player.hh @@ -0,0 +1,22 @@ +#pragma once +#include "./role.hh" + +#include +#include + +enum class PlayerStatus { + Kicked, + Alive, + Dead, + VotedOut, +}; + +struct Player { + uint32_t id; + std::string username; + Role role; + PlayerStatus status; + + Player(uint32_t id, std::string username, Role role, PlayerStatus status); + bool operator==(const Player &other) const; +}; diff --git a/src/modules/role.cc b/src/modules/role.cc new file mode 100644 index 0000000..5b3e1a9 --- /dev/null +++ b/src/modules/role.cc @@ -0,0 +1,10 @@ +#include "./role.hh" + +#include +#include + +Role::Role(std::initializer_list actions): Role(std::vector(actions)) { +} + +Role::Role(std::vector actions): actions(actions) { +} diff --git a/src/modules/role.hh b/src/modules/role.hh new file mode 100644 index 0000000..4483c40 --- /dev/null +++ b/src/modules/role.hh @@ -0,0 +1,12 @@ +#pragma once + +#include "./action.hh" + +#include +#include + +struct Role { + std::vector actions; + explicit Role(std::vector actions); + Role(std::initializer_list actions); +}; diff --git a/src/modules/room.cc b/src/modules/room.cc new file mode 100644 index 0000000..f2de501 --- /dev/null +++ b/src/modules/room.cc @@ -0,0 +1,25 @@ +#include "./room.hh" + +#include "./time.hh" + +#include +#include +#include +#include + +Room::Room(uint32_t id, std::string title, uint32_t created_at, RoomStatus status, std::vector players): + id(id), + title(title), + status(status), + players(players) { + this->created_at = create_utc_timestamp(created_at); +} + +Room::Room( + uint32_t id, std::string title, uint32_t created_at, RoomStatus status, std::initializer_list players): + id(id), + title(title), + status(status), + players(players) { + this->created_at = create_utc_timestamp(created_at); +} diff --git a/src/modules/room.hh b/src/modules/room.hh new file mode 100644 index 0000000..dfd6460 --- /dev/null +++ b/src/modules/room.hh @@ -0,0 +1,27 @@ +#pragma once + +#include "./player.hh" + +#include +#include +#include +#include +#include + +enum class RoomStatus { + AwaitingStart, + InProgress, + Stopped, + Ended, +}; + +struct Room { + uint32_t id; + std::string title; + std::tm *created_at; + RoomStatus status; + std::vector players; + + Room(uint32_t id, std::string title, uint32_t created_at, RoomStatus status, std::vector players); + Room(uint32_t id, std::string title, uint32_t created_at, RoomStatus status, std::initializer_list players); +}; diff --git a/src/prep/timeUtils.cpp b/src/modules/time.cc similarity index 84% rename from src/prep/timeUtils.cpp rename to src/modules/time.cc index e52033c..fc6edec 100644 --- a/src/prep/timeUtils.cpp +++ b/src/modules/time.cc @@ -1,10 +1,10 @@ -#include "timeUtils.hh" +#include "./time.hh" #include #include #include -std::tm *createUTCTimestamp(uint32_t timestamp) { +std::tm *create_utc_timestamp(uint32_t timestamp) { // Convert the timestamp into a time_point object std::chrono::seconds sec(timestamp); std::chrono::time_point tp(sec); diff --git a/src/modules/time.hh b/src/modules/time.hh new file mode 100644 index 0000000..73f0fa8 --- /dev/null +++ b/src/modules/time.hh @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +std::tm *create_utc_timestamp(uint32_t timestamp); diff --git a/src/prep/CMakeLists.txt b/src/prep/CMakeLists.txt deleted file mode 100644 index 6d9cc1d..0000000 --- a/src/prep/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_library(prepLib prep.cpp prep.hh timeUtils.cpp timeUtils.hh) diff --git a/src/prep/prep.cpp b/src/prep/prep.cpp deleted file mode 100644 index aabfd4c..0000000 --- a/src/prep/prep.cpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "prep.hh" - -#include "timeUtils.hh" - -#include -#include - -Action::Action(std::string name, bool hasTarget) { - this->name = name; - this->hasTarget = hasTarget; -} - -bool Action::operator==(const Action &other) const { - return this->name == other.name; -} - -Role::Role(std::initializer_list actions): Role(std::vector(actions)) { -} - -Role::Role(std::vector actions): actions(actions) { -} - -Player::Player(uint32_t id, std::string username, Role role, PlayerStatus playerStatus): - id(id), - username(username), - role(role), - playerStatus(playerStatus) { -} - -bool Player::operator==(const Player &other) const { - return this->id == other.id; -} - -Room::Room( - uint32_t id, std::string title, uint32_t utcTimestampCreatedAt, RoomStatus status, std::vector players): - id(id), - title(title), - status(status), - players(players) { - this->utcTimestampCreatedAt = createUTCTimestamp(utcTimestampCreatedAt); -} - -Room::Room(uint32_t id, - std::string title, - uint32_t utcTimestampCreatedAt, - RoomStatus status, - std::initializer_list players): - Room(id, title, utcTimestampCreatedAt, status, std::vector(players)) { - this->utcTimestampCreatedAt = createUTCTimestamp(utcTimestampCreatedAt); -} - -Event::Event(std::string title, - uint32_t utcTimestampCreatedAt, - uint32_t numberNight, - bool isVisible, - std::vector prohibits, - std::vector allows): - title(title), - utcTimestampCreatedAt(createUTCTimestamp(utcTimestampCreatedAt)), - numberNight(numberNight), - isVisible(isVisible), - prohibits(prohibits), - allows(allows) { - this->utcTimestampCreatedAt = createUTCTimestamp(utcTimestampCreatedAt); -} - -Event::Event(std::string title, - uint32_t utcTimestampCreatedAt, - uint32_t numberNight, - bool isVisible, - std::initializer_list prohibits, - std::initializer_list allows): - Event(title, - utcTimestampCreatedAt, - numberNight, - isVisible, - std::vector(prohibits), - std::vector(allows)) { - this->utcTimestampCreatedAt = createUTCTimestamp(utcTimestampCreatedAt); -} - -bool Event::operator<(const Event &right) const { - return this->utcTimestampCreatedAt < right.utcTimestampCreatedAt; -} - -bool Event::operator==(const Event &right) const { - return this->utcTimestampCreatedAt == right.utcTimestampCreatedAt; -} - -bool Event::operator>(const Event &right) const { - return this->utcTimestampCreatedAt > right.utcTimestampCreatedAt; -} diff --git a/src/prep/prep.hh b/src/prep/prep.hh deleted file mode 100644 index d99d6fd..0000000 --- a/src/prep/prep.hh +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef PREP_H -#define PREP_H - -#include -#include -#include -#include - -// All IDs are uint32_t -enum EventType { - PHASE_CHANGE, - ACTION, - ROOM_STATE_CHANGE, - PLAYER_STATE_CHANGE, -}; - -enum RoomStatus { - AWAITING_START, - IN_PROGRESS, - STOPPED, - ENDED, -}; - -enum PlayerStatus { - KICKED, - ALIVE, - DEAD, - VOTED_OUT, -}; - -struct Role; -struct Player; -struct Room; -struct Event; - -struct Action { - std::string name; - bool hasTarget; - - Action(std::string name, bool hasTarget); - bool operator==(const Action &other) const; -}; - -struct Role { - std::vector actions; - - Role(std::initializer_list actions); - Role(std::vector actions); -}; - -struct Player { - uint32_t id; - std::string username; - Role role; - PlayerStatus playerStatus; - - Player(uint32_t id, std::string username, Role role, PlayerStatus playerStatus); - bool operator==(const Player &other) const; -}; - -struct Room { - uint32_t id; - std::string title; - std::tm *utcTimestampCreatedAt; - RoomStatus status; - std::vector players; - - Room( - uint32_t id, std::string title, uint32_t utcTimestampCreatedAt, RoomStatus status, std::vector players); - Room(uint32_t id, - std::string title, - uint32_t utcTimestampCreatedAt, - RoomStatus status, - std::initializer_list players); -}; - -struct Event { - std::string title; - std::tm *utcTimestampCreatedAt; - uint32_t numberNight; - bool isVisible; - std::vector prohibits; - std::vector allows; - - bool operator<(const Event &other) const; - bool operator==(const Event &other) const; - bool operator>(const Event &other) const; - - Event(std::string title, - uint32_t utcTimestampCreatedAt, - uint32_t numberNight, - bool isVisible, - std::vector prohibits, - std::vector allows); - Event(std::string title, - uint32_t utcTimestampCreatedAt, - uint32_t numberNight, - bool isVisible, - std::initializer_list prohibits, - std::initializer_list allows); -}; - -#endif diff --git a/src/prep/timeUtils.hh b/src/prep/timeUtils.hh deleted file mode 100644 index 74060e2..0000000 --- a/src/prep/timeUtils.hh +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include - -#ifndef TIMEUTILS_H -# define TIMEUTILS_H - -std::tm *createUTCTimestamp(uint32_t timestamp); - -#endif diff --git a/src/test.cpp b/src/test.cpp deleted file mode 100644 index 279a50c..0000000 --- a/src/test.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include - -TEST(ProgramTest, testFunction) { - EXPECT_EQ(8, 8); -} diff --git a/src/test_validation.cc b/src/test_validation.cc new file mode 100644 index 0000000..b79b28f --- /dev/null +++ b/src/test_validation.cc @@ -0,0 +1,10 @@ +#include "gtest/gtest.h" + +TEST(ExampleTest, Example) { + EXPECT_EQ(1, 1); +} + +int main(int argc, char *argv[]) { + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/validation.cc b/src/validation.cc new file mode 100644 index 0000000..2c73902 --- /dev/null +++ b/src/validation.cc @@ -0,0 +1,116 @@ +#include "./validation.hh" + +#include "modules/action.hh" +#include "modules/event.hh" +#include "modules/player.hh" +#include "modules/role.hh" +#include "modules/room.hh" + +#include +#include + +/** + * Check if a player belongs to a given room. + * + * @param player Pointer to the player object. + * @param room Pointer to the room object. + * @return `true` if the player belongs to the room, otherwise `false`. + */ +bool player_belongs_to_room(const Player *player, const Room *room) { + return std::find(room->players.begin(), room->players.end(), *player) != room->players.end(); +} + +/** + * Check if an action belongs to a given role. + * + * @param role Pointer to the role object. + * @param action Pointer to the action object. + * @return `true` if the action belongs to the role, otherwise `false`. + */ +bool action_belongs_to_role(const Role *role, const Action *action) { + return std::find(role->actions.begin(), role->actions.end(), *action) != role->actions.end(); +} + +/** + * Check if an action is allowed based on relevant events. + * + * @param action Pointer to the action object. + * @param relevantEvents Pointer to the vector of relevant events. + * @return `true` if the action is allowed, otherwise `false`. + */ +bool is_action_allowed(const Action *action, std::vector *relevant_events) { + bool allowed = false; // Actions are disabled by default + std::sort(relevant_events->begin(), relevant_events->end()); + for (const auto &event : *relevant_events) { + if (std::find(event.prohibits.begin(), event.prohibits.end(), *action) != event.prohibits.end()) { + allowed = false; + } + if (std::find(event.allows.begin(), event.allows.end(), *action) != event.allows.end()) { + allowed = true; + } + } + return allowed; +} + +/** + * Validate if an action is valid for a player in a room based on related events. + * + * @param actor Pointer to the player performing the action. + * @param action Pointer to the action to validate. + * @param room Pointer to the room where the action is taking place. + * @param related_events Pointer to the vector of related events. + * @param target Pointer to the target player (optional, defaults to `nullptr`). + * @return An integer representing the validation status. + */ +ValidationStatus validate_action( + Player *actor, const Action *action, Room *room, std::vector *related_events, Player *target = nullptr) { + if (!actor) { + return ValidationStatus::NoActor; + } + if (!action) { + return ValidationStatus::NoAction; + } + if (!room) { + return ValidationStatus::NoRoom; + } + if (!related_events) { + return ValidationStatus::NoRelatedEvents; + } + if (!player_belongs_to_room(actor, room)) { + return ValidationStatus::PlayerNotInRoom; + } + if (action->has_target && !target) { + return ValidationStatus::NoTargetPlayerSpecified; + } + if (room->status != RoomStatus::InProgress) { + return ValidationStatus::RoomNotInProgress; + } + Role *role = &actor->role; + if (!role) { + return ValidationStatus::NoRole; + } + if (!action_belongs_to_role(role, action)) { + return ValidationStatus::ActionDoesNotBelongToRole; + } + if (!is_action_allowed(action, related_events)) { + return ValidationStatus::ActionProhibited; + } + return ValidationStatus::ActionValid; +} + +std::string ValidationStatusUtils::to_string(ValidationStatus status) { + switch (status) { + case ValidationStatus::PlayerNotInRoom: return "player not in room"; + case ValidationStatus::NoTargetPlayerSpecified: return "no target player specified"; + case ValidationStatus::RoomNotInProgress: return "room not in progress"; + case ValidationStatus::ActionDoesNotBelongToRole: return "action does not belong to role"; + case ValidationStatus::ActionProhibited: return "action prohibited"; + case ValidationStatus::NoActor: return "no actor"; + case ValidationStatus::NoAction: return "no action"; + case ValidationStatus::NoRole: return "no role"; + case ValidationStatus::NoRoom: return "no room"; + case ValidationStatus::NoRelatedEvents: return "no relevant events"; + case ValidationStatus::ActionValid: return "action valid"; + default: return "unknown validation status"; + } +} diff --git a/src/validation.hh b/src/validation.hh new file mode 100644 index 0000000..712ce4f --- /dev/null +++ b/src/validation.hh @@ -0,0 +1,31 @@ +#pragma once +#include "modules/event.hh" +#include "modules/player.hh" +#include "modules/room.hh" + +#include +#include + +enum class ValidationStatus { + PlayerNotInRoom, + NoTargetPlayerSpecified, + RoomNotInProgress, + ActionDoesNotBelongToRole, + ActionProhibited, + NoActor, + NoAction, + NoRole, + NoRoom, + NoRelatedEvents, + ActionValid, +}; + +std::string validation_status_to_string(ValidationStatus status); + +ValidationStatus + validate_action(Player *actor, const Action *action, Room *room, std::vector *relatedEvents, Player *target); + +class ValidationStatusUtils { + public: + static std::string to_string(ValidationStatus status); +};