diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/yaml-rust | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
22 files changed, 8543 insertions, 0 deletions
diff --git a/third_party/rust/yaml-rust/.cargo-checksum.json b/third_party/rust/yaml-rust/.cargo-checksum.json new file mode 100644 index 0000000000..17a3b8aa9c --- /dev/null +++ b/third_party/rust/yaml-rust/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"5adbbb13a18a6dcce5077f0eaf9d1c487fcc1e5551cd6b70d2af22858776d349","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"70480dc70c2fe1d9bbb64dab9a0abce266332905ffef9cabeae26dd027716ecb","README.md":"6d44ee744e35bc15b3b97215a78666fbb137e89e26802b28113d11fd52de8795","appveyor.yml":"84647e5326f965627e2fe102efbff852fa9cd7d2d5ccec21d0051045336193e5","examples/dump_yaml.rs":"fb108a4284f094b3addb2c45901ef49edd7fb7ed17bc7316144902030418ef08","src/emitter.rs":"46ea033971f50caf611b6de183b35b72e59a9cfb1d6504968195787e6f87b25a","src/lib.rs":"d6893e5372d9e59e097d0b3018f067d8ffd783b3f7d7b7cf1f2dee12ee0ea572","src/parser.rs":"60c3d4c9b203512b89ce9bf612110b52bd3b0bd6657c368b79546f5ce73aa1a7","src/scanner.rs":"c56a6763d8ecbb7231c9a8ffad027ebf32a02a24d042a20e6914a1a7a6ded666","src/yaml.rs":"cc177b37a28f7e14e02d5e6b470a0f0fc2228285d74678464e3fecfb9a328af5","tests/quickcheck.rs":"d4ec0bb0f4dc4beec82f8922ccacc926ad05912a91a96799b6190c8b8bb8a30e","tests/spec_test.rs":"1b02d189c98b7bfa2774ea49196e90986898e54950be5e48c2431d2c72584486","tests/spec_test.rs.inc":"544c4d483bbde2401d869c6bf3f2246d3b79fbd13686186acf008f1e19cc86f6","tests/specexamples.rs.inc":"9fa45b9ab96063371878f13f4c3560c560a9c3ba0d71b678265c54523148651c","tests/specs/cpp2rust.rb":"054eca3596adfa59aeec65a15467e41eed472fdcab94900705779cb3376b1c7b","tests/specs/handler_spec_test.cpp":"da8bd253c852ede98e77e8f9196bfaccdae48b77409c3c481b80b6ef56fa40df","tests/specs/libyaml_fail-01.yaml":"c71bced67468f970c195caf605c65fd94009a3be692287a0ad119d9b8e976788","tests/specs/libyaml_fail-02.yaml":"c2e77dd417a474b257651f73f685009d267388be62235d11f195a350a7751ec5","tests/specs/libyaml_fail-03.yaml":"6b0db56f8ce8b2e0ba0a361b86067718a67839b2ce62eb91165ea93f22a9a4a7","tests/test_round_trip.rs":"99a6fbedd8fdf0894319a2dd86dad0251007902819bce31cc57b5bc4778d28aa"},"package":"95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e"}
\ No newline at end of file diff --git a/third_party/rust/yaml-rust/Cargo.toml b/third_party/rust/yaml-rust/Cargo.toml new file mode 100644 index 0000000000..c90bb7315b --- /dev/null +++ b/third_party/rust/yaml-rust/Cargo.toml @@ -0,0 +1,26 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g. crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "yaml-rust" +version = "0.4.2" +authors = ["Yuheng Chen <yuhengchen@sensetime.com>"] +description = "The missing YAML 1.2 parser for rust" +homepage = "http://chyh1990.github.io/yaml-rust/" +documentation = "https://docs.rs/yaml-rust" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/chyh1990/yaml-rust" +[dependencies.linked-hash-map] +version = ">=0.0.9, <0.6" +[dev-dependencies.quickcheck] +version = "0.7" diff --git a/third_party/rust/yaml-rust/LICENSE-APACHE b/third_party/rust/yaml-rust/LICENSE-APACHE new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/third_party/rust/yaml-rust/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +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. diff --git a/third_party/rust/yaml-rust/LICENSE-MIT b/third_party/rust/yaml-rust/LICENSE-MIT new file mode 100644 index 0000000000..2526547425 --- /dev/null +++ b/third_party/rust/yaml-rust/LICENSE-MIT @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Chen Yuheng + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/third_party/rust/yaml-rust/README.md b/third_party/rust/yaml-rust/README.md new file mode 100644 index 0000000000..8517ad3011 --- /dev/null +++ b/third_party/rust/yaml-rust/README.md @@ -0,0 +1,121 @@ +# yaml-rust + +The missing YAML 1.2 implementation for Rust. + +[![Travis](https://travis-ci.org/chyh1990/yaml-rust.svg?branch=master)](https://travis-ci.org/chyh1990/yaml-rust) +[![AppVeyor](https://ci.appveyor.com/api/projects/status/scf47535ckp4ylg4?svg=true)](https://ci.appveyor.com/project/chyh1990/yaml-rust) +[![crates.io](https://img.shields.io/crates/v/yaml-rust.svg)](https://crates.io/crates/yaml-rust) +[![docs.rs](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/yaml-rust) + +`yaml-rust` is a pure Rust YAML 1.2 implementation, +which enjoys the memory safety +property and other benefits from the Rust language. +The parser is heavily influenced by `libyaml` and `yaml-cpp`. + +## Quick Start + +Add the following to the Cargo.toml of your project: + +```toml +[dependencies] +yaml-rust = "0.4" +``` + +and import: + +```rust +extern crate yaml_rust; +``` + +Use `yaml::YamlLoader` to load the YAML documents and access it +as Vec/HashMap: + +```rust +extern crate yaml_rust; +use yaml_rust::{YamlLoader, YamlEmitter}; + +fn main() { + let s = +" +foo: + - list1 + - list2 +bar: + - 1 + - 2.0 +"; + let docs = YamlLoader::load_from_str(s).unwrap(); + + // Multi document support, doc is a yaml::Yaml + let doc = &docs[0]; + + // Debug support + println!("{:?}", doc); + + // Index access for map & array + assert_eq!(doc["foo"][0].as_str().unwrap(), "list1"); + assert_eq!(doc["bar"][1].as_f64().unwrap(), 2.0); + + // Chained key/array access is checked and won't panic, + // return BadValue if they are not exist. + assert!(doc["INVALID_KEY"][100].is_badvalue()); + + // Dump the YAML object + let mut out_str = String::new(); + { + let mut emitter = YamlEmitter::new(&mut out_str); + emitter.dump(doc).unwrap(); // dump the YAML object to a String + } + println!("{}", out_str); +} +``` + +Note that `yaml_rust::Yaml` implements `Index<&'a str>` & `Index<usize>`: + +* `Index<usize>` assumes the container is an Array +* `Index<&'a str>` assumes the container is a string to value Map +* otherwise, `Yaml::BadValue` is returned + +If your document does not conform to this convention (e.g. map with +complex type key), you can use the `Yaml::as_XXX` family API to access your +documents. + +## Features + +* Pure Rust +* Ruby-like Array/Hash access API +* Low-level YAML events emission + +## Specification Compliance + +This implementation aims to provide YAML parser fully compatible with +the YAML 1.2 specification. The parser can correctly parse almost all +examples in the specification, except for the following known bugs: + +* Empty plain scalar in certain contexts + +However, the widely used library `libyaml` also fails to parse these examples, +so it may not be a huge problem for most users. + +## Goals + +* Encoder +* Tag directive +* Alias while desearilization + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +## Contribution + +Fork & PR on Github. + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any +additional terms or conditions. diff --git a/third_party/rust/yaml-rust/appveyor.yml b/third_party/rust/yaml-rust/appveyor.yml new file mode 100644 index 0000000000..8f2e88c45d --- /dev/null +++ b/third_party/rust/yaml-rust/appveyor.yml @@ -0,0 +1,13 @@ +install: + - ps: Start-FileDownload 'https://static.rust-lang.org/dist/rust-1.22.1-i686-pc-windows-gnu.exe' + - rust-1.22.1-i686-pc-windows-gnu.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust" + - SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin + - SET PATH=%PATH%;C:\MinGW\bin + - rustc -V + - cargo -V + - git submodule update --init --recursive + +build: false + +test_script: + - cargo test --verbose diff --git a/third_party/rust/yaml-rust/examples/dump_yaml.rs b/third_party/rust/yaml-rust/examples/dump_yaml.rs new file mode 100644 index 0000000000..8fce0f3c1a --- /dev/null +++ b/third_party/rust/yaml-rust/examples/dump_yaml.rs @@ -0,0 +1,46 @@ +extern crate yaml_rust; + +use std::env; +use std::fs::File; +use std::io::prelude::*; +use yaml_rust::yaml; + +fn print_indent(indent: usize) { + for _ in 0..indent { + print!(" "); + } +} + +fn dump_node(doc: &yaml::Yaml, indent: usize) { + match *doc { + yaml::Yaml::Array(ref v) => { + for x in v { + dump_node(x, indent + 1); + } + } + yaml::Yaml::Hash(ref h) => { + for (k, v) in h { + print_indent(indent); + println!("{:?}:", k); + dump_node(v, indent + 1); + } + } + _ => { + print_indent(indent); + println!("{:?}", doc); + } + } +} + +fn main() { + let args: Vec<_> = env::args().collect(); + let mut f = File::open(&args[1]).unwrap(); + let mut s = String::new(); + f.read_to_string(&mut s).unwrap(); + + let docs = yaml::YamlLoader::load_from_str(&s).unwrap(); + for doc in &docs { + println!("---"); + dump_node(doc, 0); + } +} diff --git a/third_party/rust/yaml-rust/src/emitter.rs b/third_party/rust/yaml-rust/src/emitter.rs new file mode 100644 index 0000000000..10f43ab622 --- /dev/null +++ b/third_party/rust/yaml-rust/src/emitter.rs @@ -0,0 +1,641 @@ +use std::convert::From; +use std::error::Error; +use std::fmt::{self, Display}; +use yaml::{Hash, Yaml}; + +#[derive(Copy, Clone, Debug)] +pub enum EmitError { + FmtError(fmt::Error), + BadHashmapKey, +} + +impl Error for EmitError { + fn description(&self) -> &str { + match *self { + EmitError::FmtError(ref err) => err.description(), + EmitError::BadHashmapKey => "bad hashmap key", + } + } + + fn cause(&self) -> Option<&Error> { + None + } +} + +impl Display for EmitError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match *self { + EmitError::FmtError(ref err) => Display::fmt(err, formatter), + EmitError::BadHashmapKey => formatter.write_str("bad hashmap key"), + } + } +} + +impl From<fmt::Error> for EmitError { + fn from(f: fmt::Error) -> Self { + EmitError::FmtError(f) + } +} + +pub struct YamlEmitter<'a> { + writer: &'a mut fmt::Write, + best_indent: usize, + compact: bool, + + level: isize, +} + +pub type EmitResult = Result<(), EmitError>; + +// from serialize::json +fn escape_str(wr: &mut fmt::Write, v: &str) -> Result<(), fmt::Error> { + try!(wr.write_str("\"")); + + let mut start = 0; + + for (i, byte) in v.bytes().enumerate() { + let escaped = match byte { + b'"' => "\\\"", + b'\\' => "\\\\", + b'\x00' => "\\u0000", + b'\x01' => "\\u0001", + b'\x02' => "\\u0002", + b'\x03' => "\\u0003", + b'\x04' => "\\u0004", + b'\x05' => "\\u0005", + b'\x06' => "\\u0006", + b'\x07' => "\\u0007", + b'\x08' => "\\b", + b'\t' => "\\t", + b'\n' => "\\n", + b'\x0b' => "\\u000b", + b'\x0c' => "\\f", + b'\r' => "\\r", + b'\x0e' => "\\u000e", + b'\x0f' => "\\u000f", + b'\x10' => "\\u0010", + b'\x11' => "\\u0011", + b'\x12' => "\\u0012", + b'\x13' => "\\u0013", + b'\x14' => "\\u0014", + b'\x15' => "\\u0015", + b'\x16' => "\\u0016", + b'\x17' => "\\u0017", + b'\x18' => "\\u0018", + b'\x19' => "\\u0019", + b'\x1a' => "\\u001a", + b'\x1b' => "\\u001b", + b'\x1c' => "\\u001c", + b'\x1d' => "\\u001d", + b'\x1e' => "\\u001e", + b'\x1f' => "\\u001f", + b'\x7f' => "\\u007f", + _ => continue, + }; + + if start < i { + try!(wr.write_str(&v[start..i])); + } + + try!(wr.write_str(escaped)); + + start = i + 1; + } + + if start != v.len() { + try!(wr.write_str(&v[start..])); + } + + try!(wr.write_str("\"")); + Ok(()) +} + +impl<'a> YamlEmitter<'a> { + pub fn new(writer: &'a mut fmt::Write) -> YamlEmitter { + YamlEmitter { + writer, + best_indent: 2, + compact: true, + level: -1, + } + } + + /// Set 'compact inline notation' on or off, as described for block + /// [sequences](http://www.yaml.org/spec/1.2/spec.html#id2797382) + /// and + /// [mappings](http://www.yaml.org/spec/1.2/spec.html#id2798057). + /// + /// In this form, blocks cannot have any properties (such as anchors + /// or tags), which should be OK, because this emitter doesn't + /// (currently) emit those anyways. + pub fn compact(&mut self, compact: bool) { + self.compact = compact; + } + + /// Determine if this emitter is using 'compact inline notation'. + pub fn is_compact(&self) -> bool { + self.compact + } + + pub fn dump(&mut self, doc: &Yaml) -> EmitResult { + // write DocumentStart + try!(write!(self.writer, "---\n")); + self.level = -1; + self.emit_node(doc) + } + + fn write_indent(&mut self) -> EmitResult { + if self.level <= 0 { + return Ok(()); + } + for _ in 0..self.level { + for _ in 0..self.best_indent { + try!(write!(self.writer, " ")); + } + } + Ok(()) + } + + fn emit_node(&mut self, node: &Yaml) -> EmitResult { + match *node { + Yaml::Array(ref v) => self.emit_array(v), + Yaml::Hash(ref h) => self.emit_hash(h), + Yaml::String(ref v) => { + if need_quotes(v) { + try!(escape_str(self.writer, v)); + } else { + try!(write!(self.writer, "{}", v)); + } + Ok(()) + } + Yaml::Boolean(v) => { + if v { + try!(self.writer.write_str("true")); + } else { + try!(self.writer.write_str("false")); + } + Ok(()) + } + Yaml::Integer(v) => { + try!(write!(self.writer, "{}", v)); + Ok(()) + } + Yaml::Real(ref v) => { + try!(write!(self.writer, "{}", v)); + Ok(()) + } + Yaml::Null | Yaml::BadValue => { + try!(write!(self.writer, "~")); + Ok(()) + } + // XXX(chenyh) Alias + _ => Ok(()), + } + } + + fn emit_array(&mut self, v: &[Yaml]) -> EmitResult { + if v.is_empty() { + try!(write!(self.writer, "[]")); + } else { + self.level += 1; + for (cnt, x) in v.iter().enumerate() { + if cnt > 0 { + try!(write!(self.writer, "\n")); + try!(self.write_indent()); + } + try!(write!(self.writer, "-")); + try!(self.emit_val(true, x)); + } + self.level -= 1; + } + Ok(()) + } + + fn emit_hash(&mut self, h: &Hash) -> EmitResult { + if h.is_empty() { + try!(self.writer.write_str("{}")); + } else { + self.level += 1; + for (cnt, (k, v)) in h.iter().enumerate() { + let complex_key = match *k { + Yaml::Hash(_) | Yaml::Array(_) => true, + _ => false, + }; + if cnt > 0 { + try!(write!(self.writer, "\n")); + try!(self.write_indent()); + } + if complex_key { + try!(write!(self.writer, "?")); + try!(self.emit_val(true, k)); + try!(write!(self.writer, "\n")); + try!(self.write_indent()); + try!(write!(self.writer, ":")); + try!(self.emit_val(true, v)); + } else { + try!(self.emit_node(k)); + try!(write!(self.writer, ":")); + try!(self.emit_val(false, v)); + } + } + self.level -= 1; + } + Ok(()) + } + + /// Emit a yaml as a hash or array value: i.e., which should appear + /// following a ":" or "-", either after a space, or on a new line. + /// If `inline` is true, then the preceeding characters are distinct + /// and short enough to respect the compact flag. + fn emit_val(&mut self, inline: bool, val: &Yaml) -> EmitResult { + match *val { + Yaml::Array(ref v) => { + if (inline && self.compact) || v.is_empty() { + try!(write!(self.writer, " ")); + } else { + try!(write!(self.writer, "\n")); + self.level += 1; + try!(self.write_indent()); + self.level -= 1; + } + self.emit_array(v) + } + Yaml::Hash(ref h) => { + if (inline && self.compact) || h.is_empty() { + try!(write!(self.writer, " ")); + } else { + try!(write!(self.writer, "\n")); + self.level += 1; + try!(self.write_indent()); + self.level -= 1; + } + self.emit_hash(h) + } + _ => { + try!(write!(self.writer, " ")); + self.emit_node(val) + } + } + } +} + +/// Check if the string requires quoting. +/// Strings starting with any of the following characters must be quoted. +/// :, &, *, ?, |, -, <, >, =, !, %, @ +/// Strings containing any of the following characters must be quoted. +/// {, }, [, ], ,, #, ` +/// +/// If the string contains any of the following control characters, it must be escaped with double quotes: +/// \0, \x01, \x02, \x03, \x04, \x05, \x06, \a, \b, \t, \n, \v, \f, \r, \x0e, \x0f, \x10, \x11, \x12, \x13, \x14, \x15, \x16, \x17, \x18, \x19, \x1a, \e, \x1c, \x1d, \x1e, \x1f, \N, \_, \L, \P +/// +/// Finally, there are other cases when the strings must be quoted, no matter if you're using single or double quotes: +/// * When the string is true or false (otherwise, it would be treated as a boolean value); +/// * When the string is null or ~ (otherwise, it would be considered as a null value); +/// * When the string looks like a number, such as integers (e.g. 2, 14, etc.), floats (e.g. 2.6, 14.9) and exponential numbers (e.g. 12e7, etc.) (otherwise, it would be treated as a numeric value); +/// * When the string looks like a date (e.g. 2014-12-31) (otherwise it would be automatically converted into a Unix timestamp). +fn need_quotes(string: &str) -> bool { + fn need_quotes_spaces(string: &str) -> bool { + string.starts_with(' ') || string.ends_with(' ') + } + + string == "" + || need_quotes_spaces(string) + || string.starts_with(|character: char| match character { + '&' | '*' | '?' | '|' | '-' | '<' | '>' | '=' | '!' | '%' | '@' => true, + _ => false, + }) + || string.contains(|character: char| match character { + ':' + | '{' + | '}' + | '[' + | ']' + | ',' + | '#' + | '`' + | '\"' + | '\'' + | '\\' + | '\0'...'\x06' + | '\t' + | '\n' + | '\r' + | '\x0e'...'\x1a' + | '\x1c'...'\x1f' => true, + _ => false, + }) + || [ + // http://yaml.org/type/bool.html + // Note: 'y', 'Y', 'n', 'N', is not quoted deliberately, as in libyaml. PyYAML also parse + // them as string, not booleans, although it is volating the YAML 1.1 specification. + // See https://github.com/dtolnay/serde-yaml/pull/83#discussion_r152628088. + "yes", "Yes", "YES", "no", "No", "NO", "True", "TRUE", "true", "False", "FALSE", + "false", "on", "On", "ON", "off", "Off", "OFF", + // http://yaml.org/type/null.html + "null", "Null", "NULL", "~", + ] + .contains(&string) + || string.starts_with('.') + || string.parse::<i64>().is_ok() + || string.parse::<f64>().is_ok() +} + +#[cfg(test)] +mod test { + use super::*; + use 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!(format!("{}", 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!(format!("{}", 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{}\n", writer); + } + + #[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{}\nactual:\n{}\n", + expected, writer + ); + } + + #[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); + } + +} diff --git a/third_party/rust/yaml-rust/src/lib.rs b/third_party/rust/yaml-rust/src/lib.rs new file mode 100644 index 0000000000..3ff03c9cac --- /dev/null +++ b/third_party/rust/yaml-rust/src/lib.rs @@ -0,0 +1,121 @@ +// Copyright 2015, Yuheng Chen. See the LICENSE file at the top-level +// directory of this distribution. + +//! YAML 1.2 implementation in pure Rust. +//! +//! # Usage +//! +//! This crate is [on github](https://github.com/chyh1990/yaml-rust) and can be +//! used by adding `yaml-rust` to the dependencies in your project's `Cargo.toml`. +//! +//! ```toml +//! [dependencies.yaml-rust] +//! git = "https://github.com/chyh1990/yaml-rust.git" +//! ``` +//! +//! 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 +//! +//! ``` +//! use yaml_rust::{YamlLoader, YamlEmitter}; +//! +//! let docs = YamlLoader::load_from_str("[1, 2, 3]").unwrap(); +//! let doc = &docs[0]; // select the first document +//! assert_eq!(doc[0].as_i64().unwrap(), 1); // access elements by index +//! +//! let mut out_str = String::new(); +//! let mut emitter = YamlEmitter::new(&mut out_str); +//! emitter.dump(doc).unwrap(); // dump the YAML object to a String +//! +//! ``` + +#![doc(html_root_url = "https://docs.rs/yaml-rust/0.4.2")] +#![cfg_attr(feature = "cargo-clippy", allow(renamed_and_removed_lints))] +#![cfg_attr(feature = "cargo-clippy", warn(cyclomatic_complexity))] +#![cfg_attr( + feature = "cargo-clippy", + allow(match_same_arms, should_implement_trait) +)] + +extern crate linked_hash_map; + +pub mod emitter; +pub mod parser; +pub mod scanner; +pub mod yaml; + +// reexport key APIs +pub use emitter::{EmitError, YamlEmitter}; +pub use parser::Event; +pub use scanner::ScanError; +pub use 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 = try!(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()); + } + +} diff --git a/third_party/rust/yaml-rust/src/parser.rs b/third_party/rust/yaml-rust/src/parser.rs new file mode 100644 index 0000000000..190d84a141 --- /dev/null +++ b/third_party/rust/yaml-rust/src/parser.rs @@ -0,0 +1,858 @@ +use scanner::*; +use std::collections::HashMap; + +#[derive(Clone, Copy, PartialEq, Debug, Eq)] +enum State { + StreamStart, + ImplicitDocumentStart, + DocumentStart, + DocumentContent, + DocumentEnd, + BlockNode, + // BlockNodeOrIndentlessSequence, + // FlowNode, + BlockSequenceFirstEntry, + BlockSequenceEntry, + IndentlessSequenceEntry, + BlockMappingFirstKey, + BlockMappingKey, + BlockMappingValue, + FlowSequenceFirstEntry, + FlowSequenceEntry, + FlowSequenceEntryMappingKey, + FlowSequenceEntryMappingValue, + FlowSequenceEntryMappingEnd, + FlowMappingFirstKey, + FlowMappingKey, + FlowMappingValue, + FlowMappingEmptyValue, + End, +} + +/// `Event` is used with the low-level event base parsing API, +/// see `EventReceiver` trait. +#[derive(Clone, PartialEq, Debug, Eq)] +pub enum Event { + /// Reserved for internal use + Nothing, + StreamStart, + StreamEnd, + DocumentStart, + DocumentEnd, + /// Refer to an anchor ID + Alias(usize), + /// Value, style, anchor_id, tag + Scalar(String, TScalarStyle, usize, Option<TokenType>), + /// Anchor ID + SequenceStart(usize), + SequenceEnd, + /// Anchor ID + MappingStart(usize), + MappingEnd, +} + +impl Event { + fn empty_scalar() -> Event { + // a null scalar + Event::Scalar("~".to_owned(), TScalarStyle::Plain, 0, None) + } + + fn empty_scalar_with_anchor(anchor: usize, tag: Option<TokenType>) -> Event { + Event::Scalar("".to_owned(), TScalarStyle::Plain, anchor, tag) + } +} + +#[derive(Debug)] +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, +} + +pub trait EventReceiver { + fn on_event(&mut self, ev: Event); +} + +pub trait MarkedEventReceiver { + fn on_event(&mut self, ev: Event, _mark: Marker); +} + +impl<R: EventReceiver> MarkedEventReceiver for R { + fn on_event(&mut self, ev: Event, _mark: Marker) { + self.on_event(ev) + } +} + +pub type ParseResult = Result<(Event, Marker), ScanError>; + +impl<T: Iterator<Item = char>> Parser<T> { + 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, + + anchors: HashMap::new(), + // valid anchor_id starts from 1 + anchor_id: 1, + } + } + + pub fn peek(&mut self) -> Result<&(Event, Marker), ScanError> { + match self.current { + Some(ref x) => Ok(x), + None => { + self.current = Some(try!(self.next())); + self.peek() + } + } + } + + pub fn next(&mut self) -> ParseResult { + match self.current { + None => self.parse(), + Some(_) => Ok(self.current.take().unwrap()), + } + } + + fn peek_token(&mut self) -> Result<&Token, ScanError> { + match self.token { + None => { + self.token = Some(try!(self.scan_next_token())); + Ok(self.token.as_ref().unwrap()) + } + Some(ref tok) => Ok(tok), + } + } + + fn scan_next_token(&mut self) -> Result<Token, ScanError> { + let token = self.scanner.next(); + match token { + None => match self.scanner.get_error() { + None => Err(ScanError::new(self.scanner.mark(), "unexpected eof")), + Some(e) => Err(e), + }, + Some(tok) => Ok(tok), + } + } + + fn fetch_token(&mut self) -> Token { + self.token + .take() + .expect("fetch_token needs to be preceded by peek_token") + } + + fn skip(&mut self) { + self.token = None; + //self.peek_token(); + } + fn pop_state(&mut self) { + self.state = self.states.pop().unwrap() + } + fn push_state(&mut self, state: State) { + self.states.push(state); + } + + fn parse(&mut self) -> ParseResult { + if self.state == State::End { + return Ok((Event::StreamEnd, self.scanner.mark())); + } + let (ev, mark) = try!(self.state_machine()); + // println!("EV {:?}", ev); + Ok((ev, mark)) + } + + pub fn load<R: MarkedEventReceiver>( + &mut self, + recv: &mut R, + multi: bool, + ) -> Result<(), ScanError> { + if !self.scanner.stream_started() { + let (ev, mark) = try!(self.next()); + assert_eq!(ev, Event::StreamStart); + recv.on_event(ev, mark); + } + + if self.scanner.stream_ended() { + // XXX has parsed? + recv.on_event(Event::StreamEnd, self.scanner.mark()); + return Ok(()); + } + loop { + let (ev, mark) = try!(self.next()); + if ev == Event::StreamEnd { + recv.on_event(ev, mark); + return Ok(()); + } + // clear anchors before a new document + self.anchors.clear(); + try!(self.load_document(ev, mark, recv)); + if !multi { + break; + } + } + Ok(()) + } + + fn load_document<R: MarkedEventReceiver>( + &mut self, + first_ev: Event, + mark: Marker, + recv: &mut R, + ) -> Result<(), ScanError> { + assert_eq!(first_ev, Event::DocumentStart); + recv.on_event(first_ev, mark); + + let (ev, mark) = try!(self.next()); + try!(self.load_node(ev, mark, recv)); + + // DOCUMENT-END is expected. + let (ev, mark) = try!(self.next()); + assert_eq!(ev, Event::DocumentEnd); + recv.on_event(ev, mark); + + Ok(()) + } + + fn load_node<R: MarkedEventReceiver>( + &mut self, + first_ev: Event, + mark: Marker, + recv: &mut R, + ) -> Result<(), ScanError> { + match first_ev { + Event::Alias(..) | Event::Scalar(..) => { + recv.on_event(first_ev, mark); + Ok(()) + } + Event::SequenceStart(_) => { + recv.on_event(first_ev, mark); + self.load_sequence(recv) + } + Event::MappingStart(_) => { + recv.on_event(first_ev, mark); + self.load_mapping(recv) + } + _ => { + println!("UNREACHABLE EVENT: {:?}", first_ev); + unreachable!(); + } + } + } + + fn load_mapping<R: MarkedEventReceiver>(&mut self, recv: &mut R) -> Result<(), ScanError> { + let (mut key_ev, mut key_mark) = try!(self.next()); + while key_ev != Event::MappingEnd { + // key + try!(self.load_node(key_ev, key_mark, recv)); + + // value + let (ev, mark) = try!(self.next()); + try!(self.load_node(ev, mark, recv)); + + // next event + let (ev, mark) = try!(self.next()); + key_ev = ev; + key_mark = mark; + } + recv.on_event(key_ev, key_mark); + Ok(()) + } + + fn load_sequence<R: MarkedEventReceiver>(&mut self, recv: &mut R) -> Result<(), ScanError> { + let (mut ev, mut mark) = try!(self.next()); + while ev != Event::SequenceEnd { + try!(self.load_node(ev, mark, recv)); + + // next event + let (next_ev, next_mark) = try!(self.next()); + ev = next_ev; + mark = next_mark; + } + recv.on_event(ev, mark); + Ok(()) + } + + fn state_machine(&mut self) -> ParseResult { + // let next_tok = try!(self.peek_token()); + // println!("cur_state {:?}, next tok: {:?}", self.state, next_tok); + match self.state { + State::StreamStart => self.stream_start(), + + State::ImplicitDocumentStart => self.document_start(true), + State::DocumentStart => self.document_start(false), + State::DocumentContent => self.document_content(), + State::DocumentEnd => self.document_end(), + + State::BlockNode => self.parse_node(true, false), + // State::BlockNodeOrIndentlessSequence => self.parse_node(true, true), + // State::FlowNode => self.parse_node(false, false), + State::BlockMappingFirstKey => self.block_mapping_key(true), + State::BlockMappingKey => self.block_mapping_key(false), + State::BlockMappingValue => self.block_mapping_value(), + + State::BlockSequenceFirstEntry => self.block_sequence_entry(true), + State::BlockSequenceEntry => self.block_sequence_entry(false), + + State::FlowSequenceFirstEntry => self.flow_sequence_entry(true), + State::FlowSequenceEntry => self.flow_sequence_entry(false), + + State::FlowMappingFirstKey => self.flow_mapping_key(true), + State::FlowMappingKey => self.flow_mapping_key(false), + State::FlowMappingValue => self.flow_mapping_value(false), + + State::IndentlessSequenceEntry => self.indentless_sequence_entry(), + + State::FlowSequenceEntryMappingKey => self.flow_sequence_entry_mapping_key(), + State::FlowSequenceEntryMappingValue => self.flow_sequence_entry_mapping_value(), + State::FlowSequenceEntryMappingEnd => self.flow_sequence_entry_mapping_end(), + State::FlowMappingEmptyValue => self.flow_mapping_value(true), + + /* impossible */ + State::End => unreachable!(), + } + } + + fn stream_start(&mut self) -> ParseResult { + match *try!(self.peek_token()) { + Token(mark, TokenType::StreamStart(_)) => { + self.state = State::ImplicitDocumentStart; + self.skip(); + Ok((Event::StreamStart, mark)) + } + Token(mark, _) => Err(ScanError::new(mark, "did not find expected <stream-start>")), + } + } + + fn document_start(&mut self, implicit: bool) -> ParseResult { + if !implicit { + while let TokenType::DocumentEnd = try!(self.peek_token()).1 { + self.skip(); + } + } + + match *try!(self.peek_token()) { + Token(mark, TokenType::StreamEnd) => { + self.state = State::End; + self.skip(); + Ok((Event::StreamEnd, mark)) + } + Token(_, TokenType::VersionDirective(..)) + | Token(_, TokenType::TagDirective(..)) + | Token(_, TokenType::DocumentStart) => { + // explicit document + self._explict_document_start() + } + Token(mark, _) if implicit => { + try!(self.parser_process_directives()); + self.push_state(State::DocumentEnd); + self.state = State::BlockNode; + Ok((Event::DocumentStart, mark)) + } + _ => { + // explicit document + self._explict_document_start() + } + } + } + + fn parser_process_directives(&mut self) -> Result<(), ScanError> { + loop { + match try!(self.peek_token()).1 { + TokenType::VersionDirective(_, _) => { + // XXX parsing with warning according to spec + //if major != 1 || minor > 2 { + // return Err(ScanError::new(tok.0, + // "found incompatible YAML document")); + //} + } + TokenType::TagDirective(..) => { + // TODO add tag directive + } + _ => break, + } + self.skip(); + } + // TODO tag directive + Ok(()) + } + + fn _explict_document_start(&mut self) -> ParseResult { + try!(self.parser_process_directives()); + match *try!(self.peek_token()) { + Token(mark, TokenType::DocumentStart) => { + self.push_state(State::DocumentEnd); + self.state = State::DocumentContent; + self.skip(); + Ok((Event::DocumentStart, mark)) + } + Token(mark, _) => Err(ScanError::new( + mark, + "did not find expected <document start>", + )), + } + } + + fn document_content(&mut self) -> ParseResult { + match *try!(self.peek_token()) { + Token(mark, TokenType::VersionDirective(..)) + | Token(mark, TokenType::TagDirective(..)) + | Token(mark, TokenType::DocumentStart) + | Token(mark, TokenType::DocumentEnd) + | Token(mark, TokenType::StreamEnd) => { + self.pop_state(); + // empty scalar + Ok((Event::empty_scalar(), mark)) + } + _ => self.parse_node(true, false), + } + } + + fn document_end(&mut self) -> ParseResult { + let mut _implicit = true; + let marker: Marker = match *try!(self.peek_token()) { + Token(mark, TokenType::DocumentEnd) => { + self.skip(); + _implicit = false; + mark + } + Token(mark, _) => mark, + }; + + // TODO tag handling + self.state = State::DocumentStart; + Ok((Event::DocumentEnd, marker)) + } + + fn register_anchor(&mut self, name: String, _: &Marker) -> Result<usize, ScanError> { + // anchors can be overrided/reused + // if self.anchors.contains_key(name) { + // return Err(ScanError::new(*mark, + // "while parsing anchor, found duplicated anchor")); + // } + let new_id = self.anchor_id; + self.anchor_id += 1; + self.anchors.insert(name, new_id); + Ok(new_id) + } + + fn parse_node(&mut self, block: bool, indentless_sequence: bool) -> ParseResult { + let mut anchor_id = 0; + let mut tag = None; + match *try!(self.peek_token()) { + Token(_, TokenType::Alias(_)) => { + self.pop_state(); + if let Token(mark, TokenType::Alias(name)) = self.fetch_token() { + match self.anchors.get(&name) { + None => { + return Err(ScanError::new( + mark, + "while parsing node, found unknown anchor", + )) + } + Some(id) => return Ok((Event::Alias(*id), mark)), + } + } else { + unreachable!() + } + } + Token(_, TokenType::Anchor(_)) => { + if let Token(mark, TokenType::Anchor(name)) = self.fetch_token() { + anchor_id = try!(self.register_anchor(name, &mark)); + if let TokenType::Tag(..) = try!(self.peek_token()).1 { + if let tg @ TokenType::Tag(..) = self.fetch_token().1 { + tag = Some(tg); + } else { + unreachable!() + } + } + } else { + unreachable!() + } + } + Token(_, TokenType::Tag(..)) => { + if let tg @ TokenType::Tag(..) = self.fetch_token().1 { + tag = Some(tg); + if let TokenType::Anchor(_) = try!(self.peek_token()).1 { + if let Token(mark, TokenType::Anchor(name)) = self.fetch_token() { + anchor_id = try!(self.register_anchor(name, &mark)); + } else { + unreachable!() + } + } + } else { + unreachable!() + } + } + _ => {} + } + match *try!(self.peek_token()) { + Token(mark, TokenType::BlockEntry) if indentless_sequence => { + self.state = State::IndentlessSequenceEntry; + Ok((Event::SequenceStart(anchor_id), mark)) + } + Token(_, TokenType::Scalar(..)) => { + self.pop_state(); + if let Token(mark, TokenType::Scalar(style, v)) = self.fetch_token() { + Ok((Event::Scalar(v, style, anchor_id, tag), mark)) + } else { + unreachable!() + } + } + Token(mark, TokenType::FlowSequenceStart) => { + self.state = State::FlowSequenceFirstEntry; + Ok((Event::SequenceStart(anchor_id), mark)) + } + Token(mark, TokenType::FlowMappingStart) => { + self.state = State::FlowMappingFirstKey; + Ok((Event::MappingStart(anchor_id), mark)) + } + Token(mark, TokenType::BlockSequenceStart) if block => { + self.state = State::BlockSequenceFirstEntry; + Ok((Event::SequenceStart(anchor_id), mark)) + } + Token(mark, TokenType::BlockMappingStart) if block => { + self.state = State::BlockMappingFirstKey; + Ok((Event::MappingStart(anchor_id), mark)) + } + // ex 7.2, an empty scalar can follow a secondary tag + Token(mark, _) if tag.is_some() || anchor_id > 0 => { + self.pop_state(); + Ok((Event::empty_scalar_with_anchor(anchor_id, tag), mark)) + } + Token(mark, _) => Err(ScanError::new( + mark, + "while parsing a node, did not find expected node content", + )), + } + } + + fn block_mapping_key(&mut self, first: bool) -> ParseResult { + // skip BlockMappingStart + if first { + let _ = try!(self.peek_token()); + //self.marks.push(tok.0); + self.skip(); + } + match *try!(self.peek_token()) { + Token(_, TokenType::Key) => { + self.skip(); + match *try!(self.peek_token()) { + Token(mark, TokenType::Key) + | Token(mark, TokenType::Value) + | Token(mark, TokenType::BlockEnd) => { + self.state = State::BlockMappingValue; + // empty scalar + Ok((Event::empty_scalar(), mark)) + } + _ => { + self.push_state(State::BlockMappingValue); + self.parse_node(true, true) + } + } + } + // XXX(chenyh): libyaml failed to parse spec 1.2, ex8.18 + Token(mark, TokenType::Value) => { + self.state = State::BlockMappingValue; + Ok((Event::empty_scalar(), mark)) + } + Token(mark, TokenType::BlockEnd) => { + self.pop_state(); + self.skip(); + Ok((Event::MappingEnd, mark)) + } + Token(mark, _) => Err(ScanError::new( + mark, + "while parsing a block mapping, did not find expected key", + )), + } + } + + fn block_mapping_value(&mut self) -> ParseResult { + match *try!(self.peek_token()) { + Token(_, TokenType::Value) => { + self.skip(); + match *try!(self.peek_token()) { + Token(mark, TokenType::Key) + | Token(mark, TokenType::Value) + | Token(mark, TokenType::BlockEnd) => { + self.state = State::BlockMappingKey; + // empty scalar + Ok((Event::empty_scalar(), mark)) + } + _ => { + self.push_state(State::BlockMappingKey); + self.parse_node(true, true) + } + } + } + Token(mark, _) => { + self.state = State::BlockMappingKey; + // empty scalar + Ok((Event::empty_scalar(), mark)) + } + } + } + + fn flow_mapping_key(&mut self, first: bool) -> ParseResult { + if first { + let _ = try!(self.peek_token()); + self.skip(); + } + let marker: Marker = + { + match *try!(self.peek_token()) { + Token(mark, TokenType::FlowMappingEnd) => mark, + Token(mark, _) => { + if !first { + match *try!(self.peek_token()) { + Token(_, TokenType::FlowEntry) => self.skip(), + Token(mark, _) => return Err(ScanError::new(mark, + "while parsing a flow mapping, did not find expected ',' or '}'")) + } + } + + match *try!(self.peek_token()) { + Token(_, TokenType::Key) => { + self.skip(); + match *try!(self.peek_token()) { + Token(mark, TokenType::Value) + | Token(mark, TokenType::FlowEntry) + | Token(mark, TokenType::FlowMappingEnd) => { + self.state = State::FlowMappingValue; + return Ok((Event::empty_scalar(), mark)); + } + _ => { + self.push_state(State::FlowMappingValue); + return self.parse_node(false, false); + } + } + } + Token(marker, TokenType::Value) => { + self.state = State::FlowMappingValue; + return Ok((Event::empty_scalar(), marker)); + } + Token(_, TokenType::FlowMappingEnd) => (), + _ => { + self.push_state(State::FlowMappingEmptyValue); + return self.parse_node(false, false); + } + } + + mark + } + } + }; + + self.pop_state(); + self.skip(); + Ok((Event::MappingEnd, marker)) + } + + fn flow_mapping_value(&mut self, empty: bool) -> ParseResult { + let mark: Marker = { + if empty { + let Token(mark, _) = *try!(self.peek_token()); + self.state = State::FlowMappingKey; + return Ok((Event::empty_scalar(), mark)); + } else { + match *try!(self.peek_token()) { + Token(marker, TokenType::Value) => { + self.skip(); + match try!(self.peek_token()).1 { + TokenType::FlowEntry | TokenType::FlowMappingEnd => {} + _ => { + self.push_state(State::FlowMappingKey); + return self.parse_node(false, false); + } + } + marker + } + Token(marker, _) => marker, + } + } + }; + + self.state = State::FlowMappingKey; + Ok((Event::empty_scalar(), mark)) + } + + fn flow_sequence_entry(&mut self, first: bool) -> ParseResult { + // skip FlowMappingStart + if first { + let _ = try!(self.peek_token()); + //self.marks.push(tok.0); + self.skip(); + } + match *try!(self.peek_token()) { + Token(mark, TokenType::FlowSequenceEnd) => { + self.pop_state(); + self.skip(); + return Ok((Event::SequenceEnd, mark)); + } + Token(_, TokenType::FlowEntry) if !first => { + self.skip(); + } + Token(mark, _) if !first => { + return Err(ScanError::new( + mark, + "while parsing a flow sequence, expectd ',' or ']'", + )); + } + _ => { /* next */ } + } + match *try!(self.peek_token()) { + Token(mark, TokenType::FlowSequenceEnd) => { + self.pop_state(); + self.skip(); + Ok((Event::SequenceEnd, mark)) + } + Token(mark, TokenType::Key) => { + self.state = State::FlowSequenceEntryMappingKey; + self.skip(); + Ok((Event::MappingStart(0), mark)) + } + _ => { + self.push_state(State::FlowSequenceEntry); + self.parse_node(false, false) + } + } + } + + fn indentless_sequence_entry(&mut self) -> ParseResult { + match *try!(self.peek_token()) { + Token(_, TokenType::BlockEntry) => (), + Token(mark, _) => { + self.pop_state(); + return Ok((Event::SequenceEnd, mark)); + } + } + self.skip(); + match *try!(self.peek_token()) { + Token(mark, TokenType::BlockEntry) + | Token(mark, TokenType::Key) + | Token(mark, TokenType::Value) + | Token(mark, TokenType::BlockEnd) => { + self.state = State::IndentlessSequenceEntry; + Ok((Event::empty_scalar(), mark)) + } + _ => { + self.push_state(State::IndentlessSequenceEntry); + self.parse_node(true, false) + } + } + } + + fn block_sequence_entry(&mut self, first: bool) -> ParseResult { + // BLOCK-SEQUENCE-START + if first { + let _ = try!(self.peek_token()); + //self.marks.push(tok.0); + self.skip(); + } + match *try!(self.peek_token()) { + Token(mark, TokenType::BlockEnd) => { + self.pop_state(); + self.skip(); + Ok((Event::SequenceEnd, mark)) + } + Token(_, TokenType::BlockEntry) => { + self.skip(); + match *try!(self.peek_token()) { + Token(mark, TokenType::BlockEntry) | Token(mark, TokenType::BlockEnd) => { + self.state = State::BlockSequenceEntry; + Ok((Event::empty_scalar(), mark)) + } + _ => { + self.push_state(State::BlockSequenceEntry); + self.parse_node(true, false) + } + } + } + Token(mark, _) => Err(ScanError::new( + mark, + "while parsing a block collection, did not find expected '-' indicator", + )), + } + } + + fn flow_sequence_entry_mapping_key(&mut self) -> ParseResult { + match *try!(self.peek_token()) { + Token(mark, TokenType::Value) + | Token(mark, TokenType::FlowEntry) + | Token(mark, TokenType::FlowSequenceEnd) => { + self.skip(); + self.state = State::FlowSequenceEntryMappingValue; + Ok((Event::empty_scalar(), mark)) + } + _ => { + self.push_state(State::FlowSequenceEntryMappingValue); + self.parse_node(false, false) + } + } + } + + fn flow_sequence_entry_mapping_value(&mut self) -> ParseResult { + match *try!(self.peek_token()) { + Token(_, TokenType::Value) => { + self.skip(); + self.state = State::FlowSequenceEntryMappingValue; + match *try!(self.peek_token()) { + Token(mark, TokenType::FlowEntry) | Token(mark, TokenType::FlowSequenceEnd) => { + self.state = State::FlowSequenceEntryMappingEnd; + Ok((Event::empty_scalar(), mark)) + } + _ => { + self.push_state(State::FlowSequenceEntryMappingEnd); + self.parse_node(false, false) + } + } + } + Token(mark, _) => { + self.state = State::FlowSequenceEntryMappingEnd; + Ok((Event::empty_scalar(), mark)) + } + } + } + + fn flow_sequence_entry_mapping_end(&mut self) -> ParseResult { + self.state = State::FlowSequenceEntry; + Ok((Event::MappingEnd, self.scanner.mark())) + } +} + +#[cfg(test)] +mod test { + use super::{Event, Parser}; + + #[test] + fn test_peek_eq_parse() { + let s = " +a0 bb: val +a1: &x + b1: 4 + b2: d +a2: 4 +a3: [1, 2, 3] +a4: + - [a1, a2] + - 2 +a5: *x +"; + let mut p = Parser::new(s.chars()); + while { + let event_peek = p.peek().unwrap().clone(); + let event = p.next().unwrap(); + assert_eq!(event, event_peek); + event.0 != Event::StreamEnd + } {} + } +} diff --git a/third_party/rust/yaml-rust/src/scanner.rs b/third_party/rust/yaml-rust/src/scanner.rs new file mode 100644 index 0000000000..d4b877407e --- /dev/null +++ b/third_party/rust/yaml-rust/src/scanner.rs @@ -0,0 +1,2097 @@ +use std::collections::VecDeque; +use std::error::Error; +use std::{char, fmt}; + +#[derive(Clone, Copy, PartialEq, Debug, Eq)] +pub enum TEncoding { + Utf8, +} + +#[derive(Clone, Copy, PartialEq, Debug, Eq)] +pub enum TScalarStyle { + Any, + Plain, + SingleQuoted, + DoubleQuoted, + + Literal, + Foled, +} + +#[derive(Clone, Copy, PartialEq, Debug, Eq)] +pub struct Marker { + index: usize, + line: usize, + col: usize, +} + +impl Marker { + fn new(index: usize, line: usize, col: usize) -> Marker { + Marker { index, line, col } + } + + pub fn index(&self) -> usize { + self.index + } + + pub fn line(&self) -> usize { + self.line + } + + pub fn col(&self) -> usize { + self.col + } +} + +#[derive(Clone, PartialEq, Debug, Eq)] +pub struct ScanError { + mark: Marker, + info: String, +} + +impl ScanError { + pub fn new(loc: Marker, info: &str) -> ScanError { + ScanError { + mark: loc, + info: info.to_owned(), + } + } + + pub fn marker(&self) -> &Marker { + &self.mark + } +} + +impl Error for ScanError { + fn description(&self) -> &str { + self.info.as_ref() + } + + fn cause(&self) -> Option<&Error> { + None + } +} + +impl fmt::Display for ScanError { + // col starts from 0 + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "{} at line {} column {}", + self.info, + self.mark.line, + self.mark.col + 1 + ) + } +} + +#[derive(Clone, PartialEq, Debug, Eq)] +pub enum TokenType { + NoToken, + StreamStart(TEncoding), + StreamEnd, + /// major, minor + VersionDirective(u32, u32), + /// handle, prefix + TagDirective(String, String), + DocumentStart, + DocumentEnd, + BlockSequenceStart, + BlockMappingStart, + BlockEnd, + FlowSequenceStart, + FlowSequenceEnd, + FlowMappingStart, + FlowMappingEnd, + BlockEntry, + FlowEntry, + Key, + Value, + Alias(String), + Anchor(String), + /// handle, suffix + Tag(String, String), + Scalar(TScalarStyle, String), +} + +#[derive(Clone, PartialEq, Debug, Eq)] +pub struct Token(pub Marker, pub TokenType); + +#[derive(Clone, PartialEq, Debug, Eq)] +struct SimpleKey { + possible: bool, + required: bool, + token_number: usize, + mark: Marker, +} + +impl SimpleKey { + fn new(mark: Marker) -> SimpleKey { + SimpleKey { + possible: false, + required: false, + token_number: 0, + mark, + } + } +} + +#[derive(Debug)] +pub struct Scanner<T> { + rdr: T, + mark: Marker, + tokens: VecDeque<Token>, + buffer: VecDeque<char>, + error: Option<ScanError>, + + stream_start_produced: bool, + stream_end_produced: bool, + simple_key_allowed: bool, + simple_keys: Vec<SimpleKey>, + indent: isize, + indents: Vec<isize>, + flow_level: u8, + tokens_parsed: usize, + token_available: bool, +} + +impl<T: Iterator<Item = char>> Iterator for Scanner<T> { + type Item = Token; + fn next(&mut self) -> Option<Token> { + if self.error.is_some() { + return None; + } + match self.next_token() { + Ok(tok) => tok, + Err(e) => { + self.error = Some(e); + None + } + } + } +} + +#[inline] +fn is_z(c: char) -> bool { + c == '\0' +} +#[inline] +fn is_break(c: char) -> bool { + c == '\n' || c == '\r' +} +#[inline] +fn is_breakz(c: char) -> bool { + is_break(c) || is_z(c) +} +#[inline] +fn is_blank(c: char) -> bool { + c == ' ' || c == '\t' +} +#[inline] +fn is_blankz(c: char) -> bool { + is_blank(c) || is_breakz(c) +} +#[inline] +fn is_digit(c: char) -> bool { + c >= '0' && c <= '9' +} +#[inline] +fn is_alpha(c: char) -> bool { + match c { + '0'...'9' | 'a'...'z' | 'A'...'Z' => true, + '_' | '-' => true, + _ => false, + } +} +#[inline] +fn is_hex(c: char) -> bool { + (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') +} +#[inline] +fn as_hex(c: char) -> u32 { + match c { + '0'...'9' => (c as u32) - ('0' as u32), + 'a'...'f' => (c as u32) - ('a' as u32) + 10, + 'A'...'F' => (c as u32) - ('A' as u32) + 10, + _ => unreachable!(), + } +} + +pub type ScanResult = Result<(), ScanError>; + +impl<T: Iterator<Item = char>> Scanner<T> { + /// Creates the YAML tokenizer. + pub fn new(rdr: T) -> Scanner<T> { + Scanner { + rdr, + buffer: VecDeque::new(), + mark: Marker::new(0, 1, 0), + tokens: VecDeque::new(), + error: None, + + stream_start_produced: false, + stream_end_produced: false, + simple_key_allowed: true, + simple_keys: Vec::new(), + indent: -1, + indents: Vec::new(), + flow_level: 0, + tokens_parsed: 0, + token_available: false, + } + } + #[inline] + pub fn get_error(&self) -> Option<ScanError> { + match self.error { + None => None, + Some(ref e) => Some(e.clone()), + } + } + + #[inline] + fn lookahead(&mut self, count: usize) { + if self.buffer.len() >= count { + return; + } + for _ in 0..(count - self.buffer.len()) { + self.buffer.push_back(self.rdr.next().unwrap_or('\0')); + } + } + #[inline] + fn skip(&mut self) { + let c = self.buffer.pop_front().unwrap(); + + self.mark.index += 1; + if c == '\n' { + self.mark.line += 1; + self.mark.col = 0; + } else { + self.mark.col += 1; + } + } + #[inline] + fn skip_line(&mut self) { + if self.buffer[0] == '\r' && self.buffer[1] == '\n' { + self.skip(); + self.skip(); + } else if is_break(self.buffer[0]) { + self.skip(); + } + } + #[inline] + fn ch(&self) -> char { + self.buffer[0] + } + #[inline] + fn ch_is(&self, c: char) -> bool { + self.buffer[0] == c + } + #[allow(dead_code)] + #[inline] + fn eof(&self) -> bool { + self.ch_is('\0') + } + #[inline] + pub fn stream_started(&self) -> bool { + self.stream_start_produced + } + #[inline] + pub fn stream_ended(&self) -> bool { + self.stream_end_produced + } + #[inline] + pub fn mark(&self) -> Marker { + self.mark + } + #[inline] + fn read_break(&mut self, s: &mut String) { + if self.buffer[0] == '\r' && self.buffer[1] == '\n' { + s.push('\n'); + self.skip(); + self.skip(); + } else if self.buffer[0] == '\r' || self.buffer[0] == '\n' { + s.push('\n'); + self.skip(); + } else { + unreachable!(); + } + } + fn insert_token(&mut self, pos: usize, tok: Token) { + let old_len = self.tokens.len(); + assert!(pos <= old_len); + self.tokens.push_back(tok); + for i in 0..old_len - pos { + self.tokens.swap(old_len - i, old_len - i - 1); + } + } + fn allow_simple_key(&mut self) { + self.simple_key_allowed = true; + } + fn disallow_simple_key(&mut self) { + self.simple_key_allowed = false; + } + + pub fn fetch_next_token(&mut self) -> ScanResult { + self.lookahead(1); + // println!("--> fetch_next_token Cur {:?} {:?}", self.mark, self.ch()); + + if !self.stream_start_produced { + self.fetch_stream_start(); + return Ok(()); + } + self.skip_to_next_token(); + + try!(self.stale_simple_keys()); + + let mark = self.mark; + self.unroll_indent(mark.col as isize); + + self.lookahead(4); + + if is_z(self.ch()) { + try!(self.fetch_stream_end()); + return Ok(()); + } + + // Is it a directive? + if self.mark.col == 0 && self.ch_is('%') { + return self.fetch_directive(); + } + + if self.mark.col == 0 + && self.buffer[0] == '-' + && self.buffer[1] == '-' + && self.buffer[2] == '-' + && is_blankz(self.buffer[3]) + { + try!(self.fetch_document_indicator(TokenType::DocumentStart)); + return Ok(()); + } + + if self.mark.col == 0 + && self.buffer[0] == '.' + && self.buffer[1] == '.' + && self.buffer[2] == '.' + && is_blankz(self.buffer[3]) + { + try!(self.fetch_document_indicator(TokenType::DocumentEnd)); + return Ok(()); + } + + let c = self.buffer[0]; + let nc = self.buffer[1]; + match c { + '[' => self.fetch_flow_collection_start(TokenType::FlowSequenceStart), + '{' => self.fetch_flow_collection_start(TokenType::FlowMappingStart), + ']' => self.fetch_flow_collection_end(TokenType::FlowSequenceEnd), + '}' => self.fetch_flow_collection_end(TokenType::FlowMappingEnd), + ',' => self.fetch_flow_entry(), + '-' if is_blankz(nc) => self.fetch_block_entry(), + '?' if self.flow_level > 0 || is_blankz(nc) => self.fetch_key(), + ':' if self.flow_level > 0 || is_blankz(nc) => self.fetch_value(), + // Is it an alias? + '*' => self.fetch_anchor(true), + // Is it an anchor? + '&' => self.fetch_anchor(false), + '!' => self.fetch_tag(), + // Is it a literal scalar? + '|' if self.flow_level == 0 => self.fetch_block_scalar(true), + // Is it a folded scalar? + '>' if self.flow_level == 0 => self.fetch_block_scalar(false), + '\'' => self.fetch_flow_scalar(true), + '"' => self.fetch_flow_scalar(false), + // plain scalar + '-' if !is_blankz(nc) => self.fetch_plain_scalar(), + ':' | '?' if !is_blankz(nc) && self.flow_level == 0 => self.fetch_plain_scalar(), + '%' | '@' | '`' => Err(ScanError::new( + self.mark, + &format!("unexpected character: `{}'", c), + )), + _ => self.fetch_plain_scalar(), + } + } + + pub fn next_token(&mut self) -> Result<Option<Token>, ScanError> { + if self.stream_end_produced { + return Ok(None); + } + + if !self.token_available { + try!(self.fetch_more_tokens()); + } + let t = self.tokens.pop_front().unwrap(); + self.token_available = false; + self.tokens_parsed += 1; + + if let TokenType::StreamEnd = t.1 { + self.stream_end_produced = true; + } + Ok(Some(t)) + } + + pub fn fetch_more_tokens(&mut self) -> ScanResult { + let mut need_more; + loop { + need_more = false; + if self.tokens.is_empty() { + need_more = true; + } else { + try!(self.stale_simple_keys()); + for sk in &self.simple_keys { + if sk.possible && sk.token_number == self.tokens_parsed { + need_more = true; + break; + } + } + } + + if !need_more { + break; + } + try!(self.fetch_next_token()); + } + self.token_available = true; + + Ok(()) + } + + fn stale_simple_keys(&mut self) -> ScanResult { + for sk in &mut self.simple_keys { + if sk.possible + && (sk.mark.line < self.mark.line || sk.mark.index + 1024 < self.mark.index) + { + if sk.required { + return Err(ScanError::new(self.mark, "simple key expect ':'")); + } + sk.possible = false; + } + } + Ok(()) + } + + fn skip_to_next_token(&mut self) { + loop { + self.lookahead(1); + // TODO(chenyh) BOM + match self.ch() { + ' ' => self.skip(), + '\t' if self.flow_level > 0 || !self.simple_key_allowed => self.skip(), + '\n' | '\r' => { + self.lookahead(2); + self.skip_line(); + if self.flow_level == 0 { + self.allow_simple_key(); + } + } + '#' => while !is_breakz(self.ch()) { + self.skip(); + self.lookahead(1); + }, + _ => break, + } + } + } + + fn fetch_stream_start(&mut self) { + let mark = self.mark; + self.indent = -1; + self.stream_start_produced = true; + self.allow_simple_key(); + self.tokens + .push_back(Token(mark, TokenType::StreamStart(TEncoding::Utf8))); + self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0))); + } + + fn fetch_stream_end(&mut self) -> ScanResult { + // force new line + if self.mark.col != 0 { + self.mark.col = 0; + self.mark.line += 1; + } + + self.unroll_indent(-1); + try!(self.remove_simple_key()); + self.disallow_simple_key(); + + self.tokens + .push_back(Token(self.mark, TokenType::StreamEnd)); + Ok(()) + } + + fn fetch_directive(&mut self) -> ScanResult { + self.unroll_indent(-1); + try!(self.remove_simple_key()); + + self.disallow_simple_key(); + + let tok = try!(self.scan_directive()); + + self.tokens.push_back(tok); + + Ok(()) + } + + fn scan_directive(&mut self) -> Result<Token, ScanError> { + let start_mark = self.mark; + self.skip(); + + let name = try!(self.scan_directive_name()); + let tok = match name.as_ref() { + "YAML" => try!(self.scan_version_directive_value(&start_mark)), + "TAG" => try!(self.scan_tag_directive_value(&start_mark)), + // XXX This should be a warning instead of an error + _ => { + // skip current line + self.lookahead(1); + while !is_breakz(self.ch()) { + self.skip(); + self.lookahead(1); + } + // XXX return an empty TagDirective token + Token( + start_mark, + TokenType::TagDirective(String::new(), String::new()), + ) + // return Err(ScanError::new(start_mark, + // "while scanning a directive, found unknown directive name")) + } + }; + self.lookahead(1); + + while is_blank(self.ch()) { + self.skip(); + self.lookahead(1); + } + + if self.ch() == '#' { + while !is_breakz(self.ch()) { + self.skip(); + self.lookahead(1); + } + } + + if !is_breakz(self.ch()) { + return Err(ScanError::new( + start_mark, + "while scanning a directive, did not find expected comment or line break", + )); + } + + // Eat a line break + if is_break(self.ch()) { + self.lookahead(2); + self.skip_line(); + } + + Ok(tok) + } + + fn scan_version_directive_value(&mut self, mark: &Marker) -> Result<Token, ScanError> { + self.lookahead(1); + + while is_blank(self.ch()) { + self.skip(); + self.lookahead(1); + } + + let major = try!(self.scan_version_directive_number(mark)); + + if self.ch() != '.' { + return Err(ScanError::new( + *mark, + "while scanning a YAML directive, did not find expected digit or '.' character", + )); + } + + self.skip(); + + let minor = try!(self.scan_version_directive_number(mark)); + + Ok(Token(*mark, TokenType::VersionDirective(major, minor))) + } + + fn scan_directive_name(&mut self) -> Result<String, ScanError> { + let start_mark = self.mark; + let mut string = String::new(); + self.lookahead(1); + while is_alpha(self.ch()) { + string.push(self.ch()); + self.skip(); + self.lookahead(1); + } + + if string.is_empty() { + return Err(ScanError::new( + start_mark, + "while scanning a directive, could not find expected directive name", + )); + } + + if !is_blankz(self.ch()) { + return Err(ScanError::new( + start_mark, + "while scanning a directive, found unexpected non-alphabetical character", + )); + } + + Ok(string) + } + + fn scan_version_directive_number(&mut self, mark: &Marker) -> Result<u32, ScanError> { + let mut val = 0u32; + let mut length = 0usize; + self.lookahead(1); + while is_digit(self.ch()) { + if length + 1 > 9 { + return Err(ScanError::new( + *mark, + "while scanning a YAML directive, found extremely long version number", + )); + } + length += 1; + val = val * 10 + ((self.ch() as u32) - ('0' as u32)); + self.skip(); + self.lookahead(1); + } + + if length == 0 { + return Err(ScanError::new( + *mark, + "while scanning a YAML directive, did not find expected version number", + )); + } + + Ok(val) + } + + fn scan_tag_directive_value(&mut self, mark: &Marker) -> Result<Token, ScanError> { + self.lookahead(1); + /* Eat whitespaces. */ + while is_blank(self.ch()) { + self.skip(); + self.lookahead(1); + } + let handle = try!(self.scan_tag_handle(true, mark)); + + self.lookahead(1); + /* Eat whitespaces. */ + while is_blank(self.ch()) { + self.skip(); + self.lookahead(1); + } + + let is_secondary = handle == "!!"; + let prefix = try!(self.scan_tag_uri(true, is_secondary, &String::new(), mark)); + + self.lookahead(1); + + if is_blankz(self.ch()) { + Ok(Token(*mark, TokenType::TagDirective(handle, prefix))) + } else { + Err(ScanError::new( + *mark, + "while scanning TAG, did not find expected whitespace or line break", + )) + } + } + + fn fetch_tag(&mut self) -> ScanResult { + try!(self.save_simple_key()); + self.disallow_simple_key(); + + let tok = try!(self.scan_tag()); + self.tokens.push_back(tok); + Ok(()) + } + + fn scan_tag(&mut self) -> Result<Token, ScanError> { + let start_mark = self.mark; + let mut handle = String::new(); + let mut suffix; + let mut secondary = false; + + // Check if the tag is in the canonical form (verbatim). + self.lookahead(2); + + if self.buffer[1] == '<' { + // Eat '!<' + self.skip(); + self.skip(); + suffix = try!(self.scan_tag_uri(false, false, &String::new(), &start_mark)); + + if self.ch() != '>' { + return Err(ScanError::new( + start_mark, + "while scanning a tag, did not find the expected '>'", + )); + } + + self.skip(); + } else { + // The tag has either the '!suffix' or the '!handle!suffix' + handle = try!(self.scan_tag_handle(false, &start_mark)); + // Check if it is, indeed, handle. + if handle.len() >= 2 && handle.starts_with('!') && handle.ends_with('!') { + if handle == "!!" { + secondary = true; + } + suffix = try!(self.scan_tag_uri(false, secondary, &String::new(), &start_mark)); + } else { + suffix = try!(self.scan_tag_uri(false, false, &handle, &start_mark)); + handle = "!".to_owned(); + // A special case: the '!' tag. Set the handle to '' and the + // suffix to '!'. + if suffix.is_empty() { + handle.clear(); + suffix = "!".to_owned(); + } + } + } + + self.lookahead(1); + if is_blankz(self.ch()) { + // XXX: ex 7.2, an empty scalar can follow a secondary tag + Ok(Token(start_mark, TokenType::Tag(handle, suffix))) + } else { + Err(ScanError::new( + start_mark, + "while scanning a tag, did not find expected whitespace or line break", + )) + } + } + + fn scan_tag_handle(&mut self, directive: bool, mark: &Marker) -> Result<String, ScanError> { + let mut string = String::new(); + self.lookahead(1); + if self.ch() != '!' { + return Err(ScanError::new( + *mark, + "while scanning a tag, did not find expected '!'", + )); + } + + string.push(self.ch()); + self.skip(); + + self.lookahead(1); + while is_alpha(self.ch()) { + string.push(self.ch()); + self.skip(); + self.lookahead(1); + } + + // Check if the trailing character is '!' and copy it. + if self.ch() == '!' { + string.push(self.ch()); + self.skip(); + } else if directive && string != "!" { + // It's either the '!' tag or not really a tag handle. If it's a %TAG + // directive, it's an error. If it's a tag token, it must be a part of + // URI. + return Err(ScanError::new( + *mark, + "while parsing a tag directive, did not find expected '!'", + )); + } + Ok(string) + } + + fn scan_tag_uri( + &mut self, + directive: bool, + _is_secondary: bool, + head: &str, + mark: &Marker, + ) -> Result<String, ScanError> { + let mut length = head.len(); + let mut string = String::new(); + + // Copy the head if needed. + // Note that we don't copy the leading '!' character. + if length > 1 { + string.extend(head.chars().skip(1)); + } + + self.lookahead(1); + /* + * The set of characters that may appear in URI is as follows: + * + * '0'-'9', 'A'-'Z', 'a'-'z', '_', '-', ';', '/', '?', ':', '@', '&', + * '=', '+', '$', ',', '.', '!', '~', '*', '\'', '(', ')', '[', ']', + * '%'. + */ + while match self.ch() { + ';' | '/' | '?' | ':' | '@' | '&' => true, + '=' | '+' | '$' | ',' | '.' | '!' | '~' | '*' | '\'' | '(' | ')' | '[' | ']' => true, + '%' => true, + c if is_alpha(c) => true, + _ => false, + } { + // Check if it is a URI-escape sequence. + if self.ch() == '%' { + string.push(try!(self.scan_uri_escapes(directive, mark))); + } else { + string.push(self.ch()); + self.skip(); + } + + length += 1; + self.lookahead(1); + } + + if length == 0 { + return Err(ScanError::new( + *mark, + "while parsing a tag, did not find expected tag URI", + )); + } + + Ok(string) + } + + fn scan_uri_escapes(&mut self, _directive: bool, mark: &Marker) -> Result<char, ScanError> { + let mut width = 0usize; + let mut code = 0u32; + loop { + self.lookahead(3); + + if !(self.ch() == '%' && is_hex(self.buffer[1]) && is_hex(self.buffer[2])) { + return Err(ScanError::new( + *mark, + "while parsing a tag, did not find URI escaped octet", + )); + } + + let octet = (as_hex(self.buffer[1]) << 4) + as_hex(self.buffer[2]); + if width == 0 { + width = match octet { + _ if octet & 0x80 == 0x00 => 1, + _ if octet & 0xE0 == 0xC0 => 2, + _ if octet & 0xF0 == 0xE0 => 3, + _ if octet & 0xF8 == 0xF0 => 4, + _ => { + return Err(ScanError::new( + *mark, + "while parsing a tag, found an incorrect leading UTF-8 octet", + )); + } + }; + code = octet; + } else { + if octet & 0xc0 != 0x80 { + return Err(ScanError::new( + *mark, + "while parsing a tag, found an incorrect trailing UTF-8 octet", + )); + } + code = (code << 8) + octet; + } + + self.skip(); + self.skip(); + self.skip(); + + width -= 1; + if width == 0 { + break; + } + } + + match char::from_u32(code) { + Some(ch) => Ok(ch), + None => Err(ScanError::new( + *mark, + "while parsing a tag, found an invalid UTF-8 codepoint", + )), + } + } + + fn fetch_anchor(&mut self, alias: bool) -> ScanResult { + try!(self.save_simple_key()); + self.disallow_simple_key(); + + let tok = try!(self.scan_anchor(alias)); + + self.tokens.push_back(tok); + + Ok(()) + } + + fn scan_anchor(&mut self, alias: bool) -> Result<Token, ScanError> { + let mut string = String::new(); + let start_mark = self.mark; + + self.skip(); + self.lookahead(1); + while is_alpha(self.ch()) { + string.push(self.ch()); + self.skip(); + self.lookahead(1); + } + + if string.is_empty() || match self.ch() { + c if is_blankz(c) => false, + '?' | ':' | ',' | ']' | '}' | '%' | '@' | '`' => false, + _ => true, + } { + return Err(ScanError::new(start_mark, "while scanning an anchor or alias, did not find expected alphabetic or numeric character")); + } + + if alias { + Ok(Token(start_mark, TokenType::Alias(string))) + } else { + Ok(Token(start_mark, TokenType::Anchor(string))) + } + } + + fn fetch_flow_collection_start(&mut self, tok: TokenType) -> ScanResult { + // The indicators '[' and '{' may start a simple key. + try!(self.save_simple_key()); + + self.increase_flow_level()?; + + self.allow_simple_key(); + + let start_mark = self.mark; + self.skip(); + + self.tokens.push_back(Token(start_mark, tok)); + Ok(()) + } + + fn fetch_flow_collection_end(&mut self, tok: TokenType) -> ScanResult { + try!(self.remove_simple_key()); + self.decrease_flow_level(); + + self.disallow_simple_key(); + + let start_mark = self.mark; + self.skip(); + + self.tokens.push_back(Token(start_mark, tok)); + Ok(()) + } + + fn fetch_flow_entry(&mut self) -> ScanResult { + try!(self.remove_simple_key()); + self.allow_simple_key(); + + let start_mark = self.mark; + self.skip(); + + self.tokens + .push_back(Token(start_mark, TokenType::FlowEntry)); + Ok(()) + } + + fn increase_flow_level(&mut self) -> ScanResult { + self.simple_keys.push(SimpleKey::new(Marker::new(0, 0, 0))); + self.flow_level = self + .flow_level + .checked_add(1) + .ok_or_else(|| ScanError::new(self.mark, "recursion limit exceeded"))?; + Ok(()) + } + fn decrease_flow_level(&mut self) { + if self.flow_level > 0 { + self.flow_level -= 1; + self.simple_keys.pop().unwrap(); + } + } + + fn fetch_block_entry(&mut self) -> ScanResult { + if self.flow_level == 0 { + // Check if we are allowed to start a new entry. + if !self.simple_key_allowed { + return Err(ScanError::new( + self.mark, + "block sequence entries are not allowed in this context", + )); + } + + let mark = self.mark; + // generate BLOCK-SEQUENCE-START if indented + self.roll_indent(mark.col, None, TokenType::BlockSequenceStart, mark); + } else { + // - * only allowed in block + return Err(ScanError::new( + self.mark, + r#""-" is only valid inside a block"#, + )); + } + try!(self.remove_simple_key()); + self.allow_simple_key(); + + let start_mark = self.mark; + self.skip(); + + self.tokens + .push_back(Token(start_mark, TokenType::BlockEntry)); + Ok(()) + } + + fn fetch_document_indicator(&mut self, t: TokenType) -> ScanResult { + self.unroll_indent(-1); + try!(self.remove_simple_key()); + self.disallow_simple_key(); + + let mark = self.mark; + + self.skip(); + self.skip(); + self.skip(); + + self.tokens.push_back(Token(mark, t)); + Ok(()) + } + + fn fetch_block_scalar(&mut self, literal: bool) -> ScanResult { + try!(self.save_simple_key()); + self.allow_simple_key(); + let tok = try!(self.scan_block_scalar(literal)); + + self.tokens.push_back(tok); + Ok(()) + } + + fn scan_block_scalar(&mut self, literal: bool) -> Result<Token, ScanError> { + let start_mark = self.mark; + let mut chomping: i32 = 0; + let mut increment: usize = 0; + let mut indent: usize = 0; + let mut trailing_blank: bool; + let mut leading_blank: bool = false; + + let mut string = String::new(); + let mut leading_break = String::new(); + let mut trailing_breaks = String::new(); + + // skip '|' or '>' + self.skip(); + self.lookahead(1); + + if self.ch() == '+' || self.ch() == '-' { + if self.ch() == '+' { + chomping = 1; + } else { + chomping = -1; + } + self.skip(); + self.lookahead(1); + if is_digit(self.ch()) { + if self.ch() == '0' { + return Err(ScanError::new( + start_mark, + "while scanning a block scalar, found an intendation indicator equal to 0", + )); + } + increment = (self.ch() as usize) - ('0' as usize); + self.skip(); + } + } else if is_digit(self.ch()) { + if self.ch() == '0' { + return Err(ScanError::new( + start_mark, + "while scanning a block scalar, found an intendation indicator equal to 0", + )); + } + + increment = (self.ch() as usize) - ('0' as usize); + self.skip(); + self.lookahead(1); + if self.ch() == '+' || self.ch() == '-' { + if self.ch() == '+' { + chomping = 1; + } else { + chomping = -1; + } + self.skip(); + } + } + + // Eat whitespaces and comments to the end of the line. + self.lookahead(1); + + while is_blank(self.ch()) { + self.skip(); + self.lookahead(1); + } + + if self.ch() == '#' { + while !is_breakz(self.ch()) { + self.skip(); + self.lookahead(1); + } + } + + // Check if we are at the end of the line. + if !is_breakz(self.ch()) { + return Err(ScanError::new( + start_mark, + "while scanning a block scalar, did not find expected comment or line break", + )); + } + + if is_break(self.ch()) { + self.lookahead(2); + self.skip_line(); + } + + if increment > 0 { + indent = if self.indent >= 0 { + (self.indent + increment as isize) as usize + } else { + increment + } + } + // Scan the leading line breaks and determine the indentation level if needed. + try!(self.block_scalar_breaks(&mut indent, &mut trailing_breaks)); + + self.lookahead(1); + + let start_mark = self.mark; + + while self.mark.col == indent && !is_z(self.ch()) { + // We are at the beginning of a non-empty line. + trailing_blank = is_blank(self.ch()); + if !literal && !leading_break.is_empty() && !leading_blank && !trailing_blank { + if trailing_breaks.is_empty() { + string.push(' '); + } + leading_break.clear(); + } else { + string.push_str(&leading_break); + leading_break.clear(); + } + + string.push_str(&trailing_breaks); + trailing_breaks.clear(); + + leading_blank = is_blank(self.ch()); + + while !is_breakz(self.ch()) { + string.push(self.ch()); + self.skip(); + self.lookahead(1); + } + // break on EOF + if is_z(self.ch()) { + break; + } + + self.lookahead(2); + self.read_break(&mut leading_break); + + // Eat the following intendation spaces and line breaks. + try!(self.block_scalar_breaks(&mut indent, &mut trailing_breaks)); + } + + // Chomp the tail. + if chomping != -1 { + string.push_str(&leading_break); + } + + if chomping == 1 { + string.push_str(&trailing_breaks); + } + + if literal { + Ok(Token( + start_mark, + TokenType::Scalar(TScalarStyle::Literal, string), + )) + } else { + Ok(Token( + start_mark, + TokenType::Scalar(TScalarStyle::Foled, string), + )) + } + } + + fn block_scalar_breaks(&mut self, indent: &mut usize, breaks: &mut String) -> ScanResult { + let mut max_indent = 0; + loop { + self.lookahead(1); + while (*indent == 0 || self.mark.col < *indent) && self.buffer[0] == ' ' { + self.skip(); + self.lookahead(1); + } + + if self.mark.col > max_indent { + max_indent = self.mark.col; + } + + // Check for a tab character messing the intendation. + if (*indent == 0 || self.mark.col < *indent) && self.buffer[0] == '\t' { + return Err(ScanError::new(self.mark, + "while scanning a block scalar, found a tab character where an intendation space is expected")); + } + + if !is_break(self.ch()) { + break; + } + + self.lookahead(2); + // Consume the line break. + self.read_break(breaks); + } + + if *indent == 0 { + *indent = max_indent; + if *indent < (self.indent + 1) as usize { + *indent = (self.indent + 1) as usize; + } + if *indent < 1 { + *indent = 1; + } + } + Ok(()) + } + + fn fetch_flow_scalar(&mut self, single: bool) -> ScanResult { + try!(self.save_simple_key()); + self.disallow_simple_key(); + + let tok = try!(self.scan_flow_scalar(single)); + + self.tokens.push_back(tok); + Ok(()) + } + + fn scan_flow_scalar(&mut self, single: bool) -> Result<Token, ScanError> { + let start_mark = self.mark; + + let mut string = String::new(); + let mut leading_break = String::new(); + let mut trailing_breaks = String::new(); + let mut whitespaces = String::new(); + let mut leading_blanks; + + /* Eat the left quote. */ + self.skip(); + + loop { + /* Check for a document indicator. */ + self.lookahead(4); + + if self.mark.col == 0 + && (((self.buffer[0] == '-') && (self.buffer[1] == '-') && (self.buffer[2] == '-')) + || ((self.buffer[0] == '.') + && (self.buffer[1] == '.') + && (self.buffer[2] == '.'))) + && is_blankz(self.buffer[3]) + { + return Err(ScanError::new( + start_mark, + "while scanning a quoted scalar, found unexpected document indicator", + )); + } + + if is_z(self.ch()) { + return Err(ScanError::new( + start_mark, + "while scanning a quoted scalar, found unexpected end of stream", + )); + } + + self.lookahead(2); + + leading_blanks = false; + // Consume non-blank characters. + + while !is_blankz(self.ch()) { + match self.ch() { + // Check for an escaped single quote. + '\'' if self.buffer[1] == '\'' && single => { + string.push('\''); + self.skip(); + self.skip(); + } + // Check for the right quote. + '\'' if single => break, + '"' if !single => break, + // Check for an escaped line break. + '\\' if !single && is_break(self.buffer[1]) => { + self.lookahead(3); + self.skip(); + self.skip_line(); + leading_blanks = true; + break; + } + // Check for an escape sequence. + '\\' if !single => { + let mut code_length = 0usize; + match self.buffer[1] { + '0' => string.push('\0'), + 'a' => string.push('\x07'), + 'b' => string.push('\x08'), + 't' | '\t' => string.push('\t'), + 'n' => string.push('\n'), + 'v' => string.push('\x0b'), + 'f' => string.push('\x0c'), + 'r' => string.push('\x0d'), + 'e' => string.push('\x1b'), + ' ' => string.push('\x20'), + '"' => string.push('"'), + '\'' => string.push('\''), + '\\' => string.push('\\'), + // NEL (#x85) + 'N' => string.push(char::from_u32(0x85).unwrap()), + // #xA0 + '_' => string.push(char::from_u32(0xA0).unwrap()), + // LS (#x2028) + 'L' => string.push(char::from_u32(0x2028).unwrap()), + // PS (#x2029) + 'P' => string.push(char::from_u32(0x2029).unwrap()), + 'x' => code_length = 2, + 'u' => code_length = 4, + 'U' => code_length = 8, + _ => { + return Err(ScanError::new( + start_mark, + "while parsing a quoted scalar, found unknown escape character", + )) + } + } + self.skip(); + self.skip(); + // Consume an arbitrary escape code. + if code_length > 0 { + self.lookahead(code_length); + let mut value = 0u32; + for i in 0..code_length { + if !is_hex(self.buffer[i]) { + return Err(ScanError::new(start_mark, + "while parsing a quoted scalar, did not find expected hexdecimal number")); + } + value = (value << 4) + as_hex(self.buffer[i]); + } + + let ch = match char::from_u32(value) { + Some(v) => v, + None => { + return Err(ScanError::new(start_mark, + "while parsing a quoted scalar, found invalid Unicode character escape code")); + } + }; + string.push(ch); + + for _ in 0..code_length { + self.skip(); + } + } + } + c => { + string.push(c); + self.skip(); + } + } + self.lookahead(2); + } + self.lookahead(1); + match self.ch() { + '\'' if single => break, + '"' if !single => break, + _ => {} + } + + // Consume blank characters. + while is_blank(self.ch()) || is_break(self.ch()) { + if is_blank(self.ch()) { + // Consume a space or a tab character. + if leading_blanks { + self.skip(); + } else { + whitespaces.push(self.ch()); + self.skip(); + } + } else { + self.lookahead(2); + // Check if it is a first line break. + if leading_blanks { + self.read_break(&mut trailing_breaks); + } else { + whitespaces.clear(); + self.read_break(&mut leading_break); + leading_blanks = true; + } + } + self.lookahead(1); + } + // Join the whitespaces or fold line breaks. + if leading_blanks { + if leading_break.is_empty() { + string.push_str(&leading_break); + string.push_str(&trailing_breaks); + trailing_breaks.clear(); + leading_break.clear(); + } else { + if trailing_breaks.is_empty() { + string.push(' '); + } else { + string.push_str(&trailing_breaks); + trailing_breaks.clear(); + } + leading_break.clear(); + } + } else { + string.push_str(&whitespaces); + whitespaces.clear(); + } + } // loop + + // Eat the right quote. + self.skip(); + + if single { + Ok(Token( + start_mark, + TokenType::Scalar(TScalarStyle::SingleQuoted, string), + )) + } else { + Ok(Token( + start_mark, + TokenType::Scalar(TScalarStyle::DoubleQuoted, string), + )) + } + } + + fn fetch_plain_scalar(&mut self) -> ScanResult { + try!(self.save_simple_key()); + self.disallow_simple_key(); + + let tok = try!(self.scan_plain_scalar()); + + self.tokens.push_back(tok); + Ok(()) + } + + fn scan_plain_scalar(&mut self) -> Result<Token, ScanError> { + let indent = self.indent + 1; + let start_mark = self.mark; + + let mut string = String::new(); + let mut leading_break = String::new(); + let mut trailing_breaks = String::new(); + let mut whitespaces = String::new(); + let mut leading_blanks = false; + + loop { + /* Check for a document indicator. */ + self.lookahead(4); + + if self.mark.col == 0 + && (((self.buffer[0] == '-') && (self.buffer[1] == '-') && (self.buffer[2] == '-')) + || ((self.buffer[0] == '.') + && (self.buffer[1] == '.') + && (self.buffer[2] == '.'))) + && is_blankz(self.buffer[3]) + { + break; + } + + if self.ch() == '#' { + break; + } + while !is_blankz(self.ch()) { + if self.flow_level > 0 && self.ch() == ':' && is_blankz(self.ch()) { + return Err(ScanError::new( + start_mark, + "while scanning a plain scalar, found unexpected ':'", + )); + } + // indicators ends a plain scalar + match self.ch() { + ':' if is_blankz(self.buffer[1]) => break, + ',' | ':' | '?' | '[' | ']' | '{' | '}' if self.flow_level > 0 => break, + _ => {} + } + + if leading_blanks || !whitespaces.is_empty() { + if leading_blanks { + if leading_break.is_empty() { + string.push_str(&leading_break); + string.push_str(&trailing_breaks); + trailing_breaks.clear(); + leading_break.clear(); + } else { + if trailing_breaks.is_empty() { + string.push(' '); + } else { + string.push_str(&trailing_breaks); + trailing_breaks.clear(); + } + leading_break.clear(); + } + leading_blanks = false; + } else { + string.push_str(&whitespaces); + whitespaces.clear(); + } + } + + string.push(self.ch()); + self.skip(); + self.lookahead(2); + } + // is the end? + if !(is_blank(self.ch()) || is_break(self.ch())) { + break; + } + self.lookahead(1); + + while is_blank(self.ch()) || is_break(self.ch()) { + if is_blank(self.ch()) { + if leading_blanks && (self.mark.col as isize) < indent && self.ch() == '\t' { + return Err(ScanError::new( + start_mark, + "while scanning a plain scalar, found a tab", + )); + } + + if leading_blanks { + self.skip(); + } else { + whitespaces.push(self.ch()); + self.skip(); + } + } else { + self.lookahead(2); + // Check if it is a first line break + if leading_blanks { + self.read_break(&mut trailing_breaks); + } else { + whitespaces.clear(); + self.read_break(&mut leading_break); + leading_blanks = true; + } + } + self.lookahead(1); + } + + // check intendation level + if self.flow_level == 0 && (self.mark.col as isize) < indent { + break; + } + } + + if leading_blanks { + self.allow_simple_key(); + } + + Ok(Token( + start_mark, + TokenType::Scalar(TScalarStyle::Plain, string), + )) + } + + fn fetch_key(&mut self) -> ScanResult { + let start_mark = self.mark; + if self.flow_level == 0 { + // Check if we are allowed to start a new key (not nessesary simple). + if !self.simple_key_allowed { + return Err(ScanError::new( + self.mark, + "mapping keys are not allowed in this context", + )); + } + self.roll_indent( + start_mark.col, + None, + TokenType::BlockMappingStart, + start_mark, + ); + } + + try!(self.remove_simple_key()); + + if self.flow_level == 0 { + self.allow_simple_key(); + } else { + self.disallow_simple_key(); + } + + self.skip(); + self.tokens.push_back(Token(start_mark, TokenType::Key)); + Ok(()) + } + + fn fetch_value(&mut self) -> ScanResult { + let sk = self.simple_keys.last().unwrap().clone(); + let start_mark = self.mark; + if sk.possible { + // insert simple key + let tok = Token(sk.mark, TokenType::Key); + let tokens_parsed = self.tokens_parsed; + self.insert_token(sk.token_number - tokens_parsed, tok); + + // Add the BLOCK-MAPPING-START token if needed. + self.roll_indent( + sk.mark.col, + Some(sk.token_number), + TokenType::BlockMappingStart, + start_mark, + ); + + self.simple_keys.last_mut().unwrap().possible = false; + self.disallow_simple_key(); + } else { + // The ':' indicator follows a complex key. + if self.flow_level == 0 { + if !self.simple_key_allowed { + return Err(ScanError::new( + start_mark, + "mapping values are not allowed in this context", + )); + } + + self.roll_indent( + start_mark.col, + None, + TokenType::BlockMappingStart, + start_mark, + ); + } + + if self.flow_level == 0 { + self.allow_simple_key(); + } else { + self.disallow_simple_key(); + } + } + self.skip(); + self.tokens.push_back(Token(start_mark, TokenType::Value)); + + Ok(()) + } + + fn roll_indent(&mut self, col: usize, number: Option<usize>, tok: TokenType, mark: Marker) { + if self.flow_level > 0 { + return; + } + + if self.indent < col as isize { + self.indents.push(self.indent); + self.indent = col as isize; + let tokens_parsed = self.tokens_parsed; + match number { + Some(n) => self.insert_token(n - tokens_parsed, Token(mark, tok)), + None => self.tokens.push_back(Token(mark, tok)), + } + } + } + + fn unroll_indent(&mut self, col: isize) { + if self.flow_level > 0 { + return; + } + while self.indent > col { + self.tokens.push_back(Token(self.mark, TokenType::BlockEnd)); + self.indent = self.indents.pop().unwrap(); + } + } + + fn save_simple_key(&mut self) -> Result<(), ScanError> { + let required = self.flow_level > 0 && self.indent == (self.mark.col as isize); + if self.simple_key_allowed { + let mut sk = SimpleKey::new(self.mark); + sk.possible = true; + sk.required = required; + sk.token_number = self.tokens_parsed + self.tokens.len(); + + try!(self.remove_simple_key()); + + self.simple_keys.pop(); + self.simple_keys.push(sk); + } + Ok(()) + } + + fn remove_simple_key(&mut self) -> ScanResult { + let last = self.simple_keys.last_mut().unwrap(); + if last.possible && last.required { + return Err(ScanError::new(self.mark, "simple key expected")); + } + + last.possible = false; + Ok(()) + } +} + +#[cfg(test)] +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_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 + } +} diff --git a/third_party/rust/yaml-rust/src/yaml.rs b/third_party/rust/yaml-rust/src/yaml.rs new file mode 100644 index 0000000000..7e144357a1 --- /dev/null +++ b/third_party/rust/yaml-rust/src/yaml.rs @@ -0,0 +1,734 @@ +use linked_hash_map::LinkedHashMap; +use parser::*; +use scanner::{Marker, ScanError, TScalarStyle, TokenType}; +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. +/// +/// # Examples +/// +/// ``` +/// use yaml_rust::Yaml; +/// let foo = Yaml::from_str("-123"); // convert the string to the appropriate YAML type +/// assert_eq!(foo.as_i64().unwrap(), -123); +/// +/// // iterate over an Array +/// let vec = Yaml::Array(vec![Yaml::Integer(1), Yaml::Integer(2)]); +/// for v in vec.as_vec().unwrap() { +/// assert!(v.as_i64().is_some()); +/// } +/// ``` +#[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), + /// YAML int is stored as i64. + Integer(i64), + /// YAML scalar. + String(string::String), + /// YAML bool, e.g. `true` or `false`. + Boolean(bool), + /// YAML array, can be accessed as a `Vec`. + Array(self::Array), + /// YAML hash, can be accessed as a `LinkedHashMap`. + /// + /// Itertion order will match the order of insertion into the map. + Hash(self::Hash), + /// Alias, not fully supported yet. + Alias(usize), + /// YAML null, e.g. `null` or `~`. + Null, + /// Accessing a nonexistent node via the Index trait returns `BadValue`. This + /// simplifies error handling in the calling code. Invalid type conversion also + /// returns `BadValue`. + BadValue, +} + +pub type Array = Vec<Yaml>; +pub type Hash = LinkedHashMap<Yaml, Yaml>; + +// parse f64 as Core schema +// See: https://github.com/chyh1990/yaml-rust/issues/51 +fn parse_f64(v: &str) -> Option<f64> { + match v { + ".inf" | ".Inf" | ".INF" | "+.inf" | "+.Inf" | "+.INF" => Some(f64::INFINITY), + "-.inf" | "-.Inf" | "-.INF" => Some(f64::NEG_INFINITY), + ".nan" | "NaN" | ".NAN" => Some(f64::NAN), + _ => v.parse::<f64>().ok(), + } +} + +pub struct YamlLoader { + docs: Vec<Yaml>, + // states + // (current node, anchor_id) tuple + doc_stack: Vec<(Yaml, usize)>, + key_stack: Vec<Yaml>, + anchor_map: BTreeMap<usize, Yaml>, +} + +impl MarkedEventReceiver for YamlLoader { + fn on_event(&mut self, ev: Event, _: Marker) { + // println!("EV {:?}", ev); + match ev { + Event::DocumentStart => { + // do nothing + } + Event::DocumentEnd => { + match self.doc_stack.len() { + // empty document + 0 => self.docs.push(Yaml::BadValue), + 1 => self.docs.push(self.doc_stack.pop().unwrap().0), + _ => unreachable!(), + } + } + Event::SequenceStart(aid) => { + self.doc_stack.push((Yaml::Array(Vec::new()), aid)); + } + Event::SequenceEnd => { + let node = self.doc_stack.pop().unwrap(); + self.insert_new_node(node); + } + Event::MappingStart(aid) => { + self.doc_stack.push((Yaml::Hash(Hash::new()), aid)); + self.key_stack.push(Yaml::BadValue); + } + Event::MappingEnd => { + self.key_stack.pop().unwrap(); + let node = self.doc_stack.pop().unwrap(); + self.insert_new_node(node); + } + Event::Scalar(v, style, aid, tag) => { + let node = if style != TScalarStyle::Plain { + Yaml::String(v) + } else if let Some(TokenType::Tag(ref handle, ref suffix)) = tag { + // XXX tag:yaml.org,2002: + if handle == "!!" { + match suffix.as_ref() { + "bool" => { + // "true" or "false" + match v.parse::<bool>() { + Err(_) => Yaml::BadValue, + Ok(v) => Yaml::Boolean(v), + } + } + "int" => match v.parse::<i64>() { + Err(_) => Yaml::BadValue, + Ok(v) => Yaml::Integer(v), + }, + "float" => match parse_f64(&v) { + Some(_) => Yaml::Real(v), + None => Yaml::BadValue, + }, + "null" => match v.as_ref() { + "~" | "null" => Yaml::Null, + _ => Yaml::BadValue, + }, + _ => Yaml::String(v), + } + } else { + Yaml::String(v) + } + } else { + // Datatype is not specified, or unrecognized + Yaml::from_str(&v) + }; + + self.insert_new_node((node, aid)); + } + Event::Alias(id) => { + let n = match self.anchor_map.get(&id) { + Some(v) => v.clone(), + None => Yaml::BadValue, + }; + self.insert_new_node((n, 0)); + } + _ => { /* ignore */ } + } + // println!("DOC {:?}", self.doc_stack); + } +} + +impl YamlLoader { + fn insert_new_node(&mut self, node: (Yaml, usize)) { + // valid anchor id starts from 1 + if node.1 > 0 { + self.anchor_map.insert(node.1, node.0.clone()); + } + if self.doc_stack.is_empty() { + self.doc_stack.push(node); + } else { + let parent = self.doc_stack.last_mut().unwrap(); + match *parent { + (Yaml::Array(ref mut v), _) => v.push(node.0), + (Yaml::Hash(ref mut h), _) => { + let cur_key = self.key_stack.last_mut().unwrap(); + // current node is a key + if cur_key.is_badvalue() { + *cur_key = node.0; + // current node is a value + } else { + let mut newkey = Yaml::BadValue; + mem::swap(&mut newkey, cur_key); + h.insert(newkey, node.0); + } + } + _ => unreachable!(), + } + } + } + + pub fn load_from_str(source: &str) -> 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()); + try!(parser.load(&mut loader, true)); + Ok(loader.docs) + } +} + +macro_rules! define_as ( + ($name:ident, $t:ident, $yt:ident) => ( +pub fn $name(&self) -> Option<$t> { + match *self { + Yaml::$yt(v) => Some(v), + _ => None + } +} + ); +); + +macro_rules! define_as_ref ( + ($name:ident, $t:ty, $yt:ident) => ( +pub fn $name(&self) -> Option<$t> { + match *self { + Yaml::$yt(ref v) => Some(v), + _ => None + } +} + ); +); + +macro_rules! define_into ( + ($name:ident, $t:ty, $yt:ident) => ( +pub fn $name(self) -> Option<$t> { + match self { + Yaml::$yt(v) => Some(v), + _ => None + } +} + ); +); + +impl Yaml { + define_as!(as_bool, bool, Boolean); + define_as!(as_i64, i64, Integer); + + define_as_ref!(as_str, &str, String); + define_as_ref!(as_hash, &Hash, Hash); + define_as_ref!(as_vec, &Array, Array); + + define_into!(into_bool, bool, Boolean); + define_into!(into_i64, i64, Integer); + define_into!(into_string, String, String); + define_into!(into_hash, Hash, Hash); + define_into!(into_vec, Array, Array); + + pub fn is_null(&self) -> bool { + match *self { + Yaml::Null => true, + _ => false, + } + } + + pub fn is_badvalue(&self) -> bool { + match *self { + Yaml::BadValue => true, + _ => false, + } + } + + pub fn is_array(&self) -> bool { + match *self { + Yaml::Array(_) => true, + _ => false, + } + } + + pub fn as_f64(&self) -> Option<f64> { + match *self { + Yaml::Real(ref v) => parse_f64(v), + _ => None, + } + } + + pub fn into_f64(self) -> Option<f64> { + match self { + Yaml::Real(ref v) => parse_f64(v), + _ => None, + } + } +} + +#[cfg_attr(feature = "cargo-clippy", allow(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. + pub fn from_str(v: &str) -> Yaml { + if v.starts_with("0x") { + let n = i64::from_str_radix(&v[2..], 16); + if n.is_ok() { + return Yaml::Integer(n.unwrap()); + } + } + if v.starts_with("0o") { + let n = i64::from_str_radix(&v[2..], 8); + if n.is_ok() { + return Yaml::Integer(n.unwrap()); + } + } + if v.starts_with('+') && v[1..].parse::<i64>().is_ok() { + return Yaml::Integer(v[1..].parse::<i64>().unwrap()); + } + match v { + "~" | "null" => Yaml::Null, + "true" => Yaml::Boolean(true), + "false" => Yaml::Boolean(false), + _ if v.parse::<i64>().is_ok() => Yaml::Integer(v.parse::<i64>().unwrap()), + // try parsing as f64 + _ if parse_f64(v).is_some() => Yaml::Real(v.to_owned()), + _ => Yaml::String(v.to_owned()), + } + } +} + +static BAD_VALUE: Yaml = Yaml::BadValue; +impl<'a> Index<&'a str> for Yaml { + type Output = Yaml; + + fn index(&self, idx: &'a str) -> &Yaml { + let key = Yaml::String(idx.to_owned()); + match self.as_hash() { + Some(h) => h.get(&key).unwrap_or(&BAD_VALUE), + None => &BAD_VALUE, + } + } +} + +impl Index<usize> for Yaml { + type Output = Yaml; + + fn index(&self, idx: usize) -> &Yaml { + if let Some(v) = self.as_vec() { + v.get(idx).unwrap_or(&BAD_VALUE) + } else if let Some(v) = self.as_hash() { + let key = Yaml::Integer(idx as i64); + v.get(&key).unwrap_or(&BAD_VALUE) + } else { + &BAD_VALUE + } + } +} + +impl IntoIterator for Yaml { + type Item = Yaml; + type IntoIter = YamlIter; + + fn into_iter(self) -> Self::IntoIter { + YamlIter { + yaml: self.into_vec().unwrap_or_else(Vec::new).into_iter(), + } + } +} + +pub struct YamlIter { + yaml: vec::IntoIter<Yaml>, +} + +impl Iterator for YamlIter { + type Item = Yaml; + + fn next(&mut self) -> Option<Yaml> { + self.yaml.next() + } +} + +#[cfg(test)] +mod test { + use std::f64; + use yaml::*; + #[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 = "".to_owned(); + 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_hypen() { + // 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()); + } +} diff --git a/third_party/rust/yaml-rust/tests/quickcheck.rs b/third_party/rust/yaml-rust/tests/quickcheck.rs new file mode 100644 index 0000000000..c2c89bc738 --- /dev/null +++ b/third_party/rust/yaml-rust/tests/quickcheck.rs @@ -0,0 +1,22 @@ +extern crate yaml_rust; +#[macro_use] +extern crate quickcheck; + +use quickcheck::TestResult; +use std::error::Error; +use yaml_rust::{Yaml, YamlEmitter, YamlLoader}; + +quickcheck! { + fn test_check_weird_keys(xs: Vec<String>) -> TestResult { + let mut out_str = String::new(); + let input = Yaml::Array(xs.into_iter().map(Yaml::String).collect()); + { + let mut emitter = YamlEmitter::new(&mut out_str); + emitter.dump(&input).unwrap(); + } + match YamlLoader::load_from_str(&out_str) { + Ok(output) => TestResult::from_bool(output.len() == 1 && input == output[0]), + Err(err) => TestResult::error(err.description()), + } + } +} diff --git a/third_party/rust/yaml-rust/tests/spec_test.rs b/third_party/rust/yaml-rust/tests/spec_test.rs new file mode 100644 index 0000000000..442728f4f3 --- /dev/null +++ b/third_party/rust/yaml-rust/tests/spec_test.rs @@ -0,0 +1,140 @@ +#![allow(dead_code)] +#![allow(non_upper_case_globals)] +extern crate yaml_rust; + +use yaml_rust::parser::{Event, EventReceiver, Parser}; +use yaml_rust::scanner::TScalarStyle; + +// These names match the names used in the C++ test suite. +#[cfg_attr(feature = "cargo-clippy", allow(enum_variant_names))] +#[derive(Clone, PartialEq, PartialOrd, Debug)] +enum TestEvent { + OnDocumentStart, + OnDocumentEnd, + OnSequenceStart, + OnSequenceEnd, + OnMapStart, + OnMapEnd, + OnScalar, + OnAlias, + OnNull, +} + +struct YamlChecker { + pub evs: Vec<TestEvent>, +} + +impl EventReceiver for YamlChecker { + fn on_event(&mut self, ev: Event) { + let tev = match ev { + Event::DocumentStart => TestEvent::OnDocumentStart, + Event::DocumentEnd => TestEvent::OnDocumentEnd, + Event::SequenceStart(..) => TestEvent::OnSequenceStart, + Event::SequenceEnd => TestEvent::OnSequenceEnd, + Event::MappingStart(..) => TestEvent::OnMapStart, + Event::MappingEnd => TestEvent::OnMapEnd, + Event::Scalar(ref v, style, _, _) => { + if v == "~" && style == TScalarStyle::Plain { + TestEvent::OnNull + } else { + TestEvent::OnScalar + } + } + Event::Alias(_) => TestEvent::OnAlias, + _ => return, // ignore other events + }; + self.evs.push(tev); + } +} + +fn str_to_test_events(docs: &str) -> Vec<TestEvent> { + let mut p = YamlChecker { evs: Vec::new() }; + let mut parser = Parser::new(docs.chars()); + parser.load(&mut p, true).unwrap(); + p.evs +} + +macro_rules! assert_next { + ($v:expr, $p:pat) => { + match $v.next().unwrap() { + $p => {} + e => { + panic!("unexpected event: {:?}", e); + } + } + }; +} + +// auto generated from handler_spec_test.cpp +include!("specexamples.rs.inc"); +include!("spec_test.rs.inc"); + +// hand-crafted tests +//#[test] +//fn test_hc_alias() { +//} + +#[test] +fn test_mapvec_legal() { + use yaml_rust::yaml::{Array, Hash, Yaml}; + use yaml_rust::{YamlEmitter, YamlLoader}; + + // Emitting a `map<map<seq<_>>, _>` should result in legal yaml that + // we can parse. + + let mut key = Array::new(); + key.push(Yaml::Integer(1)); + key.push(Yaml::Integer(2)); + key.push(Yaml::Integer(3)); + + let mut keyhash = Hash::new(); + keyhash.insert(Yaml::String("key".into()), Yaml::Array(key)); + + let mut val = Array::new(); + val.push(Yaml::Integer(4)); + val.push(Yaml::Integer(5)); + val.push(Yaml::Integer(6)); + + let mut hash = Hash::new(); + hash.insert(Yaml::Hash(keyhash), Yaml::Array(val)); + + let mut out_str = String::new(); + { + let mut emitter = YamlEmitter::new(&mut out_str); + emitter.dump(&Yaml::Hash(hash)).unwrap(); + } + + // At this point, we are tempted to naively render like this: + // + // ```yaml + // --- + // {key: + // - 1 + // - 2 + // - 3}: + // - 4 + // - 5 + // - 6 + // ``` + // + // However, this doesn't work, because the key sequence [1, 2, 3] is + // rendered in block mode, which is not legal (as far as I can tell) + // inside the flow mode of the key. We need to either fully render + // everything that's in a key in flow mode (which may make for some + // long lines), or use the explicit map identifier '?': + // + // ```yaml + // --- + // ? + // key: + // - 1 + // - 2 + // - 3 + // : + // - 4 + // - 5 + // - 6 + // ``` + + YamlLoader::load_from_str(&out_str).unwrap(); +} diff --git a/third_party/rust/yaml-rust/tests/spec_test.rs.inc b/third_party/rust/yaml-rust/tests/spec_test.rs.inc new file mode 100644 index 0000000000..bb50b3b3cc --- /dev/null +++ b/third_party/rust/yaml-rust/tests/spec_test.rs.inc @@ -0,0 +1,1513 @@ +#[test] +fn test_ex2_1_seq_scalars() { + let mut v = str_to_test_events(EX2_1).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_2_mapping_scalars_to_scalars() { + let mut v = str_to_test_events(EX2_2).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_3_mapping_scalars_to_sequences() { + let mut v = str_to_test_events(EX2_3).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_4_sequence_of_mappings() { + let mut v = str_to_test_events(EX2_4).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_5_sequence_of_sequences() { + let mut v = str_to_test_events(EX2_5).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_6_mapping_of_mappings() { + let mut v = str_to_test_events(EX2_6).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_7_two_documents_in_a_stream() { + let mut v = str_to_test_events(EX2_7).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_8_play_by_play_feed() { + let mut v = str_to_test_events(EX2_8).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_9_single_document_with_two_comments() { + let mut v = str_to_test_events(EX2_9).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_10_simple_anchor() { + let mut v = str_to_test_events(EX2_10).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnAlias); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_11_mapping_between_sequences() { + let mut v = str_to_test_events(EX2_11).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_12_compact_nested_mapping() { + let mut v = str_to_test_events(EX2_12).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_13_in_literals_newlines_are_preserved() { + let mut v = str_to_test_events(EX2_13).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_14_in_folded_scalars_newlines_become_spaces() { + let mut v = str_to_test_events(EX2_14).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_15_folded_newlines_are_preserved_for_more_indented_and_blank_lines() { + let mut v = str_to_test_events(EX2_15).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_16_indentation_determines_scope() { + let mut v = str_to_test_events(EX2_16).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_17_quoted_scalars() { + let mut v = str_to_test_events(EX2_17).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_18_multi_line_flow_scalars() { + let mut v = str_to_test_events(EX2_18).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_23_various_explicit_tags() { + let mut v = str_to_test_events(EX2_23).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_24_global_tags() { + let mut v = str_to_test_events(EX2_24).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnAlias); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnAlias); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_25_unordered_sets() { + let mut v = str_to_test_events(EX2_25).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_26_ordered_mappings() { + let mut v = str_to_test_events(EX2_26).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_27_invoice() { + let mut v = str_to_test_events(EX2_27).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnAlias); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex2_28_log_file() { + let mut v = str_to_test_events(EX2_28).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex5_3_block_structure_indicators() { + let mut v = str_to_test_events(EX5_3).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex5_4_flow_structure_indicators() { + let mut v = str_to_test_events(EX5_4).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex5_6_node_property_indicators() { + let mut v = str_to_test_events(EX5_6).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnAlias); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex5_7_block_scalar_indicators() { + let mut v = str_to_test_events(EX5_7).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex5_8_quoted_scalar_indicators() { + let mut v = str_to_test_events(EX5_8).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex5_11_line_break_characters() { + let mut v = str_to_test_events(EX5_11).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex5_12_tabs_and_spaces() { + let mut v = str_to_test_events(EX5_12).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex5_13_escaped_characters() { + let mut v = str_to_test_events(EX5_13).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_1_indentation_spaces() { + let mut v = str_to_test_events(EX6_1).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_2_indentation_indicators() { + let mut v = str_to_test_events(EX6_2).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_3_separation_spaces() { + let mut v = str_to_test_events(EX6_3).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_4_line_prefixes() { + let mut v = str_to_test_events(EX6_4).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_5_empty_lines() { + let mut v = str_to_test_events(EX6_5).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_6_line_folding() { + let mut v = str_to_test_events(EX6_6).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_7_block_folding() { + let mut v = str_to_test_events(EX6_7).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_8_flow_folding() { + let mut v = str_to_test_events(EX6_8).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_9_separated_comment() { + let mut v = str_to_test_events(EX6_9).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_12_separation_spaces_ii() { + let mut v = str_to_test_events(EX6_12).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_13_reserved_directives() { + let mut v = str_to_test_events(EX6_13).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_14_yaml_directive() { + let mut v = str_to_test_events(EX6_14).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_16_tag_directive() { + let mut v = str_to_test_events(EX6_16).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_18_primary_tag_handle() { + let mut v = str_to_test_events(EX6_18).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_19_secondary_tag_handle() { + let mut v = str_to_test_events(EX6_19).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_20_tag_handles() { + let mut v = str_to_test_events(EX6_20).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_21_local_tag_prefix() { + let mut v = str_to_test_events(EX6_21).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_22_global_tag_prefix() { + let mut v = str_to_test_events(EX6_22).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_23_node_properties() { + let mut v = str_to_test_events(EX6_23).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnAlias); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_24_verbatim_tags() { + let mut v = str_to_test_events(EX6_24).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_26_tag_shorthands() { + let mut v = str_to_test_events(EX6_26).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_28_non_specific_tags() { + let mut v = str_to_test_events(EX6_28).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex6_29_node_anchors() { + let mut v = str_to_test_events(EX6_29).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnAlias); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_1_alias_nodes() { + let mut v = str_to_test_events(EX7_1).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnAlias); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnAlias); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[allow(dead_code)] +fn test_ex7_2_empty_nodes() { + let mut v = str_to_test_events(EX7_2).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_3_completely_empty_nodes() { + let mut v = str_to_test_events(EX7_3).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_4_double_quoted_implicit_keys() { + let mut v = str_to_test_events(EX7_4).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_5_double_quoted_line_breaks() { + let mut v = str_to_test_events(EX7_5).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_6_double_quoted_lines() { + let mut v = str_to_test_events(EX7_6).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_7_single_quoted_characters() { + let mut v = str_to_test_events(EX7_7).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_8_single_quoted_implicit_keys() { + let mut v = str_to_test_events(EX7_8).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_9_single_quoted_lines() { + let mut v = str_to_test_events(EX7_9).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[allow(dead_code)] +fn test_ex7_10_plain_characters() { + let mut v = str_to_test_events(EX7_10).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_11_plain_implicit_keys() { + let mut v = str_to_test_events(EX7_11).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_12_plain_lines() { + let mut v = str_to_test_events(EX7_12).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_13_flow_sequence() { + let mut v = str_to_test_events(EX7_13).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_14_flow_sequence_entries() { + let mut v = str_to_test_events(EX7_14).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_15_flow_mappings() { + let mut v = str_to_test_events(EX7_15).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_16_flow_mapping_entries() { + let mut v = str_to_test_events(EX7_16).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[allow(dead_code)] +fn test_ex7_17_flow_mapping_separate_values() { + let mut v = str_to_test_events(EX7_17).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_18_flow_mapping_adjacent_values() { + let mut v = str_to_test_events(EX7_18).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_19_single_pair_flow_mappings() { + let mut v = str_to_test_events(EX7_19).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_20_single_pair_explicit_entry() { + let mut v = str_to_test_events(EX7_20).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[allow(dead_code)] +fn test_ex7_21_single_pair_implicit_entries() { + let mut v = str_to_test_events(EX7_21).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_23_flow_content() { + let mut v = str_to_test_events(EX7_23).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex7_24_flow_nodes() { + let mut v = str_to_test_events(EX7_24).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnAlias); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_1_block_scalar_header() { + let mut v = str_to_test_events(EX8_1).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[allow(dead_code)] +fn test_ex8_2_block_indentation_header() { + let mut v = str_to_test_events(EX8_2).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_4_chomping_final_line_break() { + let mut v = str_to_test_events(EX8_4).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_6_empty_scalar_chomping() { + let mut v = str_to_test_events(EX8_6).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_7_literal_scalar() { + let mut v = str_to_test_events(EX8_7).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_8_literal_content() { + let mut v = str_to_test_events(EX8_8).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_9_folded_scalar() { + let mut v = str_to_test_events(EX8_9).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_10_folded_lines() { + let mut v = str_to_test_events(EX8_10).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_11_more_indented_lines() { + let mut v = str_to_test_events(EX8_11).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_12_empty_separation_lines() { + let mut v = str_to_test_events(EX8_12).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_13_final_empty_lines() { + let mut v = str_to_test_events(EX8_13).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_14_block_sequence() { + let mut v = str_to_test_events(EX8_14).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_15_block_sequence_entry_types() { + let mut v = str_to_test_events(EX8_15).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_16_block_mappings() { + let mut v = str_to_test_events(EX8_16).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_17_explicit_block_mapping_entries() { + let mut v = str_to_test_events(EX8_17).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_18_implicit_block_mapping_entries() { + let mut v = str_to_test_events(EX8_18).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnNull); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_19_compact_block_mappings() { + let mut v = str_to_test_events(EX8_19).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_20_block_node_types() { + let mut v = str_to_test_events(EX8_20).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + +#[test] +fn test_ex8_22_block_collection_nodes() { + let mut v = str_to_test_events(EX8_22).into_iter(); + assert_next!(v, TestEvent::OnDocumentStart); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnSequenceEnd); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapStart); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnScalar); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnMapEnd); + assert_next!(v, TestEvent::OnDocumentEnd); +} + diff --git a/third_party/rust/yaml-rust/tests/specexamples.rs.inc b/third_party/rust/yaml-rust/tests/specexamples.rs.inc new file mode 100644 index 0000000000..a5398c3ab1 --- /dev/null +++ b/third_party/rust/yaml-rust/tests/specexamples.rs.inc @@ -0,0 +1,337 @@ +const EX2_1 : &'static str = + "- Mark McGwire\n- Sammy Sosa\n- Ken Griffey"; + +const EX2_2 : &'static str = + "hr: 65 # Home runs\navg: 0.278 # Batting average\nrbi: 147 # Runs Batted In"; + +const EX2_3 : &'static str = + "american:\n- Boston Red Sox\n- Detroit Tigers\n- New York Yankees\nnational:\n- New York Mets\n- Chicago Cubs\n- Atlanta Braves"; + +const EX2_4 : &'static str = + "-\n name: Mark McGwire\n hr: 65\n avg: 0.278\n-\n name: Sammy Sosa\n hr: 63\n avg: 0.288"; + +const EX2_5 : &'static str = + "- [name , hr, avg ]\n- [Mark McGwire, 65, 0.278]\n- [Sammy Sosa , 63, 0.288]"; + +const EX2_6 : &'static str = + "Mark McGwire: {hr: 65, avg: 0.278}\nSammy Sosa: {\n hr: 63,\n avg: 0.288\n }"; + +const EX2_7 : &'static str = + "# Ranking of 1998 home runs\n---\n- Mark McGwire\n- Sammy Sosa\n- Ken Griffey\n\n# Team ranking\n---\n- Chicago Cubs\n- St Louis Cardinals"; + +const EX2_8 : &'static str = + "---\ntime: 20:03:20\nplayer: Sammy Sosa\naction: strike (miss)\n...\n---\ntime: 20:03:47\nplayer: Sammy Sosa\naction: grand slam\n..."; + +const EX2_9 : &'static str = + "---\nhr: # 1998 hr ranking\n - Mark McGwire\n - Sammy Sosa\nrbi:\n # 1998 rbi ranking\n - Sammy Sosa\n - Ken Griffey"; + +const EX2_10 : &'static str = + "---\nhr:\n - Mark McGwire\n # Following node labeled SS\n - &SS Sammy Sosa\nrbi:\n - *SS # Subsequent occurrence\n - Ken Griffey"; + +const EX2_11 : &'static str = + "? - Detroit Tigers\n - Chicago cubs\n:\n - 2001-07-23\n\n? [ New York Yankees,\n Atlanta Braves ]\n: [ 2001-07-02, 2001-08-12,\n 2001-08-14 ]"; + +const EX2_12 : &'static str = + "---\n# Products purchased\n- item : Super Hoop\n quantity: 1\n- item : Basketball\n quantity: 4\n- item : Big Shoes\n quantity: 1"; + +const EX2_13 : &'static str = + "# ASCII Art\n--- |\n \\//||\\/||\n // || ||__"; + +const EX2_14 : &'static str = + "--- >\n Mark McGwire's\n year was crippled\n by a knee injury."; + +const EX2_15 : &'static str = + ">\n Sammy Sosa completed another\n fine season with great stats.\n \n 63 Home Runs\n 0.288 Batting Average\n \n What a year!"; + +const EX2_16 : &'static str = + "name: Mark McGwire\naccomplishment: >\n Mark set a major league\n home run record in 1998.\nstats: |\n 65 Home Runs\n 0.278 Batting Average\n"; + +const EX2_17 : &'static str = + "unicode: \"Sosa did fine.\\u263A\"\ncontrol: \"\\b1998\\t1999\\t2000\\n\"\nhex esc: \"\\x0d\\x0a is \\r\\n\"\n\nsingle: '\"Howdy!\" he cried.'\nquoted: ' # Not a ''comment''.'\ntie-fighter: '|\\-*-/|'"; + +const EX2_18 : &'static str = + "plain:\n This unquoted scalar\n spans many lines.\n\nquoted: \"So does this\n quoted scalar.\\n\""; + +// TODO: 2.19 - 2.22 schema tags + +const EX2_23 : &'static str = + "---\nnot-date: !!str 2002-04-28\n\npicture: !!binary |\n R0lGODlhDAAMAIQAAP//9/X\n 17unp5WZmZgAAAOfn515eXv\n Pz7Y6OjuDg4J+fn5OTk6enp\n 56enmleECcgggoBADs=\n\napplication specific tag: !something |\n The semantics of the tag\n above may be different for\n different documents."; + +const EX2_24 : &'static str = + "%TAG ! tag:clarkevans.com,2002:\n--- !shape\n # Use the ! handle for presenting\n # tag:clarkevans.com,2002:circle\n- !circle\n center: &ORIGIN {x: 73, y: 129}\n radius: 7\n- !line\n start: *ORIGIN\n finish: { x: 89, y: 102 }\n- !label\n start: *ORIGIN\n color: 0xFFEEBB\n text: Pretty vector drawing."; + +const EX2_25 : &'static str = + "# Sets are represented as a\n# Mapping where each key is\n# associated with a null value\n--- !!set\n? Mark McGwire\n? Sammy Sosa\n? Ken Griffey"; + +const EX2_26 : &'static str = + "# Ordered maps are represented as\n# A sequence of mappings, with\n# each mapping having one key\n--- !!omap\n- Mark McGwire: 65\n- Sammy Sosa: 63\n- Ken Griffey: 58"; + +const EX2_27 : &'static str = + "--- !<tag:clarkevans.com,2002:invoice>\ninvoice: 34843\ndate : 2001-01-23\nbill-to: &id001\n given : Chris\n family : Dumars\n address:\n lines: |\n 458 Walkman Dr.\n Suite #292\n city : Royal Oak\n state : MI\n postal : 48046\nship-to: *id001\nproduct:\n - sku : BL394D\n quantity : 4\n description : Basketball\n price : 450.00\n - sku : BL4438H\n quantity : 1\n description : Super Hoop\n price : 2392.00\ntax : 251.42\ntotal: 4443.52\ncomments:\n Late afternoon is best.\n Backup contact is Nancy\n Billsmer @ 338-4338."; + +const EX2_28 : &'static str = + "---\nTime: 2001-11-23 15:01:42 -5\nUser: ed\nWarning:\n This is an error message\n for the log file\n---\nTime: 2001-11-23 15:02:31 -5\nUser: ed\nWarning:\n A slightly different error\n message.\n---\nDate: 2001-11-23 15:03:17 -5\nUser: ed\nFatal:\n Unknown variable \"bar\"\nStack:\n - file: TopClass.py\n line: 23\n code: |\n x = MoreObject(\"345\\n\")\n - file: MoreClass.py\n line: 58\n code: |-\n foo = bar"; + +// TODO: 5.1 - 5.2 BOM + +const EX5_3 : &'static str = + "sequence:\n- one\n- two\nmapping:\n ? sky\n : blue\n sea : green"; + +const EX5_4 : &'static str = + "sequence: [ one, two, ]\nmapping: { sky: blue, sea: green }"; + +const EX5_5 : &'static str = "# Comment only."; + +const EX5_6 : &'static str = + "anchored: !local &anchor value\nalias: *anchor"; + +const EX5_7 : &'static str = + "literal: |\n some\n text\nfolded: >\n some\n text\n"; + +const EX5_8 : &'static str = + "single: 'text'\ndouble: \"text\""; + +// TODO: 5.9 directive +// TODO: 5.10 reserved indicator + +const EX5_11 : &'static str = + "|\n Line break (no glyph)\n Line break (glyphed)\n"; + +const EX5_12 : &'static str = + "# Tabs and spaces\nquoted: \"Quoted\t\"\nblock: |\n void main() {\n \tprintf(\"Hello, world!\\n\");\n }"; + +const EX5_13 : &'static str = + "\"Fun with \\\\\n\\\" \\a \\b \\e \\f \\\n\\n \\r \\t \\v \\0 \\\n\\ \\_ \\N \\L \\P \\\n\\x41 \\u0041 \\U00000041\""; + +const EX5_14 : &'static str = + "Bad escapes:\n \"\\c\n \\xq-\""; + +const EX6_1 : &'static str = + " # Leading comment line spaces are\n # neither content nor indentation.\n \nNot indented:\n By one space: |\n By four\n spaces\n Flow style: [ # Leading spaces\n By two, # in flow style\n Also by two, # are neither\n \tStill by two # content nor\n ] # indentation."; + +const EX6_2 : &'static str = + "? a\n: -\tb\n - -\tc\n - d"; + +const EX6_3 : &'static str = + "- foo:\t bar\n- - baz\n -\tbaz"; + +const EX6_4 : &'static str = + "plain: text\n lines\nquoted: \"text\n \tlines\"\nblock: |\n text\n \tlines\n"; + +const EX6_5 : &'static str = + "Folding:\n \"Empty line\n \t\n as a line feed\"\nChomping: |\n Clipped empty lines\n "; + +const EX6_6 : &'static str = + ">-\n trimmed\n \n \n\n as\n space"; + +const EX6_7 : &'static str = + ">\n foo \n \n \t bar\n\n baz\n"; + +const EX6_8 : &'static str = + "\"\n foo \n \n \t bar\n\n baz\n\""; + +const EX6_9 : &'static str = + "key: # Comment\n value"; + +const EX6_10 : &'static str = + " # Comment\n \n\n"; + +const EX6_11 : &'static str = + "key: # Comment\n # lines\n value\n\n"; + +const EX6_12 : &'static str = + "{ first: Sammy, last: Sosa }:\n# Statistics:\n hr: # Home runs\n 65\n avg: # Average\n 0.278"; + +const EX6_13 : &'static str = + "%FOO bar baz # Should be ignored\n # with a warning.\n--- \"foo\""; + +const EX6_14 : &'static str = + "%YAML 1.3 # Attempt parsing\n # with a warning\n---\n\"foo\""; + +const EX6_15 : &'static str = + "%YAML 1.2\n%YAML 1.1\nfoo"; + +const EX6_16 : &'static str = + "%TAG !yaml! tag:yaml.org,2002:\n---\n!yaml!str \"foo\""; + +const EX6_17 : &'static str = + "%TAG ! !foo\n%TAG ! !foo\nbar"; + +const EX6_18 : &'static str = + "# Private\n!foo \"bar\"\n...\n# Global\n%TAG ! tag:example.com,2000:app/\n---\n!foo \"bar\""; + +const EX6_19 : &'static str = + "%TAG !! tag:example.com,2000:app/\n---\n!!int 1 - 3 # Interval, not integer"; + +const EX6_20 : &'static str = + "%TAG !e! tag:example.com,2000:app/\n---\n!e!foo \"bar\""; + +const EX6_21 : &'static str = + "%TAG !m! !my-\n--- # Bulb here\n!m!light fluorescent\n...\n%TAG !m! !my-\n--- # Color here\n!m!light green"; + +const EX6_22 : &'static str = + "%TAG !e! tag:example.com,2000:app/\n---\n- !e!foo \"bar\""; + +const EX6_23 : &'static str = + "!!str &a1 \"foo\":\n !!str bar\n&a2 baz : *a1"; + +const EX6_24 : &'static str = + "!<tag:yaml.org,2002:str> foo :\n !<!bar> baz"; + +const EX6_25 : &'static str = + "- !<!> foo\n- !<$:?> bar\n"; + +const EX6_26 : &'static str = + "%TAG !e! tag:example.com,2000:app/\n---\n- !local foo\n- !!str bar\n- !e!tag%21 baz\n"; + +const EX6_27a : &'static str = + "%TAG !e! tag:example,2000:app/\n---\n- !e! foo"; + +const EX6_27b : &'static str = + "%TAG !e! tag:example,2000:app/\n---\n- !h!bar baz"; + +const EX6_28 : &'static str = + "# Assuming conventional resolution:\n- \"12\"\n- 12\n- ! 12"; + +const EX6_29 : &'static str = + "First occurrence: &anchor Value\nSecond occurrence: *anchor"; + +const EX7_1 : &'static str = + "First occurrence: &anchor Foo\nSecond occurrence: *anchor\nOverride anchor: &anchor Bar\nReuse anchor: *anchor"; + +const EX7_2 : &'static str = + "{\n foo : !!str,\n !!str : bar,\n}"; + +const EX7_3 : &'static str = + "{\n ? foo :,\n : bar,\n}\n"; + +const EX7_4 : &'static str = + "\"implicit block key\" : [\n \"implicit flow key\" : value,\n ]"; + +const EX7_5 : &'static str = + "\"folded \nto a space,\t\n \nto a line feed, or \t\\\n \\ \tnon-content\""; + +const EX7_6 : &'static str = + "\" 1st non-empty\n\n 2nd non-empty \n\t3rd non-empty \""; + +const EX7_7 : &'static str = " 'here''s to \"quotes\"'"; + +const EX7_8 : &'static str = + "'implicit block key' : [\n 'implicit flow key' : value,\n ]"; + +const EX7_9 : &'static str = + "' 1st non-empty\n\n 2nd non-empty \n\t3rd non-empty '"; + +const EX7_10 : &'static str = + "# Outside flow collection:\n- ::vector\n- \": - ()\"\n- Up, up, and away!\n- -123\n- http://example.com/foo#bar\n# Inside flow collection:\n- [ ::vector,\n \": - ()\",\n \"Up, up, and away!\",\n -123,\n http://example.com/foo#bar ]"; + +const EX7_11 : &'static str = + "implicit block key : [\n implicit flow key : value,\n ]"; + +const EX7_12 : &'static str = + "1st non-empty\n\n 2nd non-empty \n\t3rd non-empty"; + +const EX7_13 : &'static str = + "- [ one, two, ]\n- [three ,four]"; + +const EX7_14 : &'static str = + "[\n\"double\n quoted\", 'single\n quoted',\nplain\n text, [ nested ],\nsingle: pair,\n]"; + +const EX7_15 : &'static str = + "- { one : two , three: four , }\n- {five: six,seven : eight}"; + +const EX7_16 : &'static str = + "{\n? explicit: entry,\nimplicit: entry,\n?\n}"; + +const EX7_17 : &'static str = + "{\nunquoted : \"separate\",\nhttp://foo.com,\nomitted value:,\n: omitted key,\n}"; + +const EX7_18 : &'static str = + "{\n\"adjacent\":value,\n\"readable\":value,\n\"empty\":\n}"; + +const EX7_19 : &'static str = + "[\nfoo: bar\n]"; + +const EX7_20 : &'static str = + "[\n? foo\n bar : baz\n]"; + +const EX7_21 : &'static str = + "- [ YAML : separate ]\n- [ : empty key entry ]\n- [ {JSON: like}:adjacent ]"; + +const EX7_22 : &'static str = + "[ foo\n bar: invalid,"; // Note: we don't check (on purpose) the >1K chars for an + // implicit key + +const EX7_23 : &'static str = + "- [ a, b ]\n- { a: b }\n- \"a\"\n- 'b'\n- c"; + +const EX7_24 : &'static str = + "- !!str \"a\"\n- 'b'\n- &anchor \"c\"\n- *anchor\n- !!str"; + +const EX8_1 : &'static str = + "- | # Empty header\n literal\n- >1 # Indentation indicator\n folded\n- |+ # Chomping indicator\n keep\n\n- >1- # Both indicators\n strip\n"; + +const EX8_2 : &'static str = + "- |\n detected\n- >\n \n \n # detected\n- |1\n explicit\n- >\n \t\n detected\n"; + +const EX8_3a : &'static str = + "- |\n \n text"; + +const EX8_3b : &'static str = + "- >\n text\n text"; + +const EX8_3c : &'static str = + "- |2\n text"; + +const EX8_4 : &'static str = + "strip: |-\n text\nclip: |\n text\nkeep: |+\n text\n"; + +const EX8_5 : &'static str = + " # Strip\n # Comments:\nstrip: |-\n # text\n \n # Clip\n # comments:\n\nclip: |\n # text\n \n # Keep\n # comments:\n\nkeep: |+\n # text\n\n # Trail\n # Comments\n"; + +const EX8_6 : &'static str = + "strip: >-\n\nclip: >\n\nkeep: |+\n\n"; + +const EX8_7 : &'static str = + "|\n literal\n \ttext\n\n"; + +const EX8_8 : &'static str = + "|\n \n \n literal\n \n \n text\n\n # Comment\n"; + +const EX8_9 : &'static str = + ">\n folded\n text\n\n"; + +const EX8_10 : &'static str = + ">\n\n folded\n line\n\n next\n line\n * bullet\n\n * list\n * lines\n\n last\n line\n\n# Comment\n"; + +const EX8_11 : &'static str = EX8_10; +const EX8_12 : &'static str = EX8_10; +const EX8_13 : &'static str = EX8_10; + +const EX8_14 : &'static str = + "block sequence:\n - one\n - two : three\n"; + +const EX8_15 : &'static str = + "- # Empty\n- |\n block node\n- - one # Compact\n - two # sequence\n- one: two # Compact mapping\n"; + +const EX8_16 : &'static str = + "block mapping:\n key: value\n"; + +const EX8_17 : &'static str = + "? explicit key # Empty value\n? |\n block key\n: - one # Explicit compact\n - two # block value\n"; + +// XXX libyaml failed this test +const EX8_18 : &'static str = + "plain key: in-line value\n: # Both empty\n\"quoted key\":\n- entry\n"; + +const EX8_19 : &'static str = + "- sun: yellow\n- ? earth: blue\n : moon: white\n"; + +const EX8_20 : &'static str = + "-\n \"flow in block\"\n- >\n Block scalar\n- !!map # Block collection\n foo : bar\n"; + +const EX8_21 : &'static str = + "literal: |2\n value\nfolded:\n !foo\n >1\n value\n"; + +const EX8_22 : &'static str = + "sequence: !!seq\n- entry\n- !!seq\n - nested\nmapping: !!map\n foo: bar\n"; diff --git a/third_party/rust/yaml-rust/tests/specs/cpp2rust.rb b/third_party/rust/yaml-rust/tests/specs/cpp2rust.rb new file mode 100755 index 0000000000..25813c87a6 --- /dev/null +++ b/third_party/rust/yaml-rust/tests/specs/cpp2rust.rb @@ -0,0 +1,78 @@ +#!/usr/bin/env ruby + +TEST_REGEX = /TEST_F\([a-zA-Z0-9_]+,\s+([a-zA-Z0-9_]+)\)/ + +DISABLED_TESTS = %w( + test_ex7_10_plain_characters + test_ex7_17_flow_mapping_separate_values + test_ex7_21_single_pair_implicit_entries + test_ex7_2_empty_nodes + test_ex8_2_block_indentation_header +) + +class Context + attr_accessor :name, :ev, :src + def initialize + @name = "" + @src = "" + @ev = [] + end +end + +class String + def snakecase + self + .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2') + .gsub(/([a-z\d])([A-Z])/, '\1_\2') + .tr('-', '_') + .gsub(/\s/, '_') + .gsub(/__+/, '_') + .downcase + end +end + +ctx = nil + +tests = [] +IO.foreach(ARGV[0]) do |line| + line.strip! + if ctx + fail "unexpected TEST_F" if line =~ TEST_REGEX + if line =~ /^}/ + tests << ctx + ctx = nil + end + if line =~ /^EXPECT_CALL/ + fail 'not end with ;' unless line[-1] == ';' + v = line.gsub('(', ' ').gsub(')', ' ').split + ctx.ev << v[2] + end + else + next unless line =~ TEST_REGEX + name = $1 + next unless name =~ /^(Ex\d+_\d+)/ + str = $1.upcase + $stderr.puts "found #{name}" + ctx = Context.new + ctx.name = "test_#{name.snakecase}" + ctx.src = str + end +end + +# code gen +tests.each do |t| + next if t.ev.size == 0 + if DISABLED_TESTS.include? t.name + puts "#[allow(dead_code)]" + else + puts "#[test]" + end + puts "fn #{t.name}() {" + puts " let mut v = str_to_test_events(#{t.src}).into_iter();" + t.ev.each do |e| + puts " assert_next!(v, TestEvent::#{e});" + end + puts "}" + puts +end + diff --git a/third_party/rust/yaml-rust/tests/specs/handler_spec_test.cpp b/third_party/rust/yaml-rust/tests/specs/handler_spec_test.cpp new file mode 100644 index 0000000000..aa4f7ca238 --- /dev/null +++ b/third_party/rust/yaml-rust/tests/specs/handler_spec_test.cpp @@ -0,0 +1,1532 @@ +#include "handler_test.h" +#include "specexamples.h" // IWYU pragma: keep +#include "yaml-cpp/yaml.h" // IWYU pragma: keep + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using ::testing::_; + +#define EXPECT_THROW_PARSER_EXCEPTION(statement, message) \ + ASSERT_THROW(statement, ParserException); \ + try { \ + statement; \ + } catch (const ParserException& e) { \ + EXPECT_EQ(e.msg, message); \ + } + +namespace YAML { +namespace { + +typedef HandlerTest HandlerSpecTest; + +TEST_F(HandlerSpecTest, Ex2_1_SeqScalars) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Mark McGwire")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Ken Griffey")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_1); +} + +TEST_F(HandlerSpecTest, Ex2_2_MappingScalarsToScalars) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "hr")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "65")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "avg")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "0.278")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "rbi")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "147")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_2); +} + +TEST_F(HandlerSpecTest, Ex2_3_MappingScalarsToSequences) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "american")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Boston Red Sox")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Detroit Tigers")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "New York Yankees")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "national")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "New York Mets")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Chicago Cubs")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Atlanta Braves")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_3); +} + +TEST_F(HandlerSpecTest, Ex2_4_SequenceOfMappings) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "name")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Mark McGwire")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "hr")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "65")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "avg")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "0.278")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "name")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "hr")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "63")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "avg")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "0.288")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_4); +} + +TEST_F(HandlerSpecTest, Ex2_5_SequenceOfSequences) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "name")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "hr")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "avg")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Mark McGwire")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "65")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "0.278")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "63")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "0.288")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_5); +} + +TEST_F(HandlerSpecTest, Ex2_6_MappingOfMappings) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Mark McGwire")); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "hr")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "65")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "avg")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "0.278")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "hr")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "63")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "avg")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "0.288")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_6); +} + +TEST_F(HandlerSpecTest, Ex2_7_TwoDocumentsInAStream) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Mark McGwire")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Ken Griffey")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Chicago Cubs")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "St Louis Cardinals")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_7); +} + +TEST_F(HandlerSpecTest, Ex2_8_PlayByPlayFeed) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "time")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "20:03:20")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "player")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "action")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "strike (miss)")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "time")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "20:03:47")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "player")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "action")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "grand slam")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_8); +} + +TEST_F(HandlerSpecTest, Ex2_9_SingleDocumentWithTwoComments) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "hr")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Mark McGwire")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "rbi")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Ken Griffey")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_9); +} + +TEST_F(HandlerSpecTest, Ex2_10_SimpleAnchor) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "hr")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Mark McGwire")); + EXPECT_CALL(handler, OnScalar(_, "?", 1, "Sammy Sosa")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "rbi")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnAlias(_, 1)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Ken Griffey")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_10); +} + +TEST_F(HandlerSpecTest, Ex2_11_MappingBetweenSequences) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Detroit Tigers")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Chicago cubs")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "2001-07-23")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "New York Yankees")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Atlanta Braves")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "2001-07-02")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "2001-08-12")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "2001-08-14")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_11); +} + +TEST_F(HandlerSpecTest, Ex2_12_CompactNestedMapping) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "item")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Super Hoop")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "quantity")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "1")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "item")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Basketball")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "quantity")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "4")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "item")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Big Shoes")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "quantity")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "1")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_12); +} + +TEST_F(HandlerSpecTest, Ex2_13_InLiteralsNewlinesArePreserved) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\\//||\\/||\n// || ||__")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_13); +} + +TEST_F(HandlerSpecTest, Ex2_14_InFoldedScalarsNewlinesBecomeSpaces) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Mark McGwire's year was crippled by a knee injury.")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_14); +} + +TEST_F(HandlerSpecTest, Ex2_15_FoldedNewlinesArePreservedForMoreIndentedAndBlankLines) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Sammy Sosa completed another fine season with great stats.\n\n 63 Home Runs\n 0.288 Batting Average\n\nWhat a year!")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_15); +} + +TEST_F(HandlerSpecTest, Ex2_16_IndentationDeterminesScope) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "name")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Mark McGwire")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "accomplishment")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Mark set a major league home run record in 1998.\n")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "stats")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "65 Home Runs\n0.278 Batting Average\n")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_16); +} + +TEST_F(HandlerSpecTest, Ex2_17_QuotedScalars) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "unicode")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Sosa did fine.\xE2\x98\xBA")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "control")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\b1998\t1999\t2000\n")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "hex esc")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\x0d\x0a is \r\n")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "single")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\"Howdy!\" he cried.")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "quoted")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, " # Not a 'comment'.")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "tie-fighter")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "|\\-*-/|")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_17); +} + +TEST_F(HandlerSpecTest, Ex2_18_MultiLineFlowScalars) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "plain")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "This unquoted scalar spans many lines.")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "quoted")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "So does this quoted scalar.\n")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_18); +} + +// TODO: 2.19 - 2.22 schema tags + +TEST_F(HandlerSpecTest, Ex2_23_VariousExplicitTags) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "not-date")); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:str", 0, "2002-04-28")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "picture")); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:binary", 0, "R0lGODlhDAAMAIQAAP//9/X\n17unp5WZmZgAAAOfn515eXv\nPz7Y6OjuDg4J+fn5OTk6enp\n56enmleECcgggoBADs=\n")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "application specific tag")); + EXPECT_CALL(handler, OnScalar(_, "!something", 0, "The semantics of the tag\nabove may be different for\ndifferent documents.")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_23); +} + +TEST_F(HandlerSpecTest, Ex2_24_GlobalTags) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "tag:clarkevans.com,2002:shape", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "tag:clarkevans.com,2002:circle", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "center")); + EXPECT_CALL(handler, OnMapStart(_, "?", 1, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "x")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "73")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "y")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "129")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "radius")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "7")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "tag:clarkevans.com,2002:line", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "start")); + EXPECT_CALL(handler, OnAlias(_, 1)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "finish")); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "x")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "89")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "y")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "102")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "tag:clarkevans.com,2002:label", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "start")); + EXPECT_CALL(handler, OnAlias(_, 1)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "color")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "0xFFEEBB")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "text")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Pretty vector drawing.")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_24); +} + +TEST_F(HandlerSpecTest, Ex2_25_UnorderedSets) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "tag:yaml.org,2002:set", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Mark McGwire")); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Ken Griffey")); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_25); +} + +TEST_F(HandlerSpecTest, Ex2_26_OrderedMappings) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "tag:yaml.org,2002:omap", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Mark McGwire")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "65")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy Sosa")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "63")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Ken Griffey")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "58")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_26); +} + +TEST_F(HandlerSpecTest, Ex2_27_Invoice) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "tag:clarkevans.com,2002:invoice", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "invoice")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "34843")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "date")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "2001-01-23")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "bill-to")); + EXPECT_CALL(handler, OnMapStart(_, "?", 1, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "given")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Chris")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "family")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Dumars")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "address")); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "lines")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "458 Walkman Dr.\nSuite #292\n")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "city")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Royal Oak")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "state")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "MI")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "postal")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "48046")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "ship-to")); + EXPECT_CALL(handler, OnAlias(_, 1)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "product")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "sku")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "BL394D")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "quantity")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "4")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "description")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Basketball")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "price")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "450.00")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "sku")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "BL4438H")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "quantity")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "1")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "description")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Super Hoop")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "price")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "2392.00")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "tax")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "251.42")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "total")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "4443.52")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "comments")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338.")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_27); +} + +TEST_F(HandlerSpecTest, Ex2_28_LogFile) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Time")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "2001-11-23 15:01:42 -5")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "User")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "ed")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Warning")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "This is an error message for the log file")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Time")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "2001-11-23 15:02:31 -5")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "User")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "ed")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Warning")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "A slightly different error message.")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Date")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "2001-11-23 15:03:17 -5")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "User")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "ed")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Fatal")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Unknown variable \"bar\"")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Stack")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "file")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "TopClass.py")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "line")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "23")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "code")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "x = MoreObject(\"345\\n\")\n")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "file")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "MoreClass.py")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "line")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "58")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "code")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "foo = bar")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex2_28); +} + +// TODO: 5.1 - 5.2 BOM + +TEST_F(HandlerSpecTest, Ex5_3_BlockStructureIndicators) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "sequence")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "one")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "two")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "mapping")); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "sky")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "blue")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "sea")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "green")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex5_3); +} + +TEST_F(HandlerSpecTest, Ex5_4_FlowStructureIndicators) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "sequence")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "one")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "two")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "mapping")); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "sky")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "blue")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "sea")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "green")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex5_4); +} + + +TEST_F(HandlerSpecTest, Ex5_6_NodePropertyIndicators) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "anchored")); + EXPECT_CALL(handler, OnScalar(_, "!local", 1, "value")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "alias")); + EXPECT_CALL(handler, OnAlias(_, 1)); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex5_6); +} + +TEST_F(HandlerSpecTest, Ex5_7_BlockScalarIndicators) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "literal")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "some\ntext\n")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "folded")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "some text\n")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex5_7); +} + +TEST_F(HandlerSpecTest, Ex5_8_QuotedScalarIndicators) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "single")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "text")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "double")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "text")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex5_8); +} + +// TODO: 5.9 directive +// TODO: 5.10 reserved indicator + +TEST_F(HandlerSpecTest, Ex5_11_LineBreakCharacters) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Line break (no glyph)\nLine break (glyphed)\n")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex5_11); +} + +TEST_F(HandlerSpecTest, Ex5_12_TabsAndSpaces) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "quoted")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Quoted\t")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "block")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "void main() {\n\tprintf(\"Hello, world!\\n\");\n}")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex5_12); +} + +TEST_F(HandlerSpecTest, Ex5_13_EscapedCharacters) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Fun with \x5C \x22 \x07 \x08 \x1B \x0C \x0A \x0D \x09 \x0B \x00 \x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9 A A A")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex5_13); +} + +TEST_F(HandlerSpecTest, Ex5_14_InvalidEscapedCharacters) { + EXPECT_THROW_PARSER_EXCEPTION(IgnoreParse(ex5_14), std::string(ErrorMsg::INVALID_ESCAPE) + "c"); +} + +TEST_F(HandlerSpecTest, Ex6_1_IndentationSpaces) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Not indented")); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "By one space")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "By four\n spaces\n")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Flow style")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "By two")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Also by two")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Still by two")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_1); +} + +TEST_F(HandlerSpecTest, Ex6_2_IndentationIndicators) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "a")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "b")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "c")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "d")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_2); +} + +TEST_F(HandlerSpecTest, Ex6_3_SeparationSpaces) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "foo")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "bar")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "baz")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "baz")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_3); +} + +TEST_F(HandlerSpecTest, Ex6_4_LinePrefixes) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "plain")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "text lines")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "quoted")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "text lines")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "block")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "text\n \tlines\n")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_4); +} + +TEST_F(HandlerSpecTest, Ex6_5_EmptyLines) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Folding")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Empty line\nas a line feed")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Chomping")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Clipped empty lines\n")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_5); +} + +TEST_F(HandlerSpecTest, Ex6_6_LineFolding) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "trimmed\n\n\nas space")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_6); +} + +TEST_F(HandlerSpecTest, Ex6_7_BlockFolding) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "foo \n\n\t bar\n\nbaz\n")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_7); +} + +TEST_F(HandlerSpecTest, Ex6_8_FlowFolding) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, " foo\nbar\nbaz ")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_8); +} + +TEST_F(HandlerSpecTest, Ex6_9_SeparatedComment) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "key")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "value")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_9); +} + + +TEST_F(HandlerSpecTest, _MultiLineComments) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "key")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "value")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_11); +} + +TEST_F(HandlerSpecTest, Ex6_12_SeparationSpacesII) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "first")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sammy")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "last")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Sosa")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "hr")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "65")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "avg")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "0.278")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_12); +} + +TEST_F(HandlerSpecTest, Ex6_13_ReservedDirectives) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "foo")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_13); +} + +TEST_F(HandlerSpecTest, Ex6_14_YAMLDirective) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "foo")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_14); +} + +TEST_F(HandlerSpecTest, Ex6_15_InvalidRepeatedYAMLDirective) { + EXPECT_THROW_PARSER_EXCEPTION(IgnoreParse(ex6_15), ErrorMsg::REPEATED_YAML_DIRECTIVE); +} + +TEST_F(HandlerSpecTest, Ex6_16_TagDirective) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:str", 0, "foo")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_16); +} + +TEST_F(HandlerSpecTest, Ex6_17_InvalidRepeatedTagDirective) { + EXPECT_THROW_PARSER_EXCEPTION(IgnoreParse(ex6_17), ErrorMsg::REPEATED_TAG_DIRECTIVE); +} + +TEST_F(HandlerSpecTest, Ex6_18_PrimaryTagHandle) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!foo", 0, "bar")); + EXPECT_CALL(handler, OnDocumentEnd()); + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "tag:example.com,2000:app/foo", 0, "bar")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_18); +} + +TEST_F(HandlerSpecTest, Ex6_19_SecondaryTagHandle) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "tag:example.com,2000:app/int", 0, "1 - 3")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_19); +} + +TEST_F(HandlerSpecTest, Ex6_20_TagHandles) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "tag:example.com,2000:app/foo", 0, "bar")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_20); +} + +TEST_F(HandlerSpecTest, Ex6_21_LocalTagPrefix) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!my-light", 0, "fluorescent")); + EXPECT_CALL(handler, OnDocumentEnd()); + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!my-light", 0, "green")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_21); +} + +TEST_F(HandlerSpecTest, Ex6_22_GlobalTagPrefix) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "tag:example.com,2000:app/foo", 0, "bar")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_22); +} + +TEST_F(HandlerSpecTest, Ex6_23_NodeProperties) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:str", 1, "foo")); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:str", 0, "bar")); + EXPECT_CALL(handler, OnScalar(_, "?", 2, "baz")); + EXPECT_CALL(handler, OnAlias(_, 1)); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_23); +} + +TEST_F(HandlerSpecTest, Ex6_24_VerbatimTags) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:str", 0, "foo")); + EXPECT_CALL(handler, OnScalar(_, "!bar", 0, "baz")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_24); +} + +// TODO: Implement +TEST_F(HandlerSpecTest, DISABLED_Ex6_25_InvalidVerbatimTags) { + Parse(ex6_25); + FAIL() << "not implemented yet"; +} + +TEST_F(HandlerSpecTest, Ex6_26_TagShorthands) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "!local", 0, "foo")); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:str", 0, "bar")); + EXPECT_CALL(handler, OnScalar(_, "tag:example.com,2000:app/tag%21", 0, "baz")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_26); +} + +TEST_F(HandlerSpecTest, Ex6_27a_InvalidTagShorthands) { + EXPECT_THROW_PARSER_EXCEPTION(IgnoreParse(ex6_27a), ErrorMsg::TAG_WITH_NO_SUFFIX); +} + +// TODO: should we reject this one (since !h! is not declared)? +TEST_F(HandlerSpecTest, DISABLED_Ex6_27b_InvalidTagShorthands) { + Parse(ex6_27b); + FAIL() << "not implemented yet"; +} + +TEST_F(HandlerSpecTest, Ex6_28_NonSpecificTags) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "12")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "12")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "12")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_28); +} + +TEST_F(HandlerSpecTest, Ex6_29_NodeAnchors) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "First occurrence")); + EXPECT_CALL(handler, OnScalar(_, "?", 1, "Value")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Second occurrence")); + EXPECT_CALL(handler, OnAlias(_, 1)); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex6_29); +} + +TEST_F(HandlerSpecTest, Ex7_1_AliasNodes) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "First occurrence")); + EXPECT_CALL(handler, OnScalar(_, "?", 1, "Foo")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Second occurrence")); + EXPECT_CALL(handler, OnAlias(_, 1)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Override anchor")); + EXPECT_CALL(handler, OnScalar(_, "?", 2, "Bar")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Reuse anchor")); + EXPECT_CALL(handler, OnAlias(_, 2)); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_1); +} + +TEST_F(HandlerSpecTest, Ex7_2_EmptyNodes) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "foo")); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:str", 0, "")); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:str", 0, "")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "bar")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_2); +} + +TEST_F(HandlerSpecTest, Ex7_3_CompletelyEmptyNodes) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "foo")); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "bar")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_3); +} + +TEST_F(HandlerSpecTest, Ex7_4_DoubleQuotedImplicitKeys) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "implicit block key")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "implicit flow key")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "value")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_4); +} + +TEST_F(HandlerSpecTest, Ex7_5_DoubleQuotedLineBreaks) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "folded to a space,\nto a line feed, or \t \tnon-content")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_5); +} + +TEST_F(HandlerSpecTest, Ex7_6_DoubleQuotedLines) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, " 1st non-empty\n2nd non-empty 3rd non-empty ")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_6); +} + +TEST_F(HandlerSpecTest, Ex7_7_SingleQuotedCharacters) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "here's to \"quotes\"")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_7); +} + +TEST_F(HandlerSpecTest, Ex7_8_SingleQuotedImplicitKeys) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "implicit block key")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "implicit flow key")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "value")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_8); +} + +TEST_F(HandlerSpecTest, Ex7_9_SingleQuotedLines) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, " 1st non-empty\n2nd non-empty 3rd non-empty ")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_9); +} + +TEST_F(HandlerSpecTest, Ex7_10_PlainCharacters) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "::vector")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, ": - ()")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "Up, up, and away!")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "-123")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "http://example.com/foo#bar")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "::vector")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, ": - ()")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Up, up, and away!")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "-123")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "http://example.com/foo#bar")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_10); +} + +TEST_F(HandlerSpecTest, Ex7_11_PlainImplicitKeys) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "implicit block key")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "implicit flow key")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "value")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_11); +} + +TEST_F(HandlerSpecTest, Ex7_12_PlainLines) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "1st non-empty\n2nd non-empty 3rd non-empty")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_12); +} + +TEST_F(HandlerSpecTest, Ex7_13_FlowSequence) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "one")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "two")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "three")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "four")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_13); +} + +TEST_F(HandlerSpecTest, Ex7_14_FlowSequenceEntries) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "double quoted")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "single quoted")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "plain text")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "nested")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "single")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "pair")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_14); +} + +TEST_F(HandlerSpecTest, Ex7_15_FlowMappings) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "one")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "two")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "three")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "four")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "five")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "six")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "seven")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "eight")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_15); +} + +TEST_F(HandlerSpecTest, Ex7_16_FlowMappingEntries) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "explicit")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "entry")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "implicit")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "entry")); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_16); +} + +TEST_F(HandlerSpecTest, Ex7_17_FlowMappingSeparateValues) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "unquoted")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "separate")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "http://foo.com")); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "omitted value")); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "omitted key")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_17); +} + +TEST_F(HandlerSpecTest, Ex7_18_FlowMappingAdjacentValues) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "adjacent")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "value")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "readable")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "value")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "empty")); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_18); +} + +TEST_F(HandlerSpecTest, Ex7_19_SinglePairFlowMappings) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "foo")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "bar")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_19); +} + +TEST_F(HandlerSpecTest, Ex7_20_SinglePairExplicitEntry) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "foo bar")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "baz")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_20); +} + +TEST_F(HandlerSpecTest, Ex7_21_SinglePairImplicitEntries) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "YAML")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "separate")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Default)); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "empty key entry")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "JSON")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "like")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "adjacent")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_21); +} + +TEST_F(HandlerSpecTest, Ex7_22_InvalidImplicitKeys) { + EXPECT_THROW_PARSER_EXCEPTION(IgnoreParse(ex7_22), ErrorMsg::END_OF_SEQ_FLOW); +} + +TEST_F(HandlerSpecTest, Ex7_23_FlowContent) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "a")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "b")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Flow)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "a")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "b")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "a")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "b")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "c")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_23); +} + +TEST_F(HandlerSpecTest, Ex7_24_FlowNodes) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:str", 0, "a")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "b")); + EXPECT_CALL(handler, OnScalar(_, "!", 1, "c")); + EXPECT_CALL(handler, OnAlias(_, 1)); + EXPECT_CALL(handler, OnScalar(_, "tag:yaml.org,2002:str", 0, "")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex7_24); +} + +TEST_F(HandlerSpecTest, Ex8_1_BlockScalarHeader) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "literal\n")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, " folded\n")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "keep\n\n")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, " strip")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_1); +} + +TEST_F(HandlerSpecTest, Ex8_2_BlockIndentationHeader) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "detected\n")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\n\n# detected\n")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, " explicit\n")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\t\ndetected\n")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_2); +} + +TEST_F(HandlerSpecTest, Ex8_3a_InvalidBlockScalarIndentationIndicators) { + EXPECT_THROW_PARSER_EXCEPTION(IgnoreParse(ex8_3a), ErrorMsg::END_OF_SEQ); +} + +TEST_F(HandlerSpecTest, Ex8_3b_InvalidBlockScalarIndentationIndicators) { + EXPECT_THROW_PARSER_EXCEPTION(IgnoreParse(ex8_3b), ErrorMsg::END_OF_SEQ); +} + +TEST_F(HandlerSpecTest, Ex8_3c_InvalidBlockScalarIndentationIndicators) { + EXPECT_THROW_PARSER_EXCEPTION(IgnoreParse(ex8_3c), ErrorMsg::END_OF_SEQ); +} + +TEST_F(HandlerSpecTest, Ex8_4_ChompingFinalLineBreak) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "strip")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "text")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "clip")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "text\n")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "keep")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "text\n")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_4); +} + +TEST_F(HandlerSpecTest, DISABLED_Ex8_5_ChompingTrailingLines) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "strip")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "# text")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "clip")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "# text\n")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "keep")); + // NOTE: I believe this is a bug in the YAML spec - + // it should be "# text\n\n" + EXPECT_CALL(handler, OnScalar(_, "!", 0, "# text\n")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_5); +} + +TEST_F(HandlerSpecTest, Ex8_6_EmptyScalarChomping) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "strip")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "clip")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "keep")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\n")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_6); +} + +TEST_F(HandlerSpecTest, Ex8_7_LiteralScalar) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "literal\n\ttext\n")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_7); +} + +TEST_F(HandlerSpecTest, Ex8_8_LiteralContent) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\n\nliteral\n \n\ntext\n")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_8); +} + +TEST_F(HandlerSpecTest, Ex8_9_FoldedScalar) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "folded text\n")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_9); +} + +TEST_F(HandlerSpecTest, Ex8_10_FoldedLines) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_10); +} + +TEST_F(HandlerSpecTest, Ex8_11_MoreIndentedLines) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_11); +} + +TEST_F(HandlerSpecTest, Ex8_12_EmptySeparationLines) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_12); +} + +TEST_F(HandlerSpecTest, Ex8_13_FinalEmptyLines) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n")); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_13); +} + +TEST_F(HandlerSpecTest, Ex8_14_BlockSequence) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "block sequence")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "one")); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "two")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "three")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_14); +} + +TEST_F(HandlerSpecTest, Ex8_15_BlockSequenceEntryTypes) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "block node\n")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "one")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "two")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "one")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "two")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_15); +} + +TEST_F(HandlerSpecTest, Ex8_16_BlockMappings) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "block mapping")); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "key")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "value")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_16); +} + +TEST_F(HandlerSpecTest, Ex8_17_ExplicitBlockMappingEntries) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "explicit key")); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "block key\n")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "one")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "two")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_17); +} + +TEST_F(HandlerSpecTest, Ex8_18_ImplicitBlockMappingEntries) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "plain key")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "in-line value")); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnNull(_, 0)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "quoted key")); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "entry")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_18); +} + +TEST_F(HandlerSpecTest, Ex8_19_CompactBlockMappings) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "sun")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "yellow")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "earth")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "blue")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "moon")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "white")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_19); +} + +TEST_F(HandlerSpecTest, Ex8_20_BlockNodeTypes) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnSequenceStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "flow in block")); + EXPECT_CALL(handler, OnScalar(_, "!", 0, "Block scalar\n")); + EXPECT_CALL(handler, OnMapStart(_, "tag:yaml.org,2002:map", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "foo")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "bar")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_20); +} + +TEST_F(HandlerSpecTest, DISABLED_Ex8_21_BlockScalarNodes) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "literal")); + // NOTE: I believe this is a bug in the YAML spec + // - it should be "value\n" + EXPECT_CALL(handler, OnScalar(_, "!", 0, "value")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "folded")); + EXPECT_CALL(handler, OnScalar(_, "!foo", 0, "value")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_21); +} + +TEST_F(HandlerSpecTest, Ex8_22_BlockCollectionNodes) { + EXPECT_CALL(handler, OnDocumentStart(_)); + EXPECT_CALL(handler, OnMapStart(_, "?", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "sequence")); + EXPECT_CALL(handler, OnSequenceStart(_, "tag:yaml.org,2002:seq", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "entry")); + EXPECT_CALL(handler, OnSequenceStart(_, "tag:yaml.org,2002:seq", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "nested")); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnSequenceEnd()); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "mapping")); + EXPECT_CALL(handler, OnMapStart(_, "tag:yaml.org,2002:map", 0, EmitterStyle::Block)); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "foo")); + EXPECT_CALL(handler, OnScalar(_, "?", 0, "bar")); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnMapEnd()); + EXPECT_CALL(handler, OnDocumentEnd()); + Parse(ex8_22); +} +} +} diff --git a/third_party/rust/yaml-rust/tests/specs/libyaml_fail-01.yaml b/third_party/rust/yaml-rust/tests/specs/libyaml_fail-01.yaml new file mode 100644 index 0000000000..5e6c0dc56a --- /dev/null +++ b/third_party/rust/yaml-rust/tests/specs/libyaml_fail-01.yaml @@ -0,0 +1,6 @@ +# Ex 8.18 +plain key: in-line value +: # Both empty +"quoted key": +- entry + diff --git a/third_party/rust/yaml-rust/tests/specs/libyaml_fail-02.yaml b/third_party/rust/yaml-rust/tests/specs/libyaml_fail-02.yaml new file mode 100644 index 0000000000..60074dea2b --- /dev/null +++ b/third_party/rust/yaml-rust/tests/specs/libyaml_fail-02.yaml @@ -0,0 +1,7 @@ +# Ex 7.17 +{ +unqoted : "separate", +http://foo.com, +omitted value:, +: omitted key, +} diff --git a/third_party/rust/yaml-rust/tests/specs/libyaml_fail-03.yaml b/third_party/rust/yaml-rust/tests/specs/libyaml_fail-03.yaml new file mode 100644 index 0000000000..fc821dc73e --- /dev/null +++ b/third_party/rust/yaml-rust/tests/specs/libyaml_fail-03.yaml @@ -0,0 +1,5 @@ +# ex 7.2 +{ + foo : !!str, + !!str : bar, +} diff --git a/third_party/rust/yaml-rust/tests/test_round_trip.rs b/third_party/rust/yaml-rust/tests/test_round_trip.rs new file mode 100644 index 0000000000..bfa9602751 --- /dev/null +++ b/third_party/rust/yaml-rust/tests/test_round_trip.rs @@ -0,0 +1,23 @@ +extern crate yaml_rust; + +use yaml_rust::{Yaml, YamlEmitter, YamlLoader}; + +fn test_round_trip(original: &Yaml) { + let mut out = String::new(); + YamlEmitter::new(&mut out).dump(original).unwrap(); + let documents = YamlLoader::load_from_str(&out).unwrap(); + assert_eq!(documents.len(), 1); + assert_eq!(documents[0], *original); +} + +#[test] +fn test_escape_character() { + let y = Yaml::String("\x1b".to_owned()); + test_round_trip(&y); +} + +#[test] +fn test_colon_in_string() { + let y = Yaml::String("x: %".to_owned()); + test_round_trip(&y); +} |