use std::num::{NonZeroI32, ParseIntError};
use inpt::{inpt, Inpt};
#[test]
fn test_pair_no_regex() {
#[derive(Inpt, Debug, PartialEq)]
struct Pair {
a: usize,
b: usize,
}
assert_eq!(inpt::<Pair>("42 69").unwrap(), Pair { a: 42, b: 69 });
}
#[test]
fn test_pair_regex() {
#[derive(Inpt, Debug, PartialEq)]
#[inpt(regex = r"(\d+) -> (\d+)")]
struct Pair {
a: usize,
b: usize,
}
assert_eq!(inpt::<Pair>("42 -> 69").unwrap(), Pair { a: 42, b: 69 });
}
#[test]
fn test_enum() {
#[derive(Inpt, Debug, PartialEq)]
enum AOrB {
#[inpt(regex = r"a(\d+)")]
A { x: usize },
#[inpt(regex = r"b(\d+)")]
B { x: usize },
}
assert_eq!(inpt::<AOrB>("a42").unwrap(), AOrB::A { x: 42 });
assert_eq!(inpt::<AOrB>("b69").unwrap(), AOrB::B { x: 69 });
}
#[test]
fn test_pair_regex_tuple() {
#[derive(Inpt, Debug, PartialEq)]
#[inpt(regex = r"(\d+) -> (\d+)")]
struct Pair(usize, usize);
assert_eq!(inpt::<Pair>("42 -> 69").unwrap(), Pair(42, 69));
}
#[test]
fn test_enum_tuple() {
#[derive(Inpt, Debug, PartialEq)]
enum AOrB {
#[inpt(regex = r"a(\d+)")]
A(usize),
#[inpt(regex = r"b(\d+)")]
B(usize),
}
assert_eq!(inpt::<AOrB>("a42").unwrap(), AOrB::A(42));
assert_eq!(inpt::<AOrB>("b69").unwrap(), AOrB::B(69));
}
#[test]
fn test_skip() {
#[derive(Inpt, Debug, PartialEq)]
struct Pair {
a: i32,
#[inpt(skip)]
b: i32,
c: i32,
}
assert_eq!(inpt::<Pair>("42 69").unwrap(), Pair { a: 42, b: 0, c: 69 });
}
#[test]
fn test_skip_regex() {
#[derive(Inpt, Debug, PartialEq)]
#[inpt(regex = r"(\d+) -> (\d+)")]
struct Pair {
a: i32,
#[inpt(skip)]
b: i32,
c: i32,
}
assert_eq!(
inpt::<Pair>("42 -> 69").unwrap(),
Pair { a: 42, b: 0, c: 69 }
);
}
#[test]
fn test_field_default_trim() {
#[derive(Inpt, Debug, PartialEq)]
struct A {
a: i32,
b: i32,
}
assert_eq!(inpt::<A>(",1,2,").unwrap(), A { a: 1, b: 2 });
}
#[test]
fn test_capture_default_trim() {
#[derive(Inpt, Debug, PartialEq)]
#[inpt(regex = "(.*)_(.*)")]
struct A {
a: i32,
b: i32,
}
assert_eq!(inpt::<A>(",1,_,2,").unwrap(), A { a: 1, b: 2 });
}
#[test]
fn test_field_iter_default_trim() {
#[derive(Inpt, Debug, PartialEq)]
struct A {
a: i32,
#[inpt(from_iter = "i32")]
b: Vec<i32>,
}
assert_eq!(
inpt::<A>(",1,2,3,4,5,").unwrap(),
A {
a: 1,
b: vec![2, 3, 4, 5]
}
);
}
#[test]
fn test_capture_iter_default_trim() {
#[derive(Inpt, Debug, PartialEq)]
#[inpt(regex = "(.*)_(.*)")]
struct A {
a: i32,
#[inpt(from_iter = "i32")]
b: Vec<i32>,
}
assert_eq!(
inpt::<A>(",1,_,2,3,4,5,").unwrap(),
A {
a: 1,
b: vec![2, 3, 4, 5]
}
);
}
#[test]
fn test_field_iter_custom_trim() {
#[derive(Inpt, Debug, PartialEq)]
struct A {
a: i32,
#[inpt(from_iter = "i32", trim = "-")]
b: Vec<i32>,
}
assert_eq!(
inpt::<A>(" 1-2-3-4-5- ").unwrap(),
A {
a: 1,
b: vec![2, 3, 4, 5]
}
);
}
#[test]
fn test_capture_iter_custom_trim() {
#[derive(Inpt, Debug, PartialEq)]
#[inpt(regex = "(.*)_(.*)")]
struct A {
a: i32,
#[inpt(from_iter = "i32", trim = "-")]
b: Vec<i32>,
}
assert_eq!(
inpt::<A>(" 1_-2-3-4-5- ").unwrap(),
A {
a: 1,
b: vec![2, 3, 4, 5]
}
);
}
#[test]
fn test_field_custom_trim() {
#[derive(Inpt)]
struct A {
_c: char,
#[inpt(trim = r"\d")]
x: String,
}
assert_eq!(inpt::<A>("_8hello").unwrap().x, "hello");
assert_eq!(inpt::<A>("_8 hello").unwrap().x, " hello");
}
#[test]
fn test_struct_custom_trim() {
#[derive(Inpt)]
#[inpt(trim = r"\d\s")]
struct A {
x: String,
}
assert_eq!(inpt::<A>(" 9 435 34hello03459 2\t").unwrap().x, "hello");
}
#[test]
fn test_capture_custom_trim() {
#[derive(Inpt, Debug, PartialEq)]
#[inpt(regex = "_(.+?)_")]
struct A<'s> {
#[inpt(before, trim = "_")]
a: i32,
#[inpt(trim = r"_")]
b: &'s str,
#[inpt(after, trim = "_")]
c: &'s str,
}
assert_eq!(
inpt::<A>("__42__ohea__rtns").unwrap(),
A {
a: 42,
b: "ohea",
c: "rtns"
}
);
}
#[test]
fn test_struct_and_field_custom_trim() {
#[derive(Inpt)]
#[inpt(trim = r"\d\s")]
struct A {
x: String,
}
#[derive(Inpt)]
struct B {
#[inpt(trim = "")]
x: A,
}
#[derive(Inpt)]
struct C {
x: A,
}
assert_eq!(
inpt::<B>(" 9 435 34hello03459 2\t").unwrap().x.x,
"9 435 34hello03459 2"
);
assert_eq!(inpt::<C>(" 9 435 34hello03459 2\t").unwrap().x.x, "hello");
}
#[test]
fn test_optional_gruop() {
#[derive(Inpt, Debug, PartialEq)]
#[inpt(regex = r"(\d+) (?:-> (\d+)|<- (\d+))")]
struct DirPair {
a: usize,
b: Option<usize>,
c: Option<usize>,
}
assert_eq!(
inpt::<DirPair>("42 -> 69").unwrap(),
DirPair {
a: 42,
b: Some(69),
c: None,
}
);
assert_eq!(
inpt::<DirPair>("42 <- 69").unwrap(),
DirPair {
a: 42,
b: None,
c: Some(69),
}
);
}
#[test]
fn test_regex_before() {
#[derive(Inpt, Debug, PartialEq)]
#[inpt(regex = r"([a-zA-Z]+)")]
struct Pair<'s> {
#[inpt(before)]
rest: f32,
unit: &'s str,
}
assert_eq!(
inpt::<Pair>("42cm").unwrap(),
Pair {
rest: 42.0,
unit: "cm",
}
);
inpt::<Pair>("42-").unwrap_err();
}
#[test]
fn test_regex_after() {
#[derive(Inpt, Debug, PartialEq)]
#[inpt(regex = r"(\+|-)")]
struct Pair {
sign: char,
#[inpt(after)]
rest: f32,
}
assert_eq!(
inpt::<Pair>("-42").unwrap(),
Pair {
sign: '-',
rest: 42.0,
}
);
assert_eq!(
inpt::<Pair>("+ 42.0").unwrap(),
Pair {
sign: '+',
rest: 42.0,
}
);
inpt::<Pair>("*42").unwrap_err();
}
#[test]
fn test_split_field() {
#[derive(Inpt, Debug, PartialEq)]
struct X {
#[inpt(split = "Word")]
a: i32,
#[inpt(split = "Word")]
b: i32,
}
assert_eq!(inpt::<X>("3.-14.").unwrap(), X { a: 3, b: 14 });
}
#[test]
fn test_split_from_str() {
#[derive(Inpt, Debug, PartialEq)]
struct X {
#[inpt(from_str, split = "Word")]
a: NonZeroI32,
#[inpt(from_str, split = "Word")]
b: NonZeroI32,
}
assert_eq!(
inpt::<X>("3.-14.").unwrap(),
X {
a: NonZeroI32::new(3).unwrap(),
b: NonZeroI32::new(14).unwrap(),
}
);
}
#[test]
fn test_split_from_iter() {
#[derive(Inpt, Debug, PartialEq)]
struct X {
#[inpt(from_iter = "char", split = "Line")]
a: Vec<char>,
#[inpt(from_iter = "char", split = "Line")]
b: Vec<char>,
}
assert_eq!(
inpt::<X>("ohea\nrtns").unwrap(),
X {
a: vec!['o', 'h', 'e', 'a'],
b: vec!['r', 't', 'n', 's'],
}
);
}
#[test]
fn test_recursion_error() {
#[derive(Inpt, Debug)]
#[inpt(bounds = "")]
struct Blank {
_next: Box<Blank>,
}
let mut error_text = Vec::<u8>::new();
inpt::<Blank>("_")
.unwrap_err()
.annotated(&mut error_text, Some(false))
.unwrap();
let error_text = std::str::from_utf8(&error_text).unwrap();
eprintln!("{error_text}");
assert!(error_text.contains("<^ derive::test_recursion_error::Blank />"));
}
#[test]
fn test_nested_generics_not_recursion() {
#[derive(Inpt)]
struct Wrapper<T> {
_inner: T,
}
inpt::<Wrapper<Wrapper<i32>>>("42").unwrap();
}
#[test]
fn test_derive_with_from() {
#[derive(Inpt, PartialEq, Debug)]
#[inpt(from = "i32")]
struct Foo(i32, i32);
impl From<i32> for Foo {
fn from(x: i32) -> Self {
Foo(0, x)
}
}
assert_eq!(inpt::<Foo>("42").unwrap(), Foo(0, 42));
}
#[test]
fn test_derive_with_try_from_ok() {
#[derive(Inpt, PartialEq, Debug)]
#[inpt(try_from = "&'s str")]
struct Foo(i32, i32);
impl<'s> TryFrom<&'s str> for Foo {
type Error = ParseIntError;
fn try_from(x: &'s str) -> Result<Self, ParseIntError> {
Ok(Foo(0, x.parse()?))
}
}
assert_eq!(inpt::<Foo>("42").unwrap(), Foo(0, 42));
}
#[test]
fn test_derive_with_try_from_err() {
#[derive(Inpt, PartialEq, Debug)]
#[inpt(try_from = "&'s str")]
struct Foo(i32, i32);
impl<'s> TryFrom<&'s str> for Foo {
type Error = ParseIntError;
fn try_from(x: &'s str) -> Result<Self, ParseIntError> {
Ok(Foo(0, x.parse()?))
}
}
let mut error_text = Vec::<u8>::new();
inpt::<Foo>("fourty-two")
.unwrap_err()
.annotated(&mut error_text, Some(false))
.unwrap();
let error_text = std::str::from_utf8(&error_text).unwrap();
eprintln!("{error_text}");
assert!(error_text.contains("Foo><! invalid digit found in string >"));
}
#[test]
fn test_derive_with_from_inherits_trim() {
#[derive(Inpt, PartialEq, Debug)]
#[inpt(from = "i32")]
struct Foo(i32, i32);
impl From<i32> for Foo {
fn from(x: i32) -> Self {
Foo(0, x)
}
}
assert_eq!(inpt::<Foo>(",,42,,").unwrap(), Foo(0, 42));
}
#[test]
fn test_derive_with_from_custom_trim() {
#[derive(Inpt, PartialEq, Debug)]
#[inpt(from = "i32", trim = "0")]
struct Foo(i32, i32);
impl From<i32> for Foo {
fn from(x: i32) -> Self {
Foo(0, x)
}
}
assert_eq!(inpt::<Foo>("004200").unwrap(), Foo(0, 42));
}
#[test]
fn test_no_trim_at_ends() {
assert_eq!(inpt::<inpt::NoTrim<&str>>(" ohea ").unwrap().0, " ohea ");
}