test: Initial unit testing
- Test quests vector loading - Test default quest on empty fields - Test correct quest - Fixed config paths handling
This commit is contained in:
parent
a5eac1b64f
commit
94d771107d
7 changed files with 102 additions and 15 deletions
|
|
@ -1,30 +1,32 @@
|
||||||
//! Configuration file that handles (de-)serializing other components
|
//! Configuration file that handles (de-)serializing other components
|
||||||
|
|
||||||
use std::{fs::{self, DirEntry},path::PathBuf};
|
use std::{fs::{self, DirEntry},path::{Path, PathBuf}};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::quest::{Quest,error::QuestError};
|
use crate::quest::{Quest,error::QuestError};
|
||||||
|
|
||||||
/// Struct for containing paths to other (de-)serializable things
|
/// Struct for containing paths to other (de-)serializable things
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
/// Path to config directory
|
||||||
|
#[serde(skip)]
|
||||||
|
path: PathBuf,
|
||||||
|
|
||||||
/// Path to serialized [quests][`crate::quest::Quest`] folder
|
/// Path to serialized [quests][`crate::quest::Quest`] folder
|
||||||
#[serde(default)]
|
|
||||||
pub quests_path: PathBuf,
|
pub quests_path: PathBuf,
|
||||||
|
|
||||||
/// Path to serialized [accounts][`crate::account::Account`] folder
|
/// Path to serialized [accounts][`crate::account::Account`] folder
|
||||||
#[serde(default)]
|
|
||||||
pub accounts_path: PathBuf,
|
pub accounts_path: PathBuf,
|
||||||
|
|
||||||
/// Path to serialized [map][`crate::map::Map`] file
|
/// Path to serialized [map][`crate::map::Map`] file
|
||||||
#[serde(default)]
|
|
||||||
pub map: PathBuf
|
pub map: PathBuf
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Config {
|
Config {
|
||||||
|
path: ".".into(),
|
||||||
quests_path: "quests".into(),
|
quests_path: "quests".into(),
|
||||||
accounts_path: "accounts".into(),
|
accounts_path: "accounts".into(),
|
||||||
map: "map.toml".into()
|
map: "map.toml".into()
|
||||||
|
|
@ -60,16 +62,22 @@ impl Config {
|
||||||
/// let config = Config::load(path);
|
/// let config = Config::load(path);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn load(path: PathBuf) -> Self {
|
pub fn load(path: PathBuf) -> Self {
|
||||||
|
let dir = path.parent()
|
||||||
|
.unwrap_or(Path::new("."))
|
||||||
|
.to_owned();
|
||||||
match fs::read_to_string(path) {
|
match fs::read_to_string(path) {
|
||||||
Ok(string) => {
|
Ok(string) => {
|
||||||
match toml::from_str::<Config>(&string) {
|
match toml::from_str::<Config>(&string) {
|
||||||
Ok(conf) => {
|
Ok(mut conf) => {
|
||||||
println!("Successfully loaded config");
|
println!("Successfully loaded config");
|
||||||
|
conf.path = dir;
|
||||||
conf
|
conf
|
||||||
},
|
},
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
eprintln!("Error on parsing config: {error}");
|
eprintln!("Error on parsing config: {error}");
|
||||||
Config::default()
|
let mut cfg = Config::default();
|
||||||
|
cfg.path = dir;
|
||||||
|
cfg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -99,7 +107,10 @@ impl Config {
|
||||||
pub fn load_quests(&self) -> Vec<Quest> {
|
pub fn load_quests(&self) -> Vec<Quest> {
|
||||||
let mut out_vec = Vec::new();
|
let mut out_vec = Vec::new();
|
||||||
|
|
||||||
match fs::read_dir(&self.quests_path) {
|
let mut path = self.path.clone();
|
||||||
|
path.push(self.quests_path.clone());
|
||||||
|
|
||||||
|
match fs::read_dir(path) {
|
||||||
Ok(iter) => {
|
Ok(iter) => {
|
||||||
for entry in iter {
|
for entry in iter {
|
||||||
match entry {
|
match entry {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use serde::{ Serialize, Deserialize };
|
||||||
use error::QuestError;
|
use error::QuestError;
|
||||||
|
|
||||||
/// Difficulty of the quest
|
/// Difficulty of the quest
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
pub enum QuestDifficulty {
|
pub enum QuestDifficulty {
|
||||||
/// Easy quest
|
/// Easy quest
|
||||||
Easy,
|
Easy,
|
||||||
|
|
@ -39,33 +39,41 @@ fn default_answer() -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Quest struct
|
/// Quest struct
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
|
#[serde(default)]
|
||||||
pub struct Quest {
|
pub struct Quest {
|
||||||
/// Quest identifier
|
/// Quest identifier
|
||||||
#[serde(default)]
|
|
||||||
pub id: u16,
|
pub id: u16,
|
||||||
|
|
||||||
/// Difficulty of this quest
|
/// Difficulty of this quest
|
||||||
#[serde(default)]
|
|
||||||
pub difficulty: QuestDifficulty,
|
pub difficulty: QuestDifficulty,
|
||||||
|
|
||||||
/// Reward for the quest
|
/// Reward for the quest
|
||||||
#[serde(default)]
|
|
||||||
pub reward: u32,
|
pub reward: u32,
|
||||||
|
|
||||||
/// Visible quest name
|
/// Visible quest name
|
||||||
#[serde(default = "default_name")]
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
||||||
/// Visible quest description
|
/// Visible quest description
|
||||||
#[serde(default = "default_description")]
|
|
||||||
pub description: String,
|
pub description: String,
|
||||||
|
|
||||||
/// Quest answer, available for admins
|
/// Quest answer, available for admins
|
||||||
#[serde(default = "default_answer")]
|
|
||||||
pub answer: String,
|
pub answer: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for Quest {
|
||||||
|
fn default() -> Self {
|
||||||
|
Quest {
|
||||||
|
id: u16::default(),
|
||||||
|
difficulty: QuestDifficulty::default(),
|
||||||
|
reward: u32::default(),
|
||||||
|
name: default_name(),
|
||||||
|
description: default_description(),
|
||||||
|
answer: default_answer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Quest {
|
impl Quest {
|
||||||
/// Parse quest TOML or return error
|
/// Parse quest TOML or return error
|
||||||
pub fn load(path: PathBuf) -> Result<Self, QuestError> {
|
pub fn load(path: PathBuf) -> Result<Self, QuestError> {
|
||||||
|
|
|
||||||
10
tests/cfg/config.toml
Normal file
10
tests/cfg/config.toml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Default config
|
||||||
|
|
||||||
|
# Path to quests folder relative to config
|
||||||
|
quests_path = "quests"
|
||||||
|
|
||||||
|
# Path to accounts folder relative to config
|
||||||
|
accounts_path = "accounts"
|
||||||
|
|
||||||
|
# Path to map .toml file relative to config
|
||||||
|
map = "map.toml"
|
||||||
2
tests/cfg/quests/0.toml
Normal file
2
tests/cfg/quests/0.toml
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# This example demonstrates that empty quests will be loaded correctly with default values
|
||||||
|
# see main.rs
|
||||||
8
tests/cfg/quests/1.toml
Normal file
8
tests/cfg/quests/1.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# This example demonstrates typical quest
|
||||||
|
# see main.rs
|
||||||
|
id = 1
|
||||||
|
difficulty = "Easy"
|
||||||
|
reward = 100
|
||||||
|
name = "Example easy quest"
|
||||||
|
description = "Answer this quest without any attachments or comments"
|
||||||
|
answer = "Accept the answer if it has no attachments and an empty comment"
|
||||||
8
tests/cfg/quests/2.toml
Normal file
8
tests/cfg/quests/2.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# This example demonstrates incorrect quest which will not be loaded from config
|
||||||
|
# see main.rs
|
||||||
|
id = 133713371337
|
||||||
|
difficulty = sick
|
||||||
|
reward = an infinite amount of coffee
|
||||||
|
name = "Impossible quest"
|
||||||
|
description = "This quest won't be loaded in the game, therefore you can't solve it"
|
||||||
|
answer = 42
|
||||||
40
tests/main.rs
Normal file
40
tests/main.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
use squad_quest::{config::Config, quest::Quest};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn load_quests() {
|
||||||
|
let config = Config::load("./tests/cfg/config.toml".into());
|
||||||
|
let quests = config.load_quests();
|
||||||
|
|
||||||
|
assert_eq!(quests.len(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_quest_is_default() {
|
||||||
|
// First loaded quest should be 0.toml, which is empty
|
||||||
|
let config = Config::load("./tests/cfg/config.toml".into());
|
||||||
|
let mut quests = config.load_quests();
|
||||||
|
quests.sort_by(|a,b| a.id.cmp(&b.id));
|
||||||
|
let quest = quests.first().unwrap();
|
||||||
|
|
||||||
|
let default = Quest::default();
|
||||||
|
|
||||||
|
assert_eq!(*quest, default);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn quest_one() {
|
||||||
|
let config = Config::load("./tests/cfg/config.toml".into());
|
||||||
|
let quests = config.load_quests();
|
||||||
|
let quest = quests.iter().find(|q| q.id == 1).unwrap();
|
||||||
|
|
||||||
|
let expected = Quest {
|
||||||
|
id: 1,
|
||||||
|
difficulty: squad_quest::quest::QuestDifficulty::Easy,
|
||||||
|
reward: 100,
|
||||||
|
name: "Example easy quest".to_owned(),
|
||||||
|
description: "Answer this quest without any attachments or comments".to_owned(),
|
||||||
|
answer: "Accept the answer if it has no attachments and an empty comment".to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(*quest, expected);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue