test(sync): add unit tests for StatsSnapshot::win_rate and AchievementRecord::unlock
Both public APIs in solitaire_sync had no test coverage: - win_rate(): None before any game, 100/50/0% cases - AchievementRecord::locked(), unlock(), idempotency preserving earliest date Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -46,3 +46,36 @@ impl AchievementRecord {
|
||||
self.unlock_date = Some(at);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn locked_creates_an_unlocked_record() {
|
||||
let r = AchievementRecord::locked("first_win");
|
||||
assert_eq!(r.id, "first_win");
|
||||
assert!(!r.unlocked);
|
||||
assert!(r.unlock_date.is_none());
|
||||
assert!(!r.reward_granted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unlock_sets_unlocked_and_stores_timestamp() {
|
||||
let mut r = AchievementRecord::locked("first_win");
|
||||
let ts = Utc::now();
|
||||
r.unlock(ts);
|
||||
assert!(r.unlocked);
|
||||
assert_eq!(r.unlock_date, Some(ts));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unlock_is_idempotent_and_preserves_earliest_date() {
|
||||
let mut r = AchievementRecord::locked("first_win");
|
||||
let early = DateTime::UNIX_EPOCH;
|
||||
let later = Utc::now();
|
||||
r.unlock(early);
|
||||
r.unlock(later); // should be a no-op
|
||||
assert_eq!(r.unlock_date, Some(early), "earliest unlock date must be preserved");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,3 +74,53 @@ impl StatsSnapshot {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn win_rate_is_none_before_any_game() {
|
||||
let s = StatsSnapshot::default();
|
||||
assert!(s.win_rate().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn win_rate_100_when_all_games_won() {
|
||||
let s = StatsSnapshot {
|
||||
games_played: 5,
|
||||
games_won: 5,
|
||||
..StatsSnapshot::default()
|
||||
};
|
||||
let rate = s.win_rate().expect("should have a rate");
|
||||
assert!((rate - 100.0).abs() < 0.01, "expected 100.0, got {rate}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn win_rate_50_when_half_won() {
|
||||
let s = StatsSnapshot {
|
||||
games_played: 10,
|
||||
games_won: 5,
|
||||
..StatsSnapshot::default()
|
||||
};
|
||||
let rate = s.win_rate().expect("should have a rate");
|
||||
assert!((rate - 50.0).abs() < 0.01, "expected 50.0, got {rate}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn win_rate_0_when_no_wins() {
|
||||
let s = StatsSnapshot {
|
||||
games_played: 3,
|
||||
games_won: 0,
|
||||
..StatsSnapshot::default()
|
||||
};
|
||||
let rate = s.win_rate().expect("should have a rate");
|
||||
assert!((rate - 0.0).abs() < 0.01, "expected 0.0, got {rate}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fastest_win_seconds_defaults_to_max() {
|
||||
let s = StatsSnapshot::default();
|
||||
assert_eq!(s.fastest_win_seconds, u64::MAX);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user