diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/nom/tests | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/nom/tests')
-rw-r--r-- | third_party/rust/nom/tests/arithmetic.rs | 109 | ||||
-rw-r--r-- | third_party/rust/nom/tests/arithmetic_ast.rs | 172 | ||||
-rw-r--r-- | third_party/rust/nom/tests/blockbuf-arithmetic.rs | 321 | ||||
-rw-r--r-- | third_party/rust/nom/tests/css.rs | 51 | ||||
-rw-r--r-- | third_party/rust/nom/tests/custom_errors.rs | 53 | ||||
-rw-r--r-- | third_party/rust/nom/tests/escaped.rs | 25 | ||||
-rw-r--r-- | third_party/rust/nom/tests/float.rs | 46 | ||||
-rw-r--r-- | third_party/rust/nom/tests/inference.rs | 53 | ||||
-rw-r--r-- | third_party/rust/nom/tests/ini.rs | 221 | ||||
-rw-r--r-- | third_party/rust/nom/tests/ini_str.rs | 215 | ||||
-rw-r--r-- | third_party/rust/nom/tests/issues.rs | 318 | ||||
-rw-r--r-- | third_party/rust/nom/tests/json.rs | 105 | ||||
-rw-r--r-- | third_party/rust/nom/tests/mp4.rs | 319 | ||||
-rw-r--r-- | third_party/rust/nom/tests/multiline.rs | 36 | ||||
-rw-r--r-- | third_party/rust/nom/tests/named_args.rs | 161 | ||||
-rw-r--r-- | third_party/rust/nom/tests/overflow.rs | 139 | ||||
-rw-r--r-- | third_party/rust/nom/tests/reborrow_fold.rs | 18 | ||||
-rw-r--r-- | third_party/rust/nom/tests/test1.rs | 44 |
18 files changed, 2406 insertions, 0 deletions
diff --git a/third_party/rust/nom/tests/arithmetic.rs b/third_party/rust/nom/tests/arithmetic.rs new file mode 100644 index 0000000000..b3c38931df --- /dev/null +++ b/third_party/rust/nom/tests/arithmetic.rs @@ -0,0 +1,109 @@ +extern crate nom; + + +use nom::{ + IResult, + branch::alt, + combinator::map_res, + character::complete::char, + bytes::complete::tag, + character::complete::{digit1 as digit, space0 as space}, + multi::fold_many0, + sequence::{delimited, pair} +}; + +// Parser definition + +use std::str::FromStr; + +// We parse any expr surrounded by parens, ignoring all whitespaces around those +fn parens(i: &str) -> IResult<&str, i64> { + delimited( + space, + delimited( + tag("("), + expr, + tag(")") + ), + space + )(i) +} + +// We transform an integer string into a i64, ignoring surrounding whitespaces +// We look for a digit suite, and try to convert it. +// If either str::from_utf8 or FromStr::from_str fail, +// we fallback to the parens parser defined above +fn factor(i: &str) -> IResult<&str, i64> { + alt(( + map_res(delimited(space, digit, space), FromStr::from_str), + parens + ))(i) +} + +// We read an initial factor and for each time we find +// a * or / operator followed by another factor, we do +// the math by folding everything +fn term(i: &str) -> IResult<&str, i64> { + let (i, init) = factor(i)?; + + fold_many0( + pair(alt((char('*'), char('/'))), factor), + init, + |acc, (op, val): (char, i64)| { + if op == '*' { acc * val } else { acc / val } + } + )(i) +} + +fn expr(i: &str) -> IResult<&str, i64> { + let (i, init) = term(i)?; + + fold_many0( + pair(alt((char('+'), char('-'))), term), + init, + |acc, (op, val): (char, i64)| { + if op == '+' { acc + val } else { acc - val } + } + )(i) +} + +#[test] +fn factor_test() { + assert_eq!(factor("3"), Ok(("", 3))); + assert_eq!(factor(" 12"), Ok(("", 12))); + assert_eq!(factor("537 "), Ok(("", 537))); + assert_eq!(factor(" 24 "), Ok(("", 24))); +} + +#[test] +fn term_test() { + assert_eq!(term(" 12 *2 / 3"), Ok(("", 8))); + assert_eq!( + term(" 2* 3 *2 *2 / 3"), + Ok(("", 8)) + ); + assert_eq!(term(" 48 / 3/2"), Ok(("", 8))); +} + +#[test] +fn expr_test() { + assert_eq!(expr(" 1 + 2 "), Ok(("", 3))); + assert_eq!( + expr(" 12 + 6 - 4+ 3"), + Ok(("", 17)) + ); + assert_eq!(expr(" 1 + 2*3 + 4"), Ok(("", 11))); +} + +#[test] +fn parens_test() { + assert_eq!(expr(" ( 2 )"), Ok(("", 2))); + assert_eq!( + expr(" 2* ( 3 + 4 ) "), + Ok(("", 14)) + ); + assert_eq!( + expr(" 2*2 / ( 5 - 1) + 3"), + Ok(("", 4)) + ); +} diff --git a/third_party/rust/nom/tests/arithmetic_ast.rs b/third_party/rust/nom/tests/arithmetic_ast.rs new file mode 100644 index 0000000000..ecb8d40641 --- /dev/null +++ b/third_party/rust/nom/tests/arithmetic_ast.rs @@ -0,0 +1,172 @@ +extern crate nom; + +use std::fmt; +use std::fmt::{Debug, Display, Formatter}; + +use std::str::FromStr; + +use nom::{ + IResult, + character::complete::{digit1 as digit, multispace0 as multispace}, + sequence::{preceded, delimited}, + combinator::{map, map_res}, + multi::many0, + branch::alt, + bytes::complete::tag, +}; + +pub enum Expr { + Value(i64), + Add(Box<Expr>, Box<Expr>), + Sub(Box<Expr>, Box<Expr>), + Mul(Box<Expr>, Box<Expr>), + Div(Box<Expr>, Box<Expr>), + Paren(Box<Expr>), +} + +#[derive(Debug)] +pub enum Oper { + Add, + Sub, + Mul, + Div, +} + +impl Display for Expr { + fn fmt(&self, format: &mut Formatter) -> fmt::Result { + use self::Expr::*; + match *self { + Value(val) => write!(format, "{}", val), + Add(ref left, ref right) => write!(format, "{} + {}", left, right), + Sub(ref left, ref right) => write!(format, "{} - {}", left, right), + Mul(ref left, ref right) => write!(format, "{} * {}", left, right), + Div(ref left, ref right) => write!(format, "{} / {}", left, right), + Paren(ref expr) => write!(format, "({})", expr), + } + } +} + +impl Debug for Expr { + fn fmt(&self, format: &mut Formatter) -> fmt::Result { + use self::Expr::*; + match *self { + Value(val) => write!(format, "{}", val), + Add(ref left, ref right) => write!(format, "({:?} + {:?})", left, right), + Sub(ref left, ref right) => write!(format, "({:?} - {:?})", left, right), + Mul(ref left, ref right) => write!(format, "({:?} * {:?})", left, right), + Div(ref left, ref right) => write!(format, "({:?} / {:?})", left, right), + Paren(ref expr) => write!(format, "[{:?}]", expr), + } + } +} + +fn parens(i: &str) -> IResult<&str, Expr> { + delimited( + multispace, + delimited( + tag("("), + map(expr, |e| Expr::Paren(Box::new(e))), + tag(")") + ), + multispace + )(i) +} + +fn factor(i: &str) -> IResult<&str, Expr> { + alt(( + map( + map_res( + delimited(multispace, digit, multispace), + FromStr::from_str + ), + Expr::Value + ), + parens + ))(i) +} + +fn fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr { + remainder.into_iter().fold(initial, |acc, pair| { + let (oper, expr) = pair; + match oper { + Oper::Add => Expr::Add(Box::new(acc), Box::new(expr)), + Oper::Sub => Expr::Sub(Box::new(acc), Box::new(expr)), + Oper::Mul => Expr::Mul(Box::new(acc), Box::new(expr)), + Oper::Div => Expr::Div(Box::new(acc), Box::new(expr)), + } + }) +} + +fn term(i: &str) -> IResult<&str, Expr> { + let (i, initial) = factor(i)?; + let (i, remainder) = many0(alt(( + |i| { + let(i, mul) = preceded(tag("*"), factor)(i)?; + Ok((i,(Oper::Mul, mul))) + }, + |i| { + let(i, div) = preceded(tag("/"), factor)(i)?; + Ok((i, (Oper::Div, div))) + }, + + )))(i)?; + + Ok((i, fold_exprs(initial, remainder))) +} + +fn expr(i: &str) -> IResult<&str, Expr> { + let (i, initial) = term(i)?; + let (i, remainder) = many0(alt(( + |i| { + let(i, add) = preceded(tag("+"), term)(i)?; + Ok((i,(Oper::Add, add))) + }, + |i| { + let(i, sub) = preceded(tag("-"), term)(i)?; + Ok((i, (Oper::Sub, sub))) + }, + + )))(i)?; + + Ok((i, fold_exprs(initial, remainder))) +} + +#[test] +fn factor_test() { + assert_eq!( + factor(" 3 ").map(|(i, x)| (i, format!("{:?}", x))), + Ok(("", String::from("3"))) + ); +} + +#[test] +fn term_test() { + assert_eq!( + term(" 3 * 5 ").map(|(i, x)| (i, format!("{:?}", x))), + Ok(("", String::from("(3 * 5)"))) + ); +} + +#[test] +fn expr_test() { + assert_eq!( + expr(" 1 + 2 * 3 ").map(|(i, x)| (i, format!("{:?}", x))), + Ok(("", String::from("(1 + (2 * 3))"))) + ); + assert_eq!( + expr(" 1 + 2 * 3 / 4 - 5 ").map(|(i, x)| (i, format!("{:?}", x))), + Ok(("", String::from("((1 + ((2 * 3) / 4)) - 5)"))) + ); + assert_eq!( + expr(" 72 / 2 / 3 ").map(|(i, x)| (i, format!("{:?}", x))), + Ok(("", String::from("((72 / 2) / 3)"))) + ); +} + +#[test] +fn parens_test() { + assert_eq!( + expr(" ( 1 + 2 ) * 3 ").map(|(i, x)| (i, format!("{:?}", x))), + Ok(("", String::from("([(1 + 2)] * 3)"))) + ); +} diff --git a/third_party/rust/nom/tests/blockbuf-arithmetic.rs b/third_party/rust/nom/tests/blockbuf-arithmetic.rs new file mode 100644 index 0000000000..27a295fc77 --- /dev/null +++ b/third_party/rust/nom/tests/blockbuf-arithmetic.rs @@ -0,0 +1,321 @@ +/* +#[macro_use] +extern crate nom; +extern crate bytes; + +use nom::{Compare,CompareResult,InputLength,InputIter,Slice,HexDisplay}; + +use std::str; +use std::str::FromStr; +use bytes::{Buf,MutBuf}; +use bytes::buf::{BlockBuf,BlockBufCursor}; +use std::ops::{Range,RangeTo,RangeFrom,RangeFull}; +use std::iter::{Enumerate,Iterator}; +use std::fmt; +use std::cmp::{min,PartialEq}; + +#[derive(Clone,Copy)] +#[repr(C)] +pub struct BlockSlice<'a> { + buf: &'a BlockBuf, + start: usize, + end: usize, +} + +impl<'a> BlockSlice<'a> { + fn cursor(&self) -> WrapCursor<'a> { + let mut cur = self.buf.buf(); + cur.advance(self.start); + WrapCursor { + cursor: cur, + length: self.end - self.start, + } + } +} + +impl<'a> fmt::Debug for BlockSlice<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "BlockSlice {{ start: {}, end: {}, data:\n{}\n}}", self.start, self.end, self.buf.bytes().unwrap_or(&b""[..]).to_hex(16)) + } +} + +impl<'a> PartialEq for BlockSlice<'a> { + fn eq(&self, other: &BlockSlice<'a>) -> bool { + let bufs = (self.buf as *const BlockBuf) == (other.buf as *const BlockBuf); + self.start == other.start && self.end == other.end && bufs + } +} + +impl<'a> Slice<Range<usize>> for BlockSlice<'a> { + fn slice(&self, range:Range<usize>) -> Self { + BlockSlice { + buf: self.buf, + start: self.start + range.start, + //FIXME: check for valid end here + end: self.start + range.end, + } + } +} + +impl<'a> Slice<RangeTo<usize>> for BlockSlice<'a> { + fn slice(&self, range:RangeTo<usize>) -> Self { + self.slice(0..range.end) + } +} + +impl<'a> Slice<RangeFrom<usize>> for BlockSlice<'a> { + fn slice(&self, range:RangeFrom<usize>) -> Self { + self.slice(range.start..self.end - self.start) + } +} + +impl<'a> Slice<RangeFull> for BlockSlice<'a> { + fn slice(&self, _:RangeFull) -> Self { + BlockSlice { + buf: self.buf, + start: self.start, + end: self.end, + } + } +} + + +impl<'a> InputIter for BlockSlice<'a> { + type Item = u8; + type RawItem = u8; + type Iter = Enumerate<WrapCursor<'a>>; + type IterElem = WrapCursor<'a>; + + fn iter_indices(&self) -> Self::Iter { + self.cursor().enumerate() + } + fn iter_elements(&self) -> Self::IterElem { + self.cursor() + } + fn position<P>(&self, predicate: P) -> Option<usize> where P: Fn(Self::RawItem) -> bool { + self.cursor().position(|b| predicate(b)) + } + fn slice_index(&self, count:usize) -> Option<usize> { + if self.end - self.start >= count { + Some(count) + } else { + None + } + } +} + + +impl<'a> InputLength for BlockSlice<'a> { + fn input_len(&self) -> usize { + self.end - self.start + } +} + +impl<'a,'b> Compare<&'b[u8]> for BlockSlice<'a> { + fn compare(&self, t: &'b[u8]) -> CompareResult { + let len = self.end - self.start; + let blen = t.len(); + let m = if len < blen { len } else { blen }; + let reduced = self.slice(..m); + let b = &t[..m]; + + for (a,b) in reduced.cursor().zip(b.iter()) { + if a != *b { + return CompareResult::Error; + } + } + if m < blen { + CompareResult::Incomplete + } else { + CompareResult::Ok + } + } + + + #[inline(always)] + fn compare_no_case(&self, t: &'b[u8]) -> CompareResult { + let len = self.end - self.start; + let blen = t.len(); + let m = if len < blen { len } else { blen }; + let reduced = self.slice(..m); + let other = &t[..m]; + + if !reduced.cursor().zip(other).all(|(a, b)| { + match (a,*b) { + (0...64, 0...64) | (91...96, 91...96) | (123...255, 123...255) => a == *b, + (65...90, 65...90) | (97...122, 97...122) | (65...90, 97...122 ) |(97...122, 65...90) => { + a & 0b01000000 == *b & 0b01000000 + } + _ => false + } + }) { + CompareResult::Error + } else if m < blen { + CompareResult::Incomplete + } else { + CompareResult::Ok + } + } +} + +impl<'a,'b> Compare<&'b str> for BlockSlice<'a> { + fn compare(&self, t: &'b str) -> CompareResult { + self.compare(str::as_bytes(t)) + } + fn compare_no_case(&self, t: &'b str) -> CompareResult { + self.compare_no_case(str::as_bytes(t)) + } +} + +//Wrapper to implement Iterator on BlockBufCursor +pub struct WrapCursor<'a> { + pub cursor: BlockBufCursor<'a>, + pub length: usize, +} + +impl<'a> Iterator for WrapCursor<'a> { + type Item = u8; + fn next(&mut self) -> Option<u8> { + //println!("NEXT: length={}, remaining={}", self.length, self.cursor.remaining()); + if min(self.length, self.cursor.remaining()) > 0 { + self.length -=1; + Some(self.cursor.read_u8()) + } else { + None + } + } +} + +//Reimplement eat_separator instead of fixing iterators +#[macro_export] +macro_rules! block_eat_separator ( + ($i:expr, $arr:expr) => ( + { + use nom::{InputLength,InputIter,Slice}; + if ($i).input_len() == 0 { + Ok(($i, ($i).slice(0..0))) + } else { + match ($i).iter_indices().position(|(_, item)| { + for (_,c) in ($arr).iter_indices() { + if *c == item { return false; } + } + true + }) { + Some(index) => { + Ok((($i).slice(index..), ($i).slice(..index))) + }, + None => { + Ok((($i).slice(($i).input_len()..), $i)) + } + } + } + } + ) +); + +#[macro_export] +macro_rules! block_named ( + ($name:ident, $submac:ident!( $($args:tt)* )) => ( + fn $name<'a>( i: BlockSlice<'a> ) -> nom::IResult<BlockSlice<'a>, BlockSlice<'a>, u32> { + $submac!(i, $($args)*) + } + ); + ($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => ( + fn $name<'a>( i: BlockSlice<'a> ) -> nom::IResult<BlockSlice<'a>, $o, u32> { + $submac!(i, $($args)*) + } + ); +); + +block_named!(sp, block_eat_separator!(&b" \t\r\n"[..])); + +macro_rules! block_ws ( + ($i:expr, $($args:tt)*) => ( + { + sep!($i, sp, $($args)*) + } + ) +); + +block_named!(digit, is_a!("0123456789")); + +block_named!(parens<i64>, block_ws!(delimited!( tag!("("), expr, tag!(")") )) ); + + +block_named!(factor<i64>, alt!( + map_res!( + block_ws!(digit), + to_i64 + ) + | parens + ) +); + +block_named!(term <i64>, do_parse!( + init: factor >> + res: fold_many0!( + pair!(alt!(tag!("*") | tag!("/")), factor), + init, + |acc, (op, val): (BlockSlice, i64)| { + if (op.cursor().next().unwrap() as char) == '*' { acc * val } else { acc / val } + } + ) >> + (res) + ) +); + +block_named!(expr <i64>, do_parse!( + init: term >> + res: fold_many0!( + pair!(alt!(tag!("+") | tag!("-")), term), + init, + |acc, (op, val): (BlockSlice, i64)| { + if (op.cursor().next().unwrap() as char) == '+' { acc + val } else { acc - val } + } + ) >> + (res) + ) +); + + +fn blockbuf_from(input: &[u8]) -> BlockBuf { + let mut b = BlockBuf::new(2, 100); + b.copy_from(input); + b +} + + +fn sl<'a>(input: &'a BlockBuf) -> BlockSlice<'a> { + BlockSlice { + buf: input, + start: 0, + end: input.len(), + } +} + +fn to_i64<'a>(input: BlockSlice<'a>) -> Result<i64, ()> { + let v: Vec<u8> = input.cursor().collect(); + + match str::from_utf8(&v) { + Err(_) => Err(()), + Ok(s) => match FromStr::from_str(s) { + Err(_) => Err(()), + Ok(i) => Ok(i) + } + } +} + +#[test] +fn factor_test() { + let a = blockbuf_from(&b"3"[..]); + println!("calculated: {:?}", factor(sl(&a))); +} + +#[test] +fn parens_test() { + let input1 = blockbuf_from(&b" 2* ( 3 + 4 ) "[..]); + println!("calculated 1: {:?}", expr(sl(&input1))); + let input2 = blockbuf_from(&b" 2*2 / ( 5 - 1) + 3"[..]); + println!("calculated 2: {:?}", expr(sl(&input2))); +} +*/ diff --git a/third_party/rust/nom/tests/css.rs b/third_party/rust/nom/tests/css.rs new file mode 100644 index 0000000000..0ce7e77b05 --- /dev/null +++ b/third_party/rust/nom/tests/css.rs @@ -0,0 +1,51 @@ +extern crate nom; + +use nom::IResult; +use nom::bytes::complete::{tag, take_while_m_n}; +use nom::combinator::map_res; +use nom::sequence::tuple; + +#[derive(Debug, PartialEq)] +pub struct Color { + pub red: u8, + pub green: u8, + pub blue: u8, +} + +fn from_hex(input: &str) -> Result<u8, std::num::ParseIntError> { + u8::from_str_radix(input, 16) +} + +fn is_hex_digit(c: char) -> bool { + c.is_digit(16) +} + +fn hex_primary(input: &str) -> IResult<&str, u8> { + map_res( + take_while_m_n(2, 2, is_hex_digit), + from_hex + )(input) +} + +fn hex_color(input: &str) -> IResult<&str, Color> { + let (input, _) = tag("#")(input)?; + let (input, (red, green, blue)) = tuple((hex_primary, hex_primary, hex_primary))(input)?; + + Ok((input, Color { red, green, blue })) +} + + +#[test] +fn parse_color() { + assert_eq!( + hex_color("#2F14DF"), + Ok(( + "", + Color { + red: 47, + green: 20, + blue: 223, + } + )) + ); +} diff --git a/third_party/rust/nom/tests/custom_errors.rs b/third_party/rust/nom/tests/custom_errors.rs new file mode 100644 index 0000000000..89366dc9e1 --- /dev/null +++ b/third_party/rust/nom/tests/custom_errors.rs @@ -0,0 +1,53 @@ +#![allow(dead_code)] +#![cfg_attr(feature = "cargo-clippy", allow(block_in_if_condition_stmt))] + +#[macro_use] +extern crate nom; + +use nom::IResult; +use nom::error::{ErrorKind,ParseError}; +use nom::character::streaming::digit1 as digit; + +use std::convert::From; + +#[derive(Debug)] +pub struct CustomError(String); + +impl<'a> From<(&'a str, ErrorKind)> for CustomError { + fn from(error: (&'a str, ErrorKind)) -> Self { + CustomError(format!("error code was: {:?}", error)) + } +} + +impl<'a> ParseError<&'a str> for CustomError { + fn from_error_kind(_: &'a str, kind: ErrorKind) -> Self { + CustomError(format!("error code was: {:?}", kind)) + } + + fn append(_: &'a str, kind: ErrorKind, other: CustomError) -> Self { + CustomError(format!("{:?}\nerror code was: {:?}", other, kind)) + + } + +} + +fn test1(input: &str) -> IResult<&str, &str, CustomError> { + //fix_error!(input, CustomError, tag!("abcd")) + tag!(input, "abcd") +} + +fn test2(input: &str) -> IResult<&str, &str, CustomError> { + //terminated!(input, test1, fix_error!(CustomError, digit)) + terminated!(input, test1, digit) +} + +fn test3(input: &str) -> IResult<&str, &str, CustomError> { + verify!(input, test1, |s: &str| { + s.starts_with("abcd") + }) +} + +#[cfg(feature = "alloc")] +fn test4(input: &str) -> IResult<&str, Vec<&str>, CustomError> { + count!(input, test1, 4) +} diff --git a/third_party/rust/nom/tests/escaped.rs b/third_party/rust/nom/tests/escaped.rs new file mode 100644 index 0000000000..19c1ed70a4 --- /dev/null +++ b/third_party/rust/nom/tests/escaped.rs @@ -0,0 +1,25 @@ +use nom::{Err, error::ErrorKind, IResult}; +use nom::character::complete::digit1; +use nom::bytes::complete::escaped; +use nom::character::complete::one_of; + +fn esc(s: &str) -> IResult<&str, &str> { + escaped(digit1, '\\', one_of("\"n\\"))(s) +} + +#[cfg(feature="alloc")] +fn esc_trans(s: &str) -> IResult<&str, String> { + use nom::bytes::complete::{escaped_transform, tag}; + escaped_transform(digit1, '\\', |i: &str| tag("n")(i))(s) +} + +#[test] +fn test_escaped() { + assert_eq!(esc("abcd"), Err(Err::Error(("abcd", ErrorKind::Escaped)))); +} + +#[test] +#[cfg(feature="alloc")] +fn test_escaped_transform() { + assert_eq!(esc_trans("abcd"), Err(Err::Error(("abcd", ErrorKind::EscapedTransform)))); +} diff --git a/third_party/rust/nom/tests/float.rs b/third_party/rust/nom/tests/float.rs new file mode 100644 index 0000000000..eb82804f29 --- /dev/null +++ b/third_party/rust/nom/tests/float.rs @@ -0,0 +1,46 @@ +#[macro_use] +extern crate nom; + +use nom::character::streaming::digit1 as digit; + +use std::str; +use std::str::FromStr; + +named!( + unsigned_float<f32>, + map_res!( + map_res!( + recognize!(alt!( + delimited!(digit, tag!("."), opt!(digit)) | delimited!(opt!(digit), tag!("."), digit) + )), + str::from_utf8 + ), + FromStr::from_str + ) +); + +named!( + float<f32>, + map!( + pair!(opt!(alt!(tag!("+") | tag!("-"))), unsigned_float), + |(sign, value): (Option<&[u8]>, f32)| sign + .and_then(|s| if s[0] == b'-' { Some(-1f32) } else { None }) + .unwrap_or(1f32) * value + ) +); + +#[test] +fn unsigned_float_test() { + assert_eq!(unsigned_float(&b"123.456;"[..]), Ok((&b";"[..], 123.456))); + assert_eq!(unsigned_float(&b"0.123;"[..]), Ok((&b";"[..], 0.123))); + assert_eq!(unsigned_float(&b"123.0;"[..]), Ok((&b";"[..], 123.0))); + assert_eq!(unsigned_float(&b"123.;"[..]), Ok((&b";"[..], 123.0))); + assert_eq!(unsigned_float(&b".123;"[..]), Ok((&b";"[..], 0.123))); +} + +#[test] +fn float_test() { + assert_eq!(float(&b"123.456;"[..]), Ok((&b";"[..], 123.456))); + assert_eq!(float(&b"+123.456;"[..]), Ok((&b";"[..], 123.456))); + assert_eq!(float(&b"-123.456;"[..]), Ok((&b";"[..], -123.456))); +} diff --git a/third_party/rust/nom/tests/inference.rs b/third_party/rust/nom/tests/inference.rs new file mode 100644 index 0000000000..851c1382c9 --- /dev/null +++ b/third_party/rust/nom/tests/inference.rs @@ -0,0 +1,53 @@ +//! test type inference issues in parsee compilation +//#![feature(trace_macros)] +#![allow(dead_code)] +#![allow(unused_comparisons)] +#![allow(unused_variables)] +#![allow(unused_imports)] + +#[macro_use] +extern crate nom; + +use std::str; +use nom::character::{streaming::alpha1 as alpha, is_digit}; + +// issue #617 +named!(multi<&[u8], () >, fold_many0!( take_while1!( is_digit ), (), |_, _| {})); + +// issue #561 +#[cfg(feature = "alloc")] +named!( + value<Vec<Vec<&str>>>, + do_parse!( + first_line: map_res!(is_not!("\n"), std::str::from_utf8) + >> rest: + many_m_n!( + 0, + 1, + separated_list!( + tag!("\n\t"), + map_res!(take_while!(call!(|c| c != b'\n')), std::str::from_utf8) + ) + ) >> (rest) + ) +); + +// issue #534 +#[cfg(feature = "alloc")] +fn wrap_suffix(input: &Option<Vec<&[u8]>>) -> Option<String> { + if input.is_some() { + // I've tried both of the lines below individually and get the same error. + Some("hello".to_string()) + //Some(str::from_utf8(u).expect("Found invalid UTF-8").to_string()) + } else { + None + } +} + +#[cfg(feature = "alloc")] +named!(parse_suffix<&[u8],Option<String>>,do_parse!( + u: opt!(many1!(alt!( + complete!(tag!("%")) | complete!(tag!("#")) | complete!(tag!("@")) | complete!(alpha) + ))) >> + (wrap_suffix(&u)) +)); diff --git a/third_party/rust/nom/tests/ini.rs b/third_party/rust/nom/tests/ini.rs new file mode 100644 index 0000000000..c3f9b750d7 --- /dev/null +++ b/third_party/rust/nom/tests/ini.rs @@ -0,0 +1,221 @@ +#[macro_use] +extern crate nom; + +use nom::{ + IResult, + bytes::complete::take_while, + sequence::delimited, + combinator::map_res, + character::complete::{char, alphanumeric1 as alphanumeric, multispace0 as multispace, space0 as space} +}; + +use std::str; +use std::collections::HashMap; + +fn category(i: &[u8]) -> IResult<&[u8], &str> { + map_res(delimited(char('['), take_while(|c| c != b']'), char(']')), str::from_utf8)(i) +} + +fn complete_byte_slice_to_str<'a>(s: &'a[u8]) -> Result<&'a str, str::Utf8Error> { + str::from_utf8(s) +} + +named!(key_value <&[u8],(&str,&str)>, + do_parse!( + key: map_res!(alphanumeric, complete_byte_slice_to_str) + >> opt!(space) + >> char!('=') + >> opt!(space) + >> val: map_res!( + take_while!(call!(|c| c != b'\n' && c != b';')), + complete_byte_slice_to_str + ) + >> opt!(pair!(char!(';'), take_while!(call!(|c| c != b'\n')))) + >> (key, val) + ) +); + +named!(keys_and_values<&[u8], HashMap<&str, &str> >, + map!( + many0!(terminated!(key_value, opt!(multispace))), + |vec: Vec<_>| vec.into_iter().collect() + ) +); + +named!(category_and_keys<&[u8],(&str,HashMap<&str,&str>)>, + do_parse!( + category: category >> + opt!(multispace) >> + keys: keys_and_values >> + (category, keys) + ) +); + +named!(categories<&[u8], HashMap<&str, HashMap<&str,&str> > >, + map!( + many0!( + separated_pair!( + category, + opt!(multispace), + map!( + many0!(terminated!(key_value, opt!(multispace))), + |vec: Vec<_>| vec.into_iter().collect() + ) + ) + ), + |vec: Vec<_>| vec.into_iter().collect() + ) +); + +#[test] +fn parse_category_test() { + let ini_file = &b"[category] + +parameter=value +key = value2"[..]; + + let ini_without_category = &b"\n\nparameter=value +key = value2"[..]; + + let res = category(ini_file); + println!("{:?}", res); + match res { + Ok((i, o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o), + _ => println!("error"), + } + + assert_eq!(res, Ok((ini_without_category, "category"))); +} + +#[test] +fn parse_key_value_test() { + let ini_file = &b"parameter=value +key = value2"[..]; + + let ini_without_key_value = &b"\nkey = value2"[..]; + + let res = key_value(ini_file); + println!("{:?}", res); + match res { + Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2), + _ => println!("error"), + } + + assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); +} + +#[test] +fn parse_key_value_with_space_test() { + let ini_file = &b"parameter = value +key = value2"[..]; + + let ini_without_key_value = &b"\nkey = value2"[..]; + + let res = key_value(ini_file); + println!("{:?}", res); + match res { + Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2), + _ => println!("error"), + } + + assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); +} + +#[test] +fn parse_key_value_with_comment_test() { + let ini_file = &b"parameter=value;abc +key = value2"[..]; + + let ini_without_key_value = &b"\nkey = value2"[..]; + + let res = key_value(ini_file); + println!("{:?}", res); + match res { + Ok((i, (o1, o2))) => println!("i: {:?} | o: ({:?},{:?})", str::from_utf8(i), o1, o2), + _ => println!("error"), + } + + assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); +} + +#[test] +fn parse_multiple_keys_and_values_test() { + let ini_file = &b"parameter=value;abc + +key = value2 + +[category]"[..]; + + let ini_without_key_value = &b"[category]"[..]; + + let res = keys_and_values(ini_file); + println!("{:?}", res); + match res { + Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o), + _ => println!("error"), + } + + let mut expected: HashMap<&str, &str> = HashMap::new(); + expected.insert("parameter", "value"); + expected.insert("key", "value2"); + assert_eq!(res, Ok((ini_without_key_value, expected))); +} + +#[test] +fn parse_category_then_multiple_keys_and_values_test() { + //FIXME: there can be an empty line or a comment line after a category + let ini_file = &b"[abcd] +parameter=value;abc + +key = value2 + +[category]"[..]; + + let ini_after_parser = &b"[category]"[..]; + + let res = category_and_keys(ini_file); + println!("{:?}", res); + match res { + Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o), + _ => println!("error"), + } + + let mut expected_h: HashMap<&str, &str> = HashMap::new(); + expected_h.insert("parameter", "value"); + expected_h.insert("key", "value2"); + assert_eq!(res, Ok((ini_after_parser, ("abcd", expected_h)))); +} + +#[test] +fn parse_multiple_categories_test() { + let ini_file = &b"[abcd] + +parameter=value;abc + +key = value2 + +[category] +parameter3=value3 +key4 = value4 +"[..]; + + let ini_after_parser = &b""[..]; + + let res = categories(ini_file); + //println!("{:?}", res); + match res { + Ok((i, ref o)) => println!("i: {:?} | o: {:?}", str::from_utf8(i), o), + _ => println!("error"), + } + + let mut expected_1: HashMap<&str, &str> = HashMap::new(); + expected_1.insert("parameter", "value"); + expected_1.insert("key", "value2"); + let mut expected_2: HashMap<&str, &str> = HashMap::new(); + expected_2.insert("parameter3", "value3"); + expected_2.insert("key4", "value4"); + let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); + expected_h.insert("abcd", expected_1); + expected_h.insert("category", expected_2); + assert_eq!(res, Ok((ini_after_parser, expected_h))); +} diff --git a/third_party/rust/nom/tests/ini_str.rs b/third_party/rust/nom/tests/ini_str.rs new file mode 100644 index 0000000000..d778918c40 --- /dev/null +++ b/third_party/rust/nom/tests/ini_str.rs @@ -0,0 +1,215 @@ +#[macro_use] +extern crate nom; + +use nom::{ + IResult, + combinator::opt, + bytes::complete::{take_while, is_a}, + sequence::{delimited, terminated}, + character::complete::{char, alphanumeric1 as alphanumeric, space0 as space} +}; + +use std::collections::HashMap; + +fn is_line_ending_or_comment(chr: char) -> bool { + chr == ';' || chr == '\n' +} + +fn not_line_ending(i: &str) -> IResult<&str, &str> { + take_while(|c| c != '\r' && c != '\n')(i) +} + +fn space_or_line_ending(i: &str) -> IResult<&str, &str> { + is_a(" \r\n")(i) +} + +fn category(i: &str) -> IResult<&str, &str> { + terminated(delimited(char('['), take_while(|c| c != ']'), char(']')), opt(is_a(" \r\n")))(i) +} + +named!(key_value <&str,(&str,&str)>, + do_parse!( + key: alphanumeric >> + opt!(space) >> + tag!("=") >> + opt!(space) >> + val: take_till!(is_line_ending_or_comment) >> + opt!(space) >> + opt!(pair!(tag!(";"), not_line_ending)) >> + opt!(space_or_line_ending) >> + (key, val) + ) +); + +named!(keys_and_values_aggregator<&str, Vec<(&str, &str)> >, many0!(key_value)); + +fn keys_and_values(input: &str) -> IResult<&str, HashMap<&str, &str>> { + match keys_and_values_aggregator(input) { + Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())), + Err(e) => Err(e), + } +} + +named!(category_and_keys<&str,(&str,HashMap<&str,&str>)>, + pair!(category, keys_and_values) +); + +named!(categories_aggregator<&str, Vec<(&str, HashMap<&str,&str>)> >, many0!(category_and_keys)); + +fn categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str>>> { + match categories_aggregator(input) { + Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())), + Err(e) => Err(e), + } +} + +#[test] +fn parse_category_test() { + let ini_file = "[category] + +parameter=value +key = value2"; + + let ini_without_category = "parameter=value +key = value2"; + + let res = category(ini_file); + println!("{:?}", res); + match res { + Ok((i, o)) => println!("i: {} | o: {:?}", i, o), + _ => println!("error"), + } + + assert_eq!(res, Ok((ini_without_category, "category"))); +} + +#[test] +fn parse_key_value_test() { + let ini_file = "parameter=value +key = value2"; + + let ini_without_key_value = "key = value2"; + + let res = key_value(ini_file); + println!("{:?}", res); + match res { + Ok((i, (o1, o2))) => println!("i: {} | o: ({:?},{:?})", i, o1, o2), + _ => println!("error"), + } + + assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); +} + +#[test] +fn parse_key_value_with_space_test() { + let ini_file = "parameter = value +key = value2"; + + let ini_without_key_value = "key = value2"; + + let res = key_value(ini_file); + println!("{:?}", res); + match res { + Ok((i, (o1, o2))) => println!("i: {} | o: ({:?},{:?})", i, o1, o2), + _ => println!("error"), + } + + assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); +} + +#[test] +fn parse_key_value_with_comment_test() { + let ini_file = "parameter=value;abc +key = value2"; + + let ini_without_key_value = "key = value2"; + + let res = key_value(ini_file); + println!("{:?}", res); + match res { + Ok((i, (o1, o2))) => println!("i: {} | o: ({:?},{:?})", i, o1, o2), + _ => println!("error"), + } + + assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); +} + +#[test] +fn parse_multiple_keys_and_values_test() { + let ini_file = "parameter=value;abc + +key = value2 + +[category]"; + + let ini_without_key_value = "[category]"; + + let res = keys_and_values(ini_file); + println!("{:?}", res); + match res { + Ok((i, ref o)) => println!("i: {} | o: {:?}", i, o), + _ => println!("error"), + } + + let mut expected: HashMap<&str, &str> = HashMap::new(); + expected.insert("parameter", "value"); + expected.insert("key", "value2"); + assert_eq!(res, Ok((ini_without_key_value, expected))); +} + +#[test] +fn parse_category_then_multiple_keys_and_values_test() { + //FIXME: there can be an empty line or a comment line after a category + let ini_file = "[abcd] +parameter=value;abc + +key = value2 + +[category]"; + + let ini_after_parser = "[category]"; + + let res = category_and_keys(ini_file); + println!("{:?}", res); + match res { + Ok((i, ref o)) => println!("i: {} | o: {:?}", i, o), + _ => println!("error"), + } + + let mut expected_h: HashMap<&str, &str> = HashMap::new(); + expected_h.insert("parameter", "value"); + expected_h.insert("key", "value2"); + assert_eq!(res, Ok((ini_after_parser, ("abcd", expected_h)))); +} + +#[test] +fn parse_multiple_categories_test() { + let ini_file = "[abcd] + +parameter=value;abc + +key = value2 + +[category] +parameter3=value3 +key4 = value4 +"; + + let res = categories(ini_file); + //println!("{:?}", res); + match res { + Ok((i, ref o)) => println!("i: {} | o: {:?}", i, o), + _ => println!("error"), + } + + let mut expected_1: HashMap<&str, &str> = HashMap::new(); + expected_1.insert("parameter", "value"); + expected_1.insert("key", "value2"); + let mut expected_2: HashMap<&str, &str> = HashMap::new(); + expected_2.insert("parameter3", "value3"); + expected_2.insert("key4", "value4"); + let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); + expected_h.insert("abcd", expected_1); + expected_h.insert("category", expected_2); + assert_eq!(res, Ok(("", expected_h))); +} diff --git a/third_party/rust/nom/tests/issues.rs b/third_party/rust/nom/tests/issues.rs new file mode 100644 index 0000000000..62a1a01bc5 --- /dev/null +++ b/third_party/rust/nom/tests/issues.rs @@ -0,0 +1,318 @@ +//#![feature(trace_macros)] +#![allow(dead_code)] +#![cfg_attr(feature = "cargo-clippy", allow(redundant_closure))] + +#[macro_use] +extern crate nom; + +use nom::{character::{is_digit, streaming::space1 as space}, Err, IResult, Needed, error::ErrorKind, number::streaming::le_u64}; + +#[allow(dead_code)] +struct Range { + start: char, + end: char, +} + +pub fn take_char(input: &[u8]) -> IResult<&[u8], char> { + if !input.is_empty() { + Ok((&input[1..], input[0] as char)) + } else { + Err(Err::Incomplete(Needed::Size(1))) + } +} + +//trace_macros!(true); + +#[allow(dead_code)] +named!(range<&[u8], Range>, + alt!( + do_parse!( + start: take_char >> + tag!("-") >> + end: take_char >> + (Range { + start: start, + end: end, + }) + ) | + map!( + take_char, + |c| { + Range { + start: c, + end: c, + } + } + ) + ) +); + +#[allow(dead_code)] +named!(literal<&[u8], Vec<char> >, + map!( + many1!(take_char), + |cs| { + cs + } + ) +); + +#[test] +fn issue_58() { + let _ = range(&b"abcd"[..]); + let _ = literal(&b"abcd"[..]); +} + +//trace_macros!(false); + +#[cfg(feature = "std")] +mod parse_int { + use nom::HexDisplay; + use nom::{IResult, character::streaming::{digit1 as digit, space1 as space}}; + use std::str; + + named!(parse_ints<Vec<i32>>, many0!(spaces_or_int)); + + fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32> { + println!("{}", input.to_hex(8)); + do_parse!( + input, + opt!(complete!(space)) >> res: map!(complete!(digit), |x| { + println!("x: {:?}", x); + let result = str::from_utf8(x).unwrap(); + println!("Result: {}", result); + println!("int is empty?: {}", x.is_empty()); + match result.parse() { + Ok(i) => i, + Err(e) => panic!("UH OH! NOT A DIGIT! {:?}", e), + } + }) >> (res) + ) + } + + #[test] + fn issue_142() { + let subject = parse_ints(&b"12 34 5689a"[..]); + let expected = Ok((&b"a"[..], vec![12, 34, 5689])); + assert_eq!(subject, expected); + + let subject = parse_ints(&b"12 34 5689 "[..]); + let expected = Ok((&b" "[..], vec![12, 34, 5689])); + assert_eq!(subject, expected) + } +} + +#[test] +fn usize_length_bytes_issue() { + use nom::number::streaming::be_u16; + let _: IResult<&[u8], &[u8], (&[u8], ErrorKind)> = length_data!(b"012346", be_u16); +} + +/* + DOES NOT COMPILE +#[test] +fn issue_152() { + named!(take4, take!(4)); + named!(xyz, tag!("XYZ")); + named!(abc, tag!("abc")); + + + named!(sw, + switch!(take4, + b"abcd" => xyz | + b"efgh" => abc + ) + ); +} +*/ + +#[test] +fn take_till_issue() { + named!(nothing, take_till!(call!(|_| true))); + + assert_eq!(nothing(b""), Err(Err::Incomplete(Needed::Size(1)))); + assert_eq!(nothing(b"abc"), Ok((&b"abc"[..], &b""[..]))); +} + +named!( + issue_498<Vec<&[u8]>>, + separated_nonempty_list!(opt!(space), tag!("abcd")) +); + +named!(issue_308(&str) -> bool, + do_parse! ( + tag! ("foo") >> + b: alt! ( + complete!(map! (tag! ("1"), |_: &str|->bool {true})) | + value! (false) + ) >> + (b) )); + +#[cfg(feature = "alloc")] +fn issue_302(input: &[u8]) -> IResult<&[u8], Option<Vec<u64>>> { + do_parse!(input, entries: cond!(true, count!(le_u64, 3)) >> (entries)) +} + +#[test] +fn issue_655() { + use nom::character::streaming::{line_ending, not_line_ending}; + named!(twolines(&str) -> (&str, &str), + do_parse!( + l1 : not_line_ending >> + line_ending >> + l2 : not_line_ending >> + line_ending >> + ((l1, l2)) + ) + ); + + assert_eq!(twolines("foo\nbar\n"), Ok(("", ("foo", "bar")))); + assert_eq!(twolines("féo\nbar\n"), Ok(("", ("féo", "bar")))); + assert_eq!(twolines("foé\nbar\n"), Ok(("", ("foé", "bar")))); + assert_eq!(twolines("foé\r\nbar\n"), Ok(("", ("foé", "bar")))); +} + +#[test] +fn issue_721() { + named!(f1<&str, u16>, parse_to!(u16)); + named!(f2<&str, String>, parse_to!(String)); + assert_eq!(f1("1234"), Ok(("", 1234))); + assert_eq!(f2("foo"), Ok(("", "foo".to_string()))); + //assert_eq!(parse_to!("1234", u16), Ok(("", 1234))); + //assert_eq!(parse_to!("foo", String), Ok(("", "foo".to_string()))); +} + +#[cfg(feature = "alloc")] +named!(issue_717<&[u8], Vec<&[u8]> >, + separated_list!(tag!([0x0]), is_not!([0x0u8])) +); + +struct NoPartialEq { + value: i32, +} + +named!(issue_724<&str, i32>, + do_parse!( + metadata: permutation!( + map!(tag!("hello"), |_| NoPartialEq { value: 1 }), + map!(tag!("world"), |_| NoPartialEq { value: 2 }) + ) >> + (metadata.0.value + metadata.1.value) + ) +); + +#[test] +fn issue_752() { + assert_eq!( + Err::Error(("ab", nom::error::ErrorKind::ParseTo)), + parse_to!("ab", usize).unwrap_err() + ) +} + +fn atom_specials(c: u8) -> bool { + c == b'q' +} + +named!( + capability<&str>, + do_parse!(tag!(" ") >> _atom: map_res!(take_till1!(atom_specials), std::str::from_utf8) >> ("a")) +); + +#[test] +fn issue_759() { + assert_eq!(capability(b" abcqd"), Ok((&b"qd"[..], "a"))); +} + +named_args!(issue_771(count: usize)<Vec<u32>>, + length_count!(value!(count), call!(nom::number::streaming::be_u32)) +); + +/// This test is in a separate module to check that all required symbols are imported in +/// `escaped_transform!()`. Without the module, the `use`-es of the current module would +/// mask the error ('"Use of undeclared type or module `Needed`" in escaped_transform!'). +mod issue_780 { + named!(issue_780<&str, String>, + escaped_transform!(call!(::nom::character::streaming::alpha1), '\\', tag!("n")) + ); +} + +// issue 617 +named!(digits, take_while1!( is_digit )); +named!(multi_617<&[u8], () >, fold_many0!( digits, (), |_, _| {})); + +// Sad :( +named!(multi_617_fails<&[u8], () >, fold_many0!( take_while1!( is_digit ), (), |_, _| {})); + +mod issue_647 { + use nom::{Err, number::streaming::be_f64, error::ErrorKind}; + pub type Input<'a> = &'a [u8]; + + #[derive(PartialEq, Debug, Clone)] + struct Data { + c: f64, + v: Vec<f64> + } + + fn list<'a,'b>(input: Input<'a>, _cs: &'b f64) -> Result<(Input<'a>,Vec<f64>), Err<(&'a [u8], ErrorKind)>> { + separated_list!(input, complete!(tag!(",")), complete!(be_f64)) + } + + named!(data<Input,Data>, map!( + do_parse!( + c: be_f64 >> + tag!("\n") >> + v: call!(list,&c) >> + (c,v) + ), |(c,v)| { + Data { + c: c, + v: v + } + } + )); +} + +named!(issue_775, take_till1!(|_| true)); + +#[test] +fn issue_848_overflow_incomplete_bits_to_bytes() { + named!(take, take!(0x2000000000000000)); + named!(parser<&[u8], &[u8]>, bits!(bytes!(take))); + assert_eq!(parser(&b""[..]), Err(Err::Failure(error_position!(&b""[..], ErrorKind::TooLarge)))); +} + +#[test] +fn issue_942() { + use nom::error::ParseError; + pub fn parser<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, usize, E> { + use nom::{character::complete::char, error::context, multi::many0_count}; + many0_count(context("char_a", char('a')))(i) + } + assert_eq!(parser::<()>("aaa"), Ok(("", 3))); +} + +#[test] +fn issue_many_m_n_with_zeros() { + use nom::multi::many_m_n; + use nom::character::complete::char; + let parser = many_m_n::<_, _, (), _>(0, 0, char('a')); + assert_eq!(parser("aaa"), Ok(("aaa", vec!()))); +} + +#[test] +fn issue_1027_convert_error_panic_nonempty() { + use nom::error::{VerboseError, convert_error}; + use nom::sequence::pair; + use nom::character::complete::char; + + let input = "a"; + + let result: IResult<_, _, VerboseError<&str>> = pair(char('a'), char('b'))(input); + let err = match result.unwrap_err() { + Err::Error(e) => e, + _ => unreachable!(), + }; + + let msg = convert_error(&input, err); + assert_eq!(msg, "0: at line 1:\na\n ^\nexpected \'b\', got end of input\n\n"); +} diff --git a/third_party/rust/nom/tests/json.rs b/third_party/rust/nom/tests/json.rs new file mode 100644 index 0000000000..14329a16ae --- /dev/null +++ b/third_party/rust/nom/tests/json.rs @@ -0,0 +1,105 @@ +#![cfg(feature = "alloc")] +//#![feature(trace_macros)] + +#[macro_use] +extern crate nom; + +use nom::{character::is_alphanumeric, number::complete::recognize_float}; + +use std::str; +use std::collections::HashMap; + +#[derive(Debug, PartialEq)] +pub enum JsonValue { + Str(String), + Num(f32), + Array(Vec<JsonValue>), + Object(HashMap<String, JsonValue>), +} + +named!(float<f32>, flat_map!(recognize_float, parse_to!(f32))); + +//FIXME: verify how json strings are formatted +named!( + string<&str>, + delimited!( + char!('"'), + //map_res!(escaped!(call!(alphanumeric), '\\', is_a!("\"n\\")), str::from_utf8), + map_res!( + escaped!(take_while1!(is_alphanumeric), '\\', one_of!("\"n\\")), + str::from_utf8 + ), + char!('"') + ) +); + +named!( + array<Vec<JsonValue>>, + ws!(delimited!( + char!('['), + separated_list!(char!(','), value), + char!(']') + )) +); + +named!( + key_value<(&str, JsonValue)>, + ws!(separated_pair!(string, char!(':'), value)) +); + +named!( + hash<HashMap<String, JsonValue>>, + ws!(map!( + delimited!(char!('{'), separated_list!(char!(','), key_value), char!('}')), + |tuple_vec| { + let mut h: HashMap<String, JsonValue> = HashMap::new(); + for (k, v) in tuple_vec { + h.insert(String::from(k), v); + } + h + } + )) +); + +named!( + value<JsonValue>, + ws!(alt!( + hash => { |h| JsonValue::Object(h) } | + array => { |v| JsonValue::Array(v) } | + string => { |s| JsonValue::Str(String::from(s)) } | + float => { |num| JsonValue::Num(num) } + )) +); + +#[test] +fn json_object() { + let input = + r#"{ + "a": 42, + "b": "x" + }\0"#; + + let mut expected_map = HashMap::new(); + expected_map.insert(String::from("a"), JsonValue::Num(42f32)); + expected_map.insert(String::from("b"), JsonValue::Str(String::from("x"))); + let expected = JsonValue::Object(expected_map); + + assert_eq!(expected, value(input.as_bytes()).unwrap().1); +} + +#[test] +fn json_array() { + let input = + r#"[ + 42, + "x" + ]\0"#; + + let expected_vec = vec![ + JsonValue::Num(42f32), + JsonValue::Str(String::from("x")) + ]; + let expected = JsonValue::Array(expected_vec); + + assert_eq!(expected, value(input.as_bytes()).unwrap().1); +} diff --git a/third_party/rust/nom/tests/mp4.rs b/third_party/rust/nom/tests/mp4.rs new file mode 100644 index 0000000000..1432621611 --- /dev/null +++ b/third_party/rust/nom/tests/mp4.rs @@ -0,0 +1,319 @@ +#![allow(dead_code)] + +#[macro_use] +extern crate nom; + +use nom::{ + IResult, Needed, Err, + error::ErrorKind, + number::streaming::{be_u16, be_u32, be_u64, be_f32} +}; + +use std::str; + +fn mp4_box(input: &[u8]) -> IResult<&[u8], &[u8]> { + match be_u32(input) { + Ok((i, offset)) => { + let sz: usize = offset as usize; + if i.len() >= sz - 4 { + Ok((&i[(sz - 4)..], &i[0..(sz - 4)])) + } else { + Err(Err::Incomplete(Needed::Size(offset as usize + 4))) + } + } + Err(e) => Err(e), + } +} + +#[cfg_attr(rustfmt, rustfmt_skip)] +#[derive(PartialEq,Eq,Debug)] +struct FileType<'a> { + major_brand: &'a str, + major_brand_version: &'a [u8], + compatible_brands: Vec<&'a str> +} + +#[cfg_attr(rustfmt, rustfmt_skip)] +#[allow(non_snake_case)] +#[derive(Debug,Clone)] +pub struct Mvhd32 { + version_flags: u32, // actually: + // version: u8, + // flags: u24 // 3 bytes + created_date: u32, + modified_date: u32, + scale: u32, + duration: u32, + speed: f32, + volume: u16, // actually a 2 bytes decimal + /* 10 bytes reserved */ + scaleA: f32, + rotateB: f32, + angleU: f32, + rotateC: f32, + scaleD: f32, + angleV: f32, + positionX: f32, + positionY: f32, + scaleW: f32, + preview: u64, + poster: u32, + selection: u64, + current_time: u32, + track_id: u32 +} + +#[cfg_attr(rustfmt, rustfmt_skip)] +#[allow(non_snake_case)] +#[derive(Debug,Clone)] +pub struct Mvhd64 { + version_flags: u32, // actually: + // version: u8, + // flags: u24 // 3 bytes + created_date: u64, + modified_date: u64, + scale: u32, + duration: u64, + speed: f32, + volume: u16, // actually a 2 bytes decimal + /* 10 bytes reserved */ + scaleA: f32, + rotateB: f32, + angleU: f32, + rotateC: f32, + scaleD: f32, + angleV: f32, + positionX: f32, + positionY: f32, + scaleW: f32, + preview: u64, + poster: u32, + selection: u64, + current_time: u32, + track_id: u32 +} + +#[allow(non_snake_case)] +named!(mvhd32 <&[u8], MvhdBox>, + do_parse!( + version_flags: be_u32 >> + created_date: be_u32 >> + modified_date: be_u32 >> + scale: be_u32 >> + duration: be_u32 >> + speed: be_f32 >> + volume: be_u16 >> // actually a 2 bytes decimal + take!(10) >> + scale_a: be_f32 >> + rotate_b: be_f32 >> + angle_u: be_f32 >> + rotate_c: be_f32 >> + scale_d: be_f32 >> + angle_v: be_f32 >> + position_x: be_f32 >> + position_y: be_f32 >> + scale_w: be_f32 >> + preview: be_u64 >> + poster: be_u32 >> + selection: be_u64 >> + current_time: be_u32 >> + track_id: be_u32 >> + ( + MvhdBox::M32(Mvhd32 { + version_flags: version_flags, + created_date: created_date, + modified_date: modified_date, + scale: scale, + duration: duration, + speed: speed, + volume: volume, + scaleA: scale_a, + rotateB: rotate_b, + angleU: angle_u, + rotateC: rotate_c, + scaleD: scale_d, + angleV: angle_v, + positionX: position_x, + positionY: position_y, + scaleW: scale_w, + preview: preview, + poster: poster, + selection: selection, + current_time: current_time, + track_id: track_id + }) + )) +); + +#[allow(non_snake_case)] +named!(mvhd64 <&[u8], MvhdBox>, + do_parse!( + version_flags: be_u32 >> + created_date: be_u64 >> + modified_date: be_u64 >> + scale: be_u32 >> + duration: be_u64 >> + speed: be_f32 >> + volume: be_u16 >> // actually a 2 bytes decimal + take!(10) >> + scale_a: be_f32 >> + rotate_b: be_f32 >> + angle_u: be_f32 >> + rotate_c: be_f32 >> + scale_d: be_f32 >> + angle_v: be_f32 >> + position_x: be_f32 >> + position_y: be_f32 >> + scale_w: be_f32 >> + preview: be_u64 >> + poster: be_u32 >> + selection: be_u64 >> + current_time: be_u32 >> + track_id: be_u32 >> + ( + MvhdBox::M64(Mvhd64 { + version_flags: version_flags, + created_date: created_date, + modified_date: modified_date, + scale: scale, + duration: duration, + speed: speed, + volume: volume, + scaleA: scale_a, + rotateB: rotate_b, + angleU: angle_u, + rotateC: rotate_c, + scaleD: scale_d, + angleV: angle_v, + positionX: position_x, + positionY: position_y, + scaleW: scale_w, + preview: preview, + poster: poster, + selection: selection, + current_time: current_time, + track_id: track_id + }) + )) +); + +#[derive(Debug, Clone)] +pub enum MvhdBox { + M32(Mvhd32), + M64(Mvhd64), +} + +#[derive(Debug, Clone)] +pub enum MoovBox { + Mdra, + Dref, + Cmov, + Rmra, + Iods, + Mvhd(MvhdBox), + Clip, + Trak, + Udta, +} + +#[derive(Debug)] +enum MP4BoxType { + Ftyp, + Moov, + Mdat, + Free, + Skip, + Wide, + Mdra, + Dref, + Cmov, + Rmra, + Iods, + Mvhd, + Clip, + Trak, + Udta, + Unknown, +} + +#[derive(Debug)] +struct MP4BoxHeader { + length: u32, + tag: MP4BoxType, +} + +named!(brand_name<&[u8],&str>, map_res!(take!(4), str::from_utf8)); + +named!(filetype_parser<&[u8], FileType>, + do_parse!( + m: brand_name >> + v: take!(4) >> + c: many0!(brand_name) >> + (FileType{ major_brand: m, major_brand_version:v, compatible_brands: c }) + ) +); + +fn mvhd_box(input: &[u8]) -> IResult<&[u8], MvhdBox> { + let res = if input.len() < 100 { + Err(Err::Incomplete(Needed::Size(100))) + } else if input.len() == 100 { + mvhd32(input) + } else if input.len() == 112 { + mvhd64(input) + } else { + Err(Err::Error(error_position!(input, ErrorKind::TooLarge))) + }; + println!("res: {:?}", res); + res +} + +fn unknown_box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType> { + Ok((input, MP4BoxType::Unknown)) +} + +//named!(box_type<&[u8], MP4BoxType>, +fn box_type(input: &[u8]) -> IResult<&[u8], MP4BoxType> { + alt!(input, + tag!("ftyp") => { |_| MP4BoxType::Ftyp } | + tag!("moov") => { |_| MP4BoxType::Moov } | + tag!("mdat") => { |_| MP4BoxType::Mdat } | + tag!("free") => { |_| MP4BoxType::Free } | + tag!("skip") => { |_| MP4BoxType::Skip } | + tag!("wide") => { |_| MP4BoxType::Wide } | + unknown_box_type + ) +} + +// warning, an alt combinator with 9 branches containing a tag combinator +// can make the compilation very slow. Use functions as sub parsers, +// or split into multiple alt! parsers if it gets slow +named!(moov_type<&[u8], MP4BoxType>, + alt!( + tag!("mdra") => { |_| MP4BoxType::Mdra } | + tag!("dref") => { |_| MP4BoxType::Dref } | + tag!("cmov") => { |_| MP4BoxType::Cmov } | + tag!("rmra") => { |_| MP4BoxType::Rmra } | + tag!("iods") => { |_| MP4BoxType::Iods } | + tag!("mvhd") => { |_| MP4BoxType::Mvhd } | + tag!("clip") => { |_| MP4BoxType::Clip } | + tag!("trak") => { |_| MP4BoxType::Trak } | + tag!("udta") => { |_| MP4BoxType::Udta } + ) +); + +named!(box_header<&[u8],MP4BoxHeader>, + do_parse!( + length: be_u32 >> + tag: box_type >> + (MP4BoxHeader{ length: length, tag: tag}) + ) +); + +named!(moov_header<&[u8],MP4BoxHeader>, + do_parse!( + length: be_u32 >> + tag: moov_type >> + (MP4BoxHeader{ length: length, tag: tag}) + ) +); + diff --git a/third_party/rust/nom/tests/multiline.rs b/third_party/rust/nom/tests/multiline.rs new file mode 100644 index 0000000000..cca19ecbad --- /dev/null +++ b/third_party/rust/nom/tests/multiline.rs @@ -0,0 +1,36 @@ +extern crate nom; + +use nom::{ + IResult, + multi::many0, + sequence::terminated, + character::complete::{alphanumeric1 as alphanumeric, line_ending as eol} +}; + +pub fn end_of_line(input: &str) -> IResult<&str, &str> { + if input.is_empty() { + Ok((input, input)) + } else { + eol(input) + } +} + +pub fn read_line(input: &str) -> IResult<&str, &str> { + terminated(alphanumeric, end_of_line)(input) +} + +pub fn read_lines(input: &str) -> IResult<&str, Vec<&str>> { + many0(read_line)(input) +} + +#[cfg(feature = "alloc")] +#[test] +fn read_lines_test() { + let res = Ok(( + "", + vec!["Duck", "Dog", "Cow"], + )); + + assert_eq!(read_lines("Duck\nDog\nCow\n"), res); + assert_eq!(read_lines("Duck\nDog\nCow"), res); +} diff --git a/third_party/rust/nom/tests/named_args.rs b/third_party/rust/nom/tests/named_args.rs new file mode 100644 index 0000000000..811b0a0dce --- /dev/null +++ b/third_party/rust/nom/tests/named_args.rs @@ -0,0 +1,161 @@ +#[macro_use] +extern crate nom; + +use nom::{ + branch::alt, + sequence::{delimited, pair, preceded}, + character::complete::{digit1 as digit, space0 as space}, + bytes::complete::tag +}; + +// Parser definition + +use std::str; +use std::str::FromStr; + +use self::Operator::*; + +enum Operator { + Slash, + Star, +} + +impl Operator { + fn to_str(&self) -> &'static str { + match *self { + Slash => "/", + Star => "*", + } + } +} + +// Parse the specified `Operator`. +named_args!(operator(op: Operator) <&[u8], &[u8]>, + call!(tag(op.to_str())) +); + +// We parse any expr surrounded by the tags `open_tag` and `close_tag`, ignoring all whitespaces around those +named_args!(brackets<'a>(open_tag: &str, close_tag: &str) <&'a[u8], i64>, + call!(delimited( + space, + delimited(tag(open_tag), preceded(space, expr), preceded(space, tag(close_tag))), + space + )) +); + +fn byte_slice_to_str<'a>(s: &'a[u8]) -> Result<&'a str, str::Utf8Error> { + str::from_utf8(s) +} + +// We transform an integer string into a i64, ignoring surrounding whitespaces +// We look for a digit suite, and try to convert it. +// If either str::from_utf8 or FromStr::from_str fail, +// we fallback to the brackets parser defined above +named!(factor<&[u8], i64>, alt!( + map_res!( + map_res!( + call!(delimited(space, digit, space)), + byte_slice_to_str + ), + FromStr::from_str + ) + | call!(brackets, "(", ")") + ) +); + +// We read an initial factor and for each time we find +// a * or / operator followed by another factor, we do +// the math by folding everything +named!(term <&[u8], i64>, do_parse!( + init: factor >> + res: fold_many0!( + pair!(alt!(call!(operator, Star) | call!(operator, Slash)), factor), + init, + |acc, (op, val): (&[u8], i64)| { + if (op[0] as char) == '*' { acc * val } else { acc / val } + } + ) >> + (res) + ) +); + +named!(expr <&[u8], i64>, do_parse!( + init: term >> + res: fold_many0!( + call!(pair(alt((tag("+"), tag("-"))), term)), + init, + |acc, (op, val): (&[u8], i64)| { + if (op[0] as char) == '+' { acc + val } else { acc - val } + } + ) >> + (res) + ) +); + +#[test] +fn factor_test() { + assert_eq!( + factor(&b"3"[..]), + Ok((&b""[..], 3)) + ); + assert_eq!( + factor(&b" 12"[..]), + Ok((&b""[..], 12)) + ); + assert_eq!( + factor(&b"537 "[..]), + Ok((&b""[..], 537)) + ); + assert_eq!( + factor(&b" 24 "[..]), + Ok((&b""[..], 24)) + ); +} + +#[test] +fn term_test() { + assert_eq!( + term(&b" 12 *2 / 3"[..]), + Ok((&b""[..], 8)) + ); + assert_eq!( + term(&b" 2* 3 *2 *2 / 3"[..]), + Ok((&b""[..], 8)) + ); + assert_eq!( + term(&b" 48 / 3/2"[..]), + Ok((&b""[..], 8)) + ); +} + +#[test] +fn expr_test() { + assert_eq!( + expr(&b" 1 + 2 "[..]), + Ok((&b""[..], 3)) + ); + assert_eq!( + expr(&b" 12 + 6 - 4+ 3"[..]), + Ok((&b""[..], 17)) + ); + assert_eq!( + expr(&b" 1 + 2*3 + 4"[..]), + Ok((&b""[..], 11)) + ); +} + +#[test] +fn parens_test() { + assert_eq!( + expr(&b" ( 2 )"[..]), + Ok((&b""[..], 2)) + ); + assert_eq!( + expr(&b" 2* ( 3 + 4 ) "[..]), + Ok((&b""[..], 14)) + ); + assert_eq!( + expr(&b" 2*2 / ( 5 - 1) + 3"[..]), + Ok((&b""[..], 4)) + ); +} diff --git a/third_party/rust/nom/tests/overflow.rs b/third_party/rust/nom/tests/overflow.rs new file mode 100644 index 0000000000..2f4a87f34a --- /dev/null +++ b/third_party/rust/nom/tests/overflow.rs @@ -0,0 +1,139 @@ +#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] +#![cfg(target_pointer_width = "64")] + +#[macro_use] +extern crate nom; + +use nom::{Err, Needed}; +#[cfg(feature = "alloc")] +use nom::number::streaming::be_u64; + +// Parser definition + +// We request a length that would trigger an overflow if computing consumed + requested +named!(parser01<&[u8],()>, + do_parse!( + hdr: take!(1) >> + data: take!(18446744073709551615) >> + ({ + let _ = hdr; + let _ = data; + () + }) + ) +); + +// We request a length that would trigger an overflow if computing consumed + requested +named!(parser02<&[u8],(&[u8],&[u8])>, + tuple!(take!(1),take!(18446744073709551615)) +); + +#[test] +fn overflow_incomplete_do_parse() { + assert_eq!( + parser01(&b"3"[..]), + Err(Err::Incomplete(Needed::Size(18446744073709551615))) + ); +} + +#[test] +fn overflow_incomplete_tuple() { + assert_eq!( + parser02(&b"3"[..]), + Err(Err::Incomplete(Needed::Size(18446744073709551615))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn overflow_incomplete_length_bytes() { + named!(multi<&[u8], Vec<&[u8]> >, many0!( length_data!(be_u64) ) ); + + // Trigger an overflow in length_data + assert_eq!( + multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xff\xaa"[..]), + Err(Err::Incomplete(Needed::Size(18446744073709551615))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn overflow_incomplete_many0() { + named!(multi<&[u8], Vec<&[u8]> >, many0!( length_data!(be_u64) ) ); + + // Trigger an overflow in many0 + assert_eq!( + multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), + Err(Err::Incomplete(Needed::Size(18446744073709551599))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn overflow_incomplete_many1() { + named!(multi<&[u8], Vec<&[u8]> >, many1!( length_data!(be_u64) ) ); + + // Trigger an overflow in many1 + assert_eq!( + multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), + Err(Err::Incomplete(Needed::Size(18446744073709551599))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn overflow_incomplete_many_till() { + named!(multi<&[u8], (Vec<&[u8]>, &[u8]) >, many_till!( length_data!(be_u64), tag!("abc") ) ); + + // Trigger an overflow in many_till + assert_eq!( + multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), + Err(Err::Incomplete(Needed::Size(18446744073709551599))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn overflow_incomplete_many_m_n() { + named!(multi<&[u8], Vec<&[u8]> >, many_m_n!(2, 4, length_data!(be_u64) ) ); + + // Trigger an overflow in many_m_n + assert_eq!( + multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), + Err(Err::Incomplete(Needed::Size(18446744073709551599))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn overflow_incomplete_count() { + named!(counter<&[u8], Vec<&[u8]> >, count!( length_data!(be_u64), 2 ) ); + + assert_eq!( + counter(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xef\xaa"[..]), + Err(Err::Incomplete(Needed::Size(18446744073709551599))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn overflow_incomplete_length_count() { + use nom::number::streaming::be_u8; + named!(multi<&[u8], Vec<&[u8]> >, length_count!( be_u8, length_data!(be_u64) ) ); + + assert_eq!( + multi(&b"\x04\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xee\xaa"[..]), + Err(Err::Incomplete(Needed::Size(18446744073709551598))) + ); +} + +#[test] +#[cfg(feature = "alloc")] +fn overflow_incomplete_length_data() { + named!(multi<&[u8], Vec<&[u8]> >, many0!( length_data!(be_u64) ) ); + + assert_eq!( + multi(&b"\x00\x00\x00\x00\x00\x00\x00\x01\xaa\xff\xff\xff\xff\xff\xff\xff\xff\xaa"[..]), + Err(Err::Incomplete(Needed::Size(18446744073709551615))) + ); +} diff --git a/third_party/rust/nom/tests/reborrow_fold.rs b/third_party/rust/nom/tests/reborrow_fold.rs new file mode 100644 index 0000000000..b53555b074 --- /dev/null +++ b/third_party/rust/nom/tests/reborrow_fold.rs @@ -0,0 +1,18 @@ +#![allow(dead_code)] +#![allow(unused_variables)] + +#[macro_use] +extern crate nom; + +use std::str; + +named_args!(atom<'a>(tomb: &'a mut ())<String>, + map!(map_res!(is_not!(" \t\r\n()"), str::from_utf8), ToString::to_string)); + +/*FIXME: should we support the use case of borrowing data mutably in a parser? +named_args!(list<'a>(tomb: &'a mut ())<String>, + delimited!( + char!('('), + fold_many0!(call!(atom, tomb), "".to_string(), |acc: String, next: String| acc + next.as_str()), + char!(')'))); +*/ diff --git a/third_party/rust/nom/tests/test1.rs b/third_party/rust/nom/tests/test1.rs new file mode 100644 index 0000000000..85c442fe84 --- /dev/null +++ b/third_party/rust/nom/tests/test1.rs @@ -0,0 +1,44 @@ +#![cfg(feature = "stream")] + +#[macro_use] +extern crate nom; + +use nom::{not_line_ending, IResult}; + +use std::fmt::Debug; + +/* +#[test] +#[allow(unused_must_use)] +fn tag() { + FileProducer::new("assets/links.txt", 20).map(|producer: FileProducer| { + let mut p = producer; + p.refill(); + + consumer_from_parser!(PrintConsumer<()>, flat_map!(map_res!(tag!("https!"), str::from_utf8), print)); + let mut cs = PrintConsumer::new(); + for _ in 1..4 { + p.apply(&mut cs); + } + }); +} +*/ + +pub fn print<T: Debug>(input: T) -> IResult<T, ()> { + println!("{:?}", input); + Ok((input, ())) +} + +#[test] +fn is_not() { + //is_not!(foo b"\r\n"); + named!(foo<&[u8],&[u8]>, is_not!(&b"\r\n"[..])); + let a = &b"ab12cd\nefgh"[..]; + assert_eq!(foo(a), Ok((&b"\nefgh"[..], &b"ab12cd"[..]))); +} + +#[test] +fn exported_public_method_defined_by_macro() { + let a = &b"ab12cd\nefgh"[..]; + assert_eq!(not_line_ending(a), Ok((&b"\nefgh"[..], &b"ab12cd"[..]))); +} |