use super::VarSeg;
use super::repeat::expand_repeat_blocks;
use proc_macro2::TokenStream;
fn segs() -> Vec<VarSeg> {
vec![
VarSeg { prefix: "A".into(), start: 0, len: 3 },
VarSeg { prefix: "B".into(), start: 1, len: 2 },
]
}
fn expand(s: &str) -> Result<String, String> {
let ts = s.parse::<TokenStream>().map_err(|e| e.to_string())?;
expand_repeat_blocks(ts, &segs()).map(|o| o.to_string()).map_err(|e| e.to_string())
}
#[test]
fn single_segment_rounds() {
assert_eq!(
expand("@(@A::f(&self.@0),)..").unwrap(),
"A0 :: f (& self .0) , A1 :: f (& self .1) , A2 :: f (& self .2) ,"
);
}
#[test]
fn offset_start_name_numbering() {
assert_eq!(
expand("@(@B::f(&self.@1),)..").unwrap(),
"B1 :: f (& self .1) , B2 :: f (& self .2) ,"
);
}
#[test]
fn multi_segment_parallel_rounds() {
let segs = vec![
VarSeg { prefix: "A".into(), start: 0, len: 2 },
VarSeg { prefix: "B".into(), start: 2, len: 2 },
];
let ts = "@(@A + @B,)..".parse::<TokenStream>().unwrap();
let out = expand_repeat_blocks(ts, &segs).unwrap().to_string();
assert_eq!(out, "A0 + B2 , A1 + B3 ,");
}
#[test]
fn unequal_segment_lengths_error() {
let segs = vec![
VarSeg { prefix: "A".into(), start: 0, len: 3 },
VarSeg { prefix: "B".into(), start: 1, len: 2 },
];
let ts = "@(@A + @B,)..".parse::<TokenStream>().unwrap();
assert!(expand_repeat_blocks(ts, &segs).is_err());
}
#[test]
fn nested_cartesian() {
let out = expand("@(@A::f(&self.@0) @(@B::g(&self.@1),)..)..").unwrap();
assert_eq!(
out,
"A0 :: f (& self .0) B1 :: g (& self .1) , B2 :: g (& self .2) , \
A1 :: f (& self .1) B1 :: g (& self .1) , B2 :: g (& self .2) , \
A2 :: f (& self .2) B1 :: g (& self .1) , B2 :: g (& self .2) ,"
);
}
#[test]
fn no_trailing_separator_concatenates() {
assert_eq!(expand("@(@A)..").unwrap(), "A0 A1 A2");
}
#[test]
fn float_literal_at_path_fixed() {
let segs = vec![VarSeg { prefix: "A".into(), start: 0, len: 2 }];
let ts = "@(@A::from(self.0.@0),)..".parse::<TokenStream>().unwrap();
let out = expand_repeat_blocks(ts, &segs).unwrap().to_string();
assert_eq!(out, "A0 :: from (self . 0 . 0) , A1 :: from (self . 0 . 1) ,");
}
#[test]
fn plain_body_passthrough() {
let s = "fn combine (& self , rhs : & Self) -> Self { todo ! () }";
assert_eq!(expand(s).unwrap(), s);
}
#[test]
fn declared_driver_cursor_only() {
let segs = vec![VarSeg { prefix: "A".into(), start: 0, len: 3 }];
let ts = "@A(self.@0,)..".parse::<TokenStream>().unwrap();
let out = expand_repeat_blocks(ts, &segs).unwrap().to_string();
assert_eq!(out, "self .0 , self .1 , self .2 ,");
}
#[test]
fn cursor_only_single_segment() {
let segs = vec![VarSeg { prefix: "A".into(), start: 0, len: 2 }];
let ts = "@(self.@0,)..".parse::<TokenStream>().unwrap();
let out = expand_repeat_blocks(ts, &segs).unwrap().to_string();
assert_eq!(out, "self .0 , self .1 ,");
}
#[test]
fn cursor_only_multi_segment_errors() {
let segs = vec![
VarSeg { prefix: "A".into(), start: 0, len: 2 },
VarSeg { prefix: "B".into(), start: 2, len: 2 },
];
let ts = "@(self.@0,)..".parse::<TokenStream>().unwrap();
assert!(expand_repeat_blocks(ts, &segs).is_err());
}
#[test]
fn declared_driver_conflict_errors() {
let segs = vec![
VarSeg { prefix: "A".into(), start: 0, len: 2 },
VarSeg { prefix: "B".into(), start: 2, len: 2 },
];
let ts = "@A(@B::f(),)..".parse::<TokenStream>().unwrap();
assert!(expand_repeat_blocks(ts, &segs).is_err());
}
#[test]
fn bare_at_errors() {
assert!(expand("x @ 0").is_err());
}
#[test]
fn unknown_segment_errors() {
assert!(expand("@(@X::f(),)..").is_err());
}
#[test]
fn no_driver_errors() {
assert!(expand("@(@0,)..").is_err());
}