<commit_before>use character::controls::CharacterControl;
use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_app::controls::{Control, TilemapControls};
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::{GlContext, KeyboardInput, MouseButton};
use glutin::ElementState::{Pressed, Released};
use glutin::VirtualKeyCode::{A, D, Escape, R, S, W, X, Z};
use glutin::dpi::{LogicalSize, PhysicalSize};

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct WindowContext {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl WindowContext {
  pub fn new() -> WindowContext {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      let logical_size = LogicalSize::new(RESOLUTION_X.into(), RESOLUTION_Y.into());
      window_title
        .with_dimensions(logical_size)
        .with_min_dimensions(logical_size)
        .with_max_dimensions(logical_size)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("No monitor found")
      };
      let monitor_resolution = monitor.get_dimensions();

      let resolution = ((monitor_resolution.width as f32 * 16.0 / 9.0) as u32, monitor_resolution.height);

      let logical_size = LogicalSize::new(resolution.0.into(), resolution.1.into());
      window_title.with_fullscreen(Some(monitor))
                  .with_decorations(false)
                  .with_dimensions(logical_size)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8);

    let (window, device, factory, rtv, dsv) =
      gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    WindowContext {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WindowStatus {
  Open,
  Close,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> WindowStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for WindowContext {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    if cfg!(feature = "windowed") {
      (RESOLUTION_X as f32, RESOLUTION_Y as f32)
    } else {
      let monitor = self.events_loop.get_available_monitors().nth(0).expect("No monitor found");
      let monitor_resolution = monitor.get_dimensions();
      ((monitor_resolution.width as f32 * 16.0 / 9.0) as f32, monitor_resolution.height as f32)
    }
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.get_hidpi_factor() as f32
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> WindowStatus {
    use glutin::WindowEvent::{CursorMoved, CloseRequested, MouseInput};

    // Hack for MacOS 10.14
    let resolution = self.get_viewport_size();
    self.window.resize(PhysicalSize::new(resolution.0.into(), resolution.1.into()));

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };

    let m_pos = &mut self.mouse_pos;
    let mut game_status = WindowStatus::Open;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => { process_keyboard_input(input, controls) },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            WindowStatus::Open
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            WindowStatus::Open
          }
          CursorMoved { position, .. } => {
            *m_pos = ((position.x as f32).into(), (position.y as f32).into());
            WindowStatus::Open
          }
          CloseRequested => WindowStatus::Close,
          _ => WindowStatus::Open,
        }
      } else {
        WindowStatus::Open
      };
    });
    game_status
  }
}

fn process_keyboard_input(input: glutin::KeyboardInput, controls: &mut TilemapControls) -> WindowStatus {
  match input {
    KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
      controls.zoom(&Control::Negative);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Plus);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Released);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
      controls.move_character(CharacterControl::Up);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::Down);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::YMoveStop);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
      controls.move_character(CharacterControl::Left);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::Right);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::XMoveStop);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(true);
    },
    KeyboardInput { state: Released, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(false);
    },
    KeyboardInput { state: Pressed, modifiers, .. } => {
      if modifiers.ctrl {
        controls.ctrl_pressed(true);
      }
    }
    KeyboardInput { state: Released, modifiers, .. } => {
      if !modifiers.ctrl {
        controls.ctrl_pressed(false);
      }
    }
  }
  if let Some(Escape) = input.virtual_keycode {
    WindowStatus::Close
  } else {
    WindowStatus::Open
  }
}

<commit_msg>Fix linter issue<commit_after>use character::controls::CharacterControl;
use game::constants::{RESOLUTION_X, RESOLUTION_Y};
use gfx;
use gfx_app::controls::{Control, TilemapControls};
use gfx_device_gl;
use gfx_window_glutin;
use glutin;
use glutin::{GlContext, KeyboardInput, MouseButton};
use glutin::ElementState::{Pressed, Released};
use glutin::VirtualKeyCode::{A, D, Escape, R, S, W, X, Z};
use glutin::dpi::{LogicalSize, PhysicalSize};

pub mod init;
pub mod renderer;
pub mod system;
pub mod controls;
pub mod mouse_controls;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

pub struct WindowContext {
  window: glutin::GlWindow,
  controls: Option<controls::TilemapControls>,
  events_loop: glutin::EventsLoop,
  device: gfx_device_gl::Device,
  factory: gfx_device_gl::Factory,
  render_target_view: gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat>,
  depth_stencil_view: gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat>,
  mouse_pos: (f64, f64),
}

impl WindowContext {
  pub fn new() -> WindowContext {
    let events_loop = glutin::EventsLoop::new();

    let window_title = glutin::WindowBuilder::new()
      .with_title("Hinterland");

    let builder = if cfg!(feature = "windowed") {
      let logical_size = LogicalSize::new(RESOLUTION_X.into(), RESOLUTION_Y.into());
      window_title
        .with_dimensions(logical_size)
        .with_min_dimensions(logical_size)
        .with_max_dimensions(logical_size)
    } else {
      let monitor = {
        events_loop.get_available_monitors().nth(0).expect("No monitor found")
      };
      let monitor_resolution = monitor.get_dimensions();

      let resolution = ((monitor_resolution.width as f32 * 16.0 / 9.0) as u32, monitor_resolution.height);

      let logical_size = LogicalSize::new(resolution.0.into(), resolution.1);
      window_title.with_fullscreen(Some(monitor))
                  .with_decorations(false)
                  .with_dimensions(logical_size)
    };

    let context = glutin::ContextBuilder::new()
      .with_vsync(true)
      .with_pixel_format(24, 8);

    let (window, device, factory, rtv, dsv) =
      gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder, context, &events_loop);

    WindowContext {
      window,
      controls: None,
      events_loop,
      device,
      factory,
      render_target_view: rtv,
      depth_stencil_view: dsv,
      mouse_pos: (0.0, 0.0),
    }
  }
}

#[derive(Debug, PartialEq, Eq)]
pub enum WindowStatus {
  Open,
  Close,
}

pub trait Window<D: gfx::Device, F: gfx::Factory<D::Resources>> {
  fn swap_window(&mut self);
  fn create_buffers(&mut self, count: usize) -> Vec<D::CommandBuffer>;
  fn set_controls(&mut self, controls: controls::TilemapControls);
  fn get_viewport_size(&mut self) -> (f32, f32);
  fn get_device(&mut self) -> &mut D;
  fn get_factory(&mut self) -> &mut F;
  fn get_hidpi_factor(&mut self) -> f32;
  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<D::Resources, ColorFormat>;
  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<D::Resources, DepthFormat>;
  fn poll_events(&mut self) -> WindowStatus;
}

impl Window<gfx_device_gl::Device, gfx_device_gl::Factory> for WindowContext {
  fn swap_window(&mut self) {
    use gfx::Device;
    self.window
        .swap_buffers()
        .expect("Unable to swap buffers");
    self.device.cleanup();
  }

  fn create_buffers(&mut self, count: usize) -> Vec<gfx_device_gl::CommandBuffer> {
    let mut bufs = Vec::new();
    for _ in 0..count {
      bufs.push(self.factory.create_command_buffer());
    }
    bufs
  }

  fn set_controls(&mut self, controls: controls::TilemapControls) {
    self.controls = Some(controls);
  }

  fn get_viewport_size(&mut self) -> (f32, f32) {
    if cfg!(feature = "windowed") {
      (RESOLUTION_X as f32, RESOLUTION_Y as f32)
    } else {
      let monitor = self.events_loop.get_available_monitors().nth(0).expect("No monitor found");
      let monitor_resolution = monitor.get_dimensions();
      ((monitor_resolution.width as f32 * 16.0 / 9.0) as f32, monitor_resolution.height as f32)
    }
  }

  fn get_device(&mut self) -> &mut gfx_device_gl::Device {
    &mut self.device
  }

  fn get_factory(&mut self) -> &mut gfx_device_gl::Factory {
    &mut self.factory
  }

  fn get_hidpi_factor(&mut self) -> f32 {
    self.window.get_hidpi_factor() as f32
  }

  fn get_render_target_view(&mut self) -> gfx::handle::RenderTargetView<gfx_device_gl::Resources, ColorFormat> {
    self.render_target_view.clone()
  }

  fn get_depth_stencil_view(&mut self) -> gfx::handle::DepthStencilView<gfx_device_gl::Resources, DepthFormat> {
    self.depth_stencil_view.clone()
  }

  fn poll_events(&mut self) -> WindowStatus {
    use glutin::WindowEvent::{CursorMoved, CloseRequested, MouseInput};

    // Hack for MacOS 10.14
    let resolution = self.get_viewport_size();
    self.window.resize(PhysicalSize::new(resolution.0.into(), resolution.1.into()));

    let controls = match self.controls {
      Some(ref mut c) => c,
      None => panic!("Terrain controls have not been initialized"),
    };

    let m_pos = &mut self.mouse_pos;
    let mut game_status = WindowStatus::Open;

    self.events_loop.poll_events(|event| {
      game_status = if let glutin::Event::WindowEvent { event, .. } = event {
        match event {
          glutin::WindowEvent::KeyboardInput { input, .. } => { process_keyboard_input(input, controls) },
          MouseInput { state: Pressed, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Left, .. } => {
            controls.mouse_left_click(None);
            WindowStatus::Open
          }
          MouseInput { state: Pressed, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(Some(*m_pos));
            WindowStatus::Open
          }
          MouseInput { state: Released, button: MouseButton::Right, .. } => {
            controls.mouse_right_click(None);
            WindowStatus::Open
          }
          CursorMoved { position, .. } => {
            *m_pos = ((position.x as f32).into(), (position.y as f32).into());
            WindowStatus::Open
          }
          CloseRequested => WindowStatus::Close,
          _ => WindowStatus::Open,
        }
      } else {
        WindowStatus::Open
      };
    });
    game_status
  }
}

fn process_keyboard_input(input: glutin::KeyboardInput, controls: &mut TilemapControls) -> WindowStatus {
  match input {
    KeyboardInput { state: Pressed, virtual_keycode: Some(Z), .. } => {
      controls.zoom(&Control::Negative);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Plus);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(Z), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(X), .. } => {
      controls.zoom(&Control::Released);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(W), .. } => {
      controls.move_character(CharacterControl::Up);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::Down);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(W), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(S), .. } => {
      controls.move_character(CharacterControl::YMoveStop);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(A), .. } => {
      controls.move_character(CharacterControl::Left);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::Right);
    }
    KeyboardInput { state: Released, virtual_keycode: Some(A), .. } |
    KeyboardInput { state: Released, virtual_keycode: Some(D), .. } => {
      controls.move_character(CharacterControl::XMoveStop);
    }
    KeyboardInput { state: Pressed, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(true);
    },
    KeyboardInput { state: Released, virtual_keycode: Some(R), .. } => {
      controls.reload_weapon(false);
    },
    KeyboardInput { state: Pressed, modifiers, .. } => {
      if modifiers.ctrl {
        controls.ctrl_pressed(true);
      }
    }
    KeyboardInput { state: Released, modifiers, .. } => {
      if !modifiers.ctrl {
        controls.ctrl_pressed(false);
      }
    }
  }
  if let Some(Escape) = input.virtual_keycode {
    WindowStatus::Close
  } else {
    WindowStatus::Open
  }
}

<|endoftext|>


<commit_before>//! Console logger

use log::*;

/// Logs to console
pub struct CLILogger;

impl CLILogger {
    pub fn init<'a>(level: &'a str) -> Result<(), SetLoggerError> {
        set_logger(|max_log_level| {
            max_log_level.set(match level {
                "info" => LogLevelFilter::Info,
                "debug" => LogLevelFilter::Debug,
                "error" => LogLevelFilter::Error,
                "warn" => LogLevelFilter::Warn,
                "trace" => LogLevelFilter::Trace,
                _ => LogLevelFilter::Info
            });
            Box::new(CLILogger)
        })
    }
}

impl Log for CLILogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= max_log_level()
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            if record.level() == LogLevel::Info {
                println!("{}", record.args());
            } else {
                println!("[{}] - {}", record.level(), record.args());
            }
        }
    }
}
<commit_msg>Print log level for info messages<commit_after>//! Console logger

use log::*;

/// Logs to console
pub struct CLILogger;

impl CLILogger {
    pub fn init<'a>(level: &'a str) -> Result<(), SetLoggerError> {
        set_logger(|max_log_level| {
            max_log_level.set(match level {
                "info" => LogLevelFilter::Info,
                "debug" => LogLevelFilter::Debug,
                "error" => LogLevelFilter::Error,
                "warn" => LogLevelFilter::Warn,
                "trace" => LogLevelFilter::Trace,
                _ => LogLevelFilter::Info
            });
            Box::new(CLILogger)
        })
    }
}

impl Log for CLILogger {
    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= max_log_level()
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            println!("[{}] - {}", record.level(), record.args());
        }
    }
}
<|endoftext|>


<commit_before>//! This module reexports the OS-specific module that actually implements Platform.
pub mod common;
pub use self::common::*;

#[cfg(windows)]
pub mod windows;
pub use self::windows::PlatformImpl;

#[cfg(unix)]
pub mod unix;

#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
pub mod bsd;

#[cfg(target_os = "freebsd")]
pub mod freebsd;
#[cfg(target_os = "freebsd")]
pub use self::freebsd::PlatformImpl;

#[cfg(target_os = "openbsd")]
pub mod openbsd;
#[cfg(target_os = "openbsd")]
pub use self::openbsd::PlatformImpl;

#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "linux")]
pub use self::linux::PlatformImpl;

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::time::Duration;

    #[test]
    fn test_cpu_load() {
        let load = PlatformImpl::new().cpu_load().unwrap();
        thread::sleep(Duration::from_millis(300));
        let load = load.done().unwrap();
        assert!(load.len() >= 1);
        for cpu in load.iter() {
            let sum = cpu.user + cpu.nice + cpu.system + cpu.interrupt + cpu.idle;
            assert!(sum > 0.95 && sum < 1.05);
        }
    }

    #[test]
    fn test_cpu_load_aggregate() {
        let cpu = PlatformImpl::new().cpu_load_aggregate().unwrap();
        thread::sleep(Duration::from_millis(300));
        let cpu = cpu.done().unwrap();
        let sum = cpu.user + cpu.nice + cpu.system + cpu.interrupt + cpu.idle;
        assert!(sum > 0.95 && sum < 1.05);
    }

    #[test]
    fn test_load_average() {
        let load = PlatformImpl::new().load_average().unwrap();
        assert!(load.one > 0.00001 && load.five > 0.00001 && load.fifteen > 0.00001);
    }

    #[test]
    fn test_memory() {
        let mem = PlatformImpl::new().memory().unwrap();
        assert!(mem.free.as_usize() > 1024 && mem.total.as_usize() > 1024);
    }

    #[test]
    fn test_battery_life() {
        if let Ok(bat) = PlatformImpl::new().battery_life() {
            assert!(bat.remaining_capacity <= 100.0 && bat.remaining_capacity >= 0.0);
        }
    }

    #[test]
    fn test_on_ac_power() {
        PlatformImpl::new().on_ac_power().unwrap();
    }

    #[test]
    fn test_mounts() {
        let mounts = PlatformImpl::new().mounts().unwrap();
        assert!(mounts.len() > 0);
        assert!(mounts.iter().find(|m| m.fs_mounted_on == "/").unwrap().fs_mounted_on == "/");
    }

    #[test]
    fn test_mount_at() {
        let mount = PlatformImpl::new().mount_at("/").unwrap();
        assert!(mount.fs_mounted_on == "/");
    }

    #[test]
    fn test_networks() {
        let networks = PlatformImpl::new().networks().unwrap();
        assert!(networks.values().find(|n| n.name == "lo0").unwrap().addrs.len() > 0);
    }

}
<commit_msg>Fix windows conditional<commit_after>//! This module reexports the OS-specific module that actually implements Platform.
pub mod common;
pub use self::common::*;

#[cfg(windows)]
pub mod windows;
#[cfg(windows)]
pub use self::windows::PlatformImpl;

#[cfg(unix)]
pub mod unix;

#[cfg(any(target_os = "freebsd", target_os = "openbsd"))]
pub mod bsd;

#[cfg(target_os = "freebsd")]
pub mod freebsd;
#[cfg(target_os = "freebsd")]
pub use self::freebsd::PlatformImpl;

#[cfg(target_os = "openbsd")]
pub mod openbsd;
#[cfg(target_os = "openbsd")]
pub use self::openbsd::PlatformImpl;

#[cfg(target_os = "linux")]
pub mod linux;
#[cfg(target_os = "linux")]
pub use self::linux::PlatformImpl;

#[cfg(test)]
mod tests {
    use super::*;
    use std::thread;
    use std::time::Duration;

    #[test]
    fn test_cpu_load() {
        let load = PlatformImpl::new().cpu_load().unwrap();
        thread::sleep(Duration::from_millis(300));
        let load = load.done().unwrap();
        assert!(load.len() >= 1);
        for cpu in load.iter() {
            let sum = cpu.user + cpu.nice + cpu.system + cpu.interrupt + cpu.idle;
            assert!(sum > 0.95 && sum < 1.05);
        }
    }

    #[test]
    fn test_cpu_load_aggregate() {
        let cpu = PlatformImpl::new().cpu_load_aggregate().unwrap();
        thread::sleep(Duration::from_millis(300));
        let cpu = cpu.done().unwrap();
        let sum = cpu.user + cpu.nice + cpu.system + cpu.interrupt + cpu.idle;
        assert!(sum > 0.95 && sum < 1.05);
    }

    #[test]
    fn test_load_average() {
        let load = PlatformImpl::new().load_average().unwrap();
        assert!(load.one > 0.00001 && load.five > 0.00001 && load.fifteen > 0.00001);
    }

    #[test]
    fn test_memory() {
        let mem = PlatformImpl::new().memory().unwrap();
        assert!(mem.free.as_usize() > 1024 && mem.total.as_usize() > 1024);
    }

    #[test]
    fn test_battery_life() {
        if let Ok(bat) = PlatformImpl::new().battery_life() {
            assert!(bat.remaining_capacity <= 100.0 && bat.remaining_capacity >= 0.0);
        }
    }

    #[test]
    fn test_on_ac_power() {
        PlatformImpl::new().on_ac_power().unwrap();
    }

    #[test]
    fn test_mounts() {
        let mounts = PlatformImpl::new().mounts().unwrap();
        assert!(mounts.len() > 0);
        assert!(mounts.iter().find(|m| m.fs_mounted_on == "/").unwrap().fs_mounted_on == "/");
    }

    #[test]
    fn test_mount_at() {
        let mount = PlatformImpl::new().mount_at("/").unwrap();
        assert!(mount.fs_mounted_on == "/");
    }

    #[test]
    fn test_networks() {
        let networks = PlatformImpl::new().networks().unwrap();
        assert!(networks.values().find(|n| n.name == "lo0").unwrap().addrs.len() > 0);
    }

}
<|endoftext|>


<commit_before>use std::collections::TreeMap;
use std::time::Duration;
use time::{get_time, Timespec};

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator
};
use message::{
    IrcMessage
};

static MAX_USER_RECORDS_KEPT: uint = 5;

pub struct SeenRecord {
    when: Timespec,
    message: IrcMessage
}

impl SeenRecord {
    fn new(when: Timespec, message: IrcMessage) -> SeenRecord {
        SeenRecord {
            when: when,
            message: message
        }
    }

    fn with_now(message: IrcMessage) -> SeenRecord {
        SeenRecord::new(get_time(), message)
    }
}

pub struct SeenPlugin {
    map: TreeMap<String, Vec<SeenRecord>>,
}

impl SeenPlugin {
    pub fn new() -> SeenPlugin {
        SeenPlugin {
            map: TreeMap::new()
        }
    }
}

fn trim_vec<T>(vec: Vec<T>) -> Vec<T> {
    if vec.len() <= MAX_USER_RECORDS_KEPT {
        return vec;
    }
    let excess_elem = vec.len() - MAX_USER_RECORDS_KEPT;
    vec.into_iter().skip(excess_elem).collect()
}

fn is_message_interesting(message: &IrcMessage) -> bool {
    match message.command() {
        // "JOIN" => true,
        // "ACTION" => true,
        "PRIVMSG" => true,
        "QUIT" => true,
        _ => false
    }
}

enum SeenCommandType<'a> {
    Seen(&'a str)
}

fn parse_seen<'a>(message: &'a IrcMessage) -> Option<SeenCommandType<'a>> {
    let message_body = message.get_arg(1).as_slice();
    match message_body.find(' ') {
        Some(idx) => Some(Seen(message_body.slice_from(idx + 1))),
        None => None
    }
}

fn parse_command<'a>(m: &CommandMapperDispatch, message: &'a IrcMessage) -> Option<SeenCommandType<'a>> {
    match m.command() {
        Some("seen") => parse_seen(message),
        Some(_) => None,
        None => None
    }
}

fn duration_to_string(dur: Duration) -> String {
    let seconds = dur.num_seconds();

    let days = dur.num_days();
    let hours = dur.num_hours();
    let minutes = dur.num_minutes();

    let mut string = String::new();
    if days > 0 {
        string = string.append(format!("{:d}d", days).as_slice());
    }
    if hours > 0 {
        string = string.append(format!("{:02d}h", hours).as_slice());
    }
    if minutes > 0 {
        string = string.append(format!("{:02d}m", minutes).as_slice());
    }
    if string.len() == 0 || seconds > 0 {
        string = string.append(format!("{:02d}s", seconds).as_slice());
    }
    string
}

fn format_activity(nick: &str, records: &Vec<SeenRecord>) -> String {
    let mut user_has_quit: Option<Timespec> = None;
    let mut prev_message: Option<&SeenRecord> = None;

    for record in records.iter().rev() {
        if record.message.command() == "QUIT" {
            user_has_quit = Some(record.when.clone());
        }
        if record.message.is_privmsg() {
            prev_message = Some(record);
            break;
        }
    }
    let now = get_time();
    match (user_has_quit, prev_message) {
        (Some(when_quit), Some(record)) => {
            format!(
                "{} said ``{}'' {} ago before quitting {} later",
                nick,
                record.message.get_arg(1),
                duration_to_string(now - record.when),
                duration_to_string(when_quit - record.when))
        },
        (None, Some(record)) => {
            // let message_sent = format_message_sent(message);
            format!(
                "{} said ``{}'' {} ago",
                nick,
                record.message.get_arg(1),
                duration_to_string(now - record.when))
        },
        (Some(when_quit), None) => {
            format!(
                "{} quit {} seconds ago",
                nick,
                duration_to_string(now - when_quit))
        },
        (None, None) => {
            format!("Sorry, I am very confused about {}", nick)
        }
    }
}

impl RustBotPlugin for SeenPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map("seen");
    }

    fn accept(&mut self, _m: &CommandMapperDispatch, message: &IrcMessage) {
        if !is_message_interesting(message) {
            return;
        }
        let source_nick = match message.source_nick() {
            Some(source_nick) => source_nick,
            None => return
        };
        match self.map.pop(&source_nick) {
            Some(mut records) => {
                records.push(SeenRecord::with_now(message.clone()));
                self.map.insert(source_nick, trim_vec(records));
            },
            None => {
                let records = vec![SeenRecord::with_now(message.clone())];
                self.map.insert(source_nick, records);
            }
        }
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMessage) {
        let source_nick = match message.source_nick() {
            Some(source_nick) => source_nick,
            None => return
        };

        if !message.target_is_channel() {
            return;
        }

        if !message.is_privmsg() {
            return;
        }

        match parse_command(m, message) {
            Some(Seen(target_nick)) => {
                if source_nick.as_slice() == target_nick {
                    m.reply(format!("Looking for yourself, {}?", source_nick));
                    return;
                }

                if m.current_nick() == target_nick {
                    m.reply(format!("You found me, {}!", source_nick));
                    return;
                }
                let target_nick_str = String::from_str(target_nick);
                let activity = match self.map.find(&target_nick_str) {
                    Some(val) => val,
                    None => {
                        m.reply(format!("{} is unknown", target_nick));
                        return
                    }
                };
                m.reply(format_activity(target_nick.as_slice(), activity));
            },
            None => return
        }
    }
}
<commit_msg>Maybe fix the !seen bug<commit_after>use std::collections::TreeMap;
use std::time::Duration;
use time::{get_time, Timespec};

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator
};
use message::{
    IrcMessage
};

static MAX_USER_RECORDS_KEPT: uint = 5;

pub struct SeenRecord {
    when: Timespec,
    message: IrcMessage
}

impl SeenRecord {
    fn new(when: Timespec, message: IrcMessage) -> SeenRecord {
        SeenRecord {
            when: when,
            message: message
        }
    }

    fn with_now(message: IrcMessage) -> SeenRecord {
        SeenRecord::new(get_time(), message)
    }
}

pub struct SeenPlugin {
    map: TreeMap<String, Vec<SeenRecord>>,
}

impl SeenPlugin {
    pub fn new() -> SeenPlugin {
        SeenPlugin {
            map: TreeMap::new()
        }
    }
}

fn trim_vec<T>(vec: Vec<T>) -> Vec<T> {
    if vec.len() <= MAX_USER_RECORDS_KEPT {
        return vec;
    }
    let excess_elem = vec.len() - MAX_USER_RECORDS_KEPT;
    vec.into_iter().skip(excess_elem).collect()
}

fn is_message_interesting(message: &IrcMessage) -> bool {
    match message.command() {
        // "JOIN" => true,
        // "ACTION" => true,
        "PRIVMSG" => true,
        "QUIT" => true,
        _ => false
    }
}

enum SeenCommandType<'a> {
    Seen(&'a str)
}

fn parse_seen<'a>(message: &'a IrcMessage) -> Option<SeenCommandType<'a>> {
    let message_body = message.get_arg(1).as_slice();
    match message_body.find(' ') {
        Some(idx) => Some(Seen(message_body.slice_from(idx + 1))),
        None => None
    }
}

fn parse_command<'a>(m: &CommandMapperDispatch, message: &'a IrcMessage) -> Option<SeenCommandType<'a>> {
    match m.command() {
        Some("seen") => parse_seen(message),
        Some(_) => None,
        None => None
    }
}

fn duration_to_string(dur: Duration) -> String {
    let days = dur.num_days();
    let hours = dur.num_hours() % 24;
    let minutes = dur.num_minutes() % 60;
    let seconds = dur.num_seconds() % 60;

    let mut string = String::new();
    if days > 0 {
        string = string.append(format!("{:d}d", days).as_slice());
    }
    if hours > 0 {
        string = string.append(format!("{:02d}h", hours).as_slice());
    }
    if minutes > 0 {
        string = string.append(format!("{:02d}m", minutes).as_slice());
    }
    if string.len() == 0 || seconds > 0 {
        string = string.append(format!("{:02d}s", seconds).as_slice());
    }
    string
}

fn format_activity(nick: &str, records: &Vec<SeenRecord>) -> String {
    let mut user_has_quit: Option<Timespec> = None;
    let mut prev_message: Option<&SeenRecord> = None;

    for record in records.iter().rev() {
        if record.message.command() == "QUIT" {
            user_has_quit = Some(record.when.clone());
        }
        if record.message.is_privmsg() {
            prev_message = Some(record);
            break;
        }
    }
    let now = get_time();
    match (user_has_quit, prev_message) {
        (Some(when_quit), Some(record)) => {
            format!(
                "{} said ``{}'' {} ago before quitting {} later",
                nick,
                record.message.get_arg(1),
                duration_to_string(now - record.when),
                duration_to_string(when_quit - record.when))
        },
        (None, Some(record)) => {
            // let message_sent = format_message_sent(message);
            format!(
                "{} said ``{}'' {} ago",
                nick,
                record.message.get_arg(1),
                duration_to_string(now - record.when))
        },
        (Some(when_quit), None) => {
            format!(
                "{} quit {} seconds ago",
                nick,
                duration_to_string(now - when_quit))
        },
        (None, None) => {
            format!("Sorry, I am very confused about {}", nick)
        }
    }
}

impl RustBotPlugin for SeenPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map("seen");
    }

    fn accept(&mut self, _m: &CommandMapperDispatch, message: &IrcMessage) {
        if !is_message_interesting(message) {
            return;
        }
        let source_nick = match message.source_nick() {
            Some(source_nick) => source_nick,
            None => return
        };
        match self.map.pop(&source_nick) {
            Some(mut records) => {
                records.push(SeenRecord::with_now(message.clone()));
                self.map.insert(source_nick, trim_vec(records));
            },
            None => {
                let records = vec![SeenRecord::with_now(message.clone())];
                self.map.insert(source_nick, records);
            }
        }
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMessage) {
        let source_nick = match message.source_nick() {
            Some(source_nick) => source_nick,
            None => return
        };

        if !message.target_is_channel() {
            return;
        }

        if !message.is_privmsg() {
            return;
        }

        match parse_command(m, message) {
            Some(Seen(target_nick)) => {
                if source_nick.as_slice() == target_nick {
                    m.reply(format!("Looking for yourself, {}?", source_nick));
                    return;
                }

                if m.current_nick() == target_nick {
                    m.reply(format!("You found me, {}!", source_nick));
                    return;
                }
                let target_nick_str = String::from_str(target_nick);
                let activity = match self.map.find(&target_nick_str) {
                    Some(val) => val,
                    None => {
                        m.reply(format!("{} is unknown", target_nick));
                        return
                    }
                };
                m.reply(format_activity(target_nick.as_slice(), activity));
            },
            None => return
        }
    }
}
<|endoftext|>


<commit_before>// spell-checker:ignore regfile
use crate::common::util::*;

static GIBBERISH: &str = "supercalifragilisticexpialidocious";

#[cfg(not(windows))]
static NOT_A_DIRECTORY: &str = "Not a directory";
#[cfg(windows)]
static NOT_A_DIRECTORY: &str = "The directory name is invalid.";

#[test]
fn test_resolve() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene.ucmd().arg("bar").succeeds().stdout_contains("foo\n");
}

#[test]
fn test_canonicalize() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-f").arg(".").run().stdout_move_str();
    let expect = at.root_dir_resolved() + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_canonicalize_existing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-e").arg(".").run().stdout_move_str();
    let expect = at.root_dir_resolved() + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_canonicalize_missing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-m").arg(GIBBERISH).run().stdout_move_str();
    let expect = path_concat!(at.root_dir_resolved(), GIBBERISH) + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_long_redirection_to_current_dir() {
    let (at, mut ucmd) = at_and_ucmd!();
    // Create a 256-character path to current directory
    let dir = path_concat!(".", ..128);
    let actual = ucmd.arg("-n").arg("-m").arg(dir).run().stdout_move_str();
    let expect = at.root_dir_resolved();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_long_redirection_to_root() {
    // Create a 255-character path to root
    let dir = path_concat!("..", ..85);
    let actual = new_ucmd!()
        .arg("-n")
        .arg("-m")
        .arg(dir)
        .run()
        .stdout_move_str();
    let expect = get_root_path();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_symlink_to_itself_verbose() {
    let (at, mut ucmd) = at_and_ucmd!();
    at.relative_symlink_file("a", "a");
    ucmd.args(&["-ev", "a"])
        .fails()
        .code_is(1)
        .stderr_contains("Too many levels of symbolic links");
}

#[test]
fn test_trailing_slash_regular_file() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    scene
        .ucmd()
        .args(&["-ev", "./regfile/"])
        .fails()
        .code_is(1)
        .stderr_contains(NOT_A_DIRECTORY)
        .no_stdout();
    scene
        .ucmd()
        .args(&["-e", "./regfile"])
        .succeeds()
        .stdout_contains("regfile");
}

#[test]
fn test_trailing_slash_symlink_to_regular_file() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    at.relative_symlink_file("regfile", "link");
    scene
        .ucmd()
        .args(&["-ev", "./link/"])
        .fails()
        .code_is(1)
        .stderr_contains(NOT_A_DIRECTORY)
        .no_stdout();
    scene
        .ucmd()
        .args(&["-e", "./link"])
        .succeeds()
        .stdout_contains("regfile");
    scene
        .ucmd()
        .args(&["-e", "./link/more"])
        .fails()
        .code_is(1)
        .no_stdout();
}

#[test]
fn test_trailing_slash_directory() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("directory");
    for query in ["./directory", "./directory/"] {
        scene
            .ucmd()
            .args(&["-e", query])
            .succeeds()
            .stdout_contains("directory");
    }
}

#[test]
fn test_trailing_slash_symlink_to_directory() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("directory");
    at.relative_symlink_dir("directory", "link");
    for query in ["./link", "./link/"] {
        scene
            .ucmd()
            .args(&["-e", query])
            .succeeds()
            .stdout_contains("directory");
    }
    scene
        .ucmd()
        .args(&["-ev", "./link/more"])
        .fails()
        .code_is(1)
        .stderr_contains("No such file or directory")
        .no_stdout();
}

#[test]
fn test_trailing_slash_symlink_to_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_file("missing", "link");
    at.relative_symlink_file("subdir/missing", "link2");
    for query in [
        "missing",
        "./missing/",
        "link",
        "./link/",
        "link/more",
        "link2",
        "./link2/",
        "link2/more",
    ] {
        scene
            .ucmd()
            .args(&["-ev", query])
            .fails()
            .code_is(1)
            .stderr_contains("No such file or directory")
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_regfile() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    at.relative_symlink_file("regfile", "link1");
    for name in ["regfile", "link1"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("regfile");
        scene
            .ucmd()
            .args(&["-fv", &format!("./{}/", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-fv", &format!("{}/more", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-fv", &format!("./{}/more/", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_subdir() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_dir("subdir", "link2");
    for name in ["subdir", "link2"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("subdir");
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/", name)])
            .succeeds()
            .stdout_contains("subdir");
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more", name)])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "more"));
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/", name)])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "more"));
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more/more2", name)])
            .fails()
            .code_is(1)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/more2/", name)])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.relative_symlink_file("missing", "link3");
    for name in ["missing", "link3"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("missing");
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/", name)])
            .succeeds()
            .stdout_contains("missing");
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more", name)])
            .fails()
            .code_is(1)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/", name)])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_subdir_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_file("subdir/missing", "link4");
    for query in ["link4", "./link4/"] {
        scene
            .ucmd()
            .args(&["-f", query])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "missing"));
    }
    for query in ["link4/more", "./link4/more/"] {
        scene
            .ucmd()
            .args(&["-f", query])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_symlink_loop() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.relative_symlink_file("link5", "link5");
    for query in ["link5", "./link5/", "link5/more", "./link5/more/"] {
        scene
            .ucmd()
            .args(&["-f", query])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}
<commit_msg>tests/readlink: add test for delimiters usage<commit_after>// spell-checker:ignore regfile
use crate::common::util::*;

static GIBBERISH: &str = "supercalifragilisticexpialidocious";

#[cfg(not(windows))]
static NOT_A_DIRECTORY: &str = "Not a directory";
#[cfg(windows)]
static NOT_A_DIRECTORY: &str = "The directory name is invalid.";

#[test]
fn test_resolve() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    at.touch("foo");
    at.symlink_file("foo", "bar");

    scene.ucmd().arg("bar").succeeds().stdout_contains("foo\n");
}

#[test]
fn test_canonicalize() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-f").arg(".").run().stdout_move_str();
    let expect = at.root_dir_resolved() + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_canonicalize_existing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-e").arg(".").run().stdout_move_str();
    let expect = at.root_dir_resolved() + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_canonicalize_missing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let actual = ucmd.arg("-m").arg(GIBBERISH).run().stdout_move_str();
    let expect = path_concat!(at.root_dir_resolved(), GIBBERISH) + "\n";
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_long_redirection_to_current_dir() {
    let (at, mut ucmd) = at_and_ucmd!();
    // Create a 256-character path to current directory
    let dir = path_concat!(".", ..128);
    let actual = ucmd.arg("-n").arg("-m").arg(dir).run().stdout_move_str();
    let expect = at.root_dir_resolved();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_long_redirection_to_root() {
    // Create a 255-character path to root
    let dir = path_concat!("..", ..85);
    let actual = new_ucmd!()
        .arg("-n")
        .arg("-m")
        .arg(dir)
        .run()
        .stdout_move_str();
    let expect = get_root_path();
    println!("actual: {:?}", actual);
    println!("expect: {:?}", expect);
    assert_eq!(actual, expect);
}

#[test]
fn test_symlink_to_itself_verbose() {
    let (at, mut ucmd) = at_and_ucmd!();
    at.relative_symlink_file("a", "a");
    ucmd.args(&["-ev", "a"])
        .fails()
        .code_is(1)
        .stderr_contains("Too many levels of symbolic links");
}

#[test]
fn test_trailing_slash_regular_file() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    scene
        .ucmd()
        .args(&["-ev", "./regfile/"])
        .fails()
        .code_is(1)
        .stderr_contains(NOT_A_DIRECTORY)
        .no_stdout();
    scene
        .ucmd()
        .args(&["-e", "./regfile"])
        .succeeds()
        .stdout_contains("regfile");
}

#[test]
fn test_trailing_slash_symlink_to_regular_file() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    at.relative_symlink_file("regfile", "link");
    scene
        .ucmd()
        .args(&["-ev", "./link/"])
        .fails()
        .code_is(1)
        .stderr_contains(NOT_A_DIRECTORY)
        .no_stdout();
    scene
        .ucmd()
        .args(&["-e", "./link"])
        .succeeds()
        .stdout_contains("regfile");
    scene
        .ucmd()
        .args(&["-e", "./link/more"])
        .fails()
        .code_is(1)
        .no_stdout();
}

#[test]
fn test_trailing_slash_directory() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("directory");
    for query in ["./directory", "./directory/"] {
        scene
            .ucmd()
            .args(&["-e", query])
            .succeeds()
            .stdout_contains("directory");
    }
}

#[test]
fn test_trailing_slash_symlink_to_directory() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("directory");
    at.relative_symlink_dir("directory", "link");
    for query in ["./link", "./link/"] {
        scene
            .ucmd()
            .args(&["-e", query])
            .succeeds()
            .stdout_contains("directory");
    }
    scene
        .ucmd()
        .args(&["-ev", "./link/more"])
        .fails()
        .code_is(1)
        .stderr_contains("No such file or directory")
        .no_stdout();
}

#[test]
fn test_trailing_slash_symlink_to_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_file("missing", "link");
    at.relative_symlink_file("subdir/missing", "link2");
    for query in [
        "missing",
        "./missing/",
        "link",
        "./link/",
        "link/more",
        "link2",
        "./link2/",
        "link2/more",
    ] {
        scene
            .ucmd()
            .args(&["-ev", query])
            .fails()
            .code_is(1)
            .stderr_contains("No such file or directory")
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_regfile() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.touch("regfile");
    at.relative_symlink_file("regfile", "link1");
    for name in ["regfile", "link1"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("regfile");
        scene
            .ucmd()
            .args(&["-fv", &format!("./{}/", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-fv", &format!("{}/more", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-fv", &format!("./{}/more/", name)])
            .fails()
            .code_is(1)
            .stderr_contains(NOT_A_DIRECTORY)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_subdir() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_dir("subdir", "link2");
    for name in ["subdir", "link2"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("subdir");
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/", name)])
            .succeeds()
            .stdout_contains("subdir");
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more", name)])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "more"));
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/", name)])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "more"));
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more/more2", name)])
            .fails()
            .code_is(1)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/more2/", name)])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.relative_symlink_file("missing", "link3");
    for name in ["missing", "link3"] {
        scene
            .ucmd()
            .args(&["-f", name])
            .succeeds()
            .stdout_contains("missing");
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/", name)])
            .succeeds()
            .stdout_contains("missing");
        scene
            .ucmd()
            .args(&["-f", &format!("{}/more", name)])
            .fails()
            .code_is(1)
            .no_stdout();
        scene
            .ucmd()
            .args(&["-f", &format!("./{}/more/", name)])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_subdir_missing() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.mkdir("subdir");
    at.relative_symlink_file("subdir/missing", "link4");
    for query in ["link4", "./link4/"] {
        scene
            .ucmd()
            .args(&["-f", query])
            .succeeds()
            .stdout_contains(path_concat!("subdir", "missing"));
    }
    for query in ["link4/more", "./link4/more/"] {
        scene
            .ucmd()
            .args(&["-f", query])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}

#[test]
fn test_canonicalize_trailing_slash_symlink_loop() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    at.relative_symlink_file("link5", "link5");
    for query in ["link5", "./link5/", "link5/more", "./link5/more/"] {
        scene
            .ucmd()
            .args(&["-f", query])
            .fails()
            .code_is(1)
            .no_stdout();
    }
}

#[test]
#[cfg(not(windows))]
fn test_delimiters() {
    new_ucmd!()
        .args(&["--zero", "-n", "-m", "/a"])
        .succeeds()
        .stdout_only("/a");
    new_ucmd!()
        .args(&["-n", "-m", "/a"])
        .succeeds()
        .stdout_only("/a");
    new_ucmd!()
        .args(&["--zero", "-m", "/a"])
        .succeeds()
        .stdout_only("/a\0");
    new_ucmd!()
        .args(&["-m", "/a"])
        .succeeds()
        .stdout_only("/a\n");
    new_ucmd!()
        .args(&["--zero", "-n", "-m", "/a", "/a"])
        .succeeds()
        .stderr_contains("ignoring --no-newline with multiple arguments")
        .stdout_is("/a\0/a\0");
    new_ucmd!()
        .args(&["-n", "-m", "/a", "/a"])
        .succeeds()
        .stderr_contains("ignoring --no-newline with multiple arguments")
        .stdout_is("/a\n/a\n");
}
<|endoftext|>


<commit_before>// Allow unstable items until Rust hits 1.0
#![feature(io)]

extern crate yaml;

use yaml::error::YamlError;
use yaml::emitter::YamlEmitter;
use yaml::ffi::{YamlEncoding, YamlScalarStyle};

use std::error::Error;
use std::io;
use std::io::{Read, Write};

struct MockRW {
    _data: ()
}

impl MockRW {
    pub fn new() -> MockRW {
        MockRW { _data: () }
    }
}

impl Read for MockRW {
    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::Other, ""))
    }
}

impl Write for MockRW {
    fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::Other, ""))
    }

    fn flush(&mut self) -> io::Result<()> {
        Err(io::Error::new(io::ErrorKind::Other, ""))
    }
}

#[test]
fn error_cause_test_read() {
    let mut mock_reader = MockRW::new();
    match yaml::parse_io_utf8(&mut mock_reader) {
        Ok(_) => panic!("Should return an error"),
        Err(e) => assert_eq!(e.cause().map(|ioe| format!("{}", ioe)), Some("".to_string()))
    }
}

fn write_to_bad_stream() -> Result<(), YamlError> {
    let mut mock_writer = MockRW::new();
    let mut emitter = YamlEmitter::init(&mut mock_writer);
    try!(emitter.emit_stream(YamlEncoding::YamlUtf8Encoding, |stream|
        stream.emit_document(None, &[], true, |doc| {
            doc.emit_scalar_event(None, None, "a", true, false, YamlScalarStyle::YamlPlainScalarStyle)
        })
    ));
    emitter.flush()
}

#[test]
fn error_cause_test_write() {
    match write_to_bad_stream() {
        Ok(_) => panic!("Should return an error"),
        Err(e) => assert_eq!(e.cause().map(|ioe| format!("{}", ioe)), Some("".to_string()))
    }
}
<commit_msg>Rust changes: feature(io) stabilized<commit_after>extern crate yaml;

use yaml::error::YamlError;
use yaml::emitter::YamlEmitter;
use yaml::ffi::{YamlEncoding, YamlScalarStyle};

use std::error::Error;
use std::io;
use std::io::{Read, Write};

struct MockRW {
    _data: ()
}

impl MockRW {
    pub fn new() -> MockRW {
        MockRW { _data: () }
    }
}

impl Read for MockRW {
    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::Other, ""))
    }
}

impl Write for MockRW {
    fn write(&mut self, _buf: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::Other, ""))
    }

    fn flush(&mut self) -> io::Result<()> {
        Err(io::Error::new(io::ErrorKind::Other, ""))
    }
}

#[test]
fn error_cause_test_read() {
    let mut mock_reader = MockRW::new();
    match yaml::parse_io_utf8(&mut mock_reader) {
        Ok(_) => panic!("Should return an error"),
        Err(e) => assert_eq!(e.cause().map(|ioe| format!("{}", ioe)), Some("".to_string()))
    }
}

fn write_to_bad_stream() -> Result<(), YamlError> {
    let mut mock_writer = MockRW::new();
    let mut emitter = YamlEmitter::init(&mut mock_writer);
    try!(emitter.emit_stream(YamlEncoding::YamlUtf8Encoding, |stream|
        stream.emit_document(None, &[], true, |doc| {
            doc.emit_scalar_event(None, None, "a", true, false, YamlScalarStyle::YamlPlainScalarStyle)
        })
    ));
    emitter.flush()
}

#[test]
fn error_cause_test_write() {
    match write_to_bad_stream() {
        Ok(_) => panic!("Should return an error"),
        Err(e) => assert_eq!(e.cause().map(|ioe| format!("{}", ioe)), Some("".to_string()))
    }
}
<|endoftext|>


<commit_before>//! Implements the rules of chess and static position evaluation
//! logic.

#![allow(dead_code)]
#![allow(unused_variables)]

pub mod board_geometry;
pub mod board;

// use notation;
use basetypes::*;
use chess_move::*;
use self::board::{Board, IllegalBoard};

pub type Value = i16;

/// Represents an illegal possiton error.
pub struct IllegalPosition;

/// Represents a chess position.
///
/// `Position` can generate all possible moves in the current
/// position, play a selected move, and take it back. It can also
/// statically (without doing extensive tree-searching) evaluate the
/// chances of the sides, so that tree-searching algorithms can use
/// this evaluation to assign realistic game outcomes to their leaf
/// nodes. `Position` can also fabricate a "null move" that can be
/// used to aggressively prune the search tree.
pub struct Position {
    board: Board,
    halfmove_clock: u32,
    fullmove_number: u32, /* move_stack
                           * move_history (including fullmove_number?)
                           * ply
                           * hply?
                           * various hash tables
                           * first_move_index[usize; MAX_PLY]
                           * undo_move data stack */
}

impl Position {
    fn from_fen(fen: &str) -> Result<Position, IllegalBoard> {
        let parts: Vec<_> = fen.split_whitespace().collect();

        if parts.len() == 6 {
            let p = Position {
                board: try!(Board::from_fen(fen)),
                halfmove_clock: try!(parts[4].parse::<u32>().map_err(|_| IllegalBoard)),
                fullmove_number: try!(parts[5].parse::<u32>().map_err(|_| IllegalBoard)),
            };
            Ok(p)
        } else {
            Err(IllegalBoard)
        }
    }

    /// Creates a new instance.
    ///
    /// `fen` should be the Forsyth–Edwards Notation of a legal
    /// starting position. `moves` should be an iterator over all the
    /// moves that were played from that position.
    pub fn from_history(fen: &str,
                        moves: &mut Iterator<Item = &str>)
                        -> Result<Position, IllegalPosition> {
        Err(IllegalPosition)
    }

    /// Evaluates a final position.
    ///
    /// In final positions this method is guaranteed to return the
    /// correct value of the position (white wins, black wins,
    /// draw). A position is guaranteed to be final if
    /// `generate_moves` method generates no legal moves (it may
    /// generate some pseudo-legal moves, but if none of them is
    /// legal, then the position is guaranteed to be a final
    /// position).
    pub fn evaluate_final(&self) -> Value {
        0
    }

    /// Statically evaluates the position.
    ///
    /// This method considers only static material and positional
    /// properties of the position. If the position is dynamic, with
    /// pending tactical threats, this function will return a grossly
    /// incorrect evaluation. Therefore, if should be relied upon only
    /// for reasonably "quiet" positions.
    ///
    /// `lower_bound` and `upper_bound` together give the interval
    /// within which an as precise as possible evaluation is
    /// required. If during the calculation it is determined that the
    /// evaluation is outside this interval, this method may return
    /// any value outside of the interval (including the bounds), but
    /// always staying on the correct side of the interval.
    pub fn evaluate_static(&self, lower_bound: Value, upper_bound: Value) -> Value {
        0
    }

    /// Performs "quiescence search" and returns an evaluation.
    ///
    /// The purpose of the "quiescence search" is to only evaluate
    /// "quiet" positions (positions where there are no winning
    /// tactical moves to be made).
    ///
    /// `lower_bound` and `upper_bound` together give the interval
    /// within which an as precise as possible evaluation is
    /// required. If during the calculation it is determined that the
    /// evaluation is outside this interval, this method may return
    /// any value outside of the interval (including the bounds), but
    /// always staying on the correct side of the interval.
    ///
    /// TODO: Add more details for the algorithm used.
    pub fn evaluate(&self, lower_bound: Value, upper_bound: Value) -> Value {
        0
    }

    /// Returns an almost unique hash value for the position.
    #[inline(always)]
    pub fn hash(&self) -> u64 {
        0
    }

    /// Plays a move on the board.
    ///
    /// It verifies if the move is legal. If the move is legal, the
    /// board is updated and `true` is returned. If the move is
    /// illegal, `false` is returned without updating the board. The
    /// move passed to this method **must** have been generated by
    /// `generate_moves` or `null_move` methods for the current
    /// position on the board.
    ///
    /// Moves generated by the `null_move` method are exceptions. For
    /// them `do_move(m)` will return `false` if and only if the king
    /// is in check.
    #[inline]
    pub fn do_move(&self, m: Move) -> bool {
        false
    }

    /// Takes back the last played move.
    #[inline]
    pub fn undo_move(&self) {}

    /// Generates pseudo-legal moves and write them to `move_stack`.
    ///
    /// If all of the moves generated by this methods are illegal
    /// (this means that `do_move(m)` returns `false` for all of
    /// them), then it is guaranteed that the position is final, and
    /// `evaluate_final()` will return its correct value.
    #[inline]
    pub fn generate_moves(&self, move_stack: &mut Vec<Move>) {}

    /// Returns a null move.
    ///
    /// "Null move" is an illegal pseudo-move that changes only the
    /// side to move. For the move generated by this method,
    /// `do_move(m)` will return `false` if and only if the king is in
    /// check.
    #[inline]
    pub fn null_move(&self) -> Move {
        use castling_rights::CastlingRights;
        Move::new(WHITE,
                  0,
                  MOVE_NORMAL,
                  KING,
                  0,
                  0,
                  NO_PIECE,
                  8, // no en-passant file
                  CastlingRights::new(),
                  0)
    }
}

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

    #[test]
    fn test_fen_parsing() {
        assert!(Position::from_fen("nbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr1/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBN b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR/ b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNRR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP01PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP91PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP*1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 * 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 *")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b - e3 0 1")
                    .is_ok());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_ok());
        assert!(Position::from_fen("8/8/8/8/8/8/8/8 w - - 0 1").is_err());
        assert!(Position::from_fen("8/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/6KK w - - 0 1").is_err());
        assert!(Position::from_fen("k7/pppppppp/p7/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/7P/PPPPPPPP/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/pppppppp/8/8/8/8/PPPPPPPP/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k7/1P6/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/1B6/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/1N6/8/8/8/8/8/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k3P3/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k3p3/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/pP5K w - - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1").is_ok());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K2B w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w Qkq - 0 1").is_ok());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Qkq - 0 1").is_err());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Qk - 0 1").is_err());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Q - 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/8/7P/8/8/7K w - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/8/8/7K b - h3 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/7P/8/8/8/7K b - h4 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/7P/8/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/8/7P/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/6P1/7P/8/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("8/8/8/6k1/7P/8/8/7K b - h3 0 1").is_ok());
        assert!(Position::from_fen("8/8/8/6k1/7P/8/8/6RK b - h3 0 1").is_err());
        assert!(Position::from_fen("8/8/8/6k1/3P4/8/8/2B4K b - d3 0 1").is_ok());
        assert!(Position::from_fen("8/8/8/6k1/7P/4B3/8/7K b - h3 0 1").is_err());
    }
}
<commit_msg>implemented dummy static evaluation.<commit_after>//! Implements the rules of chess and static position evaluation
//! logic.

#![allow(dead_code)]
#![allow(unused_variables)]

pub mod board_geometry;
pub mod board;

// use notation;
use basetypes::*;
use bitsets::*;
use chess_move::*;
use self::board::{Board, IllegalBoard};

pub type Value = i16;

/// Represents an illegal possiton error.
pub struct IllegalPosition;

/// Represents a chess position.
///
/// `Position` can generate all possible moves in the current
/// position, play a selected move, and take it back. It can also
/// statically (without doing extensive tree-searching) evaluate the
/// chances of the sides, so that tree-searching algorithms can use
/// this evaluation to assign realistic game outcomes to their leaf
/// nodes. `Position` can also fabricate a "null move" that can be
/// used to aggressively prune the search tree.
pub struct Position {
    board: Board,
    halfmove_clock: u32,
    fullmove_number: u32, /* move_stack
                           * move_history (including fullmove_number?)
                           * ply
                           * hply?
                           * various hash tables
                           * first_move_index[usize; MAX_PLY]
                           * undo_move data stack */
}

impl Position {
    fn from_fen(fen: &str) -> Result<Position, IllegalBoard> {
        let parts: Vec<_> = fen.split_whitespace().collect();

        if parts.len() == 6 {
            let p = Position {
                board: try!(Board::from_fen(fen)),
                halfmove_clock: try!(parts[4].parse::<u32>().map_err(|_| IllegalBoard)),
                fullmove_number: try!(parts[5].parse::<u32>().map_err(|_| IllegalBoard)),
            };
            Ok(p)
        } else {
            Err(IllegalBoard)
        }
    }

    /// Creates a new instance.
    ///
    /// `fen` should be the Forsyth–Edwards Notation of a legal
    /// starting position. `moves` should be an iterator over all the
    /// moves that were played from that position.
    pub fn from_history(fen: &str,
                        moves: &mut Iterator<Item = &str>)
                        -> Result<Position, IllegalPosition> {
        Err(IllegalPosition)
    }

    /// Evaluates a final position.
    ///
    /// In final positions this method is guaranteed to return the
    /// correct value of the position (white wins, black wins,
    /// draw). A position is guaranteed to be final if
    /// `generate_moves` method generates no legal moves (it may
    /// generate some pseudo-legal moves, but if none of them is
    /// legal, then the position is guaranteed to be a final
    /// position).
    pub fn evaluate_final(&self) -> Value {
        0
    }

    /// Statically evaluates the position.
    ///
    /// This method considers only static material and positional
    /// properties of the position. If the position is dynamic, with
    /// pending tactical threats, this function will return a grossly
    /// incorrect evaluation. Therefore, if should be relied upon only
    /// for reasonably "quiet" positions.
    ///
    /// `lower_bound` and `upper_bound` together give the interval
    /// within which an as precise as possible evaluation is
    /// required. If during the calculation it is determined that the
    /// evaluation is outside this interval, this method may return
    /// any value outside of the interval (including the bounds), but
    /// always staying on the correct side of the interval.
    pub fn evaluate_static(&self, lower_bound: Value, upper_bound: Value) -> Value {
        // TODO: Implement a real evaluation.

        const VALUE: [Value; 6] = [10000, 975, 500, 325, 325, 100];
        let piece_type = self.board.piece_type();
        let color = self.board.color();
        let us = self.board.to_move();
        let them = 1 ^ us;
        let mut result = 0;
        for piece in QUEEN..NO_PIECE {
            result += VALUE[piece] *
                      (pop_count(piece_type[piece] & color[us]) as i16 -
                       pop_count(piece_type[piece] & color[them]) as i16);
        }
        result
    }

    /// Performs "quiescence search" and returns an evaluation.
    ///
    /// The purpose of the "quiescence search" is to only evaluate
    /// "quiet" positions (positions where there are no winning
    /// tactical moves to be made).
    ///
    /// `lower_bound` and `upper_bound` together give the interval
    /// within which an as precise as possible evaluation is
    /// required. If during the calculation it is determined that the
    /// evaluation is outside this interval, this method may return
    /// any value outside of the interval (including the bounds), but
    /// always staying on the correct side of the interval.
    ///
    /// TODO: Add more details for the algorithm used.
    pub fn evaluate(&self, lower_bound: Value, upper_bound: Value) -> Value {
        0
    }

    /// Returns an almost unique hash value for the position.
    #[inline(always)]
    pub fn hash(&self) -> u64 {
        0
    }

    /// Plays a move on the board.
    ///
    /// It verifies if the move is legal. If the move is legal, the
    /// board is updated and `true` is returned. If the move is
    /// illegal, `false` is returned without updating the board. The
    /// move passed to this method **must** have been generated by
    /// `generate_moves` or `null_move` methods for the current
    /// position on the board.
    ///
    /// Moves generated by the `null_move` method are exceptions. For
    /// them `do_move(m)` will return `false` if and only if the king
    /// is in check.
    #[inline]
    pub fn do_move(&self, m: Move) -> bool {
        false
    }

    /// Takes back the last played move.
    #[inline]
    pub fn undo_move(&self) {}

    /// Generates pseudo-legal moves and write them to `move_stack`.
    ///
    /// If all of the moves generated by this methods are illegal
    /// (this means that `do_move(m)` returns `false` for all of
    /// them), then it is guaranteed that the position is final, and
    /// `evaluate_final()` will return its correct value.
    #[inline]
    pub fn generate_moves(&self, move_stack: &mut Vec<Move>) {}

    /// Returns a null move.
    ///
    /// "Null move" is an illegal pseudo-move that changes only the
    /// side to move. For the move generated by this method,
    /// `do_move(m)` will return `false` if and only if the king is in
    /// check.
    #[inline]
    pub fn null_move(&self) -> Move {
        use castling_rights::CastlingRights;
        Move::new(WHITE,
                  0,
                  MOVE_NORMAL,
                  KING,
                  0,
                  0,
                  NO_PIECE,
                  8, // no en-passant file
                  CastlingRights::new(),
                  0)
    }
}

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

    #[test]
    fn test_fen_parsing() {
        assert!(Position::from_fen("nbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr1/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBN b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR/ b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNRR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP01PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP91PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP*1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 * 1")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 *")
                    .is_err());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b - e3 0 1")
                    .is_ok());
        assert!(Position::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_ok());
        assert!(Position::from_fen("8/8/8/8/8/8/8/8 w - - 0 1").is_err());
        assert!(Position::from_fen("8/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/6KK w - - 0 1").is_err());
        assert!(Position::from_fen("k7/pppppppp/p7/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/7P/PPPPPPPP/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/pppppppp/8/8/8/8/PPPPPPPP/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k7/1P6/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/1B6/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/1N6/8/8/8/8/8/7K w - - 0 1").is_ok());
        assert!(Position::from_fen("k3P3/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k3p3/8/8/8/8/8/8/7K w - - 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/8/8/8/pP5K w - - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K2R w KQkq - 0 1").is_ok());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K2B w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w KQkq - 0 1").is_err());
        assert!(Position::from_fen("r3k2r/8/8/8/8/8/8/R3K3 w Qkq - 0 1").is_ok());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Qkq - 0 1").is_err());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Qk - 0 1").is_err());
        assert!(Position::from_fen("r2k3r/8/8/8/8/8/8/R3K3 w Q - 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/8/7P/8/8/7K w - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/8/8/7K b - h3 0 1").is_ok());
        assert!(Position::from_fen("k7/8/8/7P/8/8/8/7K b - h4 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/7P/8/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/7P/8/7P/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("k7/8/8/8/6P1/7P/8/7K b - h3 0 1").is_err());
        assert!(Position::from_fen("8/8/8/6k1/7P/8/8/7K b - h3 0 1").is_ok());
        assert!(Position::from_fen("8/8/8/6k1/7P/8/8/6RK b - h3 0 1").is_err());
        assert!(Position::from_fen("8/8/8/6k1/3P4/8/8/2B4K b - d3 0 1").is_ok());
        assert!(Position::from_fen("8/8/8/6k1/7P/4B3/8/7K b - h3 0 1").is_err());
    }

    #[test]
    fn test_evaluate_static_parsing() {
        assert_eq!(Position::from_fen("krq5/p7/8/8/8/8/8/KRQ5 w - - 0 1")
                       .ok().unwrap()
                       .evaluate_static(-1000, 1000),
                   -100);
    }
}
<|endoftext|>


<commit_before>//! List ALL projects
//!
//! https://docs.gitlab.com/ce/api/projects.html#list-all-projects
//!
//! # List ALL projects
//!
//! Get a list of all GitLab projects (admin only).
//!
//! ```text
//! GET /projects/all
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `archived` | boolean | no | Limit by archived status |
//! | `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
//! | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
//! | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
//! | `search` | string | no | Return list of authorized projects matching the search criteria |
<commit_msg>Add projects all<commit_after>//! List ALL projects
//!
//! https://docs.gitlab.com/ce/api/projects.html#list-all-projects
//!
//! # List ALL projects
//!
//! Get a list of all GitLab projects (admin only).
//!
//! ```text
//! GET /projects/all
//! ```
//!
//! Parameters:
//!
//! | Attribute | Type | Required | Description |
//! | --------- | ---- | -------- | ----------- |
//! | `archived` | boolean | no | Limit by archived status |
//! | `visibility` | string | no | Limit by visibility `public`, `internal`, or `private` |
//! | `order_by` | string | no | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. Default is `created_at` |
//! | `sort` | string | no | Return projects sorted in `asc` or `desc` order. Default is `desc` |
//! | `search` | string | no | Return list of authorized projects matching the search criteria |

use BuildQuery;

#[derive(Debug, Copy, Clone)]
pub enum ListingVisibility {
    Public,
    Internal,
    Private,
}

#[derive(Debug, Copy, Clone)]
pub enum ListingOrderBy {
    Id,
    Name,
    Path,
    CreatedAt,
    UpdatedAt,
    LastActivityAt,
}

#[derive(Debug, Copy, Clone)]
pub enum ListingSort {
    Asc,
    Desc,
}

#[derive(Default, Debug, Clone)]
pub struct Listing {
    /// Limit by archived status
    archived:  Option<bool>,
    /// Limit by visibility.
    visibility: Option<ListingVisibility>,
    /// Return requests ordered by. Default is `ListingOrderBy::CreatedAt`.
    order_by:  Option<ListingOrderBy>,
    /// Return requests sorted. Default is `ListingSort::Desc`.
    sort: Option<ListingSort>,
    /// Return list of authorized projects matching the search criteria.
    search:  String,
}

impl Listing {
    pub fn new() -> Listing {
        Default::default()
    }
    pub fn archived(&mut self, archived: bool) -> &mut Listing {
        self.archived = Some(archived);
        self
    }
    pub fn visibility(&mut self, visibility: ListingVisibility) -> &mut Listing {
        self.visibility = Some(visibility);
        self
    }
    pub fn order_by(&mut self, order_by: ListingOrderBy) -> &mut Listing {
        self.order_by = Some(order_by);
        self
    }
    fn sort(&mut self, sort: ListingSort) -> &mut Listing {
        self.sort = Some(sort);
        self
    }
    pub fn search(&mut self, search: String) -> &mut Listing {
        self.search = search;
        self
    }
}

impl BuildQuery for Listing {
    fn build_query(&self) -> String {

        let mut query = String::from("projects/all");

        let amp_char = "&";
        let none_char = "";
        let mut split_char = &none_char;

        // Append a "?" only if at least one of the `Option` is `Some(_)` or if
        // strings contain something.
        query.push_str(match (&self.archived,
                              &self.visibility,
                              &self.order_by,
                              &self.sort,
                              self.search.is_empty()) {
            (&None, &None, &None, &None, true) => "",
            _ => "?",
        });

        self.archived.map(|archived| {
            query.push_str(split_char);
            split_char = &amp_char;

            if archived {
                query.push_str("archived=true")
            } else {
                query.push_str("archived=false")
            }
        });

        self.visibility.map(|visibility| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("visibility=");
            query.push_str(match visibility {
                ListingVisibility::Public => "public",
                ListingVisibility::Internal => "internal",
                ListingVisibility::Private => "private",
            });
        });

        self.order_by.map(|order_by| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("order_by=");
            query.push_str(match order_by {
                ListingOrderBy::Id => "id",
                ListingOrderBy::Name => "name",
                ListingOrderBy::Path => "path",
                ListingOrderBy::CreatedAt => "created_at",
                ListingOrderBy::UpdatedAt => "updated_at",
                ListingOrderBy::LastActivityAt => "last_activity_at",
            });
        });

        self.sort.map(|sort| {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("sort=");
            query.push_str(match sort {
                ListingSort::Asc => "asc",
                ListingSort::Desc => "desc",
            });
        });

        if !self.search.is_empty() {
            query.push_str(split_char);
            split_char = &amp_char;

            query.push_str("search=");
            query.push_str(&self.search);
        }

        query
    }
}

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

    #[test]
    fn build_query_default() {
        let expected_string = "projects/all";
        let listing: Listing = Default::default();
        let query = listing.build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects/all";
        let listing = Listing::new();
        let query = listing.build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_archived() {
        let expected_string = "projects/all?archived=true";
        let query = Listing::new().archived(true).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects/all?archived=false";
        let query = Listing::new().archived(false).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_visibility() {
        let expected_string = "projects/all?visibility=public";
        let query = Listing::new().visibility(ListingVisibility::Public).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects/all?visibility=internal";
        let query = Listing::new().visibility(ListingVisibility::Internal).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects/all?visibility=private";
        let query = Listing::new().visibility(ListingVisibility::Private).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_order_by() {
        let expected_string = "projects/all?order_by=id";
        let query = Listing::new().order_by(ListingOrderBy::Id).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects/all?order_by=name";
        let query = Listing::new().order_by(ListingOrderBy::Name).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects/all?order_by=path";
        let query = Listing::new().order_by(ListingOrderBy::Path).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects/all?order_by=created_at";
        let query = Listing::new().order_by(ListingOrderBy::CreatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects/all?order_by=updated_at";
        let query = Listing::new().order_by(ListingOrderBy::UpdatedAt).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects/all?order_by=last_activity_at";
        let query = Listing::new().order_by(ListingOrderBy::LastActivityAt).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_sort() {
        let expected_string = "projects/all?sort=asc";
        let query = Listing::new().sort(ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);

        let expected_string = "projects/all?sort=desc";
        let query = Listing::new().sort(ListingSort::Desc).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn build_query_search() {
        let expected_string = "projects/all?search=SearchPattern";
        let query = Listing::new().search(String::from("SearchPattern")).build_query();
        assert_eq!(query, expected_string);
    }

    #[test]
    fn groups_build_query_multiple() {
        let expected_string = "projects/all?archived=false&sort=asc";
        let query = Listing::new().archived(false).sort(ListingSort::Asc).build_query();
        assert_eq!(query, expected_string);
    }
}
<|endoftext|>