//! The traits a consumer needs on the public types, pinned so they cannot be //! removed by accident. //! //! This is written from a consumer's position — deriving `Debug` on a struct //! that *holds* a `History` — because that is the thing that failed. Asserting //! `History: Debug` in isolation would not have caught the generic-bound half: //! `Rating` derives `PartialEq`, but that is only usable if `D: PartialEq`, and //! the crate's own only `Drift` impl did not satisfy it. use trueskill_tt::{ ConstantDrift, ConvergenceOptions, ConvergenceReport, Event, GameOptions, Gaussian, History, HistoryBuilder, InferenceError, Member, Outcome, Rating, Team, }; /// The reported failure, verbatim: a consumer holding a history in app state. #[derive(Debug)] #[allow( dead_code, reason = "held only so `derive(Debug)` has something to render" )] struct App { history: History, } #[test] fn a_struct_holding_a_history_can_derive_debug() { let app = App { history: History::default(), }; let rendered = format!("{app:?}"); // Summarising, not a dump of every skill store — the same choice `Joint`'s // manual `Debug` makes about its n² factorisation. assert!(rendered.contains("competitors"), "{rendered}"); assert!(rendered.contains("time_slices"), "{rendered}"); assert!( !rendered.contains("SkillStore"), "History's Debug should summarise, not dump: {rendered}" ); } #[test] fn history_builder_is_debug_and_clone() { let b: HistoryBuilder = History::builder(); let cloned = b.clone(); assert!(!format!("{cloned:?}").is_empty()); } #[test] fn config_and_input_value_types_are_comparable() { assert_eq!(ConstantDrift::new(0.1), ConstantDrift::new(0.1)); assert_ne!(ConstantDrift::new(0.1), ConstantDrift::new(0.2)); assert_eq!(ConvergenceOptions::default(), ConvergenceOptions::default()); assert_eq!(GameOptions::default(), GameOptions::default()); // `Rating: PartialEq` is only reachable through `D: PartialEq`. assert_eq!(Rating::::default(), Rating::default()); assert_ne!( Rating::default(), Rating::::default().with_drift_scale(2.0) ); assert_eq!(Member::new("a"), Member::new("a")); assert_ne!(Member::new("a"), Member::new("b")); assert_eq!( Team::with_members([Member::new("a")]), Team::with_members([Member::new("a")]) ); let event = || Event { time: 1, teams: [ Team::with_members([Member::new("a")]), Team::with_members([Member::new("b")]), ] .into_iter() .collect(), outcome: Outcome::winner(0, 2), }; assert_eq!(event(), event()); assert_eq!(Gaussian::default(), Gaussian::default()); } #[test] fn a_history_is_send_and_sync_and_default() { fn assert_send_sync() {} assert_send_sync::(); assert_send_sync::(); let mut h = History::default(); let report: ConvergenceReport = h.converge().expect("an empty history converges"); assert_eq!(report, report.clone()); }