<commit_before>use std::fs::File;
use std::io::*;
use std::mem;
use std::slice;
use std::thread;

use super::FONT;
use super::Event;
use super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// True if the window should not wait for events
    async: bool,
    /// The input scheme
    file: File,
    /// Window data
    data: Box<[Color]>,
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Box<Self>> {
        Window::new_flags(x, y, w, h, title, false)
    }

    /// Create a new window with flags
    pub fn new_flags(x: i32, y: i32, w: u32, h: u32, title: &str, async: bool) -> Option<Box<Self>> {
        match File::open(&format!("orbital:{}/{}/{}/{}/{}/{}", if async { "a" } else { "" }, x, y, w, h, title)) {
            Ok(file) => {
                Some(box Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    async: async,
                    file: file,
                    data: vec![Color::rgb(0, 0, 0); (w * h * 4) as usize].into_boxed_slice(),
                })
            }
            Err(_) => None,
        }
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Ok(path) = self.file.path() {
            // orbital:/x/y/w/h/t
            if let Some(path_str) = path.to_str() {
                let mut parts = path_str.split('/').skip(1);
                if let Some(x) = parts.next() {
                    self.x = x.parse::<i32>().unwrap_or(0);
                }
                if let Some(y) = parts.next() {
                    self.y = y.parse::<i32>().unwrap_or(0);
                }
                if let Some(w) = parts.next() {
                    self.w = w.parse::<u32>().unwrap_or(0);
                }
                if let Some(h) = parts.next() {
                    self.h = h.parse::<u32>().unwrap_or(0);
                }
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get width
    pub fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    pub fn height(&self) -> u32 {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, _: &str) {
        // TODO
    }

    pub fn data(&self) -> &[Color] {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut [Color] {
        &mut self.data
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: i32, y: i32, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as i32 && y < self.h as i32 {
            let new = color.data;

            let alpha = (new >> 24) & 0xFF;
            if alpha > 0 {
                let old = &mut self.data[y as usize * self.w as usize + x as usize].data;
                if alpha >= 255 {
                    *old = new;
                } else {
                    let n_r = (((new >> 16) & 0xFF) * alpha) >> 8;
                    let n_g = (((new >> 8) & 0xFF) * alpha) >> 8;
                    let n_b = ((new & 0xFF) * alpha) >> 8;

                    let n_alpha = 255 - alpha;
                    let o_a = (((*old >> 24) & 0xFF) * n_alpha) >> 8;
                    let o_r = (((*old >> 16) & 0xFF) * n_alpha) >> 8;
                    let o_g = (((*old >> 8) & 0xFF) * n_alpha) >> 8;
                    let o_b = ((*old & 0xFF) * n_alpha) >> 8;

                    *old = ((o_a << 24) | (o_r << 16) | (o_g << 8) | o_b) + ((alpha << 24) | (n_r << 16) | (n_g << 8) | n_b);
                }
            }
        }
    }

    pub fn line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: Color) {
        let triangle_x = x2 - x1;
        let triangle_y = y2 - y1;

        if triangle_x > triangle_y {
            let ratio = triangle_y as f32 / triangle_x as f32;
            for pixel in x1..x2 {
                self.pixel(pixel, y1 + (ratio * pixel as f32 - x1 as f32) as i32);
            }
        } else if triangle_y >= triangle_x {
            let ratio = triangle_x as f32 / triangle_y as f32;
            for pixel in y1..y2 {
                self.pixel(x1 + (ratio * pixel as f32 - y1 as f32) as i32, pixel);
            }
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < FONT.len() {
                row_data = FONT[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as i32, y + row as i32, color);
                }
            }
            offset += 1;
        }
    }

    // TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        for mut d in self.data.iter_mut() {
            *d = color;
        }
    }

    /// Draw rectangle
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn rect(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, color: Color) {
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                self.pixel(x, y, color);
            }
        }
    }

    /// Display an image
    // TODO: Improve speed
    pub fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Blocking iterator over events
    pub fn events(&mut self) -> EventIter {
        let mut iter = EventIter {
            events: [Event::new(); 128],
            i: 0,
            count: 0,
        };

        'blocking: loop {
            //Should it be cleared? iter.events = [Event::new(); 128];
            match self.file.read(unsafe {
                slice::from_raw_parts_mut(iter.events.as_mut_ptr() as *mut u8, iter.events.len() * mem::size_of::<Event>())
            }){
                Ok(0) => if ! self.async {
                    thread::yield_now();
                } else {
                    break 'blocking;
                },
                Ok(count) => {
                    iter.count = count/mem::size_of::<Event>();
                    break 'blocking;
                },
                Err(_) => break 'blocking,
            }
        }

        iter
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.write(unsafe {
            slice::from_raw_parts(self.data.as_ptr() as *const u8, self.data.len() * mem::size_of::<Color>())
        }).is_ok()
    }
}

/// Event iterator
pub struct EventIter {
    events: [Event; 128],
    i: usize,
    count: usize,
}

impl Iterator for EventIter {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        if self.i < self.count {
            if let Some(event) = self.events.get(self.i) {
                self.i += 1;
                Some(*event)
            } else {
                None
            }
        } else {
            None
        }
    }
}
<commit_msg>Added docstring to line function<commit_after>use std::fs::File;
use std::io::*;
use std::mem;
use std::slice;
use std::thread;

use super::FONT;
use super::Event;
use super::Color;

/// A window
pub struct Window {
    /// The x coordinate of the window
    x: i32,
    /// The y coordinate of the window
    y: i32,
    /// The width of the window
    w: u32,
    /// The height of the window
    h: u32,
    /// The title of the window
    t: String,
    /// True if the window should not wait for events
    async: bool,
    /// The input scheme
    file: File,
    /// Window data
    data: Box<[Color]>,
}

impl Window {
    /// Create a new window
    pub fn new(x: i32, y: i32, w: u32, h: u32, title: &str) -> Option<Box<Self>> {
        Window::new_flags(x, y, w, h, title, false)
    }

    /// Create a new window with flags
    pub fn new_flags(x: i32, y: i32, w: u32, h: u32, title: &str, async: bool) -> Option<Box<Self>> {
        match File::open(&format!("orbital:{}/{}/{}/{}/{}/{}", if async { "a" } else { "" }, x, y, w, h, title)) {
            Ok(file) => {
                Some(box Window {
                    x: x,
                    y: y,
                    w: w,
                    h: h,
                    t: title.to_string(),
                    async: async,
                    file: file,
                    data: vec![Color::rgb(0, 0, 0); (w * h * 4) as usize].into_boxed_slice(),
                })
            }
            Err(_) => None,
        }
    }

    // TODO: Replace with smarter mechanism, maybe a move event?
    pub fn sync_path(&mut self) {
        if let Ok(path) = self.file.path() {
            // orbital:/x/y/w/h/t
            if let Some(path_str) = path.to_str() {
                let mut parts = path_str.split('/').skip(1);
                if let Some(x) = parts.next() {
                    self.x = x.parse::<i32>().unwrap_or(0);
                }
                if let Some(y) = parts.next() {
                    self.y = y.parse::<i32>().unwrap_or(0);
                }
                if let Some(w) = parts.next() {
                    self.w = w.parse::<u32>().unwrap_or(0);
                }
                if let Some(h) = parts.next() {
                    self.h = h.parse::<u32>().unwrap_or(0);
                }
            }
        }
    }

    /// Get x
    // TODO: Sync with window movements
    pub fn x(&self) -> i32 {
        self.x
    }

    /// Get y
    // TODO: Sync with window movements
    pub fn y(&self) -> i32 {
        self.y
    }

    /// Get width
    pub fn width(&self) -> u32 {
        self.w
    }

    /// Get height
    pub fn height(&self) -> u32 {
        self.h
    }

    /// Get title
    pub fn title(&self) -> String {
        self.t.clone()
    }

    /// Set title
    pub fn set_title(&mut self, _: &str) {
        // TODO
    }

    pub fn data(&self) -> &[Color] {
        &self.data
    }

    pub fn data_mut(&mut self) -> &mut [Color] {
        &mut self.data
    }

    /// Draw a pixel
    pub fn pixel(&mut self, x: i32, y: i32, color: Color) {
        if x >= 0 && y >= 0 && x < self.w as i32 && y < self.h as i32 {
            let new = color.data;

            let alpha = (new >> 24) & 0xFF;
            if alpha > 0 {
                let old = &mut self.data[y as usize * self.w as usize + x as usize].data;
                if alpha >= 255 {
                    *old = new;
                } else {
                    let n_r = (((new >> 16) & 0xFF) * alpha) >> 8;
                    let n_g = (((new >> 8) & 0xFF) * alpha) >> 8;
                    let n_b = ((new & 0xFF) * alpha) >> 8;

                    let n_alpha = 255 - alpha;
                    let o_a = (((*old >> 24) & 0xFF) * n_alpha) >> 8;
                    let o_r = (((*old >> 16) & 0xFF) * n_alpha) >> 8;
                    let o_g = (((*old >> 8) & 0xFF) * n_alpha) >> 8;
                    let o_b = ((*old & 0xFF) * n_alpha) >> 8;

                    *old = ((o_a << 24) | (o_r << 16) | (o_g << 8) | o_b) + ((alpha << 24) | (n_r << 16) | (n_g << 8) | n_b);
                }
            }
        }
    }

    /// Draw a line
    pub fn line(&mut self, x1: i32, y1: i32, x2: i32, y2: i32, color: Color) {
        let triangle_x = x2 - x1;
        let triangle_y = y2 - y1;

        if triangle_x > triangle_y {
            let ratio = triangle_y as f32 / triangle_x as f32;
            for pixel in x1..x2 {
                self.pixel(pixel, y1 + (ratio * pixel as f32 - x1 as f32) as i32);
            }
        } else if triangle_y >= triangle_x {
            let ratio = triangle_x as f32 / triangle_y as f32;
            for pixel in y1..y2 {
                self.pixel(x1 + (ratio * pixel as f32 - y1 as f32) as i32, pixel);
            }
        }
    }

    /// Draw a character, using the loaded font
    pub fn char(&mut self, x: i32, y: i32, c: char, color: Color) {
        let mut offset = (c as usize) * 16;
        for row in 0..16 {
            let row_data;
            if offset < FONT.len() {
                row_data = FONT[offset];
            } else {
                row_data = 0;
            }

            for col in 0..8 {
                let pixel = (row_data >> (7 - col)) & 1;
                if pixel > 0 {
                    self.pixel(x + col as i32, y + row as i32, color);
                }
            }
            offset += 1;
        }
    }

    // TODO move, resize, set_title

    /// Set entire window to a color
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn set(&mut self, color: Color) {
        for mut d in self.data.iter_mut() {
            *d = color;
        }
    }

    /// Draw rectangle
    // TODO: Improve speed
    #[allow(unused_variables)]
    pub fn rect(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, color: Color) {
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                self.pixel(x, y, color);
            }
        }
    }

    /// Display an image
    // TODO: Improve speed
    pub fn image(&mut self, start_x: i32, start_y: i32, w: u32, h: u32, data: &[Color]) {
        let mut i = 0;
        for y in start_y..start_y + h as i32 {
            for x in start_x..start_x + w as i32 {
                if i < data.len() {
                    self.pixel(x, y, data[i])
                }
                i += 1;
            }
        }
    }

    /// Blocking iterator over events
    pub fn events(&mut self) -> EventIter {
        let mut iter = EventIter {
            events: [Event::new(); 128],
            i: 0,
            count: 0,
        };

        'blocking: loop {
            //Should it be cleared? iter.events = [Event::new(); 128];
            match self.file.read(unsafe {
                slice::from_raw_parts_mut(iter.events.as_mut_ptr() as *mut u8, iter.events.len() * mem::size_of::<Event>())
            }){
                Ok(0) => if ! self.async {
                    thread::yield_now();
                } else {
                    break 'blocking;
                },
                Ok(count) => {
                    iter.count = count/mem::size_of::<Event>();
                    break 'blocking;
                },
                Err(_) => break 'blocking,
            }
        }

        iter
    }

    /// Flip the window buffer
    pub fn sync(&mut self) -> bool {
        self.file.write(unsafe {
            slice::from_raw_parts(self.data.as_ptr() as *const u8, self.data.len() * mem::size_of::<Color>())
        }).is_ok()
    }
}

/// Event iterator
pub struct EventIter {
    events: [Event; 128],
    i: usize,
    count: usize,
}

impl Iterator for EventIter {
    type Item = Event;
    fn next(&mut self) -> Option<Event> {
        if self.i < self.count {
            if let Some(event) = self.events.get(self.i) {
                self.i += 1;
                Some(*event)
            } else {
                None
            }
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>//! Access to I/O ports

use core::marker::PhantomData;

pub use crate::structures::port::{PortRead, PortReadWrite, PortWrite};

impl PortRead for u8 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn read_from_port(port: u16) -> u8 {
        let value: u8;
        asm!("inb $1, $0" : "={al}"(value) : "N{dx}"(port) :: "volatile");
        value
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn read_from_port(port: u16) -> u8 {
        crate::asm::x86_64_asm_read_from_port_u8(port)
    }
}

impl PortRead for u16 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn read_from_port(port: u16) -> u16 {
        let value: u16;
        asm!("inw $1, $0" : "={ax}"(value) : "N{dx}"(port) :: "volatile");
        value
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn read_from_port(port: u16) -> u16 {
        crate::asm::x86_64_asm_read_from_port_u16(port)
    }
}

impl PortRead for u32 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn read_from_port(port: u16) -> u32 {
        let value: u32;
        asm!("inl $1, $0" : "={eax}"(value) : "N{dx}"(port) :: "volatile");
        value
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn read_from_port(port: u16) -> u32 {
        crate::asm::x86_64_asm_read_from_port_u32(port)
    }
}

impl PortWrite for u8 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn write_to_port(port: u16, value: u8) {
        asm!("outb $1, $0" :: "N{dx}"(port), "{al}"(value) :: "volatile");
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn write_to_port(port: u16, value: u8) {
        crate::asm::x86_64_asm_write_to_port_u8(port, value)
    }
}

impl PortWrite for u16 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn write_to_port(port: u16, value: u16) {
        asm!("outw $1, $0" :: "N{dx}"(port), "{ax}"(value) :: "volatile");
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn write_to_port(port: u16, value: u16) {
        crate::asm::x86_64_asm_write_to_port_u16(port, value)
    }
}

impl PortWrite for u32 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn write_to_port(port: u16, value: u32) {
        asm!("outl $1, $0" :: "N{dx}"(port), "{eax}"(value) :: "volatile");
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn write_to_port(port: u16, value: u32) {
        crate::asm::x86_64_asm_write_to_port_u32(port, value)
    }
}

impl PortReadWrite for u8 {}
impl PortReadWrite for u16 {}
impl PortReadWrite for u32 {}

/// A read only I/O port.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PortReadOnly<T: PortRead> {
    port: u16,
    phantom: PhantomData<T>,
}

/// A write only I/O port.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PortWriteOnly<T: PortWrite> {
    port: u16,
    phantom: PhantomData<T>,
}

/// An I/O port.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Port<T: PortReadWrite> {
    port: u16,
    phantom: PhantomData<T>,
}

impl<T: PortRead> PortReadOnly<T> {
    /// Creates a read only I/O port with the given port number.
    #[cfg(feature = "const_fn")]
    pub const fn new(port: u16) -> PortReadOnly<T> {
        PortReadOnly {
            port: port,
            phantom: PhantomData,
        }
    }

    /// Creates a read only I/O port with the given port number.
    #[cfg(not(feature = "const_fn"))]
    pub fn new(port: u16) -> PortReadOnly<T> {
        PortReadOnly {
            port: port,
            phantom: PhantomData,
        }
    }

    /// Reads from the port.
    ///
    /// This function is unsafe because the I/O port could have side effects that violate memory
    /// safety.
    #[inline]
    pub unsafe fn read(&mut self) -> T {
        T::read_from_port(self.port)
    }
}

impl<T: PortWrite> PortWriteOnly<T> {
    /// Creates a write only I/O port with the given port number.
    #[cfg(feature = "const_fn")]
    pub const fn new(port: u16) -> PortWriteOnly<T> {
        PortWriteOnly {
            port: port,
            phantom: PhantomData,
        }
    }

    /// Creates a write only I/O port with the given port number.
    #[cfg(not(feature = "const_fn"))]
    pub fn new(port: u16) -> PortWriteOnly<T> {
        PortWriteOnly {
            port: port,
            phantom: PhantomData,
        }
    }

    /// Writes to the port.
    ///
    /// This function is unsafe because the I/O port could have side effects that violate memory
    /// safety.
    #[inline]
    pub unsafe fn write(&mut self, value: T) {
        T::write_to_port(self.port, value)
    }
}

impl<T: PortReadWrite> Port<T> {
    /// Creates an I/O port with the given port number.
    #[cfg(feature = "const_fn")]
    pub const fn new(port: u16) -> Port<T> {
        Port {
            port: port,
            phantom: PhantomData,
        }
    }

    /// Creates an I/O port with the given port number.
    #[cfg(not(feature = "const_fn"))]
    pub fn new(port: u16) -> Port<T> {
        Port {
            port: port,
            phantom: PhantomData,
        }
    }

    /// Reads from the port.
    ///
    /// This function is unsafe because the I/O port could have side effects that violate memory
    /// safety.
    #[inline]
    pub unsafe fn read(&mut self) -> T {
        T::read_from_port(self.port)
    }

    /// Writes to the port.
    ///
    /// This function is unsafe because the I/O port could have side effects that violate memory
    /// safety.
    #[inline]
    pub unsafe fn write(&mut self, value: T) {
        T::write_to_port(self.port, value)
    }
}
<commit_msg>redundant field names in struct initialization<commit_after>//! Access to I/O ports

use core::marker::PhantomData;

pub use crate::structures::port::{PortRead, PortReadWrite, PortWrite};

impl PortRead for u8 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn read_from_port(port: u16) -> u8 {
        let value: u8;
        asm!("inb $1, $0" : "={al}"(value) : "N{dx}"(port) :: "volatile");
        value
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn read_from_port(port: u16) -> u8 {
        crate::asm::x86_64_asm_read_from_port_u8(port)
    }
}

impl PortRead for u16 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn read_from_port(port: u16) -> u16 {
        let value: u16;
        asm!("inw $1, $0" : "={ax}"(value) : "N{dx}"(port) :: "volatile");
        value
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn read_from_port(port: u16) -> u16 {
        crate::asm::x86_64_asm_read_from_port_u16(port)
    }
}

impl PortRead for u32 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn read_from_port(port: u16) -> u32 {
        let value: u32;
        asm!("inl $1, $0" : "={eax}"(value) : "N{dx}"(port) :: "volatile");
        value
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn read_from_port(port: u16) -> u32 {
        crate::asm::x86_64_asm_read_from_port_u32(port)
    }
}

impl PortWrite for u8 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn write_to_port(port: u16, value: u8) {
        asm!("outb $1, $0" :: "N{dx}"(port), "{al}"(value) :: "volatile");
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn write_to_port(port: u16, value: u8) {
        crate::asm::x86_64_asm_write_to_port_u8(port, value)
    }
}

impl PortWrite for u16 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn write_to_port(port: u16, value: u16) {
        asm!("outw $1, $0" :: "N{dx}"(port), "{ax}"(value) :: "volatile");
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn write_to_port(port: u16, value: u16) {
        crate::asm::x86_64_asm_write_to_port_u16(port, value)
    }
}

impl PortWrite for u32 {
    #[cfg(feature = "inline_asm")]
    #[inline]
    unsafe fn write_to_port(port: u16, value: u32) {
        asm!("outl $1, $0" :: "N{dx}"(port), "{eax}"(value) :: "volatile");
    }

    #[cfg(not(feature = "inline_asm"))]
    unsafe fn write_to_port(port: u16, value: u32) {
        crate::asm::x86_64_asm_write_to_port_u32(port, value)
    }
}

impl PortReadWrite for u8 {}
impl PortReadWrite for u16 {}
impl PortReadWrite for u32 {}

/// A read only I/O port.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PortReadOnly<T: PortRead> {
    port: u16,
    phantom: PhantomData<T>,
}

/// A write only I/O port.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PortWriteOnly<T: PortWrite> {
    port: u16,
    phantom: PhantomData<T>,
}

/// An I/O port.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Port<T: PortReadWrite> {
    port: u16,
    phantom: PhantomData<T>,
}

impl<T: PortRead> PortReadOnly<T> {
    /// Creates a read only I/O port with the given port number.
    #[cfg(feature = "const_fn")]
    pub const fn new(port: u16) -> PortReadOnly<T> {
        PortReadOnly {
            port,
            phantom: PhantomData,
        }
    }

    /// Creates a read only I/O port with the given port number.
    #[cfg(not(feature = "const_fn"))]
    pub fn new(port: u16) -> PortReadOnly<T> {
        PortReadOnly {
            port,
            phantom: PhantomData,
        }
    }

    /// Reads from the port.
    ///
    /// This function is unsafe because the I/O port could have side effects that violate memory
    /// safety.
    #[inline]
    pub unsafe fn read(&mut self) -> T {
        T::read_from_port(self.port)
    }
}

impl<T: PortWrite> PortWriteOnly<T> {
    /// Creates a write only I/O port with the given port number.
    #[cfg(feature = "const_fn")]
    pub const fn new(port: u16) -> PortWriteOnly<T> {
        PortWriteOnly {
            port,
            phantom: PhantomData,
        }
    }

    /// Creates a write only I/O port with the given port number.
    #[cfg(not(feature = "const_fn"))]
    pub fn new(port: u16) -> PortWriteOnly<T> {
        PortWriteOnly {
            port,
            phantom: PhantomData,
        }
    }

    /// Writes to the port.
    ///
    /// This function is unsafe because the I/O port could have side effects that violate memory
    /// safety.
    #[inline]
    pub unsafe fn write(&mut self, value: T) {
        T::write_to_port(self.port, value)
    }
}

impl<T: PortReadWrite> Port<T> {
    /// Creates an I/O port with the given port number.
    #[cfg(feature = "const_fn")]
    pub const fn new(port: u16) -> Port<T> {
        Port {
            port,
            phantom: PhantomData,
        }
    }

    /// Creates an I/O port with the given port number.
    #[cfg(not(feature = "const_fn"))]
    pub fn new(port: u16) -> Port<T> {
        Port {
            port,
            phantom: PhantomData,
        }
    }

    /// Reads from the port.
    ///
    /// This function is unsafe because the I/O port could have side effects that violate memory
    /// safety.
    #[inline]
    pub unsafe fn read(&mut self) -> T {
        T::read_from_port(self.port)
    }

    /// Writes to the port.
    ///
    /// This function is unsafe because the I/O port could have side effects that violate memory
    /// safety.
    #[inline]
    pub unsafe fn write(&mut self, value: T) {
        T::write_to_port(self.port, value)
    }
}
<|endoftext|>


<commit_before>/// Derive a builder for a struct
///
/// Use in combiantion with [custom_derive][custom_derive].
///
/// [custom_derive]: https://crates.io/crates/custom_derive
///
/// # Examples
///
/// ```rust
/// #[macro_use] extern crate custom_derive;
/// #[macro_use] extern crate derive_builder;
///
/// custom_derive!{
///     #[derive(Debug, PartialEq, Default, Builder)]
///     struct Lorem {
///         ipsum: String,
///         dolor: i32,
///     }
/// }
///
/// fn main() {
///     let x = Lorem::default().ipsum("sit").dolor(42);
///     assert_eq!(x, Lorem { ipsum: "sit".into(), dolor: 42 });
/// }
/// ```
///
/// ## Generic structs
///
/// ```rust
/// #[macro_use] extern crate custom_derive;
/// #[macro_use] extern crate derive_builder;
///
/// custom_derive!{
///     #[derive(Debug, PartialEq, Default, Builder)]
///     struct GenLorem<T> {
///         ipsum: String,
///         dolor: T,
///     }
/// }
///
/// fn main() {
///     let x = GenLorem::default().ipsum("sit").dolor(42);
///     assert_eq!(x, GenLorem { ipsum: "sit".into(), dolor: 42 });
/// }
/// ```
///
/// ## Gotchas
///
/// - Tuple structs and unit structs are not supported as they have no field
///   names.
/// - When defining a generic struct, you cannot use `V` as a generic parameter
///   as this is what all setters are using.
///
#[macro_export]
macro_rules! Builder {
    // Strip empty argument list if given (Passed by custom_derive macro)
    (() $($body:tt)*) => {
        Builder! { $($body)* }
    };

    // Strip meta items, pub (if present) and struct from definition
    (
        $(#[$ignore:meta])*
        $(pub)* struct $($body:tt)*
    ) => {
        Builder! { $($body)* }
    };

    // Struct with generics.
    //
    // Receive parsed fields of normal struct from `__diesel_parse_struct_body`
    // and add implementation.
    //
    // These patterns must appear above those which start with an ident to
    // compile.
    (
        (
            struct_name = $struct_name:ident,
            generics = ($($generics:ident),*),
        ),
        fields = [$({
            field_name: $field_name:ident,
            column_name: $column_name:ident,
            field_ty: $field_ty:ty,
            field_kind: $field_kind:ident,
        })+],
    ) => {
        #[allow(dead_code)]
        impl<$($generics),*> $struct_name<$($generics),*> {
            $(
                fn $field_name<V: Into<$field_ty>>(mut self, value: V) -> Self {
                    self.$field_name = value.into();
                    self
                }
            )+
        }
    };

    // Struct without generics.
    //
    // Receive parsed fields of normal struct from `__diesel_parse_struct_body`
    // and add implementation.
    //
    // These patterns must appear above those which start with an ident to
    // compile.
    (
        (
            struct_name = $struct_name:ident,
            generics = (),
        ),
        fields = [$({
            field_name: $field_name:ident,
            column_name: $column_name:ident,
            field_ty: $field_ty:ty,
            field_kind: $field_kind:ident,
        })+],
    ) => {
        #[allow(dead_code)]
        impl $struct_name {
            $(
                fn $field_name<V: Into<$field_ty>>(mut self, value: V) -> Self {
                    self.$field_name = value.into();
                    self
                }
            )+
        }
    };

    // Handle struct with generics
    (
        $struct_name:ident <$($generics:ident),*>
        $body:tt $(;)*
    ) => {
        __diesel_parse_struct_body! {
            (
                struct_name = $struct_name,
                generics = ($($generics),*),
            ),
            callback = Builder,
            body = $body,
        }
    };

    // Handle struct with no generics
    (
        $struct_name:ident
        $body:tt $(;)*
    ) => {
        __diesel_parse_struct_body! {
            (
                struct_name = $struct_name,
                generics = (),
            ),
            callback = Builder,
            body = $body,
        }
    };
}
<commit_msg>Change generic label to `VALUE`<commit_after>/// Derive a builder for a struct
///
/// Use in combiantion with [custom_derive][custom_derive].
///
/// [custom_derive]: https://crates.io/crates/custom_derive
///
/// # Examples
///
/// ```rust
/// #[macro_use] extern crate custom_derive;
/// #[macro_use] extern crate derive_builder;
///
/// custom_derive!{
///     #[derive(Debug, PartialEq, Default, Builder)]
///     struct Lorem {
///         ipsum: String,
///         dolor: i32,
///     }
/// }
///
/// fn main() {
///     let x = Lorem::default().ipsum("sit").dolor(42);
///     assert_eq!(x, Lorem { ipsum: "sit".into(), dolor: 42 });
/// }
/// ```
///
/// ## Generic structs
///
/// ```rust
/// #[macro_use] extern crate custom_derive;
/// #[macro_use] extern crate derive_builder;
///
/// custom_derive!{
///     #[derive(Debug, PartialEq, Default, Builder)]
///     struct GenLorem<T> {
///         ipsum: String,
///         dolor: T,
///     }
/// }
///
/// fn main() {
///     let x = GenLorem::default().ipsum("sit").dolor(42);
///     assert_eq!(x, GenLorem { ipsum: "sit".into(), dolor: 42 });
/// }
/// ```
///
/// ## Gotchas
///
/// - Tuple structs and unit structs are not supported as they have no field
///   names.
/// - When defining a generic struct, you cannot use `V` as a generic parameter
///   as this is what all setters are using.
///
#[macro_export]
macro_rules! Builder {
    // Strip empty argument list if given (Passed by custom_derive macro)
    (() $($body:tt)*) => {
        Builder! { $($body)* }
    };

    // Strip meta items, pub (if present) and struct from definition
    (
        $(#[$ignore:meta])*
        $(pub)* struct $($body:tt)*
    ) => {
        Builder! { $($body)* }
    };

    // Struct with generics.
    //
    // Receive parsed fields of normal struct from `__diesel_parse_struct_body`
    // and add implementation.
    //
    // These patterns must appear above those which start with an ident to
    // compile.
    (
        (
            struct_name = $struct_name:ident,
            generics = ($($generics:ident),*),
        ),
        fields = [$({
            field_name: $field_name:ident,
            column_name: $column_name:ident,
            field_ty: $field_ty:ty,
            field_kind: $field_kind:ident,
        })+],
    ) => {
        #[allow(dead_code)]
        impl<$($generics),*> $struct_name<$($generics),*> {
            $(
                fn $field_name<VALUE: Into<$field_ty>>(mut self, value: VALUE) -> Self {
                    self.$field_name = value.into();
                    self
                }
            )+
        }
    };

    // Struct without generics.
    //
    // Receive parsed fields of normal struct from `__diesel_parse_struct_body`
    // and add implementation.
    //
    // These patterns must appear above those which start with an ident to
    // compile.
    (
        (
            struct_name = $struct_name:ident,
            generics = (),
        ),
        fields = [$({
            field_name: $field_name:ident,
            column_name: $column_name:ident,
            field_ty: $field_ty:ty,
            field_kind: $field_kind:ident,
        })+],
    ) => {
        #[allow(dead_code)]
        impl $struct_name {
            $(
                fn $field_name<VALUE: Into<$field_ty>>(mut self, value: VALUE) -> Self {
                    self.$field_name = value.into();
                    self
                }
            )+
        }
    };

    // Handle struct with generics
    (
        $struct_name:ident <$($generics:ident),*>
        $body:tt $(;)*
    ) => {
        __diesel_parse_struct_body! {
            (
                struct_name = $struct_name,
                generics = ($($generics),*),
            ),
            callback = Builder,
            body = $body,
        }
    };

    // Handle struct with no generics
    (
        $struct_name:ident
        $body:tt $(;)*
    ) => {
        __diesel_parse_struct_body! {
            (
                struct_name = $struct_name,
                generics = (),
            ),
            callback = Builder,
            body = $body,
        }
    };
}
<|endoftext|>


<commit_before>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![deny(missing_docs)]

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

extern crate log;
extern crate draw_state;
extern crate gfx_core as core;

/// public re-exported traits
pub mod traits {
    pub use core::{Device, Factory};
    pub use core::memory::Pod;
    pub use factory::FactoryExt;
}

// draw state re-exports
pub use draw_state::{preset, state};
pub use draw_state::target::*;

// public re-exports
pub use core::{Device, Resources, Primitive};
pub use core::{VertexCount, InstanceCount};
pub use core::{ShaderSet, VertexShader, HullShader, DomainShader, GeometryShader, PixelShader};
pub use core::{buffer, format, handle, texture, mapping};
pub use core::factory::{Factory, ResourceViewError, TargetViewError, CombinedError};
pub use core::memory::{self, Bind, TRANSFER_SRC, TRANSFER_DST, RENDER_TARGET,
                       DEPTH_STENCIL, SHADER_RESOURCE, UNORDERED_ACCESS};
pub use core::command::{Buffer as CommandBuffer, InstanceParams};
pub use core::shade::{ProgramInfo, UniformValue};

pub use encoder::{CopyBufferResult, CopyBufferTextureResult, CopyError,
                  CopyTextureBufferResult, Encoder, UpdateError};
pub use factory::PipelineStateError;
pub use slice::{Slice, IntoIndexBuffer, IndexBuffer};
pub use pso::{PipelineState};
pub use pso::buffer::{VertexBuffer, InstanceBuffer, RawVertexBuffer,
                      ConstantBuffer, RawConstantBuffer, Global};
pub use pso::resource::{ShaderResource, RawShaderResource, UnorderedAccess,
                        Sampler, TextureSampler};
pub use pso::target::{DepthStencilTarget, DepthTarget, StencilTarget,
                      RenderTarget, RawRenderTarget, BlendTarget, BlendRef, Scissor};
pub use pso::bundle::{Bundle};

/// Render commands encoder
mod encoder;
/// Factory extensions
mod factory;
/// Slices
mod slice;
// Pipeline states
pub mod pso;
/// Shaders
pub mod shade;
/// Convenience macros
pub mod macros;
<commit_msg>Reexport SubmissionError and SubmissionResult in gfx<commit_after>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![deny(missing_docs)]

//! An efficient, low-level, bindless graphics API for Rust. See [the
//! blog](http://gfx-rs.github.io/) for explanations and annotated examples.

extern crate log;
extern crate draw_state;
extern crate gfx_core as core;

/// public re-exported traits
pub mod traits {
    pub use core::{Device, Factory};
    pub use core::memory::Pod;
    pub use factory::FactoryExt;
}

// draw state re-exports
pub use draw_state::{preset, state};
pub use draw_state::target::*;

// public re-exports
pub use core::{Device, Primitive, Resources, SubmissionError, SubmissionResult};
pub use core::{VertexCount, InstanceCount};
pub use core::{ShaderSet, VertexShader, HullShader, DomainShader, GeometryShader, PixelShader};
pub use core::{buffer, format, handle, texture, mapping};
pub use core::factory::{Factory, ResourceViewError, TargetViewError, CombinedError};
pub use core::memory::{self, Bind, TRANSFER_SRC, TRANSFER_DST, RENDER_TARGET,
                       DEPTH_STENCIL, SHADER_RESOURCE, UNORDERED_ACCESS};
pub use core::command::{Buffer as CommandBuffer, InstanceParams};
pub use core::shade::{ProgramInfo, UniformValue};

pub use encoder::{CopyBufferResult, CopyBufferTextureResult, CopyError,
                  CopyTextureBufferResult, Encoder, UpdateError};
pub use factory::PipelineStateError;
pub use slice::{Slice, IntoIndexBuffer, IndexBuffer};
pub use pso::{PipelineState};
pub use pso::buffer::{VertexBuffer, InstanceBuffer, RawVertexBuffer,
                      ConstantBuffer, RawConstantBuffer, Global};
pub use pso::resource::{ShaderResource, RawShaderResource, UnorderedAccess,
                        Sampler, TextureSampler};
pub use pso::target::{DepthStencilTarget, DepthTarget, StencilTarget,
                      RenderTarget, RawRenderTarget, BlendTarget, BlendRef, Scissor};
pub use pso::bundle::{Bundle};

/// Render commands encoder
mod encoder;
/// Factory extensions
mod factory;
/// Slices
mod slice;
// Pipeline states
pub mod pso;
/// Shaders
pub mod shade;
/// Convenience macros
pub mod macros;
<|endoftext|>


<commit_before>extern crate hamming;

fn process_distance_case(strand_pair: [&str; 2], expected_distance: Option<usize>) {
    assert_eq!(
        hamming::hamming_distance(strand_pair[0], strand_pair[1]),
        expected_distance
    );
}

#[test]
fn test_empty_strands() {
    process_distance_case(["", ""], Some(0));
}

#[test]
#[ignore]
fn test_no_difference_between_identical_strands() {
    process_distance_case(["GGACTGA", "GGACTGA"], Some(0));
}

#[test]
#[ignore]
fn test_complete_hamming_distance_in_small_strand() {
    assert_eq!(hamming::hamming_distance("ACT", "GGA"), Some(3));
}

#[test]
#[ignore]
fn test_small_hamming_distance_in_the_middle_somewhere() {
    assert_eq!(hamming::hamming_distance("GGACG", "GGTCG"), Some(1));
}

#[test]
#[ignore]
fn test_larger_distance() {
    assert_eq!(hamming::hamming_distance("ACCAGGG", "ACTATGG"), Some(2));
}

#[test]
#[ignore]
fn test_first_string_is_longer() {
    assert_eq!(hamming::hamming_distance("AAA", "AA"), None);
}

#[test]
#[ignore]
fn test_second_string_is_longer() {
    assert_eq!(hamming::hamming_distance("A", "AA"), None);
}

#[test]
#[ignore]
/// non-unique character in first strand
fn test_nonunique_character_in_first_strand() {
    process_distance_case(["AAG", "AAA"], Some(1));
}

#[test]
#[ignore]
/// identical strands
fn test_identical_strands() {
    process_distance_case(["A", "A"], Some(0));
}

#[test]
#[ignore]
/// complete distance in small strands
fn test_complete_distance_in_small_strands() {
    process_distance_case(["AG", "CT"], Some(2));
}

#[test]
#[ignore]
/// disallow first strand longer
fn test_disallow_first_strand_longer() {
    process_distance_case(["AATG", "AAA"], None);
}

#[test]
#[ignore]
/// large distance
fn test_large_distance() {
    process_distance_case(["GATACA", "GCATAA"], Some(4));
}

#[test]
#[ignore]
/// long identical strands
fn test_long_identical_strands() {
    process_distance_case(["GGACTGA", "GGACTGA"], Some(0));
}

#[test]
#[ignore]
/// complete distance in single nucleotide strands
fn test_complete_distance_in_single_nucleotide_strands() {
    process_distance_case(["A", "G"], Some(1));
}

#[test]
#[ignore]
/// small distance
fn test_small_distance() {
    process_distance_case(["GGACG", "GGTCG"], Some(1));
}

#[test]
#[ignore]
/// non-unique character in second strand
fn test_nonunique_character_in_second_strand() {
    process_distance_case(["AAA", "AAG"], Some(1));
}

#[test]
#[ignore]
/// small distance in long strands
fn test_small_distance_in_long_strands() {
    process_distance_case(["ACCAGGG", "ACTATGG"], Some(2));
}

#[test]
#[ignore]
/// disallow second strand longer
fn test_disallow_second_strand_longer() {
    process_distance_case(["ATA", "AGTG"], None);
}

#[test]
#[ignore]
/// small distance in small strands
fn test_small_distance_in_small_strands() {
    process_distance_case(["AT", "CT"], Some(1));
}

#[test]
#[ignore]
/// large distance in off-by-one strand
fn test_large_distance_in_offbyone_strand() {
    process_distance_case(["GGACGGATTCTG", "AGGACGGATTCT"], Some(9));
}

#[test]
#[ignore]
/// same nucleotides in different positions
fn test_same_nucleotides_in_different_positions() {
    process_distance_case(["TAG", "GAT"], Some(2));
}
<commit_msg>hamming: Replaced the assert_eq! invocations in the old test cases with the process_distance_case function<commit_after>extern crate hamming;

fn process_distance_case(strand_pair: [&str; 2], expected_distance: Option<usize>) {
    assert_eq!(
        hamming::hamming_distance(strand_pair[0], strand_pair[1]),
        expected_distance
    );
}

#[test]
fn test_empty_strands() {
    process_distance_case(["", ""], Some(0));
}

#[test]
#[ignore]
fn test_no_difference_between_identical_strands() {
    process_distance_case(["GGACTGA", "GGACTGA"], Some(0));
}

#[test]
#[ignore]
fn test_complete_hamming_distance_in_small_strand() {
    process_distance_case(["ACT", "GGA"], Some(3));
}

#[test]
#[ignore]
fn test_small_hamming_distance_in_the_middle_somewhere() {
    process_distance_case(["GGACG", "GGTCG"], Some(1));
}

#[test]
#[ignore]
fn test_larger_distance() {
    process_distance_case(["ACCAGGG", "ACTATGG"], Some(2));
}

#[test]
#[ignore]
fn test_first_string_is_longer() {
    process_distance_case(["AAA", "AA"], None);
}

#[test]
#[ignore]
fn test_second_string_is_longer() {
    process_distance_case(["A", "AA"], None);
}

#[test]
#[ignore]
/// non-unique character in first strand
fn test_nonunique_character_in_first_strand() {
    process_distance_case(["AAG", "AAA"], Some(1));
}

#[test]
#[ignore]
/// identical strands
fn test_identical_strands() {
    process_distance_case(["A", "A"], Some(0));
}

#[test]
#[ignore]
/// complete distance in small strands
fn test_complete_distance_in_small_strands() {
    process_distance_case(["AG", "CT"], Some(2));
}

#[test]
#[ignore]
/// disallow first strand longer
fn test_disallow_first_strand_longer() {
    process_distance_case(["AATG", "AAA"], None);
}

#[test]
#[ignore]
/// large distance
fn test_large_distance() {
    process_distance_case(["GATACA", "GCATAA"], Some(4));
}

#[test]
#[ignore]
/// long identical strands
fn test_long_identical_strands() {
    process_distance_case(["GGACTGA", "GGACTGA"], Some(0));
}

#[test]
#[ignore]
/// complete distance in single nucleotide strands
fn test_complete_distance_in_single_nucleotide_strands() {
    process_distance_case(["A", "G"], Some(1));
}

#[test]
#[ignore]
/// small distance
fn test_small_distance() {
    process_distance_case(["GGACG", "GGTCG"], Some(1));
}

#[test]
#[ignore]
/// non-unique character in second strand
fn test_nonunique_character_in_second_strand() {
    process_distance_case(["AAA", "AAG"], Some(1));
}

#[test]
#[ignore]
/// small distance in long strands
fn test_small_distance_in_long_strands() {
    process_distance_case(["ACCAGGG", "ACTATGG"], Some(2));
}

#[test]
#[ignore]
/// disallow second strand longer
fn test_disallow_second_strand_longer() {
    process_distance_case(["ATA", "AGTG"], None);
}

#[test]
#[ignore]
/// small distance in small strands
fn test_small_distance_in_small_strands() {
    process_distance_case(["AT", "CT"], Some(1));
}

#[test]
#[ignore]
/// large distance in off-by-one strand
fn test_large_distance_in_offbyone_strand() {
    process_distance_case(["GGACGGATTCTG", "AGGACGGATTCT"], Some(9));
}

#[test]
#[ignore]
/// same nucleotides in different positions
fn test_same_nucleotides_in_different_positions() {
    process_distance_case(["TAG", "GAT"], Some(2));
}
<|endoftext|>


<commit_before>use delivery::git::git_command;
use delivery::utils::copy_recursive;
use delivery::utils::say;
use std::io::prelude::*;
use tempdir::TempDir;
use std::fs::File;
use support::paths::fixture_file;
use std::process::Command;
use std::env;
use rustc_serialize::json::Json;
use delivery::utils::path_join_many::PathJoinMany;

// ** Functions used in tests **

fn setup() {
    say::turn_off_spinner();
}

/// Sets up a mock delivery git project from the test_repo fixture.
/// Includes copying in the `.delivery/config.json` that you plan
/// on using.
fn setup_mock_delivery_project_git(dot_config: &str) -> TempDir {
    let tmpdir = TempDir::new("mock-delivery-remote").unwrap();
    let test_repo_path = fixture_file("test_repo");
    panic_on_error!(copy_recursive(&test_repo_path.join(".delivery"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&test_repo_path.join("README.md"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&test_repo_path.join("cookbooks"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&fixture_file(dot_config), &tmpdir.path().join_many(&[".delivery", "config.json"])));
    panic_on_error!(git_command(&["init", tmpdir.path().to_str().unwrap()], tmpdir.path()));
    panic_on_error!(git_command(&["add", "."], tmpdir.path()));
    panic_on_error!(git_command(&["commit", "-a", "-m", "Initial Commit"], tmpdir.path()));
    tmpdir
}

/// Given a path, it copies the build cookbook into it, and turns it
/// into a git repository
fn setup_build_cookbook_project(tmpdir: &TempDir) {
    let build_cookbook_path = fixture_file("delivery_test");
    panic_on_error!(copy_recursive(&build_cookbook_path, &tmpdir.path().to_path_buf()));
    panic_on_error!(git_command(&["init", tmpdir.path().join("delivery_test").to_str().unwrap()], &tmpdir.path().join("delivery_test")));
    panic_on_error!(git_command(&["add", "."], &tmpdir.path().join("delivery_test")));
    panic_on_error!(git_command(&["commit", "-a", "-m", "Initial Commit"], &tmpdir.path().join("delivery_test")));
}

/// Clones a mock delivery git project to a local copy, as if it was
/// on a workstation. Also creates a mock delivery remote pointing at
/// the on-disk mocked delivery project.
fn setup_local_project_clone(delivery_project_git: &TempDir) -> TempDir {
    let tmpdir = TempDir::new("local-project").unwrap();
    panic_on_error!(git_command(&["clone",
                                  delivery_project_git.path().to_str().unwrap(),
                                  tmpdir.path().to_str().unwrap()
                                 ], tmpdir.path()));
    panic_on_error!(git_command(&["remote", "add", "delivery", delivery_project_git.path().to_str().unwrap()], tmpdir.path()));
    let result = panic_on_error!(delivery_cmd()
                    .arg("setup")
                    .arg("--user").arg("cavalera")
                    .arg("--server").arg("localhost")
                    .arg("--ent").arg("family")
                    .arg("--org").arg("sepultura")
                    .arg("--for").arg("master")
                    .arg("--config-path").arg(tmpdir.path().to_str().unwrap())
                    .current_dir(tmpdir.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed 'delivery setup'\nOUT: {}\nERR: {}\nPath: {}", &output, &error, tmpdir.path().to_str().unwrap());
    }
    tmpdir
}

/// Makes a change to a project on the named branch. Creates a
/// file named `filename` and writes some stuff to it.
///
/// When it returns, the project you pass in will be left on your
/// new branch.
fn setup_change(tmpdir: &TempDir, branch: &str, filename: &str) {
    panic_on_error!(git_command(&["checkout", "master"], tmpdir.path()));
    panic_on_error!(git_command(&["branch", branch], tmpdir.path()));
    {
        let mut f = panic_on_error!(File::create(&tmpdir.path().join(filename)));
        panic_on_error!(f.write_all(b"I like cookies"));
    }
    panic_on_error!(git_command(&["add", "."], tmpdir.path()));
    panic_on_error!(git_command(&["commit", "-a", "-m", filename], tmpdir.path()));
}

/// Checks out the named branch
fn setup_checkout_branch(tmpdir: &TempDir, branch: &str) {
    panic_on_error!(git_command(&["checkout", branch], tmpdir.path()));
}

/// Calls delivery review, and creates the two stub branches that the
/// api would create (`_reviews/PIPELINE/BRANCH/1` and `_reviews/PIPELINE/BRANCH/latest`)
fn delivery_review(local: &TempDir, remote: &TempDir, branch: &str, pipeline: &str) {
    panic_on_error!(git_command(&["checkout", branch], local.path()));
    let result = panic_on_error!(delivery_cmd().arg("review").arg("--no-open").arg("--for").arg(pipeline).current_dir(&local.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed 'delivery review'\nOUT: {}\nERR: {}\nPath: {}", &output, &error, local.path().to_str().unwrap());
    }
    // Stub out the behavior of the delivery-api
    panic_on_error!(git_command(&["branch", &format!("_reviews/{}/{}/1", pipeline, branch)], remote.path()));
    panic_on_error!(git_command(&["branch", &format!("_reviews/{}/{}/latest", pipeline, branch)], remote.path()));
}

/// Returns a Command set to the delivery binary created when you
/// ran `cargo test`.
fn delivery_cmd() -> Command {
    let mut delivery_path = env::current_exe().unwrap();
    delivery_path.pop();
    Command::new(delivery_path.join("delivery").to_str().unwrap())
}

/// A handy debugging function. Insert it when you want to sleep,
/// pass it a tmpdir, and you can inspect it.
///
/// Make sure you run `cargo test -- --nocapture` to see the output.
#[allow(dead_code)]
fn debug_sleep(tmpdir: &TempDir) {
    println!("Sleeping for 1000 seconds for {:?}", tmpdir.path());
    panic_on_error!(Command::new("sleep").arg("1000").output());
}

// ** Actual tests **

// Tests `delivery review`. Fails if the command fails, or if we fail to create
// the remote branch _for/master/rust/test, which is what we need to push to
// the API server.
test!(review {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git);
    setup_change(&local_project, "rust/test", "freaky");
    delivery_review(&local_project, &delivery_project_git, "rust/test", "master");
    setup_checkout_branch(&delivery_project_git, "_for/master/rust/test");
});

test!(job_verify_unit_with_path_config {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git);
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project, "rust/test", "freaky");
    let result = panic_on_error!(delivery_cmd().
                                 arg("job").
                                 arg("verify").
                                 arg("unit").
                                 arg("--no-spinner").
                                 arg("--job-root").arg(job_root.path().to_str().unwrap()).
                                 current_dir(local_project.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed 'delivery job verify unit'\nOUT: {}\nERR: {}\nPath: {}", &output, &error, local_project.path().to_str().unwrap());
    }
});

test!(job_verify_unit_with_git_config {
    let delivery_project_git = setup_mock_delivery_project_git("git_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git);
    let job_root = TempDir::new("job-root").unwrap();
    setup_build_cookbook_project(&job_root);
    setup_change(&local_project, "rust/test", "freaky");
    let result = panic_on_error!(delivery_cmd().
                                 arg("job").
                                 arg("verify").
                                 arg("unit").
                                 arg("--no-spinner").
                                 arg("--job-root").arg(job_root.path().to_str().unwrap()).
                                 current_dir(local_project.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed 'delivery verify unit'\nOUT: {}\nERR: {}\nPath: {}", &output, &error, local_project.path().to_str().unwrap());
    }
});

test!(job_verify_unit_with_supermarket_config {
    let delivery_project_git = setup_mock_delivery_project_git("supermarket_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git);
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project, "rust/test", "freaky");
    let result = panic_on_error!(delivery_cmd().
                                 arg("job").
                                 arg("verify").
                                 arg("unit").
                                 arg("--no-spinner").
                                 arg("--job-root").arg(job_root.path().to_str().unwrap()).
                                 current_dir(local_project.path()).output());
    if result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("The 'delivery verify unit' ought to have failed\nOUT: {}\nERR: {}\nPath: {}", &output, &error, local_project.path().to_str().unwrap());
    }
    assert!(job_root.path().join_many(&["chef", "cookbooks", "httpd"]).is_dir());
    assert!(job_root.path().join_many(&["chef", "cookbooks", "httpd", "templates", "default", "magic.erb"]).is_file());
});

test!(job_verify_dna_json {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git);
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project, "rust/test", "freaky");
    let result = panic_on_error!(delivery_cmd().
                                 arg("job").
                                 arg("verify").
                                 arg("unit").
                                 arg("--no-spinner").
                                 arg("--job-root").arg(job_root.path().to_str().unwrap()).
                                 current_dir(local_project.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed 'delivery job verify unit'\nOUT: {}\nERR: {}\nPath: {}", &output, &error, local_project.path().to_str().unwrap());
    }
    let mut dna_file = panic_on_error!(File::open(&job_root.path().join_many(&["chef", "dna.json"])));
    let mut dna_json = String::new();
    panic_on_error!(dna_file.read_to_string(&mut dna_json));
    let dna_data = panic_on_error!(Json::from_str(&dna_json));
    match dna_data.find_path(&["delivery", "workspace", "repo"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("repo").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/repo, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "chef"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("chef").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/chef, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "cache"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("cache").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/cache, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "root"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().to_str().unwrap());
        },
        None => panic!("No delivery/workspace/root, {}", dna_data)
    };
    match dna_data.find_path(&["delivery_builder", "build_user"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), "dbuild");
        },
        None => panic!("No delivery_builderl/build_user, {}", dna_data)
    };
});

<commit_msg>Fix delivery review integration test<commit_after>use delivery::git::git_command;
use delivery::utils::copy_recursive;
use delivery::utils::say;
use std::io::prelude::*;
use tempdir::TempDir;
use std::fs::File;
use support::paths::fixture_file;
use std::process::Command;
use std::env;
use rustc_serialize::json::Json;
use delivery::utils::path_join_many::PathJoinMany;

// ** Functions used in tests **

fn setup() {
    say::turn_off_spinner();
}

/// Sets up a mock delivery git project from the test_repo fixture.
/// Includes copying in the `.delivery/config.json` that you plan
/// on using.
fn setup_mock_delivery_project_git(dot_config: &str) -> TempDir {
    let tmpdir = TempDir::new("mock-delivery-remote").unwrap();
    let test_repo_path = fixture_file("test_repo");
    panic_on_error!(copy_recursive(&test_repo_path.join(".delivery"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&test_repo_path.join("README.md"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&test_repo_path.join("cookbooks"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&fixture_file(dot_config), &tmpdir.path().join_many(&[".delivery", "config.json"])));
    panic_on_error!(git_command(&["init", tmpdir.path().to_str().unwrap()], tmpdir.path()));
    panic_on_error!(git_command(&["add", "."], tmpdir.path()));
    panic_on_error!(git_command(&["commit", "-a", "-m", "Initial Commit"], tmpdir.path()));
    tmpdir
}

/// Given a path, it copies the build cookbook into it, and turns it
/// into a git repository
fn setup_build_cookbook_project(tmpdir: &TempDir) {
    let build_cookbook_path = fixture_file("delivery_test");
    panic_on_error!(copy_recursive(&build_cookbook_path, &tmpdir.path().to_path_buf()));
    panic_on_error!(git_command(&["init", tmpdir.path().join("delivery_test").to_str().unwrap()], &tmpdir.path().join("delivery_test")));
    panic_on_error!(git_command(&["add", "."], &tmpdir.path().join("delivery_test")));
    panic_on_error!(git_command(&["commit", "-a", "-m", "Initial Commit"], &tmpdir.path().join("delivery_test")));
}

/// Clones a mock delivery git project to a local copy, as if it was
/// on a workstation. Also creates a mock delivery remote pointing at
/// the on-disk mocked delivery project.
fn setup_local_project_clone(delivery_project_git: &TempDir) -> TempDir {
    let tmpdir = TempDir::new("local-project").unwrap();
    panic_on_error!(git_command(&["clone",
                                  delivery_project_git.path().to_str().unwrap(),
                                  tmpdir.path().to_str().unwrap()
                                 ], tmpdir.path()));
    panic_on_error!(git_command(&["remote", "add", "delivery", delivery_project_git.path().to_str().unwrap()], tmpdir.path()));
    let result = panic_on_error!(delivery_cmd()
                    .arg("setup")
                    .arg("--user").arg("cavalera")
                    .arg("--server").arg("localhost")
                    .arg("--ent").arg("family")
                    .arg("--org").arg("sepultura")
                    .arg("--for").arg("master")
                    .arg("--config-path").arg(tmpdir.path().to_str().unwrap())
                    .current_dir(tmpdir.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed 'delivery setup'\nOUT: {}\nERR: {}\nPath: {}", &output, &error, tmpdir.path().to_str().unwrap());
    }
    tmpdir
}

/// Makes a change to a project on the named branch. Creates a
/// file named `filename` and writes some stuff to it.
///
/// When it returns, the project you pass in will be left on your
/// new branch.
fn setup_change(tmpdir: &TempDir, branch: &str, filename: &str) {
    panic_on_error!(git_command(&["checkout", "master"], tmpdir.path()));
    panic_on_error!(git_command(&["branch", branch], tmpdir.path()));
    {
        let mut f = panic_on_error!(File::create(&tmpdir.path().join(filename)));
        panic_on_error!(f.write_all(b"I like cookies"));
    }
    panic_on_error!(git_command(&["add", filename], tmpdir.path()));
    panic_on_error!(git_command(&["commit", "-a", "-m", filename], tmpdir.path()));
}

/// Checks out the named branch
fn setup_checkout_branch(tmpdir: &TempDir, branch: &str) {
    panic_on_error!(git_command(&["checkout", branch], tmpdir.path()));
}

/// Calls delivery review, and creates the two stub branches that the
/// api would create (`_reviews/PIPELINE/BRANCH/1` and `_reviews/PIPELINE/BRANCH/latest`)
fn delivery_review(local: &TempDir, remote: &TempDir, branch: &str, pipeline: &str) {
    panic_on_error!(git_command(&["checkout", branch], local.path()));
    let result = panic_on_error!(delivery_cmd().arg("review").arg("--no-open").arg("--for").arg(pipeline).current_dir(&local.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed 'delivery review'\nOUT: {}\nERR: {}\nPath: {}", &output, &error, local.path().to_str().unwrap());
    }
    // Stub out the behavior of the delivery-api
    panic_on_error!(git_command(&["branch", &format!("_reviews/{}/{}/1", pipeline, branch)], remote.path()));
    panic_on_error!(git_command(&["branch", &format!("_reviews/{}/{}/latest", pipeline, branch)], remote.path()));
}

/// Returns a Command set to the delivery binary created when you
/// ran `cargo test`.
fn delivery_cmd() -> Command {
    let mut delivery_path = env::current_exe().unwrap();
    delivery_path.pop();
    Command::new(delivery_path.join("delivery").to_str().unwrap())
}

/// A handy debugging function. Insert it when you want to sleep,
/// pass it a tmpdir, and you can inspect it.
///
/// Make sure you run `cargo test -- --nocapture` to see the output.
#[allow(dead_code)]
fn debug_sleep(tmpdir: &TempDir) {
    println!("Sleeping for 1000 seconds for {:?}", tmpdir.path());
    panic_on_error!(Command::new("sleep").arg("1000").output());
}

// ** Actual tests **

// Tests `delivery review`. Fails if the command fails, or if we fail to create
// the remote branch _for/master/rust/test, which is what we need to push to
// the API server.
test!(review {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git);
    setup_change(&local_project, "rust/test", "freaky");
    delivery_review(&local_project, &delivery_project_git, "rust/test", "master");
    setup_checkout_branch(&delivery_project_git, "_for/master/rust/test");
});

test!(job_verify_unit_with_path_config {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git);
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project, "rust/test", "freaky");
    let result = panic_on_error!(delivery_cmd().
                                 arg("job").
                                 arg("verify").
                                 arg("unit").
                                 arg("--no-spinner").
                                 arg("--job-root").arg(job_root.path().to_str().unwrap()).
                                 current_dir(local_project.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed 'delivery job verify unit'\nOUT: {}\nERR: {}\nPath: {}", &output, &error, local_project.path().to_str().unwrap());
    }
});

test!(job_verify_unit_with_git_config {
    let delivery_project_git = setup_mock_delivery_project_git("git_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git);
    let job_root = TempDir::new("job-root").unwrap();
    setup_build_cookbook_project(&job_root);
    setup_change(&local_project, "rust/test", "freaky");
    let result = panic_on_error!(delivery_cmd().
                                 arg("job").
                                 arg("verify").
                                 arg("unit").
                                 arg("--no-spinner").
                                 arg("--job-root").arg(job_root.path().to_str().unwrap()).
                                 current_dir(local_project.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed 'delivery verify unit'\nOUT: {}\nERR: {}\nPath: {}", &output, &error, local_project.path().to_str().unwrap());
    }
});

test!(job_verify_unit_with_supermarket_config {
    let delivery_project_git = setup_mock_delivery_project_git("supermarket_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git);
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project, "rust/test", "freaky");
    let result = panic_on_error!(delivery_cmd().
                                 arg("job").
                                 arg("verify").
                                 arg("unit").
                                 arg("--no-spinner").
                                 arg("--job-root").arg(job_root.path().to_str().unwrap()).
                                 current_dir(local_project.path()).output());
    if result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("The 'delivery verify unit' ought to have failed\nOUT: {}\nERR: {}\nPath: {}", &output, &error, local_project.path().to_str().unwrap());
    }
    assert!(job_root.path().join_many(&["chef", "cookbooks", "httpd"]).is_dir());
    assert!(job_root.path().join_many(&["chef", "cookbooks", "httpd", "templates", "default", "magic.erb"]).is_file());
});

test!(job_verify_dna_json {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git);
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project, "rust/test", "freaky");
    let result = panic_on_error!(delivery_cmd().
                                 arg("job").
                                 arg("verify").
                                 arg("unit").
                                 arg("--no-spinner").
                                 arg("--job-root").arg(job_root.path().to_str().unwrap()).
                                 current_dir(local_project.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed 'delivery job verify unit'\nOUT: {}\nERR: {}\nPath: {}", &output, &error, local_project.path().to_str().unwrap());
    }
    let mut dna_file = panic_on_error!(File::open(&job_root.path().join_many(&["chef", "dna.json"])));
    let mut dna_json = String::new();
    panic_on_error!(dna_file.read_to_string(&mut dna_json));
    let dna_data = panic_on_error!(Json::from_str(&dna_json));
    match dna_data.find_path(&["delivery", "workspace", "repo"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("repo").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/repo, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "chef"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("chef").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/chef, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "cache"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("cache").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/cache, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "root"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().to_str().unwrap());
        },
        None => panic!("No delivery/workspace/root, {}", dna_data)
    };
    match dna_data.find_path(&["delivery_builder", "build_user"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), "dbuild");
        },
        None => panic!("No delivery_builderl/build_user, {}", dna_data)
    };
});

<|endoftext|>


<commit_before>extern crate atomicwrites;
extern crate tempdir;

use std::{fs,path};
use std::io::{Read,Write};
use atomicwrites::{AtomicFile,AllowOverwrite,DisallowOverwrite};
use tempdir::TempDir;

fn get_tmp() -> path::PathBuf {
    TempDir::new_in(".", "atomicwrites-test").unwrap().into_path()
}

#[test]
fn test_simple_allow_override() {
    let tmpdir = get_tmp();
    let path = tmpdir.join("haha");

    let af = AtomicFile::new(&path, AllowOverwrite);
    af.write(|f| f.write_all(b"HELLO")).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(&rv[..], "HELLO");
}

#[test]
fn test_simple_disallow_override() {
    let tmpdir = get_tmp();
    let path = tmpdir.join("haha");

    let af = AtomicFile::new(&path, DisallowOverwrite);
    af.write(|f| f.write_all(b"HELLO")).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(&rv[..], "HELLO");
}

#[test]
fn test_allowed_pathtypes() {
    AtomicFile::new("haha", DisallowOverwrite);
    AtomicFile::new(&"haha", DisallowOverwrite);
    AtomicFile::new(&path::Path::new("haha"), DisallowOverwrite);
    AtomicFile::new(&path::PathBuf::from("haha"), DisallowOverwrite);
}

#[test]
fn test_unicode() {
    let dmitri = "Дмитрий";
    let greeting = format!("HELLO {}", dmitri);

    let tmpdir = get_tmp();
    let path = tmpdir.join(dmitri);

    let af = AtomicFile::new(&path, DisallowOverwrite);
    af.write(|f| {
        f.write_all(greeting.as_bytes())
    }).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(rv, greeting);
}
<commit_msg>Add more tests<commit_after>extern crate atomicwrites;
extern crate tempdir;

use std::{fs,path};
use std::io::{Read,Write};
use atomicwrites::{AtomicFile,AllowOverwrite,DisallowOverwrite};
use tempdir::TempDir;

fn get_tmp() -> path::PathBuf {
    TempDir::new_in(".", "atomicwrites-test").unwrap().into_path()
}

#[test]
fn test_simple_allow_override() {
    let tmpdir = get_tmp();
    let path = tmpdir.join("haha");

    let af = AtomicFile::new(&path, AllowOverwrite);
    af.write(|f| f.write_all(b"HELLO")).unwrap();
    af.write(|f| f.write_all(b"HELLO")).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(&rv[..], "HELLO");
}

#[test]
fn test_simple_disallow_override() {
    let tmpdir = get_tmp();
    let path = tmpdir.join("haha");

    let af = AtomicFile::new(&path, DisallowOverwrite);
    af.write(|f| f.write_all(b"HELLO")).unwrap();
    assert!(af.write(|f| f.write_all(b"HELLO")).is_err());

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(&rv[..], "HELLO");
}

#[test]
fn test_allowed_pathtypes() {
    AtomicFile::new("haha", DisallowOverwrite);
    AtomicFile::new(&"haha", DisallowOverwrite);
    AtomicFile::new(&path::Path::new("haha"), DisallowOverwrite);
    AtomicFile::new(&path::PathBuf::from("haha"), DisallowOverwrite);
}

#[test]
fn test_unicode() {
    let dmitri = "Дмитрий";
    let greeting = format!("HELLO {}", dmitri);

    let tmpdir = get_tmp();
    let path = tmpdir.join(dmitri);

    let af = AtomicFile::new(&path, DisallowOverwrite);
    af.write(|f| {
        f.write_all(greeting.as_bytes())
    }).unwrap();

    let mut rv = String::new();
    let mut testfd = fs::File::open(&path).unwrap();
    testfd.read_to_string(&mut rv).unwrap();
    assert_eq!(rv, greeting);
}
<|endoftext|>


<commit_before>extern crate hal;
extern crate arrayfire as af;

use af::{Array, Dim4};

use hal::{utils, activations, initializations, loss};

fn verify_derivative<F>(ufunc: F, name: &str, kinks: bool)
  where F : Fn(&Array) -> Array
{
  println!("\nGradient testing {}...", name);
  let dims = Dim4::new(&[32, 1, 1, 1]);
  let x = initializations::normal(dims, 0.05f32);
  let grad = activations::get_derivative(name, &ufunc(&x)).unwrap();
  match kinks {
    true  => utils::verify_gradient_kinks(ufunc, &x, 1e-5, &grad).unwrap(),
    false => utils::verify_gradient_smooth(ufunc, &x, 1e-5, &grad).unwrap(),
  };
}

fn verify_func<F>(ufunc: F, name: &str, truth: &[f32])
  where F : Fn(&Array) -> Array
{
  println!("\nTesting unitary function {}...", name);
  let dims = Dim4::new(&[5, 1, 1, 1]);
  let x = Array::new(&[-1.0, 0.0, 1.0, 2.0, 3.0], dims).unwrap();

  // verify with L2 Loss
  let x_t = Array::new(truth, dims).unwrap();
  let l2 = loss::get_loss("l2", &ufunc(&x), &x_t).unwrap();
  assert!(l2 <= 1e-4, "L2 loss of {} is higher than expected: {}", name, l2);
}

#[test]
fn lrelu_gradient() {
  verify_derivative(activations::lrelu
                    , "lrelu"
                    , true);
}

#[test]
fn tanh_gradient() {
  verify_derivative(activations::tanh
                    , "tanh"
                    , false);
}

#[test]
fn sigmoid_gradient() {
  verify_derivative(activations::sigmoid
                    , "sigmoid"
                    , false);
}

// TODO: Why is this broken? Do you need softmax + xentropy
// #[test]
// fn softmax_gradient() {
//   verify_derivative(activations::softmax
//                     , "softmax"
//                     , false);
//}

#[test]
fn relu_gradient() {
  verify_derivative(activations::relu
                    , "relu"
                    , true);
}

#[test]
fn ones_gradient() {
  verify_derivative(activations::ones
                    , "ones"
                    , false);
}

/// Test unitary functions

#[test]
fn tanh(){
  verify_func(activations::tanh
              , "tanh"
              , &[-0.7616, 0.0000, 0.7616, 0.9640, 0.9951]);
}

#[test]
fn sigmoid(){
  verify_func(activations::sigmoid
              , "sigmoid"
              , &[0.2689, 0.5000, 0.7311, 0.8808, 0.9526]);
}

#[test]
fn relu(){
  verify_func(activations::relu
              , "relu"
              , &[0.0, 0.0, 1.0, 2.0, 3.0]);
}

#[test]
fn lrelu(){
  verify_func(activations::lrelu
              , "lrelu"
              , &[-0.01, 0.0, 1.0, 2.0, 3.0]);
}

#[test]
fn softmax(){
  verify_func(activations::softmax
              , "softmax"
              , &[0.0117, 0.0317, 0.0861, 0.2341, 0.6364]);
}

#[test]
fn ones(){
  verify_func(activations::ones
              , "ones"
              , &[-1.0, 0.0, 1.0, 2.0, 3.0]);
}
<commit_msg>add xent-softmax test [still missing derivative]<commit_after>extern crate hal;
extern crate arrayfire as af;

use af::{Array, Dim4};

use hal::{utils, activations, initializations, loss};

fn verify_derivative<F>(ufunc: F, name: &str, kinks: bool)
  where F : Fn(&Array) -> Array
{
  println!("\nGradient testing {}...", name);
  let dims = Dim4::new(&[32, 1, 1, 1]);
  let x = initializations::normal(dims, 0.05f32);
  let grad = activations::get_derivative(name, &ufunc(&x)).unwrap();
  match kinks {
    true  => utils::verify_gradient_kinks(ufunc, &x, 1e-5, &grad).unwrap(),
    false => utils::verify_gradient_smooth(ufunc, &x, 1e-5, &grad).unwrap(),
  };
}

fn verify_func<F>(ufunc: F, name: &str, truth: &[f32])
  where F : Fn(&Array) -> Array
{
  println!("\nTesting unitary function {}...", name);
  let dims = Dim4::new(&[5, 1, 1, 1]);
  let x = Array::new(&[-1.0, 0.0, 1.0, 2.0, 3.0], dims).unwrap();

  // verify with L2 Loss
  let x_t = Array::new(truth, dims).unwrap();
  let l2 = loss::get_loss("l2", &ufunc(&x), &x_t).unwrap();
  assert!(l2 <= 1e-4, "L2 loss of {} is higher than expected: {}", name, l2);
}

/// test derivatives

#[test]
fn lrelu_gradient() {
  verify_derivative(activations::lrelu
                    , "lrelu"
                    , true);
}

#[test]
fn tanh_gradient() {
  verify_derivative(activations::tanh
                    , "tanh"
                    , false);
}

#[test]
fn sigmoid_gradient() {
  verify_derivative(activations::sigmoid
                    , "sigmoid"
                    , false);
}

// TODO: Why is this broken? Do you need softmax + xentropy
// #[test]
// fn softmax_gradient() {
//   verify_derivative(activations::softmax
//                     , "softmax"
//                     , false);
//}

#[test]
fn relu_gradient() {
  verify_derivative(activations::relu
                    , "relu"
                    , true);
}

#[test]
fn ones_gradient() {
  verify_derivative(activations::ones
                    , "ones"
                    , false);
}

/// Test unitary functions

#[test]
fn tanh(){
  verify_func(activations::tanh
              , "tanh"
              , &[-0.7616, 0.0000, 0.7616, 0.9640, 0.9951]);
}

#[test]
fn sigmoid(){
  verify_func(activations::sigmoid
              , "sigmoid"
              , &[0.2689, 0.5000, 0.7311, 0.8808, 0.9526]);
}

#[test]
fn relu(){
  verify_func(activations::relu
              , "relu"
              , &[0.0, 0.0, 1.0, 2.0, 3.0]);
}

#[test]
fn lrelu(){
  verify_func(activations::lrelu
              , "lrelu"
              , &[-0.01, 0.0, 1.0, 2.0, 3.0]);
}

#[test]
fn softmax(){
  verify_func(activations::softmax
              , "softmax"
              , &[0.0117, 0.0317, 0.0861, 0.2341, 0.6364]);
}

#[test]
fn ones(){
  verify_func(activations::ones
              , "ones"
              , &[-1.0, 0.0, 1.0, 2.0, 3.0]);
}

/// test losses
#[test]
fn cross_entropy_softmax(){
  println!("\nTesting Cross-Entropy Softmax...");
  let dims = Dim4::new(&[5, 1, 1, 1]);
  let x = Array::new(&[-0.01, 0.00, 1.10, 2.20, 3.15], dims).unwrap();
  let target = Array::new(&[1.0, 0.00, 0.00, 0.00, 0.00], dims).unwrap();
  let x_t = 4.9980f32;

  let x_pred = loss::get_loss("cross_entropy"
                              , &activations::softmax(&x)
                              , &target).unwrap();
  let l2 = x_t * x_t - x_pred * x_pred;
  assert!(l2 < 1e-7
          , "cross-entropy-softmax loss is more than expected {} vs {} => {}"
          , x_t, x_pred, l2);
}
<|endoftext|>


<commit_before>
// extern crate file_api;

mod file_api;
mod http_buffer;
<commit_msg>remove lib to disable double launch of unit tests<commit_after><|endoftext|>


<commit_before>#![recursion_limit="128"]
#![no_std]
#[macro_use]
extern crate generic_array;
use core::cell::Cell;
use core::ops::Drop;
use generic_array::GenericArray;
use generic_array::sequence::*;
use generic_array::typenum::{U1, U3, U4, U97};

#[test]
fn test() {
    let mut list97 = [0; 97];
    for i in 0..97 {
        list97[i] = i as i32;
    }
    let l: GenericArray<i32, U97> = GenericArray::clone_from_slice(&list97);
    assert_eq!(l[0], 0);
    assert_eq!(l[1], 1);
    assert_eq!(l[32], 32);
    assert_eq!(l[56], 56);
}

#[test]
fn test_drop() {
    #[derive(Clone)]
    struct TestDrop<'a>(&'a Cell<u32>);

    impl<'a> Drop for TestDrop<'a> {
        fn drop(&mut self) {
            self.0.set(self.0.get() + 1);
        }
    }

    let drop_counter = Cell::new(0);
    {
        let _: GenericArray<TestDrop, U3> =
            arr![TestDrop; TestDrop(&drop_counter),
                           TestDrop(&drop_counter),
                           TestDrop(&drop_counter)];
    }
    assert_eq!(drop_counter.get(), 3);
}

#[test]
fn test_arr() {
    let test: GenericArray<u32, U3> = arr![u32; 1, 2, 3];
    assert_eq!(test[1], 2);
}

#[test]
fn test_copy() {
    let test = arr![u32; 1, 2, 3];
    let test2 = test;
    // if GenericArray is not copy, this should fail as a use of a moved value
    assert_eq!(test[1], 2);
    assert_eq!(test2[0], 1);
}

#[test]
fn test_iter_flat_map() {
    assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10));
}

#[derive(Debug, PartialEq, Eq)]
struct NoClone<T>(T);

#[test]
fn test_from_slice() {
    let arr = [1, 2, 3, 4];
    let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]);
    assert_eq!(&arr[..3], gen_arr.as_slice());
    let arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)];
    let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]);
    assert_eq!(&arr[..3], gen_arr.as_slice());
}

#[test]
fn test_from_mut_slice() {
    let mut arr = [1, 2, 3, 4];
    {
        let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]);
        gen_arr[2] = 10;
    }
    assert_eq!(arr, [1, 2, 10, 4]);
    let mut arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)];
    {
        let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]);
        gen_arr[2] = NoClone(10);
    }
    assert_eq!(arr, [NoClone(1), NoClone(2), NoClone(10), NoClone(4)]);
}

#[test]
fn test_default() {
    let arr = GenericArray::<u8, U1>::default();
    assert_eq!(arr[0], 0);
}

#[test]
fn test_from() {
    let data = [(1, 2, 3), (4, 5, 6), (7, 8, 9)];
    let garray: GenericArray<(usize, usize, usize), U3> = data.into();
    assert_eq!(&data, garray.as_slice());
}

#[test]
fn test_unit_macro() {
    let arr = arr![f32; 3.14];
    assert_eq!(arr[0], 3.14);
}

#[test]
fn test_empty_macro() {
    let _arr = arr![f32;];
}

#[test]
fn test_cmp() {
    arr![u8; 0x00].cmp(&arr![u8; 0x00]);
}

/// This test should cause a helpful compile error if uncommented.
// #[test]
// fn test_empty_macro2(){
//     let arr = arr![];
// }
#[cfg(feature = "serde")]
mod impl_serde {
    extern crate serde_json;

    use generic_array::GenericArray;
    use generic_array::typenum::U6;

    #[test]
    fn test_serde_implementation() {
        let array: GenericArray<f64, U6> = arr![f64; 0.0, 5.0, 3.0, 7.07192, 76.0, -9.0];
        let string = serde_json::to_string(&array).unwrap();
        assert_eq!(string, "[0.0,5.0,3.0,7.07192,76.0,-9.0]");

        let test_array: GenericArray<f64, U6> = serde_json::from_str(&string).unwrap();
        assert_eq!(test_array, array);
    }
}

#[test]
fn test_map() {
    let b: GenericArray<i32, U4> = GenericArray::generate(|i| i as i32 * 4).map(|x| x - 3);

    assert_eq!(b, arr![i32; -3, 1, 5, 9]);
}

#[test]
fn test_zip() {
    let a: GenericArray<_, U4> = GenericArray::generate(|i| i + 1);
    let b: GenericArray<_, U4> = GenericArray::generate(|i| i as i32 * 4);

    let c = a.zip(b, |r, l| r as i32 + l);

    assert_eq!(c, arr![i32; 1, 6, 11, 16]);
}

#[test]
fn test_from_iter() {
    use core::iter::repeat;

    let a: GenericArray<_, U4> = repeat(11).take(3).collect();

    assert_eq!(a, arr![i32; 11, 11, 11, 0]);
}

#[test]
fn test_sizes() {
    #![allow(dead_code)]
    use core::mem::{size_of, size_of_val};

    #[derive(Debug)]
    #[repr(C)]
    #[repr(packed)]
    #[derive(Default)]
    struct Test {
        t: u16,
        s: u32,
        r: u16,
        f: u16,
        o: u32,
    }

    assert_eq!(size_of::<Test>(), 14);

    assert_eq!(size_of_val(&arr![u8; 1, 2, 3]), size_of::<u8>() * 3);
    assert_eq!(size_of_val(&arr![u32; 1]), size_of::<u32>() * 1);
    assert_eq!(size_of_val(&arr![u64; 1, 2, 3, 4]), size_of::<u64>() * 4);

    assert_eq!(size_of::<GenericArray<Test, U97>>(), size_of::<Test>() * 97);
}

#[test]
fn test_resize() {
    let a = arr![i32; 1, 2, 3, 4];
    let b = arr![i32; 1, 2, 3];

    let (init, last) = a.shorten();

    assert_eq!(init, b);
    assert_eq!(last, 4);

    let c = init.lengthen(5);

    assert_eq!(c, arr![i32; 1, 2, 3, 5]);

    let d = init.shorten().0.lengthen(1)
                .shorten().0.lengthen(2)
                .shorten().0.lengthen(34);

    assert_eq!(d, arr![i32; 1, 2, 34]);
}

#[test]
fn test_split() {
    let a = arr![i32; 1, 2, 3, 4];

    let (b, c) = a.split();

    assert_eq!(b, arr![i32; 1]);
    assert_eq!(c, arr![i32; 2, 3, 4]);

    let (e, f) = a.split();

    assert_eq!(e, arr![i32; 1, 2]);
    assert_eq!(f, arr![i32; 3, 4]);
}

#[test]
fn test_concat() {

}<commit_msg>Add missing Concat test<commit_after>#![recursion_limit="128"]
#![no_std]
#[macro_use]
extern crate generic_array;
use core::cell::Cell;
use core::ops::Drop;
use generic_array::GenericArray;
use generic_array::sequence::*;
use generic_array::typenum::{U1, U3, U4, U97};

#[test]
fn test() {
    let mut list97 = [0; 97];
    for i in 0..97 {
        list97[i] = i as i32;
    }
    let l: GenericArray<i32, U97> = GenericArray::clone_from_slice(&list97);
    assert_eq!(l[0], 0);
    assert_eq!(l[1], 1);
    assert_eq!(l[32], 32);
    assert_eq!(l[56], 56);
}

#[test]
fn test_drop() {
    #[derive(Clone)]
    struct TestDrop<'a>(&'a Cell<u32>);

    impl<'a> Drop for TestDrop<'a> {
        fn drop(&mut self) {
            self.0.set(self.0.get() + 1);
        }
    }

    let drop_counter = Cell::new(0);
    {
        let _: GenericArray<TestDrop, U3> =
            arr![TestDrop; TestDrop(&drop_counter),
                           TestDrop(&drop_counter),
                           TestDrop(&drop_counter)];
    }
    assert_eq!(drop_counter.get(), 3);
}

#[test]
fn test_arr() {
    let test: GenericArray<u32, U3> = arr![u32; 1, 2, 3];
    assert_eq!(test[1], 2);
}

#[test]
fn test_copy() {
    let test = arr![u32; 1, 2, 3];
    let test2 = test;
    // if GenericArray is not copy, this should fail as a use of a moved value
    assert_eq!(test[1], 2);
    assert_eq!(test2[0], 1);
}

#[test]
fn test_iter_flat_map() {
    assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10));
}

#[derive(Debug, PartialEq, Eq)]
struct NoClone<T>(T);

#[test]
fn test_from_slice() {
    let arr = [1, 2, 3, 4];
    let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]);
    assert_eq!(&arr[..3], gen_arr.as_slice());
    let arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)];
    let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]);
    assert_eq!(&arr[..3], gen_arr.as_slice());
}

#[test]
fn test_from_mut_slice() {
    let mut arr = [1, 2, 3, 4];
    {
        let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]);
        gen_arr[2] = 10;
    }
    assert_eq!(arr, [1, 2, 10, 4]);
    let mut arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)];
    {
        let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]);
        gen_arr[2] = NoClone(10);
    }
    assert_eq!(arr, [NoClone(1), NoClone(2), NoClone(10), NoClone(4)]);
}

#[test]
fn test_default() {
    let arr = GenericArray::<u8, U1>::default();
    assert_eq!(arr[0], 0);
}

#[test]
fn test_from() {
    let data = [(1, 2, 3), (4, 5, 6), (7, 8, 9)];
    let garray: GenericArray<(usize, usize, usize), U3> = data.into();
    assert_eq!(&data, garray.as_slice());
}

#[test]
fn test_unit_macro() {
    let arr = arr![f32; 3.14];
    assert_eq!(arr[0], 3.14);
}

#[test]
fn test_empty_macro() {
    let _arr = arr![f32;];
}

#[test]
fn test_cmp() {
    arr![u8; 0x00].cmp(&arr![u8; 0x00]);
}

/// This test should cause a helpful compile error if uncommented.
// #[test]
// fn test_empty_macro2(){
//     let arr = arr![];
// }
#[cfg(feature = "serde")]
mod impl_serde {
    extern crate serde_json;

    use generic_array::GenericArray;
    use generic_array::typenum::U6;

    #[test]
    fn test_serde_implementation() {
        let array: GenericArray<f64, U6> = arr![f64; 0.0, 5.0, 3.0, 7.07192, 76.0, -9.0];
        let string = serde_json::to_string(&array).unwrap();
        assert_eq!(string, "[0.0,5.0,3.0,7.07192,76.0,-9.0]");

        let test_array: GenericArray<f64, U6> = serde_json::from_str(&string).unwrap();
        assert_eq!(test_array, array);
    }
}

#[test]
fn test_map() {
    let b: GenericArray<i32, U4> = GenericArray::generate(|i| i as i32 * 4).map(|x| x - 3);

    assert_eq!(b, arr![i32; -3, 1, 5, 9]);
}

#[test]
fn test_zip() {
    let a: GenericArray<_, U4> = GenericArray::generate(|i| i + 1);
    let b: GenericArray<_, U4> = GenericArray::generate(|i| i as i32 * 4);

    let c = a.zip(b, |r, l| r as i32 + l);

    assert_eq!(c, arr![i32; 1, 6, 11, 16]);
}

#[test]
fn test_from_iter() {
    use core::iter::repeat;

    let a: GenericArray<_, U4> = repeat(11).take(3).collect();

    assert_eq!(a, arr![i32; 11, 11, 11, 0]);
}

#[test]
fn test_sizes() {
    #![allow(dead_code)]
    use core::mem::{size_of, size_of_val};

    #[derive(Debug)]
    #[repr(C)]
    #[repr(packed)]
    #[derive(Default)]
    struct Test {
        t: u16,
        s: u32,
        r: u16,
        f: u16,
        o: u32,
    }

    assert_eq!(size_of::<Test>(), 14);

    assert_eq!(size_of_val(&arr![u8; 1, 2, 3]), size_of::<u8>() * 3);
    assert_eq!(size_of_val(&arr![u32; 1]), size_of::<u32>() * 1);
    assert_eq!(size_of_val(&arr![u64; 1, 2, 3, 4]), size_of::<u64>() * 4);

    assert_eq!(size_of::<GenericArray<Test, U97>>(), size_of::<Test>() * 97);
}

#[test]
fn test_resize() {
    let a = arr![i32; 1, 2, 3, 4];
    let b = arr![i32; 1, 2, 3];

    let (init, last) = a.shorten();

    assert_eq!(init, b);
    assert_eq!(last, 4);

    let c = init.lengthen(5);

    assert_eq!(c, arr![i32; 1, 2, 3, 5]);

    let d = init.shorten().0.lengthen(1)
                .shorten().0.lengthen(2)
                .shorten().0.lengthen(34);

    assert_eq!(d, arr![i32; 1, 2, 34]);
}

#[test]
fn test_split() {
    let a = arr![i32; 1, 2, 3, 4];

    let (b, c) = a.split();

    assert_eq!(b, arr![i32; 1]);
    assert_eq!(c, arr![i32; 2, 3, 4]);

    let (e, f) = a.split();

    assert_eq!(e, arr![i32; 1, 2]);
    assert_eq!(f, arr![i32; 3, 4]);
}

#[test]
fn test_concat() {
    let a = arr![i32; 1, 2];
    let b = arr![i32; 3, 4];

    let c = a.concat(b);

    assert_eq!(c, arr![i32; 1, 2, 3, 4]);

    let (d, e) = c.split();

    assert_eq!(d, arr![i32; 1]);
    assert_eq!(e, arr![i32; 2, 3, 4]);
}<|endoftext|>