use std::fs::File; use std::io::Read; use std::io::{BufRead, BufReader}; use std::collections::HashMap; use serde_json::Error; use lordeckcodes::encoder::deck_from_code; use lordeckcodes::{encoder, CardCodeAndCount, Deck, LorError}; #[test] fn basic_decode_test() { let deck = encoder::deck_from_code(String::from( "CIBAEAIBAQTQMAIAAILSQLBNGUBACAIBFYDACAAHBEHR2IBLAEBACAIFAY", )); assert!(deck.is_ok()); } #[test] fn basic_encode_test() { let deck: Deck = [ ("01SI015", 3), ("01SI044", 3), ("01SI048", 3), ("01SI054", 3), ("01FR003", 3), ("01FR012", 3), ("01FR020", 3), ("01FR024", 3), ("01FR033", 3), ("01FR036", 3), ("01FR039", 3), ("01FR052", 3), ("01SI005", 2), ("01FR004", 2), ] .iter() .collect(); let code = encoder::code_from_deck(&deck); assert_eq!( code.unwrap(), "CEBAIAIFB4WDANQIAEAQGDAUDAQSIJZUAIAQCAIEAEAQKBIA" ); } #[test] fn encode_decode_recommended() -> Result<(), Box> { let f = File::open("tests/DeckCodesTestData.txt").unwrap(); let mut f = BufReader::new(f); let mut codes = vec![]; let mut decks = vec![]; loop { match f.by_ref().lines().next() { Some(code) => { codes.push(code?); } None => { break; } } let deck = f .by_ref() .lines() .map(|l| l.unwrap()) .take_while(|l| !l.is_empty()) .fold(Deck::new(), |mut deck, line| { let mut parts = line.rsplit(':'); deck.add_from_data( parts.next().unwrap(), parts.next().unwrap().parse().unwrap(), ) .unwrap(); deck }); decks.push(deck); } for (i, _deck) in decks.iter().enumerate() { assert_eq!(encoder::code_from_deck(&decks[i]).unwrap(), codes[i]); assert!(verify_rehydration( &encoder::deck_from_code(&codes[i]).unwrap(), &decks[i], )); } Ok(()) } #[test] fn small_deck() { let deck = Deck::from_vec(vec![CardCodeAndCount::from_data("01DE002", 1).unwrap()]); let code = encoder::code_from_deck(&deck); let decoded_deck = encoder::deck_from_code(code.unwrap()); assert_eq!(deck, decoded_deck.unwrap()); } #[test] fn large_deck() { let deck = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 3).unwrap(), CardCodeAndCount::from_data("01DE003", 3).unwrap(), CardCodeAndCount::from_data("01DE004", 3).unwrap(), CardCodeAndCount::from_data("01DE005", 3).unwrap(), CardCodeAndCount::from_data("01DE006", 3).unwrap(), CardCodeAndCount::from_data("01DE007", 3).unwrap(), CardCodeAndCount::from_data("01DE008", 3).unwrap(), CardCodeAndCount::from_data("01DE009", 3).unwrap(), CardCodeAndCount::from_data("01DE010", 3).unwrap(), CardCodeAndCount::from_data("01DE011", 3).unwrap(), CardCodeAndCount::from_data("01DE012", 3).unwrap(), CardCodeAndCount::from_data("01DE013", 3).unwrap(), CardCodeAndCount::from_data("01DE014", 3).unwrap(), CardCodeAndCount::from_data("01DE015", 3).unwrap(), CardCodeAndCount::from_data("01DE016", 3).unwrap(), CardCodeAndCount::from_data("01DE017", 3).unwrap(), CardCodeAndCount::from_data("01DE018", 3).unwrap(), CardCodeAndCount::from_data("01DE019", 3).unwrap(), CardCodeAndCount::from_data("01DE020", 3).unwrap(), CardCodeAndCount::from_data("01DE021", 3).unwrap(), ]); let code = encoder::code_from_deck(&deck); let decoded_deck = encoder::deck_from_code(code.unwrap()); assert!(verify_rehydration(&deck, &decoded_deck.unwrap())); } #[test] fn deck_with_counts_more_than_3_small() { let deck = Deck::from_vec(vec![CardCodeAndCount::from_data("01DE002", 4).unwrap()]); let code = encoder::code_from_deck(&deck); let decoded_deck = encoder::deck_from_code(code.unwrap()); assert!(verify_rehydration(&deck, &decoded_deck.unwrap())); } #[test] fn deck_with_more_than_3_large() { let deck = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 3).unwrap(), CardCodeAndCount::from_data("01DE003", 3).unwrap(), CardCodeAndCount::from_data("01DE004", 3).unwrap(), CardCodeAndCount::from_data("01DE005", 3).unwrap(), CardCodeAndCount::from_data("01DE006", 4).unwrap(), CardCodeAndCount::from_data("01DE007", 5).unwrap(), CardCodeAndCount::from_data("01DE008", 6).unwrap(), CardCodeAndCount::from_data("01DE009", 7).unwrap(), CardCodeAndCount::from_data("01DE010", 8).unwrap(), CardCodeAndCount::from_data("01DE011", 9).unwrap(), CardCodeAndCount::from_data("01DE012", 3).unwrap(), CardCodeAndCount::from_data("01DE013", 3).unwrap(), CardCodeAndCount::from_data("01DE014", 3).unwrap(), CardCodeAndCount::from_data("01DE015", 3).unwrap(), CardCodeAndCount::from_data("01DE016", 3).unwrap(), CardCodeAndCount::from_data("01DE017", 3).unwrap(), CardCodeAndCount::from_data("01DE018", 3).unwrap(), CardCodeAndCount::from_data("01DE019", 3).unwrap(), CardCodeAndCount::from_data("01DE020", 3).unwrap(), CardCodeAndCount::from_data("01DE021", 3).unwrap(), ]); let code = encoder::code_from_deck(&deck); let decoded_deck = encoder::deck_from_code(code.unwrap()); assert!(verify_rehydration(&deck, &decoded_deck.unwrap())); } #[test] fn single_card_40_times() { let deck = Deck::from_vec(vec![CardCodeAndCount::from_data("01DE002", 40).unwrap()]); let code = encoder::code_from_deck(&deck); let decoded_deck = encoder::deck_from_code(code.unwrap()); assert!(verify_rehydration(&deck, &decoded_deck.unwrap())); } #[test] fn worst_case_length() { let deck = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 4).unwrap(), CardCodeAndCount::from_data("01DE003", 4).unwrap(), CardCodeAndCount::from_data("01DE004", 4).unwrap(), CardCodeAndCount::from_data("01DE005", 4).unwrap(), CardCodeAndCount::from_data("01DE006", 4).unwrap(), CardCodeAndCount::from_data("01DE007", 5).unwrap(), CardCodeAndCount::from_data("01DE008", 6).unwrap(), CardCodeAndCount::from_data("01DE009", 7).unwrap(), CardCodeAndCount::from_data("01DE010", 8).unwrap(), CardCodeAndCount::from_data("01DE011", 9).unwrap(), CardCodeAndCount::from_data("01DE012", 4).unwrap(), CardCodeAndCount::from_data("01DE013", 4).unwrap(), CardCodeAndCount::from_data("01DE014", 4).unwrap(), CardCodeAndCount::from_data("01DE015", 4).unwrap(), CardCodeAndCount::from_data("01DE016", 4).unwrap(), CardCodeAndCount::from_data("01DE017", 4).unwrap(), CardCodeAndCount::from_data("01DE018", 4).unwrap(), CardCodeAndCount::from_data("01DE019", 4).unwrap(), CardCodeAndCount::from_data("01DE020", 4).unwrap(), CardCodeAndCount::from_data("01DE021", 4).unwrap(), ]); let code = encoder::code_from_deck(&deck); let decoded_deck = encoder::deck_from_code(code.unwrap()); assert!(verify_rehydration(&deck, &decoded_deck.unwrap())); } #[test] fn order_should_not_matter_1() { let deck1 = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 1).unwrap(), CardCodeAndCount::from_data("01DE003", 2).unwrap(), CardCodeAndCount::from_data("02DE003", 3).unwrap(), ]); let deck2 = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE003", 2).unwrap(), CardCodeAndCount::from_data("02DE003", 3).unwrap(), CardCodeAndCount::from_data("01DE002", 1).unwrap(), ]); assert_eq!( encoder::code_from_deck(&deck1).unwrap(), encoder::code_from_deck(&deck2).unwrap() ); let deck3 = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 4).unwrap(), CardCodeAndCount::from_data("01DE003", 2).unwrap(), CardCodeAndCount::from_data("02DE003", 3).unwrap(), ]); let deck4 = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE003", 2).unwrap(), CardCodeAndCount::from_data("02DE003", 3).unwrap(), CardCodeAndCount::from_data("01DE002", 4).unwrap(), ]); assert_eq!( encoder::code_from_deck(&deck3).unwrap(), encoder::code_from_deck(&deck4).unwrap() ); } #[test] fn order_should_not_matter_2() { let deck1 = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 4).unwrap(), CardCodeAndCount::from_data("01DE003", 2).unwrap(), CardCodeAndCount::from_data("02DE003", 3).unwrap(), CardCodeAndCount::from_data("01DE004", 5).unwrap(), ]); let deck2 = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE004", 5).unwrap(), CardCodeAndCount::from_data("01DE003", 2).unwrap(), CardCodeAndCount::from_data("02DE003", 3).unwrap(), CardCodeAndCount::from_data("01DE002", 4).unwrap(), ]); assert_eq!( encoder::code_from_deck(&deck1).unwrap(), encoder::code_from_deck(&deck2).unwrap() ); } #[test] fn bilgewater_set() { let deck = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 4).unwrap(), CardCodeAndCount::from_data("02BW003", 2).unwrap(), CardCodeAndCount::from_data("02BW010", 3).unwrap(), CardCodeAndCount::from_data("01DE004", 5).unwrap(), ]); let code = encoder::code_from_deck(&deck); let decoded_deck = encoder::deck_from_code(code.unwrap()); assert!(verify_rehydration(&deck, &decoded_deck.unwrap())); } #[test] fn shurima_set() { let deck = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 4).unwrap(), CardCodeAndCount::from_data("02BW003", 2).unwrap(), CardCodeAndCount::from_data("02BW010", 3).unwrap(), CardCodeAndCount::from_data("04SH047", 5).unwrap(), ]); let code = encoder::code_from_deck(&deck); let decoded_deck = encoder::deck_from_code(code.unwrap()); assert!(verify_rehydration(&deck, &decoded_deck.unwrap())); } #[test] fn mttargon_set() { let deck = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 4).unwrap(), CardCodeAndCount::from_data("03MT003", 2).unwrap(), CardCodeAndCount::from_data("03MT010", 3).unwrap(), CardCodeAndCount::from_data("02BW004", 5).unwrap(), ]); let code = encoder::code_from_deck(&deck); let decoded_deck = encoder::deck_from_code(code.unwrap()); assert!(verify_rehydration(&deck, &decoded_deck.unwrap())); } #[test] fn runeterra_set() { let deck = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 4).unwrap(), CardCodeAndCount::from_data("03MT003", 2).unwrap(), CardCodeAndCount::from_data("03MT010", 3).unwrap(), CardCodeAndCount::from_data("01RU001", 5).unwrap(), ]); let code = encoder::code_from_deck(&deck); let decoded_deck = encoder::deck_from_code(code.unwrap()); assert!(verify_rehydration(&deck, &decoded_deck.unwrap())); } #[test] fn bad_version() -> Result<(), Box> { // make sure that a deck with an invalid version fails let deck = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE002", 4).unwrap(), CardCodeAndCount::from_data("01DE003", 2).unwrap(), CardCodeAndCount::from_data("02DE003", 3).unwrap(), CardCodeAndCount::from_data("01DE004", 5).unwrap(), ]); let mut bytes_from_deck = data_encoding::BASE32_NOPAD.decode(encoder::code_from_deck(&deck).unwrap().as_bytes())?; bytes_from_deck.remove(0); bytes_from_deck.insert(0, 88u8); let bad_version_code = data_encoding::BASE32_NOPAD.encode(&bytes_from_deck); let bad_deck = encoder::deck_from_code(bad_version_code); assert!(bad_deck.is_err()); Ok(()) } #[test] fn bad_card_codes() { assert!(CardCodeAndCount::from_data("01DE02", 1).is_err()); assert!(CardCodeAndCount::from_data("01YY002", 1).is_err()); assert!(CardCodeAndCount::from_data("01DE002", 0).is_err()); } #[test] fn bad_count() { assert!(CardCodeAndCount::from_data("01DE002", 0).is_err()); assert!(CardCodeAndCount::from_data("01DE002", -1).is_err()); match CardCodeAndCount::from_data("01DE002", -1) { Err(LorError::InvalidCard) => assert!(true), _ => assert!(false), } } #[test] fn garbage_decoding() { let bad_encoding_not_base32 = String::from("I'm no card code!"); let bad_encoding32 = String::from("ABCDEFG"); let bad_encoding_empty = String::from(""); assert!(encoder::deck_from_code(&bad_encoding_not_base32).is_err()); assert!(encoder::deck_from_code(&bad_encoding32).is_err()); assert!(encoder::deck_from_code(&bad_encoding_empty).is_err()); match encoder::deck_from_code(&bad_encoding_empty) { Err(LorError::InvalidCard) => assert!(true), _ => assert!(false), } } #[test] fn deck_version_is_the_minimum_library_version_that_supports_the_contained_factions() { fn extract_version_from_deck_code(code: &str) -> u8 { let bytes = data_encoding::BASE32_NOPAD.decode(code.as_bytes()).unwrap(); bytes[0] & 0xF } let faction_number_to_version: HashMap<&'static str, u8> = { let mut map = HashMap::new(); map.insert("DE", 1); map.insert("FR", 1); map.insert("IO", 1); map.insert("NX", 1); map.insert("PZ", 1); map.insert("SI", 1); map.insert("BW", 2); map.insert("MT", 2); map.insert("SH", 3); map.insert("BC", 4); map }; for (&faction, &version) in faction_number_to_version.iter() { let deck = Deck::from_vec(vec![ CardCodeAndCount::from_data("01DE001", 1).unwrap(), CardCodeAndCount::from_data(format!("01{faction}002").as_str(), 1).unwrap(), CardCodeAndCount::from_data("01FR001", 1).unwrap(), ]); let deck_code = encoder::code_from_deck(&deck).unwrap(); let min_supported_library_version = extract_version_from_deck_code(&deck_code); assert_eq!(version, min_supported_library_version); } } #[test] fn argument_exception_on_future_version() { let single_card_deck_with_version_10 = "DEAAABABAEFACAIBAAAQCAIFAEAQGCTP"; assert!(deck_from_code(&single_card_deck_with_version_10).is_err()); } #[test] fn deck_serialize_deserialize() { let deck = Deck::from_vec(vec![ CardCodeAndCount::from_data("01SI015", 3).unwrap(), CardCodeAndCount::from_data("01SI044", 3).unwrap(), CardCodeAndCount::from_data("01SI048", 3).unwrap(), CardCodeAndCount::from_data("01SI054", 3).unwrap(), CardCodeAndCount::from_data("01FR003", 3).unwrap(), CardCodeAndCount::from_data("01FR012", 3).unwrap(), CardCodeAndCount::from_data("01FR020", 3).unwrap(), CardCodeAndCount::from_data("01FR024", 3).unwrap(), CardCodeAndCount::from_data("01FR033", 3).unwrap(), CardCodeAndCount::from_data("01FR036", 3).unwrap(), CardCodeAndCount::from_data("01FR039", 3).unwrap(), CardCodeAndCount::from_data("01FR052", 3).unwrap(), CardCodeAndCount::from_data("01SI005", 2).unwrap(), CardCodeAndCount::from_data("01FR004", 2).unwrap(), ]); let deck_json = serde_json::to_string(&deck); assert!(deck_json.is_ok()); let code = encoder::code_from_deck(&deck); assert!(code.is_ok()); let deck_from_json: Result = serde_json::from_str(&deck_json.unwrap()); assert!(deck_from_json.is_ok()); assert!(verify_rehydration(&deck, &deck_from_json.unwrap())); } fn verify_rehydration(d: &Deck, other: &Deck) -> bool { if d.cards().len() != other.cards().len() { return false; } for card_count in d.cards() { let res = other.cards().iter().find(|x| *x == card_count); if res.is_none() { return false; } } true }