<commit_before>//! string handles parsing of GPX-spec strings.

use errors::*;
use std::io::Read;
use xml::reader::XmlEvent;

use parser::verify_starting_tag;
use parser::Context;

/// consume consumes a single string as tag content.
pub fn consume<R: Read>(
    context: &mut Context<R>,
    tagname: &'static str,
    allow_empty: bool,
) -> Result<String> {
    let mut string: Option<String> = None;
    if allow_empty {
        string = Some("".to_string());
    }
    verify_starting_tag(context, tagname)?;

    for event in context.reader() {
        match event.chain_err(|| "error while parsing XML")? {
            XmlEvent::StartElement { ref name, .. } => {
                bail!(ErrorKind::InvalidChildElement(
                    name.local_name.clone(),
                    tagname
                ));
            }
            XmlEvent::Characters(content) => string = Some(content),
            XmlEvent::EndElement { ref name } => {
                ensure!(
                    name.local_name == tagname,
                    ErrorKind::InvalidClosingTag(name.local_name.clone(), tagname)
                );
                return string.ok_or("no content inside string".into());
            }
            _ => {}
        }
    }
    bail!(ErrorKind::MissingClosingTag(tagname));
}

#[cfg(test)]
mod tests {
    use std::io::BufReader;

    use super::consume;
    use GpxVersion;

    #[test]
    fn consume_simple_string() {
        let result = consume!("<string>hello world</string>", GpxVersion::Gpx11, "string", false);

        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "hello world");
    }

    #[test]
    fn consume_new_tag() {
        // cannot start new tag inside string
        let result = consume!("<foo>bar<baz></baz></foo>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_start_tag() {
        // must have starting tag
        let result = consume!("bar</foo>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_end_tag() {
        // must have ending tag
        let result = consume!("<foo>bar", GpxVersion::Gpx11, "foo", false);<commit_msg>fix cargo fmt issue<commit_after>//! string handles parsing of GPX-spec strings.

use errors::*;
use std::io::Read;
use xml::reader::XmlEvent;

use parser::verify_starting_tag;
use parser::Context;

/// consume consumes a single string as tag content.
pub fn consume<R: Read>(
    context: &mut Context<R>,
    tagname: &'static str,
    allow_empty: bool,
) -> Result<String> {
    let mut string: Option<String> = None;
    if allow_empty {
        string = Some("".to_string());
    }
    verify_starting_tag(context, tagname)?;

    for event in context.reader() {
        match event.chain_err(|| "error while parsing XML")? {
            XmlEvent::StartElement { ref name, .. } => {
                bail!(ErrorKind::InvalidChildElement(
                    name.local_name.clone(),
                    tagname
                ));
            }
            XmlEvent::Characters(content) => string = Some(content),
            XmlEvent::EndElement { ref name } => {
                ensure!(
                    name.local_name == tagname,
                    ErrorKind::InvalidClosingTag(name.local_name.clone(), tagname)
                );
                return string.ok_or("no content inside string".into());
            }
            _ => {}
        }
    }
    bail!(ErrorKind::MissingClosingTag(tagname));
}

#[cfg(test)]
mod tests {
    use std::io::BufReader;

    use super::consume;
    use GpxVersion;

    #[test]
    fn consume_simple_string() {
        let result = consume!(
            "<string>hello world</string>",
            GpxVersion::Gpx11,
            "string",
            false
        );

        assert!(result.is_ok());
        assert_eq!(result.unwrap(), "hello world");
    }

    #[test]
    fn consume_new_tag() {
        // cannot start new tag inside string
        let result = consume!("<foo>bar<baz></baz></foo>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_start_tag() {
        // must have starting tag
        let result = consume!("bar</foo>", GpxVersion::Gpx11, "foo", false);

        assert!(result.is_err());
    }

    #[test]
    fn consume_end_tag() {
        // must have ending tag
        let result = consume!("<foo>bar", GpxVersion::Gpx11, "foo", false);
{'fraction_non_alphanumeric': 0.14495985727029437, 'fraction_numerical': 0.003568242640499554, 'mean_word_length': 2.1451612903225805, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3266131', 'n_tokens_mistral': 1344, 'n_tokens_neox': 1314, 'n_words': 301}