hurl/packages/hurlfmt/tests/json.rs

299 lines
9.5 KiB
Rust
Raw Normal View History

2020-08-27 10:07:46 +03:00
/*
* 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.
*
*/
2020-11-02 20:30:13 +03:00
2020-08-27 10:07:46 +03:00
extern crate proptest;
2020-09-20 09:40:02 +03:00
use std::fs;
2020-08-27 10:07:46 +03:00
use proptest::prelude::prop::test_runner::TestRunner;
2020-09-20 09:40:02 +03:00
use proptest::prelude::*;
2020-08-27 10:07:46 +03:00
2020-11-02 20:30:13 +03:00
use hurl_core::ast::*;
use hurl_core::parser::{parse_json, Reader};
use hurlfmt::format::{Token, Tokenizable};
2020-08-27 10:07:46 +03:00
fn whitespace() -> BoxedStrategy<String> {
prop_oneof![
Just("".to_string()),
Just(" ".to_string()),
Just(" ".to_string()),
2020-09-20 09:40:02 +03:00
]
.boxed()
2020-08-27 10:07:46 +03:00
}
// region strategy scalar/leaves
fn value_number() -> BoxedStrategy<JsonValue> {
2020-08-27 10:07:46 +03:00
prop_oneof![
Just(JsonValue::Number("0".to_string())),
Just(JsonValue::Number("1".to_string())),
Just(JsonValue::Number("1.33".to_string())),
Just(JsonValue::Number("-100".to_string()))
2020-09-20 09:40:02 +03:00
]
.boxed()
2020-08-27 10:07:46 +03:00
}
fn value_boolean() -> BoxedStrategy<JsonValue> {
2020-08-27 10:07:46 +03:00
prop_oneof![
Just(JsonValue::Boolean(true)),
Just(JsonValue::Boolean(false)),
2020-09-20 09:40:02 +03:00
]
.boxed()
2020-08-27 10:07:46 +03:00
}
fn value_string() -> BoxedStrategy<JsonValue> {
2020-08-27 10:07:46 +03:00
let source_info = SourceInfo::init(0, 0, 0, 0);
2020-09-20 09:40:02 +03:00
let variable = Variable {
name: "name".to_string(),
source_info: source_info.clone(),
};
2020-08-27 10:07:46 +03:00
prop_oneof![
Just(JsonValue::String(Template {
2020-09-20 09:40:02 +03:00
elements: vec![],
2020-08-27 10:07:46 +03:00
quotes: true,
2020-09-20 09:40:02 +03:00
source_info: source_info.clone()
2020-08-27 10:07:46 +03:00
})),
Just(JsonValue::String(Template {
2020-09-20 09:40:02 +03:00
elements: vec![TemplateElement::String {
encoded: "Hello".to_string(),
value: "Hello".to_string(),
}],
2020-08-27 10:07:46 +03:00
quotes: true,
source_info: source_info.clone()
})),
Just(JsonValue::String(Template {
2020-08-27 10:07:46 +03:00
elements: vec![
TemplateElement::String {
encoded: "Hello\\u0020 ".to_string(),
value: "Hello ".to_string(),
},
2020-09-20 09:40:02 +03:00
TemplateElement::Expression(Expr {
space0: Whitespace {
value: "".to_string(),
source_info: source_info.clone()
},
variable,
space1: Whitespace {
value: "".to_string(),
source_info: source_info.clone()
},
})
2020-08-27 10:07:46 +03:00
],
quotes: true,
source_info
})),
2020-09-20 09:40:02 +03:00
]
.boxed()
2020-08-27 10:07:46 +03:00
}
// endregion
// region strategy value
fn value() -> BoxedStrategy<JsonValue> {
2020-09-20 09:40:02 +03:00
let leaf = prop_oneof![value_boolean(), value_string(), value_number(),];
2020-08-27 10:07:46 +03:00
leaf.prop_recursive(
2020-09-20 09:40:02 +03:00
8, // 8 levels deep
2020-08-27 10:07:46 +03:00
256, // Shoot for maximum size of 256 nodes
2020-09-20 09:40:02 +03:00
10, // We put up to 10 items per collection
2020-08-27 10:07:46 +03:00
|value| {
prop_oneof![
// Lists
(whitespace()).prop_map(|space0| JsonValue::List {
2020-09-20 09:40:02 +03:00
space0,
elements: vec![]
}),
(whitespace(), whitespace(), value.clone()).prop_map(|(space0, space1, value)| {
JsonValue::List {
2020-09-20 09:40:02 +03:00
space0,
elements: vec![JsonListElement {
2020-09-20 09:40:02 +03:00
space0: "".to_string(),
value,
space1,
}],
}
}),
(
whitespace(),
whitespace(),
value_number(),
whitespace(),
whitespace(),
value_number()
)
.prop_map(
|(space00, space01, value0, space10, space11, value1)| JsonValue::List {
2020-09-20 09:40:02 +03:00
space0: space00,
elements: vec![
JsonListElement {
2020-09-20 09:40:02 +03:00
space0: "".to_string(),
value: value0,
space1: space01
},
JsonListElement {
2020-09-20 09:40:02 +03:00
space0: space10,
value: value1,
space1: space11
},
]
}
),
(
whitespace(),
whitespace(),
value_boolean(),
whitespace(),
whitespace(),
value_boolean()
)
.prop_map(
|(space00, space01, value0, space10, space11, value1)| JsonValue::List {
2020-09-20 09:40:02 +03:00
space0: space00,
elements: vec![
JsonListElement {
2020-09-20 09:40:02 +03:00
space0: "".to_string(),
value: value0,
space1: space01
},
JsonListElement {
2020-09-20 09:40:02 +03:00
space0: space10,
value: value1,
space1: space11
},
]
}
),
(
whitespace(),
whitespace(),
value_string(),
whitespace(),
whitespace(),
value_string()
)
.prop_map(
|(space00, space01, value0, space10, space11, value1)| JsonValue::List {
2020-09-20 09:40:02 +03:00
space0: space00,
elements: vec![
JsonListElement {
2020-09-20 09:40:02 +03:00
space0: "".to_string(),
value: value0,
space1: space01
},
JsonListElement {
2020-09-20 09:40:02 +03:00
space0: space10,
value: value1,
space1: space11
},
]
}
),
2020-08-27 10:07:46 +03:00
// Object
(whitespace()).prop_map(|space0| JsonValue::Object {
2020-09-20 09:40:02 +03:00
space0,
elements: vec![]
}),
(
whitespace(),
whitespace(),
whitespace(),
value,
whitespace()
)
.prop_map(|(space0, space1, space2, value, space3)| {
JsonValue::Object {
2020-09-20 09:40:02 +03:00
space0,
elements: vec![JsonObjectElement {
2020-09-20 09:40:02 +03:00
space0: "".to_string(),
name: "key1".to_string(),
space1,
space2,
value,
space3,
}],
}
}),
2020-08-27 10:07:46 +03:00
]
2020-09-20 09:40:02 +03:00
},
)
.boxed()
2020-08-27 10:07:46 +03:00
}
// endregion
// region test-echo
fn format_token(token: Token) -> String {
match token {
2020-09-20 09:40:02 +03:00
Token::Whitespace(s)
| Token::Number(s)
| Token::Boolean(s)
2020-09-20 09:40:02 +03:00
| Token::String(s)
| Token::Keyword(s)
| Token::Quote(s)
| Token::QueryType(s)
| Token::CodeVariable(s)
| Token::CodeDelimiter(s) => s,
2020-08-27 10:07:46 +03:00
_ => panic!("invalid token {:?}", token),
}
}
fn format_value(value: JsonValue) -> String {
2020-08-27 10:07:46 +03:00
let tokens = value.tokenize();
//eprintln!("{:?}", tokens);
2020-09-20 09:40:02 +03:00
tokens
.iter()
.map(|t| format_token(t.clone()))
.collect::<Vec<String>>()
.join("")
2020-08-27 10:07:46 +03:00
}
#[test]
fn test_echo() {
let mut runner = TestRunner::default();
//let mut runner = TestRunner::new(ProptestConfig::with_cases(10000));
2020-09-20 09:40:02 +03:00
runner
.run(&value(), |value| {
//eprintln!("value={:#?}", value);
let s = format_value(value);
eprintln!("s={}", s);
let mut reader = Reader::init(s.as_str());
let parsed_value = parse_json(&mut reader).unwrap();
2020-09-20 09:40:02 +03:00
assert_eq!(format_value(parsed_value), s);
Ok(())
})
.unwrap();
2020-08-27 10:07:46 +03:00
//assert_eq!(1,2);
}
#[test]
fn test_parse_files() {
let paths = fs::read_dir("tests/json").unwrap();
for p in paths {
let path = p.unwrap().path();
println!("parsing json file {}", path.display());
2020-09-20 09:40:02 +03:00
let s = fs::read_to_string(path).expect("Something went wrong reading the file");
let mut reader = Reader::init(s.as_str());
let parsed_value = parse_json(&mut reader).unwrap();
2020-08-27 10:07:46 +03:00
assert_eq!(format_value(parsed_value), s);
}
}