mirror of
https://github.com/jorenchik/testing-spring-2024.git
synced 2025-10-21 20:10:36 +00:00
Merge pull request #14 from jorenchik/kristoferssolo/refactor/root
This commit is contained in:
commit
0e74bc30d5
@ -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)
|
||||
|
||||
28
README-lv.md
28
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.
|
||||
|
||||
17
README.md
17
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`.
|
||||
|
||||
@ -1 +0,0 @@
|
||||
add_library(cppunit cppunit.cpp cppunit.hh)
|
||||
@ -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
|
||||
98
src/lib.cpp
98
src/lib.cpp
@ -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;
|
||||
}
|
||||
@ -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
24
src/main.cc
Normal 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;
|
||||
}
|
||||
@ -1,8 +0,0 @@
|
||||
#include "lib.hh"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
run();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
14
src/modules/CMakeLists.txt
Normal file
14
src/modules/CMakeLists.txt
Normal 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
12
src/modules/action.cc
Normal 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
10
src/modules/action.hh
Normal 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
48
src/modules/event.cc
Normal 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
41
src/modules/event.hh
Normal 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
16
src/modules/player.cc
Normal 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
22
src/modules/player.hh
Normal 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
10
src/modules/role.cc
Normal 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
12
src/modules/role.hh
Normal 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
25
src/modules/room.cc
Normal 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
27
src/modules/room.hh
Normal 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);
|
||||
};
|
||||
@ -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
6
src/modules/time.hh
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
|
||||
std::tm *create_utc_timestamp(uint32_t timestamp);
|
||||
@ -1 +0,0 @@
|
||||
add_library(prepLib prep.cpp prep.hh timeUtils.cpp timeUtils.hh)
|
||||
@ -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;
|
||||
}
|
||||
103
src/prep/prep.hh
103
src/prep/prep.hh
@ -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
|
||||
@ -1,9 +0,0 @@
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
|
||||
#ifndef TIMEUTILS_H
|
||||
# define TIMEUTILS_H
|
||||
|
||||
std::tm *createUTCTimestamp(uint32_t timestamp);
|
||||
|
||||
#endif
|
||||
@ -1,5 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
TEST(ProgramTest, testFunction) {
|
||||
EXPECT_EQ(8, 8);
|
||||
}
|
||||
10
src/test_validation.cc
Normal file
10
src/test_validation.cc
Normal 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
116
src/validation.cc
Normal 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
31
src/validation.hh
Normal 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);
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user