Add some tests

This commit is contained in:
Timothy Warren 2020-02-07 20:01:10 -05:00
parent 5e4e8c4356
commit 7588f29cc9
1 changed files with 48 additions and 13 deletions

View File

@ -1,6 +1,6 @@
//! # Naive JSON Parser
use std::collections::HashMap;
use std::iter::FromIterator;
use crate::ParseError::UnexpectedEndOfInput;
#[derive(Debug, PartialEq)]
pub enum JSONValue {
@ -13,7 +13,7 @@ pub enum JSONValue {
Null,
}
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum ParseError {
UnexpectedEndOfInput(String),
ExpectedEndOfInput(String),
@ -25,7 +25,7 @@ pub enum ParseError {
ExpectedUnicodeEscape(String),
}
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct JSON {
chars: Vec<char>,
i: usize
@ -55,7 +55,7 @@ impl JSON {
match types.next() {
Some(val) => Ok(val),
None => Err(UnexpectedEndOfInput(String::new()))
None => Err(ParseError::UnexpectedEndOfInput(String::new()))
}
}
@ -76,7 +76,7 @@ impl JSON {
// we take the path of string -> whitespace -> ':' -> value -> ...
while self.chars[self.i] != '}' {
if initial == false {
self.eat_char(',')?;
self.eat(',')?;
self.skip_whitespace();
}
@ -89,7 +89,7 @@ impl JSON {
};
self.skip_whitespace();
self.eat_char(':')?;
self.eat(':')?;
let value = self.parse_value()?;
result.insert(key, value);
@ -116,7 +116,7 @@ impl JSON {
while self.chars[self.i] != ']' {
if initial == false {
self.eat_char(',')?;
self.eat(',')?;
}
let value = self.parse_value()?;
result.push(value);
@ -130,15 +130,22 @@ impl JSON {
}
fn parse_string(&mut self) -> PartialResult {
todo!();
Ok(None)
}
fn parse_number(&mut self) -> PartialResult {
todo!();
Ok(None)
}
fn parse_keyword(&mut self, search: &str, value: JSONValue) -> PartialResult {
let slice = &String::from_iter(&self.chars[self.i..self.i+search.len()]);
let start = self.i;
let end = if self.i + search.len() > self.chars.len() {
self.chars.len()
} else {
self.i + search.len()
};
let slice = &String::from_iter(&self.chars[start..end]);
if slice == search {
self.i += search.len();
@ -154,7 +161,7 @@ impl JSON {
}
}
fn eat_char(&mut self, ch: char) -> Result<(), ParseError> {
fn eat(&mut self, ch: char) -> Result<(), ParseError> {
if self.chars[self.i] != ch {
let msg = format!(r#"Expected "{}"."#, ch);
return Err(ParseError::ExpectedToken(msg));
@ -165,6 +172,7 @@ impl JSON {
Ok(())
}
/// Convert a `&str` containing JSON into a `Result<JSONValue, ParseError>`
pub fn parse(json: &str) -> JSONResult {
JSON::new(json).parse_value()
}
@ -177,7 +185,34 @@ mod tests {
use super::*;
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
fn parse_keyword() {
let mut parser = JSON::new(r#""foobarbaz""#);
let res = JSON::parse_keyword(&mut parser, "true", JSONValue::True);
assert_eq!(res, Ok(None));
let mut parser = JSON::new("true");
let res = JSON::parse_keyword(&mut parser, "true", JSONValue::True);
assert_eq!(res, Ok(Some(JSONValue::True)));
}
#[test]
fn skip_whitespace() {
let mut parser = JSON::new(" \t\r\nx");
parser.skip_whitespace();
assert_eq!('x', parser.chars[parser.i]);
}
#[test]
fn parse_empty_array() {
let mut parser = JSON::new("[]");
let res = JSON::parse_value(&mut parser);
assert_eq!(res, Ok(JSONValue::Array(vec![])));
}
#[test]
fn can_parse_array_of_keywords() {
let result = JSON::parse("[true,false,null]");
assert_eq!(result, Ok(JSONValue::Array(vec![JSONValue::True, JSONValue::False, JSONValue::Null])));
}
}