use super::Parser;
use crate::Error;
impl<'a> Parser<'a> {
pub fn expect(&mut self, expected: &[u8]) -> crate::Result<&mut Self> {
if expected.is_empty() {
return Ok(self);
}
let input_len = self.input.len();
if input_len - self.pos < expected.len() {
return Err(self.err_expected(Error::EXPECTED_PATTERN));
}
if self.starts_with(expected) {
let end_pos = self.pos + expected.len();
let scan_end = end_pos.min(input_len);
let mut i = self.pos;
while i < scan_end {
match self.input[i] {
b'\n' => {
self.line += 1;
i += 1;
}
b'\r' => {
if i + 1 < scan_end && self.input[i + 1] == b'\n' {
i += 2;
self.line += 1;
} else {
self.line += 1;
i += 1;
}
}
_ => {
i += 1;
}
}
}
self.pos = end_pos;
Ok(self)
} else {
Err(self.err_expected(Error::EXPECTED_PATTERN))
}
}
pub fn expect_then_skip(&mut self, expected: &[u8]) -> crate::Result<&mut Self> {
self.expect(expected)?;
self.skip_newlines_and_spaces();
Ok(self)
}
pub fn expect_with_msg(
&mut self,
expected: &[u8],
msg: &'static str,
) -> crate::Result<&mut Self> {
let line = self.line;
self.expect(expected).map_err(|_| Error::expected_at(msg, line))
}
pub fn expect_keyword_then_skip(
&mut self,
keyword: &[u8],
error_msg: &'static str,
) -> crate::Result<&mut Self> {
let line = self.line;
self.expect(keyword).map_err(|_| Error::expected_at(error_msg, line))?;
self.skip_newlines_and_spaces();
Ok(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn expect_succeeds_with_version() {
use crate::VERSION;
let input = b"VERSION";
let mut parser = Parser::new(input).unwrap();
let result = parser.expect(VERSION.as_bytes());
assert!(result.is_ok());
assert_eq!(parser.pos, 7);
assert_eq!(parser.remaining(), b"");
}
#[test]
fn expect_fails_with_different_input() {
use crate::VERSION;
let input = b"TEST";
let mut parser = Parser::new(input).unwrap();
let result = parser.expect(VERSION.as_bytes());
assert!(result.is_err());
match result.unwrap_err() {
Error::Expected { line, .. } => {
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::Expected"),
}
assert_eq!(parser.pos, 0);
}
#[test]
fn expect_fails_with_partial_match() {
use crate::VERSION;
let input = b"VERSIO";
let mut parser = Parser::new(input).unwrap();
let result = parser.expect(VERSION.as_bytes());
assert!(result.is_err());
match result.unwrap_err() {
Error::Expected { .. } => {}
_ => panic!("Expected Error::Expected"),
}
}
#[test]
fn expect_fails_when_remaining_input_too_short() {
use crate::VERSION;
let input = b"VER";
let mut parser = Parser::new(input).unwrap();
let result = parser.expect(VERSION.as_bytes());
assert!(result.is_err());
match result.unwrap_err() {
Error::Expected { .. } => {}
_ => panic!("Expected Error::Expected"),
}
}
#[test]
fn expect_succeeds_and_advances_position() {
use crate::VERSION;
let input = b"VERSION test";
let mut parser = Parser::new(input).unwrap();
let result = parser.expect(VERSION.as_bytes());
assert!(result.is_ok());
assert_eq!(parser.pos, 7);
assert_eq!(parser.remaining(), b" test");
}
#[test]
fn expect_fails_when_not_at_start() {
use crate::VERSION;
let input = b" VERSION";
let mut parser = Parser::new(input).unwrap();
parser.pos = 1; let result = parser.expect(VERSION.as_bytes());
assert!(result.is_ok());
assert_eq!(parser.pos, 8);
}
#[test]
fn at_newline_returns_true_for_unix_newline() {
let input = b"\ntest";
let parser = Parser::new(input).unwrap();
assert!(parser.at_newline());
}
#[test]
fn at_newline_returns_true_for_windows_newline() {
let input = b"\r\ntest";
let parser = Parser::new(input).unwrap();
assert!(parser.at_newline());
}
#[test]
fn at_newline_returns_true_for_mac_newline() {
let input = b"\rtest";
let parser = Parser::new(input).unwrap();
assert!(parser.at_newline());
}
#[test]
fn at_newline_returns_false_for_non_newline() {
let input = b"test";
let parser = Parser::new(input).unwrap();
assert!(!parser.at_newline());
}
#[test]
fn at_newline_returns_false_for_space() {
let input = b" test";
let parser = Parser::new(input).unwrap();
assert!(!parser.at_newline());
}
#[test]
fn expect_with_msg_includes_line_number() {
let input = b"test";
let mut parser = Parser::new(input).unwrap();
let result = parser.expect_with_msg(b"VERSION", "Expected VERSION keyword");
assert!(result.is_err());
match result.unwrap_err() {
Error::Expected { msg, line } => {
assert_eq!(msg, "Expected VERSION keyword");
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::Expected"),
}
}
}