use std::{sync::Arc, thread::spawn};
use cubing_core::{
alg::{Alg, AlgBuilder, AlgNode, Move, MoveLayer, MovePrefix, MoveRange, Newline, QuantumMove},
kpuzzle::InvalidAlgError,
};
#[test]
fn it_works() -> Result<(), InvalidAlgError> {
assert_eq!(
"R",
format!(
"{}",
Move {
quantum: QuantumMove::new("R", None).into(),
amount: 1
}
)
);
assert_eq!("F2", format!("{}", Move::try_from("F2").unwrap()));
assert_eq!("F2", format!("{}", "F2".parse::<Move>().unwrap()));
assert_eq!("F", format!("{}", "F1".parse::<Move>().unwrap()));
assert_eq!("F", format!("{}", "F".parse::<Move>().unwrap()));
assert_eq!("F'", format!("{}", "F1'".parse::<Move>().unwrap()));
assert_eq!("F0", format!("{}", "F0".parse::<Move>().unwrap()));
assert_eq!("F2'", format!("{}", "F2'".parse::<Move>().unwrap()));
assert_eq!("U_R", format!("{}", "U_R".parse::<Move>().unwrap()));
assert_eq!("4R2'", format!("{}", "4R2'".parse::<Move>().unwrap()));
assert_eq!("3-7R2'", format!("{}", "3-7R2'".parse::<Move>().unwrap()));
assert_eq!("R++", format!("{}", "R++".parse::<Move>().unwrap()));
assert_eq!("D--", format!("{}", "D--".parse::<Move>().unwrap()));
assert_eq!("/", format!("{}", "/".parse::<Move>().unwrap()));
assert_eq!("R1+", format!("{}", "R1+".parse::<Move>().unwrap()));
assert_eq!("DR3-", format!("{}", "DR3-".parse::<Move>().unwrap()));
assert_eq!("U0+", format!("{}", "U0+".parse::<Move>().unwrap()));
assert!("R+".parse::<Move>().is_err());
assert!("DR-".parse::<Move>().is_err());
assert!("DR+3".parse::<Move>().is_err());
assert!("DR+3'".parse::<Move>().is_err());
assert!("DR-3".parse::<Move>().is_err());
assert!("DR-3'".parse::<Move>().is_err());
assert!("DR++1".parse::<Move>().is_err());
assert!("DR++3".parse::<Move>().is_err());
assert_eq!("(3, 4)", format!("{}", "(3, 4)".parse::<Alg>().unwrap()));
assert_eq!("(-3, 4)", format!("{}", "(-3, 4)".parse::<Alg>().unwrap()));
assert_eq!("(3, -4)", format!("{}", "(3, -4)".parse::<Alg>().unwrap()));
assert_eq!(
"(-3, -4)",
format!("{}", "(-3, -4)".parse::<Alg>().unwrap())
);
assert_eq!("(1, 0)", format!("{}", "(1, 0)".parse::<Alg>().unwrap()));
assert_eq!("\n", Newline {}.to_string());
assert_eq!(
"3-7R2'",
format!(
"{}",
Move {
quantum: QuantumMove::new("R", MoveRange::new(3, 7).into()).into(),
amount: -2
}
)
);
assert_eq!(MoveLayer::from(7), MoveLayer { layer: 7 });
let single_move = "R2'".parse::<Move>().unwrap();
assert_eq!(single_move.quantum.prefix, None);
assert_eq!(single_move.quantum.family, "R");
assert_eq!(single_move.amount, -2);
let face_move = "R2'".parse::<Move>().unwrap();
assert_eq!(face_move.quantum.prefix, None);
assert_eq!(face_move.quantum.family, "R");
assert_eq!(face_move.amount, -2);
let block_move = "7R2'".parse::<Move>().unwrap();
assert_eq!(block_move.quantum.prefix, MoveLayer::new(7).into());
assert_eq!(block_move.quantum.family, "R");
assert_eq!(block_move.amount, -2);
let range_move = "3-7R2'".parse::<Move>().unwrap();
assert_eq!(range_move.quantum.prefix, MoveRange::new(3, 7).into());
assert_eq!(range_move.quantum.family, "R");
assert_eq!(range_move.amount, -2);
let range_move = "R++".parse::<Move>().unwrap();
assert_eq!(range_move.quantum.prefix, None);
assert_eq!(range_move.quantum.family, "R_PLUSPLUS_");
assert_eq!(range_move.amount, 1);
let range_move = "D--".parse::<Move>().unwrap();
assert_eq!(range_move.quantum.prefix, None);
assert_eq!(range_move.quantum.family, "D_PLUSPLUS_");
assert_eq!(range_move.amount, -1);
assert_eq!(
"R2".parse::<Move>().unwrap(),
Move {
quantum: QuantumMove {
family: "R".into(),
prefix: None
}
.into(),
amount: 2
}
);
assert_eq!("F2'", format!("{}", "F2".parse::<Move>().unwrap().invert()));
assert_eq!(
("2R3'").parse::<Move>()?.quantum.as_ref(),
&QuantumMove {
prefix: Some(MovePrefix::Layer(MoveLayer { layer: 2 },)),
family: "R".into()
}
);
assert_eq!(("2R3'").parse::<Move>()?.amount, -3);
assert!("2".parse::<Move>().is_err());
assert!("U-R".parse::<Move>().is_err());
std::convert::TryInto::<Move>::try_into("UR43")?;
let a1 = Alg {
nodes: vec![
Move::try_from("F2").unwrap().into(),
Move::try_from("R").unwrap().into(),
],
};
let a2 = Alg {
nodes: vec![
Move::try_from("R'").unwrap().into(),
Move::try_from("F2'").unwrap().into(),
],
};
assert!(a1 == a2.invert());
assert_eq!("R U' R'".parse::<Alg>()?, "R U R'".parse::<Alg>()?.invert());
assert_eq!(" R U' R' ".parse::<Alg>()?, "R U' R'".parse::<Alg>()?);
assert_eq!("R U' R'", " R U' R' ".parse::<Alg>()?.to_string());
assert_eq!(Alg { nodes: vec![] }, "".parse::<Alg>()?);
assert_eq!(Alg { nodes: vec![] }, " ".parse::<Alg>()?);
assert_eq!(
Alg {
nodes: vec!["R'".parse::<Move>()?.into()]
},
" R' ".parse::<Alg>()?
);
assert_eq!("(R U' R')", "(R U' R' )".parse::<Alg>()?.to_string());
assert_eq!(
"[R, U]",
" [ U , R ] ".parse::<Alg>()?.invert().to_string()
);
assert_eq!(
"[R: U']",
" [ R : U ] ".parse::<Alg>()?.invert().to_string()
);
assert_eq!("R'".parse::<Move>()?, ("R'").parse::<Move>()?);
assert_eq!("R U R'".parse::<Alg>()?, ("R U R'").parse::<Alg>()?);
assert_eq!(
"[R', F]3",
format!("{}", "([R', F])3".parse::<Alg>().unwrap())
);
let wr = "y x' // inspection
U R2 U' F' L F' U' L' // XX-Cross + EO
U' R U R' // 3rd slot
R' U R U2' R' U R // 4th slot
U R' U' R U' R' U2 R // OLL / ZBLL
U // AUF
// from http://cubesolv.es/solve/5757";
wr.parse::<Alg>()?;
assert_eq!(wr, wr.parse::<Alg>()?.to_string()); assert_eq!("\n\n", "\n\n".parse::<Alg>()?.to_string()); assert_eq!("\n", "\n".parse::<Alg>()?.to_string()); assert_eq!(
"R\nB // comment\n\n",
"R\nB // comment\n\n".parse::<Alg>()?.to_string()
);
assert_eq!(
"R\nB // comment\n",
"R\nB // comment\n".parse::<Alg>()?.to_string()
);
Ok(())
}
#[test]
fn it_can_build_and_parse_long_strings() -> Result<(), InvalidAlgError> {
let mut builder = AlgBuilder::default();
let quantum = Arc::new(QuantumMove {
family: "R".into(),
prefix: None,
});
for amount in 1..1000 {
let r#move = Move {
quantum: quantum.clone(),
amount,
};
let alg_node: AlgNode = r#move.into();
builder.push(&alg_node);
}
let alg = builder.to_alg();
let s = alg.to_string();
let re_parsed = s.parse::<Alg>()?;
assert_eq!(alg, re_parsed);
Ok(())
}
#[test]
fn mixed_puzzle_notation() -> Result<(), InvalidAlgError> {
assert!("(R 2-5r3' R++)' / [ UR , F2 ]".parse::<Alg>().is_ok());
Ok(())
}
#[test]
fn it_handles_crowding() -> Result<(), String> {
assert!("R'U".parse::<Alg>().is_err());
assert!("R//F".parse::<Alg>().is_err());
Ok(())
}
#[test]
fn alg_can_be_sent_to_and_returned_from_threads() -> Result<(), InvalidAlgError> {
let alg = "R U R'".parse::<Alg>()?;
let inverse = alg.invert();
let inverse_clone = alg.invert();
let result = spawn(move || inverse_clone.invert()).join().unwrap();
assert_eq!(alg, result);
assert_ne!(inverse, result);
Ok(())
}