diff --git a/Cargo.lock b/Cargo.lock index 0a6e103..c51c9df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "anstream" version = "0.6.15" @@ -57,6 +66,12 @@ version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + [[package]] name = "cfg-if" version = "1.0.0" @@ -109,6 +124,55 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-macro", + "futures-task", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "getrandom" version = "0.2.13" @@ -120,12 +184,34 @@ dependencies = [ "wasi", ] +[[package]] +name = "glob" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "indexmap" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -138,12 +224,39 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -192,12 +305,101 @@ dependencies = [ "getrandom", ] +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "rstest" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e905296805ab93e13c1ec3a03f4b6c4f35e9498a3d5fa96dc626d22c03cd89" +dependencies = [ + "futures-timer", + "futures-util", + "rstest_macros", + "rustc_version", +] + +[[package]] +name = "rstest_macros" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef0053bbffce09062bee4bcc499b0fbe7a57b879f1efe088d6d8d4c7adcdef9b" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn", + "unicode-ident", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "rustversion" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" +[[package]] +name = "semver" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "strsim" version = "0.11.1" @@ -235,10 +437,27 @@ dependencies = [ ] [[package]] -name = "unicode-ident" -version = "1.0.12" +name = "toml_datetime" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "utf8parse" @@ -325,6 +544,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310" +dependencies = [ + "memchr", +] + [[package]] name = "zeal" version = "0.1.0" @@ -332,6 +560,7 @@ dependencies = [ "anyhow", "clap", "rand", + "rstest", "strum", "strum_macros", ] diff --git a/Cargo.toml b/Cargo.toml index 8eeea2b..6efe038 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" anyhow = "1.0.95" clap = { version = "4.5.26", features = ["derive"] } rand = { version = "0.8.5", features = ["small_rng"] } +rstest = "0.24.0" strum = "0.26.3" strum_macros = "0.26.4" diff --git a/src/movegen/move.rs b/src/movegen/move.rs index f55c94e..63c2b5a 100644 --- a/src/movegen/move.rs +++ b/src/movegen/move.rs @@ -251,98 +251,70 @@ impl Move { #[cfg(test)] mod tests { - use super::Move; use crate::board::fen::from_fen; use crate::board::square::Square; use crate::movegen::r#move::MoveType; + use super::Move; + + use rstest::rstest; const FEN: &'static str = "1r2k2r/2P1pq1p/2npb3/1p3ppP/p3P3/P2B1Q2/1P1PNPP1/R3K2R w KQk g6 0 1"; - #[test] - fn test_parse_from_str_quiet() -> Result<(), String> { - let game = from_fen(FEN)?; - let mv_str = "b2b3"; - let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::new(Square::B2, Square::B3); + #[rstest] + #[case::quiet("b2b3")] + #[case::double_push("b2b4")] + #[case::king_castle("e1g1")] + #[case::queen_castle("e1c1")] + #[case::capture("d3b5")] + #[case::en_passant("h5g6")] + #[case::promotion_knight("c7c8n")] + #[case::promotion_bishop("c7c8b")] + #[case::promotion_rook("c7c8r")] + #[case::promotion_queen("c7c8q")] + #[case::promotion_capture_knight("c7b8n")] + #[case::promotion_capture_bishop("c7b8b")] + #[case::promotion_capture_rook("c7b8r")] + #[case::promotion_capture_queen("c7b8q")] + fn test_parse_from_str(#[case] mv_str: &str) { + use crate::movegen::r#move::Move; + + let game = from_fen(FEN).unwrap(); + let actual = Move::parse_from_str(&game, mv_str).unwrap(); + let expected = match mv_str { + "b2b3" => Move::new_with_type(Square::B2, Square::B3, MoveType::Quiet), + "b2b4" => Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush), + "e1g1" => Move::new_with_type(Square::E1, Square::G1, MoveType::KingCastle), + "e1c1" => Move::new_with_type(Square::E1, Square::C1, MoveType::QueenCastle), + "d3b5" => Move::new_with_type(Square::D3, Square::B5, MoveType::Capture), + "h5g6" => Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant), + "c7c8n" => Move::new_with_type(Square::C7, Square::C8, MoveType::PromotionKnight), + "c7c8b" => Move::new_with_type(Square::C7, Square::C8, MoveType::PromotionBishop), + "c7c8r" => Move::new_with_type(Square::C7, Square::C8, MoveType::PromotionRook), + "c7c8q" => Move::new_with_type(Square::C7, Square::C8, MoveType::PromotionQueen), + "c7b8n" => Move::new_with_type(Square::C7, Square::B8, MoveType::PromotionCaptureKnight), + "c7b8b" => Move::new_with_type(Square::C7, Square::B8, MoveType::PromotionCaptureBishop), + "c7b8r" => Move::new_with_type(Square::C7, Square::B8, MoveType::PromotionCaptureRook), + "c7b8q" => Move::new_with_type(Square::C7, Square::B8, MoveType::PromotionCaptureQueen), + _ => unreachable!(), + }; assert_eq!(expected, actual); - - Ok(()) } - #[test] - fn test_parse_from_str_capture() -> Result<(), String> { - let game = from_fen(FEN)?; - let mv_str = "d3b5"; - let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::new_with_type(Square::D3, Square::B5, MoveType::Capture); - assert_eq!(expected, actual); - - Ok(()) - } - - #[test] - fn test_parse_from_str_en_passant() -> Result<(), String> { - let game = from_fen(FEN)?; - let mv_str = "h5g6"; - let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::new_with_type(Square::H5, Square::G6, MoveType::EnPassant); - - assert_eq!(expected, actual); - - Ok(()) - } - - #[test] - fn test_parse_from_str_double_push() -> Result<(), String> { - let game = from_fen(FEN)?; - let mv_str = "b2b4"; - let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::new_with_type(Square::B2, Square::B4, MoveType::DoublePush); - - assert_eq!(expected, actual); - - Ok(()) - } - - #[test] - fn test_parse_from_str_promotion() -> Result<(), String> { - let game = from_fen(FEN)?; - let mv_str = "c7c8q"; - let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::new_with_type(Square::C7, Square::C8, MoveType::PromotionQueen); - - assert_eq!(expected, actual); - - Ok(()) - } - - #[test] - fn test_parse_from_str_promotion_capture() -> Result<(), String> { - let game = from_fen(FEN)?; - let mv_str = "c7b8q"; - let actual = Move::parse_from_str(&game, &mv_str)?; - let expected = Move::new_with_type(Square::C7, Square::B8, MoveType::PromotionCaptureQueen); - - assert_eq!(expected, actual); - - Ok(()) - } - - #[test] + #[rstest] + #[case("c7c8qq")] #[should_panic(expected = "Invalid move characters length")] - fn test_parse_from_str_panic_1() { + fn test_parse_from_str_panic_invalid_char_length(#[case] mv_str: &str) { let game = from_fen(FEN); - let mv_str = "c7c8qq"; Move::parse_from_str(&game.unwrap(), &mv_str).unwrap(); } - #[test] + #[rstest] + #[case("c7c8w")] #[should_panic(expected = "Unrecongisable character in promotion piece index")] - fn test_parse_from_str_panic_2() -> () { - let game = from_fen(FEN); - let mv_str = "c7c8w"; + fn test_parse_from_str_panic_invalid_promo_char(#[case] mv_str: &str) { + let game: Result = from_fen(FEN); Move::parse_from_str(&game.unwrap(), &mv_str).unwrap(); } }