<commit_before>extern crate pinyin;

struct TestCase {
    hans: String,
    args: pinyin::Args,
    result: Vec<Vec<String>>,
    lazy_result: Vec<String>,
}

impl TestCase {
    pub fn new(
        hans: String,
        args: pinyin::Args,
        result: Vec<Vec<String>>,
        lazy_result: Vec<String>,
    ) -> TestCase {
        TestCase {
            hans,
            args,
            result,
            lazy_result,
        }
    }
}

#[test]
fn test_pinyin() {
    let test_data = vec![
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args::new(),
            vec![
                vec!["zhong".to_string()],
                vec!["guo".to_string()],
                vec!["ren".to_string()],
            ],
            vec!["zhong".to_string(), "guo".to_string(), "ren".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Normal,
                heteronym: false,
            },
            vec![
                vec!["zhong".to_string()],
                vec!["guo".to_string()],
                vec!["ren".to_string()],
            ],
            vec!["zhong".to_string(), "guo".to_string(), "ren".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Tone,
                heteronym: false,
            },
            vec![
                vec!["zhōng".to_string()],
                vec!["guó".to_string()],
                vec!["rén".to_string()],
            ],
            vec!["zhōng".to_string(), "guó".to_string(), "rén".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Tone2,
                heteronym: false,
            },
            vec![
                vec!["zho1ng".to_string()],
                vec!["guo2".to_string()],
                vec!["re2n".to_string()],
            ],
            vec!["zho1ng".to_string(), "guo2".to_string(), "re2n".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Initials,
                heteronym: false,
            },
            vec![
                vec!["zh".to_string()],
                vec!["g".to_string()],
                vec!["r".to_string()],
            ],
            vec!["zh".to_string(), "g".to_string(), "r".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::FirstLetter,
                heteronym: false,
            },
            vec![
                vec!["z".to_string()],
                vec!["g".to_string()],
                vec!["r".to_string()],
            ],
            vec!["z".to_string(), "g".to_string(), "r".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Finals,
                heteronym: false,
            },
            vec![
                vec!["ong".to_string()],
                vec!["uo".to_string()],
                vec!["en".to_string()],
            ],
            vec!["ong".to_string(), "uo".to_string(), "en".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::FinalsTone,
                heteronym: false,
            },
            vec![
                vec!["ōng".to_string()],
                vec!["uó".to_string()],
                vec!["én".to_string()],
            ],
            vec!["ōng".to_string(), "uó".to_string(), "én".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::FinalsTone2,
                heteronym: false,
            },
            vec![
                vec!["o1ng".to_string()],
                vec!["uo2".to_string()],
                vec!["e2n".to_string()],
            ],
            vec!["o1ng".to_string(), "uo2".to_string(), "e2n".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Normal,
                heteronym: true,
            },
            vec![
                vec!["zhong".to_string(), "zhong".to_string()],
                vec!["guo".to_string()],
                vec!["ren".to_string()],
            ],
            vec!["zhong".to_string(), "guo".to_string(), "ren".to_string()],
        ),
    ];
    for data in &test_data {
        assert_eq!(data.result, pinyin::pinyin(&data.hans, &data.args));
        assert_eq!(
            data.lazy_result,
            pinyin::lazy_pinyin(&data.hans, &data.args)
        );
    }
}

#[test]
fn test_non_chinese_pinyin() {
    let hans = "中国人abc你好";
    let expect = vec![
        vec!["zhong".to_string()],
        vec!["guo".to_string()],
        vec!["ren".to_string()],
        vec![],
        vec![],
        vec![],
        vec!["ni".to_string()],
        vec!["hao".to_string()],
    ];
    let result = pinyin::pinyin(hans, &pinyin::Args::new());
    assert_eq!(expect, result);
}

#[test]
fn test_non_chinese_lazy_pinyin() {
    let hans = "中国人abc你好";
    let expect = vec![
        "zhong".to_string(),
        "guo".to_string(),
        "ren".to_string(),
        "ni".to_string(),
        "hao".to_string(),
    ];
    let result = pinyin::lazy_pinyin(hans, &pinyin::Args::new());
    assert_eq!(expect, result);
}

#[test]
fn test_new_args() {
    let args = pinyin::Args::new();
    assert_eq!(pinyin::Style::Normal, args.style);
    assert_eq!(false, args.heteronym);

    let expected = pinyin::Args {
        style: pinyin::Style::Normal,
        heteronym: false,
    };
    assert_eq!(expected, args);
}

#[test]
fn test_default_args() {
    let args = pinyin::Args::default();
    assert_eq!(pinyin::Style::Normal, args.style);
    assert_eq!(false, args.heteronym);

    let expected = pinyin::Args {
        style: pinyin::Style::Normal,
        heteronym: false,
    };
    assert_eq!(expected, args);
}

#[test]
fn test_no_initial() {
    let hans = "安";
    let mut expect = vec!["an".to_string()];
    let mut result = pinyin::lazy_pinyin(hans, &pinyin::Args::new());
    assert_eq!(expect, result);

    expect = vec!["an".to_string()];
    result = pinyin::lazy_pinyin(
        hans,
        &pinyin::Args {
            style: pinyin::Style::Finals,
            heteronym: false,
        },
    );
    assert_eq!(expect, result);
}

#[test]
fn test_no_phonetic_symbol() {
    let hans = "啊";
    let mut expect = vec!["a".to_string()];
    let mut result = pinyin::lazy_pinyin(hans, &pinyin::Args::new());
    assert_eq!(expect, result);

    expect = vec!["a".to_string()];
    result = pinyin::lazy_pinyin(
        hans,
        &pinyin::Args {
            style: pinyin::Style::Finals,
            heteronym: false,
        },
    );
    assert_eq!(expect, result);
}
<commit_msg>测试 Default::default()<commit_after>extern crate pinyin;

struct TestCase {
    hans: String,
    args: pinyin::Args,
    result: Vec<Vec<String>>,
    lazy_result: Vec<String>,
}

impl TestCase {
    pub fn new(
        hans: String,
        args: pinyin::Args,
        result: Vec<Vec<String>>,
        lazy_result: Vec<String>,
    ) -> TestCase {
        TestCase {
            hans,
            args,
            result,
            lazy_result,
        }
    }
}

#[test]
fn test_pinyin() {
    let test_data = vec![
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args::new(),
            vec![
                vec!["zhong".to_string()],
                vec!["guo".to_string()],
                vec!["ren".to_string()],
            ],
            vec!["zhong".to_string(), "guo".to_string(), "ren".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Normal,
                heteronym: false,
            },
            vec![
                vec!["zhong".to_string()],
                vec!["guo".to_string()],
                vec!["ren".to_string()],
            ],
            vec!["zhong".to_string(), "guo".to_string(), "ren".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Tone,
                heteronym: false,
            },
            vec![
                vec!["zhōng".to_string()],
                vec!["guó".to_string()],
                vec!["rén".to_string()],
            ],
            vec!["zhōng".to_string(), "guó".to_string(), "rén".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Tone2,
                heteronym: false,
            },
            vec![
                vec!["zho1ng".to_string()],
                vec!["guo2".to_string()],
                vec!["re2n".to_string()],
            ],
            vec!["zho1ng".to_string(), "guo2".to_string(), "re2n".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Initials,
                heteronym: false,
            },
            vec![
                vec!["zh".to_string()],
                vec!["g".to_string()],
                vec!["r".to_string()],
            ],
            vec!["zh".to_string(), "g".to_string(), "r".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::FirstLetter,
                heteronym: false,
            },
            vec![
                vec!["z".to_string()],
                vec!["g".to_string()],
                vec!["r".to_string()],
            ],
            vec!["z".to_string(), "g".to_string(), "r".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Finals,
                heteronym: false,
            },
            vec![
                vec!["ong".to_string()],
                vec!["uo".to_string()],
                vec!["en".to_string()],
            ],
            vec!["ong".to_string(), "uo".to_string(), "en".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::FinalsTone,
                heteronym: false,
            },
            vec![
                vec!["ōng".to_string()],
                vec!["uó".to_string()],
                vec!["én".to_string()],
            ],
            vec!["ōng".to_string(), "uó".to_string(), "én".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::FinalsTone2,
                heteronym: false,
            },
            vec![
                vec!["o1ng".to_string()],
                vec!["uo2".to_string()],
                vec!["e2n".to_string()],
            ],
            vec!["o1ng".to_string(), "uo2".to_string(), "e2n".to_string()],
        ),
        TestCase::new(
            "中国人".to_string(),
            pinyin::Args {
                style: pinyin::Style::Normal,
                heteronym: true,
            },
            vec![
                vec!["zhong".to_string(), "zhong".to_string()],
                vec!["guo".to_string()],
                vec!["ren".to_string()],
            ],
            vec!["zhong".to_string(), "guo".to_string(), "ren".to_string()],
        ),
    ];
    for data in &test_data {
        assert_eq!(data.result, pinyin::pinyin(&data.hans, &data.args));
        assert_eq!(
            data.lazy_result,
            pinyin::lazy_pinyin(&data.hans, &data.args)
        );
    }
}

#[test]
fn test_non_chinese_pinyin() {
    let hans = "中国人abc你好";
    let expect = vec![
        vec!["zhong".to_string()],
        vec!["guo".to_string()],
        vec!["ren".to_string()],
        vec![],
        vec![],
        vec![],
        vec!["ni".to_string()],
        vec!["hao".to_string()],
    ];
    let result = pinyin::pinyin(hans, &pinyin::Args::new());
    assert_eq!(expect, result);
}

#[test]
fn test_non_chinese_lazy_pinyin() {
    let hans = "中国人abc你好";
    let expect = vec![
        "zhong".to_string(),
        "guo".to_string(),
        "ren".to_string(),
        "ni".to_string(),
        "hao".to_string(),
    ];
    let result = pinyin::lazy_pinyin(hans, &pinyin::Args::new());
    assert_eq!(expect, result);
}

#[test]
fn test_new_args() {
    let args = pinyin::Args::new();
    assert_eq!(pinyin::Style::Normal, args.style);
    assert_eq!(false, args.heteronym);

    let expected = pinyin::Args {
        style: pinyin::Style::Normal,
        heteronym: false,
    };
    assert_eq!(expected, args);
}

#[test]
fn test_default_args() {
    let args: pinyin::Args = Default::default();
    assert_eq!(pinyin::Style::Normal, args.style);
    assert_eq!(false, args.heteronym);

    let args = pinyin::Args::default();
    assert_eq!(pinyin::Style::Normal, args.style);
    assert_eq!(false, args.heteronym);

    let expected = pinyin::Args {
        style: pinyin::Style::Normal,
        heteronym: false,
    };
    assert_eq!(expected, args);
}

#[test]
fn test_no_initial() {
    let hans = "安";
    let mut expect = vec!["an".to_string()];
    let mut result = pinyin::lazy_pinyin(hans, &pinyin::Args::new());
    assert_eq!(expect, result);

    expect = vec!["an".to_string()];
    result = pinyin::lazy_pinyin(
        hans,
        &pinyin::Args {
            style: pinyin::Style::Finals,
            heteronym: false,
        },
    );
    assert_eq!(expect, result);
}

#[test]
fn test_no_phonetic_symbol() {
    let hans = "啊";
    let mut expect = vec!["a".to_string()];
    let mut result = pinyin::lazy_pinyin(hans, &pinyin::Args::new());
    assert_eq!(expect, result);

    expect = vec!["a".to_string()];
    result = pinyin::lazy_pinyin(
        hans,
        &pinyin::Args {
            style: pinyin::Style::Finals,
            heteronym: false,
        },
    );
    assert_eq!(expect, result);
}
<|endoftext|>


<commit_before>#![feature(collections, path_ext)]

extern crate backbonzo;
extern crate time;
extern crate tempdir;

use backbonzo::{AesEncrypter, BonzoError};
use std::io::{Read, Write, self};
use std::fs::{File, PathExt, create_dir_all, rename, remove_file, OpenOptions};
use time::{Duration, get_time};
use tempdir::TempDir;
use std::convert::AsRef;
use std::path::{PathBuf, Path};
use std::thread::sleep_ms;

fn open_read_write<P: AsRef<Path>>(path: &P) -> io::Result<File> {
    OpenOptions::new().read(true).write(true).append(false).open(path)
}

#[test]
fn cleanup() {
    let source_temp = TempDir::new("cleanup-source").unwrap();
    let destination_temp = TempDir::new("cleanup-dest").unwrap();
    let source_path = PathBuf::from(source_temp.path());
    let destination_path = PathBuf::from(destination_temp.path());
    let crypto_scheme = AesEncrypter::new("testpassword");
    let deadline = time::now() + Duration::minutes(1);

}

#[test]
fn init() {
    let source_dir = TempDir::new("init").unwrap();
    let backup_dir = TempDir::new("init-backup").unwrap();

    let crypto_scheme = AesEncrypter::new("testpassword");

    let result = backbonzo::init(
        PathBuf::from(source_dir.path()),
        PathBuf::from(backup_dir.path()),
        &crypto_scheme
    );

    assert!(result.is_ok());

    let second_result = backbonzo::init(
        PathBuf::from(source_dir.path()),
        PathBuf::from(backup_dir.path()),
        &crypto_scheme
    );

    let is_expected = match second_result {
        Err(BonzoError::Other(ref str)) => &str[..] == "Database file already exists",
        _                               => false
    };

    assert!(is_expected);
}

#[test]
fn backup_wrong_password() {
    let dir = TempDir::new("wrong-password").unwrap();
    let source_path = PathBuf::from(dir.path());
    let destination_path = source_path.clone();
    let deadline = time::now();

    assert!(
        backbonzo::init(
            source_path.clone(),
            destination_path.clone(),
            &AesEncrypter::new("testpassword")
        ).is_ok()
    );

    let backup_result = backbonzo::backup(
        source_path,
        1000000,
        &AesEncrypter::new("differentpassword"),
        0,
        deadline
    );

    let is_expected = match backup_result {
        Err(BonzoError::Other(ref str)) => &str[..] == "Password is not the same as in database",
        _                               => false
    };

    assert!(is_expected);
}

#[test]
fn backup_no_init() {
    let dir = TempDir::new("no-init").unwrap();
    let source_path = PathBuf::from(dir.path());
    let deadline = time::now();

    let backup_result = backbonzo::backup(
        source_path,
        1000000,
        &AesEncrypter::new("differentpassword"),
        0,
        deadline
    );

    assert_eq!(&format!("{}", backup_result.unwrap_err())[..], "Database error: unable to open database file");
}

#[test]
// tests recursive behaviour, and filters for restore
fn backup_and_restore() {
    let source_temp = TempDir::new("source").unwrap();
    let destination_temp = TempDir::new("destination").unwrap();
    let source_path = PathBuf::from(source_temp.path());
    let destination_path = PathBuf::from(destination_temp.path());
    let crypto_scheme = AesEncrypter::new("testpassword");
    let deadline = time::now() + Duration::minutes(1);

    assert!(create_dir_all(&source_path.join("test")).is_ok());

    let filenames = ["welcome.txt", "welco.yolo", "smth_diffrent.jpg"];
    let bytes = b"71d6e2f35502c03743f676449c503f487de29988";

    for filename in filenames.iter() {
        let file_path = source_path.join(filename);
        let mut file = File::create(&file_path).unwrap();
        assert!(file.write_all(bytes).is_ok());
        assert!(file.sync_all().is_ok());
    }

    {
        let subdir_path = source_path.join("test").join("welcomg!");
        let mut file = File::create(&subdir_path).unwrap();
        assert!(file.write_all(bytes).is_ok());
        assert!(file.sync_all().is_ok());
    }

    assert!(
        backbonzo::init(
            source_path.clone(),
            destination_path.clone(),
            &crypto_scheme
        ).is_ok()
    );

    let backup_result = backbonzo::backup(
        source_path.clone(),
        1000000,
        &crypto_scheme,
        0,
        deadline
    );

    assert!(backup_result.is_ok());

    let timestamp = epoch_milliseconds();
    let restore_temp = TempDir::new("restore").unwrap();
    let restore_path = PathBuf::from(restore_temp.path());

    let restore_result = backbonzo::restore(
        restore_path.clone(),
        destination_path.clone(),
        &crypto_scheme,
        timestamp,
        String::from_str("**/welco*")
    );

    assert!(restore_result.is_ok());

    let restored_file_path = restore_path.join("welco.yolo");

    assert!(restored_file_path.exists());

    let mut restored_file = File::open(&restored_file_path).unwrap();
    let mut buffer = Vec::new();
    restored_file.read_to_end(&mut buffer).unwrap();

    assert_eq!(&bytes[..], &buffer[..]);

    assert!(!restore_path.join("smth_diffrent.jpg").exists());
    assert!(restore_path.join("welcome.txt").exists());
    assert!(restore_path.join("test").join("welcomg!").exists());
}

fn epoch_milliseconds() -> u64 {
    let stamp = get_time();

    stamp.nsec as u64 / 1000 / 1000 + stamp.sec as u64 * 1000
}

#[test]
fn renames() {
    let source_temp = TempDir::new("rename-source").unwrap();
    let destination_temp = TempDir::new("first-destination").unwrap();
    let source_path = PathBuf::from(source_temp.path());
    let destination_path = PathBuf::from(destination_temp.path());
    let crypto_scheme = AesEncrypter::new("helloworld");
    let deadline = time::now() + Duration::minutes(10);
    let max_age_milliseconds = 60 * 60 * 1000;

    assert!(
        backbonzo::init(
            source_path.clone(),
            destination_path.clone(),
            &crypto_scheme
        ).is_ok()
    );

    let first_file_name = "first";
    let first_message   = b"first message. ";

    let second_file_name = "second";
    let second_message   = b"second";

    let mixed_message = b"secondmessage. ";

    // create 1 file in source map
    let first_timestamp = {
        let file_path = source_path.join(first_file_name);
        let mut file = File::create(&file_path).unwrap();
        file.write_all(first_message).unwrap();
        file.sync_all().unwrap();

        let backup_result = backbonzo::backup(
            source_path.clone(),
            1000000,
            &crypto_scheme,
            max_age_milliseconds,
            deadline
        );

        assert!(backup_result.is_ok());

        epoch_milliseconds()
    };

    sleep_ms(100);

    // rename file, update modified date and backup again
    let second_timestamp = {
        let prev_path = source_path.join(first_file_name);
        let file_path = source_path.join(second_file_name);

        rename(&prev_path, &file_path).unwrap();

        let mut file = open_read_write(&file_path).unwrap();
        file.write_all(second_message).unwrap();
        file.sync_all().unwrap();

        let backup_result = backbonzo::backup(
            source_path.clone(),
            1000000,
            &crypto_scheme,
            max_age_milliseconds,
            deadline
        );

        assert!(backup_result.is_ok());

        epoch_milliseconds()
    };

    sleep_ms(100);

    // rename file to first and update timestamp
    let third_timestamp = {
        let first_path = source_path.join(first_file_name);
        let second_path = source_path.join(second_file_name);

        rename(&second_path, &first_path).unwrap();

        let backup_result = backbonzo::backup(
            source_path.clone(),
            1000000,
            &crypto_scheme,
            max_age_milliseconds,
            deadline
        );

        assert!(backup_result.is_ok());

        epoch_milliseconds()
    };

    sleep_ms(100);

    // delete file
    {
        let first_path = source_path.join(first_file_name);

        remove_file(&first_path).unwrap();

        let backup_result = backbonzo::backup(
            source_path.clone(),
            1000000,
            &crypto_scheme,
            max_age_milliseconds,
            deadline
        );

        assert!(backup_result.is_ok());
    }

    // restore to second state
    {
        let restore_temp = TempDir::new("rename-store").unwrap();
        let restore_path = PathBuf::from(restore_temp.path());

        let restore_result = backbonzo::restore(
            restore_path.clone(),
            destination_path.clone(),
            &crypto_scheme,
            second_timestamp + 1,
            String::from_str("**")
        );

        assert!(restore_result.is_ok());

        let first_path = restore_path.join(first_file_name);
        let second_path = restore_path.join(second_file_name);

        assert!(second_path.exists());
        assert!(! first_path.exists());

        let mut file = open_read_write(&second_path).unwrap();
        let mut contents = Vec::new();
        file.read_to_end(&mut contents).unwrap();

        assert_eq!(mixed_message, &contents[..]);
    }

    // restore to third state
    {
        let restore_temp = TempDir::new("rename-store").unwrap();
        let restore_path = PathBuf::from(restore_temp.path());

        let restore_result = backbonzo::restore(
            restore_path.clone(),
            destination_path.clone(),
            &crypto_scheme,
            third_timestamp + 1,
            String::from_str("**")
        );

        assert!(restore_result.is_ok());

        let first_path = restore_path.join(first_file_name);
        let second_path = restore_path.join(second_file_name);

        assert!( ! second_path.exists());
        assert!(first_path.exists());

        let mut file = open_read_write(&first_path).unwrap();
        let mut contents = Vec::new();
        file.read_to_end(&mut contents).unwrap();

        assert_eq!(&mixed_message[..], &contents[..]);
    }

    // restore to last state
    {
        let restore_temp = TempDir::new("rename-store").unwrap();
        let restore_path = PathBuf::from(restore_temp.path());

        let restore_result = backbonzo::restore(
            restore_path.clone(),
            destination_path.clone(),
            &crypto_scheme,
            epoch_milliseconds(),
            String::from_str("**")
        );

        assert!(restore_result.is_ok());

        let first_path = restore_path.join(first_file_name);
        let second_path = restore_path.join(second_file_name);

        assert!(! second_path.exists());
        assert!(! first_path.exists());
    }

    // restore to first state
    {
        let restore_temp = TempDir::new("rename-store").unwrap();
        let restore_path = PathBuf::from(restore_temp.path());

        let restore_result = backbonzo::restore(
            restore_path.clone(),
            destination_path.clone(),
            &crypto_scheme,
            first_timestamp + 1,
            String::from_str("**")
        );

        assert!(restore_result.is_ok());

        let first_path = restore_path.join(first_file_name);
        let second_path = restore_path.join(second_file_name);

        assert!(! second_path.exists());
        assert!(first_path.exists());

        let mut file = open_read_write(&first_path).unwrap();
        let mut contents = Vec::new();
        file.read_to_end(&mut contents).unwrap();

        assert_eq!(&first_message[..], &contents[..]);
    }

    // restore to initial state
    {
        let restore_temp = TempDir::new("rename-store").unwrap();
        let restore_path = PathBuf::from(restore_temp.path());

        let restore_result = backbonzo::restore(
            restore_path.clone(),
            destination_path.clone(),
            &crypto_scheme,
            5000,
            String::from_str("**")
        );

        assert!(restore_result.is_ok());

        let first_path = restore_path.join(first_file_name);
        let second_path = restore_path.join(second_file_name);

        assert!(! second_path.exists());
        assert!(! first_path.exists());
    }
}
<commit_msg>add integration test for cleanup behaviour<commit_after>#![feature(collections, path_ext)]

extern crate backbonzo;
extern crate time;
extern crate tempdir;

use backbonzo::{AesEncrypter, BonzoError};
use std::io::{Read, Write, self};
use std::fs::{File, PathExt, create_dir_all, rename, remove_file, OpenOptions};
use time::{Duration, get_time};
use tempdir::TempDir;
use std::convert::AsRef;
use std::path::{PathBuf, Path};
use std::thread::sleep_ms;

fn open_read_write<P: AsRef<Path>>(path: &P) -> io::Result<File> {
    OpenOptions::new().read(true).write(true).append(false).open(path)
}

#[test]
fn cleanup() {
    let source_temp = TempDir::new("cleanup-source").unwrap();
    let destination_temp = TempDir::new("cleanup-dest").unwrap();
    let source_path = PathBuf::from(source_temp.path());
    let destination_path = PathBuf::from(destination_temp.path());
    let crypto_scheme = AesEncrypter::new("testpassword");
    let deadline = time::now() + Duration::minutes(1);

    let init_result = backbonzo::init(
        PathBuf::from(&source_path),
        PathBuf::from(&destination_path),
        &crypto_scheme
    );

    assert!(init_result.is_ok());

    // write initial file
    let file_path = source_path.join("file1");
    {
        let mut file = File::create(&file_path).unwrap();
        file.write_all(b"first edition!").ok().expect("Failed writing to file.");
        assert!(file.sync_all().is_ok());
    }

    // run backup of file
    backbonzo::backup(
        source_path.clone(),
        1000000,
        &crypto_scheme,
        0,
        deadline
    ).ok().expect("First backup failed");

    // save timestamp
    let timestamp = epoch_milliseconds();
    sleep_ms(100);

    // delete file and re-run backup with forgiving max_age parameter
    remove_file(&file_path).ok().expect("Couldn't remove file");
    assert!(file_path.exists() == false);

    backbonzo::backup(
        source_path.clone(),
        1000000,
        &crypto_scheme,
        60 * 1000,
        deadline
    ).ok().expect("Second backup failed");

    // run restore and check that our file is restored
    backbonzo::restore(
        source_path.clone(),
        destination_path.clone(),
        &crypto_scheme,
        timestamp,
        "**".to_owned()
    ).ok().expect("First restore failed");

    assert!(file_path.exists());

    // delete file again
    remove_file(&file_path).ok().expect("Couldn't remove file");
    assert!(file_path.exists() == false);

    // run backup with very strict max_age parameter
    backbonzo::backup(
        source_path.clone(),
        1000000,
        &crypto_scheme,
        1,
        deadline
    ).ok().expect("Third backup failed");

    // again run restore and make sure that we cleaned up our file
    backbonzo::restore(
        source_path.clone(),
        destination_path.clone(),
        &crypto_scheme,
        timestamp,
        "**".to_owned()
    ).ok().expect("Second restore failed");

    assert!(file_path.exists() == false);
}

#[test]
fn init() {
    let source_dir = TempDir::new("init").unwrap();
    let backup_dir = TempDir::new("init-backup").unwrap();

    let crypto_scheme = AesEncrypter::new("testpassword");

    let result = backbonzo::init(
        PathBuf::from(source_dir.path()),
        PathBuf::from(backup_dir.path()),
        &crypto_scheme
    );

    assert!(result.is_ok());

    let second_result = backbonzo::init(
        PathBuf::from(source_dir.path()),
        PathBuf::from(backup_dir.path()),
        &crypto_scheme
    );

    let is_expected = match second_result {
        Err(BonzoError::Other(ref str)) => &str[..] == "Database file already exists",
        _                               => false
    };

    assert!(is_expected);
}

#[test]
fn backup_wrong_password() {
    let dir = TempDir::new("wrong-password").unwrap();
    let source_path = PathBuf::from(dir.path());
    let destination_path = source_path.clone();
    let deadline = time::now();

    assert!(
        backbonzo::init(
            source_path.clone(),
            destination_path.clone(),
            &AesEncrypter::new("testpassword")
        ).is_ok()
    );

    let backup_result = backbonzo::backup(
        source_path,
        1000000,
        &AesEncrypter::new("differentpassword"),
        0,
        deadline
    );

    let is_expected = match backup_result {
        Err(BonzoError::Other(ref str)) => &str[..] == "Password is not the same as in database",
        _                               => false
    };

    assert!(is_expected);
}

#[test]
fn backup_no_init() {
    let dir = TempDir::new("no-init").unwrap();
    let source_path = PathBuf::from(dir.path());
    let deadline = time::now();

    let backup_result = backbonzo::backup(
        source_path,
        1000000,
        &AesEncrypter::new("differentpassword"),
        0,
        deadline
    );

    assert_eq!(&format!("{}", backup_result.unwrap_err())[..], "Database error: unable to open database file");
}

#[test]
// tests recursive behaviour, and filters for restore
fn backup_and_restore() {
    let source_temp = TempDir::new("source").unwrap();
    let destination_temp = TempDir::new("destination").unwrap();
    let source_path = PathBuf::from(source_temp.path());
    let destination_path = PathBuf::from(destination_temp.path());
    let crypto_scheme = AesEncrypter::new("testpassword");
    let deadline = time::now() + Duration::minutes(1);

    assert!(create_dir_all(&source_path.join("test")).is_ok());

    let filenames = ["welcome.txt", "welco.yolo", "smth_diffrent.jpg"];
    let bytes = b"71d6e2f35502c03743f676449c503f487de29988";

    for filename in filenames.iter() {
        let file_path = source_path.join(filename);
        let mut file = File::create(&file_path).unwrap();
        assert!(file.write_all(bytes).is_ok());
        assert!(file.sync_all().is_ok());
    }

    {
        let subdir_path = source_path.join("test").join("welcomg!");
        let mut file = File::create(&subdir_path).unwrap();
        assert!(file.write_all(bytes).is_ok());
        assert!(file.sync_all().is_ok());
    }

    assert!(
        backbonzo::init(
            source_path.clone(),
            destination_path.clone(),
            &crypto_scheme
        ).is_ok()
    );

    let backup_result = backbonzo::backup(
        source_path.clone(),
        1000000,
        &crypto_scheme,
        0,
        deadline
    );

    assert!(backup_result.is_ok());

    let timestamp = epoch_milliseconds();
    let restore_temp = TempDir::new("restore").unwrap();
    let restore_path = PathBuf::from(restore_temp.path());

    let restore_result = backbonzo::restore(
        restore_path.clone(),
        destination_path.clone(),
        &crypto_scheme,
        timestamp,
        String::from_str("**/welco*")
    );

    assert!(restore_result.is_ok());

    let restored_file_path = restore_path.join("welco.yolo");

    assert!(restored_file_path.exists());

    let mut restored_file = File::open(&restored_file_path).unwrap();
    let mut buffer = Vec::new();
    restored_file.read_to_end(&mut buffer).unwrap();

    assert_eq!(&bytes[..], &buffer[..]);

    assert!(!restore_path.join("smth_diffrent.jpg").exists());
    assert!(restore_path.join("welcome.txt").exists());
    assert!(restore_path.join("test").join("welcomg!").exists());
}

fn epoch_milliseconds() -> u64 {
    let stamp = get_time();

    stamp.nsec as u64 / 1000 / 1000 + stamp.sec as u64 * 1000
}

#[test]
fn renames() {
    let source_temp = TempDir::new("rename-source").unwrap();
    let destination_temp = TempDir::new("first-destination").unwrap();
    let source_path = PathBuf::from(source_temp.path());
    let destination_path = PathBuf::from(destination_temp.path());
    let crypto_scheme = AesEncrypter::new("helloworld");
    let deadline = time::now() + Duration::minutes(10);
    let max_age_milliseconds = 60 * 60 * 1000;

    assert!(
        backbonzo::init(
            source_path.clone(),
            destination_path.clone(),
            &crypto_scheme
        ).is_ok()
    );

    let first_file_name = "first";
    let first_message   = b"first message. ";

    let second_file_name = "second";
    let second_message   = b"second";

    let mixed_message = b"secondmessage. ";

    // create 1 file in source map
    let first_timestamp = {
        let file_path = source_path.join(first_file_name);
        let mut file = File::create(&file_path).unwrap();
        file.write_all(first_message).unwrap();
        file.sync_all().unwrap();

        let backup_result = backbonzo::backup(
            source_path.clone(),
            1000000,
            &crypto_scheme,
            max_age_milliseconds,
            deadline
        );

        assert!(backup_result.is_ok());

        epoch_milliseconds()
    };

    sleep_ms(100);

    // rename file, update modified date and backup again
    let second_timestamp = {
        let prev_path = source_path.join(first_file_name);
        let file_path = source_path.join(second_file_name);

        rename(&prev_path, &file_path).unwrap();

        let mut file = open_read_write(&file_path).unwrap();
        file.write_all(second_message).unwrap();
        file.sync_all().unwrap();

        let backup_result = backbonzo::backup(
            source_path.clone(),
            1000000,
            &crypto_scheme,
            max_age_milliseconds,
            deadline
        );

        assert!(backup_result.is_ok());

        epoch_milliseconds()
    };

    sleep_ms(100);

    // rename file to first and update timestamp
    let third_timestamp = {
        let first_path = source_path.join(first_file_name);
        let second_path = source_path.join(second_file_name);

        rename(&second_path, &first_path).unwrap();

        let backup_result = backbonzo::backup(
            source_path.clone(),
            1000000,
            &crypto_scheme,
            max_age_milliseconds,
            deadline
        );

        assert!(backup_result.is_ok());

        epoch_milliseconds()
    };

    sleep_ms(100);

    // delete file
    {
        let first_path = source_path.join(first_file_name);

        remove_file(&first_path).unwrap();

        let backup_result = backbonzo::backup(
            source_path.clone(),
            1000000,
            &crypto_scheme,
            max_age_milliseconds,
            deadline
        );

        assert!(backup_result.is_ok());
    }

    // restore to second state
    {
        let restore_temp = TempDir::new("rename-store").unwrap();
        let restore_path = PathBuf::from(restore_temp.path());

        let restore_result = backbonzo::restore(
            restore_path.clone(),
            destination_path.clone(),
            &crypto_scheme,
            second_timestamp + 1,
            String::from_str("**")
        );

        assert!(restore_result.is_ok());

        let first_path = restore_path.join(first_file_name);
        let second_path = restore_path.join(second_file_name);

        assert!(second_path.exists());
        assert!(! first_path.exists());

        let mut file = open_read_write(&second_path).unwrap();
        let mut contents = Vec::new();
        file.read_to_end(&mut contents).unwrap();

        assert_eq!(mixed_message, &contents[..]);
    }

    // restore to third state
    {
        let restore_temp = TempDir::new("rename-store").unwrap();
        let restore_path = PathBuf::from(restore_temp.path());

        let restore_result = backbonzo::restore(
            restore_path.clone(),
            destination_path.clone(),
            &crypto_scheme,
            third_timestamp + 1,
            String::from_str("**")
        );

        assert!(restore_result.is_ok());

        let first_path = restore_path.join(first_file_name);
        let second_path = restore_path.join(second_file_name);

        assert!( ! second_path.exists());
        assert!(first_path.exists());

        let mut file = open_read_write(&first_path).unwrap();
        let mut contents = Vec::new();
        file.read_to_end(&mut contents).unwrap();

        assert_eq!(&mixed_message[..], &contents[..]);
    }

    // restore to last state
    {
        let restore_temp = TempDir::new("rename-store").unwrap();
        let restore_path = PathBuf::from(restore_temp.path());

        let restore_result = backbonzo::restore(
            restore_path.clone(),
            destination_path.clone(),
            &crypto_scheme,
            epoch_milliseconds(),
            String::from_str("**")
        );

        assert!(restore_result.is_ok());

        let first_path = restore_path.join(first_file_name);
        let second_path = restore_path.join(second_file_name);

        assert!(! second_path.exists());
        assert!(! first_path.exists());
    }

    // restore to first state
    {
        let restore_temp = TempDir::new("rename-store").unwrap();
        let restore_path = PathBuf::from(restore_temp.path());

        let restore_result = backbonzo::restore(
            restore_path.clone(),
            destination_path.clone(),
            &crypto_scheme,
            first_timestamp + 1,
            String::from_str("**")
        );

        assert!(restore_result.is_ok());

        let first_path = restore_path.join(first_file_name);
        let second_path = restore_path.join(second_file_name);

        assert!(! second_path.exists());
        assert!(first_path.exists());

        let mut file = open_read_write(&first_path).unwrap();
        let mut contents = Vec::new();
        file.read_to_end(&mut contents).unwrap();

        assert_eq!(&first_message[..], &contents[..]);
    }

    // restore to initial state
    {
        let restore_temp = TempDir::new("rename-store").unwrap();
        let restore_path = PathBuf::from(restore_temp.path());

        let restore_result = backbonzo::restore(
            restore_path.clone(),
            destination_path.clone(),
            &crypto_scheme,
            5000,
            String::from_str("**")
        );

        assert!(restore_result.is_ok());

        let first_path = restore_path.join(first_file_name);
        let second_path = restore_path.join(second_file_name);

        assert!(! second_path.exists());
        assert!(! first_path.exists());
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_variables)]

extern crate rebind;
extern crate input;

use rebind::{Action, ButtonTuple, InputTranslator, RebindBuilder, InputRebind, Translated};
use input::Input;
use input::Button::Keyboard;
use input::keyboard::Key;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
enum TestAction {
    Action1, Action2, Action3, Action4, Action5,
    Action6, Action7, Action8, Action9, Action10
}

impl Action for TestAction { }

type TestBuilder = RebindBuilder<TestAction>;
type TestTranslator = InputTranslator<TestAction>;
type TestRebind = InputRebind<TestAction>;

fn create_prepopulated_builder() -> TestBuilder {
    RebindBuilder::default()
        .with_action_mapping(Keyboard(Key::Up),    TestAction::Action1)
        .with_action_mapping(Keyboard(Key::W),     TestAction::Action1)
        .with_action_mapping(Keyboard(Key::Down),  TestAction::Action2)
        .with_action_mapping(Keyboard(Key::S),     TestAction::Action2)
        .with_action_mapping(Keyboard(Key::Left),  TestAction::Action3)
        .with_action_mapping(Keyboard(Key::A),     TestAction::Action3)
        .with_action_mapping(Keyboard(Key::Right), TestAction::Action4)
        .with_action_mapping(Keyboard(Key::D),     TestAction::Action4)
}

#[test]
fn test_translator_get_action_from_buttonpress() {
    let translator = create_prepopulated_builder().build_translator();

    assert_eq!(translator.translate(&Input::Press(Keyboard(Key::Down))).unwrap(),
               Translated::Press(TestAction::Action2));

    assert_eq!(translator.translate(&Input::Press(Keyboard(Key::D))).unwrap(),
               Translated::Press(TestAction::Action4));

    assert_eq!(translator.translate(&Input::Press(Keyboard(Key::Left))).unwrap(),
               Translated::Press(TestAction::Action3));

    assert_eq!(translator.translate(&Input::Press(Keyboard(Key::W))).unwrap(),
               Translated::Press(TestAction::Action1));
}

#[test]
fn test_conversion_from_rebind_to_translator() {
    let translator = create_prepopulated_builder().build_translator();

    let translator_clone = translator.clone();
    let converted_translator = Into::<TestTranslator>::into(
            Into::<TestRebind>::into(translator));

    assert_eq!(translator_clone, converted_translator);
}

#[test]
fn test_add_button_to_translator_using_rebind() {
    use input::Button;
    const Q_KEY: Button = Keyboard(Key::Q);
    const E_KEY: Button = Keyboard(Key::E);

    let translator = create_prepopulated_builder().build_translator();
    let mut rebind = translator.into_rebind();
    rebind.insert_action_with_buttons(TestAction::Action5, ButtonTuple(Some(Q_KEY), Some(E_KEY), None));

    let translator = rebind.into_translator();

    assert_eq!(translator.translate(&Input::Press(Q_KEY)), Some(Translated::Press(TestAction::Action5)));
    assert_eq!(translator.translate(&Input::Press(E_KEY)), Some(Translated::Press(TestAction::Action5)));
}

#[test]
fn test_get_button_len() {
    let bt = ButtonTuple(Some(Keyboard(Key::B)), None, None);
    let mut bti = bt.iter();
    assert_eq!(bti.len(), 3);
    let _ = bti.next();
    assert_eq!(bti.len(), 2);
    let _ = bti.next();
    assert_eq!(bti.len(), 1);
    let _ = bti.next();
    assert_eq!(bti.len(), 0);
    let _ = bti.next();
    assert_eq!(bti.len(), 0);
}<commit_msg>Rename `test_get_button_len` to `test_get_button_iter_len` to better reflect purpose of test<commit_after>#![allow(dead_code, unused_variables)]

extern crate rebind;
extern crate input;

use rebind::{Action, ButtonTuple, InputTranslator, RebindBuilder, InputRebind, Translated};
use input::Input;
use input::Button::Keyboard;
use input::keyboard::Key;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
enum TestAction {
    Action1, Action2, Action3, Action4, Action5,
    Action6, Action7, Action8, Action9, Action10
}

impl Action for TestAction { }

type TestBuilder = RebindBuilder<TestAction>;
type TestTranslator = InputTranslator<TestAction>;
type TestRebind = InputRebind<TestAction>;

fn create_prepopulated_builder() -> TestBuilder {
    RebindBuilder::default()
        .with_action_mapping(Keyboard(Key::Up),    TestAction::Action1)
        .with_action_mapping(Keyboard(Key::W),     TestAction::Action1)
        .with_action_mapping(Keyboard(Key::Down),  TestAction::Action2)
        .with_action_mapping(Keyboard(Key::S),     TestAction::Action2)
        .with_action_mapping(Keyboard(Key::Left),  TestAction::Action3)
        .with_action_mapping(Keyboard(Key::A),     TestAction::Action3)
        .with_action_mapping(Keyboard(Key::Right), TestAction::Action4)
        .with_action_mapping(Keyboard(Key::D),     TestAction::Action4)
}

#[test]
fn test_translator_get_action_from_buttonpress() {
    let translator = create_prepopulated_builder().build_translator();

    assert_eq!(translator.translate(&Input::Press(Keyboard(Key::Down))).unwrap(),
               Translated::Press(TestAction::Action2));

    assert_eq!(translator.translate(&Input::Press(Keyboard(Key::D))).unwrap(),
               Translated::Press(TestAction::Action4));

    assert_eq!(translator.translate(&Input::Press(Keyboard(Key::Left))).unwrap(),
               Translated::Press(TestAction::Action3));

    assert_eq!(translator.translate(&Input::Press(Keyboard(Key::W))).unwrap(),
               Translated::Press(TestAction::Action1));
}

#[test]
fn test_conversion_from_rebind_to_translator() {
    let translator = create_prepopulated_builder().build_translator();

    let translator_clone = translator.clone();
    let converted_translator = Into::<TestTranslator>::into(
            Into::<TestRebind>::into(translator));

    assert_eq!(translator_clone, converted_translator);
}

#[test]
fn test_add_button_to_translator_using_rebind() {
    use input::Button;
    const Q_KEY: Button = Keyboard(Key::Q);
    const E_KEY: Button = Keyboard(Key::E);

    let translator = create_prepopulated_builder().build_translator();
    let mut rebind = translator.into_rebind();
    rebind.insert_action_with_buttons(TestAction::Action5, ButtonTuple(Some(Q_KEY), Some(E_KEY), None));

    let translator = rebind.into_translator();

    assert_eq!(translator.translate(&Input::Press(Q_KEY)), Some(Translated::Press(TestAction::Action5)));
    assert_eq!(translator.translate(&Input::Press(E_KEY)), Some(Translated::Press(TestAction::Action5)));
}

#[test]
fn test_get_button_iter_len() {
    let bt = ButtonTuple(Some(Keyboard(Key::B)), None, None);
    let mut bti = bt.iter();
    assert_eq!(bti.len(), 3);
    let _ = bti.next();
    assert_eq!(bti.len(), 2);
    let _ = bti.next();
    assert_eq!(bti.len(), 1);
    let _ = bti.next();
    assert_eq!(bti.len(), 0);
    let _ = bti.next();
    assert_eq!(bti.len(), 0);
}<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Eugene P. <mahou@shoujo.pw>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

extern crate growable;

use std::mem::size_of;
use growable::*;

/// Some sample trait.
trait Trait {

    fn get(&self) -> u32;
}

/// Some basic trait implementor.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct StandardType(u32);

impl Trait for StandardType {

    fn get(&self) -> u32 {
        self.0
    }
}

/// Zero-sized trait implementor.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct ZST;

impl Trait for ZST {

    fn get(&self) -> u32 {
        42
    }
}

#[test]
fn access() {
    let buffer = Growable::new();
    let v = buffer.assign_as_trait::<_, [u8]>([1, 2, 3, 4, 5, 6]);
    assert_eq!(  v.len(), 6);
    assert_eq!(&*v, &[1, 2, 3, 4, 5, 6]);
    let buffer = v.free();
    let v = buffer.assign_as_trait::<_, [u8]>([1, 2, 3, 4]);
    assert_eq!(  v.len(), 4);
    assert_eq!(&*v, &[1, 2, 3, 4]);
    let buffer = v.free();
    let v = buffer.assign_as_trait::<_, [u8]>([1, 2, 3, 4, 5, 6, 7, 8, 9]);
    assert_eq!(  v.len(), 9);
    assert_eq!(&*v, &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
    let buffer = v.free();
}

#[test]
fn assign_as_trait() {
    let buffer = Growable::new();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    assert_eq!(buffer.ptr_alignment(), None);
    let v = buffer.assign_as_trait::<_, Trait>(StandardType(24));
    assert_eq!(v.get(), 24);
    let buffer = v.free();
    assert!( ! buffer.is_empty());
    assert_eq!(buffer.len(), size_of::<StandardType>());
    assert_eq!(buffer.ptr_alignment(), Some(4));
    let v = buffer.assign_as_trait::<_, Trait>(StandardType(48));
    assert_eq!(v.get(), 48);
}

#[test]
fn access_zst() {
    let buffer = Growable::new();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v = buffer.assign(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v = buffer.assign(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
}

#[test]
fn access_zst_as_trait() {
    let buffer = Growable::new();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v: Reusable<Trait> = buffer.assign(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v: Reusable<Trait> = buffer.assign(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v: Reusable<Trait> = buffer.assign_as_trait(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v: Reusable<Trait> = buffer.assign_as_trait(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
}

#[test]
fn drop() {
    use std::cell::Cell;
    use std::rc::Rc;
    let drop_counter = Rc::new(Cell::new(0));
    trait Droppable {}
    struct Foo(Rc<Cell<usize>>);
    impl Droppable for Foo {};
    impl Drop for Foo {
        fn drop(&mut self) { self.0.set(self.0.get() + 1); }
    }
    {
        let buffer = Growable::new();
        // Dropped by leaving the current scope:
        let _: Reusable<Droppable> = buffer.assign_as_trait(Foo(Rc::clone(&drop_counter)));
        let buffer = Growable::new();
        let v: Reusable<Droppable> = buffer.assign_as_trait(Foo(Rc::clone(&drop_counter)));
        // Dropped manually:
        v.free();
    }
    assert_eq!(drop_counter.get(), 2);
}

#[test]
fn with_capacity() {
    let buffer = Growable::with_capacity(0, 1);
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    assert_eq!(buffer.ptr_alignment(), Some(0));
    let buffer = Growable::with_capacity(1, 2);
    assert!( ! buffer.is_empty());
    assert_eq!(buffer.len(), 1);
    assert_eq!(buffer.ptr_alignment(), Some(1));
}<commit_msg>Remove an unused variable in tests.<commit_after>/*
 * Copyright (c) 2017 Eugene P. <mahou@shoujo.pw>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

extern crate growable;

use std::mem::size_of;
use growable::*;

/// Some sample trait.
trait Trait {

    fn get(&self) -> u32;
}

/// Some basic trait implementor.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct StandardType(u32);

impl Trait for StandardType {

    fn get(&self) -> u32 {
        self.0
    }
}

/// Zero-sized trait implementor.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct ZST;

impl Trait for ZST {

    fn get(&self) -> u32 {
        42
    }
}

#[test]
fn access() {
    let buffer = Growable::new();
    let v = buffer.assign_as_trait::<_, [u8]>([1, 2, 3, 4, 5, 6]);
    assert_eq!(  v.len(), 6);
    assert_eq!(&*v, &[1, 2, 3, 4, 5, 6]);
    let buffer = v.free();
    let v = buffer.assign_as_trait::<_, [u8]>([1, 2, 3, 4]);
    assert_eq!(  v.len(), 4);
    assert_eq!(&*v, &[1, 2, 3, 4]);
    let buffer = v.free();
    let v = buffer.assign_as_trait::<_, [u8]>([1, 2, 3, 4, 5, 6, 7, 8, 9]);
    assert_eq!(  v.len(), 9);
    assert_eq!(&*v, &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
}

#[test]
fn assign_as_trait() {
    let buffer = Growable::new();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    assert_eq!(buffer.ptr_alignment(), None);
    let v = buffer.assign_as_trait::<_, Trait>(StandardType(24));
    assert_eq!(v.get(), 24);
    let buffer = v.free();
    assert!( ! buffer.is_empty());
    assert_eq!(buffer.len(), size_of::<StandardType>());
    assert_eq!(buffer.ptr_alignment(), Some(4));
    let v = buffer.assign_as_trait::<_, Trait>(StandardType(48));
    assert_eq!(v.get(), 48);
}

#[test]
fn access_zst() {
    let buffer = Growable::new();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v = buffer.assign(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v = buffer.assign(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
}

#[test]
fn access_zst_as_trait() {
    let buffer = Growable::new();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v: Reusable<Trait> = buffer.assign(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v: Reusable<Trait> = buffer.assign(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v: Reusable<Trait> = buffer.assign_as_trait(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    let v: Reusable<Trait> = buffer.assign_as_trait(ZST);
    assert_eq!(v.get(), 42);
    let buffer = v.free();
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
}

#[test]
fn drop() {
    use std::cell::Cell;
    use std::rc::Rc;
    let drop_counter = Rc::new(Cell::new(0));
    trait Droppable {}
    struct Foo(Rc<Cell<usize>>);
    impl Droppable for Foo {};
    impl Drop for Foo {
        fn drop(&mut self) { self.0.set(self.0.get() + 1); }
    }
    {
        let buffer = Growable::new();
        // Dropped by leaving the current scope:
        let _: Reusable<Droppable> = buffer.assign_as_trait(Foo(Rc::clone(&drop_counter)));
        let buffer = Growable::new();
        let v: Reusable<Droppable> = buffer.assign_as_trait(Foo(Rc::clone(&drop_counter)));
        // Dropped manually:
        v.free();
    }
    assert_eq!(drop_counter.get(), 2);
}

#[test]
fn with_capacity() {
    let buffer = Growable::with_capacity(0, 1);
    assert!(   buffer.is_empty());
    assert_eq!(buffer.len(), 0);
    assert_eq!(buffer.ptr_alignment(), Some(0));
    let buffer = Growable::with_capacity(1, 2);
    assert!( ! buffer.is_empty());
    assert_eq!(buffer.len(), 1);
    assert_eq!(buffer.ptr_alignment(), Some(1));
}<|endoftext|>


<commit_before>extern crate data_url;
extern crate rustc_test;
extern crate serde_json;

fn run_data_url(input: String, expected_mime: Option<String>, expected_body: Option<Vec<u8>>) {
    let url = data_url::DataUrl::process(&input);
    if let Some(expected_mime) = expected_mime {
        let url = url.unwrap();
        let (body, _) = url.decode_to_vec().unwrap();
        if expected_mime == "" {
            assert_eq!(*url.mime_type(), "text/plain;charset=US-ASCII")
        } else {
            assert_eq!(*url.mime_type(), &*expected_mime)
        }
        if let Some(expected_body) = expected_body {
            assert_eq!(body, expected_body)
        }
    } else if let Ok(url) = url {
        assert!(url.decode_to_vec().is_err(), "{:?}", url.mime_type())
    }
}

fn collect_data_url<F>(add_test: &mut F)
    where F: FnMut(String, bool, rustc_test::TestFn)
{
    let json = include_str!("data-urls.json");
    let v: serde_json::Value = serde_json::from_str(json).unwrap();
    for test in v.as_array().unwrap() {
        let input = test.get(0).unwrap().as_str().unwrap().to_owned();

        let expected_mime = test.get(1).unwrap();
        let expected_mime = if expected_mime.is_null() {
            None
        } else {
            Some(expected_mime.as_str().unwrap().to_owned())
        };

        let expected_body = test.get(2).map(json_byte_array);

        let should_panic = [
            "data://test:test/,X",
            "data:;%62ase64,WA",
            "data:;base 64,WA",
            "data:;base64;,WA",
            "data:;base64;base64,WA",
            "data:;charset =x,X",
            "data:;charset,X",
            "data:;charset=,X",
            "data:text/plain;,X",
            "data:text/plain;a=\",\",X",
            "data:x/x;base64;base64,WA",
            "data:x/x;base64;base64x,WA",
            "data:x/x;base64;charset=x,WA",
            "data:x/x;base64;charset=x;base64,WA",
        ].contains(&&*input);
        add_test(
            format!("data: URL {:?}", input),
            should_panic,
            rustc_test::TestFn::dyn_test_fn(move || {
                run_data_url(input, expected_mime, expected_body)
            })
        );
    }
}

fn run_base64(input: String, expected: Option<Vec<u8>>) {
    let result = data_url::forgiving_base64::decode_to_vec(input.as_bytes());
    match (result, expected) {
        (Ok(bytes), Some(expected)) => assert_eq!(bytes, expected),
        (Ok(bytes), None) => panic!("Expected error, got {:?}", bytes),
        (Err(e), Some(expected)) => panic!("Expected {:?}, got error {:?}", expected, e),
        (Err(_), None) => {}
    }
}

fn collect_base64<F>(add_test: &mut F)
    where F: FnMut(String, bool, rustc_test::TestFn)
{
    let json = include_str!("base64.json");
    let v: serde_json::Value = serde_json::from_str(json).unwrap();
    for test in v.as_array().unwrap() {
        let input = test.get(0).unwrap().as_str().unwrap().to_owned();
        let expected = test.get(1).unwrap();
        let expected = if expected.is_null() {
            None
        } else {
            Some(json_byte_array(expected))
        };

        let known_failures = [];
        let should_panic = known_failures.contains(&&*input);
        add_test(
            format!("base64 {:?}", input),
            should_panic,
            rustc_test::TestFn::dyn_test_fn(move || {
                run_base64(input, expected)
            })
        );
    }
}

fn json_byte_array(j: &serde_json::Value) -> Vec<u8> {
    j.as_array().unwrap().iter().map(|byte| {
        let byte = byte.as_u64().unwrap();
        assert!(byte <= 0xFF);
        byte as u8
    }).collect()
}

fn main() {
    let mut tests = Vec::new();
    {
        let mut add_one = |name: String, should_panic: bool, run: rustc_test::TestFn| {
            let mut desc = rustc_test::TestDesc::new(rustc_test::DynTestName(name));
            if should_panic {
                desc.should_panic = rustc_test::ShouldPanic::Yes
            }
            tests.push(rustc_test::TestDescAndFn { desc, testfn: run })
        };
        collect_data_url(&mut add_one);
        collect_base64(&mut add_one);
    }
    rustc_test::test_main(&std::env::args().collect::<Vec<_>>(), tests)
}
<commit_msg>Run (very few of) the WPT MIME parsing tests<commit_after>extern crate data_url;
extern crate rustc_test;
extern crate serde_json;

fn run_data_url(input: String, expected_mime: Option<String>, expected_body: Option<Vec<u8>>) {
    let url = data_url::DataUrl::process(&input);
    if let Some(expected_mime) = expected_mime {
        let url = url.unwrap();
        let (body, _) = url.decode_to_vec().unwrap();
        if expected_mime == "" {
            assert_eq!(*url.mime_type(), "text/plain;charset=US-ASCII")
        } else {
            assert_eq!(*url.mime_type(), &*expected_mime)
        }
        if let Some(expected_body) = expected_body {
            assert_eq!(body, expected_body)
        }
    } else if let Ok(url) = url {
        assert!(url.decode_to_vec().is_err(), "{:?}", url.mime_type())
    }
}

fn collect_data_url<F>(add_test: &mut F)
    where F: FnMut(String, bool, rustc_test::TestFn)
{
    let known_failures = [
        "data://test:test/,X",
        "data:;%62ase64,WA",
        "data:;base 64,WA",
        "data:;base64;,WA",
        "data:;base64;base64,WA",
        "data:;charset =x,X",
        "data:;charset,X",
        "data:;charset=,X",
        "data:text/plain;,X",
        "data:text/plain;a=\",\",X",
        "data:x/x;base64;base64,WA",
        "data:x/x;base64;base64x,WA",
        "data:x/x;base64;charset=x,WA",
        "data:x/x;base64;charset=x;base64,WA",
    ];

    let json = include_str!("data-urls.json");
    let v: serde_json::Value = serde_json::from_str(json).unwrap();
    for test in v.as_array().unwrap() {
        let input = test.get(0).unwrap().as_str().unwrap().to_owned();

        let expected_mime = test.get(1).unwrap();
        let expected_mime = if expected_mime.is_null() {
            None
        } else {
            Some(expected_mime.as_str().unwrap().to_owned())
        };

        let expected_body = test.get(2).map(json_byte_array);

        let should_panic = known_failures.contains(&&*input);
        add_test(
            format!("data: URL {:?}", input),
            should_panic,
            rustc_test::TestFn::dyn_test_fn(move || {
                run_data_url(input, expected_mime, expected_body)
            })
        );
    }
}

fn run_base64(input: String, expected: Option<Vec<u8>>) {
    let result = data_url::forgiving_base64::decode_to_vec(input.as_bytes());
    match (result, expected) {
        (Ok(bytes), Some(expected)) => assert_eq!(bytes, expected),
        (Ok(bytes), None) => panic!("Expected error, got {:?}", bytes),
        (Err(e), Some(expected)) => panic!("Expected {:?}, got error {:?}", expected, e),
        (Err(_), None) => {}
    }
}

fn collect_base64<F>(add_test: &mut F)
    where F: FnMut(String, bool, rustc_test::TestFn)
{
    let known_failures = [];

    let json = include_str!("base64.json");
    let v: serde_json::Value = serde_json::from_str(json).unwrap();
    for test in v.as_array().unwrap() {
        let input = test.get(0).unwrap().as_str().unwrap().to_owned();
        let expected = test.get(1).unwrap();
        let expected = if expected.is_null() {
            None
        } else {
            Some(json_byte_array(expected))
        };

        let should_panic = known_failures.contains(&&*input);
        add_test(
            format!("base64 {:?}", input),
            should_panic,
            rustc_test::TestFn::dyn_test_fn(move || {
                run_base64(input, expected)
            })
        );
    }
}

fn run_mime(input: String, expected: Option<String>) {
    let result = input.parse::<data_url::mime::Mime>();
    match (result, expected) {
        (Ok(bytes), Some(expected)) => assert_eq!(bytes, &*expected),
        (Ok(bytes), None) => panic!("Expected error, got {:?}", bytes),
        (Err(e), Some(expected)) => panic!("Expected {:?}, got error {:?}", expected, e),
        (Err(_), None) => {}
    }
}

fn collect_mime<F>(add_test: &mut F)
    where F: FnMut(String, bool, rustc_test::TestFn)
{
    // Many WPT tests fail with the mime crate’s parser,
    // since that parser is not written for the same spec.
    // Only run a few of them for now, since listing all the failures individually is not useful.
    let only_run_first_n_tests = 5;
    let known_failures = [
        "text/html;charset=gbk(",
    ];

    let json = include_str!("mime-types.json");
    let json2 = include_str!("generated-mime-types.json");
    let v: serde_json::Value = serde_json::from_str(json).unwrap();
    let v2: serde_json::Value = serde_json::from_str(json2).unwrap();
    let tests = v.as_array().unwrap().iter().chain(v2.as_array().unwrap());

    let mut last_comment = None;
    for test in tests.take(only_run_first_n_tests) {
        if let Some(s) = test.as_str() {
            last_comment = Some(s);
            continue
        }
        let input = test.get("input").unwrap().as_str().unwrap().to_owned();
        let expected = test.get("output").unwrap();
        let expected = if expected.is_null() {
            None
        } else {
            Some(expected.as_str().unwrap().to_owned())
        };

        let should_panic = known_failures.contains(&&*input);
        add_test(
            if let Some(s) = last_comment {
                format!("MIME type {:?} {:?}", s, input)
            } else {
                format!("MIME type {:?}", input)
            },
            should_panic,
            rustc_test::TestFn::dyn_test_fn(move || {
                run_mime(input, expected)
            })
        );
    }
}

fn json_byte_array(j: &serde_json::Value) -> Vec<u8> {
    j.as_array().unwrap().iter().map(|byte| {
        let byte = byte.as_u64().unwrap();
        assert!(byte <= 0xFF);
        byte as u8
    }).collect()
}

fn main() {
    let mut tests = Vec::new();
    {
        let mut add_one = |name: String, should_panic: bool, run: rustc_test::TestFn| {
            let mut desc = rustc_test::TestDesc::new(rustc_test::DynTestName(name));
            if should_panic {
                desc.should_panic = rustc_test::ShouldPanic::Yes
            }
            tests.push(rustc_test::TestDescAndFn { desc, testfn: run })
        };
        collect_data_url(&mut add_one);
        collect_base64(&mut add_one);
        collect_mime(&mut add_one);
    }
    rustc_test::test_main(&std::env::args().collect::<Vec<_>>(), tests)
}
<|endoftext|>


<commit_before>use common::{R};
use lapack::{lapack_int, alloc_doubles, alloc_ints};

use std::vec;
use std::vec::raw;
use std::cast;
use std::ptr;
use std::libc::{c_double, c_ulong, c_int, c_uint, c_void, malloc, calloc, realloc, free};

/// Sparse matrix type, with compressed sparse row storage, 3-array variation (CSR3).
/// Values must be pushed into the matrix in increasing order of their (row, column)
/// pairs, with the row being most significant, and with each row being represented by
/// at least one pushed value (which may be 0).
pub struct SparseMatrix {
  values: ~[R],
  value_cols: ~[lapack_int],
  row_begins: ~[lapack_int],
  matrix_type: MatrixType,
}

pub enum MatrixType {
  Symmetric,             // symmetric with values in upper triangle
  StructurallySymmetric, // structurally symmetric, m_{i,j} present iff m_{j,i} present.
  General,
}

impl SparseMatrix {

  pub fn new_with_capacities(values_capacity: uint, rows_capacity: uint, mtype: MatrixType) -> SparseMatrix {
    SparseMatrix {
      values: vec::with_capacity(values_capacity),
      value_cols: vec::with_capacity(values_capacity),
      row_begins: vec::with_capacity(rows_capacity+1),
      matrix_type: mtype
    }
  }

  #[inline]
  pub fn push(&mut self, r: uint, c: uint, val: R) {
    match r {
      last_row if last_row == self.row_begins.len()-1 => {
        if c <= self.value_cols[self.value_cols.len()-1] as uint {
          fail!("Column numbers must be pushed in strictly increasing order within sparse matrix rows.")
        }
      }
      new_row if new_row == self.row_begins.len() => {
        self.row_begins.push(self.values.len() as lapack_int);
      }
      _ => fail!("Push to sparse matrix must be to last existing row or next non-existing row")
    }
    self.values.push(val);
    self.value_cols.push(c as lapack_int);
  }

  pub fn num_rows(&self) -> uint {
    self.row_begins.len()
  }

  pub fn num_values(&self) -> uint {
    self.values.len()
  }

  pub fn matrix_type(&self) -> MatrixType { self.matrix_type }

  pub fn get(&self, r: uint, c: uint) -> R {
    let next_row_begin = if r == self.row_begins.len()-1 { self.values.len() } else { self.row_begins[r+1] as uint };
    for i in range(self.row_begins[r] as uint, next_row_begin) {
      match (c as lapack_int).cmp(&self.value_cols[i]) {
        Less =>  { return 0 as R; }
        Equal => { return self.values[i]; }
        Greater => {} // keep looking
      }
    }
    0 as R
  }

  pub fn debug_print(&self) {
    for r in range(0, self.row_begins.len()) {
      let next_row_begin = if r == self.row_begins.len()-1 { self.values.len() } else { self.row_begins[r+1] as uint};
      for i in range(self.row_begins[r] as uint, next_row_begin) {
        let c = self.value_cols[i];
        println!("{}\t{}\t{:.10f}", r+1, c+1, self.values[i]);
      }
    }
  }

  /// Returns the 3-array variant (a, ia, ja) of the Compressed Sparse Row format as pointers to the values array a,
  /// the row beginning indexes ia into the values array, and the corresponding column numbers ja of the values.
  /// The row_begins vector must have a capacity of at least one greater than its length, otherwise an error
  /// is generated. This allows an extra "cap" entry to be written past the proper row beginning index values
  /// as required by lapack, in the reserved capacity part of the row_begins buffer.
  pub unsafe fn csr3_ptrs(&self) -> (*R, *lapack_int, *lapack_int) {
    if self.row_begins.capacity() <= self.row_begins.len() {
      fail!("Need one capacity element beyond the length of the row_begins vector for conversion to raw pointers.");
    }
    else {
      // Cap the row_begins buffer with the number of values as trailing "ghost" row start index.
      let row_begins_ptr = raw::to_mut_ptr(cast::transmute_mut(self).row_begins);
      *ptr::mut_offset(row_begins_ptr, self.row_begins.len() as int) = self.values.len() as lapack_int;

      (raw::to_ptr(self.values),
       raw::to_ptr(self.row_begins),
       raw::to_ptr(self.value_cols))
    }
  }

}

<commit_msg>Use cvec storage with 64 byte alignment in place of rust vectors.<commit_after>use common::{R};
use lapack;
use lapack::lapack_int;

use extra::c_vec::CVec;
use std::cast::transmute;
use std::ptr;
use std::libc::{c_ulong};

/// Sparse matrix type, with compressed sparse row storage, 3-array variation (CSR3).
/// Values must be pushed into the matrix in increasing order of their (row, column)
/// pairs, with the row being most significant, and with each row being represented by
/// at least one pushed value (which may be 0).
pub struct SparseMatrix {

  priv values: CVec<R>,
  priv value_cols: CVec<lapack_int>,
  priv row_first_value_ixs: CVec<lapack_int>,

  priv num_values: uint,
  priv num_rows: uint,

  priv matrix_type: MatrixType,
}

pub enum MatrixType {
  Symmetric,             // symmetric with values in upper triangle
  StructurallySymmetric, // structurally symmetric, m_{i,j} present iff m_{j,i} present.
  General,
}

impl SparseMatrix {

  pub fn new_with_capacities(values_capacity: uint, rows_capacity: uint, mtype: MatrixType) -> SparseMatrix {
    let (values, value_cols, row_first_value_ixs) = unsafe {
      (CVec::new(lapack::alloc_doubles(values_capacity as c_ulong), values_capacity),
       CVec::new(lapack::alloc_ints(values_capacity as c_ulong), values_capacity),
       CVec::new(lapack::alloc_ints((rows_capacity+1u) as c_ulong), rows_capacity)) // alloc extra element for cap value
    };
    SparseMatrix {
      values: values,
      value_cols: value_cols,
      row_first_value_ixs: row_first_value_ixs,
      num_values: 0u,
      num_rows: 0u,
      matrix_type: mtype
    }
  }

  #[inline]
  pub fn push(&mut self, r: uint, c: uint, val: R) {
    match r {
      // If continuing on the same row, the column number should be greater than the last.
      last_row if last_row == self.num_rows-1 => {
        if c <= *self.value_cols.get(self.num_values-1) as uint {
          fail!("Columns must be added in strictly increasing order within sparse matrix rows.")
        }
      }
      // Else the new row must be the next row sequentially. Add the initial value index for the row.
      new_row if new_row == self.num_rows => {
        *self.row_first_value_ixs.get_mut(new_row) = self.num_values as lapack_int;
        self.num_rows += 1;
      }
      _ => fail!("Push to sparse matrix must be to last existing row or next non-existing row")
    }

    // Add the value and its column index.
    *self.values.get_mut(self.num_values) = val;
    *self.value_cols.get_mut(self.num_values) = c as lapack_int;
    self.num_values += 1;
  }

  pub fn num_rows(&self) -> uint {
    self.num_rows
  }

  pub fn num_values(&self) -> uint {
    self.num_values
  }

  pub fn matrix_type(&self) -> MatrixType { self.matrix_type }

  pub fn get(&self, r: uint, c: uint) -> R {
    if r >= self.num_rows { fail!("Row index out of range.") }
    let first_val_ix = *self.row_first_value_ixs.get(r) as uint;
    let next_row_begin = if r == self.num_rows-1 { self.num_values } else { *self.row_first_value_ixs.get(r+1) as uint };
    for i in range(first_val_ix, next_row_begin) {
      match (c as lapack_int).cmp(self.value_cols.get(i)) {
        Less =>  { return 0 as R; }
        Equal => { return *self.values.get(i); }
        Greater => {} // keep looking
      }
    }
    0 as R
  }

  pub fn debug_print(&self) {
    unsafe {
      for r in range(0, self.num_rows) {
        let first_val_ix = *self.row_first_value_ixs.get(r) as uint;
        let next_row_begin = if r == self.num_rows-1 { self.num_values } else { *self.row_first_value_ixs.get(r+1) as uint };
        for i in range(first_val_ix, next_row_begin) {
          let c = *self.value_cols.get(i);
          println!("{}\t{}\t{:.10f}", r+1, c+1, *self.values.get(i));
        }
      }
    }
  }

  /// Returns the 3-array variant (a, ia, ja) of the Compressed Sparse Row format as pointers to the values array a,
  /// the row beginning indexes ia into the values array, and the corresponding column numbers ja of the values.
  /// The row_first_value_ixs vector must have a capacity of at least one greater than its length, otherwise an error
  /// is generated. This allows an extra "cap" entry to be written past the proper row beginning index values
  /// as required by lapack, in the reserved capacity part of the row_first_value_ixs buffer.
  pub unsafe fn csr3_ptrs(&self) -> (*R, *lapack_int, *lapack_int) {
    // Cap the row_first_value_ixs buffer with the number of values as required by some solvers (other solvers unaffected).
    // Extra storage for this item was allocated and is gauranteed to still be unused because it was not made available
    // through the bounds-checked cvec accessors used elsewhere in this implementation.
    *ptr::mut_offset(transmute(self.row_first_value_ixs.get(0)), self.num_rows as int) = self.num_values as lapack_int;

    (transmute(self.values.get(0)),
     transmute(self.row_first_value_ixs.get(0)),
     transmute(self.value_cols.get(0)))
  }

}

#[unsafe_destructor]
impl Drop for SparseMatrix {
  #[inline(never)]
  fn drop(&mut self) {
    unsafe {
      lapack::free_doubles(transmute(self.values.get(0)));
      lapack::free_ints(transmute(self.row_first_value_ixs.get(0)));
      lapack::free_ints(transmute(self.value_cols.get(0)));
    }
  }
}

<|endoftext|>


<commit_before>//! Draw the view.

use cgmath;
use gl;
use time;
use yaglw;

use view;
use view::camera::{set_camera};
use view::light::{set_sun, set_ambient_light};

fn set_eye_position(shader: &mut yaglw::shader::Shader, camera: &view::camera::T) {
  unsafe {
    let uniform = shader.get_uniform_location("eye_position");
    let ptr = &camera.position as *const _ as *const _;
    gl::Uniform3fv(uniform, 1, ptr);
  }
}

fn set_clip(shader: &mut yaglw::shader::Shader, near: f32, far: f32) {
  unsafe {
    let uniform = shader.get_uniform_location("near_clip");
    gl::Uniform1f(uniform, near);
    let uniform = shader.get_uniform_location("far_clip");
    gl::Uniform1f(uniform, far);
  }
}

fn draw_backdrop(
  rndr: &mut view::T,
) {
  rndr.shaders.sky.shader.use_shader(&mut rndr.gl);

  unsafe {
    gl::BindVertexArray(rndr.empty_gl_array.gl_id);
  }

  set_sun(&mut rndr.shaders.sky.shader, &mut rndr.gl, &rndr.sun);
  set_eye_position(&mut rndr.shaders.sky.shader, &rndr.camera);

  unsafe {
    let time_ms_uniform = rndr.shaders.sky.shader.get_uniform_location("time_ms");
    gl::Uniform1f(time_ms_uniform, (time::precise_time_ns() / 1_000_000) as f32);

    let projection_uniform = rndr.shaders.sky.shader.get_uniform_location("projection_matrix");
    let projection_matrix = rndr.camera.projection_matrix();
    let ptr = &projection_matrix as *const _ as *const _;
    gl::UniformMatrix4fv(projection_uniform, 1, 0, ptr);

    let window_size_uniform = rndr.shaders.sky.shader.get_uniform_location("window_size");
    let window_size = cgmath::Vector2::new(rndr.window_size.x as f32, rndr.window_size.y as f32);
    let ptr = &window_size as *const _ as *const _;
    gl::Uniform2fv(window_size_uniform, 1, ptr);

    gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);

    gl::Clear(gl::DEPTH_BUFFER_BIT);
  }
}

fn draw_grass_billboards(
  rndr: &mut view::T,
) {
  rndr.shaders.grass_billboard.shader.use_shader(&mut rndr.gl);
  unsafe {
    let time_ms_uniform = rndr.shaders.grass_billboard.shader.get_uniform_location("time_ms");
    gl::Uniform1f(time_ms_uniform, (time::precise_time_ns() / 1_000_000) as f32);
  }
  set_ambient_light(&mut rndr.shaders.grass_billboard.shader, &mut rndr.gl, &rndr.sun);
  set_camera(&mut rndr.shaders.grass_billboard.shader, &mut rndr.gl, &rndr.camera);
  set_clip(&mut rndr.shaders.grass_billboard.shader, rndr.near_clip, rndr.far_clip);
  set_eye_position(&mut rndr.shaders.grass_billboard.shader, &rndr.camera);
  set_sun(&mut rndr.shaders.grass_billboard.shader, &mut rndr.gl, &rndr.sun);
  let alpha_threshold_uniform =
    rndr.shaders.grass_billboard.shader.get_uniform_location("alpha_threshold");
  unsafe {
    gl::Disable(gl::CULL_FACE);
    gl::Uniform1f(alpha_threshold_uniform, 0.5);
    gl::ActiveTexture(rndr.misc_texture_unit.gl_id());
    gl::BindTexture(gl::TEXTURE_2D, rndr.grass_texture.handle.gl_id);
  }
  rndr.grass_buffers.draw(&mut rndr.gl);
}

#[allow(missing_docs)]
pub fn render(
  rndr: &mut view::T,
) {
  rndr.gl.clear_buffer();

  draw_backdrop(rndr);

  unsafe {
    gl::Enable(gl::CULL_FACE);
  }

  // draw the world
  rndr.shaders.terrain_shader.shader.use_shader(&mut rndr.gl);
  set_ambient_light(&mut rndr.shaders.terrain_shader.shader, &mut rndr.gl, &rndr.sun);
  set_camera(&mut rndr.shaders.terrain_shader.shader, &mut rndr.gl, &rndr.camera);
  set_clip(&mut rndr.shaders.grass_billboard.shader, rndr.near_clip, rndr.far_clip);
  set_eye_position(&mut rndr.shaders.terrain_shader.shader, &rndr.camera);
  set_sun(&mut rndr.shaders.terrain_shader.shader, &mut rndr.gl, &rndr.sun);
  rndr.terrain_buffers.draw(&mut rndr.gl);

  rndr.shaders.mob_shader.shader.use_shader(&mut rndr.gl);
  set_camera(&mut rndr.shaders.mob_shader.shader, &mut rndr.gl, &rndr.camera);
  rndr.mob_buffers.draw(&mut rndr.gl);
  rndr.player_buffers.draw(&mut rndr.gl);

  draw_grass_billboards(rndr);

  if rndr.show_hud {
    rndr.shaders.hud_color_shader.shader.use_shader(&mut rndr.gl);
    rndr.hud_triangles.bind(&mut rndr.gl);
    rndr.hud_triangles.draw(&mut rndr.gl);
  }
}
<commit_msg>bugfixes<commit_after>//! Draw the view.

use cgmath;
use gl;
use time;
use yaglw;

use view;
use view::camera::{set_camera};
use view::light::{set_sun, set_ambient_light};

fn set_eye_position(shader: &mut yaglw::shader::Shader, camera: &view::camera::T) {
  unsafe {
    let uniform = shader.get_uniform_location("eye_position");
    let ptr = &camera.position as *const _ as *const _;
    gl::Uniform3fv(uniform, 1, ptr);
  }
}

fn set_clip(shader: &mut yaglw::shader::Shader, near: f32, far: f32) {
  unsafe {
    let uniform = shader.get_uniform_location("near_clip");
    gl::Uniform1f(uniform, near);
    let uniform = shader.get_uniform_location("far_clip");
    gl::Uniform1f(uniform, far);
  }
}

fn draw_backdrop(
  rndr: &mut view::T,
) {
  rndr.shaders.sky.shader.use_shader(&mut rndr.gl);

  unsafe {
    gl::BindVertexArray(rndr.empty_gl_array.gl_id);
  }

  set_sun(&mut rndr.shaders.sky.shader, &mut rndr.gl, &rndr.sun);
  set_eye_position(&mut rndr.shaders.sky.shader, &rndr.camera);

  unsafe {
    let time_ms_uniform = rndr.shaders.sky.shader.get_uniform_location("time_ms");
    gl::Uniform1f(time_ms_uniform, (time::precise_time_ns() / 1_000_000) as f32);

    let projection_uniform = rndr.shaders.sky.shader.get_uniform_location("projection_matrix");
    let projection_matrix = rndr.camera.projection_matrix();
    let ptr = &projection_matrix as *const _ as *const _;
    gl::UniformMatrix4fv(projection_uniform, 1, 0, ptr);

    let window_size_uniform = rndr.shaders.sky.shader.get_uniform_location("window_size");
    let window_size = cgmath::Vector2::new(rndr.window_size.x as f32, rndr.window_size.y as f32);
    let ptr = &window_size as *const _ as *const _;
    gl::Uniform2fv(window_size_uniform, 1, ptr);

    gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);

    gl::Clear(gl::DEPTH_BUFFER_BIT);
  }
}

fn draw_grass_billboards(
  rndr: &mut view::T,
) {
  rndr.shaders.grass_billboard.shader.use_shader(&mut rndr.gl);
  unsafe {
    let time_ms_uniform = rndr.shaders.grass_billboard.shader.get_uniform_location("time_ms");
    gl::Uniform1f(time_ms_uniform, (time::precise_time_ns() / 1_000_000) as f32);
  }
  set_ambient_light(&mut rndr.shaders.grass_billboard.shader, &mut rndr.gl, &rndr.sun);
  set_camera(&mut rndr.shaders.grass_billboard.shader, &mut rndr.gl, &rndr.camera);
  set_clip(&mut rndr.shaders.grass_billboard.shader, rndr.near_clip, rndr.far_clip);
  set_eye_position(&mut rndr.shaders.grass_billboard.shader, &rndr.camera);
  set_sun(&mut rndr.shaders.grass_billboard.shader, &mut rndr.gl, &rndr.sun);
  let alpha_threshold_uniform =
    rndr.shaders.grass_billboard.shader.get_uniform_location("alpha_threshold");
  unsafe {
    gl::Disable(gl::CULL_FACE);
    gl::Uniform1f(alpha_threshold_uniform, 0.5);
    gl::ActiveTexture(rndr.misc_texture_unit.gl_id());
    gl::BindTexture(gl::TEXTURE_2D, rndr.grass_texture.handle.gl_id);
  }
  rndr.grass_buffers.draw(&mut rndr.gl);
}

#[allow(missing_docs)]
pub fn render(
  rndr: &mut view::T,
) {
  rndr.gl.clear_buffer();

  draw_backdrop(rndr);

  unsafe {
    gl::Enable(gl::CULL_FACE);
  }

  // draw the world
  rndr.shaders.terrain_shader.shader.use_shader(&mut rndr.gl);
  set_ambient_light(&mut rndr.shaders.terrain_shader.shader, &mut rndr.gl, &rndr.sun);
  set_camera(&mut rndr.shaders.terrain_shader.shader, &mut rndr.gl, &rndr.camera);
  set_clip(&mut rndr.shaders.terrain_shader.shader, rndr.near_clip, rndr.far_clip);
  set_eye_position(&mut rndr.shaders.terrain_shader.shader, &rndr.camera);
  set_sun(&mut rndr.shaders.terrain_shader.shader, &mut rndr.gl, &rndr.sun);
  rndr.terrain_buffers.draw(&mut rndr.gl);

  rndr.shaders.mob_shader.shader.use_shader(&mut rndr.gl);
  set_camera(&mut rndr.shaders.mob_shader.shader, &mut rndr.gl, &rndr.camera);
  set_clip(&mut rndr.shaders.mob_shader.shader, rndr.near_clip, rndr.far_clip);
  rndr.mob_buffers.draw(&mut rndr.gl);
  rndr.player_buffers.draw(&mut rndr.gl);

  draw_grass_billboards(rndr);

  if rndr.show_hud {
    rndr.shaders.hud_color_shader.shader.use_shader(&mut rndr.gl);
    rndr.hud_triangles.bind(&mut rndr.gl);
    rndr.hud_triangles.draw(&mut rndr.gl);
  }
}
<|endoftext|>