<commit_before>extern crate itertools;

use itertools::Stride;
use itertools::StrideMut;

#[test]
fn mut_stride() {
    let mut xs = vec![1, 1, 1, 1, 1, 1];
    for x in StrideMut::from_slice(&mut *xs, 2) {
        *x = 0;
    }
    assert_eq!(xs, vec![0, 1, 0, 1, 0, 1]);
}

#[test]
fn mut_stride_compose() {
    let mut xs = vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
    {
        let iter1 = StrideMut::from_slice(&mut *xs, 2);
        let iter2 = StrideMut::from_stride(iter1, 3);
        for x in iter2 {
            *x = 0;
        }
    }
    assert_eq!(xs, vec![0, 1, 1, 1, 1, 1, 0, 1, 1, 1]);
}

#[test]
fn stride_uneven() {
    let xs = &[7, 9, 8];
    let mut it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 8);
    assert!(it.len() == 0);
    assert!(it.next().is_none());

    let xs = &[7, 9, 8, 10];
    let mut it = Stride::from_slice(&xs[1..], 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 10);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride_compose() {
    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let odds = Stride::from_slice(xs, 2);
    let it = Stride::from_stride(odds, 2);
    let ans: Vec<isize> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![1, 5, 9]);

    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(&xs[1..], 2);
    let it = Stride::from_stride(evens, 2);
    let ans: Vec<isize> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![2, 6]);

    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(&xs[1..], 2);
    let it = Stride::from_stride(evens, 1);
    let ans: Vec<isize> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![2, 4, 6, 8]);

    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.swap_ends();
    let it = Stride::from_stride(odds, 2);
    let ans: Vec<isize> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![9, 5, 1]);

    let xs = &[1, 2, 3];
    let every = Stride::from_slice(xs, 1);
    assert_eq!(every.len(), 3);
    let odds = Stride::from_stride(every, 2);
    assert_eq!(odds.len(), 2);
    let v = odds.cloned().collect::<Vec<isize>>();
    assert_eq!(v, vec![1, 3]);

    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(&xs[1..], 2);
    let it = Stride::from_stride(evens, -2);
    let ans: Vec<isize> = it.map(|&x| x).collect();
    assert_eq!(ans, vec![8, 4]);
}

#[test]
fn from_stride_empty()
{
    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.by_ref().count();
    assert!(odds.len() == 0);
    assert!(odds.next().is_none());
    let mut it = Stride::from_stride(odds, 2);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride() {
    let xs: &[u8]  = &[];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (0, Some(0)));
    assert!(it.next().is_none());

    let xs = &[7, 9, 8, 10];
    let mut it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 8);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 2).rev();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let xs = &[7, 9, 8, 10];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (4, Some(4)));
    assert!(*it.next().unwrap() == 7);
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 10);
    assert!(it.len() == 0);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 1).rev();
    assert!(it.size_hint() == (4, Some(4)));
    assert!(*it.next().unwrap() == 10);
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 9);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, 2);
    it.swap_ends();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(*it.next().unwrap() == 8);
    assert!(*it.next().unwrap() == 7);
    assert!(it.next().is_none());

    let mut it = Stride::from_slice(xs, -2);
    assert_eq!(it.size_hint(), (2, Some(2)));
    assert_eq!(*it.next().unwrap(), 10);
    assert_eq!(*it.next().unwrap(), 9);
    assert_eq!(it.next(), None);
}

#[test]
fn stride_index() {
    let xs = &[7, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    assert_eq!(it[0], 7);
    assert_eq!(it[1], 8);
}

#[test]
#[should_panic]
fn stride_index_fail() {
    let xs = &[7, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    let _ = it[2];
}
<commit_msg>tests: Improve stride tests<commit_after>extern crate itertools;

use itertools::Stride;
use itertools::StrideMut;
use itertools::equal;

#[test]
fn mut_stride() {
    let mut xs = vec![1, 1, 1, 1, 1, 1];
    for x in StrideMut::from_slice(&mut *xs, 2) {
        *x = 0;
    }
    assert_eq!(xs, vec![0, 1, 0, 1, 0, 1]);
}

#[test]
fn mut_stride_compose() {
    let mut xs = vec![1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
    {
        let iter1 = StrideMut::from_slice(&mut *xs, 2);
        let iter2 = StrideMut::from_stride(iter1, 3);
        for x in iter2 {
            *x = 0;
        }
    }
    assert_eq!(xs, vec![0, 1, 1, 1, 1, 1, 0, 1, 1, 1]);
}

#[test]
fn stride_uneven() {
    let xs = &[7, 9, 8];
    let it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(equal(it, &[7, 8]));

    let xs = &[7, 9, 8, 10];
    let it = Stride::from_slice(&xs[1..], 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(equal(it, &[9, 10]));
}

#[test]
fn stride_compose() {
    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let odds = Stride::from_slice(xs, 2);
    let it = Stride::from_stride(odds, 2);
    assert!(equal(it, &[1, 5, 9]));

    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(&xs[1..], 2);
    let it = Stride::from_stride(evens, 2);
    assert!(equal(it, &[2, 6]));

    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(&xs[1..], 2);
    let it = Stride::from_stride(evens, 1);
    assert!(equal(it, &[2, 4, 6, 8]));

    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.swap_ends();
    let it = Stride::from_stride(odds, 2);
    assert!(equal(it, &[9, 5, 1]));

    let xs = &[1, 2, 3];
    let every = Stride::from_slice(xs, 1);
    assert_eq!(every.len(), 3);
    let odds = Stride::from_stride(every, 2);
    assert_eq!(odds.len(), 2);
    assert!(equal(odds, &[1, 3]));

    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let evens = Stride::from_slice(&xs[1..], 2);
    let it = Stride::from_stride(evens, -2);
    assert!(equal(it, &[8, 4]));
}

#[test]
fn from_stride_empty()
{
    let xs = &[1, 2, 3, 4, 5, 6, 7, 8, 9];
    let mut odds = Stride::from_slice(xs, 2);
    odds.by_ref().count();
    assert!(odds.len() == 0);
    assert!(odds.next().is_none());
    let mut it = Stride::from_stride(odds, 2);
    assert!(it.len() == 0);
    assert!(it.next().is_none());
}

#[test]
fn stride() {
    let xs: &[u8]  = &[];
    let mut it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (0, Some(0)));
    assert!(it.next().is_none());

    let xs = &[7, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    assert!(it.size_hint() == (2, Some(2)));
    assert!(equal(it, &[7, 8]));

    let it = Stride::from_slice(xs, 2).rev();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(equal(it, &[8, 7]));

    let xs = &[7, 9, 8, 10];
    let it = Stride::from_slice(xs, 1);
    assert!(it.size_hint() == (4, Some(4)));
    assert!(equal(it, &[7, 9, 8, 10]));

    let it = Stride::from_slice(xs, 1).rev();
    assert!(it.size_hint() == (4, Some(4)));
    assert!(equal(it, &[10, 8, 9, 7]));

    let mut it = Stride::from_slice(xs, 2);
    it.swap_ends();
    assert!(it.size_hint() == (2, Some(2)));
    assert!(equal(it, &[8, 7]));

    let it = Stride::from_slice(xs, -2);
    assert_eq!(it.size_hint(), (2, Some(2)));
    assert!(equal(it, &[10, 9]));
}

#[test]
fn stride_index() {
    let xs = &[7, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    assert_eq!(it[0], 7);
    assert_eq!(it[1], 8);
}

#[test]
#[should_panic]
fn stride_index_fail() {
    let xs = &[7, 9, 8, 10];
    let it = Stride::from_slice(xs, 2);
    let _ = it[2];
}
<|endoftext|>


<commit_before>//! VM Runtime
use utils::bigint::M256;
use utils::gas::Gas;
use super::commit::{AccountState, BlockhashState};
use super::errors::{RequireError, MachineError, CommitError, EvalError, PCError};
use super::{Stack, Context, BlockHeader, Patch, PC, Memory, AccountCommitment, Log};

use self::check::{check_opcode, extra_check_opcode};
use self::run::run_opcode;
use self::cost::{gas_refund, gas_stipend, gas_cost, memory_cost, memory_gas, code_deposit_gas};
use self::utils::copy_into_memory;

mod cost;
mod run;
mod check;
mod utils;
mod precompiled;

/// A VM state without PC.
pub struct State<M> {
    pub memory: M,
    pub stack: Stack,

    pub context: Context,
    pub block: BlockHeader,
    pub patch: &'static Patch,

    pub out: Vec<u8>,

    pub memory_cost: Gas,
    pub used_gas: Gas,
    pub refunded_gas: Gas,

    pub account_state: AccountState,
    pub blockhash_state: BlockhashState,
    pub logs: Vec<Log>,

    pub depth: usize,
}

impl<M> State<M> {
    pub fn memory_gas(&self) -> Gas {
        memory_gas(self.memory_cost)
    }

    pub fn available_gas(&self) -> Gas {
        self.context.gas_limit - self.memory_gas() - self.used_gas
    }
}

/// A VM state with PC.
pub struct Machine<M> {
    state: State<M>,
    pc: PC,
    status: MachineStatus,
}

#[derive(Debug, Clone)]
/// Represents the current runtime status.
pub enum MachineStatus {
    /// This runtime is actively running or has just been started.
    Running,
    /// This runtime has exited successfully. Calling `step` on this
    /// runtime again would panic.
    ExitedOk,
    /// This runtime has exited with errors. Calling `step` on this
    /// runtime again would panic.
    ExitedErr(MachineError),
    /// This runtime requires execution of a sub runtime, which is a
    /// ContractCreation instruction.
    InvokeCreate(Context),
    /// This runtime requires execution of a sub runtime, which is a
    /// MessageCall instruction.
    InvokeCall(Context, (M256, M256)),
}

#[derive(Debug, Clone)]
/// Used for `check` for additional checks related to the runtime.
pub enum ControlCheck {
    Jump(M256),
}

#[derive(Debug, Clone)]
/// Used for `step` for additional operations related to the runtime.
pub enum Control {
    Stop,
    Jump(M256),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

impl<M: Memory + Default> Machine<M> {
    /// Create a new runtime.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch, depth: usize) -> Self {
        Self::with_states(context, block, patch, depth,
                          AccountState::default(), BlockhashState::default())
    }

    pub fn with_states(context: Context, block: BlockHeader, patch: &'static Patch,
                       depth: usize, account_state: AccountState,
                       blockhash_state: BlockhashState) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context,
                block,
                patch,

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state,
                blockhash_state,
                logs: Vec::new(),

                depth,
            },
        }
    }

    /// Derive this runtime to create a sub runtime. This will not
    /// modify the current runtime, and it will have a chance to
    /// review whether it wants to accept the result of this sub
    /// runtime afterwards.
    pub fn derive(&self, context: Context) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: self.state.block.clone(),
                patch: self.state.patch.clone(),

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: self.state.account_state.clone(),
                blockhash_state: self.state.blockhash_state.clone(),
                logs: self.state.logs.clone(),

                depth: self.state.depth + 1,
            },
        }
    }

    pub fn initialize_call(&mut self) {
        self.state.account_state.decrease_balance(self.state.context.caller, self.state.context.value);
        self.state.account_state.increase_balance(self.state.context.address, self.state.context.value);
    }

    pub fn initialize_create(&mut self) {
        self.state.account_state.decrease_balance(self.state.context.caller, self.state.context.value);
        self.state.account_state.create(self.state.context.address, self.state.context.value);
    }

    /// Commit a new account into this runtime.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        self.state.account_state.commit(commitment)
    }

    /// Commit a new blockhash into this runtime.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        self.state.blockhash_state.commit(number, hash)
    }

    pub fn code_deposit(&mut self) -> Result<(), RequireError> {
        match self.status() {
            MachineStatus::ExitedOk | MachineStatus::ExitedErr(_) => (),
            _ => panic!(),
        }

        let deposit_cost = code_deposit_gas(self.state.out.len());
        if deposit_cost > self.state.available_gas() {
            if !self.state.patch.force_code_deposit {
                self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            } else {
                self.state.account_state.code_deposit(self.state.context.address, &[]);
            }
        } else {
            self.state.used_gas = self.state.used_gas + deposit_cost;
            self.state.account_state.code_deposit(self.state.context.address,
                                                  self.state.out.as_slice());
        }
        Ok(())
    }

    pub fn finalize(&mut self, real_used_gas: Gas, fresh_account_state: &AccountState) -> Result<(), RequireError> {
        match self.status() {
            MachineStatus::ExitedOk => (),
            MachineStatus::ExitedErr(_) => {
                // If exited with error, reset all changes.
                self.state.account_state = fresh_account_state.clone();
            },
            _ => panic!(),
        }

        let gas_dec = real_used_gas * self.state.context.gas_price;
        self.state.account_state.decrease_balance(self.state.context.caller, gas_dec.into());

        match self.status() {
            MachineStatus::ExitedOk => (),
            MachineStatus::ExitedErr(_) => return Ok(()),
            _ => panic!(),
        }

        Ok(())
    }

    #[allow(unused_variables)]
    /// Apply a sub runtime into the current runtime. This sub runtime
    /// should have been created by the current runtime's `derive`
    /// function. Depending whether the current runtime is invoking a
    /// ContractCreation or MessageCall instruction, it will apply
    /// various states back.
    pub fn apply_sub(&mut self, sub: Machine<M>) {
        use std::mem::swap;
        let mut status = MachineStatus::Running;
        swap(&mut status, &mut self.status);
        match status {
            MachineStatus::InvokeCreate(_) => {
                self.apply_create(sub);
            },
            MachineStatus::InvokeCall(_, (out_start, out_len)) => {
                self.apply_call(sub, out_start, out_len);
            },
            _ => panic!(),
        }
    }

    fn apply_create(&mut self, sub: Machine<M>) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                if self.state.available_gas() >= code_deposit_gas(sub.state.out.len()) {
                    self.state.account_state.decrease_balance(sub.state.context.caller,
                                                              code_deposit_gas(sub.state.out.len()).into());
                    self.state.account_state.code_deposit(sub.state.context.address,
                                                          sub.state.out.as_slice());
                } else {
                    self.state.account_state.code_deposit(sub.state.context.address, &[]);
                }

            },
            MachineStatus::ExitedErr(_) => {
                // self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                // self.state.stack.pop().unwrap();
                // self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    fn apply_call(&mut self, sub: Machine<M>, out_start: M256, out_len: M256) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                copy_into_memory(&mut self.state.memory, sub.state.out.as_slice(),
                                 out_start, M256::zero(), out_len);
            },
            MachineStatus::ExitedErr(_) => {
                // self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::from(1u64)).unwrap();
            },
            _ => panic!(),
        }
    }

    /// Check the next instruction about whether it will return
    /// errors.
    pub fn check(&self) -> Result<(), EvalError> {
        let instruction = self.pc.peek()?;
        check_opcode(instruction, &self.state).and_then(|v| {
            match v {
                None => Ok(()),
                Some(ControlCheck::Jump(dest)) => {
                    if dest <= M256::from(usize::max_value()) && self.pc.is_valid(dest.into()) {
                        Ok(())
                    } else {
                        Err(EvalError::Machine(MachineError::PC(PCError::BadJumpDest)))
                    }
                }
            }
        })
    }

    /// Step an instruction in the PC. The eval result is refected by
    /// the runtime status, and it will only return an error if
    /// there're accounts or blockhashes to be committed to this
    /// runtime for it to run. In that case, the state of the current
    /// runtime will not be affected.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match &self.status {
            &MachineStatus::Running => (),
            _ => panic!(),
        }

        if self.step_precompiled() {
            return Ok(());
        }

        if self.state.depth >= self.state.patch.callstack_limit {
            self.status = MachineStatus::ExitedErr(MachineError::CallstackOverflow);
            return Ok(());
        }

        if self.pc.is_end() {
            self.status = MachineStatus::ExitedOk;
            return Ok(());
        }

        match self.check() {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        };

        let instruction = self.pc.peek().unwrap();
        let position = self.pc.position();
        let memory_cost = memory_cost(instruction, &self.state);
        let memory_gas = memory_gas(memory_cost);
        let gas_cost = gas_cost(instruction, &self.state);
        let gas_stipend = gas_stipend(instruction, &self.state);
        let gas_refund = gas_refund(instruction, &self.state);

        let all_gas_cost = memory_gas + self.state.used_gas + gas_cost - gas_stipend;
        if self.state.context.gas_limit < all_gas_cost {
            self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            return Ok(());
        }

        let after_gas = self.state.context.gas_limit - all_gas_cost;

        match extra_check_opcode(instruction, &self.state, gas_stipend, after_gas) {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        }

        let instruction = self.pc.read().unwrap();
        let result = run_opcode((instruction, position),
                                &mut self.state, gas_stipend, after_gas);

        self.state.used_gas = self.state.used_gas + gas_cost - gas_stipend;
        self.state.memory_cost = memory_cost;
        self.state.refunded_gas = self.state.refunded_gas + gas_refund;

        match result {
            None => Ok(()),
            Some(Control::Jump(dest)) => {
                self.pc.jump(dest.into()).unwrap();
                Ok(())
            },
            Some(Control::InvokeCall(context, (from, len))) => {
                self.status = MachineStatus::InvokeCall(context, (from, len));
                Ok(())
            },
            Some(Control::InvokeCreate(context)) => {
                self.status = MachineStatus::InvokeCreate(context);
                Ok(())
            },
            Some(Control::Stop) => {
                self.status = MachineStatus::ExitedOk;
                Ok(())
            },
        }
    }

    /// Get the runtime state.
    pub fn state(&self) -> &State<M> {
        &self.state
    }

    /// Get the current runtime status.
    pub fn status(&self) -> MachineStatus {
        self.status.clone()
    }
}
<commit_msg>Problem: logs should be reset if VM fails<commit_after>//! VM Runtime
use utils::bigint::M256;
use utils::gas::Gas;
use super::commit::{AccountState, BlockhashState};
use super::errors::{RequireError, MachineError, CommitError, EvalError, PCError};
use super::{Stack, Context, BlockHeader, Patch, PC, Memory, AccountCommitment, Log};

use self::check::{check_opcode, extra_check_opcode};
use self::run::run_opcode;
use self::cost::{gas_refund, gas_stipend, gas_cost, memory_cost, memory_gas, code_deposit_gas};
use self::utils::copy_into_memory;

mod cost;
mod run;
mod check;
mod utils;
mod precompiled;

/// A VM state without PC.
pub struct State<M> {
    pub memory: M,
    pub stack: Stack,

    pub context: Context,
    pub block: BlockHeader,
    pub patch: &'static Patch,

    pub out: Vec<u8>,

    pub memory_cost: Gas,
    pub used_gas: Gas,
    pub refunded_gas: Gas,

    pub account_state: AccountState,
    pub blockhash_state: BlockhashState,
    pub logs: Vec<Log>,

    pub depth: usize,
}

impl<M> State<M> {
    pub fn memory_gas(&self) -> Gas {
        memory_gas(self.memory_cost)
    }

    pub fn available_gas(&self) -> Gas {
        self.context.gas_limit - self.memory_gas() - self.used_gas
    }
}

/// A VM state with PC.
pub struct Machine<M> {
    state: State<M>,
    pc: PC,
    status: MachineStatus,
}

#[derive(Debug, Clone)]
/// Represents the current runtime status.
pub enum MachineStatus {
    /// This runtime is actively running or has just been started.
    Running,
    /// This runtime has exited successfully. Calling `step` on this
    /// runtime again would panic.
    ExitedOk,
    /// This runtime has exited with errors. Calling `step` on this
    /// runtime again would panic.
    ExitedErr(MachineError),
    /// This runtime requires execution of a sub runtime, which is a
    /// ContractCreation instruction.
    InvokeCreate(Context),
    /// This runtime requires execution of a sub runtime, which is a
    /// MessageCall instruction.
    InvokeCall(Context, (M256, M256)),
}

#[derive(Debug, Clone)]
/// Used for `check` for additional checks related to the runtime.
pub enum ControlCheck {
    Jump(M256),
}

#[derive(Debug, Clone)]
/// Used for `step` for additional operations related to the runtime.
pub enum Control {
    Stop,
    Jump(M256),
    InvokeCreate(Context),
    InvokeCall(Context, (M256, M256)),
}

impl<M: Memory + Default> Machine<M> {
    /// Create a new runtime.
    pub fn new(context: Context, block: BlockHeader, patch: &'static Patch, depth: usize) -> Self {
        Self::with_states(context, block, patch, depth,
                          AccountState::default(), BlockhashState::default())
    }

    pub fn with_states(context: Context, block: BlockHeader, patch: &'static Patch,
                       depth: usize, account_state: AccountState,
                       blockhash_state: BlockhashState) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context,
                block,
                patch,

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state,
                blockhash_state,
                logs: Vec::new(),

                depth,
            },
        }
    }

    /// Derive this runtime to create a sub runtime. This will not
    /// modify the current runtime, and it will have a chance to
    /// review whether it wants to accept the result of this sub
    /// runtime afterwards.
    pub fn derive(&self, context: Context) -> Self {
        Machine {
            pc: PC::new(context.code.as_slice()),
            status: MachineStatus::Running,
            state: State {
                memory: M::default(),
                stack: Stack::default(),

                context: context,
                block: self.state.block.clone(),
                patch: self.state.patch.clone(),

                out: Vec::new(),

                memory_cost: Gas::zero(),
                used_gas: Gas::zero(),
                refunded_gas: Gas::zero(),

                account_state: self.state.account_state.clone(),
                blockhash_state: self.state.blockhash_state.clone(),
                logs: self.state.logs.clone(),

                depth: self.state.depth + 1,
            },
        }
    }

    pub fn initialize_call(&mut self) {
        self.state.account_state.decrease_balance(self.state.context.caller, self.state.context.value);
        self.state.account_state.increase_balance(self.state.context.address, self.state.context.value);
    }

    pub fn initialize_create(&mut self) {
        self.state.account_state.decrease_balance(self.state.context.caller, self.state.context.value);
        self.state.account_state.create(self.state.context.address, self.state.context.value);
    }

    /// Commit a new account into this runtime.
    pub fn commit_account(&mut self, commitment: AccountCommitment) -> Result<(), CommitError> {
        self.state.account_state.commit(commitment)
    }

    /// Commit a new blockhash into this runtime.
    pub fn commit_blockhash(&mut self, number: M256, hash: M256) -> Result<(), CommitError> {
        self.state.blockhash_state.commit(number, hash)
    }

    pub fn code_deposit(&mut self) -> Result<(), RequireError> {
        match self.status() {
            MachineStatus::ExitedOk | MachineStatus::ExitedErr(_) => (),
            _ => panic!(),
        }

        let deposit_cost = code_deposit_gas(self.state.out.len());
        if deposit_cost > self.state.available_gas() {
            if !self.state.patch.force_code_deposit {
                self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            } else {
                self.state.account_state.code_deposit(self.state.context.address, &[]);
            }
        } else {
            self.state.used_gas = self.state.used_gas + deposit_cost;
            self.state.account_state.code_deposit(self.state.context.address,
                                                  self.state.out.as_slice());
        }
        Ok(())
    }

    pub fn finalize(&mut self, real_used_gas: Gas, fresh_account_state: &AccountState) -> Result<(), RequireError> {
        match self.status() {
            MachineStatus::ExitedOk => (),
            MachineStatus::ExitedErr(_) => {
                // If exited with error, reset all changes.
                self.state.account_state = fresh_account_state.clone();
                self.state.logs = Vec::new();
            },
            _ => panic!(),
        }

        let gas_dec = real_used_gas * self.state.context.gas_price;
        self.state.account_state.decrease_balance(self.state.context.caller, gas_dec.into());

        match self.status() {
            MachineStatus::ExitedOk => (),
            MachineStatus::ExitedErr(_) => return Ok(()),
            _ => panic!(),
        }

        Ok(())
    }

    #[allow(unused_variables)]
    /// Apply a sub runtime into the current runtime. This sub runtime
    /// should have been created by the current runtime's `derive`
    /// function. Depending whether the current runtime is invoking a
    /// ContractCreation or MessageCall instruction, it will apply
    /// various states back.
    pub fn apply_sub(&mut self, sub: Machine<M>) {
        use std::mem::swap;
        let mut status = MachineStatus::Running;
        swap(&mut status, &mut self.status);
        match status {
            MachineStatus::InvokeCreate(_) => {
                self.apply_create(sub);
            },
            MachineStatus::InvokeCall(_, (out_start, out_len)) => {
                self.apply_call(sub, out_start, out_len);
            },
            _ => panic!(),
        }
    }

    fn apply_create(&mut self, sub: Machine<M>) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                if self.state.available_gas() >= code_deposit_gas(sub.state.out.len()) {
                    self.state.account_state.decrease_balance(sub.state.context.caller,
                                                              code_deposit_gas(sub.state.out.len()).into());
                    self.state.account_state.code_deposit(sub.state.context.address,
                                                          sub.state.out.as_slice());
                } else {
                    self.state.account_state.code_deposit(sub.state.context.address, &[]);
                }

            },
            MachineStatus::ExitedErr(_) => {
                // self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                // self.state.stack.pop().unwrap();
                // self.state.stack.push(M256::zero()).unwrap();
            },
            _ => panic!(),
        }
    }

    fn apply_call(&mut self, sub: Machine<M>, out_start: M256, out_len: M256) {
        if self.state.available_gas() < sub.state.used_gas {
            panic!();
        }

        match sub.status() {
            MachineStatus::ExitedOk => {
                self.state.account_state = sub.state.account_state;
                self.state.blockhash_state = sub.state.blockhash_state;
                self.state.logs = sub.state.logs;
                self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.refunded_gas = self.state.refunded_gas + sub.state.refunded_gas;
                copy_into_memory(&mut self.state.memory, sub.state.out.as_slice(),
                                 out_start, M256::zero(), out_len);
            },
            MachineStatus::ExitedErr(_) => {
                // self.state.used_gas = self.state.used_gas + sub.state.used_gas;
                self.state.stack.pop().unwrap();
                self.state.stack.push(M256::from(1u64)).unwrap();
            },
            _ => panic!(),
        }
    }

    /// Check the next instruction about whether it will return
    /// errors.
    pub fn check(&self) -> Result<(), EvalError> {
        let instruction = self.pc.peek()?;
        check_opcode(instruction, &self.state).and_then(|v| {
            match v {
                None => Ok(()),
                Some(ControlCheck::Jump(dest)) => {
                    if dest <= M256::from(usize::max_value()) && self.pc.is_valid(dest.into()) {
                        Ok(())
                    } else {
                        Err(EvalError::Machine(MachineError::PC(PCError::BadJumpDest)))
                    }
                }
            }
        })
    }

    /// Step an instruction in the PC. The eval result is refected by
    /// the runtime status, and it will only return an error if
    /// there're accounts or blockhashes to be committed to this
    /// runtime for it to run. In that case, the state of the current
    /// runtime will not be affected.
    pub fn step(&mut self) -> Result<(), RequireError> {
        match &self.status {
            &MachineStatus::Running => (),
            _ => panic!(),
        }

        if self.step_precompiled() {
            return Ok(());
        }

        if self.state.depth >= self.state.patch.callstack_limit {
            self.status = MachineStatus::ExitedErr(MachineError::CallstackOverflow);
            return Ok(());
        }

        if self.pc.is_end() {
            self.status = MachineStatus::ExitedOk;
            return Ok(());
        }

        match self.check() {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        };

        let instruction = self.pc.peek().unwrap();
        let position = self.pc.position();
        let memory_cost = memory_cost(instruction, &self.state);
        let memory_gas = memory_gas(memory_cost);
        let gas_cost = gas_cost(instruction, &self.state);
        let gas_stipend = gas_stipend(instruction, &self.state);
        let gas_refund = gas_refund(instruction, &self.state);

        let all_gas_cost = memory_gas + self.state.used_gas + gas_cost - gas_stipend;
        if self.state.context.gas_limit < all_gas_cost {
            self.status = MachineStatus::ExitedErr(MachineError::EmptyGas);
            return Ok(());
        }

        let after_gas = self.state.context.gas_limit - all_gas_cost;

        match extra_check_opcode(instruction, &self.state, gas_stipend, after_gas) {
            Ok(()) => (),
            Err(EvalError::Machine(error)) => {
                self.status = MachineStatus::ExitedErr(error);
                return Ok(());
            },
            Err(EvalError::Require(error)) => {
                return Err(error);
            },
        }

        let instruction = self.pc.read().unwrap();
        let result = run_opcode((instruction, position),
                                &mut self.state, gas_stipend, after_gas);

        self.state.used_gas = self.state.used_gas + gas_cost - gas_stipend;
        self.state.memory_cost = memory_cost;
        self.state.refunded_gas = self.state.refunded_gas + gas_refund;

        match result {
            None => Ok(()),
            Some(Control::Jump(dest)) => {
                self.pc.jump(dest.into()).unwrap();
                Ok(())
            },
            Some(Control::InvokeCall(context, (from, len))) => {
                self.status = MachineStatus::InvokeCall(context, (from, len));
                Ok(())
            },
            Some(Control::InvokeCreate(context)) => {
                self.status = MachineStatus::InvokeCreate(context);
                Ok(())
            },
            Some(Control::Stop) => {
                self.status = MachineStatus::ExitedOk;
                Ok(())
            },
        }
    }

    /// Get the runtime state.
    pub fn state(&self) -> &State<M> {
        &self.state
    }

    /// Get the current runtime status.
    pub fn status(&self) -> MachineStatus {
        self.status.clone()
    }
}
<|endoftext|>


<commit_before>//! The Rust Prelude.
//!
//! Rust comes with a variety of things in its standard library. However, if
//! you had to manually import every single thing that you used, it would be
//! very verbose. But importing a lot of things that a program never uses isn't
//! good either. A balance needs to be struck.
//!
//! The *prelude* is the list of things that Rust automatically imports into
//! every Rust program. It's kept as small as possible, and is focused on
//! things, particularly traits, which are used in almost every single Rust
//! program.
//!
//! # Other preludes
//!
//! Preludes can be seen as a pattern to make using multiple types more
//! convenient. As such, you'll find other preludes in the standard library,
//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may
//! also define their own preludes.
//!
//! [`std::io::prelude`]: crate::io::prelude
//!
//! The difference between 'the prelude' and these other preludes is that they
//! are not automatically `use`'d, and must be imported manually. This is still
//! easier than importing all of their constituent components.
//!
//! # Prelude contents
//!
//! The current version of the prelude (version 1) lives in
//! [`std::prelude::v1`], and re-exports the following:
//!
//! * [std::marker]::{[Copy], [Send], [Sized], [Sync], [Unpin]},
//!   marker traits that indicate fundamental properties of types.
//! * [std::ops]::{[Drop], [Fn], [FnMut], [FnOnce]}, various
//!   operations for both destructors and overloading `()`.
//! * [std::mem]::[drop][mem::drop], a convenience function for explicitly
//!   dropping a value.
//! * [std::boxed]::[Box], a way to allocate values on the heap.
//! * [std::borrow]::[ToOwned], the conversion trait that defines
//!   [`to_owned`], the generic method for creating an owned type from a
//!   borrowed type.
//! * [std::clone]::[Clone], the ubiquitous trait that defines
//!   [`clone`][Clone::clone], the method for producing a copy of a value.
//! * [std::cmp]::{[PartialEq], [PartialOrd], [Eq], [Ord]}, the
//!   comparison traits, which implement the comparison operators and are often
//!   seen in trait bounds.
//! * [std::convert]::{[AsRef], [AsMut], [Into], [From]}, generic
//!   conversions, used by savvy API authors to create overloaded methods.
//! * [std::default]::[Default], types that have default values.
//! * [std::iter]::{[Iterator], [Extend], [IntoIterator], [DoubleEndedIterator], [ExactSizeIterator]},
//!   iterators of various
//!   kinds.
//! * [std::option]::[Option]::{[self][Option], [Some], [None]}, a
//!   type which expresses the presence or absence of a value. This type is so
//!   commonly used, its variants are also exported.
//! * [std::result]::[Result]::{[self][Result], [Ok], [Err]}, a type
//!   for functions that may succeed or fail. Like [`Option`], its variants are
//!   exported as well.
//! * [std::string]::{[String], [ToString]}, heap-allocated strings.
//! * [std::vec]::[Vec], a growable, heap-allocated vector.
//!
//! [mem::drop]: crate::mem::drop
//! [std::borrow]: crate::borrow
//! [std::boxed]: crate::boxed
//! [std::clone]: crate::clone
//! [std::cmp]: crate::cmp
//! [std::convert]: crate::convert
//! [std::default]: crate::default
//! [std::iter]: crate::iter
//! [std::marker]: crate::marker
//! [std::mem]: crate::mem
//! [std::ops]: crate::ops
//! [std::option]: crate::option
//! [`std::prelude::v1`]: v1
//! [std::result]: crate::result
//! [std::slice]: crate::slice
//! [std::string]: crate::string
//! [std::vec]: mod@crate::vec
//! [`to_owned`]: crate::borrow::ToOwned::to_owned
//! [book-closures]: ../../book/ch13-01-closures.html
//! [book-dtor]: ../../book/ch15-03-drop.html
//! [book-enums]: ../../book/ch06-01-defining-an-enum.html
//! [book-iter]: ../../book/ch13-02-iterators.html

#![stable(feature = "rust1", since = "1.0.0")]

pub mod v1;
<commit_msg>Change back prelude headline<commit_after>//! # The Rust Prelude
//!
//! Rust comes with a variety of things in its standard library. However, if
//! you had to manually import every single thing that you used, it would be
//! very verbose. But importing a lot of things that a program never uses isn't
//! good either. A balance needs to be struck.
//!
//! The *prelude* is the list of things that Rust automatically imports into
//! every Rust program. It's kept as small as possible, and is focused on
//! things, particularly traits, which are used in almost every single Rust
//! program.
//!
//! # Other preludes
//!
//! Preludes can be seen as a pattern to make using multiple types more
//! convenient. As such, you'll find other preludes in the standard library,
//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may
//! also define their own preludes.
//!
//! [`std::io::prelude`]: crate::io::prelude
//!
//! The difference between 'the prelude' and these other preludes is that they
//! are not automatically `use`'d, and must be imported manually. This is still
//! easier than importing all of their constituent components.
//!
//! # Prelude contents
//!
//! The current version of the prelude (version 1) lives in
//! [`std::prelude::v1`], and re-exports the following:
//!
//! * [std::marker]::{[Copy], [Send], [Sized], [Sync], [Unpin]},
//!   marker traits that indicate fundamental properties of types.
//! * [std::ops]::{[Drop], [Fn], [FnMut], [FnOnce]}, various
//!   operations for both destructors and overloading `()`.
//! * [std::mem]::[drop][mem::drop], a convenience function for explicitly
//!   dropping a value.
//! * [std::boxed]::[Box], a way to allocate values on the heap.
//! * [std::borrow]::[ToOwned], the conversion trait that defines
//!   [`to_owned`], the generic method for creating an owned type from a
//!   borrowed type.
//! * [std::clone]::[Clone], the ubiquitous trait that defines
//!   [`clone`][Clone::clone], the method for producing a copy of a value.
//! * [std::cmp]::{[PartialEq], [PartialOrd], [Eq], [Ord]}, the
//!   comparison traits, which implement the comparison operators and are often
//!   seen in trait bounds.
//! * [std::convert]::{[AsRef], [AsMut], [Into], [From]}, generic
//!   conversions, used by savvy API authors to create overloaded methods.
//! * [std::default]::[Default], types that have default values.
//! * [std::iter]::{[Iterator], [Extend], [IntoIterator], [DoubleEndedIterator], [ExactSizeIterator]},
//!   iterators of various
//!   kinds.
//! * [std::option]::[Option]::{[self][Option], [Some], [None]}, a
//!   type which expresses the presence or absence of a value. This type is so
//!   commonly used, its variants are also exported.
//! * [std::result]::[Result]::{[self][Result], [Ok], [Err]}, a type
//!   for functions that may succeed or fail. Like [`Option`], its variants are
//!   exported as well.
//! * [std::string]::{[String], [ToString]}, heap-allocated strings.
//! * [std::vec]::[Vec], a growable, heap-allocated vector.
//!
//! [mem::drop]: crate::mem::drop
//! [std::borrow]: crate::borrow
//! [std::boxed]: crate::boxed
//! [std::clone]: crate::clone
//! [std::cmp]: crate::cmp
//! [std::convert]: crate::convert
//! [std::default]: crate::default
//! [std::iter]: crate::iter
//! [std::marker]: crate::marker
//! [std::mem]: crate::mem
//! [std::ops]: crate::ops
//! [std::option]: crate::option
//! [`std::prelude::v1`]: v1
//! [std::result]: crate::result
//! [std::slice]: crate::slice
//! [std::string]: crate::string
//! [std::vec]: mod@crate::vec
//! [`to_owned`]: crate::borrow::ToOwned::to_owned
//! [book-closures]: ../../book/ch13-01-closures.html
//! [book-dtor]: ../../book/ch15-03-drop.html
//! [book-enums]: ../../book/ch06-01-defining-an-enum.html
//! [book-iter]: ../../book/ch13-02-iterators.html

#![stable(feature = "rust1", since = "1.0.0")]

pub mod v1;
<|endoftext|>


<commit_before>#![feature(test)]

use compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        let s: String = name.to_owned();
        config.filter = Some(s)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps -Dwarnings -Zui-testing",
        host_libs().display()
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    // clean rmeta data, otherwise "cargo check; cargo test" fails (#2896)
    cfg.clean_rmeta();
    compiletest::run_tests(&cfg);
}

#[allow(clippy::identity_conversion)]
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<commit_msg>compiletest: Disambiguate extern crate deps shared with the compiler<commit_after>#![feature(test)]

use compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        let s: String = name.to_owned();
        config.filter = Some(s)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }

    // When we'll want to use `extern crate ..` for a dependency that is used
    // both by the crate and the compiler itself, we can't simply pass -L flags
    // as we'll get a duplicate matching versions. Instead, disambiguate with
    // `--extern dep=path`.
    // See https://github.com/rust-lang/rust-clippy/issues/4015.
    let needs_disambiguation = ["serde"];
    // This assumes that deps are compiled (they are for Cargo integration tests).
    let deps = std::fs::read_dir(host_libs().join("deps")).unwrap();
    let disambiguated = deps
        .filter_map(|dep| {
            let path = dep.ok()?.path();
            let name = path.file_name()?.to_string_lossy();
            // NOTE: This only handles a single dep
            // https://github.com/laumann/compiletest-rs/issues/101
            needs_disambiguation
                .iter()
                .find(|dep| name.starts_with(&format!("lib{}-", dep)))
                .map(|dep| format!("--extern {}={}", dep, path.display()))
        })
        .collect::<Vec<_>>();

    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps -Dwarnings -Zui-testing {1}",
        host_libs().display(),
        disambiguated.join(" ")
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    // clean rmeta data, otherwise "cargo check; cargo test" fails (#2896)
    cfg.clean_rmeta();
    compiletest::run_tests(&cfg);
}

#[allow(clippy::identity_conversion)]
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<|endoftext|>


<commit_before>#![feature(test)] // compiletest_rs requires this attribute

use compiletest_rs as compiletest;
use compiletest_rs::common::Mode as TestMode;

use std::env::{self, set_var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

mod cargo;

fn host_lib() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        cargo::CARGO_TARGET_DIR.join(env!("PROFILE"))
    }
}

fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        cargo::TARGET_LIB.join("clippy-driver")
    }
}

// When we'll want to use `extern crate ..` for a dependency that is used
// both by the crate and the compiler itself, we can't simply pass -L flags
// as we'll get a duplicate matching versions. Instead, disambiguate with
// `--extern dep=path`.
// See https://github.com/rust-lang/rust-clippy/issues/4015.
//
// FIXME: We cannot use `cargo build --message-format=json` to resolve to dependency files.
//        Because it would force-rebuild if the options passed to `build` command is not the same
//        as what we manually pass to `cargo` invocation
fn third_party_crates() -> String {
    use std::collections::HashMap;
    static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints", "syn", "quote"];
    let dep_dir = cargo::TARGET_LIB.join("deps");
    let mut crates: HashMap<&str, PathBuf> = HashMap::with_capacity(CRATES.len());
    for entry in fs::read_dir(dep_dir).unwrap() {
        let path = match entry {
            Ok(entry) => entry.path(),
            Err(_) => continue,
        };
        if let Some(name) = path.file_name().and_then(OsStr::to_str) {
            for dep in CRATES {
                if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") {
                    crates.entry(dep).or_insert(path);
                    break;
                }
            }
        }
    }

    let v: Vec<_> = crates
        .into_iter()
        .map(|(dep, path)| format!("--extern {}={}", dep, path.display()))
        .collect();
    v.join(" ")
}

fn default_config() -> compiletest::Config {
    let mut config = compiletest::Config::default();

    if let Ok(name) = env::var("TESTNAME") {
        config.filter = Some(name);
    }

    if let Some(path) = option_env!("RUSTC_LIB_PATH") {
        let path = PathBuf::from(path);
        config.run_lib_path = path.clone();
        config.compile_lib_path = path;
    }

    config.target_rustcflags = Some(format!(
        "-L {0} -L {1} -Dwarnings -Zui-testing {2}",
        host_lib().join("deps").display(),
        cargo::TARGET_LIB.join("deps").display(),
        third_party_crates(),
    ));

    config.build_base = if cargo::is_rustc_test_suite() {
        // This make the stderr files go to clippy OUT_DIR on rustc repo build dir
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        host_lib().join("test_build_base")
    };
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(cfg: &mut compiletest::Config) {
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui");
    compiletest::run_tests(&cfg);
}

fn run_ui_toml(config: &mut compiletest::Config) {
    fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);
        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }
            let dir_path = dir.path();
            set_var("CARGO_MANIFEST_DIR", &dir_path);
            for file in fs::read_dir(&dir_path)? {
                let file = file?;
                let file_path = file.path();
                if file.file_type()?.is_dir() {
                    continue;
                }
                if file_path.extension() != Some(OsStr::new("rs")) {
                    continue;
                }
                let paths = compiletest::common::TestPaths {
                    file: file_path,
                    base: config.src_base.clone(),
                    relative_dir: dir_path.file_name().unwrap().into(),
                };
                let test_name = compiletest::make_test_name(&config, &paths);
                let index = tests
                    .iter()
                    .position(|test| test.desc.name == test_name)
                    .expect("The test should be in there");
                result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
            }
        }
        Ok(result)
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();

    let tests = compiletest::make_tests(&config);

    let res = run_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn run_ui_cargo(config: &mut compiletest::Config) {
    fn run_tests(
        config: &compiletest::Config,
        filter: &Option<String>,
        mut tests: Vec<tester::TestDescAndFn>,
    ) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);

        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }

            // Use the filter if provided
            let dir_path = dir.path();
            match &filter {
                Some(name) if !dir_path.ends_with(name) => continue,
                _ => {},
            }

            for case in fs::read_dir(&dir_path)? {
                let case = case?;
                if !case.file_type()?.is_dir() {
                    continue;
                }

                let src_path = case.path().join("src");
                env::set_current_dir(&src_path)?;

                for file in fs::read_dir(&src_path)? {
                    let file = file?;
                    if file.file_type()?.is_dir() {
                        continue;
                    }

                    // Search for the main file to avoid running a test for each file in the project
                    let file_path = file.path();
                    match file_path.file_name().and_then(OsStr::to_str) {
                        Some("main.rs") => {},
                        _ => continue,
                    }

                    let paths = compiletest::common::TestPaths {
                        file: file_path,
                        base: config.src_base.clone(),
                        relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
                    };
                    let test_name = compiletest::make_test_name(&config, &paths);
                    let index = tests
                        .iter()
                        .position(|test| test.desc.name == test_name)
                        .expect("The test should be in there");
                    result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
                }
            }
        }
        Ok(result)
    }

    if cargo::is_rustc_test_suite() {
        return;
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();

    let tests = compiletest::make_tests(&config);

    let current_dir = env::current_dir().unwrap();
    let filter = env::var("TESTNAME").ok();
    let res = run_tests(&config, &filter, tests);
    env::set_current_dir(current_dir).unwrap();

    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    let mut config = default_config();
    run_mode(&mut config);
    run_ui_toml(&mut config);
    run_ui_cargo(&mut config);
}
<commit_msg>Auto merge of #5662 - ebroto:cargo_tests_invalid_crate, r=flip1995<commit_after>#![feature(test)] // compiletest_rs requires this attribute

use compiletest_rs as compiletest;
use compiletest_rs::common::Mode as TestMode;

use std::env::{self, set_var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

mod cargo;

fn host_lib() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        cargo::CARGO_TARGET_DIR.join(env!("PROFILE"))
    }
}

fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        cargo::TARGET_LIB.join("clippy-driver")
    }
}

// When we'll want to use `extern crate ..` for a dependency that is used
// both by the crate and the compiler itself, we can't simply pass -L flags
// as we'll get a duplicate matching versions. Instead, disambiguate with
// `--extern dep=path`.
// See https://github.com/rust-lang/rust-clippy/issues/4015.
//
// FIXME: We cannot use `cargo build --message-format=json` to resolve to dependency files.
//        Because it would force-rebuild if the options passed to `build` command is not the same
//        as what we manually pass to `cargo` invocation
fn third_party_crates() -> String {
    use std::collections::HashMap;
    static CRATES: &[&str] = &["serde", "serde_derive", "regex", "clippy_lints", "syn", "quote"];
    let dep_dir = cargo::TARGET_LIB.join("deps");
    let mut crates: HashMap<&str, PathBuf> = HashMap::with_capacity(CRATES.len());
    for entry in fs::read_dir(dep_dir).unwrap() {
        let path = match entry {
            Ok(entry) => entry.path(),
            Err(_) => continue,
        };
        if let Some(name) = path.file_name().and_then(OsStr::to_str) {
            for dep in CRATES {
                if name.starts_with(&format!("lib{}-", dep)) && name.ends_with(".rlib") {
                    crates.entry(dep).or_insert(path);
                    break;
                }
            }
        }
    }

    let v: Vec<_> = crates
        .into_iter()
        .map(|(dep, path)| format!("--extern {}={}", dep, path.display()))
        .collect();
    v.join(" ")
}

fn default_config() -> compiletest::Config {
    let mut config = compiletest::Config::default();

    if let Ok(name) = env::var("TESTNAME") {
        config.filter = Some(name);
    }

    if let Some(path) = option_env!("RUSTC_LIB_PATH") {
        let path = PathBuf::from(path);
        config.run_lib_path = path.clone();
        config.compile_lib_path = path;
    }

    config.target_rustcflags = Some(format!(
        "-L {0} -L {1} -Dwarnings -Zui-testing {2}",
        host_lib().join("deps").display(),
        cargo::TARGET_LIB.join("deps").display(),
        third_party_crates(),
    ));

    config.build_base = if cargo::is_rustc_test_suite() {
        // This make the stderr files go to clippy OUT_DIR on rustc repo build dir
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        host_lib().join("test_build_base")
    };
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(cfg: &mut compiletest::Config) {
    cfg.mode = TestMode::Ui;
    cfg.src_base = Path::new("tests").join("ui");
    compiletest::run_tests(&cfg);
}

fn run_ui_toml(config: &mut compiletest::Config) {
    fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);
        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }
            let dir_path = dir.path();
            set_var("CARGO_MANIFEST_DIR", &dir_path);
            for file in fs::read_dir(&dir_path)? {
                let file = file?;
                let file_path = file.path();
                if file.file_type()?.is_dir() {
                    continue;
                }
                if file_path.extension() != Some(OsStr::new("rs")) {
                    continue;
                }
                let paths = compiletest::common::TestPaths {
                    file: file_path,
                    base: config.src_base.clone(),
                    relative_dir: dir_path.file_name().unwrap().into(),
                };
                let test_name = compiletest::make_test_name(&config, &paths);
                let index = tests
                    .iter()
                    .position(|test| test.desc.name == test_name)
                    .expect("The test should be in there");
                result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
            }
        }
        Ok(result)
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();

    let tests = compiletest::make_tests(&config);

    let res = run_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn run_ui_cargo(config: &mut compiletest::Config) {
    fn run_tests(
        config: &compiletest::Config,
        filter: &Option<String>,
        mut tests: Vec<tester::TestDescAndFn>,
    ) -> Result<bool, io::Error> {
        let mut result = true;
        let opts = compiletest::test_opts(config);

        for dir in fs::read_dir(&config.src_base)? {
            let dir = dir?;
            if !dir.file_type()?.is_dir() {
                continue;
            }

            // Use the filter if provided
            let dir_path = dir.path();
            match &filter {
                Some(name) if !dir_path.ends_with(name) => continue,
                _ => {},
            }

            for case in fs::read_dir(&dir_path)? {
                let case = case?;
                if !case.file_type()?.is_dir() {
                    continue;
                }

                let src_path = case.path().join("src");

                // When switching between branches, if the previous branch had a test
                // that the current branch does not have, the directory is not removed
                // because an ignored Cargo.lock file exists.
                if !src_path.exists() {
                    continue;
                }

                env::set_current_dir(&src_path)?;
                for file in fs::read_dir(&src_path)? {
                    let file = file?;
                    if file.file_type()?.is_dir() {
                        continue;
                    }

                    // Search for the main file to avoid running a test for each file in the project
                    let file_path = file.path();
                    match file_path.file_name().and_then(OsStr::to_str) {
                        Some("main.rs") => {},
                        _ => continue,
                    }

                    let paths = compiletest::common::TestPaths {
                        file: file_path,
                        base: config.src_base.clone(),
                        relative_dir: src_path.strip_prefix(&config.src_base).unwrap().into(),
                    };
                    let test_name = compiletest::make_test_name(&config, &paths);
                    let index = tests
                        .iter()
                        .position(|test| test.desc.name == test_name)
                        .expect("The test should be in there");
                    result &= tester::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
                }
            }
        }
        Ok(result)
    }

    if cargo::is_rustc_test_suite() {
        return;
    }

    config.mode = TestMode::Ui;
    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();

    let tests = compiletest::make_tests(&config);

    let current_dir = env::current_dir().unwrap();
    let filter = env::var("TESTNAME").ok();
    let res = run_tests(&config, &filter, tests);
    env::set_current_dir(current_dir).unwrap();

    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            panic!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    let mut config = default_config();
    run_mode(&mut config);
    run_ui_toml(&mut config);
    run_ui_cargo(&mut config);
}
<|endoftext|>


<commit_before>#![feature(test)]

use compiletest_rs as compiletest;
use libtest::TestDescAndFn;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        let s: String = name.to_owned();
        config.filter = Some(s)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps -Dwarnings -Zui-testing",
        host_libs().display()
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    // clean rmeta data, otherwise "cargo check; cargo test" fails (#2896)
    cfg.clean_rmeta();
    compiletest::run_tests(&cfg);
}

#[warn(clippy::identity_conversion)]
fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir_path = dir.unwrap().path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name.to_string() == test_name.to_string())
                .expect("The test should be in there");
            let opts = libtest::TestOpts {
                list: opts.list,
                filter: opts.filter.clone(),
                filter_exact: opts.filter_exact,
                exclude_should_panic: Default::default(),
                run_ignored: libtest::RunIgnored::No,
                run_tests: opts.run_tests,
                bench_benchmarks: opts.bench_benchmarks,
                logfile: opts.logfile.clone(),
                nocapture: opts.nocapture,
                color: libtest::ColorConfig::AutoColor,
                format: libtest::OutputFormat::Pretty,
                test_threads: opts.test_threads,
                skip: opts.skip.clone(),
                options: libtest::Options::new(),
            };
            result &= libtest::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let tests = tests
        .into_iter()
        .map(|test| {
            libtest::TestDescAndFn {
                desc: libtest::TestDesc {
                    name: libtest::TestName::DynTestName(test.desc.name.to_string()),
                    ignore: test.desc.ignore,
                    allow_fail: test.desc.allow_fail,
                    should_panic: libtest::ShouldPanic::No,
                },
                // oli obk giving up
                testfn: unsafe { std::mem::transmute(test.testfn) },
            }
        })
        .collect();

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<commit_msg>Revert tests/compile-test.rs to 61aa5c957c219abe1fb2d1b5e51db8b365b4f565<commit_after>#![feature(test)]

use compiletest_rs as compiletest;
extern crate test;

use std::env::{set_var, var};
use std::ffi::OsStr;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};

fn clippy_driver_path() -> PathBuf {
    if let Some(path) = option_env!("CLIPPY_DRIVER_PATH") {
        PathBuf::from(path)
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/clippy-driver"))
    }
}

fn host_libs() -> PathBuf {
    if let Some(path) = option_env!("HOST_LIBS") {
        PathBuf::from(path)
    } else {
        Path::new("target").join(env!("PROFILE"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn config(mode: &str, dir: PathBuf) -> compiletest::Config {
    let mut config = compiletest::Config::default();

    let cfg_mode = mode.parse().expect("Invalid mode");
    if let Ok(name) = var::<&str>("TESTNAME") {
        let s: String = name.to_owned();
        config.filter = Some(s)
    }

    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.target_rustcflags = Some(format!(
        "-L {0} -L {0}/deps -Dwarnings -Zui-testing",
        host_libs().display()
    ));

    config.mode = cfg_mode;
    config.build_base = if rustc_test_suite().is_some() {
        // we don't need access to the stderr files on travis
        let mut path = PathBuf::from(env!("OUT_DIR"));
        path.push("test_build_base");
        path
    } else {
        let mut path = std::env::current_dir().unwrap();
        path.push("target/debug/test_build_base");
        path
    };
    config.src_base = dir;
    config.rustc_path = clippy_driver_path();
    config
}

fn run_mode(mode: &str, dir: PathBuf) {
    let cfg = config(mode, dir);
    // clean rmeta data, otherwise "cargo check; cargo test" fails (#2896)
    cfg.clean_rmeta();
    compiletest::run_tests(&cfg);
}

fn run_ui_toml_tests(config: &compiletest::Config, mut tests: Vec<test::TestDescAndFn>) -> Result<bool, io::Error> {
    let mut result = true;
    let opts = compiletest::test_opts(config);
    for dir in fs::read_dir(&config.src_base)? {
        let dir = dir?;
        if !dir.file_type()?.is_dir() {
            continue;
        }
        let dir_path = dir.path();
        set_var("CARGO_MANIFEST_DIR", &dir_path);
        for file in fs::read_dir(&dir_path)? {
            let file = file?;
            let file_path = file.path();
            if !file.file_type()?.is_file() {
                continue;
            }
            if file_path.extension() != Some(OsStr::new("rs")) {
                continue;
            }
            let paths = compiletest::common::TestPaths {
                file: file_path,
                base: config.src_base.clone(),
                relative_dir: dir_path.file_name().unwrap().into(),
            };
            let test_name = compiletest::make_test_name(&config, &paths);
            let index = tests
                .iter()
                .position(|test| test.desc.name == test_name)
                .expect("The test should be in there");
            result &= test::run_tests_console(&opts, vec![tests.swap_remove(index)])?;
        }
    }
    Ok(result)
}

fn run_ui_toml() {
    let path = PathBuf::from("tests/ui-toml").canonicalize().unwrap();
    let config = config("ui", path);
    let tests = compiletest::make_tests(&config);

    let res = run_ui_toml_tests(&config, tests);
    match res {
        Ok(true) => {},
        Ok(false) => panic!("Some tests failed"),
        Err(e) => {
            println!("I/O failure during tests: {:?}", e);
        },
    }
}

fn prepare_env() {
    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
    set_var("CLIPPY_TESTS", "true");
    //set_var("RUST_BACKTRACE", "0");
}

#[test]
fn compile_test() {
    prepare_env();
    run_mode("ui", "tests/ui".into());
    run_ui_toml();
}
<|endoftext|>


<commit_before>use nom::{IResult, le_u32, le_u16};
use block::RawBlock;
use options::{parse_options, Options};

pub const TY: u32 = 0x00000001;

//     0                   1                   2                   3
//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//    +---------------------------------------------------------------+
//  0 |                    Block Type = 0x00000001                    |
//    +---------------------------------------------------------------+
//  4 |                      Block Total Length                       |
//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//  8 |           LinkType            |           Reserved            |
//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// 12 |                            SnapLen                            |
//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// 16 /                                                               /
//    /                      Options (variable)                       /
//    /                                                               /
//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//    |                      Block Total Length                       |
//    +---------------------------------------------------------------+

named!(interface_description_body<&[u8], InterfaceDescription>,
       do_parse!(
              link_type: le_u16
           >> reserved:  le_u16
           >> snap_len:  le_u32
           >> options:   opt!(parse_options)
           >> (
               InterfaceDescription {
                   ty: TY,
                   block_length: 0,
                   link_type: link_type,
                   reserved: reserved,
                   snap_len: snap_len,
                   options: options,
                   check_length: 0,
               }

           )
       )
);

#[derive(Debug)]
pub struct InterfaceDescription<'a> {
    pub ty: u32,
    pub block_length: u32,
    pub link_type: u16,
    pub reserved: u16,
    pub snap_len: u32,
    // sduquette: Make options a Vec<Opt> instead?
    pub options: Option<Options<'a>>,
    pub check_length: u32,
}

pub fn parse(blk: RawBlock) -> IResult<&[u8], InterfaceDescription> {
    match interface_description_body(blk.body) {
        // FIXME(richo) Actually do something with the leftover bytes
        Ok((left, mut block)) => {
            block.block_length = blk.block_length;
            block.check_length = blk.check_length;
            Ok((left, block))
        },
        other => other
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use block::parse_block;
    use blocks::constants::{BlockType, LinkType, LinkTypeOptions};

    #[test]
    fn test_parse_interface_description_header() {
        let input = b"\x01\x00\x00\x00\x88\x00\x00\x00\x01\x00\x00\x00\x00\x00\x04\x00\x02\x00\x32\
\x00\x5C\x44\x65\x76\x69\x63\x65\x5C\x4E\x50\x46\x5F\x7B\x45\x34\x43\x31\x34\x31\x32\x38\
\x2D\x34\x31\x46\x35\x2D\x34\x32\x43\x35\x2D\x39\x41\x35\x35\x2D\x44\x36\x32\x32\x33\x42\
\x30\x32\x43\x32\x42\x31\x7D\x00\x00\x09\x00\x01\x00\x06\x00\x00\x00\x0C\x00\x2B\x00\x33\
\x32\x2D\x62\x69\x74\x20\x57\x69\x6E\x64\x6F\x77\x73\x20\x37\x20\x53\x65\x72\x76\x69\x63\
\x65\x20\x50\x61\x63\x6B\x20\x31\x2C\x20\x62\x75\x69\x6C\x64\x20\x37\x36\x30\x31\x00\x00\
\x00\x00\x00\x88\x00\x00\x00";

        match parse_block(input) {
            Ok((_, block)) => {
                match parse(block) {
                    Ok((left, interface_description_header)) => {
                        assert_eq!(left, []);
                        assert_eq!(interface_description_header.ty, BlockType::InterfaceDescription as u32);
                        assert_eq!(interface_description_header.block_length, 136);
                        assert_eq!(interface_description_header.link_type, LinkType::ETHERNET as u16);
                        assert_eq!(interface_description_header.snap_len, 0x40000);
                        assert_eq!(interface_description_header.check_length, 136);

                        if let Some(opts) = interface_description_header.options {
                            assert_eq!(opts.options.len(), 4);

                            let o = &opts.options[0];
                            assert_eq!(o.code, LinkTypeOptions::Name as u16);
                            assert_eq!(o.length, 0x32);
                            assert_eq!(o.value[..], b"\\Device\\NPF_{E4C14128-41F5-42C5-9A55-D6223B02C2B1}"[..]);

                            let o = &opts.options[1];
                            assert_eq!(o.code, LinkTypeOptions::TsResol as u16);
                            assert_eq!(o.length, 1);
                            assert_eq!(o.value[..], b"\x06"[..]);

                            let o = &opts.options[2];
                            assert_eq!(o.code, LinkTypeOptions::OS as u16);
                            assert_eq!(o.value[..], b"32-bit Windows 7 Service Pack 1, build 7601"[..]);

                        } else {
                            panic!("expected options.");
                        }
                    },
                    err => {
                        panic!("failed to parse interface_description block: {:?}", err);
                    }
                }
            },
            Err(nom::Err::Incomplete(e)) => {
                println!("Incomplete: {:?}", e);
                assert!(false, "failed to parse interface_description header");
            }
            Err(nom::Err::Error(e)) => {
                println!("Error: {:?}", e);
                assert!(false, "failed to parse interface_description header");
            }
            Err(nom::Err::Failure(f)) => {
                println!("Failure: {:?}", f);
                assert!(false, "failed to parse interface_description header");
            }
        }
    }
}
<commit_msg>removed unneccesary type annotation<commit_after>use nom::{IResult, le_u32, le_u16};
use block::RawBlock;
use options::{parse_options, Options};

pub const TY: u32 = 0x00000001;

//     0                   1                   2                   3
//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//    +---------------------------------------------------------------+
//  0 |                    Block Type = 0x00000001                    |
//    +---------------------------------------------------------------+
//  4 |                      Block Total Length                       |
//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//  8 |           LinkType            |           Reserved            |
//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// 12 |                            SnapLen                            |
//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// 16 /                                                               /
//    /                      Options (variable)                       /
//    /                                                               /
//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//    |                      Block Total Length                       |
//    +---------------------------------------------------------------+

named!(interface_description_body<InterfaceDescription>,
       do_parse!(
              link_type: le_u16
           >> reserved:  le_u16
           >> snap_len:  le_u32
           >> options:   opt!(parse_options)
           >> (
               InterfaceDescription {
                   ty: TY,
                   block_length: 0,
                   link_type: link_type,
                   reserved: reserved,
                   snap_len: snap_len,
                   options: options,
                   check_length: 0,
               }

           )
       )
);

#[derive(Debug)]
pub struct InterfaceDescription<'a> {
    pub ty: u32,
    pub block_length: u32,
    pub link_type: u16,
    pub reserved: u16,
    pub snap_len: u32,
    // sduquette: Make options a Vec<Opt> instead?
    pub options: Option<Options<'a>>,
    pub check_length: u32,
}

pub fn parse(blk: RawBlock) -> IResult<&[u8], InterfaceDescription> {
    match interface_description_body(blk.body) {
        // FIXME(richo) Actually do something with the leftover bytes
        Ok((left, mut block)) => {
            block.block_length = blk.block_length;
            block.check_length = blk.check_length;
            Ok((left, block))
        },
        other => other
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use block::parse_block;
    use blocks::constants::{BlockType, LinkType, LinkTypeOptions};

    #[test]
    fn test_parse_interface_description_header() {
        let input = b"\x01\x00\x00\x00\x88\x00\x00\x00\x01\x00\x00\x00\x00\x00\x04\x00\x02\x00\x32\
\x00\x5C\x44\x65\x76\x69\x63\x65\x5C\x4E\x50\x46\x5F\x7B\x45\x34\x43\x31\x34\x31\x32\x38\
\x2D\x34\x31\x46\x35\x2D\x34\x32\x43\x35\x2D\x39\x41\x35\x35\x2D\x44\x36\x32\x32\x33\x42\
\x30\x32\x43\x32\x42\x31\x7D\x00\x00\x09\x00\x01\x00\x06\x00\x00\x00\x0C\x00\x2B\x00\x33\
\x32\x2D\x62\x69\x74\x20\x57\x69\x6E\x64\x6F\x77\x73\x20\x37\x20\x53\x65\x72\x76\x69\x63\
\x65\x20\x50\x61\x63\x6B\x20\x31\x2C\x20\x62\x75\x69\x6C\x64\x20\x37\x36\x30\x31\x00\x00\
\x00\x00\x00\x88\x00\x00\x00";

        match parse_block(input) {
            Ok((_, block)) => {
                match parse(block) {
                    Ok((left, interface_description_header)) => {
                        assert_eq!(left, []);
                        assert_eq!(interface_description_header.ty, BlockType::InterfaceDescription as u32);
                        assert_eq!(interface_description_header.block_length, 136);
                        assert_eq!(interface_description_header.link_type, LinkType::ETHERNET as u16);
                        assert_eq!(interface_description_header.snap_len, 0x40000);
                        assert_eq!(interface_description_header.check_length, 136);

                        if let Some(opts) = interface_description_header.options {
                            assert_eq!(opts.options.len(), 4);

                            let o = &opts.options[0];
                            assert_eq!(o.code, LinkTypeOptions::Name as u16);
                            assert_eq!(o.length, 0x32);
                            assert_eq!(o.value[..], b"\\Device\\NPF_{E4C14128-41F5-42C5-9A55-D6223B02C2B1}"[..]);

                            let o = &opts.options[1];
                            assert_eq!(o.code, LinkTypeOptions::TsResol as u16);
                            assert_eq!(o.length, 1);
                            assert_eq!(o.value[..], b"\x06"[..]);

                            let o = &opts.options[2];
                            assert_eq!(o.code, LinkTypeOptions::OS as u16);
                            assert_eq!(o.value[..], b"32-bit Windows 7 Service Pack 1, build 7601"[..]);

                        } else {
                            panic!("expected options.");
                        }
                    },
                    err => {
                        panic!("failed to parse interface_description block: {:?}", err);
                    }
                }
            },
            Err(nom::Err::Incomplete(e)) => {
                println!("Incomplete: {:?}", e);
                assert!(false, "failed to parse interface_description header");
            }
            Err(nom::Err::Error(e)) => {
                println!("Error: {:?}", e);
                assert!(false, "failed to parse interface_description header");
            }
            Err(nom::Err::Failure(f)) => {
                println!("Failure: {:?}", f);
                assert!(false, "failed to parse interface_description header");
            }
        }
    }
}
<|endoftext|>