Support mocking DB to increase testability.
This commit is contained in:
parent
8d12c88904
commit
4652fa52cf
110
Cargo.lock
generated
110
Cargo.lock
generated
@ -151,6 +151,8 @@ dependencies = [
|
||||
"humantime",
|
||||
"itertools",
|
||||
"log",
|
||||
"mockall",
|
||||
"mockall_double",
|
||||
"nix",
|
||||
"nom",
|
||||
"once_cell",
|
||||
@ -479,6 +481,12 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "difflib"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.6"
|
||||
@ -490,6 +498,12 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
|
||||
|
||||
[[package]]
|
||||
name = "educe"
|
||||
version = "0.4.20"
|
||||
@ -537,6 +551,15 @@ dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "float-cmp"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@ -552,6 +575,12 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fragile"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.25"
|
||||
@ -1019,6 +1048,45 @@ dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockall"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50e4a1c770583dac7ab5e2f6c139153b783a53a1bbee9729613f193e59828326"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"downcast",
|
||||
"fragile",
|
||||
"lazy_static",
|
||||
"mockall_derive",
|
||||
"predicates",
|
||||
"predicates-tree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockall_derive"
|
||||
version = "0.11.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "832663583d5fa284ca8810bf7015e46c9fff9622d3cf34bd1eea5003fec06dd0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockall_double"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae71c7bb287375187c775cf82e2dcf1bef3388aaf58f0789a77f9c7ab28466f6"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multipart"
|
||||
version = "0.18.0"
|
||||
@ -1061,6 +1129,12 @@ dependencies = [
|
||||
"minimal-lexical",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "normalize-line-endings"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
|
||||
|
||||
[[package]]
|
||||
name = "num-bigint"
|
||||
version = "0.4.3"
|
||||
@ -1281,6 +1355,36 @@ version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "predicates"
|
||||
version = "2.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd"
|
||||
dependencies = [
|
||||
"difflib",
|
||||
"float-cmp",
|
||||
"itertools",
|
||||
"normalize-line-endings",
|
||||
"predicates-core",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "predicates-core"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2"
|
||||
|
||||
[[package]]
|
||||
name = "predicates-tree"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d"
|
||||
dependencies = [
|
||||
"predicates-core",
|
||||
"termtree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "0.1.5"
|
||||
@ -1780,6 +1884,12 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termtree"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8"
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.38"
|
||||
|
@ -39,3 +39,5 @@ async-recursion = "1.0.0"
|
||||
rand_distr = "0.4.3"
|
||||
humantime = "2.1.0"
|
||||
rust_decimal = "1.28.0"
|
||||
mockall = "0.11.3"
|
||||
mockall_double = "0.3.0"
|
||||
|
@ -25,6 +25,8 @@ use serde::{Serialize, Deserialize};
|
||||
use serde_json::{self, Value};
|
||||
use futures::FutureExt;
|
||||
use chrono::{DateTime, Utc};
|
||||
#[cfg(test)]
|
||||
use mockall::automock;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DBPool {
|
||||
@ -70,6 +72,7 @@ pub struct LocationStats {
|
||||
pub total_weight: u64,
|
||||
}
|
||||
|
||||
#[cfg_attr(test, allow(dead_code))]
|
||||
impl DBPool {
|
||||
pub async fn record_listener_ping(self: &DBPool, listener: Uuid) -> DResult<()> {
|
||||
self.get_conn().await?.execute(
|
||||
@ -246,18 +249,19 @@ impl ItemSearchParams<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg_attr(test, automock)]
|
||||
#[cfg_attr(test, allow(dead_code))]
|
||||
impl DBTrans {
|
||||
pub async fn queue_for_session(self: &Self,
|
||||
session: &ListenerSession,
|
||||
message: Option<&str>) -> DResult<()> {
|
||||
pub async fn queue_for_session<'a>(self: &'a Self,
|
||||
session: &'a ListenerSession,
|
||||
message: Option<&'a str>) -> DResult<()> {
|
||||
self.pg_trans()?
|
||||
.execute("INSERT INTO sendqueue (session, listener, message) VALUES ($1, $2, $3)",
|
||||
&[&session.session, &session.listener, &message]).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_session_user_model(self: &Self, session: &ListenerSession) -> DResult<Option<(Session, Option<User>)>> {
|
||||
pub async fn get_session_user_model<'a>(self: &'a Self, session: &'a ListenerSession) -> DResult<Option<(Session, Option<User>)>> {
|
||||
match self.pg_trans()?
|
||||
.query_opt("SELECT s.details AS sess_details, \
|
||||
u.details AS user_details FROM sessions s \
|
||||
@ -277,7 +281,7 @@ impl DBTrans {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn save_session_model(self: &Self, session: &ListenerSession, details: &Session)
|
||||
pub async fn save_session_model<'a>(self: &'a Self, session: &'a ListenerSession, details: &Session)
|
||||
-> DResult<()> {
|
||||
self.pg_trans()?
|
||||
.execute("UPDATE sessions SET details = $1 WHERE session = $2",
|
||||
@ -285,7 +289,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn find_by_username(self: &Self, username: &str) -> DResult<Option<User>> {
|
||||
pub async fn find_by_username<'a>(self: &'a Self, username: &'a str) -> DResult<Option<User>> {
|
||||
if let Some(details_json) = self.pg_trans()?
|
||||
.query_opt("SELECT details FROM users WHERE username=$1",
|
||||
&[&username.to_lowercase()]).await? {
|
||||
@ -294,13 +298,13 @@ impl DBTrans {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub async fn create_item(self: &Self, item: &Item) -> DResult<i64> {
|
||||
pub async fn create_item<'a>(self: &'a Self, item: &'a Item) -> DResult<i64> {
|
||||
Ok(self.pg_trans()?.query_one("INSERT INTO items (details) VALUES ($1) RETURNING item_id",
|
||||
&[&serde_json::to_value(item)?]).await?
|
||||
.get("item_id"))
|
||||
}
|
||||
|
||||
pub async fn limited_update_static_item(self: &Self, item: &Item) -> DResult<()> {
|
||||
pub async fn limited_update_static_item<'a>(self: &'a Self, item: &'a Item) -> DResult<()> {
|
||||
let value = serde_json::to_value(item)?;
|
||||
let obj_map = value.as_object()
|
||||
.expect("Static item to be object in JSON");
|
||||
@ -323,7 +327,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn limited_update_static_task(self: &Self, task: &Task) -> DResult<()> {
|
||||
pub async fn limited_update_static_task<'a>(self: &'a Self, task: &'a Task) -> DResult<()> {
|
||||
let value = serde_json::to_value(task)?;
|
||||
let obj_map = value.as_object()
|
||||
.expect("Static task to be object in JSON");
|
||||
@ -346,7 +350,7 @@ impl DBTrans {
|
||||
}
|
||||
|
||||
|
||||
pub async fn create_user(self: &Self, session: &ListenerSession, user_dat: &User) -> DResult<()> {
|
||||
pub async fn create_user<'a>(self: &'a Self, session: &'a ListenerSession, user_dat: &'a User) -> DResult<()> {
|
||||
self.pg_trans()?.execute("INSERT INTO users (\
|
||||
username, current_session, current_listener, details\
|
||||
) VALUES ($1, $2, $3, $4)", &[&user_dat.username.to_lowercase(),
|
||||
@ -356,7 +360,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn save_user_model(self: &Self, details: &User)
|
||||
pub async fn save_user_model<'a>(self: &'a Self, details: &'a User)
|
||||
-> DResult<()> {
|
||||
self.pg_trans()?
|
||||
.execute("UPDATE users SET details = $1 WHERE username = $2",
|
||||
@ -365,8 +369,8 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn attach_user_to_session(self: &Self, username: &str,
|
||||
session: &ListenerSession) -> DResult<()> {
|
||||
pub async fn attach_user_to_session<'a>(self: &'a Self, username: &'a str,
|
||||
session: &'a ListenerSession) -> DResult<()> {
|
||||
let username_l = username.to_lowercase();
|
||||
self.pg_trans()?
|
||||
.execute("INSERT INTO sendqueue (session, listener, message) \
|
||||
@ -386,7 +390,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn find_static_items_by_type(self: &Self, item_type: &str) ->
|
||||
pub async fn find_static_items_by_type<'a>(self: &'a Self, item_type: &'a str) ->
|
||||
DResult<Box<BTreeSet<String>>> {
|
||||
Ok(Box::new(
|
||||
self.pg_trans()?
|
||||
@ -399,7 +403,7 @@ impl DBTrans {
|
||||
.collect()))
|
||||
}
|
||||
|
||||
pub async fn find_static_tasks_by_type(self: &Self, task_type: &str) ->
|
||||
pub async fn find_static_tasks_by_type<'a>(self: &'a Self, task_type: &'a str) ->
|
||||
DResult<Box<BTreeSet<String>>> {
|
||||
Ok(Box::new(
|
||||
self.pg_trans()?
|
||||
@ -412,7 +416,7 @@ impl DBTrans {
|
||||
.collect()))
|
||||
}
|
||||
|
||||
pub async fn delete_static_items_by_code(self: &Self, item_type: &str,
|
||||
pub async fn delete_static_items_by_code<'a>(self: &'a Self, item_type: &'a str,
|
||||
item_code: &str) -> DResult<()> {
|
||||
self.pg_trans()?.query(
|
||||
"DELETE FROM items WHERE details->>'is_static' = 'true' AND \
|
||||
@ -422,8 +426,8 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_static_tasks_by_code(self: &Self, task_type: &str,
|
||||
task_code: &str) -> DResult<()> {
|
||||
pub async fn delete_static_tasks_by_code<'a>(self: &'a Self, task_type: &'a str,
|
||||
task_code: &'a str) -> DResult<()> {
|
||||
self.pg_trans()?.query(
|
||||
"DELETE FROM task WHERE details->>'is_static' = 'true' AND \
|
||||
details->>'task_type' = $1 AND \
|
||||
@ -432,7 +436,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn find_item_by_type_code(self: &Self, item_type: &str, item_code: &str) ->
|
||||
pub async fn find_item_by_type_code<'a>(self: &'a Self, item_type: &'a str, item_code: &'a str) ->
|
||||
DResult<Option<Arc<Item>>> {
|
||||
if let Some(item) = self.pg_trans()?.query_opt(
|
||||
"SELECT details FROM items WHERE \
|
||||
@ -443,7 +447,7 @@ impl DBTrans {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub async fn transfer_all_possessions_code(self: &Self, src_loc: &str, dst_loc: &str) -> DResult<()> {
|
||||
pub async fn transfer_all_possessions_code<'a>(self: &'a Self, src_loc: &'a str, dst_loc: &'a str) -> DResult<()> {
|
||||
self.pg_trans()?.execute(
|
||||
"UPDATE items SET details=JSONB_SET(details, '{location}', $1) \
|
||||
WHERE details->>'location' = $2",
|
||||
@ -451,14 +455,14 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn transfer_all_possessions(self: &Self, source: &Item, dest: &Item) -> DResult<()> {
|
||||
pub async fn transfer_all_possessions<'a>(self: &'a Self, source: &'a Item, dest: &'a Item) -> DResult<()> {
|
||||
let src_loc = format!("{}/{}", &source.item_type, &source.item_code);
|
||||
let dst_loc = format!("{}/{}", &dest.item_type, &dest.item_code);
|
||||
self.transfer_all_possessions_code(&src_loc, &dst_loc).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn find_items_by_location(self: &Self, location: &str) -> DResult<Vec<Arc<Item>>> {
|
||||
pub async fn find_items_by_location<'a>(self: &'a Self, location: &'a str) -> DResult<Vec<Arc<Item>>> {
|
||||
Ok(self.pg_trans()?.query(
|
||||
"SELECT details FROM items WHERE details->>'location' = $1 \
|
||||
ORDER BY details->>'display'
|
||||
@ -480,7 +484,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn delete_item(self: &Self, item_type: &str, item_code: &str) -> DResult<()> {
|
||||
pub async fn delete_item<'a>(self: &'a Self, item_type: &'a str, item_code: &'a str) -> DResult<()> {
|
||||
self.pg_trans()?
|
||||
.execute("DELETE FROM items WHERE \
|
||||
details->>'item_type' = $1 AND \
|
||||
@ -489,7 +493,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn find_session_for_player(self: &Self, item_code: &str) -> DResult<Option<(ListenerSession, Session)>> {
|
||||
pub async fn find_session_for_player<'a>(self: &'a Self, item_code: &'a str) -> DResult<Option<(ListenerSession, Session)>> {
|
||||
Ok(self.pg_trans()?
|
||||
.query_opt("SELECT u.current_listener, u.current_session, s.details \
|
||||
FROM users u JOIN sessions s ON s.session = u.current_session \
|
||||
@ -505,7 +509,7 @@ impl DBTrans {
|
||||
}
|
||||
|
||||
pub async fn resolve_items_by_display_name_for_player<'l>(
|
||||
self: &Self,
|
||||
self: &'l Self,
|
||||
search: &'l ItemSearchParams<'l>
|
||||
) -> DResult<Arc<Vec<Arc<Item>>>> {
|
||||
let mut ctes: Vec<String> = Vec::new();
|
||||
@ -587,7 +591,7 @@ impl DBTrans {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn delete_task(&self, task_type: &str, task_code: &str) -> DResult<()> {
|
||||
pub async fn delete_task<'a>(&'a self, task_type: &'a str, task_code: &'a str) -> DResult<()> {
|
||||
self.pg_trans()?.execute(
|
||||
"DELETE FROM tasks WHERE details->>'task_type' = $1 AND \
|
||||
details->>'task_code' = $2", &[&task_type, &task_code]
|
||||
@ -595,7 +599,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn upsert_task(&self, task: &Task) -> DResult<()> {
|
||||
pub async fn upsert_task<'a>(&'a self, task: &'a Task) -> DResult<()> {
|
||||
self.pg_trans()?.execute(
|
||||
"INSERT INTO tasks (details) \
|
||||
VALUES ($1) \
|
||||
@ -604,7 +608,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn update_task(&self, task_type: &str, task_code: &str, task: &TaskParse) -> DResult<()> {
|
||||
pub async fn update_task<'a>(&'a self, task_type: &'a str, task_code: &'a str, task: &'a TaskParse) -> DResult<()> {
|
||||
self.pg_trans()?.execute(
|
||||
"UPDATE tasks SET details = $3 WHERE details->>'task_type' = $1 AND \
|
||||
details->>'task_code' = $2",
|
||||
@ -681,7 +685,7 @@ impl DBTrans {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pg_trans(self: &Self) -> DResult<&Transaction> {
|
||||
pub fn pg_trans<'a>(self: &'a Self) -> DResult<&'a Transaction<'a>> {
|
||||
self.borrow_trans().as_ref().ok_or("Transaction already closed".into())
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,17 @@ pub struct ListenerSession {
|
||||
pub session: Uuid
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for ListenerSession {
|
||||
fn default() -> ListenerSession {
|
||||
use uuid::uuid;
|
||||
ListenerSession {
|
||||
listener: uuid!("6f9c9b61-9228-4427-abd7-c4aef127a862"),
|
||||
session: uuid!("668efb68-79d3-4004-9d6a-1e5757792e1a")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn handle(listener: Uuid, msg: MessageFromListener, pool: db::DBPool)
|
||||
-> DResult<()> {
|
||||
match msg {
|
||||
|
@ -1,11 +1,13 @@
|
||||
use super::ListenerSession;
|
||||
use crate::DResult;
|
||||
use crate::db::{DBTrans, DBPool, ItemSearchParams};
|
||||
use ansi::ansi;
|
||||
use crate::db::{DBPool, ItemSearchParams};
|
||||
use mockall_double::double;
|
||||
#[double] use crate::db::DBTrans;
|
||||
#[cfg(not(test))] use ansi::ansi;
|
||||
use phf::phf_map;
|
||||
use async_trait::async_trait;
|
||||
use crate::models::{session::Session, user::User, item::Item};
|
||||
use log::warn;
|
||||
#[cfg(not(test))] use log::warn;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -149,6 +151,7 @@ fn resolve_handler(ctx: &VerbContext, cmd: &str) -> Option<&'static UserVerbRef>
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub async fn handle(session: &ListenerSession, msg: &str, pool: &DBPool) -> DResult<()> {
|
||||
let (cmd, params) = parsing::parse_command_name(msg);
|
||||
let trans = pool.start_transaction().await?;
|
||||
@ -161,11 +164,11 @@ pub async fn handle(session: &ListenerSession, msg: &str, pool: &DBPool) -> DRes
|
||||
}
|
||||
Some(v) => v
|
||||
};
|
||||
|
||||
|
||||
let mut ctx = VerbContext { session, trans: &trans, session_dat: &mut session_dat,
|
||||
user_dat: &mut user_dat };
|
||||
let handler_opt = resolve_handler(&ctx, cmd);
|
||||
|
||||
|
||||
match handler_opt {
|
||||
None => {
|
||||
trans.queue_for_session(session,
|
||||
@ -190,6 +193,11 @@ pub async fn handle(session: &ListenerSession, msg: &str, pool: &DBPool) -> DRes
|
||||
pool.bump_session_time(&session).await?;
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(test)]
|
||||
pub async fn handle(_session: &ListenerSession, _msg: &str, _pool: &DBPool) -> DResult<()> {
|
||||
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
pub fn is_likely_explicit(msg: &str) -> bool {
|
||||
static EXPLICIT_MARKER_WORDS: OnceCell<Vec<&'static str>> =
|
||||
@ -230,3 +238,22 @@ pub async fn search_item_for_user<'l>(ctx: &'l VerbContext<'l>, search: &'l Item
|
||||
item1.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)] mod test {
|
||||
use crate::db::MockDBTrans;
|
||||
|
||||
#[test]
|
||||
fn resolve_handler_finds_unregistered() {
|
||||
use super::*;
|
||||
|
||||
let trans = MockDBTrans::new();
|
||||
let sess: ListenerSession = Default::default();
|
||||
let mut user_dat: Option<User> = None;
|
||||
let mut session_dat: Session = Default::default();
|
||||
let ctx = VerbContext { session: &sess,
|
||||
trans: &trans,
|
||||
session_dat: &mut session_dat,
|
||||
user_dat: &mut user_dat };
|
||||
resolve_handler(&ctx, "less_explicit_mode");
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ use crate::{
|
||||
queue_command
|
||||
},
|
||||
static_content::room::{self, Direction, ExitType},
|
||||
db::DBTrans,
|
||||
models::item::{
|
||||
Item,
|
||||
SkillType,
|
||||
@ -26,6 +25,8 @@ use crate::{
|
||||
combat::handle_resurrect,
|
||||
}
|
||||
};
|
||||
use mockall_double::double;
|
||||
#[double] use crate::db::DBTrans;
|
||||
use std::time;
|
||||
|
||||
pub async fn announce_move(trans: &DBTrans, character: &Item, leaving: &Item, arriving: &Item) -> DResult<()> {
|
||||
|
@ -4,8 +4,9 @@ use super::{VerbContext, UserVerb, UserVerbRef, UResult, UserError,
|
||||
use crate::{
|
||||
models::item::{Item, ItemFlag},
|
||||
services::broadcast_to_room,
|
||||
db::DBTrans
|
||||
};
|
||||
use mockall_double::double;
|
||||
#[double] use crate::db::DBTrans;
|
||||
use async_trait::async_trait;
|
||||
use ansi::{ignore_special_characters, ansi};
|
||||
|
||||
|
@ -3,22 +3,25 @@ use async_trait::async_trait;
|
||||
use crate::{
|
||||
DResult,
|
||||
db,
|
||||
models::task::{Task, TaskParse, TaskRecurrence},
|
||||
models::task::Task,
|
||||
listener::{ListenerMap, ListenerSend},
|
||||
static_content::npc,
|
||||
services::combat,
|
||||
};
|
||||
#[cfg(not(test))] use crate::models::task::{TaskParse, TaskRecurrence};
|
||||
use mockall_double::double;
|
||||
#[double] use crate::db::DBTrans;
|
||||
use blastmud_interfaces::MessageToListener;
|
||||
use log::warn;
|
||||
use once_cell::sync::OnceCell;
|
||||
use std::ops::AddAssign;
|
||||
#[cfg(not(test))] use std::ops::AddAssign;
|
||||
use std::collections::BTreeMap;
|
||||
use chrono::Utc;
|
||||
#[cfg(not(test))] use chrono::Utc;
|
||||
|
||||
pub mod queued_command;
|
||||
|
||||
pub struct TaskRunContext<'l> {
|
||||
pub trans: &'l db::DBTrans,
|
||||
pub trans: &'l DBTrans,
|
||||
pub task: &'l mut Task
|
||||
}
|
||||
|
||||
@ -112,6 +115,7 @@ fn start_send_queue_task(pool: db::DBPool, listener_map: ListenerMap) {
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(test))]
|
||||
async fn process_tasks_once(pool: db::DBPool) -> DResult<()> {
|
||||
loop {
|
||||
let tx = pool.start_transaction().await?;
|
||||
@ -198,6 +202,12 @@ async fn process_tasks_once(pool: db::DBPool) -> DResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
async fn process_tasks_once(_pool: db::DBPool) -> DResult<()> {
|
||||
task_handler_registry();
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn start_task_runner(pool: db::DBPool) {
|
||||
task::spawn(async move {
|
||||
loop {
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::{
|
||||
db::DBTrans,
|
||||
DResult,
|
||||
models::item::Item,
|
||||
};
|
||||
use mockall_double::double;
|
||||
#[double] use crate::db::DBTrans;
|
||||
|
||||
pub mod skills;
|
||||
pub mod combat;
|
||||
|
@ -1,8 +1,9 @@
|
||||
use crate::{
|
||||
db::DBTrans,
|
||||
DResult,
|
||||
};
|
||||
use crate::DResult;
|
||||
use mockall_double::double;
|
||||
#[double] use crate::db::DBTrans;
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum CapacityLevel {
|
||||
Unburdened,
|
||||
SlightlyBurdened,
|
||||
@ -34,3 +35,25 @@ pub async fn check_item_capacity(trans: &DBTrans,
|
||||
}
|
||||
Ok(CapacityLevel::Unburdened)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::db::{
|
||||
MockDBTrans,
|
||||
LocationStats
|
||||
};
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn check_item_capacity_should_say_above_item_limit_if_over() {
|
||||
let mut mock_db = MockDBTrans::new();
|
||||
mock_db.expect_get_location_stats()
|
||||
.withf(|s| s == "player/foo")
|
||||
.returning(|_| Ok(LocationStats {
|
||||
total_count: 49,
|
||||
total_weight: 100,
|
||||
}));
|
||||
assert_eq!(check_item_capacity(&mock_db, "player/foo", 10).await.unwrap(),
|
||||
CapacityLevel::AboveItemLimit);
|
||||
}
|
||||
}
|
||||
|
@ -15,8 +15,9 @@ use crate::{
|
||||
message_handler::user_commands::{user_error, UResult},
|
||||
regular_tasks::{TaskRunContext, TaskHandler},
|
||||
DResult,
|
||||
db::DBTrans,
|
||||
};
|
||||
use mockall_double::double;
|
||||
#[double] use crate::db::DBTrans;
|
||||
use async_trait::async_trait;
|
||||
use chrono::Utc;
|
||||
use async_recursion::async_recursion;
|
||||
|
@ -3,12 +3,13 @@ use crate::{
|
||||
item::{Item, SkillType, StatType, BuffImpact},
|
||||
user::User
|
||||
},
|
||||
db::DBTrans,
|
||||
DResult,
|
||||
};
|
||||
use rand::{self, Rng};
|
||||
use chrono::Utc;
|
||||
use std::collections::BTreeMap;
|
||||
use mockall_double::double;
|
||||
#[double] use crate::db::DBTrans;
|
||||
|
||||
pub fn calculate_total_stats_skills_for_user(target_item: &mut Item, user: &User) {
|
||||
target_item.total_stats = BTreeMap::new();
|
||||
|
Loading…
Reference in New Issue
Block a user