<commit_before>// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details

use {Context, Stream};
use cubeb_core::{DeviceId, DeviceType, StreamParams, ffi};
use cubeb_core::binding::Binding;
use std::ffi::CStr;
use std::os::raw::{c_char, c_int, c_void};

macro_rules! t(
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => return e.raw_code()
    })
    );

#[macro_export]
macro_rules! capi_new(
    ($ctx:ident, $stm:ident) => (
        Ops {
            init: Some($crate::capi::capi_init::<$ctx>),
            get_backend_id: Some($crate::capi::capi_get_backend_id::<$ctx>),
            get_max_channel_count: Some($crate::capi::capi_get_max_channel_count::<$ctx>),
            get_min_latency: Some($crate::capi::capi_get_min_latency::<$ctx>),
            get_preferred_sample_rate: Some($crate::capi::capi_get_preferred_sample_rate::<$ctx>),
            get_preferred_channel_layout: Some($crate::capi::capi_get_preferred_channel_layout::<$ctx>),
            enumerate_devices: Some($crate::capi::capi_enumerate_devices::<$ctx>),
            device_collection_destroy: Some($crate::capi::capi_device_collection_destroy::<$ctx>),
            destroy: Some($crate::capi::capi_destroy::<$ctx>),
            stream_init: Some($crate::capi::capi_stream_init::<$ctx>),
            stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>),
            stream_start: Some($crate::capi::capi_stream_start::<$stm>),
            stream_stop: Some($crate::capi::capi_stream_stop::<$stm>),
            stream_reset_default_device: Some($crate::capi::capi_stream_reset_default_device::<$stm>),
            stream_get_position: Some($crate::capi::capi_stream_get_position::<$stm>),
            stream_get_latency: Some($crate::capi::capi_stream_get_latency::<$stm>),
            stream_set_volume: Some($crate::capi::capi_stream_set_volume::<$stm>),
            stream_set_panning: Some($crate::capi::capi_stream_set_panning::<$stm>),
            stream_get_current_device: Some($crate::capi::capi_stream_get_current_device::<$stm>),
            stream_device_destroy: Some($crate::capi::capi_stream_device_destroy::<$stm>),
            stream_register_device_changed_callback: None,
            register_device_collection_changed: Some($crate::capi::capi_register_device_collection_changed::<$ctx>)
        }));

pub unsafe extern "C" fn capi_init<CTX: Context>(
    c: *mut *mut ffi::cubeb,
    context_name: *const c_char,
) -> c_int {
    let anchor = &();
    let context_name = opt_cstr(anchor, context_name);
    *c = t!(CTX::init(context_name));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_backend_id<CTX: Context>(
    c: *mut ffi::cubeb,
) -> *const c_char {
    let ctx = &mut *(c as *mut CTX);
    ctx.backend_id().as_ptr()
}

pub unsafe extern "C" fn capi_get_max_channel_count<CTX: Context>(
    c: *mut ffi::cubeb,
    max_channels: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *max_channels = t!(ctx.max_channel_count());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_min_latency<CTX: Context>(
    c: *mut ffi::cubeb,
    param: ffi::cubeb_stream_params,
    latency_frames: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let param = StreamParams::from_raw(&param);
    *latency_frames = t!(ctx.min_latency(&param));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_preferred_sample_rate<CTX: Context>(
    c: *mut ffi::cubeb,
    rate: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *rate = t!(ctx.preferred_sample_rate());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_preferred_channel_layout<CTX: Context>(
    c: *mut ffi::cubeb,
    layout: *mut ffi::cubeb_channel_layout,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *layout = t!(ctx.preferred_channel_layout()) as _;
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_enumerate_devices<CTX: Context>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    *collection = t!(ctx.enumerate_devices(devtype));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_device_collection_destroy<CTX: Context>(
    c: *mut ffi::cubeb,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    ctx.device_collection_destroy(collection);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_destroy<CTX>(c: *mut ffi::cubeb) {
    let _: Box<CTX> = Box::from_raw(c as *mut _);
}

pub unsafe extern "C" fn capi_stream_init<CTX: Context>(
    c: *mut ffi::cubeb,
    s: *mut *mut ffi::cubeb_stream,
    stream_name: *const c_char,
    input_device: ffi::cubeb_devid,
    input_stream_params: *const ffi::cubeb_stream_params,
    output_device: ffi::cubeb_devid,
    output_stream_params: *const ffi::cubeb_stream_params,
    latency_frames: u32,
    data_callback: ffi::cubeb_data_callback,
    state_callback: ffi::cubeb_state_callback,
    user_ptr: *mut c_void,
) -> c_int {
    let ctx = &*(c as *const CTX);
    let anchor = &(); // for lifetime of stream_name as CStr

    let input_device = DeviceId::from_raw(input_device);
    let input_stream_params = input_stream_params.as_opt_ref();
    let output_device = DeviceId::from_raw(output_device);
    let output_stream_params = output_stream_params.as_opt_ref();

    *s = t!(ctx.stream_init(
        opt_cstr(anchor, stream_name),
        input_device,
        input_stream_params,
        output_device,
        output_stream_params,
        latency_frames,
        data_callback,
        state_callback,
        user_ptr
    ));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_destroy<STM>(s: *mut ffi::cubeb_stream) {
    let _ = Box::from_raw(s as *mut STM);
}

pub unsafe extern "C" fn capi_stream_start<STM: Stream>(
    s: *mut ffi::cubeb_stream,
) -> c_int {
    let stm = &*(s as *const STM);

    let _ = t!(stm.start());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_stop<STM: Stream>(
    s: *mut ffi::cubeb_stream,
) -> c_int {
    let stm = &*(s as *const STM);

    let _ = t!(stm.stop());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_reset_default_device<STM: Stream>(
    s: *mut ffi::cubeb_stream,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    let _ = t!(stm.reset_default_device());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_position<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    position: *mut u64,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *position = t!(stm.position());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_latency<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    latency: *mut u32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *latency = t!(stm.latency());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_volume<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    volume: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    let _ = t!(stm.set_volume(volume));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_panning<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    panning: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    let _ = t!(stm.set_panning(panning));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_current_device<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    device: *mut *const ffi::cubeb_device,
) -> i32 {
    let stm = &mut *(s as *mut STM);

    *device = t!(stm.current_device());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_device_destroy<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    device: *const ffi::cubeb_device,
) -> c_int {
    let stm = &mut *(s as *mut STM);
    let _ = stm.device_destroy(device);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_register_device_collection_changed<CTX: Context>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
    user_ptr: *mut c_void,
) -> i32 {
    let ctx = &*(c as *const CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    let _ = t!(ctx.register_device_collection_changed(
        devtype,
        collection_changed_callback,
        user_ptr
    ));
    ffi::CUBEB_OK
}

trait AsOptRef<'a, T: 'a> {
    fn as_opt_ref(self) -> Option<&'a T>;
}

impl<'a, T> AsOptRef<'a, T> for *const T
where
    T: 'a,
{
    fn as_opt_ref(self) -> Option<&'a T> {
        if self.is_null() {
            None
        } else {
            Some(unsafe { &*self })
        }
    }
}

fn opt_cstr<'a, T: 'a>(_anchor: &'a T, ptr: *const c_char) -> Option<&'a CStr> {
    if ptr.is_null() {
        None
    } else {
        Some(unsafe { CStr::from_ptr(ptr) })
    }
}
<commit_msg>cubeb-backend: Rename t! to _try!<commit_after>// Copyright © 2017 Mozilla Foundation
//
// This program is made available under an ISC-style license.  See the
// accompanying file LICENSE for details

use {Context, Stream};
use cubeb_core::{DeviceId, DeviceType, StreamParams, ffi};
use cubeb_core::binding::Binding;
use std::ffi::CStr;
use std::os::raw::{c_char, c_int, c_void};

// Helper macro for unwrapping `Result` values from rust-api calls
// while returning early with a c-api error code if the value of the
// expression is `Err`.
macro_rules! _try(
    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => return e.raw_code()
    })
);

#[macro_export]
macro_rules! capi_new(
    ($ctx:ident, $stm:ident) => (
        Ops {
            init: Some($crate::capi::capi_init::<$ctx>),
            get_backend_id: Some($crate::capi::capi_get_backend_id::<$ctx>),
            get_max_channel_count: Some($crate::capi::capi_get_max_channel_count::<$ctx>),
            get_min_latency: Some($crate::capi::capi_get_min_latency::<$ctx>),
            get_preferred_sample_rate: Some($crate::capi::capi_get_preferred_sample_rate::<$ctx>),
            get_preferred_channel_layout: Some($crate::capi::capi_get_preferred_channel_layout::<$ctx>),
            enumerate_devices: Some($crate::capi::capi_enumerate_devices::<$ctx>),
            device_collection_destroy: Some($crate::capi::capi_device_collection_destroy::<$ctx>),
            destroy: Some($crate::capi::capi_destroy::<$ctx>),
            stream_init: Some($crate::capi::capi_stream_init::<$ctx>),
            stream_destroy: Some($crate::capi::capi_stream_destroy::<$stm>),
            stream_start: Some($crate::capi::capi_stream_start::<$stm>),
            stream_stop: Some($crate::capi::capi_stream_stop::<$stm>),
            stream_reset_default_device: Some($crate::capi::capi_stream_reset_default_device::<$stm>),
            stream_get_position: Some($crate::capi::capi_stream_get_position::<$stm>),
            stream_get_latency: Some($crate::capi::capi_stream_get_latency::<$stm>),
            stream_set_volume: Some($crate::capi::capi_stream_set_volume::<$stm>),
            stream_set_panning: Some($crate::capi::capi_stream_set_panning::<$stm>),
            stream_get_current_device: Some($crate::capi::capi_stream_get_current_device::<$stm>),
            stream_device_destroy: Some($crate::capi::capi_stream_device_destroy::<$stm>),
            stream_register_device_changed_callback: None,
            register_device_collection_changed: Some($crate::capi::capi_register_device_collection_changed::<$ctx>)
        }));

pub unsafe extern "C" fn capi_init<CTX: Context>(
    c: *mut *mut ffi::cubeb,
    context_name: *const c_char,
) -> c_int {
    let anchor = &();
    let context_name = opt_cstr(anchor, context_name);
    *c = _try!(CTX::init(context_name));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_backend_id<CTX: Context>(
    c: *mut ffi::cubeb,
) -> *const c_char {
    let ctx = &mut *(c as *mut CTX);
    ctx.backend_id().as_ptr()
}

pub unsafe extern "C" fn capi_get_max_channel_count<CTX: Context>(
    c: *mut ffi::cubeb,
    max_channels: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *max_channels = _try!(ctx.max_channel_count());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_min_latency<CTX: Context>(
    c: *mut ffi::cubeb,
    param: ffi::cubeb_stream_params,
    latency_frames: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let param = StreamParams::from_raw(&param);
    *latency_frames = _try!(ctx.min_latency(&param));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_preferred_sample_rate<CTX: Context>(
    c: *mut ffi::cubeb,
    rate: *mut u32,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *rate = _try!(ctx.preferred_sample_rate());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_get_preferred_channel_layout<CTX: Context>(
    c: *mut ffi::cubeb,
    layout: *mut ffi::cubeb_channel_layout,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    *layout = _try!(ctx.preferred_channel_layout()) as _;
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_enumerate_devices<CTX: Context>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    *collection = _try!(ctx.enumerate_devices(devtype));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_device_collection_destroy<CTX: Context>(
    c: *mut ffi::cubeb,
    collection: *mut ffi::cubeb_device_collection,
) -> c_int {
    let ctx = &mut *(c as *mut CTX);

    ctx.device_collection_destroy(collection);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_destroy<CTX>(c: *mut ffi::cubeb) {
    let _: Box<CTX> = Box::from_raw(c as *mut _);
}

pub unsafe extern "C" fn capi_stream_init<CTX: Context>(
    c: *mut ffi::cubeb,
    s: *mut *mut ffi::cubeb_stream,
    stream_name: *const c_char,
    input_device: ffi::cubeb_devid,
    input_stream_params: *const ffi::cubeb_stream_params,
    output_device: ffi::cubeb_devid,
    output_stream_params: *const ffi::cubeb_stream_params,
    latency_frames: u32,
    data_callback: ffi::cubeb_data_callback,
    state_callback: ffi::cubeb_state_callback,
    user_ptr: *mut c_void,
) -> c_int {
    let ctx = &*(c as *const CTX);
    let anchor = &(); // for lifetime of stream_name as CStr

    let input_device = DeviceId::from_raw(input_device);
    let input_stream_params = input_stream_params.as_opt_ref();
    let output_device = DeviceId::from_raw(output_device);
    let output_stream_params = output_stream_params.as_opt_ref();

    *s = _try!(ctx.stream_init(
        opt_cstr(anchor, stream_name),
        input_device,
        input_stream_params,
        output_device,
        output_stream_params,
        latency_frames,
        data_callback,
        state_callback,
        user_ptr
    ));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_destroy<STM>(s: *mut ffi::cubeb_stream) {
    let _ = Box::from_raw(s as *mut STM);
}

pub unsafe extern "C" fn capi_stream_start<STM: Stream>(
    s: *mut ffi::cubeb_stream,
) -> c_int {
    let stm = &*(s as *const STM);

    let _ = _try!(stm.start());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_stop<STM: Stream>(
    s: *mut ffi::cubeb_stream,
) -> c_int {
    let stm = &*(s as *const STM);

    let _ = _try!(stm.stop());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_reset_default_device<STM: Stream>(
    s: *mut ffi::cubeb_stream,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    let _ = _try!(stm.reset_default_device());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_position<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    position: *mut u64,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *position = _try!(stm.position());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_latency<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    latency: *mut u32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    *latency = _try!(stm.latency());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_volume<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    volume: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    let _ = _try!(stm.set_volume(volume));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_set_panning<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    panning: f32,
) -> c_int {
    let stm = &mut *(s as *mut STM);

    let _ = _try!(stm.set_panning(panning));
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_get_current_device<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    device: *mut *const ffi::cubeb_device,
) -> i32 {
    let stm = &mut *(s as *mut STM);

    *device = _try!(stm.current_device());
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_stream_device_destroy<STM: Stream>(
    s: *mut ffi::cubeb_stream,
    device: *const ffi::cubeb_device,
) -> c_int {
    let stm = &mut *(s as *mut STM);
    let _ = stm.device_destroy(device);
    ffi::CUBEB_OK
}

pub unsafe extern "C" fn capi_register_device_collection_changed<CTX: Context>(
    c: *mut ffi::cubeb,
    devtype: ffi::cubeb_device_type,
    collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
    user_ptr: *mut c_void,
) -> i32 {
    let ctx = &*(c as *const CTX);
    let devtype = DeviceType::from_bits_truncate(devtype);
    let _ = _try!(ctx.register_device_collection_changed(
        devtype,
        collection_changed_callback,
        user_ptr
    ));
    ffi::CUBEB_OK
}

trait AsOptRef<'a, T: 'a> {
    fn as_opt_ref(self) -> Option<&'a T>;
}

impl<'a, T> AsOptRef<'a, T> for *const T
where
    T: 'a,
{
    fn as_opt_ref(self) -> Option<&'a T> {
        if self.is_null() {
            None
        } else {
            Some(unsafe { &*self })
        }
    }
}

fn opt_cstr<'a, T: 'a>(_anchor: &'a T, ptr: *const c_char) -> Option<&'a CStr> {
    if ptr.is_null() {
        None
    } else {
        Some(unsafe { CStr::from_ptr(ptr) })
    }
}
<|endoftext|>


<commit_before>#![crate_id = "chroot#1.0.0"]
/*
 * This file is part of the uutils coreutils package.
 *
 * © Vsevolod Velichko <torkvemada@sorokdva.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]
extern crate getopts;
extern crate libc;
extern crate debug;

use getopts::{optflag, optopt, getopts, usage};
use c_types::{get_pw_from_args, get_group};
use libc::funcs::posix88::unistd::{execvp, setuid, setgid};

#[path = "../common/util.rs"] mod util;
#[path = "../common/c_types.rs"] mod c_types;

extern {
    fn chroot(path: *libc::c_char) -> libc::c_int;
    fn setgroups(size: libc::c_int, list: *libc::uid_t) -> libc::c_int;
}

static NAME : &'static str = "chroot";
static VERSION : &'static str = "1.0.0";

#[allow(dead_code)]
fn main () { std::os::set_exit_status(uumain(std::os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let program = args.get(0);

    let options = [
        optopt("u", "user", "User (ID or name) to switch before running the program", "USER"),
        optopt("g", "group", "Group (ID or name) to switch to", "GROUP"),
        optopt("G", "groups", "Comma-separated list of groups to switch to", "GROUP1,GROUP2…"),
        optopt("", "userspec", "Colon-separated user and group to switch to. \
                                Same as -u USER -g GROUP. \
                                Userspec has higher preference than -u and/or -g", "USER:GROUP"),
        optflag("h", "help", "Show help"),
        optflag("V", "version", "Show program's version")
    ];

    let opts = match getopts(args.tail(), options) {
        Ok(m) => {m}
        Err(f) => {
            println!("{}", f);
            help_menu(program.as_slice(), options);
            return 1
        }
    };

    if opts.opt_present("V") { version(); return 0 }
    if opts.opt_present("h") { help_menu(program.as_slice(), options); return 0 }

    if opts.free.len() == 0 {
        println!("Missing operand: NEWROOT");
        println!("Try `{:s} --help` for more information.", program.as_slice());
        return 1
    }

    let defaultShell : &'static str = "/bin/sh";
    let defaultOption : &'static str = "-i";
    let userShell = std::os::getenv("SHELL");

    let newroot = Path::new(opts.free.get(0).as_slice());
    if !newroot.is_dir() {
        crash!(1, "cannot change root directory to `{}`: no such directory", newroot.display());
    }

    let command : Vec<&str> = match opts.free.len() {
        1 => {
            let shell : &str = match userShell {
                None => {defaultShell}
                Some(ref s) => {s.as_slice()}
            };
            vec!(shell, defaultOption)
        }
        _ => { opts.free.slice(1, opts.free.len()).iter().map(|x| x.as_slice()).collect() }
    };

    set_context(&newroot, &opts);

    unsafe {
        let executable = command.get(0).as_slice().to_c_str().unwrap();
        let mut commandParts : Vec<*i8> = command.iter().map(|x| x.to_c_str().unwrap()).collect();
        commandParts.push(std::ptr::null());
        execvp(executable as *libc::c_char, commandParts.as_ptr() as **libc::c_char) as int
    }
}

fn set_context(root: &Path, options: &getopts::Matches) {
    let userspecStr = options.opt_str("userspec");
    let userStr = options.opt_str("user").unwrap_or_default();
    let groupStr = options.opt_str("group").unwrap_or_default();
    let groupsStr = options.opt_str("groups").unwrap_or_default();
    let userspec = match userspecStr {
        Some(ref u) => {
            let s : Vec<&str> = u.as_slice().split(':').collect();
            if s.len() != 2 {
                crash!(1, "invalid userspec: `{:s}`", u.as_slice())
            };
            s
        }
        None => { Vec::new() }
    };
    let user = if userspec.is_empty() { userStr.as_slice() } else { userspec.get(0).as_slice() };
    let group = if userspec.is_empty() { groupStr.as_slice() } else { userspec.get(1).as_slice() };

    enter_chroot(root);

    set_groups(groupsStr.as_slice());
    set_main_group(group);
    set_user(user);
}

fn enter_chroot(root: &Path) {
    let rootStr = root.display();
    if !std::os::change_dir(root) {
        crash!(1, "cannot chdir to {}", rootStr)
    };
    let err = unsafe {
        chroot(".".to_c_str().unwrap() as *libc::c_char)
    };
    if err != 0 {
        crash!(1, "cannot chroot to {}: {:s}", rootStr, strerror(err).as_slice())
    };
}

fn set_main_group(group: &str) {
    if !group.is_empty() {
        let group_id = match get_group(group) {
            None => { crash!(1, "no such group: {}", group) }
            Some(g) => g.gr_gid
        };
        let err = unsafe { setgid(group_id) };
        if err != 0 {
            crash!(1, "cannot set gid to {:u}: {:s}", group_id, strerror(err).as_slice())
        }
    }
}

fn set_groups(groups: &str) {
    if !groups.is_empty() {
        let groupsVec : Vec<libc::uid_t> = FromIterator::from_iter(
            groups.split(',').map(
                |x| match get_group(x) {
                    None => { crash!(1, "no such group: {}", x) }
                    Some(g) => { g.gr_gid }
                })
            );
        let err = unsafe {
            setgroups(groupsVec.len() as libc::c_int,
                      groupsVec.as_slice().as_ptr() as *libc::uid_t)
        };
        if err != 0 {
            crash!(1, "cannot set groups: {:s}", strerror(err).as_slice())
        }
    }
}

fn set_user(user: &str) {
    if !user.is_empty() {
        let user_id = get_pw_from_args(&vec!(String::from_str(user))).unwrap().pw_uid;
        let err = unsafe { setuid(user_id as libc::uid_t) };
        if err != 0 {
            crash!(1, "cannot set user to {:s}: {:s}", user, strerror(err).as_slice())
        }
    }
}

fn strerror(errno: i32) -> String {
    unsafe {
        let err = libc::funcs::c95::string::strerror(errno);
        std::str::raw::from_c_str(err)
    }
}

fn version() {
    println!("{} v{}", NAME, VERSION)
}

fn help_menu(program: &str, options: &[getopts::OptGroup]) {
    version();
    println!("Usage:");
    println!("  {:s} [OPTION]… NEWROOT [COMMAND [ARG]…]", program);
    println!("");
    print!("{:s}", usage(
            "Run COMMAND with root directory set to NEWROOT.\n\
             If COMMAND is not specified, it defaults to '${SHELL} -i'. \
             If ${SHELL} is not set, /bin/sh is used.", options))
}
<commit_msg>Remove unused debug crate import<commit_after>#![crate_id = "chroot#1.0.0"]
/*
 * This file is part of the uutils coreutils package.
 *
 * © Vsevolod Velichko <torkvemada@sorokdva.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

#![feature(macro_rules)]
extern crate getopts;
extern crate libc;

use getopts::{optflag, optopt, getopts, usage};
use c_types::{get_pw_from_args, get_group};
use libc::funcs::posix88::unistd::{execvp, setuid, setgid};

#[path = "../common/util.rs"] mod util;
#[path = "../common/c_types.rs"] mod c_types;

extern {
    fn chroot(path: *libc::c_char) -> libc::c_int;
    fn setgroups(size: libc::c_int, list: *libc::uid_t) -> libc::c_int;
}

static NAME : &'static str = "chroot";
static VERSION : &'static str = "1.0.0";

#[allow(dead_code)]
fn main () { std::os::set_exit_status(uumain(std::os::args())); }

pub fn uumain(args: Vec<String>) -> int {
    let program = args.get(0);

    let options = [
        optopt("u", "user", "User (ID or name) to switch before running the program", "USER"),
        optopt("g", "group", "Group (ID or name) to switch to", "GROUP"),
        optopt("G", "groups", "Comma-separated list of groups to switch to", "GROUP1,GROUP2…"),
        optopt("", "userspec", "Colon-separated user and group to switch to. \
                                Same as -u USER -g GROUP. \
                                Userspec has higher preference than -u and/or -g", "USER:GROUP"),
        optflag("h", "help", "Show help"),
        optflag("V", "version", "Show program's version")
    ];

    let opts = match getopts(args.tail(), options) {
        Ok(m) => {m}
        Err(f) => {
            println!("{}", f);
            help_menu(program.as_slice(), options);
            return 1
        }
    };

    if opts.opt_present("V") { version(); return 0 }
    if opts.opt_present("h") { help_menu(program.as_slice(), options); return 0 }

    if opts.free.len() == 0 {
        println!("Missing operand: NEWROOT");
        println!("Try `{:s} --help` for more information.", program.as_slice());
        return 1
    }

    let defaultShell : &'static str = "/bin/sh";
    let defaultOption : &'static str = "-i";
    let userShell = std::os::getenv("SHELL");

    let newroot = Path::new(opts.free.get(0).as_slice());
    if !newroot.is_dir() {
        crash!(1, "cannot change root directory to `{}`: no such directory", newroot.display());
    }

    let command : Vec<&str> = match opts.free.len() {
        1 => {
            let shell : &str = match userShell {
                None => {defaultShell}
                Some(ref s) => {s.as_slice()}
            };
            vec!(shell, defaultOption)
        }
        _ => { opts.free.slice(1, opts.free.len()).iter().map(|x| x.as_slice()).collect() }
    };

    set_context(&newroot, &opts);

    unsafe {
        let executable = command.get(0).as_slice().to_c_str().unwrap();
        let mut commandParts : Vec<*i8> = command.iter().map(|x| x.to_c_str().unwrap()).collect();
        commandParts.push(std::ptr::null());
        execvp(executable as *libc::c_char, commandParts.as_ptr() as **libc::c_char) as int
    }
}

fn set_context(root: &Path, options: &getopts::Matches) {
    let userspecStr = options.opt_str("userspec");
    let userStr = options.opt_str("user").unwrap_or_default();
    let groupStr = options.opt_str("group").unwrap_or_default();
    let groupsStr = options.opt_str("groups").unwrap_or_default();
    let userspec = match userspecStr {
        Some(ref u) => {
            let s : Vec<&str> = u.as_slice().split(':').collect();
            if s.len() != 2 {
                crash!(1, "invalid userspec: `{:s}`", u.as_slice())
            };
            s
        }
        None => { Vec::new() }
    };
    let user = if userspec.is_empty() { userStr.as_slice() } else { userspec.get(0).as_slice() };
    let group = if userspec.is_empty() { groupStr.as_slice() } else { userspec.get(1).as_slice() };

    enter_chroot(root);

    set_groups(groupsStr.as_slice());
    set_main_group(group);
    set_user(user);
}

fn enter_chroot(root: &Path) {
    let rootStr = root.display();
    if !std::os::change_dir(root) {
        crash!(1, "cannot chdir to {}", rootStr)
    };
    let err = unsafe {
        chroot(".".to_c_str().unwrap() as *libc::c_char)
    };
    if err != 0 {
        crash!(1, "cannot chroot to {}: {:s}", rootStr, strerror(err).as_slice())
    };
}

fn set_main_group(group: &str) {
    if !group.is_empty() {
        let group_id = match get_group(group) {
            None => { crash!(1, "no such group: {}", group) }
            Some(g) => g.gr_gid
        };
        let err = unsafe { setgid(group_id) };
        if err != 0 {
            crash!(1, "cannot set gid to {:u}: {:s}", group_id, strerror(err).as_slice())
        }
    }
}

fn set_groups(groups: &str) {
    if !groups.is_empty() {
        let groupsVec : Vec<libc::uid_t> = FromIterator::from_iter(
            groups.split(',').map(
                |x| match get_group(x) {
                    None => { crash!(1, "no such group: {}", x) }
                    Some(g) => { g.gr_gid }
                })
            );
        let err = unsafe {
            setgroups(groupsVec.len() as libc::c_int,
                      groupsVec.as_slice().as_ptr() as *libc::uid_t)
        };
        if err != 0 {
            crash!(1, "cannot set groups: {:s}", strerror(err).as_slice())
        }
    }
}

fn set_user(user: &str) {
    if !user.is_empty() {
        let user_id = get_pw_from_args(&vec!(String::from_str(user))).unwrap().pw_uid;
        let err = unsafe { setuid(user_id as libc::uid_t) };
        if err != 0 {
            crash!(1, "cannot set user to {:s}: {:s}", user, strerror(err).as_slice())
        }
    }
}

fn strerror(errno: i32) -> String {
    unsafe {
        let err = libc::funcs::c95::string::strerror(errno);
        std::str::raw::from_c_str(err)
    }
}

fn version() {
    println!("{} v{}", NAME, VERSION)
}

fn help_menu(program: &str, options: &[getopts::OptGroup]) {
    version();
    println!("Usage:");
    println!("  {:s} [OPTION]… NEWROOT [COMMAND [ARG]…]", program);
    println!("");
    print!("{:s}", usage(
            "Run COMMAND with root directory set to NEWROOT.\n\
             If COMMAND is not specified, it defaults to '${SHELL} -i'. \
             If ${SHELL} is not set, /bin/sh is used.", options))
}
<|endoftext|>


<commit_before>use command_prelude::*;

use cargo::core::{GitReference, SourceId};
use cargo::ops;
use cargo::util::ToUrl;

pub fn cli() -> App {
    subcommand("install")
        .about("Install a Rust binary")
        .arg(Arg::with_name("crate").empty_values(false).multiple(true))
        .arg(
            opt("version", "Specify a version to install from crates.io")
                .alias("vers")
                .value_name("VERSION"),
        )
        .arg(opt("git", "Git URL to install the specified crate from").value_name("URL"))
        .arg(opt("branch", "Branch to use when installing from git").value_name("BRANCH"))
        .arg(opt("tag", "Tag to use when installing from git").value_name("TAG"))
        .arg(opt("rev", "Specific commit to use when installing from git").value_name("SHA"))
        .arg(opt("path", "Filesystem path to local crate to install").value_name("PATH"))
        .arg(opt(
            "list",
            "list all installed packages and their versions",
        ))
        .arg_jobs()
        .arg(opt("force", "Force overwriting existing crates or binaries").short("f"))
        .arg_features()
        .arg(opt("debug", "Build in debug mode instead of release mode"))
        .arg_targets_bins_examples(
            "Install only the specified binary",
            "Install all binaries",
            "Install only the specified example",
            "Install all examples",
        )
        .arg_target_triple("Build for the target triple")
        .arg(opt("root", "Directory to install packages into").value_name("DIR"))
        .arg(opt("registry", "Registry to use").value_name("REGISTRY"))
        .after_help(
            "\
This command manages Cargo's local set of installed binary crates. Only packages
which have [[bin]] targets can be installed, and all binaries are installed into
the installation root's `bin` folder. The installation root is determined, in
order of precedence, by `--root`, `$CARGO_INSTALL_ROOT`, the `install.root`
configuration key, and finally the home directory (which is either
`$CARGO_HOME` if set or `$HOME/.cargo` by default).

There are multiple sources from which a crate can be installed. The default
location is crates.io but the `--git` and `--path` flags can change this source.
If the source contains more than one package (such as crates.io or a git
repository with multiple crates) the `<crate>` argument is required to indicate
which crate should be installed.

Crates from crates.io can optionally specify the version they wish to install
via the `--vers` flags, and similarly packages from git repositories can
optionally specify the branch, tag, or revision that should be installed. If a
crate has multiple binaries, the `--bin` argument can selectively install only
one of them, and if you'd rather install examples the `--example` argument can
be used as well.

By default cargo will refuse to overwrite existing binaries. The `--force` flag
enables overwriting existing binaries. Thus you can reinstall a crate with
`cargo install --force <crate>`.

Omitting the <crate> specification entirely will
install the crate in the current directory. That is, `install` is equivalent to
the more explicit `install --path .`.  This behaviour is deprecated, and no
longer supported as of the Rust 2018 edition.

If the source is crates.io or `--git` then by default the crate will be built
in a temporary target directory.  To avoid this, the target directory can be
specified by setting the `CARGO_TARGET_DIR` environment variable to a relative
path.  In particular, this can be useful for caching build artifacts on
continuous integration systems.",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    config.reload_rooted_at_cargo_home()?;
    let mut compile_opts = args.compile_options(config, CompileMode::Build)?;

    compile_opts.build_config.release = !args.is_present("debug");

    let krates = args.values_of("crate")
        .unwrap_or_default()
        .collect::<Vec<_>>();

    let mut from_cwd = false;

    let source = if let Some(url) = args.value_of("git") {
        let url = url.to_url()?;
        let gitref = if let Some(branch) = args.value_of("branch") {
            GitReference::Branch(branch.to_string())
        } else if let Some(tag) = args.value_of("tag") {
            GitReference::Tag(tag.to_string())
        } else if let Some(rev) = args.value_of("rev") {
            GitReference::Rev(rev.to_string())
        } else {
            GitReference::Branch("master".to_string())
        };
        SourceId::for_git(&url, gitref)?
    } else if let Some(path) = args.value_of_path("path", config) {
        SourceId::for_path(&path)?
    } else if krates.is_empty() {
        from_cwd = true;
        SourceId::for_path(config.cwd())?
    } else if let Some(registry) = args.value_of("registry") {
        SourceId::alt_registry(config, registry)?
    } else {
        SourceId::crates_io(config)?
    };

    let version = args.value_of("version");
    let root = args.value_of("root");

    if args.is_present("list") {
        ops::install_list(root, config)?;
    } else {
        ops::install(
            root,
            krates,
            &source,
            from_cwd,
            version,
            &compile_opts,
            args.is_present("force"),
        )?;
    }
    Ok(())
}
<commit_msg>Switch to use registry<commit_after>use command_prelude::*;

use cargo::core::{GitReference, SourceId};
use cargo::ops;
use cargo::util::ToUrl;

pub fn cli() -> App {
    subcommand("install")
        .about("Install a Rust binary")
        .arg(Arg::with_name("crate").empty_values(false).multiple(true))
        .arg(
            opt("version", "Specify a version to install from crates.io")
                .alias("vers")
                .value_name("VERSION"),
        )
        .arg(opt("git", "Git URL to install the specified crate from").value_name("URL"))
        .arg(opt("branch", "Branch to use when installing from git").value_name("BRANCH"))
        .arg(opt("tag", "Tag to use when installing from git").value_name("TAG"))
        .arg(opt("rev", "Specific commit to use when installing from git").value_name("SHA"))
        .arg(opt("path", "Filesystem path to local crate to install").value_name("PATH"))
        .arg(opt(
            "list",
            "list all installed packages and their versions",
        ))
        .arg_jobs()
        .arg(opt("force", "Force overwriting existing crates or binaries").short("f"))
        .arg_features()
        .arg(opt("debug", "Build in debug mode instead of release mode"))
        .arg_targets_bins_examples(
            "Install only the specified binary",
            "Install all binaries",
            "Install only the specified example",
            "Install all examples",
        )
        .arg_target_triple("Build for the target triple")
        .arg(opt("root", "Directory to install packages into").value_name("DIR"))
        .arg(opt("registry", "Registry to use").value_name("REGISTRY"))
        .after_help(
            "\
This command manages Cargo's local set of installed binary crates. Only packages
which have [[bin]] targets can be installed, and all binaries are installed into
the installation root's `bin` folder. The installation root is determined, in
order of precedence, by `--root`, `$CARGO_INSTALL_ROOT`, the `install.root`
configuration key, and finally the home directory (which is either
`$CARGO_HOME` if set or `$HOME/.cargo` by default).

There are multiple sources from which a crate can be installed. The default
location is crates.io but the `--git` and `--path` flags can change this source.
If the source contains more than one package (such as crates.io or a git
repository with multiple crates) the `<crate>` argument is required to indicate
which crate should be installed.

Crates from crates.io can optionally specify the version they wish to install
via the `--vers` flags, and similarly packages from git repositories can
optionally specify the branch, tag, or revision that should be installed. If a
crate has multiple binaries, the `--bin` argument can selectively install only
one of them, and if you'd rather install examples the `--example` argument can
be used as well.

By default cargo will refuse to overwrite existing binaries. The `--force` flag
enables overwriting existing binaries. Thus you can reinstall a crate with
`cargo install --force <crate>`.

Omitting the <crate> specification entirely will
install the crate in the current directory. That is, `install` is equivalent to
the more explicit `install --path .`.  This behaviour is deprecated, and no
longer supported as of the Rust 2018 edition.

If the source is crates.io or `--git` then by default the crate will be built
in a temporary target directory.  To avoid this, the target directory can be
specified by setting the `CARGO_TARGET_DIR` environment variable to a relative
path.  In particular, this can be useful for caching build artifacts on
continuous integration systems.",
        )
}

pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
    let registry = args.registry(config)?;

    config.reload_rooted_at_cargo_home()?;
    let mut compile_opts = args.compile_options(config, CompileMode::Build)?;

    compile_opts.build_config.release = !args.is_present("debug");

    let krates = args.values_of("crate")
        .unwrap_or_default()
        .collect::<Vec<_>>();

    let mut from_cwd = false;

    let source = if let Some(url) = args.value_of("git") {
        let url = url.to_url()?;
        let gitref = if let Some(branch) = args.value_of("branch") {
            GitReference::Branch(branch.to_string())
        } else if let Some(tag) = args.value_of("tag") {
            GitReference::Tag(tag.to_string())
        } else if let Some(rev) = args.value_of("rev") {
            GitReference::Rev(rev.to_string())
        } else {
            GitReference::Branch("master".to_string())
        };
        SourceId::for_git(&url, gitref)?
    } else if let Some(path) = args.value_of_path("path", config) {
        SourceId::for_path(&path)?
    } else if krates.is_empty() {
        from_cwd = true;
        SourceId::for_path(config.cwd())?
    } else if let Some(registry) = registry {
        SourceId::alt_registry(config, &registry)?
    } else {
        SourceId::crates_io(config)?
    };

    let version = args.value_of("version");
    let root = args.value_of("root");

    if args.is_present("list") {
        ops::install_list(root, config)?;
    } else {
        ops::install(
            root,
            krates,
            &source,
            from_cwd,
            version,
            &compile_opts,
            args.is_present("force"),
        )?;
    }
    Ok(())
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate validator_derive;
extern crate validator;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate regex;
#[macro_use]
extern crate lazy_static;

use regex::Regex;
use validator::{Validate, ValidationError, ValidationErrors};

fn validate_unique_username(username: &str) -> Result<(), ValidationError> {
    if username == "xXxShad0wxXx" {
        return Err(ValidationError::new("terrible_username"));
    }

    Ok(())
}

fn validate_signup(data: &SignupData) -> Result<(), ValidationError> {
    if data.mail.ends_with("gmail.com") && data.age == 18 {
        return Err(ValidationError::new("stupid_rule"));
    }

    Ok(())
}

#[derive(Debug, Validate, Deserialize)]
#[validate(schema(function = "validate_signup", skip_on_field_errors = "false"))]
struct SignupData {
    #[validate(email)]
    mail: String,
    #[validate(url)]
    site: String,
    #[validate(length(min = "1"), custom = "validate_unique_username")]
    #[serde(rename = "firstName")]
    first_name: String,
    #[validate(range(min = "18", max = "20"))]
    age: u32,
}

#[test]
fn is_fine_with_many_valid_validations() {
    let signup = SignupData {
        mail: "bob@bob.com".to_string(),
        site: "http://hello.com".to_string(),
        first_name: "Bob".to_string(),
        age: 18,
    };

    assert!(signup.validate().is_ok());
}

#[test]
fn failed_validation_points_to_original_field_name() {
    let signup = SignupData {
        mail: "bob@bob.com".to_string(),
        site: "http://hello.com".to_string(),
        first_name: "".to_string(),
        age: 18,
    };
    let res = signup.validate();
    assert!(res.is_err());
    let errs = res.unwrap_err().inner();
    assert!(errs.contains_key("firstName"));
    assert_eq!(errs["firstName"].len(), 1);
    assert_eq!(errs["firstName"][0].code, "length");
}

#[test]
fn test_can_validate_option_fields_with_lifetime() {
    lazy_static! {
        static ref RE2: Regex = Regex::new(r"[a-z]{2}").unwrap();
    }

    #[derive(Debug, Validate)]
    struct PutStruct<'a> {
        #[validate(length(min = "1", max = "10"))]
        name: Option<&'a str>,
        #[validate(length(min = "1", max = "10"))]
        address: Option<Option<&'a str>>,
        #[validate(range(min = "1", max = "100"))]
        age: Option<Option<usize>>,
        #[validate(range(min = "1", max = "10"))]
        range: Option<usize>,
        #[validate(email)]
        email: Option<&'a str>,
        #[validate(url)]
        url: Option<&'a str>,
        #[validate(contains = "@")]
        text: Option<&'a str>,
        #[validate(regex = "RE2")]
        re: Option<&'a str>,
        #[validate(custom = "check_str")]
        custom: Option<&'a str>,
    }

    fn check_str(_: &str) -> Result<(), ValidationError> {
        Ok(())
    }

    let s = PutStruct {
        name: Some("al"),
        address: Some(Some("gol")),
        age: Some(Some(20)),
        range: Some(2),
        email: Some("hi@gmail.com"),
        url: Some("http://google.com"),
        text: Some("@someone"),
        re: Some("hi"),
        custom: Some("hey"),
    };
    assert!(s.validate().is_ok());
}

#[test]
fn test_can_validate_option_fields_without_lifetime() {
    lazy_static! {
        static ref RE2: Regex = Regex::new(r"[a-z]{2}").unwrap();
    }

    #[derive(Debug, Validate)]
    struct PutStruct {
        #[validate(length(min = "1", max = "10"))]
        name: Option<String>,
        #[validate(length(min = "1", max = "10"))]
        address: Option<Option<String>>,
        #[validate(length(min = "1", max = "10"))]
        ids: Option<Vec<usize>>,
        #[validate(range(min = "1", max = "100"))]
        age: Option<Option<usize>>,
        #[validate(range(min = "1", max = "10"))]
        range: Option<usize>,
        #[validate(email)]
        email: Option<String>,
        #[validate(url)]
        url: Option<String>,
        #[validate(contains = "@")]
        text: Option<String>,
        #[validate(regex = "RE2")]
        re: Option<String>,
        #[validate(custom = "check_str")]
        custom: Option<String>,
    }

    fn check_str(_: &str) -> Result<(), ValidationError> {
        Ok(())
    }

    let s = PutStruct {
        name: Some("al".to_string()),
        address: Some(Some("gol".to_string())),
        ids: Some(vec![1, 2, 3]),
        age: Some(Some(20)),
        range: Some(2),
        email: Some("hi@gmail.com".to_string()),
        url: Some("http://google.com".to_string()),
        text: Some("@someone".to_string()),
        re: Some("hi".to_string()),
        custom: Some("hey".to_string()),
    };
    assert!(s.validate().is_ok());
}

#[test]
fn test_works_with_question_mark_operator() {
    fn some_fn() -> Result<(), ValidationErrors> {
        let signup = SignupData {
            mail: "invalid_email".to_string(),
            site: "http://hello.com".to_string(),
            first_name: "Bob".to_string(),
            age: 18,
        };

        signup.validate()?;
        Ok(())
    }

    assert!(some_fn().is_err());
}
<commit_msg>Added Option<Option<Vec<T>> field to test<commit_after>#[macro_use]
extern crate validator_derive;
extern crate validator;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate regex;
#[macro_use]
extern crate lazy_static;

use regex::Regex;
use validator::{Validate, ValidationError, ValidationErrors};

fn validate_unique_username(username: &str) -> Result<(), ValidationError> {
    if username == "xXxShad0wxXx" {
        return Err(ValidationError::new("terrible_username"));
    }

    Ok(())
}

fn validate_signup(data: &SignupData) -> Result<(), ValidationError> {
    if data.mail.ends_with("gmail.com") && data.age == 18 {
        return Err(ValidationError::new("stupid_rule"));
    }

    Ok(())
}

#[derive(Debug, Validate, Deserialize)]
#[validate(schema(function = "validate_signup", skip_on_field_errors = "false"))]
struct SignupData {
    #[validate(email)]
    mail: String,
    #[validate(url)]
    site: String,
    #[validate(length(min = "1"), custom = "validate_unique_username")]
    #[serde(rename = "firstName")]
    first_name: String,
    #[validate(range(min = "18", max = "20"))]
    age: u32,
}

#[test]
fn is_fine_with_many_valid_validations() {
    let signup = SignupData {
        mail: "bob@bob.com".to_string(),
        site: "http://hello.com".to_string(),
        first_name: "Bob".to_string(),
        age: 18,
    };

    assert!(signup.validate().is_ok());
}

#[test]
fn failed_validation_points_to_original_field_name() {
    let signup = SignupData {
        mail: "bob@bob.com".to_string(),
        site: "http://hello.com".to_string(),
        first_name: "".to_string(),
        age: 18,
    };
    let res = signup.validate();
    assert!(res.is_err());
    let errs = res.unwrap_err().inner();
    assert!(errs.contains_key("firstName"));
    assert_eq!(errs["firstName"].len(), 1);
    assert_eq!(errs["firstName"][0].code, "length");
}

#[test]
fn test_can_validate_option_fields_with_lifetime() {
    lazy_static! {
        static ref RE2: Regex = Regex::new(r"[a-z]{2}").unwrap();
    }

    #[derive(Debug, Validate)]
    struct PutStruct<'a> {
        #[validate(length(min = "1", max = "10"))]
        name: Option<&'a str>,
        #[validate(length(min = "1", max = "10"))]
        address: Option<Option<&'a str>>,
        #[validate(range(min = "1", max = "100"))]
        age: Option<Option<usize>>,
        #[validate(range(min = "1", max = "10"))]
        range: Option<usize>,
        #[validate(email)]
        email: Option<&'a str>,
        #[validate(url)]
        url: Option<&'a str>,
        #[validate(contains = "@")]
        text: Option<&'a str>,
        #[validate(regex = "RE2")]
        re: Option<&'a str>,
        #[validate(custom = "check_str")]
        custom: Option<&'a str>,
    }

    fn check_str(_: &str) -> Result<(), ValidationError> {
        Ok(())
    }

    let s = PutStruct {
        name: Some("al"),
        address: Some(Some("gol")),
        age: Some(Some(20)),
        range: Some(2),
        email: Some("hi@gmail.com"),
        url: Some("http://google.com"),
        text: Some("@someone"),
        re: Some("hi"),
        custom: Some("hey"),
    };
    assert!(s.validate().is_ok());
}

#[test]
fn test_can_validate_option_fields_without_lifetime() {
    lazy_static! {
        static ref RE2: Regex = Regex::new(r"[a-z]{2}").unwrap();
    }

    #[derive(Debug, Validate)]
    struct PutStruct {
        #[validate(length(min = "1", max = "10"))]
        name: Option<String>,
        #[validate(length(min = "1", max = "10"))]
        address: Option<Option<String>>,
        #[validate(length(min = "1", max = "10"))]
        ids: Option<Vec<usize>>,
        #[validate(length(min = "1", max = "10"))]
        opt_ids: Option<Option<Vec<usize>>>,
        #[validate(range(min = "1", max = "100"))]
        age: Option<Option<usize>>,
        #[validate(range(min = "1", max = "10"))]
        range: Option<usize>,
        #[validate(email)]
        email: Option<String>,
        #[validate(url)]
        url: Option<String>,
        #[validate(contains = "@")]
        text: Option<String>,
        #[validate(regex = "RE2")]
        re: Option<String>,
        #[validate(custom = "check_str")]
        custom: Option<String>,
    }

    fn check_str(_: &str) -> Result<(), ValidationError> {
        Ok(())
    }

    let s = PutStruct {
        name: Some("al".to_string()),
        address: Some(Some("gol".to_string())),
        ids: Some(vec![1, 2, 3]),
        opt_ids: Some(Some(vec![1, 2, 3])),
        age: Some(Some(20)),
        range: Some(2),
        email: Some("hi@gmail.com".to_string()),
        url: Some("http://google.com".to_string()),
        text: Some("@someone".to_string()),
        re: Some("hi".to_string()),
        custom: Some("hey".to_string()),
    };
    assert!(s.validate().is_ok());
}

#[test]
fn test_works_with_question_mark_operator() {
    fn some_fn() -> Result<(), ValidationErrors> {
        let signup = SignupData {
            mail: "invalid_email".to_string(),
            site: "http://hello.com".to_string(),
            first_name: "Bob".to_string(),
            age: 18,
        };

        signup.validate()?;
        Ok(())
    }

    assert!(some_fn().is_err());
}
<|endoftext|>


<commit_before>//! Completion for derives
use hir::HasAttrs;
use itertools::Itertools;
use rustc_hash::FxHashMap;
use syntax::ast;

use crate::{
    context::CompletionContext,
    item::{CompletionItem, CompletionItemKind, CompletionKind},
    Completions,
};

pub(super) fn complete_derive(
    acc: &mut Completions,
    ctx: &CompletionContext,
    derive_input: ast::TokenTree,
) {
    if let Some(existing_derives) = super::parse_comma_sep_input(derive_input) {
        for (derive, docs) in get_derive_names_in_scope(ctx) {
            let (label, lookup) = if let Some(derive_completion) = DEFAULT_DERIVE_COMPLETIONS
                .iter()
                .find(|derive_completion| derive_completion.label == derive)
            {
                let mut components = vec![derive_completion.label];
                components.extend(
                    derive_completion
                        .dependencies
                        .iter()
                        .filter(|&&dependency| !existing_derives.contains(dependency)),
                );
                let lookup = components.join(", ");
                let label = components.iter().rev().join(", ");
                (label, Some(lookup))
            } else {
                (derive, None)
            };
            let mut item =
                CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
            item.kind(CompletionItemKind::Attribute);
            if let Some(docs) = docs {
                item.documentation(docs);
            }
            if let Some(lookup) = lookup {
                item.lookup_by(lookup);
            }
            item.add_to(acc);
        }
    }
}

fn get_derive_names_in_scope(
    ctx: &CompletionContext,
) -> FxHashMap<String, Option<hir::Documentation>> {
    let mut result = FxHashMap::default();
    ctx.scope.process_all_names(&mut |name, scope_def| {
        if let hir::ScopeDef::MacroDef(mac) = scope_def {
            if mac.kind() == hir::MacroKind::Derive {
                result.insert(name.to_string(), mac.docs(ctx.db));
            }
        }
    });
    result
}

struct DeriveDependencies {
    label: &'static str,
    dependencies: &'static [&'static str],
}

/// Standard Rust derives that have dependencies
/// (the dependencies are needed so that the main derive don't break the compilation when added)
const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[
    DeriveDependencies { label: "Copy", dependencies: &["Clone"] },
    DeriveDependencies { label: "Eq", dependencies: &["PartialEq"] },
    DeriveDependencies { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
    DeriveDependencies { label: "PartialOrd", dependencies: &["PartialEq"] },
];

#[cfg(test)]
mod tests {
    use expect_test::{expect, Expect};

    use crate::{test_utils::completion_list, CompletionKind};

    fn check(ra_fixture: &str, expect: Expect) {
        let actual = completion_list(ra_fixture, CompletionKind::Attribute);
        expect.assert_eq(&actual);
    }

    #[test]
    fn no_completion_for_incorrect_derive() {
        check(r#"#[derive{$0)] struct Test;"#, expect![[]])
    }

    #[test]
    fn empty_derive() {
        // FIXME: Add build-in derives to fixture.
        check(r#"#[derive($0)] struct Test;"#, expect![[r#""#]]);
    }

    #[test]
    fn derive_with_input() {
        // FIXME: Add build-in derives to fixture.
        check(r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#, expect![[r#""#]])
    }

    #[test]
    fn derive_with_input2() {
        // FIXME: Add build-in derives to fixture.
        check(r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#, expect![[r#""#]])
    }
}
<commit_msg>Add builtin derives to attribute completion fixtures<commit_after>//! Completion for derives
use hir::HasAttrs;
use itertools::Itertools;
use rustc_hash::FxHashMap;
use syntax::ast;

use crate::{
    context::CompletionContext,
    item::{CompletionItem, CompletionItemKind, CompletionKind},
    Completions,
};

pub(super) fn complete_derive(
    acc: &mut Completions,
    ctx: &CompletionContext,
    derive_input: ast::TokenTree,
) {
    if let Some(existing_derives) = super::parse_comma_sep_input(derive_input) {
        for (derive, docs) in get_derive_names_in_scope(ctx) {
            let (label, lookup) = if let Some(derive_completion) = DEFAULT_DERIVE_COMPLETIONS
                .iter()
                .find(|derive_completion| derive_completion.label == derive)
            {
                let mut components = vec![derive_completion.label];
                components.extend(
                    derive_completion
                        .dependencies
                        .iter()
                        .filter(|&&dependency| !existing_derives.contains(dependency)),
                );
                let lookup = components.join(", ");
                let label = components.iter().rev().join(", ");
                (label, Some(lookup))
            } else {
                (derive, None)
            };
            let mut item =
                CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
            item.kind(CompletionItemKind::Attribute);
            if let Some(docs) = docs {
                item.documentation(docs);
            }
            if let Some(lookup) = lookup {
                item.lookup_by(lookup);
            }
            item.add_to(acc);
        }
    }
}

fn get_derive_names_in_scope(
    ctx: &CompletionContext,
) -> FxHashMap<String, Option<hir::Documentation>> {
    let mut result = FxHashMap::default();
    ctx.scope.process_all_names(&mut |name, scope_def| {
        if let hir::ScopeDef::MacroDef(mac) = scope_def {
            if mac.kind() == hir::MacroKind::Derive {
                result.insert(name.to_string(), mac.docs(ctx.db));
            }
        }
    });
    result
}

struct DeriveDependencies {
    label: &'static str,
    dependencies: &'static [&'static str],
}

/// Standard Rust derives that have dependencies
/// (the dependencies are needed so that the main derive don't break the compilation when added)
const DEFAULT_DERIVE_COMPLETIONS: &[DeriveDependencies] = &[
    DeriveDependencies { label: "Copy", dependencies: &["Clone"] },
    DeriveDependencies { label: "Eq", dependencies: &["PartialEq"] },
    DeriveDependencies { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
    DeriveDependencies { label: "PartialOrd", dependencies: &["PartialEq"] },
];

#[cfg(test)]
mod tests {
    use expect_test::{expect, Expect};

    use crate::{test_utils::completion_list, CompletionKind};

    fn check(ra_fixture: &str, expect: Expect) {
        let builtin_derives = r#"
#[rustc_builtin_macro]
pub macro Clone {}
#[rustc_builtin_macro]
pub macro Copy {}
#[rustc_builtin_macro]
pub macro Default {}
#[rustc_builtin_macro]
pub macro Debug {}
#[rustc_builtin_macro]
pub macro Hash {}
#[rustc_builtin_macro]
pub macro PartialEq {}
#[rustc_builtin_macro]
pub macro Eq {}
#[rustc_builtin_macro]
pub macro PartialOrd {}
#[rustc_builtin_macro]
pub macro Ord {}

"#;
        let actual = completion_list(
            &format!("{} {}", builtin_derives, ra_fixture),
            CompletionKind::Attribute,
        );
        expect.assert_eq(&actual);
    }

    #[test]
    fn no_completion_for_incorrect_derive() {
        check(r#"#[derive{$0)] struct Test;"#, expect![[]])
    }

    #[test]
    fn empty_derive() {
        check(
            r#"#[derive($0)] struct Test;"#,
            expect![[r#"
            at PartialEq
            at Default
            at PartialEq, Eq
            at PartialEq, Eq, PartialOrd, Ord
            at Clone, Copy
            at Debug
            at Clone
            at Hash
            at PartialEq, PartialOrd
        "#]],
        );
    }

    #[test]
    fn derive_with_input() {
        check(
            r#"#[derive(serde::Serialize, PartialEq, $0)] struct Test;"#,
            expect![[r#"
            at PartialEq
            at Default
            at Eq
            at Eq, PartialOrd, Ord
            at Clone, Copy
            at Debug
            at Clone
            at Hash
            at PartialOrd
        "#]],
        )
    }

    #[test]
    fn derive_with_input2() {
        check(
            r#"#[derive($0 serde::Serialize, PartialEq)] struct Test;"#,
            expect![[r#"
            at PartialEq
            at Default
            at Eq
            at Eq, PartialOrd, Ord
            at Clone, Copy
            at Debug
            at Clone
            at Hash
            at PartialOrd
        "#]],
        )
    }
}
<|endoftext|>


<commit_before>// Regression tests from American Fuzzy Lop test cases.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

extern crate mp4parse;

use std::io::Cursor;

/// https://github.com/mozilla/mp4parse-rust/issues/2
#[test]
fn fuzz_2() {
    let mut c = Cursor::new(b"\x00\x00\x00\x04\xa6\x00\x04\xa6".to_vec());
    let mut context = mp4parse::MediaContext::new();
    let _ = mp4parse::read_box(&mut c, &mut context);
}

/// https://github.com/mozilla/mp4parse-rust/issues/4
#[test]
fn fuzz_4() {
    let mut c = Cursor::new(b"\x00\x00\x00\x01\x30\x30\x30\x30\x00\x00\x00\x00\x00\x00\x00\x00".to_vec());
    let mut context = mp4parse::MediaContext::new();
    let _ = mp4parse::read_box(&mut c, &mut context);
}

/// https://github.com/mozilla/mp4parse-rust/issues/5
#[test]
fn fuzz_5() {
    let mut c =
    Cursor::new(b"\x30\x30\x30\x30\x66\x74\x79\x70\x30\x30\x30\x30\x30\x30\x30\x30".to_vec());
    let mut context = mp4parse::MediaContext::new();
    let _ = mp4parse::read_box(&mut c, &mut context);
}
<commit_msg>Document what each afl fuzz case does.<commit_after>/// Regression tests from American Fuzzy Lop test cases.

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

/// These all caused crashes at some point during development.

extern crate mp4parse;

use std::io::Cursor;

/// https://github.com/mozilla/mp4parse-rust/issues/2
///
/// Test a box with 4-byte size, smaller than the smallest header.
#[test]
fn fuzz_2() {
    let mut c = Cursor::new(b"\x00\x00\x00\x04\xa6\x00\x04\xa6".to_vec());
    let mut context = mp4parse::MediaContext::new();
    let _ = mp4parse::read_box(&mut c, &mut context);
}

/// https://github.com/mozilla/mp4parse-rust/issues/4
///
/// Test a large (64 bit) box header with zero declared size.
#[test]
fn fuzz_4() {
    let mut c = Cursor::new(b"\x00\x00\x00\x01\x30\x30\x30\x30\x00\x00\x00\x00\x00\x00\x00\x00".to_vec());
    let mut context = mp4parse::MediaContext::new();
    let _ = mp4parse::read_box(&mut c, &mut context);
}

/// https://github.com/mozilla/mp4parse-rust/issues/5
///
/// Declares 202116104 compatible brands but does not supply them,
/// verifying read is properly bounded at the end of the stream.
#[test]
fn fuzz_5() {
    let mut c =
    Cursor::new(b"\x30\x30\x30\x30\x66\x74\x79\x70\x30\x30\x30\x30\x30\x30\x30\x30".to_vec());
    let mut context = mp4parse::MediaContext::new();
    let _ = mp4parse::read_box(&mut c, &mut context);
}
<|endoftext|>


<commit_before>extern crate sdl2_net;
extern crate sdl2;

#[test]
fn init() {
    sdl2::init(sdl2::INIT_VIDEO);

    sdl2_net::init();

    let socket_set = sdl2_net::alloc_socket_set(20);

    let thing = sdl2_net::become_host(1234);

    match thing {
        Some(x) => println!("Started a server."),
        None => println!("Failed to init."),
    }

    let socket_some = sdl2_net::tcp_open();

    let mut socket: sdl2_net::TCPsocket;

    match socket_some {
        Some(s) => {socket = s; println!("Opened up a listening socket!")},
        None => {println!("Could not open a socket."); return},
    }

    sdl2_net::add_socket(&socket_set, &socket);

    let mut running = true;

    while running {

        let amnt = sdl2_net::check_sockets(&socket_set, 20);
        if amnt > 0{
            println!("Data is ready to be processed. {} stuffs.", amnt);
        }

        if sdl2_net::socket_ready(&socket) != 0{
            println!("New connection!!");
            /* Accept the connection here */
            running = false;
        }
    }

    println!("Closing server...");

    sdl2_net::free_socket_set(&socket_set);
    sdl2_net::tcp_close(&socket);
    sdl2_net::quit();

    println!("Finished.");
}
<commit_msg>Remove bad tests<commit_after><|endoftext|>


<commit_before>extern crate trustines;

mod memory {
    use trustines::memory::Memory;
    #[test]
    fn write() {
        let mut m = Memory::new();
        m.write(0, &[0,1,2]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(1,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
        m.write(1, &[3]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(3,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
    }

    #[test]
    fn read8_basic() {
        let mut m = Memory::new();
        m.write(0,&[5,10]);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn write8_basic() {
        let mut m = Memory::new();
        m.write8(0,5);
        assert_eq!(5,m.mem[0]);

        m.write8(1,10);
        assert_eq!(5,m.mem[0]);
        assert_eq!(10,m.mem[1]);
    }

    #[test]
    fn read16_basic() {
        let mut m = Memory::new();
        m.write(0,&[2,1,0]);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(1,m.read16(1).unwrap());
    }
    #[test]
    fn write16_basic() {
        let mut m = Memory::new();
        m.write16(0,258);
        assert_eq!(2,m.mem[0]);
        assert_eq!(1,m.mem[1]);
    }
    #[test]
    fn readwrite8() {
        let mut m = Memory::new();
        m.write8(0,5);
        m.write8(1,10);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn readwrite16() {
        let mut m = Memory::new();
        m.write16(0,258);
        m.write16(2,300);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(300,m.read16(2).unwrap());
    }
}

mod address_mode {
    use trustines::cpu;
    use trustines::memory::Memory;

    fn build_executor() -> cpu::CpuExecutor {
        let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
        return cpu::CpuExecutor::new(opcode_info.0);
    }
    fn build_memory(instr:u8,index:u16, ops: &[u8]) -> Memory {
        let mut m = Memory::new();
        update_memory(&mut m,instr,index,ops);
        return m;
    }
    fn update_memory(m:&mut Memory, instr:u8,index:u16, ops: &[u8]) {
        m.write8(index,instr);
        if ops.len() > 0 {
            m.write(index+1,ops);
        }
    }

    // NOTE: the opcodes specified in build_memory are not being executed, so the
    //       opcode class (ADC, ASL, BRK, etc) don't actually matter.  What matters
    //       is the addressing mode (Absolute, AbsoluteX, ZeroPage, etc)
    //

// ------------------ Non-Indexed, Non-Memory ------------------ //

    #[test]
    fn accumulator() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x0A,0, &[]);// 0x0A = ASL Accumulator
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x0A);
    }
    #[test]
    fn immediate() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x69,0, &[]);// 0x69 = ADC Immediate
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x69);
    }
    #[test]
    fn implied() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x00,0, &[]);// 0x00 = BRK Implied
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x00);
    }

// ------------------ Non-Indexed, Memory ------------------ //

    #[test]
    fn absolute() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x6D,0, &[]); //0x6D = ADC Absolute
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x6D);
    }
    #[test]
    fn indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x6C,0, &[]);// 0x6C = JMP Indirect
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x6C);
    }
    #[test]
    fn relative() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x90,0, &[]);// 0x90 = BCC IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x90);
    }
    #[test]
    fn zeropage() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x65,0, &[]);// 0x65 = ADC IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x65);
    }

// ------------------ Indexed, Memory ------------------ //

    #[test]
    fn absolute_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x7D,0, &[]); // 0x7D = ADC AbsoluteX
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x7D);
    }
    #[test]
    fn absolute_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x79,0, &[]);// 0x79 = ADC AbsoluteY
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x79);
    }
    #[test]
    fn zeropage_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x75,0, &[]);// 0x75 = LDX ZeroPageX
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x75);
    }
    #[test]
    fn zeropage_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0xB6,0, &[]);// 0xB6 = LDX IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0xB6);
    }
    #[test]
    fn indexed_indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x61,0, &[]);// 0x61 = ADC IndexedIndirect
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x61);
    }
    #[test]
    fn indirect_indexed() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x71,0, &[]);// 0x71 = ADC IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x71);
    }
}

<commit_msg>the Non-Indexed, Memory Addressing Mode tests are implemented<commit_after>extern crate trustines;

mod memory {
    use trustines::memory::Memory;
    #[test]
    fn write() {
        let mut m = Memory::new();
        m.write(0, &[0,1,2]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(1,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
        m.write(1, &[3]);
        assert_eq!(0,m.read8(0).unwrap());
        assert_eq!(3,m.read8(1).unwrap());
        assert_eq!(2,m.read8(2).unwrap());
    }

    #[test]
    fn read8_basic() {
        let mut m = Memory::new();
        m.write(0,&[5,10]);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn write8_basic() {
        let mut m = Memory::new();
        m.write8(0,5);
        assert_eq!(5,m.mem[0]);

        m.write8(1,10);
        assert_eq!(5,m.mem[0]);
        assert_eq!(10,m.mem[1]);
    }

    #[test]
    fn read16_basic() {
        let mut m = Memory::new();
        m.write(0,&[2,1,0]);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(1,m.read16(1).unwrap());
    }
    #[test]
    fn write16_basic() {
        let mut m = Memory::new();
        m.write16(0,258);
        assert_eq!(2,m.mem[0]);
        assert_eq!(1,m.mem[1]);
    }
    #[test]
    fn readwrite8() {
        let mut m = Memory::new();
        m.write8(0,5);
        m.write8(1,10);
        assert_eq!(5,m.read8(0).unwrap());
        assert_eq!(10,m.read8(1).unwrap());
    }
    #[test]
    fn readwrite16() {
        let mut m = Memory::new();
        m.write16(0,258);
        m.write16(2,300);
        assert_eq!(258,m.read16(0).unwrap());
        assert_eq!(300,m.read16(2).unwrap());
    }
}

mod address_mode {
    use trustines::cpu;
    use trustines::memory::Memory;
    use trustines::cpu::OpcodeClass;
    use trustines::cpu::AddressMode;

    fn build_executor() -> cpu::CpuExecutor {
        let opcode_info = cpu::opcode::load_from_file("resources/opcodes.csv").unwrap();
        return cpu::CpuExecutor::new(opcode_info.0);
    }
    fn build_memory(instr:u8,index:u16, ops: &[u8]) -> Memory {
        let mut m = Memory::new();
        update_memory(&mut m,instr,index,ops);
        return m;
    }
    fn update_memory(m:&mut Memory, instr:u8,index:u16, ops: &[u8]) {
        m.write8(index,instr);
        if ops.len() > 0 {
            m.write(index+1,ops);
        }
    }

    // NOTE: the opcodes specified in build_memory are not being executed, so the
    //       opcode class (ADC, ASL, BRK, etc) don't actually matter.  What matters
    //       is the addressing mode (Absolute, AbsoluteX, ZeroPage, etc)
    //

// ------------------ Non-Indexed, Non-Memory ------------------ //

    #[test]
    fn accumulator() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x0A,0, &[]);// 0x0A = ASL Accumulator
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x0A);
    }
    #[test]
    fn immediate() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x69,0, &[]);// 0x69 = ADC Immediate
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x69);
    }
    #[test]
    fn implied() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x00,0, &[]);// 0x00 = BRK Implied
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x00);
    }

// ------------------ Non-Indexed, Memory ------------------ //

    #[test]
    fn absolute() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x6D,0, &[]); //0x6D = ADC Absolute
        let exec = build_executor();

        //mem.write8(0,0x6D);
        mem.write16(1,300);
        mem.write8(300,5);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);
        let s = OpcodeClass::ADC;

        assert_eq!(0x6D,cpu.instruction_register);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }

        assert_eq!(300,cpu.decode_register.addr_final.unwrap());
        assert_eq!(5,cpu.decode_register.value_final.unwrap());
    }
    #[test]
    fn indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x6C,0, &[]);// 0x6C = JMP Indirect
        let exec = build_executor();

        //mem.write8(0,0x6C);
        mem.write16(1,300);
        mem.write16(300,500);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x6C);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::JMP => {},
            _ => panic!("Expected JMP opcode class")
        }

        assert_eq!(300,cpu.decode_register.addr_intermediate.unwrap());
        assert_eq!(500,cpu.decode_register.addr_final.unwrap());
    }
    #[test]
    fn relative() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x90,0, &[]);// 0x90 = BCC IndirectIndexed
        let exec = build_executor();

        mem.write8(1,100);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x90);

        match cpu.decode_register.info.opcode_class {
            OpcodeClass::BCC => {},
            _ => panic!("Expected BCC opcode class")
        }
        assert_eq!(1,cpu.decode_register.addr_final.unwrap());
        assert_eq!(100,cpu.decode_register.value_final.unwrap());
    }
    #[test]
    fn zeropage() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x65,0, &[]);// 0x65 = ADC IndirectIndexed
        let exec = build_executor();

        mem.write8(1,100);
        mem.write8(100,5);

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x65);
        match cpu.decode_register.info.opcode_class {
            OpcodeClass::ADC => {},
            _ => panic!("Expected ADC opcode class")
        }
        assert_eq!(100,cpu.decode_register.addr_final.unwrap());
        assert_eq!(5,cpu.decode_register.value_final.unwrap());
    }

// ------------------ Indexed, Memory ------------------ //

    #[test]
    fn absolute_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x7D,0, &[]); // 0x7D = ADC AbsoluteX
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x7D);
    }
    #[test]
    fn absolute_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x79,0, &[]);// 0x79 = ADC AbsoluteY
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x79);
    }
    #[test]
    fn zeropage_x() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x75,0, &[]);// 0x75 = LDX ZeroPageX
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x75);
    }
    #[test]
    fn zeropage_y() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0xB6,0, &[]);// 0xB6 = LDX IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0xB6);
    }
    #[test]
    fn indexed_indirect() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x61,0, &[]);// 0x61 = ADC IndexedIndirect
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x61);
    }
    #[test]
    fn indirect_indexed() {
        let mut cpu: cpu::CpuState = Default::default();
        let mut mem = build_memory(0x71,0, &[]);// 0x71 = ADC IndirectIndexed
        let exec = build_executor();

        cpu.pc = 0;
        exec.fetch_and_decode(&mut cpu,&mut mem);

        assert_eq!(cpu.instruction_register,0x71);
    }
}

<|endoftext|>