<commit_before>
use std::fs;
use std::path::{Path, PathBuf};
use std::io;
use std::char::from_u32;
use std::io::Write;
use std::process::{Command, Stdio, ExitStatus};
use std::ffi::{OsStr, OsString};
use hyper::{self, Client};
use openssl::crypto::hash::Hasher;

use rand::random;

pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P, callback: F) -> io::Result<bool> {
	if !is_directory(path.as_ref()) {
		callback(path.as_ref());
		fs::create_dir_all(path.as_ref()).map(|()| true)
	} else {
		Ok(false)
	}
}

pub fn is_directory<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).ok().as_ref().map(fs::Metadata::is_dir) == Some(true)
}

pub fn is_file<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).ok().as_ref().map(fs::Metadata::is_file) == Some(true)
}

pub fn path_exists<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).is_ok()
}

pub fn random_string(length: usize) -> String {
	let chars = b"abcdefghijklmnopqrstuvwxyz0123456789_";
	(0..length).map(|_| from_u32(chars[random::<usize>() % chars.len()] as u32).unwrap()).collect()
}

pub fn if_not_empty<S: PartialEq<str>>(s: S) -> Option<S> {
	if s == *"" {
		None
	} else {
		Some(s)
	}
}

pub fn write_file(path: &Path, contents: &str) -> io::Result<()> {
	let mut file = try!(fs::OpenOptions::new()
		.write(true)
		.truncate(true)
		.create(true)
		.open(path));

	try!(io::Write::write_all(&mut file, contents.as_bytes()));

	try!(file.sync_data());

	Ok(())
}

pub fn read_file(path: &Path) -> io::Result<String> {
	let mut file = try!(fs::OpenOptions::new()
		.read(true)
		.open(path));

	let mut contents = String::new();

	try!(io::Read::read_to_string(&mut file, &mut contents));

	Ok(contents)
}

pub fn filter_file<F: FnMut(&str) -> bool>(src: &Path, dest: &Path, mut filter: F) -> io::Result<usize> {
	let src_file = try!(fs::File::open(src));
	let dest_file = try!(fs::File::create(dest));

	let mut reader = io::BufReader::new(src_file);
	let mut writer = io::BufWriter::new(dest_file);
	let mut removed = 0;

	for result in io::BufRead::lines(&mut reader) {
		let line = try!(result);
		if filter(&line) {
			try!(writeln!(&mut writer, "{}", &line));
		} else {
			removed += 1;
		}
	}

	try!(writer.flush());

	Ok(removed)
}

pub fn match_file<T, F: FnMut(&str) -> Option<T>>(src: &Path, mut f: F) -> io::Result<Option<T>> {
	let src_file = try!(fs::File::open(src));

	let mut reader = io::BufReader::new(src_file);

	for result in io::BufRead::lines(&mut reader) {
		let line = try!(result);
		if let Some(r) = f(&line) {
			return Ok(Some(r));
		}
	}

	Ok(None)
}

pub fn append_file(dest: &Path, line: &str) -> io::Result<()> {
	let mut dest_file = try!(fs::OpenOptions::new()
		.write(true)
		.append(true)
		.create(true)
		.open(dest)
		);

	try!(writeln!(&mut dest_file, "{}", line));

	try!(dest_file.sync_data());

	Ok(())
}

pub enum DownloadError {
	Status(hyper::status::StatusCode),
	Network(hyper::Error),
	File(io::Error),
}
pub type DownloadResult<T> = Result<T, DownloadError>;

pub fn download_file<P: AsRef<Path>>(url: hyper::Url, path: P, mut hasher: Option<&mut Hasher>) -> DownloadResult<()> {
	let client = Client::new();

	let mut res = try!(client.get(url).send().map_err(DownloadError::Network));
	if res.status != hyper::Ok { return Err(DownloadError::Status(res.status)); }

	let buffer_size = 0x10000;
	let mut buffer = vec![0u8; buffer_size];

	let mut file = try!(fs::File::create(path).map_err(DownloadError::File));

	loop {
		let bytes_read = try!(io::Read::read(&mut res, &mut buffer)
			.map_err(hyper::Error::Io)
			.map_err(DownloadError::Network)
			);

		if bytes_read != 0 {
			if let Some(ref mut h) = hasher {
				try!(io::Write::write_all(*h, &mut buffer[0..bytes_read]).map_err(DownloadError::File));
			}
			try!(io::Write::write_all(&mut file, &mut buffer[0..bytes_read]).map_err(DownloadError::File));
		} else {
			try!(file.sync_data().map_err(DownloadError::File));
			return Ok(());
		}
	}
}

pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
	#[cfg(windows)]
	fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
		::std::os::windows::fs::symlink_dir(src, dest)
	}
	#[cfg(not(windows))]
	fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
		::std::os::unix::fs::symlink(src, dest)
	}

	// This is stupid, but seems to be the safest way to delete
	// a directory that may be a symbol link, without accidentally
	// deleting the contents too...
	let _ = fs::remove_file(dest);
	let _ = fs::remove_dir(dest);
	let _ = fs::remove_dir_all(dest);
	symlink_dir_inner(src, dest)
}

pub fn symlink_file(src: &Path, dest: &Path) -> io::Result<()> {
	#[cfg(windows)]
	fn symlink_file_inner(src: &Path, dest: &Path) -> io::Result<()> {
		::std::os::windows::fs::symlink_file(src, dest)
	}
	#[cfg(not(windows))]
	fn symlink_file_inner(src: &Path, dest: &Path) -> io::Result<()> {
		::std::os::unix::fs::symlink(src, dest)
	}

	let _ = fs::remove_file(dest);
	symlink_file_inner(src, dest)
}

pub fn hardlink(src: &Path, dest: &Path) -> io::Result<()> {
	let _ = fs::remove_file(dest);
	fs::hard_link(src, dest)
}

pub enum CommandError {
	Io(io::Error),
	Status(ExitStatus),
}

pub type CommandResult<T> = Result<T, CommandError>;

pub fn cmd_status(cmd: &mut Command) -> CommandResult<()> {
	cmd.status().map_err(CommandError::Io).and_then(|s| {
		if s.success() {
			Ok(())
		} else {
			Err(CommandError::Status(s))
		}
	})
}

pub fn copy_dir(src: &Path, dest: &Path) -> CommandResult<()> {
	#[cfg(windows)]
	fn copy_dir_inner(src: &Path, dest: &Path) -> CommandResult<()> {
		cmd_status(Command::new("robocopy").arg(src).arg(dest).arg("/E"))
	}
	#[cfg(not(windows))]
	fn copy_dir_inner(src: &Path, dest: &Path) -> CommandResult<()> {
		cmd_status(Command::new("cp").arg("-R").arg(src).arg(dest))
	}

	copy_dir_inner(src, dest)
}

pub fn prefix_arg<S: AsRef<OsStr>>(name: &str, s: S) -> OsString {
	let mut arg = OsString::from(name);
	arg.push(s);
	arg
}

pub fn open_browser(path: &Path) -> io::Result<bool> {
	#[cfg(not(windows))]
	fn has_cmd(cmd: &&str) -> bool {
		Command::new("command")
			.arg("-v").arg(cmd)
			.stdin(Stdio::null())
			.stdout(Stdio::null())
			.stderr(Stdio::null())
			.status()
			.map(|s| s.success())
			.unwrap_or(false)
	}
	#[cfg(not(windows))]
	fn inner(path: &Path) -> io::Result<bool> {
		let commands = ["xdg-open", "open", "firefox", "chromium"];
		if let Some(cmd) = commands.iter().map(|s| *s).filter(has_cmd).next() {
			Command::new(cmd)
				.arg(path)
				.stdin(Stdio::null())
				.stdout(Stdio::null())
				.stderr(Stdio::null())
				.spawn()
				.map(|_| true)
		} else {
			Ok(false)
		}
	}
	#[cfg(windows)]
	fn inner(path: &Path) -> io::Result<bool> {
		Command::new("start")
			.arg(path)
			.stdin(Stdio::null())
			.stdout(Stdio::null())
			.stderr(Stdio::null())
			.spawn()
			.map(|_| true)
	}
	inner(path)
}
pub fn home_dir() -> Option<PathBuf> {
	#[cfg(not(windows))]
	fn inner() -> Option<PathBuf> {
		std::env::home_dir()
	}
	#[cfg(windows)]
	fn inner() -> Option<PathBuf> {
		windows::get_special_folder(&windows::FOLDERID_Profile).ok()
	}

	inner()
}

#[cfg(windows)]
pub mod windows {
	use winapi::*;
	use std::io;
	use std::path::PathBuf;
	use std::ptr;
	use std::slice;
	use std::ffi::OsString;
	use std::os::windows::ffi::OsStringExt;
	use shell32;
	use ole32;

	#[allow(non_upper_case_globals)]
	pub const FOLDERID_LocalAppData: GUID = GUID {
		Data1: 0xF1B32785,
		Data2: 0x6FBA,
		Data3: 0x4FCF,
		Data4: [0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91],
	};
	#[allow(non_upper_case_globals)]
	pub const FOLDERID_Profile: GUID = GUID {
		Data1: 0x5E6C858F,
		Data2: 0x0E22,
		Data3: 0x4760,
		Data4: [0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73],
	};

	pub fn get_special_folder(id: &shtypes::KNOWNFOLDERID) -> io::Result<PathBuf> {

		let mut path = ptr::null_mut();
		let result;

		unsafe {
			let code = shell32::SHGetKnownFolderPath(id, 0, ptr::null_mut(), &mut path);
			if code == 0 {
				let mut length = 0usize;
				while *path.offset(length as isize) != 0 {
					length += 1;
				}
				let slice = slice::from_raw_parts(path, length);
				result = Ok(OsString::from_wide(slice).into());
			} else {
				result = Err(io::Error::from_raw_os_error(code));
			}
			ole32::CoTaskMemFree(path as *mut _);
		}
		result
	}
}
<commit_msg>paths...<commit_after>
use std::fs;
use std::path::{Path, PathBuf};
use std::io;
use std::char::from_u32;
use std::io::Write;
use std::process::{Command, Stdio, ExitStatus};
use std::ffi::{OsStr, OsString};
use hyper::{self, Client};
use openssl::crypto::hash::Hasher;

use rand::random;

pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P, callback: F) -> io::Result<bool> {
	if !is_directory(path.as_ref()) {
		callback(path.as_ref());
		fs::create_dir_all(path.as_ref()).map(|()| true)
	} else {
		Ok(false)
	}
}

pub fn is_directory<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).ok().as_ref().map(fs::Metadata::is_dir) == Some(true)
}

pub fn is_file<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).ok().as_ref().map(fs::Metadata::is_file) == Some(true)
}

pub fn path_exists<P: AsRef<Path>>(path: P) -> bool {
	fs::metadata(path).is_ok()
}

pub fn random_string(length: usize) -> String {
	let chars = b"abcdefghijklmnopqrstuvwxyz0123456789_";
	(0..length).map(|_| from_u32(chars[random::<usize>() % chars.len()] as u32).unwrap()).collect()
}

pub fn if_not_empty<S: PartialEq<str>>(s: S) -> Option<S> {
	if s == *"" {
		None
	} else {
		Some(s)
	}
}

pub fn write_file(path: &Path, contents: &str) -> io::Result<()> {
	let mut file = try!(fs::OpenOptions::new()
		.write(true)
		.truncate(true)
		.create(true)
		.open(path));

	try!(io::Write::write_all(&mut file, contents.as_bytes()));

	try!(file.sync_data());

	Ok(())
}

pub fn read_file(path: &Path) -> io::Result<String> {
	let mut file = try!(fs::OpenOptions::new()
		.read(true)
		.open(path));

	let mut contents = String::new();

	try!(io::Read::read_to_string(&mut file, &mut contents));

	Ok(contents)
}

pub fn filter_file<F: FnMut(&str) -> bool>(src: &Path, dest: &Path, mut filter: F) -> io::Result<usize> {
	let src_file = try!(fs::File::open(src));
	let dest_file = try!(fs::File::create(dest));

	let mut reader = io::BufReader::new(src_file);
	let mut writer = io::BufWriter::new(dest_file);
	let mut removed = 0;

	for result in io::BufRead::lines(&mut reader) {
		let line = try!(result);
		if filter(&line) {
			try!(writeln!(&mut writer, "{}", &line));
		} else {
			removed += 1;
		}
	}

	try!(writer.flush());

	Ok(removed)
}

pub fn match_file<T, F: FnMut(&str) -> Option<T>>(src: &Path, mut f: F) -> io::Result<Option<T>> {
	let src_file = try!(fs::File::open(src));

	let mut reader = io::BufReader::new(src_file);

	for result in io::BufRead::lines(&mut reader) {
		let line = try!(result);
		if let Some(r) = f(&line) {
			return Ok(Some(r));
		}
	}

	Ok(None)
}

pub fn append_file(dest: &Path, line: &str) -> io::Result<()> {
	let mut dest_file = try!(fs::OpenOptions::new()
		.write(true)
		.append(true)
		.create(true)
		.open(dest)
		);

	try!(writeln!(&mut dest_file, "{}", line));

	try!(dest_file.sync_data());

	Ok(())
}

pub enum DownloadError {
	Status(hyper::status::StatusCode),
	Network(hyper::Error),
	File(io::Error),
}
pub type DownloadResult<T> = Result<T, DownloadError>;

pub fn download_file<P: AsRef<Path>>(url: hyper::Url, path: P, mut hasher: Option<&mut Hasher>) -> DownloadResult<()> {
	let client = Client::new();

	let mut res = try!(client.get(url).send().map_err(DownloadError::Network));
	if res.status != hyper::Ok { return Err(DownloadError::Status(res.status)); }

	let buffer_size = 0x10000;
	let mut buffer = vec![0u8; buffer_size];

	let mut file = try!(fs::File::create(path).map_err(DownloadError::File));

	loop {
		let bytes_read = try!(io::Read::read(&mut res, &mut buffer)
			.map_err(hyper::Error::Io)
			.map_err(DownloadError::Network)
			);

		if bytes_read != 0 {
			if let Some(ref mut h) = hasher {
				try!(io::Write::write_all(*h, &mut buffer[0..bytes_read]).map_err(DownloadError::File));
			}
			try!(io::Write::write_all(&mut file, &mut buffer[0..bytes_read]).map_err(DownloadError::File));
		} else {
			try!(file.sync_data().map_err(DownloadError::File));
			return Ok(());
		}
	}
}

pub fn symlink_dir(src: &Path, dest: &Path) -> io::Result<()> {
	#[cfg(windows)]
	fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
		::std::os::windows::fs::symlink_dir(src, dest)
	}
	#[cfg(not(windows))]
	fn symlink_dir_inner(src: &Path, dest: &Path) -> io::Result<()> {
		::std::os::unix::fs::symlink(src, dest)
	}

	// This is stupid, but seems to be the safest way to delete
	// a directory that may be a symbol link, without accidentally
	// deleting the contents too...
	let _ = fs::remove_file(dest);
	let _ = fs::remove_dir(dest);
	let _ = fs::remove_dir_all(dest);
	symlink_dir_inner(src, dest)
}

pub fn symlink_file(src: &Path, dest: &Path) -> io::Result<()> {
	#[cfg(windows)]
	fn symlink_file_inner(src: &Path, dest: &Path) -> io::Result<()> {
		::std::os::windows::fs::symlink_file(src, dest)
	}
	#[cfg(not(windows))]
	fn symlink_file_inner(src: &Path, dest: &Path) -> io::Result<()> {
		::std::os::unix::fs::symlink(src, dest)
	}

	let _ = fs::remove_file(dest);
	symlink_file_inner(src, dest)
}

pub fn hardlink(src: &Path, dest: &Path) -> io::Result<()> {
	let _ = fs::remove_file(dest);
	fs::hard_link(src, dest)
}

pub enum CommandError {
	Io(io::Error),
	Status(ExitStatus),
}

pub type CommandResult<T> = Result<T, CommandError>;

pub fn cmd_status(cmd: &mut Command) -> CommandResult<()> {
	cmd.status().map_err(CommandError::Io).and_then(|s| {
		if s.success() {
			Ok(())
		} else {
			Err(CommandError::Status(s))
		}
	})
}

pub fn copy_dir(src: &Path, dest: &Path) -> CommandResult<()> {
	#[cfg(windows)]
	fn copy_dir_inner(src: &Path, dest: &Path) -> CommandResult<()> {
		cmd_status(Command::new("robocopy").arg(src).arg(dest).arg("/E"))
	}
	#[cfg(not(windows))]
	fn copy_dir_inner(src: &Path, dest: &Path) -> CommandResult<()> {
		cmd_status(Command::new("cp").arg("-R").arg(src).arg(dest))
	}

	copy_dir_inner(src, dest)
}

pub fn prefix_arg<S: AsRef<OsStr>>(name: &str, s: S) -> OsString {
	let mut arg = OsString::from(name);
	arg.push(s);
	arg
}

pub fn open_browser(path: &Path) -> io::Result<bool> {
	#[cfg(not(windows))]
	fn has_cmd(cmd: &&str) -> bool {
		Command::new("command")
			.arg("-v").arg(cmd)
			.stdin(Stdio::null())
			.stdout(Stdio::null())
			.stderr(Stdio::null())
			.status()
			.map(|s| s.success())
			.unwrap_or(false)
	}
	#[cfg(not(windows))]
	fn inner(path: &Path) -> io::Result<bool> {
		let commands = ["xdg-open", "open", "firefox", "chromium"];
		if let Some(cmd) = commands.iter().map(|s| *s).filter(has_cmd).next() {
			Command::new(cmd)
				.arg(path)
				.stdin(Stdio::null())
				.stdout(Stdio::null())
				.stderr(Stdio::null())
				.spawn()
				.map(|_| true)
		} else {
			Ok(false)
		}
	}
	#[cfg(windows)]
	fn inner(path: &Path) -> io::Result<bool> {
		Command::new("start")
			.arg(path)
			.stdin(Stdio::null())
			.stdout(Stdio::null())
			.stderr(Stdio::null())
			.spawn()
			.map(|_| true)
	}
	inner(path)
}
pub fn home_dir() -> Option<PathBuf> {
	#[cfg(not(windows))]
	fn inner() -> Option<PathBuf> {
		::std::env::home_dir()
	}
	#[cfg(windows)]
	fn inner() -> Option<PathBuf> {
		windows::get_special_folder(&windows::FOLDERID_Profile).ok()
	}

	inner()
}

#[cfg(windows)]
pub mod windows {
	use winapi::*;
	use std::io;
	use std::path::PathBuf;
	use std::ptr;
	use std::slice;
	use std::ffi::OsString;
	use std::os::windows::ffi::OsStringExt;
	use shell32;
	use ole32;

	#[allow(non_upper_case_globals)]
	pub const FOLDERID_LocalAppData: GUID = GUID {
		Data1: 0xF1B32785,
		Data2: 0x6FBA,
		Data3: 0x4FCF,
		Data4: [0x9D, 0x55, 0x7B, 0x8E, 0x7F, 0x15, 0x70, 0x91],
	};
	#[allow(non_upper_case_globals)]
	pub const FOLDERID_Profile: GUID = GUID {
		Data1: 0x5E6C858F,
		Data2: 0x0E22,
		Data3: 0x4760,
		Data4: [0x9A, 0xFE, 0xEA, 0x33, 0x17, 0xB6, 0x71, 0x73],
	};

	pub fn get_special_folder(id: &shtypes::KNOWNFOLDERID) -> io::Result<PathBuf> {

		let mut path = ptr::null_mut();
		let result;

		unsafe {
			let code = shell32::SHGetKnownFolderPath(id, 0, ptr::null_mut(), &mut path);
			if code == 0 {
				let mut length = 0usize;
				while *path.offset(length as isize) != 0 {
					length += 1;
				}
				let slice = slice::from_raw_parts(path, length);
				result = Ok(OsString::from_wide(slice).into());
			} else {
				result = Err(io::Error::from_raw_os_error(code));
			}
			ole32::CoTaskMemFree(path as *mut _);
		}
		result
	}
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

use std::path::PathBuf;

#[get("/test/<path..>")]
fn test(path: PathBuf) -> String {
    format!("{:?}", path)
}

#[get("/two/<path..>")]
fn two(path: PathBuf) -> String {
    format!("{:?}", path)
}

#[get("/one/two/<path..>")]
fn one_two(path: PathBuf) -> String {
    format!("{:?}", path)
}

#[get("/<path..>", rank = 2)]
fn none(path: PathBuf) -> String {
    format!("{:?}", path)
}

use rocket::testing::MockRequest;
use rocket::http::Method::*;

#[test]
fn segments_works() {
    let rocket = rocket::ignite().mount("/", routes![test, two, one_two, none]);

    // We construct a path that matches each of the routes above. We ensure the
    // prefix is stripped, confirming that dynamic segments are working.
    for prefix in &["", "/test", "/two", "/one/two"] {
        let path = "this/is/the/path/we/want";
        let mut req = MockRequest::new(Get, format!("{}/{}", prefix, path));

        let mut response = req.dispatch_with(&rocket);
        let body_str = response.body().and_then(|b| b.into_string());
        assert_eq!(body_str, Some(format!("{:?}", path)));
    }
}
<commit_msg>Don't depend on path separator in segments tests.<commit_after>#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

use rocket::http::uri::Segments;

#[get("/test/<path..>")]
fn test(path: Segments) -> String {
    path.collect::<Vec<_>>().join("/")
}

#[get("/two/<path..>")]
fn two(path: Segments) -> String {
    path.collect::<Vec<_>>().join("/")
}

#[get("/one/two/<path..>")]
fn one_two(path: Segments) -> String {
    path.collect::<Vec<_>>().join("/")
}

#[get("/<path..>", rank = 2)]
fn none(path: Segments) -> String {
    path.collect::<Vec<_>>().join("/")
}

use rocket::testing::MockRequest;
use rocket::http::Method::*;

#[test]
fn segments_works() {
    let rocket = rocket::ignite().mount("/", routes![test, two, one_two, none]);

    // We construct a path that matches each of the routes above. We ensure the
    // prefix is stripped, confirming that dynamic segments are working.
    for prefix in &["", "/test", "/two", "/one/two"] {
        let path = "this/is/the/path/we/want";
        let mut req = MockRequest::new(Get, format!("{}/{}", prefix, path));

        let mut response = req.dispatch_with(&rocket);
        let body_str = response.body().and_then(|b| b.into_string());
        assert_eq!(body_str, Some(path.into()));
    }
}
<|endoftext|>


<commit_before>//! The `pact_models` crate provides all the structs and traits required to model a Pact.

use std::fmt::{Display, Formatter};
use std::fmt;

use anyhow::anyhow;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};

use crate::verify_json::{json_type_of, PactFileVerificationResult, PactJsonVerifier, ResultLevel};

pub mod content_types;
pub mod bodies;
pub mod v4;
pub mod provider_states;
pub mod verify_json;
pub mod json_utils;
pub mod expression_parser;
pub mod time_utils;
mod timezone_db;
pub mod file_utils;
pub mod xml_utils;
pub mod matchingrules;
pub mod generators;
pub mod path_exp;
pub mod query_strings;
pub mod http_utils;
pub mod http_parts;
pub mod request;
pub mod response;
pub mod headers;
pub mod interaction;
pub mod sync_interaction;
pub mod message;
pub mod pact;
pub mod sync_pact;
pub mod message_pact;

/// Version of the library
pub const PACT_RUST_VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");

/// Enum defining the pact specification versions supported by the library
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Deserialize, Serialize)]
#[allow(non_camel_case_types)]
pub enum PactSpecification {
  /// Unknown or unsupported specification version
  Unknown,
  /// First version of the pact specification (`https://github.com/pact-foundation/pact-specification/tree/version-1`)
  V1,
  /// Second version of the pact specification (`https://github.com/pact-foundation/pact-specification/tree/version-1.1`)
  V1_1,
  /// Version two of the pact specification (`https://github.com/pact-foundation/pact-specification/tree/version-2`)
  V2,
  /// Version three of the pact specification (`https://github.com/pact-foundation/pact-specification/tree/version-3`)
  V3,
  /// Version four of the pact specification (`https://github.com/pact-foundation/pact-specification/tree/version-4`)
  V4
}

impl Default for PactSpecification {
  fn default() -> Self {
        PactSpecification::Unknown
    }
}

impl PactSpecification {
  /// Returns the semantic version string of the specification version.
  pub fn version_str(&self) -> String {
    match *self {
        PactSpecification::V1 => "1.0.0",
        PactSpecification::V1_1 => "1.1.0",
        PactSpecification::V2 => "2.0.0",
        PactSpecification::V3 => "3.0.0",
        PactSpecification::V4 => "4.0",
        _ => "unknown"
    }.into()
  }

  /// Parse a version string into a PactSpecification
  pub fn parse_version<S: Into<String>>(input: S) -> anyhow::Result<PactSpecification> {
    let str_version = input.into();
    let version = lenient_semver::parse(str_version.as_str())
      .map_err(|_| anyhow!("Invalid specification version '{}'", str_version))?;
    match version.major {
      1 => match version.minor {
        0 => Ok(PactSpecification::V1),
        1 => Ok(PactSpecification::V1_1),
        _ => Err(anyhow!("Unsupported specification version '{}'", str_version))
      },
      2 => match version.minor {
        0 => Ok(PactSpecification::V2),
        _ => Err(anyhow!("Unsupported specification version '{}'", str_version))
      },
      3 => match version.minor {
        0 => Ok(PactSpecification::V3),
        _ => Err(anyhow!("Unsupported specification version '{}'", str_version))
      },
      4 => match version.minor {
        0 => Ok(PactSpecification::V4),
        _ => Err(anyhow!("Unsupported specification version '{}'", str_version))
      },
      _ => Err(anyhow!("Invalid specification version '{}'", str_version))
    }
  }
}

impl From<&str> for PactSpecification {
  fn from(s: &str) -> Self {
    match s.to_uppercase().as_str() {
      "V1" => PactSpecification::V1,
      "V1.1" => PactSpecification::V1_1,
      "V2" => PactSpecification::V2,
      "V3" => PactSpecification::V3,
      "V4" => PactSpecification::V4,
      _ => PactSpecification::Unknown
    }
  }
}

impl From<String> for PactSpecification {
  fn from(s: String) -> Self {
    PactSpecification::from(s.as_str())
  }
}

impl From<&String> for PactSpecification {
  fn from(s: &String) -> Self {
    PactSpecification::from(s.as_str())
  }
}

impl ToString for PactSpecification {
  fn to_string(&self) -> String {
    match *self {
      PactSpecification::V1 => "V1",
      PactSpecification::V1_1 => "V1.1",
      PactSpecification::V2 => "V2",
      PactSpecification::V3 => "V3",
      PactSpecification::V4 => "V4",
      _ => "unknown"
    }.into()
  }
}

/// Struct that defines the consumer of the pact.
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
pub struct Consumer {
  /// Each consumer should have a unique name to identify it.
  pub name: String
}

impl Consumer {
  /// Builds a `Consumer` from the `Json` struct.
  pub fn from_json(pact_json: &Value) -> Consumer {
    let val = match pact_json.get("name") {
      Some(v) => match v.clone() {
        Value::String(s) => s,
        _ => v.to_string()
      },
      None => "consumer".to_string()
    };
    Consumer { name: val.clone() }
  }

  /// Converts this `Consumer` to a `Value` struct.
  pub fn to_json(&self) -> Value {
    json!({ "name" : self.name })
  }

  /// Generate the JSON schema properties for the given Pact specification
  pub fn schema(_spec_version: PactSpecification) -> Value {
    json!({
      "properties": {
        "name": {
          "type": "string"
        }
      },
      "required": ["name"],
      "type": "object"
    })
  }
}

impl PactJsonVerifier for Consumer {
  fn verify_json(path: &str, pact_json: &Value, strict: bool, _spec_version: PactSpecification) -> Vec<PactFileVerificationResult> {
    let mut results = vec![];

    match pact_json {
      Value::Object(values) => {
        if let Some(name) = values.get("name") {
          if !name.is_string() {
            results.push(PactFileVerificationResult::new(path.to_owned() + "/name", ResultLevel::ERROR,
              format!("Must be a String, got {}", json_type_of(pact_json))))
          }
        } else {
          results.push(PactFileVerificationResult::new(path.to_owned() + "/name",
            if strict { ResultLevel::ERROR } else { ResultLevel::WARNING }, "Missing name"))
        }

        for key in values.keys() {
          if key != "name" {
            results.push(PactFileVerificationResult::new(path.to_owned(),
              if strict { ResultLevel::ERROR } else { ResultLevel::WARNING }, format!("Unknown attribute '{}'", key)))
          }
        }
      }
      _ => results.push(PactFileVerificationResult::new(path, ResultLevel::ERROR,
        format!("Must be an Object, got {}", json_type_of(pact_json))))
    }

    results
  }
}

/// Struct that defines a provider of a pact.
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
pub struct Provider {
  /// Each provider should have a unique name to identify it.
  pub name: String
}

impl Provider {
  /// Builds a `Provider` from a `Value` struct.
  pub fn from_json(pact_json: &Value) -> Provider {
    let val = match pact_json.get("name") {
      Some(v) => match v.clone() {
        Value::String(s) => s,
        _ => v.to_string()
      },
      None => "provider".to_string()
    };
    Provider { name: val.clone() }
  }

  /// Converts this `Provider` to a `Value` struct.
  pub fn to_json(&self) -> Value {
    json!({ "name" : self.name })
  }

  /// Generate the JSON schema properties for the given Pact specification
  pub fn schema(_spec_version: PactSpecification) -> Value {
    json!({
      "properties": {
        "name": {
          "type": "string"
        }
      },
      "required": ["name"],
      "type": "object"
    })
  }
}

impl PactJsonVerifier for Provider {
  fn verify_json(path: &str, pact_json: &Value, strict: bool, _spec_version: PactSpecification) -> Vec<PactFileVerificationResult> {
    let mut results = vec![];

    match pact_json {
      Value::Object(values) => {
        if let Some(name) = values.get("name") {
          if !name.is_string() {
            results.push(PactFileVerificationResult::new(path.to_owned() + "/name", ResultLevel::ERROR,
                                                         format!("Must be a String, got {}", json_type_of(pact_json))))
          }
        } else {
          results.push(PactFileVerificationResult::new(path.to_owned() + "/name",
            if strict { ResultLevel::ERROR } else { ResultLevel::WARNING }, "Missing name"))
        }

        for key in values.keys() {
          if key != "name" {
            results.push(PactFileVerificationResult::new(path.to_owned(),
              if strict { ResultLevel::ERROR } else { ResultLevel::WARNING }, format!("Unknown attribute '{}'", key)))
          }
        }
      }
      _ => results.push(PactFileVerificationResult::new(path, ResultLevel::ERROR,
                                                        format!("Must be an Object, got {}", json_type_of(pact_json))))
    }

    results
  }
}

/// Enumeration of the types of differences between requests and responses
#[derive(PartialEq, Debug, Clone, Eq)]
pub enum DifferenceType {
  /// Methods differ
  Method,
  /// Paths differ
  Path,
  /// Headers differ
  Headers,
  /// Query parameters differ
  QueryParameters,
  /// Bodies differ
  Body,
  /// Matching Rules differ
  MatchingRules,
  /// Response status differ
  Status
}

/// Enum that defines the different types of HTTP statuses
#[derive(Debug, Clone, Deserialize, Serialize, Ord, PartialOrd, Eq, PartialEq)]
pub enum HttpStatus {
  /// Informational responses (100–199)
  Information,
  /// Successful responses (200–299)
  Success,
  /// Redirects (300–399)
  Redirect,
  /// Client errors (400–499)
  ClientError,
  /// Server errors (500–599)
  ServerError,
  /// Explicit status codes
  StatusCodes(Vec<u16>),
  /// Non-error response(< 400)
  NonError,
  /// Any error response (>= 400)
  Error
}

impl HttpStatus {
  /// Parse a JSON structure into a HttpStatus
  pub fn from_json(value: &Value) -> anyhow::Result<Self> {
    match value {
      Value::String(s) => match s.as_str() {
        "info" => Ok(HttpStatus::Information),
        "success" => Ok(HttpStatus::Success),
        "redirect" => Ok(HttpStatus::Redirect),
        "clientError" => Ok(HttpStatus::ClientError),
        "serverError" => Ok(HttpStatus::ServerError),
        "nonError" => Ok(HttpStatus::NonError),
        "error" => Ok(HttpStatus::Error),
        _ => Err(anyhow!("'{}' is not a valid value for an HTTP Status", s))
      },
      Value::Array(a) => {
        let status_codes = a.iter().map(|status| match status {
          Value::Number(n) => if n.is_u64() {
            Ok(n.as_u64().unwrap() as u16)
          } else if n.is_i64() {
            Ok(n.as_i64().unwrap() as u16)
          } else {
            Ok(n.as_f64().unwrap() as u16)
          },
          Value::String(s) => s.parse::<u16>().map_err(|err| anyhow!(err)),
          _ => Err(anyhow!("'{}' is not a valid JSON value for an HTTP Status", status))
        }).collect::<Vec<anyhow::Result<u16>>>();
        if status_codes.iter().any(|it| it.is_err()) {
          Err(anyhow!("'{}' is not a valid JSON value for an HTTP Status", value))
        } else {
          Ok(HttpStatus::StatusCodes(status_codes.iter().map(|code| *code.as_ref().unwrap()).collect()))
        }
      }
      _ => Err(anyhow!("'{}' is not a valid JSON value for an HTTP Status", value))
    }
  }

  /// Generate a JSON structure for this status
  pub fn to_json(&self) -> Value {
    match self {
      HttpStatus::StatusCodes(codes) => json!(codes),
      HttpStatus::Information => json!("info"),
      HttpStatus::Success => json!("success"),
      HttpStatus::Redirect => json!("redirect"),
      HttpStatus::ClientError => json!("clientError"),
      HttpStatus::ServerError => json!("serverError"),
      HttpStatus::NonError => json!("nonError"),
      HttpStatus::Error => json!("error")
    }
  }
}

impl Display for HttpStatus {
  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    match self {
      HttpStatus::Information => write!(f, "Informational response (100–199)"),
      HttpStatus::Success => write!(f, "Successful response (200–299)"),
      HttpStatus::Redirect => write!(f, "Redirect (300–399)"),
      HttpStatus::ClientError => write!(f, "Client error (400–499)"),
      HttpStatus::ServerError => write!(f, "Server error (500–599)"),
      HttpStatus::StatusCodes(status) =>
        write!(f, "{}", status.iter().map(|s| s.to_string()).join(", ")),
      HttpStatus::NonError => write!(f, "Non-error response (< 400)"),
      HttpStatus::Error => write!(f, "Error response (>= 400)")
    }
  }
}

#[cfg(test)]
mod tests;
<commit_msg>chore: add a prelude module to the models crate<commit_after>//! The `pact_models` crate provides all the structs and traits required to model a Pact.

use std::fmt::{Display, Formatter};
use std::fmt;

use anyhow::anyhow;
use itertools::Itertools;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};

use crate::verify_json::{json_type_of, PactFileVerificationResult, PactJsonVerifier, ResultLevel};

pub mod content_types;
pub mod bodies;
pub mod v4;
pub mod provider_states;
pub mod verify_json;
pub mod json_utils;
pub mod expression_parser;
pub mod time_utils;
mod timezone_db;
pub mod file_utils;
pub mod xml_utils;
pub mod matchingrules;
pub mod generators;
pub mod path_exp;
pub mod query_strings;
pub mod http_utils;
pub mod http_parts;
pub mod request;
pub mod response;
pub mod headers;
pub mod interaction;
pub mod sync_interaction;
pub mod message;
pub mod pact;
pub mod sync_pact;
pub mod message_pact;

/// A "prelude" or a default list of import types to include.
pub mod prelude {
  pub use crate::{Consumer, Provider};
  pub use crate::bodies::OptionalBody;
  pub use crate::content_types::ContentType;
  pub use crate::expression_parser::DataType;
  pub use crate::generators::{Generator, GeneratorCategory, Generators};
  pub use crate::interaction::Interaction;
  pub use crate::matchingrules::{Category, MatchingRuleCategory, MatchingRules, RuleLogic};
  pub use crate::message_pact::MessagePact;
  pub use crate::pact::Pact;
  pub use crate::PactSpecification;
  pub use crate::provider_states::ProviderState;
  pub use crate::request::Request;
  pub use crate::response::Response;
  pub use crate::sync_interaction::RequestResponseInteraction;
  pub use crate::sync_pact::RequestResponsePact;
  pub use crate::http_utils::HttpAuth;

  pub mod v4 {
    pub use crate::v4::pact::V4Pact;
    pub use crate::v4::synch_http::SynchronousHttp;
  }
}

/// Version of the library
pub const PACT_RUST_VERSION: Option<&'static str> = option_env!("CARGO_PKG_VERSION");

/// Enum defining the pact specification versions supported by the library
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Deserialize, Serialize)]
#[allow(non_camel_case_types)]
pub enum PactSpecification {
  /// Unknown or unsupported specification version
  Unknown,
  /// First version of the pact specification (`https://github.com/pact-foundation/pact-specification/tree/version-1`)
  V1,
  /// Second version of the pact specification (`https://github.com/pact-foundation/pact-specification/tree/version-1.1`)
  V1_1,
  /// Version two of the pact specification (`https://github.com/pact-foundation/pact-specification/tree/version-2`)
  V2,
  /// Version three of the pact specification (`https://github.com/pact-foundation/pact-specification/tree/version-3`)
  V3,
  /// Version four of the pact specification (`https://github.com/pact-foundation/pact-specification/tree/version-4`)
  V4
}

impl Default for PactSpecification {
  fn default() -> Self {
        PactSpecification::Unknown
    }
}

impl PactSpecification {
  /// Returns the semantic version string of the specification version.
  pub fn version_str(&self) -> String {
    match *self {
        PactSpecification::V1 => "1.0.0",
        PactSpecification::V1_1 => "1.1.0",
        PactSpecification::V2 => "2.0.0",
        PactSpecification::V3 => "3.0.0",
        PactSpecification::V4 => "4.0",
        _ => "unknown"
    }.into()
  }

  /// Parse a version string into a PactSpecification
  pub fn parse_version<S: Into<String>>(input: S) -> anyhow::Result<PactSpecification> {
    let str_version = input.into();
    let version = lenient_semver::parse(str_version.as_str())
      .map_err(|_| anyhow!("Invalid specification version '{}'", str_version))?;
    match version.major {
      1 => match version.minor {
        0 => Ok(PactSpecification::V1),
        1 => Ok(PactSpecification::V1_1),
        _ => Err(anyhow!("Unsupported specification version '{}'", str_version))
      },
      2 => match version.minor {
        0 => Ok(PactSpecification::V2),
        _ => Err(anyhow!("Unsupported specification version '{}'", str_version))
      },
      3 => match version.minor {
        0 => Ok(PactSpecification::V3),
        _ => Err(anyhow!("Unsupported specification version '{}'", str_version))
      },
      4 => match version.minor {
        0 => Ok(PactSpecification::V4),
        _ => Err(anyhow!("Unsupported specification version '{}'", str_version))
      },
      _ => Err(anyhow!("Invalid specification version '{}'", str_version))
    }
  }
}

impl From<&str> for PactSpecification {
  fn from(s: &str) -> Self {
    match s.to_uppercase().as_str() {
      "V1" => PactSpecification::V1,
      "V1.1" => PactSpecification::V1_1,
      "V2" => PactSpecification::V2,
      "V3" => PactSpecification::V3,
      "V4" => PactSpecification::V4,
      _ => PactSpecification::Unknown
    }
  }
}

impl From<String> for PactSpecification {
  fn from(s: String) -> Self {
    PactSpecification::from(s.as_str())
  }
}

impl From<&String> for PactSpecification {
  fn from(s: &String) -> Self {
    PactSpecification::from(s.as_str())
  }
}

impl ToString for PactSpecification {
  fn to_string(&self) -> String {
    match *self {
      PactSpecification::V1 => "V1",
      PactSpecification::V1_1 => "V1.1",
      PactSpecification::V2 => "V2",
      PactSpecification::V3 => "V3",
      PactSpecification::V4 => "V4",
      _ => "unknown"
    }.into()
  }
}

/// Struct that defines the consumer of the pact.
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
pub struct Consumer {
  /// Each consumer should have a unique name to identify it.
  pub name: String
}

impl Consumer {
  /// Builds a `Consumer` from the `Json` struct.
  pub fn from_json(pact_json: &Value) -> Consumer {
    let val = match pact_json.get("name") {
      Some(v) => match v.clone() {
        Value::String(s) => s,
        _ => v.to_string()
      },
      None => "consumer".to_string()
    };
    Consumer { name: val.clone() }
  }

  /// Converts this `Consumer` to a `Value` struct.
  pub fn to_json(&self) -> Value {
    json!({ "name" : self.name })
  }

  /// Generate the JSON schema properties for the given Pact specification
  pub fn schema(_spec_version: PactSpecification) -> Value {
    json!({
      "properties": {
        "name": {
          "type": "string"
        }
      },
      "required": ["name"],
      "type": "object"
    })
  }
}

impl PactJsonVerifier for Consumer {
  fn verify_json(path: &str, pact_json: &Value, strict: bool, _spec_version: PactSpecification) -> Vec<PactFileVerificationResult> {
    let mut results = vec![];

    match pact_json {
      Value::Object(values) => {
        if let Some(name) = values.get("name") {
          if !name.is_string() {
            results.push(PactFileVerificationResult::new(path.to_owned() + "/name", ResultLevel::ERROR,
              format!("Must be a String, got {}", json_type_of(pact_json))))
          }
        } else {
          results.push(PactFileVerificationResult::new(path.to_owned() + "/name",
            if strict { ResultLevel::ERROR } else { ResultLevel::WARNING }, "Missing name"))
        }

        for key in values.keys() {
          if key != "name" {
            results.push(PactFileVerificationResult::new(path.to_owned(),
              if strict { ResultLevel::ERROR } else { ResultLevel::WARNING }, format!("Unknown attribute '{}'", key)))
          }
        }
      }
      _ => results.push(PactFileVerificationResult::new(path, ResultLevel::ERROR,
        format!("Must be an Object, got {}", json_type_of(pact_json))))
    }

    results
  }
}

/// Struct that defines a provider of a pact.
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq)]
pub struct Provider {
  /// Each provider should have a unique name to identify it.
  pub name: String
}

impl Provider {
  /// Builds a `Provider` from a `Value` struct.
  pub fn from_json(pact_json: &Value) -> Provider {
    let val = match pact_json.get("name") {
      Some(v) => match v.clone() {
        Value::String(s) => s,
        _ => v.to_string()
      },
      None => "provider".to_string()
    };
    Provider { name: val.clone() }
  }

  /// Converts this `Provider` to a `Value` struct.
  pub fn to_json(&self) -> Value {
    json!({ "name" : self.name })
  }

  /// Generate the JSON schema properties for the given Pact specification
  pub fn schema(_spec_version: PactSpecification) -> Value {
    json!({
      "properties": {
        "name": {
          "type": "string"
        }
      },
      "required": ["name"],
      "type": "object"
    })
  }
}

impl PactJsonVerifier for Provider {
  fn verify_json(path: &str, pact_json: &Value, strict: bool, _spec_version: PactSpecification) -> Vec<PactFileVerificationResult> {
    let mut results = vec![];

    match pact_json {
      Value::Object(values) => {
        if let Some(name) = values.get("name") {
          if !name.is_string() {
            results.push(PactFileVerificationResult::new(path.to_owned() + "/name", ResultLevel::ERROR,
                                                         format!("Must be a String, got {}", json_type_of(pact_json))))
          }
        } else {
          results.push(PactFileVerificationResult::new(path.to_owned() + "/name",
            if strict { ResultLevel::ERROR } else { ResultLevel::WARNING }, "Missing name"))
        }

        for key in values.keys() {
          if key != "name" {
            results.push(PactFileVerificationResult::new(path.to_owned(),
              if strict { ResultLevel::ERROR } else { ResultLevel::WARNING }, format!("Unknown attribute '{}'", key)))
          }
        }
      }
      _ => results.push(PactFileVerificationResult::new(path, ResultLevel::ERROR,
                                                        format!("Must be an Object, got {}", json_type_of(pact_json))))
    }

    results
  }
}

/// Enumeration of the types of differences between requests and responses
#[derive(PartialEq, Debug, Clone, Eq)]
pub enum DifferenceType {
  /// Methods differ
  Method,
  /// Paths differ
  Path,
  /// Headers differ
  Headers,
  /// Query parameters differ
  QueryParameters,
  /// Bodies differ
  Body,
  /// Matching Rules differ
  MatchingRules,
  /// Response status differ
  Status
}

/// Enum that defines the different types of HTTP statuses
#[derive(Debug, Clone, Deserialize, Serialize, Ord, PartialOrd, Eq, PartialEq)]
pub enum HttpStatus {
  /// Informational responses (100–199)
  Information,
  /// Successful responses (200–299)
  Success,
  /// Redirects (300–399)
  Redirect,
  /// Client errors (400–499)
  ClientError,
  /// Server errors (500–599)
  ServerError,
  /// Explicit status codes
  StatusCodes(Vec<u16>),
  /// Non-error response(< 400)
  NonError,
  /// Any error response (>= 400)
  Error
}

impl HttpStatus {
  /// Parse a JSON structure into a HttpStatus
  pub fn from_json(value: &Value) -> anyhow::Result<Self> {
    match value {
      Value::String(s) => match s.as_str() {
        "info" => Ok(HttpStatus::Information),
        "success" => Ok(HttpStatus::Success),
        "redirect" => Ok(HttpStatus::Redirect),
        "clientError" => Ok(HttpStatus::ClientError),
        "serverError" => Ok(HttpStatus::ServerError),
        "nonError" => Ok(HttpStatus::NonError),
        "error" => Ok(HttpStatus::Error),
        _ => Err(anyhow!("'{}' is not a valid value for an HTTP Status", s))
      },
      Value::Array(a) => {
        let status_codes = a.iter().map(|status| match status {
          Value::Number(n) => if n.is_u64() {
            Ok(n.as_u64().unwrap() as u16)
          } else if n.is_i64() {
            Ok(n.as_i64().unwrap() as u16)
          } else {
            Ok(n.as_f64().unwrap() as u16)
          },
          Value::String(s) => s.parse::<u16>().map_err(|err| anyhow!(err)),
          _ => Err(anyhow!("'{}' is not a valid JSON value for an HTTP Status", status))
        }).collect::<Vec<anyhow::Result<u16>>>();
        if status_codes.iter().any(|it| it.is_err()) {
          Err(anyhow!("'{}' is not a valid JSON value for an HTTP Status", value))
        } else {
          Ok(HttpStatus::StatusCodes(status_codes.iter().map(|code| *code.as_ref().unwrap()).collect()))
        }
      }
      _ => Err(anyhow!("'{}' is not a valid JSON value for an HTTP Status", value))
    }
  }

  /// Generate a JSON structure for this status
  pub fn to_json(&self) -> Value {
    match self {
      HttpStatus::StatusCodes(codes) => json!(codes),
      HttpStatus::Information => json!("info"),
      HttpStatus::Success => json!("success"),
      HttpStatus::Redirect => json!("redirect"),
      HttpStatus::ClientError => json!("clientError"),
      HttpStatus::ServerError => json!("serverError"),
      HttpStatus::NonError => json!("nonError"),
      HttpStatus::Error => json!("error")
    }
  }
}

impl Display for HttpStatus {
  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    match self {
      HttpStatus::Information => write!(f, "Informational response (100–199)"),
      HttpStatus::Success => write!(f, "Successful response (200–299)"),
      HttpStatus::Redirect => write!(f, "Redirect (300–399)"),
      HttpStatus::ClientError => write!(f, "Client error (400–499)"),
      HttpStatus::ServerError => write!(f, "Server error (500–599)"),
      HttpStatus::StatusCodes(status) =>
        write!(f, "{}", status.iter().map(|s| s.to_string()).join(", ")),
      HttpStatus::NonError => write!(f, "Non-error response (< 400)"),
      HttpStatus::Error => write!(f, "Error response (>= 400)")
    }
  }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>//! Checks for any invariants we expect to be true, and pages whoever is on call
//! if they are not.
//!
//! Usage:
//!     cargo run --bin monitor

#![deny(warnings)]

mod on_call;

use cargo_registry::{db, util::CargoResult};
use diesel::prelude::*;

fn main() -> CargoResult<()> {
    let conn = db::connect_now()?;

    check_stalled_background_jobs(&conn)?;
    Ok(())
}

fn check_stalled_background_jobs(conn: &PgConnection) -> CargoResult<()> {
    use cargo_registry::schema::background_jobs::dsl::*;
    use diesel::dsl::*;

    const BACKGROUND_JOB_KEY: &str = "background_jobs";

    println!("Checking for stalled background jobs");

    let max_job_time = dotenv::var("MAX_JOB_TIME")
        .map(|s| s.parse::<i32>().unwrap())
        .unwrap_or(15);

    let stalled_job_count = background_jobs
        .filter(created_at.lt(now - max_job_time.minutes()))
        .count()
        .get_result::<i64>(conn)?;

    let event = if stalled_job_count > 0 {
        on_call::Event::Trigger {
            incident_key: Some(BACKGROUND_JOB_KEY.into()),
            description: format!(
                "{} jobs have been in the queue for more than {} minutes",
                stalled_job_count, max_job_time
            ),
        }
    } else {
        on_call::Event::Resolve {
            incident_key: BACKGROUND_JOB_KEY.into(),
            description: Some("No stalled background jobs".into()),
        }
    };

    log_and_trigger_event(event)?;
    Ok(())
}

fn log_and_trigger_event(event: on_call::Event) -> CargoResult<()> {
    match event {
        on_call::Event::Trigger {
            ref description, ..
        } => println!("Paging on-call: {}", description),
        on_call::Event::Resolve {
            description: Some(ref description),
            ..
        } => println!("{}", description),
        _ => {} // noop
    }
    event.send()
}
<commit_msg>Auto merge of #1678 - sgrif:sg-monitor-spam, r=jtgeibel<commit_after>//! Checks for any invariants we expect to be true, and pages whoever is on call
//! if they are not.
//!
//! Usage:
//!     cargo run --bin monitor

#![deny(warnings)]

mod on_call;

use cargo_registry::{db, schema::*, util::CargoResult};
use diesel::prelude::*;

fn main() -> CargoResult<()> {
    let conn = db::connect_now()?;

    check_stalled_background_jobs(&conn)?;
    check_spam_attack(&conn)?;
    Ok(())
}

fn check_stalled_background_jobs(conn: &PgConnection) -> CargoResult<()> {
    use cargo_registry::schema::background_jobs::dsl::*;
    use diesel::dsl::*;

    const EVENT_KEY: &str = "background_jobs";

    println!("Checking for stalled background jobs");

    let max_job_time = dotenv::var("MAX_JOB_TIME")
        .map(|s| s.parse::<i32>().unwrap())
        .unwrap_or(15);

    let stalled_job_count = background_jobs
        .filter(created_at.lt(now - max_job_time.minutes()))
        .count()
        .get_result::<i64>(conn)?;

    let event = if stalled_job_count > 0 {
        on_call::Event::Trigger {
            incident_key: Some(EVENT_KEY.into()),
            description: format!(
                "{} jobs have been in the queue for more than {} minutes",
                stalled_job_count, max_job_time
            ),
        }
    } else {
        on_call::Event::Resolve {
            incident_key: EVENT_KEY.into(),
            description: Some("No stalled background jobs".into()),
        }
    };

    log_and_trigger_event(event)?;
    Ok(())
}

fn check_spam_attack(conn: &PgConnection) -> CargoResult<()> {
    use cargo_registry::models::krate::canon_crate_name;
    use diesel::dsl::*;
    use diesel::sql_types::Bool;

    const EVENT_KEY: &str = "spam_attack";

    println!("Checking for crates indicating someone is spamming us");

    let bad_crate_names = dotenv::var("SPAM_CRATE_NAMES");
    let bad_crate_names: Vec<_> = bad_crate_names
        .as_ref()
        .map(|s| s.split(',').collect())
        .unwrap_or_default();
    let bad_author_patterns = dotenv::var("SPAM_AUTHOR_PATTERNS");
    let bad_author_patterns: Vec<_> = bad_author_patterns
        .as_ref()
        .map(|s| s.split(',').collect())
        .unwrap_or_default();

    let mut event_description = None;

    let bad_crate = crates::table
        .filter(canon_crate_name(crates::name).eq(any(bad_crate_names)))
        .select(crates::name)
        .first::<String>(conn)
        .optional()?;

    if let Some(bad_crate) = bad_crate {
        event_description = Some(format!("Crate named {} published", bad_crate));
    }

    let mut query = version_authors::table
        .select(version_authors::name)
        .filter(false.into_sql::<Bool>()) // Never return anything if we have no patterns
        .into_boxed();
    for author_pattern in bad_author_patterns {
        query = query.or_filter(version_authors::name.like(author_pattern));
    }
    let bad_author = query.first::<String>(conn).optional()?;

    if let Some(bad_author) = bad_author {
        event_description = Some(format!("Crate with author {} published", bad_author));
    }

    let event = if let Some(event_description) = event_description {
        on_call::Event::Trigger {
            incident_key: Some(EVENT_KEY.into()),
            description: format!("{}, possible spam attack underway", event_description,),
        }
    } else {
        on_call::Event::Resolve {
            incident_key: EVENT_KEY.into(),
            description: Some("No spam crates detected".into()),
        }
    };

    log_and_trigger_event(event)?;
    Ok(())
}

fn log_and_trigger_event(event: on_call::Event) -> CargoResult<()> {
    match event {
        on_call::Event::Trigger {
            ref description, ..
        } => println!("Paging on-call: {}", description),
        on_call::Event::Resolve {
            description: Some(ref description),
            ..
        } => println!("{}", description),
        _ => {} // noop
    }
    event.send()
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::fmt;
use std::ops::{Deref, DerefMut};
use std::iter::FromIterator;

#[derive(PartialEq,Eq, Debug)]
pub enum Stone {
    Empty,
    White,
    Black,
}

impl Default for Stone {
    fn default() -> Stone {Stone::Empty}
}

impl fmt::Display for Stone {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match *self {
            Stone::Empty => ".",
            Stone::White => "O",
            Stone::Black => "X",
        })
    }
}
#[derive(Clone, Copy, Debug)]
pub struct Point {
    pub x: u32,
    pub y: u32,
}

pub struct BoardMarker {
    pub point: Point,
    pub color: Stone,
}

impl fmt::Debug for BoardMarker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result{
        write!(f, "|[{:>2},{:>2}]{:?}|", self.point.x, self.point.y, self.color)
    }
}

impl fmt::Display for BoardMarker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", match self.color {
            Stone::Empty => ".",
            Stone::White => "O",
            Stone::Black => "X",
        })
    }
}

impl Point {
    pub fn new(x:u32, y:u32) -> Point {
        Point { x: x, y:y, }
    }
    pub fn from_1d(idx: u32, width: u32) -> Point {
        Point {
            x: idx % width,
            y: idx / width,
        }
    }
    pub fn to_1d(self, width: u32) -> u32 {
        self.x + self.y * width
    }
}

#[derive(Debug)]
pub struct VecBoard(Vec<BoardMarker>);

impl VecBoard {
    fn new() -> VecBoard {
        VecBoard(Vec::new())
    }

    fn add(&mut self, elem: BoardMarker) {
        self.0.push(elem);
    }
}

impl Deref for VecBoard {
    type Target = Vec<BoardMarker>;

    fn deref(&self) -> &Vec<BoardMarker> {
        &self.0
    }
}

impl DerefMut for VecBoard {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Vec<BoardMarker> {
        &mut self.0
    }
}

#[derive(Debug)]
pub struct Board {
    pub boardsize: u32,
    pub last_move: Option<Point>,
    pub board: VecBoard,
}

impl fmt::Display for VecBoard {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure if needed - let vec: Vec<BoardMarker> = *self;
        let mut dy: u32 = 0;
        let width: u32 = self.last().clone().unwrap().point.y +1;
        for marker in self.iter() {
            if marker.point.y == dy {
                if marker.point.x != width {
                    write!(f, "{} ", marker);
                } else {
                    write!(f, "{}", marker);
                }
            } else {
                dy += 1;
                write!(f, "\n{} ", marker);
            }
        }
        write!(f, "")
    }

}

impl Board {
    pub fn new(boardsize: u32) -> Board {
        let board: VecBoard = (0..boardsize*boardsize).map(|idx| {
                BoardMarker { point: Point::from_1d(idx, boardsize), color: Stone::Empty }
            }).collect();
        Board {
            boardsize: boardsize,
            last_move: None,
            board: board,
        }
    }
    pub fn clear(&mut self) {
        self.board = (0..self.boardsize*self.boardsize).map(|idx| {
            BoardMarker { point: Point::from_1d(idx, self.boardsize), color: Stone::Empty }
        }).collect();
    }
    // FIXME: Use `Result` instead of Option
    pub fn get(&self, pos: Point) -> Option<&BoardMarker> {
        self.board.get(pos.to_1d(self.boardsize) as usize)
    }

    pub fn getxy(&self, x: u32, y: u32) -> Option<&BoardMarker> {
        self.board.get((x + y*self.boardsize) as usize)
    }
    pub fn get_mut(&mut self, pos: Point) -> Option<&mut BoardMarker> {
        self.board.get_mut(pos.to_1d(self.boardsize) as usize)
    }
    /// Set `pos` as `color`
    pub fn set(&mut self, pos: Point, color: Stone) {
        self.board[pos.to_1d(self.boardsize) as usize].color = color;
    }
}

impl FromIterator<BoardMarker> for VecBoard {
    fn from_iter<I: IntoIterator<Item=BoardMarker>>(iterator: I) -> Self {
        let mut c = VecBoard::new();

        for i in iterator {
            c.add(i);
        }
        c
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn check_if_board_works(){
        let mut board = Board::new(15);
        assert_eq!(board.board.len(), 15*15);
        let p = Point {x:0, y: 0};
        board.set(p, Stone::White);
        assert_eq!(board.get(p).unwrap().color, Stone::White);
        let p = Point {x:3, y: 2};
        board.set(p, Stone::Black);
        assert_eq!(board.get(p).unwrap().color, Stone::Black);
        // println!("{:?}", board);
        println!("test:check_if_board_works:Board\n{}", board.board);
    }

    #[test]
    fn clear_board() {
        let mut board = Board::new(15);
        let p = Point {x:7, y:7};
        board.set(p, Stone::White);
        println!("test:clear_board:Board:\n{}", board.board);
        board.clear();
        println!("test:clear_board:Board(Cleared):\n{}", board.board);
        assert_eq!(board.get(p).unwrap().color, Stone::Empty);
    }
}
<commit_msg>Linted and some major changes. (Not working!)<commit_after>#![allow(dead_code)]

use std::fmt;
use std::ops::{Deref, DerefMut};
use std::iter::FromIterator;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Stone {
    Empty,
    White,
    Black,
}

impl Default for Stone {
    fn default() -> Stone {
        Stone::Empty
    }
}

impl fmt::Display for Stone {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}",
               match *self {
                   Stone::Empty => ".",
                   Stone::White => "O",
                   Stone::Black => "X",
               })
    }
}
#[derive(Clone, Copy, Debug)]
pub struct Point {
    pub x: u32,
    pub y: u32,
}

#[derive(Copy, Clone)]
pub struct BoardMarker {
    pub point: Point,
    pub color: Stone,
}

impl fmt::Debug for BoardMarker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "|[{:>2},{:>2}]{:?}|", self.point.x, self.point.y, self.color)
    }
}

impl fmt::Display for BoardMarker {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}",
               match self.color {
                   Stone::Empty => ".",
                   Stone::White => "O",
                   Stone::Black => "X",
               })
    }
}

impl Point {
    pub fn new(x: u32, y: u32) -> Point {
        Point { x: x, y: y }
    }
    pub fn from_1d(idx: u32, width: u32) -> Point {
        Point {
            x: idx % width,
            y: idx / width,
        }
    }
    pub fn to_1d(self, width: u32) -> u32 {
        self.x + self.y * width
    }
}

pub struct BoardArr(Vec<BoardMarker>);

impl BoardArr {
    fn new() -> BoardArr {
        BoardArr(Vec::new())
    }

    fn add(&mut self, elem: BoardMarker) {
        self.0.push(elem);
    }
}

impl Deref for BoardArr {
    type Target = Vec<BoardMarker>;

    fn deref(&self) -> &Vec<BoardMarker> {
        &self.0
    }
}

impl DerefMut for BoardArr {
    fn deref_mut<'a>(&'a mut self) -> &'a mut Vec<BoardMarker> {
        &mut self.0
    }
}

#[derive(Debug, Copy, Clone)]
pub struct Board {
    pub boardsize: u32,
    pub last_move: Option<Point>,
    pub board: BoardArr,
}

impl fmt::Display for BoardArr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Not sure if needed - let vec: Vec<BoardMarker> = *self;
        let mut dy: u32 = 0;
        let width: u32 = self.last().clone().unwrap().point.y + 1;
        for marker in self.iter() {
            if marker.point.y == dy {
                if marker.point.x != width {
                    write!(f, "{} ", marker);
                } else {
                    write!(f, "{}", marker);
                }
            } else {
                dy += 1;
                write!(f, "\n{} ", marker);
            }
        }
        write!(f, "")
    }
}

impl Board {
    pub fn new(boardsize: u32) -> Board {
        let board: BoardArr = (0..boardsize * boardsize)
            .map(|idx|
                    BoardMarker { point: Point::from_1d(idx, boardsize),
                                color: Stone::Empty }
            ).collect();

        Board {
            boardsize: boardsize,
            last_move: None,
            board: board,
        }
    }
    pub fn clear(&mut self) {
        self.board = (0..self.boardsize * self.boardsize)
            .map(|idx|
                {
                     BoardMarker { point: Point::from_1d(idx, self.boardsize),  color: Stone::Empty,
                             }
                         })
                         .collect();
    }
    // FIXME: Use `Result` instead of Option
    pub fn get(&self, pos: Point) -> Option<&BoardMarker> {
        self.board.get(pos.to_1d(self.boardsize) as usize)
    }

    pub fn getxy(&self, x: u32, y: u32) -> Option<&BoardMarker> {
        self.board.get((x + y * self.boardsize) as usize)
    }
    pub fn get_mut(&mut self, pos: Point) -> Option<&mut BoardMarker> {
        self.board.get_mut(pos.to_1d(self.boardsize) as usize)
    }
    /// Set `pos` as `color`
    pub fn set(&mut self, pos: Point, color: Stone) {
        self.board[pos.to_1d(self.boardsize) as usize].color = color;
    }
}

impl FromIterator<BoardMarker> for BoardArr {
    fn from_iter<I: IntoIterator<Item = BoardMarker>>(iterator: I) -> Self {
        let mut c = BoardArr::new();

        for i in iterator {
            c.add(i);
        }
        c
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn check_if_board_works() {
        let mut board = Board::new(15);
        assert_eq!(board.board.len(), 15 * 15);
        let p = Point { x: 0, y: 0 };
        board.set(p, Stone::White);
        assert_eq!(board.get(p).unwrap().color, Stone::White);
        let p = Point { x: 3, y: 2 };
        board.set(p, Stone::Black);
        assert_eq!(board.get(p).unwrap().color, Stone::Black);
        // println!("{:?}", board);
        println!("test:check_if_board_works:Board\n{}", board.board);
    }

    #[test]
    fn clear_board() {
        let mut board = Board::new(15);
        let p = Point { x: 7, y: 7 };
        board.set(p, Stone::White);
        println!("test:clear_board:Board:\n{}", board.board);
        board.clear();
        println!("test:clear_board:Board(Cleared):\n{}", board.board);
        assert_eq!(board.get(p).unwrap().color, Stone::Empty);
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::fs::{self, File, metadata};
use std::io::{Write, Result};

use book::bookconfig::BookConfig;
use book::bookitem::BookItem;
use parse;

pub struct MDBook {
    title: String,
    author: String,
    config: BookConfig,
    pub content: Vec<BookItem>
}

impl MDBook {

    pub fn new(path: &PathBuf) -> Self {

        // Hacky way to check if the path exists... Until PathExt moves to stable
        match metadata(path) {
            Err(_) => panic!("Directory does not exist"),
            Ok(f) => {
                if !f.is_dir() {
                    panic!("Is not a directory");
                }
            }
        }

        MDBook {
            title: String::from(""),
            author: String::from(""),
            content: vec![],
            config: BookConfig::new()
                        .set_src(path.join("src"))
                        .set_dest(path.join("book")),
        }
    }

    pub fn init(&self) -> Result<()> {

        let dest = self.config.dest();
        let src = self.config.src();

        // Hacky way to check if the directory exists... Until PathExt moves to stable
        match metadata(&dest) {
            Err(_) => {
                // There is a very high chance that the error is due to the fact that
                // the directory / file does not exist
                fs::create_dir(&dest).unwrap();
            },
            Ok(_) => { /* If there is no error, the directory / file does exist */ }
        }

        // Hacky way to check if the directory exists... Until PathExt moves to stable
        match metadata(&src) {
            Err(_) => {
                // There is a very high chance that the error is due to the fact that
                // the directory / file does not exist
                fs::create_dir(&src).unwrap();
            },
            Ok(_) => { /* If there is no error, the directory / file does exist */ }
        }

        // Hacky way to check if the directory exists... Until PathExt moves to stable
        let summary = match metadata(&src.join("SUMMARY.md")) {
            Err(_) => {
                // There is a very high chance that the error is due to the fact that
                // the directory / file does not exist
                Ok(File::create(&src.join("SUMMARY.md")).unwrap())
            },
            Ok(_) => {
                /* If there is no error, the directory / file does exist */
                Err("SUMMARY.md does already exist")
            }
        };

        if let Ok(mut f) = summary {
            try!(writeln!(f, "# Summary"));
            try!(writeln!(f, ""));
            try!(writeln!(f, "[Chapter 1](./chapter_1.md)"));

            let mut chapter_1 = File::create(&src.join("chapter_1.md")).unwrap();
            try!(writeln!(chapter_1, "# Chapter 1"));
        }

        return Ok(());
    }

    pub fn build(&mut self) -> Result<()> {

        try!(self.parse_summary());

        Ok(())
    }

    // Builder functions
    pub fn set_dest(mut self, dest: PathBuf) -> Self {
        self.config = self.config.set_dest(dest);
        self
    }

    pub fn set_src(mut self, src: PathBuf) -> Self {
        self.config = self.config.set_src(src);
        self
    }

    pub fn set_title(mut self, title: String) -> Self {
        self.title = title;
        self
    }

    pub fn set_author(mut self, author: String) -> Self {
        self.author = author;
        self
    }

    // Construct book
    fn parse_summary(&mut self) -> Result<()> {

        // When append becomes stale, use self.content.append() ...
        let book_items = try!(parse::construct_bookitems(&self.config.src().join("SUMMARY.md")));

        for item in book_items {
            self.content.push(item)
        }

        // Debug
        for item in &self.content {
            println!("name: \"{}\" path: {:?}", item.name, item.path);
        }

        Ok(())
    }

}
<commit_msg>fix error in init(): write "- [chapter 1](...)" to SUMMARY.md instead of "[chapter 1](...)" note the lack of dash at the beginning<commit_after>use std::path::PathBuf;
use std::fs::{self, File, metadata};
use std::io::{Write, Result};

use book::bookconfig::BookConfig;
use book::bookitem::BookItem;
use parse;

pub struct MDBook {
    title: String,
    author: String,
    config: BookConfig,
    pub content: Vec<BookItem>
}

impl MDBook {

    pub fn new(path: &PathBuf) -> Self {

        // Hacky way to check if the path exists... Until PathExt moves to stable
        match metadata(path) {
            Err(_) => panic!("Directory does not exist"),
            Ok(f) => {
                if !f.is_dir() {
                    panic!("Is not a directory");
                }
            }
        }

        MDBook {
            title: String::from(""),
            author: String::from(""),
            content: vec![],
            config: BookConfig::new()
                        .set_src(path.join("src"))
                        .set_dest(path.join("book")),
        }
    }

    pub fn init(&self) -> Result<()> {

        let dest = self.config.dest();
        let src = self.config.src();

        // Hacky way to check if the directory exists... Until PathExt moves to stable
        match metadata(&dest) {
            Err(_) => {
                // There is a very high chance that the error is due to the fact that
                // the directory / file does not exist
                fs::create_dir(&dest).unwrap();
            },
            Ok(_) => { /* If there is no error, the directory / file does exist */ }
        }

        // Hacky way to check if the directory exists... Until PathExt moves to stable
        match metadata(&src) {
            Err(_) => {
                // There is a very high chance that the error is due to the fact that
                // the directory / file does not exist
                fs::create_dir(&src).unwrap();
            },
            Ok(_) => { /* If there is no error, the directory / file does exist */ }
        }

        // Hacky way to check if the directory exists... Until PathExt moves to stable
        let summary = match metadata(&src.join("SUMMARY.md")) {
            Err(_) => {
                // There is a very high chance that the error is due to the fact that
                // the directory / file does not exist
                Ok(File::create(&src.join("SUMMARY.md")).unwrap())
            },
            Ok(_) => {
                /* If there is no error, the directory / file does exist */
                Err("SUMMARY.md does already exist")
            }
        };

        if let Ok(mut f) = summary {
            try!(writeln!(f, "# Summary"));
            try!(writeln!(f, ""));
            try!(writeln!(f, "- [Chapter 1](./chapter_1.md)"));

            let mut chapter_1 = File::create(&src.join("chapter_1.md")).unwrap();
            try!(writeln!(chapter_1, "# Chapter 1"));
        }

        return Ok(());
    }

    pub fn build(&mut self) -> Result<()> {

        try!(self.parse_summary());

        Ok(())
    }

    // Builder functions
    pub fn set_dest(mut self, dest: PathBuf) -> Self {
        self.config = self.config.set_dest(dest);
        self
    }

    pub fn set_src(mut self, src: PathBuf) -> Self {
        self.config = self.config.set_src(src);
        self
    }

    pub fn set_title(mut self, title: String) -> Self {
        self.title = title;
        self
    }

    pub fn set_author(mut self, author: String) -> Self {
        self.author = author;
        self
    }

    // Construct book
    fn parse_summary(&mut self) -> Result<()> {

        // When append becomes stale, use self.content.append() ...
        let book_items = try!(parse::construct_bookitems(&self.config.src().join("SUMMARY.md")));

        for item in book_items {
            self.content.push(item)
        }

        // Debug
        for item in &self.content {
            println!("name: \"{}\" path: {:?}", item.name, item.path);
        }

        Ok(())
    }

}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.

//! Bstream module.
//! This is a blocking stream designed to block on read/write until

use std::result::Result;
use std::net::{TcpStream, Shutdown};
use std::io::{Read, Write, Error};

use super::readbuffer::ReadBuffer;

/// Represents the result of attempting a read on the underlying file descriptor
pub type ReadResult = Result<Vec<u8>, Error>;

/// Represents the result attempting a write on the underlying fild descriptor
pub type WriteResult = Result<(), Error>;

/// States the current stream can be in
#[derive(PartialEq, Clone)]
enum ReadState {
    /// Currently reading the payload length
    PayloadLen,
    /// Currently reading the payload
    Payload
}

pub struct Bstream {
    /// Current state
    state: ReadState,
    /// Underlying std::net::TcpStream
    stream: TcpStream,
    /// Message buffer
    buffer: ReadBuffer
}

impl Bstream {

    /// Returns a new Bstream
    pub fn new(stream: TcpStream) -> Bstream {
        Bstream {
            state: ReadState::PayloadLen,
            stream: stream,
            buffer: ReadBuffer::new()
        }
    }

    /// Performs a blocking read and returns when a complete message
    /// has been returned, or an error has occured
    pub fn read(&mut self) -> ReadResult {
        loop {
            // Create a buffer for this specific read iteration
            let count = self.buffer.remaining();
            let mut buffer = Vec::<u8>::with_capacity(count as usize);
            unsafe { buffer.set_len(count as usize); }

            let result = self.stream.read(&mut buffer[..]);
            if result.is_err() {
                return Err(result.unwrap_err());
            }

            let num_read = result.unwrap();
            for x in 0..num_read {
                self.buffer.push(buffer[x]);
            }

            if self.buffer.remaining() == 0 {
                if self.state == ReadState::PayloadLen {
                    self.buffer.calc_payload_len();
                    let p_len = self.buffer.payload_len();
                    self.buffer.set_capacity(p_len);
                    self.state = ReadState::Payload;
                } else { // Payload completely read
                    self.buffer.reset();
                    self.state = ReadState::PayloadLen;
                    break;
                }
            }
        }
        let mut buffer = self.buffer.drain_queue();

        // This should always be .len() of 1
        // if it isn't - we're doing some bad stuff in here
        if buffer.len() != 1 {
            panic!("Error - Bstream.read() - Internal buffer was not equal to one...?")
        }

        match buffer.pop() {
            Some(buf) => Ok(buf),
            None => unimplemented!()
        }
    }

    /// Performs a blocking write operation and returns the complete buffer has
    /// been written, or an error has occured
    pub fn write(&mut self, buffer: &Vec<u8>) -> WriteResult {
        let mut plen_buf = [0u8; 2];
        let plen = buffer.len() as u16;
        plen_buf[0] = (plen >> 8) as u8;
        plen_buf[1] = plen as u8;

        let mut n_buffer = Vec::<u8>::with_capacity(buffer.len() + 2);
        n_buffer.push(plen_buf[0]);
        n_buffer.push(plen_buf[1]);

        for x in 0..buffer.len() {
            n_buffer.push(buffer[x]);
        }

        match self.stream.write_all(&n_buffer[..]) {
            Ok(()) => {
                let _ = self.stream.flush();
                Ok(())
            }
            Err(e) => Err(e)
        }
    }

    /// Shuts down the connection
    pub fn shutdown(&self) {
        let result = self.stream.shutdown(Shutdown::Both);
        if result.is_err() {
            panic!("Error shutting down stream: {}", result.unwrap_err())
        }
    }
}

impl Clone for Bstream {
    fn clone(&self) -> Bstream {
        Bstream {
            state: self.state.clone(),
            stream: self.stream.try_clone().unwrap(),
            buffer: self.buffer.clone()
        }
    }
}
<commit_msg>Going to work commit<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.

//! Bstream module.
//! This is a blocking stream designed to block on read/write until

use std::result::Result;
use std::net::{TcpStream, Shutdown};
use std::io::{Read, Write, Error};

use super::readbuffer::ReadBuffer;

/// Represents the result of attempting a read on the underlying file descriptor
pub type ReadResult = Result<Vec<u8>, Error>;

/// Represents the result attempting a write on the underlying fild descriptor
pub type WriteResult = Result<(), Error>;

/// States the current stream can be in
#[derive(PartialEq, Clone)]
enum ReadState {
    Start,
    /// Currently reading the payload length
    PayloadLen,
    /// Currently reading the payload
    Payload,
    End
}

pub struct Bstream {
    /// Current state
    state: ReadState,
    /// Underlying std::net::TcpStream
    stream: TcpStream,
    /// Message buffer
    buffer: ReadBuffer
}

impl Bstream {

    /// Returns a new Bstream
    pub fn new(stream: TcpStream) -> Bstream {
        Bstream {
            state: ReadState::PayloadLen,
            stream: stream,
            buffer: ReadBuffer::new()
        }
    }

    /// Performs a blocking read and returns when a complete message
    /// has been returned, or an error has occured
    pub fn read(&mut self) -> ReadResult {
        loop {
            // Create a buffer for this specific read iteration
            let count = self.buffer.remaining();
            let mut buffer = Vec::<u8>::with_capacity(count as usize);
            unsafe { buffer.set_len(count as usize); }

            let result = self.stream.read(&mut buffer[..]);
            if result.is_err() {
                return Err(result.unwrap_err());
            }

            let num_read = result.unwrap();
            for x in 0..num_read {
                self.buffer.push(buffer[x]);
            }

            if self.buffer.remaining() == 0 {
                if self.state == ReadState::Start {

                } else if self.state == ReadState::PayloadLen {
                    self.buffer.calc_payload_len();
                    let p_len = self.buffer.payload_len();
                    self.buffer.set_capacity(p_len);
                    self.state = ReadState::Payload;
                } else if self.state == ReadState::Payload { // Payload completely read

                } else if self.state == ReadState::End {
                    self.buffer.reset();
                    self.state = ReadState::PayloadLen;
                    break;
                }
            }
        }
        let mut buffer = self.buffer.drain_queue();

        // This should always be .len() of 1
        // if it isn't - we're doing some bad stuff in here
        if buffer.len() != 1 {
            panic!("Error - Bstream.read() - Internal buffer was not equal to one...?")
        }

        match buffer.pop() {
            Some(buf) => Ok(buf),
            None => unimplemented!()
        }
    }

    /// Performs a blocking write operation and returns the complete buffer has
    /// been written, or an error has occured
    pub fn write(&mut self, buffer: &Vec<u8>) -> WriteResult {
        let mut plen_buf = [0u8; 2];
        let plen = buffer.len() as u16;
        plen_buf[0] = (plen >> 8) as u8;
        plen_buf[1] = plen as u8;

        let mut n_buffer = Vec::<u8>::with_capacity(buffer.len() + 4);
        n_buffer.push(0x01);
        n_buffer.push(plen_buf[0]);
        n_buffer.push(plen_buf[1]);
        for x in 0..buffer.len() {
            n_buffer.push(buffer[x]);
        }
        n_buffer.push(0x17);

        match self.stream.write_all(&n_buffer[..]) {
            Ok(()) => {
                let _ = self.stream.flush();
                Ok(())
            }
            Err(e) => Err(e)
        }
    }

    /// Shuts down the connection
    pub fn shutdown(&self) {
        let result = self.stream.shutdown(Shutdown::Both);
        if result.is_err() {
            panic!("Error shutting down stream: {}", result.unwrap_err())
        }
    }
}

impl Clone for Bstream {
    fn clone(&self) -> Bstream {
        Bstream {
            state: self.state.clone(),
            stream: self.stream.try_clone().unwrap(),
            buffer: self.buffer.clone()
        }
    }
}
<|endoftext|>


<commit_before>extern crate bitstreams;

use bitstreams::Bit;

#[test]
fn basic_integration_test()
{
    let x = Bit::Zero;
    let y = Bit::One;

    assert_eq!(x & y, Bit::Zero);
}
<commit_msg>Fixed small bug when renaming the project.<commit_after>extern crate bears_bits_battlestar_galactica;

use bears_bits_battlestar_galactica::Bit;

#[test]
fn basic_integration_test()
{
    let x = Bit::Zero;
    let y = Bit::One;

    assert_eq!(x & y, Bit::Zero);
}
<|endoftext|>


<commit_before>// ToDO: add tests
<commit_msg>kill: add integration tests<commit_after>use crate::common::util::*;
use regex::Regex;
use std::os::unix::process::ExitStatusExt;
use std::process::{Child, Command};

// A child process the tests will try to kill.
struct Target {
    child: Child,
    killed: bool,
}

impl Target {
    // Creates a target that will naturally die after some time if not killed
    // fast enough.
    // This timeout avoids hanging failing tests.
    fn new() -> Target {
        Target {
            child: Command::new("sleep")
                .arg("30")
                .spawn()
                .expect("cannot spawn target"),
            killed: false,
        }
    }

    // Waits for the target to complete and returns the signal it received if any.
    fn wait_for_signal(&mut self) -> Option<i32> {
        let sig = self.child.wait().expect("cannot wait on target").signal();
        self.killed = true;
        sig
    }

    fn pid(&self) -> u32 {
        self.child.id()
    }
}

impl Drop for Target {
    // Terminates this target to avoid littering test boxes with zombi processes
    // when a test fails after creating a target but before killing it.
    fn drop(&mut self) {
        if !self.killed {
            self.child.kill().expect("cannot kill target");
        }
    }
}

#[test]
fn test_kill_list_all_signals() {
    // Check for a few signals.  Do not try to be comprehensive.
    new_ucmd!()
        .arg("-l")
        .succeeds()
        .stdout_contains("KILL")
        .stdout_contains("TERM")
        .stdout_contains("HUP");
}

#[test]
fn test_kill_list_all_signals_as_table() {
    // Check for a few signals.  Do not try to be comprehensive.
    new_ucmd!()
        .arg("-t")
        .succeeds()
        .stdout_contains("KILL")
        .stdout_contains("TERM")
        .stdout_contains("HUP");
}

#[test]
fn test_kill_list_one_signal_from_name() {
    // Use SIGKILL because it is 9 on all unixes.
    new_ucmd!()
        .arg("-l")
        .arg("KILL")
        .succeeds()
        .stdout_matches(&Regex::new("\\b9\\b").unwrap());
}

#[test]
fn test_kill_set_bad_signal_name() {
    new_ucmd!()
        .arg("-s")
        .arg("IAMNOTASIGNAL")
        .fails()
        .stderr_contains("unknown signal");
}

#[test]
fn test_kill_with_default_signal() {
    let mut target = Target::new();
    new_ucmd!().arg(format!("{}", target.pid())).succeeds();
    assert_eq!(target.wait_for_signal(), Some(libc::SIGTERM));
}

#[test]
fn test_kill_with_signal_number_old_form() {
    let mut target = Target::new();
    new_ucmd!()
        .arg("-9")
        .arg(format!("{}", target.pid()))
        .succeeds();
    assert_eq!(target.wait_for_signal(), Some(9));
}

#[test]
fn test_kill_with_signal_number_new_form() {
    let mut target = Target::new();
    new_ucmd!()
        .arg("-s")
        .arg("9")
        .arg(format!("{}", target.pid()))
        .succeeds();
    assert_eq!(target.wait_for_signal(), Some(9));
}

#[test]
fn test_kill_with_signal_name_new_form() {
    let mut target = Target::new();
    new_ucmd!()
        .arg("-s")
        .arg("KILL")
        .arg(format!("{}", target.pid()))
        .succeeds();
    assert_eq!(target.wait_for_signal(), Some(libc::SIGKILL));
}
<|endoftext|>


<commit_before>use handlebars::*;
use serde_json::json;

fn dump<'reg, 'rc>(
    h: &Helper<'reg, 'rc>,
    _: &'reg Handlebars,
    _: &Context,
    _: &mut RenderContext,
    out: &mut dyn Output,
) -> Result<(), RenderError> {
    assert_eq!(1, h.params().len());

    let data = h.param(0).unwrap().value().render();
    out.write(&data)?;
    Ok(())
}

#[test]
fn test_helper_with_space_param() {
    let mut r = Handlebars::new();
    r.register_helper("echo", Box::new(dump));

    let s = r
        .render_template("Output: {{echo \"Mozilla Firefox\"}}", &json!({}))
        .unwrap();
    assert_eq!(s, "Output: Mozilla Firefox".to_owned());
}
<commit_msg>(test) add more assertion for #328<commit_after>use handlebars::*;
use serde_json::json;

fn dump<'reg, 'rc>(
    h: &Helper<'reg, 'rc>,
    _: &'reg Handlebars,
    _: &Context,
    _: &mut RenderContext,
    out: &mut dyn Output,
) -> Result<(), RenderError> {
    assert_eq!(2, h.params().len());

    let result = h
        .params()
        .iter()
        .map(|p| p.value().render())
        .collect::<Vec<String>>()
        .join(", ");
    out.write(&result)?;

    Ok(())
}

#[test]
fn test_helper_with_space_param() {
    let mut r = Handlebars::new();
    r.register_helper("echo", Box::new(dump));

    let s = r
        .render_template(
            "Output: {{echo \"Mozilla Firefox\" \"Google Chrome\"}}",
            &json!({}),
        )
        .unwrap();
    assert_eq!(s, "Output: Mozilla Firefox, Google Chrome".to_owned());
}
<|endoftext|>