diff options
Diffstat (limited to 'third_party/rust/xml-rs/tests')
19 files changed, 1302 insertions, 0 deletions
diff --git a/third_party/rust/xml-rs/tests/documents/sample_1.xml b/third_party/rust/xml-rs/tests/documents/sample_1.xml new file mode 100644 index 0000000000..4d1cbc0564 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_1.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<project name="project-name"> + <libraries> + <library groupId="org.example" artifactId="<name>" version="0.1"/> + <library groupId="com.example" artifactId=""cool-lib&" version="999"/> + </libraries> + <module name="module-1"> + <files> + <file name="somefile.java" type="java"> + Some <java> class + </file> + <file name="another_file.java" type="java"> + Another "java" class + </file> + <file name="config.xml" type="xml"> + Weird 'XML' config + </file> + </files> + <libraries> + <library groupId="junit" artifactId="junit" version="1.9.5"/> + </libraries> + </module> + <module name="module-2"> + <files> + <file name="program.js" type="javascript"> + JavaScript & program + </file> + <file name="style.css" type="css"> + Cascading style sheet: © - ҉ + </file> + </files> + </module> +</project> + diff --git a/third_party/rust/xml-rs/tests/documents/sample_1_full.txt b/third_party/rust/xml-rs/tests/documents/sample_1_full.txt new file mode 100644 index 0000000000..a8d64d01b3 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_1_full.txt @@ -0,0 +1,58 @@ +StartDocument(1.0, utf-8) +StartElement(project [name="project-name"]) +Whitespace("\n ") +StartElement(libraries) +Whitespace("\n ") +StartElement(library [groupId="org.example", artifactId="<name>", version="0.1"]) +EndElement(library) +Whitespace("\n ") +StartElement(library [groupId="com.example", artifactId="\"cool-lib&", version="999"]) +EndElement(library) +Whitespace("\n ") +EndElement(libraries) +Whitespace("\n ") +StartElement(module [name="module-1"]) +Whitespace("\n ") +StartElement(files) +Whitespace("\n ") +StartElement(file [name="somefile.java", type="java"]) +Characters("\n Some <java> class\n ") +EndElement(file) +Whitespace("\n ") +StartElement(file [name="another_file.java", type="java"]) +Characters("\n Another \"java\" class\n ") +EndElement(file) +Whitespace("\n ") +StartElement(file [name="config.xml", type="xml"]) +Characters("\n Weird \'XML\' config\n ") +EndElement(file) +Whitespace("\n ") +EndElement(files) +Whitespace("\n ") +StartElement(libraries) +Whitespace("\n ") +StartElement(library [groupId="junit", artifactId="junit", version="1.9.5"]) +EndElement(library) +Whitespace("\n ") +EndElement(libraries) +Whitespace("\n ") +EndElement(module) +Whitespace("\n ") +StartElement(module [name="module-2"]) +Whitespace("\n ") +StartElement(files) +Whitespace("\n ") +StartElement(file [name="program.js", type="javascript"]) +Characters("\n JavaScript & program\n ") +EndElement(file) +Whitespace("\n ") +StartElement(file [name="style.css", type="css"]) +Characters("\n Cascading style sheet: © - ҉\n ") +EndElement(file) +Whitespace("\n ") +EndElement(files) +Whitespace("\n ") +EndElement(module) +Whitespace("\n") +EndElement(project) +EndDocument diff --git a/third_party/rust/xml-rs/tests/documents/sample_1_short.txt b/third_party/rust/xml-rs/tests/documents/sample_1_short.txt new file mode 100644 index 0000000000..4dbe285b95 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_1_short.txt @@ -0,0 +1,37 @@ +StartDocument(1.0, utf-8) +StartElement(project [name="project-name"]) +StartElement(libraries) +StartElement(library [groupId="org.example", artifactId="<name>", version="0.1"]) +EndElement(library) +StartElement(library [groupId="com.example", artifactId="\"cool-lib&", version="999"]) +EndElement(library) +EndElement(libraries) +StartElement(module [name="module-1"]) +StartElement(files) +StartElement(file [name="somefile.java", type="java"]) +Characters("Some <java> class") +EndElement(file) +StartElement(file [name="another_file.java", type="java"]) +Characters("Another \"java\" class") +EndElement(file) +StartElement(file [name="config.xml", type="xml"]) +Characters("Weird \'XML\' config") +EndElement(file) +EndElement(files) +StartElement(libraries) +StartElement(library [groupId="junit", artifactId="junit", version="1.9.5"]) +EndElement(library) +EndElement(libraries) +EndElement(module) +StartElement(module [name="module-2"]) +StartElement(files) +StartElement(file [name="program.js", type="javascript"]) +Characters("JavaScript & program") +EndElement(file) +StartElement(file [name="style.css", type="css"]) +Characters("Cascading style sheet: © - ҉") +EndElement(file) +EndElement(files) +EndElement(module) +EndElement(project) +EndDocument diff --git a/third_party/rust/xml-rs/tests/documents/sample_2.xml b/third_party/rust/xml-rs/tests/documents/sample_2.xml new file mode 100644 index 0000000000..f9543acab3 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_2.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<p:data xmlns:d="urn:example:double" xmlns:h="urn:example:header" xmlns:p="urn:example:namespace"> + <p:datum id="34"> + <p:name>Name</p:name> + <d:name>Another name</d:name> + <d:arg>0.3</d:arg> + <d:arg>0.2</d:arg> + <p:arg>0.1</p:arg> + <p:arg>0.01</p:arg> + <h:header name="Header-1">header 1 value</h:header> + <h:header name="Header-2"> + Some bigger value + </h:header> + </p:datum> +</p:data> diff --git a/third_party/rust/xml-rs/tests/documents/sample_2_full.txt b/third_party/rust/xml-rs/tests/documents/sample_2_full.txt new file mode 100644 index 0000000000..75075cd661 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_2_full.txt @@ -0,0 +1,41 @@ +StartDocument(1.0, utf-8) +StartElement({urn:example:namespace}p:data) +Whitespace("\n ") +StartElement({urn:example:namespace}p:datum [id="34"]) +Whitespace("\n ") +StartElement({urn:example:namespace}p:name) +Characters("Name") +EndElement({urn:example:namespace}p:name) +Whitespace("\n ") +StartElement({urn:example:double}d:name) +Characters("Another name") +EndElement({urn:example:double}d:name) +Whitespace("\n ") +StartElement({urn:example:double}d:arg) +Characters("0.3") +EndElement({urn:example:double}d:arg) +Whitespace("\n ") +StartElement({urn:example:double}d:arg) +Characters("0.2") +EndElement({urn:example:double}d:arg) +Whitespace("\n ") +StartElement({urn:example:namespace}p:arg) +Characters("0.1") +EndElement({urn:example:namespace}p:arg) +Whitespace("\n ") +StartElement({urn:example:namespace}p:arg) +Characters("0.01") +EndElement({urn:example:namespace}p:arg) +Whitespace("\n ") +StartElement({urn:example:header}h:header [name="Header-1"]) +Characters("header 1 value") +EndElement({urn:example:header}h:header) +Whitespace("\n ") +StartElement({urn:example:header}h:header [name="Header-2"]) +Characters("\n Some bigger value\n ") +EndElement({urn:example:header}h:header) +Whitespace("\n ") +EndElement({urn:example:namespace}p:datum) +Whitespace("\n") +EndElement({urn:example:namespace}p:data) +EndDocument diff --git a/third_party/rust/xml-rs/tests/documents/sample_2_short.txt b/third_party/rust/xml-rs/tests/documents/sample_2_short.txt new file mode 100644 index 0000000000..23680255a4 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_2_short.txt @@ -0,0 +1,30 @@ +StartDocument(1.0, utf-8) +StartElement({urn:example:namespace}p:data) +StartElement({urn:example:namespace}p:datum [id="34"]) +StartElement({urn:example:namespace}p:name) +Characters("Name") +EndElement({urn:example:namespace}p:name) +StartElement({urn:example:double}d:name) +Characters("Another name") +EndElement({urn:example:double}d:name) +StartElement({urn:example:double}d:arg) +Characters("0.3") +EndElement({urn:example:double}d:arg) +StartElement({urn:example:double}d:arg) +Characters("0.2") +EndElement({urn:example:double}d:arg) +StartElement({urn:example:namespace}p:arg) +Characters("0.1") +EndElement({urn:example:namespace}p:arg) +StartElement({urn:example:namespace}p:arg) +Characters("0.01") +EndElement({urn:example:namespace}p:arg) +StartElement({urn:example:header}h:header [name="Header-1"]) +Characters("header 1 value") +EndElement({urn:example:header}h:header) +StartElement({urn:example:header}h:header [name="Header-2"]) +Characters("Some bigger value") +EndElement({urn:example:header}h:header) +EndElement({urn:example:namespace}p:datum) +EndElement({urn:example:namespace}p:data) +EndDocument diff --git a/third_party/rust/xml-rs/tests/documents/sample_3.xml b/third_party/rust/xml-rs/tests/documents/sample_3.xml new file mode 100644 index 0000000000..657e37d1a5 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_3.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<p:data xmlns:p="urn:x" z=">"> + <!-- abcd < > & --> + <a>test</a> + <b>kkss" = ddd' ></b> + <![CDATA[ + <a>ddddd</b>!e3--><!-- ddckx + ]]> + <c/> + <![CDATA[ + <![CDATA[zzzz]]]]><![CDATA[>]]> +</p:data> + diff --git a/third_party/rust/xml-rs/tests/documents/sample_3_full.txt b/third_party/rust/xml-rs/tests/documents/sample_3_full.txt new file mode 100644 index 0000000000..e9a0f7e3d3 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_3_full.txt @@ -0,0 +1,23 @@ +1:1 StartDocument(1.0, utf-8) +2:1 StartElement({urn:x}p:data [z=">"]) +2:31 Whitespace("\n ") +3:5 Comment(" abcd < > & ") +3:34 Whitespace("\n ") +4:5 StartElement(a) +4:8 Characters("test") +4:12 EndElement(a) +4:16 Whitespace("\n ") +5:5 StartElement(b) +5:8 Characters("kkss\" = ddd\' >") +5:22 EndElement(b) +5:26 Whitespace("\n ") +6:5 CData("\n <a>ddddd</b>!e3--><!-- ddckx\n ") +8:8 Characters("\n ") +9:5 StartElement(c) +9:5 EndElement(c) +9:9 Whitespace("\n ") +10:5 CData("\n <![CDATA[zzzz]]") +11:23 CData(">") +11:36 Characters("\n") +12:1 EndElement({urn:x}p:data) +14:1 EndDocument diff --git a/third_party/rust/xml-rs/tests/documents/sample_3_short.txt b/third_party/rust/xml-rs/tests/documents/sample_3_short.txt new file mode 100644 index 0000000000..2582f3357e --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_3_short.txt @@ -0,0 +1,14 @@ +1:1 StartDocument(1.0, utf-8) +2:1 StartElement({urn:x}p:data [z=">"]) +4:5 StartElement(a) +4:8 Characters("test") +4:12 EndElement(a) +5:5 StartElement(b) +5:8 Characters("kkss\" = ddd\' >") +5:22 EndElement(b) +6:5 Characters("<a>ddddd</b>!e3--><!-- ddckx") +9:5 StartElement(c) +9:5 EndElement(c) +10:5 Characters("<![CDATA[zzzz]]>") +12:1 EndElement({urn:x}p:data) +14:1 EndDocument diff --git a/third_party/rust/xml-rs/tests/documents/sample_4.xml b/third_party/rust/xml-rs/tests/documents/sample_4.xml new file mode 100644 index 0000000000..fb915ffc82 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_4.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE data SYSTEM "abcd.dtd"> +<p:data xmlns:p="urn:x" z=">"> + <!-- abcd < > & --> + <a>test</a> + <b>kkss" = ddd' ></b> + <![CDATA[ + <a>ddddd</b>!e3--><!-- ddckx + ]]> + <c/> + <![CDATA[ + <![CDATA[zzzz]]]]><![CDATA[>]]> +</p:data> + + diff --git a/third_party/rust/xml-rs/tests/documents/sample_4_full.txt b/third_party/rust/xml-rs/tests/documents/sample_4_full.txt new file mode 100644 index 0000000000..4bdadfb74f --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_4_full.txt @@ -0,0 +1,23 @@ +StartDocument(1.0, utf-8) +StartElement({urn:x}p:data [z=">"]) +Whitespace("\n ") +Comment(" abcd < > & ") +Whitespace("\n ") +StartElement(a) +Characters("test") +EndElement(a) +Whitespace("\n ") +StartElement(b) +Characters("kkss\" = ddd\' >") +EndElement(b) +Whitespace("\n ") +CData("\n <a>ddddd</b>!e3--><!-- ddckx\n ") +Characters("\n ") +StartElement(c) +EndElement(c) +Whitespace("\n ") +CData("\n <![CDATA[zzzz]]") +CData(">") +Characters("\n") +EndElement({urn:x}p:data) +EndDocument diff --git a/third_party/rust/xml-rs/tests/documents/sample_4_short.txt b/third_party/rust/xml-rs/tests/documents/sample_4_short.txt new file mode 100644 index 0000000000..52e4b83e1a --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_4_short.txt @@ -0,0 +1,14 @@ +StartDocument(1.0, utf-8) +StartElement({urn:x}p:data [z=">"]) +StartElement(a) +Characters("test") +EndElement(a) +StartElement(b) +Characters("kkss\" = ddd\' >") +EndElement(b) +Characters("<a>ddddd</b>!e3--><!-- ddckx") +StartElement(c) +EndElement(c) +Characters("<![CDATA[zzzz]]>") +EndElement({urn:x}p:data) +EndDocument diff --git a/third_party/rust/xml-rs/tests/documents/sample_5.xml b/third_party/rust/xml-rs/tests/documents/sample_5.xml new file mode 100644 index 0000000000..92aa31d329 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_5.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE data SYSTEM "abcd.dtd"> +<p> + <a>test ©≂̸</a> +</p> + + diff --git a/third_party/rust/xml-rs/tests/documents/sample_5_short.txt b/third_party/rust/xml-rs/tests/documents/sample_5_short.txt new file mode 100644 index 0000000000..3079811784 --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_5_short.txt @@ -0,0 +1,7 @@ +StartDocument(1.0, utf-8) +StartElement(p) +StartElement(a) +Characters("test ©≂̸") +EndElement(a) +EndElement(p) +EndDocument diff --git a/third_party/rust/xml-rs/tests/documents/sample_6.xml b/third_party/rust/xml-rs/tests/documents/sample_6.xml new file mode 100644 index 0000000000..943c02d36f --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_6.xml @@ -0,0 +1,4 @@ +<?xml version="1.0"?> +<?xml-stylesheet href="doc.xsl"?> + +<doc>Hello</doc> diff --git a/third_party/rust/xml-rs/tests/documents/sample_6_full.txt b/third_party/rust/xml-rs/tests/documents/sample_6_full.txt new file mode 100644 index 0000000000..debb366edb --- /dev/null +++ b/third_party/rust/xml-rs/tests/documents/sample_6_full.txt @@ -0,0 +1,8 @@ +StartDocument(1.0, UTF-8) +Whitespace("\n") +ProcessingInstruction(xml-stylesheet="href=\"doc.xsl\"") +Whitespace("\n\n") +StartElement(doc) +Characters("Hello") +EndElement(doc) +EndDocument diff --git a/third_party/rust/xml-rs/tests/event_reader.rs b/third_party/rust/xml-rs/tests/event_reader.rs new file mode 100644 index 0000000000..750dcc46b3 --- /dev/null +++ b/third_party/rust/xml-rs/tests/event_reader.rs @@ -0,0 +1,587 @@ +#![forbid(unsafe_code)] + +extern crate xml; +#[macro_use] +extern crate lazy_static; + +use std::env; +use std::fmt; +use std::fs::File; +use std::io::{BufRead, BufReader, Write, stderr}; +use std::path::Path; + +use xml::name::OwnedName; +use xml::common::Position; +use xml::reader::{Result, XmlEvent, ParserConfig, EventReader}; + +/// Dummy function that opens a file, parses it, and returns a `Result`. +/// There can be IO errors (from `File::open`) and XML errors (from the parser). +/// Having `impl From<std::io::Error> for xml::reader::Error` allows the user to +/// do this without defining their own error type. +#[allow(dead_code)] +fn count_event_in_file(name: &Path) -> Result<usize> { + let mut event_count = 0; + for event in EventReader::new(BufReader::new(try!(File::open(name)))) { + try!(event); + event_count += 1; + } + Ok(event_count) +} + +#[test] +fn sample_1_short() { + test( + include_bytes!("documents/sample_1.xml"), + include_bytes!("documents/sample_1_short.txt"), + ParserConfig::new() + .ignore_comments(true) + .whitespace_to_characters(true) + .cdata_to_characters(true) + .trim_whitespace(true) + .coalesce_characters(true), + false + ); +} + +#[test] +fn sample_1_full() { + test( + include_bytes!("documents/sample_1.xml"), + include_bytes!("documents/sample_1_full.txt"), + ParserConfig::new() + .ignore_comments(false) + .whitespace_to_characters(false) + .cdata_to_characters(false) + .trim_whitespace(false) + .coalesce_characters(false), + false + ); +} + +#[test] +fn sample_2_short() { + test( + include_bytes!("documents/sample_2.xml"), + include_bytes!("documents/sample_2_short.txt"), + ParserConfig::new() + .ignore_comments(true) + .whitespace_to_characters(true) + .cdata_to_characters(true) + .trim_whitespace(true) + .coalesce_characters(true), + false + ); +} + +#[test] +fn sample_2_full() { + test( + include_bytes!("documents/sample_2.xml"), + include_bytes!("documents/sample_2_full.txt"), + ParserConfig::new() + .ignore_comments(false) + .whitespace_to_characters(false) + .cdata_to_characters(false) + .trim_whitespace(false) + .coalesce_characters(false), + false + ); +} + +#[test] +fn sample_3_short() { + test( + include_bytes!("documents/sample_3.xml"), + include_bytes!("documents/sample_3_short.txt"), + ParserConfig::new() + .ignore_comments(true) + .whitespace_to_characters(true) + .cdata_to_characters(true) + .trim_whitespace(true) + .coalesce_characters(true), + true + ); +} + +#[test] +fn sample_3_full() { + test( + include_bytes!("documents/sample_3.xml"), + include_bytes!("documents/sample_3_full.txt"), + ParserConfig::new() + .ignore_comments(false) + .whitespace_to_characters(false) + .cdata_to_characters(false) + .trim_whitespace(false) + .coalesce_characters(false), + true + ); +} + +#[test] +fn sample_4_short() { + test( + include_bytes!("documents/sample_4.xml"), + include_bytes!("documents/sample_4_short.txt"), + ParserConfig::new() + .ignore_comments(true) + .whitespace_to_characters(true) + .cdata_to_characters(true) + .trim_whitespace(true) + .coalesce_characters(true), + false + ); +} + +#[test] +fn sample_4_full() { + test( + include_bytes!("documents/sample_4.xml"), + include_bytes!("documents/sample_4_full.txt"), + ParserConfig::new() + .ignore_comments(false) + .whitespace_to_characters(false) + .cdata_to_characters(false) + .trim_whitespace(false) + .coalesce_characters(false), + false + ); + +} + +#[test] +fn sample_5_short() { + test( + include_bytes!("documents/sample_5.xml"), + include_bytes!("documents/sample_5_short.txt"), + ParserConfig::new() + .ignore_comments(true) + .whitespace_to_characters(true) + .cdata_to_characters(true) + .trim_whitespace(true) + .coalesce_characters(true) + .add_entity("nbsp", " ") + .add_entity("copy", "©") + .add_entity("NotEqualTilde", "≂̸"), + false + ); +} + +#[test] +fn sample_6_full() { + test( + include_bytes!("documents/sample_6.xml"), + include_bytes!("documents/sample_6_full.txt"), + ParserConfig::new() + .ignore_root_level_whitespace(false) + .ignore_comments(false) + .whitespace_to_characters(false) + .cdata_to_characters(false) + .trim_whitespace(false) + .coalesce_characters(false), + false + ); +} + +#[test] +fn eof_1() { + test( + br#"<?xml"#, + br#"1:6 Unexpected end of stream: no root element found"#, + ParserConfig::new(), + false + ); +} + +#[test] +fn bad_1() { + test( + br#"<?xml&.,"#, + br#"1:6 Unexpected token: <?xml&"#, + ParserConfig::new(), + false + ); +} + +#[test] +fn dashes_in_comments() { + test( + br#"<!-- comment -- --><hello/>"#, + br#" + |1:14 Unexpected token '--' before ' ' + "#, + ParserConfig::new(), + false + ); + + test( + br#"<!-- comment ---><hello/>"#, + br#" + |1:14 Unexpected token '--' before '-' + "#, + ParserConfig::new(), + false + ); +} + +#[test] +fn tabs_1() { + test( + b"\t<a>\t<b/></a>", + br#" + |1:2 StartDocument(1.0, UTF-8) + |1:2 StartElement(a) + |1:6 StartElement(b) + |1:6 EndElement(b) + |1:10 EndElement(a) + |1:14 EndDocument + "#, + ParserConfig::new() + .trim_whitespace(true), + true + ); +} + +#[test] +fn issue_32_unescaped_cdata_end() { + test( + br#"<hello>]]></hello>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(hello) + |Characters("]]>") + |EndElement(hello) + |EndDocument + "#, + ParserConfig::new(), + false + ); +} + +#[test] +fn issue_unescaped_processing_instruction_end() { + test( + br#"<hello>?></hello>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(hello) + |Characters("?>") + |EndElement(hello) + |EndDocument + "#, + ParserConfig::new(), + false + ); +} + +#[test] +fn issue_unescaped_empty_tag_end() { + test( + br#"<hello>/></hello>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(hello) + |Characters("/>") + |EndElement(hello) + |EndDocument + "#, + ParserConfig::new(), + false + ); +} + +#[test] +fn issue_83_duplicate_attributes() { + test( + br#"<hello><some-tag a='10' a="20"></hello>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(hello) + |1:30 Attribute 'a' is redefined + "#, + ParserConfig::new(), + false + ); +} + +#[test] +fn issue_93_large_characters_in_entity_references() { + test( + r#"<hello>&𤶼;</hello>"#.as_bytes(), + r#" + |StartDocument(1.0, UTF-8) + |StartElement(hello) + |1:10 Unexpected entity: 𤶼 + "#.as_bytes(), // FIXME: it shouldn't be 10, looks like indices are off slightly + ParserConfig::new(), + false + ) +} + +#[test] +fn issue_98_cdata_ending_with_right_bracket() { + test( + br#"<hello><![CDATA[Foo [Bar]]]></hello>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(hello) + |CData("Foo [Bar]") + |EndElement(hello) + |EndDocument + "#, + ParserConfig::new(), + false + ) +} + +#[test] +fn issue_105_unexpected_double_dash() { + test( + br#"<hello>-- </hello>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(hello) + |Characters("-- ") + |EndElement(hello) + |EndDocument + "#, + ParserConfig::new(), + false + ); + + test( + br#"<hello>--</hello>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(hello) + |Characters("--") + |EndElement(hello) + |EndDocument + "#, + ParserConfig::new(), + false + ); + + test( + br#"<hello>--></hello>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(hello) + |Characters("-->") + |EndElement(hello) + |EndDocument + "#, + ParserConfig::new(), + false + ); + + test( + br#"<hello><![CDATA[--]]></hello>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(hello) + |CData("--") + |EndElement(hello) + |EndDocument + "#, + ParserConfig::new(), + false + ); +} + +#[test] +fn issue_attribues_have_no_default_namespace () { + test( + br#"<hello xmlns="urn:foo" x="y"/>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement({urn:foo}hello [x="y"]) + |EndElement({urn:foo}hello) + |EndDocument + "#, + ParserConfig::new(), + false + ); +} + +#[test] +fn issue_replacement_character_entity_reference() { + test( + br#"<doc>��</doc>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(doc) + |1:13 Invalid decimal character number in an entity: #55357 + "#, + ParserConfig::new(), + false, + ); + + test( + br#"<doc>��</doc>"#, + br#" + |StartDocument(1.0, UTF-8) + |StartElement(doc) + |1:13 Invalid hexadecimal character number in an entity: #xd83d + "#, + ParserConfig::new(), + false, + ); + + test( + br#"<doc>��</doc>"#, + format!( + r#" + |StartDocument(1.0, UTF-8) + |StartElement(doc) + |Characters("{replacement_character}{replacement_character}") + |EndElement(doc) + |EndDocument + "#, + replacement_character = "\u{fffd}" + ) + .as_bytes(), + ParserConfig::new() + .replace_unknown_entity_references(true), + false, + ); + + test( + br#"<doc>��</doc>"#, + format!( + r#" + |StartDocument(1.0, UTF-8) + |StartElement(doc) + |Characters("{replacement_character}{replacement_character}") + |EndElement(doc) + |EndDocument + "#, + replacement_character = "\u{fffd}" + ) + .as_bytes(), + ParserConfig::new() + .replace_unknown_entity_references(true), + false, + ); +} + +lazy_static! { + // If PRINT_SPEC env variable is set, print the lines + // to stderr instead of comparing with the output + // it can be used like this: + // PRINT_SPEC=1 cargo test --test event_reader sample_1_full 2> sample_1_full.txt + static ref PRINT: bool = { + for (key, value) in env::vars() { + if key == "PRINT_SPEC" && value == "1" { + return true; + } + } + false + }; +} + +// clones a lot but that's fine +fn trim_until_bar(s: String) -> String { + match s.trim() { + ts if ts.starts_with('|') => return ts[1..].to_owned(), + _ => {} + } + s +} + +fn test(input: &[u8], output: &[u8], config: ParserConfig, test_position: bool) { + let mut reader = config.create_reader(input); + let mut spec_lines = BufReader::new(output).lines() + .map(|line| line.unwrap()) + .enumerate() + .map(|(i, line)| (i, trim_until_bar(line))) + .filter(|&(_, ref line)| !line.trim().is_empty()); + + loop { + let e = reader.next(); + let line = + if test_position { + format!("{} {}", reader.position(), Event(&e)) + } else { + format!("{}", Event(&e)) + }; + + if *PRINT { + writeln!(&mut stderr(), "{}", line).unwrap(); + } else { + if let Some((n, spec)) = spec_lines.next() { + if line != spec { + const SPLITTER: &'static str = "-------------------"; + panic!("\n{}\nUnexpected event at line {}:\nExpected: {}\nFound: {}\n{}\n", + SPLITTER, n + 1, spec, line, std::str::from_utf8(output).unwrap()); + } + } else { + panic!("Unexpected event: {}", line); + } + } + + match e { + Ok(XmlEvent::EndDocument) | Err(_) => break, + _ => {}, + } + } +} + +// Here we define our own string representation of events so we don't depend +// on the specifics of Display implementation for XmlEvent and OwnedName. + +struct Name<'a>(&'a OwnedName); + +impl <'a> fmt::Display for Name<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(ref namespace) = self.0.namespace { + try! { write!(f, "{{{}}}", namespace) } + } + + if let Some(ref prefix) = self.0.prefix { + try! { write!(f, "{}:", prefix) } + } + + write!(f, "{}", self.0.local_name) + } +} + +struct Event<'a>(&'a Result<XmlEvent>); + +impl<'a> fmt::Display for Event<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let empty = String::new(); + match *self.0 { + Ok(ref e) => match *e { + XmlEvent::StartDocument { ref version, ref encoding, .. } => + write!(f, "StartDocument({}, {})", version, encoding), + XmlEvent::EndDocument => + write!(f, "EndDocument"), + XmlEvent::ProcessingInstruction { ref name, ref data } => + write!(f, "ProcessingInstruction({}={:?})", name, + data.as_ref().unwrap_or(&empty)), + XmlEvent::StartElement { ref name, ref attributes, .. } => { + if attributes.is_empty() { + write!(f, "StartElement({})", Name(name)) + } + else { + let attrs: Vec<_> = attributes.iter() + .map(|a| format!("{}={:?}", Name(&a.name), a.value)) .collect(); + write!(f, "StartElement({} [{}])", Name(name), attrs.join(", ")) + } + }, + XmlEvent::EndElement { ref name } => + write!(f, "EndElement({})", Name(name)), + XmlEvent::Comment(ref data) => + write!(f, r#"Comment("{}")"#, data.escape_debug()), + XmlEvent::CData(ref data) => + write!(f, r#"CData("{}")"#, data.escape_debug()), + XmlEvent::Characters(ref data) => + write!(f, r#"Characters("{}")"#, data.escape_debug()), + XmlEvent::Whitespace(ref data) => + write!(f, r#"Whitespace("{}")"#, data.escape_debug()), + }, + Err(ref e) => e.fmt(f), + } + } +} diff --git a/third_party/rust/xml-rs/tests/event_writer.rs b/third_party/rust/xml-rs/tests/event_writer.rs new file mode 100644 index 0000000000..dd64a4392e --- /dev/null +++ b/third_party/rust/xml-rs/tests/event_writer.rs @@ -0,0 +1,269 @@ +#![forbid(unsafe_code)] + +extern crate xml; + +use std::io::{BufReader, SeekFrom}; +use std::io::prelude::*; +use std::fs::File; +use std::str; + +use xml::reader::EventReader; +use xml::writer::EmitterConfig; + +macro_rules! unwrap_all { + ($($e:expr);+) => {{ + $($e.unwrap();)+ + }} +} + +#[test] +fn reading_writing_equal_with_namespaces() { + let mut f = File::open("tests/documents/sample_2.xml").unwrap(); + let mut b = Vec::new(); + + { + let r = EventReader::new(BufReader::new(&mut f)); + let mut w = EmitterConfig::default().perform_indent(true).create_writer(&mut b); + + for e in r { + match e { + Ok(e) => if let Some(e) = e.as_writer_event() { + match w.write(e) { + Ok(_) => {}, + Err(e) => panic!("Writer error: {:?}", e) + } + }, + Err(e) => panic!("Error: {}", e) + } + } + } + + f.seek(SeekFrom::Start(0)).unwrap(); + let mut fs = String::new(); + f.read_to_string(&mut fs).unwrap(); + + let bs = String::from_utf8(b).unwrap(); + + assert_eq!(fs.trim(), bs.trim()); +} + +#[test] +fn writing_simple() { + use xml::writer::XmlEvent; + + let mut b = Vec::new(); + + { + let mut w = EmitterConfig::new().write_document_declaration(false).create_writer(&mut b); + + w.write(XmlEvent::start_element("h:hello").ns("h", "urn:hello-world")).unwrap(); + w.write("hello world").unwrap(); + w.write(XmlEvent::end_element()).unwrap(); + } + + assert_eq!( + str::from_utf8(&b).unwrap(), + r#"<h:hello xmlns:h="urn:hello-world">hello world</h:hello>"# + ); +} + +#[test] +fn writing_empty_elements_with_normalizing() { + use xml::writer::XmlEvent; + + let mut b = Vec::new(); + + { + let mut w = EmitterConfig::new().write_document_declaration(false).create_writer(&mut b); + + unwrap_all! { + w.write(XmlEvent::start_element("hello")); + w.write(XmlEvent::start_element("world")); + w.write(XmlEvent::end_element()); + w.write(XmlEvent::end_element()) + } + } + + assert_eq!(str::from_utf8(&b).unwrap(), r#"<hello><world /></hello>"#); +} + +#[test] +fn writing_empty_elements_without_normalizing() { + use xml::writer::XmlEvent; + + let mut b = Vec::new(); + + { + let mut w = EmitterConfig::new() + .write_document_declaration(false) + .normalize_empty_elements(false) + .create_writer(&mut b); + + unwrap_all! { + w.write(XmlEvent::start_element("hello")); + w.write(XmlEvent::start_element("world")); + w.write(XmlEvent::end_element()); + w.write(XmlEvent::end_element()) + } + } + + assert_eq!(str::from_utf8(&b).unwrap(), r#"<hello><world></world></hello>"#); +} + +#[test] +fn writing_empty_elements_without_pad_self_closing() { + use xml::writer::XmlEvent; + + let mut b = Vec::new(); + + { + let mut w = EmitterConfig::new() + .write_document_declaration(false) + .pad_self_closing(false) + .create_writer(&mut b); + + unwrap_all! { + w.write(XmlEvent::start_element("hello")); + w.write(XmlEvent::start_element("world")); + w.write(XmlEvent::end_element()); + w.write(XmlEvent::end_element()) + } + } + + assert_eq!(str::from_utf8(&b).unwrap(), r#"<hello><world/></hello>"#); +} +#[test] +fn writing_empty_elements_pad_self_closing_explicit() { + use xml::writer::XmlEvent; + + let mut b = Vec::new(); + + { + let mut w = EmitterConfig::new() + .write_document_declaration(false) + .pad_self_closing(true) + .create_writer(&mut b); + + unwrap_all! { + w.write(XmlEvent::start_element("hello")); + w.write(XmlEvent::start_element("world")); + w.write(XmlEvent::end_element()); + w.write(XmlEvent::end_element()) + } + } + + assert_eq!(str::from_utf8(&b).unwrap(), r#"<hello><world /></hello>"#); +} + +#[test] +fn writing_comments_with_indentation() { + use xml::writer::XmlEvent; + + let mut b = Vec::new(); + + { + let mut w = EmitterConfig::new() + .write_document_declaration(false) + .perform_indent(true) + .create_writer(&mut b); + + unwrap_all! { + w.write(XmlEvent::start_element("hello")); + w.write(XmlEvent::start_element("world")); + w.write(XmlEvent::comment(" this is a manually padded comment\t")); + w.write(XmlEvent::comment("this is an unpadded comment")); + w.write(XmlEvent::end_element()); + w.write(XmlEvent::end_element()) + } + } + + assert_eq!( + str::from_utf8(&b).unwrap(), + "<hello> + <world> + <!-- this is a manually padded comment\t--> + <!-- this is an unpadded comment --> + </world> +</hello>"); +} + +#[test] +fn issue_112_overriding_namepace_prefix() { + use xml::writer::XmlEvent; + + let mut b = Vec::new(); + + { + let mut w = EmitterConfig::new() + .write_document_declaration(false) + .create_writer(&mut b); + + unwrap_all! { + w.write(XmlEvent::start_element("iq").ns("", "jabber:client").ns("a", "urn:A")); + w.write(XmlEvent::start_element("bind").ns("", "urn:ietf:params:xml:ns:xmpp-bind")); + w.write(XmlEvent::end_element()); + w.write(XmlEvent::start_element("whatever").ns("a", "urn:X")); + w.write(XmlEvent::end_element()); + w.write(XmlEvent::end_element()) + } + } + + assert_eq!( + str::from_utf8(&b).unwrap(), + r#"<iq xmlns="jabber:client" xmlns:a="urn:A"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind" /><whatever xmlns:a="urn:X" /></iq>"# + ) +} + +#[test] +fn attribute_escaping() { + use xml::writer::XmlEvent; + + let mut b = Vec::new(); + + { + let mut w = EmitterConfig::new() + .write_document_declaration(false) + .perform_indent(true) + .create_writer(&mut b); + + unwrap_all! { + w.write( + XmlEvent::start_element("hello") + .attr("testLt", "<") + .attr("testGt", ">") + ); + w.write(XmlEvent::end_element()); + w.write( + XmlEvent::start_element("hello") + .attr("testQuot", "\"") + .attr("testApos", "\'") + ); + w.write(XmlEvent::end_element()); + w.write( + XmlEvent::start_element("hello") + .attr("testAmp", "&") + ); + w.write(XmlEvent::end_element()); + w.write( + XmlEvent::start_element("hello") + .attr("testNl", "\n") + .attr("testCr", "\r") + ); + w.write(XmlEvent::end_element()); + w.write( + XmlEvent::start_element("hello") + .attr("testNl", "\\n") + .attr("testCr", "\\r") + ); + w.write(XmlEvent::end_element()) + } + } + assert_eq!( + str::from_utf8(&b).unwrap(), + "<hello testLt=\"<\" testGt=\">\" /> +<hello testQuot=\""\" testApos=\"'\" /> +<hello testAmp=\"&\" /> +<hello testNl=\"
\" testCr=\"
\" /> +<hello testNl=\"\\n\" testCr=\"\\r\" />" + ); +}
\ No newline at end of file diff --git a/third_party/rust/xml-rs/tests/streaming.rs b/third_party/rust/xml-rs/tests/streaming.rs new file mode 100644 index 0000000000..a577a00e6a --- /dev/null +++ b/third_party/rust/xml-rs/tests/streaming.rs @@ -0,0 +1,103 @@ +#![forbid(unsafe_code)] + +extern crate xml; + +use std::io::{Cursor, Write}; + +use xml::EventReader; +use xml::reader::ParserConfig; +use xml::reader::XmlEvent; + +macro_rules! assert_match { + ($actual:expr, $expected:pat) => { + match $actual { + $expected => {}, + _ => panic!("assertion failed: `(left matches right)` \ + (left: `{:?}`, right: `{}`", $actual, stringify!($expected)) + } + }; + ($actual:expr, $expected:pat if $guard:expr) => { + match $actual { + $expected if $guard => {}, + _ => panic!("assertion failed: `(left matches right)` \ + (left: `{:?}`, right: `{} if {}`", + $actual, stringify!($expected), stringify!($guard)) + } + } +} + +fn write_and_reset_position<W>(c: &mut Cursor<W>, data: &[u8]) where Cursor<W>: Write { + let p = c.position(); + c.write_all(data).unwrap(); + c.set_position(p); +} + +#[test] +fn reading_streamed_content() { + let buf = Cursor::new(b"<root>".to_vec()); + let reader = EventReader::new(buf); + + let mut it = reader.into_iter(); + + assert_match!(it.next(), Some(Ok(XmlEvent::StartDocument { .. }))); + assert_match!(it.next(), Some(Ok(XmlEvent::StartElement { ref name, .. })) if name.local_name == "root"); + + write_and_reset_position(it.source_mut(), b"<child-1>content</child-1>"); + assert_match!(it.next(), Some(Ok(XmlEvent::StartElement { ref name, .. })) if name.local_name == "child-1"); + assert_match!(it.next(), Some(Ok(XmlEvent::Characters(ref c))) if c == "content"); + assert_match!(it.next(), Some(Ok(XmlEvent::EndElement { ref name })) if name.local_name == "child-1"); + + write_and_reset_position(it.source_mut(), b"<child-2/>"); + assert_match!(it.next(), Some(Ok(XmlEvent::StartElement { ref name, .. })) if name.local_name == "child-2"); + assert_match!(it.next(), Some(Ok(XmlEvent::EndElement { ref name })) if name.local_name == "child-2"); + + write_and_reset_position(it.source_mut(), b"<child-3/>"); + assert_match!(it.next(), Some(Ok(XmlEvent::StartElement { ref name, .. })) if name.local_name == "child-3"); + assert_match!(it.next(), Some(Ok(XmlEvent::EndElement { ref name })) if name.local_name == "child-3"); + // doesn't seem to work because of how tags parsing is done +// write_and_reset_position(it.source_mut(), b"some text"); + // assert_match!(it.next(), Some(Ok(XmlEvent::Characters(ref c))) if c == "some text"); + + write_and_reset_position(it.source_mut(), b"</root>"); + assert_match!(it.next(), Some(Ok(XmlEvent::EndElement { ref name })) if name.local_name == "root"); + assert_match!(it.next(), Some(Ok(XmlEvent::EndDocument))); + assert_match!(it.next(), None); +} + +#[test] +fn reading_streamed_content2() { + let buf = Cursor::new(b"<root>".to_vec()); + let mut config = ParserConfig::new(); + config.ignore_end_of_stream = true; + let readerb = EventReader::new_with_config(buf, config); + + let mut reader = readerb.into_iter(); + + assert_match!(reader.next(), Some(Ok(XmlEvent::StartDocument { .. }))); + assert_match!(reader.next(), Some(Ok(XmlEvent::StartElement { ref name, .. })) if name.local_name == "root"); + + write_and_reset_position(reader.source_mut(), b"<child-1>content</child-1>"); + assert_match!(reader.next(), Some(Ok(XmlEvent::StartElement { ref name, .. })) if name.local_name == "child-1"); + assert_match!(reader.next(), Some(Ok(XmlEvent::Characters(ref c))) if c == "content"); + assert_match!(reader.next(), Some(Ok(XmlEvent::EndElement { ref name })) if name.local_name == "child-1"); + + write_and_reset_position(reader.source_mut(), b"<child-2>content</child-2>"); + + assert_match!(reader.next(), Some(Ok(XmlEvent::StartElement { ref name, .. })) if name.local_name == "child-2"); + assert_match!(reader.next(), Some(Ok(XmlEvent::Characters(ref c))) if c == "content"); + assert_match!(reader.next(), Some(Ok(XmlEvent::EndElement { ref name })) if name.local_name == "child-2"); + assert_match!(reader.next(), Some(Err(_))); + write_and_reset_position(reader.source_mut(), b"<child-3></child-3>"); + assert_match!(reader.next(), Some(Ok(XmlEvent::StartElement { ref name, .. })) if name.local_name == "child-3"); + write_and_reset_position(reader.source_mut(), b"<child-4 type='get'"); + match reader.next() { + None | + Some(Ok(_)) => { + panic!("At this point, parser must not detect something."); + }, + Some(Err(_)) => {} + }; + write_and_reset_position(reader.source_mut(), b" />"); + assert_match!(reader.next(), Some(Ok(XmlEvent::StartElement { ref name, .. })) if name.local_name == "child-4"); +} + |