<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

#![doc(html_logo_url = "https://raw.githubusercontent.com/vulkano-rs/vulkano/master/logo.png")]
//! Safe and rich Rust wrapper around the Vulkan API.
//!
//! # Brief summary of Vulkan
//!
//! - The [`VulkanLibrary`](crate::VulkanLibrary) represents a Vulkan library on the system.
//!   It must be loaded before you can do anything with Vulkan.
//!
//! - The [`Instance`](crate::instance::Instance) object is the API entry point, and represents
//!   an initialised Vulkan library. This is the first Vulkan object that you create.
//!
//! - The [`PhysicalDevice`](crate::device::physical::PhysicalDevice) object represents a
//!   Vulkan-capable device that is available on the system (eg. a graphics card, a software
//!   implementation, etc.). Physical devices can be enumerated from an instance with
//!   [`PhysicalDevice::enumerate`](crate::device::physical::PhysicalDevice::enumerate).
//!
//! - Once you have chosen a physical device to use, you can create a
//!   [`Device`](crate::device::Device) object from it. The `Device` is the most important
//!   object of Vulkan, as it represents an open channel of communication with a physical device.
//!   You always need to have one before you can do interesting things with Vulkan.
//!
//! - [*Buffers*](crate::buffer) and [*images*](crate::image) can be used to store data on
//!   memory accessible by the GPU (or more generally by the Vulkan implementation). Buffers are
//!   usually used to store information about vertices, lights, etc. or arbitrary data, while
//!   images are used to store textures or multi-dimensional data.
//!
//! - In order to show something on the screen, you need a
//!   [`Surface` and a `Swapchain`](crate::swapchain).
//!   A `Swapchain` contains special `Image`s that correspond to the content of the window or the
//!   monitor. When you *present* a swapchain, the content of one of these special images is shown
//!   on the screen.
//!
//! - For graphical operations, [`RenderPass`es and `Framebuffer`s](crate::render_pass)
//!   describe which images the device must draw upon.
//!
//! - In order to be able to perform operations on the device, you need to have created a
//!   [pipeline object](crate::pipeline) that describes the operation you want. These objects are usually
//!   created during your program's initialization. `Shader`s are programs that the GPU will
//!   execute as part of a pipeline. [*Descriptor sets*](crate::descriptor_set) can be used to access
//!   the content of buffers or images from within shaders.
//!
//! - To tell the GPU to do something, you must create a
//!   [*command buffer*](crate::command_buffer). A command buffer contains a list of commands
//!   that the GPU must perform. This can include copies between buffers and images, compute
//!   operations, or graphics operations. For the work to start, the command buffer must then be
//!   submitted to a [`Queue`](crate::device::Queue), which is obtained when you create the
//!   `Device`.
//!
//! - Once you have built a *command buffer* that contains a list of commands, submitting it to the
//!   GPU will return an object that implements [the `GpuFuture` trait](crate::sync::GpuFuture).
//!   `GpuFuture`s allow you to chain multiple submissions together and are essential to performing
//!   multiple operations on multiple different GPU queues.
//!

//#![warn(missing_docs)]        // TODO: activate

// These lints are a bit too pedantic, so they're disabled here.
#![allow(
    clippy::collapsible_else_if,
    clippy::collapsible_if,
    clippy::large_enum_variant,
    clippy::len_without_is_empty,
    clippy::missing_safety_doc, // TODO: remove
    clippy::module_inception,
    clippy::mutable_key_type,
    clippy::new_without_default,
    clippy::nonminimal_bool,
    clippy::op_ref, // Seems to be bugged, the fixed code triggers a compile error
    clippy::too_many_arguments,
    clippy::type_complexity,
    clippy::vec_box,
    clippy::wrong_self_convention
)]

pub use ash::vk::Handle;
pub use half;
pub use library::VulkanLibrary;
use parking_lot::MutexGuard;
use std::{error::Error, fmt, ops::Deref, sync::Arc};
pub use version::Version;

#[macro_use]
mod tests;
#[macro_use]
mod extensions;
pub mod buffer;
pub mod command_buffer;
pub mod descriptor_set;
pub mod device;
pub mod format;
mod version;
#[macro_use]
pub mod render_pass;
mod fns;
pub mod image;
pub mod instance;
pub mod library;
pub mod memory;
pub mod pipeline;
pub mod query;
mod range_map;
pub mod range_set;
pub mod sampler;
pub mod shader;
pub mod swapchain;
pub mod sync;

/// Represents memory size and offset values on a Vulkan device.
/// Analogous to the Rust `usize` type on the host.
pub use ash::vk::DeviceSize;

/// Alternative to the `Deref` trait. Contrary to `Deref`, must always return the same object.
pub unsafe trait SafeDeref: Deref {}
unsafe impl<'a, T: ?Sized> SafeDeref for &'a T {}
unsafe impl<T: ?Sized> SafeDeref for Arc<T> {}
unsafe impl<T: ?Sized> SafeDeref for Box<T> {}

/// Gives access to the internal identifier of an object.
pub unsafe trait VulkanObject {
    /// The type of the object.
    type Object: ash::vk::Handle;

    /// Returns a reference to the object.
    fn internal_object(&self) -> Self::Object;
}

/// Gives access to the internal identifier of an object.
// TODO: remove ; crappy design
pub unsafe trait SynchronizedVulkanObject {
    /// The type of the object.
    type Object: ash::vk::Handle;

    /// Returns a reference to the object.
    fn internal_object_guard(&self) -> MutexGuard<Self::Object>;
}

/// Error type returned by most Vulkan functions.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OomError {
    /// There is no memory available on the host (ie. the CPU, RAM, etc.).
    OutOfHostMemory,
    /// There is no memory available on the device (ie. video memory).
    OutOfDeviceMemory,
}

impl Error for OomError {}

impl fmt::Display for OomError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(
            fmt,
            "{}",
            match *self {
                OomError::OutOfHostMemory => "no memory available on the host",
                OomError::OutOfDeviceMemory => "no memory available on the graphical device",
            }
        )
    }
}

impl From<VulkanError> for OomError {
    #[inline]
    fn from(err: VulkanError) -> OomError {
        match err {
            VulkanError::OutOfHostMemory => OomError::OutOfHostMemory,
            VulkanError::OutOfDeviceMemory => OomError::OutOfDeviceMemory,
            _ => panic!("unexpected error: {:?}", err),
        }
    }
}

// Generated by build.rs
include!(concat!(env!("OUT_DIR"), "/errors.rs"));

impl Error for VulkanError {}

impl fmt::Display for VulkanError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            VulkanError::OutOfHostMemory => write!(
                f,
                "A host memory allocation has failed.",
            ),
            VulkanError::OutOfDeviceMemory => write!(
                f,
                "A device memory allocation has failed.",
            ),
            VulkanError::InitializationFailed => write!(
                f,
                "Initialization of an object could not be completed for implementation-specific reasons.",
            ),
            VulkanError::DeviceLost => write!(
                f,
                "The logical or physical device has been lost.",
            ),
            VulkanError::MemoryMapFailed => write!(
                f,
                "Mapping of a memory object has failed.",
            ),
            VulkanError::LayerNotPresent => write!(
                f,
                "A requested layer is not present or could not be loaded.",
            ),
            VulkanError::ExtensionNotPresent => write!(
                f,
                "A requested extension is not supported.",
            ),
            VulkanError::FeatureNotPresent => write!(
                f,
                "A requested feature is not supported.",
            ),
            VulkanError::IncompatibleDriver => write!(
                f,
                "The requested version of Vulkan is not supported by the driver or is otherwise incompatible for implementation-specific reasons.",
            ),
            VulkanError::TooManyObjects => write!(
                f,
                "Too many objects of the type have already been created.",
            ),
            VulkanError::FormatNotSupported => write!(
                f,
                "A requested format is not supported on this device.",
            ),
            VulkanError::FragmentedPool => write!(
                f,
                "A pool allocation has failed due to fragmentation of the pool's memory.",
            ),
            VulkanError::Unknown => write!(
                f,
                "An unknown error has occurred; either the application has provided invalid input, or an implementation failure has occurred.",
            ),
            VulkanError::OutOfPoolMemory => write!(
                f,
                "A pool memory allocation has failed.",
            ),
            VulkanError::InvalidExternalHandle => write!(
                f,
                "An external handle is not a valid handle of the specified type.",
            ),
            VulkanError::Fragmentation => write!(
                f,
                "A descriptor pool creation has failed due to fragmentation.",
            ),
            VulkanError::InvalidOpaqueCaptureAddress => write!(
                f,
                "A buffer creation or memory allocation failed because the requested address is not available. A shader group handle assignment failed because the requested shader group handle information is no longer valid.",
            ),
            VulkanError::IncompatibleDisplay => write!(
                f,
                "The display used by a swapchain does not use the same presentable image layout, or is incompatible in a way that prevents sharing an image.",
            ),
            VulkanError::NotPermitted => write!(
                f,
                "A requested operation was not permitted.",
            ),
            VulkanError::SurfaceLost => write!(
                f,
                "A surface is no longer available.",
            ),
            VulkanError::NativeWindowInUse => write!(
                f,
                "The requested window is already in use by Vulkan or another API in a manner which prevents it from being used again.",
            ),
            VulkanError::OutOfDate => write!(
                f,
                "A surface has changed in such a way that it is no longer compatible with the swapchain, and further presentation requests using the swapchain will fail.",
            ),
            VulkanError::ValidationFailed => write!(
                f,
                "Validation failed.",
            ),
            VulkanError::FullScreenExclusiveModeLost => write!(
                f,
                "An operation on a swapchain created with application controlled full-screen access failed as it did not have exclusive full-screen access.",
            ),
            VulkanError::InvalidDrmFormatModifierPlaneLayout => write!(
                f,
                "The requested DRM format modifier plane layout is invalid.",
            ),
            VulkanError::InvalidShader => write!(
                f,
                "One or more shaders failed to compile or link.",
            ),
            VulkanError::Unnamed(result) => write!(
                f,
                "Unnamed error, VkResult value {}",
                result.as_raw(),
            ),
        }
    }
}

/// A helper type for non-exhaustive structs.
///
/// This type cannot be constructed outside Vulkano. Structures with a field of this type can only
/// be constructed by calling a constructor function or `Default::default()`. The effect is similar
/// to the standard Rust `#[non_exhaustive]` attribute, except that it does not prevent update
/// syntax from being used.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] // add traits as needed
pub struct NonExhaustive(pub(crate) ());
<commit_msg>vulkano: export LoadingError (#1961)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

#![doc(html_logo_url = "https://raw.githubusercontent.com/vulkano-rs/vulkano/master/logo.png")]
//! Safe and rich Rust wrapper around the Vulkan API.
//!
//! # Brief summary of Vulkan
//!
//! - The [`VulkanLibrary`](crate::VulkanLibrary) represents a Vulkan library on the system.
//!   It must be loaded before you can do anything with Vulkan.
//!
//! - The [`Instance`](crate::instance::Instance) object is the API entry point, and represents
//!   an initialised Vulkan library. This is the first Vulkan object that you create.
//!
//! - The [`PhysicalDevice`](crate::device::physical::PhysicalDevice) object represents a
//!   Vulkan-capable device that is available on the system (eg. a graphics card, a software
//!   implementation, etc.). Physical devices can be enumerated from an instance with
//!   [`PhysicalDevice::enumerate`](crate::device::physical::PhysicalDevice::enumerate).
//!
//! - Once you have chosen a physical device to use, you can create a
//!   [`Device`](crate::device::Device) object from it. The `Device` is the most important
//!   object of Vulkan, as it represents an open channel of communication with a physical device.
//!   You always need to have one before you can do interesting things with Vulkan.
//!
//! - [*Buffers*](crate::buffer) and [*images*](crate::image) can be used to store data on
//!   memory accessible by the GPU (or more generally by the Vulkan implementation). Buffers are
//!   usually used to store information about vertices, lights, etc. or arbitrary data, while
//!   images are used to store textures or multi-dimensional data.
//!
//! - In order to show something on the screen, you need a
//!   [`Surface` and a `Swapchain`](crate::swapchain).
//!   A `Swapchain` contains special `Image`s that correspond to the content of the window or the
//!   monitor. When you *present* a swapchain, the content of one of these special images is shown
//!   on the screen.
//!
//! - For graphical operations, [`RenderPass`es and `Framebuffer`s](crate::render_pass)
//!   describe which images the device must draw upon.
//!
//! - In order to be able to perform operations on the device, you need to have created a
//!   [pipeline object](crate::pipeline) that describes the operation you want. These objects are usually
//!   created during your program's initialization. `Shader`s are programs that the GPU will
//!   execute as part of a pipeline. [*Descriptor sets*](crate::descriptor_set) can be used to access
//!   the content of buffers or images from within shaders.
//!
//! - To tell the GPU to do something, you must create a
//!   [*command buffer*](crate::command_buffer). A command buffer contains a list of commands
//!   that the GPU must perform. This can include copies between buffers and images, compute
//!   operations, or graphics operations. For the work to start, the command buffer must then be
//!   submitted to a [`Queue`](crate::device::Queue), which is obtained when you create the
//!   `Device`.
//!
//! - Once you have built a *command buffer* that contains a list of commands, submitting it to the
//!   GPU will return an object that implements [the `GpuFuture` trait](crate::sync::GpuFuture).
//!   `GpuFuture`s allow you to chain multiple submissions together and are essential to performing
//!   multiple operations on multiple different GPU queues.
//!

//#![warn(missing_docs)]        // TODO: activate

// These lints are a bit too pedantic, so they're disabled here.
#![allow(
    clippy::collapsible_else_if,
    clippy::collapsible_if,
    clippy::large_enum_variant,
    clippy::len_without_is_empty,
    clippy::missing_safety_doc, // TODO: remove
    clippy::module_inception,
    clippy::mutable_key_type,
    clippy::new_without_default,
    clippy::nonminimal_bool,
    clippy::op_ref, // Seems to be bugged, the fixed code triggers a compile error
    clippy::too_many_arguments,
    clippy::type_complexity,
    clippy::vec_box,
    clippy::wrong_self_convention
)]

pub use ash::vk::Handle;
pub use half;
pub use library::{LoadingError, VulkanLibrary};
use parking_lot::MutexGuard;
use std::{error::Error, fmt, ops::Deref, sync::Arc};
pub use version::Version;

#[macro_use]
mod tests;
#[macro_use]
mod extensions;
pub mod buffer;
pub mod command_buffer;
pub mod descriptor_set;
pub mod device;
pub mod format;
mod version;
#[macro_use]
pub mod render_pass;
mod fns;
pub mod image;
pub mod instance;
pub mod library;
pub mod memory;
pub mod pipeline;
pub mod query;
mod range_map;
pub mod range_set;
pub mod sampler;
pub mod shader;
pub mod swapchain;
pub mod sync;

/// Represents memory size and offset values on a Vulkan device.
/// Analogous to the Rust `usize` type on the host.
pub use ash::vk::DeviceSize;

/// Alternative to the `Deref` trait. Contrary to `Deref`, must always return the same object.
pub unsafe trait SafeDeref: Deref {}
unsafe impl<'a, T: ?Sized> SafeDeref for &'a T {}
unsafe impl<T: ?Sized> SafeDeref for Arc<T> {}
unsafe impl<T: ?Sized> SafeDeref for Box<T> {}

/// Gives access to the internal identifier of an object.
pub unsafe trait VulkanObject {
    /// The type of the object.
    type Object: ash::vk::Handle;

    /// Returns a reference to the object.
    fn internal_object(&self) -> Self::Object;
}

/// Gives access to the internal identifier of an object.
// TODO: remove ; crappy design
pub unsafe trait SynchronizedVulkanObject {
    /// The type of the object.
    type Object: ash::vk::Handle;

    /// Returns a reference to the object.
    fn internal_object_guard(&self) -> MutexGuard<Self::Object>;
}

/// Error type returned by most Vulkan functions.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OomError {
    /// There is no memory available on the host (ie. the CPU, RAM, etc.).
    OutOfHostMemory,
    /// There is no memory available on the device (ie. video memory).
    OutOfDeviceMemory,
}

impl Error for OomError {}

impl fmt::Display for OomError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(
            fmt,
            "{}",
            match *self {
                OomError::OutOfHostMemory => "no memory available on the host",
                OomError::OutOfDeviceMemory => "no memory available on the graphical device",
            }
        )
    }
}

impl From<VulkanError> for OomError {
    #[inline]
    fn from(err: VulkanError) -> OomError {
        match err {
            VulkanError::OutOfHostMemory => OomError::OutOfHostMemory,
            VulkanError::OutOfDeviceMemory => OomError::OutOfDeviceMemory,
            _ => panic!("unexpected error: {:?}", err),
        }
    }
}

// Generated by build.rs
include!(concat!(env!("OUT_DIR"), "/errors.rs"));

impl Error for VulkanError {}

impl fmt::Display for VulkanError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            VulkanError::OutOfHostMemory => write!(
                f,
                "A host memory allocation has failed.",
            ),
            VulkanError::OutOfDeviceMemory => write!(
                f,
                "A device memory allocation has failed.",
            ),
            VulkanError::InitializationFailed => write!(
                f,
                "Initialization of an object could not be completed for implementation-specific reasons.",
            ),
            VulkanError::DeviceLost => write!(
                f,
                "The logical or physical device has been lost.",
            ),
            VulkanError::MemoryMapFailed => write!(
                f,
                "Mapping of a memory object has failed.",
            ),
            VulkanError::LayerNotPresent => write!(
                f,
                "A requested layer is not present or could not be loaded.",
            ),
            VulkanError::ExtensionNotPresent => write!(
                f,
                "A requested extension is not supported.",
            ),
            VulkanError::FeatureNotPresent => write!(
                f,
                "A requested feature is not supported.",
            ),
            VulkanError::IncompatibleDriver => write!(
                f,
                "The requested version of Vulkan is not supported by the driver or is otherwise incompatible for implementation-specific reasons.",
            ),
            VulkanError::TooManyObjects => write!(
                f,
                "Too many objects of the type have already been created.",
            ),
            VulkanError::FormatNotSupported => write!(
                f,
                "A requested format is not supported on this device.",
            ),
            VulkanError::FragmentedPool => write!(
                f,
                "A pool allocation has failed due to fragmentation of the pool's memory.",
            ),
            VulkanError::Unknown => write!(
                f,
                "An unknown error has occurred; either the application has provided invalid input, or an implementation failure has occurred.",
            ),
            VulkanError::OutOfPoolMemory => write!(
                f,
                "A pool memory allocation has failed.",
            ),
            VulkanError::InvalidExternalHandle => write!(
                f,
                "An external handle is not a valid handle of the specified type.",
            ),
            VulkanError::Fragmentation => write!(
                f,
                "A descriptor pool creation has failed due to fragmentation.",
            ),
            VulkanError::InvalidOpaqueCaptureAddress => write!(
                f,
                "A buffer creation or memory allocation failed because the requested address is not available. A shader group handle assignment failed because the requested shader group handle information is no longer valid.",
            ),
            VulkanError::IncompatibleDisplay => write!(
                f,
                "The display used by a swapchain does not use the same presentable image layout, or is incompatible in a way that prevents sharing an image.",
            ),
            VulkanError::NotPermitted => write!(
                f,
                "A requested operation was not permitted.",
            ),
            VulkanError::SurfaceLost => write!(
                f,
                "A surface is no longer available.",
            ),
            VulkanError::NativeWindowInUse => write!(
                f,
                "The requested window is already in use by Vulkan or another API in a manner which prevents it from being used again.",
            ),
            VulkanError::OutOfDate => write!(
                f,
                "A surface has changed in such a way that it is no longer compatible with the swapchain, and further presentation requests using the swapchain will fail.",
            ),
            VulkanError::ValidationFailed => write!(
                f,
                "Validation failed.",
            ),
            VulkanError::FullScreenExclusiveModeLost => write!(
                f,
                "An operation on a swapchain created with application controlled full-screen access failed as it did not have exclusive full-screen access.",
            ),
            VulkanError::InvalidDrmFormatModifierPlaneLayout => write!(
                f,
                "The requested DRM format modifier plane layout is invalid.",
            ),
            VulkanError::InvalidShader => write!(
                f,
                "One or more shaders failed to compile or link.",
            ),
            VulkanError::Unnamed(result) => write!(
                f,
                "Unnamed error, VkResult value {}",
                result.as_raw(),
            ),
        }
    }
}

/// A helper type for non-exhaustive structs.
///
/// This type cannot be constructed outside Vulkano. Structures with a field of this type can only
/// be constructed by calling a constructor function or `Default::default()`. The effect is similar
/// to the standard Rust `#[non_exhaustive]` attribute, except that it does not prevent update
/// syntax from being used.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] // add traits as needed
pub struct NonExhaustive(pub(crate) ());
<|endoftext|>


<commit_before>use libc;

use std::ffi::CStr;
use std::str;

// In paint servers (patterns, gradients, etc.), we have an
// Option<String> for fallback names.  This is a utility function to
// clone one of those.
pub fn clone_fallback_name(fallback: &Option<String>) -> Option<String> {
    if let Some(ref fallback_name) = *fallback {
        Some(fallback_name.clone())
    } else {
        None
    }
}

/// Converts a `char *` which is known to be valid UTF-8 into a `&str`
///
/// The usual `from_glib_none(s)` allocates an owned String.  The
/// purpose of `utf8_cstr()` is to get a temporary string slice into a
/// C string which is already known to be valid UTF-8; for example,
/// as for strings which come from `libxml2`.
pub unsafe fn utf8_cstr<'a>(s: *const libc::c_char) -> &'a str {
    assert!(!s.is_null());

    str::from_utf8_unchecked(CStr::from_ptr(s).to_bytes())
}
<commit_msg>util.rs: new function utf8_cstr_opt()<commit_after>use libc;

use std::ffi::CStr;
use std::str;

// In paint servers (patterns, gradients, etc.), we have an
// Option<String> for fallback names.  This is a utility function to
// clone one of those.
pub fn clone_fallback_name(fallback: &Option<String>) -> Option<String> {
    if let Some(ref fallback_name) = *fallback {
        Some(fallback_name.clone())
    } else {
        None
    }
}

/// Converts a `char *` which is known to be valid UTF-8 into a `&str`
///
/// The usual `from_glib_none(s)` allocates an owned String.  The
/// purpose of `utf8_cstr()` is to get a temporary string slice into a
/// C string which is already known to be valid UTF-8; for example,
/// as for strings which come from `libxml2`.
pub unsafe fn utf8_cstr<'a>(s: *const libc::c_char) -> &'a str {
    assert!(!s.is_null());

    str::from_utf8_unchecked(CStr::from_ptr(s).to_bytes())
}

pub unsafe fn utf8_cstr_opt<'a>(s: *const libc::c_char) -> Option<&'a str> {
    if s.is_null() {
        None
    } else {
        Some(utf8_cstr(s))
    }
}
<|endoftext|>


<commit_before>use nom::{IResult, double, is_alphabetic};
use std::str;
use std::f64::consts::*;

// I don't know how to copy a nom::IError for long-term storage
// (i.e. when it can no longer reference the &[u8]).  So, we explode a
// nom::IError into a simple error struct that can be passed around.
#[derive(Debug, Clone, PartialEq)]
pub struct ParseError {
    pub display: String
}

/*
impl<'a> From<IError<&'a [u8]>> for NomError {
    fn from (e: IError<&[u8]>) -> NomError {
        match e {
            IError::Error (err) => NomError { display: format! ("{}", err) },

            IError::Incomplete (_) => NomError { display: "incomplete data".to_string () }
        }
    }
}
*/

fn is_whitespace (c: u8) -> bool {
    match c as char {
        ' ' | '\t' | '\r' | '\n' => true,
        _ => false
    }
}

// comma-wsp:
//     (wsp+ comma? wsp*) | (comma wsp*)

named! (comma, complete! (tag! (",")));
named! (wsp, recognize! (take_while1! (is_whitespace)));
named! (wsp_opt, recognize! (take_while! (is_whitespace)));

named! (comma_wsp,
    alt! (recognize! (tuple! (comma,
                              wsp_opt))
          | recognize! (tuple! (wsp,
                                opt! (comma),
                                wsp_opt))));

// angle:
// https://www.w3.org/TR/SVG/types.html#DataTypeAngle
//
// angle ::= number ("deg" | "grad" | "rad")?
//
// Returns an f64 angle in degrees

fn is_alphabetic_or_dash (c: u8) -> bool {
     is_alphabetic (c) || c == '-' as u8 || c == '%' as u8
}

named! (pub number_and_units<(f64, &[u8])>,
        tuple! (double,
                take_while! (is_alphabetic_or_dash)));

pub fn angle_degrees (s: &str) -> Result <f64, ParseError> {
    let r = number_and_units (s.as_bytes ()).to_full_result ();

    match r {
        Ok ((value, unit)) => {
            match unit {
                b"deg"  => Ok (value),
                b"grad" => Ok (value * 360.0 / 400.0),
                b"rad"  => Ok (value * 180.0 / PI),
                b""     => Ok (value),
                _       => Err (ParseError { display: "expected (\"deg\", \"rad\", \"grad\")? after number".to_string () })
            }
        },

        _ => Err (ParseError { display: "expected a number".to_string () })
    }
}

// Parse a viewBox attribute
// https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
//
// viewBox: double [,] double [,] double [,] double [,]
//
// x, y, w, h
//
// Where w and h must be nonnegative.

named! (pub view_box<(f64, f64, f64, f64)>,
        ws! (do_parse! (x: double    >>
                        opt! (comma) >>
                        y: double    >>
                        opt! (comma) >>
                        w: double    >>
                        opt! (comma) >>
                        h: double    >>
                        eof! ()      >>
                        (x, y, w, h))));

// Coordinate pairs, separated by optional (whitespace-and/or comma)
//
// All of these yield (1, -2): "1 -2", "1, -2", "1-2"

named! (pub coordinate_pair<(f64, f64)>,
        do_parse! (x: double        >>
                   opt! (comma_wsp) >>
                   y: double        >>
                   (x, y)));

// Parse a list-of-points as for polyline and polygon elements
// https://www.w3.org/TR/SVG/shapes.html#PointsBNF

named! (list_of_points_impl<Vec<(f64, f64)>>,
        terminated! (separated_list! (comma_wsp, coordinate_pair),
                     eof! ()));

pub fn list_of_points (string: &[u8]) -> Result <Vec<(f64, f64)>, ParseError> {
    list_of_points_impl (string)
        .to_full_result ()
        .map_err (|_| ParseError { display: "invalid syntax for list of points".to_string () })
    /*
        .map_err (|e| match e { IError::Error (err) => ParseError { display: format! ("{}", err) },
                                _ => ParseError { display: "incomplete list of points".to_string () }
        })
     */
}

named! (pub separated_numbers<Vec<f64>>,
        separated_list! (comma_wsp, double));

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_view_box () {
        assert_eq! (view_box (b"1 2 3 4"), IResult::Done (&b""[..], (1.0, 2.0, 3.0, 4.0)));
        assert_eq! (view_box (b"1,2,3 4"), IResult::Done (&b""[..], (1.0, 2.0, 3.0, 4.0)));
        assert_eq! (view_box (b" 1,2,3 4 "), IResult::Done (&b""[..], (1.0, 2.0, 3.0, 4.0)));

        let result = view_box (b"1 2 3 4 5");

        match result {
            IResult::Error (_) => { },
            _ => { panic! ("{:?} should be an invalid viewBox", result); }
        }
    }

    #[test]
    fn parses_coordinate_pairs () {
        assert_eq! (coordinate_pair (b"1 2"),    IResult::Done (&b""[..], (1.0, 2.0)));
        assert_eq! (coordinate_pair (b"1-2"),    IResult::Done (&b""[..], (1.0, -2.0)));
        assert_eq! (coordinate_pair (b"1,2"),    IResult::Done (&b""[..], (1.0, 2.0)));
        assert_eq! (coordinate_pair (b"1, 2"),   IResult::Done (&b""[..], (1.0, 2.0)));
        assert_eq! (coordinate_pair (b"1 ,2"),   IResult::Done (&b""[..], (1.0, 2.0)));
        assert_eq! (coordinate_pair (b"1 , 2"),  IResult::Done (&b""[..], (1.0, 2.0)));
        assert_eq! (coordinate_pair (b"1 -2"),   IResult::Done (&b""[..], (1.0, -2.0)));
        assert_eq! (coordinate_pair (b"1,-2"),   IResult::Done (&b""[..], (1.0, -2.0)));
        assert_eq! (coordinate_pair (b"1, -2"),  IResult::Done (&b""[..], (1.0, -2.0)));
        assert_eq! (coordinate_pair (b"1 , -2"), IResult::Done (&b""[..], (1.0, -2.0)));
    }

    #[test]
    fn detects_incomplete_coordinate_pair () {
        let result = coordinate_pair (b"1");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }

        let result = coordinate_pair (b"1,");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }

        let result = coordinate_pair (b"1, ");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }

        let result = coordinate_pair (b"1-");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }

        let result = coordinate_pair (b"1,-");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }

        let result = coordinate_pair (b"-1 -");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }
    }

    #[test]
    fn parses_comma_wsp () {
        assert_eq! (comma_wsp (b" , "), IResult::Done (&b""[..], &b" , "[..]));
        assert_eq! (comma_wsp (b","),   IResult::Done (&b""[..], &b","[..]));
        assert_eq! (comma_wsp (b" "),   IResult::Done (&b""[..], &b" "[..]));
        assert_eq! (comma_wsp (b", "),  IResult::Done (&b""[..], &b", "[..]));
        assert_eq! (comma_wsp (b" ,"),  IResult::Done (&b""[..], &b" ,"[..]));
    }

    #[test]
    fn parses_separated_numbers () {
        assert_eq! (separated_numbers (b"1 2 3 4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1,2,3,4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1 ,2 ,3 ,4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1  ,2  ,3  ,4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1, 2, 3, 4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1,  2,  3,  4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1 , 2 , 3 , 4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1  , 2  , 3  , 4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1  ,  2  ,  3  ,  4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
    }

    #[test]
    fn parses_list_of_points () {
        // FIXME: we are missing optional whitespace at the beginning and end of the list
        assert_eq! (list_of_points (b"1 2"),      Ok (vec! [(1.0, 2.0)]));
        assert_eq! (list_of_points (b"1 2 3 4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points (b"1,2,3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points (b"1,2 3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points (b"1,2 -3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
        assert_eq! (list_of_points (b"1,2,-3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
    }

    #[test]
    fn errors_on_invalid_list_of_points () {
        assert! (list_of_points (b"-1-2-3-4").is_err ());
        assert! (list_of_points (b"1 2-3,-4").is_err ());
    }

    #[test]
    fn parses_number_and_units () {
        assert_eq! (number_and_units (b"-1"), IResult::Done (&b""[..], (-1.0, &b""[..])));
        assert_eq! (number_and_units (b"0x"), IResult::Done (&b""[..], (0.0, &b"x"[..])));
        assert_eq! (number_and_units (b"-55.5x-large"), IResult::Done (&b""[..], (-55.5, &b"x-large"[..])));
    }

    #[test]
    fn parses_angle () {
        assert_eq! (angle_degrees ("0"),        Ok (0.0));
        assert_eq! (angle_degrees ("15"),       Ok (15.0));
        assert_eq! (angle_degrees ("180.5deg"), Ok (180.5));
        assert_eq! (angle_degrees ("1rad"),     Ok (180.0 / PI));
        assert_eq! (angle_degrees ("-400grad"), Ok (-360.0));

        assert! (angle_degrees ("").is_err ());
        assert! (angle_degrees ("foo").is_err ());
        assert! (angle_degrees ("300foo").is_err ());
    }
}
<commit_msg>parsers.rs: New helper ParseError::new() which duplicates the description string itself<commit_after>use nom::{IResult, double, is_alphabetic};
use std::str;
use std::f64::consts::*;

// I don't know how to copy a nom::IError for long-term storage
// (i.e. when it can no longer reference the &[u8]).  So, we explode a
// nom::IError into a simple error struct that can be passed around.
#[derive(Debug, Clone, PartialEq)]
pub struct ParseError {
    pub display: String
}

impl ParseError {
    pub fn new (msg: &str) -> ParseError {
        ParseError { display: msg.to_string () }
    }
}

/*
impl<'a> From<IError<&'a [u8]>> for NomError {
    fn from (e: IError<&[u8]>) -> NomError {
        match e {
            IError::Error (err) => NomError { display: format! ("{}", err) },

            IError::Incomplete (_) => NomError { display: "incomplete data".to_string () }
        }
    }
}
*/

fn is_whitespace (c: u8) -> bool {
    match c as char {
        ' ' | '\t' | '\r' | '\n' => true,
        _ => false
    }
}

// comma-wsp:
//     (wsp+ comma? wsp*) | (comma wsp*)

named! (comma, complete! (tag! (",")));
named! (wsp, recognize! (take_while1! (is_whitespace)));
named! (wsp_opt, recognize! (take_while! (is_whitespace)));

named! (comma_wsp,
    alt! (recognize! (tuple! (comma,
                              wsp_opt))
          | recognize! (tuple! (wsp,
                                opt! (comma),
                                wsp_opt))));

// angle:
// https://www.w3.org/TR/SVG/types.html#DataTypeAngle
//
// angle ::= number ("deg" | "grad" | "rad")?
//
// Returns an f64 angle in degrees

fn is_alphabetic_or_dash (c: u8) -> bool {
     is_alphabetic (c) || c == '-' as u8 || c == '%' as u8
}

named! (pub number_and_units<(f64, &[u8])>,
        tuple! (double,
                take_while! (is_alphabetic_or_dash)));

pub fn angle_degrees (s: &str) -> Result <f64, ParseError> {
    let r = number_and_units (s.as_bytes ()).to_full_result ();

    match r {
        Ok ((value, unit)) => {
            match unit {
                b"deg"  => Ok (value),
                b"grad" => Ok (value * 360.0 / 400.0),
                b"rad"  => Ok (value * 180.0 / PI),
                b""     => Ok (value),
                _       => Err (ParseError::new ("expected (\"deg\", \"rad\", \"grad\")? after number"))
            }
        },

        _ => Err (ParseError::new ("expected a number"))
    }
}

// Parse a viewBox attribute
// https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
//
// viewBox: double [,] double [,] double [,] double [,]
//
// x, y, w, h
//
// Where w and h must be nonnegative.

named! (pub view_box<(f64, f64, f64, f64)>,
        ws! (do_parse! (x: double    >>
                        opt! (comma) >>
                        y: double    >>
                        opt! (comma) >>
                        w: double    >>
                        opt! (comma) >>
                        h: double    >>
                        eof! ()      >>
                        (x, y, w, h))));

// Coordinate pairs, separated by optional (whitespace-and/or comma)
//
// All of these yield (1, -2): "1 -2", "1, -2", "1-2"

named! (pub coordinate_pair<(f64, f64)>,
        do_parse! (x: double        >>
                   opt! (comma_wsp) >>
                   y: double        >>
                   (x, y)));

// Parse a list-of-points as for polyline and polygon elements
// https://www.w3.org/TR/SVG/shapes.html#PointsBNF

named! (list_of_points_impl<Vec<(f64, f64)>>,
        terminated! (separated_list! (comma_wsp, coordinate_pair),
                     eof! ()));

pub fn list_of_points (string: &[u8]) -> Result <Vec<(f64, f64)>, ParseError> {
    list_of_points_impl (string)
        .to_full_result ()
        .map_err (|_| ParseError::new ("invalid syntax for list of points"))
    /*
        .map_err (|e| match e { IError::Error (err) => ParseError::new (format! ("{}", err)),
                                _ => ParseError::new ("incomplete list of points")
        })
     */
}

named! (pub separated_numbers<Vec<f64>>,
        separated_list! (comma_wsp, double));

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn parses_view_box () {
        assert_eq! (view_box (b"1 2 3 4"), IResult::Done (&b""[..], (1.0, 2.0, 3.0, 4.0)));
        assert_eq! (view_box (b"1,2,3 4"), IResult::Done (&b""[..], (1.0, 2.0, 3.0, 4.0)));
        assert_eq! (view_box (b" 1,2,3 4 "), IResult::Done (&b""[..], (1.0, 2.0, 3.0, 4.0)));

        let result = view_box (b"1 2 3 4 5");

        match result {
            IResult::Error (_) => { },
            _ => { panic! ("{:?} should be an invalid viewBox", result); }
        }
    }

    #[test]
    fn parses_coordinate_pairs () {
        assert_eq! (coordinate_pair (b"1 2"),    IResult::Done (&b""[..], (1.0, 2.0)));
        assert_eq! (coordinate_pair (b"1-2"),    IResult::Done (&b""[..], (1.0, -2.0)));
        assert_eq! (coordinate_pair (b"1,2"),    IResult::Done (&b""[..], (1.0, 2.0)));
        assert_eq! (coordinate_pair (b"1, 2"),   IResult::Done (&b""[..], (1.0, 2.0)));
        assert_eq! (coordinate_pair (b"1 ,2"),   IResult::Done (&b""[..], (1.0, 2.0)));
        assert_eq! (coordinate_pair (b"1 , 2"),  IResult::Done (&b""[..], (1.0, 2.0)));
        assert_eq! (coordinate_pair (b"1 -2"),   IResult::Done (&b""[..], (1.0, -2.0)));
        assert_eq! (coordinate_pair (b"1,-2"),   IResult::Done (&b""[..], (1.0, -2.0)));
        assert_eq! (coordinate_pair (b"1, -2"),  IResult::Done (&b""[..], (1.0, -2.0)));
        assert_eq! (coordinate_pair (b"1 , -2"), IResult::Done (&b""[..], (1.0, -2.0)));
    }

    #[test]
    fn detects_incomplete_coordinate_pair () {
        let result = coordinate_pair (b"1");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }

        let result = coordinate_pair (b"1,");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }

        let result = coordinate_pair (b"1, ");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }

        let result = coordinate_pair (b"1-");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }

        let result = coordinate_pair (b"1,-");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }

        let result = coordinate_pair (b"-1 -");
        match result {
            IResult::Incomplete (_) => { },
            _ => { panic! ("{:?} should be an incomplete coordinate-pair", result); }
        }
    }

    #[test]
    fn parses_comma_wsp () {
        assert_eq! (comma_wsp (b" , "), IResult::Done (&b""[..], &b" , "[..]));
        assert_eq! (comma_wsp (b","),   IResult::Done (&b""[..], &b","[..]));
        assert_eq! (comma_wsp (b" "),   IResult::Done (&b""[..], &b" "[..]));
        assert_eq! (comma_wsp (b", "),  IResult::Done (&b""[..], &b", "[..]));
        assert_eq! (comma_wsp (b" ,"),  IResult::Done (&b""[..], &b" ,"[..]));
    }

    #[test]
    fn parses_separated_numbers () {
        assert_eq! (separated_numbers (b"1 2 3 4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1,2,3,4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1 ,2 ,3 ,4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1  ,2  ,3  ,4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1, 2, 3, 4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1,  2,  3,  4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1 , 2 , 3 , 4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1  , 2  , 3  , 4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
        assert_eq! (separated_numbers (b"1  ,  2  ,  3  ,  4"), IResult::Done (&b""[..], vec! [1.0, 2.0, 3.0, 4.0]));
    }

    #[test]
    fn parses_list_of_points () {
        // FIXME: we are missing optional whitespace at the beginning and end of the list
        assert_eq! (list_of_points (b"1 2"),      Ok (vec! [(1.0, 2.0)]));
        assert_eq! (list_of_points (b"1 2 3 4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points (b"1,2,3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points (b"1,2 3,4"),  Ok (vec! [(1.0, 2.0), (3.0, 4.0)]));
        assert_eq! (list_of_points (b"1,2 -3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
        assert_eq! (list_of_points (b"1,2,-3,4"), Ok (vec! [(1.0, 2.0), (-3.0, 4.0)]));
    }

    #[test]
    fn errors_on_invalid_list_of_points () {
        assert! (list_of_points (b"-1-2-3-4").is_err ());
        assert! (list_of_points (b"1 2-3,-4").is_err ());
    }

    #[test]
    fn parses_number_and_units () {
        assert_eq! (number_and_units (b"-1"), IResult::Done (&b""[..], (-1.0, &b""[..])));
        assert_eq! (number_and_units (b"0x"), IResult::Done (&b""[..], (0.0, &b"x"[..])));
        assert_eq! (number_and_units (b"-55.5x-large"), IResult::Done (&b""[..], (-55.5, &b"x-large"[..])));
    }

    #[test]
    fn parses_angle () {
        assert_eq! (angle_degrees ("0"),        Ok (0.0));
        assert_eq! (angle_degrees ("15"),       Ok (15.0));
        assert_eq! (angle_degrees ("180.5deg"), Ok (180.5));
        assert_eq! (angle_degrees ("1rad"),     Ok (180.0 / PI));
        assert_eq! (angle_degrees ("-400grad"), Ok (-360.0));

        assert! (angle_degrees ("").is_err ());
        assert! (angle_degrees ("foo").is_err ());
        assert! (angle_degrees ("300foo").is_err ());
    }
}
<|endoftext|>


<commit_before>
extern crate centralgithook;
use centralgithook::*;
#[allow(dead_code)]
mod helpers;
extern crate git2;
extern crate tempdir;
use tempdir::TempDir;

fn sorted(mut v: Vec<String>) -> Vec<String>
{
    v.sort();
    v
}

#[test]
fn test_find_all_subtrees()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("foo");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);
    let subdirs = scratch.find_all_subdirs(&head.as_commit().unwrap().tree().unwrap());
    assert_eq!(0, subdirs.len());

    repo.add_file("bla/foo");
    let head = scratch.transfer(&repo.commit("2"), &repo.path);
    let subdirs = scratch.find_all_subdirs(&head.as_commit().unwrap().tree().unwrap());
    assert_eq!(vec![
        format!("bla"),
    ], sorted(subdirs));

    repo.add_file("a/b/c/d/foo");
    let head = scratch.transfer(&repo.commit("2"), &repo.path);
    let subdirs = scratch.find_all_subdirs(&head.as_commit().unwrap().tree().unwrap());
    assert_eq!(vec![
        format!("a"),
        format!("a/b"),
        format!("a/b/c"),
        format!("a/b/c/d"),
        format!("bla"),
    ], sorted(subdirs));

    repo.add_file("a/b/c/.bla/foo");
    let head = scratch.transfer(&repo.commit("2"), &repo.path);
    let subdirs = scratch.find_all_subdirs(&head.as_commit().unwrap().tree().unwrap());
    assert_eq!(vec![
        format!("a"),
        format!("a/b"),
        format!("a/b/c"),
        format!("a/b/c/d"),
        format!("bla"),
    ], sorted(subdirs));
}

fn split_subdir_ref(repo: &helpers::TestRepo, module: &str, newrev: git2::Oid) -> Option<git2::Oid>
{
    repo.shell.command("rm -Rf refs/original");
    repo.shell.command("rm -Rf .git-rewrite");

    repo.repo.set_head_detached(newrev).expect("can't detatch head");;

    repo.shell.command(&format!("git filter-branch --subdirectory-filter {}/ -- HEAD", module));

    return Some(repo.repo
        .revparse_single("HEAD")
        .expect("can't find rewritten branch").id());
}

#[test]
fn test_split_subdir_one_commit()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("foo/bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);

    assert_eq!(split_subdir_ref(&repo, "foo", head.id()), scratch.split_subdir("foo", head.id()));
}

#[test]
fn test_split_subdir_two_commits()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("foo/bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.add_file("foo/bla_bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);

    assert_eq!(split_subdir_ref(&repo, "foo", head.id()), scratch.split_subdir("foo", head.id()));
}

#[test]
fn test_split_subdir_three_commits_middle_unrelated()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("foo/bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.add_file("x");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.add_file("foo/bla_bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);

    assert_eq!(split_subdir_ref(&repo, "foo", head.id()), scratch.split_subdir("foo", head.id()));
}

#[test]
fn test_split_subdir_three_commits_first_unrelated()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("x");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.add_file("foo/bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.add_file("foo/bla_bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);

    assert_eq!(split_subdir_ref(&repo, "foo", head.id()), scratch.split_subdir("foo", head.id()));
}

#[test]
fn test_split_subdir_branch()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("foo/bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.shell.command("git checkout -b tmp");
    repo.add_file("foo/bla_bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.shell.command("git checkout master");
    repo.shell.command("git merge tmp --no-ff");
    println!("{}",repo.shell.command("git log"));
    let head = scratch.transfer(&repo.rev("HEAD"), &repo.path);

    assert_eq!(split_subdir_ref(&repo, "foo", head.id()), scratch.split_subdir("foo", head.id()));
}
<commit_msg>fix warnings<commit_after>
extern crate centralgithook;
use centralgithook::*;
#[allow(dead_code)]
mod helpers;
extern crate git2;
extern crate tempdir;
use tempdir::TempDir;

fn sorted(mut v: Vec<String>) -> Vec<String>
{
    v.sort();
    v
}

#[test]
fn test_find_all_subtrees()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("foo");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);
    let subdirs = scratch.find_all_subdirs(&head.as_commit().unwrap().tree().unwrap());
    assert_eq!(0, subdirs.len());

    repo.add_file("bla/foo");
    let head = scratch.transfer(&repo.commit("2"), &repo.path);
    let subdirs = scratch.find_all_subdirs(&head.as_commit().unwrap().tree().unwrap());
    assert_eq!(vec![
        format!("bla"),
    ], sorted(subdirs));

    repo.add_file("a/b/c/d/foo");
    let head = scratch.transfer(&repo.commit("2"), &repo.path);
    let subdirs = scratch.find_all_subdirs(&head.as_commit().unwrap().tree().unwrap());
    assert_eq!(vec![
        format!("a"),
        format!("a/b"),
        format!("a/b/c"),
        format!("a/b/c/d"),
        format!("bla"),
    ], sorted(subdirs));

    repo.add_file("a/b/c/.bla/foo");
    let head = scratch.transfer(&repo.commit("2"), &repo.path);
    let subdirs = scratch.find_all_subdirs(&head.as_commit().unwrap().tree().unwrap());
    assert_eq!(vec![
        format!("a"),
        format!("a/b"),
        format!("a/b/c"),
        format!("a/b/c/d"),
        format!("bla"),
    ], sorted(subdirs));
}

fn split_subdir_ref(repo: &helpers::TestRepo, module: &str, newrev: git2::Oid) -> Option<git2::Oid>
{
    repo.shell.command("rm -Rf refs/original");
    repo.shell.command("rm -Rf .git-rewrite");

    repo.repo.set_head_detached(newrev).expect("can't detatch head");;

    repo.shell.command(&format!("git filter-branch --subdirectory-filter {}/ -- HEAD", module));

    return Some(repo.repo
        .revparse_single("HEAD")
        .expect("can't find rewritten branch").id());
}

#[test]
fn test_split_subdir_one_commit()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("foo/bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);

    assert_eq!(split_subdir_ref(&repo, "foo", head.id()), scratch.split_subdir("foo", head.id()));
}

#[test]
fn test_split_subdir_two_commits()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("foo/bla");
    let _ = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.add_file("foo/bla_bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);

    assert_eq!(split_subdir_ref(&repo, "foo", head.id()), scratch.split_subdir("foo", head.id()));
}

#[test]
fn test_split_subdir_three_commits_middle_unrelated()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("foo/bla");
    let _ = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.add_file("x");
    let _ = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.add_file("foo/bla_bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);

    assert_eq!(split_subdir_ref(&repo, "foo", head.id()), scratch.split_subdir("foo", head.id()));
}

#[test]
fn test_split_subdir_three_commits_first_unrelated()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("x");
    let _ = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.add_file("foo/bla");
    let _ = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.add_file("foo/bla_bla");
    let head = scratch.transfer(&repo.commit("1"), &repo.path);

    assert_eq!(split_subdir_ref(&repo, "foo", head.id()), scratch.split_subdir("foo", head.id()));
}

#[test]
fn test_split_subdir_branch()
{
    let td = TempDir::new("cgh_test").expect("folder cgh_test should be created");
    let host = helpers::TestHost::new();
    let scratch = Scratch::new(&td.path().join("scratch"), &host);
    let repo = helpers::TestRepo::new(&td.path().join("repo"));

    repo.add_file("foo/bla");
    let _ = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.shell.command("git checkout -b tmp");
    repo.add_file("foo/bla_bla");
    let _ = scratch.transfer(&repo.commit("1"), &repo.path);
    repo.shell.command("git checkout master");
    repo.shell.command("git merge tmp --no-ff");
    println!("{}",repo.shell.command("git log"));
    let head = scratch.transfer(&repo.rev("HEAD"), &repo.path);

    assert_eq!(split_subdir_ref(&repo, "foo", head.id()), scratch.split_subdir("foo", head.id()));
}
<|endoftext|>


<commit_before>extern crate consul;
extern crate rand;

use consul::session::{Session, SessionEntry};
use consul::{Client, Config};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use rstest::*;

#[rstest]
fn session_create_test() {
    let (client, unique_test_identifier) = set_up();

    assert_eq!(
        get_number_of_session_entries_with_matching_name(&client, &unique_test_identifier),
        0
    );

    let entry = SessionEntry {
        Name: Some(unique_test_identifier.to_string()),
        ..Default::default()
    };

    let (created_session_entry, _) = client.create(&entry, None).unwrap();

    assert_eq!(
        get_number_of_session_entries_with_matching_name(&client, &unique_test_identifier),
        1
    );

    tear_down(&client, &created_session_entry.ID.unwrap());
}

#[rstest]
fn session_destroy_test() {
    let (client, unique_test_identifier) = set_up();

    let entry = SessionEntry {
        Name: Some(unique_test_identifier.to_string()),
        ..Default::default()
    };

    let (created_session_entry, _) = client.create(&entry, None).unwrap();

    assert_eq!(
        get_number_of_session_entries_with_matching_name(&client, &unique_test_identifier),
        1
    );

    let created_session_entry_id = created_session_entry.ID.unwrap();

    client.destroy(&created_session_entry_id, None).unwrap();

    assert_eq!(
        get_number_of_session_entries_with_matching_name(&client, &unique_test_identifier),
        0
    );

    tear_down(&client, &created_session_entry_id);
}

#[rstest]
fn session_info_test() {
    let (client, unique_test_identifier) = set_up();

    let entry = SessionEntry {
        Name: Some(unique_test_identifier.to_string()),
        ..Default::default()
    };

    let (created_session_entry, _) = client.create(&entry, None).unwrap();

    let created_session_entry_id = created_session_entry.ID.unwrap();

    let (session_entries, _) = client.info(&created_session_entry_id, None).unwrap();

    assert_eq!(session_entries.len(), 1);

    let session_entry = session_entries.iter().next().unwrap();

    assert_eq!(
        session_entry.Name.as_ref().unwrap(),
        &unique_test_identifier
    );

    tear_down(&client, &created_session_entry_id);
}

#[rstest]
fn session_list_test() {
    let (client, unique_test_identifier) = set_up();

    let entry_names = vec![
        format!("{}-1", unique_test_identifier),
        format!("{}-2", unique_test_identifier),
        format!("{}-3", unique_test_identifier),
    ];

    let mut session_ids = Vec::<String>::new();

    for entry_name in &entry_names {
        let entry = SessionEntry {
            Name: Some(entry_name.to_string()),
            ..Default::default()
        };

        let (created_session_entry, _) = client.create(&entry, None).unwrap();

        session_ids.push(created_session_entry.ID.unwrap());
    }

    let (session_entries, _) = client.list(None).unwrap();

    let filtered_session_entries = session_entries
        .iter()
        .filter(|s| s.Name.as_ref().unwrap().contains(&unique_test_identifier))
        .collect::<Vec<&SessionEntry>>();

    assert_eq!(filtered_session_entries.len(), 3);

    let mut filtered_session_entry_names = filtered_session_entries
        .iter()
        .map(|s| s.Name.as_ref().unwrap().to_string())
        .collect::<Vec<String>>();

    filtered_session_entry_names.sort();

    assert_eq!(filtered_session_entry_names, entry_names);

    for session_id in session_ids {
        tear_down(&client, &session_id);
    }
}

#[rstest]
fn session_node_test() {
    let (client, unique_test_identifier) = set_up();

    let entry = SessionEntry {
        Name: Some(unique_test_identifier.to_string()),
        ..Default::default()
    };

    let (created_session_entry, _) = client.create(&entry, None).unwrap();

    let created_session_entry_id = created_session_entry.ID.unwrap();

    let system_hostname = hostname::get().unwrap().into_string().unwrap();

    let (session_entries, _) = client.node(&system_hostname, None).unwrap();

    let filtered_session_entries = session_entries
        .iter()
        .filter(|s| s.Name.as_ref().unwrap() == &unique_test_identifier)
        .collect::<Vec<&SessionEntry>>();

    assert_eq!(filtered_session_entries.len(), 1);

    tear_down(&client, &created_session_entry_id);
}

#[rstest]
fn session_renew_test() {
    let (client, unique_test_identifier) = set_up();

    let entry = SessionEntry {
        Name: Some(unique_test_identifier.to_string()),
        ..Default::default()
    };

    let (created_session_entry, _) = client.create(&entry, None).unwrap();

    let created_session_entry_id = created_session_entry.ID.unwrap();

    client.renew(&created_session_entry_id, None).unwrap();

    tear_down(&client, &created_session_entry_id);
}

fn set_up() -> (Client, String) {
    let config = Config::new().unwrap();
    let client = Client::new(config);

    let unique_test_identifier: String = thread_rng()
        .sample_iter(&Alphanumeric)
        .take(16)
        .map(char::from)
        .collect();

    return (client, unique_test_identifier);
}

fn tear_down(client: &Client, session_id: &str) {
    client.destroy(session_id, None).unwrap();
}

fn get_number_of_session_entries_with_matching_name(
    client: &Client,
    unique_test_identifier: &str,
) -> usize {
    let (session_entries, _) = client.list(None).unwrap();

    let filtered_session_entries = session_entries
        .iter()
        .filter(|s| s.Name.as_ref().unwrap() == &unique_test_identifier)
        .collect::<Vec<&SessionEntry>>();

    return filtered_session_entries.len();
}<commit_msg>Running cargo fmt<commit_after>extern crate consul;
extern crate rand;

use consul::session::{Session, SessionEntry};
use consul::{Client, Config};
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use rstest::*;

#[rstest]
fn session_create_test() {
    let (client, unique_test_identifier) = set_up();

    assert_eq!(
        get_number_of_session_entries_with_matching_name(&client, &unique_test_identifier),
        0
    );

    let entry = SessionEntry {
        Name: Some(unique_test_identifier.to_string()),
        ..Default::default()
    };

    let (created_session_entry, _) = client.create(&entry, None).unwrap();

    assert_eq!(
        get_number_of_session_entries_with_matching_name(&client, &unique_test_identifier),
        1
    );

    tear_down(&client, &created_session_entry.ID.unwrap());
}

#[rstest]
fn session_destroy_test() {
    let (client, unique_test_identifier) = set_up();

    let entry = SessionEntry {
        Name: Some(unique_test_identifier.to_string()),
        ..Default::default()
    };

    let (created_session_entry, _) = client.create(&entry, None).unwrap();

    assert_eq!(
        get_number_of_session_entries_with_matching_name(&client, &unique_test_identifier),
        1
    );

    let created_session_entry_id = created_session_entry.ID.unwrap();

    client.destroy(&created_session_entry_id, None).unwrap();

    assert_eq!(
        get_number_of_session_entries_with_matching_name(&client, &unique_test_identifier),
        0
    );

    tear_down(&client, &created_session_entry_id);
}

#[rstest]
fn session_info_test() {
    let (client, unique_test_identifier) = set_up();

    let entry = SessionEntry {
        Name: Some(unique_test_identifier.to_string()),
        ..Default::default()
    };

    let (created_session_entry, _) = client.create(&entry, None).unwrap();

    let created_session_entry_id = created_session_entry.ID.unwrap();

    let (session_entries, _) = client.info(&created_session_entry_id, None).unwrap();

    assert_eq!(session_entries.len(), 1);

    let session_entry = session_entries.iter().next().unwrap();

    assert_eq!(
        session_entry.Name.as_ref().unwrap(),
        &unique_test_identifier
    );

    tear_down(&client, &created_session_entry_id);
}

#[rstest]
fn session_list_test() {
    let (client, unique_test_identifier) = set_up();

    let entry_names = vec![
        format!("{}-1", unique_test_identifier),
        format!("{}-2", unique_test_identifier),
        format!("{}-3", unique_test_identifier),
    ];

    let mut session_ids = Vec::<String>::new();

    for entry_name in &entry_names {
        let entry = SessionEntry {
            Name: Some(entry_name.to_string()),
            ..Default::default()
        };

        let (created_session_entry, _) = client.create(&entry, None).unwrap();

        session_ids.push(created_session_entry.ID.unwrap());
    }

    let (session_entries, _) = client.list(None).unwrap();

    let filtered_session_entries = session_entries
        .iter()
        .filter(|s| s.Name.as_ref().unwrap().contains(&unique_test_identifier))
        .collect::<Vec<&SessionEntry>>();

    assert_eq!(filtered_session_entries.len(), 3);

    let mut filtered_session_entry_names = filtered_session_entries
        .iter()
        .map(|s| s.Name.as_ref().unwrap().to_string())
        .collect::<Vec<String>>();

    filtered_session_entry_names.sort();

    assert_eq!(filtered_session_entry_names, entry_names);

    for session_id in session_ids {
        tear_down(&client, &session_id);
    }
}

#[rstest]
fn session_node_test() {
    let (client, unique_test_identifier) = set_up();

    let entry = SessionEntry {
        Name: Some(unique_test_identifier.to_string()),
        ..Default::default()
    };

    let (created_session_entry, _) = client.create(&entry, None).unwrap();

    let created_session_entry_id = created_session_entry.ID.unwrap();

    let system_hostname = hostname::get().unwrap().into_string().unwrap();

    let (session_entries, _) = client.node(&system_hostname, None).unwrap();

    let filtered_session_entries = session_entries
        .iter()
        .filter(|s| s.Name.as_ref().unwrap() == &unique_test_identifier)
        .collect::<Vec<&SessionEntry>>();

    assert_eq!(filtered_session_entries.len(), 1);

    tear_down(&client, &created_session_entry_id);
}

#[rstest]
fn session_renew_test() {
    let (client, unique_test_identifier) = set_up();

    let entry = SessionEntry {
        Name: Some(unique_test_identifier.to_string()),
        ..Default::default()
    };

    let (created_session_entry, _) = client.create(&entry, None).unwrap();

    let created_session_entry_id = created_session_entry.ID.unwrap();

    client.renew(&created_session_entry_id, None).unwrap();

    tear_down(&client, &created_session_entry_id);
}

fn set_up() -> (Client, String) {
    let config = Config::new().unwrap();
    let client = Client::new(config);

    let unique_test_identifier: String = thread_rng()
        .sample_iter(&Alphanumeric)
        .take(16)
        .map(char::from)
        .collect();

    return (client, unique_test_identifier);
}

fn tear_down(client: &Client, session_id: &str) {
    client.destroy(session_id, None).unwrap();
}

fn get_number_of_session_entries_with_matching_name(
    client: &Client,
    unique_test_identifier: &str,
) -> usize {
    let (session_entries, _) = client.list(None).unwrap();

    let filtered_session_entries = session_entries
        .iter()
        .filter(|s| s.Name.as_ref().unwrap() == &unique_test_identifier)
        .collect::<Vec<&SessionEntry>>();

    return filtered_session_entries.len();
}
<|endoftext|>


<commit_before>use syn::Type;

#[test]
fn test_mut_self() {
    syn::parse_str::<Type>("fn(mut self)").unwrap();
    syn::parse_str::<Type>("fn(mut self: ())").unwrap();
    syn::parse_str::<Type>("fn(mut self: ...)").unwrap_err();
    syn::parse_str::<Type>("fn(mut self: mut self)").unwrap_err();
    syn::parse_str::<Type>("fn(mut self::T)").unwrap_err();
}
<commit_msg>Add test for Type containing macro metavariable<commit_after>#[macro_use]
mod macros;

use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, Span, TokenStream, TokenTree};
use quote::quote;
use std::iter::FromIterator;
use syn::Type;

#[test]
fn test_mut_self() {
    syn::parse_str::<Type>("fn(mut self)").unwrap();
    syn::parse_str::<Type>("fn(mut self: ())").unwrap();
    syn::parse_str::<Type>("fn(mut self: ...)").unwrap_err();
    syn::parse_str::<Type>("fn(mut self: mut self)").unwrap_err();
    syn::parse_str::<Type>("fn(mut self::T)").unwrap_err();
}

#[test]
fn test_macro_variable_type() {
    // mimics the token stream corresponding to `$ty<T>`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Group(Group::new(Delimiter::None, quote! { ty })),
        TokenTree::Punct(Punct::new('<', Spacing::Alone)),
        TokenTree::Ident(Ident::new("T", Span::call_site())),
        TokenTree::Punct(Punct::new('>', Spacing::Alone)),
    ]);

    snapshot!(tokens as Type, @r###"
    Type::Path {
        path: Path {
            segments: [
                PathSegment {
                    ident: "ty",
                    arguments: PathArguments::AngleBracketed {
                        args: [
                            Type(Type::Path {
                                path: Path {
                                    segments: [
                                        PathSegment {
                                            ident: "T",
                                            arguments: None,
                                        },
                                    ],
                                },
                            }),
                        ],
                    },
                },
            ],
        },
    }
    "###);
}
<|endoftext|>


<commit_before>extern crate windows_win;
extern crate clipboard_win;
extern crate winapi;

use winapi::um::winuser::{AddClipboardFormatListener, SetLastErrorEx};

use clipboard_win::{
    set_clipboard_string
};

use windows_win::{
    Window
};

use windows_win::raw::window::{
    get_by_class,
    get_by_title,
    get_by_pid,
    is_visible,
    get_text,
    send_get_text,
    send_set_text,
    send_sys_command,
    Builder,
    destroy
};

use windows_win::raw::process::{
    open,
    close,
    get_exe_path,
};

fn start_prog(name: &str) -> std::process::Child {
    let res = std::process::Command::new(name).spawn().unwrap();
    //Give a bit of time for window to appear
    sleep(100);

    res
}

fn sleep(ms: u64) {
    std::thread::sleep(std::time::Duration::from_millis(ms))
}

#[test]
fn test_get_windows_by_class() {
    let result = get_by_class("IME", None);
    assert!(result.is_ok());
    let result = result.unwrap();
    assert!(result.len() > 0);
}

#[test]
fn test_interact_notepad() {
    let mut notepad = start_prog("notepad");

    test_open_close(notepad.id());
    test_query_process_exe(notepad.id());
    test_get_windows_by_title(notepad.id());
    test_get_window_by_pid_after_error(notepad.id());
    test_window_set_text_message(notepad.id());
    //This test should be last as it closes notepad
    test_window_sys_command_close(notepad.id());

    notepad.wait().expect("Failed to wait for notepad to close");
}

fn test_query_process_exe(notepad_id: u32) {
    let result = open(notepad_id, 0x0400);
    assert!(result.is_ok());
    let notepad = result.unwrap();

    let result = get_exe_path(notepad);
    assert!(result.is_ok());
    let result = result.unwrap();
    assert!(result.starts_with("C:\\Windows\\"));
    assert!(result.ends_with("\\notepad.exe"));

    let result = close(notepad);
    assert!(result.is_ok());
}

fn test_open_close(notepad_id: u32) {
    let result = open(notepad_id, 0x0038);
    assert!(result.is_ok());

    let result = close(result.unwrap());
    assert!(result.is_ok());
}

fn test_get_windows_by_title(notepad_id: u32) {
    let notepad_window = get_by_pid(notepad_id);
    assert!(notepad_window.is_ok());
    let notepad_window = notepad_window.unwrap();
    assert!(notepad_window.is_some());
    let notepad_window = notepad_window.unwrap();

    let result = send_get_text(notepad_window);
    assert!(result.is_some());
    let notepad_orig_title = result.unwrap();

    let result = get_by_title(&notepad_orig_title, None);
    assert!(result.is_ok());
    let result = result.unwrap();
    assert!(result.len() > 0);
    let result = result[0];

    let result = get_text(result);
    assert!(result.is_ok());
    let result = result.unwrap();

    assert_eq!(notepad_orig_title, result);
}

fn test_get_window_by_pid_after_error(notepad_id: u32) {
    unsafe { SetLastErrorEx(5, 0) };
    let notepad_window = get_by_pid(notepad_id);
    assert!(notepad_window.is_ok());
}

fn test_window_set_text_message(notepad_id: u32) {
    let notepad_window = get_by_pid(notepad_id);
    assert!(notepad_window.is_ok());
    let notepad_window = notepad_window.unwrap();
    assert!(notepad_window.is_some());
    let notepad_window = notepad_window.unwrap();

    let result = send_get_text(notepad_window);
    assert!(result.is_some());
    let notepad_orig_title = result.unwrap();

    let new_title = "OLOLO notepad";
    let result = send_set_text(notepad_window, new_title);
    assert!(result);
    let result = send_get_text(notepad_window);
    assert!(result.is_some());
    let notepad_new_title = result.unwrap();

    assert!(notepad_new_title != notepad_orig_title);
    assert_eq!(notepad_new_title, new_title);
}

fn test_window_sys_command_close(notepad_id: u32) {
    let notepad_window = get_by_pid(notepad_id);
    assert!(notepad_window.is_ok());
    let notepad_window = notepad_window.unwrap();
    assert!(notepad_window.is_some());
    let notepad_window = notepad_window.unwrap();

    assert!(is_visible(notepad_window) == true);
    assert!(send_sys_command(notepad_window, 0xF060, 0));
    assert!(is_visible(notepad_window) == false);
}

#[cfg(target_env="msvc")]
#[test]
fn test_window_create() {
    let window = Window::from_builder(Builder::new().class_name("BUTTON").parent_message());
    assert!(window.is_ok());
    let window = window.unwrap();

    unsafe { AddClipboardFormatListener(window.inner()); }

    assert!(set_clipboard_string("Test").is_ok());
    let msg = windows_win::Messages::new().window(Some(window.inner())).next();
    assert!(msg.is_some());
    let msg = msg.unwrap();
    assert!(msg.is_ok());
    let msg = msg.unwrap();

    assert_eq!(msg.id(), 797); //Clipboard update

    assert!(destroy(window.into()));
}

#[test]
fn test_window_create_dummy() {
    let window = Builder::new().class_name("BUTTON").create();
    assert!(window.is_ok());
    let window = window.unwrap();
    assert!(destroy(window));
}

#[test]
fn check_enum_by_with_last_error_will_not_fail() {
    unsafe {
        SetLastErrorEx(1, 0)
    }

    let result = windows_win::raw::window::enum_by_until(None, |_| {
        1
    });

    assert!(result.is_ok());
}
<commit_msg>Update enum_by_until error test<commit_after>extern crate windows_win;
extern crate clipboard_win;
extern crate winapi;

use winapi::um::winuser::{AddClipboardFormatListener, SetLastErrorEx};

use clipboard_win::{
    set_clipboard_string
};

use windows_win::{
    Window
};

use windows_win::raw::window::{
    get_by_class,
    get_by_title,
    get_by_pid,
    is_visible,
    get_text,
    send_get_text,
    send_set_text,
    send_sys_command,
    Builder,
    destroy
};

use windows_win::raw::process::{
    open,
    close,
    get_exe_path,
};

fn start_prog(name: &str) -> std::process::Child {
    let res = std::process::Command::new(name).spawn().unwrap();
    //Give a bit of time for window to appear
    sleep(100);

    res
}

fn sleep(ms: u64) {
    std::thread::sleep(std::time::Duration::from_millis(ms))
}

#[test]
fn test_get_windows_by_class() {
    let result = get_by_class("IME", None);
    assert!(result.is_ok());
    let result = result.unwrap();
    assert!(result.len() > 0);
}

#[test]
fn test_interact_notepad() {
    let mut notepad = start_prog("notepad");

    test_open_close(notepad.id());
    test_query_process_exe(notepad.id());
    test_get_windows_by_title(notepad.id());
    test_get_window_by_pid_after_error(notepad.id());
    test_window_set_text_message(notepad.id());
    //This test should be last as it closes notepad
    test_window_sys_command_close(notepad.id());

    notepad.wait().expect("Failed to wait for notepad to close");
}

fn test_query_process_exe(notepad_id: u32) {
    let result = open(notepad_id, 0x0400);
    assert!(result.is_ok());
    let notepad = result.unwrap();

    let result = get_exe_path(notepad);
    assert!(result.is_ok());
    let result = result.unwrap();
    assert!(result.starts_with("C:\\Windows\\"));
    assert!(result.ends_with("\\notepad.exe"));

    let result = close(notepad);
    assert!(result.is_ok());
}

fn test_open_close(notepad_id: u32) {
    let result = open(notepad_id, 0x0038);
    assert!(result.is_ok());

    let result = close(result.unwrap());
    assert!(result.is_ok());
}

fn test_get_windows_by_title(notepad_id: u32) {
    let notepad_window = get_by_pid(notepad_id);
    assert!(notepad_window.is_ok());
    let notepad_window = notepad_window.unwrap();
    assert!(notepad_window.is_some());
    let notepad_window = notepad_window.unwrap();

    let result = send_get_text(notepad_window);
    assert!(result.is_some());
    let notepad_orig_title = result.unwrap();

    let result = get_by_title(&notepad_orig_title, None);
    assert!(result.is_ok());
    let result = result.unwrap();
    assert!(result.len() > 0);
    let result = result[0];

    let result = get_text(result);
    assert!(result.is_ok());
    let result = result.unwrap();

    assert_eq!(notepad_orig_title, result);
}

fn test_get_window_by_pid_after_error(notepad_id: u32) {
    unsafe { SetLastErrorEx(5, 0) };
    let notepad_window = get_by_pid(notepad_id);
    assert!(notepad_window.is_ok());
}

fn test_window_set_text_message(notepad_id: u32) {
    let notepad_window = get_by_pid(notepad_id);
    assert!(notepad_window.is_ok());
    let notepad_window = notepad_window.unwrap();
    assert!(notepad_window.is_some());
    let notepad_window = notepad_window.unwrap();

    let result = send_get_text(notepad_window);
    assert!(result.is_some());
    let notepad_orig_title = result.unwrap();

    let new_title = "OLOLO notepad";
    let result = send_set_text(notepad_window, new_title);
    assert!(result);
    let result = send_get_text(notepad_window);
    assert!(result.is_some());
    let notepad_new_title = result.unwrap();

    assert!(notepad_new_title != notepad_orig_title);
    assert_eq!(notepad_new_title, new_title);
}

fn test_window_sys_command_close(notepad_id: u32) {
    let notepad_window = get_by_pid(notepad_id);
    assert!(notepad_window.is_ok());
    let notepad_window = notepad_window.unwrap();
    assert!(notepad_window.is_some());
    let notepad_window = notepad_window.unwrap();

    assert!(is_visible(notepad_window) == true);
    assert!(send_sys_command(notepad_window, 0xF060, 0));
    assert!(is_visible(notepad_window) == false);
}

#[cfg(target_env="msvc")]
#[test]
fn test_window_create() {
    let window = Window::from_builder(Builder::new().class_name("BUTTON").parent_message());
    assert!(window.is_ok());
    let window = window.unwrap();

    unsafe { AddClipboardFormatListener(window.inner()); }

    assert!(set_clipboard_string("Test").is_ok());
    let msg = windows_win::Messages::new().window(Some(window.inner())).next();
    assert!(msg.is_some());
    let msg = msg.unwrap();
    assert!(msg.is_ok());
    let msg = msg.unwrap();

    assert_eq!(msg.id(), 797); //Clipboard update

    assert!(destroy(window.into()));
}

#[test]
fn test_window_create_dummy() {
    let window = Builder::new().class_name("BUTTON").create();
    assert!(window.is_ok());
    let window = window.unwrap();
    assert!(destroy(window));
}

#[test]
fn check_enum_by_with_last_error_will_not_fail() {
    unsafe {
        SetLastErrorEx(1, 0)
    }

    let result = windows_win::raw::window::enum_by_until(None, |_| {
        0
    });

    assert!(result.is_ok());

    let result = windows_win::raw::window::enum_by_until(None, |_| {
        1
    });

    assert!(result.is_ok());
}
<|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 = 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));

        // I don't get why this is necessary, but Travis seems to need it?
        let md = fs::metadata(&dir);
        if fs::metadata(&dir).map(|md| md.is_dir()).unwrap_or(false) {
            if let Err(err) = fs::remove_dir_all(&dir) {
                panic!("Could not remove directory '{:?}': {}", dir, err);
            }
        }
        if fs::metadata(&dir).map(|md| md.is_file()).unwrap_or(false) {
            if let Err(err) = fs::remove_file(&dir) {
                panic!("Could not remove file '{:?}': {}", dir, err);
            }
        }
        if let Err(err) = fs::create_dir_all(&dir) {
            panic!("Could not create '{:?}': {}", dir, 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 = match csv::Writer::from_file(&self.path(name)) {
            Ok(wtr) => wtr.flexible(self.flexible),
            Err(err) => panic!("Could not open '{:?}': {}",
                                self.path(name), err),
        };
        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>more tries<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 = 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));

        // I don't get why this is necessary, but Travis seems to need it?
        // let md = fs::metadata(&dir);
        // if fs::metadata(&dir).map(|md| md.is_dir()).unwrap_or(false) {
            // if let Err(err) = fs::remove_dir_all(&dir) {
                // panic!("Could not remove directory '{:?}': {}", dir, err);
            // }
        // }
        // if fs::metadata(&dir).map(|md| md.is_file()).unwrap_or(false) {
            // if let Err(err) = fs::remove_file(&dir) {
                // panic!("Could not remove file '{:?}': {}", dir, err);
            // }
        // }
        if let Err(err) = fs::create_dir_all(&dir) {
            let md = fs::metadata(&dir).unwrap();
            panic!("Could not create '{:?}': {} -- {}, {}, {}",
                   dir, err, md.is_dir(), md.is_file(), md.len());
        }
        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 = match csv::Writer::from_file(&self.path(name)) {
            Ok(wtr) => wtr.flexible(self.flexible),
            Err(err) => panic!("Could not open '{:?}': {}",
                                self.path(name), err),
        };
        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>extern crate edit_distance;

#[test]
fn simple() {
    assert_eq!(edit_distance::edit_distance("kitten", "sitting"), 3);
    assert_eq!(edit_distance::edit_distance("Tier", "Tor"), 2);
}
<commit_msg>Some more tests<commit_after>extern crate edit_distance;

#[test]
fn simple() {
    assert_eq!(edit_distance::edit_distance("kitten", "sitting"), 3);
    assert_eq!(edit_distance::edit_distance("Tier", "Tor"), 2);
}

#[test]
fn same() {
    assert_eq!(edit_distance::edit_distance("kitten", "kitten"), 0);
}

#[test]
fn empty_a() {
    assert_eq!(edit_distance::edit_distance("", "kitten"), 6);
}

#[test]
fn empty_b() {
    assert_eq!(edit_distance::edit_distance("sitting", ""), 7);
}

#[test]
fn empty_both() {
    assert_eq!(edit_distance::edit_distance("", ""), 0);
}
<|endoftext|>