diff --git a/src/modes/pair.rs b/src/modes/pair.rs index 565c913..9bda445 100644 --- a/src/modes/pair.rs +++ b/src/modes/pair.rs @@ -101,68 +101,105 @@ mod tests { use super::*; use crate::{ card::{make_decks, Rank}, - modes::tests::test_non_reflexivity, + modes::tests::test_footstool_non_reflexivity, }; #[test] fn new() { - // Two jokers can never be a pair. + /* + There are 3 cases for generating a pair: + 1) Not a pair + 2) An improper pair made up of one joker + 3) A proper pair made up of two playing cards. + */ + + // TEST: Two jokers can never be a pair. assert_eq!(Pair::new(Card::make_joker(), Card::make_joker()), None); - // Iterate over all ranks - for r1 in Rank::iter_all() { - // Iterate over all cards in a rank - for c1 in r1.cards() { - // Iterate over all ranks that aren't r1 - for r2 in Rank::iter_all().filter(|&r2| r2 != r1) { - // TEST: Cannot compose a pair made from two different - // ranked cards. - let all_cards = r2.cards(); - let all_pairs = - all_cards.filter_map(|c2| Pair::new(c1, c2)); - - assert_eq!(all_pairs.count(), 0); - } - - // Iterate over all cards that are of the same rank as r1. - for c2 in r1.cards() { - // TEST: Pairs are composed of two similar rank cards. - let pair = { - let pair = Pair::new(c1, c2); - assert_ne!(pair, None); - pair.unwrap() - }; - - // Test: Pairs of two playing cards are proper - assert!(pair.is_proper()); - - // TEST: Pairs always sort their cards in strength. - let (b1, b2) = ordered(c1, c2); - assert_eq!(pair.0, b1); - assert_eq!(pair.1, b2); - } - - // TEST: Pairs may have one joker. - let pair = { - let p = Pair::new(c1, Card::make_joker()); - assert_ne!(p, None); - p.unwrap() - }; + // TEST: Non pair tests. + Rank::iter_all() + // Generate a mapping (r1, r2) where r1, r2 are ranks and r1 != r2 + .flat_map(|r1| { + Rank::iter_all() + .filter(move |&r2| r2 != r1) + .map(move |r2| (r1, r2)) + }) + // Flat Map for combinations of (cards of rank r1, cards of rank r2) + .flat_map(|(r1, r2)| { + r1.cards() + .flat_map(move |c1| r2.cards().map(move |c2| (c1, c2))) + }) + .for_each(|(c1, c2)| { + // TEST: Two cards of differing rank cannot be a pair + let pair = Pair::new(c1, c2); + assert!( + pair.is_none(), + "Expected cards {c1} and {c2} to never form a pair." + ) + }); + // TEST: Improper pair tests. + PlayingCard::iter_deck(1) + .map(Card::PlayingCard) + .map(|c1| { + // TEST: Any card with one joker can be made into a valid pair. + let c2 = Card::make_joker(); + let pair = Pair::new(c1, c2); + assert!( + pair.is_some(), + "Expected ({c1}, {c2}) to be a valid pair", + ); + pair.unwrap() + }) + .for_each(|pair| { // TEST: Pairs with a joker are improper. - assert!(pair.is_improper()); + assert!(pair.is_improper(), "Expected {pair} to be improper"); // TEST: Improper pairs have a Joker in Pair::0. - assert!(matches!(pair.0, Card::Joker(_))); - assert!(matches!(pair.1, Card::PlayingCard(_))); - } - } + assert!( + matches!(pair.0, Card::Joker(_)), + "Expected {} to be a joker", + pair.0 + ); + + // TEST: Improper pairs have a playing card in Pair::1. + assert!( + matches!(pair.1, Card::PlayingCard(_)), + "Expected {} to be a playing card", + pair.1 + ); + }); + + // TEST: Proper pair tests + PlayingCard::iter_deck(1) + .map(Card::PlayingCard) + // Flat Map every card (c1) into combinations (c1, card of same rank as c1) + .flat_map(|c1| c1.rank().unwrap().cards().map(move |c2| (c1, c2))) + // Map every (c1, c2) into a pair + .map(|(c1, c2)| { + // TEST: Two cards of similar rank make a valid pair. + let pair = { + let pair = Pair::new(c1, c2); + assert!( + pair.is_some(), + "Expected {c1} and {c2} to form a valid pair." + ); + pair.unwrap() + }; + // TEST: Pairs of two playing cards are proper + assert!(pair.is_proper(), "Expected {pair} to be proper."); + (c1, c2, pair) + }) + .for_each(|(c1, c2, pair)| { + // TEST: Pairs always sort their cards in strength. + let (b1, b2) = ordered(c1, c2); + assert_eq!(pair.0, b1, "Expected {} to be {b1}", pair.0); + assert_eq!(pair.1, b2, "Expected {} to be {b2}", pair.1); + }); } + /** Create an exhaustive set of pairs for one deck. */ fn exhaustive_pairs_deck() -> impl Iterator { - // A rank has 4 cards. There are a total of 10 proper pairs that can be - // made out of 4 cards. With n jokers, add 4n improper pairs to the - // total count of pairs for a single rank. make_decks(1).flat_map(|c1| { make_decks(1).filter_map(move |c2| Pair::new(c1, c2)) }) @@ -171,10 +208,7 @@ mod tests { #[test] fn ordering() { fn expected_ordering_relation(p1: &Pair, p2: &Pair) -> bool { - let pair_ordering = p1.cmp(p2); - let high_card_ordering = p1.1.cmp(&p2.1); - - match (pair_ordering, high_card_ordering) { + match (p1.cmp(p2), p1.1.cmp(&p2.1)) { // For any two pairs, we expect the high cards to dictate the // ordering of the pairs - the lower card should be irrelevant. (x, y) if x == y => true, @@ -184,44 +218,43 @@ mod tests { // exclusively one of the pairs is improper - pairs that are // improper should be sorted less than the proper one. (Ordering::Less, Ordering::Equal) => { - // p1 has a joker, p2 doesn't => p1 < p2 + // p1 is improper, p2 is proper => p1 < p2 p1.is_improper() && p2.is_proper() } (Ordering::Greater, Ordering::Equal) => { - // p2 has a joker, p1 doesn't => p1 > p2 + // p2 is improper, p1 is proper => p1 > p2 p2.is_improper() && p1.is_proper() } _ => false, } } - for p1 in exhaustive_pairs_deck() { - for p2 in exhaustive_pairs_deck() { - // TEST: For any two pair we expect them to have the + exhaustive_pairs_deck() + // Create a flat map of all combinations of two valid pairs. + .flat_map(|p1| exhaustive_pairs_deck().map(move |p2| (p1, p2))) + .for_each(|(p1, p2)| { + // TEST: For any two valid pairs we expect them to have the // `expected_ordering_relation`. assert!(expected_ordering_relation(&p1, &p2)); - } - } + }) } #[test] fn footstool() { - for p1 in exhaustive_pairs_deck() { - for p2 in exhaustive_pairs_deck() { - let (p1_on_p2, p2_on_p1) = test_non_reflexivity(&p1, &p2); + exhaustive_pairs_deck() + .flat_map(|p1| exhaustive_pairs_deck().map(move |p2| (p1, p2))) + .for_each(|(p1, p2)| { + let (p1_on_p2, p2_on_p1) = + test_footstool_non_reflexivity(&p1, &p2); let (hc1_on_hc2, hc2_on_hc1) = { - let [high_card_1, high_card_2] = - [p1.1, p2.1].map(Single::new).map(|x| { - assert!(x.is_some()); - x.unwrap() - }); - test_non_reflexivity(&high_card_1, &high_card_2) + let high_card_1 = Single::new(p1.1).unwrap(); + let high_card_2 = Single::new(p2.1).unwrap(); + test_footstool_non_reflexivity(&high_card_1, &high_card_2) }; // TEST: We expect pair footstools to mirror footstool rules of // Singles on the high card. assert!(p1_on_p2 == hc1_on_hc2 && p2_on_p1 == hc2_on_hc1); - } - } + }); } }