Move emitter/scanner tests to their folder.
Change scanner's complex test: ```diff - *coffee: + *coffee : amount: 4 - *cookies: + *cookies : amount: 4 ``` According to https://play.yaml.io/main/parser, this example was invalid in the first place. Adding a space makes it so that the colon is not part of the alias name. Also fix colons not being able to be part of anchors.
This commit is contained in:
parent
3cdb815556
commit
f9eb8c6d60
5 changed files with 737 additions and 747 deletions
|
@ -334,302 +334,3 @@ fn need_quotes(string: &str) -> bool {
|
||||||
|| string.parse::<i64>().is_ok()
|
|| string.parse::<i64>().is_ok()
|
||||||
|| string.parse::<f64>().is_ok()
|
|| string.parse::<f64>().is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[allow(clippy::similar_names)]
|
|
||||||
mod test {
|
|
||||||
use super::*;
|
|
||||||
use crate::YamlLoader;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_emit_simple() {
|
|
||||||
let s = "
|
|
||||||
# comment
|
|
||||||
a0 bb: val
|
|
||||||
a1:
|
|
||||||
b1: 4
|
|
||||||
b2: d
|
|
||||||
a2: 4 # i'm comment
|
|
||||||
a3: [1, 2, 3]
|
|
||||||
a4:
|
|
||||||
- [a1, a2]
|
|
||||||
- 2
|
|
||||||
";
|
|
||||||
|
|
||||||
let docs = YamlLoader::load_from_str(s).unwrap();
|
|
||||||
let doc = &docs[0];
|
|
||||||
let mut writer = String::new();
|
|
||||||
{
|
|
||||||
let mut emitter = YamlEmitter::new(&mut writer);
|
|
||||||
emitter.dump(doc).unwrap();
|
|
||||||
}
|
|
||||||
println!("original:\n{s}");
|
|
||||||
println!("emitted:\n{writer}");
|
|
||||||
let docs_new = match YamlLoader::load_from_str(&writer) {
|
|
||||||
Ok(y) => y,
|
|
||||||
Err(e) => panic!("{}", e),
|
|
||||||
};
|
|
||||||
let doc_new = &docs_new[0];
|
|
||||||
|
|
||||||
assert_eq!(doc, doc_new);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_emit_complex() {
|
|
||||||
let s = r#"
|
|
||||||
cataloge:
|
|
||||||
product: &coffee { name: Coffee, price: 2.5 , unit: 1l }
|
|
||||||
product: &cookies { name: Cookies!, price: 3.40 , unit: 400g}
|
|
||||||
|
|
||||||
products:
|
|
||||||
*coffee:
|
|
||||||
amount: 4
|
|
||||||
*cookies:
|
|
||||||
amount: 4
|
|
||||||
[1,2,3,4]:
|
|
||||||
array key
|
|
||||||
2.4:
|
|
||||||
real key
|
|
||||||
true:
|
|
||||||
bool key
|
|
||||||
{}:
|
|
||||||
empty hash key
|
|
||||||
"#;
|
|
||||||
let docs = YamlLoader::load_from_str(s).unwrap();
|
|
||||||
let doc = &docs[0];
|
|
||||||
let mut writer = String::new();
|
|
||||||
{
|
|
||||||
let mut emitter = YamlEmitter::new(&mut writer);
|
|
||||||
emitter.dump(doc).unwrap();
|
|
||||||
}
|
|
||||||
let docs_new = match YamlLoader::load_from_str(&writer) {
|
|
||||||
Ok(y) => y,
|
|
||||||
Err(e) => panic!("{}", e),
|
|
||||||
};
|
|
||||||
let doc_new = &docs_new[0];
|
|
||||||
assert_eq!(doc, doc_new);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_emit_avoid_quotes() {
|
|
||||||
let s = r#"---
|
|
||||||
a7: 你好
|
|
||||||
boolean: "true"
|
|
||||||
boolean2: "false"
|
|
||||||
date: 2014-12-31
|
|
||||||
empty_string: ""
|
|
||||||
empty_string1: " "
|
|
||||||
empty_string2: " a"
|
|
||||||
empty_string3: " a "
|
|
||||||
exp: "12e7"
|
|
||||||
field: ":"
|
|
||||||
field2: "{"
|
|
||||||
field3: "\\"
|
|
||||||
field4: "\n"
|
|
||||||
field5: "can't avoid quote"
|
|
||||||
float: "2.6"
|
|
||||||
int: "4"
|
|
||||||
nullable: "null"
|
|
||||||
nullable2: "~"
|
|
||||||
products:
|
|
||||||
"*coffee":
|
|
||||||
amount: 4
|
|
||||||
"*cookies":
|
|
||||||
amount: 4
|
|
||||||
".milk":
|
|
||||||
amount: 1
|
|
||||||
"2.4": real key
|
|
||||||
"[1,2,3,4]": array key
|
|
||||||
"true": bool key
|
|
||||||
"{}": empty hash key
|
|
||||||
x: test
|
|
||||||
y: avoid quoting here
|
|
||||||
z: string with spaces"#;
|
|
||||||
|
|
||||||
let docs = YamlLoader::load_from_str(s).unwrap();
|
|
||||||
let doc = &docs[0];
|
|
||||||
let mut writer = String::new();
|
|
||||||
{
|
|
||||||
let mut emitter = YamlEmitter::new(&mut writer);
|
|
||||||
emitter.dump(doc).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(s, writer, "actual:\n\n{writer}\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn emit_quoted_bools() {
|
|
||||||
let input = r#"---
|
|
||||||
string0: yes
|
|
||||||
string1: no
|
|
||||||
string2: "true"
|
|
||||||
string3: "false"
|
|
||||||
string4: "~"
|
|
||||||
null0: ~
|
|
||||||
[true, false]: real_bools
|
|
||||||
[True, TRUE, False, FALSE, y,Y,yes,Yes,YES,n,N,no,No,NO,on,On,ON,off,Off,OFF]: false_bools
|
|
||||||
bool0: true
|
|
||||||
bool1: false"#;
|
|
||||||
let expected = r#"---
|
|
||||||
string0: "yes"
|
|
||||||
string1: "no"
|
|
||||||
string2: "true"
|
|
||||||
string3: "false"
|
|
||||||
string4: "~"
|
|
||||||
null0: ~
|
|
||||||
? - true
|
|
||||||
- false
|
|
||||||
: real_bools
|
|
||||||
? - "True"
|
|
||||||
- "TRUE"
|
|
||||||
- "False"
|
|
||||||
- "FALSE"
|
|
||||||
- y
|
|
||||||
- Y
|
|
||||||
- "yes"
|
|
||||||
- "Yes"
|
|
||||||
- "YES"
|
|
||||||
- n
|
|
||||||
- N
|
|
||||||
- "no"
|
|
||||||
- "No"
|
|
||||||
- "NO"
|
|
||||||
- "on"
|
|
||||||
- "On"
|
|
||||||
- "ON"
|
|
||||||
- "off"
|
|
||||||
- "Off"
|
|
||||||
- "OFF"
|
|
||||||
: false_bools
|
|
||||||
bool0: true
|
|
||||||
bool1: false"#;
|
|
||||||
|
|
||||||
let docs = YamlLoader::load_from_str(input).unwrap();
|
|
||||||
let doc = &docs[0];
|
|
||||||
let mut writer = String::new();
|
|
||||||
{
|
|
||||||
let mut emitter = YamlEmitter::new(&mut writer);
|
|
||||||
emitter.dump(doc).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
expected, writer,
|
|
||||||
"expected:\n{expected}\nactual:\n{writer}\n",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_empty_and_nested() {
|
|
||||||
test_empty_and_nested_flag(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_empty_and_nested_compact() {
|
|
||||||
test_empty_and_nested_flag(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_empty_and_nested_flag(compact: bool) {
|
|
||||||
let s = if compact {
|
|
||||||
r#"---
|
|
||||||
a:
|
|
||||||
b:
|
|
||||||
c: hello
|
|
||||||
d: {}
|
|
||||||
e:
|
|
||||||
- f
|
|
||||||
- g
|
|
||||||
- h: []"#
|
|
||||||
} else {
|
|
||||||
r#"---
|
|
||||||
a:
|
|
||||||
b:
|
|
||||||
c: hello
|
|
||||||
d: {}
|
|
||||||
e:
|
|
||||||
- f
|
|
||||||
- g
|
|
||||||
-
|
|
||||||
h: []"#
|
|
||||||
};
|
|
||||||
|
|
||||||
let docs = YamlLoader::load_from_str(s).unwrap();
|
|
||||||
let doc = &docs[0];
|
|
||||||
let mut writer = String::new();
|
|
||||||
{
|
|
||||||
let mut emitter = YamlEmitter::new(&mut writer);
|
|
||||||
emitter.compact(compact);
|
|
||||||
emitter.dump(doc).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(s, writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_nested_arrays() {
|
|
||||||
let s = r#"---
|
|
||||||
a:
|
|
||||||
- b
|
|
||||||
- - c
|
|
||||||
- d
|
|
||||||
- - e
|
|
||||||
- f"#;
|
|
||||||
|
|
||||||
let docs = YamlLoader::load_from_str(s).unwrap();
|
|
||||||
let doc = &docs[0];
|
|
||||||
let mut writer = String::new();
|
|
||||||
{
|
|
||||||
let mut emitter = YamlEmitter::new(&mut writer);
|
|
||||||
emitter.dump(doc).unwrap();
|
|
||||||
}
|
|
||||||
println!("original:\n{s}");
|
|
||||||
println!("emitted:\n{writer}");
|
|
||||||
|
|
||||||
assert_eq!(s, writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_deeply_nested_arrays() {
|
|
||||||
let s = r#"---
|
|
||||||
a:
|
|
||||||
- b
|
|
||||||
- - c
|
|
||||||
- d
|
|
||||||
- - e
|
|
||||||
- - f
|
|
||||||
- - e"#;
|
|
||||||
|
|
||||||
let docs = YamlLoader::load_from_str(s).unwrap();
|
|
||||||
let doc = &docs[0];
|
|
||||||
let mut writer = String::new();
|
|
||||||
{
|
|
||||||
let mut emitter = YamlEmitter::new(&mut writer);
|
|
||||||
emitter.dump(doc).unwrap();
|
|
||||||
}
|
|
||||||
println!("original:\n{s}");
|
|
||||||
println!("emitted:\n{writer}");
|
|
||||||
|
|
||||||
assert_eq!(s, writer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_nested_hashes() {
|
|
||||||
let s = r#"---
|
|
||||||
a:
|
|
||||||
b:
|
|
||||||
c:
|
|
||||||
d:
|
|
||||||
e: f"#;
|
|
||||||
|
|
||||||
let docs = YamlLoader::load_from_str(s).unwrap();
|
|
||||||
let doc = &docs[0];
|
|
||||||
let mut writer = String::new();
|
|
||||||
{
|
|
||||||
let mut emitter = YamlEmitter::new(&mut writer);
|
|
||||||
emitter.dump(doc).unwrap();
|
|
||||||
}
|
|
||||||
println!("original:\n{s}");
|
|
||||||
println!("emitted:\n{writer}");
|
|
||||||
|
|
||||||
assert_eq!(s, writer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -951,7 +951,7 @@ impl<T: Iterator<Item = char>> Scanner<T> {
|
||||||
|
|
||||||
self.skip();
|
self.skip();
|
||||||
self.lookahead(1);
|
self.lookahead(1);
|
||||||
while is_alpha(self.ch()) {
|
while is_alpha(self.ch()) || self.ch_is(':') {
|
||||||
string.push(self.ch());
|
string.push(self.ch());
|
||||||
self.skip();
|
self.skip();
|
||||||
self.lookahead(1);
|
self.lookahead(1);
|
||||||
|
@ -960,7 +960,7 @@ impl<T: Iterator<Item = char>> Scanner<T> {
|
||||||
if string.is_empty()
|
if string.is_empty()
|
||||||
|| match self.ch() {
|
|| match self.ch() {
|
||||||
c if is_blankz(c) => false,
|
c if is_blankz(c) => false,
|
||||||
'?' | ':' | ',' | ']' | '}' | '%' | '@' | '`' => false,
|
'?' | ',' | ']' | '}' | '%' | '@' | '`' => false,
|
||||||
_ => true,
|
_ => true,
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@ -1747,447 +1747,3 @@ impl<T: Iterator<Item = char>> Scanner<T> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[allow(clippy::enum_glob_use)]
|
|
||||||
mod test {
|
|
||||||
use super::TokenType::*;
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
macro_rules! next {
|
|
||||||
($p:ident, $tk:pat) => {{
|
|
||||||
let tok = $p.next().unwrap();
|
|
||||||
match tok.1 {
|
|
||||||
$tk => {}
|
|
||||||
_ => panic!("unexpected token: {:?}", tok),
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! next_scalar {
|
|
||||||
($p:ident, $tk:expr, $v:expr) => {{
|
|
||||||
let tok = $p.next().unwrap();
|
|
||||||
match tok.1 {
|
|
||||||
Scalar(style, ref v) => {
|
|
||||||
assert_eq!(style, $tk);
|
|
||||||
assert_eq!(v, $v);
|
|
||||||
}
|
|
||||||
_ => panic!("unexpected token: {:?}", tok),
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! end {
|
|
||||||
($p:ident) => {{
|
|
||||||
assert_eq!($p.next(), None);
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
/// test cases in libyaml scanner.c
|
|
||||||
#[test]
|
|
||||||
fn test_empty() {
|
|
||||||
let s = "";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scalar() {
|
|
||||||
let s = "a scalar";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, Scalar(TScalarStyle::Plain, _));
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_explicit_scalar() {
|
|
||||||
let s = "---
|
|
||||||
'a scalar'
|
|
||||||
...
|
|
||||||
";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, DocumentStart);
|
|
||||||
next!(p, Scalar(TScalarStyle::SingleQuoted, _));
|
|
||||||
next!(p, DocumentEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_multiple_documents() {
|
|
||||||
let s = "
|
|
||||||
'a scalar'
|
|
||||||
---
|
|
||||||
'a scalar'
|
|
||||||
---
|
|
||||||
'a scalar'
|
|
||||||
";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, Scalar(TScalarStyle::SingleQuoted, _));
|
|
||||||
next!(p, DocumentStart);
|
|
||||||
next!(p, Scalar(TScalarStyle::SingleQuoted, _));
|
|
||||||
next!(p, DocumentStart);
|
|
||||||
next!(p, Scalar(TScalarStyle::SingleQuoted, _));
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_a_flow_sequence() {
|
|
||||||
let s = "[item 1, item 2, item 3]";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, FlowSequenceStart);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 1");
|
|
||||||
next!(p, FlowEntry);
|
|
||||||
next!(p, Scalar(TScalarStyle::Plain, _));
|
|
||||||
next!(p, FlowEntry);
|
|
||||||
next!(p, Scalar(TScalarStyle::Plain, _));
|
|
||||||
next!(p, FlowSequenceEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_a_flow_mapping() {
|
|
||||||
let s = "
|
|
||||||
{
|
|
||||||
a simple key: a value, # Note that the KEY token is produced.
|
|
||||||
? a complex key: another value,
|
|
||||||
}
|
|
||||||
";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, FlowMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next!(p, Scalar(TScalarStyle::Plain, _));
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, Scalar(TScalarStyle::Plain, _));
|
|
||||||
next!(p, FlowEntry);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "a complex key");
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, Scalar(TScalarStyle::Plain, _));
|
|
||||||
next!(p, FlowEntry);
|
|
||||||
next!(p, FlowMappingEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_block_sequences() {
|
|
||||||
let s = "
|
|
||||||
- item 1
|
|
||||||
- item 2
|
|
||||||
-
|
|
||||||
- item 3.1
|
|
||||||
- item 3.2
|
|
||||||
-
|
|
||||||
key 1: value 1
|
|
||||||
key 2: value 2
|
|
||||||
";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, BlockSequenceStart);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 1");
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 2");
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next!(p, BlockSequenceStart);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 3.1");
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 3.2");
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next!(p, BlockMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "key 1");
|
|
||||||
next!(p, Value);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "value 1");
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "key 2");
|
|
||||||
next!(p, Value);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "value 2");
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_block_mappings() {
|
|
||||||
let s = "
|
|
||||||
a simple key: a value # The KEY token is produced here.
|
|
||||||
? a complex key
|
|
||||||
: another value
|
|
||||||
a mapping:
|
|
||||||
key 1: value 1
|
|
||||||
key 2: value 2
|
|
||||||
a sequence:
|
|
||||||
- item 1
|
|
||||||
- item 2
|
|
||||||
";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, BlockMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, Key);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, Key);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, Value); // libyaml comment seems to be wrong
|
|
||||||
next!(p, BlockMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, Key);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, Key);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, BlockSequenceStart);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next!(p, Scalar(_, _));
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_no_block_sequence_start() {
|
|
||||||
let s = "
|
|
||||||
key:
|
|
||||||
- item 1
|
|
||||||
- item 2
|
|
||||||
";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, BlockMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "key");
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 1");
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 2");
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_collections_in_sequence() {
|
|
||||||
let s = "
|
|
||||||
- - item 1
|
|
||||||
- item 2
|
|
||||||
- key 1: value 1
|
|
||||||
key 2: value 2
|
|
||||||
- ? complex key
|
|
||||||
: complex value
|
|
||||||
";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, BlockSequenceStart);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next!(p, BlockSequenceStart);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 1");
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 2");
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next!(p, BlockMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "key 1");
|
|
||||||
next!(p, Value);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "value 1");
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "key 2");
|
|
||||||
next!(p, Value);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "value 2");
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next!(p, BlockMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "complex key");
|
|
||||||
next!(p, Value);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "complex value");
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_collections_in_mapping() {
|
|
||||||
let s = "
|
|
||||||
? a sequence
|
|
||||||
: - item 1
|
|
||||||
- item 2
|
|
||||||
? a mapping
|
|
||||||
: key 1: value 1
|
|
||||||
key 2: value 2
|
|
||||||
";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, BlockMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "a sequence");
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, BlockSequenceStart);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 1");
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "item 2");
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "a mapping");
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, BlockMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "key 1");
|
|
||||||
next!(p, Value);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "value 1");
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "key 2");
|
|
||||||
next!(p, Value);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "value 2");
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_spec_ex7_3() {
|
|
||||||
let s = "
|
|
||||||
{
|
|
||||||
? foo :,
|
|
||||||
: bar,
|
|
||||||
}
|
|
||||||
";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, FlowMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "foo");
|
|
||||||
next!(p, Value);
|
|
||||||
next!(p, FlowEntry);
|
|
||||||
next!(p, Value);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "bar");
|
|
||||||
next!(p, FlowEntry);
|
|
||||||
next!(p, FlowMappingEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_plain_scalar_starting_with_indicators_in_flow() {
|
|
||||||
// "Plain scalars must not begin with most indicators, as this would cause ambiguity with
|
|
||||||
// other YAML constructs. However, the “:”, “?” and “-” indicators may be used as the first
|
|
||||||
// character if followed by a non-space “safe” character, as this causes no ambiguity."
|
|
||||||
|
|
||||||
let s = "{a: :b}";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, FlowMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "a");
|
|
||||||
next!(p, Value);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, ":b");
|
|
||||||
next!(p, FlowMappingEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
|
|
||||||
let s = "{a: ?b}";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, FlowMappingStart);
|
|
||||||
next!(p, Key);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "a");
|
|
||||||
next!(p, Value);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "?b");
|
|
||||||
next!(p, FlowMappingEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_plain_scalar_starting_with_indicators_in_block() {
|
|
||||||
let s = ":a";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, ":a");
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
|
|
||||||
let s = "?a";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "?a");
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_plain_scalar_containing_indicators_in_block() {
|
|
||||||
let s = "a:,b";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "a:,b");
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
|
|
||||||
let s = ":,b";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, ":,b");
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_scanner_cr() {
|
|
||||||
let s = "---\r\n- tok1\r\n- tok2";
|
|
||||||
let mut p = Scanner::new(s.chars());
|
|
||||||
next!(p, StreamStart(..));
|
|
||||||
next!(p, DocumentStart);
|
|
||||||
next!(p, BlockSequenceStart);
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "tok1");
|
|
||||||
next!(p, BlockEntry);
|
|
||||||
next_scalar!(p, TScalarStyle::Plain, "tok2");
|
|
||||||
next!(p, BlockEnd);
|
|
||||||
next!(p, StreamEnd);
|
|
||||||
end!(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_uri() {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_uri_escapes() {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
294
parser/tests/emitter.rs
Normal file
294
parser/tests/emitter.rs
Normal file
|
@ -0,0 +1,294 @@
|
||||||
|
use yaml_rust::{YamlEmitter, YamlLoader};
|
||||||
|
|
||||||
|
#[allow(clippy::similar_names)]
|
||||||
|
#[test]
|
||||||
|
fn test_emit_simple() {
|
||||||
|
let s = "
|
||||||
|
# comment
|
||||||
|
a0 bb: val
|
||||||
|
a1:
|
||||||
|
b1: 4
|
||||||
|
b2: d
|
||||||
|
a2: 4 # i'm comment
|
||||||
|
a3: [1, 2, 3]
|
||||||
|
a4:
|
||||||
|
- [a1, a2]
|
||||||
|
- 2
|
||||||
|
";
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(s).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
println!("original:\n{s}");
|
||||||
|
println!("emitted:\n{writer}");
|
||||||
|
let docs_new = match YamlLoader::load_from_str(&writer) {
|
||||||
|
Ok(y) => y,
|
||||||
|
Err(e) => panic!("{}", e),
|
||||||
|
};
|
||||||
|
let doc_new = &docs_new[0];
|
||||||
|
|
||||||
|
assert_eq!(doc, doc_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_emit_complex() {
|
||||||
|
let s = r#"
|
||||||
|
cataloge:
|
||||||
|
product: &coffee { name: Coffee, price: 2.5 , unit: 1l }
|
||||||
|
product: &cookies { name: Cookies!, price: 3.40 , unit: 400g}
|
||||||
|
|
||||||
|
products:
|
||||||
|
*coffee :
|
||||||
|
amount: 4
|
||||||
|
*cookies :
|
||||||
|
amount: 4
|
||||||
|
[1,2,3,4]:
|
||||||
|
array key
|
||||||
|
2.4:
|
||||||
|
real key
|
||||||
|
true:
|
||||||
|
bool key
|
||||||
|
{}:
|
||||||
|
empty hash key
|
||||||
|
"#;
|
||||||
|
let docs = YamlLoader::load_from_str(s).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
let docs_new = match YamlLoader::load_from_str(&writer) {
|
||||||
|
Ok(y) => y,
|
||||||
|
Err(e) => panic!("{}", e),
|
||||||
|
};
|
||||||
|
let doc_new = &docs_new[0];
|
||||||
|
assert_eq!(doc, doc_new);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_emit_avoid_quotes() {
|
||||||
|
let s = r#"---
|
||||||
|
a7: 你好
|
||||||
|
boolean: "true"
|
||||||
|
boolean2: "false"
|
||||||
|
date: 2014-12-31
|
||||||
|
empty_string: ""
|
||||||
|
empty_string1: " "
|
||||||
|
empty_string2: " a"
|
||||||
|
empty_string3: " a "
|
||||||
|
exp: "12e7"
|
||||||
|
field: ":"
|
||||||
|
field2: "{"
|
||||||
|
field3: "\\"
|
||||||
|
field4: "\n"
|
||||||
|
field5: "can't avoid quote"
|
||||||
|
float: "2.6"
|
||||||
|
int: "4"
|
||||||
|
nullable: "null"
|
||||||
|
nullable2: "~"
|
||||||
|
products:
|
||||||
|
"*coffee":
|
||||||
|
amount: 4
|
||||||
|
"*cookies":
|
||||||
|
amount: 4
|
||||||
|
".milk":
|
||||||
|
amount: 1
|
||||||
|
"2.4": real key
|
||||||
|
"[1,2,3,4]": array key
|
||||||
|
"true": bool key
|
||||||
|
"{}": empty hash key
|
||||||
|
x: test
|
||||||
|
y: avoid quoting here
|
||||||
|
z: string with spaces"#;
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(s).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(s, writer, "actual:\n\n{writer}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn emit_quoted_bools() {
|
||||||
|
let input = r#"---
|
||||||
|
string0: yes
|
||||||
|
string1: no
|
||||||
|
string2: "true"
|
||||||
|
string3: "false"
|
||||||
|
string4: "~"
|
||||||
|
null0: ~
|
||||||
|
[true, false]: real_bools
|
||||||
|
[True, TRUE, False, FALSE, y,Y,yes,Yes,YES,n,N,no,No,NO,on,On,ON,off,Off,OFF]: false_bools
|
||||||
|
bool0: true
|
||||||
|
bool1: false"#;
|
||||||
|
let expected = r#"---
|
||||||
|
string0: "yes"
|
||||||
|
string1: "no"
|
||||||
|
string2: "true"
|
||||||
|
string3: "false"
|
||||||
|
string4: "~"
|
||||||
|
null0: ~
|
||||||
|
? - true
|
||||||
|
- false
|
||||||
|
: real_bools
|
||||||
|
? - "True"
|
||||||
|
- "TRUE"
|
||||||
|
- "False"
|
||||||
|
- "FALSE"
|
||||||
|
- y
|
||||||
|
- Y
|
||||||
|
- "yes"
|
||||||
|
- "Yes"
|
||||||
|
- "YES"
|
||||||
|
- n
|
||||||
|
- N
|
||||||
|
- "no"
|
||||||
|
- "No"
|
||||||
|
- "NO"
|
||||||
|
- "on"
|
||||||
|
- "On"
|
||||||
|
- "ON"
|
||||||
|
- "off"
|
||||||
|
- "Off"
|
||||||
|
- "OFF"
|
||||||
|
: false_bools
|
||||||
|
bool0: true
|
||||||
|
bool1: false"#;
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(input).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
expected, writer,
|
||||||
|
"expected:\n{expected}\nactual:\n{writer}\n",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_and_nested() {
|
||||||
|
test_empty_and_nested_flag(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_and_nested_compact() {
|
||||||
|
test_empty_and_nested_flag(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_empty_and_nested_flag(compact: bool) {
|
||||||
|
let s = if compact {
|
||||||
|
r#"---
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
c: hello
|
||||||
|
d: {}
|
||||||
|
e:
|
||||||
|
- f
|
||||||
|
- g
|
||||||
|
- h: []"#
|
||||||
|
} else {
|
||||||
|
r#"---
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
c: hello
|
||||||
|
d: {}
|
||||||
|
e:
|
||||||
|
- f
|
||||||
|
- g
|
||||||
|
-
|
||||||
|
h: []"#
|
||||||
|
};
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(s).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.compact(compact);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(s, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nested_arrays() {
|
||||||
|
let s = r#"---
|
||||||
|
a:
|
||||||
|
- b
|
||||||
|
- - c
|
||||||
|
- d
|
||||||
|
- - e
|
||||||
|
- f"#;
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(s).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
println!("original:\n{s}");
|
||||||
|
println!("emitted:\n{writer}");
|
||||||
|
|
||||||
|
assert_eq!(s, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_deeply_nested_arrays() {
|
||||||
|
let s = r#"---
|
||||||
|
a:
|
||||||
|
- b
|
||||||
|
- - c
|
||||||
|
- d
|
||||||
|
- - e
|
||||||
|
- - f
|
||||||
|
- - e"#;
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(s).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
println!("original:\n{s}");
|
||||||
|
println!("emitted:\n{writer}");
|
||||||
|
|
||||||
|
assert_eq!(s, writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nested_hashes() {
|
||||||
|
let s = r#"---
|
||||||
|
a:
|
||||||
|
b:
|
||||||
|
c:
|
||||||
|
d:
|
||||||
|
e: f"#;
|
||||||
|
|
||||||
|
let docs = YamlLoader::load_from_str(s).unwrap();
|
||||||
|
let doc = &docs[0];
|
||||||
|
let mut writer = String::new();
|
||||||
|
{
|
||||||
|
let mut emitter = YamlEmitter::new(&mut writer);
|
||||||
|
emitter.dump(doc).unwrap();
|
||||||
|
}
|
||||||
|
println!("original:\n{s}");
|
||||||
|
println!("emitted:\n{writer}");
|
||||||
|
|
||||||
|
assert_eq!(s, writer);
|
||||||
|
}
|
440
parser/tests/scanner.rs
Normal file
440
parser/tests/scanner.rs
Normal file
|
@ -0,0 +1,440 @@
|
||||||
|
#![allow(clippy::enum_glob_use)]
|
||||||
|
|
||||||
|
use yaml_rust::{scanner::TokenType::*, scanner::*};
|
||||||
|
|
||||||
|
macro_rules! next {
|
||||||
|
($p:ident, $tk:pat) => {{
|
||||||
|
let tok = $p.next().unwrap();
|
||||||
|
match tok.1 {
|
||||||
|
$tk => {}
|
||||||
|
_ => panic!("unexpected token: {:?}", tok),
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! next_scalar {
|
||||||
|
($p:ident, $tk:expr, $v:expr) => {{
|
||||||
|
let tok = $p.next().unwrap();
|
||||||
|
match tok.1 {
|
||||||
|
Scalar(style, ref v) => {
|
||||||
|
assert_eq!(style, $tk);
|
||||||
|
assert_eq!(v, $v);
|
||||||
|
}
|
||||||
|
_ => panic!("unexpected token: {:?}", tok),
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! end {
|
||||||
|
($p:ident) => {{
|
||||||
|
assert_eq!($p.next(), None);
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
/// test cases in libyaml scanner.c
|
||||||
|
#[test]
|
||||||
|
fn test_empty() {
|
||||||
|
let s = "";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scalar() {
|
||||||
|
let s = "a scalar";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, Scalar(TScalarStyle::Plain, _));
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_explicit_scalar() {
|
||||||
|
let s = "---
|
||||||
|
'a scalar'
|
||||||
|
...
|
||||||
|
";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, DocumentStart);
|
||||||
|
next!(p, Scalar(TScalarStyle::SingleQuoted, _));
|
||||||
|
next!(p, DocumentEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_multiple_documents() {
|
||||||
|
let s = "
|
||||||
|
'a scalar'
|
||||||
|
---
|
||||||
|
'a scalar'
|
||||||
|
---
|
||||||
|
'a scalar'
|
||||||
|
";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, Scalar(TScalarStyle::SingleQuoted, _));
|
||||||
|
next!(p, DocumentStart);
|
||||||
|
next!(p, Scalar(TScalarStyle::SingleQuoted, _));
|
||||||
|
next!(p, DocumentStart);
|
||||||
|
next!(p, Scalar(TScalarStyle::SingleQuoted, _));
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_a_flow_sequence() {
|
||||||
|
let s = "[item 1, item 2, item 3]";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, FlowSequenceStart);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 1");
|
||||||
|
next!(p, FlowEntry);
|
||||||
|
next!(p, Scalar(TScalarStyle::Plain, _));
|
||||||
|
next!(p, FlowEntry);
|
||||||
|
next!(p, Scalar(TScalarStyle::Plain, _));
|
||||||
|
next!(p, FlowSequenceEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_a_flow_mapping() {
|
||||||
|
let s = "
|
||||||
|
{
|
||||||
|
a simple key: a value, # Note that the KEY token is produced.
|
||||||
|
? a complex key: another value,
|
||||||
|
}
|
||||||
|
";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, FlowMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next!(p, Scalar(TScalarStyle::Plain, _));
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, Scalar(TScalarStyle::Plain, _));
|
||||||
|
next!(p, FlowEntry);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "a complex key");
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, Scalar(TScalarStyle::Plain, _));
|
||||||
|
next!(p, FlowEntry);
|
||||||
|
next!(p, FlowMappingEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_block_sequences() {
|
||||||
|
let s = "
|
||||||
|
- item 1
|
||||||
|
- item 2
|
||||||
|
-
|
||||||
|
- item 3.1
|
||||||
|
- item 3.2
|
||||||
|
-
|
||||||
|
key 1: value 1
|
||||||
|
key 2: value 2
|
||||||
|
";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, BlockSequenceStart);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 1");
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 2");
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next!(p, BlockSequenceStart);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 3.1");
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 3.2");
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next!(p, BlockMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "key 1");
|
||||||
|
next!(p, Value);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "value 1");
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "key 2");
|
||||||
|
next!(p, Value);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "value 2");
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_block_mappings() {
|
||||||
|
let s = "
|
||||||
|
a simple key: a value # The KEY token is produced here.
|
||||||
|
? a complex key
|
||||||
|
: another value
|
||||||
|
a mapping:
|
||||||
|
key 1: value 1
|
||||||
|
key 2: value 2
|
||||||
|
a sequence:
|
||||||
|
- item 1
|
||||||
|
- item 2
|
||||||
|
";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, BlockMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, Key);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, Key);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, Value); // libyaml comment seems to be wrong
|
||||||
|
next!(p, BlockMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, Key);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, Key);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, BlockSequenceStart);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next!(p, Scalar(_, _));
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_block_sequence_start() {
|
||||||
|
let s = "
|
||||||
|
key:
|
||||||
|
- item 1
|
||||||
|
- item 2
|
||||||
|
";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, BlockMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "key");
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 1");
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 2");
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_collections_in_sequence() {
|
||||||
|
let s = "
|
||||||
|
- - item 1
|
||||||
|
- item 2
|
||||||
|
- key 1: value 1
|
||||||
|
key 2: value 2
|
||||||
|
- ? complex key
|
||||||
|
: complex value
|
||||||
|
";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, BlockSequenceStart);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next!(p, BlockSequenceStart);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 1");
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 2");
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next!(p, BlockMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "key 1");
|
||||||
|
next!(p, Value);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "value 1");
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "key 2");
|
||||||
|
next!(p, Value);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "value 2");
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next!(p, BlockMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "complex key");
|
||||||
|
next!(p, Value);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "complex value");
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_collections_in_mapping() {
|
||||||
|
let s = "
|
||||||
|
? a sequence
|
||||||
|
: - item 1
|
||||||
|
- item 2
|
||||||
|
? a mapping
|
||||||
|
: key 1: value 1
|
||||||
|
key 2: value 2
|
||||||
|
";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, BlockMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "a sequence");
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, BlockSequenceStart);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 1");
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "item 2");
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "a mapping");
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, BlockMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "key 1");
|
||||||
|
next!(p, Value);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "value 1");
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "key 2");
|
||||||
|
next!(p, Value);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "value 2");
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_spec_ex7_3() {
|
||||||
|
let s = "
|
||||||
|
{
|
||||||
|
? foo :,
|
||||||
|
: bar,
|
||||||
|
}
|
||||||
|
";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, FlowMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "foo");
|
||||||
|
next!(p, Value);
|
||||||
|
next!(p, FlowEntry);
|
||||||
|
next!(p, Value);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "bar");
|
||||||
|
next!(p, FlowEntry);
|
||||||
|
next!(p, FlowMappingEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_plain_scalar_starting_with_indicators_in_flow() {
|
||||||
|
// "Plain scalars must not begin with most indicators, as this would cause ambiguity with
|
||||||
|
// other YAML constructs. However, the “:”, “?” and “-” indicators may be used as the first
|
||||||
|
// character if followed by a non-space “safe” character, as this causes no ambiguity."
|
||||||
|
|
||||||
|
let s = "{a: :b}";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, FlowMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "a");
|
||||||
|
next!(p, Value);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, ":b");
|
||||||
|
next!(p, FlowMappingEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
|
||||||
|
let s = "{a: ?b}";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, FlowMappingStart);
|
||||||
|
next!(p, Key);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "a");
|
||||||
|
next!(p, Value);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "?b");
|
||||||
|
next!(p, FlowMappingEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_plain_scalar_starting_with_indicators_in_block() {
|
||||||
|
let s = ":a";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, ":a");
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
|
||||||
|
let s = "?a";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "?a");
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_plain_scalar_containing_indicators_in_block() {
|
||||||
|
let s = "a:,b";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "a:,b");
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
|
||||||
|
let s = ":,b";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, ":,b");
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scanner_cr() {
|
||||||
|
let s = "---\r\n- tok1\r\n- tok2";
|
||||||
|
let mut p = Scanner::new(s.chars());
|
||||||
|
next!(p, StreamStart(..));
|
||||||
|
next!(p, DocumentStart);
|
||||||
|
next!(p, BlockSequenceStart);
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "tok1");
|
||||||
|
next!(p, BlockEntry);
|
||||||
|
next_scalar!(p, TScalarStyle::Plain, "tok2");
|
||||||
|
next!(p, BlockEnd);
|
||||||
|
next!(p, StreamEnd);
|
||||||
|
end!(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uri() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_uri_escapes() {
|
||||||
|
// TODO
|
||||||
|
}
|
|
@ -282,6 +282,7 @@ fn expected_events(expected_tree: &str) -> Vec<String> {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
static EXPECTED_FAILURES: &[&str] = &[
|
static EXPECTED_FAILURES: &[&str] = &[
|
||||||
// These seem to be API limited (not enough information on the event stream level)
|
// These seem to be API limited (not enough information on the event stream level)
|
||||||
// No tag available for SEQ and MAP
|
// No tag available for SEQ and MAP
|
||||||
|
@ -339,10 +340,8 @@ static EXPECTED_FAILURES: &[&str] = &[
|
||||||
"HWV9",
|
"HWV9",
|
||||||
"QT73",
|
"QT73",
|
||||||
// Unusual characters in anchors/aliases
|
// Unusual characters in anchors/aliases
|
||||||
"2SXE", // :
|
|
||||||
"8XYN", // emoji!!
|
"8XYN", // emoji!!
|
||||||
"W5VH", // :@*!$"<foo>:
|
"W5VH", // :@*!$"<foo>:
|
||||||
"Y2GN", // : in the middle
|
|
||||||
// Flow mapping colon on next line / multiline key in flow mapping
|
// Flow mapping colon on next line / multiline key in flow mapping
|
||||||
"4MUZ-00",
|
"4MUZ-00",
|
||||||
"4MUZ-01",
|
"4MUZ-01",
|
||||||
|
|
Loading…
Reference in a new issue