<commit_before>//! Contains test for all types supporting `bind_parameter`
//!
//! These tests assume there is a Stage table with a Varchar in 'A', an Integer in 'B' and a Real
//! in 'C'
extern crate odbc;
use odbc::*;

#[test]
#[ignore]
/// tested in windows中文版
fn _exec_direct() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    let stmt = Statement::with_parent(&conn).unwrap();

    // select '你好' as hello
    if let Ok(Data(mut stmt)) = stmt.exec_direct_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32].as_slice()) {
        while let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),  // when  你好 is encoded by gbk, it is [196, 227, 186, 195]
                None => panic!(" NULL"),
            }
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
#[ignore]
/// tested in windows中文版
fn _prepare_1() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select '你好' as hello where 1 = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 119, 104, 101, 114, 101, 32, 32, 49, 32, 61, 32, 63, 32].as_slice()).unwrap();
    let stmt = stmt.bind_parameter(1, &1).unwrap();

    match stmt.execute().unwrap() {
        Data(mut stmt) => {
            while let Some(mut cursor) = stmt.fetch().unwrap() {
                match cursor.get_data::<Vec<u8>>(1).unwrap() {
                    Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),
                    None => panic!(" NULL"),
                }
            }
        }
        NoData(_) => {
            panic!("SELECT did not return result set");
        }
    }

}

#[test]
#[ignore]
/// tested in windows中文版
fn _prepare_2() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select '你好' as hello where '你好' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 119, 104, 101, 114, 101, 32, 32, 39, 196, 227, 186, 195, 39, 32, 61, 32, 63, 32].as_slice()).unwrap();
    // bind  gbk encoded byte
    let param = vec![196u8, 227u8, 186u8, 195u8];
    let stmt = stmt.bind_parameter(1, &param).unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        while let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),
                None => panic!(" NULL"),
            }
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
fn exec_direct() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    let stmt = Statement::with_parent(&conn).unwrap();

    // select '你好' as hello
    if let Ok(Data(mut stmt)) = stmt.exec_direct_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 228, 189, 160, 229, 165, 189, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 32].as_slice()) {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![228u8, 189u8, 160u8, 229u8, 165u8, 189u8]),  // when  你好 is encoded by utf8, it is [228, 189, 160, 229, 165, 189]
                None => panic!(" NULL"),
            }
        } else {
            panic!("No Data");
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
fn prepare_1() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select '你好' as hello where 1 = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 228, 189, 160, 229, 165, 189, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 119, 104, 101, 114, 101, 32, 49, 32, 61, 32, 63, 32].as_slice()).unwrap();
    let stmt = stmt.bind_parameter(1, &1).unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![228u8, 189u8, 160u8, 229u8, 165u8, 189u8]),
                None => panic!(" NULL"),
            }
        } else {
            panic!("No data");
        }
    } else {
        panic!("SELECT did not return result set");
    }

}

#[test]
fn prepare_2() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select '你好' as hello where '你好' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 228, 189, 160, 229, 165, 189, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 119, 104, 101, 114, 101, 32, 39, 228, 189, 160, 229, 165, 189, 39, 32, 61, 32, 63, 32].as_slice()).unwrap();
    // bind  gbk encoded byte
    let param = vec![228u8, 189u8, 160u8, 229u8, 165u8, 189u8];
    let stmt = stmt.bind_parameter(1, &param).unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![228u8, 189u8, 160u8, 229u8, 165u8, 189u8]),
                None => panic!(" NULL"),
            }
        } else {
            panic!("No data");
        }
    } else {
        panic!("SELECT did not return result set");
    }
}
<commit_msg>appveyor windows code page is '437', i removed chinese character.<commit_after>//! Contains test for all types supporting `bind_parameter`
//!
//! These tests assume there is a Stage table with a Varchar in 'A', an Integer in 'B' and a Real
//! in 'C'
extern crate odbc;
use odbc::*;

#[test]
#[ignore]
/// tested in windows中文版 codepage 936
fn _exec_direct() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    let stmt = Statement::with_parent(&conn).unwrap();

    // select '你好' as hello
    if let Ok(Data(mut stmt)) = stmt.exec_direct_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32].as_slice()) {
        while let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),  // when  你好 is encoded by gbk, it is [196, 227, 186, 195]
                None => panic!(" NULL"),
            }
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
#[ignore]
/// tested in windows中文版 codepage 936
fn _prepare_1() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select '你好' as hello where 1 = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 119, 104, 101, 114, 101, 32, 32, 49, 32, 61, 32, 63, 32].as_slice()).unwrap();
    let stmt = stmt.bind_parameter(1, &1).unwrap();

    match stmt.execute().unwrap() {
        Data(mut stmt) => {
            while let Some(mut cursor) = stmt.fetch().unwrap() {
                match cursor.get_data::<Vec<u8>>(1).unwrap() {
                    Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),
                    None => panic!(" NULL"),
                }
            }
        }
        NoData(_) => {
            panic!("SELECT did not return result set");
        }
    }

}

#[test]
#[ignore]
/// tested in windows中文版 codepage 936
fn _prepare_2() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "sa", "123456").unwrap();
    // select '你好' as hello where '你好' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 119, 104, 101, 114, 101, 32, 32, 39, 196, 227, 186, 195, 39, 32, 61, 32, 63, 32].as_slice()).unwrap();
    // bind  gbk encoded byte
    let param = vec![196u8, 227u8, 186u8, 195u8];
    let stmt = stmt.bind_parameter(1, &param).unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        while let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),
                None => panic!(" NULL"),
            }
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
fn exec_direct() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    let stmt = Statement::with_parent(&conn).unwrap();

    // select 'hello'
    if let Ok(Data(mut stmt)) = stmt.exec_direct_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 104, 101, 108, 108, 111, 39, 32].as_slice()) {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![104, 101, 108, 108, 111]),  // when  hello is encoded by utf8, it is [104, 101, 108, 108, 111]
                None => panic!(" NULL"),
            }
        } else {
            panic!("No Data");
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
fn prepare_1() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select 'hello' where 'hello' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 104, 101, 108, 108, 111, 39, 32, 119, 104, 101, 114, 101, 32, 39, 104, 101, 108, 108, 111, 39, 32, 61, 32, 63, 32].as_slice()).unwrap();
    let stmt = stmt.bind_parameter(1, &"hello").unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![104, 101, 108, 108, 111]),
                None => panic!(" NULL"),
            }
        } else {
            panic!("No data");
        }
    } else {
        panic!("SELECT did not return result set");
    }

}

#[test]
fn prepare_2() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select 'hello' where 'hello' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 104, 101, 108, 108, 111, 39, 32, 119, 104, 101, 114, 101, 32, 39, 104, 101, 108, 108, 111, 39, 32, 61, 32, 63, 32].as_slice()).unwrap();
    // bind  utf encoded byte
    let param: Vec<u8> = vec![104, 101, 108, 108, 111];
    let stmt = stmt.bind_parameter(1, &param).unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![104, 101, 108, 108, 111]),
                None => panic!(" NULL"),
            }
        } else {
            panic!("No data");
        }
    } else {
        panic!("SELECT did not return result set");
    }
}
<|endoftext|>


<commit_before>
extern crate metl;
extern crate cocoa;

use cocoa::base::{BOOL, nil};
use cocoa::foundation::NSString;
use metl::{CompileOptions, Device, FeatureSet, LanguageVersion, PixelFormat, SpecificLanguageVersion,
           SamplerDescriptor, TextureDescriptor};
use metl::LibraryError;
use metl::{FromRaw, FromRawError, IntoRaw};
use metl::sys::{MTLCompileOptions, MTLLanguageVersion};

#[test]
fn get_device() {
    let device = Device::system_default_device();
    assert!(device.is_ok());
}

#[test]
fn get_all_devices() {
    let all_devices = Device::enumerate_all_system_devices();
    assert!(!all_devices.is_empty());
    for device in all_devices {
        assert!(device.is_ok());
    }
}

#[test]
fn get_device_name() {
    let device = Device::system_default_device().unwrap();
    assert!(!device.name().into_owned().is_empty());
}

#[cfg(target_os = "macos")]
#[test]
fn device_supports_base_features() {
    let base_osx_feature_set = FeatureSet::OsxGpuFamily1_v1;
    let device = Device::system_default_device().unwrap();
    assert!(device.supports_feature_set(base_osx_feature_set));
}

#[test]
fn set_get_command_queue_label() {
    let mut device = Device::system_default_device().unwrap();
    let mut command_queue = device.new_command_queue().unwrap();

    const DUMMY_COMMAND_QUEUE_NAME: &'static str = "foo";
    command_queue.set_label(&DUMMY_COMMAND_QUEUE_NAME);

    assert_eq!(command_queue.label(), DUMMY_COMMAND_QUEUE_NAME);
}

#[test]
fn insert_debug_capture_boundary_on_command_queue() {
    let mut device = Device::system_default_device().unwrap();
    let mut command_queue = device.new_command_queue().unwrap();
    command_queue.insert_debug_capture_boundary();
    assert!(true);
}

#[test]
fn device_from_to_raw() {
    let device = Device::system_default_device().unwrap();
    let raw = device.into_raw();
    let device = Device::from_raw(raw);
    assert!(device.is_ok());
}

#[test]
fn device_from_wrong_type() {
    let some_string = unsafe { NSString::alloc(nil).init_str("Hello") };
    let device_result = Device::from_raw(some_string);
    println!("{}", device_result.is_ok());
    match device_result {
        Result::Err(FromRawError::WrongPointerType) => {
            // pass
        }
        _ => assert!(false),
    }
}

#[test]
fn device_from_nullptr() {
    let device_result = Device::from_raw(nil);
    match device_result {
        Result::Err(FromRawError::NilPointer) => {
            // pass
        }
        _ => assert!(false),
    }
}

#[test]
fn compile_opts_creation_is_correct() {
    let fast_math_enabled = true;
    let options =
        CompileOptions::default()
            .fast_math_enabled(fast_math_enabled)
            .language_version(LanguageVersion::Specific(SpecificLanguageVersion::Version_1_0))
            .with_macro("Foo", 54)
            .with_macro("Bar", 32.0)
            .with_macro("Baz", "Hi")
            .mtl_compile_options();

    unsafe {
        assert_eq!(fast_math_enabled as BOOL, options.fastMathEnabled());
        assert_eq!(options.languageVersion(),
                   MTLLanguageVersion::MTLLanguageVersion1_0);
    }
}

#[test]
// TODO(burtonageo): Fix setting the label
fn create_sampler_and_set_label() {
    const SAMPLER_LABEL: &'static str = "ExampleSampler";

    let mut device = Device::system_default_device().unwrap();
    let mut sampler_descriptor = SamplerDescriptor::new();
    //sampler_descriptor.set_label(&SAMPLER_LABEL);
    let sampler = device.new_sampler_state(&sampler_descriptor).unwrap();

    //assert_eq!(sampler_descriptor.label(), SAMPLER_LABEL);
    //assert_eq!(sampler.label(), sampler_descriptor.label());
}

#[test]
fn create_texture() {
    const PIX_FORMAT: PixelFormat = PixelFormat::Rgba8UnormSrgb;
    const TEX_DIMS: (usize, usize) = (600, 800);
    const MIPPED: bool = false;

    let mut device = Device::system_default_device().unwrap();
    let mut tex_descriptor = TextureDescriptor::new_2d(PIX_FORMAT, TEX_DIMS.0, TEX_DIMS.1, MIPPED);
    let texture = device.new_texture(&tex_descriptor).unwrap();

    assert_eq!(texture.pixel_format(), PIX_FORMAT);
    assert_eq!(texture.width(), TEX_DIMS.0);
    assert_eq!(texture.height(), TEX_DIMS.1);
    assert_eq!(texture.texture_type(), metl::TextureType::Type2D);
}

#[test]
fn create_invalid_shader() {
    let mut device = Device::system_default_device().unwrap();
    const BAD_SHADER: &'static str = r"abcdefghijklmnopqrstuvwxyz";
    match device.new_library_with_source(&BAD_SHADER, &Default::default()) {
        Ok(_) => panic!("Incorrect result: expected an error"),
        Err(LibraryError::SourceError(_)) => assert!(true),
        Err(_) => panic!("Incorrect error type")
    }
}

#[test]
fn create_invalid_shader_async() {
    let mut device = Device::system_default_device().unwrap();
    const BAD_SHADER: &'static str = r"FooBarBaz";
    match device.new_library_with_source_async(&BAD_SHADER, &Default::default()).recv().unwrap() {
        Ok(_) => panic!("Incorrect result: expected an error"),
        Err(LibraryError::SourceError(_)) => assert!(true),
        Err(_) => panic!("Incorrect error type")
    }
}

// Shader source taken from http://metalbyexample.com/up-and-running-2/
const SHADER: &'static str = r"
using namespace metal;

struct ColoredVertex
{
    float4 position [[position]];
    float4 color;
};

vertex ColoredVertex vertex_main(constant float4 *position [[buffer(0)]],
                                 constant float4 *color [[buffer(1)]],
                                 uint vid [[vertex_id]])
{
    ColoredVertex vert;
    vert.position = position[vid];
    vert.color = color[vid];
    return vert;
}

fragment float4 fragment_main(ColoredVertex vert [[stage_in]])
{
    return vert.color;
}
";

#[test]
fn device_create_library_with_valid_shader_code_and_get_fn_names() {
    let mut device = Device::system_default_device().unwrap();
    let library = device.new_library_with_source(&SHADER, &Default::default()).ok().unwrap();
    let names = library.function_names();
    assert_eq!(names[0], "vertex_main");
    assert_eq!(names[1], "fragment_main");
}

#[test]
#[ignore]
fn device_create_library_async_with_valid_shader_code_and_get_fn_names() {
    let mut device = Device::system_default_device().unwrap();
    let library = device.new_library_with_source_async(&SHADER, &Default::default())
                        .recv()
                        .unwrap()
                        .unwrap();
    let names = library.function_names();
    assert_eq!(names[0], "vertex_main");
    assert_eq!(names[1], "fragment_main");
}

#[test]
fn shader_get_function_with_name() {
    let mut device = Device::system_default_device().unwrap();
    let mut library = device.new_library_with_source(&SHADER, &Default::default()).ok().unwrap();
    let function = library.new_function_with_name(&"fragment_main");
    assert!(function.is_some());
}

#[test]
#[ignore]
fn shader_get_struct_info() {
    use metl::{StructMember, StructType};
    let mut device = Device::system_default_device().unwrap();
    let mut library = device.new_library_with_source(&SHADER, &Default::default()).ok().unwrap();
    let function = library.new_function_with_name(&"fragment_main").unwrap();
    unimplemented!();
}
<commit_msg>Improve test so that it tests more<commit_after>
extern crate metl;
extern crate cocoa;

use cocoa::base::{BOOL, nil};
use cocoa::foundation::NSString;
use metl::{CompileOptions, Device, FeatureSet, LanguageVersion, PixelFormat, SpecificLanguageVersion,
           SamplerDescriptor, TextureDescriptor};
use metl::LibraryError;
use metl::{FromRaw, FromRawError, IntoRaw};
use metl::sys::{MTLCompileOptions, MTLLanguageVersion};

#[test]
fn get_device() {
    let device = Device::system_default_device();
    assert!(device.is_ok());
}

#[test]
fn get_all_devices() {
    let all_devices = Device::enumerate_all_system_devices();
    assert!(!all_devices.is_empty());
    for device in all_devices {
        assert!(device.is_ok());
    }
}

#[test]
fn get_device_name() {
    let device = Device::system_default_device().unwrap();
    assert!(!device.name().into_owned().is_empty());
}

#[cfg(target_os = "macos")]
#[test]
fn device_supports_base_features() {
    let base_osx_feature_set = FeatureSet::OsxGpuFamily1_v1;
    let device = Device::system_default_device().unwrap();
    assert!(device.supports_feature_set(base_osx_feature_set));
}

#[test]
fn set_get_command_queue_label() {
    let mut device = Device::system_default_device().unwrap();
    let mut command_queue = device.new_command_queue().unwrap();

    const DUMMY_COMMAND_QUEUE_NAME: &'static str = "foo";
    command_queue.set_label(&DUMMY_COMMAND_QUEUE_NAME);

    assert_eq!(command_queue.label(), DUMMY_COMMAND_QUEUE_NAME);
}

#[test]
fn insert_debug_capture_boundary_on_command_queue() {
    let mut device = Device::system_default_device().unwrap();
    let mut command_queue = device.new_command_queue().unwrap();
    command_queue.insert_debug_capture_boundary();
    assert!(true);
}

#[test]
fn device_from_to_raw() {
    let device = Device::system_default_device().unwrap();
    let raw = device.into_raw();
    let device = Device::from_raw(raw);
    assert!(device.is_ok());
}

#[test]
fn device_from_wrong_type() {
    let some_string = unsafe { NSString::alloc(nil).init_str("Hello") };
    let device_result = Device::from_raw(some_string);
    println!("{}", device_result.is_ok());
    match device_result {
        Result::Err(FromRawError::WrongPointerType) => {
            // pass
        }
        _ => assert!(false),
    }
}

#[test]
fn device_from_nullptr() {
    let device_result = Device::from_raw(nil);
    match device_result {
        Result::Err(FromRawError::NilPointer) => {
            // pass
        }
        _ => assert!(false),
    }
}

#[test]
fn compile_opts_creation_is_correct() {
    let fast_math_enabled = true;
    let options =
        CompileOptions::default()
            .fast_math_enabled(fast_math_enabled)
            .language_version(LanguageVersion::Specific(SpecificLanguageVersion::Version_1_0))
            .with_macro("Foo", 54)
            .with_macro("Bar", 32.0)
            .with_macro("Baz", "Hi")
            .mtl_compile_options();

    unsafe {
        assert_eq!(fast_math_enabled as BOOL, options.fastMathEnabled());
        assert_eq!(options.languageVersion(),
                   MTLLanguageVersion::MTLLanguageVersion1_0);
    }
}

#[test]
fn create_sampler_and_set_label() {
    const SAMPLER_LABEL: &'static str = "ExampleSampler";
    let mut device = Device::system_default_device().unwrap();

    let mut sampler_descriptor = SamplerDescriptor::new();
    sampler_descriptor.set_label(&SAMPLER_LABEL);
    assert_eq!(sampler_descriptor.label(), SAMPLER_LABEL);

    let sampler = device.new_sampler_state(&sampler_descriptor).unwrap();
    // TODO(burtonageo): Fix getting the label
    // assert_eq!(sampler.label(), sampler_descriptor.label());
}

#[test]
fn create_texture() {
    const PIX_FORMAT: PixelFormat = PixelFormat::Rgba8UnormSrgb;
    const TEX_DIMS: (usize, usize) = (600, 800);
    const MIPPED: bool = false;

    let mut device = Device::system_default_device().unwrap();
    let mut tex_descriptor = TextureDescriptor::new_2d(PIX_FORMAT, TEX_DIMS.0, TEX_DIMS.1, MIPPED);
    let texture = device.new_texture(&tex_descriptor).unwrap();

    assert_eq!(texture.pixel_format(), PIX_FORMAT);
    assert_eq!(texture.width(), TEX_DIMS.0);
    assert_eq!(texture.height(), TEX_DIMS.1);
    assert_eq!(texture.texture_type(), metl::TextureType::Type2D);
}

#[test]
fn create_invalid_shader() {
    let mut device = Device::system_default_device().unwrap();
    const BAD_SHADER: &'static str = r"abcdefghijklmnopqrstuvwxyz";
    match device.new_library_with_source(&BAD_SHADER, &Default::default()) {
        Ok(_) => panic!("Incorrect result: expected an error"),
        Err(LibraryError::SourceError(_)) => assert!(true),
        Err(_) => panic!("Incorrect error type")
    }
}

#[test]
fn create_invalid_shader_async() {
    let mut device = Device::system_default_device().unwrap();
    const BAD_SHADER: &'static str = r"FooBarBaz";
    match device.new_library_with_source_async(&BAD_SHADER, &Default::default()).recv().unwrap() {
        Ok(_) => panic!("Incorrect result: expected an error"),
        Err(LibraryError::SourceError(_)) => assert!(true),
        Err(_) => panic!("Incorrect error type")
    }
}

// Shader source taken from http://metalbyexample.com/up-and-running-2/
const SHADER: &'static str = r"
using namespace metal;

struct ColoredVertex
{
    float4 position [[position]];
    float4 color;
};

vertex ColoredVertex vertex_main(constant float4 *position [[buffer(0)]],
                                 constant float4 *color [[buffer(1)]],
                                 uint vid [[vertex_id]])
{
    ColoredVertex vert;
    vert.position = position[vid];
    vert.color = color[vid];
    return vert;
}

fragment float4 fragment_main(ColoredVertex vert [[stage_in]])
{
    return vert.color;
}
";

#[test]
fn device_create_library_with_valid_shader_code_and_get_fn_names() {
    let mut device = Device::system_default_device().unwrap();
    let library = device.new_library_with_source(&SHADER, &Default::default()).ok().unwrap();
    let names = library.function_names();
    assert_eq!(names[0], "vertex_main");
    assert_eq!(names[1], "fragment_main");
}

#[test]
#[ignore]
fn device_create_library_async_with_valid_shader_code_and_get_fn_names() {
    let mut device = Device::system_default_device().unwrap();
    let library = device.new_library_with_source_async(&SHADER, &Default::default())
                        .recv()
                        .unwrap()
                        .unwrap();
    let names = library.function_names();
    assert_eq!(names[0], "vertex_main");
    assert_eq!(names[1], "fragment_main");
}

#[test]
fn shader_get_function_with_name() {
    let mut device = Device::system_default_device().unwrap();
    let mut library = device.new_library_with_source(&SHADER, &Default::default()).ok().unwrap();
    let function = library.new_function_with_name(&"fragment_main");
    assert!(function.is_some());
}

#[test]
#[ignore]
fn shader_get_struct_info() {
    use metl::{StructMember, StructType};
    let mut device = Device::system_default_device().unwrap();
    let mut library = device.new_library_with_source(&SHADER, &Default::default()).ok().unwrap();
    let function = library.new_function_with_name(&"fragment_main").unwrap();
    unimplemented!();
}
<|endoftext|>


<commit_before>extern crate sorting;

use std::fmt::Debug;

/// Verify order of input vector as sorted by indices.
///
/// # Details
///
/// This function takes as arguments a vector of data and a vector representing the indices of the
/// first vector making it sorted.
///
/// The elements of the sorted vector are compared to the next ones to make sure they are less
/// or equal.
///
/// # Panics
///
/// The sorting of the data vector is enforced using `assert!()`.
///
/// # Examples
///
/// ```
/// let data: Vec<i32> = vec![4, 2, 3, 1];
/// let sorted_indices: Vec<usize> = vec![3, 1, 2, 0];
/// verify_sorting(&data, &sorted_indices);
/// ```
///
fn verify_sorting<T: Debug + PartialOrd>(array: &Vec<T>, sorted_indices: &Vec<usize>) {
    let n = array.len();
    assert_eq!(n , sorted_indices.len());

    if !array.is_empty() {
        for i in 0..n-1 {
            println!("array[sorted_indices[i={:?}]]={:?}   array[sorted_indices[i+1={:?}]]={:?}",
                i, array[sorted_indices[i]], i+1, array[sorted_indices[i+1]]);
            assert!(array[sorted_indices[i]] <= array[sorted_indices[i+1]]);
        }
    }
}

fn test_empty_vec<T: PartialOrd>(sorting_fct: fn(&Vec<T>) -> Vec<usize>) {
    let to_sort: Vec<T> = vec![];
    let sorted_indices = sorting_fct(&to_sort);
    assert_eq!(sorted_indices, vec![]);
    assert!(sorted_indices.is_empty());
}

/// Validate against empty vector (i8).
#[test]
fn simple_insertion_empty_vec_i8() {
    test_empty_vec::<i8>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i32).
#[test]
fn simple_insertion_empty_vec_i16() {
    test_empty_vec::<i16>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i32).
#[test]
fn simple_insertion_empty_vec_i32() {
    test_empty_vec::<i32>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i64).
#[test]
fn simple_insertion_empty_vec_i64() {
    test_empty_vec::<i64>(sorting::simplesorts::insertion::sort);
}

/// Validate against empty vector (u8).
#[test]
fn simple_insertion_empty_vec_u8() {
    test_empty_vec::<u8>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u32).
#[test]
fn simple_insertion_empty_vec_u16() {
    test_empty_vec::<u16>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u32).
#[test]
fn simple_insertion_empty_vec_u32() {
    test_empty_vec::<u32>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u64).
#[test]
fn simple_insertion_empty_vec_u64() {
    test_empty_vec::<u64>(sorting::simplesorts::insertion::sort);
}

/// Validate a vector of double precision values.
#[test]
fn simple_insertion_vec_f64() {
    let to_sort: Vec<f64> = vec![6.0,   5.0,  3.0,  1.0,  2.4, 4.0, 10.0, 7.0,
                                 3.42, 32.2, 44.2, 56.3, 67.9, 3.2, 44.2, 2.0];

    let sorted_indices = sorting::simplesorts::insertion::sort(&to_sort);

    verify_sorting(&to_sort, &sorted_indices);

    assert_eq!(sorted_indices, vec![3, 15, 4, 2, 13, 8, 5, 1, 0, 7, 6, 9, 10, 14, 11, 12]);
}
<commit_msg>Doc comments<commit_after>extern crate sorting;

use std::fmt::Debug;

/// Verify order of input vector as sorted by indices.
///
/// # Details
///
/// This function takes as arguments a vector of data and a vector representing the indices of the
/// first vector making it sorted.
///
/// The elements of the sorted vector are compared to the next ones to make sure they are less
/// or equal.
///
/// # Panics
///
/// The sorting of the data vector is enforced using `assert!()`.
///
/// # Examples
///
/// ```
/// let data: Vec<i32> = vec![4, 2, 3, 1];
/// let sorted_indices: Vec<usize> = vec![3, 1, 2, 0];
/// verify_sorting(&data, &sorted_indices);
/// ```
///
fn verify_sorting<T: Debug + PartialOrd>(array: &Vec<T>, sorted_indices: &Vec<usize>) {
    let n = array.len();
    assert_eq!(n , sorted_indices.len());

    if !array.is_empty() {
        for i in 0..n-1 {
            println!("array[sorted_indices[i={:?}]]={:?}   array[sorted_indices[i+1={:?}]]={:?}",
                i, array[sorted_indices[i]], i+1, array[sorted_indices[i+1]]);
            assert!(array[sorted_indices[i]] <= array[sorted_indices[i+1]]);
        }
    }
}

/// Call the specified sorting function on an empty vector of specific type.
///
/// # Details
///
/// This function takes as arguments a pointer to a sorting function acting and call
/// it on an empty vector of type T. The call should succeed and the index vector should
/// be empty as well.
///
/// # Panics
///
/// The emptiness of the sorted list is enforced using `assert!()`.
///
/// # Examples
///
/// ```
/// test_empty_vec::<i8>(sorting::simplesorts::insertion::sort);
/// ```
///
fn test_empty_vec<T: PartialOrd>(sorting_fct: fn(&Vec<T>) -> Vec<usize>) {
    let to_sort: Vec<T> = vec![];
    let sorted_indices = sorting_fct(&to_sort);
    assert_eq!(sorted_indices, vec![]);
    assert!(sorted_indices.is_empty());
}

/// Validate against empty vector (i8).
#[test]
fn simple_insertion_empty_vec_i8() {
    test_empty_vec::<i8>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i32).
#[test]
fn simple_insertion_empty_vec_i16() {
    test_empty_vec::<i16>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i32).
#[test]
fn simple_insertion_empty_vec_i32() {
    test_empty_vec::<i32>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (i64).
#[test]
fn simple_insertion_empty_vec_i64() {
    test_empty_vec::<i64>(sorting::simplesorts::insertion::sort);
}

/// Validate against empty vector (u8).
#[test]
fn simple_insertion_empty_vec_u8() {
    test_empty_vec::<u8>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u32).
#[test]
fn simple_insertion_empty_vec_u16() {
    test_empty_vec::<u16>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u32).
#[test]
fn simple_insertion_empty_vec_u32() {
    test_empty_vec::<u32>(sorting::simplesorts::insertion::sort);
}
/// Validate against empty vector (u64).
#[test]
fn simple_insertion_empty_vec_u64() {
    test_empty_vec::<u64>(sorting::simplesorts::insertion::sort);
}

/// Validate a vector of double precision values.
#[test]
fn simple_insertion_vec_f64() {
    let to_sort: Vec<f64> = vec![6.0,   5.0,  3.0,  1.0,  2.4, 4.0, 10.0, 7.0,
                                 3.42, 32.2, 44.2, 56.3, 67.9, 3.2, 44.2, 2.0];

    let sorted_indices = sorting::simplesorts::insertion::sort(&to_sort);

    verify_sorting(&to_sort, &sorted_indices);

    assert_eq!(sorted_indices, vec![3, 15, 4, 2, 13, 8, 5, 1, 0, 7, 6, 9, 10, 14, 11, 12]);
}
<|endoftext|>


<commit_before>
extern crate fftw;
extern crate float_cmp;

use fftw::*;
use float_cmp::ApproxEqRatio;
use std::f64::consts::PI;

#[test]
fn r2hc2r() {
    let n = 128;
    let mut pair = Pair::r2r_1d(n, R2R_KIND::FFTW_R2HC, FLAG::FFTW_ESTIMATE);
    for (i, val) in pair.field.iter_mut().enumerate() {
        *val = (i + 1) as f64;
    }
    pair.forward();
    pair.backward();
    pair.normalize_field_by(1.0 / n as f64);
    for (i, val) in pair.field.iter().enumerate() {
        let ans = (i + 1) as f64;
        if !val.approx_eq_ratio(&ans, 1e-7) {
            panic!("Not equal: ans={}/val={}", ans, val);
        }
    }
}

#[test]
fn hc2r2hc() {
    let n = 128;
    let mut pair = Pair::r2r_1d(n, R2R_KIND::FFTW_R2HC, FLAG::FFTW_ESTIMATE);
    for (i, val) in pair.coef.iter_mut().enumerate() {
        *val = (i + 1) as f64;
    }
    pair.backward();
    pair.forward();
    pair.normalize_coef_by(1.0 / n as f64);
    for (i, val) in pair.coef.iter().enumerate() {
        let ans = (i + 1) as f64;
        if !val.approx_eq_ratio(&ans, 1e-7) {
            panic!("Not equal: ans={}/val={}", ans, val);
        }
    }
}

#[test]
fn hc2r() {
    let n = 128;
    let mut pair = Pair::r2r_1d(n, R2R_KIND::FFTW_R2HC, FLAG::FFTW_ESTIMATE);
    pair.coef[0] = 2.0;
    pair.coef[1] = 1.0;
    pair.backward();
    let ans: Vec<f64> = (0..n)
        .map(|i| {
            let x = 2.0 * PI * i as f64 / n as f64;
            2.0 + 2.0 * x.cos()
        })
        .collect();
    for (v, a) in pair.field.iter().zip(ans.iter()) {
        if (v - a).abs() > 1e-7 {
            panic!("Not equal: ans={}/val={}", a, v);
        }
    }
}
<commit_msg>Fix test<commit_after>
extern crate fftw;
extern crate float_cmp;

use fftw::*;
use float_cmp::ApproxEqRatio;
use std::f64::consts::PI;

#[test]
fn r2hc2r() {
    let n = 128;
    let mut pair = Pair::<f64, f64>::r2r_1d(n, R2R_KIND::FFTW_R2HC, FLAG::FFTW_ESTIMATE);
    for (i, val) in pair.field.iter_mut().enumerate() {
        *val = (i + 1) as f64;
    }
    pair.forward();
    pair.backward();
    pair.normalize_field_by(1.0 / n as f64);
    for (i, val) in pair.field.iter().enumerate() {
        let ans = (i + 1) as f64;
        if !val.approx_eq_ratio(&ans, 1e-7) {
            panic!("Not equal: ans={}/val={}", ans, val);
        }
    }
}

#[test]
fn hc2r2hc() {
    let n = 128;
    let mut pair = Pair::<f64, f64>::r2r_1d(n, R2R_KIND::FFTW_R2HC, FLAG::FFTW_ESTIMATE);
    for (i, val) in pair.coef.iter_mut().enumerate() {
        *val = (i + 1) as f64;
    }
    pair.backward();
    pair.forward();
    pair.normalize_coef_by(1.0 / n as f64);
    for (i, val) in pair.coef.iter().enumerate() {
        let ans = (i + 1) as f64;
        if !val.approx_eq_ratio(&ans, 1e-7) {
            panic!("Not equal: ans={}/val={}", ans, val);
        }
    }
}

#[test]
fn hc2r() {
    let n = 128;
    let mut pair = Pair::<f64, f64>::r2r_1d(n, R2R_KIND::FFTW_R2HC, FLAG::FFTW_ESTIMATE);
    pair.coef[0] = 2.0;
    pair.coef[1] = 1.0;
    pair.backward();
    let ans: Vec<f64> = (0..n)
        .map(|i| {
            let x = 2.0 * PI * i as f64 / n as f64;
            2.0 + 2.0 * x.cos()
        })
        .collect();
    for (v, a) in pair.field.iter().zip(ans.iter()) {
        if (v - a).abs() > 1e-7 {
            panic!("Not equal: ans={}/val={}", a, v);
        }
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate bufstream;
extern crate cargo;
extern crate filetime;
extern crate flate2;
extern crate git2;
extern crate hamcrest;
extern crate libc;
extern crate rustc_serialize;
extern crate serde;
#[macro_use]
extern crate serde_json;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate url;
#[cfg(windows)] extern crate kernel32;
#[cfg(windows)] extern crate winapi;

use cargo::util::Rustc;
use std::ffi::OsStr;
use std::time::Duration;
use std::path::PathBuf;
use std::env;

pub mod support;
pub mod install;

thread_local!(pub static RUSTC: Rustc = Rustc::new(PathBuf::from("rustc")).unwrap());

pub fn rustc_host() -> String {
    RUSTC.with(|r| r.host.clone())
}

pub fn is_nightly() -> bool {
    RUSTC.with(|r| {
        r.verbose_version.contains("-nightly") ||
            r.verbose_version.contains("-dev")
    })
}

pub fn process<T: AsRef<OsStr>>(t: T) -> cargo::util::ProcessBuilder {
    _process(t.as_ref())
}

fn _process(t: &OsStr) -> cargo::util::ProcessBuilder {
    let mut p = cargo::util::process(t);
    p.cwd(&support::paths::root())
     .env_remove("CARGO_HOME")
     .env("HOME", support::paths::home())
     .env("CARGO_HOME", support::paths::home().join(".cargo"))
     .env_remove("RUSTC")
     .env_remove("RUSTFLAGS")
     .env_remove("CARGO_INCREMENTAL")
     .env_remove("XDG_CONFIG_HOME")      // see #2345
     .env("GIT_CONFIG_NOSYSTEM", "1")    // keep trying to sandbox ourselves
     .env_remove("CARGO_TARGET_DIR")     // we assume 'target'
     .env_remove("MSYSTEM");             // assume cmd.exe everywhere on windows

    // We'll need dynamic libraries at some point in this test suite, so ensure
    // that the rustc libdir is somewhere in LD_LIBRARY_PATH as appropriate.
    // Note that this isn't needed on Windows as we assume the bindir (with
    // dlls) is in PATH.
    if cfg!(unix) {
        let var = if cfg!(target_os = "macos") {
            "DYLD_LIBRARY_PATH"
        } else {
            "LD_LIBRARY_PATH"
        };
        let rustc = RUSTC.with(|r| r.path.clone());
        let path = env::var_os("PATH").unwrap_or(Default::default());
        let rustc = env::split_paths(&path)
                        .map(|p| p.join(&rustc))
                        .find(|p| p.exists())
                        .unwrap();
        let mut libdir = rustc.clone();
        libdir.pop();
        libdir.pop();
        libdir.push("lib");
        let prev = env::var_os(&var).unwrap_or(Default::default());
        let mut paths = env::split_paths(&prev).collect::<Vec<_>>();
        println!("libdir: {:?}", libdir);
        if !paths.contains(&libdir) {
            paths.push(libdir);
            p.env(var, env::join_paths(&paths).unwrap());
        }
    }
    return p
}

pub fn cargo_process() -> cargo::util::ProcessBuilder {
    process(&support::cargo_dir().join("cargo"))
}

pub fn sleep_ms(ms: u64) {
    std::thread::sleep(Duration::from_millis(ms));
}
<commit_msg>tests: Insulate from user git environment<commit_after>#![deny(warnings)]

extern crate bufstream;
extern crate cargo;
extern crate filetime;
extern crate flate2;
extern crate git2;
extern crate hamcrest;
extern crate libc;
extern crate rustc_serialize;
extern crate serde;
#[macro_use]
extern crate serde_json;
extern crate tar;
extern crate tempdir;
extern crate term;
extern crate url;
#[cfg(windows)] extern crate kernel32;
#[cfg(windows)] extern crate winapi;

use cargo::util::Rustc;
use std::ffi::OsStr;
use std::time::Duration;
use std::path::PathBuf;
use std::env;

pub mod support;
pub mod install;

thread_local!(pub static RUSTC: Rustc = Rustc::new(PathBuf::from("rustc")).unwrap());

pub fn rustc_host() -> String {
    RUSTC.with(|r| r.host.clone())
}

pub fn is_nightly() -> bool {
    RUSTC.with(|r| {
        r.verbose_version.contains("-nightly") ||
            r.verbose_version.contains("-dev")
    })
}

pub fn process<T: AsRef<OsStr>>(t: T) -> cargo::util::ProcessBuilder {
    _process(t.as_ref())
}

fn _process(t: &OsStr) -> cargo::util::ProcessBuilder {
    let mut p = cargo::util::process(t);
    p.cwd(&support::paths::root())
     .env_remove("CARGO_HOME")
     .env("HOME", support::paths::home())
     .env("CARGO_HOME", support::paths::home().join(".cargo"))
     .env_remove("RUSTC")
     .env_remove("RUSTFLAGS")
     .env_remove("CARGO_INCREMENTAL")
     .env_remove("XDG_CONFIG_HOME")      // see #2345
     .env("GIT_CONFIG_NOSYSTEM", "1")    // keep trying to sandbox ourselves
     .env_remove("EMAIL")
     .env_remove("GIT_AUTHOR_NAME")
     .env_remove("GIT_AUTHOR_EMAIL")
     .env_remove("GIT_COMMITTER_NAME")
     .env_remove("GIT_COMMITTER_EMAIL")
     .env_remove("CARGO_TARGET_DIR")     // we assume 'target'
     .env_remove("MSYSTEM");             // assume cmd.exe everywhere on windows

    // We'll need dynamic libraries at some point in this test suite, so ensure
    // that the rustc libdir is somewhere in LD_LIBRARY_PATH as appropriate.
    // Note that this isn't needed on Windows as we assume the bindir (with
    // dlls) is in PATH.
    if cfg!(unix) {
        let var = if cfg!(target_os = "macos") {
            "DYLD_LIBRARY_PATH"
        } else {
            "LD_LIBRARY_PATH"
        };
        let rustc = RUSTC.with(|r| r.path.clone());
        let path = env::var_os("PATH").unwrap_or(Default::default());
        let rustc = env::split_paths(&path)
                        .map(|p| p.join(&rustc))
                        .find(|p| p.exists())
                        .unwrap();
        let mut libdir = rustc.clone();
        libdir.pop();
        libdir.pop();
        libdir.push("lib");
        let prev = env::var_os(&var).unwrap_or(Default::default());
        let mut paths = env::split_paths(&prev).collect::<Vec<_>>();
        println!("libdir: {:?}", libdir);
        if !paths.contains(&libdir) {
            paths.push(libdir);
            p.env(var, env::join_paths(&paths).unwrap());
        }
    }
    return p
}

pub fn cargo_process() -> cargo::util::ProcessBuilder {
    process(&support::cargo_dir().join("cargo"))
}

pub fn sleep_ms(ms: u64) {
    std::thread::sleep(Duration::from_millis(ms));
}
<|endoftext|>


<commit_before>mod reader;
mod writer;
mod message;

use std::net::SocketAddr;
use std::{io, fmt, mem, time};
use std::net::TcpStream;

use chrono::{DateTime, Utc};

pub use self::message::Message;
use self::reader::Reader;
use self::writer::Writer;
use socket::Socket;
use torrent::{Torrent, Bitfield};
use throttle::Throttle;
use control::cio;
use rpc::{self, resource};
use tracker;
use util;
use {DHT_EXT, CONFIG};

error_chain! {
    errors {
        ProtocolError(r: &'static str) {
            description("Peer did not conform to the bittorrent protocol")
                display("Peer protocol error: {:?}", r)
        }
    }
}

/// Peer connection and associated metadata.
pub struct Peer<T: cio::CIO> {
    id: usize,
    cio: T,
    pieces: Bitfield,
    remote_status: Status,
    local_status: Status,
    queued: u16,
    tid: usize,
    downloaded: u32,
    uploaded: u32,
    downloaded_bytes: u64,
    uploaded_bytes: u64,
    last_flush: DateTime<Utc>,
    addr: SocketAddr,
    t_hash: [u8; 20],
    cid: Option<[u8; 20]>,
    rsv: Option<[u8; 8]>,
}

#[derive(Debug)]
pub struct Status {
    pub choked: bool,
    pub interested: bool,
}

pub struct PeerConn {
    last_action: time::Instant,
    sock: Socket,
    reader: Reader,
    writer: Writer,
}

impl PeerConn {
    pub fn new(sock: Socket) -> PeerConn {
        let writer = Writer::new();
        let reader = Reader::new();
        PeerConn {
            sock,
            writer,
            reader,
            last_action: time::Instant::now(),
        }
    }

    #[cfg(test)]
    pub fn test() -> PeerConn {
        let writer = Writer::new();
        let reader = Reader::new();
        PeerConn {
            last_action: time::Instant::now(),
            sock: Socket::empty(),
            writer,
            reader,
        }
    }

    pub fn sock(&self) -> &Socket {
        &self.sock
    }

    pub fn sock_mut(&mut self) -> &mut Socket {
        &mut self.sock
    }

    pub fn last_action(&self) -> &time::Instant {
        &self.last_action
    }

    /// Creates a new "outgoing" peer, which acts as a client.
    /// Once created, set_torrent should be called.
    pub fn new_outgoing(ip: &SocketAddr) -> io::Result<PeerConn> {
        Ok(PeerConn::new(Socket::new(ip)?))
    }

    /// Creates a peer where we are acting as the server.
    /// Once the handshake is received, set_torrent should be called.
    pub fn new_incoming(sock: TcpStream) -> io::Result<PeerConn> {
        Ok(PeerConn::new(Socket::from_stream(sock)?))
    }

    pub fn writable(&mut self) -> io::Result<()> {
        self.last_action = time::Instant::now();
        self.writer.writable(&mut self.sock)
    }

    pub fn readable(&mut self) -> io::Result<Option<Message>> {
        self.last_action = time::Instant::now();
        self.reader.readable(&mut self.sock)
    }

    pub fn write_message(&mut self, msg: Message) -> io::Result<()> {
        self.writer.write_message(msg, &mut self.sock)
    }

    pub fn set_throttle(&mut self, throt: Throttle) {
        self.sock.throttle = Some(throt);
    }
}

impl Status {
    fn new() -> Status {
        Status {
            choked: true,
            interested: false,
        }
    }
}

#[cfg(test)]
impl Peer<cio::test::TCIO> {
    pub fn test(
        id: usize,
        uploaded: u32,
        downloaded: u32,
        queued: u16,
        pieces: Bitfield,
    ) -> Peer<cio::test::TCIO> {
        Peer {
            id,
            remote_status: Status::new(),
            local_status: Status::new(),
            uploaded,
            downloaded,
            uploaded_bytes: 0,
            downloaded_bytes: 0,
            addr: "127.0.0.1:0".parse().unwrap(),
            cio: cio::test::TCIO::new(),
            queued,
            pieces,
            tid: 0,
            t_hash: [0u8; 20],
            rsv: None,
            cid: None,
            last_flush: Utc::now(),
        }
    }

    pub fn test_from_pieces(id: usize, pieces: Bitfield) -> Peer<cio::test::TCIO> {
        Peer::test(id, 0, 0, 0, pieces)
    }

    pub fn test_from_stats(id: usize, ul: u32, dl: u32) -> Peer<cio::test::TCIO> {
        Peer::test(id, ul, dl, 0, Bitfield::new(4))
    }

    pub fn test_with_tcio(mut cio: cio::test::TCIO) -> Peer<cio::test::TCIO> {
        use control::cio::CIO;

        let conn = PeerConn::test();
        let id = cio.add_peer(conn).unwrap();
        let mut peer = Peer::test(id, 0, 0, 0, Bitfield::new(4));
        peer.cio = cio;
        peer
    }
}

impl<T: cio::CIO> Peer<T> {
    pub fn new(
        mut conn: PeerConn,
        t: &mut Torrent<T>,
        cid: Option<[u8; 20]>,
        rsv: Option<[u8; 8]>,
    ) -> cio::Result<Peer<T>> {
        let addr = conn.sock().addr();
        conn.set_throttle(t.get_throttle(0));
        let id = t.cio.add_peer(conn)?;
        let mut p = Peer {
            id,
            addr,
            remote_status: Status::new(),
            local_status: Status::new(),
            uploaded: 0,
            downloaded: 0,
            uploaded_bytes: 0,
            downloaded_bytes: 0,
            cio: t.cio.new_handle(),
            queued: 0,
            pieces: Bitfield::new(t.info.hashes.len() as u64),
            tid: t.id,
            t_hash: t.info.hash,
            rsv,
            cid,
            last_flush: Utc::now(),
        };
        p.send_message(Message::handshake(&t.info));
        p.send_message(Message::Bitfield(t.pieces.clone()));
        p.send_rpc_info();
        Ok(p)
    }

    /// Returns whether or not the peer has received a handshake
    pub fn ready(&self) -> bool {
        self.cid.is_some()
    }

    pub fn addr(&self) -> SocketAddr {
        self.addr
    }

    pub fn pieces(&self) -> &Bitfield {
        &self.pieces
    }

    #[cfg(test)]
    pub fn pieces_mut(&mut self) -> &mut Bitfield {
        &mut self.pieces
    }

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

    pub fn flush(&mut self) -> (u32, u32) {
        (
            mem::replace(&mut self.uploaded, 0),
            mem::replace(&mut self.downloaded, 0),
        )
    }

    pub fn remote_status(&self) -> &Status {
        &self.remote_status
    }

    pub fn get_tx_rates(&mut self) -> (u64, u64) {
        let dur = Utc::now()
            .signed_duration_since(self.last_flush)
            .num_milliseconds() as u64;
        let ub = mem::replace(&mut self.uploaded_bytes, 0);
        let db = mem::replace(&mut self.downloaded_bytes, 0);
        let ul = (1000 * ub) / dur;
        let dl = (1000 * db) / dur;
        self.last_flush = Utc::now();
        (ul, dl)
    }

    pub fn can_queue_req(&mut self) -> bool {
        !self.remote_status.choked && self.queued < 5
    }

    pub fn handle_msg(&mut self, msg: &mut Message) -> Result<()> {
        match *msg {
            Message::Handshake { rsv, id, .. } => {
                if (rsv[DHT_EXT.0] & DHT_EXT.1) != 0 {
                    self.send_message(Message::Port(CONFIG.dht.port));
                }
                self.rsv = Some(rsv);
                self.cid = Some(id);
                self.send_rpc_info();
            }
            Message::Piece { length, .. } |
            Message::SharedPiece { length, .. } => {
                self.downloaded_bytes += length as u64;
                self.downloaded += 1;
                self.queued -= 1;
            }
            Message::Request { .. } => {
                if self.local_status.choked {
                    return Err(
                        ErrorKind::ProtocolError("Peer requested while choked!").into(),
                    );
                }
            }
            Message::Choke => {
                self.remote_status.choked = true;
            }
            Message::Unchoke => {
                self.remote_status.choked = false;
            }
            Message::Interested => {
                self.remote_status.interested = true;
            }
            Message::Uninterested => {
                self.remote_status.interested = false;
            }
            Message::Have(idx) => {
                if idx >= self.pieces.len() as u32 {
                    return Err(
                        ErrorKind::ProtocolError("Invalid piece provided in HAVE!").into(),
                    );
                }
                self.pieces.set_bit(idx as u64);
            }
            Message::Bitfield(ref mut pieces) => {
                // Set the correct length, then swap the pieces
                pieces.cap(self.pieces.len());
                mem::swap(pieces, &mut self.pieces);
            }
            Message::KeepAlive => {
                self.send_message(Message::KeepAlive);
            }
            Message::Cancel { index, begin, .. } => {
                self.cio.get_peer(self.id, |conn| {
                    conn.writer.write_queue.retain(|m| {
                        if let Message::Piece { index: i, begin: b, .. } = *m {
                            return !(i == index && b == begin);
                        }
                        true
                    });
                });
            }
            Message::Port(p) => {
                let mut s = self.addr();
                s.set_port(p);
                self.cio.msg_trk(tracker::Request::AddNode(s));
            }
        }
        Ok(())
    }

    pub fn request_piece(&mut self, idx: u32, offset: u32, len: u32) {
        let m = Message::request(idx, offset, len);
        self.queued += 1;
        self.send_message(m);
    }

    pub fn choke(&mut self) {
        if !self.local_status.choked {
            self.local_status.choked = true;
            self.send_message(Message::Choke);
        }
    }

    pub fn unchoke(&mut self) {
        if self.local_status.choked {
            self.local_status.choked = false;
            self.send_message(Message::Unchoke);
        }
    }

    pub fn interested(&mut self) {
        if !self.local_status.interested {
            self.local_status.interested = true;
            self.send_message(Message::Interested);
        }
    }

    pub fn uninterested(&mut self) {
        if self.local_status.interested {
            self.local_status.interested = false;
            self.send_message(Message::Uninterested);
        }
    }

    pub fn send_message(&mut self, msg: Message) {
        match msg {
            Message::SharedPiece { length, .. } |
            Message::Piece { length, .. } => {
                self.uploaded += 1;
                self.uploaded_bytes += length as u64;
            }
            _ => {}
        }
        self.cio.msg_peer(self.id, msg);
    }

    fn send_rpc_info(&mut self) {
        if let Some(cid) = self.cid {
            let id = util::peer_rpc_id(&self.t_hash, self.id as u64);
            self.cio.msg_rpc(rpc::CtlMessage::Extant(vec![
                resource::Resource::Peer(resource::Peer {
                    id,
                    torrent_id: util::hash_to_id(&self.t_hash[..]),
                    client_id: util::hash_to_id(&cid[..]),
                    ip: self.addr.to_string(),
                    rate_up: 0,
                    rate_down: 0,
                    availability: 0.,
                }),
            ]));
        }
    }

    pub fn send_rpc_removal(&mut self) {
        if self.ready() {
            self.cio.msg_rpc(rpc::CtlMessage::Removed(
                vec![util::peer_rpc_id(&self.t_hash, self.id as u64)],
            ));
        }
    }
}

impl<T: cio::CIO> Drop for Peer<T> {
    fn drop(&mut self) {
        self.send_rpc_removal();
    }
}

impl<T: cio::CIO> fmt::Debug for Peer<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Peer {{ id: {}, tid: {}, local_status: {:?}, remote_status: {:?} }}",
            self.id,
            self.tid,
            self.local_status,
            self.remote_status
        )
    }
}

#[cfg(test)]
mod tests {
    use super::Peer;
    use control::cio::{CIO, test};
    use torrent::Message;

    #[test]
    fn test_cancel() {
        let mut tcio = test::TCIO::new();
        let mut peer = Peer::test_with_tcio(tcio.new_handle());
        let p1 = Message::Piece {
            index: 0,
            begin: 0,
            data: Box::new([0u8; 16_384]),
            length: 16_384,
        };
        let p2 = Message::Piece {
            index: 1,
            begin: 1,
            data: Box::new([0u8; 16_384]),
            length: 16_384,
        };
        let p3 = Message::Piece {
            index: 2,
            begin: 2,
            data: Box::new([0u8; 16_384]),
            length: 16_384,
        };
        peer.send_message(Message::KeepAlive);
        peer.send_message(p1.clone());
        peer.send_message(p2.clone());
        peer.send_message(p3.clone());

        let mut c = Message::Cancel {
            index: 1,
            begin: 1,
            length: 16_384,
        };
        peer.handle_msg(&mut c).unwrap();
        let wq = tcio.get_peer(peer.id, |p| p.writer.write_queue.clone())
            .unwrap();
        assert_eq!(wq.len(), 2);
        assert_eq!(wq[0], p1);
        assert_eq!(wq[1], p3);
    }
}
<commit_msg>Increase pieces in request queue<commit_after>mod reader;
mod writer;
mod message;

use std::net::SocketAddr;
use std::{io, fmt, mem, time};
use std::net::TcpStream;

use chrono::{DateTime, Utc};

pub use self::message::Message;
use self::reader::Reader;
use self::writer::Writer;
use socket::Socket;
use torrent::{Torrent, Bitfield};
use throttle::Throttle;
use control::cio;
use rpc::{self, resource};
use tracker;
use util;
use {DHT_EXT, CONFIG};

error_chain! {
    errors {
        ProtocolError(r: &'static str) {
            description("Peer did not conform to the bittorrent protocol")
                display("Peer protocol error: {:?}", r)
        }
    }
}

/// Peer connection and associated metadata.
pub struct Peer<T: cio::CIO> {
    id: usize,
    cio: T,
    pieces: Bitfield,
    remote_status: Status,
    local_status: Status,
    queued: u16,
    tid: usize,
    downloaded: u32,
    uploaded: u32,
    downloaded_bytes: u64,
    uploaded_bytes: u64,
    last_flush: DateTime<Utc>,
    addr: SocketAddr,
    t_hash: [u8; 20],
    cid: Option<[u8; 20]>,
    rsv: Option<[u8; 8]>,
}

#[derive(Debug)]
pub struct Status {
    pub choked: bool,
    pub interested: bool,
}

pub struct PeerConn {
    last_action: time::Instant,
    sock: Socket,
    reader: Reader,
    writer: Writer,
}

impl PeerConn {
    pub fn new(sock: Socket) -> PeerConn {
        let writer = Writer::new();
        let reader = Reader::new();
        PeerConn {
            sock,
            writer,
            reader,
            last_action: time::Instant::now(),
        }
    }

    #[cfg(test)]
    pub fn test() -> PeerConn {
        let writer = Writer::new();
        let reader = Reader::new();
        PeerConn {
            last_action: time::Instant::now(),
            sock: Socket::empty(),
            writer,
            reader,
        }
    }

    pub fn sock(&self) -> &Socket {
        &self.sock
    }

    pub fn sock_mut(&mut self) -> &mut Socket {
        &mut self.sock
    }

    pub fn last_action(&self) -> &time::Instant {
        &self.last_action
    }

    /// Creates a new "outgoing" peer, which acts as a client.
    /// Once created, set_torrent should be called.
    pub fn new_outgoing(ip: &SocketAddr) -> io::Result<PeerConn> {
        Ok(PeerConn::new(Socket::new(ip)?))
    }

    /// Creates a peer where we are acting as the server.
    /// Once the handshake is received, set_torrent should be called.
    pub fn new_incoming(sock: TcpStream) -> io::Result<PeerConn> {
        Ok(PeerConn::new(Socket::from_stream(sock)?))
    }

    pub fn writable(&mut self) -> io::Result<()> {
        self.last_action = time::Instant::now();
        self.writer.writable(&mut self.sock)
    }

    pub fn readable(&mut self) -> io::Result<Option<Message>> {
        self.last_action = time::Instant::now();
        self.reader.readable(&mut self.sock)
    }

    pub fn write_message(&mut self, msg: Message) -> io::Result<()> {
        self.writer.write_message(msg, &mut self.sock)
    }

    pub fn set_throttle(&mut self, throt: Throttle) {
        self.sock.throttle = Some(throt);
    }
}

impl Status {
    fn new() -> Status {
        Status {
            choked: true,
            interested: false,
        }
    }
}

#[cfg(test)]
impl Peer<cio::test::TCIO> {
    pub fn test(
        id: usize,
        uploaded: u32,
        downloaded: u32,
        queued: u16,
        pieces: Bitfield,
    ) -> Peer<cio::test::TCIO> {
        Peer {
            id,
            remote_status: Status::new(),
            local_status: Status::new(),
            uploaded,
            downloaded,
            uploaded_bytes: 0,
            downloaded_bytes: 0,
            addr: "127.0.0.1:0".parse().unwrap(),
            cio: cio::test::TCIO::new(),
            queued,
            pieces,
            tid: 0,
            t_hash: [0u8; 20],
            rsv: None,
            cid: None,
            last_flush: Utc::now(),
        }
    }

    pub fn test_from_pieces(id: usize, pieces: Bitfield) -> Peer<cio::test::TCIO> {
        Peer::test(id, 0, 0, 0, pieces)
    }

    pub fn test_from_stats(id: usize, ul: u32, dl: u32) -> Peer<cio::test::TCIO> {
        Peer::test(id, ul, dl, 0, Bitfield::new(4))
    }

    pub fn test_with_tcio(mut cio: cio::test::TCIO) -> Peer<cio::test::TCIO> {
        use control::cio::CIO;

        let conn = PeerConn::test();
        let id = cio.add_peer(conn).unwrap();
        let mut peer = Peer::test(id, 0, 0, 0, Bitfield::new(4));
        peer.cio = cio;
        peer
    }
}

impl<T: cio::CIO> Peer<T> {
    pub fn new(
        mut conn: PeerConn,
        t: &mut Torrent<T>,
        cid: Option<[u8; 20]>,
        rsv: Option<[u8; 8]>,
    ) -> cio::Result<Peer<T>> {
        let addr = conn.sock().addr();
        conn.set_throttle(t.get_throttle(0));
        let id = t.cio.add_peer(conn)?;
        let mut p = Peer {
            id,
            addr,
            remote_status: Status::new(),
            local_status: Status::new(),
            uploaded: 0,
            downloaded: 0,
            uploaded_bytes: 0,
            downloaded_bytes: 0,
            cio: t.cio.new_handle(),
            queued: 0,
            pieces: Bitfield::new(t.info.hashes.len() as u64),
            tid: t.id,
            t_hash: t.info.hash,
            rsv,
            cid,
            last_flush: Utc::now(),
        };
        p.send_message(Message::handshake(&t.info));
        p.send_message(Message::Bitfield(t.pieces.clone()));
        p.send_rpc_info();
        Ok(p)
    }

    /// Returns whether or not the peer has received a handshake
    pub fn ready(&self) -> bool {
        self.cid.is_some()
    }

    pub fn addr(&self) -> SocketAddr {
        self.addr
    }

    pub fn pieces(&self) -> &Bitfield {
        &self.pieces
    }

    #[cfg(test)]
    pub fn pieces_mut(&mut self) -> &mut Bitfield {
        &mut self.pieces
    }

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

    pub fn flush(&mut self) -> (u32, u32) {
        (
            mem::replace(&mut self.uploaded, 0),
            mem::replace(&mut self.downloaded, 0),
        )
    }

    pub fn remote_status(&self) -> &Status {
        &self.remote_status
    }

    pub fn get_tx_rates(&mut self) -> (u64, u64) {
        let dur = Utc::now()
            .signed_duration_since(self.last_flush)
            .num_milliseconds() as u64;
        let ub = mem::replace(&mut self.uploaded_bytes, 0);
        let db = mem::replace(&mut self.downloaded_bytes, 0);
        let ul = (1000 * ub) / dur;
        let dl = (1000 * db) / dur;
        self.last_flush = Utc::now();
        (ul, dl)
    }

    pub fn can_queue_req(&mut self) -> bool {
        !self.remote_status.choked && self.queued < 30
    }

    pub fn handle_msg(&mut self, msg: &mut Message) -> Result<()> {
        match *msg {
            Message::Handshake { rsv, id, .. } => {
                if (rsv[DHT_EXT.0] & DHT_EXT.1) != 0 {
                    self.send_message(Message::Port(CONFIG.dht.port));
                }
                self.rsv = Some(rsv);
                self.cid = Some(id);
                self.send_rpc_info();
            }
            Message::Piece { length, .. } |
            Message::SharedPiece { length, .. } => {
                self.downloaded_bytes += length as u64;
                self.downloaded += 1;
                self.queued -= 1;
            }
            Message::Request { .. } => {
                if self.local_status.choked {
                    return Err(
                        ErrorKind::ProtocolError("Peer requested while choked!").into(),
                    );
                }
            }
            Message::Choke => {
                self.remote_status.choked = true;
            }
            Message::Unchoke => {
                self.remote_status.choked = false;
            }
            Message::Interested => {
                self.remote_status.interested = true;
            }
            Message::Uninterested => {
                self.remote_status.interested = false;
            }
            Message::Have(idx) => {
                if idx >= self.pieces.len() as u32 {
                    return Err(
                        ErrorKind::ProtocolError("Invalid piece provided in HAVE!").into(),
                    );
                }
                self.pieces.set_bit(idx as u64);
            }
            Message::Bitfield(ref mut pieces) => {
                // Set the correct length, then swap the pieces
                pieces.cap(self.pieces.len());
                mem::swap(pieces, &mut self.pieces);
            }
            Message::KeepAlive => {
                self.send_message(Message::KeepAlive);
            }
            Message::Cancel { index, begin, .. } => {
                self.cio.get_peer(self.id, |conn| {
                    conn.writer.write_queue.retain(|m| {
                        if let Message::Piece { index: i, begin: b, .. } = *m {
                            return !(i == index && b == begin);
                        }
                        true
                    });
                });
            }
            Message::Port(p) => {
                let mut s = self.addr();
                s.set_port(p);
                self.cio.msg_trk(tracker::Request::AddNode(s));
            }
        }
        Ok(())
    }

    pub fn request_piece(&mut self, idx: u32, offset: u32, len: u32) {
        let m = Message::request(idx, offset, len);
        self.queued += 1;
        self.send_message(m);
    }

    pub fn choke(&mut self) {
        if !self.local_status.choked {
            self.local_status.choked = true;
            self.send_message(Message::Choke);
        }
    }

    pub fn unchoke(&mut self) {
        if self.local_status.choked {
            self.local_status.choked = false;
            self.send_message(Message::Unchoke);
        }
    }

    pub fn interested(&mut self) {
        if !self.local_status.interested {
            self.local_status.interested = true;
            self.send_message(Message::Interested);
        }
    }

    pub fn uninterested(&mut self) {
        if self.local_status.interested {
            self.local_status.interested = false;
            self.send_message(Message::Uninterested);
        }
    }

    pub fn send_message(&mut self, msg: Message) {
        match msg {
            Message::SharedPiece { length, .. } |
            Message::Piece { length, .. } => {
                self.uploaded += 1;
                self.uploaded_bytes += length as u64;
            }
            _ => {}
        }
        self.cio.msg_peer(self.id, msg);
    }

    fn send_rpc_info(&mut self) {
        if let Some(cid) = self.cid {
            let id = util::peer_rpc_id(&self.t_hash, self.id as u64);
            self.cio.msg_rpc(rpc::CtlMessage::Extant(vec![
                resource::Resource::Peer(resource::Peer {
                    id,
                    torrent_id: util::hash_to_id(&self.t_hash[..]),
                    client_id: util::hash_to_id(&cid[..]),
                    ip: self.addr.to_string(),
                    rate_up: 0,
                    rate_down: 0,
                    availability: 0.,
                }),
            ]));
        }
    }

    pub fn send_rpc_removal(&mut self) {
        if self.ready() {
            self.cio.msg_rpc(rpc::CtlMessage::Removed(
                vec![util::peer_rpc_id(&self.t_hash, self.id as u64)],
            ));
        }
    }
}

impl<T: cio::CIO> Drop for Peer<T> {
    fn drop(&mut self) {
        self.send_rpc_removal();
    }
}

impl<T: cio::CIO> fmt::Debug for Peer<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "Peer {{ id: {}, tid: {}, local_status: {:?}, remote_status: {:?} }}",
            self.id,
            self.tid,
            self.local_status,
            self.remote_status
        )
    }
}

#[cfg(test)]
mod tests {
    use super::Peer;
    use control::cio::{CIO, test};
    use torrent::Message;

    #[test]
    fn test_cancel() {
        let mut tcio = test::TCIO::new();
        let mut peer = Peer::test_with_tcio(tcio.new_handle());
        let p1 = Message::Piece {
            index: 0,
            begin: 0,
            data: Box::new([0u8; 16_384]),
            length: 16_384,
        };
        let p2 = Message::Piece {
            index: 1,
            begin: 1,
            data: Box::new([0u8; 16_384]),
            length: 16_384,
        };
        let p3 = Message::Piece {
            index: 2,
            begin: 2,
            data: Box::new([0u8; 16_384]),
            length: 16_384,
        };
        peer.send_message(Message::KeepAlive);
        peer.send_message(p1.clone());
        peer.send_message(p2.clone());
        peer.send_message(p3.clone());

        let mut c = Message::Cancel {
            index: 1,
            begin: 1,
            length: 16_384,
        };
        peer.handle_msg(&mut c).unwrap();
        let wq = tcio.get_peer(peer.id, |p| p.writer.write_queue.clone())
            .unwrap();
        assert_eq!(wq.len(), 2);
        assert_eq!(wq[0], p1);
        assert_eq!(wq[1], p3);
    }
}
<|endoftext|>


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

#[macro_use]
extern crate galvanic_assert;

use galvanic_assert::matchers::*;

use std::result::Result;

mod assert_panic {
    use super::*;

    #[test]
    fn should_assert_a_panic() {
        assert_that!(panic!("panic"), panics);
    }

    #[test]
    fn should_fail_to_assert_a_panic() {
        let panicked = std::panic::catch_unwind(|| {
            assert_that!(&1+1, panics);
        });
        assert!(panicked.is_err());
    }
}

mod assert_does_not_panic {
    use super::*;

    #[test]
    fn should_assert_that_no_panic_occurred() {
        assert_that!(&1+1, does not panic);
    }

    #[test]
    fn should_fail_to_assert_a_panic() {
        let panicked = std::panic::catch_unwind(|| {
            assert_that!(panic!("panic"), does not panic);
        });
        assert!(panicked.is_err());
    }
}

mod assert_expression {
    use super::*;

    #[test]
    fn should_assert_an_expression_to_be_true() {
        let ok: Result<i32,i32> = Ok(4);
        assert_that!(ok.is_ok());
    }

    #[test]
    fn should_fail_to_assert_an_expression_to_be_true() {
        let err: Result<i32,i32> = Err(4);
        assert_that!(
            assert_that!(err.is_ok()),
            panics
        );
    }

    #[test]
    fn should_assert_an_expression_to_be_true_with_reason() {
        let ok: Result<i32,i32> = Ok(4);
        assert_that!(ok.is_ok(), otherwise "ok is Err");
    }

    #[test]
    fn should_fail_to_assert_an_expression_to_be_true_with_reason() {
        let err: Result<i32,i32> = Err(4);
        assert_that!(
            assert_that!(err.is_ok(), otherwise "err is Ok"),
            panics
        );
    }
}

mod invariants {
    use super::*;

    #[test]
    fn assertion_should_succeed() {
        assert_that!(&1, assertion_always_succeeds());
    }

    #[test]
    fn assertion_should_fail() {
        assert_that!(
            assert_that!(&1, assertion_always_fails()),
            panics
        );
    }
}

mod not {
    use super::*;

    #[test]
    fn should_invert_success() {
        assert_that!(&1, not(assertion_always_fails()));
    }

    #[test]
    fn should_invert_fail() {
        assert_that!(
            assert_that!(&1, not(assertion_always_succeeds())),
            panics
        );
    }
}

mod eq {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&1, eq(1));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&1, eq(2)), panics
        );
    }
}

mod less_than {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&1, less_than(2));
        assert_that!(&1, lt(2));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&1, less_than(1)),
            panics
        );
        assert_that!(
            assert_that!(&1, lt(1)),
            panics
        );
    }
}

mod greater_than {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&1, greater_than(0));
        assert_that!(&1, gt(0));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&1, greater_than(1)),
            panics
        );
        assert_that!(
            assert_that!(&1, gt(1)),
            panics
        );
    }
}

mod less_than_or_equal {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&1, less_than_or_equal(2));
        assert_that!(&1, less_than_or_equal(1));
        assert_that!(&1, leq(2));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&1, less_than_or_equal(0)),
            panics
        );
        assert_that!(
            assert_that!(&1, leq(0)),
            panics
        );
    }
}

mod greater_than_or_equal {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&1, greater_than_or_equal(0));
        assert_that!(&1, greater_than_or_equal(1));
        assert_that!(&1, geq(0));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&1, greater_than_or_equal(2)),
            panics
        );
        assert_that!(
            assert_that!(&1, geq(2)),
            panics
        );
    }
}

mod close_to {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&3.14, close_to(3.14, 0.001));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&2.2, close_to(3.14, 0.001)),
            panics
        );
    }
}

mod same_object {
    use super::*;

    #[derive(Debug)]
    struct Foo;

    #[test]
    fn should_match() {
        let foo = Foo {};
        assert_that!(&foo, same_object(&foo));
    }

    #[test]
    fn should_fail() {
        let foo1 = Foo {};
        let foo2 = Foo {};
        assert_that!(
            assert_that!(&foo1, same_object(&foo2)),
            panics
        );
    }
}

mod has_structure {
    use super::*;

    mod struct_like {
        use super::*;
        struct Foo { x: i32, y: f64 }

        #[test]
        fn should_match() {
            let foo = Foo { x: 12, y: 23.4 };
            assert_that!(&foo, structure!(Foo {
                x: eq(12),
                y: lt(25.0)
            }));
        }

        #[test]#[should_panic]
        fn should_fail() {
            let foo = Foo { x: 12, y: 23.4 };
            assert_that!(&foo, structure!(Foo {
                x: eq(13),
                y: gt(25.0)
            }));
        }
    }

    mod tuple_like {
        use super::*;
        struct Bar(i32, f64);

        #[test]
        fn should_match() {
            let bar = Bar(12, 23.4);
            assert_that!(&bar, structure!(Bar [eq(12), lt(25.0)] ));
        }

        #[test]#[should_panic]
        fn should_fail() {
            let bar = Bar(12, 23.4);
            assert_that!(&bar, structure!(Bar [eq(12), gt(25.0)] ));
        }
    }

    mod enum_like {
        use super::*;

        enum Baz {
            Var1 { x: i32, y: f64 },
            Var2(i32, f64)
        }

        #[test]
        fn should_match() {
            let var1 = Baz::Var1 { x: 12, y: 23.4 };
            assert_that!(&var1, structure!(Baz::Var1 {
                x: eq(12),
                y: lt(25.0)
            }));

            let var2 = Baz::Var2(12, 23.4);
            assert_that!(&var2, structure!(Baz::Var2 [eq(12), lt(25.0)] ));
        }

        #[test]
        fn should_fail() {
            let var1 = Baz::Var1 { x: 12, y: 23.4 };
            assert_that!(
                assert_that!(&var1, structure!(Baz::Var1 {
                    x: eq(13),
                    y: gt(25.0)
                })),
                panics
            );

            assert_that!(
                assert_that!(&var1, structure!(Baz::Var2 [any_value(), any_value()])),
                panics
            );

            let var2 = Baz::Var2(12, 23.4);
            assert_that!(
                assert_that!(&var2, structure!(Baz::Var2 [eq(13), gt(25.0)] )),
                panics
            );
            assert_that!(
                assert_that!(&var2, structure!(Baz::Var1 { x: any_value(), y: any_value() } )),
                panics
            );
        }
    }
}
<commit_msg>add missing test for structure! (incomplete fields)<commit_after>/* Copyright 20&17 Christopher Bacher
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#[macro_use]
extern crate galvanic_assert;

use galvanic_assert::matchers::*;

use std::result::Result;

mod assert_panic {
    use super::*;

    #[test]
    fn should_assert_a_panic() {
        assert_that!(panic!("panic"), panics);
    }

    #[test]
    fn should_fail_to_assert_a_panic() {
        let panicked = std::panic::catch_unwind(|| {
            assert_that!(&1+1, panics);
        });
        assert!(panicked.is_err());
    }
}

mod assert_does_not_panic {
    use super::*;

    #[test]
    fn should_assert_that_no_panic_occurred() {
        assert_that!(&1+1, does not panic);
    }

    #[test]
    fn should_fail_to_assert_a_panic() {
        let panicked = std::panic::catch_unwind(|| {
            assert_that!(panic!("panic"), does not panic);
        });
        assert!(panicked.is_err());
    }
}

mod assert_expression {
    use super::*;

    #[test]
    fn should_assert_an_expression_to_be_true() {
        let ok: Result<i32,i32> = Ok(4);
        assert_that!(ok.is_ok());
    }

    #[test]
    fn should_fail_to_assert_an_expression_to_be_true() {
        let err: Result<i32,i32> = Err(4);
        assert_that!(
            assert_that!(err.is_ok()),
            panics
        );
    }

    #[test]
    fn should_assert_an_expression_to_be_true_with_reason() {
        let ok: Result<i32,i32> = Ok(4);
        assert_that!(ok.is_ok(), otherwise "ok is Err");
    }

    #[test]
    fn should_fail_to_assert_an_expression_to_be_true_with_reason() {
        let err: Result<i32,i32> = Err(4);
        assert_that!(
            assert_that!(err.is_ok(), otherwise "err is Ok"),
            panics
        );
    }
}

mod invariants {
    use super::*;

    #[test]
    fn assertion_should_succeed() {
        assert_that!(&1, assertion_always_succeeds());
    }

    #[test]
    fn assertion_should_fail() {
        assert_that!(
            assert_that!(&1, assertion_always_fails()),
            panics
        );
    }
}

mod not {
    use super::*;

    #[test]
    fn should_invert_success() {
        assert_that!(&1, not(assertion_always_fails()));
    }

    #[test]
    fn should_invert_fail() {
        assert_that!(
            assert_that!(&1, not(assertion_always_succeeds())),
            panics
        );
    }
}

mod eq {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&1, eq(1));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&1, eq(2)), panics
        );
    }
}

mod less_than {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&1, less_than(2));
        assert_that!(&1, lt(2));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&1, less_than(1)),
            panics
        );
        assert_that!(
            assert_that!(&1, lt(1)),
            panics
        );
    }
}

mod greater_than {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&1, greater_than(0));
        assert_that!(&1, gt(0));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&1, greater_than(1)),
            panics
        );
        assert_that!(
            assert_that!(&1, gt(1)),
            panics
        );
    }
}

mod less_than_or_equal {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&1, less_than_or_equal(2));
        assert_that!(&1, less_than_or_equal(1));
        assert_that!(&1, leq(2));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&1, less_than_or_equal(0)),
            panics
        );
        assert_that!(
            assert_that!(&1, leq(0)),
            panics
        );
    }
}

mod greater_than_or_equal {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&1, greater_than_or_equal(0));
        assert_that!(&1, greater_than_or_equal(1));
        assert_that!(&1, geq(0));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&1, greater_than_or_equal(2)),
            panics
        );
        assert_that!(
            assert_that!(&1, geq(2)),
            panics
        );
    }
}

mod close_to {
    use super::*;

    #[test]
    fn should_match() {
        assert_that!(&3.14, close_to(3.14, 0.001));
    }

    #[test]
    fn should_fail() {
        assert_that!(
            assert_that!(&2.2, close_to(3.14, 0.001)),
            panics
        );
    }
}

mod same_object {
    use super::*;

    #[derive(Debug)]
    struct Foo;

    #[test]
    fn should_match() {
        let foo = Foo {};
        assert_that!(&foo, same_object(&foo));
    }

    #[test]
    fn should_fail() {
        let foo1 = Foo {};
        let foo2 = Foo {};
        assert_that!(
            assert_that!(&foo1, same_object(&foo2)),
            panics
        );
    }
}

mod has_structure {
    use super::*;

    mod struct_like {
        use super::*;
        struct Foo { x: i32, y: f64 }

        #[test]
        fn should_match() {
            let foo = Foo { x: 12, y: 23.4 };
            assert_that!(&foo, structure!(Foo {
                x: eq(12),
                y: lt(25.0)
            }));
        }

        #[test]
        fn should_match_incomplete_field_list() {
            let foo = Foo { x: 12, y: 23.4 };
            assert_that!(&foo, structure!(Foo {
                y: lt(25.0)
            }));
        }

        #[test]#[should_panic]
        fn should_fail() {
            let foo = Foo { x: 12, y: 23.4 };
            assert_that!(&foo, structure!(Foo {
                x: eq(13),
                y: gt(25.0)
            }));
        }
    }

    mod tuple_like {
        use super::*;
        struct Bar(i32, f64);

        #[test]
        fn should_match() {
            let bar = Bar(12, 23.4);
            assert_that!(&bar, structure!(Bar [eq(12), lt(25.0)] ));
        }

        #[test]#[should_panic]
        fn should_fail() {
            let bar = Bar(12, 23.4);
            assert_that!(&bar, structure!(Bar [eq(12), gt(25.0)] ));
        }
    }

    mod enum_like {
        use super::*;

        enum Baz {
            Var1 { x: i32, y: f64 },
            Var2(i32, f64)
        }

        #[test]
        fn should_match() {
            let var1 = Baz::Var1 { x: 12, y: 23.4 };
            assert_that!(&var1, structure!(Baz::Var1 {
                x: eq(12),
                y: lt(25.0)
            }));

            let var2 = Baz::Var2(12, 23.4);
            assert_that!(&var2, structure!(Baz::Var2 [eq(12), lt(25.0)] ));
        }

        #[test]
        fn should_fail() {
            let var1 = Baz::Var1 { x: 12, y: 23.4 };
            assert_that!(
                assert_that!(&var1, structure!(Baz::Var1 {
                    x: eq(13),
                    y: gt(25.0)
                })),
                panics
            );

            assert_that!(
                assert_that!(&var1, structure!(Baz::Var2 [any_value(), any_value()])),
                panics
            );

            let var2 = Baz::Var2(12, 23.4);
            assert_that!(
                assert_that!(&var2, structure!(Baz::Var2 [eq(13), gt(25.0)] )),
                panics
            );
            assert_that!(
                assert_that!(&var2, structure!(Baz::Var1 { x: any_value(), y: any_value() } )),
                panics
            );
        }
    }
}
<|endoftext|>