Score tests, and get_datetime test-util
This commit is contained in:
parent
e353977da9
commit
91229287a8
3 changed files with 246 additions and 19 deletions
|
|
@ -93,9 +93,9 @@ mod tests {
|
|||
use super::*;
|
||||
use crate::test_utils::{
|
||||
ITEM_TITLE, ITEM_GUID, ITEM_GUID2, ITEM_DESC, ITEM_CONT,
|
||||
CHANNEL_TITLE, CHANNEL_DESC, FEED1
|
||||
CHANNEL_TITLE, CHANNEL_DESC, FEED1,
|
||||
get_datetime
|
||||
};
|
||||
use chrono::TimeZone;
|
||||
|
||||
fn create_guid(value: String) -> rss::Guid {
|
||||
rss::Guid { value, permalink: false }
|
||||
|
|
@ -140,7 +140,7 @@ mod tests {
|
|||
|
||||
let rss_channel = create_channel([rss_item, rss_item2].to_vec());
|
||||
|
||||
let date: DateTime<Utc> = Utc.with_ymd_and_hms(2020,1,1,0,0,0).unwrap();
|
||||
let date: DateTime<Utc> = get_datetime();
|
||||
|
||||
let channel = FetchedRSSChannel::parse(rss_channel, date).unwrap();
|
||||
|
||||
|
|
|
|||
|
|
@ -54,9 +54,19 @@ pub enum Score {
|
|||
|
||||
impl Score {
|
||||
pub fn new() -> DecayingScore {
|
||||
Self::new_with_initial(default::INITIAL_SCORE)
|
||||
}
|
||||
|
||||
pub fn new_with_initial(initial_score: i64) -> DecayingScore {
|
||||
Self::new_with_initial_and_time(initial_score, Utc::now())
|
||||
}
|
||||
|
||||
pub fn new_with_initial_and_time(
|
||||
initial: i64, time: DateTime<Utc>
|
||||
) -> DecayingScore {
|
||||
DecayingScore {
|
||||
value: default::INITIAL_SCORE,
|
||||
last_updated: Utc::now(),
|
||||
value: initial,
|
||||
last_updated: time,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -68,12 +78,20 @@ impl Score {
|
|||
}
|
||||
|
||||
pub fn update_score(self, gravity: Gravity) -> Self {
|
||||
self.update_score_at_time(gravity, Utc::now())
|
||||
}
|
||||
|
||||
fn update_score_at_time(self, gravity: Gravity, time: DateTime<Utc>) -> Self {
|
||||
match self {
|
||||
Self::Decaying(d) => Score::Decaying(d.update_score(gravity)),
|
||||
Self::Decaying(d) => Score::Decaying(
|
||||
d.apply_gravity_to_time(gravity, time)
|
||||
),
|
||||
Self::Boosted(b) => {
|
||||
let try_unfrozen = b.try_unfreeze();
|
||||
let try_unfrozen = b.try_unfreeze_at_time(time);
|
||||
match try_unfrozen {
|
||||
Self::Decaying(s) => Score::Decaying(s.update_score(gravity)),
|
||||
Self::Decaying(s) => Score::Decaying(
|
||||
s.apply_gravity_to_time(gravity, time)
|
||||
),
|
||||
Self::Boosted(b) => Score::Boosted(b),
|
||||
}
|
||||
}
|
||||
|
|
@ -110,16 +128,12 @@ impl DecayingScore {
|
|||
self.value
|
||||
}
|
||||
|
||||
fn update_score(self, gravity: Gravity) -> Self {
|
||||
self.update_score_at_time(gravity, Utc::now())
|
||||
}
|
||||
|
||||
fn update_score_at_time(
|
||||
fn apply_gravity_to_time(
|
||||
self, gravity: Gravity, update_time: DateTime<Utc>
|
||||
) -> Self {
|
||||
let elapsed_time: TimeDelta = update_time.signed_duration_since(self.last_updated);
|
||||
let new_value = if elapsed_time <= TimeDelta::zero() { self.value } else {
|
||||
i64::from(gravity) * (elapsed_time.num_seconds() / SECONDS_IN_A_DAY)
|
||||
self.value + i64::from(gravity) * (elapsed_time.num_seconds() / SECONDS_IN_A_DAY)
|
||||
};
|
||||
Self {
|
||||
last_updated: update_time,
|
||||
|
|
@ -151,13 +165,9 @@ impl BoostedScore {
|
|||
}
|
||||
}
|
||||
|
||||
fn try_unfreeze(self) -> Score {
|
||||
self.try_unfreeze_at_time(Utc::now())
|
||||
}
|
||||
|
||||
fn try_unfreeze_at_time(self, update_time: DateTime<Utc>) -> Score {
|
||||
let boost_end = self.boosted_at + TimeDelta::seconds(default::BOOST_FREEZE_IN_SECONDS);
|
||||
if boost_end > update_time {
|
||||
if boost_end < update_time {
|
||||
Score::Decaying(DecayingScore {
|
||||
value: self.value,
|
||||
last_updated: boost_end,
|
||||
|
|
@ -167,3 +177,210 @@ impl BoostedScore {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::test_utils::get_datetime;
|
||||
|
||||
#[test]
|
||||
fn gravity_default() {
|
||||
let gravity = Gravity::new(None);
|
||||
assert_eq!(i64::from(gravity), default::GRAVITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn boost_default() {
|
||||
let boost = Boost::new(None);
|
||||
assert_eq!(i64::from(boost), default::BOOST);
|
||||
}
|
||||
|
||||
// "Score" Tests
|
||||
|
||||
#[test]
|
||||
fn parse_decaying() {
|
||||
let ups = UnparsedScore {
|
||||
value: 10,
|
||||
last_updated: get_datetime(),
|
||||
last_boosted: None,
|
||||
};
|
||||
|
||||
ups.parse().get_decaying().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_boosted() {
|
||||
let dt = get_datetime();
|
||||
let ups = UnparsedScore {
|
||||
value: 10,
|
||||
last_updated: dt,
|
||||
last_boosted: Some(dt),
|
||||
};
|
||||
|
||||
ups.parse().get_boosted().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new() {
|
||||
let score = Score::new();
|
||||
assert_eq!(score.value, default::INITIAL_SCORE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_with_values() {
|
||||
let dt = get_datetime();
|
||||
let score = Score::new_with_initial_and_time(10, dt);
|
||||
assert_eq!(score.value, 10);
|
||||
assert_eq!(score.last_updated, dt);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_score_stays_decaying() {
|
||||
let dt = get_datetime();
|
||||
let score = Score::Decaying(Score::new_with_initial_and_time(10, dt));
|
||||
let gravity = Gravity::new(None);
|
||||
|
||||
let dt2 = dt + TimeDelta::seconds(SECONDS_IN_A_DAY);
|
||||
|
||||
score.update_score_at_time(gravity, dt2).get_decaying().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_score_stays_frozen() {
|
||||
let dt = get_datetime();
|
||||
let score = Score::Boosted(BoostedScore { value: 10, boosted_at: dt });
|
||||
let gravity = Gravity::new(None);
|
||||
|
||||
let dt2 = dt + TimeDelta::seconds(default::BOOST_FREEZE_IN_SECONDS);
|
||||
|
||||
score.update_score_at_time(gravity, dt2).get_boosted().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update_score_thaws_and_decays() {
|
||||
let dt = get_datetime();
|
||||
let score = Score::Boosted(BoostedScore { value: 10, boosted_at: dt });
|
||||
let gravity = Gravity::new(None);
|
||||
|
||||
let dt2 = dt + TimeDelta::seconds(
|
||||
default::BOOST_FREEZE_IN_SECONDS + SECONDS_IN_A_DAY
|
||||
);
|
||||
|
||||
let updated = score.update_score_at_time(gravity, dt2)
|
||||
.get_decaying().unwrap();
|
||||
assert!(updated.value < 10)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_decaying_success() {
|
||||
let dt = get_datetime();
|
||||
let score = Score::Decaying(Score::new_with_initial_and_time(10, dt));
|
||||
|
||||
score.get_decaying().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic = "Attempted to get_boosted() of a decaying score"]
|
||||
fn get_boosted_failure() {
|
||||
let dt = get_datetime();
|
||||
let score = Score::Decaying(Score::new_with_initial_and_time(10, dt));
|
||||
|
||||
score.get_boosted().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic = "Attempted to get_decaying() of a boosted score"]
|
||||
fn get_decaying_failure() {
|
||||
let dt = get_datetime();
|
||||
let boost = Boost::new(None);
|
||||
let score = Score::Boosted(
|
||||
Score::new_with_initial_and_time(10, dt).boost_at_time(boost, dt)
|
||||
);
|
||||
|
||||
score.get_decaying().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_boosted_success() {
|
||||
let dt = get_datetime();
|
||||
let boost = Boost::new(None);
|
||||
let score = Score::Boosted(
|
||||
Score::new_with_initial_and_time(10, dt).boost_at_time(boost, dt)
|
||||
);
|
||||
|
||||
score.get_boosted().unwrap();
|
||||
}
|
||||
|
||||
// "DecayingScore" Tests
|
||||
|
||||
#[test]
|
||||
fn apply_gravity_to_future() {
|
||||
let dt = get_datetime();
|
||||
let score = DecayingScore { value: 10, last_updated: dt };
|
||||
let future = dt + TimeDelta::seconds(SECONDS_IN_A_DAY);
|
||||
let gravity = Gravity::new(None);
|
||||
|
||||
let updated = score.apply_gravity_to_time(gravity, future);
|
||||
|
||||
assert_eq!(updated.value, 10 + default::GRAVITY);
|
||||
assert_eq!(updated.last_updated, future);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_gravity_to_past() {
|
||||
let dt = get_datetime();
|
||||
let score = DecayingScore { value: 10, last_updated: dt };
|
||||
let past = dt - TimeDelta::seconds(SECONDS_IN_A_DAY);
|
||||
let gravity = Gravity::new(None);
|
||||
|
||||
let updated = score.apply_gravity_to_time(gravity, past);
|
||||
|
||||
assert_eq!(updated.value, 10);
|
||||
assert_eq!(updated.last_updated, past);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn boost() {
|
||||
let dt = get_datetime();
|
||||
let score = DecayingScore { value: 10, last_updated: dt };
|
||||
let boost = Boost::new(None);
|
||||
|
||||
let boosted = score.boost_at_time(boost, dt);
|
||||
assert_eq!(boosted.value, 10 + default::BOOST);
|
||||
assert_eq!(boosted.boosted_at, dt);
|
||||
}
|
||||
|
||||
// "BoostedScore" tests
|
||||
|
||||
#[test]
|
||||
fn unboost() {
|
||||
let dt = get_datetime();
|
||||
let score = DecayingScore { value: 10, last_updated: dt };
|
||||
let boost = Boost::new(None);
|
||||
let boosted = score.boost_at_time(boost, dt);
|
||||
|
||||
let unboosted = boosted.unboost(boost);
|
||||
assert_eq!(unboosted.value, 10);
|
||||
assert_eq!(unboosted.last_updated, dt);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn boosted_stays_frozen() {
|
||||
let dt = get_datetime();
|
||||
let score = BoostedScore { value: 10, boosted_at: dt };
|
||||
|
||||
let last_second = dt + TimeDelta::seconds(default::BOOST_FREEZE_IN_SECONDS);
|
||||
|
||||
score.try_unfreeze_at_time(last_second).get_boosted().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn boosted_thaws() {
|
||||
let dt = get_datetime();
|
||||
let score = BoostedScore { value: 10, boosted_at: dt };
|
||||
|
||||
let first_second = dt + TimeDelta::days(default::BOOST_FREEZE_IN_SECONDS+1);
|
||||
|
||||
score.try_unfreeze_at_time(first_second).get_decaying().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ use crate::{
|
|||
}
|
||||
};
|
||||
use reqwest::Url;
|
||||
use chrono::{
|
||||
Utc,
|
||||
TimeZone,
|
||||
DateTime
|
||||
};
|
||||
|
||||
pub const FEED1: &str = "https://example.com/feed";
|
||||
pub const FEED2: &str = "https://example2.com/feed";
|
||||
|
|
@ -26,6 +31,11 @@ pub const ITEM_TITLE: &str = "My Item!";
|
|||
pub const ITEM_DESC: &str = "My Item's description";
|
||||
pub const ITEM_CONT: &str = "The content of my Item";
|
||||
|
||||
|
||||
pub fn get_datetime() -> DateTime<Utc> {
|
||||
Utc.with_ymd_and_hms(2020,1,1,0,0,0).unwrap()
|
||||
}
|
||||
|
||||
pub async fn setup_adapter() -> Adapter {
|
||||
AdapterBuilder::new()
|
||||
.database_url("sqlite::memory:")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue