<commit_before>use std::io::Write;
use std::option::Option;
use std::os::unix::process::CommandExt;
use std::process::Command;

const SYSTEMD_RUN: &'static str = "/usr/bin/systemd-run";
const FIREJAIL: &'static str = "/usr/bin/firejail";

const FIREFOX: &'static str = "/usr/bin/firefox";
const FIREFOX_PROFILE: &'static str = "/etc/firejail/firefox.profile";
const FIREFOX_MOZILLA_SFW_PROFILE: &'static str = "default-1473025815439";

const FIREFOX_MEMORY_HIGH: i32 = 4420;
const FIREFOX_MEMORY_MAX: i32 = 5200;

const KEIRA: &'static str = "/home/kalvin/Downloads/.firefox-nightly/firefox";
const KEIRA_PROFILE: &'static str = "/etc/firejail/firefox-nightly.profile";

const MPV: &'static str = "/usr/bin/mpv";
const MPV_PROFILE: &'static str = "/etc/firejail/mpv.profile";

const TERM: &'static str = "/usr/bin/alacritty";
const TERM_PROFILE: &'static str = "/etc/firejail/x-terminal-emulator.profile";

const THUNDERBIRD: &'static str = "/home/kalvin/Downloads/.thunderbird-beta/thunderbird";
const THUNDERBIRD_PROFILE: &'static str = "/etc/firejail/thunderbird-beta.profile";

const QUODLIBET_FIFO: &'static str = "/home/kalvin/.config/quodlibet/control";

#[derive(Debug)]
struct CgroupedFirejailedCommandOptions<'a> {
    bin_path: &'a str,
    memory_high: Option<i32>,
    memory_max: Option<i32>,
    firejail_profile: Option<&'a str>,
    implicit_extra_args: Option<&'a [&'a str]>,
    argv_remainder: Vec<String>,
}

fn cgrouped_firejail_command(options: CgroupedFirejailedCommandOptions) -> Command {
    let mut command = Command::new(SYSTEMD_RUN);
    command.args(&["--user", "--scope"]);
    command.args(&["-p", "MemorySwapMax=0"]);

    if let Some(memory_high) = options.memory_high {
        let memory_high_owned_string = format!("MemoryHigh={}M", memory_high);
        command.args(&["-p", memory_high_owned_string.as_str()]);
    }
    if let Some(memory_max) = options.memory_max {
        let memory_max_owned_string = format!("MemoryMax={}M", memory_max);
        command.args(&["-p", memory_max_owned_string.as_str()]);
    }

    if let Some(firejail_profile) = options.firejail_profile {
        command.arg(FIREJAIL);
        command.arg("--ignore=seccomp");
        command.arg(format!("--profile={}", firejail_profile));
    }

    command.arg(options.bin_path);

    if let Some(implicit_extra_args) = options.implicit_extra_args {
        command.args(implicit_extra_args);
    }

    command.args(options.argv_remainder);

    command
}

fn simple_firejail_command(target: &str, args: Vec<String>) -> Command {
    let mut command = Command::new(FIREJAIL);

    command.arg(format!("--profile=/etc/firejail/{}.profile", target));
    command.arg(format!("/usr/bin/{}", target));
    command.args(args);

    command
}

fn quodlibet_command(args: Vec<String>) {
    let mut file = std::fs::OpenOptions::new()
        .append(true)
        .open(QUODLIBET_FIFO)
        .unwrap();
    file.write_all(match args[0].as_str() {
        "pp" => "play-pause".as_bytes(),
        "sa" => "stop-after 1".as_bytes(),
        _ => panic!(
            "bad argument for quodlibet command: ``{}''",
            args[0].as_str()
        ),
    })
    .unwrap();
}

fn init_command() -> Option<Command> {
    let mut args_less_the_first = std::env::args();
    // Pops the name of this executable.
    args_less_the_first.next();

    // Pops the name of the unner target.
    let target = args_less_the_first.next().unwrap();

    // Copies and collects the remaining argv.
    let args: Vec<String> = args_less_the_first.collect();

    match target.as_str() {
        "ff" => {
            return Some(cgrouped_firejail_command(
                CgroupedFirejailedCommandOptions {
                    bin_path: FIREFOX,
                    memory_high: Some(FIREFOX_MEMORY_HIGH),
                    memory_max: Some(FIREFOX_MEMORY_MAX),
                    firejail_profile: Some(FIREFOX_PROFILE),
                    implicit_extra_args: Some(&["-P", FIREFOX_MOZILLA_SFW_PROFILE]),
                    argv_remainder: args,
                },
            ));
        }
        "keira" => {
            return Some(cgrouped_firejail_command(
                CgroupedFirejailedCommandOptions {
                    bin_path: KEIRA,
                    memory_high: Some(FIREFOX_MEMORY_HIGH),
                    memory_max: Some(FIREFOX_MEMORY_MAX),
                    firejail_profile: Some(KEIRA_PROFILE),
                    implicit_extra_args: Some(&["-P", "nightly"]),
                    argv_remainder: args,
                },
            ));
        }
        "npv" => {
            return Some(cgrouped_firejail_command(
                CgroupedFirejailedCommandOptions {
                    bin_path: MPV,
                    memory_high: None,
                    memory_max: None,
                    firejail_profile: Some(MPV_PROFILE),
                    implicit_extra_args: Some(&["--pulse-buffer=13"]),
                    argv_remainder: args,
                },
            ));
        }
        "q" => {
            quodlibet_command(args);
            return None;
        }
        "read" => {
            let formatted_args: Vec<String> = vec![format!("about:reader?url={}", args[0])];
            return Some(cgrouped_firejail_command(
                CgroupedFirejailedCommandOptions {
                    bin_path: FIREFOX,
                    memory_high: Some(FIREFOX_MEMORY_HIGH),
                    memory_max: Some(FIREFOX_MEMORY_MAX),
                    firejail_profile: Some(FIREFOX_PROFILE),
                    implicit_extra_args: Some(&["-P", FIREFOX_MOZILLA_SFW_PROFILE]),
                    argv_remainder: formatted_args,
                },
            ));
        }
        "t" => {
            return Some(cgrouped_firejail_command(
                CgroupedFirejailedCommandOptions {
                    bin_path: TERM,
                    memory_high: None,
                    memory_max: None,
                    firejail_profile: Some(TERM_PROFILE),
                    implicit_extra_args: None,
                    argv_remainder: args,
                },
            ));
        }
        "tbb" => {
            return Some(cgrouped_firejail_command(
                CgroupedFirejailedCommandOptions {
                    bin_path: THUNDERBIRD,
                    memory_high: None,
                    memory_max: None,
                    firejail_profile: Some(THUNDERBIRD_PROFILE),
                    implicit_extra_args: None,
                    argv_remainder: args,
                },
            ));
        }
        "vlk" => {
            return Some(cgrouped_firejail_command(
                CgroupedFirejailedCommandOptions {
                    bin_path: "/usr/bin/vlc",
                    memory_high: None,
                    memory_max: None,
                    firejail_profile: Some("/etc/firejail/vlc.profile"),
                    implicit_extra_args: Some(&["--play-and-exit"]),
                    argv_remainder: args,
                },
            ));
        }
        "e" => return Some(simple_firejail_command("evince", args)),
        _ => panic!("no handler for ``{}''", target),
    }
}

fn main() {
    if let Some(mut command) = init_command() {
        println!("{:#?}", command);
        command.exec();
    }
}
<commit_msg>unner: Use builder pattern<commit_after>use std::io::Write;
use std::option::Option;
use std::os::unix::process::CommandExt;
use std::process::Command;

const SYSTEMD_RUN: &'static str = "/usr/bin/systemd-run";
const FIREJAIL: &'static str = "/usr/bin/firejail";

const FIREFOX: &'static str = "/usr/bin/firefox";
const FIREFOX_PROFILE: &'static str = "/etc/firejail/firefox.profile";
const FIREFOX_MOZILLA_SFW_PROFILE: &'static str = "default-1473025815439";

const FIREFOX_MEMORY_HIGH: i32 = 4420;
const FIREFOX_MEMORY_MAX: i32 = 5200;

const KEIRA: &'static str = "/home/kalvin/Downloads/.firefox-nightly/firefox";
const KEIRA_PROFILE: &'static str = "/etc/firejail/firefox-nightly.profile";

const MPV: &'static str = "/usr/bin/mpv";
const MPV_PROFILE: &'static str = "/etc/firejail/mpv.profile";

const TERM: &'static str = "/usr/bin/alacritty";
const TERM_PROFILE: &'static str = "/etc/firejail/x-terminal-emulator.profile";

const THUNDERBIRD: &'static str = "/home/kalvin/Downloads/.thunderbird-beta/thunderbird";
const THUNDERBIRD_PROFILE: &'static str = "/etc/firejail/thunderbird-beta.profile";

const QUODLIBET_FIFO: &'static str = "/home/kalvin/.config/quodlibet/control";

// Partial ordering on enums are ordered by their declaration order:
// https://users.rust-lang.org/t/how-to-sort-enum-variants/52291/2
#[derive(PartialOrd, Ord, PartialEq, Eq)]
enum BuilderWatermark {
    Unset,
    MemoryHigh,
    MemoryMax,
    FirejailProfile,
    BinPath,
    ImplicitExtraArgs,
    RemainingArgs,
}

struct CgroupedFirejailedCommand {
    pub command: std::process::Command,
    watermark: BuilderWatermark,
}

impl CgroupedFirejailedCommand {
    pub fn new() -> Self {
        let mut result = Self {
            command: std::process::Command::new(SYSTEMD_RUN),
            watermark: BuilderWatermark::Unset,
        };
        result
            .command
            .args(&["--user", "--scope", "-p", "MemorySwapMax=0"]);
        result
    }

    pub fn memory_high(mut self, param: i32) -> Self {
        assert!(self.watermark < BuilderWatermark::MemoryHigh);
        self.watermark = BuilderWatermark::MemoryHigh;
        self.command.arg("-p");
        self.command.arg(format!("MemoryHigh={}M", param));
        self
    }

    pub fn memory_max(mut self, param: i32) -> Self {
        assert!(self.watermark < BuilderWatermark::MemoryMax);
        self.watermark = BuilderWatermark::MemoryMax;
        self.command.arg("-p");
        self.command.arg(format!("MemoryMax={}M", param));
        self
    }

    pub fn firejail_profile(mut self, path: &str) -> Self {
        assert!(self.watermark < BuilderWatermark::FirejailProfile);
        self.watermark = BuilderWatermark::FirejailProfile;
        self.command.args(&[FIREJAIL, "--ignore=seccomp"]);
        self.command.arg(format!("--profile={}", path));
        self
    }

    pub fn bin_path(mut self, path: &str) -> Self {
        assert!(self.watermark < BuilderWatermark::BinPath);
        self.watermark = BuilderWatermark::BinPath;
        self.command.arg(path);
        self
    }

    pub fn implicit_extra_args(mut self, args: &[&str]) -> Self {
        assert!(self.watermark < BuilderWatermark::ImplicitExtraArgs);
        self.watermark = BuilderWatermark::ImplicitExtraArgs;
        self.command.args(args);
        self
    }

    pub fn remaining_args(mut self, args: Vec<String>) -> Self {
        assert!(self.watermark < BuilderWatermark::RemainingArgs);
        self.watermark = BuilderWatermark::RemainingArgs;
        self.command.args(args);
        self
    }
}

fn simple_firejail_command(target: &str, args: Vec<String>) -> Command {
    let mut command = Command::new(FIREJAIL);

    command.arg(format!("--profile=/etc/firejail/{}.profile", target));
    command.arg(format!("/usr/bin/{}", target));
    command.args(args);

    command
}

fn quodlibet_command(args: Vec<String>) {
    let mut file = std::fs::OpenOptions::new()
        .append(true)
        .open(QUODLIBET_FIFO)
        .unwrap();
    file.write_all(match args[0].as_str() {
        "pp" => "play-pause".as_bytes(),
        "sa" => "stop-after 1".as_bytes(),
        _ => panic!(
            "bad argument for quodlibet command: ``{}''",
            args[0].as_str()
        ),
    })
    .unwrap();
}

fn init_command() -> Option<Command> {
    let mut args_less_the_first = std::env::args();
    // Pops the name of this executable.
    args_less_the_first.next();

    // Pops the name of the unner target.
    let target = args_less_the_first.next().unwrap();

    // Copies and collects the remaining argv.
    let args: Vec<String> = args_less_the_first.collect();

    match target.as_str() {
        "ff" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(FIREFOX_PROFILE)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(args)
                    .command,
            );
        }
        "keira" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(KEIRA_PROFILE)
                    .bin_path(KEIRA)
                    .implicit_extra_args(&["-P", "nightly"])
                    .remaining_args(args)
                    .command,
            );
        }
        "npv" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(MPV_PROFILE)
                    .bin_path(MPV)
                    .implicit_extra_args(&["--pulse-buffer=13"])
                    .remaining_args(args)
                    .command,
            );
        }
        "q" => {
            quodlibet_command(args);
            return None;
        }
        "read" => {
            let formatted_args: Vec<String> = vec![format!("about:reader?url={}", args[0])];
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(FIREFOX_PROFILE)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(formatted_args)
                    .command,
            );
        }
        "t" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(TERM_PROFILE)
                    .bin_path(TERM)
                    .remaining_args(args)
                    .command,
            );
        }
        "tbb" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(THUNDERBIRD_PROFILE)
                    .bin_path(THUNDERBIRD)
                    .remaining_args(args)
                    .command,
            );
        }
        "vlk" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile("/etc/firejail/vlc.profile")
                    .bin_path("/usr/bin/vlc")
                    .implicit_extra_args(&["--play-and-exit"])
                    .remaining_args(args)
                    .command,
            );
        }
        "e" => return Some(simple_firejail_command("evince", args)),
        _ => panic!("no handler for ``{}''", target),
    }
}

fn main() {
    if let Some(mut command) = init_command() {
        println!("{:#?}", command);
        command.exec();
    }
}
<|endoftext|>


<commit_before>use crate::common::util::*;
use rust_users::*;
use std::os::unix::fs::PermissionsExt;

#[test]
fn test_install_help() {
    let (_, mut ucmd) = at_and_ucmd!();

    assert!(ucmd
        .arg("--help")
        .succeeds()
        .no_stderr()
        .stdout
        .contains("FLAGS:"));
}

#[test]
fn test_install_basic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_a";
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";

    at.touch(file1);
    at.touch(file2);
    at.mkdir(dir);
    ucmd.arg(file1).arg(file2).arg(dir).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
    assert!(at.file_exists(&format!("{}/{}", dir, file1)));
    assert!(at.file_exists(&format!("{}/{}", dir, file2)));
}

#[test]
fn test_install_twice_dir() {
    let dir = "test_install_target_dir_dir_a";
    let scene = TestScenario::new(util_name!());

    scene.ucmd().arg("-d").arg(dir).succeeds();
    scene.ucmd().arg("-d").arg(dir).succeeds();
    let at = &scene.fixtures;

    assert!(at.dir_exists(dir));
}

#[test]
fn test_install_failing_not_dir() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";
    let file3 = "test_install_target_dir_file_a3";

    at.touch(file1);
    at.touch(file2);
    at.touch(file3);
    assert!(ucmd
        .arg(file1)
        .arg(file2)
        .arg(file3)
        .fails()
        .stderr
        .contains("not a directory"));
}

#[test]
fn test_install_unimplemented_arg() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_b";
    let file = "test_install_target_dir_file_b";
    let context_arg = "--context";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd
        .arg(context_arg)
        .arg(file)
        .arg(dir)
        .fails()
        .stderr
        .contains("Unimplemented"));

    assert!(!at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_component_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component1 = "test_install_target_dir_component_c1";
    let component2 = "test_install_target_dir_component_c2";
    let component3 = "test_install_target_dir_component_c3";
    let directories_arg = "-d";

    ucmd.args(&[directories_arg, component1, component2, component3])
        .succeeds()
        .no_stderr();

    assert!(at.dir_exists(component1));
    assert!(at.dir_exists(component2));
    assert!(at.dir_exists(component3));
}

#[test]
fn test_install_mode_numeric() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    let dir = "test_install_target_dir_dir_e";
    let dir2 = "test_install_target_dir_dir_e2";

    let file = "test_install_target_dir_file_e";
    let mode_arg = "--mode=333";

    at.touch(file);
    at.mkdir(dir);
    scene
        .ucmd()
        .arg(file)
        .arg(dir)
        .arg(mode_arg)
        .succeeds()
        .no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));

    let mode_arg = "-m 0333";
    at.mkdir(dir2);

    let result = scene.ucmd().arg(mode_arg).arg(file).arg(dir2).run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    assert!(result.success);
    let dest_file = &format!("{}/{}", dir2, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_symbolic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_f";
    let file = "test_install_target_dir_file_f";
    let mode_arg = "--mode=o+wx";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file).arg(dir).arg(mode_arg).succeeds().no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100003 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_failing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_g";
    let file = "test_install_target_dir_file_g";
    let mode_arg = "--mode=999";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd
        .arg(file)
        .arg(dir)
        .arg(mode_arg)
        .fails()
        .stderr
        .contains("Invalid mode string: invalid digit found in string"));

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(!at.file_exists(dest_file));
}

#[test]
fn test_install_mode_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component = "test_install_target_dir_component_h";
    let directories_arg = "-d";
    let mode_arg = "--mode=333";

    ucmd.arg(directories_arg)
        .arg(component)
        .arg(mode_arg)
        .succeeds()
        .no_stderr();

    assert!(at.dir_exists(component));
    let permissions = at.metadata(component).permissions();
    assert_eq!(0o040333 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_target_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_file_file_i1";
    let file2 = "test_install_target_file_file_i2";

    at.touch(file1);
    at.touch(file2);
    ucmd.arg(file1).arg(file2).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
}

#[test]
fn test_install_target_new_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file)
        .arg(format!("{}/{}", dir, file))
        .succeeds()
        .no_stderr();

    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_with_group() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";
    let gid = get_effective_gid();

    at.touch(file);
    at.mkdir(dir);
    let result = ucmd
        .arg(file)
        .arg("--group")
        .arg(gid.to_string())
        .arg(format!("{}/{}", dir, file))
        .run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    if is_ci() && result.stderr.contains("error: no such group:") {
        // In the CI, some server are failing to return the group.
        // As seems to be a configuration issue, ignoring it
        return;
    }

    assert!(result.success);
    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_with_owner() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";
    let uid = get_effective_uid();

    at.touch(file);
    at.mkdir(dir);
    let result = ucmd
        .arg(file)
        .arg("--owner")
        .arg(uid.to_string())
        .arg(format!("{}/{}", dir, file))
        .run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    if is_ci() && result.stderr.contains("error: no such user:") {
        // In the CI, some server are failing to return the user id.
        // As seems to be a configuration issue, ignoring it
        return;
    }

    assert!(result.success);
    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_failing_nonexistent_parent() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_new_file_failing_file_k1";
    let file2 = "test_install_target_new_file_failing_file_k2";
    let dir = "test_install_target_new_file_failing_dir_k";

    at.touch(file1);

    let err = ucmd
        .arg(file1)
        .arg(format!("{}/{}", dir, file2))
        .fails()
        .stderr;

    assert!(err.contains("not a directory"))
}

#[test]
fn test_install_preserve_timestamps() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";
    at.touch(file1);

    ucmd.arg(file1).arg(file2).arg("-p").succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));

    let file1_metadata = at.metadata(file1);
    let file2_metadata = at.metadata(file2);

    assert_eq!(
        file1_metadata.accessed().ok(),
        file2_metadata.accessed().ok()
    );
    assert_eq!(
        file1_metadata.modified().ok(),
        file2_metadata.modified().ok()
    );
}

// These two tests are failing but should work
#[test]
fn test_install_copy_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";

    at.touch(file1);
    ucmd.arg(file1).arg(file2).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
}

#[test]
#[cfg(target_os = "linux")]
fn test_install_target_file_dev_null() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "/dev/null";
    let file2 = "test_install_target_file_file_i2";

    ucmd.arg(file1).arg(file2).succeeds().no_stderr();
    assert!(at.file_exists(file2));
}
<commit_msg>Install: remove path when copining files<commit_after>use crate::common::util::*;
use rust_users::*;
use std::os::unix::fs::PermissionsExt;

#[test]
fn test_install_help() {
    let (_, mut ucmd) = at_and_ucmd!();

    assert!(ucmd
        .arg("--help")
        .succeeds()
        .no_stderr()
        .stdout
        .contains("FLAGS:"));
}

#[test]
fn test_install_basic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_a";
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";

    at.touch(file1);
    at.touch(file2);
    at.mkdir(dir);
    ucmd.arg(file1).arg(file2).arg(dir).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
    assert!(at.file_exists(&format!("{}/{}", dir, file1)));
    assert!(at.file_exists(&format!("{}/{}", dir, file2)));
}

#[test]
fn test_install_twice_dir() {
    let dir = "test_install_target_dir_dir_a";
    let scene = TestScenario::new(util_name!());

    scene.ucmd().arg("-d").arg(dir).succeeds();
    scene.ucmd().arg("-d").arg(dir).succeeds();
    let at = &scene.fixtures;

    assert!(at.dir_exists(dir));
}

#[test]
fn test_install_failing_not_dir() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";
    let file3 = "test_install_target_dir_file_a3";

    at.touch(file1);
    at.touch(file2);
    at.touch(file3);
    assert!(ucmd
        .arg(file1)
        .arg(file2)
        .arg(file3)
        .fails()
        .stderr
        .contains("not a directory"));
}

#[test]
fn test_install_unimplemented_arg() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_b";
    let file = "test_install_target_dir_file_b";
    let context_arg = "--context";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd
        .arg(context_arg)
        .arg(file)
        .arg(dir)
        .fails()
        .stderr
        .contains("Unimplemented"));

    assert!(!at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_component_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component1 = "test_install_target_dir_component_c1";
    let component2 = "test_install_target_dir_component_c2";
    let component3 = "test_install_target_dir_component_c3";
    let directories_arg = "-d";

    ucmd.args(&[directories_arg, component1, component2, component3])
        .succeeds()
        .no_stderr();

    assert!(at.dir_exists(component1));
    assert!(at.dir_exists(component2));
    assert!(at.dir_exists(component3));
}

#[test]
fn test_install_mode_numeric() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;
    let dir = "test_install_target_dir_dir_e";
    let dir2 = "test_install_target_dir_dir_e2";

    let file = "test_install_target_dir_file_e";
    let mode_arg = "--mode=333";

    at.touch(file);
    at.mkdir(dir);
    scene
        .ucmd()
        .arg(file)
        .arg(dir)
        .arg(mode_arg)
        .succeeds()
        .no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));

    let mode_arg = "-m 0333";
    at.mkdir(dir2);

    let result = scene.ucmd().arg(mode_arg).arg(file).arg(dir2).run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    assert!(result.success);
    let dest_file = &format!("{}/{}", dir2, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100333 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_symbolic() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_f";
    let file = "test_install_target_dir_file_f";
    let mode_arg = "--mode=o+wx";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file).arg(dir).arg(mode_arg).succeeds().no_stderr();

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(at.file_exists(dest_file));
    let permissions = at.metadata(dest_file).permissions();
    assert_eq!(0o100003 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_mode_failing() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_install_target_dir_dir_g";
    let file = "test_install_target_dir_file_g";
    let mode_arg = "--mode=999";

    at.touch(file);
    at.mkdir(dir);
    assert!(ucmd
        .arg(file)
        .arg(dir)
        .arg(mode_arg)
        .fails()
        .stderr
        .contains("Invalid mode string: invalid digit found in string"));

    let dest_file = &format!("{}/{}", dir, file);
    assert!(at.file_exists(file));
    assert!(!at.file_exists(dest_file));
}

#[test]
fn test_install_mode_directories() {
    let (at, mut ucmd) = at_and_ucmd!();
    let component = "test_install_target_dir_component_h";
    let directories_arg = "-d";
    let mode_arg = "--mode=333";

    ucmd.arg(directories_arg)
        .arg(component)
        .arg(mode_arg)
        .succeeds()
        .no_stderr();

    assert!(at.dir_exists(component));
    let permissions = at.metadata(component).permissions();
    assert_eq!(0o040333 as u32, PermissionsExt::mode(&permissions));
}

#[test]
fn test_install_target_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_file_file_i1";
    let file2 = "test_install_target_file_file_i2";

    at.touch(file1);
    at.touch(file2);
    ucmd.arg(file1).arg(file2).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
}

#[test]
fn test_install_target_new_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";

    at.touch(file);
    at.mkdir(dir);
    ucmd.arg(file)
        .arg(format!("{}/{}", dir, file))
        .succeeds()
        .no_stderr();

    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_with_group() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";
    let gid = get_effective_gid();

    at.touch(file);
    at.mkdir(dir);
    let result = ucmd
        .arg(file)
        .arg("--group")
        .arg(gid.to_string())
        .arg(format!("{}/{}", dir, file))
        .run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    if is_ci() && result.stderr.contains("error: no such group:") {
        // In the CI, some server are failing to return the group.
        // As seems to be a configuration issue, ignoring it
        return;
    }

    assert!(result.success);
    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_with_owner() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_install_target_new_filer_file_j";
    let dir = "test_install_target_new_file_dir_j";
    let uid = get_effective_uid();

    at.touch(file);
    at.mkdir(dir);
    let result = ucmd
        .arg(file)
        .arg("--owner")
        .arg(uid.to_string())
        .arg(format!("{}/{}", dir, file))
        .run();

    println!("stderr = {:?}", result.stderr);
    println!("stdout = {:?}", result.stdout);

    if is_ci() && result.stderr.contains("error: no such user:") {
        // In the CI, some server are failing to return the user id.
        // As seems to be a configuration issue, ignoring it
        return;
    }

    assert!(result.success);
    assert!(at.file_exists(file));
    assert!(at.file_exists(&format!("{}/{}", dir, file)));
}

#[test]
fn test_install_target_new_file_failing_nonexistent_parent() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_new_file_failing_file_k1";
    let file2 = "test_install_target_new_file_failing_file_k2";
    let dir = "test_install_target_new_file_failing_dir_k";

    at.touch(file1);

    let err = ucmd
        .arg(file1)
        .arg(format!("{}/{}", dir, file2))
        .fails()
        .stderr;

    assert!(err.contains("not a directory"))
}

#[test]
fn test_install_preserve_timestamps() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";
    at.touch(file1);

    ucmd.arg(file1).arg(file2).arg("-p").succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));

    let file1_metadata = at.metadata(file1);
    let file2_metadata = at.metadata(file2);

    assert_eq!(
        file1_metadata.accessed().ok(),
        file2_metadata.accessed().ok()
    );
    assert_eq!(
        file1_metadata.modified().ok(),
        file2_metadata.modified().ok()
    );
}

// These two tests are failing but should work
#[test]
fn test_install_copy_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "test_install_target_dir_file_a1";
    let file2 = "test_install_target_dir_file_a2";

    at.touch(file1);
    ucmd.arg(file1).arg(file2).succeeds().no_stderr();

    assert!(at.file_exists(file1));
    assert!(at.file_exists(file2));
}

#[test]
#[cfg(target_os = "linux")]
fn test_install_target_file_dev_null() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file1 = "/dev/null";
    let file2 = "test_install_target_file_file_i2";

    ucmd.arg(file1).arg(file2).succeeds().no_stderr();
    assert!(at.file_exists(file2));
}

#[test]
fn test_install_copy_file_leading_dot() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir1 = "test_install_target_new_file_dir_l";
    let dir2 = "test_install_target_new_file_dir_m";
    let file1 = "test_install_target_file_file_l1";

    at.mkdir(dir1);
    at.mkdir(dir2);
    at.touch(&format!("{}/{}", dir1, file1));

    ucmd.arg(format!("{}/{}", dir1, file1)).arg(dir2).succeeds().no_stderr();
    assert!(at.file_exists(&format!("{}/{}", dir2, file1)));
}
<|endoftext|>


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

#![plugin(clippy)]
#![deny(clippy)]
#![allow(unused, if_let_redundant_pattern_matching)]
#![deny(single_match_else)]

use std::borrow::Cow;

enum Foo { Bar, Baz(u8) }
use Foo::*;

enum ExprNode {
    ExprAddrOf,
    Butterflies,
    Unicorns,
}

static NODE: ExprNode = ExprNode::Unicorns;

fn dummy() {
}

fn unwrap_addr() -> Option<&'static ExprNode> {
    match ExprNode::Butterflies {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else { let x = 5; None }
        ExprNode::ExprAddrOf => Some(&NODE),
        _ => { let x = 5; None },
    }
}

fn single_match(){
    let x = Some(1u8);

    match x {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let Some(y) = x { println!("{:?}", y); };
        Some(y) => { println!("{:?}", y); }
        _ => ()
    };

    let z = (1u8,1u8);
    match z {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let (2...3, 7...9) = z { dummy() };
        (2...3, 7...9) => dummy(),
        _ => {}
    };

    // Not linted (pattern guards used)
    match x {
        Some(y) if y == 0 => println!("{:?}", y),
        _ => ()
    }

    // Not linted (no block with statements in the single arm)
    match z {
        (2...3, 7...9) => println!("{:?}", z),
        _ => println!("nope"),
    }
}

fn single_match_know_enum() {
    let x = Some(1u8);
    let y : Result<_, i8> = Ok(1i8);

    match x {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let Some(y) = x { dummy() };
        Some(y) => dummy(),
        None => ()
    };

    match y {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let Ok(y) = y { dummy() };
        Ok(y) => dummy(),
        Err(..) => ()
    };

    let c = Cow::Borrowed("");

    match c {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let Cow::Borrowed(..) = c { dummy() };
        Cow::Borrowed(..) => dummy(),
        Cow::Owned(..) => (),
    };

    let z = Foo::Bar;
    // no warning
    match z {
        Bar => println!("42"),
        Baz(_) => (),
    }

    match z {
        Baz(_) => println!("42"),
        Bar => (),
    }
}

fn match_bool() {
    let test: bool = true;

    match test {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if test { 0 } else { 42 };
        true => 0,
        false => 42,
    };

    let option = 1;
    match option == 1 {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if option == 1 { 1 } else { 0 };
        true => 1,
        false => 0,
    };

    match test {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if !test { println!("Noooo!"); };
        true => (),
        false => { println!("Noooo!"); }
    };

    match test {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if !test { println!("Noooo!"); };
        false => { println!("Noooo!"); }
        _ => (),
    };

    match test && test {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if !(test && test) { println!("Noooo!"); };
    //~| ERROR equal expressions as operands
        false => { println!("Noooo!"); }
        _ => (),
    };

    match test {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if test { println!("Yes!"); } else { println!("Noooo!"); };
        false => { println!("Noooo!"); }
        true => { println!("Yes!"); }
    };

    // Not linted
    match option {
        1 ... 10 => 1,
        11 ... 20 => 2,
        _ => 3,
    };
}

fn ref_pats() {
    {
        let v = &Some(0);
        match v {
            //~^ERROR add `&` to all patterns
            //~|HELP instead of
            //~|SUGGESTION match *v { .. }
            &Some(v) => println!("{:?}", v),
            &None => println!("none"),
        }
        match v {  // this doesn't trigger, we have a different pattern
            &Some(v) => println!("some"),
            other => println!("other"),
        }
    }
    let tup =& (1, 2);
    match tup {
        //~^ERROR add `&` to all patterns
        //~|HELP instead of
        //~|SUGGESTION match *tup { .. }
        &(v, 1) => println!("{}", v),
        _ => println!("none"),
    }
    // special case: using & both in expr and pats
    let w = Some(0);
    match &w {
        //~^ERROR add `&` to both
        //~|HELP try
        //~|SUGGESTION match w { .. }
        &Some(v) => println!("{:?}", v),
        &None => println!("none"),
    }
    // false positive: only wildcard pattern
    let w = Some(0);
    match w {
        _ => println!("none"),
    }

    let a = &Some(0);
    if let &None = a {
        //~^ERROR add `&` to all patterns
        //~|HELP instead of
        //~|SUGGESTION if let .. = *a { .. }
        println!("none");
    }

    let b = Some(0);
    if let &None = &b {
        //~^ERROR add `&` to both
        //~|HELP try
        //~|SUGGESTION if let .. = b { .. }
        println!("none");
    }
}

fn overlapping() {
    const FOO : u64 = 2;

    match 42 {
        0 ... 10 => println!("0 ... 10"), //~ERROR: some ranges overlap
        0 ... 11 => println!("0 ... 11"), //~NOTE overlaps with this
        _ => (),
    }

    match 42 {
        0 ... 5 => println!("0 ... 5"), //~ERROR: some ranges overlap
        6 ... 7 => println!("6 ... 7"),
        FOO ... 11 => println!("0 ... 11"), //~NOTE overlaps with this
        _ => (),
    }

    match 42 {
        2 => println!("2"), //~NOTE overlaps with this
        0 ... 5 => println!("0 ... 5"), //~ERROR: some ranges overlap
        _ => (),
    }

    match 42 {
        2 => println!("2"), //~NOTE overlaps with this
        0 ... 2 => println!("0 ... 2"), //~ERROR: some ranges overlap
        _ => (),
    }

    match 42 {
        0 ... 10 => println!("0 ... 10"),
        11 ... 50 => println!("11 ... 50"),
        _ => (),
    }

    match 42 {
        2 => println!("2"),
        0 .. 2 => println!("0 .. 2"),
        _ => (),
    }

    match 42 {
        0 .. 10 => println!("0 .. 10"),
        10 .. 50 => println!("10 .. 50"),
        _ => (),
    }

    match 42 {
        0 .. 11 => println!("0 ... 10"), //~ERROR: some ranges overlap
        0 ... 11 => println!("0 ... 10"), //~NOTE overlaps with this
        _ => (),
    }

    if let None = Some(42) {
        // nothing
    } else if let None = Some(42) {
        // another nothing :-)
    }
}

fn main() {
}
<commit_msg>fix println message in tests<commit_after>#![feature(plugin)]
#![feature(exclusive_range_pattern)]

#![plugin(clippy)]
#![deny(clippy)]
#![allow(unused, if_let_redundant_pattern_matching)]
#![deny(single_match_else)]

use std::borrow::Cow;

enum Foo { Bar, Baz(u8) }
use Foo::*;

enum ExprNode {
    ExprAddrOf,
    Butterflies,
    Unicorns,
}

static NODE: ExprNode = ExprNode::Unicorns;

fn dummy() {
}

fn unwrap_addr() -> Option<&'static ExprNode> {
    match ExprNode::Butterflies {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let ExprNode::ExprAddrOf = ExprNode::Butterflies { Some(&NODE) } else { let x = 5; None }
        ExprNode::ExprAddrOf => Some(&NODE),
        _ => { let x = 5; None },
    }
}

fn single_match(){
    let x = Some(1u8);

    match x {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let Some(y) = x { println!("{:?}", y); };
        Some(y) => { println!("{:?}", y); }
        _ => ()
    };

    let z = (1u8,1u8);
    match z {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let (2...3, 7...9) = z { dummy() };
        (2...3, 7...9) => dummy(),
        _ => {}
    };

    // Not linted (pattern guards used)
    match x {
        Some(y) if y == 0 => println!("{:?}", y),
        _ => ()
    }

    // Not linted (no block with statements in the single arm)
    match z {
        (2...3, 7...9) => println!("{:?}", z),
        _ => println!("nope"),
    }
}

fn single_match_know_enum() {
    let x = Some(1u8);
    let y : Result<_, i8> = Ok(1i8);

    match x {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let Some(y) = x { dummy() };
        Some(y) => dummy(),
        None => ()
    };

    match y {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let Ok(y) = y { dummy() };
        Ok(y) => dummy(),
        Err(..) => ()
    };

    let c = Cow::Borrowed("");

    match c {
        //~^ ERROR you seem to be trying to use match
        //~| HELP try
        //~| SUGGESTION if let Cow::Borrowed(..) = c { dummy() };
        Cow::Borrowed(..) => dummy(),
        Cow::Owned(..) => (),
    };

    let z = Foo::Bar;
    // no warning
    match z {
        Bar => println!("42"),
        Baz(_) => (),
    }

    match z {
        Baz(_) => println!("42"),
        Bar => (),
    }
}

fn match_bool() {
    let test: bool = true;

    match test {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if test { 0 } else { 42 };
        true => 0,
        false => 42,
    };

    let option = 1;
    match option == 1 {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if option == 1 { 1 } else { 0 };
        true => 1,
        false => 0,
    };

    match test {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if !test { println!("Noooo!"); };
        true => (),
        false => { println!("Noooo!"); }
    };

    match test {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if !test { println!("Noooo!"); };
        false => { println!("Noooo!"); }
        _ => (),
    };

    match test && test {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if !(test && test) { println!("Noooo!"); };
    //~| ERROR equal expressions as operands
        false => { println!("Noooo!"); }
        _ => (),
    };

    match test {
    //~^ ERROR you seem to be trying to match on a boolean expression
    //~| HELP consider
    //~| SUGGESTION if test { println!("Yes!"); } else { println!("Noooo!"); };
        false => { println!("Noooo!"); }
        true => { println!("Yes!"); }
    };

    // Not linted
    match option {
        1 ... 10 => 1,
        11 ... 20 => 2,
        _ => 3,
    };
}

fn ref_pats() {
    {
        let v = &Some(0);
        match v {
            //~^ERROR add `&` to all patterns
            //~|HELP instead of
            //~|SUGGESTION match *v { .. }
            &Some(v) => println!("{:?}", v),
            &None => println!("none"),
        }
        match v {  // this doesn't trigger, we have a different pattern
            &Some(v) => println!("some"),
            other => println!("other"),
        }
    }
    let tup =& (1, 2);
    match tup {
        //~^ERROR add `&` to all patterns
        //~|HELP instead of
        //~|SUGGESTION match *tup { .. }
        &(v, 1) => println!("{}", v),
        _ => println!("none"),
    }
    // special case: using & both in expr and pats
    let w = Some(0);
    match &w {
        //~^ERROR add `&` to both
        //~|HELP try
        //~|SUGGESTION match w { .. }
        &Some(v) => println!("{:?}", v),
        &None => println!("none"),
    }
    // false positive: only wildcard pattern
    let w = Some(0);
    match w {
        _ => println!("none"),
    }

    let a = &Some(0);
    if let &None = a {
        //~^ERROR add `&` to all patterns
        //~|HELP instead of
        //~|SUGGESTION if let .. = *a { .. }
        println!("none");
    }

    let b = Some(0);
    if let &None = &b {
        //~^ERROR add `&` to both
        //~|HELP try
        //~|SUGGESTION if let .. = b { .. }
        println!("none");
    }
}

fn overlapping() {
    const FOO : u64 = 2;

    match 42 {
        0 ... 10 => println!("0 ... 10"), //~ERROR: some ranges overlap
        0 ... 11 => println!("0 ... 11"), //~NOTE overlaps with this
        _ => (),
    }

    match 42 {
        0 ... 5 => println!("0 ... 5"), //~ERROR: some ranges overlap
        6 ... 7 => println!("6 ... 7"),
        FOO ... 11 => println!("0 ... 11"), //~NOTE overlaps with this
        _ => (),
    }

    match 42 {
        2 => println!("2"), //~NOTE overlaps with this
        0 ... 5 => println!("0 ... 5"), //~ERROR: some ranges overlap
        _ => (),
    }

    match 42 {
        2 => println!("2"), //~NOTE overlaps with this
        0 ... 2 => println!("0 ... 2"), //~ERROR: some ranges overlap
        _ => (),
    }

    match 42 {
        0 ... 10 => println!("0 ... 10"),
        11 ... 50 => println!("11 ... 50"),
        _ => (),
    }

    match 42 {
        2 => println!("2"),
        0 .. 2 => println!("0 .. 2"),
        _ => (),
    }

    match 42 {
        0 .. 10 => println!("0 .. 10"),
        10 .. 50 => println!("10 .. 50"),
        _ => (),
    }

    match 42 {
        0 .. 11 => println!("0 .. 11"), //~ERROR: some ranges overlap
        0 ... 11 => println!("0 ... 11"), //~NOTE overlaps with this
        _ => (),
    }

    if let None = Some(42) {
        // nothing
    } else if let None = Some(42) {
        // another nothing :-)
    }
}

fn main() {
}
<|endoftext|>


<commit_before>use sdl;
use ll;
use util::Rect;

use core::result::{Result, Err, Ok};
use core::cast::transmute;
use core::cast;
use core::libc::{c_void, c_int, c_char};
use core::str;
use core::vec;

pub enum SurfaceFlag {
    SWSurface = 0x00000000,
    HWSurface = 0x00000001,
    AsyncBlit = 0x00000004,
}

pub enum VideoModeFlag {
    AnyFormat = 0x10000000,
    HWPalette = 0x20000000,
    DoubleBuf = 0x40000000,
    Fullscreen = 0x80000000,
    OpenGL = 0x00000002,
    OpenGLBlit = 0x0000000A,
    Resizable  = 0x00000010,
    NoFrame = 0x00000020,
}

pub struct Surface {
    priv raw_surface: *ll::video::SDL_Surface,
}

pub impl Surface {
    fn display_format(&self) -> Result<~Surface, ~str> {
        unsafe {
            let raw_surface = ll::video::SDL_DisplayFormat(self.raw_surface);
            if raw_surface == ptr::null() {
                Err(sdl::get_error())
            } else {
                Ok(~Surface{ raw_surface: raw_surface })
            }
        }
    }

    fn flip(&self) -> bool {
        unsafe {
            ll::video::SDL_Flip(self.raw_surface) == 0 as c_int
        }
    }

    /// Locks a surface so that the pixels can be directly accessed safely.
    fn with_lock<R>(&self, f: &fn(pixels: &mut [u8]) -> R) -> R {
        unsafe {
            if ll::video::SDL_LockSurface(self.raw_surface) != 0 { die!(~"Could not lock surface"); }
            let len = (*self.raw_surface).pitch as uint * ((*self.raw_surface).h as uint);
            let pixels: &mut [u8] = transmute(((*self.raw_surface).pixels, len));
            let rv = f(pixels);
            ll::video::SDL_UnlockSurface(self.raw_surface);
            rv
        }
    }

    fn lock(&self) -> bool {
        unsafe {
            return ll::video::SDL_LockSurface(self.raw_surface) == 0 as c_int;
        }
    }

    fn unlock(&self) {
        unsafe {
            ll::video::SDL_UnlockSurface(self.raw_surface);
        }
    }

    fn blit_surface_rect(&self, src: &Surface, srcrect: &Rect, dstrect: &Rect) -> bool {
        unsafe {
            let res = ll::video::SDL_UpperBlit(src.raw_surface,
                                               srcrect,
                                               self.raw_surface,
                                               dstrect);
            return res == 0 as c_int;
        }
    }

    fn blit_surface(&self, src: &Surface) -> bool {
        unsafe {
            let res = ll::video::SDL_UpperBlit(src.raw_surface,
                                               ptr::null(),
                                               self.raw_surface,
                                               ptr::null());
            return res == 0 as c_int;
        }
    }

    fn fill_rect(&self, rect: &Rect, color: u32) -> bool {
        unsafe {
            return ll::video::SDL_FillRect(self.raw_surface, rect, color) == 0 as c_int;
        }
    }

    fn fill(&self, color: u32) -> bool {
        unsafe {
            return ll::video::SDL_FillRect(self.raw_surface, ptr::null(), color) == 0 as c_int;
        }
    }
}

pub impl Surface : Drop {
    pub fn finalize(&self) {
        unsafe {
            ll::video::SDL_FreeSurface(self.raw_surface)
        }
    }
}

//FIXME: This needs to be called multiple times on window resize, so Drop is going to do bad things, possibly. Test it out.
//Consider making videomode surfaces their own type, with a reset method?
pub fn set_video_mode(
    width: int,
    height: int,
    bitsperpixel: int,
    surface_flags: &[SurfaceFlag],
    video_mode_flags: &[VideoModeFlag]) -> Result<~Surface, ~str> {
    let flags = vec::foldl(0u32, surface_flags, |flags, flag| {
        flags | *flag as u32
    });
    let flags = vec::foldl(flags, video_mode_flags, |flags, flag| {
        flags | *flag as u32
    });

    unsafe {
        let raw_surface = ll::video::SDL_SetVideoMode(width as c_int,
                                                      height as c_int,
                                                      bitsperpixel as c_int,
                                                      flags);

        if raw_surface == ptr::null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface{ raw_surface: raw_surface })
        }
    }
}

pub fn load_bmp(file: &str) -> Result<~Surface, ~str> {
    str::as_buf(file, |buf, _len| {
        let buf = unsafe {
            cast::reinterpret_cast(&buf)
        };
        str::as_buf(~"rb", |rbbuf, _len| {
            unsafe {
                let rbbuf = cast::reinterpret_cast(&rbbuf);
                let raw_bmp = ll::video::SDL_RWFromFile(buf, rbbuf);
                let raw_surface = ll::video::SDL_LoadBMP_RW(raw_bmp, 1 as c_int);
                if raw_surface == ptr::null() {
                    Err(sdl::get_error())
                } else {
                    Ok(~Surface{ raw_surface: raw_surface })
                }
            }
        })
    })
}

pub fn create_rgb_surface(
    surface_flags: &[SurfaceFlag],
    width: int, height: int, bits_per_pixel: int,
    rmask: u32, gmask: u32, bmask: u32, amask: u32) -> Result<~Surface, ~str> {

    let flags = vec::foldl(0u32, surface_flags, |flags, flag| {
        flags | *flag as u32
    });

    unsafe {
        let raw_surface = ll::video::SDL_CreateRGBSurface(
            flags, width as c_int, height as c_int, bits_per_pixel as c_int,
            rmask, gmask, bmask, amask);
        if raw_surface == ptr::null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface{ raw_surface: raw_surface })
        }
    }
}

pub fn swap_buffers() {
    unsafe {
        ll::video::SDL_GL_SwapBuffers();
    }
}
<commit_msg>Surfaces now track whether they're supposed ot be freed. Fixes #27<commit_after>use sdl;
use ll;
use util::Rect;

use core::result::{Result, Err, Ok};
use core::cast::transmute;
use core::cast;
use core::libc::{c_void, c_int, c_char};
use core::str;
use core::vec;

pub enum SurfaceFlag {
    SWSurface = 0x00000000,
    HWSurface = 0x00000001,
    AsyncBlit = 0x00000004,
}

pub enum VideoModeFlag {
    AnyFormat = 0x10000000,
    HWPalette = 0x20000000,
    DoubleBuf = 0x40000000,
    Fullscreen = 0x80000000,
    OpenGL = 0x00000002,
    OpenGLBlit = 0x0000000A,
    Resizable  = 0x00000010,
    NoFrame = 0x00000020,
}

pub struct Surface {
    priv raw_surface: *ll::video::SDL_Surface,
    priv needs_freeing: bool
}

pub impl Surface {
    fn display_format(&self) -> Result<~Surface, ~str> {
        unsafe {
            let raw_surface = ll::video::SDL_DisplayFormat(self.raw_surface);
            if raw_surface == ptr::null() {
                Err(sdl::get_error())
            } else {
                Ok(~Surface{ raw_surface: raw_surface, needs_freeing: true })
            }
        }
    }

    fn flip(&self) -> bool {
        unsafe {
            ll::video::SDL_Flip(self.raw_surface) == 0 as c_int
        }
    }

    /// Locks a surface so that the pixels can be directly accessed safely.
    fn with_lock<R>(&self, f: &fn(pixels: &mut [u8]) -> R) -> R {
        unsafe {
            if ll::video::SDL_LockSurface(self.raw_surface) != 0 { die!(~"Could not lock surface"); }
            let len = (*self.raw_surface).pitch as uint * ((*self.raw_surface).h as uint);
            let pixels: &mut [u8] = transmute(((*self.raw_surface).pixels, len));
            let rv = f(pixels);
            ll::video::SDL_UnlockSurface(self.raw_surface);
            rv
        }
    }

    fn lock(&self) -> bool {
        unsafe {
            return ll::video::SDL_LockSurface(self.raw_surface) == 0 as c_int;
        }
    }

    fn unlock(&self) {
        unsafe {
            ll::video::SDL_UnlockSurface(self.raw_surface);
        }
    }

    fn blit_surface_rect(&self, src: &Surface, srcrect: &Rect, dstrect: &Rect) -> bool {
        unsafe {
            let res = ll::video::SDL_UpperBlit(src.raw_surface,
                                               srcrect,
                                               self.raw_surface,
                                               dstrect);
            return res == 0 as c_int;
        }
    }

    fn blit_surface(&self, src: &Surface) -> bool {
        unsafe {
            let res = ll::video::SDL_UpperBlit(src.raw_surface,
                                               ptr::null(),
                                               self.raw_surface,
                                               ptr::null());
            return res == 0 as c_int;
        }
    }

    fn fill_rect(&self, rect: &Rect, color: u32) -> bool {
        unsafe {
            return ll::video::SDL_FillRect(self.raw_surface, rect, color) == 0 as c_int;
        }
    }

    fn fill(&self, color: u32) -> bool {
        unsafe {
            return ll::video::SDL_FillRect(self.raw_surface, ptr::null(), color) == 0 as c_int;
        }
    }
}

pub impl Surface : Drop {
    pub fn finalize(&self) {
        if self.needs_freeing {
            unsafe {
                ll::video::SDL_FreeSurface(self.raw_surface)
            }
        }
    }
}

pub fn set_video_mode(
    width: int,
    height: int,
    bitsperpixel: int,
    surface_flags: &[SurfaceFlag],
    video_mode_flags: &[VideoModeFlag]) -> Result<~Surface, ~str> {
    let flags = vec::foldl(0u32, surface_flags, |flags, flag| {
        flags | *flag as u32
    });
    let flags = vec::foldl(flags, video_mode_flags, |flags, flag| {
        flags | *flag as u32
    });

    unsafe {
        let raw_surface = ll::video::SDL_SetVideoMode(width as c_int,
                                                      height as c_int,
                                                      bitsperpixel as c_int,
                                                      flags);

        if raw_surface == ptr::null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface{ raw_surface: raw_surface, needs_freeing: false })
        }
    }
}

pub fn load_bmp(file: &str) -> Result<~Surface, ~str> {
    str::as_buf(file, |buf, _len| {
        let buf = unsafe {
            cast::reinterpret_cast(&buf)
        };
        str::as_buf(~"rb", |rbbuf, _len| {
            unsafe {
                let rbbuf = cast::reinterpret_cast(&rbbuf);
                let raw_bmp = ll::video::SDL_RWFromFile(buf, rbbuf);
                let raw_surface = ll::video::SDL_LoadBMP_RW(raw_bmp, 1 as c_int);
                if raw_surface == ptr::null() {
                    Err(sdl::get_error())
                } else {
                    Ok(~Surface{ raw_surface: raw_surface, needs_freeing: true })
                }
            }
        })
    })
}

pub fn create_rgb_surface(
    surface_flags: &[SurfaceFlag],
    width: int, height: int, bits_per_pixel: int,
    rmask: u32, gmask: u32, bmask: u32, amask: u32) -> Result<~Surface, ~str> {

    let flags = vec::foldl(0u32, surface_flags, |flags, flag| {
        flags | *flag as u32
    });

    unsafe {
        let raw_surface = ll::video::SDL_CreateRGBSurface(
            flags, width as c_int, height as c_int, bits_per_pixel as c_int,
            rmask, gmask, bmask, amask);
        if raw_surface == ptr::null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface{ raw_surface: raw_surface, needs_freeing: true })
        }
    }
}

pub fn swap_buffers() {
    unsafe {
        ll::video::SDL_GL_SwapBuffers();
    }
}
<|endoftext|>


<commit_before><commit_msg>Improve DefIndex formatting to be more semantic<commit_after><|endoftext|>


<commit_before>extern crate image;

pub struct AlignedImage {
    aligned_buffer: Vec<u8>,
    width: usize,
    height: usize,
    stride: usize,
}

impl AlignedImage {
    pub fn from_uknown_buffer(input: &[u8]) -> Result<Self, String> {
        match image::load_from_memory(input) {
            Ok(image) => match image.as_rgb8().as_ref() {
                Some(rgb_image) => {
                    // Fix stride: there must be a better way...
                    // Align to Cairo's needs: 4 bytes per pixel
                    // When converting to RGB8, image crate uses 3 bytes in different order
                    let width = rgb_image.width() as usize;
                    let height = rgb_image.height() as usize;
                    let bytes_per_pixels = 4;
                    let stride = width * bytes_per_pixels;

                    let mut new_img = AlignedImage {
                        aligned_buffer: Vec::with_capacity(height * stride),
                        width: width,
                        height: height,
                        stride: stride,
                    };

                    let mut pixel = [0; 4];
                    let mut byte_iter = rgb_image.iter();
                    loop {
                        match byte_iter.next() {
                            Some(byte) => pixel[2] = byte.clone(),
                            None => break,
                        };
                        let byte = byte_iter.next().unwrap();
                        pixel[1] = byte.clone();
                        let byte = byte_iter.next().unwrap();
                        pixel[0] = byte.clone();
                        new_img.aligned_buffer.extend_from_slice(&pixel);
                    }

                    Ok(new_img)
                },
                None => Err("Error converting image to raw RGB".to_owned()),
            },
            Err(error) => Err(format!("Error loading image: {:?}", error)),
        }
    }

    pub fn into_boxed_slice(self) -> Box<[u8]> {
        self.aligned_buffer.into_boxed_slice()
    }

    pub fn to_vec(&self) -> Vec<u8> {
        self.aligned_buffer.clone()
    }

    pub fn as_ref<'a>(&'a self) -> &'a Vec<u8> {
        self.aligned_buffer.as_ref()
    }

    pub fn width(&self) -> usize {
        self.width
    }

    pub fn height(&self) -> usize {
        self.height
    }

    pub fn stride(&self) -> usize {
        self.stride
    }
}
<commit_msg>AlignedImage: enhance realignment (#7)<commit_after>extern crate image;

pub struct AlignedImage {
    aligned_buffer: Vec<u8>,
    width: usize,
    height: usize,
    stride: usize,
}

impl AlignedImage {
    pub fn from_uknown_buffer(input: &[u8]) -> Result<Self, String> {
        match image::load_from_memory(input) {
            Ok(image) => match image.as_rgb8().as_ref() {
                Some(rgb_image) => {
                    // Fix stride: there must be a better way...
                    // Align to Cairo's needs: 4 bytes per pixel
                    // When converting to RGB8, image crate uses 3 bytes in different order
                    let width = rgb_image.width() as usize;
                    let height = rgb_image.height() as usize;
                    let bytes_per_pixels = 4;
                    let stride = width * bytes_per_pixels;

                    let mut new_img = AlignedImage {
                        aligned_buffer: Vec::with_capacity(height * stride),
                        width: width,
                        height: height,
                        stride: stride,
                    };

                    for pixel in rgb_image.chunks(3) {
                        new_img.aligned_buffer.push(pixel[2]);
                        new_img.aligned_buffer.push(pixel[1]);
                        new_img.aligned_buffer.push(pixel[0]);
                        new_img.aligned_buffer.push(0);
                    }

                    Ok(new_img)
                },
                None => Err("Error converting image to raw RGB".to_owned()),
            },
            Err(error) => Err(format!("Error loading image: {:?}", error)),
        }
    }

    pub fn into_boxed_slice(self) -> Box<[u8]> {
        self.aligned_buffer.into_boxed_slice()
    }

    pub fn to_vec(&self) -> Vec<u8> {
        self.aligned_buffer.clone()
    }

    pub fn as_ref<'a>(&'a self) -> &'a Vec<u8> {
        self.aligned_buffer.as_ref()
    }

    pub fn width(&self) -> usize {
        self.width
    }

    pub fn height(&self) -> usize {
        self.height
    }

    pub fn stride(&self) -> usize {
        self.stride
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![plugin(clippy)]
#![deny(module_inception)]

mod foo {
    mod bar {
        mod bar { //~ ERROR module has the same name as its containing module
            mod foo {}
        }
        mod foo {}
    }
    mod foo { //~ ERROR module has the same name as its containing module
        mod bar {}
    }
}

fn main() {}
<commit_msg>Add test for `#[allow(module_inception)]` on the inner module<commit_after>#![feature(plugin)]
#![plugin(clippy)]
#![deny(module_inception)]

mod foo {
    mod bar {
        mod bar { //~ ERROR module has the same name as its containing module
            mod foo {}
        }
        mod foo {}
    }
    mod foo { //~ ERROR module has the same name as its containing module
        mod bar {}
    }
}

// No warning. See <https://github.com/Manishearth/rust-clippy/issues/1220>.
mod bar {
    #[allow(module_inception)]
    mod bar {
    }
}

fn main() {}
<|endoftext|>


<commit_before>use core::ops::{Range, RangeFull, RangeFrom, RangeTo, RangeInclusive};

// Test the Range structs without the syntactic sugar.

#[test]
fn test_range() {
    let r = Range { start: 2, end: 10 };
    let mut count = 0;
    for (i, ri) in r.enumerate() {
        assert_eq!(ri, i + 2);
        assert!(ri >= 2 && ri < 10);
        count += 1;
    }
    assert_eq!(count, 8);
}

#[test]
fn test_range_from() {
    let r = RangeFrom { start: 2 };
    let mut count = 0;
    for (i, ri) in r.take(10).enumerate() {
        assert_eq!(ri, i + 2);
        assert!(ri >= 2 && ri < 12);
        count += 1;
    }
    assert_eq!(count, 10);
}

#[test]
fn test_range_to() {
    // Not much to test.
    let _ = RangeTo { end: 42 };
}

#[test]
fn test_full_range() {
    // Not much to test.
    let _ = RangeFull;
}

#[test]
fn test_range_inclusive() {
    let mut r = RangeInclusive::new(1i8, 2);
    assert_eq!(r.next(), Some(1));
    assert_eq!(r.next(), Some(2));
    assert_eq!(r.next(), None);

    r = RangeInclusive::new(127i8, 127);
    assert_eq!(r.next(), Some(127));
    assert_eq!(r.next(), None);

    r = RangeInclusive::new(-128i8, -128);
    assert_eq!(r.next_back(), Some(-128));
    assert_eq!(r.next_back(), None);

    // degenerate
    r = RangeInclusive::new(1, -1);
    assert_eq!(r.size_hint(), (0, Some(0)));
    assert_eq!(r.next(), None);
}

#[test]
fn test_range_is_empty() {
    use core::f32::*;

    assert!(!(0.0 .. 10.0).is_empty());
    assert!( (-0.0 .. 0.0).is_empty());
    assert!( (10.0 .. 0.0).is_empty());

    assert!(!(NEG_INFINITY .. INFINITY).is_empty());
    assert!( (EPSILON .. NAN).is_empty());
    assert!( (NAN .. EPSILON).is_empty());
    assert!( (NAN .. NAN).is_empty());

    assert!(!(0.0 ..= 10.0).is_empty());
    assert!(!(-0.0 ..= 0.0).is_empty());
    assert!( (10.0 ..= 0.0).is_empty());

    assert!(!(NEG_INFINITY ..= INFINITY).is_empty());
    assert!( (EPSILON ..= NAN).is_empty());
    assert!( (NAN ..= EPSILON).is_empty());
    assert!( (NAN ..= NAN).is_empty());
}
<commit_msg>Add Bound tests<commit_after>use core::ops::{Range, RangeFull, RangeFrom, RangeTo, RangeInclusive};

// Test the Range structs without the syntactic sugar.

#[test]
fn test_range() {
    let r = Range { start: 2, end: 10 };
    let mut count = 0;
    for (i, ri) in r.enumerate() {
        assert_eq!(ri, i + 2);
        assert!(ri >= 2 && ri < 10);
        count += 1;
    }
    assert_eq!(count, 8);
}

#[test]
fn test_range_from() {
    let r = RangeFrom { start: 2 };
    let mut count = 0;
    for (i, ri) in r.take(10).enumerate() {
        assert_eq!(ri, i + 2);
        assert!(ri >= 2 && ri < 12);
        count += 1;
    }
    assert_eq!(count, 10);
}

#[test]
fn test_range_to() {
    // Not much to test.
    let _ = RangeTo { end: 42 };
}

#[test]
fn test_full_range() {
    // Not much to test.
    let _ = RangeFull;
}

#[test]
fn test_range_inclusive() {
    let mut r = RangeInclusive::new(1i8, 2);
    assert_eq!(r.next(), Some(1));
    assert_eq!(r.next(), Some(2));
    assert_eq!(r.next(), None);

    r = RangeInclusive::new(127i8, 127);
    assert_eq!(r.next(), Some(127));
    assert_eq!(r.next(), None);

    r = RangeInclusive::new(-128i8, -128);
    assert_eq!(r.next_back(), Some(-128));
    assert_eq!(r.next_back(), None);

    // degenerate
    r = RangeInclusive::new(1, -1);
    assert_eq!(r.size_hint(), (0, Some(0)));
    assert_eq!(r.next(), None);
}

#[test]
fn test_range_is_empty() {
    use core::f32::*;

    assert!(!(0.0 .. 10.0).is_empty());
    assert!( (-0.0 .. 0.0).is_empty());
    assert!( (10.0 .. 0.0).is_empty());

    assert!(!(NEG_INFINITY .. INFINITY).is_empty());
    assert!( (EPSILON .. NAN).is_empty());
    assert!( (NAN .. EPSILON).is_empty());
    assert!( (NAN .. NAN).is_empty());

    assert!(!(0.0 ..= 10.0).is_empty());
    assert!(!(-0.0 ..= 0.0).is_empty());
    assert!( (10.0 ..= 0.0).is_empty());

    assert!(!(NEG_INFINITY ..= INFINITY).is_empty());
    assert!( (EPSILON ..= NAN).is_empty());
    assert!( (NAN ..= EPSILON).is_empty());
    assert!( (NAN ..= NAN).is_empty());
}

#[test]
fn test_bound_cloned_unbounded() {
    assert_eq!(Bound::<&u32>::Unbounded.cloned(), Bound::Unbounded);
}

#[test]
fn test_bound_cloned_included() {
    assert_eq!(Bound::Included(&3).cloned(), Bound::Included(3));
}

#[test]
fn test_bound_cloned_excluded() {
    assert_eq!(Bound::Excluded(&3).cloned(), Bound::Excluded(3));
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use clone::Clone;
use result::{Ok, Err};
use io::net::ip::SocketAddr;
use io::{Reader, Writer, IoResult};
use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, LocalIo};

pub struct UdpSocket {
    priv obj: ~RtioUdpSocket
}

impl UdpSocket {
    pub fn bind(addr: SocketAddr) -> IoResult<UdpSocket> {
        LocalIo::maybe_raise(|io| {
            io.udp_bind(addr).map(|s| UdpSocket { obj: s })
        })
    }

    pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> {
        self.obj.recvfrom(buf)
    }

    pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
        self.obj.sendto(buf, dst)
    }

    pub fn connect(self, other: SocketAddr) -> UdpStream {
        UdpStream { socket: self, connectedTo: other }
    }

    pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
        self.obj.socket_name()
    }
}

impl Clone for UdpSocket {
    /// Creates a new handle to this UDP socket, allowing for simultaneous reads
    /// and writes of the socket.
    ///
    /// The underlying UDP socket will not be closed until all handles to the
    /// socket have been deallocated. Two concurrent reads will not receive the
    /// same data.  Instead, the first read will receive the first packet
    /// received, and the second read will receive the second packet.
    fn clone(&self) -> UdpSocket {
        UdpSocket { obj: self.obj.clone() }
    }
}

pub struct UdpStream {
    priv socket: UdpSocket,
    priv connectedTo: SocketAddr
}

impl UdpStream {
    pub fn as_socket<T>(&mut self, f: |&mut UdpSocket| -> T) -> T {
        f(&mut self.socket)
    }

    pub fn disconnect(self) -> UdpSocket { self.socket }
}

impl Reader for UdpStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let peer = self.connectedTo;
        self.as_socket(|sock| {
            match sock.recvfrom(buf) {
                Ok((_nread, src)) if src != peer => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        })
    }
}

impl Writer for UdpStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.as_socket(|sock| sock.sendto(buf, self.connectedTo))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use io::net::ip::{SocketAddr};

    // FIXME #11530 this fails on android because tests are run as root
    iotest!(fn bind_error() {
        let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
        match UdpSocket::bind(addr) {
            Ok(..) => fail!(),
            Err(e) => assert_eq!(e.kind, PermissionDenied),
        }
    } #[ignore(cfg(windows))] #[ignore(cfg(target_os = "android"))])

    iotest!(fn socket_smoke_test_ip4() {
        let server_ip = next_test_ip4();
        let client_ip = next_test_ip4();
        let (port, chan) = Chan::new();
        let (port2, chan2) = Chan::new();

        spawn(proc() {
            match UdpSocket::bind(client_ip) {
                Ok(ref mut client) => {
                    port.recv();
                    client.sendto([99], server_ip).unwrap()
                }
                Err(..) => fail!()
            }
            chan2.send(());
        });

        match UdpSocket::bind(server_ip) {
            Ok(ref mut server) => {
                chan.send(());
                let mut buf = [0];
                match server.recvfrom(buf) {
                    Ok((nread, src)) => {
                        assert_eq!(nread, 1);
                        assert_eq!(buf[0], 99);
                        assert_eq!(src, client_ip);
                    }
                    Err(..) => fail!()
                }
            }
            Err(..) => fail!()
        }
        port2.recv();
    })

    iotest!(fn socket_smoke_test_ip6() {
        let server_ip = next_test_ip6();
        let client_ip = next_test_ip6();
        let (port, chan) = Chan::<()>::new();

        spawn(proc() {
            match UdpSocket::bind(client_ip) {
                Ok(ref mut client) => {
                    port.recv();
                    client.sendto([99], server_ip).unwrap()
                }
                Err(..) => fail!()
            }
        });

        match UdpSocket::bind(server_ip) {
            Ok(ref mut server) => {
                chan.send(());
                let mut buf = [0];
                match server.recvfrom(buf) {
                    Ok((nread, src)) => {
                        assert_eq!(nread, 1);
                        assert_eq!(buf[0], 99);
                        assert_eq!(src, client_ip);
                    }
                    Err(..) => fail!()
                }
            }
            Err(..) => fail!()
        }
    })

    iotest!(fn stream_smoke_test_ip4() {
        let server_ip = next_test_ip4();
        let client_ip = next_test_ip4();
        let (port, chan) = Chan::new();
        let (port2, chan2) = Chan::new();

        spawn(proc() {
            match UdpSocket::bind(client_ip) {
                Ok(client) => {
                    let client = ~client;
                    let mut stream = client.connect(server_ip);
                    port.recv();
                    stream.write([99]).unwrap();
                }
                Err(..) => fail!()
            }
            chan2.send(());
        });

        match UdpSocket::bind(server_ip) {
            Ok(server) => {
                let server = ~server;
                let mut stream = server.connect(client_ip);
                chan.send(());
                let mut buf = [0];
                match stream.read(buf) {
                    Ok(nread) => {
                        assert_eq!(nread, 1);
                        assert_eq!(buf[0], 99);
                    }
                    Err(..) => fail!()
                }
            }
            Err(..) => fail!()
        }
        port2.recv();
    })

    iotest!(fn stream_smoke_test_ip6() {
        let server_ip = next_test_ip6();
        let client_ip = next_test_ip6();
        let (port, chan) = Chan::new();
        let (port2, chan2) = Chan::new();

        spawn(proc() {
            match UdpSocket::bind(client_ip) {
                Ok(client) => {
                    let client = ~client;
                    let mut stream = client.connect(server_ip);
                    port.recv();
                    stream.write([99]).unwrap();
                }
                Err(..) => fail!()
            }
            chan2.send(());
        });

        match UdpSocket::bind(server_ip) {
            Ok(server) => {
                let server = ~server;
                let mut stream = server.connect(client_ip);
                chan.send(());
                let mut buf = [0];
                match stream.read(buf) {
                    Ok(nread) => {
                        assert_eq!(nread, 1);
                        assert_eq!(buf[0], 99);
                    }
                    Err(..) => fail!()
                }
            }
            Err(..) => fail!()
        }
        port2.recv();
    })

    pub fn socket_name(addr: SocketAddr) {
        let server = UdpSocket::bind(addr);

        assert!(server.is_ok());
        let mut server = server.unwrap();

        // Make sure socket_name gives
        // us the socket we binded to.
        let so_name = server.socket_name();
        assert!(so_name.is_ok());
        assert_eq!(addr, so_name.unwrap());
    }

    iotest!(fn socket_name_ip4() {
        socket_name(next_test_ip4());
    })

    iotest!(fn socket_name_ip6() {
        socket_name(next_test_ip6());
    })

    iotest!(fn udp_clone_smoke() {
        let addr1 = next_test_ip4();
        let addr2 = next_test_ip4();
        let mut sock1 = UdpSocket::bind(addr1).unwrap();
        let sock2 = UdpSocket::bind(addr2).unwrap();

        spawn(proc() {
            let mut sock2 = sock2;
            let mut buf = [0, 0];
            assert_eq!(sock2.recvfrom(buf), Ok((1, addr1)));
            assert_eq!(buf[0], 1);
            sock2.sendto([2], addr1).unwrap();
        });

        let sock3 = sock1.clone();

        let (p1, c1) = Chan::new();
        let (p2, c2) = Chan::new();
        spawn(proc() {
            let mut sock3 = sock3;
            p1.recv();
            sock3.sendto([1], addr2).unwrap();
            c2.send(());
        });
        c1.send(());
        let mut buf = [0, 0];
        assert_eq!(sock1.recvfrom(buf), Ok((1, addr2)));
        p2.recv();
    })

    iotest!(fn udp_clone_two_read() {
        let addr1 = next_test_ip4();
        let addr2 = next_test_ip4();
        let mut sock1 = UdpSocket::bind(addr1).unwrap();
        let sock2 = UdpSocket::bind(addr2).unwrap();
        let (p, c) = SharedChan::new();
        let c2 = c.clone();

        spawn(proc() {
            let mut sock2 = sock2;
            sock2.sendto([1], addr1).unwrap();
            p.recv();
            sock2.sendto([2], addr1).unwrap();
            p.recv();
        });

        let sock3 = sock1.clone();

        let (p, done) = Chan::new();
        spawn(proc() {
            let mut sock3 = sock3;
            let mut buf = [0, 0];
            sock3.recvfrom(buf).unwrap();
            c2.send(());
            done.send(());
        });
        let mut buf = [0, 0];
        sock1.recvfrom(buf).unwrap();
        c.send(());

        p.recv();
    })

    iotest!(fn udp_clone_two_write() {
        let addr1 = next_test_ip4();
        let addr2 = next_test_ip4();
        let mut sock1 = UdpSocket::bind(addr1).unwrap();
        let sock2 = UdpSocket::bind(addr2).unwrap();

        let (p, c) = SharedChan::new();

        spawn(proc() {
            let mut sock2 = sock2;
            let mut buf = [0, 1];

            for _ in p.iter() {
                match sock2.recvfrom(buf) {
                    Ok(..) => {}
                    Err(e) => fail!("failed receive: {}", e),
                }
            }
        });

        let sock3 = sock1.clone();

        let (p, done) = Chan::new();
        let c2 = c.clone();
        spawn(proc() {
            let mut sock3 = sock3;
            match sock3.sendto([1], addr2) {
                Ok(..) => c2.send(()),
                Err(..) => {}
            }
            done.send(());
        });
        match sock1.sendto([2], addr2) {
            Ok(..) => c.send(()),
            Err(..) => {}
        }

        p.recv();
    })
}
<commit_msg>auto merge of #12054 : alexcrichton/rust/less-flaky-udp, r=brson<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use clone::Clone;
use result::{Ok, Err};
use io::net::ip::SocketAddr;
use io::{Reader, Writer, IoResult};
use rt::rtio::{RtioSocket, RtioUdpSocket, IoFactory, LocalIo};

pub struct UdpSocket {
    priv obj: ~RtioUdpSocket
}

impl UdpSocket {
    pub fn bind(addr: SocketAddr) -> IoResult<UdpSocket> {
        LocalIo::maybe_raise(|io| {
            io.udp_bind(addr).map(|s| UdpSocket { obj: s })
        })
    }

    pub fn recvfrom(&mut self, buf: &mut [u8]) -> IoResult<(uint, SocketAddr)> {
        self.obj.recvfrom(buf)
    }

    pub fn sendto(&mut self, buf: &[u8], dst: SocketAddr) -> IoResult<()> {
        self.obj.sendto(buf, dst)
    }

    pub fn connect(self, other: SocketAddr) -> UdpStream {
        UdpStream { socket: self, connectedTo: other }
    }

    pub fn socket_name(&mut self) -> IoResult<SocketAddr> {
        self.obj.socket_name()
    }
}

impl Clone for UdpSocket {
    /// Creates a new handle to this UDP socket, allowing for simultaneous reads
    /// and writes of the socket.
    ///
    /// The underlying UDP socket will not be closed until all handles to the
    /// socket have been deallocated. Two concurrent reads will not receive the
    /// same data.  Instead, the first read will receive the first packet
    /// received, and the second read will receive the second packet.
    fn clone(&self) -> UdpSocket {
        UdpSocket { obj: self.obj.clone() }
    }
}

pub struct UdpStream {
    priv socket: UdpSocket,
    priv connectedTo: SocketAddr
}

impl UdpStream {
    pub fn as_socket<T>(&mut self, f: |&mut UdpSocket| -> T) -> T {
        f(&mut self.socket)
    }

    pub fn disconnect(self) -> UdpSocket { self.socket }
}

impl Reader for UdpStream {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
        let peer = self.connectedTo;
        self.as_socket(|sock| {
            match sock.recvfrom(buf) {
                Ok((_nread, src)) if src != peer => Ok(0),
                Ok((nread, _src)) => Ok(nread),
                Err(e) => Err(e),
            }
        })
    }
}

impl Writer for UdpStream {
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.as_socket(|sock| sock.sendto(buf, self.connectedTo))
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use io::net::ip::{SocketAddr};

    // FIXME #11530 this fails on android because tests are run as root
    iotest!(fn bind_error() {
        let addr = SocketAddr { ip: Ipv4Addr(0, 0, 0, 0), port: 1 };
        match UdpSocket::bind(addr) {
            Ok(..) => fail!(),
            Err(e) => assert_eq!(e.kind, PermissionDenied),
        }
    } #[ignore(cfg(windows))] #[ignore(cfg(target_os = "android"))])

    iotest!(fn socket_smoke_test_ip4() {
        let server_ip = next_test_ip4();
        let client_ip = next_test_ip4();
        let (port, chan) = Chan::new();
        let (port2, chan2) = Chan::new();

        spawn(proc() {
            match UdpSocket::bind(client_ip) {
                Ok(ref mut client) => {
                    port.recv();
                    client.sendto([99], server_ip).unwrap()
                }
                Err(..) => fail!()
            }
            chan2.send(());
        });

        match UdpSocket::bind(server_ip) {
            Ok(ref mut server) => {
                chan.send(());
                let mut buf = [0];
                match server.recvfrom(buf) {
                    Ok((nread, src)) => {
                        assert_eq!(nread, 1);
                        assert_eq!(buf[0], 99);
                        assert_eq!(src, client_ip);
                    }
                    Err(..) => fail!()
                }
            }
            Err(..) => fail!()
        }
        port2.recv();
    })

    iotest!(fn socket_smoke_test_ip6() {
        let server_ip = next_test_ip6();
        let client_ip = next_test_ip6();
        let (port, chan) = Chan::<()>::new();

        spawn(proc() {
            match UdpSocket::bind(client_ip) {
                Ok(ref mut client) => {
                    port.recv();
                    client.sendto([99], server_ip).unwrap()
                }
                Err(..) => fail!()
            }
        });

        match UdpSocket::bind(server_ip) {
            Ok(ref mut server) => {
                chan.send(());
                let mut buf = [0];
                match server.recvfrom(buf) {
                    Ok((nread, src)) => {
                        assert_eq!(nread, 1);
                        assert_eq!(buf[0], 99);
                        assert_eq!(src, client_ip);
                    }
                    Err(..) => fail!()
                }
            }
            Err(..) => fail!()
        }
    })

    iotest!(fn stream_smoke_test_ip4() {
        let server_ip = next_test_ip4();
        let client_ip = next_test_ip4();
        let (port, chan) = Chan::new();
        let (port2, chan2) = Chan::new();

        spawn(proc() {
            match UdpSocket::bind(client_ip) {
                Ok(client) => {
                    let client = ~client;
                    let mut stream = client.connect(server_ip);
                    port.recv();
                    stream.write([99]).unwrap();
                }
                Err(..) => fail!()
            }
            chan2.send(());
        });

        match UdpSocket::bind(server_ip) {
            Ok(server) => {
                let server = ~server;
                let mut stream = server.connect(client_ip);
                chan.send(());
                let mut buf = [0];
                match stream.read(buf) {
                    Ok(nread) => {
                        assert_eq!(nread, 1);
                        assert_eq!(buf[0], 99);
                    }
                    Err(..) => fail!()
                }
            }
            Err(..) => fail!()
        }
        port2.recv();
    })

    iotest!(fn stream_smoke_test_ip6() {
        let server_ip = next_test_ip6();
        let client_ip = next_test_ip6();
        let (port, chan) = Chan::new();
        let (port2, chan2) = Chan::new();

        spawn(proc() {
            match UdpSocket::bind(client_ip) {
                Ok(client) => {
                    let client = ~client;
                    let mut stream = client.connect(server_ip);
                    port.recv();
                    stream.write([99]).unwrap();
                }
                Err(..) => fail!()
            }
            chan2.send(());
        });

        match UdpSocket::bind(server_ip) {
            Ok(server) => {
                let server = ~server;
                let mut stream = server.connect(client_ip);
                chan.send(());
                let mut buf = [0];
                match stream.read(buf) {
                    Ok(nread) => {
                        assert_eq!(nread, 1);
                        assert_eq!(buf[0], 99);
                    }
                    Err(..) => fail!()
                }
            }
            Err(..) => fail!()
        }
        port2.recv();
    })

    pub fn socket_name(addr: SocketAddr) {
        let server = UdpSocket::bind(addr);

        assert!(server.is_ok());
        let mut server = server.unwrap();

        // Make sure socket_name gives
        // us the socket we binded to.
        let so_name = server.socket_name();
        assert!(so_name.is_ok());
        assert_eq!(addr, so_name.unwrap());
    }

    iotest!(fn socket_name_ip4() {
        socket_name(next_test_ip4());
    })

    iotest!(fn socket_name_ip6() {
        socket_name(next_test_ip6());
    })

    iotest!(fn udp_clone_smoke() {
        let addr1 = next_test_ip4();
        let addr2 = next_test_ip4();
        let mut sock1 = UdpSocket::bind(addr1).unwrap();
        let sock2 = UdpSocket::bind(addr2).unwrap();

        spawn(proc() {
            let mut sock2 = sock2;
            let mut buf = [0, 0];
            assert_eq!(sock2.recvfrom(buf), Ok((1, addr1)));
            assert_eq!(buf[0], 1);
            sock2.sendto([2], addr1).unwrap();
        });

        let sock3 = sock1.clone();

        let (p1, c1) = Chan::new();
        let (p2, c2) = Chan::new();
        spawn(proc() {
            let mut sock3 = sock3;
            p1.recv();
            sock3.sendto([1], addr2).unwrap();
            c2.send(());
        });
        c1.send(());
        let mut buf = [0, 0];
        assert_eq!(sock1.recvfrom(buf), Ok((1, addr2)));
        p2.recv();
    })

    iotest!(fn udp_clone_two_read() {
        let addr1 = next_test_ip4();
        let addr2 = next_test_ip4();
        let mut sock1 = UdpSocket::bind(addr1).unwrap();
        let sock2 = UdpSocket::bind(addr2).unwrap();
        let (p, c) = SharedChan::new();
        let c2 = c.clone();

        spawn(proc() {
            let mut sock2 = sock2;
            sock2.sendto([1], addr1).unwrap();
            p.recv();
            sock2.sendto([2], addr1).unwrap();
            p.recv();
        });

        let sock3 = sock1.clone();

        let (p, done) = Chan::new();
        spawn(proc() {
            let mut sock3 = sock3;
            let mut buf = [0, 0];
            sock3.recvfrom(buf).unwrap();
            c2.send(());
            done.send(());
        });
        let mut buf = [0, 0];
        sock1.recvfrom(buf).unwrap();
        c.send(());

        p.recv();
    })

    iotest!(fn udp_clone_two_write() {
        let addr1 = next_test_ip4();
        let addr2 = next_test_ip4();
        let mut sock1 = UdpSocket::bind(addr1).unwrap();
        let sock2 = UdpSocket::bind(addr2).unwrap();

        let (p, c) = SharedChan::new();
        let (serv_port, serv_chan) = Chan::new();

        spawn(proc() {
            let mut sock2 = sock2;
            let mut buf = [0, 1];

            p.recv();
            match sock2.recvfrom(buf) {
                Ok(..) => {}
                Err(e) => fail!("failed receive: {}", e),
            }
            serv_chan.send(());
        });

        let sock3 = sock1.clone();

        let (p, done) = Chan::new();
        let c2 = c.clone();
        spawn(proc() {
            let mut sock3 = sock3;
            match sock3.sendto([1], addr2) {
                Ok(..) => { let _ = c2.try_send(()); }
                Err(..) => {}
            }
            done.send(());
        });
        match sock1.sendto([2], addr2) {
            Ok(..) => { let _ = c.try_send(()); }
            Err(..) => {}
        }
        drop(c);

        p.recv();
        serv_port.recv();
    })
}
<|endoftext|>