Merge pull request #14 from jorenchik/kristoferssolo/refactor/root

This commit is contained in:
Kristofers Solo 2024-03-14 03:46:49 +02:00 committed by GitHub
commit 0e74bc30d5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 477 additions and 445 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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`.

View File

@ -1 +0,0 @@
add_library(cppunit cppunit.cpp cppunit.hh)

View File

@ -1,83 +0,0 @@
#ifndef CPPUNIT_H
#define CPPUNIT_H
// Required headers, or just use #include <bits/stdc++.h>
#include <cstring>
#include <ctime>
#include <iostream>
#include <sstream>
#include <string>
// CPlusPlusUnit - C++ Unit testing TDD framework (github.com/cppunit/cppunit)
class Cppunit {
public:
#define CHECK(a, b) check<long long>(a, b, #a, #b, __FILE__, __LINE__, __FUNCTION__);
#define CHECKT(a) check<bool>(a, true, #a, "true", __FILE__, __LINE__, __FUNCTION__);
#define CHECKS(a, b) check<cs>(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 <typename T> 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

View File

@ -1,98 +0,0 @@
#include "lib.hh"
#include "prep/prep.hh"
#include <algorithm>
#include <cstdio>
#include <vector>
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<Event> 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<Event> *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<Event> *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;
}

View File

@ -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<Event> *relevantEvents);
int validateAction(Player *actor, const Action *action, Room *room, std::vector<Event> *relatedEvents, Player *target);

24
src/main.cc Normal file
View File

@ -0,0 +1,24 @@
#include "./validation.hh"
#include <stdlib.h>
#include <string>
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<Event> 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;
}

View File

@ -1,8 +0,0 @@
#include "lib.hh"
#include <stdlib.h>
int main(int argc, char *argv[]) {
run();
return EXIT_SUCCESS;
}

View File

@ -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)

12
src/modules/action.cc Normal file
View File

@ -0,0 +1,12 @@
#include "./action.hh"
#include <string>
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;
}

10
src/modules/action.hh Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include <string>
struct Action {
std::string name;
bool has_target;
Action(std::string name, bool has_target);
bool operator==(const Action &other) const;
};

48
src/modules/event.cc Normal file
View File

@ -0,0 +1,48 @@
#include "./event.hh"
#include "./action.hh"
#include "./time.hh"
#include <initializer_list>
#include <string>
#include <vector>
Event::Event(std::string title,
uint32_t created_at,
uint32_t night_number,
bool is_visible,
std::vector<Action> prohibits,
std::vector<Action> 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<Action> prohibits,
std::initializer_list<Action> 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;
}

41
src/modules/event.hh Normal file
View File

@ -0,0 +1,41 @@
#pragma once
#include "./action.hh"
#include <cstdint>
#include <ctime>
#include <initializer_list>
#include <string>
#include <vector>
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<Action> prohibits;
std::vector<Action> 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<Action> prohibits,
std::vector<Action> allows);
Event(std::string title,
uint32_t created_at,
uint32_t night_number,
bool is_visible,
std::initializer_list<Action> prohibits,
std::initializer_list<Action> allows);
};

16
src/modules/player.cc Normal file
View File

@ -0,0 +1,16 @@
#include "./player.hh"
#include "./role.hh"
#include <string>
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;
}

22
src/modules/player.hh Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include "./role.hh"
#include <cstdint>
#include <string>
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;
};

10
src/modules/role.cc Normal file
View File

@ -0,0 +1,10 @@
#include "./role.hh"
#include <initializer_list>
#include <vector>
Role::Role(std::initializer_list<Action> actions): Role(std::vector<Action>(actions)) {
}
Role::Role(std::vector<Action> actions): actions(actions) {
}

12
src/modules/role.hh Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "./action.hh"
#include <initializer_list>
#include <vector>
struct Role {
std::vector<Action> actions;
explicit Role(std::vector<Action> actions);
Role(std::initializer_list<Action> actions);
};

25
src/modules/room.cc Normal file
View File

@ -0,0 +1,25 @@
#include "./room.hh"
#include "./time.hh"
#include <cstdint>
#include <initializer_list>
#include <string>
#include <vector>
Room::Room(uint32_t id, std::string title, uint32_t created_at, RoomStatus status, std::vector<Player> 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<Player> players):
id(id),
title(title),
status(status),
players(players) {
this->created_at = create_utc_timestamp(created_at);
}

27
src/modules/room.hh Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include "./player.hh"
#include <cstdint>
#include <ctime>
#include <initializer_list>
#include <string>
#include <vector>
enum class RoomStatus {
AwaitingStart,
InProgress,
Stopped,
Ended,
};
struct Room {
uint32_t id;
std::string title;
std::tm *created_at;
RoomStatus status;
std::vector<Player> players;
Room(uint32_t id, std::string title, uint32_t created_at, RoomStatus status, std::vector<Player> players);
Room(uint32_t id, std::string title, uint32_t created_at, RoomStatus status, std::initializer_list<Player> players);
};

View File

@ -1,10 +1,10 @@
#include "timeUtils.hh"
#include "./time.hh"
#include <chrono>
#include <cstdint>
#include <ctime>
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<std::chrono::system_clock> tp(sec);

6
src/modules/time.hh Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <cstdint>
#include <ctime>
std::tm *create_utc_timestamp(uint32_t timestamp);

View File

@ -1 +0,0 @@
add_library(prepLib prep.cpp prep.hh timeUtils.cpp timeUtils.hh)

View File

@ -1,92 +0,0 @@
#include "prep.hh"
#include "timeUtils.hh"
#include <cstdint>
#include <initializer_list>
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<Action> actions): Role(std::vector<Action>(actions)) {
}
Role::Role(std::vector<Action> 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<Player> 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<Player> players):
Room(id, title, utcTimestampCreatedAt, status, std::vector<Player>(players)) {
this->utcTimestampCreatedAt = createUTCTimestamp(utcTimestampCreatedAt);
}
Event::Event(std::string title,
uint32_t utcTimestampCreatedAt,
uint32_t numberNight,
bool isVisible,
std::vector<Action> prohibits,
std::vector<Action> 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<Action> prohibits,
std::initializer_list<Action> allows):
Event(title,
utcTimestampCreatedAt,
numberNight,
isVisible,
std::vector<Action>(prohibits),
std::vector<Action>(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;
}

View File

@ -1,103 +0,0 @@
#ifndef PREP_H
#define PREP_H
#include <cstdint>
#include <ctime>
#include <string>
#include <vector>
// 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<Action> actions;
Role(std::initializer_list<Action> actions);
Role(std::vector<Action> 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<Player> players;
Room(
uint32_t id, std::string title, uint32_t utcTimestampCreatedAt, RoomStatus status, std::vector<Player> players);
Room(uint32_t id,
std::string title,
uint32_t utcTimestampCreatedAt,
RoomStatus status,
std::initializer_list<Player> players);
};
struct Event {
std::string title;
std::tm *utcTimestampCreatedAt;
uint32_t numberNight;
bool isVisible;
std::vector<Action> prohibits;
std::vector<Action> 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<Action> prohibits,
std::vector<Action> allows);
Event(std::string title,
uint32_t utcTimestampCreatedAt,
uint32_t numberNight,
bool isVisible,
std::initializer_list<Action> prohibits,
std::initializer_list<Action> allows);
};
#endif

View File

@ -1,9 +0,0 @@
#include <cstdint>
#include <ctime>
#ifndef TIMEUTILS_H
# define TIMEUTILS_H
std::tm *createUTCTimestamp(uint32_t timestamp);
#endif

View File

@ -1,5 +0,0 @@
#include <gtest/gtest.h>
TEST(ProgramTest, testFunction) {
EXPECT_EQ(8, 8);
}

10
src/test_validation.cc Normal file
View File

@ -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();
}

116
src/validation.cc Normal file
View File

@ -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 <algorithm>
#include <string>
/**
* 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<Event> *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<Event> *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";
}
}

31
src/validation.hh Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include "modules/event.hh"
#include "modules/player.hh"
#include "modules/room.hh"
#include <string>
#include <vector>
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<Event> *relatedEvents, Player *target);
class ValidationStatusUtils {
public:
static std::string to_string(ValidationStatus status);
};