<commit_before>#![feature(proc_macro)]

extern crate proc_macro;
extern crate syn;
extern crate quote;

use proc_macro::TokenStream;
use quote::{Tokens, ToTokens};
use std::mem;
use std::str::FromStr;
use syn::{BindingMode, Block, Constness, ExprKind, FnArg, Generics, Ident, ImplItem, Item, ItemKind,
        Mutability, Pat, Path, Ty};

#[proc_macro_attribute]
pub fn inject_mocks(_: TokenStream, token_stream: TokenStream) -> TokenStream {
    let in_string = token_stream.to_string();
    let mut parsed = match syn::parse_item(&in_string) {
        Ok(parsed) => parsed,
        Err(_) => return token_stream,
    };
    inject_item(&mut parsed);
    let mut tokens = Tokens::new();
    parsed.to_tokens(&mut tokens);
    let out_string = tokens.as_str();
    let out_token_stream = TokenStream::from_str(out_string).unwrap();
    out_token_stream
}

fn inject_item(item: &mut Item) {
    match item.node {
        ItemKind::Mod(ref mut items_opt) =>
            inject_mod(items_opt.as_mut()),
        ItemKind::Fn(ref mut decl, _, ref constness, _, ref generics, ref mut block) =>
            inject_static_fn(&item.ident, &mut decl.inputs, constness, generics, block),
        ItemKind::Impl(_, _, ref generics, ref path, ref ty, ref mut items) =>
            inject_impl(generics, path.as_ref(), ty, items),
        //        ItemKind::Trait(ref mut unsafety, ref mut generics, ref mut ty_param_bound, ref mut items) => unimplemented!(),
        _ => (),
    }
}

fn inject_mod(items_opt: Option<&mut Vec<Item>>) {
    if let Some(items) = items_opt {
        for item in items {
            inject_item(item)
        }
    }
}

fn inject_impl(_generics: &Generics, path: Option<&Path>, ty: &Box<Ty>, items: &mut Vec<ImplItem>) {
    println!("PATH\n{:#?}\nTY\n{:#?}\nITEMS\n{:#?}", path, ty, items);
    if path.is_some() {
        return; // no trait support yet
    }
//    if let Ty::Path(None, Path { })

    // impl [<path> for] ty {
    //      <items>
    // }

}

fn inject_static_fn(ident: &Ident, inputs: &mut Vec<FnArg>, constness: &Constness, generics: &Generics, block: &mut Box<Block>) {
    if *constness == Constness::Const {
        return
    }
    let mut fn_name = ident.to_string();
    append_generics(&mut fn_name, generics);
    inject_fn(&fn_name, inputs, block);
}

fn inject_fn(fn_name: &str, inputs: &mut Vec<FnArg>, block: &mut Box<Block>) {
    let original_arg_names = args_to_names(inputs);
    unignore_fn_args(inputs);
    let unignored_arg_names = args_to_names(inputs);
    let header_str = format!(
        r#"{{
            let ({}) = {{
                use mocktopus::*;
                match Mockable::call_mock(&{}, (({}))) {{
                    MockResult::Continue(input) => input,
                    MockResult::Return(result) => return result,
                }}
            }};
        }}"#, original_arg_names, fn_name, unignored_arg_names);
    let header_expr = syn::parse_expr(&header_str).unwrap();
    let header_stmts = match header_expr.node {
        ExprKind::Block(_, block) => block.stmts,
        _ => unreachable!(),
    };
    //    let mut tokens = Tokens::new();
    //    for stmt in &header_stmts {
    //        stmt.to_tokens(&mut tokens);
    //    }
    //    println!("{}", tokens.as_str());
    let mut body_stmts = mem::replace(&mut block.stmts, header_stmts);
    block.stmts.append(&mut body_stmts);
}

fn unignore_fn_args(inputs: &mut Vec<FnArg>) {
    for i in 0..inputs.len() {
        let unignored = match inputs[i] {
            FnArg::Captured(Pat::Wild, ref ty) =>
                FnArg::Captured(
                    Pat::Ident(
                        BindingMode::ByValue(
                            Mutability::Immutable),
                        Ident::from(format!("__mock_unignored_argument_{}__", i)),
                        None),
                    ty.clone()),
            _ => continue,
        };
        inputs[i] = unignored;
    }
}

fn args_to_names(inputs: &Vec<FnArg>) -> String {
    inputs.iter()
        .fold(String::new(), |mut result, input| {
            match *input {
                FnArg::SelfRef(_, _) | FnArg::SelfValue(_) => result.push_str("self"),
                FnArg::Captured(Pat::Wild, _) => result.push_str("_"),
                FnArg::Captured(Pat::Ident(_, ref ident, None), _) => result.push_str(ident.as_ref()),
                _ => panic!("Invalid function input '{:?}'", input),
            };
            result.push_str(", ");
            result
        })
}

fn append_generics(fn_name: &mut String, generics: &Generics) {
    if generics.ty_params.is_empty() {
        return
    }
    fn_name.push_str("::<");
    for ty_param in &generics.ty_params {
        fn_name.push_str(&ty_param.ident.as_ref());
        fn_name.push(',');
    }
    fn_name.push('>');
}
<commit_msg>Add static method injection<commit_after>#![feature(proc_macro)]

extern crate proc_macro;
extern crate syn;
extern crate quote;

use proc_macro::TokenStream;
use quote::{Tokens, ToTokens};
use std::mem;
use std::str::FromStr;
use syn::{BindingMode, Block, Constness, ExprKind, FnArg, Generics, Ident, ImplItem, ImplItemKind, Item, ItemKind,
        MethodSig, Mutability, Pat, Path, Ty};

#[proc_macro_attribute]
pub fn inject_mocks(_: TokenStream, token_stream: TokenStream) -> TokenStream {
    let in_string = token_stream.to_string();
    let mut parsed = match syn::parse_item(&in_string) {
        Ok(parsed) => parsed,
        Err(_) => return token_stream,
    };
    inject_item(&mut parsed);
    let mut tokens = Tokens::new();
    parsed.to_tokens(&mut tokens);
    let out_string = tokens.as_str();
    let out_token_stream = TokenStream::from_str(out_string).unwrap();
    out_token_stream
}

fn inject_item(item: &mut Item) {
    match item.node {
        ItemKind::Mod(ref mut items_opt) =>
            inject_mod(items_opt.as_mut()),
        ItemKind::Fn(ref mut decl, _, ref constness, _, ref generics, ref mut block) =>
            inject_static_fn(&item.ident, &mut decl.inputs, constness, generics, block),
        ItemKind::Impl(_, _, ref generics, ref path, ref ty, ref mut items) =>
            inject_impl(generics, path.as_ref(), ty, items),
        //        ItemKind::Trait(ref mut unsafety, ref mut generics, ref mut ty_param_bound, ref mut items) => unimplemented!(),
        _ => (),
    }
}

fn inject_mod(items_opt: Option<&mut Vec<Item>>) {
    if let Some(items) = items_opt {
        for item in items {
            inject_item(item)
        }
    }
}

fn inject_impl(_generics: &Generics, path: Option<&Path>, _ty: &Box<Ty>, items: &mut Vec<ImplItem>) {
//    println!("PATH\n{:#?}\nTY\n{:#?}\nITEMS\n{:#?}", path, ty, items);
    if path.is_some() {
        return; // no trait support yet
    }
    for item in items {
        if let ImplItemKind::Method(
            MethodSig {
                unsafety: _,
                constness: ref constness_ref,
                abi: _,
                decl: ref mut decl_ref,
                generics: ref generics_ref },
            ref mut block) = item.node {
            match decl_ref.inputs.get(0) { // no non-static methods support yet
                Some(&FnArg::SelfRef(..)) | Some(&FnArg::SelfValue(..)) => continue,
                _ => (),
            };
            let mut full_fn_name = format!("Self::{}", item.ident.as_ref());
            append_generics(&mut full_fn_name, generics_ref);
            inject_fn(&full_fn_name, &mut decl_ref.inputs, constness_ref, block);
        }
    }

//    pub struct MethodSig {
//        pub unsafety: Unsafety,
//        pub constness: Constness,
//        pub abi: Option<Abi>,
//        pub decl: FnDecl,
//        pub generics: Generics,
//    }

//    pub struct ImplItem {
//        pub ident: Ident,
//        pub vis: Visibility,
//        pub defaultness: Defaultness,
//        pub attrs: Vec<Attribute>,
//        pub node: ImplItemKind,
//    }

    // impl [<path> for] ty {
    //      <items>
    // }

}

fn inject_static_fn(ident: &Ident, inputs: &mut Vec<FnArg>, constness: &Constness, generics: &Generics, block: &mut Box<Block>) {
    let mut full_fn_name = ident.to_string();
    append_generics(&mut full_fn_name, generics);
    inject_fn(&full_fn_name, inputs, constness, block);
}

fn inject_fn(full_fn_name: &str, inputs: &mut Vec<FnArg>, constness: &Constness, block: &mut Block) {
    if *constness == Constness::Const {
        return
    }
    let original_arg_names = args_to_names(inputs);
    unignore_fn_args(inputs);
    let unignored_arg_names = args_to_names(inputs);
    let header_str = format!(
        r#"{{
            let ({}) = {{
                use mocktopus::*;
                match Mockable::call_mock(&{}, (({}))) {{
                    MockResult::Continue(input) => input,
                    MockResult::Return(result) => return result,
                }}
            }};
        }}"#, original_arg_names, full_fn_name, unignored_arg_names);
    let header_expr = syn::parse_expr(&header_str).unwrap();
    let header_stmts = match header_expr.node {
        ExprKind::Block(_, block) => block.stmts,
        _ => unreachable!(),
    };
    //    let mut tokens = Tokens::new();
    //    for stmt in &header_stmts {
    //        stmt.to_tokens(&mut tokens);
    //    }
    //    println!("{}", tokens.as_str());
    let mut body_stmts = mem::replace(&mut block.stmts, header_stmts);
    block.stmts.append(&mut body_stmts);
}

fn unignore_fn_args(inputs: &mut Vec<FnArg>) {
    for i in 0..inputs.len() {
        let unignored = match inputs[i] {
            FnArg::Captured(Pat::Wild, ref ty) =>
                FnArg::Captured(
                    Pat::Ident(
                        BindingMode::ByValue(
                            Mutability::Immutable),
                        Ident::from(format!("__mock_unignored_argument_{}__", i)),
                        None),
                    ty.clone()),
            _ => continue,
        };
        inputs[i] = unignored;
    }
}

fn args_to_names(inputs: &Vec<FnArg>) -> String {
    inputs.iter()
        .fold(String::new(), |mut result, input| {
            match *input {
                FnArg::SelfRef(_, _) | FnArg::SelfValue(_) => result.push_str("self"),
                FnArg::Captured(Pat::Wild, _) => result.push_str("_"),
                FnArg::Captured(Pat::Ident(_, ref ident, None), _) => result.push_str(ident.as_ref()),
                _ => panic!("Invalid function input '{:?}'", input),
            };
            result.push_str(", ");
            result
        })
}

fn append_generics(fn_name: &mut String, generics: &Generics) {
    if generics.ty_params.is_empty() {
        return
    }
    fn_name.push_str("::<");
    for ty_param in &generics.ty_params {
        fn_name.push_str(&ty_param.ident.as_ref());
        fn_name.push(',');
    }
    fn_name.push('>');
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate seq_io;

use seq_io::fasta::{self,Record};
use seq_io::fastq::{self,Record as FastqRecord};

const FASTA: &'static [&'static [u8]; 11] = &[
   b">id desc",
   b"ACCGTAGGCT",
   b"CCGTAGGCTG",
   b"CGTAGGCTGA",
   b"GTAGGCTGAA",
   b"CCCC",
   b">id2",
   b"ATTGTTGTTT",
   b"ATTGTTGTTT",
   b"ATTGTTGTTT",
   b"GGGG"
];

fn concat_lines(lines: &[&[u8]], terminator: &[u8], last: bool) -> Vec<u8> {
   let mut out: Vec<_> = lines.iter()
        .flat_map(|s| s.iter().chain(terminator))
        .cloned()
        .collect();
   if !last {
      let l = out.len();
      out.truncate(l - terminator.len());
   }
   out
}

#[test]
fn test_fasta_reader() {
   let expected = [
      (Ok("id"), Some(Ok("desc")), (1, 6)),
      (Ok("id2"), None, (7, 11))
   ];
   let lterms: [&[u8]; 2] = [b"\n", b"\r\n"];

   // try different line endings
   for t in lterms.into_iter() {

      let fasta = concat_lines(FASTA, *t, true);
      let exp_seqs: Vec<_> = expected.iter().map(|&(_, _, (start, end))| (
         // raw sequence
         concat_lines(&FASTA[start..end], *t, false),
         // concatenated sequence
         FASTA[start..end].concat().to_vec()
      )).collect();

      // try different initial capacities to test
      // buffer growing feature
      for cap in 1 .. 100 {
         let mut exp_iter = expected.iter().zip(&exp_seqs);
         let mut reader = fasta::Reader::new(fasta.as_slice());
          while let Some((&(ref id, ref desc, _), &(ref raw_seq, ref seq))) = exp_iter.next() {
              let record = reader.next().unwrap().expect(&format!("Error reading record at cap. {}", cap));

              assert_eq!(record.id(), *id, "ID mismatch at cap. {}", cap);
              assert_eq!(record.desc(), *desc, "desc mismatch at cap. {}", cap);
              assert_eq!(record.seq(), raw_seq.as_slice(), "raw seq mismatch at cap. {}", cap);
              assert_eq!(record.owned_seq().as_slice(), seq.as_slice(), "seq mismatch at cap. {}", cap);

              let owned = record.to_owned_record();
              assert_eq!(owned.id(), *id, "ID mismatch at cap. {}", cap);
              assert_eq!(owned.desc(), *desc, "desc mismatch at cap. {}", cap);
              assert_eq!(owned.seq(), seq.as_slice(), "seq mismatch at cap. {}", cap);

          }
      }
   }
}

#[test]
fn test_fasta_invalid_start() {
    let mut reader = fasta::Reader::new(&b"id\nATGC"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Expected > at file start"));
}

#[test]
fn test_fasta_truncated() {
    let mut reader = fasta::Reader::new(&b">id\n"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Unexpected end of input"));
}

#[test]
fn test_fasta_none_after_err() {
    let mut reader = fasta::Reader::new(&b"id\nATGC"[..]);
    assert!(reader.next().unwrap().is_err());
    assert!(reader.next().is_none());
}

/// FASTQ

const FASTQ: &'static [u8] = b"@id desc
ATGC
+
~~~~
@id2
ATGC
+
~~~~";

#[test]
fn test_fastq_reader() {
   let expected = [
      (Ok("id"), Some(Ok("desc")), b"ATGC", b"~~~~"),
      (Ok("id2"), None, b"ATGC", b"~~~~")
   ];

   // try different initial capacities to test
   // buffer growing feature
   for cap in 1 .. 100 {
      let mut exp_iter = expected.iter();
      let mut reader = fastq::Reader::new(FASTQ);
      while let Some(&(ref id, ref desc, ref seq, ref qual)) = exp_iter.next() {
           let record = reader.next().unwrap().expect(&format!("Error reading record at cap. {}", cap));

           assert_eq!(record.id(), *id, "ID mismatch at cap. {}", cap);
           assert_eq!(record.desc(), *desc, "desc mismatch at cap. {}", cap);
           assert_eq!(record.seq(), *seq, "seq at cap. {}", cap);
           assert_eq!(record.qual(), *qual, "qual mismatch at cap. {}", cap);

           let owned = record.to_owned_record();
           assert_eq!(owned.id(), *id, "ID mismatch at cap. {}", cap);
           assert_eq!(owned.desc(), *desc, "desc mismatch at cap. {}", cap);
           assert_eq!(owned.seq(), *seq, "seq at cap. {}", cap);
           assert_eq!(owned.qual(), *qual, "qual mismatch at cap. {}", cap);
       }
   }
}

#[test]
fn test_fastq_invalid_start() {
    let mut reader = fastq::Reader::new(&b"id\nATGC"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Expected '@' but found 'i'"));
}

#[test]
fn test_fastq_truncated() {
    let mut reader = fastq::Reader::new(&b"@id\nATGC\n+"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Unexpected end of input"));
}

#[test]
fn test_fastq_unequal() {
    let mut reader = fastq::Reader::new(&b"@id\nATGC\n+\n~~"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Unequal lengths"));
}

#[test]
fn test_fastq_no_sep() {
    let mut reader = fastq::Reader::new(&b"@id\nATGC\n~~~~\n@id2"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Expected '+' but found '~'"));
}

#[test]
fn test_fastq_none_after_err() {
    let mut reader = fastq::Reader::new(&b"@id\nATGC"[..]);
    assert!(reader.next().unwrap().is_err());
    assert!(reader.next().is_none());
}
<commit_msg>Fix tests to actually test different capacities<commit_after>#![allow(dead_code)]

extern crate seq_io;

use seq_io::fasta::{self,Record};
use seq_io::fastq::{self,Record as FastqRecord};

const FASTA: &'static [&'static [u8]; 11] = &[
   b">id desc",
   b"ACCGTAGGCT",
   b"CCGTAGGCTG",
   b"CGTAGGCTGA",
   b"GTAGGCTGAA",
   b"CCCC",
   b">id2",
   b"ATTGTTGTTT",
   b"ATTGTTGTTT",
   b"ATTGTTGTTT",
   b"GGGG"
];

fn concat_lines(lines: &[&[u8]], terminator: &[u8], last: bool) -> Vec<u8> {
   let mut out: Vec<_> = lines.iter()
        .flat_map(|s| s.iter().chain(terminator))
        .cloned()
        .collect();
   if !last {
      let l = out.len();
      out.truncate(l - terminator.len());
   }
   out
}

#[test]
fn test_fasta_reader() {
   let expected = [
      (Ok("id"), Some(Ok("desc")), (1, 6)),
      (Ok("id2"), None, (7, 11))
   ];
   let lterms: [&[u8]; 2] = [b"\n", b"\r\n"];

   // try different line endings
   for t in lterms.into_iter() {

      let fasta = concat_lines(FASTA, *t, true);
      let exp_seqs: Vec<_> = expected.iter().map(|&(_, _, (start, end))| (
         // raw sequence
         concat_lines(&FASTA[start..end], *t, false),
         // concatenated sequence
         FASTA[start..end].concat().to_vec()
      )).collect();

      // try different initial capacities to test
      // buffer growing feature
      for cap in 3 .. 100 {
         let mut exp_iter = expected.iter().zip(&exp_seqs);
         let mut reader = fasta::Reader::with_capacity(fasta.as_slice(), cap);
          while let Some((&(ref id, ref desc, _), &(ref raw_seq, ref seq))) = exp_iter.next() {
              let record = reader.next().unwrap().expect(&format!("Error reading record at cap. {}", cap));

              assert_eq!(record.id(), *id, "ID mismatch at cap. {}", cap);
              assert_eq!(record.desc(), *desc, "desc mismatch at cap. {}", cap);
              assert_eq!(record.seq(), raw_seq.as_slice(), "raw seq mismatch at cap. {}", cap);
              assert_eq!(record.owned_seq().as_slice(), seq.as_slice(), "seq mismatch at cap. {}", cap);

              let owned = record.to_owned_record();
              assert_eq!(owned.id(), *id, "ID mismatch at cap. {}", cap);
              assert_eq!(owned.desc(), *desc, "desc mismatch at cap. {}", cap);
              assert_eq!(owned.seq(), seq.as_slice(), "seq mismatch at cap. {}", cap);

          }
      }
   }
}

#[test]
fn test_fasta_invalid_start() {
    let mut reader = fasta::Reader::new(&b"id\nATGC"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Expected > at file start"));
}

#[test]
fn test_fasta_truncated() {
    let mut reader = fasta::Reader::new(&b">id\n"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Unexpected end of input"));
}

#[test]
fn test_fasta_none_after_err() {
    let mut reader = fasta::Reader::new(&b"id\nATGC"[..]);
    assert!(reader.next().unwrap().is_err());
    assert!(reader.next().is_none());
}

/// FASTQ

const FASTQ: &'static [u8] = b"@id desc
ATGC
+
~~~~
@id2
ATGC
+
~~~~";

#[test]
fn test_fastq_reader() {
   let expected = [
      (Ok("id"), Some(Ok("desc")), b"ATGC", b"~~~~"),
      (Ok("id2"), None, b"ATGC", b"~~~~")
   ];

   // try different initial capacities to test
   // buffer growing feature
   for cap in 3 .. 100 {
      let mut exp_iter = expected.iter();
      let mut reader = fastq::Reader::with_capacity(FASTQ, cap);
      while let Some(&(ref id, ref desc, ref seq, ref qual)) = exp_iter.next() {
           let record = reader.next().unwrap().expect(&format!("Error reading record at cap. {}", cap));

           assert_eq!(record.id(), *id, "ID mismatch at cap. {}", cap);
           assert_eq!(record.desc(), *desc, "desc mismatch at cap. {}", cap);
           assert_eq!(record.seq(), *seq, "seq at cap. {}", cap);
           assert_eq!(record.qual(), *qual, "qual mismatch at cap. {}", cap);

           let owned = record.to_owned_record();
           assert_eq!(owned.id(), *id, "ID mismatch at cap. {}", cap);
           assert_eq!(owned.desc(), *desc, "desc mismatch at cap. {}", cap);
           assert_eq!(owned.seq(), *seq, "seq at cap. {}", cap);
           assert_eq!(owned.qual(), *qual, "qual mismatch at cap. {}", cap);
       }
   }
}

#[test]
fn test_fastq_invalid_start() {
    let mut reader = fastq::Reader::new(&b"id\nATGC"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Expected '@' but found 'i'"));
}

#[test]
fn test_fastq_truncated() {
    let mut reader = fastq::Reader::new(&b"@id\nATGC\n+"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Unexpected end of input"));
}

#[test]
fn test_fastq_unequal() {
    let mut reader = fastq::Reader::new(&b"@id\nATGC\n+\n~~"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Unequal lengths"));
}

#[test]
fn test_fastq_no_sep() {
    let mut reader = fastq::Reader::new(&b"@id\nATGC\n~~~~\n@id2"[..]);
    let rec = reader.next().unwrap();
    assert!(rec.is_err() && format!("{}", rec.err().unwrap()).contains("Expected '+' but found '~'"));
}

#[test]
fn test_fastq_none_after_err() {
    let mut reader = fastq::Reader::new(&b"@id\nATGC"[..]);
    assert!(reader.next().unwrap().is_err());
    assert!(reader.next().is_none());
}
<|endoftext|>


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

#![feature(core)]

extern crate genmesh;

use genmesh::{
    Quad,
    EmitTriangles,
    Triangle,
    MapToVertices,
    LruIndexer,
    Indexer,
    Vertices,
    Triangulate
};

use genmesh::generators::{Cube, Plane};

#[test]
fn test_quad_vertex() {
    let input = &[Quad::new(0u, 1, 2, 3),
                  Quad::new(1u, 2, 3, 4)];

    let output = &[Quad::new(false, true, false, true),
                   Quad::new(true, false, true, false)];

    let transformed = input.iter().map(|x| x.clone())
                                  .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_quad_vertex_two_stages() {
    let input = &[Quad::new(0u, 1, 2, 3),
                  Quad::new(1u, 2, 3, 4)];

    let output = &[Quad::new(false, true, false, true),
                   Quad::new(true, false, true, false)];

    let transformed = input.iter().map(|x| x.clone())
                                  .vertex(|v| v as u8)
                                  .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_quad_poly_simple() {
    let input = &[Quad::new(0u, 1, 2, 3),
                  Quad::new(1u, 2, 3, 4)];

    let output = &[Quad::new(0i, 1, 2, 0),
                   Quad::new(0i, 2, 3, 0)];

    let transformed = input.iter().map(|x| x.clone())
                                  .map(|v| Quad::new(0i, v.y as int, v.z as int, 0));

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_vertex() {
    let input = &[Triangle::new(0u, 1, 2),
                  Triangle::new(1u, 2, 3)];

    let output = &[Triangle::new(false, true, false),
                   Triangle::new(true, false, true)];

    let transformed = input.iter().map(|x| x.clone())
                           .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_vertex_two_stages() {
    let input = &[Triangle::new(0u, 1, 2),
                  Triangle::new(1u, 2, 3)];

    let output = &[Triangle::new(false, true, false),
                   Triangle::new(true, false, true)];

    let transformed = input.iter().map(|x| x.clone())
                           .vertex(|v| v as u8)
                           .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_poly_simple() {
    let input = &[Triangle::new(0u, 1, 2),
                  Triangle::new(1u, 2, 3)];

    let output = &[Triangle::new(0i, 1, 2),
                   Triangle::new(0i, 2, 3)];

    let transformed = input.iter().map(|x| x.clone())
                           .map(|v| Triangle::new(0i, v.y as int, v.z as int));

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_to_triangles() {
    let q = Quad::new(0u, 1, 2, 3);
    let mut result = Vec::new();
    q.emit_triangles(|v| result.push(v));

    assert_eq!(result, vec![Triangle::new(0u, 1, 2),
                            Triangle::new(2u, 3, 0)]);

    let t = Triangle::new(0u, 1, 2);
    let mut result = Vec::new();
    t.emit_triangles(|v| result.push(v));

    assert_eq!(result, vec![Triangle::new(0u, 1, 2)]);
}

#[test]
fn test_plane() {
    let mut plane = Plane::new();

    let a = plane.next().unwrap();

    let Quad {
        x: (ax, ay),
        y: (bx, by),
        z: (cx, cy),
        w: (dx, dy)
    } = a;

    assert_eq!(ax, -1.); assert_eq!(ay, -1.);
    assert_eq!(bx,  1.); assert_eq!(by, -1.);
    assert_eq!(cx,  1.); assert_eq!(cy,  1.);
    assert_eq!(dx, -1.); assert_eq!(dy,  1.);
}

#[test]
fn test_lru_indexer() {
    let mut vectices: Vec<(f32, f32, f32)> = Vec::new();
    let indexes: Vec<uint> = {
        let mut indexer = LruIndexer::new(8, |_, v| vectices.push(v));

        Cube::new().vertex(|v| indexer.index(v))
                   .vertices()
                   .collect()
    };

    assert_eq!(8, vectices.len());
    assert_eq!(6*4, indexes.len());

    let mut vectices: Vec<(f32, f32, f32)> = Vec::new();
    let indexes: Vec<uint> = {
        let mut indexer = LruIndexer::new(4, |_, v| vectices.push(v));

        Cube::new().triangulate()
                   .vertex(|v| indexer.index(v))
                   .vertices()
                   .collect()
    };

    assert_eq!(20, vectices.len());
    assert_eq!(3*6*2, indexes.len());
}
<commit_msg>fix intergers in tests<commit_after>//   Copyright Colin Sherratt 2014
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#![feature(core)]

extern crate genmesh;

use genmesh::{
    Quad,
    EmitTriangles,
    Triangle,
    MapToVertices,
    LruIndexer,
    Indexer,
    Vertices,
    Triangulate
};

use genmesh::generators::{Cube, Plane};

#[test]
fn test_quad_vertex() {
    let input = &[Quad::new(0us, 1, 2, 3),
                  Quad::new(1us, 2, 3, 4)];

    let output = &[Quad::new(false, true, false, true),
                   Quad::new(true, false, true, false)];

    let transformed = input.iter().map(|x| x.clone())
                                  .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_quad_vertex_two_stages() {
    let input = &[Quad::new(0us, 1, 2, 3),
                  Quad::new(1us, 2, 3, 4)];

    let output = &[Quad::new(false, true, false, true),
                   Quad::new(true, false, true, false)];

    let transformed = input.iter().map(|x| x.clone())
                                  .vertex(|v| v as u8)
                                  .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_quad_poly_simple() {
    let input = &[Quad::new(0us, 1, 2, 3),
                  Quad::new(1us, 2, 3, 4)];

    let output = &[Quad::new(0is, 1, 2, 0),
                   Quad::new(0is, 2, 3, 0)];

    let transformed = input.iter().map(|x| x.clone())
                                  .map(|v| Quad::new(0is, v.y as isize, v.z as isize, 0));

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_vertex() {
    let input = &[Triangle::new(0us, 1, 2),
                  Triangle::new(1us, 2, 3)];

    let output = &[Triangle::new(false, true, false),
                   Triangle::new(true, false, true)];

    let transformed = input.iter().map(|x| x.clone())
                           .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_vertex_two_stages() {
    let input = &[Triangle::new(0us, 1, 2),
                  Triangle::new(1us, 2, 3)];

    let output = &[Triangle::new(false, true, false),
                   Triangle::new(true, false, true)];

    let transformed = input.iter().map(|x| x.clone())
                           .vertex(|v| v as u8)
                           .vertex(|v| v % 2 != 0);

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_triangle_poly_simple() {
    let input = &[Triangle::new(0us, 1, 2),
                  Triangle::new(1us, 2, 3)];

    let output = &[Triangle::new(0is, 1, 2),
                   Triangle::new(0is, 2, 3)];

    let transformed = input.iter().map(|x| x.clone())
                           .map(|v| Triangle::new(0is, v.y as isize, v.z as isize));

    for (x, y) in transformed.zip(output.iter().map(|x| x.clone())) {
        assert_eq!(x, y);
    }
}

#[test]
fn test_to_triangles() {
    let q = Quad::new(0us, 1, 2, 3);
    let mut result = Vec::new();
    q.emit_triangles(|v| result.push(v));

    assert_eq!(result, vec![Triangle::new(0us, 1, 2),
                            Triangle::new(2us, 3, 0)]);

    let t = Triangle::new(0us, 1, 2);
    let mut result = Vec::new();
    t.emit_triangles(|v| result.push(v));

    assert_eq!(result, vec![Triangle::new(0us, 1, 2)]);
}

#[test]
fn test_plane() {
    let mut plane = Plane::new();

    let a = plane.next().unwrap();

    let Quad {
        x: (ax, ay),
        y: (bx, by),
        z: (cx, cy),
        w: (dx, dy)
    } = a;

    assert_eq!(ax, -1.); assert_eq!(ay, -1.);
    assert_eq!(bx,  1.); assert_eq!(by, -1.);
    assert_eq!(cx,  1.); assert_eq!(cy,  1.);
    assert_eq!(dx, -1.); assert_eq!(dy,  1.);
}

#[test]
fn test_lru_indexer() {
    let mut vectices: Vec<(f32, f32, f32)> = Vec::new();
    let indexes: Vec<usize> = {
        let mut indexer = LruIndexer::new(8, |_, v| vectices.push(v));

        Cube::new().vertex(|v| indexer.index(v))
                   .vertices()
                   .collect()
    };

    assert_eq!(8, vectices.len());
    assert_eq!(6*4, indexes.len());

    let mut vectices: Vec<(f32, f32, f32)> = Vec::new();
    let indexes: Vec<usize> = {
        let mut indexer = LruIndexer::new(4, |_, v| vectices.push(v));

        Cube::new().triangulate()
                   .vertex(|v| indexer.index(v))
                   .vertices()
                   .collect()
    };

    assert_eq!(20, vectices.len());
    assert_eq!(3*6*2, indexes.len());
}
<|endoftext|>


<commit_before>use std::env;
use std::error;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::{self, Command};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

static TEST_DIR: &'static str = "ripgrep-tests";
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

/// Setup an empty work directory and return a command pointing to the ripgrep
/// executable whose CWD is set to the work directory.
///
/// The name given will be used to create the directory. Generally, it should
/// correspond to the test name.
pub fn setup(test_name: &str) -> (Dir, TestCommand) {
    let dir = Dir::new(test_name);
    let cmd = dir.command();
    (dir, cmd)
}

/// Like `setup`, but uses PCRE2 as the underlying regex engine.
pub fn setup_pcre2(test_name: &str) -> (Dir, TestCommand) {
    let mut dir = Dir::new(test_name);
    dir.pcre2(true);
    let cmd = dir.command();
    (dir, cmd)
}

/// Break the given string into lines, sort them and then join them back
/// together. This is useful for testing output from ripgrep that may not
/// always be in the same order.
pub fn sort_lines(lines: &str) -> String {
    let mut lines: Vec<&str> = lines.trim().lines().collect();
    lines.sort();
    format!("{}\n", lines.join("\n"))
}

/// Returns true if and only if the given program can be successfully executed
/// with a `--help` flag.
pub fn cmd_exists(program: &str) -> bool {
    Command::new(program).arg("--help").output().is_ok()
}

/// Dir represents a directory in which tests should be run.
///
/// Directories are created from a global atomic counter to avoid duplicates.
#[derive(Clone, Debug)]
pub struct Dir {
    /// The directory in which this test executable is running.
    root: PathBuf,
    /// The directory in which the test should run. If a test needs to create
    /// files, they should go in here. This directory is also used as the CWD
    /// for any processes created by the test.
    dir: PathBuf,
    /// Set to true when the test should use PCRE2 as the regex engine.
    pcre2: bool,
}

impl Dir {
    /// Create a new test working directory with the given name. The name
    /// does not need to be distinct for each invocation, but should correspond
    /// to a logical grouping of tests.
    pub fn new(name: &str) -> Dir {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        let root = env::current_exe()
            .unwrap()
            .parent()
            .expect("executable's directory")
            .to_path_buf();
        let dir =
            env::temp_dir().join(TEST_DIR).join(name).join(&format!("{}", id));
        if dir.exists() {
            nice_err(&dir, fs::remove_dir_all(&dir));
        }
        nice_err(&dir, repeat(|| fs::create_dir_all(&dir)));
        Dir { root: root, dir: dir, pcre2: false }
    }

    /// Use PCRE2 for this test.
    pub fn pcre2(&mut self, yes: bool) {
        self.pcre2 = yes;
    }

    /// Returns true if and only if this test is configured to use PCRE2 as
    /// the regex engine.
    pub fn is_pcre2(&self) -> bool {
        self.pcre2
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create<P: AsRef<Path>>(&self, name: P, contents: &str) {
        self.create_bytes(name, contents.as_bytes());
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    #[allow(dead_code)] // unused on Windows
    pub fn try_create<P: AsRef<Path>>(
        &self,
        name: P,
        contents: &str,
    ) -> io::Result<()> {
        let path = self.dir.join(name);
        self.try_create_bytes(path, contents.as_bytes())
    }

    /// Create a new file with the given name and size.
    pub fn create_size<P: AsRef<Path>>(&self, name: P, filesize: u64) {
        let path = self.dir.join(name);
        let file = nice_err(&path, File::create(&path));
        nice_err(&path, file.set_len(filesize));
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create_bytes<P: AsRef<Path>>(&self, name: P, contents: &[u8]) {
        let path = self.dir.join(&name);
        nice_err(&path, self.try_create_bytes(name, contents));
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    pub fn try_create_bytes<P: AsRef<Path>>(
        &self,
        name: P,
        contents: &[u8],
    ) -> io::Result<()> {
        let path = self.dir.join(name);
        let mut file = File::create(path)?;
        file.write_all(contents)?;
        file.flush()
    }

    /// Remove a file with the given name from this directory.
    pub fn remove<P: AsRef<Path>>(&self, name: P) {
        let path = self.dir.join(name);
        nice_err(&path, fs::remove_file(&path));
    }

    /// Create a new directory with the given path (and any directories above
    /// it) inside this directory.
    pub fn create_dir<P: AsRef<Path>>(&self, path: P) {
        let path = self.dir.join(path);
        nice_err(&path, repeat(|| fs::create_dir_all(&path)));
    }

    /// Creates a new command that is set to use the ripgrep executable in
    /// this working directory.
    ///
    /// This also:
    ///
    /// * Unsets the `RIPGREP_CONFIG_PATH` environment variable.
    /// * Sets the `--path-separator` to `/` so that paths have the same output
    ///   on all systems. Tests that need to check `--path-separator` itself
    ///   can simply pass it again to override it.
    pub fn command(&self) -> TestCommand {
        let mut cmd = process::Command::new(&self.bin());
        cmd.env_remove("RIPGREP_CONFIG_PATH");
        cmd.current_dir(&self.dir);
        cmd.arg("--path-separator").arg("/");
        if self.is_pcre2() {
            cmd.arg("--pcre2");
        }
        TestCommand { dir: self.clone(), cmd: cmd }
    }

    /// Returns the path to the ripgrep executable.
    pub fn bin(&self) -> PathBuf {
        if cfg!(windows) {
            self.root.join("../rg.exe")
        } else {
            self.root.join("../rg")
        }
    }

    /// Returns the path to this directory.
    pub fn path(&self) -> &Path {
        &self.dir
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::unix::fs::symlink;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink(&src, &target));
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::windows::fs::symlink_dir;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_dir(&target);
        nice_err(&target, symlink_dir(&src, &target));
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        self.link_dir(src, target);
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    #[allow(dead_code)] // unused on Windows
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        use std::os::windows::fs::symlink_file;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink_file(&src, &target));
    }
}

/// A simple wrapper around a process::Command with some conveniences.
#[derive(Debug)]
pub struct TestCommand {
    /// The dir used to launched this command.
    dir: Dir,
    /// The actual command we use to control the process.
    cmd: Command,
}

impl TestCommand {
    /// Returns a mutable reference to the underlying command.
    pub fn cmd(&mut self) -> &mut Command {
        &mut self.cmd
    }

    /// Add an argument to pass to the command.
    pub fn arg<A: AsRef<OsStr>>(&mut self, arg: A) -> &mut TestCommand {
        self.cmd.arg(arg);
        self
    }

    /// Add any number of arguments to the command.
    pub fn args<I, A>(&mut self, args: I) -> &mut TestCommand
    where
        I: IntoIterator<Item = A>,
        A: AsRef<OsStr>,
    {
        self.cmd.args(args);
        self
    }

    /// Set the working directory for this command.
    ///
    /// Note that this does not need to be called normally, since the creation
    /// of this TestCommand causes its working directory to be set to the
    /// test's directory automatically.
    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut TestCommand {
        self.cmd.current_dir(dir);
        self
    }

    /// Runs and captures the stdout of the given command.
    pub fn stdout(&mut self) -> String {
        let o = self.output();
        let stdout = String::from_utf8_lossy(&o.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!(
                    "could not convert from string: {:?}\n\n{}",
                    err, stdout
                );
            }
        }
    }

    /// Pipe `input` to a command, and collect the output.
    pub fn pipe(&mut self, input: &[u8]) -> String {
        self.cmd.stdin(process::Stdio::piped());
        self.cmd.stdout(process::Stdio::piped());
        self.cmd.stderr(process::Stdio::piped());

        let mut child = self.cmd.spawn().unwrap();

        // Pipe input to child process using a separate thread to avoid
        // risk of deadlock between parent and child process.
        let mut stdin = child.stdin.take().expect("expected standard input");
        let input = input.to_owned();
        let worker = thread::spawn(move || stdin.write_all(&input));

        let output = self.expect_success(child.wait_with_output().unwrap());
        worker.join().unwrap().unwrap();

        let stdout = String::from_utf8_lossy(&output.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!(
                    "could not convert from string: {:?}\n\n{}",
                    err, stdout
                );
            }
        }
    }

    /// Gets the output of a command. If the command failed, then this panics.
    pub fn output(&mut self) -> process::Output {
        let output = self.cmd.output().unwrap();
        self.expect_success(output)
    }

    /// Runs the command and asserts that it resulted in an error exit code.
    pub fn assert_err(&mut self) {
        let o = self.cmd.output().unwrap();
        if o.status.success() {
            panic!(
                "\n\n===== {:?} =====\n\
                 command succeeded but expected failure!\
                 \n\ncwd: {}\
                 \n\nstatus: {}\
                 \n\nstdout: {}\n\nstderr: {}\
                 \n\n=====\n",
                self.cmd,
                self.dir.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
    }

    /// Runs the command and asserts that its exit code matches expected exit
    /// code.
    pub fn assert_exit_code(&mut self, expected_code: i32) {
        let code = self.cmd.output().unwrap().status.code().unwrap();
        assert_eq!(
            expected_code, code,
            "\n\n===== {:?} =====\n\
             expected exit code did not match\
             \n\nexpected: {}\
             \n\nfound: {}\
             \n\n=====\n",
            self.cmd, expected_code, code
        );
    }

    /// Runs the command and asserts that something was printed to stderr.
    pub fn assert_non_empty_stderr(&mut self) {
        let o = self.cmd.output().unwrap();
        if o.status.success() || o.stderr.is_empty() {
            panic!(
                "\n\n===== {:?} =====\n\
                 command succeeded but expected failure!\
                 \n\ncwd: {}\
                 \n\nstatus: {}\
                 \n\nstdout: {}\n\nstderr: {}\
                 \n\n=====\n",
                self.cmd,
                self.dir.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
    }

    fn expect_success(&self, o: process::Output) -> process::Output {
        if !o.status.success() {
            let suggest = if o.stderr.is_empty() {
                "\n\nDid your search end up with no results?".to_string()
            } else {
                "".to_string()
            };

            panic!(
                "\n\n==========\n\
                    command failed but expected success!\
                    {}\
                    \n\ncommand: {:?}\
                    \ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\
                    \n\nstderr: {}\
                    \n\n==========\n",
                suggest,
                self.cmd,
                self.dir.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
        o
    }
}

fn nice_err<T, E: error::Error>(path: &Path, res: Result<T, E>) -> T {
    match res {
        Ok(t) => t,
        Err(err) => panic!("{}: {:?}", path.display(), err),
    }
}

fn repeat<F: FnMut() -> io::Result<()>>(mut f: F) -> io::Result<()> {
    let mut last_err = None;
    for _ in 0..10 {
        if let Err(err) = f() {
            last_err = Some(err);
            thread::sleep(Duration::from_millis(500));
        } else {
            return Ok(());
        }
    }
    Err(last_err.unwrap())
}
<commit_msg>tests: make 'cross test' work<commit_after>use std::env;
use std::error;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::{self, Command};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

static TEST_DIR: &'static str = "ripgrep-tests";
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

/// Setup an empty work directory and return a command pointing to the ripgrep
/// executable whose CWD is set to the work directory.
///
/// The name given will be used to create the directory. Generally, it should
/// correspond to the test name.
pub fn setup(test_name: &str) -> (Dir, TestCommand) {
    let dir = Dir::new(test_name);
    let cmd = dir.command();
    (dir, cmd)
}

/// Like `setup`, but uses PCRE2 as the underlying regex engine.
pub fn setup_pcre2(test_name: &str) -> (Dir, TestCommand) {
    let mut dir = Dir::new(test_name);
    dir.pcre2(true);
    let cmd = dir.command();
    (dir, cmd)
}

/// Break the given string into lines, sort them and then join them back
/// together. This is useful for testing output from ripgrep that may not
/// always be in the same order.
pub fn sort_lines(lines: &str) -> String {
    let mut lines: Vec<&str> = lines.trim().lines().collect();
    lines.sort();
    format!("{}\n", lines.join("\n"))
}

/// Returns true if and only if the given program can be successfully executed
/// with a `--help` flag.
pub fn cmd_exists(program: &str) -> bool {
    Command::new(program).arg("--help").output().is_ok()
}

/// Dir represents a directory in which tests should be run.
///
/// Directories are created from a global atomic counter to avoid duplicates.
#[derive(Clone, Debug)]
pub struct Dir {
    /// The directory in which this test executable is running.
    root: PathBuf,
    /// The directory in which the test should run. If a test needs to create
    /// files, they should go in here. This directory is also used as the CWD
    /// for any processes created by the test.
    dir: PathBuf,
    /// Set to true when the test should use PCRE2 as the regex engine.
    pcre2: bool,
}

impl Dir {
    /// Create a new test working directory with the given name. The name
    /// does not need to be distinct for each invocation, but should correspond
    /// to a logical grouping of tests.
    pub fn new(name: &str) -> Dir {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        let root = env::current_exe()
            .unwrap()
            .parent()
            .expect("executable's directory")
            .to_path_buf();
        let dir =
            env::temp_dir().join(TEST_DIR).join(name).join(&format!("{}", id));
        if dir.exists() {
            nice_err(&dir, fs::remove_dir_all(&dir));
        }
        nice_err(&dir, repeat(|| fs::create_dir_all(&dir)));
        Dir { root: root, dir: dir, pcre2: false }
    }

    /// Use PCRE2 for this test.
    pub fn pcre2(&mut self, yes: bool) {
        self.pcre2 = yes;
    }

    /// Returns true if and only if this test is configured to use PCRE2 as
    /// the regex engine.
    pub fn is_pcre2(&self) -> bool {
        self.pcre2
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create<P: AsRef<Path>>(&self, name: P, contents: &str) {
        self.create_bytes(name, contents.as_bytes());
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    #[allow(dead_code)] // unused on Windows
    pub fn try_create<P: AsRef<Path>>(
        &self,
        name: P,
        contents: &str,
    ) -> io::Result<()> {
        let path = self.dir.join(name);
        self.try_create_bytes(path, contents.as_bytes())
    }

    /// Create a new file with the given name and size.
    pub fn create_size<P: AsRef<Path>>(&self, name: P, filesize: u64) {
        let path = self.dir.join(name);
        let file = nice_err(&path, File::create(&path));
        nice_err(&path, file.set_len(filesize));
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create_bytes<P: AsRef<Path>>(&self, name: P, contents: &[u8]) {
        let path = self.dir.join(&name);
        nice_err(&path, self.try_create_bytes(name, contents));
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    pub fn try_create_bytes<P: AsRef<Path>>(
        &self,
        name: P,
        contents: &[u8],
    ) -> io::Result<()> {
        let path = self.dir.join(name);
        let mut file = File::create(path)?;
        file.write_all(contents)?;
        file.flush()
    }

    /// Remove a file with the given name from this directory.
    pub fn remove<P: AsRef<Path>>(&self, name: P) {
        let path = self.dir.join(name);
        nice_err(&path, fs::remove_file(&path));
    }

    /// Create a new directory with the given path (and any directories above
    /// it) inside this directory.
    pub fn create_dir<P: AsRef<Path>>(&self, path: P) {
        let path = self.dir.join(path);
        nice_err(&path, repeat(|| fs::create_dir_all(&path)));
    }

    /// Creates a new command that is set to use the ripgrep executable in
    /// this working directory.
    ///
    /// This also:
    ///
    /// * Unsets the `RIPGREP_CONFIG_PATH` environment variable.
    /// * Sets the `--path-separator` to `/` so that paths have the same output
    ///   on all systems. Tests that need to check `--path-separator` itself
    ///   can simply pass it again to override it.
    pub fn command(&self) -> TestCommand {
        let mut cmd = self.bin();
        cmd.env_remove("RIPGREP_CONFIG_PATH");
        cmd.current_dir(&self.dir);
        cmd.arg("--path-separator").arg("/");
        if self.is_pcre2() {
            cmd.arg("--pcre2");
        }
        TestCommand { dir: self.clone(), cmd: cmd }
    }

    /// Returns the path to the ripgrep executable.
    pub fn bin(&self) -> process::Command {
        let rg = if cfg!(windows) {
            self.root.join("../rg.exe")
        } else {
            self.root.join("../rg")
        };
        match cross_runner() {
            None => process::Command::new(rg),
            Some(runner) => {
                let mut cmd = process::Command::new(runner);
                cmd.arg(rg);
                cmd
            }
        }
    }

    /// Returns the path to this directory.
    pub fn path(&self) -> &Path {
        &self.dir
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::unix::fs::symlink;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink(&src, &target));
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::windows::fs::symlink_dir;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_dir(&target);
        nice_err(&target, symlink_dir(&src, &target));
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        self.link_dir(src, target);
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    #[allow(dead_code)] // unused on Windows
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        use std::os::windows::fs::symlink_file;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink_file(&src, &target));
    }
}

/// A simple wrapper around a process::Command with some conveniences.
#[derive(Debug)]
pub struct TestCommand {
    /// The dir used to launched this command.
    dir: Dir,
    /// The actual command we use to control the process.
    cmd: Command,
}

impl TestCommand {
    /// Returns a mutable reference to the underlying command.
    pub fn cmd(&mut self) -> &mut Command {
        &mut self.cmd
    }

    /// Add an argument to pass to the command.
    pub fn arg<A: AsRef<OsStr>>(&mut self, arg: A) -> &mut TestCommand {
        self.cmd.arg(arg);
        self
    }

    /// Add any number of arguments to the command.
    pub fn args<I, A>(&mut self, args: I) -> &mut TestCommand
    where
        I: IntoIterator<Item = A>,
        A: AsRef<OsStr>,
    {
        self.cmd.args(args);
        self
    }

    /// Set the working directory for this command.
    ///
    /// Note that this does not need to be called normally, since the creation
    /// of this TestCommand causes its working directory to be set to the
    /// test's directory automatically.
    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut TestCommand {
        self.cmd.current_dir(dir);
        self
    }

    /// Runs and captures the stdout of the given command.
    pub fn stdout(&mut self) -> String {
        let o = self.output();
        let stdout = String::from_utf8_lossy(&o.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!(
                    "could not convert from string: {:?}\n\n{}",
                    err, stdout
                );
            }
        }
    }

    /// Pipe `input` to a command, and collect the output.
    pub fn pipe(&mut self, input: &[u8]) -> String {
        self.cmd.stdin(process::Stdio::piped());
        self.cmd.stdout(process::Stdio::piped());
        self.cmd.stderr(process::Stdio::piped());

        let mut child = self.cmd.spawn().unwrap();

        // Pipe input to child process using a separate thread to avoid
        // risk of deadlock between parent and child process.
        let mut stdin = child.stdin.take().expect("expected standard input");
        let input = input.to_owned();
        let worker = thread::spawn(move || stdin.write_all(&input));

        let output = self.expect_success(child.wait_with_output().unwrap());
        worker.join().unwrap().unwrap();

        let stdout = String::from_utf8_lossy(&output.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!(
                    "could not convert from string: {:?}\n\n{}",
                    err, stdout
                );
            }
        }
    }

    /// Gets the output of a command. If the command failed, then this panics.
    pub fn output(&mut self) -> process::Output {
        let output = self.cmd.output().unwrap();
        self.expect_success(output)
    }

    /// Runs the command and asserts that it resulted in an error exit code.
    pub fn assert_err(&mut self) {
        let o = self.cmd.output().unwrap();
        if o.status.success() {
            panic!(
                "\n\n===== {:?} =====\n\
                 command succeeded but expected failure!\
                 \n\ncwd: {}\
                 \n\nstatus: {}\
                 \n\nstdout: {}\n\nstderr: {}\
                 \n\n=====\n",
                self.cmd,
                self.dir.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
    }

    /// Runs the command and asserts that its exit code matches expected exit
    /// code.
    pub fn assert_exit_code(&mut self, expected_code: i32) {
        let code = self.cmd.output().unwrap().status.code().unwrap();
        assert_eq!(
            expected_code, code,
            "\n\n===== {:?} =====\n\
             expected exit code did not match\
             \n\nexpected: {}\
             \n\nfound: {}\
             \n\n=====\n",
            self.cmd, expected_code, code
        );
    }

    /// Runs the command and asserts that something was printed to stderr.
    pub fn assert_non_empty_stderr(&mut self) {
        let o = self.cmd.output().unwrap();
        if o.status.success() || o.stderr.is_empty() {
            panic!(
                "\n\n===== {:?} =====\n\
                 command succeeded but expected failure!\
                 \n\ncwd: {}\
                 \n\nstatus: {}\
                 \n\nstdout: {}\n\nstderr: {}\
                 \n\n=====\n",
                self.cmd,
                self.dir.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
    }

    fn expect_success(&self, o: process::Output) -> process::Output {
        if !o.status.success() {
            let suggest = if o.stderr.is_empty() {
                "\n\nDid your search end up with no results?".to_string()
            } else {
                "".to_string()
            };

            panic!(
                "\n\n==========\n\
                    command failed but expected success!\
                    {}\
                    \n\ncommand: {:?}\
                    \ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\
                    \n\nstderr: {}\
                    \n\n==========\n",
                suggest,
                self.cmd,
                self.dir.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
        o
    }
}

fn nice_err<T, E: error::Error>(path: &Path, res: Result<T, E>) -> T {
    match res {
        Ok(t) => t,
        Err(err) => panic!("{}: {:?}", path.display(), err),
    }
}

fn repeat<F: FnMut() -> io::Result<()>>(mut f: F) -> io::Result<()> {
    let mut last_err = None;
    for _ in 0..10 {
        if let Err(err) = f() {
            last_err = Some(err);
            thread::sleep(Duration::from_millis(500));
        } else {
            return Ok(());
        }
    }
    Err(last_err.unwrap())
}

/// When running tests with cross, we need to be a bit smarter about how we
/// run our `rg` binary. We can't just run it directly since it might be
/// compiled for a totally different target. Instead, it's likely that `cross`
/// will have setup qemu to run it. While this is integrated into the Rust
/// testing by default, we need to handle it ourselves for integration tests.
///
/// Thankfully, cross sets an environment variable that points to the proper
/// qemu binary that we want to run. So we just search for that env var and
/// return its value if we could find it.
fn cross_runner() -> Option<String> {
    for (k, v) in std::env::vars_os() {
        let (k, v) = (k.to_string_lossy(), v.to_string_lossy());
        if !k.starts_with("CARGO_TARGET_") && !k.ends_with("_RUNNER") {
            continue;
        }
        if !v.starts_with("qemu-") {
            continue;
        }
        return Some(v.into_owned());
    }
    None
}
<|endoftext|>


<commit_before>use std::env;
use std::error;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::{self, Command};
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

static TEST_DIR: &'static str = "ripgrep-tests";
static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// Setup an empty work directory and return a command pointing to the ripgrep
/// executable whose CWD is set to the work directory.
///
/// The name given will be used to create the directory. Generally, it should
/// correspond to the test name.
pub fn setup(test_name: &str) -> (Dir, TestCommand) {
    let dir = Dir::new(test_name);
    let cmd = dir.command();
    (dir, cmd)
}

/// Like `setup`, but uses PCRE2 as the underlying regex engine.
pub fn setup_pcre2(test_name: &str) -> (Dir, TestCommand) {
    let mut dir = Dir::new(test_name);
    dir.pcre2(true);
    let cmd = dir.command();
    (dir, cmd)
}

/// Break the given string into lines, sort them and then join them back
/// together. This is useful for testing output from ripgrep that may not
/// always be in the same order.
pub fn sort_lines(lines: &str) -> String {
    let mut lines: Vec<&str> = lines.trim().lines().collect();
    lines.sort();
    format!("{}\n", lines.join("\n"))
}

/// Returns true if and only if the given program can be successfully executed
/// with a `--help` flag.
pub fn cmd_exists(program: &str) -> bool {
    Command::new(program).arg("--help").output().is_ok()
}

/// Dir represents a directory in which tests should be run.
///
/// Directories are created from a global atomic counter to avoid duplicates.
#[derive(Clone, Debug)]
pub struct Dir {
    /// The directory in which this test executable is running.
    root: PathBuf,
    /// The directory in which the test should run. If a test needs to create
    /// files, they should go in here. This directory is also used as the CWD
    /// for any processes created by the test.
    dir: PathBuf,
    /// Set to true when the test should use PCRE2 as the regex engine.
    pcre2: bool,
}

impl Dir {
    /// Create a new test working directory with the given name. The name
    /// does not need to be distinct for each invocation, but should correspond
    /// to a logical grouping of tests.
    pub fn new(name: &str) -> Dir {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        let root = env::current_exe()
            .unwrap()
            .parent()
            .expect("executable's directory")
            .to_path_buf();
        let dir = env::temp_dir()
            .join(TEST_DIR)
            .join(name)
            .join(&format!("{}", id));
        nice_err(&dir, repeat(|| fs::create_dir_all(&dir)));
        Dir {
            root: root,
            dir: dir,
            pcre2: false,
        }
    }

    /// Use PCRE2 for this test.
    pub fn pcre2(&mut self, yes: bool) {
        self.pcre2 = yes;
    }

    /// Returns true if and only if this test is configured to use PCRE2 as
    /// the regex engine.
    pub fn is_pcre2(&self) -> bool {
        self.pcre2
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create<P: AsRef<Path>>(&self, name: P, contents: &str) {
        self.create_bytes(name, contents.as_bytes());
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    #[allow(dead_code)] // unused on Windows
    pub fn try_create<P: AsRef<Path>>(
        &self,
        name: P,
        contents: &str,
    ) -> io::Result<()> {
        let path = self.dir.join(name);
        self.try_create_bytes(path, contents.as_bytes())
    }

    /// Create a new file with the given name and size.
    pub fn create_size<P: AsRef<Path>>(&self, name: P, filesize: u64) {
        let path = self.dir.join(name);
        let file = nice_err(&path, File::create(&path));
        nice_err(&path, file.set_len(filesize));
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create_bytes<P: AsRef<Path>>(&self, name: P, contents: &[u8]) {
        let path = self.dir.join(&name);
        nice_err(&path, self.try_create_bytes(name, contents));
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    pub fn try_create_bytes<P: AsRef<Path>>(
        &self,
        name: P,
        contents: &[u8],
    ) -> io::Result<()> {
        let path = self.dir.join(name);
        let mut file = File::create(path)?;
        file.write_all(contents)?;
        file.flush()
    }

    /// Remove a file with the given name from this directory.
    pub fn remove<P: AsRef<Path>>(&self, name: P) {
        let path = self.dir.join(name);
        nice_err(&path, fs::remove_file(&path));
    }

    /// Create a new directory with the given path (and any directories above
    /// it) inside this directory.
    pub fn create_dir<P: AsRef<Path>>(&self, path: P) {
        let path = self.dir.join(path);
        nice_err(&path, repeat(|| fs::create_dir_all(&path)));
    }

    /// Creates a new command that is set to use the ripgrep executable in
    /// this working directory.
    ///
    /// This also:
    ///
    /// * Unsets the `RIPGREP_CONFIG_PATH` environment variable.
    /// * Sets the `--path-separator` to `/` so that paths have the same output
    ///   on all systems. Tests that need to check `--path-separator` itself
    ///   can simply pass it again to override it.
    pub fn command(&self) -> TestCommand {
        let mut cmd = process::Command::new(&self.bin());
        cmd.env_remove("RIPGREP_CONFIG_PATH");
        cmd.current_dir(&self.dir);
        cmd.arg("--path-separator").arg("/");
        if self.is_pcre2() {
            cmd.arg("--pcre2");
        }
        TestCommand { dir: self.clone(), cmd: cmd }
    }

    /// Returns the path to the ripgrep executable.
    pub fn bin(&self) -> PathBuf {
        if cfg!(windows) {
            self.root.join("../rg.exe")
        } else {
            self.root.join("../rg")
        }
    }

    /// Returns the path to this directory.
    pub fn path(&self) -> &Path {
        &self.dir
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::unix::fs::symlink;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink(&src, &target));
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::windows::fs::symlink_dir;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_dir(&target);
        nice_err(&target, symlink_dir(&src, &target));
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        self.link_dir(src, target);
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    #[allow(dead_code)] // unused on Windows
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        use std::os::windows::fs::symlink_file;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink_file(&src, &target));
    }
}

/// A simple wrapper around a process::Command with some conveniences.
#[derive(Debug)]
pub struct TestCommand {
    /// The dir used to launched this command.
    dir: Dir,
    /// The actual command we use to control the process.
    cmd: Command,
}

impl TestCommand {
    /// Returns a mutable reference to the underlying command.
    pub fn cmd(&mut self) -> &mut Command {
        &mut self.cmd
    }

    /// Add an argument to pass to the command.
    pub fn arg<A: AsRef<OsStr>>(&mut self, arg: A) -> &mut TestCommand {
        self.cmd.arg(arg);
        self
    }

    /// Add any number of arguments to the command.
    pub fn args<I, A>(
        &mut self,
        args: I,
    ) -> &mut TestCommand
    where I: IntoIterator<Item=A>,
          A: AsRef<OsStr>
    {
        self.cmd.args(args);
        self
    }

    /// Set the working directory for this command.
    ///
    /// Note that this does not need to be called normally, since the creation
    /// of this TestCommand causes its working directory to be set to the
    /// test's directory automatically.
    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut TestCommand {
        self.cmd.current_dir(dir);
        self
    }

    /// Runs and captures the stdout of the given command.
    pub fn stdout(&mut self) -> String {
        let o = self.output();
        let stdout = String::from_utf8_lossy(&o.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!(
                    "could not convert from string: {:?}\n\n{}",
                    err,
                    stdout
                );
            }
        }
    }

    /// Pipe `input` to a command, and collect the output.
    pub fn pipe(&mut self, input: &str) -> String {
        self.cmd.stdin(process::Stdio::piped());
        self.cmd.stdout(process::Stdio::piped());
        self.cmd.stderr(process::Stdio::piped());

        let mut child = self.cmd.spawn().unwrap();

        // Pipe input to child process using a separate thread to avoid
        // risk of deadlock between parent and child process.
        let mut stdin = child.stdin.take().expect("expected standard input");
        let input = input.to_owned();
        let worker = thread::spawn(move || {
            write!(stdin, "{}", input)
        });

        let output = self.expect_success(child.wait_with_output().unwrap());
        worker.join().unwrap().unwrap();

        let stdout = String::from_utf8_lossy(&output.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!(
                    "could not convert from string: {:?}\n\n{}",
                    err,
                    stdout
                );
            }
        }
    }

    /// Gets the output of a command. If the command failed, then this panics.
    pub fn output(&mut self) -> process::Output {
        let output = self.cmd.output().unwrap();
        self.expect_success(output)
    }

    /// Runs the command and asserts that it resulted in an error exit code.
    pub fn assert_err(&mut self) {
        let o = self.cmd.output().unwrap();
        if o.status.success() {
            panic!(
                "\n\n===== {:?} =====\n\
                 command succeeded but expected failure!\
                 \n\ncwd: {}\
                 \n\nstatus: {}\
                 \n\nstdout: {}\n\nstderr: {}\
                 \n\n=====\n",
                self.cmd,
                self.dir.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
    }

    /// Runs the command and asserts that its exit code matches expected exit
    /// code.
    pub fn assert_exit_code(&mut self, expected_code: i32) {
        let code = self.cmd.output().unwrap().status.code().unwrap();
        assert_eq!(
            expected_code, code,
            "\n\n===== {:?} =====\n\
             expected exit code did not match\
             \n\nexpected: {}\
             \n\nfound: {}\
             \n\n=====\n",
            self.cmd,
            expected_code,
            code
        );
    }

    /// Runs the command and asserts that something was printed to stderr.
    pub fn assert_non_empty_stderr(&mut self) {
        let o = self.cmd.output().unwrap();
        if o.status.success() || o.stderr.is_empty() {
            panic!(
                "\n\n===== {:?} =====\n\
                 command succeeded but expected failure!\
                 \n\ncwd: {}\
                 \n\nstatus: {}\
                 \n\nstdout: {}\n\nstderr: {}\
                 \n\n=====\n",
                self.cmd,
                self.dir.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
    }

    fn expect_success(&self, o: process::Output) -> process::Output {
        if !o.status.success() {
            let suggest =
                if o.stderr.is_empty() {
                    "\n\nDid your search end up with no results?".to_string()
                } else {
                    "".to_string()
                };

            panic!("\n\n==========\n\
                    command failed but expected success!\
                    {}\
                    \n\ncommand: {:?}\
                    \ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\
                    \n\nstderr: {}\
                    \n\n==========\n",
                   suggest, self.cmd, self.dir.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
        o
    }
}

fn nice_err<T, E: error::Error>(
    path: &Path,
    res: Result<T, E>,
) -> T {
    match res {
        Ok(t) => t,
        Err(err) => panic!("{}: {:?}", path.display(), err),
    }
}

fn repeat<F: FnMut() -> io::Result<()>>(mut f: F) -> io::Result<()> {
    let mut last_err = None;
    for _ in 0..10 {
        if let Err(err) = f() {
            last_err = Some(err);
            thread::sleep(Duration::from_millis(500));
        } else {
            return Ok(());
        }
    }
    Err(last_err.unwrap())
}
<commit_msg>tests: use const constructor for atomics<commit_after>use std::env;
use std::error;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process::{self, Command};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

static TEST_DIR: &'static str = "ripgrep-tests";
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);

/// Setup an empty work directory and return a command pointing to the ripgrep
/// executable whose CWD is set to the work directory.
///
/// The name given will be used to create the directory. Generally, it should
/// correspond to the test name.
pub fn setup(test_name: &str) -> (Dir, TestCommand) {
    let dir = Dir::new(test_name);
    let cmd = dir.command();
    (dir, cmd)
}

/// Like `setup`, but uses PCRE2 as the underlying regex engine.
pub fn setup_pcre2(test_name: &str) -> (Dir, TestCommand) {
    let mut dir = Dir::new(test_name);
    dir.pcre2(true);
    let cmd = dir.command();
    (dir, cmd)
}

/// Break the given string into lines, sort them and then join them back
/// together. This is useful for testing output from ripgrep that may not
/// always be in the same order.
pub fn sort_lines(lines: &str) -> String {
    let mut lines: Vec<&str> = lines.trim().lines().collect();
    lines.sort();
    format!("{}\n", lines.join("\n"))
}

/// Returns true if and only if the given program can be successfully executed
/// with a `--help` flag.
pub fn cmd_exists(program: &str) -> bool {
    Command::new(program).arg("--help").output().is_ok()
}

/// Dir represents a directory in which tests should be run.
///
/// Directories are created from a global atomic counter to avoid duplicates.
#[derive(Clone, Debug)]
pub struct Dir {
    /// The directory in which this test executable is running.
    root: PathBuf,
    /// The directory in which the test should run. If a test needs to create
    /// files, they should go in here. This directory is also used as the CWD
    /// for any processes created by the test.
    dir: PathBuf,
    /// Set to true when the test should use PCRE2 as the regex engine.
    pcre2: bool,
}

impl Dir {
    /// Create a new test working directory with the given name. The name
    /// does not need to be distinct for each invocation, but should correspond
    /// to a logical grouping of tests.
    pub fn new(name: &str) -> Dir {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        let root = env::current_exe()
            .unwrap()
            .parent()
            .expect("executable's directory")
            .to_path_buf();
        let dir = env::temp_dir()
            .join(TEST_DIR)
            .join(name)
            .join(&format!("{}", id));
        nice_err(&dir, repeat(|| fs::create_dir_all(&dir)));
        Dir {
            root: root,
            dir: dir,
            pcre2: false,
        }
    }

    /// Use PCRE2 for this test.
    pub fn pcre2(&mut self, yes: bool) {
        self.pcre2 = yes;
    }

    /// Returns true if and only if this test is configured to use PCRE2 as
    /// the regex engine.
    pub fn is_pcre2(&self) -> bool {
        self.pcre2
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create<P: AsRef<Path>>(&self, name: P, contents: &str) {
        self.create_bytes(name, contents.as_bytes());
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    #[allow(dead_code)] // unused on Windows
    pub fn try_create<P: AsRef<Path>>(
        &self,
        name: P,
        contents: &str,
    ) -> io::Result<()> {
        let path = self.dir.join(name);
        self.try_create_bytes(path, contents.as_bytes())
    }

    /// Create a new file with the given name and size.
    pub fn create_size<P: AsRef<Path>>(&self, name: P, filesize: u64) {
        let path = self.dir.join(name);
        let file = nice_err(&path, File::create(&path));
        nice_err(&path, file.set_len(filesize));
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create_bytes<P: AsRef<Path>>(&self, name: P, contents: &[u8]) {
        let path = self.dir.join(&name);
        nice_err(&path, self.try_create_bytes(name, contents));
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    pub fn try_create_bytes<P: AsRef<Path>>(
        &self,
        name: P,
        contents: &[u8],
    ) -> io::Result<()> {
        let path = self.dir.join(name);
        let mut file = File::create(path)?;
        file.write_all(contents)?;
        file.flush()
    }

    /// Remove a file with the given name from this directory.
    pub fn remove<P: AsRef<Path>>(&self, name: P) {
        let path = self.dir.join(name);
        nice_err(&path, fs::remove_file(&path));
    }

    /// Create a new directory with the given path (and any directories above
    /// it) inside this directory.
    pub fn create_dir<P: AsRef<Path>>(&self, path: P) {
        let path = self.dir.join(path);
        nice_err(&path, repeat(|| fs::create_dir_all(&path)));
    }

    /// Creates a new command that is set to use the ripgrep executable in
    /// this working directory.
    ///
    /// This also:
    ///
    /// * Unsets the `RIPGREP_CONFIG_PATH` environment variable.
    /// * Sets the `--path-separator` to `/` so that paths have the same output
    ///   on all systems. Tests that need to check `--path-separator` itself
    ///   can simply pass it again to override it.
    pub fn command(&self) -> TestCommand {
        let mut cmd = process::Command::new(&self.bin());
        cmd.env_remove("RIPGREP_CONFIG_PATH");
        cmd.current_dir(&self.dir);
        cmd.arg("--path-separator").arg("/");
        if self.is_pcre2() {
            cmd.arg("--pcre2");
        }
        TestCommand { dir: self.clone(), cmd: cmd }
    }

    /// Returns the path to the ripgrep executable.
    pub fn bin(&self) -> PathBuf {
        if cfg!(windows) {
            self.root.join("../rg.exe")
        } else {
            self.root.join("../rg")
        }
    }

    /// Returns the path to this directory.
    pub fn path(&self) -> &Path {
        &self.dir
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::unix::fs::symlink;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink(&src, &target));
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::windows::fs::symlink_dir;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_dir(&target);
        nice_err(&target, symlink_dir(&src, &target));
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        self.link_dir(src, target);
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    #[allow(dead_code)] // unused on Windows
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        use std::os::windows::fs::symlink_file;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink_file(&src, &target));
    }
}

/// A simple wrapper around a process::Command with some conveniences.
#[derive(Debug)]
pub struct TestCommand {
    /// The dir used to launched this command.
    dir: Dir,
    /// The actual command we use to control the process.
    cmd: Command,
}

impl TestCommand {
    /// Returns a mutable reference to the underlying command.
    pub fn cmd(&mut self) -> &mut Command {
        &mut self.cmd
    }

    /// Add an argument to pass to the command.
    pub fn arg<A: AsRef<OsStr>>(&mut self, arg: A) -> &mut TestCommand {
        self.cmd.arg(arg);
        self
    }

    /// Add any number of arguments to the command.
    pub fn args<I, A>(
        &mut self,
        args: I,
    ) -> &mut TestCommand
    where I: IntoIterator<Item=A>,
          A: AsRef<OsStr>
    {
        self.cmd.args(args);
        self
    }

    /// Set the working directory for this command.
    ///
    /// Note that this does not need to be called normally, since the creation
    /// of this TestCommand causes its working directory to be set to the
    /// test's directory automatically.
    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut TestCommand {
        self.cmd.current_dir(dir);
        self
    }

    /// Runs and captures the stdout of the given command.
    pub fn stdout(&mut self) -> String {
        let o = self.output();
        let stdout = String::from_utf8_lossy(&o.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!(
                    "could not convert from string: {:?}\n\n{}",
                    err,
                    stdout
                );
            }
        }
    }

    /// Pipe `input` to a command, and collect the output.
    pub fn pipe(&mut self, input: &str) -> String {
        self.cmd.stdin(process::Stdio::piped());
        self.cmd.stdout(process::Stdio::piped());
        self.cmd.stderr(process::Stdio::piped());

        let mut child = self.cmd.spawn().unwrap();

        // Pipe input to child process using a separate thread to avoid
        // risk of deadlock between parent and child process.
        let mut stdin = child.stdin.take().expect("expected standard input");
        let input = input.to_owned();
        let worker = thread::spawn(move || {
            write!(stdin, "{}", input)
        });

        let output = self.expect_success(child.wait_with_output().unwrap());
        worker.join().unwrap().unwrap();

        let stdout = String::from_utf8_lossy(&output.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!(
                    "could not convert from string: {:?}\n\n{}",
                    err,
                    stdout
                );
            }
        }
    }

    /// Gets the output of a command. If the command failed, then this panics.
    pub fn output(&mut self) -> process::Output {
        let output = self.cmd.output().unwrap();
        self.expect_success(output)
    }

    /// Runs the command and asserts that it resulted in an error exit code.
    pub fn assert_err(&mut self) {
        let o = self.cmd.output().unwrap();
        if o.status.success() {
            panic!(
                "\n\n===== {:?} =====\n\
                 command succeeded but expected failure!\
                 \n\ncwd: {}\
                 \n\nstatus: {}\
                 \n\nstdout: {}\n\nstderr: {}\
                 \n\n=====\n",
                self.cmd,
                self.dir.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
    }

    /// Runs the command and asserts that its exit code matches expected exit
    /// code.
    pub fn assert_exit_code(&mut self, expected_code: i32) {
        let code = self.cmd.output().unwrap().status.code().unwrap();
        assert_eq!(
            expected_code, code,
            "\n\n===== {:?} =====\n\
             expected exit code did not match\
             \n\nexpected: {}\
             \n\nfound: {}\
             \n\n=====\n",
            self.cmd,
            expected_code,
            code
        );
    }

    /// Runs the command and asserts that something was printed to stderr.
    pub fn assert_non_empty_stderr(&mut self) {
        let o = self.cmd.output().unwrap();
        if o.status.success() || o.stderr.is_empty() {
            panic!(
                "\n\n===== {:?} =====\n\
                 command succeeded but expected failure!\
                 \n\ncwd: {}\
                 \n\nstatus: {}\
                 \n\nstdout: {}\n\nstderr: {}\
                 \n\n=====\n",
                self.cmd,
                self.dir.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
    }

    fn expect_success(&self, o: process::Output) -> process::Output {
        if !o.status.success() {
            let suggest =
                if o.stderr.is_empty() {
                    "\n\nDid your search end up with no results?".to_string()
                } else {
                    "".to_string()
                };

            panic!("\n\n==========\n\
                    command failed but expected success!\
                    {}\
                    \n\ncommand: {:?}\
                    \ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\
                    \n\nstderr: {}\
                    \n\n==========\n",
                   suggest, self.cmd, self.dir.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
        o
    }
}

fn nice_err<T, E: error::Error>(
    path: &Path,
    res: Result<T, E>,
) -> T {
    match res {
        Ok(t) => t,
        Err(err) => panic!("{}: {:?}", path.display(), err),
    }
}

fn repeat<F: FnMut() -> io::Result<()>>(mut f: F) -> io::Result<()> {
    let mut last_err = None;
    for _ in 0..10 {
        if let Err(err) = f() {
            last_err = Some(err);
            thread::sleep(Duration::from_millis(500));
        } else {
            return Ok(());
        }
    }
    Err(last_err.unwrap())
}
<|endoftext|>


<commit_before>use utils::gas::Gas;
use utils::address::Address;
use utils::bigint::U256;

use super::errors::RequireError;
use super::{Context, AccountState};

pub enum Transaction {
    MessageCall {
        address: Address,
        caller: Address,
        gas_price: Gas,
        gas_limit: Gas,
        value: U256,
        data: Vec<u8>,
    },
    ContractCreation {
        caller: Address,
        gas_price: Gas,
        gas_limit: Gas,
        value: U256,
        init: Vec<u8>,
    },
}

impl Transaction {
    #[allow(unused_variables)]
    pub fn intrinsic_gas(&self) -> Gas {
        unimplemented!()
    }

    #[allow(unused_variables)]
    pub fn into_context(self, origin: Option<Address>,
                        account_state: AccountState) -> Result<Context, RequireError> {
        unimplemented!()
    }
}
<commit_msg>Problem: #152 wrapping transactions for VM<commit_after>use utils::gas::Gas;
use utils::address::Address;
use utils::bigint::U256;

use super::errors::RequireError;
use super::{Context, ContextVM, AccountState, BlockhashState, Patch, BlockHeader, Memory};

pub enum Transaction {
    MessageCall {
        address: Address,
        caller: Address,
        gas_price: Gas,
        gas_limit: Gas,
        value: U256,
        data: Vec<u8>,
    },
    ContractCreation {
        caller: Address,
        gas_price: Gas,
        gas_limit: Gas,
        value: U256,
        init: Vec<u8>,
    },
}

impl Transaction {
    #[allow(unused_variables)]
    pub fn intrinsic_gas(&self) -> Gas {
        unimplemented!()
    }

    #[allow(unused_variables)]
    pub fn into_context(self, origin: Option<Address>,
                        account_state: &AccountState) -> Result<Context, RequireError> {
        unimplemented!()
    }
}

enum TransactionVMState<M> {
    Running {
        vm: ContextVM<M>,
        intrinsic_gas: Gas,
    },
    Constructing {
        transaction: Transaction,
        block: BlockHeader,
        patch: &'static Patch,

        account_state: AccountState,
        blockhash_state: BlockhashState,
    },
}

pub struct TransactionVM<M>(TransactionVMState<M>);

impl<M: Memory + Default> TransactionVM<M> {
    pub fn new(transaction: Transaction, block: BlockHeader, patch: &'static Patch) -> Self {
        TransactionVM(TransactionVMState::Constructing {
            transaction: transaction,
            block: block,
            patch: patch,

            account_state: AccountState::default(),
            blockhash_state: BlockhashState::default(),
        })
    }
}
<|endoftext|>