mediawiki_parser 0.4.2

A strict parser for MediaWiki markdown.
Documentation
use peg;
use serde_derive::{Deserialize, Serialize};
use serde_yaml;
use std::env;
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};

#[allow(dead_code)]
mod ast {
    include!("src/ast.rs");
}

macro_rules! TEST_SOUCE {
    () => {
        "
// {}
#[test]
fn {} () {{
    let input = {:?};
    let target_source = {:?};

    let result = parse(&input)
        .expect(\"Parsing of the input for {} failed!\");
    eprintln!(\"{{}}\", &serde_yaml::to_string(&result).unwrap());
    let target: ast::Element = serde_yaml::from_str(&target_source)
        .expect(\"Parsing the documentation of {} failed!\");
    assert_eq!(&target, &result,
        \"comparing documentation (left) with parse result (right) failed!\");
}}
"
    };
}

macro_rules! TEST_HEADER {
    () => {
        "
// THIS DOCUMENT IS AUTO-GENERATED AND SHOULD NOT BE EDITED BY HAND!

use crate::ast;
use serde_yaml;
use crate::parse;

"
    };
}

#[derive(Debug, Serialize, Deserialize)]
struct Test {
    case: String,
    input: String,
    out: ast::Element,
}

fn escape_test_name(input: String) -> String {
    input.replace(" ", "_").to_lowercase()
}

impl Test {
    fn write_code(&self, file: &mut fs::File) -> io::Result<()> {
        writeln!(
            file,
            TEST_SOUCE!(),
            self.case,
            escape_test_name(self.case.clone()),
            self.input,
            serde_yaml::to_string(&self.out).expect("Error serializing test input!"),
            self.case,
            self.case
        )
    }
}

fn generate_tests() {
    // tell cargo to rerun if the documentation changes.
    println!("cargo:rerun-if-changed=doc/docs.yml");
    let out_dir: PathBuf = env::var_os("OUT_DIR").unwrap().into();
    let out_path = out_dir
        .join(Path::new("tests_generated.rs"))
        .with_extension("rs");

    let mut in_file = fs::File::open(Path::new("doc/docs.yml"))
        .ok()
        .expect("Could not open input file!");
    let mut out_file = fs::File::create(Path::new(&out_path))
        .ok()
        .expect("Could not open output file!");

    let mut content = String::new();
    in_file
        .read_to_string(&mut content)
        .ok()
        .expect("Could not read file!");

    let tests: Vec<Test> =
        serde_yaml::from_str(&content).expect("Could not parse the documentation!");

    write!(out_file, TEST_HEADER!()).unwrap();

    for test in &tests {
        test.write_code(&mut out_file).unwrap();
    }
}

fn main() {
    peg::cargo_build("src/grammar.rustpeg");
    generate_tests();
}