Add documentation and move tests to their folder.
This commit is contained in:
parent
fd37ebd6e5
commit
0c4a395829
4 changed files with 597 additions and 480 deletions
|
@ -13,21 +13,14 @@
|
|||
//! yaml-rust = "0.4"
|
||||
//! ```
|
||||
//!
|
||||
//! And this in your crate root:
|
||||
//!
|
||||
//! ```rust
|
||||
//! extern crate yaml_rust;
|
||||
//! ```
|
||||
//!
|
||||
//! Parse a string into `Vec<Yaml>` and then serialize it as a YAML string.
|
||||
//!
|
||||
//! # Examples
|
||||
//! Parse a string into `Vec<Yaml>` and then serialize it as a YAML string.
|
||||
//!
|
||||
//! ```
|
||||
//! use yaml_rust::{YamlLoader, YamlEmitter};
|
||||
//!
|
||||
//! let docs = YamlLoader::load_from_str("[1, 2, 3]").unwrap();
|
||||
//! let doc = &docs[0]; // select the first document
|
||||
//! let doc = &docs[0]; // select the first YAML document
|
||||
//! assert_eq!(doc[0].as_i64().unwrap(), 1); // access elements by index
|
||||
//!
|
||||
//! let mut out_str = String::new();
|
||||
|
@ -61,65 +54,3 @@ pub use crate::emitter::{EmitError, YamlEmitter};
|
|||
pub use crate::parser::Event;
|
||||
pub use crate::scanner::ScanError;
|
||||
pub use crate::yaml::{Yaml, YamlLoader};
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_api() {
|
||||
let s = "
|
||||
# from yaml-cpp example
|
||||
- name: Ogre
|
||||
position: [0, 5, 0]
|
||||
powers:
|
||||
- name: Club
|
||||
damage: 10
|
||||
- name: Fist
|
||||
damage: 8
|
||||
- name: Dragon
|
||||
position: [1, 0, 10]
|
||||
powers:
|
||||
- name: Fire Breath
|
||||
damage: 25
|
||||
- name: Claws
|
||||
damage: 15
|
||||
- name: Wizard
|
||||
position: [5, -3, 0]
|
||||
powers:
|
||||
- name: Acid Rain
|
||||
damage: 50
|
||||
- name: Staff
|
||||
damage: 3
|
||||
";
|
||||
let docs = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &docs[0];
|
||||
|
||||
assert_eq!(doc[0]["name"].as_str().unwrap(), "Ogre");
|
||||
|
||||
let mut writer = String::new();
|
||||
{
|
||||
let mut emitter = YamlEmitter::new(&mut writer);
|
||||
emitter.dump(doc).unwrap();
|
||||
}
|
||||
|
||||
assert!(!writer.is_empty());
|
||||
}
|
||||
|
||||
fn try_fail(s: &str) -> Result<Vec<Yaml>, ScanError> {
|
||||
let t = YamlLoader::load_from_str(s)?;
|
||||
Ok(t)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fail() {
|
||||
let s = "
|
||||
# syntax error
|
||||
scalar
|
||||
key: [1, 2]]
|
||||
key1:a2
|
||||
";
|
||||
assert!(YamlLoader::load_from_str(s).is_err());
|
||||
assert!(try_fail(s).is_err());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,57 +29,145 @@ enum State {
|
|||
End,
|
||||
}
|
||||
|
||||
/// `Event` is used with the low-level event base parsing API,
|
||||
/// see `EventReceiver` trait.
|
||||
/// An event generated by the YAML parser.
|
||||
///
|
||||
/// Events are used in the low-level event-based API (push parser). The API entrypoint is the
|
||||
/// [`EventReceiver`] trait.
|
||||
#[derive(Clone, PartialEq, Debug, Eq)]
|
||||
pub enum Event {
|
||||
/// Reserved for internal use
|
||||
/// Reserved for internal use.
|
||||
Nothing,
|
||||
/// Event generated at the very beginning of parsing.
|
||||
StreamStart,
|
||||
/// Last event that will be generated by the parser. Signals EOF.
|
||||
StreamEnd,
|
||||
/// The YAML start document directive (`---`).
|
||||
DocumentStart,
|
||||
/// The YAML end document directive (`...`).
|
||||
DocumentEnd,
|
||||
/// Refer to an anchor ID
|
||||
Alias(usize),
|
||||
/// A YAML Alias.
|
||||
Alias(
|
||||
/// The anchor ID the alias refers to.
|
||||
usize,
|
||||
),
|
||||
/// Value, style, anchor_id, tag
|
||||
Scalar(String, TScalarStyle, usize, Option<TokenType>),
|
||||
/// Anchor ID
|
||||
SequenceStart(usize),
|
||||
SequenceStart(
|
||||
/// The anchor ID of the start of the squence.
|
||||
usize,
|
||||
),
|
||||
SequenceEnd,
|
||||
/// Anchor ID
|
||||
MappingStart(usize),
|
||||
MappingStart(
|
||||
/// The anchor ID of the start of the mapping.
|
||||
usize,
|
||||
),
|
||||
MappingEnd,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
/// Create an empty scalar.
|
||||
fn empty_scalar() -> Event {
|
||||
// a null scalar
|
||||
Event::Scalar("~".to_owned(), TScalarStyle::Plain, 0, None)
|
||||
}
|
||||
|
||||
/// Create an empty scalar with the given anchor.
|
||||
fn empty_scalar_with_anchor(anchor: usize, tag: Option<TokenType>) -> Event {
|
||||
Event::Scalar(String::new(), TScalarStyle::Plain, anchor, tag)
|
||||
}
|
||||
}
|
||||
|
||||
/// A YAML parser.
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Parser<T> {
|
||||
scanner: Scanner<T>,
|
||||
states: Vec<State>,
|
||||
state: State,
|
||||
marks: Vec<Marker>,
|
||||
token: Option<Token>,
|
||||
current: Option<(Event, Marker)>,
|
||||
anchors: HashMap<String, usize>,
|
||||
anchor_id: usize,
|
||||
}
|
||||
|
||||
/// Trait to be implemented in order to use the low-level parsing API.
|
||||
///
|
||||
/// The low-level parsing API is event-based (a push parser), calling [`EventReceiver::on_event`]
|
||||
/// for each YAML [`Event`] that occurs.
|
||||
/// The [`EventReceiver`] trait only receives events. In order to receive both events and their
|
||||
/// location in the source, use [`MarkedEventReceiver`]. Note that [`EventReceiver`]s implement
|
||||
/// [`MarkedEventReceiver`] automatically.
|
||||
///
|
||||
/// # Event hierarchy
|
||||
/// The event stream starts with an [`Event::StreamStart`] event followed by an
|
||||
/// [`Event::DocumentStart`] event. If the YAML document starts with a mapping (an object), an
|
||||
/// [`Event::MappingStart`] event is emitted. If it starts with a sequence (an array), an
|
||||
/// [`Event::SequenceStart`] event is emitted. Otherwise, an [`Event::Scalar`] event is emitted.
|
||||
///
|
||||
/// In a mapping, key-values are sent as consecutive events. The first event after an
|
||||
/// [`Event::MappingStart`] will be the key, and following its value. If the mapping contains no
|
||||
/// sub-mapping or sub-sequence, then even events (starting from 0) will always be keys and odd
|
||||
/// ones will always be values. The mapping ends when an [`Event::MappingEnd`] event is received.
|
||||
///
|
||||
/// In a sequence, values are sent consecutively until the [`Event::SequenceEnd`] event.
|
||||
///
|
||||
/// If a value is a sub-mapping or a sub-sequence, an [`Event::MappingStart`] or
|
||||
/// [`Event::SequenceStart`] event will be sent respectively. Following events until the associated
|
||||
/// [`Event::MappingStart`] or [`Event::SequenceEnd`] (beware of nested mappings or sequences) will
|
||||
/// be part of the value and not another key-value pair or element in the sequence.
|
||||
///
|
||||
/// For instance, the following yaml:
|
||||
/// ```yaml
|
||||
/// a: b
|
||||
/// c:
|
||||
/// d: e
|
||||
/// f:
|
||||
/// - g
|
||||
/// - h
|
||||
/// ```
|
||||
/// will emit (indented and commented for lisibility):
|
||||
/// ```text
|
||||
/// StreamStart, DocumentStart, MappingStart,
|
||||
/// Scalar("a", ..), Scalar("b", ..)
|
||||
/// Scalar("c", ..), MappingStart, Scalar("d", ..), Scalar("e", ..), MappingEnd,
|
||||
/// Scalar("f", ..), SequenceStart, Scalar("g", ..), Scalar("h", ..), SequenceEnd,
|
||||
/// MappingEnd, DocumentEnd, StreamEnd
|
||||
/// ```
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # use yaml_rust::parser::{Event, EventReceiver, Parser};
|
||||
/// #
|
||||
/// /// Sink of events. Collects them into an array.
|
||||
/// struct EventSink {
|
||||
/// events: Vec<Event>,
|
||||
/// }
|
||||
///
|
||||
/// /// Implement `on_event`, pushing into `self.events`.
|
||||
/// impl EventReceiver for EventSink {
|
||||
/// fn on_event(&mut self, ev: Event) {
|
||||
/// self.events.push(ev);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// /// Load events from a yaml string.
|
||||
/// fn str_to_events(yaml: &str) -> Vec<Event> {
|
||||
/// let mut sink = EventSink { events: Vec::new() };
|
||||
/// let mut parser = Parser::new(yaml.chars());
|
||||
/// // Load events using our sink as the receiver.
|
||||
/// parser.load(&mut sink, true).unwrap();
|
||||
/// sink.events
|
||||
/// }
|
||||
/// ```
|
||||
pub trait EventReceiver {
|
||||
/// Handler called for each YAML event that is emitted by the parser.
|
||||
fn on_event(&mut self, ev: Event);
|
||||
}
|
||||
|
||||
/// Trait to be implemented for using the low-level parsing API.
|
||||
///
|
||||
/// Functionally similar to [`EventReceiver`], but receives a [`Marker`] as well as the event.
|
||||
pub trait MarkedEventReceiver {
|
||||
/// Handler called for each event that occurs.
|
||||
fn on_event(&mut self, ev: Event, _mark: Marker);
|
||||
}
|
||||
|
||||
|
@ -92,12 +180,12 @@ impl<R: EventReceiver> MarkedEventReceiver for R {
|
|||
pub type ParseResult = Result<(Event, Marker), ScanError>;
|
||||
|
||||
impl<T: Iterator<Item = char>> Parser<T> {
|
||||
/// Crate a new instance of a parser from the given input of characters.
|
||||
pub fn new(src: T) -> Parser<T> {
|
||||
Parser {
|
||||
scanner: Scanner::new(src),
|
||||
states: Vec::new(),
|
||||
state: State::StreamStart,
|
||||
marks: Vec::new(),
|
||||
token: None,
|
||||
current: None,
|
||||
|
||||
|
@ -107,6 +195,10 @@ impl<T: Iterator<Item = char>> Parser<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Try to load the next event and return it, but do not consuming it from `self`.
|
||||
///
|
||||
/// Any subsequent call to [`Parser::peek`] will return the same value, until a call to
|
||||
/// [`Parser::next`] or [`Parser::load`].
|
||||
pub fn peek(&mut self) -> Result<&(Event, Marker), ScanError> {
|
||||
if let Some(ref x) = self.current {
|
||||
Ok(x)
|
||||
|
@ -116,10 +208,11 @@ impl<T: Iterator<Item = char>> Parser<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Try to load the next event and return it, consuming it from `self`.
|
||||
pub fn next(&mut self) -> ParseResult {
|
||||
match self.current {
|
||||
match self.current.take() {
|
||||
None => self.parse(),
|
||||
Some(_) => Ok(self.current.take().unwrap()),
|
||||
Some(v) => Ok(v),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,6 +263,16 @@ impl<T: Iterator<Item = char>> Parser<T> {
|
|||
Ok((ev, mark))
|
||||
}
|
||||
|
||||
/// Load the YAML from the stream in `self`, pushing events into `recv`.
|
||||
///
|
||||
/// The contents of the stream are parsed and the corresponding events are sent into the
|
||||
/// recveiver. For detailed explanations about how events work, see [`EventReceiver`].
|
||||
///
|
||||
/// If `multi` is set to `true`, the parser will allow parsing of multiple YAML documents
|
||||
/// inside the stream.
|
||||
///
|
||||
/// Note that any [`EventReceiver`] is also a [`MarkedEventReceiver`], so implementing the
|
||||
/// former is enough to call this function.
|
||||
pub fn load<R: MarkedEventReceiver>(
|
||||
&mut self,
|
||||
recv: &mut R,
|
||||
|
|
|
@ -4,12 +4,8 @@ use crate::parser::{Event, MarkedEventReceiver, Parser};
|
|||
use crate::scanner::{Marker, ScanError, TScalarStyle, TokenType};
|
||||
use linked_hash_map::LinkedHashMap;
|
||||
use std::collections::BTreeMap;
|
||||
use std::f64;
|
||||
use std::i64;
|
||||
use std::mem;
|
||||
use std::ops::Index;
|
||||
use std::string;
|
||||
use std::vec;
|
||||
|
||||
/// A YAML node is stored as this `Yaml` enumeration, which provides an easy way to
|
||||
/// access your YAML document.
|
||||
|
@ -30,20 +26,20 @@ use std::vec;
|
|||
#[derive(Clone, PartialEq, PartialOrd, Debug, Eq, Ord, Hash)]
|
||||
pub enum Yaml {
|
||||
/// Float types are stored as String and parsed on demand.
|
||||
/// Note that f64 does NOT implement Eq trait and can NOT be stored in BTreeMap.
|
||||
Real(string::String),
|
||||
/// Note that `f64` does NOT implement Eq trait and can NOT be stored in `BTreeMap`.
|
||||
Real(String),
|
||||
/// YAML int is stored as i64.
|
||||
Integer(i64),
|
||||
/// YAML scalar.
|
||||
String(string::String),
|
||||
String(String),
|
||||
/// YAML bool, e.g. `true` or `false`.
|
||||
Boolean(bool),
|
||||
/// YAML array, can be accessed as a `Vec`.
|
||||
Array(self::Array),
|
||||
Array(Array),
|
||||
/// YAML hash, can be accessed as a `LinkedHashMap`.
|
||||
///
|
||||
/// Insertion order will match the order of insertion into the map.
|
||||
Hash(self::Hash),
|
||||
Hash(Hash),
|
||||
/// Alias, not fully supported yet.
|
||||
Alias(usize),
|
||||
/// YAML null, e.g. `null` or `~`.
|
||||
|
@ -68,6 +64,9 @@ fn parse_f64(v: &str) -> Option<f64> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Main structure for quickly parsing YAML.
|
||||
///
|
||||
/// See [`YamlLoader::load_from_str`].
|
||||
pub struct YamlLoader {
|
||||
docs: Vec<Yaml>,
|
||||
// states
|
||||
|
@ -188,14 +187,28 @@ impl YamlLoader {
|
|||
}
|
||||
}
|
||||
|
||||
/// Load the given string as a set of YAML documents.
|
||||
///
|
||||
/// The `source` is interpreted as YAML documents and is parsed. Parsing succeeds if and only
|
||||
/// if all documents are parsed successfully. An error in a latter document prevents the former
|
||||
/// from being returned.
|
||||
pub fn load_from_str(source: &str) -> Result<Vec<Yaml>, ScanError> {
|
||||
Self::load_from_iter(source.chars())
|
||||
}
|
||||
|
||||
/// Load the contents of the given iterator as a set of YAML documents.
|
||||
///
|
||||
/// The `source` is interpreted as YAML documents and is parsed. Parsing succeeds if and only
|
||||
/// if all documents are parsed successfully. An error in a latter document prevents the former
|
||||
/// from being returned.
|
||||
pub fn load_from_iter<I: Iterator<Item = char>>(source: I) -> Result<Vec<Yaml>, ScanError> {
|
||||
let mut loader = YamlLoader {
|
||||
docs: Vec::new(),
|
||||
doc_stack: Vec::new(),
|
||||
key_stack: Vec::new(),
|
||||
anchor_map: BTreeMap::new(),
|
||||
};
|
||||
let mut parser = Parser::new(source.chars());
|
||||
let mut parser = Parser::new(source);
|
||||
parser.load(&mut loader, true)?;
|
||||
Ok(loader.docs)
|
||||
}
|
||||
|
@ -251,23 +264,28 @@ impl Yaml {
|
|||
define_into!(into_hash, Hash, Hash);
|
||||
define_into!(into_vec, Array, Array);
|
||||
|
||||
/// Returns the is null of this [`Yaml`].
|
||||
/// Return whether `self` is a [`Yaml::Null`] node.
|
||||
#[must_use]
|
||||
pub fn is_null(&self) -> bool {
|
||||
matches!(*self, Yaml::Null)
|
||||
}
|
||||
|
||||
/// Returns the is badvalue of this [`Yaml`].
|
||||
/// Return whether `self` is a [`Yaml::BadValue`] node.
|
||||
#[must_use]
|
||||
pub fn is_badvalue(&self) -> bool {
|
||||
matches!(*self, Yaml::BadValue)
|
||||
}
|
||||
|
||||
/// Return whether `self` is a [`Yaml::Array`] node.
|
||||
#[must_use]
|
||||
pub fn is_array(&self) -> bool {
|
||||
matches!(*self, Yaml::Array(_))
|
||||
}
|
||||
|
||||
/// Return the `f64` value contained in this YAML node.
|
||||
///
|
||||
/// If the node is not a [`Yaml::Real`] YAML node or its contents is not a valid `f64` string,
|
||||
/// `None` is returned.
|
||||
#[must_use]
|
||||
pub fn as_f64(&self) -> Option<f64> {
|
||||
if let Yaml::Real(ref v) = self {
|
||||
|
@ -277,20 +295,35 @@ impl Yaml {
|
|||
}
|
||||
}
|
||||
|
||||
/// Return the `f64` value contained in this YAML node.
|
||||
///
|
||||
/// If the node is not a [`Yaml::Real`] YAML node or its contents is not a valid `f64` string,
|
||||
/// `None` is returned.
|
||||
#[must_use]
|
||||
pub fn into_f64(self) -> Option<f64> {
|
||||
if let Yaml::Real(ref v) = self {
|
||||
parse_f64(v)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
self.as_f64()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(clippy::should_implement_trait))]
|
||||
impl Yaml {
|
||||
// Not implementing FromStr because there is no possibility of Error.
|
||||
// This function falls back to Yaml::String if nothing else matches.
|
||||
/// Convert a string to a [`Yaml`] node.
|
||||
///
|
||||
/// [`Yaml`] does not implement [`std::str::FromStr`] since conversion may not fail. This
|
||||
/// function falls back to [`Yaml::String`] if nothing else matches.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use yaml_rust::yaml::Yaml;
|
||||
/// assert!(matches!(Yaml::from_str("42"), Yaml::Integer(42)));
|
||||
/// assert!(matches!(Yaml::from_str("0x2A"), Yaml::Integer(42)));
|
||||
/// assert!(matches!(Yaml::from_str("0o52"), Yaml::Integer(42)));
|
||||
/// assert!(matches!(Yaml::from_str("~"), Yaml::Null));
|
||||
/// assert!(matches!(Yaml::from_str("null"), Yaml::Null));
|
||||
/// assert!(matches!(Yaml::from_str("true"), Yaml::Boolean(true)));
|
||||
/// assert!(matches!(Yaml::from_str("3.14"), Yaml::Real(_)));
|
||||
/// assert!(matches!(Yaml::from_str("foo"), Yaml::String(_)));
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn from_str(v: &str) -> Yaml {
|
||||
if let Some(number) = v.strip_prefix("0x") {
|
||||
|
@ -362,8 +395,9 @@ impl IntoIterator for Yaml {
|
|||
}
|
||||
}
|
||||
|
||||
/// An iterator over a [`Yaml`] node.
|
||||
pub struct YamlIter {
|
||||
yaml: vec::IntoIter<Yaml>,
|
||||
yaml: std::vec::IntoIter<Yaml>,
|
||||
}
|
||||
|
||||
impl Iterator for YamlIter {
|
||||
|
@ -373,378 +407,3 @@ impl Iterator for YamlIter {
|
|||
self.yaml.next()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(clippy::bool_assert_comparison)]
|
||||
#[allow(clippy::float_cmp)]
|
||||
mod test {
|
||||
use crate::yaml::{vec, Yaml, YamlLoader};
|
||||
use std::f64;
|
||||
#[test]
|
||||
fn test_coerce() {
|
||||
let s = "---
|
||||
a: 1
|
||||
b: 2.2
|
||||
c: [1, 2]
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out[0];
|
||||
assert_eq!(doc["a"].as_i64().unwrap(), 1i64);
|
||||
assert_eq!(doc["b"].as_f64().unwrap(), 2.2f64);
|
||||
assert_eq!(doc["c"][1].as_i64().unwrap(), 2i64);
|
||||
assert!(doc["d"][0].is_badvalue());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_doc() {
|
||||
let s: String = String::new();
|
||||
YamlLoader::load_from_str(&s).unwrap();
|
||||
let s: String = "---".to_owned();
|
||||
assert_eq!(YamlLoader::load_from_str(&s).unwrap()[0], Yaml::Null);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parser() {
|
||||
let s: String = "
|
||||
# comment
|
||||
a0 bb: val
|
||||
a1:
|
||||
b1: 4
|
||||
b2: d
|
||||
a2: 4 # i'm comment
|
||||
a3: [1, 2, 3]
|
||||
a4:
|
||||
- - a1
|
||||
- a2
|
||||
- 2
|
||||
a5: 'single_quoted'
|
||||
a6: \"double_quoted\"
|
||||
a7: 你好
|
||||
"
|
||||
.to_owned();
|
||||
let out = YamlLoader::load_from_str(&s).unwrap();
|
||||
let doc = &out[0];
|
||||
assert_eq!(doc["a7"].as_str().unwrap(), "你好");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_doc() {
|
||||
let s = "
|
||||
'a scalar'
|
||||
---
|
||||
'a scalar'
|
||||
---
|
||||
'a scalar'
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
assert_eq!(out.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anchor() {
|
||||
let s = "
|
||||
a1: &DEFAULT
|
||||
b1: 4
|
||||
b2: d
|
||||
a2: *DEFAULT
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out[0];
|
||||
assert_eq!(doc["a2"]["b1"].as_i64().unwrap(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_anchor() {
|
||||
let s = "
|
||||
a1: &DEFAULT
|
||||
b1: 4
|
||||
b2: *DEFAULT
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out[0];
|
||||
assert_eq!(doc["a1"]["b2"], Yaml::BadValue);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_github_27() {
|
||||
// https://github.com/chyh1990/yaml-rust/issues/27
|
||||
let s = "&a";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out[0];
|
||||
assert_eq!(doc.as_str().unwrap(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_plain_datatype() {
|
||||
let s = "
|
||||
- 'string'
|
||||
- \"string\"
|
||||
- string
|
||||
- 123
|
||||
- -321
|
||||
- 1.23
|
||||
- -1e4
|
||||
- ~
|
||||
- null
|
||||
- true
|
||||
- false
|
||||
- !!str 0
|
||||
- !!int 100
|
||||
- !!float 2
|
||||
- !!null ~
|
||||
- !!bool true
|
||||
- !!bool false
|
||||
- 0xFF
|
||||
# bad values
|
||||
- !!int string
|
||||
- !!float string
|
||||
- !!bool null
|
||||
- !!null val
|
||||
- 0o77
|
||||
- [ 0xF, 0xF ]
|
||||
- +12345
|
||||
- [ true, false ]
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out[0];
|
||||
|
||||
assert_eq!(doc[0].as_str().unwrap(), "string");
|
||||
assert_eq!(doc[1].as_str().unwrap(), "string");
|
||||
assert_eq!(doc[2].as_str().unwrap(), "string");
|
||||
assert_eq!(doc[3].as_i64().unwrap(), 123);
|
||||
assert_eq!(doc[4].as_i64().unwrap(), -321);
|
||||
assert_eq!(doc[5].as_f64().unwrap(), 1.23);
|
||||
assert_eq!(doc[6].as_f64().unwrap(), -1e4);
|
||||
assert!(doc[7].is_null());
|
||||
assert!(doc[8].is_null());
|
||||
assert_eq!(doc[9].as_bool().unwrap(), true);
|
||||
assert_eq!(doc[10].as_bool().unwrap(), false);
|
||||
assert_eq!(doc[11].as_str().unwrap(), "0");
|
||||
assert_eq!(doc[12].as_i64().unwrap(), 100);
|
||||
assert_eq!(doc[13].as_f64().unwrap(), 2.0);
|
||||
assert!(doc[14].is_null());
|
||||
assert_eq!(doc[15].as_bool().unwrap(), true);
|
||||
assert_eq!(doc[16].as_bool().unwrap(), false);
|
||||
assert_eq!(doc[17].as_i64().unwrap(), 255);
|
||||
assert!(doc[18].is_badvalue());
|
||||
assert!(doc[19].is_badvalue());
|
||||
assert!(doc[20].is_badvalue());
|
||||
assert!(doc[21].is_badvalue());
|
||||
assert_eq!(doc[22].as_i64().unwrap(), 63);
|
||||
assert_eq!(doc[23][0].as_i64().unwrap(), 15);
|
||||
assert_eq!(doc[23][1].as_i64().unwrap(), 15);
|
||||
assert_eq!(doc[24].as_i64().unwrap(), 12345);
|
||||
assert!(doc[25][0].as_bool().unwrap());
|
||||
assert!(!doc[25][1].as_bool().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_hyphen() {
|
||||
// See: https://github.com/chyh1990/yaml-rust/issues/23
|
||||
let s = "{-";
|
||||
assert!(YamlLoader::load_from_str(s).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_issue_65() {
|
||||
// See: https://github.com/chyh1990/yaml-rust/issues/65
|
||||
let b = "\n\"ll\\\"ll\\\r\n\"ll\\\"ll\\\r\r\r\rU\r\r\rU";
|
||||
assert!(YamlLoader::load_from_str(b).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_docstart() {
|
||||
assert!(YamlLoader::load_from_str("---This used to cause an infinite loop").is_ok());
|
||||
assert_eq!(
|
||||
YamlLoader::load_from_str("----"),
|
||||
Ok(vec![Yaml::String(String::from("----"))])
|
||||
);
|
||||
assert_eq!(
|
||||
YamlLoader::load_from_str("--- #here goes a comment"),
|
||||
Ok(vec![Yaml::Null])
|
||||
);
|
||||
assert_eq!(
|
||||
YamlLoader::load_from_str("---- #here goes a comment"),
|
||||
Ok(vec![Yaml::String(String::from("----"))])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_plain_datatype_with_into_methods() {
|
||||
let s = "
|
||||
- 'string'
|
||||
- \"string\"
|
||||
- string
|
||||
- 123
|
||||
- -321
|
||||
- 1.23
|
||||
- -1e4
|
||||
- true
|
||||
- false
|
||||
- !!str 0
|
||||
- !!int 100
|
||||
- !!float 2
|
||||
- !!bool true
|
||||
- !!bool false
|
||||
- 0xFF
|
||||
- 0o77
|
||||
- +12345
|
||||
- -.INF
|
||||
- .NAN
|
||||
- !!float .INF
|
||||
";
|
||||
let mut out = YamlLoader::load_from_str(s).unwrap().into_iter();
|
||||
let mut doc = out.next().unwrap().into_iter();
|
||||
|
||||
assert_eq!(doc.next().unwrap().into_string().unwrap(), "string");
|
||||
assert_eq!(doc.next().unwrap().into_string().unwrap(), "string");
|
||||
assert_eq!(doc.next().unwrap().into_string().unwrap(), "string");
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 123);
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), -321);
|
||||
assert_eq!(doc.next().unwrap().into_f64().unwrap(), 1.23);
|
||||
assert_eq!(doc.next().unwrap().into_f64().unwrap(), -1e4);
|
||||
assert_eq!(doc.next().unwrap().into_bool().unwrap(), true);
|
||||
assert_eq!(doc.next().unwrap().into_bool().unwrap(), false);
|
||||
assert_eq!(doc.next().unwrap().into_string().unwrap(), "0");
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 100);
|
||||
assert_eq!(doc.next().unwrap().into_f64().unwrap(), 2.0);
|
||||
assert_eq!(doc.next().unwrap().into_bool().unwrap(), true);
|
||||
assert_eq!(doc.next().unwrap().into_bool().unwrap(), false);
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 255);
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 63);
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 12345);
|
||||
assert_eq!(doc.next().unwrap().into_f64().unwrap(), f64::NEG_INFINITY);
|
||||
assert!(doc.next().unwrap().into_f64().is_some());
|
||||
assert_eq!(doc.next().unwrap().into_f64().unwrap(), f64::INFINITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_order() {
|
||||
let s = "---
|
||||
b: ~
|
||||
a: ~
|
||||
c: ~
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let first = out.into_iter().next().unwrap();
|
||||
let mut iter = first.into_hash().unwrap().into_iter();
|
||||
assert_eq!(
|
||||
Some((Yaml::String("b".to_owned()), Yaml::Null)),
|
||||
iter.next()
|
||||
);
|
||||
assert_eq!(
|
||||
Some((Yaml::String("a".to_owned()), Yaml::Null)),
|
||||
iter.next()
|
||||
);
|
||||
assert_eq!(
|
||||
Some((Yaml::String("c".to_owned()), Yaml::Null)),
|
||||
iter.next()
|
||||
);
|
||||
assert_eq!(None, iter.next());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_integer_key() {
|
||||
let s = "
|
||||
0:
|
||||
important: true
|
||||
1:
|
||||
important: false
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let first = out.into_iter().next().unwrap();
|
||||
assert_eq!(first[0]["important"].as_bool().unwrap(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_indentation_equality() {
|
||||
let four_spaces = YamlLoader::load_from_str(
|
||||
r#"
|
||||
hash:
|
||||
with:
|
||||
indentations
|
||||
"#,
|
||||
)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let two_spaces = YamlLoader::load_from_str(
|
||||
r#"
|
||||
hash:
|
||||
with:
|
||||
indentations
|
||||
"#,
|
||||
)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let one_space = YamlLoader::load_from_str(
|
||||
r#"
|
||||
hash:
|
||||
with:
|
||||
indentations
|
||||
"#,
|
||||
)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let mixed_spaces = YamlLoader::load_from_str(
|
||||
r#"
|
||||
hash:
|
||||
with:
|
||||
indentations
|
||||
"#,
|
||||
)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(four_spaces, two_spaces);
|
||||
assert_eq!(two_spaces, one_space);
|
||||
assert_eq!(four_spaces, mixed_spaces);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_two_space_indentations() {
|
||||
// https://github.com/kbknapp/clap-rs/issues/965
|
||||
|
||||
let s = r#"
|
||||
subcommands:
|
||||
- server:
|
||||
about: server related commands
|
||||
subcommands2:
|
||||
- server:
|
||||
about: server related commands
|
||||
subcommands3:
|
||||
- server:
|
||||
about: server related commands
|
||||
"#;
|
||||
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out.into_iter().next().unwrap();
|
||||
|
||||
println!("{doc:#?}");
|
||||
assert_eq!(doc["subcommands"][0]["server"], Yaml::Null);
|
||||
assert!(doc["subcommands2"][0]["server"].as_hash().is_some());
|
||||
assert!(doc["subcommands3"][0]["server"].as_hash().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_recursion_depth_check_objects() {
|
||||
let s = "{a:".repeat(10_000) + &"}".repeat(10_000);
|
||||
assert!(YamlLoader::load_from_str(&s).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_recursion_depth_check_arrays() {
|
||||
let s = "[".repeat(10_000) + &"]".repeat(10_000);
|
||||
assert!(YamlLoader::load_from_str(&s).is_err());
|
||||
}
|
||||
}
|
||||
|
|
424
saphyr/tests/basic.rs
Normal file
424
saphyr/tests/basic.rs
Normal file
|
@ -0,0 +1,424 @@
|
|||
#![allow(clippy::bool_assert_comparison)]
|
||||
#![allow(clippy::float_cmp)]
|
||||
|
||||
use std::vec;
|
||||
use yaml_rust::{Yaml, YamlEmitter, YamlLoader};
|
||||
|
||||
#[test]
|
||||
fn test_api() {
|
||||
let s = "
|
||||
# from yaml-cpp example
|
||||
- name: Ogre
|
||||
position: [0, 5, 0]
|
||||
powers:
|
||||
- name: Club
|
||||
damage: 10
|
||||
- name: Fist
|
||||
damage: 8
|
||||
- name: Dragon
|
||||
position: [1, 0, 10]
|
||||
powers:
|
||||
- name: Fire Breath
|
||||
damage: 25
|
||||
- name: Claws
|
||||
damage: 15
|
||||
- name: Wizard
|
||||
position: [5, -3, 0]
|
||||
powers:
|
||||
- name: Acid Rain
|
||||
damage: 50
|
||||
- name: Staff
|
||||
damage: 3
|
||||
";
|
||||
let docs = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &docs[0];
|
||||
|
||||
assert_eq!(doc[0]["name"].as_str().unwrap(), "Ogre");
|
||||
|
||||
let mut writer = String::new();
|
||||
{
|
||||
let mut emitter = YamlEmitter::new(&mut writer);
|
||||
emitter.dump(doc).unwrap();
|
||||
}
|
||||
|
||||
assert!(!writer.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fail() {
|
||||
let s = "
|
||||
# syntax error
|
||||
scalar
|
||||
key: [1, 2]]
|
||||
key1:a2
|
||||
";
|
||||
assert!(YamlLoader::load_from_str(s).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_coerce() {
|
||||
let s = "---
|
||||
a: 1
|
||||
b: 2.2
|
||||
c: [1, 2]
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out[0];
|
||||
assert_eq!(doc["a"].as_i64().unwrap(), 1i64);
|
||||
assert_eq!(doc["b"].as_f64().unwrap(), 2.2f64);
|
||||
assert_eq!(doc["c"][1].as_i64().unwrap(), 2i64);
|
||||
assert!(doc["d"][0].is_badvalue());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_empty_doc() {
|
||||
let s: String = String::new();
|
||||
YamlLoader::load_from_str(&s).unwrap();
|
||||
let s: String = "---".to_owned();
|
||||
assert_eq!(YamlLoader::load_from_str(&s).unwrap()[0], Yaml::Null);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parser() {
|
||||
let s: String = "
|
||||
# comment
|
||||
a0 bb: val
|
||||
a1:
|
||||
b1: 4
|
||||
b2: d
|
||||
a2: 4 # i'm comment
|
||||
a3: [1, 2, 3]
|
||||
a4:
|
||||
- - a1
|
||||
- a2
|
||||
- 2
|
||||
a5: 'single_quoted'
|
||||
a6: \"double_quoted\"
|
||||
a7: 你好
|
||||
"
|
||||
.to_owned();
|
||||
let out = YamlLoader::load_from_str(&s).unwrap();
|
||||
let doc = &out[0];
|
||||
assert_eq!(doc["a7"].as_str().unwrap(), "你好");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multi_doc() {
|
||||
let s = "
|
||||
'a scalar'
|
||||
---
|
||||
'a scalar'
|
||||
---
|
||||
'a scalar'
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
assert_eq!(out.len(), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_anchor() {
|
||||
let s = "
|
||||
a1: &DEFAULT
|
||||
b1: 4
|
||||
b2: d
|
||||
a2: *DEFAULT
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out[0];
|
||||
assert_eq!(doc["a2"]["b1"].as_i64().unwrap(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_anchor() {
|
||||
let s = "
|
||||
a1: &DEFAULT
|
||||
b1: 4
|
||||
b2: *DEFAULT
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out[0];
|
||||
assert_eq!(doc["a1"]["b2"], Yaml::BadValue);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_github_27() {
|
||||
// https://github.com/chyh1990/yaml-rust/issues/27
|
||||
let s = "&a";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out[0];
|
||||
assert_eq!(doc.as_str().unwrap(), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_plain_datatype() {
|
||||
let s = "
|
||||
- 'string'
|
||||
- \"string\"
|
||||
- string
|
||||
- 123
|
||||
- -321
|
||||
- 1.23
|
||||
- -1e4
|
||||
- ~
|
||||
- null
|
||||
- true
|
||||
- false
|
||||
- !!str 0
|
||||
- !!int 100
|
||||
- !!float 2
|
||||
- !!null ~
|
||||
- !!bool true
|
||||
- !!bool false
|
||||
- 0xFF
|
||||
# bad values
|
||||
- !!int string
|
||||
- !!float string
|
||||
- !!bool null
|
||||
- !!null val
|
||||
- 0o77
|
||||
- [ 0xF, 0xF ]
|
||||
- +12345
|
||||
- [ true, false ]
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out[0];
|
||||
|
||||
assert_eq!(doc[0].as_str().unwrap(), "string");
|
||||
assert_eq!(doc[1].as_str().unwrap(), "string");
|
||||
assert_eq!(doc[2].as_str().unwrap(), "string");
|
||||
assert_eq!(doc[3].as_i64().unwrap(), 123);
|
||||
assert_eq!(doc[4].as_i64().unwrap(), -321);
|
||||
assert_eq!(doc[5].as_f64().unwrap(), 1.23);
|
||||
assert_eq!(doc[6].as_f64().unwrap(), -1e4);
|
||||
assert!(doc[7].is_null());
|
||||
assert!(doc[8].is_null());
|
||||
assert_eq!(doc[9].as_bool().unwrap(), true);
|
||||
assert_eq!(doc[10].as_bool().unwrap(), false);
|
||||
assert_eq!(doc[11].as_str().unwrap(), "0");
|
||||
assert_eq!(doc[12].as_i64().unwrap(), 100);
|
||||
assert_eq!(doc[13].as_f64().unwrap(), 2.0);
|
||||
assert!(doc[14].is_null());
|
||||
assert_eq!(doc[15].as_bool().unwrap(), true);
|
||||
assert_eq!(doc[16].as_bool().unwrap(), false);
|
||||
assert_eq!(doc[17].as_i64().unwrap(), 255);
|
||||
assert!(doc[18].is_badvalue());
|
||||
assert!(doc[19].is_badvalue());
|
||||
assert!(doc[20].is_badvalue());
|
||||
assert!(doc[21].is_badvalue());
|
||||
assert_eq!(doc[22].as_i64().unwrap(), 63);
|
||||
assert_eq!(doc[23][0].as_i64().unwrap(), 15);
|
||||
assert_eq!(doc[23][1].as_i64().unwrap(), 15);
|
||||
assert_eq!(doc[24].as_i64().unwrap(), 12345);
|
||||
assert!(doc[25][0].as_bool().unwrap());
|
||||
assert!(!doc[25][1].as_bool().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_hyphen() {
|
||||
// See: https://github.com/chyh1990/yaml-rust/issues/23
|
||||
let s = "{-";
|
||||
assert!(YamlLoader::load_from_str(s).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_issue_65() {
|
||||
// See: https://github.com/chyh1990/yaml-rust/issues/65
|
||||
let b = "\n\"ll\\\"ll\\\r\n\"ll\\\"ll\\\r\r\r\rU\r\r\rU";
|
||||
assert!(YamlLoader::load_from_str(b).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bad_docstart() {
|
||||
assert!(YamlLoader::load_from_str("---This used to cause an infinite loop").is_ok());
|
||||
assert_eq!(
|
||||
YamlLoader::load_from_str("----"),
|
||||
Ok(vec![Yaml::String(String::from("----"))])
|
||||
);
|
||||
assert_eq!(
|
||||
YamlLoader::load_from_str("--- #here goes a comment"),
|
||||
Ok(vec![Yaml::Null])
|
||||
);
|
||||
assert_eq!(
|
||||
YamlLoader::load_from_str("---- #here goes a comment"),
|
||||
Ok(vec![Yaml::String(String::from("----"))])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_plain_datatype_with_into_methods() {
|
||||
let s = "
|
||||
- 'string'
|
||||
- \"string\"
|
||||
- string
|
||||
- 123
|
||||
- -321
|
||||
- 1.23
|
||||
- -1e4
|
||||
- true
|
||||
- false
|
||||
- !!str 0
|
||||
- !!int 100
|
||||
- !!float 2
|
||||
- !!bool true
|
||||
- !!bool false
|
||||
- 0xFF
|
||||
- 0o77
|
||||
- +12345
|
||||
- -.INF
|
||||
- .NAN
|
||||
- !!float .INF
|
||||
";
|
||||
let mut out = YamlLoader::load_from_str(s).unwrap().into_iter();
|
||||
let mut doc = out.next().unwrap().into_iter();
|
||||
|
||||
assert_eq!(doc.next().unwrap().into_string().unwrap(), "string");
|
||||
assert_eq!(doc.next().unwrap().into_string().unwrap(), "string");
|
||||
assert_eq!(doc.next().unwrap().into_string().unwrap(), "string");
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 123);
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), -321);
|
||||
assert_eq!(doc.next().unwrap().into_f64().unwrap(), 1.23);
|
||||
assert_eq!(doc.next().unwrap().into_f64().unwrap(), -1e4);
|
||||
assert_eq!(doc.next().unwrap().into_bool().unwrap(), true);
|
||||
assert_eq!(doc.next().unwrap().into_bool().unwrap(), false);
|
||||
assert_eq!(doc.next().unwrap().into_string().unwrap(), "0");
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 100);
|
||||
assert_eq!(doc.next().unwrap().into_f64().unwrap(), 2.0);
|
||||
assert_eq!(doc.next().unwrap().into_bool().unwrap(), true);
|
||||
assert_eq!(doc.next().unwrap().into_bool().unwrap(), false);
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 255);
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 63);
|
||||
assert_eq!(doc.next().unwrap().into_i64().unwrap(), 12345);
|
||||
assert_eq!(doc.next().unwrap().into_f64().unwrap(), f64::NEG_INFINITY);
|
||||
assert!(doc.next().unwrap().into_f64().is_some());
|
||||
assert_eq!(doc.next().unwrap().into_f64().unwrap(), f64::INFINITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_order() {
|
||||
let s = "---
|
||||
b: ~
|
||||
a: ~
|
||||
c: ~
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let first = out.into_iter().next().unwrap();
|
||||
let mut iter = first.into_hash().unwrap().into_iter();
|
||||
assert_eq!(
|
||||
Some((Yaml::String("b".to_owned()), Yaml::Null)),
|
||||
iter.next()
|
||||
);
|
||||
assert_eq!(
|
||||
Some((Yaml::String("a".to_owned()), Yaml::Null)),
|
||||
iter.next()
|
||||
);
|
||||
assert_eq!(
|
||||
Some((Yaml::String("c".to_owned()), Yaml::Null)),
|
||||
iter.next()
|
||||
);
|
||||
assert_eq!(None, iter.next());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_integer_key() {
|
||||
let s = "
|
||||
0:
|
||||
important: true
|
||||
1:
|
||||
important: false
|
||||
";
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let first = out.into_iter().next().unwrap();
|
||||
assert_eq!(first[0]["important"].as_bool().unwrap(), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_indentation_equality() {
|
||||
let four_spaces = YamlLoader::load_from_str(
|
||||
r#"
|
||||
hash:
|
||||
with:
|
||||
indentations
|
||||
"#,
|
||||
)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let two_spaces = YamlLoader::load_from_str(
|
||||
r#"
|
||||
hash:
|
||||
with:
|
||||
indentations
|
||||
"#,
|
||||
)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let one_space = YamlLoader::load_from_str(
|
||||
r#"
|
||||
hash:
|
||||
with:
|
||||
indentations
|
||||
"#,
|
||||
)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
let mixed_spaces = YamlLoader::load_from_str(
|
||||
r#"
|
||||
hash:
|
||||
with:
|
||||
indentations
|
||||
"#,
|
||||
)
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(four_spaces, two_spaces);
|
||||
assert_eq!(two_spaces, one_space);
|
||||
assert_eq!(four_spaces, mixed_spaces);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_two_space_indentations() {
|
||||
// https://github.com/kbknapp/clap-rs/issues/965
|
||||
|
||||
let s = r#"
|
||||
subcommands:
|
||||
- server:
|
||||
about: server related commands
|
||||
subcommands2:
|
||||
- server:
|
||||
about: server related commands
|
||||
subcommands3:
|
||||
- server:
|
||||
about: server related commands
|
||||
"#;
|
||||
|
||||
let out = YamlLoader::load_from_str(s).unwrap();
|
||||
let doc = &out.into_iter().next().unwrap();
|
||||
|
||||
println!("{doc:#?}");
|
||||
assert_eq!(doc["subcommands"][0]["server"], Yaml::Null);
|
||||
assert!(doc["subcommands2"][0]["server"].as_hash().is_some());
|
||||
assert!(doc["subcommands3"][0]["server"].as_hash().is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_recursion_depth_check_objects() {
|
||||
let s = "{a:".repeat(10_000) + &"}".repeat(10_000);
|
||||
assert!(YamlLoader::load_from_str(&s).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_recursion_depth_check_arrays() {
|
||||
let s = "[".repeat(10_000) + &"]".repeat(10_000);
|
||||
assert!(YamlLoader::load_from_str(&s).is_err());
|
||||
}
|
Loading…
Reference in a new issue