906 lines
28 KiB
Rust
906 lines
28 KiB
Rust
/*
|
|
* hurl (https://hurl.dev)
|
|
* Copyright (C) 2020 Orange
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
*/
|
|
use crate::core::ast::Template;
|
|
use crate::core::common::Pos;
|
|
use crate::core::common::SourceInfo;
|
|
use crate::core::json;
|
|
|
|
use super::combinators::*;
|
|
use super::error;
|
|
use super::primitives::*;
|
|
use super::reader::*;
|
|
use super::template::*;
|
|
use super::ParseResult;
|
|
|
|
pub fn parse(reader: &mut Reader) -> ParseResult<'static, json::Value> {
|
|
choice(
|
|
vec![
|
|
null_value,
|
|
boolean_value,
|
|
string_value,
|
|
number_value,
|
|
list_value,
|
|
object_value,
|
|
],
|
|
reader,
|
|
)
|
|
}
|
|
|
|
fn null_value(reader: &mut Reader) -> ParseResult<'static, json::Value> {
|
|
try_literal("null", reader)?;
|
|
Ok(json::Value::Null {})
|
|
}
|
|
|
|
fn boolean_value(reader: &mut Reader) -> ParseResult<'static, json::Value> {
|
|
let value = boolean(reader)?;
|
|
Ok(json::Value::Boolean(value))
|
|
}
|
|
|
|
fn string_value(reader: &mut Reader) -> ParseResult<'static, json::Value> {
|
|
try_literal("\"", reader)?;
|
|
let quotes = true;
|
|
let mut chars = vec![];
|
|
let start = reader.state.pos.clone();
|
|
loop {
|
|
if reader.remaining().starts_with('"') || reader.is_eof() {
|
|
break;
|
|
}
|
|
let char = any_char(reader)?;
|
|
chars.push(char);
|
|
}
|
|
let end = reader.state.pos.clone();
|
|
|
|
let encoded_string = EncodedString {
|
|
source_info: SourceInfo {
|
|
start: start.clone(),
|
|
end: end.clone(),
|
|
},
|
|
chars,
|
|
};
|
|
literal("\"", reader)?;
|
|
let elements = templatize(encoded_string)?;
|
|
|
|
let template = Template {
|
|
quotes,
|
|
elements,
|
|
source_info: SourceInfo { start, end },
|
|
};
|
|
Ok(json::Value::String(template))
|
|
}
|
|
|
|
fn any_char(reader: &mut Reader) -> ParseResult<'static, (char, String, Pos)> {
|
|
let start = reader.state.clone();
|
|
match escape_char(reader) {
|
|
Ok(c) => Ok((c, reader.from(start.cursor), start.pos)),
|
|
Err(e) => {
|
|
if e.recoverable {
|
|
reader.state = start.clone();
|
|
match reader.read() {
|
|
None => Err(error::Error {
|
|
pos: start.pos,
|
|
recoverable: true,
|
|
inner: error::ParseError::Expecting {
|
|
value: "char".to_string(),
|
|
},
|
|
}),
|
|
Some(c) => {
|
|
if vec!['\\', '\x08', '\n', '\x0c', '\r', '\t'].contains(&c) {
|
|
Err(error::Error {
|
|
pos: start.pos,
|
|
recoverable: true,
|
|
inner: error::ParseError::Expecting {
|
|
value: "char".to_string(),
|
|
},
|
|
})
|
|
} else {
|
|
Ok((c, reader.from(start.cursor), start.pos))
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn escape_char(reader: &mut Reader) -> ParseResult<'static, char> {
|
|
try_literal("\\", reader)?;
|
|
let start = reader.state.clone();
|
|
match reader.read() {
|
|
Some('"') => Ok('"'),
|
|
Some('\\') => Ok('\\'),
|
|
Some('/') => Ok('/'),
|
|
Some('b') => Ok('\x08'),
|
|
Some('n') => Ok('\n'),
|
|
Some('f') => Ok('\x0c'),
|
|
Some('r') => Ok('\r'),
|
|
Some('t') => Ok('\t'),
|
|
Some('u') => unicode(reader),
|
|
_ => Err(error::Error {
|
|
pos: start.pos,
|
|
recoverable: false,
|
|
inner: error::ParseError::EscapeChar {},
|
|
}),
|
|
}
|
|
}
|
|
|
|
fn unicode(reader: &mut Reader) -> ParseResult<'static, char> {
|
|
let v = hex_value(reader)?;
|
|
let c = match std::char::from_u32(v) {
|
|
None => {
|
|
return Err(error::Error {
|
|
pos: reader.clone().state.pos,
|
|
recoverable: false,
|
|
inner: error::ParseError::Unicode {},
|
|
})
|
|
}
|
|
Some(c) => c,
|
|
};
|
|
Ok(c)
|
|
}
|
|
|
|
fn hex_value(reader: &mut Reader) -> ParseResult<'static, u32> {
|
|
let digit1 = nonrecover(|r| hex_digit(r), reader)?;
|
|
let digit2 = nonrecover(|r| hex_digit(r), reader)?;
|
|
let digit3 = nonrecover(|r| hex_digit(r), reader)?;
|
|
let digit4 = nonrecover(|r| hex_digit(r), reader)?;
|
|
let value = digit1 * (16 ^ 3) + digit2 * (16 ^ 2) + digit3 * 16 + digit4;
|
|
Ok(value)
|
|
}
|
|
|
|
fn number_value(reader: &mut Reader) -> ParseResult<'static, json::Value> {
|
|
let start = reader.state.pos.clone();
|
|
|
|
let sign = match try_literal("-", reader) {
|
|
Err(_) => "".to_string(),
|
|
Ok(_) => "-".to_string(),
|
|
};
|
|
|
|
let integer = match try_literal("0", reader) {
|
|
Err(_) => {
|
|
let digits = reader.read_while(|c| c.is_ascii_digit());
|
|
if digits.is_empty() {
|
|
return Err(error::Error {
|
|
pos: start,
|
|
recoverable: true,
|
|
inner: error::ParseError::Expecting {
|
|
value: "number".to_string(),
|
|
},
|
|
});
|
|
} else {
|
|
digits
|
|
}
|
|
}
|
|
Ok(_) => "0".to_string(),
|
|
};
|
|
|
|
let fraction = match try_literal(".", reader) {
|
|
Ok(_) => {
|
|
let digits = reader.read_while(|c| c.is_ascii_digit());
|
|
if digits.is_empty() {
|
|
return Err(error::Error {
|
|
pos: reader.state.pos.clone(),
|
|
recoverable: false,
|
|
inner: error::ParseError::Expecting {
|
|
value: "digits".to_string(),
|
|
},
|
|
});
|
|
} else {
|
|
format!(".{}", digits)
|
|
}
|
|
}
|
|
Err(_) => "".to_string(),
|
|
};
|
|
|
|
let exponent = if reader.remaining().starts_with('e') || reader.remaining().starts_with('E') {
|
|
reader.read();
|
|
let exponent_sign = match try_literal("-", reader) {
|
|
Ok(_) => "-".to_string(),
|
|
Err(_) => match try_literal("+", reader) {
|
|
Ok(_) => "+".to_string(),
|
|
Err(_) => "".to_string(),
|
|
},
|
|
};
|
|
let exponent_digits = reader.read_while(|c| c.is_ascii_digit());
|
|
format!("e{}{}", exponent_sign, exponent_digits)
|
|
} else {
|
|
"".to_string()
|
|
};
|
|
|
|
Ok(json::Value::Number(format!(
|
|
"{}{}{}{}",
|
|
sign, integer, fraction, exponent
|
|
)))
|
|
}
|
|
|
|
fn list_value(reader: &mut Reader) -> ParseResult<'static, json::Value> {
|
|
try_literal("[", reader)?;
|
|
let space0 = whitespace(reader);
|
|
let mut elements = vec![];
|
|
|
|
// at least one element
|
|
if !reader.remaining().starts_with(']') {
|
|
let first_element = list_element(None, reader)?;
|
|
elements.push(first_element.clone());
|
|
|
|
loop {
|
|
if reader.remaining().starts_with(']') {
|
|
break;
|
|
}
|
|
if !reader.remaining().starts_with(',') {
|
|
break;
|
|
}
|
|
literal(",", reader)?;
|
|
let element = list_element(Some(first_element.value._type()), reader)?;
|
|
elements.push(element);
|
|
}
|
|
}
|
|
literal("]", reader)?;
|
|
|
|
Ok(json::Value::List { space0, elements })
|
|
}
|
|
|
|
fn list_element(
|
|
_type: Option<String>,
|
|
reader: &mut Reader,
|
|
) -> ParseResult<'static, json::ListElement> {
|
|
let save = reader.state.pos.clone();
|
|
let space0 = whitespace(reader);
|
|
let pos = reader.state.pos.clone();
|
|
let value = match parse(reader) {
|
|
Ok(r) => r,
|
|
Err(_) => {
|
|
return Err(error::Error {
|
|
pos: save,
|
|
recoverable: false,
|
|
inner: error::ParseError::Json {},
|
|
})
|
|
}
|
|
};
|
|
if let Some(t) = _type {
|
|
if t != value._type() {
|
|
return Err(error::Error {
|
|
pos,
|
|
recoverable: false,
|
|
inner: error::ParseError::Expecting { value: t },
|
|
});
|
|
}
|
|
}
|
|
let space1 = whitespace(reader);
|
|
Ok(json::ListElement {
|
|
space0,
|
|
value,
|
|
space1,
|
|
})
|
|
}
|
|
|
|
fn object_value(reader: &mut Reader) -> ParseResult<'static, json::Value> {
|
|
try_literal("{", reader)?;
|
|
let space0 = whitespace(reader);
|
|
let mut elements = vec![];
|
|
if !reader.remaining().starts_with('}') {
|
|
let first_element = object_element(reader)?;
|
|
elements.push(first_element);
|
|
|
|
loop {
|
|
if reader.remaining().starts_with('}') {
|
|
break;
|
|
}
|
|
if !reader.remaining().starts_with(',') {
|
|
break;
|
|
}
|
|
literal(",", reader)?;
|
|
let element = object_element(reader)?;
|
|
elements.push(element);
|
|
}
|
|
}
|
|
|
|
// at least one element
|
|
|
|
literal("}", reader)?;
|
|
|
|
Ok(json::Value::Object { space0, elements })
|
|
}
|
|
|
|
fn object_element(reader: &mut Reader) -> ParseResult<'static, json::ObjectElement> {
|
|
let space0 = whitespace(reader);
|
|
literal("\"", reader)?;
|
|
let name = key(reader)?;
|
|
literal("\"", reader)?;
|
|
let space1 = whitespace(reader);
|
|
literal(":", reader)?;
|
|
let save = reader.state.pos.clone();
|
|
let space2 = whitespace(reader);
|
|
let value = match parse(reader) {
|
|
Ok(r) => r,
|
|
Err(_) => {
|
|
return Err(error::Error {
|
|
pos: save,
|
|
recoverable: false,
|
|
inner: error::ParseError::Json {},
|
|
})
|
|
}
|
|
};
|
|
let space3 = whitespace(reader);
|
|
Ok(json::ObjectElement {
|
|
space0,
|
|
name,
|
|
space1,
|
|
space2,
|
|
value,
|
|
space3,
|
|
})
|
|
}
|
|
|
|
fn key(reader: &mut Reader) -> ParseResult<'static, String> {
|
|
let s = reader
|
|
.read_while(|c| c.is_alphanumeric() || *c == '@' || *c == '.' || *c == '_' || *c == '-');
|
|
if s.is_empty() {
|
|
let pos = reader.state.pos.clone();
|
|
Err(error::Error {
|
|
pos,
|
|
recoverable: false,
|
|
inner: error::ParseError::Expecting {
|
|
value: "key".to_string(),
|
|
},
|
|
})
|
|
} else {
|
|
Ok(s)
|
|
}
|
|
}
|
|
|
|
fn whitespace(reader: &mut Reader) -> String {
|
|
reader.read_while(|c| *c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::core::ast::TemplateElement;
|
|
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_parse_error() {
|
|
let mut reader = Reader::init("{ \"a\":\n}");
|
|
let error = parse(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 7 });
|
|
assert_eq!(error.inner, error::ParseError::Json {});
|
|
assert_eq!(error.recoverable, false);
|
|
|
|
let mut reader = Reader::init("[0,1,]");
|
|
let error = parse(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 6 });
|
|
assert_eq!(error.inner, error::ParseError::Json {});
|
|
assert_eq!(error.recoverable, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_null_value() {
|
|
let mut reader = Reader::init("null");
|
|
assert_eq!(null_value(&mut reader).unwrap(), json::Value::Null {});
|
|
assert_eq!(reader.state.cursor, 4);
|
|
|
|
let mut reader = Reader::init("true");
|
|
let error = null_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "null".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_boolean_value() {
|
|
let mut reader = Reader::init("true");
|
|
assert_eq!(
|
|
boolean_value(&mut reader).unwrap(),
|
|
json::Value::Boolean(true)
|
|
);
|
|
assert_eq!(reader.state.cursor, 4);
|
|
|
|
let mut reader = Reader::init("1");
|
|
let error = boolean_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "true|false".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_string_value() {
|
|
let mut reader = Reader::init("\"\"");
|
|
assert_eq!(
|
|
string_value(&mut reader).unwrap(),
|
|
json::Value::String(Template {
|
|
quotes: true,
|
|
elements: vec![],
|
|
source_info: SourceInfo::init(1, 2, 1, 2),
|
|
})
|
|
);
|
|
assert_eq!(reader.state.cursor, 2);
|
|
|
|
let mut reader = Reader::init("\"Hello\\u0020{{name}}!\"");
|
|
assert_eq!(
|
|
string_value(&mut reader).unwrap(),
|
|
json::tests::hello_world_value()
|
|
);
|
|
assert_eq!(reader.state.cursor, 22);
|
|
|
|
let mut reader = Reader::init("\"{}\"");
|
|
assert_eq!(
|
|
string_value(&mut reader).unwrap(),
|
|
json::Value::String(Template {
|
|
quotes: true,
|
|
elements: vec![TemplateElement::String {
|
|
value: "{}".to_string(),
|
|
encoded: "{}".to_string(),
|
|
}],
|
|
source_info: SourceInfo::init(1, 2, 1, 4),
|
|
})
|
|
);
|
|
assert_eq!(reader.state.cursor, 4);
|
|
}
|
|
|
|
#[test]
|
|
fn test_string_value_error() {
|
|
let mut reader = Reader::init("1");
|
|
let error = string_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "\"".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, true);
|
|
|
|
let mut reader = Reader::init("\"1");
|
|
let error = string_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 3 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "\"".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, false);
|
|
|
|
let mut reader = Reader::init("\"{{x\"");
|
|
let error = string_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 5 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "}}".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_any_char() {
|
|
let mut reader = Reader::init("a");
|
|
assert_eq!(
|
|
any_char(&mut reader).unwrap(),
|
|
('a', "a".to_string(), Pos { line: 1, column: 1 })
|
|
);
|
|
assert_eq!(reader.state.cursor, 1);
|
|
|
|
let mut reader = Reader::init(" ");
|
|
assert_eq!(
|
|
any_char(&mut reader).unwrap(),
|
|
(' ', " ".to_string(), Pos { line: 1, column: 1 })
|
|
);
|
|
assert_eq!(reader.state.cursor, 1);
|
|
|
|
let mut reader = Reader::init("\\u0020 ");
|
|
assert_eq!(
|
|
any_char(&mut reader).unwrap(),
|
|
(' ', "\\u0020".to_string(), Pos { line: 1, column: 1 })
|
|
);
|
|
assert_eq!(reader.state.cursor, 6);
|
|
|
|
let mut reader = Reader::init("\\t");
|
|
assert_eq!(
|
|
any_char(&mut reader).unwrap(),
|
|
('\t', "\\t".to_string(), Pos { line: 1, column: 1 })
|
|
);
|
|
assert_eq!(reader.state.cursor, 2);
|
|
|
|
let mut reader = Reader::init("#");
|
|
assert_eq!(
|
|
any_char(&mut reader).unwrap(),
|
|
('#', "#".to_string(), Pos { line: 1, column: 1 })
|
|
);
|
|
assert_eq!(reader.state.cursor, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_any_char_error() {
|
|
let mut reader = Reader::init("");
|
|
let error = any_char(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(error.recoverable, true);
|
|
|
|
let mut reader = Reader::init("\t");
|
|
let error = any_char(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(error.recoverable, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_escape_char() {
|
|
let mut reader = Reader::init("\\n");
|
|
assert_eq!(escape_char(&mut reader).unwrap(), '\n');
|
|
assert_eq!(reader.state.cursor, 2);
|
|
|
|
let mut reader = Reader::init("\\u000a");
|
|
assert_eq!(escape_char(&mut reader).unwrap(), '\n');
|
|
assert_eq!(reader.state.cursor, 6);
|
|
|
|
let mut reader = Reader::init("x");
|
|
let error = escape_char(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "\\".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, true);
|
|
assert_eq!(reader.state.cursor, 0);
|
|
}
|
|
|
|
#[test]
|
|
fn test_unicode() {
|
|
let mut reader = Reader::init("000a");
|
|
assert_eq!(unicode(&mut reader).unwrap(), '\n');
|
|
assert_eq!(reader.state.cursor, 4);
|
|
}
|
|
|
|
#[test]
|
|
fn test_hex_value() {
|
|
let mut reader = Reader::init("0020x");
|
|
assert_eq!(hex_value(&mut reader).unwrap(), 32);
|
|
|
|
let mut reader = Reader::init("x");
|
|
let error = hex_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(error.inner, error::ParseError::HexDigit);
|
|
assert_eq!(error.recoverable, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_number_value() {
|
|
let mut reader = Reader::init("100");
|
|
assert_eq!(
|
|
number_value(&mut reader).unwrap(),
|
|
json::Value::Number("100".to_string())
|
|
);
|
|
assert_eq!(reader.state.cursor, 3);
|
|
|
|
let mut reader = Reader::init("1.333");
|
|
assert_eq!(
|
|
number_value(&mut reader).unwrap(),
|
|
json::Value::Number("1.333".to_string())
|
|
);
|
|
assert_eq!(reader.state.cursor, 5);
|
|
|
|
let mut reader = Reader::init("-1");
|
|
assert_eq!(
|
|
number_value(&mut reader).unwrap(),
|
|
json::Value::Number("-1".to_string())
|
|
);
|
|
assert_eq!(reader.state.cursor, 2);
|
|
|
|
let mut reader = Reader::init("00");
|
|
assert_eq!(
|
|
number_value(&mut reader).unwrap(),
|
|
json::Value::Number("0".to_string())
|
|
);
|
|
assert_eq!(reader.state.cursor, 1);
|
|
|
|
let mut reader = Reader::init("1e0");
|
|
assert_eq!(
|
|
number_value(&mut reader).unwrap(),
|
|
json::Value::Number("1e0".to_string())
|
|
);
|
|
assert_eq!(reader.state.cursor, 3);
|
|
|
|
let mut reader = Reader::init("1e005");
|
|
assert_eq!(
|
|
number_value(&mut reader).unwrap(),
|
|
json::Value::Number("1e005".to_string())
|
|
);
|
|
assert_eq!(reader.state.cursor, 5);
|
|
|
|
let mut reader = Reader::init("1e-005");
|
|
assert_eq!(
|
|
number_value(&mut reader).unwrap(),
|
|
json::Value::Number("1e-005".to_string())
|
|
);
|
|
assert_eq!(reader.state.cursor, 6);
|
|
}
|
|
|
|
#[test]
|
|
fn test_number_value_error() {
|
|
let mut reader = Reader::init("true");
|
|
let error = number_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "number".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, true);
|
|
|
|
let mut reader = Reader::init("1.x");
|
|
let error = number_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 3 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "digits".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_list_value() {
|
|
let mut reader = Reader::init("[]");
|
|
assert_eq!(
|
|
list_value(&mut reader).unwrap(),
|
|
json::Value::List {
|
|
space0: "".to_string(),
|
|
elements: vec![]
|
|
}
|
|
);
|
|
assert_eq!(reader.state.cursor, 2);
|
|
|
|
let mut reader = Reader::init("[ ]");
|
|
assert_eq!(
|
|
list_value(&mut reader).unwrap(),
|
|
json::Value::List {
|
|
space0: " ".to_string(),
|
|
elements: vec![]
|
|
}
|
|
);
|
|
assert_eq!(reader.state.cursor, 3);
|
|
|
|
let mut reader = Reader::init("[true]");
|
|
assert_eq!(
|
|
list_value(&mut reader).unwrap(),
|
|
json::Value::List {
|
|
space0: "".to_string(),
|
|
elements: vec![json::ListElement {
|
|
space0: "".to_string(),
|
|
value: json::Value::Boolean(true),
|
|
space1: "".to_string(),
|
|
}],
|
|
}
|
|
);
|
|
assert_eq!(reader.state.cursor, 6);
|
|
}
|
|
|
|
#[test]
|
|
fn test_list_error() {
|
|
let mut reader = Reader::init("true");
|
|
let error = list_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "[".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, true);
|
|
|
|
let mut reader = Reader::init("[1, true]");
|
|
let error = list_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 5 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "number".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, false);
|
|
|
|
let mut reader = Reader::init("[1, 2,]");
|
|
let error = list_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 7 });
|
|
assert_eq!(error.inner, error::ParseError::Json {});
|
|
assert_eq!(error.recoverable, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_list_element() {
|
|
let mut reader = Reader::init("true");
|
|
assert_eq!(
|
|
list_element(None, &mut reader).unwrap(),
|
|
json::ListElement {
|
|
space0: "".to_string(),
|
|
value: json::Value::Boolean(true),
|
|
space1: "".to_string(),
|
|
}
|
|
);
|
|
assert_eq!(reader.state.cursor, 4);
|
|
}
|
|
|
|
#[test]
|
|
fn test_list_element_error() {
|
|
let mut reader = Reader::init("true");
|
|
let error = list_element(Some("number".to_string()), &mut reader)
|
|
.err()
|
|
.unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "number".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, false);
|
|
|
|
let mut reader = Reader::init("\n]");
|
|
let error = list_element(Some("number".to_string()), &mut reader)
|
|
.err()
|
|
.unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(error.inner, error::ParseError::Json {});
|
|
assert_eq!(error.recoverable, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_object_value() {
|
|
let mut reader = Reader::init("{}");
|
|
assert_eq!(
|
|
object_value(&mut reader).unwrap(),
|
|
json::Value::Object {
|
|
space0: "".to_string(),
|
|
elements: vec![]
|
|
}
|
|
);
|
|
assert_eq!(reader.state.cursor, 2);
|
|
|
|
let mut reader = Reader::init("{ }");
|
|
assert_eq!(
|
|
object_value(&mut reader).unwrap(),
|
|
json::Value::Object {
|
|
space0: " ".to_string(),
|
|
elements: vec![]
|
|
}
|
|
);
|
|
assert_eq!(reader.state.cursor, 3);
|
|
|
|
let mut reader = Reader::init("{\n \"a\": true\n}");
|
|
assert_eq!(
|
|
object_value(&mut reader).unwrap(),
|
|
json::Value::Object {
|
|
space0: "\n ".to_string(),
|
|
elements: vec![json::ObjectElement {
|
|
space0: "".to_string(),
|
|
name: "a".to_string(),
|
|
space1: "".to_string(),
|
|
space2: " ".to_string(),
|
|
value: json::Value::Boolean(true),
|
|
space3: "\n".to_string(),
|
|
}],
|
|
}
|
|
);
|
|
assert_eq!(reader.state.cursor, 15);
|
|
|
|
let mut reader = Reader::init("true");
|
|
let error = object_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "{".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_object_error() {
|
|
let mut reader = Reader::init("{ \"a\":\n}");
|
|
let error = object_value(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 7 });
|
|
assert_eq!(error.inner, error::ParseError::Json {});
|
|
assert_eq!(error.recoverable, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_object_element() {
|
|
let mut reader = Reader::init("\"a\": true");
|
|
assert_eq!(
|
|
object_element(&mut reader).unwrap(),
|
|
json::ObjectElement {
|
|
space0: "".to_string(),
|
|
name: "a".to_string(),
|
|
space1: "".to_string(),
|
|
space2: " ".to_string(),
|
|
value: json::Value::Boolean(true),
|
|
space3: "".to_string(),
|
|
}
|
|
);
|
|
assert_eq!(reader.state.cursor, 9);
|
|
}
|
|
|
|
#[test]
|
|
fn test_object_element_error() {
|
|
let mut reader = Reader::init(":");
|
|
let error = object_element(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 1 });
|
|
assert_eq!(
|
|
error.inner,
|
|
error::ParseError::Expecting {
|
|
value: "\"".to_string()
|
|
}
|
|
);
|
|
assert_eq!(error.recoverable, false);
|
|
|
|
let mut reader = Reader::init("\"name\":\n");
|
|
let error = object_element(&mut reader).err().unwrap();
|
|
assert_eq!(error.pos, Pos { line: 1, column: 8 });
|
|
assert_eq!(error.inner, error::ParseError::Json {});
|
|
assert_eq!(error.recoverable, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_key() {
|
|
let mut reader = Reader::init("name");
|
|
assert_eq!(key(&mut reader).unwrap(), "name".to_string());
|
|
assert_eq!(reader.state.cursor, 4);
|
|
|
|
let mut reader = Reader::init("@timestamp");
|
|
assert_eq!(key(&mut reader).unwrap(), "@timestamp".to_string());
|
|
assert_eq!(reader.state.cursor, 10);
|
|
|
|
let mut reader = Reader::init("data.q_client-dns");
|
|
assert_eq!(key(&mut reader).unwrap(), "data.q_client-dns".to_string());
|
|
assert_eq!(reader.state.cursor, 17);
|
|
}
|
|
|
|
#[test]
|
|
fn test_whitespace() {
|
|
let mut reader = Reader::init("");
|
|
assert_eq!(whitespace(&mut reader), "".to_string());
|
|
assert_eq!(reader.state.cursor, 0);
|
|
|
|
let mut reader = Reader::init(" x");
|
|
assert_eq!(whitespace(&mut reader), " ".to_string());
|
|
assert_eq!(reader.state.cursor, 1);
|
|
|
|
let mut reader = Reader::init("\n x");
|
|
assert_eq!(whitespace(&mut reader), "\n ".to_string());
|
|
assert_eq!(reader.state.cursor, 3);
|
|
}
|
|
}
|