adds basic resolve_claims + test

This commit is contained in:
2019-07-24 15:55:08 +02:00
parent 89172177eb
commit 7350d5222c
2 changed files with 74 additions and 36 deletions

View File

@@ -42,7 +42,7 @@ pub type ActionResult<R> = Result<R, diesel::result::Error>;
/// x .sell_loot([players], [excluded_item_ids]) -> Success status (bool, player_share) /// x .sell_loot([players], [excluded_item_ids]) -> Success status (bool, player_share)
/// // Claims should be resolved after a certain delay /// // Claims should be resolved after a certain delay
/// x .set_claims_timeout() /// x .set_claims_timeout()
/// x .resolve_claims() /// v .resolve_claims()
/// v .add_player(player_data) /// v .add_player(player_data)
/// ``` /// ```
/// ///
@@ -126,7 +126,7 @@ impl<'q> AsPlayer<'q> {
/// # Panics /// # Panics
/// ///
/// This currently panics if player wealth fails to be updated, as this is /// This currently panics if player wealth fails to be updated, as this is
/// a serious error. TODO: handle deletion of bought item in case of wealth update failure. /// a serious error.
pub fn buy<'a>(self, name: &'a str, price: i32) -> ActionResult<(i32, i32, i32, i32)> { pub fn buy<'a>(self, name: &'a str, price: i32) -> ActionResult<(i32, i32, i32, i32)> {
self.conn.transaction(|| { self.conn.transaction(|| {
let new_item = models::item::NewLoot::to_player(self.id, (name, price)); let new_item = models::item::NewLoot::to_player(self.id, (name, price));
@@ -146,31 +146,25 @@ impl<'q> AsPlayer<'q> {
/// # Panics /// # Panics
/// ///
/// This currently panics if player wealth fails to be updated, as this is /// This currently panics if player wealth fails to be updated, as this is
/// a serious error. TODO: handle restoring of sold item in case of wealth update failure. /// a serious error.
pub fn sell( pub fn sell(
self, self,
loot_id: i32, loot_id: i32,
_price_mod: Option<f32>, _price_mod: Option<f32>,
) -> ActionResult<(i32, i32, i32, i32)> { ) -> ActionResult<(i32, i32, i32, i32)> {
// Check that the item belongs to player
let exists_and_owned: bool =
diesel::select(models::Loot::owns(self.id, loot_id)).get_result(self.conn)?;
if !exists_and_owned {
return Err(diesel::result::Error::NotFound);
}
self.conn.transaction(|| { self.conn.transaction(|| {
use schema::looted::dsl::*; use schema::looted::dsl::*;
let loot_value = looted let loot = looted
.find(loot_id) .find(loot_id)
.select(base_price) .first::<models::Loot>(self.conn)?;
.first::<i32>(self.conn)?; if loot.owner != self.id {
let sell_value = (loot_value / 2) as f32; // If the item does not belong to player,
// it can't be what we're looking for
return Err(diesel::result::Error::NotFound);
}
let sell_value = (loot.base_price / 2) as f32;
let _deleted = diesel::delete(looted.find(loot_id)) let _deleted = diesel::delete(looted.find(loot_id))
.execute(self.conn) .execute(self.conn)?;
.map(|rows_updated| match rows_updated {
1 => (),
_ => panic!("RuntimeError: Sell did not update DB as expected"),
})?;
self.update_wealth(sell_value) self.update_wealth(sell_value)
}) })
@@ -271,10 +265,32 @@ impl<'q> AsAdmin<'q> {
.grouped_by(&loot); .grouped_by(&loot);
// For each claimed item // For each claimed item
let data = loot.into_iter().zip(claims).collect::<Vec<_>>(); let data = loot.into_iter().zip(claims).collect::<Vec<_>>();
dbg!(data); dbg!(&data);
// If mutiples claims -> find highest resolve, give to this player
// If only one claim -> give to claiming for (loot, claims) in data {
Err(diesel::result::Error::NotFound) match claims.len() {
1 => {
let claim = claims.get(0).unwrap();
let player_id = claim.player_id;
self.0.transaction(|| {
use schema::looted::dsl::*;
diesel::update(looted.find(claim.loot_id))
.set(owner_id.eq(player_id))
.execute(self.0)?;
diesel::delete(schema::claims::table.find(claim.id))
.execute(self.0)?;
{
use schema::players::dsl::*;
diesel::update(players.find(player_id))
.set(debt.eq(debt + (loot.base_price / 2)))
.execute(self.0)
}
})?;
},
_ => (),
}
}
Ok(())
} }
} }
@@ -304,7 +320,7 @@ mod tests {
/// When migrations are run, a special player with id 0 and name "Groupe" /// When migrations are run, a special player with id 0 and name "Groupe"
/// must be created. /// must be created.
#[test] #[test]
fn test_group_is_autocreated() { fn global_group_is_autocreated() {
let conn = test_connection(); let conn = test_connection();
let players = DbApi::with_conn(&conn).fetch_players().unwrap(); let players = DbApi::with_conn(&conn).fetch_players().unwrap();
assert_eq!(players.len(), 1); assert_eq!(players.len(), 1);
@@ -316,7 +332,7 @@ mod tests {
/// When a player updates wealth, a difference is returned by API. /// When a player updates wealth, a difference is returned by API.
/// Added to the previous amount of coins, it should equal the updated weath. /// Added to the previous amount of coins, it should equal the updated weath.
#[test] #[test]
fn test_player_updates_wealth() { fn as_player_updates_wealth() {
let conn = test_connection(); let conn = test_connection();
DbApi::with_conn(&conn) DbApi::with_conn(&conn)
.as_admin() .as_admin()
@@ -339,7 +355,7 @@ mod tests {
} }
#[test] #[test]
fn test_admin_add_player() { fn as_admin_add_player() {
let conn = test_connection(); let conn = test_connection();
let result = DbApi::with_conn(&conn) let result = DbApi::with_conn(&conn)
.as_admin() .as_admin()
@@ -356,15 +372,35 @@ mod tests {
} }
#[test] #[test]
fn test_admin_resolve_claims() { fn as_admin_resolve_claims() {
let conn = test_connection(); let conn = test_connection();
let claims = DbApi::with_conn(&conn).fetch_claims().unwrap(); let claims = DbApi::with_conn(&conn).fetch_claims().unwrap();
assert_eq!(claims.len(), 0); assert_eq!(claims.len(), 0);
assert_eq!(true, false); // Failing as test is not complete
// Add items
assert_eq!(DbApi::with_conn(&conn).as_admin().add_loot(vec![
("Épée", 40),
("Arc", 40),
]).is_ok(), true);
// Add players
DbApi::with_conn(&conn).as_admin().add_player("Player1".to_string(), 0.0).unwrap();
DbApi::with_conn(&conn).as_admin().add_player("Player2".to_string(), 0.0).unwrap();
// Put claims on one different item each
DbApi::with_conn(&conn).as_player(1).claim(1).unwrap();
DbApi::with_conn(&conn).as_player(2).claim(2).unwrap();
let result = DbApi::with_conn(&conn).as_admin().resolve_claims();
assert_eq!(result.is_ok(), true);
// Check that both players received an item
let players = DbApi::with_conn(&conn).fetch_players().unwrap();
for &i in [1, 2].into_iter() {
assert_eq!(DbApi::with_conn(&conn).as_player(i).loot().unwrap().len(), 1);
let player = players.get(i as usize).unwrap();
assert_eq!(player.debt, 20);
}
} }
#[test] #[test]
fn test_player_claim_item() { fn as_player_claim_item() {
let conn = test_connection(); let conn = test_connection();
DbApi::with_conn(&conn) DbApi::with_conn(&conn)
.as_admin() .as_admin()
@@ -388,7 +424,7 @@ mod tests {
} }
#[test] #[test]
fn test_player_unclaim_item() { fn as_player_unclaim_item() {
let conn = test_connection(); let conn = test_connection();
DbApi::with_conn(&conn) DbApi::with_conn(&conn)
.as_admin() .as_admin()
@@ -418,8 +454,9 @@ mod tests {
/// ///
/// Checks that player's chest and wealth are updated. /// Checks that player's chest and wealth are updated.
/// Checks that items are sold at half their value. /// Checks that items are sold at half their value.
/// Checks that a player cannot sell item he does not own.
#[test] #[test]
fn test_buy_sell_simple() { fn as_player_simple_buy_sell() {
let conn = test_connection(); let conn = test_connection();
DbApi::with_conn(&conn) DbApi::with_conn(&conn)
.as_admin() .as_admin()
@@ -438,10 +475,11 @@ mod tests {
let players = DbApi::with_conn(&conn).fetch_players().unwrap(); let players = DbApi::with_conn(&conn).fetch_players().unwrap();
let player = players.get(1).unwrap(); let player = players.get(1).unwrap();
assert_eq!(player.pp, 2); assert_eq!(player.pp, 2);
// A player cannot sell loot from an other's chest
let result = DbApi::with_conn(&conn).as_player(0).sell(loot.id, None);
assert_eq!(result.is_ok(), false);
// Sell back // Sell back
let sold = DbApi::with_conn(&conn) let sold = DbApi::with_conn(&conn).as_player(1).sell(loot.id, None);
.as_player(1)
.sell(loot.id, None);
assert_eq!(sold.ok(), Some((0, 0, 0, 4))); assert_eq!(sold.ok(), Some((0, 0, 0, 4)));
let chest = DbApi::with_conn(&conn).as_player(1).loot().unwrap(); let chest = DbApi::with_conn(&conn).as_player(1).loot().unwrap();
assert_eq!(chest.len(), 0); assert_eq!(chest.len(), 0);
@@ -451,7 +489,7 @@ mod tests {
} }
#[test] #[test]
fn test_admin_add_loot() { fn as_admin_add_loot() {
let conn = test_connection(); let conn = test_connection();
assert_eq!( assert_eq!(
0, 0,

View File

@@ -35,8 +35,8 @@ type OwnedLoot = Filter<looted::table, WithOwner>;
pub(crate) struct Loot { pub(crate) struct Loot {
id: i32, id: i32,
name: String, name: String,
base_price: i32, pub(crate) base_price: i32,
owner: i32, pub(crate) owner: i32,
} }
impl Loot { impl Loot {