use assert_cmd::Command;
use md5_rs::Context;
use scopeguard::defer;
use std::ffi::OsString;
use std::fs::File;
use std::fs::{copy, create_dir, create_dir_all, metadata, read_dir, remove_dir_all, remove_file};
use std::io::{ErrorKind, Read};
const CARGO_BIN_NAME: &str = "onetime-cli";
const FILES_DIR: &str = "./tests/files";
const FILES_ORIG_DIR: &str = "./tests/files_original";
fn copy_files(input_dir: &str, dest_dir: &str) -> std::io::Result<()> {
fn traverse_dir(dir: &str, dest_dir: &OsString) -> std::io::Result<()> {
for entry in read_dir(dir)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
let path_str = path.to_str().unwrap();
let new_dest_dir = {
let dir_name = path.file_name().unwrap();
let mut dir = dest_dir.to_owned();
dir.push("/");
dir.push(dir_name);
dir
};
match create_dir(&new_dest_dir) {
Ok(_) => {}
Err(e) => match e.kind() {
ErrorKind::AlreadyExists => (),
_ => {
return Err(e);
}
},
};
traverse_dir(path_str, &new_dest_dir)?
} else if path.is_file() {
let mut new_file = dest_dir.to_owned();
new_file.push("/");
new_file.push(path.file_name().unwrap());
copy(path, new_file)?;
}
}
Ok(())
}
let orig_dir_name = format!("{FILES_ORIG_DIR}/{input_dir}");
let dest_dir = format!("{FILES_DIR}/{dest_dir}");
clear_files(&dest_dir);
if let Err(e) = create_dir_all(&dest_dir) {
match e.kind() {
ErrorKind::AlreadyExists => (),
_ => {
panic!("{dest_dir}: {e}");
}
}
};
traverse_dir(&orig_dir_name, &OsString::from(dest_dir))?;
Ok(())
}
fn clear_files(dir_name: &str) {
let dir_name = format!("{FILES_DIR}/{dir_name}");
if let Err(e) = remove_dir_all(dir_name) {
match e.kind() {
ErrorKind::NotFound => (),
_ => {
panic!("{}", e);
}
}
}
}
fn get_md5_sum(path: &str) -> Result<[u8; 16], std::io::Error> {
let mut ctx = Context::new();
let mut file = File::open(path)?;
let mut buffer = [0u8; 4096];
loop {
let bytes = file.read(&mut buffer)?;
if bytes == 0 {
break;
}
ctx.read(&buffer[..bytes]);
}
Ok(ctx.finish())
}
fn assert_path_exists(path: &str) {
if let Err(e) = metadata(path) {
panic!("{path}: {e}");
}
}
fn assert_path_not_found(path: &str) {
if let Err(e) = metadata(path) {
match e.kind() {
ErrorKind::NotFound => (),
_ => panic!("{path}: {e}"),
}
} else {
panic!("{path} exists");
}
}
#[test]
fn test_encrypt_decrypt() {
copy_files("files_1", "test_encrypt_decrypt").unwrap();
defer! {
clear_files("test_encrypt_decrypt")
}
let original_md5 = get_md5_sum("./tests/files/test_encrypt_decrypt/file1.txt").unwrap();
let mut cmd = Command::cargo_bin(CARGO_BIN_NAME).unwrap();
let assert = cmd
.current_dir("./tests/files/test_encrypt_decrypt")
.arg("encrypt")
.arg("file1.txt")
.assert();
assert
.success()
.stdout("Successfully encrypted file1.txt\n")
.stderr("");
remove_file("./tests/files/test_encrypt_decrypt/file1.txt").unwrap();
let mut cmd = Command::cargo_bin(CARGO_BIN_NAME).unwrap();
let assert = cmd
.current_dir("./tests/files/test_encrypt_decrypt")
.arg("decrypt")
.arg("file1.txt")
.assert();
assert
.success()
.stdout("Successfully decrypted file1.txt\n")
.stderr("");
let md5_now = get_md5_sum("./tests/files/test_encrypt_decrypt/file1.txt").unwrap();
assert_eq!(original_md5, md5_now);
}
#[test]
fn test_encrypt_decrypt_with_manually_set_input_and_output_files() {
copy_files(
"files_1",
"test_encrypt_decrypt_with_manually_set_input_and_output_files",
)
.unwrap();
defer! {
clear_files("test_encrypt_decrypt_with_manually_set_input_and_output_files")
}
let original_md5 = get_md5_sum(
"./tests/files/test_encrypt_decrypt_with_manually_set_input_and_output_files/file1.txt",
)
.unwrap();
let mut cmd = Command::cargo_bin(CARGO_BIN_NAME).unwrap();
let assert = cmd
.current_dir("./tests/files/test_encrypt_decrypt_with_manually_set_input_and_output_files")
.arg("encrypt")
.args(["--out1-suffix", "encrypted.part0"])
.args(["--out2-suffix", "encrypted.part1"])
.arg("file1.txt")
.assert();
assert
.success()
.stdout("Successfully encrypted file1.txt\n")
.stderr("");
remove_file(
"./tests/files/test_encrypt_decrypt_with_manually_set_input_and_output_files/file1.txt",
)
.unwrap();
assert_path_exists(&format!("{FILES_DIR}/test_encrypt_decrypt_with_manually_set_input_and_output_files/file1.txt.encrypted.part0"));
assert_path_exists(&format!("{FILES_DIR}/test_encrypt_decrypt_with_manually_set_input_and_output_files/file1.txt.encrypted.part1"));
let mut cmd = Command::cargo_bin(CARGO_BIN_NAME).unwrap();
let assert = cmd
.current_dir("./tests/files/test_encrypt_decrypt_with_manually_set_input_and_output_files")
.arg("decrypt")
.args(["--in1-suffix", "encrypted.part1"])
.args(["--in2-suffix", "encrypted.part0"])
.arg("file1.txt")
.assert();
assert
.success()
.stdout("Successfully decrypted file1.txt\n")
.stderr("");
let md5_now = get_md5_sum(
"./tests/files/test_encrypt_decrypt_with_manually_set_input_and_output_files/file1.txt",
)
.unwrap();
assert_eq!(original_md5, md5_now);
}
#[test]
fn test_delete_after_encryption() {
copy_files("files_1", "test_delete_after_encryption").unwrap();
defer! {
clear_files("test_delete_after_encryption")
}
let mut cmd = Command::cargo_bin(CARGO_BIN_NAME).unwrap();
let assert = cmd
.current_dir("./tests/files/test_delete_after_encryption")
.arg("encrypt")
.arg("--rm")
.arg("file1.txt")
.assert();
assert
.success()
.stdout("Successfully encrypted file1.txt\n")
.stderr("");
assert_path_not_found(&format!(
"{FILES_DIR}/test_delete_after_encryption/file1.txt"
));
assert_path_exists(&format!(
"{FILES_DIR}/test_delete_after_encryption/file1.txt.otp.0"
));
assert_path_exists(&format!(
"{FILES_DIR}/test_delete_after_encryption/file1.txt.otp.1"
));
}
#[test]
fn test_delete_after_decryption() {
copy_files("files_2", "test_delete_after_decryption").unwrap();
defer! {
clear_files("test_delete_after_decryption")
}
let mut cmd = Command::cargo_bin(CARGO_BIN_NAME).unwrap();
let assert = cmd
.current_dir("./tests/files/test_delete_after_decryption")
.arg("decrypt")
.arg("--rm")
.arg("file2.txt")
.assert();
assert
.success()
.stdout("Successfully decrypted file2.txt\n")
.stderr("");
assert_path_not_found(&format!(
"{FILES_DIR}/test_delete_after_decryption/file2.txt.otp.0"
));
assert_path_not_found(&format!(
"{FILES_DIR}/test_delete_after_decryption/file2.txt.otp.1"
));
assert_path_exists(&format!(
"{FILES_DIR}/test_delete_after_decryption/file2.txt"
));
}
#[test]
fn test_encrypt_decrypt_quiet() {
copy_files("files_1", "test_encrypt_decrypt_quiet").unwrap();
defer! {
clear_files("test_encrypt_decrypt_quiet")
}
let original_md5 = get_md5_sum("./tests/files/test_encrypt_decrypt_quiet/file1.txt").unwrap();
let mut cmd = Command::cargo_bin(CARGO_BIN_NAME).unwrap();
let assert = cmd
.current_dir("./tests/files/test_encrypt_decrypt_quiet")
.arg("-q")
.arg("encrypt")
.arg("file1.txt")
.assert();
assert
.success()
.stdout("")
.stderr("");
remove_file("./tests/files/test_encrypt_decrypt_quiet/file1.txt").unwrap();
let mut cmd = Command::cargo_bin(CARGO_BIN_NAME).unwrap();
let assert = cmd
.current_dir("./tests/files/test_encrypt_decrypt_quiet")
.arg("-q")
.arg("decrypt")
.arg("file1.txt")
.assert();
assert
.success()
.stdout("")
.stderr("");
let md5_now = get_md5_sum("./tests/files/test_encrypt_decrypt_quiet/file1.txt").unwrap();
assert_eq!(original_md5, md5_now);
}