<commit_before>extern crate rustyline;
extern crate easy_ll;
extern crate weld;

use rustyline::error::ReadlineError;
use rustyline::Editor;
use std::env;
use std::path::Path;
use std::path::PathBuf;
use std::fs::File;
use std::error::Error;
use std::io::prelude::*;
use std::fmt;
use std::collections::HashMap;

use weld::*;
use weld::llvm::LlvmGenerator;
use weld::parser::*;
use weld::pretty_print::*;
use weld::type_inference::*;
use weld::sir::ast_to_sir;

// To prevent de-duplication. Really annoying to have these everywhere...how to prevent them from
// being optimized out?
fn runtime_functions() {
    weld_rt_free(0, weld_rt_realloc(0, weld_rt_malloc(0, 16), 32));
    weld_rt_set_errno(-1, WeldRuntimeErrno::Success);
    weld_rt_get_errno(-1);
    // TODO(shoumik): just print out the function pointers, like James did in integration tests.
    let x = new_merger(0, 16, 1);
    if get_merger_at_index(x, 16, 0) != std::ptr::null_mut() {
        free_merger(0, x);
    }

}

enum ReplCommands {
    LoadFile,
}

impl fmt::Display for ReplCommands {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReplCommands::LoadFile => write!(f, "load"),
        }
    }
}

/// Processes the LoadFile command.
///
/// The argument is a filename containing a Weld program. Returns the string
/// representation of the program or an error with an error message.
fn process_loadfile(arg: String) -> Result<String, String> {
    if arg.len() == 0 {
        return Err("Error: expected argument for command 'load'".to_string());
    }
    let path = Path::new(&arg);
    let path_display = path.display();
    let mut file;
    match File::open(&path) {
        Err(why) => {
            return Err(format!("Error: couldn't open {}: {}",
                               path_display,
                               why.description()));
        }
        Ok(res) => {
            file = res;
        }
    }

    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Err(why) => {
            return Err(format!("Error: couldn't read {}: {}",
                               path_display,
                               why.description()));
        }
        _ => {}
    }
    Ok(contents.trim().to_string())
}

fn main() {
    let home_path = env::home_dir().unwrap_or(PathBuf::new());
    let history_file_path = home_path.join(".weld_history");
    let history_file_path = history_file_path.to_str().unwrap_or(".weld_history");

    runtime_functions();

    let mut reserved_words = HashMap::new();
    reserved_words.insert(ReplCommands::LoadFile.to_string(), ReplCommands::LoadFile);

    let mut rl = Editor::<()>::new();
    if let Err(_) = rl.load_history(&history_file_path) {}

    loop {
        let raw_readline = rl.readline(">> ");
        let readline;
        match raw_readline {
            Ok(raw_readline) => {
                rl.add_history_entry(&raw_readline);
                readline = raw_readline;
            }
            Err(ReadlineError::Interrupted) => {
                println!("Exiting!");
                break;
            }
            Err(ReadlineError::Eof) => {
                println!("Exiting!");
                break;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }

        let trimmed = readline.trim();
        if trimmed == "" {
            continue;
        }

        let program;

        // Do some basic token parsing here.
        let mut tokens = trimmed.splitn(2, " ");
        let command = tokens.next().unwrap();
        let arg = tokens.next().unwrap_or("");
        if reserved_words.contains_key(command) {
            let command = reserved_words.get(command).unwrap();
            match *command {
                ReplCommands::LoadFile => {
                    match process_loadfile(arg.to_string()) {
                        Err(s) => {
                            println!("{}", s);
                            continue;
                        }
                        Ok(code) => {
                            program = parse_program(&code);
                        }
                    }
                }
            }
        } else {
            program = parse_program(trimmed);
        }

        if let Err(ref e) = program {
            println!("Error during parsing: {:?}", e);
            continue;
        }
        let program = program.unwrap();
        println!("Raw structure:\n{:?}\n", program);

        let expr = macro_processor::process_program(&program);
        if let Err(ref e) = expr {
            println!("Error during macro substitution: {}", e);
            continue;
        }
        let mut expr = expr.unwrap();
        println!("After macro substitution:\n{}\n", print_expr(&expr));

        transforms::inline_apply(&mut expr);
        println!("After inline_apply:\n{}\n", print_expr(&expr));

        transforms::uniquify(&mut expr);
        println!("After uniquify :\n{}\n", print_expr(&expr));

        if let Err(ref e) = infer_types(&mut expr) {
            println!("Error during type inference: {}\n", e);
            println!("Partially inferred types:\n{}\n", print_typed_expr(&expr));
            continue;
        }
        println!("After type inference:\n{}\n", print_typed_expr(&expr));
        println!("Expression type: {}\n", print_type(&expr.ty));

        let mut expr = expr.to_typed().unwrap();

        transforms::inline_zips(&mut expr);
        println!("After inlining zips:\n{}\n", print_typed_expr(&expr));

        transforms::fuse_loops_horizontal(&mut expr);
        println!("After horizontal loop fusion:\n{}\n",
                 print_typed_expr(&expr));

        transforms::fuse_loops_vertical(&mut expr);
        println!("After vertical loop fusion:\n{}\n", print_typed_expr(&expr));

        println!("final program raw: {:?}", expr);

        let sir_result = ast_to_sir(&expr);
        match sir_result {
            Ok(sir) => {
                println!("SIR representation:\n{}\n", &sir);
                let mut llvm_gen = LlvmGenerator::new();
                if let Err(ref e) = llvm_gen.add_function_on_pointers("run", &sir) {
                    println!("Error during LLVM code gen:\n{}\n", e);
                } else {
                    let llvm_code = llvm_gen.result();
                    println!("LLVM code:\n{}\n", llvm_code);

                    if let Err(ref e) = easy_ll::compile_module(&llvm_code) {
                        println!("Error during LLVM compilation:\n{}\n", e);
                    } else {
                        println!("LLVM module compiled successfully\n");
                    }
                }
            }
            Err(ref e) => {
                println!("Error during SIR code gen:\n{}\n", e);
            }
        }
    }
    rl.save_history(&history_file_path).unwrap();
}
<commit_msg>Fixes REPL bug (#75)<commit_after>extern crate rustyline;
extern crate easy_ll;
extern crate weld;

use rustyline::error::ReadlineError;
use rustyline::Editor;
use std::env;
use std::path::Path;
use std::path::PathBuf;
use std::fs::File;
use std::error::Error;
use std::io::prelude::*;
use std::fmt;
use std::collections::HashMap;

use weld::*;
use weld::llvm::LlvmGenerator;
use weld::parser::*;
use weld::pretty_print::*;
use weld::type_inference::*;
use weld::sir::ast_to_sir;

enum ReplCommands {
    LoadFile,
    PrintFunctions,
}

impl fmt::Display for ReplCommands {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ReplCommands::LoadFile => write!(f, "load"),
            ReplCommands::PrintFunctions => write!(f, "print_functions"),
        }
    }
}

/// Processes the LoadFile command.
///
/// The argument is a filename containing a Weld program. Returns the string
/// representation of the program or an error with an error message.
fn process_loadfile(arg: String) -> Result<String, String> {
    if arg.len() == 0 {
        return Err("Error: expected argument for command 'load'".to_string());
    }
    let path = Path::new(&arg);
    let path_display = path.display();
    let mut file;
    match File::open(&path) {
        Err(why) => {
            return Err(format!("Error: couldn't open {}: {}",
                               path_display,
                               why.description()));
        }
        Ok(res) => {
            file = res;
        }
    }

    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Err(why) => {
            return Err(format!("Error: couldn't read {}: {}",
                               path_display,
                               why.description()));
        }
        _ => {}
    }
    Ok(contents.trim().to_string())
}

fn main() {
    let home_path = env::home_dir().unwrap_or(PathBuf::new());
    let history_file_path = home_path.join(".weld_history");
    let history_file_path = history_file_path.to_str().unwrap_or(".weld_history");

    let mut reserved_words = HashMap::new();
    reserved_words.insert(ReplCommands::LoadFile.to_string(), ReplCommands::LoadFile);
    reserved_words.insert(ReplCommands::PrintFunctions.to_string(),
                          ReplCommands::PrintFunctions);

    let mut rl = Editor::<()>::new();
    if let Err(_) = rl.load_history(&history_file_path) {}

    loop {
        let raw_readline = rl.readline(">> ");
        let readline;
        match raw_readline {
            Ok(raw_readline) => {
                rl.add_history_entry(&raw_readline);
                readline = raw_readline;
            }
            Err(ReadlineError::Interrupted) => {
                println!("Exiting!");
                break;
            }
            Err(ReadlineError::Eof) => {
                println!("Exiting!");
                break;
            }
            Err(err) => {
                println!("Error: {:?}", err);
                break;
            }
        }

        let trimmed = readline.trim();
        if trimmed == "" {
            continue;
        }

        let program;

        // Do some basic token parsing here.
        let mut tokens = trimmed.splitn(2, " ");
        let command = tokens.next().unwrap();
        let arg = tokens.next().unwrap_or("");
        if reserved_words.contains_key(command) {
            let command = reserved_words.get(command).unwrap();
            match *command {
                ReplCommands::LoadFile => {
                    match process_loadfile(arg.to_string()) {
                        Err(s) => {
                            println!("{}", s);
                            continue;
                        }
                        Ok(code) => {
                            program = parse_program(&code);
                        }
                    }
                }
                ReplCommands::PrintFunctions => {
                    weld::weld_print_function_pointers();
                    continue;
                }
            }
        } else {
            program = parse_program(trimmed);
        }

        if let Err(ref e) = program {
            println!("Error during parsing: {:?}", e);
            continue;
        }
        let program = program.unwrap();
        println!("Raw structure:\n{:?}\n", program);

        let expr = macro_processor::process_program(&program);
        if let Err(ref e) = expr {
            println!("Error during macro substitution: {}", e);
            continue;
        }
        let mut expr = expr.unwrap();
        println!("After macro substitution:\n{}\n", print_expr(&expr));

        transforms::inline_apply(&mut expr);
        println!("After inline_apply:\n{}\n", print_expr(&expr));

        transforms::uniquify(&mut expr);
        println!("After uniquify :\n{}\n", print_expr(&expr));

        if let Err(ref e) = infer_types(&mut expr) {
            println!("Error during type inference: {}\n", e);
            println!("Partially inferred types:\n{}\n", print_typed_expr(&expr));
            continue;
        }
        println!("After type inference:\n{}\n", print_typed_expr(&expr));
        println!("Expression type: {}\n", print_type(&expr.ty));

        let mut expr = expr.to_typed().unwrap();

        transforms::inline_zips(&mut expr);
        println!("After inlining zips:\n{}\n", print_typed_expr(&expr));

        transforms::fuse_loops_horizontal(&mut expr);
        println!("After horizontal loop fusion:\n{}\n",
                 print_typed_expr(&expr));

        transforms::fuse_loops_vertical(&mut expr);
        println!("After vertical loop fusion:\n{}\n", print_typed_expr(&expr));

        println!("final program raw: {:?}", expr);

        let sir_result = ast_to_sir(&expr);
        match sir_result {
            Ok(sir) => {
                println!("SIR representation:\n{}\n", &sir);
                let mut llvm_gen = LlvmGenerator::new();
                if let Err(ref e) = llvm_gen.add_function_on_pointers("run", &sir) {
                    println!("Error during LLVM code gen:\n{}\n", e);
                } else {
                    let llvm_code = llvm_gen.result();
                    println!("LLVM code:\n{}\n", llvm_code);

                    if let Err(ref e) = easy_ll::compile_module(&llvm_code) {
                        println!("Error during LLVM compilation:\n{}\n", e);
                    } else {
                        println!("LLVM module compiled successfully\n");
                    }
                }
            }
            Err(ref e) => {
                println!("Error during SIR code gen:\n{}\n", e);
            }
        }
    }
    rl.save_history(&history_file_path).unwrap();
}
<|endoftext|>


<commit_before>use std::io::{BufferedReader, File};
use material::materials::CookTorranceMaterial;
use geometry::{Mesh, Prim};
use geometry::prims::Triangle;
use raytracer::compositor::{Surface, ColorRGBA};
use vec3::Vec3;

/// This is limited to only CookTorranceMaterials, as I couldn't get a Box<Material> to clone
/// a new material for each triangle primitive in the object model.
#[allow(dead_code)]
pub fn from_obj(position: Vec3, scale: f64, material: CookTorranceMaterial /*Box<Material>*/, flip_normals: bool, filename: &str) -> Mesh {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));

    let mut vertices: Vec<Vec3> = Vec::new();
    let mut tex_coords: Vec<Vec<f64>> = Vec::new();
    let mut normals: Vec<Vec3> = Vec::new();
    let mut triangles: Vec<Box<Prim+Send+Share>> = Vec::new();

    let start_time = ::time::get_time();
    let print_progress_every = 1024u;
    let mut current_line = 0;
    let mut processed_bytes = 0;
    let total_bytes = match path.stat() {
        Ok(stat) => stat.size,
        Err(e) => fail!(e)
    };

    for line_iter in file.lines() {
        let line: String = match line_iter {
            Ok(x) => x,
            Err(e) => fail!("Could not open file {} (file missing?): {}", filename, e)
        };

        let tokens: Vec<&str> = line.as_slice().words().collect();
        if tokens.len() < 4 { continue }

        match tokens[0].as_slice() {
            "v" => {
                vertices.push(Vec3 {
                    x: parse_coord_str(tokens[1].as_slice(), scale, line.as_slice()),
                    y: parse_coord_str(tokens[2].as_slice(), scale, line.as_slice()),
                    z: parse_coord_str(tokens[3].as_slice(), scale, line.as_slice()),
                });
            },
            "vt" => {
                tex_coords.push(vec![
                    parse_coord_str(tokens[1].as_slice(), scale, line.as_slice()),
                    parse_coord_str(tokens[2].as_slice(), scale, line.as_slice())
                ]);
            },
            "vn" => {
                let normals_flip_scale = if flip_normals { -1.0 } else { 1.0 } * scale;
                normals.push(Vec3 {
                    x: parse_coord_str(tokens[1].as_slice(), scale * normals_flip_scale, line.as_slice()),
                    y: parse_coord_str(tokens[2].as_slice(), scale * normals_flip_scale, line.as_slice()),
                    z: parse_coord_str(tokens[3].as_slice(), scale * normals_flip_scale, line.as_slice()),
                });
            },
            "f" => {
                // ["f", "1/2/3", "2/2/2", "12//4"] => [[1, 2, 3], [2, 2, 2], [12, -1u, 4]]
                let pairs: Vec<Vec<uint>> = tokens.tail().iter().map( |token| {
                    let str_tokens: Vec<&str> = token.as_slice().split('/').collect();
                    str_tokens.iter().map( |str_tok| {
                        match from_str::<uint>(*str_tok) {
                            Some(uint_tok) => uint_tok - 1,
                            None => !0 // No data available/not supplied
                        }
                    }).collect()
                }).collect();

                // If no texture coordinates were supplied, default to zero.
                let mut u = Vec3::zero();
                let mut v = Vec3::zero();

                // We store nothing supplied as !0
                if pairs[0][1] != !0 {
                    u = Vec3 {
                        x: tex_coords[pairs[0][1]][0],
                        y: tex_coords[pairs[1][1]][0],
                        z: tex_coords[pairs[2][1]][0]
                    };

                    v = Vec3 {
                        x: tex_coords[pairs[0][1]][1],
                        y: tex_coords[pairs[1][1]][1],
                        z: tex_coords[pairs[2][1]][1]
                    };
                }

                triangles.push(box Triangle {
                    v0: vertices[pairs[0][0]],
                    v1: vertices[pairs[1][0]],
                    v2: vertices[pairs[2][0]],

                    n0: normals[pairs[0][2]],
                    n1: normals[pairs[1][2]],
                    n2: normals[pairs[2][2]],

                    u: u,
                    v: v,
                    material: box material.clone()
                });
            },
            _ => {}
        }

        current_line += 1;
        processed_bytes += line.as_bytes().len();
        if current_line % print_progress_every == 0 {
            ::util::print_progress("Bytes", start_time, processed_bytes, total_bytes as uint);
        }
    }

    // Cheat the progress meter
    ::util::print_progress("Bytes", start_time, total_bytes as uint, total_bytes as uint);

    Mesh {
        position: position,
        scale: scale,
        triangles: triangles
    }
}

fn parse_coord_str(coord: &str, scale: f64, line: &str) -> f64 {
    match from_str::<f64>(coord.as_slice()) {
        Some(f) => f * scale,
        None => fail!(format!("Bad vertex or texture coordinate in file. `{}`", line))
    }
}

#[allow(dead_code)]
pub fn from_ppm(filename: &str) -> Surface {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));

    let tex = match file.read_to_string() { Ok(f) => f, Err(e) => { fail!("Could not open file {} (file missing?): {}", filename, e) }};
    let mut tokens: Vec<&str> = tex.as_slice().words().collect();

    tokens.remove(0); // PPM type
    let width  = match tokens.remove(0) { Some(x) => uint_from_string(x), None => fail!("Bad PPM") };
    let height = match tokens.remove(0) { Some(x) => uint_from_string(x), None => fail!("Bad PPM") };
    tokens.remove(0); // Max color value

    print!("Importing image texture {}", filename);
    println!(" {}x{}", width, height);

    let mut surface = Surface::new(width, height, ColorRGBA::new_rgb(0, 0, 0));

    let mut i = 0u;

    for chunk in tokens.as_slice().chunks(3) {
        let x = i % width;
        let y = i / width;
        i += 1;

        if x >= width || y >= height { break };

        *surface.get_mut(x, y) = ColorRGBA::new_rgb(
            uint_from_string(chunk[0]) as u8,
            uint_from_string(chunk[1]) as u8,
            uint_from_string(chunk[2]) as u8
        );
    }

    surface
}

fn uint_from_string(s: &str) -> uint {
     match from_str::<uint>(s) {
        Some(x) => x,
        None => fail!("Bad uint string {}", s)
    }
}
<commit_msg>Better error message for missing model file.<commit_after>use std::io::{BufferedReader, File};
use material::materials::CookTorranceMaterial;
use geometry::{Mesh, Prim};
use geometry::prims::Triangle;
use raytracer::compositor::{Surface, ColorRGBA};
use vec3::Vec3;

/// This is limited to only CookTorranceMaterials, as I couldn't get a Box<Material> to clone
/// a new material for each triangle primitive in the object model.
#[allow(dead_code)]
pub fn from_obj(position: Vec3, scale: f64, material: CookTorranceMaterial /*Box<Material>*/, flip_normals: bool, filename: &str) -> Mesh {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));

    let mut vertices: Vec<Vec3> = Vec::new();
    let mut tex_coords: Vec<Vec<f64>> = Vec::new();
    let mut normals: Vec<Vec3> = Vec::new();
    let mut triangles: Vec<Box<Prim+Send+Share>> = Vec::new();

    let start_time = ::time::get_time();
    let print_progress_every = 1024u;
    let mut current_line = 0;
    let mut processed_bytes = 0;
    let total_bytes = match path.stat() {
        Ok(stat) => stat.size,
        Err(e) => fail!("Could not open file {} (file missing?): {}", filename, e)
    };

    for line_iter in file.lines() {
        let line: String = match line_iter {
            Ok(x) => x,
            Err(e) => fail!("Could not open file {} (file missing?): {}", filename, e)
        };

        let tokens: Vec<&str> = line.as_slice().words().collect();
        if tokens.len() < 4 { continue }

        match tokens[0].as_slice() {
            "v" => {
                vertices.push(Vec3 {
                    x: parse_coord_str(tokens[1].as_slice(), scale, line.as_slice()),
                    y: parse_coord_str(tokens[2].as_slice(), scale, line.as_slice()),
                    z: parse_coord_str(tokens[3].as_slice(), scale, line.as_slice()),
                });
            },
            "vt" => {
                tex_coords.push(vec![
                    parse_coord_str(tokens[1].as_slice(), scale, line.as_slice()),
                    parse_coord_str(tokens[2].as_slice(), scale, line.as_slice())
                ]);
            },
            "vn" => {
                let normals_flip_scale = if flip_normals { -1.0 } else { 1.0 } * scale;
                normals.push(Vec3 {
                    x: parse_coord_str(tokens[1].as_slice(), scale * normals_flip_scale, line.as_slice()),
                    y: parse_coord_str(tokens[2].as_slice(), scale * normals_flip_scale, line.as_slice()),
                    z: parse_coord_str(tokens[3].as_slice(), scale * normals_flip_scale, line.as_slice()),
                });
            },
            "f" => {
                // ["f", "1/2/3", "2/2/2", "12//4"] => [[1, 2, 3], [2, 2, 2], [12, -1u, 4]]
                let pairs: Vec<Vec<uint>> = tokens.tail().iter().map( |token| {
                    let str_tokens: Vec<&str> = token.as_slice().split('/').collect();
                    str_tokens.iter().map( |str_tok| {
                        match from_str::<uint>(*str_tok) {
                            Some(uint_tok) => uint_tok - 1,
                            None => !0 // No data available/not supplied
                        }
                    }).collect()
                }).collect();

                // If no texture coordinates were supplied, default to zero.
                let mut u = Vec3::zero();
                let mut v = Vec3::zero();

                // We store nothing supplied as !0
                if pairs[0][1] != !0 {
                    u = Vec3 {
                        x: tex_coords[pairs[0][1]][0],
                        y: tex_coords[pairs[1][1]][0],
                        z: tex_coords[pairs[2][1]][0]
                    };

                    v = Vec3 {
                        x: tex_coords[pairs[0][1]][1],
                        y: tex_coords[pairs[1][1]][1],
                        z: tex_coords[pairs[2][1]][1]
                    };
                }

                triangles.push(box Triangle {
                    v0: vertices[pairs[0][0]],
                    v1: vertices[pairs[1][0]],
                    v2: vertices[pairs[2][0]],

                    n0: normals[pairs[0][2]],
                    n1: normals[pairs[1][2]],
                    n2: normals[pairs[2][2]],

                    u: u,
                    v: v,
                    material: box material.clone()
                });
            },
            _ => {}
        }

        current_line += 1;
        processed_bytes += line.as_bytes().len();
        if current_line % print_progress_every == 0 {
            ::util::print_progress("Bytes", start_time, processed_bytes, total_bytes as uint);
        }
    }

    // Cheat the progress meter
    ::util::print_progress("Bytes", start_time, total_bytes as uint, total_bytes as uint);

    Mesh {
        position: position,
        scale: scale,
        triangles: triangles
    }
}

fn parse_coord_str(coord: &str, scale: f64, line: &str) -> f64 {
    match from_str::<f64>(coord.as_slice()) {
        Some(f) => f * scale,
        None => fail!(format!("Bad vertex or texture coordinate in file. `{}`", line))
    }
}

#[allow(dead_code)]
pub fn from_ppm(filename: &str) -> Surface {
    let path = Path::new(filename);
    let mut file = BufferedReader::new(File::open(&path));

    let tex = match file.read_to_string() { Ok(f) => f, Err(e) => { fail!("Could not open file {} (file missing?): {}", filename, e) }};
    let mut tokens: Vec<&str> = tex.as_slice().words().collect();

    tokens.remove(0); // PPM type
    let width  = match tokens.remove(0) { Some(x) => uint_from_string(x), None => fail!("Bad PPM") };
    let height = match tokens.remove(0) { Some(x) => uint_from_string(x), None => fail!("Bad PPM") };
    tokens.remove(0); // Max color value

    print!("Importing image texture {}", filename);
    println!(" {}x{}", width, height);

    let mut surface = Surface::new(width, height, ColorRGBA::new_rgb(0, 0, 0));

    let mut i = 0u;

    for chunk in tokens.as_slice().chunks(3) {
        let x = i % width;
        let y = i / width;
        i += 1;

        if x >= width || y >= height { break };

        *surface.get_mut(x, y) = ColorRGBA::new_rgb(
            uint_from_string(chunk[0]) as u8,
            uint_from_string(chunk[1]) as u8,
            uint_from_string(chunk[2]) as u8
        );
    }

    surface
}

fn uint_from_string(s: &str) -> uint {
     match from_str::<uint>(s) {
        Some(x) => x,
        None => fail!("Bad uint string {}", s)
    }
}
<|endoftext|>


<commit_before>#![feature(globs, phase, macro_rules)]

#[phase(link, plugin)]
extern crate support;

extern crate input;
extern crate opentype;

use support::*;

#[cfg(test)]
mod Structure {
    use support::*;
    use input::Structure;
    use opentype::format::{OffsetTable, CFF_FORMAT_TAG};

    #[test]
    fn read_test() {
        let mut file = open_fixture!("SourceSerifPro-Regular.otf");

        let table: OffsetTable = Structure::read(&mut file).unwrap();

        assert_eq!(table.tag, CFF_FORMAT_TAG);
        assert_eq!(table.numTables, 12);
        assert_eq!(table.searchRange, 8 * 16);
        assert_eq!(table.entrySelector, 3);
        assert_eq!(table.rangeShift, table.numTables * 16 - table.searchRange);
    }
}

#[test]
fn stringify_le_u32_test() {
    assert_eq!(input::stringify_le_u32(0x64636261).unwrap().as_slice(), "abcd");
}

#[test]
fn read_be_u16_test() {
    let mut file = open_fixture!("SourceSerifPro-Regular.otf");

    match input::read_be_u32(&mut file, 1).unwrap().as_slice() {
        [one, .. rest] => {
            assert_eq!(one, 0x4F54544F);
            assert!(rest.is_empty());
        }
        _ => assert!(false)
    }
}
<commit_msg>Improved a bit the read_be_u32 test<commit_after>#![feature(globs, phase, macro_rules)]

#[phase(link, plugin)]
extern crate support;

extern crate input;
extern crate opentype;

use support::*;

#[cfg(test)]
mod Structure {
    use support::*;
    use input::Structure;
    use opentype::format::{OffsetTable, CFF_FORMAT_TAG};

    #[test]
    fn read_test() {
        let mut file = open_fixture!("SourceSerifPro-Regular.otf");

        let table: OffsetTable = Structure::read(&mut file).unwrap();

        assert_eq!(table.tag, CFF_FORMAT_TAG);
        assert_eq!(table.numTables, 12);
        assert_eq!(table.searchRange, 8 * 16);
        assert_eq!(table.entrySelector, 3);
        assert_eq!(table.rangeShift, table.numTables * 16 - table.searchRange);
    }
}

#[test]
fn stringify_le_u32_test() {
    assert_eq!(input::stringify_le_u32(0x64636261).unwrap().as_slice(), "abcd");
}

#[test]
fn read_be_u32_test() {
    let mut file = open_fixture!("SourceSerifPro-Regular.otf");

    match input::read_be_u32(&mut file, 2).unwrap().as_slice() {
        [one, two, .. rest] => {
            assert_eq!(one, 0x4F54544F);
            assert_eq!(two, 0x000C0080);
            assert!(rest.is_empty());
        }
        _ => assert!(false)
    }
}
<|endoftext|>


<commit_before>mod utils;

use clap::{Args, Parser};

#[test]
fn generic() {
    #[derive(Args, PartialEq, Debug)]
    struct A {
        arg: i32,
    }

    #[derive(Args, PartialEq, Debug)]
    struct B {
        arg: String,
    }

    #[derive(Parser, PartialEq, Debug)]
    struct Opt<T: Args> {
        #[clap(flatten)]
        inner: T,
    }
    assert_eq!(
        Opt {
            inner: A { arg: 42 }
        },
        Opt::try_parse_from(&["test", "42"]).unwrap()
    );
    assert_eq!(
        Opt {
            inner: B {
                arg: "42".to_owned()
            }
        },
        Opt::try_parse_from(&["test", "42"]).unwrap()
    );
}
<commit_msg>Port tests from structopt<commit_after>mod utils;

use clap::{Args, Parser};

#[test]
fn generic_struct_flatten() {
    #[derive(Args, PartialEq, Debug)]
    struct Inner {
        pub answer: isize,
    }

    #[derive(Parser, PartialEq, Debug)]
    struct Outer<T: Args> {
        #[clap(flatten)]
        pub inner: T,
    }

    assert_eq!(
        Outer {
            inner: Inner { answer: 42 }
        },
        Outer::parse_from(&["--answer", "42"])
    )
}

#[test]
fn generic_struct_flatten_w_where_clause() {
    #[derive(Args, PartialEq, Debug)]
    struct Inner {
        pub answer: isize,
    }

    #[derive(Parser, PartialEq, Debug)]
    struct Outer<T>
    where
        T: Args,
    {
        #[clap(flatten)]
        pub inner: T,
    }

    assert_eq!(
        Outer {
            inner: Inner { answer: 42 }
        },
        Outer::parse_from(&["--answer", "42"])
    )
}

#[test]
fn generic_enum() {
    #[derive(Args, PartialEq, Debug)]
    struct Inner {
        pub answer: isize,
    }

    #[derive(Parser, PartialEq, Debug)]
    enum GenericEnum<T: Args> {
        Start(T),
        Stop,
    }

    assert_eq!(
        GenericEnum::Start(Inner { answer: 42 }),
        GenericEnum::parse_from(&["test", "start", "42"])
    )
}

#[test]
fn generic_enum_w_where_clause() {
    #[derive(Args, PartialEq, Debug)]
    struct Inner {
        pub answer: isize,
    }

    #[derive(Parser, PartialEq, Debug)]
    enum GenericEnum<T>
    where
        T: Args,
    {
        Start(T),
        Stop,
    }

    assert_eq!(
        GenericEnum::Start(Inner { answer: 42 }),
        GenericEnum::parse_from(&["test", "start", "42"])
    )
}

#[test]
fn generic_w_fromstr_trait_bound() {
    use std::str::FromStr;

    #[derive(Parser, PartialEq, Debug)]
    struct Opt<T>
    where
        T: FromStr,
        <T as FromStr>::Err: std::error::Error + Sync + Send + 'static,
    {
        answer: T,
    }

    assert_eq!(
        Opt::<isize> { answer: 42 },
        Opt::<isize>::parse_from(&["--answer", "42"])
    )
}

#[test]
fn generic_wo_trait_bound() {
    use std::time::Duration;

    #[derive(Parser, PartialEq, Debug)]
    struct Opt<T> {
        answer: isize,
        #[clap(skip)]
        took: Option<T>,
    }

    assert_eq!(
        Opt::<Duration> {
            answer: 42,
            took: None
        },
        Opt::<Duration>::parse_from(&["--answer", "42"])
    )
}

#[test]
fn generic_where_clause_w_trailing_comma() {
    use std::str::FromStr;

    #[derive(Parser, PartialEq, Debug)]
    struct Opt<T>
    where
        T: FromStr,
        <T as FromStr>::Err: std::error::Error + Sync + Send + 'static,
    {
        pub answer: T,
    }

    assert_eq!(
        Opt::<isize> { answer: 42 },
        Opt::<isize>::parse_from(&["--answer", "42"])
    )
}
<|endoftext|>


<commit_before>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    cmd_history: ~[~str],
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cmd_history: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let line = stdin.read_line().unwrap();
            let mut cmd_line: ~str = line.trim().to_owned();
            let mut background: bool = false;
            if cmd_line.char_len() > 0 {
                background = cmd_line.char_at(cmd_line.char_len() - 1) == '&';
                if background {
                    cmd_line = cmd_line.slice(0, cmd_line.char_len() - 1).trim().to_owned();
                }
            }

            let params = cmd_line.clone().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""          =>  { continue; }
                "exit"      =>  { return; }
                "cd"        =>  { Shell::run_check_mode(background, Shell::run_cd(params)); }
                "history"   =>  { Shell::run_check_mode(background, Shell::run_history(params, self.cmd_history)); }
                _           =>  { Shell::run_check_mode(background, Shell::run_cmdline(params)); }
            }

            self.cmd_history.push(program.to_owned());
        }
    }

    fn run_check_mode(background: bool, f: proc()) {
        if background {
            spawn(proc() { f(); });
        } else {
            f();
        }
    }

    fn run_cmdline_single(cmd_line: &str) {
        (Shell::run_cmdline(cmd_line))();
    }

    fn run_cmdline(cmd_line: &str) -> proc() {
        let params = cmd_line.to_owned();
        return proc() {
            let mut argv: ~[~str] = Shell::get_args(params);

            if argv.len() > 0 {
                let program: ~str = argv.remove(0);
                Shell::run_cmd(program, argv);
            }
        };
    }

    fn run_cmd(program: &str, argv: &[~str]) {
        if Shell::cmd_exists(program) {
            run::process_status(program, argv);
        } else {
            println!("{:s}: command not found", program);
        }
    }

    fn cmd_exists(cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn run_cd(cmd_line: &str) -> proc() {
        let params = cmd_line.to_owned();
        return proc() {
            let argv: ~[~str] = Shell::get_args(params);
            let pathOpt: Option<Path> = match argv.len() {
                1   =>  { os::homedir() }
                0   =>  { os::homedir() }
                _   =>  { Some(Path::new(argv[1])) }
            };

            match pathOpt {
                Some(path)   =>  {
                    if path.is_dir() {
                        os::change_dir(&path);
                    } else {
                        println!("Error: {:s} is not a directory", path.as_str().unwrap());
                    }
                }
                None        =>  {
                    println!("Error: Invalid path");
                }
            };
        };
    }

    fn run_history(cmd_line: &str, cmd_history: &[~str]) -> proc() {
        let history = cmd_history.to_owned();
        let params = cmd_line.to_owned();
        return proc() {
            let argv: ~[~str] = Shell::get_args(params);
            if (argv.len() > 1) {
                println!("Error: history does not take options (sadly).");
            }
            else {
                let mut i = 1;
                for entry in history.iter() {
                    println!("{:d} \t{:s}", i, entry.to_owned());
                    i = i + 1;
                }
            }
        };
    }

    fn get_args(cmd_line: &str) -> ~[~str] {
        return cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::run_cmdline_single(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<commit_msg>asjdfksajf;ldsfjlljsfa<commit_after>//
// gash.rs
//
// Starting code for PS2
// Running on Rust 0.9
//
// University of Virginia - cs4414 Spring 2014
// Weilin Xu, David Evans
// Version 0.4
//

extern mod extra;

use std::{io, run, os};
use std::io::buffered::BufferedReader;
// use std::io::stdio::StdReader;
// use std::io::Reader;
// use std::io::Writer;
use std::io::stdin;
use extra::getopts;

struct Shell {
    cmd_prompt: ~str,
    cmd_history: ~[~str],
}

impl Shell {
    fn new(prompt_str: &str) -> Shell {
        Shell {
            cmd_prompt: prompt_str.to_owned(),
            cmd_history: ~[],
        }
    }

    fn run(&mut self) {
        let mut stdin = BufferedReader::new(stdin());

        loop {
            print(self.cmd_prompt);
            io::stdio::flush();

            let mut line : ~str = stdin.read_line().unwrap().to_owned();
            let mut cmd_line: ~str = line.trim().to_owned();
            let mut background: bool = false;
            let mut i : uint = 0;

            // This block handles if there are no spaces around pipe.
            let lineClone = line.clone();
            for character in lineClone.chars() {
                if character == '<' {
                    line = line.slice(0, i).to_owned() + " < " + line.slice(i+1, line.char_len()).to_owned();
                    i = i + 2;
                } else if character == '>' {
                    line = line.slice(0, i).to_owned() + " > " + line.slice(i+1, line.char_len()).to_owned();
                    i = i + 2;
                } else if character == '|' {
                    line = line.slice(0, i).to_owned() + " | " + line.slice(i+1, line.char_len()).to_owned();
                    i = i + 2;
                }
                i = i + 1;
            }

            if cmd_line.char_len() > 0 {
                background = cmd_line.char_at(cmd_line.char_len() - 1) == '&';
                if background {
                    cmd_line = cmd_line.slice(0, cmd_line.char_len() - 1).trim().to_owned();
                }
            }

            let params = cmd_line.clone().to_owned();
            let program = cmd_line.splitn(' ', 1).nth(0).expect("no program");

            match program {
                ""          =>  { continue; }
                "exit"      =>  { return; }
                "cd"        =>  { Shell::run_check_mode(background, Shell::run_cd(params)); }
                "history"   =>  { Shell::run_check_mode(background, Shell::run_history(params, self.cmd_history)); }
                _           =>  { Shell::run_check_mode(background, Shell::run_cmdline(params)); }
            }

            self.cmd_history.push(program.to_owned());
        }
    }

    fn run_check_mode(background: bool, f: proc()) {
        if background {
            spawn(proc() { f(); });
        } else {
            f();
        }
    }

    fn run_cmdline_single(cmd_line: &str) {
        (Shell::run_cmdline(cmd_line))();
    }

    fn run_cmdline(cmd_line: &str) -> proc() {
        let params = cmd_line.to_owned();
        return proc() {
            let mut argv: ~[~str] = Shell::get_args(params);

            if argv.len() > 0 {
                let program: ~str = argv.remove(0);
                Shell::run_cmd(program, argv/*, None, false*/);
            }
        };
    }

    fn run_cmd(program: &str, argv: &[~str]/*, inputStream: Option<~Reader>, hasOutRedirect: bool*/) /*-> Option<~[u8]>*/ {
        if Shell::cmd_exists(program) {
            run::process_status(program, argv);

            // let mut options = run::ProcessOptions::new();
            // options.in_fd = match inputStream {
            //     Some(reader) => { None }
            //     None => { Some(0) }
            // };

            // if hasOutRedirect {
            //     options.out_fd = None;
            // } else {
            //     options.out_fd = Some(1);
            // }

            // let mut process = run::Process::new(program, argv, options).unwrap();
            // match options.in_fd {
            //     Some(_) => {  }
            //     None => {
            //         let buf = inputStream.read_to_str().into_bytes();
            //         process.input().write(buf);
            //     }
            // }

            // if hasOutRedirect {
            //     let mut processOutput = process.finish_with_output();
            //     return Some(processOutput.output);

            // } else {
            //     process.finish();
            //     return None;
            // }
        } else {
            println!("{:s}: command not found", program);
            // return None;
        }
    }

    fn cmd_exists(cmd_path: &str) -> bool {
        let ret = run::process_output("which", [cmd_path.to_owned()]);
        return ret.expect("exit code error.").status.success();
    }

    fn run_cd(cmd_line: &str) -> proc() {
        let params = cmd_line.to_owned();
        return proc() {
            let argv: ~[~str] = Shell::get_args(params);
            let pathOpt: Option<Path> = match argv.len() {
                1   =>  { os::homedir() }
                0   =>  { os::homedir() }
                _   =>  { Some(Path::new(argv[1])) }
            };

            match pathOpt {
                Some(path)   =>  {
                    if path.is_dir() {
                        os::change_dir(&path);
                    } else {
                        println!("Error: {:s} is not a directory", path.as_str().unwrap());
                    }
                }
                None        =>  {
                    println!("Error: Invalid path");
                }
            };
        };
    }

    fn run_history(cmd_line: &str, cmd_history: &[~str]) -> proc() {
        let history = cmd_history.to_owned();
        let params = cmd_line.to_owned();
        return proc() {
            let argv: ~[~str] = Shell::get_args(params);
            if (argv.len() > 1) {
                println!("Error: history does not take options (sadly).");
            }
            else {
                let mut i = 1;
                for entry in history.iter() {
                    println!("{:d} \t{:s}", i, entry.to_owned());
                    i = i + 1;
                }
            }
        };
    }

    fn get_args(cmd_line: &str) -> ~[~str] {
        return cmd_line.split(' ').filter_map(|x| if x != "" { Some(x.to_owned()) } else { None }).to_owned_vec();
    }
}

fn get_cmdline_from_args() -> Option<~str> {
    /* Begin processing program arguments and initiate the parameters. */
    let args = os::args();

    let opts = ~[
        getopts::optopt("c")
    ];

    let matches = match getopts::getopts(args.tail(), opts) {
        Ok(m) => { m }
        Err(f) => { fail!(f.to_err_msg()) }
    };

    if matches.opt_present("c") {
        let cmd_str = match matches.opt_str("c") {
                                                Some(cmd_str) => {cmd_str.to_owned()},
                                                None => {~""}
                                              };
        return Some(cmd_str);
    } else {
        return None;
    }
}

fn main() {
    let opt_cmd_line = get_cmdline_from_args();

    match opt_cmd_line {
        Some(cmd_line) => Shell::run_cmdline_single(cmd_line),
        None           => Shell::new("gash > ").run()
    }
}
<|endoftext|>


<commit_before>extern crate cargotest;
extern crate kernel32;
extern crate libc;
extern crate winapi;

use std::net::TcpListener;
use std::io::{self, Read};
use std::process::{Stdio, Child};

use cargotest::support::project;

#[cfg(unix)]
fn enabled() -> bool {
    true
}

// On Windows suport for these tests is only enabled through the usage of job
// objects. Support for nested job objects, however, was added in recent-ish
// versions of Windows, so this test may not always be able to succeed.
//
// As a result, we try to add ourselves to a job object here
// can succeed or not.
#[cfg(windows)]
fn enabled() -> bool {
    use kernel32;
    use winapi;
    unsafe {
        // If we're not currently in a job, then we can definitely run these
        // tests.
        let me = kernel32::GetCurrentProcess();
        let mut ret = 0;
        let r = kernel32::IsProcessInJob(me, 0 as *mut _, &mut ret);
        assert!(r != 0);
        if ret == winapi::FALSE {
            return true
        }

        // If we are in a job, then we can run these tests if we can be added to
        // a nested job (as we're going to create a nested job no matter what as
        // part of these tests.
        //
        // If we can't be added to a nested job, then these tests will
        // definitely fail, and there's not much we can do about that.
        let job = kernel32::CreateJobObjectW(0 as *mut _, 0 as *const _);
        assert!(!job.is_null());
        let r = kernel32::AssignProcessToJobObject(job, me);
        kernel32::CloseHandle(job);
        r != 0
    }
}

#[test]
fn ctrl_c_kills_everyone() {
    if !enabled() {
        return
    }

    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = listener.local_addr().unwrap();

    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
            build = "build.rs"
        "#)
        .file("src/lib.rs", "")
        .file("build.rs", &format!(r#"
            use std::net::TcpStream;
            use std::io::Read;

            fn main() {{
                let mut socket = TcpStream::connect("{}").unwrap();
                let _ = socket.read(&mut [0; 10]);
                panic!("that read should never return");
            }}
        "#, addr));
    p.build();

    let mut cargo = p.cargo("build").build_command();
    cargo.stdin(Stdio::piped())
         .stdout(Stdio::piped())
         .stderr(Stdio::piped())
         .env("__CARGO_TEST_SETSID_PLEASE_DONT_USE_ELSEWHERE", "1");
    let mut child = cargo.spawn().unwrap();

    let mut sock = listener.accept().unwrap().0;
    ctrl_c(&mut child);

    assert!(!child.wait().unwrap().success());
    match sock.read(&mut [0; 10]) {
        Ok(n) => assert_eq!(n, 0),
        Err(e) => assert_eq!(e.kind(), io::ErrorKind::ConnectionReset),
    }
}

#[cfg(unix)]
fn ctrl_c(child: &mut Child) {
    use libc;

    let r = unsafe { libc::kill(-(child.id() as i32), libc::SIGINT) };
    if r < 0 {
        panic!("failed to kill: {}", io::Error::last_os_error());
    }
}

#[cfg(windows)]
fn ctrl_c(child: &mut Child) {
    child.kill().unwrap();
}
<commit_msg>Auto merge of #3480 - alexcrichton:one-flaky-test, r=brson<commit_after>extern crate cargotest;
extern crate kernel32;
extern crate libc;
extern crate winapi;

use std::fs;
use std::io::{self, Read};
use std::net::TcpListener;
use std::process::{Stdio, Child};
use std::thread;
use std::time::Duration;

use cargotest::support::project;

#[cfg(unix)]
fn enabled() -> bool {
    true
}

// On Windows suport for these tests is only enabled through the usage of job
// objects. Support for nested job objects, however, was added in recent-ish
// versions of Windows, so this test may not always be able to succeed.
//
// As a result, we try to add ourselves to a job object here
// can succeed or not.
#[cfg(windows)]
fn enabled() -> bool {
    use kernel32;
    use winapi;
    unsafe {
        // If we're not currently in a job, then we can definitely run these
        // tests.
        let me = kernel32::GetCurrentProcess();
        let mut ret = 0;
        let r = kernel32::IsProcessInJob(me, 0 as *mut _, &mut ret);
        assert!(r != 0);
        if ret == winapi::FALSE {
            return true
        }

        // If we are in a job, then we can run these tests if we can be added to
        // a nested job (as we're going to create a nested job no matter what as
        // part of these tests.
        //
        // If we can't be added to a nested job, then these tests will
        // definitely fail, and there's not much we can do about that.
        let job = kernel32::CreateJobObjectW(0 as *mut _, 0 as *const _);
        assert!(!job.is_null());
        let r = kernel32::AssignProcessToJobObject(job, me);
        kernel32::CloseHandle(job);
        r != 0
    }
}

#[test]
fn ctrl_c_kills_everyone() {
    if !enabled() {
        return
    }

    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
    let addr = listener.local_addr().unwrap();

    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
            build = "build.rs"
        "#)
        .file("src/lib.rs", "")
        .file("build.rs", &format!(r#"
            use std::net::TcpStream;
            use std::io::Read;

            fn main() {{
                let mut socket = TcpStream::connect("{}").unwrap();
                let _ = socket.read(&mut [0; 10]);
                panic!("that read should never return");
            }}
        "#, addr));
    p.build();

    let mut cargo = p.cargo("build").build_command();
    cargo.stdin(Stdio::piped())
         .stdout(Stdio::piped())
         .stderr(Stdio::piped())
         .env("__CARGO_TEST_SETSID_PLEASE_DONT_USE_ELSEWHERE", "1");
    let mut child = cargo.spawn().unwrap();

    let mut sock = listener.accept().unwrap().0;
    ctrl_c(&mut child);

    assert!(!child.wait().unwrap().success());
    match sock.read(&mut [0; 10]) {
        Ok(n) => assert_eq!(n, 0),
        Err(e) => assert_eq!(e.kind(), io::ErrorKind::ConnectionReset),
    }

    // Ok so what we just did was spawn cargo that spawned a build script, then
    // we killed cargo in hopes of it killing the build script as well. If all
    // went well the build script is now dead. On Windows, however, this is
    // enforced with job objects which means that it may actually be in the
    // *process* of being torn down at this point.
    //
    // Now on Windows we can't completely remove a file until all handles to it
    // have been closed. Including those that represent running processes. So if
    // we were to return here then there may still be an open reference to some
    // file in the build directory. What we want to actually do is wait for the
    // build script to *complete* exit. Take care of that by blowing away the
    // build directory here, and panicking if we eventually spin too long
    // without being able to.
    for i in 0..10 {
        match fs::remove_dir_all(&p.root().join("target")) {
            Ok(()) => return,
            Err(e) => println!("attempt {}: {}", i, e),
        }
        thread::sleep(Duration::from_millis(100));
    }

    panic!("couldn't remove build directory after a few tries, seems like \
            we won't be able to!");
}

#[cfg(unix)]
fn ctrl_c(child: &mut Child) {
    use libc;

    let r = unsafe { libc::kill(-(child.id() as i32), libc::SIGINT) };
    if r < 0 {
        panic!("failed to kill: {}", io::Error::last_os_error());
    }
}

#[cfg(windows)]
fn ctrl_c(child: &mut Child) {
    child.kill().unwrap();
}
<|endoftext|>


<commit_before>use crate::common::util::*;

#[test]
fn test_link_existing_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_link_existing_file";
    let link = "test_link_existing_file_link";

    at.touch(file);
    at.write(file, "foobar");
    assert!(at.file_exists(file));

    ucmd.args(&[file, link]).succeeds().no_stderr();
    assert!(at.file_exists(file));
    assert!(at.file_exists(link));
    assert_eq!(at.read(file), at.read(link));
}

#[test]
fn test_link_no_circular() {
    let (at, mut ucmd) = at_and_ucmd!();
    let link = "test_link_no_circular";

    ucmd.args(&[link, link])
        .fails()
        .stderr_is("link: error: No such file or directory (os error 2)\n");
    assert!(!at.file_exists(link));
}

#[test]
fn test_link_nonexistent_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_link_nonexistent_file";
    let link = "test_link_nonexistent_file_link";

    ucmd.args(&[file, link])
        .fails()
        .stderr_is("link: error: No such file or directory (os error 2)\n");
    assert!(!at.file_exists(file));
    assert!(!at.file_exists(link));
}
<commit_msg>Add tests to check link fails with 1 or 3 argument(s)<commit_after>use crate::common::util::*;

#[test]
fn test_link_existing_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_link_existing_file";
    let link = "test_link_existing_file_link";

    at.touch(file);
    at.write(file, "foobar");
    assert!(at.file_exists(file));

    ucmd.args(&[file, link]).succeeds().no_stderr();
    assert!(at.file_exists(file));
    assert!(at.file_exists(link));
    assert_eq!(at.read(file), at.read(link));
}

#[test]
fn test_link_no_circular() {
    let (at, mut ucmd) = at_and_ucmd!();
    let link = "test_link_no_circular";

    ucmd.args(&[link, link])
        .fails()
        .stderr_is("link: error: No such file or directory (os error 2)\n");
    assert!(!at.file_exists(link));
}

#[test]
fn test_link_nonexistent_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_link_nonexistent_file";
    let link = "test_link_nonexistent_file_link";

    ucmd.args(&[file, link])
        .fails()
        .stderr_is("link: error: No such file or directory (os error 2)\n");
    assert!(!at.file_exists(file));
    assert!(!at.file_exists(link));
}

#[test]
fn test_link_one_argument() {
    let (_, mut ucmd) = at_and_ucmd!();
    let file = "test_link_argument";
    ucmd.args(&[file]).fails().stderr_contains(
        "error: The argument '<FILES>...' requires at least 2 values, but only 1 was provide",
    );
}

#[test]
fn test_link_three_arguments() {
    let (_, mut ucmd) = at_and_ucmd!();
    let arguments = vec![
        "test_link_argument1",
        "test_link_argument2",
        "test_link_argument3",
    ];
    ucmd.args(&arguments[..]).fails().stderr_contains(
        format!("error: The value '{}' was provided to '<FILES>...', but it wasn't expecting any more values", arguments[2]),
    );
}
<|endoftext|>


<commit_before>extern crate log_domain;
#[macro_use]
extern crate rustomata;

use log_domain::LogDomain;
use std::fs::File;
use std::io::Read;
use std::rc::Rc;

use rustomata::approximation::ApproximationStrategy;
use rustomata::approximation::equivalence_classes::EquivalenceRelation;
use rustomata::approximation::relabel::RlbElement;
use rustomata::approximation::tts::TTSElement;
use rustomata::pmcfg::*;
use rustomata::pmcfg::negra::to_negra;
use rustomata::recognisable::*;
use rustomata::recognisable::coarse_to_fine::CoarseToFineRecogniser;
use rustomata::tree_stack_automaton::*;

fn pmcfg_from_file(grammar_file_path: &str) -> PMCFG<String, String, LogDomain<f64>>
{
    let mut grammar_file = File::open(grammar_file_path).unwrap();
    let mut grammar_string = String::new();
    let _ = grammar_file.read_to_string(&mut grammar_string);
    grammar_string.parse().unwrap()
}

#[test]
fn test_example_pmcfg_to_negra() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.pmcfg"));
    let tree_stack = automaton.recognise(
        String::from("aabccd").chars().map(|x| x.to_string()).collect()
    ).next().unwrap().0;

    let syntax_tree = to_abstract_syntax_tree(tree_stack.storage.to_tree());
    let separated_syntax_tree = separate_terminal_rules(&syntax_tree);

    let negra_string = to_negra(&separated_syntax_tree, 0);
    let negra_control_string = String::from(
        "#BOS 0\n\
         a\ta\t--\t--\t1\n\
         a\ta\t--\t--\t2\n\
         b\tb\t--\t--\t3\n\
         c\tc\t--\t--\t1\n\
         c\tc\t--\t--\t2\n\
         d\td\t--\t--\t3\n\
         #1\tA\t--\t--\t4\n\
         #2\tA\t--\t--\t1\n\
         #3\tB\t--\t--\t4\n\
         #4\tS\t--\t--\t0\n\
         #EOS 0"
    );

    assert_eq!(negra_control_string, negra_string);
}

#[test]
fn test_from_str_automaton() {
    let i1: TreeStackInstruction<String> = TreeStackInstruction::Up {
        n: 1,
        current_val: "zwei".to_string(),
        old_val: "drei".to_string(),
        new_val: "vier".to_string(),
    };

    let i2: TreeStackInstruction<String> = TreeStackInstruction::Push {
        n: 1,
        current_val: "zwei".to_string(),
        new_val: "vier".to_string(),
    };

    let i3: TreeStackInstruction<String> = TreeStackInstruction::Down {
        current_val: "zwei".to_string(),
        old_val: "drei".to_string(),
        new_val: "vier".to_string(),
    };

    let i1_string = "Up 1 zwei drei vier";
    let i1_string2 = "   Up 1  zwei  drei   vier  ";
    let i2_string = "Push 1 zwei vier";
    let i3_string = "Down zwei drei vier";

    assert_eq!(Ok(i1.clone()), i1_string.parse());
    assert_eq!(Ok(i1.clone()), i1_string2.parse());
    assert_eq!(Ok(i2.clone()), i2_string.parse());
    assert_eq!(Ok(i3.clone()), i3_string.parse());

    let t1 = Transition {
        word: vec!["hello".to_string(), "world".to_string()],
        weight: LogDomain::new(0.5).unwrap(),
        instruction: i1,
    };

    let t2 = Transition {
        word: vec!["\"hello\\".to_string(), "world".to_string()],
        weight: LogDomain::new(0.5).unwrap(),
        instruction: i2,
    };

    let t3 = Transition {
        word: vec!["\"hello\\".to_string(), "world".to_string()],
        weight: LogDomain::new(0.5).unwrap(),
        instruction: i3,
    };

    let mut t1_string = String::from("Transition [\"hello\",\"world\"] (");
    t1_string.push_str(i1_string);
    t1_string.push_str(") #0.5");

    let mut t2_string = String::from("Transition [\"\\\"hello\\\\\",\"world\"] (");
    t2_string.push_str(i2_string);
    t2_string.push_str(") #0.5");

    let mut t3_string = String::from("Transition [\"\\\"hello\\\\\",\"world\"] (");
    t3_string.push_str(i3_string);
    t3_string.push_str(") #0.5");

    assert_eq!(Ok(t1.clone()), t1_string.parse());
    assert_eq!(Ok(t2.clone()), t2_string.parse());
    assert_eq!(Ok(t3.clone()), t3_string.parse());

    let automaton: TreeStackAutomaton<String, String, LogDomain<f64>> = TreeStackAutomaton::new(
        vec![t1.clone(), t2.clone(), t3.clone()],
        TreeStack::new("eins".to_string())
    );

    let mut automaton_string: String = String::from("initial: eins\n\n");
    automaton_string.push_str(t1_string.as_str());
    automaton_string.push_str("\n");
    automaton_string.push_str(t2_string.as_str());
    automaton_string.push_str("\n");
    automaton_string.push_str(t3_string.as_str());
    automaton_string.push_str("\n");

    let automaton_parse: TreeStackAutomaton<String, String, LogDomain<f64>> = automaton_string.parse().unwrap();

    let ts1: Vec<_> = automaton.list_transitions().collect();
    let ts2: Vec<_> = automaton_parse.list_transitions().collect();

    assert_eq!(ts1, ts2);

    assert_eq!(
        automaton.initial(),
        automaton_parse.initial()
    );
}

#[test]
fn test_coarse_to_fine_recogniser_correctness() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.pmcfg"));
    let tts = TTSElement::new();
    let rel: EquivalenceRelation<String, String> = "0 [A, B]\n1 *".parse().unwrap();
    let mapping = |ps: &PosState<_>| ps
        .map(|r: &PMCFGRule<_, _, _>| r.map_nonterminals(|nt| rel.project(nt)));
    let rlb = RlbElement::new(&mapping);
    let recogniser = coarse_to_fine_recogniser!(automaton.clone(); tts, rlb);

    let words = vec![
        "aabccd",
        "aaabcccd",
        "abccd",
        "abbcd",
    ];

    for word in words {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            automaton.recognise(input.clone()).next(),
            recogniser.recognise(input).next()
        );
    }
}

#[test]
fn test_tts_correctness() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.pmcfg"));
    let tts = TTSElement::new();
    let (tts_ed_automaton, _) = tts.approximate_automaton(&automaton);

    let true_positives_and_true_negatives = vec![
        "",
        "abcd",
        "aabccd",
        "aaabcccd",
    ];

    for word in true_positives_and_true_negatives {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            automaton.recognise(input.clone()).next().is_some(),
            tts_ed_automaton.recognise(input).next().is_some()
        );
    }

    let false_positives = vec![
        "aabcd",
        "aabbcd",
        "abbcccdddd",
        "abbbccdddd",
    ];

    for word in false_positives {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(false, automaton.recognise(input.clone()).next().is_some());
        assert_eq!(true, tts_ed_automaton.recognise(input).next().is_some());
    }
}

#[test]
fn test_pmcfg_from_str_correctness() {
    let rule_s0 = PMCFGRule {
        head: String::from("S"),
        tail: vec![String::from("A"), String::from("B")],
        composition: Composition { composition: vec![
            vec![VarT::Var(0, 0), VarT::Var(1, 0), VarT::Var(0, 1), VarT::Var(1, 1)],
        ] },
        weight: LogDomain::new(1.0).unwrap()
    };
    let rule_a0 = PMCFGRule {
        head: String::from("A"),
        tail: vec![String::from("A")],
        composition: Composition { composition: vec![
            vec![VarT::T(String::from("a")), VarT::Var(0, 0)],
            vec![VarT::T(String::from("c")), VarT::Var(0, 1)],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let rule_a1 = PMCFGRule {
        head: String::from("A"),
        tail: vec![],
        composition: Composition { composition: vec![
            vec![],
            vec![],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let rule_b0 = PMCFGRule {
        head: String::from("B"),
        tail: vec![String::from("B")],
        composition: Composition { composition: vec![
            vec![VarT::T(String::from("b")), VarT::Var(0, 0)],
            vec![VarT::T(String::from("d")), VarT::Var(0, 1)],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let rule_b1 = PMCFGRule {
        head: String::from("B"),
        tail: vec![],
        composition: Composition { composition: vec![
            vec![],
            vec![],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let control_grammar = PMCFG {
        initial: vec![String::from("S")],
        rules: vec![rule_s0, rule_a0, rule_a1, rule_b0, rule_b1]
    };

    let grammar = pmcfg_from_file("examples/example.pmcfg");
    assert_eq!(
        control_grammar.clone(),
        grammar.clone()
    );

    let control_automaton = TreeStackAutomaton::from(control_grammar);
    let automaton = TreeStackAutomaton::from(grammar);
    let words = vec![
        "",
        "aabccd",
        "aabbcd",
        "aabccdd",
    ];

    for word in words {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            control_automaton.recognise(input.clone()).next().is_some(),
            automaton.recognise(input).next().is_some()
        );
    }
}
<commit_msg>tests/pmcfg.rs: reworked integration test of TreeStackAutomaton::from_str()<commit_after>extern crate log_domain;
#[macro_use]
extern crate rustomata;

use log_domain::LogDomain;
use std::collections::HashSet;
use std::fs::File;
use std::io::Read;
use std::rc::Rc;

use rustomata::approximation::ApproximationStrategy;
use rustomata::approximation::equivalence_classes::EquivalenceRelation;
use rustomata::approximation::relabel::RlbElement;
use rustomata::approximation::tts::TTSElement;
use rustomata::pmcfg::*;
use rustomata::pmcfg::negra::to_negra;
use rustomata::recognisable::*;
use rustomata::recognisable::coarse_to_fine::CoarseToFineRecogniser;
use rustomata::tree_stack_automaton::*;

fn pmcfg_from_file(grammar_file_path: &str) -> PMCFG<String, String, LogDomain<f64>>
{
    let mut grammar_file = File::open(grammar_file_path).unwrap();
    let mut grammar_string = String::new();
    let _ = grammar_file.read_to_string(&mut grammar_string);
    grammar_string.parse().unwrap()
}

#[test]
fn test_example_pmcfg_to_negra() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.pmcfg"));
    let tree_stack = automaton.recognise(
        String::from("aabccd").chars().map(|x| x.to_string()).collect()
    ).next().unwrap().0;

    let syntax_tree = to_abstract_syntax_tree(tree_stack.storage.to_tree());
    let separated_syntax_tree = separate_terminal_rules(&syntax_tree);

    let negra_string = to_negra(&separated_syntax_tree, 0);
    let negra_control_string = String::from(
        "#BOS 0\n\
         a\ta\t--\t--\t1\n\
         a\ta\t--\t--\t2\n\
         b\tb\t--\t--\t3\n\
         c\tc\t--\t--\t1\n\
         c\tc\t--\t--\t2\n\
         d\td\t--\t--\t3\n\
         #1\tA\t--\t--\t4\n\
         #2\tA\t--\t--\t1\n\
         #3\tB\t--\t--\t4\n\
         #4\tS\t--\t--\t0\n\
         #EOS 0"
    );

    assert_eq!(negra_control_string, negra_string);
}

#[test]
fn test_coarse_to_fine_recogniser_correctness() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.pmcfg"));
    let tts = TTSElement::new();
    let rel: EquivalenceRelation<String, String> = "0 [A, B]\n1 *".parse().unwrap();
    let mapping = |ps: &PosState<_>| ps
        .map(|r: &PMCFGRule<_, _, _>| r.map_nonterminals(|nt| rel.project(nt)));
    let rlb = RlbElement::new(&mapping);
    let recogniser = coarse_to_fine_recogniser!(automaton.clone(); tts, rlb);

    let words = vec![
        "aabccd",
        "aaabcccd",
        "abccd",
        "abbcd",
    ];

    for word in words {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            automaton.recognise(input.clone()).next(),
            recogniser.recognise(input).next()
        );
    }
}

#[test]
fn test_tts_correctness() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.pmcfg"));
    let tts = TTSElement::new();
    let (tts_ed_automaton, _) = tts.approximate_automaton(&automaton);

    let true_positives_and_true_negatives = vec![
        "",
        "abcd",
        "aabccd",
        "aaabcccd",
    ];

    for word in true_positives_and_true_negatives {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            automaton.recognise(input.clone()).next().is_some(),
            tts_ed_automaton.recognise(input).next().is_some()
        );
    }

    let false_positives = vec![
        "aabcd",
        "aabbcd",
        "abbcccdddd",
        "abbbccdddd",
    ];

    for word in false_positives {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(false, automaton.recognise(input.clone()).next().is_some());
        assert_eq!(true, tts_ed_automaton.recognise(input).next().is_some());
    }
}

#[test]
fn test_pmcfg_from_str_correctness() {
    let rule_s0 = PMCFGRule {
        head: String::from("S"),
        tail: vec![String::from("A"), String::from("B")],
        composition: Composition { composition: vec![
            vec![VarT::Var(0, 0), VarT::Var(1, 0), VarT::Var(0, 1), VarT::Var(1, 1)],
        ] },
        weight: LogDomain::new(1.0).unwrap()
    };
    let rule_a0 = PMCFGRule {
        head: String::from("A"),
        tail: vec![String::from("A")],
        composition: Composition { composition: vec![
            vec![VarT::T(String::from("a")), VarT::Var(0, 0)],
            vec![VarT::T(String::from("c")), VarT::Var(0, 1)],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let rule_a1 = PMCFGRule {
        head: String::from("A"),
        tail: vec![],
        composition: Composition { composition: vec![
            vec![],
            vec![],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let rule_b0 = PMCFGRule {
        head: String::from("B"),
        tail: vec![String::from("B")],
        composition: Composition { composition: vec![
            vec![VarT::T(String::from("b")), VarT::Var(0, 0)],
            vec![VarT::T(String::from("d")), VarT::Var(0, 1)],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let rule_b1 = PMCFGRule {
        head: String::from("B"),
        tail: vec![],
        composition: Composition { composition: vec![
            vec![],
            vec![],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let control_grammar = PMCFG {
        initial: vec![String::from("S")],
        rules: vec![rule_s0, rule_a0, rule_a1, rule_b0, rule_b1]
    };

    let grammar = pmcfg_from_file("examples/example.pmcfg");
    assert_eq!(
        control_grammar.clone(),
        grammar.clone()
    );

    let control_automaton = TreeStackAutomaton::from(control_grammar);
    let automaton = TreeStackAutomaton::from(grammar);
    let words = vec![
        "",
        "aabccd",
        "aabbcd",
        "aabccdd",
    ];

    for word in words {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            control_automaton.recognise(input.clone()).next().is_some(),
            automaton.recognise(input).next().is_some()
        );
    }
}

#[test]
fn test_tree_stack_automaton_from_str() {
    use TreeStackInstruction::{Up, Down, Push};

    let unprocessed_transitions = vec![
        ("",  Push { n: 0, current_val: 1.to_string(), new_val: 2.to_string() },                            1.0),
        ("",  Push { n: 0, current_val: 1.to_string(), new_val: 3.to_string() },                            1.0),
        ("",  Down { current_val: 4.to_string(), old_val: 18.to_string(), new_val: 19.to_string() },        1.0),
        ("",  Down { current_val: 5.to_string(), old_val: 6.to_string(), new_val: 5.to_string() },          1.0),
        ("",  Down { current_val: 5.to_string(), old_val: 7.to_string(), new_val: 8.to_string() },          1.0),
        ("d", Up   { n: 0, current_val: 9.to_string(), old_val: 10.to_string(), new_val: 11.to_string() },  1.0),
        ("d", Up   { n: 0, current_val: 9.to_string(), old_val: 5.to_string(), new_val: 9.to_string() },    1.0),
        ("",  Up   { n: 0, current_val: 12.to_string(), old_val: 2.to_string(), new_val: 13.to_string() },  1.0),
        ("",  Up   { n: 0, current_val: 12.to_string(), old_val: 14.to_string(), new_val: 15.to_string() }, 1.0),
        ("c", Up   { n: 0, current_val: 6.to_string(), old_val: 13.to_string(), new_val: 10.to_string() },  1.0),
        ("c", Up   { n: 0, current_val: 6.to_string(), old_val: 16.to_string(), new_val: 6.to_string() },   1.0),
        ("",  Down { current_val: 11.to_string(), old_val: 9.to_string(), new_val: 17.to_string() },        1.0),
        ("",  Down { current_val: 11.to_string(), old_val: 8.to_string(), new_val: 4.to_string() },         1.0),
        ("b", Up   { n: 0, current_val: 15.to_string(), old_val: 2.to_string(), new_val: 13.to_string() },  1.0),
        ("b", Up   { n: 0, current_val: 15.to_string(), old_val: 14.to_string(), new_val: 15.to_string() }, 1.0),
        ("",  Push { n: 0, current_val: 18.to_string(), new_val: 1.to_string() },                           1.0),
        ("",  Down { current_val: 17.to_string(), old_val: 9.to_string(), new_val: 17.to_string() },        1.0),
        ("",  Down { current_val: 17.to_string(), old_val: 8.to_string(), new_val: 4.to_string() },         1.0),
        ("",  Down { current_val: 2.to_string(), old_val: 3.to_string(), new_val: 14.to_string() },         1.0),
        ("",  Down { current_val: 2.to_string(), old_val: 1.to_string(), new_val: 12.to_string() },         1.0),
        ("",  Up   { n: 0, current_val: 8.to_string(), old_val: 10.to_string(), new_val: 11.to_string() },  1.0),
        ("",  Up   { n: 0, current_val: 8.to_string(), old_val: 5.to_string(), new_val: 9.to_string() },    1.0),
        ("a", Push { n: 0, current_val: 3.to_string(), new_val: 2.to_string() },                            1.0),
        ("a", Push { n: 0, current_val: 3.to_string(), new_val: 3.to_string() },                            1.0),
        ("",  Down { current_val: 13.to_string(), old_val: 15.to_string(), new_val: 16.to_string() },       1.0),
        ("",  Down { current_val: 13.to_string(), old_val: 12.to_string(), new_val: 7.to_string() },        1.0),
        ("",  Down { current_val: 10.to_string(), old_val: 6.to_string(), new_val: 5.to_string() },         1.0),
        ("",  Down { current_val: 10.to_string(), old_val: 7.to_string(), new_val: 8.to_string() },         1.0),
        ("",  Up   { n: 0, current_val: 7.to_string(), old_val: 13.to_string(), new_val: 10.to_string() },  1.0),
        ("",  Up   { n: 0, current_val: 7.to_string(), old_val: 16.to_string(), new_val: 6.to_string() },   1.0),
        ("",  Down { current_val: 14.to_string(), old_val: 3.to_string(), new_val: 14.to_string() },        1.0),
        ("",  Down { current_val: 14.to_string(), old_val: 1.to_string(), new_val: 12.to_string() },        1.0),
        ("",  Down { current_val: 16.to_string(), old_val: 15.to_string(), new_val: 16.to_string() },       1.0),
        ("",  Down { current_val: 16.to_string(), old_val: 12.to_string(), new_val: 7.to_string() },        1.0),
    ];

    let mut transitions = Vec::new();
    for (terminal, instruction, weight) in unprocessed_transitions {
        transitions.push(Transition {
            word: terminal.chars().map(|x| x.to_string()).collect(),
            instruction,
            weight: LogDomain::new(weight).unwrap()
        });
    }
    let control_automaton = TreeStackAutomaton::new(transitions, TreeStack::new(18.to_string()));

    let mut automaton_file = File::open("examples/example.tsa").unwrap();
    let mut automaton_string = String::new();
    let _ = automaton_file.read_to_string(&mut automaton_string);
    let automaton: TreeStackAutomaton<String, String, LogDomain<f64>> = automaton_string.parse().unwrap();

    assert_eq!(
        control_automaton.initial(),
        automaton.initial()
    );
    assert_eq!(
        control_automaton.list_transitions().collect::<HashSet<_>>(),
        automaton.list_transitions().collect::<HashSet<_>>()
    );
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "qc", feature(plugin, custom_attribute))]
#![cfg_attr(feature="qc", plugin(quickcheck_macros))]
#![allow(dead_code)]

//! The purpose of these tests is to cover corner cases of iterators
//! and adaptors.
//!
//! In particular we test the tedious size_hint and exact size correctness.

#[macro_use]
extern crate itertools;

#[cfg(feature = "qc")]
extern crate quickcheck;

#[cfg(feature = "qc")]
mod quicktests {

use std::default::Default;

use quickcheck as qc;
use std::ops::Range;
use itertools;
use itertools::Itertools;
use itertools::{
    Zip,
    Stride,
    EitherOrBoth,
};

/// Our base iterator that we can impl Arbitrary for
///
/// NOTE: Iter is tricky and is not fused, to help catch bugs.
/// At the end it will return None once, then return Some(0),
/// then return None again.
#[derive(Clone, Debug)]
struct Iter<T>(Range<T>, i32); // with fuse/done flag

impl<T> Iter<T>
{
    fn new(it: Range<T>) -> Self
    {
        Iter(it, 0)
    }
}

impl<T> Iterator for Iter<T> where Range<T>: Iterator,
    <Range<T> as Iterator>::Item: Default,
{
    type Item = <Range<T> as Iterator>::Item;

    fn next(&mut self) -> Option<Self::Item>
    {
        let elt = self.0.next();
        if elt.is_none() {
            self.1 += 1;
            // check fuse flag
            if self.1 == 2 {
                return Some(Default::default())
            }
        }
        elt
    }

    fn size_hint(&self) -> (usize, Option<usize>)
    {
        self.0.size_hint()
    }
}

impl<T> DoubleEndedIterator for Iter<T> where Range<T>: DoubleEndedIterator,
    <Range<T> as Iterator>::Item: Default,
{
    fn next_back(&mut self) -> Option<Self::Item> { self.0.next_back() }
}

impl<T> ExactSizeIterator for Iter<T> where Range<T>: ExactSizeIterator,
    <Range<T> as Iterator>::Item: Default,
{ }

impl<T> qc::Arbitrary for Iter<T> where T: qc::Arbitrary
{
    fn arbitrary<G: qc::Gen>(g: &mut G) -> Self
    {
        Iter::new(T::arbitrary(g)..T::arbitrary(g))
    }

    fn shrink(&self) -> Box<Iterator<Item=Iter<T>>>
    {
        let r = self.0.clone();
        Box::new(
            r.start.shrink().flat_map(move |x| {
                r.end.shrink().map(move |y| (x.clone(), y))
            })
            .map(|(a, b)| Iter::new(a..b))
        )
    }
}

fn correct_size_hint_fast<I: Iterator>(it: I) -> bool {
    let (low, hi) = it.size_hint();
    let cnt = it.count();
    cnt >= low &&
        (hi.is_none() || hi.unwrap() >= cnt)
}

fn correct_size_hint<I: Iterator>(mut it: I) -> bool {
    // record size hint at each iteration
    let initial_hint = it.size_hint();
    let mut hints = Vec::with_capacity(initial_hint.0 + 1);
    hints.push(initial_hint);
    while let Some(_) = it.next() {
        hints.push(it.size_hint())
    }

    let mut true_count = hints.len(); // start off +1 too much

    // check all the size hints
    for &(low, hi) in &hints {
        true_count -= 1;
        if low > true_count ||
            (hi.is_some() && hi.unwrap() < true_count)
        {
            println!("True size: {:?}, size hint: {:?}", true_count, (low, hi));
            //println!("All hints: {:?}", hints);
            return false
        }
    }
    true
}

fn exact_size<I: ExactSizeIterator>(mut it: I) -> bool {
    // check every iteration
    let (mut low, mut hi) = it.size_hint();
    if Some(low) != hi { return false; }
    while let Some(_) = it.next() {
        let (xlow, xhi) = it.size_hint();
        if low != xlow + 1 { return false; }
        low = xlow;
        hi = xhi;
        if Some(low) != hi { return false; }
    }
    let (low, hi) = it.size_hint();
    low == 0 && hi == Some(0)
}

/*
 * NOTE: Range<i8> is broken!
 * (all signed ranges are)
#[quickcheck]
fn size_range_i8(a: Iter<i8>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_i16(a: Iter<i16>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_u8(a: Iter<u8>) -> bool {
    exact_size(a)
}
 */

#[quickcheck]
fn size_stride(data: Vec<u8>, mut stride: isize) -> bool {
    if stride == 0 {
        stride += 1; // never zero
    }
    exact_size(Stride::from_slice(&data, stride))
}

#[quickcheck]
fn equal_stride(data: Vec<u8>, mut stride: i8) -> bool {
    if stride == 0 {
        // never zero
        stride += 1;
    }
    if stride > 0 {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().step(stride as usize))
    } else {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().rev().step(-stride as usize))
    }
}

#[quickcheck]
fn size_product(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.cartesian_product(b))
}

#[quickcheck]
fn size_product3(a: Iter<u16>, b: Iter<u16>, c: Iter<u16>) -> bool {
    correct_size_hint(iproduct!(a, b, c))
}

#[quickcheck]
fn size_step(a: Iter<i16>, mut s: usize) -> bool {
    if s == 0 {
        s += 1; // never zero
    }
    let filt = a.clone().dedup();
    correct_size_hint(filt.step(s)) &&
        exact_size(a.step(s))
}

#[quickcheck]
fn size_multipeek(a: Iter<u16>, s: u8) -> bool {
    let mut it = a.multipeek();
    // peek a few times
    for _ in 0..s {
        it.peek();
    }
    exact_size(it)
}

#[quickcheck]
fn equal_merge(a: Vec<i16>, b: Vec<i16>) -> bool {
    let mut sa = a.clone();
    let mut sb = b.clone();
    sa.sort();
    sb.sort();
    let mut merged = sa.clone() + &sb;
    merged.sort();
    itertools::equal(&merged, sa.iter().merge(&sb))

}
#[quickcheck]
fn size_merge(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.merge(b))
}

#[quickcheck]
fn size_zip(a: Iter<i16>, b: Iter<i16>, c: Iter<i16>) -> bool {
    let filt = a.clone().dedup();
    correct_size_hint(Zip::new((filt, b.clone(), c.clone()))) &&
        exact_size(Zip::new((a, b, c)))
}

#[quickcheck]
fn size_zip_rc(a: Iter<i16>, b: Iter<i16>) -> bool {
    let rc = a.clone().into_rc();
    correct_size_hint(Zip::new((&rc, &rc, b)))
}

#[quickcheck]
fn size_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    let filt = a.clone().dedup();
    let filt2 = b.clone().dedup();
    correct_size_hint(filt.zip_longest(b.clone())) &&
    correct_size_hint(a.clone().zip_longest(filt2)) &&
        exact_size(a.zip_longest(b))
}

#[quickcheck]
fn size_2_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    let it = a.clone().zip_longest(b.clone());
    let jt = a.clone().zip_longest(b.clone());
    itertools::equal(a.clone(),
                     it.filter_map(|elt| match elt {
                         EitherOrBoth::Both(x, _) => Some(x),
                         EitherOrBoth::Left(x) => Some(x),
                         _ => None,
                     }
                     ))
        &&
    itertools::equal(b.clone(),
                     jt.filter_map(|elt| match elt {
                         EitherOrBoth::Both(_, y) => Some(y),
                         EitherOrBoth::Right(y) => Some(y),
                         _ => None,
                     }
                     ))
}

fn equal_islice(a: Vec<i16>, x: usize, y: usize) -> bool {
    if x > y || y > a.len() { return true; }
    let slc = &a[x..y];
    itertools::equal(a.iter().slice(x..y), slc)
}

fn size_islice(a: Iter<i16>, x: usize, y: usize) -> bool {
    correct_size_hint(a.clone().dedup().slice(x..y)) &&
        exact_size(a.clone().slice(x..y))
}

#[quickcheck]
fn size_interleave(a: Iter<i16>, b: Iter<i16>) -> bool {
    correct_size_hint(a.interleave(b))
}

#[quickcheck]
fn size_intersperse(a: Iter<i16>, x: i16) -> bool {
    correct_size_hint(a.intersperse(x))
}

#[quickcheck]
fn equal_intersperse(a: Vec<i32>, x: i32) -> bool {
    let mut inter = false;
    let mut i = 0;
    for elt in a.iter().cloned().intersperse(x) {
        if inter {
            if elt != x { return false }
        } else {
            if elt != a[i] { return false }
            i += 1;
        }
        inter = !inter;
    }
    true
}

#[quickcheck]
fn equal_dedup(a: Vec<i32>) -> bool {
    let mut b = a.clone();
    b.dedup();
    itertools::equal(&b, a.iter().dedup())
}

#[quickcheck]
fn size_dedup(a: Vec<i32>) -> bool {
    correct_size_hint(a.iter().dedup())
}

#[quickcheck]
fn size_group_by(a: Vec<i8>) -> bool {
    correct_size_hint(a.iter().group_by(|x| x.abs()))
}

#[quickcheck]
fn size_linspace(a: f32, b: f32, n: usize) -> bool {
    let it = itertools::linspace(a, b, n);
    it.len() == n &&
        exact_size(it)
}

#[quickcheck]
fn equal_repeatn(n: usize, x: i32) -> bool {
    let it = itertools::RepeatN::new(x, n);
    exact_size(it)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted(a: Vec<u8>, b: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted3(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), c.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn equal_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    let it = itertools::ZipTrusted::new((a.iter(), b.iter(), x..y));
    let jt = Zip::new((a.iter(), b.iter(), x..y));
    itertools::equal(it, jt)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), x..y)))
}

#[quickcheck]
fn size_put_back(a: Vec<u8>, x: Option<u8>) -> bool {
    let mut it = itertools::PutBack::new(a.into_iter());
    match x {
        Some(t) => it.put_back(t),
        None => {}
    }
    correct_size_hint(it)
}

#[quickcheck]
fn size_tee(a: Vec<u8>) -> bool {
    let (mut t1, mut t2) = a.iter().tee();
    t1.next();
    t1.next();
    t2.next();
    exact_size(t1) && exact_size(t2)
}

#[quickcheck]
fn size_tee_2(a: Vec<u8>) -> bool {
    let (mut t1, mut t2) = a.iter().dedup().tee();
    t1.next();
    t1.next();
    t2.next();
    correct_size_hint(t1) && correct_size_hint(t2)
}

#[quickcheck]
fn size_mend_slices(a: Vec<u8>, splits: Vec<usize>) -> bool {
    let slice_iter = splits.into_iter().map(|ix|
        if ix < a.len() {
            &a[ix..(ix + 1)]
        } else {
            &a[0..0]
        }
    ).mend_slices();
    correct_size_hint(slice_iter)
}

#[quickcheck]
fn size_take_while_ref(a: Vec<u8>, stop: u8) -> bool {
    correct_size_hint(a.iter().take_while_ref(|x| **x != stop))
}

}
<commit_msg>Quickcheck for partition<commit_after>#![cfg_attr(feature = "qc", feature(plugin, custom_attribute))]
#![cfg_attr(feature="qc", plugin(quickcheck_macros))]
#![allow(dead_code)]

//! The purpose of these tests is to cover corner cases of iterators
//! and adaptors.
//!
//! In particular we test the tedious size_hint and exact size correctness.

#[macro_use]
extern crate itertools;

#[cfg(feature = "qc")]
extern crate quickcheck;

#[cfg(feature = "qc")]
mod quicktests {

use std::default::Default;

use quickcheck as qc;
use std::ops::Range;
use itertools;
use itertools::Itertools;
use itertools::{
    Zip,
    Stride,
    EitherOrBoth,
};

/// Our base iterator that we can impl Arbitrary for
///
/// NOTE: Iter is tricky and is not fused, to help catch bugs.
/// At the end it will return None once, then return Some(0),
/// then return None again.
#[derive(Clone, Debug)]
struct Iter<T>(Range<T>, i32); // with fuse/done flag

impl<T> Iter<T>
{
    fn new(it: Range<T>) -> Self
    {
        Iter(it, 0)
    }
}

impl<T> Iterator for Iter<T> where Range<T>: Iterator,
    <Range<T> as Iterator>::Item: Default,
{
    type Item = <Range<T> as Iterator>::Item;

    fn next(&mut self) -> Option<Self::Item>
    {
        let elt = self.0.next();
        if elt.is_none() {
            self.1 += 1;
            // check fuse flag
            if self.1 == 2 {
                return Some(Default::default())
            }
        }
        elt
    }

    fn size_hint(&self) -> (usize, Option<usize>)
    {
        self.0.size_hint()
    }
}

impl<T> DoubleEndedIterator for Iter<T> where Range<T>: DoubleEndedIterator,
    <Range<T> as Iterator>::Item: Default,
{
    fn next_back(&mut self) -> Option<Self::Item> { self.0.next_back() }
}

impl<T> ExactSizeIterator for Iter<T> where Range<T>: ExactSizeIterator,
    <Range<T> as Iterator>::Item: Default,
{ }

impl<T> qc::Arbitrary for Iter<T> where T: qc::Arbitrary
{
    fn arbitrary<G: qc::Gen>(g: &mut G) -> Self
    {
        Iter::new(T::arbitrary(g)..T::arbitrary(g))
    }

    fn shrink(&self) -> Box<Iterator<Item=Iter<T>>>
    {
        let r = self.0.clone();
        Box::new(
            r.start.shrink().flat_map(move |x| {
                r.end.shrink().map(move |y| (x.clone(), y))
            })
            .map(|(a, b)| Iter::new(a..b))
        )
    }
}

fn correct_size_hint_fast<I: Iterator>(it: I) -> bool {
    let (low, hi) = it.size_hint();
    let cnt = it.count();
    cnt >= low &&
        (hi.is_none() || hi.unwrap() >= cnt)
}

fn correct_size_hint<I: Iterator>(mut it: I) -> bool {
    // record size hint at each iteration
    let initial_hint = it.size_hint();
    let mut hints = Vec::with_capacity(initial_hint.0 + 1);
    hints.push(initial_hint);
    while let Some(_) = it.next() {
        hints.push(it.size_hint())
    }

    let mut true_count = hints.len(); // start off +1 too much

    // check all the size hints
    for &(low, hi) in &hints {
        true_count -= 1;
        if low > true_count ||
            (hi.is_some() && hi.unwrap() < true_count)
        {
            println!("True size: {:?}, size hint: {:?}", true_count, (low, hi));
            //println!("All hints: {:?}", hints);
            return false
        }
    }
    true
}

fn exact_size<I: ExactSizeIterator>(mut it: I) -> bool {
    // check every iteration
    let (mut low, mut hi) = it.size_hint();
    if Some(low) != hi { return false; }
    while let Some(_) = it.next() {
        let (xlow, xhi) = it.size_hint();
        if low != xlow + 1 { return false; }
        low = xlow;
        hi = xhi;
        if Some(low) != hi { return false; }
    }
    let (low, hi) = it.size_hint();
    low == 0 && hi == Some(0)
}

/*
 * NOTE: Range<i8> is broken!
 * (all signed ranges are)
#[quickcheck]
fn size_range_i8(a: Iter<i8>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_i16(a: Iter<i16>) -> bool {
    exact_size(a)
}

#[quickcheck]
fn size_range_u8(a: Iter<u8>) -> bool {
    exact_size(a)
}
 */

#[quickcheck]
fn size_stride(data: Vec<u8>, mut stride: isize) -> bool {
    if stride == 0 {
        stride += 1; // never zero
    }
    exact_size(Stride::from_slice(&data, stride))
}

#[quickcheck]
fn equal_stride(data: Vec<u8>, mut stride: i8) -> bool {
    if stride == 0 {
        // never zero
        stride += 1;
    }
    if stride > 0 {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().step(stride as usize))
    } else {
        itertools::equal(Stride::from_slice(&data, stride as isize),
                         data.iter().rev().step(-stride as usize))
    }
}

#[quickcheck]
fn size_product(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.cartesian_product(b))
}

#[quickcheck]
fn size_product3(a: Iter<u16>, b: Iter<u16>, c: Iter<u16>) -> bool {
    correct_size_hint(iproduct!(a, b, c))
}

#[quickcheck]
fn size_step(a: Iter<i16>, mut s: usize) -> bool {
    if s == 0 {
        s += 1; // never zero
    }
    let filt = a.clone().dedup();
    correct_size_hint(filt.step(s)) &&
        exact_size(a.step(s))
}

#[quickcheck]
fn size_multipeek(a: Iter<u16>, s: u8) -> bool {
    let mut it = a.multipeek();
    // peek a few times
    for _ in 0..s {
        it.peek();
    }
    exact_size(it)
}

#[quickcheck]
fn equal_merge(a: Vec<i16>, b: Vec<i16>) -> bool {
    let mut sa = a.clone();
    let mut sb = b.clone();
    sa.sort();
    sb.sort();
    let mut merged = sa.clone();
    merged.extend(sb.iter().cloned());
    merged.sort();
    itertools::equal(&merged, sa.iter().merge(&sb))

}
#[quickcheck]
fn size_merge(a: Iter<u16>, b: Iter<u16>) -> bool {
    correct_size_hint(a.merge(b))
}

#[quickcheck]
fn size_zip(a: Iter<i16>, b: Iter<i16>, c: Iter<i16>) -> bool {
    let filt = a.clone().dedup();
    correct_size_hint(Zip::new((filt, b.clone(), c.clone()))) &&
        exact_size(Zip::new((a, b, c)))
}

#[quickcheck]
fn size_zip_rc(a: Iter<i16>, b: Iter<i16>) -> bool {
    let rc = a.clone().into_rc();
    correct_size_hint(Zip::new((&rc, &rc, b)))
}

#[quickcheck]
fn size_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    let filt = a.clone().dedup();
    let filt2 = b.clone().dedup();
    correct_size_hint(filt.zip_longest(b.clone())) &&
    correct_size_hint(a.clone().zip_longest(filt2)) &&
        exact_size(a.zip_longest(b))
}

#[quickcheck]
fn size_2_zip_longest(a: Iter<i16>, b: Iter<i16>) -> bool {
    let it = a.clone().zip_longest(b.clone());
    let jt = a.clone().zip_longest(b.clone());
    itertools::equal(a.clone(),
                     it.filter_map(|elt| match elt {
                         EitherOrBoth::Both(x, _) => Some(x),
                         EitherOrBoth::Left(x) => Some(x),
                         _ => None,
                     }
                     ))
        &&
    itertools::equal(b.clone(),
                     jt.filter_map(|elt| match elt {
                         EitherOrBoth::Both(_, y) => Some(y),
                         EitherOrBoth::Right(y) => Some(y),
                         _ => None,
                     }
                     ))
}

fn equal_islice(a: Vec<i16>, x: usize, y: usize) -> bool {
    if x > y || y > a.len() { return true; }
    let slc = &a[x..y];
    itertools::equal(a.iter().slice(x..y), slc)
}

fn size_islice(a: Iter<i16>, x: usize, y: usize) -> bool {
    correct_size_hint(a.clone().dedup().slice(x..y)) &&
        exact_size(a.clone().slice(x..y))
}

#[quickcheck]
fn size_interleave(a: Iter<i16>, b: Iter<i16>) -> bool {
    correct_size_hint(a.interleave(b))
}

#[quickcheck]
fn size_intersperse(a: Iter<i16>, x: i16) -> bool {
    correct_size_hint(a.intersperse(x))
}

#[quickcheck]
fn equal_intersperse(a: Vec<i32>, x: i32) -> bool {
    let mut inter = false;
    let mut i = 0;
    for elt in a.iter().cloned().intersperse(x) {
        if inter {
            if elt != x { return false }
        } else {
            if elt != a[i] { return false }
            i += 1;
        }
        inter = !inter;
    }
    true
}

#[quickcheck]
fn equal_dedup(a: Vec<i32>) -> bool {
    let mut b = a.clone();
    b.dedup();
    itertools::equal(&b, a.iter().dedup())
}

#[quickcheck]
fn size_dedup(a: Vec<i32>) -> bool {
    correct_size_hint(a.iter().dedup())
}

#[quickcheck]
fn size_group_by(a: Vec<i8>) -> bool {
    correct_size_hint(a.iter().group_by(|x| x.abs()))
}

#[quickcheck]
fn size_linspace(a: f32, b: f32, n: usize) -> bool {
    let it = itertools::linspace(a, b, n);
    it.len() == n &&
        exact_size(it)
}

#[quickcheck]
fn equal_repeatn(n: usize, x: i32) -> bool {
    let it = itertools::RepeatN::new(x, n);
    exact_size(it)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted(a: Vec<u8>, b: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted3(a: Vec<u8>, b: Vec<u8>, c: Vec<u8>) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), c.iter())))
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn equal_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    let it = itertools::ZipTrusted::new((a.iter(), b.iter(), x..y));
    let jt = Zip::new((a.iter(), b.iter(), x..y));
    itertools::equal(it, jt)
}

#[cfg(feature = "unstable")]
#[quickcheck]
fn size_ziptrusted_mix(a: Vec<u8>, b: Vec<()>, x: u8, y: u8) -> bool {
    exact_size(itertools::ZipTrusted::new((a.iter(), b.iter(), x..y)))
}

#[quickcheck]
fn size_put_back(a: Vec<u8>, x: Option<u8>) -> bool {
    let mut it = itertools::PutBack::new(a.into_iter());
    match x {
        Some(t) => it.put_back(t),
        None => {}
    }
    correct_size_hint(it)
}

#[quickcheck]
fn size_tee(a: Vec<u8>) -> bool {
    let (mut t1, mut t2) = a.iter().tee();
    t1.next();
    t1.next();
    t2.next();
    exact_size(t1) && exact_size(t2)
}

#[quickcheck]
fn size_tee_2(a: Vec<u8>) -> bool {
    let (mut t1, mut t2) = a.iter().dedup().tee();
    t1.next();
    t1.next();
    t2.next();
    correct_size_hint(t1) && correct_size_hint(t2)
}

#[quickcheck]
fn size_mend_slices(a: Vec<u8>, splits: Vec<usize>) -> bool {
    let slice_iter = splits.into_iter().map(|ix|
        if ix < a.len() {
            &a[ix..(ix + 1)]
        } else {
            &a[0..0]
        }
    ).mend_slices();
    correct_size_hint(slice_iter)
}

#[quickcheck]
fn size_take_while_ref(a: Vec<u8>, stop: u8) -> bool {
    correct_size_hint(a.iter().take_while_ref(|x| **x != stop))
}

#[quickcheck]
fn equal_partition(mut a: Vec<i32>) -> bool {
    let mut ap = a.clone();
    let split_index = itertools::partition(&mut ap, |x| *x >= 0);
    let parted = (0..split_index).all(|i| ap[i] >= 0) &&
        (split_index..a.len()).all(|i| ap[i] < 0);

    a.sort();
    ap.sort();
    parted && (a == ap)
}

}
<|endoftext|>