<commit_before>extern crate rand;

pub use self::rand::Rng;

use super::structure::{Program,Condition,Command,Expression,Sensor};

#[macro_export]
macro_rules! pick {
    ($total: expr, $( $lower: expr, $upper: expr, $expression: expr),+) => {{
        let mut rng = rand::thread_rng();
		    match rng.gen_range(0, $total) {
            $( i @ $lower...$upper if i < $upper => $expression,)+
			      _ => panic!(),
		    }
    }}
}

impl rand::Rand for Program {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 2) {
			i @ 0...1 if i < 1 => Program::If(Condition::rand(rng), Box::new(Program::rand(rng)), Box::new(Program::rand(rng))),
			i @ 1...2 if i < 2 => Program::Command(Command::rand(rng)),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Condition {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 10) {
			i @ 0...1  if i < 1  => Condition::True,
			i @ 1...2  if i < 2  => Condition::False,
			i @ 2...3  if i < 3  => Condition::Not(Box::new(Condition::rand(rng))),
			i @ 3...4  if i < 4  => Condition::Or(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 4...5  if i < 5  => Condition::And(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 5...6  if i < 6  => Condition::Less(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 6...7  if i < 7  => Condition::LessEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 7...8  if i < 8  => Condition::Equal(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 8...9  if i < 9  => Condition::GreaterEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 9...10 if i < 10 => Condition::Greater(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Command {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 4) {
			i @ 0...1 if i < 1 => Command::Skip,
			i @ 1...2 if i < 2 => Command::Left,
			i @ 2...3 if i < 3 => Command::Right,
			i @ 3...4 if i < 4 => Command::Up,
			_ => panic!(),
		}
	}
}

impl rand::Rand for Expression {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Expression::Constant(rng.next_f32()),
			i @ 1...2 if i < 2 => Expression::Sensor(Sensor::rand(rng)),
			i @ 2...3 if i < 3 => Expression::Plus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 3...4 if i < 4 => Expression::Minus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 4...5 if i < 5 => Expression::Multiply(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 5...6 if i < 6 => Expression::Divide(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Sensor {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Sensor::X,
			i @ 1...2 if i < 2 => Sensor::Y,
			i @ 2...3 if i < 3 => Sensor::Vx,
			i @ 3...4 if i < 4 => Sensor::Vy,
			i @ 4...5 if i < 5 => Sensor::O,
			i @ 5...6 if i < 6 => Sensor::W,
			_ => panic!(),
		}
	}
}
<commit_msg>Prepare for next level macro<commit_after>extern crate rand;

pub use self::rand::Rng;

use super::structure::{Program,Condition,Command,Expression,Sensor};

#[macro_export]
macro_rules! pickWeighted {
    ($total: expr, $( $lower: expr, $upper: expr, $expression: expr),+) => {{
        let mut rng = rand::thread_rng();
		    match rng.gen_range(0, $total) {
            $( i @ $lower...$upper if i < $upper => $expression,)+
			      _ => panic!(),
		    }
    }}
}

impl rand::Rand for Program {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 2) {
			i @ 0...1 if i < 1 => Program::If(Condition::rand(rng), Box::new(Program::rand(rng)), Box::new(Program::rand(rng))),
			i @ 1...2 if i < 2 => Program::Command(Command::rand(rng)),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Condition {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 10) {
			i @ 0...1  if i < 1  => Condition::True,
			i @ 1...2  if i < 2  => Condition::False,
			i @ 2...3  if i < 3  => Condition::Not(Box::new(Condition::rand(rng))),
			i @ 3...4  if i < 4  => Condition::Or(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 4...5  if i < 5  => Condition::And(Box::new(Condition::rand(rng)), Box::new(Condition::rand(rng))),
			i @ 5...6  if i < 6  => Condition::Less(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 6...7  if i < 7  => Condition::LessEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 7...8  if i < 8  => Condition::Equal(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 8...9  if i < 9  => Condition::GreaterEqual(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 9...10 if i < 10 => Condition::Greater(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Command {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 4) {
			i @ 0...1 if i < 1 => Command::Skip,
			i @ 1...2 if i < 2 => Command::Left,
			i @ 2...3 if i < 3 => Command::Right,
			i @ 3...4 if i < 4 => Command::Up,
			_ => panic!(),
		}
	}
}

impl rand::Rand for Expression {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Expression::Constant(rng.next_f32()),
			i @ 1...2 if i < 2 => Expression::Sensor(Sensor::rand(rng)),
			i @ 2...3 if i < 3 => Expression::Plus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 3...4 if i < 4 => Expression::Minus(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 4...5 if i < 5 => Expression::Multiply(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			i @ 5...6 if i < 6 => Expression::Divide(Box::new(Expression::rand(rng)), Box::new(Expression::rand(rng))),
			_ => panic!(),
		}
	}
}

impl rand::Rand for Sensor {
	fn rand<R: rand::Rng>(rng: &mut R) -> Self {
		match rng.gen_range(0, 6) {
			i @ 0...1 if i < 1 => Sensor::X,
			i @ 1...2 if i < 2 => Sensor::Y,
			i @ 2...3 if i < 3 => Sensor::Vx,
			i @ 3...4 if i < 4 => Sensor::Vy,
			i @ 4...5 if i < 5 => Sensor::O,
			i @ 5...6 if i < 6 => Sensor::W,
			_ => panic!(),
		}
	}
}
<|endoftext|>


<commit_before>extern crate data_encoding;
extern crate pem;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json as json;
extern crate tempdir;
extern crate tuf;
extern crate url;

use data_encoding::HEXLOWER;
use std::fs::{self, File, DirEntry};
use std::io::{self, Read};
use std::path::{PathBuf, Path};
use std::str;
use tempdir::TempDir;
use tuf::{Tuf, Config, Error, RemoteRepo};
use tuf::meta::{Key, KeyValue, KeyType};
use url::Url;

fn load_vector_meta() -> String {
    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("tuf-test-vectors")
        .join("tuf")
        .join("vector-meta.json");
    let mut file = File::open(path).expect("couldn't open vector meta");
    let mut buf = String::new();
    file.read_to_string(&mut buf).expect("couldn't read vector meta");
    buf
}

#[derive(Deserialize)]
struct VectorMeta {
    vectors: Vec<VectorMetaEntry>,
}

#[derive(Deserialize)]
struct VectorMetaEntry {
    repo: String,
    error: Option<String>,
    is_success: bool,
    root_keys: Vec<RootKeyData>,
}

#[derive(Deserialize)]
struct RootKeyData {
    path: String,
    #[serde(rename = "type")]
    typ: String,
}

enum TestType {
    File,
    Http
}

fn ensure_empty(path: &Path) {
    if !path.is_dir() {
        panic!("Path wasn't a dir: {:?}", path)
    }

    let res = fs::read_dir(path).expect("couldn't read dir").collect::<Vec<io::Result<DirEntry>>>();
    if !res.is_empty() {
        panic!("Temp dir not empty: {:?}", res)
    }
    if !res.iter().all(|x| x.is_ok()) {
        panic!("Temp dir errors: {:?}", res)
    }
}

fn run_test_vector(test_path: &str, test_type: TestType, pin_root_keys: bool) {
    let temp_dir = TempDir::new("rust-tuf").expect("couldn't make temp dir");
    let temp_path = temp_dir.into_path();

    println!("Temp dir is: {:?}", temp_path);

    let vector_meta: VectorMeta = json::from_str(&load_vector_meta())
        .expect("couldn't deserializd meta");

    let test_vector = vector_meta.vectors
        .iter()
        .filter(|v| v.repo == test_path)
        .collect::<Vec<&VectorMetaEntry>>()
        .pop()
        .expect(format!("No repo named {}", test_path).as_str());

    let vector_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("tuf-test-vectors")
        .join("tuf")
        .join(test_vector.repo.clone());

    println!("The test vector path is: {}",
             vector_path.to_string_lossy().into_owned());

    let config = match test_type {
        TestType::File => Config::build()
            .remote(RemoteRepo::File(vector_path.join("repo"))),
        TestType::Http => Config::build()
            .remote(RemoteRepo::Http(Url::parse(
                        &format!("http://localhost:8080/{}/repo", test_path)).expect("bad url"))),
    }.local_path(temp_path.clone())
        .finish()
        .expect("bad config");

    let tuf = if pin_root_keys {
        let root_keys = test_vector.root_keys
            .iter()
            .map(|k| {
                let file_path = vector_path.join("keys").join(k.path.clone());
                let mut file = File::open(file_path)
                    .expect("couldn't open file");
                let mut buf = Vec::new();
                file.read_to_end(&mut buf).expect("couldn't read key");

                let len = buf.len();
                if buf[len - 1] == b'\n' {
                    buf.truncate(len - 1)
                }

                let key = str::from_utf8(&buf).expect("not utf-8").to_string();

                match k.typ.as_ref() {
                    "ed25519" => {
                        let val = HEXLOWER.decode(key.replace("\n", "").as_ref())
                            .expect("key value not hex");
                        Key {
                            typ: KeyType::Ed25519,
                            value: KeyValue {
                                typ: KeyType::Ed25519,
                                value: val,
                                original: key,
                            },
                        }
                    }
                    "rsa" => {
                        let val = pem::parse(key.clone())
                            .expect("key value not pem");
                        Key {
                            typ: KeyType::Rsa,
                            value: KeyValue {
                                typ: KeyType::Rsa,
                                value: val.contents,
                                original: key,
                            },
                        }
                    }
                    x => panic!("unknown key type: {}", x),
                }
            })
            .collect();
        Tuf::from_root_keys(root_keys, config)
    } else {
        Tuf::initialize(&temp_path)
            .expect("failed to initialize");
        fs::copy(vector_path.join("repo").join("1.root.json"),
                 temp_path.join("metadata").join("current").join("root.json"))
            .expect("failed to copy root.json");
        Tuf::new(config)
    };

    match (tuf, &test_vector.error) {
        (Ok(ref tuf), &None) => {
            // first time pulls remote
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()), Ok(()));
            assert!(temp_path.join("targets").join("targets").join("file.txt").exists());
            // second time pulls local
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()), Ok(()));
        }

        (Ok(ref tuf), &Some(ref err)) if err == &"TargetHashMismatch".to_string() => {
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()),
                       Err(Error::UnavailableTarget));
        }

        (Ok(ref tuf), &Some(ref err)) if err == &"OversizedTarget".to_string() => {
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()),
                       Err(Error::UnavailableTarget));
        }

        (Err(Error::ExpiredMetadata(ref role)), &Some(ref err))
            if err.starts_with("ExpiredMetadata::") => {
            assert!(err.to_lowercase()
                        .ends_with(role.to_string().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        (Err(Error::UnmetThreshold(ref role)), &Some(ref err))
            if err == &"IllegalRsaKeySize".to_string() => {
            ()
        }

        (Err(Error::UnmetThreshold(_)), &Some(ref err))
            if err.starts_with("UnmetThreshold::") => {
            assert!(err.to_lowercase()
                        .ends_with(role.to_string().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        (Err(Error::MetadataHashMismatch(ref role)), &Some(ref err))
            if err.starts_with("MetadataHashMismatch::") => {
            assert!(err.to_lowercase()
                        .ends_with(role.to_string().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        (Err(Error::OversizedMetadata(ref role)), &Some(ref err))
            if err.starts_with("OversizedMetadata::") => {
            assert!(err.to_lowercase()
                        .ends_with(role.to_string().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        // we're using a json error because the threshold is checked in the deserializer
        // this may need to change in the future
        (Err(Error::Json(ref msg)), &Some(ref err)) if err.starts_with("IllegalThreshold::") => {
            let role = err.split("::").last().unwrap();

            assert!(msg.contains("threshold"),
                    format!("Role: {}, err: {}", role, err));
            assert!(err.to_lowercase()
                        .contains(role.to_lowercase().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        (Err(Error::NonUniqueSignatures(ref role)), &Some(ref err)) if err.starts_with("NonUniqueSignatures::") => {
            assert!(err.to_lowercase()
                        .ends_with(role.to_string().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        (Ok(ref tuf), &Some(ref err)) if err == &"UnavailableTarget".to_string() => {
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()),
                       Err(Error::UnavailableTarget));
        }

        (Ok(ref tuf), &Some(ref err))
            if err == &"UnmetThreshold::Delegation".to_string() => {
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()), Err(Error::UnavailableTarget));
        }

        x => panic!("Unexpected failures: {:?}", x),
    }
    ensure_empty(&temp_path.join("temp"));
    if !test_vector.is_success {
        ensure_empty(&temp_path.join("targets"))
    }
}

macro_rules! test_cases {
    ($name: expr, $md: ident) => {
        mod $md {
            use $crate::{run_test_vector, TestType};

            #[test]
            fn file_pinned() {
                run_test_vector($name, TestType::File, true)
            }

            #[test]
            fn file_unpinned() {
                run_test_vector($name, TestType::File, false)
            }

            // TODO no idea how windows shell scipting works
            #[cfg(not(windows))]
            #[test]
            fn http_pinned() {
                run_test_vector($name, TestType::Http, true)
            }

            // TODO no idea how windows shell scipting works
            #[cfg(not(windows))]
            #[test]
            fn http_unpinned() {
                run_test_vector($name, TestType::Http, false)
            }
        }
    }
}

test_cases!("001", _001);
test_cases!("002", _002);
test_cases!("003", _003);
test_cases!("004", _004);
test_cases!("005", _005);
test_cases!("006", _006);
test_cases!("007", _007);
test_cases!("008", _008);
test_cases!("009", _009);
test_cases!("010", _010);
test_cases!("011", _011);
test_cases!("012", _012);
test_cases!("013", _013);
test_cases!("014", _014);
test_cases!("015", _015);
test_cases!("016", _016);
test_cases!("017", _017);
test_cases!("018", _018);
test_cases!("019", _019);
test_cases!("020", _020);
test_cases!("021", _021);
test_cases!("022", _022);
test_cases!("023", _023);
test_cases!("024", _024);
test_cases!("025", _025);
test_cases!("026", _026);
test_cases!("027", _027);
test_cases!("028", _028);
test_cases!("029", _029);
test_cases!("030", _030);
test_cases!("031", _031);
test_cases!("032", _032);
test_cases!("033", _033);
test_cases!("034", _034);
test_cases!("035", _035);
test_cases!("036", _036);
test_cases!("037", _037);
test_cases!("038", _038);
test_cases!("039", _039);
test_cases!("040", _040);
test_cases!("041", _041);
test_cases!("042", _042);
test_cases!("043", _043);
test_cases!("044", _044);
test_cases!("045", _045);
test_cases!("046", _046);
test_cases!("047", _047);
test_cases!("048", _048);
test_cases!("049", _049);
test_cases!("050", _050);
test_cases!("051", _051);
test_cases!("052", _052);
test_cases!("053", _053);
test_cases!("054", _054);
test_cases!("055", _055);
<commit_msg>fix broken test<commit_after>extern crate data_encoding;
extern crate pem;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json as json;
extern crate tempdir;
extern crate tuf;
extern crate url;

use data_encoding::HEXLOWER;
use std::fs::{self, File, DirEntry};
use std::io::{self, Read};
use std::path::{PathBuf, Path};
use std::str;
use tempdir::TempDir;
use tuf::{Tuf, Config, Error, RemoteRepo};
use tuf::meta::{Key, KeyValue, KeyType};
use url::Url;

fn load_vector_meta() -> String {
    let path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("tuf-test-vectors")
        .join("tuf")
        .join("vector-meta.json");
    let mut file = File::open(path).expect("couldn't open vector meta");
    let mut buf = String::new();
    file.read_to_string(&mut buf).expect("couldn't read vector meta");
    buf
}

#[derive(Deserialize)]
struct VectorMeta {
    vectors: Vec<VectorMetaEntry>,
}

#[derive(Deserialize)]
struct VectorMetaEntry {
    repo: String,
    error: Option<String>,
    is_success: bool,
    root_keys: Vec<RootKeyData>,
}

#[derive(Deserialize)]
struct RootKeyData {
    path: String,
    #[serde(rename = "type")]
    typ: String,
}

enum TestType {
    File,
    Http
}

fn ensure_empty(path: &Path) {
    if !path.is_dir() {
        panic!("Path wasn't a dir: {:?}", path)
    }

    let res = fs::read_dir(path).expect("couldn't read dir").collect::<Vec<io::Result<DirEntry>>>();
    if !res.is_empty() {
        panic!("Temp dir not empty: {:?}", res)
    }
    if !res.iter().all(|x| x.is_ok()) {
        panic!("Temp dir errors: {:?}", res)
    }
}

fn run_test_vector(test_path: &str, test_type: TestType, pin_root_keys: bool) {
    let temp_dir = TempDir::new("rust-tuf").expect("couldn't make temp dir");
    let temp_path = temp_dir.into_path();

    println!("Temp dir is: {:?}", temp_path);

    let vector_meta: VectorMeta = json::from_str(&load_vector_meta())
        .expect("couldn't deserializd meta");

    let test_vector = vector_meta.vectors
        .iter()
        .filter(|v| v.repo == test_path)
        .collect::<Vec<&VectorMetaEntry>>()
        .pop()
        .expect(format!("No repo named {}", test_path).as_str());

    let vector_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("tuf-test-vectors")
        .join("tuf")
        .join(test_vector.repo.clone());

    println!("The test vector path is: {}",
             vector_path.to_string_lossy().into_owned());

    let config = match test_type {
        TestType::File => Config::build()
            .remote(RemoteRepo::File(vector_path.join("repo"))),
        TestType::Http => Config::build()
            .remote(RemoteRepo::Http(Url::parse(
                        &format!("http://localhost:8080/{}/repo", test_path)).expect("bad url"))),
    }.local_path(temp_path.clone())
        .finish()
        .expect("bad config");

    let tuf = if pin_root_keys {
        let root_keys = test_vector.root_keys
            .iter()
            .map(|k| {
                let file_path = vector_path.join("keys").join(k.path.clone());
                let mut file = File::open(file_path)
                    .expect("couldn't open file");
                let mut buf = Vec::new();
                file.read_to_end(&mut buf).expect("couldn't read key");

                let len = buf.len();
                if buf[len - 1] == b'\n' {
                    buf.truncate(len - 1)
                }

                let key = str::from_utf8(&buf).expect("not utf-8").to_string();

                match k.typ.as_ref() {
                    "ed25519" => {
                        let val = HEXLOWER.decode(key.replace("\n", "").as_ref())
                            .expect("key value not hex");
                        Key {
                            typ: KeyType::Ed25519,
                            value: KeyValue {
                                typ: KeyType::Ed25519,
                                value: val,
                                original: key,
                            },
                        }
                    }
                    "rsa" => {
                        let val = pem::parse(key.clone())
                            .expect("key value not pem");
                        Key {
                            typ: KeyType::Rsa,
                            value: KeyValue {
                                typ: KeyType::Rsa,
                                value: val.contents,
                                original: key,
                            },
                        }
                    }
                    x => panic!("unknown key type: {}", x),
                }
            })
            .collect();
        Tuf::from_root_keys(root_keys, config)
    } else {
        Tuf::initialize(&temp_path)
            .expect("failed to initialize");
        fs::copy(vector_path.join("repo").join("1.root.json"),
                 temp_path.join("metadata").join("current").join("root.json"))
            .expect("failed to copy root.json");
        Tuf::new(config)
    };

    match (tuf, &test_vector.error) {
        (Ok(ref tuf), &None) => {
            // first time pulls remote
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()), Ok(()));
            assert!(temp_path.join("targets").join("targets").join("file.txt").exists());
            // second time pulls local
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()), Ok(()));
        }

        (Ok(ref tuf), &Some(ref err)) if err == &"TargetHashMismatch".to_string() => {
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()),
                       Err(Error::UnavailableTarget));
        }

        (Ok(ref tuf), &Some(ref err)) if err == &"OversizedTarget".to_string() => {
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()),
                       Err(Error::UnavailableTarget));
        }

        (Err(Error::ExpiredMetadata(ref role)), &Some(ref err))
            if err.starts_with("ExpiredMetadata::") => {
            assert!(err.to_lowercase()
                        .ends_with(role.to_string().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        (Err(Error::UnmetThreshold(_)), &Some(ref err))
            if err == &"IllegalRsaKeySize".to_string() => {
            ()
        }

        (Err(Error::UnmetThreshold(ref role)), &Some(ref err))
            if err.starts_with("UnmetThreshold::") => {
            assert!(err.to_lowercase()
                        .ends_with(role.to_string().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        (Err(Error::MetadataHashMismatch(ref role)), &Some(ref err))
            if err.starts_with("MetadataHashMismatch::") => {
            assert!(err.to_lowercase()
                        .ends_with(role.to_string().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        (Err(Error::OversizedMetadata(ref role)), &Some(ref err))
            if err.starts_with("OversizedMetadata::") => {
            assert!(err.to_lowercase()
                        .ends_with(role.to_string().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        // we're using a json error because the threshold is checked in the deserializer
        // this may need to change in the future
        (Err(Error::Json(ref msg)), &Some(ref err)) if err.starts_with("IllegalThreshold::") => {
            let role = err.split("::").last().unwrap();

            assert!(msg.contains("threshold"),
                    format!("Role: {}, err: {}", role, err));
            assert!(err.to_lowercase()
                        .contains(role.to_lowercase().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        (Err(Error::NonUniqueSignatures(ref role)), &Some(ref err)) if err.starts_with("NonUniqueSignatures::") => {
            assert!(err.to_lowercase()
                        .ends_with(role.to_string().as_str()),
                    format!("Role: {}, err: {}", role, err))
        }

        (Ok(ref tuf), &Some(ref err)) if err == &"UnavailableTarget".to_string() => {
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()),
                       Err(Error::UnavailableTarget));
        }

        (Ok(ref tuf), &Some(ref err))
            if err == &"UnmetThreshold::Delegation".to_string() => {
            assert_eq!(tuf.fetch_target("targets/file.txt").map(|_| ()), Err(Error::UnavailableTarget));
        }

        x => panic!("Unexpected failures: {:?}", x),
    }
    ensure_empty(&temp_path.join("temp"));
    if !test_vector.is_success {
        ensure_empty(&temp_path.join("targets"))
    }
}

macro_rules! test_cases {
    ($name: expr, $md: ident) => {
        mod $md {
            use $crate::{run_test_vector, TestType};

            #[test]
            fn file_pinned() {
                run_test_vector($name, TestType::File, true)
            }

            #[test]
            fn file_unpinned() {
                run_test_vector($name, TestType::File, false)
            }

            // TODO no idea how windows shell scipting works
            #[cfg(not(windows))]
            #[test]
            fn http_pinned() {
                run_test_vector($name, TestType::Http, true)
            }

            // TODO no idea how windows shell scipting works
            #[cfg(not(windows))]
            #[test]
            fn http_unpinned() {
                run_test_vector($name, TestType::Http, false)
            }
        }
    }
}

test_cases!("001", _001);
test_cases!("002", _002);
test_cases!("003", _003);
test_cases!("004", _004);
test_cases!("005", _005);
test_cases!("006", _006);
test_cases!("007", _007);
test_cases!("008", _008);
test_cases!("009", _009);
test_cases!("010", _010);
test_cases!("011", _011);
test_cases!("012", _012);
test_cases!("013", _013);
test_cases!("014", _014);
test_cases!("015", _015);
test_cases!("016", _016);
test_cases!("017", _017);
test_cases!("018", _018);
test_cases!("019", _019);
test_cases!("020", _020);
test_cases!("021", _021);
test_cases!("022", _022);
test_cases!("023", _023);
test_cases!("024", _024);
test_cases!("025", _025);
test_cases!("026", _026);
test_cases!("027", _027);
test_cases!("028", _028);
test_cases!("029", _029);
test_cases!("030", _030);
test_cases!("031", _031);
test_cases!("032", _032);
test_cases!("033", _033);
test_cases!("034", _034);
test_cases!("035", _035);
test_cases!("036", _036);
test_cases!("037", _037);
test_cases!("038", _038);
test_cases!("039", _039);
test_cases!("040", _040);
test_cases!("041", _041);
test_cases!("042", _042);
test_cases!("043", _043);
test_cases!("044", _044);
test_cases!("045", _045);
test_cases!("046", _046);
test_cases!("047", _047);
test_cases!("048", _048);
test_cases!("049", _049);
test_cases!("050", _050);
test_cases!("051", _051);
test_cases!("052", _052);
test_cases!("053", _053);
test_cases!("054", _054);
test_cases!("055", _055);
<|endoftext|>


<commit_before>extern crate chamkho;

#[cfg(test)]
mod tests {
    use chamkho::dict::Dict;
    use chamkho::wordcut::Wordcut;
    use chamkho::graph::TextRange;
    use std::path::Path;

    #[test]
    fn test_default_dict() {
        let dict = Dict::load(Dict::default_path());
        assert!(dict.is_ok());
        assert!(dict.unwrap().r() > 10000);
    }

    #[test]
    fn test_vec_dict() {
        let dict = Dict::create(&vec!["ก".to_string(), "กา".to_string()]);
        assert!(dict.is_ok());
        assert!(dict.unwrap().r() == 1);
    }

    #[test]
    fn test_segment_into_ranges() {
        let dict = Dict::load(Path::new("data/tdict-std.txt"));
        let wordcut = Wordcut::new(dict.unwrap());
        let ranges = wordcut.segment(&"กากกา".to_string());
        let expected = vec![TextRange{s:0,e:3}, TextRange{s:3,e:5}];
        assert_eq!(ranges, expected)
    }

    #[test]
    fn test_segment_into_strings() {
        let dict = Dict::load(Path::new("data/tdict-std.txt"));
        let wordcut = Wordcut::new(dict.unwrap());
        let words = wordcut.segment_into_strings(&"กากกา".to_string());
        let expected = vec!["กาก".to_string(), "กา".to_string()];
        assert_eq!(words, expected)
    }

    #[test]
    fn test_space() {
        let dict = Dict::load(Path::new("data/tdict-std.txt"));
        let wordcut = Wordcut::new(dict.unwrap());
        let words = wordcut.segment(&"a cat".to_string());
        let expected = vec![TextRange{s:0,e:1},TextRange{s:1,e:2},TextRange{s:2,e:5}];
        assert_eq!(words, expected)
    }
}
<commit_msg>test Lao word segmentation<commit_after>extern crate chamkho;

#[cfg(test)]
mod tests {
    use chamkho::dict::Dict;
    use chamkho::wordcut::Wordcut;
    use chamkho::graph::TextRange;
    use std::path::Path;

    #[test]
    fn test_default_dict() {
        let dict = Dict::load(Dict::default_path());
        assert!(dict.is_ok());
        assert!(dict.unwrap().r() > 10000);
    }

    #[test]
    fn test_vec_dict() {
        let dict = Dict::create(&vec!["ก".to_string(), "กา".to_string()]);
        assert!(dict.is_ok());
        assert!(dict.unwrap().r() == 1);
    }

    #[test]
    fn test_segment_into_ranges() {
        let dict = Dict::load(Path::new("data/tdict-std.txt"));
        let wordcut = Wordcut::new(dict.unwrap());
        let ranges = wordcut.segment(&"กากกา".to_string());
        let expected = vec![TextRange{s:0,e:3}, TextRange{s:3,e:5}];
        assert_eq!(ranges, expected)
    }

    #[test]
    fn test_segment_into_strings() {
        let dict = Dict::load(Path::new("data/tdict-std.txt"));
        let wordcut = Wordcut::new(dict.unwrap());
        let words = wordcut.segment_into_strings(&"กากกา".to_string());
        let expected = vec!["กาก".to_string(), "กา".to_string()];
        assert_eq!(words, expected)
    }

    #[test]
    fn test_space() {
        let dict = Dict::load(Path::new("data/tdict-std.txt"));
        let wordcut = Wordcut::new(dict.unwrap());
        let words = wordcut.segment(&"a cat".to_string());
        let expected = vec![TextRange{s:0,e:1},TextRange{s:1,e:2},TextRange{s:2,e:5}];
        assert_eq!(words, expected)
    }

    #[test]
    fn test_lao() {
        let dict = Dict::load(Dict::lao_path());
        let wordcut = Wordcut::new(dict.unwrap());
        let words = wordcut.segment(&"ພາສາລາວມີ".to_string());
        let expected = vec![TextRange{s:0,e:4},TextRange{s:4,e:7},TextRange{s:7,e:9}];
        assert_eq!(words, expected)
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fmt;
use std::fs::{self, PathExt};
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;
use std::str::FromStr;
use std::sync::atomic;

use csv;

use Csv;

static XSV_INTEGRATION_TEST_DIR: &'static str = "xit";

static NEXT_ID: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;

pub struct Workdir {
    root: PathBuf,
    dir: PathBuf,
    flexible: bool,
}

impl Workdir {
    pub fn new(name: &str) -> Workdir {
        let id = NEXT_ID.fetch_add(1, atomic::Ordering::SeqCst);
        let root = PathBuf::new(&env::current_exe().unwrap())
                           .parent()
                           .expect("executable's directory")
                           .to_path_buf();
        let dir = root.join(XSV_INTEGRATION_TEST_DIR)
                      .join(name)
                      .join(&format!("test-{}", id));
        if dir.exists() {
            fs::remove_dir_all(&dir).unwrap();
        }
        fs::create_dir_all(&dir).unwrap();
        Workdir { root: root, dir: dir, flexible: false }
    }

    pub fn flexible(mut self, yes: bool) -> Workdir {
        self.flexible = yes;
        self
    }

    pub fn create<T: Csv>(&self, name: &str, rows: T) {
        let mut wtr = csv::Writer::from_file(&self.path(name)).unwrap()
                                  .flexible(self.flexible);
        for row in rows.to_vecs().into_iter() {
            wtr.write(row.iter()).unwrap();
        }
        wtr.flush().unwrap();
    }

    pub fn create_indexed<T: Csv>(&self, name: &str, rows: T) {
        self.create(name, rows);

        let mut cmd = self.command("index");
        cmd.arg(name);
        self.run(&mut cmd);
    }

    pub fn read_stdout<T: Csv>(&self, cmd: &mut process::Command) -> T {
        let mut rdr = csv::Reader::from_string(self.stdout::<String>(cmd))
                                  .has_headers(false);
        Csv::from_vecs(rdr.records().collect::<Result<_, _>>().unwrap())
    }

    pub fn command(&self, sub_command: &str) -> process::Command {
        let mut cmd = process::Command::new(&self.xsv_bin());
        cmd.current_dir(&self.dir).arg(sub_command);
        cmd
    }

    pub fn output(&self, cmd: &mut process::Command) -> process::Output {
        debug!("[{}]: {:?}", self.dir.display(), cmd);
        let o = cmd.output().unwrap();
        if !o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command failed but expected success!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr))
        }
        o
    }

    pub fn run(&self, cmd: &mut process::Command) {
        self.output(cmd);
    }

    pub fn stdout<T: FromStr>(&self, cmd: &mut process::Command) -> T {
        let o = self.output(cmd);
        let stdout = String::from_utf8_lossy(&o.stdout);
        stdout.trim().parse().ok().expect(
            &format!("Could not convert from string: '{}'", stdout))
    }

    pub fn assert_err(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }

    pub fn from_str<T: FromStr>(&self, name: &Path) -> T {
        let mut o = String::new();
        fs::File::open(name).unwrap().read_to_string(&mut o).unwrap();
        o.parse().ok().expect("fromstr")
    }

    pub fn path(&self, name: &str) -> PathBuf {
        self.dir.join(name)
    }

    pub fn xsv_bin(&self) -> PathBuf {
        self.root.join("xsv")
    }
}

impl fmt::Debug for Workdir {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "path={}", self.dir.display())
    }
}
<commit_msg>Better error messages, hopefully.<commit_after>use std::env;
use std::fmt;
use std::fs::{self, PathExt};
use std::io::Read;
use std::path::{Path, PathBuf};
use std::process;
use std::str::FromStr;
use std::sync::atomic;

use csv;

use Csv;

static XSV_INTEGRATION_TEST_DIR: &'static str = "xit";

static NEXT_ID: atomic::AtomicUsize = atomic::ATOMIC_USIZE_INIT;

pub struct Workdir {
    root: PathBuf,
    dir: PathBuf,
    flexible: bool,
}

impl Workdir {
    pub fn new(name: &str) -> Workdir {
        let id = NEXT_ID.fetch_add(1, atomic::Ordering::SeqCst);
        let root = PathBuf::new(&env::current_exe().unwrap())
                           .parent()
                           .expect("executable's directory")
                           .to_path_buf();
        let dir = root.join(XSV_INTEGRATION_TEST_DIR)
                      .join(name)
                      .join(&format!("test-{}", id));
        if dir.exists() {
            if let Err(err) = fs::remove_dir_all(&dir) {
                panic!("{}", err);
            }
        }
        if let Err(err) = fs::create_dir_all(&dir) {
            panic!("{}", err);
        }
        Workdir { root: root, dir: dir, flexible: false }
    }

    pub fn flexible(mut self, yes: bool) -> Workdir {
        self.flexible = yes;
        self
    }

    pub fn create<T: Csv>(&self, name: &str, rows: T) {
        let mut wtr = csv::Writer::from_file(&self.path(name)).unwrap()
                                  .flexible(self.flexible);
        for row in rows.to_vecs().into_iter() {
            wtr.write(row.iter()).unwrap();
        }
        wtr.flush().unwrap();
    }

    pub fn create_indexed<T: Csv>(&self, name: &str, rows: T) {
        self.create(name, rows);

        let mut cmd = self.command("index");
        cmd.arg(name);
        self.run(&mut cmd);
    }

    pub fn read_stdout<T: Csv>(&self, cmd: &mut process::Command) -> T {
        let mut rdr = csv::Reader::from_string(self.stdout::<String>(cmd))
                                  .has_headers(false);
        Csv::from_vecs(rdr.records().collect::<Result<_, _>>().unwrap())
    }

    pub fn command(&self, sub_command: &str) -> process::Command {
        let mut cmd = process::Command::new(&self.xsv_bin());
        cmd.current_dir(&self.dir).arg(sub_command);
        cmd
    }

    pub fn output(&self, cmd: &mut process::Command) -> process::Output {
        debug!("[{}]: {:?}", self.dir.display(), cmd);
        let o = cmd.output().unwrap();
        if !o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command failed but expected success!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr))
        }
        o
    }

    pub fn run(&self, cmd: &mut process::Command) {
        self.output(cmd);
    }

    pub fn stdout<T: FromStr>(&self, cmd: &mut process::Command) -> T {
        let o = self.output(cmd);
        let stdout = String::from_utf8_lossy(&o.stdout);
        stdout.trim().parse().ok().expect(
            &format!("Could not convert from string: '{}'", stdout))
    }

    pub fn assert_err(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }

    pub fn from_str<T: FromStr>(&self, name: &Path) -> T {
        let mut o = String::new();
        fs::File::open(name).unwrap().read_to_string(&mut o).unwrap();
        o.parse().ok().expect("fromstr")
    }

    pub fn path(&self, name: &str) -> PathBuf {
        self.dir.join(name)
    }

    pub fn xsv_bin(&self) -> PathBuf {
        self.root.join("xsv")
    }
}

impl fmt::Debug for Workdir {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "path={}", self.dir.display())
    }
}
<|endoftext|>


<commit_before>use neb::server::*;
use neb::ram::schema::*;
use neb::ram::types::*;
use neb::ram::cell::*;
use neb::client;
use neb::client::transaction::TxnError;
use env_logger;

use super::*;

#[test]
pub fn general() {
    let server_addr = String::from("127.0.0.1:5400");
    let server = NebServer::new(ServerOptions {
        chunk_count: 1,
        memory_size: 16 * 1024 * 1024,
        standalone: false,
        is_meta: true,
        meta_members: vec!(server_addr.clone()),
        address: server_addr.clone(),
        backup_storage: None,
        meta_storage: None,
        group_name: String::from("test"),
    }).unwrap();
    let mut schema = Schema {
        id: 1,
        name: String::from("test"),
        key_field: None,
        fields: default_fields()
    };
    let client = client::Client::new(
        &server.rpc, &vec!(server_addr),
        &String::from("test")).unwrap();
    client.new_schema(&mut schema).unwrap();
    let mut data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(100));
    data_map.insert(String::from("score"), Value::U64(70));
    data_map.insert(String::from("name"), Value::String(String::from("Jack")));
    let cell_1 = Cell::new(schema.id, &Id::rand(), data_map.clone());
    client.write_cell(&cell_1).unwrap().unwrap();
    client.read_cell(&cell_1.id()).unwrap().unwrap();
    client.transaction(|ref mut trans| {
        Ok(()) // empty transaction
    }).unwrap();
    let should_aborted = client.transaction(|ref mut trans| {
        trans.abort()
    });
    match should_aborted {
        Err(TxnError::Aborted) => {},
        _ => panic!("{:?}", should_aborted)
    }

}<commit_msg>transaction concurrent counter<commit_after>use neb::server::*;
use neb::ram::schema::*;
use neb::ram::types::*;
use neb::ram::cell::*;
use neb::client;
use neb::client::transaction::TxnError;
use std::thread;
use std::sync::Arc;
use env_logger;

use super::*;

#[test]
pub fn general() {
    let server_addr = String::from("127.0.0.1:5400");
    let server = NebServer::new(ServerOptions {
        chunk_count: 1,
        memory_size: 16 * 1024 * 1024,
        standalone: false,
        is_meta: true,
        meta_members: vec!(server_addr.clone()),
        address: server_addr.clone(),
        backup_storage: None,
        meta_storage: None,
        group_name: String::from("test"),
    }).unwrap();
    let mut schema = Schema {
        id: 1,
        name: String::from("test"),
        key_field: None,
        fields: default_fields()
    };
    let client = Arc::new(client::Client::new(
        &server.rpc, &vec!(server_addr),
        &String::from("test")).unwrap());
    client.new_schema(&mut schema).unwrap();
    let mut data_map = Map::<String, Value>::new();
    data_map.insert(String::from("id"), Value::I64(100));
    data_map.insert(String::from("score"), Value::U64(0));
    data_map.insert(String::from("name"), Value::String(String::from("Jack")));
    let cell_1 = Cell::new(schema.id, &Id::rand(), data_map.clone());
    client.write_cell(&cell_1).unwrap().unwrap();
    client.read_cell(&cell_1.id()).unwrap().unwrap();
    client.transaction(|ref mut trans| {
        Ok(()) // empty transaction
    }).unwrap();
    let should_aborted = client.transaction(|ref mut trans| {
        trans.abort()
    });
    match should_aborted {
        Err(TxnError::Aborted) => {},
        _ => panic!("{:?}", should_aborted)
    }
    let cell_id = cell_1.id();
    let thread_count = 200;
    let mut threads: Vec<thread::JoinHandle<()>> = Vec::with_capacity(thread_count);
    for _ in 0..thread_count {
        let client = client.clone();
        threads.push(thread::spawn(move || {
            client.transaction(|ref mut txn| {
                let mut cell = txn.read(&cell_id)?.unwrap();
                let mut score = cell.data.Map().unwrap().get("score").unwrap().U64().unwrap();
                score += 1;
                let mut data = cell.data.Map().unwrap().clone();
                data.insert(String::from("score"), Value::U64(score));
                cell.data = Value::Map(data);
                txn.update(&cell)?;
                Ok(())
            }).unwrap();
        }));
    }
    for handle in threads {
        handle.join();
    }
    let cell_1_r = client.read_cell(&cell_1.id()).unwrap().unwrap();
    assert_eq!(cell_1_r.data.Map().unwrap().get("score").unwrap().U64().unwrap(), thread_count as u64);
}<|endoftext|>


<commit_before>// NOTE converted from assets/kate-syntax/rust.xml

use gfx::Color;

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Style {
    pub color: Color,
    pub bold: bool
}

// extensions=r".*\.rs" mimetype="text/x-rust"
pub struct Rust<'a, I> {
    lines: I,
    depth: usize,
    current_line: &'a str,
    output: Vec<(usize, Vec<(usize, Style)>)>
}

impl<'a, I> Rust<'a, I> where I: Iterator<Item=&'a str> {
    pub fn run(mut lines: I) -> (usize, Vec<(usize, Vec<(usize, Style)>)>) {
        let mut hl = Rust {
            current_line: lines.next().unwrap_or(""),
            lines: lines,
            depth: 0,
            output: vec![(0, vec![])]
        };
        hl.normal();
        (hl.depth, hl.output)
    }

    fn advance(&mut self, len: usize, style: Style) {
        self.current_line = &self.current_line[len..];

        let last = &mut self.output.last_mut().unwrap().1;
        if let Some(&mut (ref mut prev_len, prev_style)) = last.last_mut() {
            if style == prev_style {
                *prev_len += len;
                return;
            }
        }
        last.push((len, style))
    }

    fn next_line(&mut self) -> bool {
        if let Some(line) = self.lines.next() {
            self.current_line = line;
            self.output.push((self.depth, vec![]));
            true
        } else {
            self.current_line = "";
            false
        }
    }
}

macro_rules! rust_ident { () => ("[a-zA-Z_][a-zA-Z_0-9]*") }
macro_rules! rust_int_suf { () => ("([iu](8|16|32|64)?)?") }

macro_rules! re {
    ($($r:expr),+) => (regex!(concat!("^(?:", $($r,)* ")")))
}
macro_rules! kw {
    ($($r:expr),+) => (regex!(concat!("^(?:" $(,$r,)"|"* r")\b")))
}

macro_rules! goto {
    ($s:expr, {}) => (());
    ($s:expr, return) => ({ $s.depth -= 1; return;});
    ($s:expr, $cx:ident) => ({ $s.depth += 1; $s.$cx() })
}

#[cfg(not(test))]
macro_rules! cases {
    ($s:expr, $ds:ident:) => { $s.advance(1, styles::$ds) };
    ($s:expr, $ds:ident: $re:expr; $($rest:tt)*) => { cases!($s, $ds: $re, $ds => {}; $($rest)*) };
    ($s:expr, $ds:ident: $re:expr => $goto:tt; $($rest:tt)*) => { cases!($s, $ds: $re, $ds => $goto; $($rest)*) };
    ($s:expr, $ds:ident: $re:expr, $style:ident; $($rest:tt)*) => { cases!($s, $ds: $re, $style => {}; $($rest)*) };
    ($s:expr, $ds:ident: $re:expr, $style:ident => $goto:tt; $($rest:tt)*) => {
        if let Some((0, len)) = $re.find($s.current_line) {
            $s.advance(len, styles::$style);
            goto!($s, $goto);
        } else {
            cases!($s, $ds: $($rest)*)
        }
    }
}

#[cfg(test)]
macro_rules! cases { ($($rest:tt)*) => {()} }

macro_rules! context {
    ($name:ident, $ds:ident: $($rest:tt)*) => { context!{$name, $ds => {}: $($rest)*} };
    ($name:ident, $ds:ident => $line_end_cx:tt: $($rest:tt)*) => {
        fn $name(&mut self) {
            loop {
                while !self.current_line.is_empty() {
                    cases!(self, $ds: $($rest)*);
                }
                if self.next_line() {
                    goto!(self, $line_end_cx);
                } else {
                    return;
                }
            }
        }
    }
}

macro_rules! normal_like {
    ($($x:tt)+) => {context!{$($x)*
        re!(r"\s+");
        kw!("fn"), Keyword => function;
        kw!("type"), Keyword => type_;

        kw!("abstract",
            "alignof",
            "become",
            "do",
            "final",
            "offsetof",
            "override",
            "priv",
            "pure",
            "sizeof",
            "typeof",
            "unsized",
            "yield"), Keyword;
         kw!("as",
            "box",
            "break",
            "const",
            "continue",
            "crate",
            "else",
            "enum",
            "extern",
            "for",
            "if",
            "impl",
            "in",
            "let",
            "loop",
            "match",
            "mod",
            "move",
            "mut",
            "pub",
            "ref",
            "return",
            "static",
            "struct",
            "super",
            "trait",
            "unsafe",
            "use",
            "virtual",
            "where",
            "while"), Keyword;
        kw!("bool",
            "int",
            "isize",
            "uint",
            "usize",
            "i8",
            "i16",
            "i32",
            "i64",
            "u8",
            "u16",
            "u32",
            "u64",
            "f32",
            "f64",
            "float",
            "char",
            "str",
            "Option",
            "Result",
            "Self",
            "Box",
            "Vec",
            "String"), Type;
        kw!("AsSlice",
            "CharExt",
            "Clone",
            "Copy",
            "Debug",
            "Decodable",
            "Default",
            "Display",
            "DoubleEndedIterator",
            "Drop",
            "Encodable",
            "Eq",
            "Default",
            "Extend",
            "Fn",
            "FnMut",
            "FnOnce",
            "FromPrimitive",
            "Hash",
            "Iterator",
            "IteratorExt",
            "MutPtrExt",
            "Ord",
            "PartialEq",
            "PartialOrd",
            "PtrExt",
            "Rand",
            "Send",
            "Sized",
            "SliceConcatExt",
            "SliceExt",
            "Str",
            "StrExt",
            "Sync",
            "ToString"), Trait;
        kw!("c_float",
            "c_double",
            "c_void",
            "FILE",
            "fpos_t",
            "DIR",
            "dirent",
            "c_char",
            "c_schar",
            "c_uchar",
            "c_short",
            "c_ushort",
            "c_int",
            "c_uint",
            "c_long",
            "c_ulong",
            "size_t",
            "ptrdiff_t",
            "clock_t",
            "time_t",
            "c_longlong",
            "c_ulonglong",
            "intptr_t",
            "uintptr_t",
            "off_t",
            "dev_t",
            "ino_t",
            "pid_t",
            "mode_t",
            "ssize_t"), CType;
        kw!("self"), SelfKw;
        kw!("true",
            "false",
            "Some",
            "None",
            "Ok",
            "Err",
            "Success",
            "Failure",
            "Cons",
            "Nil"), Constant;
        kw!("EXIT_FAILURE",
            "EXIT_SUCCESS",
            "RAND_MAX",
            "EOF",
            "SEEK_SET",
            "SEEK_CUR",
            "SEEK_END",
            "_IOFBF",
            "_IONBF",
            "_IOLBF",
            "BUFSIZ",
            "FOPEN_MAX",
            "FILENAME_MAX",
            "L_tmpnam",
            "TMP_MAX",
            "O_RDONLY",
            "O_WRONLY",
            "O_RDWR",
            "O_APPEND",
            "O_CREAT",
            "O_EXCL",
            "O_TRUNC",
            "S_IFIFO",
            "S_IFCHR",
            "S_IFBLK",
            "S_IFDIR",
            "S_IFREG",
            "S_IFMT",
            "S_IEXEC",
            "S_IWRITE",
            "S_IREAD",
            "S_IRWXU",
            "S_IXUSR",
            "S_IWUSR",
            "S_IRUSR",
            "F_OK",
            "R_OK",
            "W_OK",
            "X_OK",
            "STDIN_FILENO",
            "STDOUT_FILENO",
            "STDERR_FILENO"), CConstant;

        // Match special comments for region markers
        re!("//BEGIN"), RegionMarker => region_marker;
        re!("//END"), RegionMarker => region_marker;

        // Match comments
        re!("//"), Comment => comment;
        re!(r"/\*"), Comment => comment2;
        re!(r"0x[0-9a-fA-F_]+", rust_int_suf!()), Hex;
        re!(r"0o[0-7_]+", rust_int_suf!()), Octal;
        re!(r"0b[0-1_]+", rust_int_suf!()), Binary;
        re!(r"[0-9][0-9_]*\.[0-9_]*([eE][+-]?[0-9_]+)?(f32|f64|f)?"), Float;
        re!(r"[0-9][0-9_]*", rust_int_suf!()), Decimal;
        re!(r"#\["), Attribute => attribute;
        re!(r"#!\["), Attribute => attribute;
        re!(rust_ident!(), "::"), Scope;
        re!(rust_ident!(), "!"), Macro;
        //re!("'", rust_ident!(), "(?!')"), Lifetime;
        re!(r"[{}\[\]]"), Symbol;
        re!("r\""), String => raw_string;
        re!("r##\""), String => raw_hashed2;
        re!("r#\""), String => raw_hashed1;
        re!("\""), String => string;
        re!(r"'"), Character => character;
        re!(rust_ident!());
    }}
}

impl<'a, I> Rust<'a, I> where I: Iterator<Item=&'a str> {
    normal_like!{normal, NormalText:}
    normal_like!{attribute, Attribute:
        re!(r"\]"), Attribute => return;
    }
    context!{function, Definition:
        re!(r"\s+");
        re!(r"\("), NormalText => return;
        re!(r">"), NormalText => return;
    }
    context!{type_, Definition:
        re!(r"\s+");
        re!(r"[=<;]"), NormalText => return;
    }
    // Rustc allows strings to extend over multiple lines, and the
    // only thing a backshash at end-of-line does is remove the whitespace.
    context!{string, String:
        re!(r"\\"), CharEscape => char_escape;
        re!("\""), String => return;
    }
    context!{raw_string, String:
        re!("\""), String => return;
    }
    // These rules are't complete: they won't match r###"abc"###
    context!{raw_hashed1, String:
        re!("\"#"), String => return;
    }
    context!{raw_hashed2, String:
        re!("\"##"), String => return;
    }
    context!{character, Character => return:
        re!(r"\\"), CharEscape => char_escape;
        re!(r"'"), Character => return;
    }
    context!{char_escape, CharEscape => return:
        re!("[nrt'\"]"), CharEscape => return;
        re!(r"x[0-9a-fA-F]{2}"), CharEscape => return;
        re!(r"u\{[0-9a-fA-F]{1,6}\}"), CharEscape => return;
        re!(r"u[0-9a-fA-F]{4}"), CharEscape => return;
        re!(r"U[0-9a-fA-F]{8}"), CharEscape => return;
        re!(r"\."), Error => return;
    }
    context!{region_marker, RegionMarker => return:}
    context!{comment, Comment => return:
        re!(r"\s+");
    }
    context!{comment2, Comment:
        re!(r"\s+");
        re!(r"\*/"), Comment => return;
    }
}

#[allow(non_upper_case_globals)]
pub mod base_styles {
    use super::Style;

    const DEFAULT: Style = Style { color: [1.0, 1.0, 1.0, 1.0], bold: false };

    macro_rules! styles {
        () => {};
        ($name:ident => ($r:expr,$g:expr,$b:expr) $($rest:tt)*) => {
            styles!($name => color=[$r as f32 / 255.0, $g as f32 / 255.0, $b as f32 / 255.0, 1.0] $($rest)*);
        };
        ($name:ident => $($extra:ident=$val:expr),*; $($rest:tt)*) => {
            pub const $name: Style = Style { $($extra: $val,)* ..DEFAULT };
            styles!($($rest)*);
        }
    }

    styles!{
        Normal => (239,240,241);
        Keyword => (239,240,241), bold=true;
        Function => (246,116,0);
        DataType => (41,128,185);
        DecVal => (246,116,0);
        BaseN => (246,116,0);
        Float => (246,116,0);
        Char => (61,174,233);
        String => (218,68,83);
        Comment => (189,195,199);
        RegionMarker => (41,128,185);
        Others => (39,174,96);
        Error => (218,68,83);
    }
}

#[allow(non_upper_case_globals)]
pub mod styles {
    use super::{Style, base_styles};

    macro_rules! styles {
        () => {};
        ($name:ident => $base:ident; $($rest:tt)*) => {
            pub const $name: Style = base_styles::$base;
            styles!($($rest)*);
        };
        ($name:ident => $base:ident, $($extra:ident=$val:expr),*; $($rest:tt)*) => {
            pub const $name: Style = Style { $($extra: $val,)* ..base_styles::$base };
            styles!($($rest)*);
        }
    }

    styles!{
        NormalText => Normal;
        Keyword => Keyword;
        SelfKw => Function, bold=true;
        Type => DataType, bold=true;
        Trait => DataType, bold=true;
        CType => DataType;
        Constant => Keyword;
        CConstant => Normal;
        Definition => Function;
        Comment => Comment;
        Scope => Others, bold=true;
        Decimal => DecVal;
        Hex => BaseN;
        Octal => BaseN;
        Binary => BaseN;
        Float => Float;
        String => String;
        CharEscape => Char;
        Character => Char;
        Macro => Others;
        Attribute => Others;
        Lifetime => Char, bold=true;
        RegionMarker => RegionMarker;
        Error => Error;

        Symbol => Normal;
    }
}
<commit_msg>highlight: fix one character skipping to handle multibyte correctly.<commit_after>// NOTE converted from assets/kate-syntax/rust.xml

use gfx::Color;

#[derive(Copy, Clone, PartialEq, Debug)]
pub struct Style {
    pub color: Color,
    pub bold: bool
}

// extensions=r".*\.rs" mimetype="text/x-rust"
pub struct Rust<'a, I> {
    lines: I,
    depth: usize,
    current_line: &'a str,
    output: Vec<(usize, Vec<(usize, Style)>)>
}

impl<'a, I> Rust<'a, I> where I: Iterator<Item=&'a str> {
    pub fn run(mut lines: I) -> (usize, Vec<(usize, Vec<(usize, Style)>)>) {
        let mut hl = Rust {
            current_line: lines.next().unwrap_or(""),
            lines: lines,
            depth: 0,
            output: vec![(0, vec![])]
        };
        hl.normal();
        (hl.depth, hl.output)
    }

    fn advance(&mut self, len: usize, style: Style) {
        self.current_line = &self.current_line[len..];

        let last = &mut self.output.last_mut().unwrap().1;
        if let Some(&mut (ref mut prev_len, prev_style)) = last.last_mut() {
            if style == prev_style {
                *prev_len += len;
                return;
            }
        }
        last.push((len, style))
    }

    fn next_line(&mut self) -> bool {
        if let Some(line) = self.lines.next() {
            self.current_line = line;
            self.output.push((self.depth, vec![]));
            true
        } else {
            self.current_line = "";
            false
        }
    }
}

macro_rules! rust_ident { () => ("[a-zA-Z_][a-zA-Z_0-9]*") }
macro_rules! rust_int_suf { () => ("([iu](8|16|32|64)?)?") }

macro_rules! re {
    ($($r:expr),+) => (regex!(concat!("^(?:", $($r,)* ")")))
}
macro_rules! kw {
    ($($r:expr),+) => (regex!(concat!("^(?:" $(,$r,)"|"* r")\b")))
}

macro_rules! goto {
    ($s:expr, {}) => (());
    ($s:expr, return) => ({ $s.depth -= 1; return;});
    ($s:expr, $cx:ident) => ({ $s.depth += 1; $s.$cx() })
}

#[cfg(not(test))]
macro_rules! cases {
    ($s:expr, $ds:ident:) => { {
        let ch_len = {
            let mut idx = $s.current_line.char_indices().map(|(i, _)| i);
            idx.next();
            idx.next().unwrap_or($s.current_line.len())
        };
        $s.advance(ch_len, styles::$ds)
    } };
    ($s:expr, $ds:ident: $re:expr; $($rest:tt)*) => { cases!($s, $ds: $re, $ds => {}; $($rest)*) };
    ($s:expr, $ds:ident: $re:expr => $goto:tt; $($rest:tt)*) => { cases!($s, $ds: $re, $ds => $goto; $($rest)*) };
    ($s:expr, $ds:ident: $re:expr, $style:ident; $($rest:tt)*) => { cases!($s, $ds: $re, $style => {}; $($rest)*) };
    ($s:expr, $ds:ident: $re:expr, $style:ident => $goto:tt; $($rest:tt)*) => {
        if let Some((0, len)) = $re.find($s.current_line) {
            $s.advance(len, styles::$style);
            goto!($s, $goto);
        } else {
            cases!($s, $ds: $($rest)*)
        }
    }
}

#[cfg(test)]
macro_rules! cases { ($($rest:tt)*) => {()} }

macro_rules! context {
    ($name:ident, $ds:ident: $($rest:tt)*) => { context!{$name, $ds => {}: $($rest)*} };
    ($name:ident, $ds:ident => $line_end_cx:tt: $($rest:tt)*) => {
        fn $name(&mut self) {
            loop {
                while !self.current_line.is_empty() {
                    cases!(self, $ds: $($rest)*);
                }
                if self.next_line() {
                    goto!(self, $line_end_cx);
                } else {
                    return;
                }
            }
        }
    }
}

macro_rules! normal_like {
    ($($x:tt)+) => {context!{$($x)*
        re!(r"\s+");
        kw!("fn"), Keyword => function;
        kw!("type"), Keyword => type_;

        kw!("abstract",
            "alignof",
            "become",
            "do",
            "final",
            "offsetof",
            "override",
            "priv",
            "pure",
            "sizeof",
            "typeof",
            "unsized",
            "yield"), Keyword;
         kw!("as",
            "box",
            "break",
            "const",
            "continue",
            "crate",
            "else",
            "enum",
            "extern",
            "for",
            "if",
            "impl",
            "in",
            "let",
            "loop",
            "match",
            "mod",
            "move",
            "mut",
            "pub",
            "ref",
            "return",
            "static",
            "struct",
            "super",
            "trait",
            "unsafe",
            "use",
            "virtual",
            "where",
            "while"), Keyword;
        kw!("bool",
            "int",
            "isize",
            "uint",
            "usize",
            "i8",
            "i16",
            "i32",
            "i64",
            "u8",
            "u16",
            "u32",
            "u64",
            "f32",
            "f64",
            "float",
            "char",
            "str",
            "Option",
            "Result",
            "Self",
            "Box",
            "Vec",
            "String"), Type;
        kw!("AsSlice",
            "CharExt",
            "Clone",
            "Copy",
            "Debug",
            "Decodable",
            "Default",
            "Display",
            "DoubleEndedIterator",
            "Drop",
            "Encodable",
            "Eq",
            "Default",
            "Extend",
            "Fn",
            "FnMut",
            "FnOnce",
            "FromPrimitive",
            "Hash",
            "Iterator",
            "IteratorExt",
            "MutPtrExt",
            "Ord",
            "PartialEq",
            "PartialOrd",
            "PtrExt",
            "Rand",
            "Send",
            "Sized",
            "SliceConcatExt",
            "SliceExt",
            "Str",
            "StrExt",
            "Sync",
            "ToString"), Trait;
        kw!("c_float",
            "c_double",
            "c_void",
            "FILE",
            "fpos_t",
            "DIR",
            "dirent",
            "c_char",
            "c_schar",
            "c_uchar",
            "c_short",
            "c_ushort",
            "c_int",
            "c_uint",
            "c_long",
            "c_ulong",
            "size_t",
            "ptrdiff_t",
            "clock_t",
            "time_t",
            "c_longlong",
            "c_ulonglong",
            "intptr_t",
            "uintptr_t",
            "off_t",
            "dev_t",
            "ino_t",
            "pid_t",
            "mode_t",
            "ssize_t"), CType;
        kw!("self"), SelfKw;
        kw!("true",
            "false",
            "Some",
            "None",
            "Ok",
            "Err",
            "Success",
            "Failure",
            "Cons",
            "Nil"), Constant;
        kw!("EXIT_FAILURE",
            "EXIT_SUCCESS",
            "RAND_MAX",
            "EOF",
            "SEEK_SET",
            "SEEK_CUR",
            "SEEK_END",
            "_IOFBF",
            "_IONBF",
            "_IOLBF",
            "BUFSIZ",
            "FOPEN_MAX",
            "FILENAME_MAX",
            "L_tmpnam",
            "TMP_MAX",
            "O_RDONLY",
            "O_WRONLY",
            "O_RDWR",
            "O_APPEND",
            "O_CREAT",
            "O_EXCL",
            "O_TRUNC",
            "S_IFIFO",
            "S_IFCHR",
            "S_IFBLK",
            "S_IFDIR",
            "S_IFREG",
            "S_IFMT",
            "S_IEXEC",
            "S_IWRITE",
            "S_IREAD",
            "S_IRWXU",
            "S_IXUSR",
            "S_IWUSR",
            "S_IRUSR",
            "F_OK",
            "R_OK",
            "W_OK",
            "X_OK",
            "STDIN_FILENO",
            "STDOUT_FILENO",
            "STDERR_FILENO"), CConstant;

        // Match special comments for region markers
        re!("//BEGIN"), RegionMarker => region_marker;
        re!("//END"), RegionMarker => region_marker;

        // Match comments
        re!("//"), Comment => comment;
        re!(r"/\*"), Comment => comment2;
        re!(r"0x[0-9a-fA-F_]+", rust_int_suf!()), Hex;
        re!(r"0o[0-7_]+", rust_int_suf!()), Octal;
        re!(r"0b[0-1_]+", rust_int_suf!()), Binary;
        re!(r"[0-9][0-9_]*\.[0-9_]*([eE][+-]?[0-9_]+)?(f32|f64|f)?"), Float;
        re!(r"[0-9][0-9_]*", rust_int_suf!()), Decimal;
        re!(r"#\["), Attribute => attribute;
        re!(r"#!\["), Attribute => attribute;
        re!(rust_ident!(), "::"), Scope;
        re!(rust_ident!(), "!"), Macro;
        //re!("'", rust_ident!(), "(?!')"), Lifetime;
        re!(r"[{}\[\]]"), Symbol;
        re!("r\""), String => raw_string;
        re!("r##\""), String => raw_hashed2;
        re!("r#\""), String => raw_hashed1;
        re!("\""), String => string;
        re!(r"'"), Character => character;
        re!(rust_ident!());
    }}
}

impl<'a, I> Rust<'a, I> where I: Iterator<Item=&'a str> {
    normal_like!{normal, NormalText:}
    normal_like!{attribute, Attribute:
        re!(r"\]"), Attribute => return;
    }
    context!{function, Definition:
        re!(r"\s+");
        re!(r"\("), NormalText => return;
        re!(r">"), NormalText => return;
    }
    context!{type_, Definition:
        re!(r"\s+");
        re!(r"[=<;]"), NormalText => return;
    }
    // Rustc allows strings to extend over multiple lines, and the
    // only thing a backshash at end-of-line does is remove the whitespace.
    context!{string, String:
        re!(r"\\"), CharEscape => char_escape;
        re!("\""), String => return;
    }
    context!{raw_string, String:
        re!("\""), String => return;
    }
    // These rules are't complete: they won't match r###"abc"###
    context!{raw_hashed1, String:
        re!("\"#"), String => return;
    }
    context!{raw_hashed2, String:
        re!("\"##"), String => return;
    }
    context!{character, Character => return:
        re!(r"\\"), CharEscape => char_escape;
        re!(r"'"), Character => return;
    }
    context!{char_escape, CharEscape => return:
        re!("[nrt'\"]"), CharEscape => return;
        re!(r"x[0-9a-fA-F]{2}"), CharEscape => return;
        re!(r"u\{[0-9a-fA-F]{1,6}\}"), CharEscape => return;
        re!(r"u[0-9a-fA-F]{4}"), CharEscape => return;
        re!(r"U[0-9a-fA-F]{8}"), CharEscape => return;
        re!(r"\."), Error => return;
    }
    context!{region_marker, RegionMarker => return:}
    context!{comment, Comment => return:
        re!(r"\s+");
    }
    context!{comment2, Comment:
        re!(r"\s+");
        re!(r"\*/"), Comment => return;
    }
}

#[allow(non_upper_case_globals)]
pub mod base_styles {
    use super::Style;

    const DEFAULT: Style = Style { color: [1.0, 1.0, 1.0, 1.0], bold: false };

    macro_rules! styles {
        () => {};
        ($name:ident => ($r:expr,$g:expr,$b:expr) $($rest:tt)*) => {
            styles!($name => color=[$r as f32 / 255.0, $g as f32 / 255.0, $b as f32 / 255.0, 1.0] $($rest)*);
        };
        ($name:ident => $($extra:ident=$val:expr),*; $($rest:tt)*) => {
            pub const $name: Style = Style { $($extra: $val,)* ..DEFAULT };
            styles!($($rest)*);
        }
    }

    styles!{
        Normal => (239,240,241);
        Keyword => (239,240,241), bold=true;
        Function => (246,116,0);
        DataType => (41,128,185);
        DecVal => (246,116,0);
        BaseN => (246,116,0);
        Float => (246,116,0);
        Char => (61,174,233);
        String => (218,68,83);
        Comment => (189,195,199);
        RegionMarker => (41,128,185);
        Others => (39,174,96);
        Error => (218,68,83);
    }
}

#[allow(non_upper_case_globals)]
pub mod styles {
    use super::{Style, base_styles};

    macro_rules! styles {
        () => {};
        ($name:ident => $base:ident; $($rest:tt)*) => {
            pub const $name: Style = base_styles::$base;
            styles!($($rest)*);
        };
        ($name:ident => $base:ident, $($extra:ident=$val:expr),*; $($rest:tt)*) => {
            pub const $name: Style = Style { $($extra: $val,)* ..base_styles::$base };
            styles!($($rest)*);
        }
    }

    styles!{
        NormalText => Normal;
        Keyword => Keyword;
        SelfKw => Function, bold=true;
        Type => DataType, bold=true;
        Trait => DataType, bold=true;
        CType => DataType;
        Constant => Keyword;
        CConstant => Normal;
        Definition => Function;
        Comment => Comment;
        Scope => Others, bold=true;
        Decimal => DecVal;
        Hex => BaseN;
        Octal => BaseN;
        Binary => BaseN;
        Float => Float;
        String => String;
        CharEscape => Char;
        Character => Char;
        Macro => Others;
        Attribute => Others;
        Lifetime => Char, bold=true;
        RegionMarker => RegionMarker;
        Error => Error;

        Symbol => Normal;
    }
}
<|endoftext|>


<commit_before>use std::ops::AddAssign;
use std::fs:: { OpenOptions, File as OutputFile };
use std::convert::AsRef;
use std::result:: { Result };
use std::io:: { Result as IOResult };
use std::io::prelude::*;
use std::path::Path;
use std::fmt;
use lcov_parser:: {
    LCOVParser, LCOVRecord, LineData, FunctionData as FunctionDataRecord,
    BranchData as BranchDataRecord,
    FunctionName, ParseError, FromFile
};

use result::summary:: { Summary };
use result::test:: { Tests };
use result::file:: { File, Files };
use result::line:: { CheckSums };
use record:: { RecordWriter };

pub fn parse_file<T: AsRef<Path>>(file: T) -> Result<Report, ParseError> {
    let mut parse = ReportParser::new();
    parse.parse(file)
}

pub fn merge_files<T: AsRef<Path> + fmt::Display>(files: &[T]) -> Result<Report, ParseError> {
    let mut merged_report:Option<Report> = None;

    for file in files.iter() {
        let mut parse = ReportParser::new();
        match parse.parse(file) {
            Ok(report) => {
                if merged_report.is_some() {
                    let mut merged = merged_report.as_mut().unwrap();
                    *merged += report;
                } else {
                    merged_report = Some(report);
                }
            },
            Err(err) => {
                return Err(err)
            }
        };
    }
    Ok(merged_report.unwrap())
}

struct ReportParser {
    test_name: Option<String>,
    source_name: Option<String>,
    tests: Tests,
    checksum: CheckSums,
    files: Files
}

impl ReportParser {
    fn new() -> Self {
        ReportParser {
            test_name: None,
            source_name: None,
            tests: Tests::new(),
            checksum: CheckSums::new(),
            files: Files::new()
        }
    }
    fn parse<T: AsRef<Path>>(&mut self, file: T) -> Result<Report, ParseError> {
        let mut parser = try!(LCOVParser::from_file(file));

        loop {
            let result = try!(parser.next());

            if result.is_none() {
                break;
            }
            let record = result.unwrap();

            match record {
                LCOVRecord::TestName(ref name) => self.on_test_name(name),
                LCOVRecord::SourceFile(ref name) => self.on_source_file(name),
                LCOVRecord::Data(ref data) => self.on_data(data),
                LCOVRecord::FunctionName(ref func_name) => self.on_func_name(func_name),
                LCOVRecord::FunctionData(ref func_data) => self.on_func_data(func_data),
                LCOVRecord::BranchData(ref branch_data) => self.on_branch_data(branch_data),
                LCOVRecord::EndOfRecord => self.on_end_of_record(),
                _ => { continue; }
            };
        }
        Ok(Report::new(self.files.clone()))
    }
    fn on_test_name(&mut self, test_name: &Option<String>) {
        self.test_name = match test_name {
            &Some(ref name) => Some(name.clone()),
            &None => Some(String::new())
        };
        let current_test_name = self.test_name.as_ref().unwrap();
        self.tests += current_test_name;
    }
    fn on_source_file(&mut self, source_name: &String) {
        self.source_name = Some(source_name.clone());
    }
    fn on_data(&mut self, line_data: &LineData) {
        if self.test_name.is_some() {
            let test_name = self.test_name.as_ref().unwrap();
            self.tests += (test_name, line_data);
        }

        if line_data.checksum.is_none() {
            return;
        }
        self.checksum += line_data;

        let checksum_value = line_data.checksum.clone().unwrap();
        let current_checksum = self.checksum.get(&line_data.line).unwrap();
        if current_checksum != &checksum_value {
            println!("{} {}", current_checksum, checksum_value);
        }
    }
    fn on_func_name(&mut self, func_name: &FunctionName) {
        if self.test_name.is_none() {
            return;
        }

        let test_name = self.test_name.as_ref().unwrap();
        self.tests += (test_name, func_name);
    }
    fn on_func_data(&mut self, func_data: &FunctionDataRecord) {
        if self.test_name.is_none() {
            return;
        }

        let test_name = self.test_name.as_ref().unwrap();
        self.tests += (test_name, func_data);
    }
    fn on_branch_data(&mut self, branch_data: &BranchDataRecord) {
        if self.test_name.is_none() {
            return;
        }

        let test_name = self.test_name.as_ref().unwrap();
        self.tests += (test_name, branch_data);
    }
    fn on_end_of_record(&mut self) {
        let source_name = self.source_name.as_ref().unwrap();
        let file = File::new(self.tests.clone());
        self.files += (source_name, &file);
        self.tests = Tests::new();
        self.checksum = CheckSums::new();
    }
}

pub struct Report {
    files: Files
}

impl Report {
    pub fn new(files: Files) -> Self {
        Report {
            files: files
        }
    }
    pub fn get(&self, key: &str) -> Option<&File> {
        self.files.get(&key.to_string())
    }
    pub fn files(&self) -> &Files {
        &self.files
    }
    pub fn len(&self) -> usize {
        self.files.len()
    }
    pub fn save_as<T: AsRef<Path>>(&self, path: T) -> IOResult<()> {
        let mut output = try!(OpenOptions::new().create(true).write(true).open(path));
        self.write_to::<OutputFile>(&mut output)
    }
}

impl AsRef<Files> for Report {
    fn as_ref(&self) -> &Files {
        &self.files
    }
}

impl AddAssign for Report {
    fn add_assign(&mut self, other: Report) {
        self.files += other.as_ref();
    }
}

impl RecordWriter for Report {
    fn write_to<T: Write>(&self, output: &mut T) -> IOResult<()> {
        writeln!(output, "{}", self)
    }
}

impl fmt::Display for Report {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (source_name, file) in self.files.iter() {
            for (test_name, test) in file.tests().iter() {
                try!(writeln!(f, "TN:{}", test_name));
                try!(writeln!(f, "SF:{}", source_name));
                try!(write!(f, "{}", test.functions()));
                try!(write!(f, "{}", test.branches()));
                try!(write!(f, "{}", test.lines()));
                try!(writeln!(f, "end_of_record"));
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use report::*;
    use std::path::Path;
    use std::fs::File;
    use std::io::*;

    #[test]
    fn merge_report_files() {
        let report_path = "tests/fixtures/fixture1.info";
        let report = merge_files(&[
            report_path,
            report_path
        ]).unwrap();

        let readed_file_content = {
            let merged_report_path = "tests/fixtures/merged_fixture.info";
            let mut output = String::new();
            let mut f = File::open(merged_report_path).unwrap();
            let _ = f.read_to_string(&mut output);
            output
        };
        assert_eq!(report.to_string(), readed_file_content);
    }

    #[test]
    fn save_as() {
        let report_path = "tests/fixtures/fixture1.info";
        let report = parse_file(report_path).unwrap();
        let _ = report.save_as("/tmp/report.lcov").unwrap();

        assert_eq!(Path::new("/tmp/report.lcov").exists(), true);
    }

    #[test]
    fn display() {
        let report_path = "tests/fixtures/fixture1.info";
        let readed_file_content = {
            let mut output = String::new();
            let mut f = File::open(report_path).unwrap();
            let _ = f.read_to_string(&mut output);
            output
        };
        let report = parse_file(report_path).unwrap();
        assert_eq!(report.to_string(), readed_file_content);
    }
}
<commit_msg>remove display trait<commit_after>use std::ops::AddAssign;
use std::fs:: { OpenOptions, File as OutputFile };
use std::convert::AsRef;
use std::result:: { Result };
use std::io:: { Result as IOResult };
use std::io::prelude::*;
use std::path::Path;
use std::fmt;
use lcov_parser:: {
    LCOVParser, LCOVRecord, LineData, FunctionData as FunctionDataRecord,
    BranchData as BranchDataRecord,
    FunctionName, ParseError, FromFile
};

use result::summary:: { Summary };
use result::test:: { Tests };
use result::file:: { File, Files };
use result::line:: { CheckSums };
use record:: { RecordWriter };

pub fn parse_file<T: AsRef<Path>>(file: T) -> Result<Report, ParseError> {
    let mut parse = ReportParser::new();
    parse.parse(file)
}

pub fn merge_files<T: AsRef<Path>>(files: &[T]) -> Result<Report, ParseError> {
    let mut merged_report:Option<Report> = None;

    for file in files.iter() {
        let mut parse = ReportParser::new();
        match parse.parse(file) {
            Ok(report) => {
                if merged_report.is_some() {
                    let mut merged = merged_report.as_mut().unwrap();
                    *merged += report;
                } else {
                    merged_report = Some(report);
                }
            },
            Err(err) => {
                return Err(err)
            }
        };
    }
    Ok(merged_report.unwrap())
}

struct ReportParser {
    test_name: Option<String>,
    source_name: Option<String>,
    tests: Tests,
    checksum: CheckSums,
    files: Files
}

impl ReportParser {
    fn new() -> Self {
        ReportParser {
            test_name: None,
            source_name: None,
            tests: Tests::new(),
            checksum: CheckSums::new(),
            files: Files::new()
        }
    }
    fn parse<T: AsRef<Path>>(&mut self, file: T) -> Result<Report, ParseError> {
        let mut parser = try!(LCOVParser::from_file(file));

        loop {
            let result = try!(parser.next());

            if result.is_none() {
                break;
            }
            let record = result.unwrap();

            match record {
                LCOVRecord::TestName(ref name) => self.on_test_name(name),
                LCOVRecord::SourceFile(ref name) => self.on_source_file(name),
                LCOVRecord::Data(ref data) => self.on_data(data),
                LCOVRecord::FunctionName(ref func_name) => self.on_func_name(func_name),
                LCOVRecord::FunctionData(ref func_data) => self.on_func_data(func_data),
                LCOVRecord::BranchData(ref branch_data) => self.on_branch_data(branch_data),
                LCOVRecord::EndOfRecord => self.on_end_of_record(),
                _ => { continue; }
            };
        }
        Ok(Report::new(self.files.clone()))
    }
    fn on_test_name(&mut self, test_name: &Option<String>) {
        self.test_name = match test_name {
            &Some(ref name) => Some(name.clone()),
            &None => Some(String::new())
        };
        let current_test_name = self.test_name.as_ref().unwrap();
        self.tests += current_test_name;
    }
    fn on_source_file(&mut self, source_name: &String) {
        self.source_name = Some(source_name.clone());
    }
    fn on_data(&mut self, line_data: &LineData) {
        if self.test_name.is_some() {
            let test_name = self.test_name.as_ref().unwrap();
            self.tests += (test_name, line_data);
        }

        if line_data.checksum.is_none() {
            return;
        }
        self.checksum += line_data;

        let checksum_value = line_data.checksum.clone().unwrap();
        let current_checksum = self.checksum.get(&line_data.line).unwrap();
        if current_checksum != &checksum_value {
            println!("{} {}", current_checksum, checksum_value);
        }
    }
    fn on_func_name(&mut self, func_name: &FunctionName) {
        if self.test_name.is_none() {
            return;
        }

        let test_name = self.test_name.as_ref().unwrap();
        self.tests += (test_name, func_name);
    }
    fn on_func_data(&mut self, func_data: &FunctionDataRecord) {
        if self.test_name.is_none() {
            return;
        }

        let test_name = self.test_name.as_ref().unwrap();
        self.tests += (test_name, func_data);
    }
    fn on_branch_data(&mut self, branch_data: &BranchDataRecord) {
        if self.test_name.is_none() {
            return;
        }

        let test_name = self.test_name.as_ref().unwrap();
        self.tests += (test_name, branch_data);
    }
    fn on_end_of_record(&mut self) {
        let source_name = self.source_name.as_ref().unwrap();
        let file = File::new(self.tests.clone());
        self.files += (source_name, &file);
        self.tests = Tests::new();
        self.checksum = CheckSums::new();
    }
}

pub struct Report {
    files: Files
}

impl Report {
    pub fn new(files: Files) -> Self {
        Report {
            files: files
        }
    }
    pub fn get(&self, key: &str) -> Option<&File> {
        self.files.get(&key.to_string())
    }
    pub fn files(&self) -> &Files {
        &self.files
    }
    pub fn len(&self) -> usize {
        self.files.len()
    }
    pub fn save_as<T: AsRef<Path>>(&self, path: T) -> IOResult<()> {
        let mut output = try!(OpenOptions::new().create(true).write(true).open(path));
        self.write_to::<OutputFile>(&mut output)
    }
}

impl AsRef<Files> for Report {
    fn as_ref(&self) -> &Files {
        &self.files
    }
}

impl AddAssign for Report {
    fn add_assign(&mut self, other: Report) {
        self.files += other.as_ref();
    }
}

impl RecordWriter for Report {
    fn write_to<T: Write>(&self, output: &mut T) -> IOResult<()> {
        writeln!(output, "{}", self)
    }
}

impl fmt::Display for Report {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for (source_name, file) in self.files.iter() {
            for (test_name, test) in file.tests().iter() {
                try!(writeln!(f, "TN:{}", test_name));
                try!(writeln!(f, "SF:{}", source_name));
                try!(write!(f, "{}", test.functions()));
                try!(write!(f, "{}", test.branches()));
                try!(write!(f, "{}", test.lines()));
                try!(writeln!(f, "end_of_record"));
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use report::*;
    use std::path::Path;
    use std::fs::File;
    use std::io::*;

    #[test]
    fn merge_report_files() {
        let report_path = "tests/fixtures/fixture1.info";
        let report = merge_files(&[
            report_path,
            report_path
        ]).unwrap();

        let readed_file_content = {
            let merged_report_path = "tests/fixtures/merged_fixture.info";
            let mut output = String::new();
            let mut f = File::open(merged_report_path).unwrap();
            let _ = f.read_to_string(&mut output);
            output
        };
        assert_eq!(report.to_string(), readed_file_content);
    }

    #[test]
    fn save_as() {
        let report_path = "tests/fixtures/fixture1.info";
        let report = parse_file(report_path).unwrap();
        let _ = report.save_as("/tmp/report.lcov").unwrap();

        assert_eq!(Path::new("/tmp/report.lcov").exists(), true);
    }

    #[test]
    fn display() {
        let report_path = "tests/fixtures/fixture1.info";
        let readed_file_content = {
            let mut output = String::new();
            let mut f = File::open(report_path).unwrap();
            let _ = f.read_to_string(&mut output);
            output
        };
        let report = parse_file(report_path).unwrap();
        assert_eq!(report.to_string(), readed_file_content);
    }
}
<|endoftext|>