Skip to content

Commit

Permalink
Add test suite
Browse files Browse the repository at this point in the history
  • Loading branch information
Daan Sprenkels committed Oct 19, 2017
1 parent 6ccaca4 commit 8a83873
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 17 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,6 @@ shamirsecretsharing = "0.1"
version = "2.25"
default-features = false
features = [ "suggestions", "color" ]

[dev-dependencies]
duct = "0.9"
100 changes: 99 additions & 1 deletion src/bin/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fn main() {
error!("error while reading stdin: {}", err);
exit(1)
});
let lines = shares_string.lines().collect::<Vec<&str>>();
let lines = shares_string.lines().filter(|x| !x.is_empty()).collect::<Vec<&str>>();

// Decode the lines
if lines.is_empty() {
Expand All @@ -72,6 +72,10 @@ fn main() {
decoded_line.push(b);
offset += 2;
}
if decoded_line.len() < KEYSHARE_SIZE {
error!("share {} is too short", line_idx + 1);
exit(1);
}
decoded_lines.push(decoded_line);
}

Expand Down Expand Up @@ -138,3 +142,97 @@ fn main() {
exit(1);
};
}

#[cfg(test)]
mod tests {
extern crate duct;
use self::duct::cmd;

macro_rules! cmd {
( $program:expr, $( $arg:expr ),* ) => (
{
let args = [ $( $arg ),* ];
cmd($program, args.iter())
}
)
}

macro_rules! run_self {
( $( $arg:expr ),* ) => (
{
let args = ["run", "--quiet", "--bin", "secret-share-combine", "--", $( $arg ),* ];
cmd(env!("CARGO"), args.iter())
}
)
}

#[test]
fn functional() {
let secret = "secret";
let echo = cmd!("echo", secret);
let split = echo.pipe(cmd!(env!("CARGO"), "run", "--quiet", "--bin", "secret-share-split",
"--", "--count", "5", "--threshold", "4"));
let combine = split.pipe(run_self!());
let output = combine.read().unwrap();
assert_eq!(output, secret);
}

#[test]
fn no_shares() {
let echo = cmd!("echo", "");
let combine = echo.pipe(run_self!()).unchecked().stderr_to_stdout();
let output = combine.read().unwrap();
assert_eq!(output, "ERROR:secret_share_combine: no input shares supplied");
}

#[test]
fn uneven_hex_len() {
let echo = cmd!("echo", "0");
let combine = echo.pipe(run_self!()).unchecked().stderr_to_stdout();
let output = combine.read().unwrap();
assert_eq!(output, "ERROR:secret_share_combine: share 1 is of an incorrect length \
(the length is not even)");
}

#[test]
fn short_hex_len() {
let echo = cmd!("echo", "00");
let combine = echo.pipe(run_self!()).unchecked().stderr_to_stdout();
let output = combine.read().unwrap();
assert_eq!(output, "ERROR:secret_share_combine: share 1 is too short");
}

#[test]
fn no_content() {
let shares = "
01b5d858849053ec0b475b84c580a0a50e13fc283bdebfee35082a1fbe99ef74206efc338ab1f54cbbc63d2807ba07d6f6
02deb4f2a93e55d8a0a7644723b33ec94fa5ca52e5dfa1cc92c86f937a1d0114fb6efc338ab1f54cbbc63d2807ba07d6f6
".trim();
let echo = cmd!("echo", shares);
let combine = echo.pipe(run_self!());
let output = combine.read().unwrap();
assert_eq!(output, "");
}

/// Test shares generated by the demo page (currently) located at https://dsprenkels.com/sss/
#[test]
fn demo_shares() {
let shares = "
017d784898d4ea3ffcbe2fb814542e1a25ff4926cb886ccff926d0fab1cbb299226737bde1c0b5e6\
c2e4c927ccb26abbc27ef9632ae4903853a569abefbca5882ea0e1e31c54df1a3d9b0ed09e90f653\
6d0aeeb5b1654d3348cabcdcf04637a25ee9f001bd6e04dd8b0bee7383c863aa79
028cd8cb05ee80dab157d352da41e0e2a83a16bc0e975de7e55faf9b93f1c2924e6737bde1c0b5e6\
c2e4c927ccb26abbc27ef9632ae4903853a569abefbca5882ea0e1e31c54df1a3d9b0ed09e90f653\
6d0aeeb5b1654d3348cabcdcf04637a25ee9f001bd6e04dd8b0bee7383c863aa79".trim();
let echo = cmd!("echo", shares);
let combine = echo.pipe(run_self!());
let output = combine.stdout_capture().run().unwrap();
let mut expected: Vec<u8> = Vec::with_capacity(64);
expected.extend("Hello World! :D".as_bytes());
expected.push(0x80);
while expected.len() < 64 {
expected.push(0x00);
}
assert_eq!(output.stdout, expected);
}
}
179 changes: 163 additions & 16 deletions src/bin/split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,29 +57,36 @@ fn main() {
let count = matches
.value_of("count")
.unwrap()
.parse()
.parse::<isize>()
.map_err(|_| {
error!("count is not a valid number");
exit(1);
})
.and_then(|x| if 2 <= x { Ok(x) } else { Err(x) })
error!("count is not a valid number");
exit(1);
})
.and_then(|x| if 2 <= x && x <= 255 { Ok(x) } else { Err(x) })
.unwrap_or_else(|x| {
error!("count must be a number between 2 and 255 (instead of {})", x);
exit(1);
});
error!("count must be a number between 2 and 255 (instead of {})",
x);
exit(1);
}) as u8;
let treshold = matches
.value_of("threshold")
.unwrap()
.parse()
.parse::<isize>()
.map_err(|_| {
error!("threshold is not a valid number");
exit(1);
})
.and_then(|x| if 2 <= x && x <= count { Ok(x) } else { Err(x) })
error!("threshold is not a valid number");
exit(1);
})
.and_then(|x| if 2 <= x && x <= (count as isize) {
Ok(x)
} else {
Err(x)
})
.unwrap_or_else(|x| {
error!("threshold must be a number between 2 and {} (instead of {})", count, x);
exit(1);
});
error!("threshold must be a number between 2 and {} (instead of {})",
count,
x);
exit(1);
}) as u8;

// Open the input file and read its contents
let mut input_file: Box<Read> = match input_fn {
Expand Down Expand Up @@ -118,3 +125,143 @@ fn main() {
println!("{}", line);
}
}

#[cfg(test)]
mod tests {
extern crate duct;
use self::duct::cmd;

macro_rules! cmd {
( $program:expr, $( $arg:expr ),* ) => (
{
let args = [ $( $arg ),* ];
cmd($program, args.iter())
}
)
}

macro_rules! run_self {
( $( $arg:expr ),* ) => (
{
let args = ["run", "--quiet", "--bin", "secret-share-split", "--", $( $arg ),* ];
cmd(env!("CARGO"), args.iter())
}
)
}

#[test]
fn functional() {
let secret = "Hello World!";
let echo = cmd!("echo", "-n", secret);
let output = echo.pipe(run_self!("--count", "5", "--threshold", "4"))
.read()
.unwrap();
let mut idx = 0;
for line in output.lines() {
assert_eq!(line.len(), 2 * (49 + secret.len()));
let x = format!("{:02}", idx + 1);
assert!(line.starts_with(&x));
idx += 1;
}
assert_eq!(idx, 5);
}

#[test]
fn no_args() {
let output = run_self!()
.unchecked()
.stderr_to_stdout()
.read()
.unwrap();
assert!(output.starts_with("error: The following required arguments were not provided:
--count <n>
--threshold <k>"));
}

#[test]
fn no_count() {
let output = run_self!("--threshold", "4")
.unchecked()
.stderr_to_stdout()
.read()
.unwrap();
assert!(output.starts_with("error: The following required arguments were not provided:
--count <n>"));
}

#[test]
fn no_threshold() {
let output = run_self!("--count", "5")
.unchecked()
.stderr_to_stdout()
.read()
.unwrap();
assert!(output.starts_with("error: The following required arguments were not provided:
--threshold <k>"));
}

#[test]
fn count_parse() {
let output = run_self!("--count", "not a number", "--threshold", "4")
.unchecked()
.stderr_to_stdout()
.read()
.unwrap();
assert_eq!(output, format!("ERROR:secret_share_split: count is not a valid number"));
}

#[test]
fn count_range() {
macro_rules! test_bad_count {
($n:expr, $k:expr) => (
let output = run_self!("--count", $n, "--threshold", $k)
.unchecked().stderr_to_stdout().read().unwrap();
assert_eq!(output, format!("ERROR:secret_share_split: \
count must be a number between 2 \
and 255 (instead of {})", $n));
)
}
test_bad_count!("0", "4");
test_bad_count!("1", "4");
test_bad_count!("256", "4");
}

#[test]
fn threshold_parse() {
let output = run_self!("--count", "5", "--threshold", "not a number")
.unchecked()
.stderr_to_stdout()
.read()
.unwrap();
assert_eq!(output, format!("ERROR:secret_share_split: threshold is not a valid number"));
}

#[test]
fn threshold_range() {
macro_rules! test_bad_threshold {
($n:expr, $k:expr) => (
let output = run_self!("--count", $n, "--threshold", $k)
.unchecked().stderr_to_stdout().read().unwrap();
assert_eq!(output, format!("ERROR:secret_share_split: \
threshold must be a number between 2 and \
5 (instead of {})", $k));
)
}
test_bad_threshold!("5", "0");
test_bad_threshold!("5", "1");
test_bad_threshold!("5", "6");
test_bad_threshold!("5", "256");
}

#[test]
fn nonexistent_file() {
let output = run_self!("--count", "5", "--threshold", "4", "nonexistent")
.unchecked()
.stderr_to_stdout()
.read()
.unwrap();
assert_eq!(output,
"ERROR:secret_share_split: error while opening file \'nonexistent\': \
No such file or directory (os error 2)");
}
}

0 comments on commit 8a83873

Please sign in to comment.