我的测试parse_line_repeat
在最后一行崩溃了(这是无效的),而不是像测试本身那样将其作为余数返回。
我试过用tuple
代替pair
,用many0
代替many1
,第一个问题用this blogpost on nom解决,第二个问题在再次阅读documentation on choosing a combinator后解决。
我想做的可能被描述为错误恢复,但通过这个article说,否则,因此我出了什么搜索的想法。
这里是lib.rs
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::space0,
multi::{many1, many_till},
sequence::pair,
IResult,
};
fn parse_token(input: &str) -> IResult<&str, bool> {
let (remaining, token) = alt((tag("0"), tag("1")))(input)?;
if token == "1" {
return Ok((remaining, true));
} else {
return Ok((remaining, false));
}
}
#[allow(dead_code)]
fn parse_line(input: &str) -> IResult<&str, Vec<bool>> {
let (remaining, (tokens_raw, _)) = pair(
many1(many_till(space0, parse_token)),
many_till(space0, tag("\n")),
)(input)?;
let mut tokens = Vec::new();
for (_, token) in tokens_raw {
let token: bool = token;
tokens.push(token);
}
Ok((remaining, tokens))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_token_test() {
assert_eq!(parse_token("0"), Ok(("", false)));
assert_eq!(parse_token("1"), Ok(("", true)));
}
#[test]
fn parse_line_test() {
assert_eq!(parse_line("1 \n"), Ok(("", vec![true])));
assert_eq!(parse_line("0 \n"), Ok(("", vec![false])));
assert_eq!(
parse_line("1 1 1 1\n"),
Ok(("", vec![true, true, true, true]))
);
}
#[test]
fn parse_line_repeat() {
let rtn = parse_line("1 \n 1\n");
assert_eq!(rtn, Ok((" 1\n", vec![true])));
let rtn = parse_line(rtn.unwrap().0);
assert_eq!(rtn, Ok(("", vec![true])));
let rtn = parse_line("1\n 1\n\n");
assert_eq!(rtn, Ok((" 1\n\n", vec![true])));
let rtn = parse_line(rtn.unwrap().0);
assert_eq!(rtn, Ok(("\n", vec![true])));
let rtn = parse_line(rtn.unwrap().0);
assert_eq!(rtn, Ok(("\n", vec![])));
}
}
字符串
这里是Cargo.toml
[package]
name = "minimal"
version = "0.1.0"
edition = "2021"
[lib]
name = "minimal"
path = "src/lib.rs"
[dependencies]
nom = "7.1.3"
型
错误代码:
$ cargo test
Finished test [unoptimized + debuginfo] target(s) in 0.94s
Running unittests minimal/main.rs
running 3 tests
test tests::parse_line_test ... ok
test tests::parse_token_test ... ok
test tests::parse_line_repeat ... FAILED
failures:
---- tests::parse_line_repeat stdout ----
thread 'tests::parse_line_repeat' panicked at 'assertion failed: `(left == right)`
left: `Err(Error(Error { input: "\n", code: ManyTill }))`,
right: `Ok(("\n", []))`', minimal/main.rs:67:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
tests::parse_line_repeat
test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: test failed, to rerun pass `--lib`
2条答案
按热度按时间dgsult0t1#
我认为真实的的原因是你的测试/预期行为有缺陷。
换句话说,您的最后一个测试检查
parse_line
的以下行为:1 \n 1\n
->1\n
+[true]
1\n
-><empty>
+[true]
然后,您检查:
1\n 1\n\n
->1\n\n
+[true]
1\n\n
->\n
+[true]
最后:
\n
->\n
+[]
。最后一个对我来说没什么意义。如果
1\n
应该变成<empty>
,那么为什么\n
不应该也变成<empty>
呢?为什么一个使用换行符,而另一个不使用?如果是因为没有1
s的空行不应该被解析器使用,那么为什么它返回错误呢?返回错误是无法使用对象的解析器的预期结果。所以你可以选择的方法是:
\n
)不能被您的代码消耗。在这种情况下,你的代码已经是正确的,测试是有缺陷的,应该期待一个错误。\n
)可由您的代码使用。在这种情况下,你的代码和测试都有缺陷。代码应该是many0
而不是many1
,测试应该在最后检查Ok(("", vec![]))
。您的原始代码表明您希望空行不被消耗。在这种情况下,我会将测试修改为:
字符串
zf9nrax12#
您可以直接执行此操作,而不是在
parse_line
中的错误情况下立即使用?
失败:字符串
这并不总是做什么写在可以,它不
parse_line
,它忽略了一行,什么也不做。当然,在更复杂的场景中,您可能希望更深入地研究错误细节,然后您可能希望使用
match
而不是简单的let ... else