2020-02-14 00:12:49 -08:00
|
|
|
use crate::common::*;
|
2020-03-12 22:05:49 -07:00
|
|
|
use verify_step::VerifyStep;
|
|
|
|
|
|
|
|
mod verify_step;
|
2020-02-14 00:12:49 -08:00
|
|
|
|
2020-04-21 22:23:54 -07:00
|
|
|
const METAINFO_HELP: &str = "Verify torrent contents against torrent metainfo in `METAINFO`. If \
|
|
|
|
`METAINFO` is `-`, read metainfo from standard input.";
|
|
|
|
|
|
|
|
const INPUT_POSITIONAL: &str = "<INPUT>";
|
|
|
|
|
|
|
|
const INPUT_FLAG: &str = "input-flag";
|
|
|
|
|
2020-02-14 00:12:49 -08:00
|
|
|
#[derive(StructOpt)]
|
|
|
|
#[structopt(
|
|
|
|
help_message(consts::HELP_MESSAGE),
|
|
|
|
version_message(consts::VERSION_MESSAGE),
|
2020-04-11 04:17:09 -07:00
|
|
|
about("Verify files against a .torrent file.")
|
2020-02-14 00:12:49 -08:00
|
|
|
)]
|
|
|
|
pub(crate) struct Verify {
|
|
|
|
#[structopt(
|
2020-03-07 20:10:59 -08:00
|
|
|
long = "content",
|
|
|
|
short = "c",
|
2020-03-07 00:52:44 -08:00
|
|
|
value_name = "PATH",
|
2020-04-05 18:17:38 -07:00
|
|
|
empty_values(false),
|
|
|
|
parse(from_os_str),
|
2020-03-07 20:10:59 -08:00
|
|
|
help = "Verify torrent content at `PATH` against torrent metainfo. Defaults to `name` field \
|
2020-04-05 18:17:38 -07:00
|
|
|
of torrent info dictionary."
|
2020-02-14 00:12:49 -08:00
|
|
|
)]
|
2020-03-07 20:10:59 -08:00
|
|
|
content: Option<PathBuf>,
|
2020-04-21 22:23:54 -07:00
|
|
|
#[structopt(
|
|
|
|
name = INPUT_POSITIONAL,
|
|
|
|
value_name = "INPUT",
|
|
|
|
empty_values = false,
|
|
|
|
required_unless = INPUT_FLAG,
|
|
|
|
conflicts_with = INPUT_FLAG,
|
|
|
|
parse(try_from_os_str = InputTarget::try_from_os_str),
|
|
|
|
help = METAINFO_HELP,
|
|
|
|
)]
|
|
|
|
input_positional: Option<InputTarget>,
|
|
|
|
#[structopt(
|
|
|
|
name = INPUT_FLAG,
|
|
|
|
long = "input",
|
|
|
|
short = "i",
|
|
|
|
value_name = "METAINFO",
|
|
|
|
empty_values = false,
|
|
|
|
parse(try_from_os_str = InputTarget::try_from_os_str),
|
|
|
|
help = METAINFO_HELP,
|
|
|
|
)]
|
|
|
|
input_flag: Option<InputTarget>,
|
2020-02-14 00:12:49 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Verify {
|
2020-04-19 16:56:54 -07:00
|
|
|
pub(crate) fn run(self, env: &mut Env, options: &Options) -> Result<(), Error> {
|
2020-04-21 22:23:54 -07:00
|
|
|
let target = xor_args(
|
|
|
|
"input_positional",
|
|
|
|
&self.input_positional,
|
|
|
|
"input_flag",
|
|
|
|
&self.input_flag,
|
|
|
|
)?;
|
|
|
|
|
2020-04-19 16:56:54 -07:00
|
|
|
if !options.quiet {
|
2020-04-21 22:23:54 -07:00
|
|
|
VerifyStep::Loading { metainfo: &target }.print(env)?;
|
2020-03-12 22:05:49 -07:00
|
|
|
}
|
|
|
|
|
2020-04-21 22:23:54 -07:00
|
|
|
let input = env.read(target.clone())?;
|
2020-03-18 02:48:57 -07:00
|
|
|
|
|
|
|
let metainfo = Metainfo::from_input(&input)?;
|
|
|
|
|
|
|
|
let content = if let Some(content) = &self.content {
|
|
|
|
content.clone()
|
2020-02-14 00:12:49 -08:00
|
|
|
} else {
|
2020-04-21 22:23:54 -07:00
|
|
|
match target {
|
2020-04-18 14:36:54 -07:00
|
|
|
InputTarget::Path(path) => path.join("..").join(&metainfo.info.name).clean(),
|
2020-03-18 02:48:57 -07:00
|
|
|
InputTarget::Stdin => PathBuf::from(&metainfo.info.name),
|
|
|
|
}
|
2020-02-14 00:12:49 -08:00
|
|
|
};
|
|
|
|
|
2020-04-19 16:56:54 -07:00
|
|
|
let progress_bar = if env.err().is_styled_term() && !options.quiet {
|
2020-03-12 22:05:49 -07:00
|
|
|
let style = ProgressStyle::default_bar()
|
2020-04-07 22:08:37 -07:00
|
|
|
.template(consts::PROGRESS_STYLE)
|
2020-03-12 22:05:49 -07:00
|
|
|
.tick_chars(consts::TICK_CHARS)
|
|
|
|
.progress_chars(consts::PROGRESS_CHARS);
|
|
|
|
|
|
|
|
Some(ProgressBar::new(metainfo.content_size().count()).with_style(style))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2020-04-19 16:56:54 -07:00
|
|
|
if !options.quiet {
|
|
|
|
VerifyStep::Verifying { content: &content }.print(env)?;
|
|
|
|
}
|
2020-03-12 22:05:49 -07:00
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let status = metainfo.verify(&env.resolve(content)?, progress_bar)?;
|
2020-02-14 00:12:49 -08:00
|
|
|
|
2020-03-15 22:41:47 -07:00
|
|
|
status.print(env)?;
|
|
|
|
|
2020-02-14 00:12:49 -08:00
|
|
|
if status.good() {
|
2020-04-19 16:56:54 -07:00
|
|
|
if !options.quiet {
|
|
|
|
errln!(
|
|
|
|
env,
|
|
|
|
"\u{2728}\u{2728} Verification succeeded! \u{2728}\u{2728}"
|
|
|
|
)?;
|
|
|
|
}
|
2020-02-14 00:12:49 -08:00
|
|
|
Ok(())
|
|
|
|
} else {
|
2020-03-15 22:41:47 -07:00
|
|
|
Err(Error::Verify)
|
2020-02-14 00:12:49 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
2020-03-15 22:41:47 -07:00
|
|
|
use pretty_assertions::assert_eq;
|
|
|
|
|
2020-02-14 00:12:49 -08:00
|
|
|
#[test]
|
2020-04-21 22:23:54 -07:00
|
|
|
fn require_input() {
|
|
|
|
let mut env = test_env! {
|
|
|
|
args: ["torrent", "verify"],
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
assert_matches!(env.run(), Err(Error::Clap { .. }));
|
|
|
|
|
|
|
|
// flag is ok
|
|
|
|
let mut env = test_env! {
|
|
|
|
args: ["torrent", "verify", "--input", "foo"],
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
assert_matches!(env.run(), Err(Error::Filesystem { .. }));
|
|
|
|
|
|
|
|
// positional is ok
|
2020-03-05 21:44:20 -08:00
|
|
|
let mut env = test_env! {
|
2020-04-21 22:23:54 -07:00
|
|
|
args: ["torrent", "verify", "foo"],
|
2020-03-05 21:44:20 -08:00
|
|
|
tree: {},
|
|
|
|
};
|
2020-04-21 22:23:54 -07:00
|
|
|
assert_matches!(env.run(), Err(Error::Filesystem { .. }));
|
|
|
|
|
|
|
|
// both are fail
|
|
|
|
let mut env = test_env! {
|
|
|
|
args: ["torrent", "verify", "--input", "foo", "foo"],
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
assert_matches!(env.run(), Err(Error::Clap { .. }));
|
2020-02-14 00:12:49 -08:00
|
|
|
}
|
2020-03-05 21:44:20 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn pass() -> Result<()> {
|
|
|
|
let mut create_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"create",
|
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"https://bar",
|
|
|
|
],
|
|
|
|
tree: {
|
|
|
|
foo: {
|
|
|
|
a: "abc",
|
|
|
|
d: "efg",
|
|
|
|
h: "ijk",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
create_env.assert_ok();
|
2020-03-05 21:44:20 -08:00
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let torrent = create_env.resolve("foo.torrent")?;
|
2020-03-05 21:44:20 -08:00
|
|
|
|
|
|
|
let mut verify_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"verify",
|
2020-03-07 20:10:59 -08:00
|
|
|
"--input",
|
2020-03-12 22:05:49 -07:00
|
|
|
&torrent,
|
2020-03-05 21:44:20 -08:00
|
|
|
],
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
verify_env.assert_ok();
|
2020-03-05 21:44:20 -08:00
|
|
|
|
2020-03-12 22:05:49 -07:00
|
|
|
let want = format!(
|
|
|
|
"[1/2] \u{1F4BE} Loading metainfo from `{}`…\n[2/2] \u{1F9EE} Verifying pieces from \
|
|
|
|
`{}`…\n\u{2728}\u{2728} Verification succeeded! \u{2728}\u{2728}\n",
|
|
|
|
torrent.display(),
|
2020-04-05 18:17:38 -07:00
|
|
|
create_env.resolve("foo")?.display()
|
2020-03-12 22:05:49 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(verify_env.err(), want);
|
|
|
|
assert_eq!(verify_env.out(), "");
|
2020-03-05 21:44:20 -08:00
|
|
|
|
2020-04-21 22:23:54 -07:00
|
|
|
let mut verify_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"verify",
|
|
|
|
&torrent,
|
|
|
|
],
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
|
|
|
|
verify_env.assert_ok();
|
|
|
|
|
|
|
|
let want = format!(
|
|
|
|
"[1/2] \u{1F4BE} Loading metainfo from `{}`…\n[2/2] \u{1F9EE} Verifying pieces from \
|
|
|
|
`{}`…\n\u{2728}\u{2728} Verification succeeded! \u{2728}\u{2728}\n",
|
|
|
|
torrent.display(),
|
|
|
|
create_env.resolve("foo")?.display()
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(verify_env.err(), want);
|
|
|
|
assert_eq!(verify_env.out(), "");
|
|
|
|
|
2020-03-05 21:44:20 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn fail() -> Result<()> {
|
|
|
|
let mut create_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"create",
|
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"https://bar",
|
|
|
|
],
|
|
|
|
tree: {
|
|
|
|
foo: {
|
|
|
|
a: "abc",
|
|
|
|
d: "efg",
|
|
|
|
h: "ijk",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
create_env.assert_ok();
|
2020-03-05 21:44:20 -08:00
|
|
|
|
|
|
|
create_env.write("foo/a", "xyz");
|
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let torrent = create_env.resolve("foo.torrent")?;
|
2020-03-05 21:44:20 -08:00
|
|
|
|
|
|
|
let mut verify_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"verify",
|
2020-03-07 20:10:59 -08:00
|
|
|
"--input",
|
2020-03-12 22:05:49 -07:00
|
|
|
&torrent,
|
2020-03-05 21:44:20 -08:00
|
|
|
],
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
|
2020-03-15 22:41:47 -07:00
|
|
|
assert_matches!(verify_env.status(), Err(EXIT_FAILURE));
|
|
|
|
|
|
|
|
let want = [
|
|
|
|
&format!(
|
|
|
|
"[1/2] \u{1F4BE} Loading metainfo from `{}`…",
|
|
|
|
torrent.display()
|
|
|
|
),
|
|
|
|
&format!(
|
|
|
|
"[2/2] \u{1F9EE} Verifying pieces from `{}`…",
|
2020-04-05 18:17:38 -07:00
|
|
|
create_env.resolve("foo")?.display()
|
2020-03-15 22:41:47 -07:00
|
|
|
),
|
|
|
|
"Pieces corrupted.",
|
|
|
|
"error: Torrent verification failed.",
|
|
|
|
"",
|
|
|
|
]
|
|
|
|
.join("\n");
|
2020-03-12 22:05:49 -07:00
|
|
|
|
|
|
|
assert_eq!(verify_env.err(), want);
|
|
|
|
assert_eq!(verify_env.out(), "");
|
2020-03-05 21:44:20 -08:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-03-07 20:10:59 -08:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn alternate_path() -> Result<()> {
|
|
|
|
let mut create_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"create",
|
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"https://bar",
|
|
|
|
],
|
|
|
|
tree: {
|
|
|
|
foo: {
|
|
|
|
a: "abc",
|
|
|
|
d: "efg",
|
|
|
|
h: "ijk",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
create_env.assert_ok();
|
2020-03-07 20:10:59 -08:00
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let torrent = create_env.resolve("foo.torrent")?;
|
2020-03-07 20:10:59 -08:00
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let foo = create_env.resolve("foo")?;
|
2020-03-07 20:10:59 -08:00
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let bar = create_env.resolve("bar")?;
|
2020-03-07 20:10:59 -08:00
|
|
|
|
|
|
|
fs::rename(&foo, &bar).unwrap();
|
|
|
|
|
|
|
|
let mut verify_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"verify",
|
|
|
|
"--input",
|
2020-03-12 22:05:49 -07:00
|
|
|
&torrent,
|
2020-03-07 20:10:59 -08:00
|
|
|
"--content",
|
2020-03-12 22:05:49 -07:00
|
|
|
&bar,
|
2020-03-07 20:10:59 -08:00
|
|
|
],
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
verify_env.assert_ok();
|
2020-03-07 20:10:59 -08:00
|
|
|
|
2020-03-12 22:05:49 -07:00
|
|
|
let want = format!(
|
|
|
|
"[1/2] \u{1F4BE} Loading metainfo from `{}`…\n[2/2] \u{1F9EE} Verifying pieces from \
|
|
|
|
`{}`…\n\u{2728}\u{2728} Verification succeeded! \u{2728}\u{2728}\n",
|
|
|
|
torrent.display(),
|
|
|
|
bar.display(),
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(verify_env.err(), want);
|
|
|
|
assert_eq!(verify_env.out(), "");
|
2020-03-07 20:10:59 -08:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-03-15 22:41:47 -07:00
|
|
|
|
2020-03-18 02:48:57 -07:00
|
|
|
#[test]
|
|
|
|
fn verify_stdin() -> Result<()> {
|
|
|
|
let mut create_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"create",
|
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"https://bar",
|
|
|
|
],
|
|
|
|
tree: {
|
|
|
|
foo: {
|
|
|
|
a: "abc",
|
|
|
|
d: "efg",
|
|
|
|
h: "ijk",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
create_env.assert_ok();
|
2020-03-18 02:48:57 -07:00
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let torrent = create_env.resolve("foo.torrent")?;
|
|
|
|
let content = create_env.resolve("foo")?;
|
2020-03-18 02:48:57 -07:00
|
|
|
|
|
|
|
let mut verify_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"verify",
|
|
|
|
"--input",
|
|
|
|
"-",
|
|
|
|
"--content",
|
|
|
|
&content,
|
|
|
|
],
|
|
|
|
input: fs::read(&torrent).unwrap(),
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
verify_env.assert_ok();
|
2020-03-18 02:48:57 -07:00
|
|
|
|
|
|
|
let want = format!(
|
|
|
|
"[1/2] \u{1F4BE} Loading metainfo from standard input…\n[2/2] \u{1F9EE} Verifying pieces \
|
|
|
|
from `{}`…\n\u{2728}\u{2728} Verification succeeded! \u{2728}\u{2728}\n",
|
|
|
|
content.display()
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(verify_env.err(), want);
|
|
|
|
assert_eq!(verify_env.out(), "");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-03-15 22:41:47 -07:00
|
|
|
#[test]
|
|
|
|
fn output_multiple() -> Result<()> {
|
|
|
|
let mut create_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"create",
|
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"https://bar",
|
|
|
|
"--md5",
|
|
|
|
],
|
|
|
|
tree: {
|
|
|
|
foo: {
|
|
|
|
a: "abc",
|
|
|
|
d: "efg",
|
|
|
|
h: "ijk",
|
|
|
|
l: "mno",
|
|
|
|
p: "qrs",
|
|
|
|
t: "uvw",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
create_env.assert_ok();
|
2020-03-15 22:41:47 -07:00
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let torrent = create_env.resolve("foo.torrent")?;
|
2020-03-15 22:41:47 -07:00
|
|
|
|
|
|
|
create_env.write("foo/a", "xyz");
|
|
|
|
create_env.write("foo/d", "efgg");
|
|
|
|
create_env.write("foo/h", "ik");
|
|
|
|
create_env.remove_file("foo/l");
|
|
|
|
create_env.remove_file("foo/p");
|
|
|
|
create_env.create_dir("foo/p");
|
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
use std::os::unix::fs::PermissionsExt;
|
|
|
|
let metadata = create_env.metadata("foo/t");
|
|
|
|
let mut permissions = metadata.permissions();
|
|
|
|
permissions.set_mode(0);
|
|
|
|
create_env.set_permissions("foo/t", permissions);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut verify_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"verify",
|
|
|
|
"--input",
|
|
|
|
&torrent,
|
|
|
|
],
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_matches!(verify_env.status(), Err(EXIT_FAILURE));
|
|
|
|
|
|
|
|
let want = [
|
|
|
|
&format!(
|
|
|
|
"[1/2] \u{1F4BE} Loading metainfo from `{}`…",
|
|
|
|
torrent.display()
|
|
|
|
),
|
|
|
|
&format!(
|
|
|
|
"[2/2] \u{1F9EE} Verifying pieces from `{}`…",
|
2020-04-05 18:17:38 -07:00
|
|
|
create_env.resolve("foo")?.display()
|
2020-03-15 22:41:47 -07:00
|
|
|
),
|
2020-03-17 03:02:02 -07:00
|
|
|
"a: MD5 checksum mismatch: d16fb36f0911f878998c136191af705e (expected \
|
|
|
|
900150983cd24fb0d6963f7d28e17f72)",
|
2020-03-15 22:41:47 -07:00
|
|
|
"d: 1 byte too long",
|
|
|
|
"h: 1 byte too short",
|
|
|
|
"l: File missing",
|
|
|
|
"p: Expected file but found directory",
|
|
|
|
#[cfg(unix)]
|
|
|
|
"t: Permission denied (os error 13)",
|
|
|
|
"Pieces corrupted.",
|
|
|
|
"error: Torrent verification failed.",
|
|
|
|
"",
|
|
|
|
]
|
|
|
|
.join("\n");
|
|
|
|
|
|
|
|
assert_eq!(verify_env.err(), want);
|
|
|
|
assert_eq!(verify_env.out(), "");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn output_color() -> Result<()> {
|
|
|
|
let mut create_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"create",
|
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"https://bar",
|
|
|
|
"--md5",
|
|
|
|
],
|
|
|
|
tree: {
|
|
|
|
foo: {
|
|
|
|
a: "abc",
|
|
|
|
d: "efg",
|
|
|
|
h: "ijk",
|
|
|
|
l: "mno",
|
|
|
|
p: "qrs",
|
|
|
|
t: "uvw",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
create_env.assert_ok();
|
2020-03-15 22:41:47 -07:00
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let torrent = create_env.resolve("foo.torrent")?;
|
2020-03-15 22:41:47 -07:00
|
|
|
|
|
|
|
create_env.write("foo/a", "xyz");
|
|
|
|
create_env.write("foo/d", "efgg");
|
|
|
|
create_env.write("foo/h", "ik");
|
|
|
|
create_env.remove_file("foo/l");
|
|
|
|
create_env.remove_file("foo/p");
|
|
|
|
create_env.create_dir("foo/p");
|
|
|
|
|
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
use std::os::unix::fs::PermissionsExt;
|
|
|
|
let metadata = create_env.metadata("foo/t");
|
|
|
|
let mut permissions = metadata.permissions();
|
|
|
|
permissions.set_mode(0);
|
|
|
|
create_env.set_permissions("foo/t", permissions);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut verify_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"verify",
|
|
|
|
"--input",
|
|
|
|
&torrent,
|
|
|
|
],
|
|
|
|
err_style: true,
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_matches!(verify_env.status(), Err(EXIT_FAILURE));
|
|
|
|
|
|
|
|
let style = Style::active();
|
|
|
|
|
|
|
|
fn error(path: &str, message: &str) -> String {
|
|
|
|
let style = Style::active();
|
|
|
|
format!(
|
|
|
|
"{}{}:{} {}",
|
|
|
|
style.message().prefix(),
|
|
|
|
path,
|
|
|
|
style.message().suffix(),
|
2020-03-16 01:07:29 -07:00
|
|
|
message,
|
2020-03-15 22:41:47 -07:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
let want = [
|
|
|
|
&format!(
|
|
|
|
"{} \u{1F4BE} {}",
|
|
|
|
style.dim().paint("[1/2]"),
|
|
|
|
style
|
|
|
|
.message()
|
|
|
|
.paint(format!("Loading metainfo from `{}`…", torrent.display()))
|
|
|
|
),
|
|
|
|
&format!(
|
|
|
|
"{} \u{1F9EE} {}",
|
|
|
|
style.dim().paint("[2/2]"),
|
|
|
|
style.message().paint(format!(
|
|
|
|
"Verifying pieces from `{}`…",
|
2020-04-05 18:17:38 -07:00
|
|
|
create_env.resolve("foo")?.display()
|
2020-03-15 22:41:47 -07:00
|
|
|
))
|
|
|
|
),
|
2020-03-16 01:07:29 -07:00
|
|
|
&format!(
|
|
|
|
"{} MD5 checksum mismatch: {} (expected {})",
|
|
|
|
style.message().paint("a:"),
|
2020-03-17 03:02:02 -07:00
|
|
|
style.error().paint("d16fb36f0911f878998c136191af705e"),
|
|
|
|
style.good().paint("900150983cd24fb0d6963f7d28e17f72"),
|
2020-03-15 22:41:47 -07:00
|
|
|
),
|
|
|
|
&error("d", "1 byte too long"),
|
|
|
|
&error("h", "1 byte too short"),
|
|
|
|
&error("l", "File missing"),
|
|
|
|
&error("p", "Expected file but found directory"),
|
|
|
|
#[cfg(unix)]
|
|
|
|
&error("t", "Permission denied (os error 13)"),
|
|
|
|
"Pieces corrupted.",
|
|
|
|
&format!(
|
|
|
|
"{}{}",
|
|
|
|
style.error().paint("error"),
|
|
|
|
style.message().paint(": Torrent verification failed.")
|
|
|
|
),
|
|
|
|
"",
|
|
|
|
]
|
|
|
|
.join("\n");
|
|
|
|
|
|
|
|
assert_eq!(verify_env.err(), want);
|
|
|
|
assert_eq!(verify_env.out(), "");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn output_single() -> Result<()> {
|
|
|
|
let mut create_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"create",
|
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"https://bar",
|
|
|
|
],
|
|
|
|
tree: {
|
|
|
|
foo: "abc",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
create_env.assert_ok();
|
2020-03-15 22:41:47 -07:00
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let torrent = create_env.resolve("foo.torrent")?;
|
2020-03-15 22:41:47 -07:00
|
|
|
|
|
|
|
create_env.write("foo", "abcxyz");
|
|
|
|
|
|
|
|
let mut verify_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"verify",
|
|
|
|
"--input",
|
|
|
|
&torrent,
|
|
|
|
],
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
|
|
|
|
assert_matches!(verify_env.status(), Err(EXIT_FAILURE));
|
|
|
|
|
|
|
|
let want = [
|
|
|
|
&format!(
|
|
|
|
"[1/2] \u{1F4BE} Loading metainfo from `{}`…",
|
|
|
|
torrent.display()
|
|
|
|
),
|
|
|
|
&format!(
|
|
|
|
"[2/2] \u{1F9EE} Verifying pieces from `{}`…",
|
2020-04-05 18:17:38 -07:00
|
|
|
create_env.resolve("foo")?.display()
|
2020-03-15 22:41:47 -07:00
|
|
|
),
|
|
|
|
"3 bytes too long",
|
|
|
|
"Pieces corrupted.",
|
|
|
|
"error: Torrent verification failed.",
|
|
|
|
"",
|
|
|
|
]
|
|
|
|
.join("\n");
|
|
|
|
|
|
|
|
assert_eq!(verify_env.err(), want);
|
|
|
|
assert_eq!(verify_env.out(), "");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-03-18 02:48:57 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn stdin_uses_name() -> Result<()> {
|
|
|
|
let mut create_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"create",
|
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"https://bar",
|
|
|
|
],
|
|
|
|
tree: {
|
|
|
|
foo: {
|
|
|
|
a: "abc",
|
|
|
|
d: "efg",
|
|
|
|
h: "ijk",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
create_env.assert_ok();
|
2020-03-18 02:48:57 -07:00
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
let torrent = create_env.resolve("foo.torrent")?;
|
2020-03-18 02:48:57 -07:00
|
|
|
|
|
|
|
let metainfo = fs::read(torrent).unwrap();
|
|
|
|
|
|
|
|
let mut verify_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"verify",
|
|
|
|
"--input",
|
|
|
|
"-",
|
|
|
|
],
|
|
|
|
input: metainfo,
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
|
2020-04-05 18:17:38 -07:00
|
|
|
fs::rename(create_env.resolve("foo")?, verify_env.resolve("foo")?).unwrap();
|
2020-03-18 02:48:57 -07:00
|
|
|
|
2020-04-06 11:38:40 -07:00
|
|
|
verify_env.assert_ok();
|
2020-03-18 02:48:57 -07:00
|
|
|
|
|
|
|
let want = format!(
|
|
|
|
"[1/2] \u{1F4BE} Loading metainfo from standard input…\n[2/2] \u{1F9EE} Verifying pieces \
|
|
|
|
from `foo`…\n\u{2728}\u{2728} Verification succeeded! \u{2728}\u{2728}\n",
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(verify_env.err(), want);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-04-19 16:56:54 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn no_output_when_quiet() -> Result<()> {
|
|
|
|
let mut create_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"torrent",
|
|
|
|
"create",
|
|
|
|
"--input",
|
|
|
|
"foo"
|
|
|
|
],
|
|
|
|
tree: {
|
|
|
|
foo: "",
|
|
|
|
}
|
|
|
|
};
|
|
|
|
create_env.assert_ok();
|
|
|
|
|
|
|
|
let torrent = create_env.resolve("foo.torrent")?;
|
|
|
|
|
|
|
|
let mut verify_env = test_env! {
|
|
|
|
args: [
|
|
|
|
"--quiet",
|
|
|
|
"torrent",
|
|
|
|
"verify",
|
|
|
|
"--input",
|
|
|
|
&torrent,
|
|
|
|
],
|
|
|
|
tree: {},
|
|
|
|
};
|
|
|
|
verify_env.assert_ok();
|
|
|
|
|
|
|
|
assert_eq!(verify_env.out(), "");
|
|
|
|
assert_eq!(verify_env.err(), "");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-02-14 00:12:49 -08:00
|
|
|
}
|