2019-05-24 01:25:55 -07:00
|
|
|
use crate::common::*;
|
|
|
|
|
|
|
|
#[derive(StructOpt)]
|
|
|
|
pub(crate) struct Create {
|
|
|
|
#[structopt(name = "INPUT", long = "input")]
|
|
|
|
input: PathBuf,
|
|
|
|
#[structopt(name = "OUTPUT", long = "output")]
|
|
|
|
output: Option<PathBuf>,
|
|
|
|
#[structopt(name = "PRIVATE", long = "private")]
|
|
|
|
private: bool,
|
|
|
|
#[structopt(name = "NO-CREATION-DATE", long = "no-creation-date")]
|
|
|
|
no_creation_date: bool,
|
|
|
|
#[structopt(name = "NO-CREATED-BY", long = "no-created-by")]
|
|
|
|
no_created_by: bool,
|
|
|
|
#[structopt(name = "COMMENT", long = "comment")]
|
|
|
|
comment: Option<String>,
|
|
|
|
#[structopt(name = "PIECE-LENGTH", long = "piece-length", default_value = "524288")]
|
2020-01-04 18:58:42 -08:00
|
|
|
piece_length: u32,
|
2019-05-24 01:25:55 -07:00
|
|
|
#[structopt(name = "ANNOUNCE", long = "announce", required(true))]
|
|
|
|
announce: Vec<String>,
|
|
|
|
#[structopt(name = "MD5SUM", long = "md5sum")]
|
|
|
|
md5sum: bool,
|
|
|
|
#[structopt(name = "NAME", long = "name")]
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Create {
|
|
|
|
pub(crate) fn run(self, env: &Environment) -> Result<(), Error> {
|
|
|
|
let input = env.resolve(&self.input);
|
|
|
|
|
|
|
|
let mut announce_list = Vec::new();
|
|
|
|
for announce in &self.announce {
|
|
|
|
let tier = announce
|
2020-01-04 18:58:42 -08:00
|
|
|
.split(',')
|
2019-05-24 01:25:55 -07:00
|
|
|
.map(str::to_string)
|
|
|
|
.collect::<Vec<String>>();
|
|
|
|
|
|
|
|
tier
|
|
|
|
.iter()
|
|
|
|
.map(|announce| announce.parse())
|
|
|
|
.collect::<Result<Vec<Url>, url::ParseError>>()
|
|
|
|
.context(error::AnnounceUrlParse)?;
|
|
|
|
|
|
|
|
announce_list.push(tier);
|
|
|
|
}
|
|
|
|
|
|
|
|
let announce = if let Some(primary) = announce_list.first().and_then(|tier| tier.first()) {
|
|
|
|
primary.clone()
|
|
|
|
} else {
|
|
|
|
return Err(Error::AnnounceEmpty);
|
|
|
|
};
|
|
|
|
|
|
|
|
let filename = input.file_name().ok_or_else(|| Error::FilenameExtract {
|
|
|
|
path: input.clone(),
|
|
|
|
})?;
|
|
|
|
|
|
|
|
let name = match &self.name {
|
|
|
|
Some(name) => name.clone(),
|
|
|
|
None => filename
|
|
|
|
.to_str()
|
|
|
|
.ok_or_else(|| Error::FilenameDecode {
|
|
|
|
filename: filename.to_os_string(),
|
|
|
|
})?
|
|
|
|
.to_owned(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let output = self
|
|
|
|
.output
|
|
|
|
.as_ref()
|
|
|
|
.map(|output| env.resolve(&output))
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
let mut torrent_name = name.to_owned();
|
|
|
|
torrent_name.push_str(".torrent");
|
|
|
|
|
|
|
|
input.parent().unwrap().join(torrent_name)
|
|
|
|
});
|
|
|
|
|
|
|
|
let private = if self.private { 1 } else { 0 };
|
|
|
|
|
|
|
|
let creation_date = if self.no_creation_date {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(
|
|
|
|
SystemTime::now()
|
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)?
|
|
|
|
.as_secs(),
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
let created_by = if self.no_created_by {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(String::from(consts::CREATED_BY_DEFAULT))
|
|
|
|
};
|
|
|
|
|
|
|
|
let (mode, pieces) = Hasher::hash(&input, self.md5sum, self.piece_length)?;
|
|
|
|
|
|
|
|
let info = Info {
|
|
|
|
piece_length: self.piece_length,
|
|
|
|
mode,
|
|
|
|
pieces,
|
|
|
|
name,
|
|
|
|
private,
|
|
|
|
};
|
|
|
|
|
|
|
|
let metainfo = Metainfo {
|
2020-01-04 18:58:42 -08:00
|
|
|
comment: self.comment,
|
2019-05-24 01:25:55 -07:00
|
|
|
encoding: consts::ENCODING_UTF8.to_string(),
|
|
|
|
announce,
|
|
|
|
announce_list,
|
|
|
|
creation_date,
|
|
|
|
created_by,
|
|
|
|
info,
|
|
|
|
};
|
|
|
|
|
|
|
|
let bytes = serde_bencode::ser::to_bytes(&metainfo)?;
|
|
|
|
|
|
|
|
fs::write(&output, bytes).context(error::Filesystem { path: &output })?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
fn environment(args: &[&str]) -> Environment {
|
|
|
|
testing::environment(["torrent", "create"].iter().chain(args).cloned())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn require_input_argument() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&[]);
|
2019-05-24 01:25:55 -07:00
|
|
|
assert!(matches!(env.run(), Err(Error::Clap { .. })));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn require_input_present() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
assert!(matches!(env.run(), Err(Error::Filesystem { .. })));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn torrent_file_is_bencode_dict() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let value = bencode::Value::decode(&bytes).unwrap();
|
|
|
|
assert!(matches!(value, bencode::Value::Dict(_)));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn privacy_defaults_to_false() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.info.private, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn privacy_flag_sets_privacy() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar", "--private"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.info.private, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn tracker_flag_must_be_url() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
assert!(matches!(env.run(), Err(Error::AnnounceUrlParse { .. })));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn announce_single() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.announce, "http://bar");
|
|
|
|
assert_eq!(metainfo.announce_list, vec![vec!["http://bar"]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn announce_single_tier() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar,http://baz"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.announce, "http://bar");
|
|
|
|
assert_eq!(
|
|
|
|
metainfo.announce_list,
|
|
|
|
vec![vec!["http://bar", "http://baz"]]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn announce_multiple_tiers() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&[
|
2019-05-24 01:25:55 -07:00
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"http://bar,http://baz",
|
|
|
|
"--announce",
|
|
|
|
"http://abc,http://xyz",
|
|
|
|
]);
|
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.announce, "http://bar");
|
|
|
|
assert_eq!(
|
|
|
|
metainfo.announce_list,
|
|
|
|
vec![
|
|
|
|
vec!["http://bar", "http://baz"],
|
|
|
|
vec!["http://abc", "http://xyz"],
|
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn comment_default() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.comment, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn comment_set() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&[
|
2019-05-24 01:25:55 -07:00
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"http://bar",
|
|
|
|
"--comment",
|
|
|
|
"Hello, world!",
|
|
|
|
]);
|
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.comment.unwrap(), "Hello, world!");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn piece_length_default() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
2020-01-04 18:58:42 -08:00
|
|
|
assert_eq!(metainfo.info.piece_length, 512 * 2u32.pow(10));
|
2019-05-24 01:25:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn piece_length_override() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&[
|
2019-05-24 01:25:55 -07:00
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"http://bar",
|
|
|
|
"--piece-length",
|
|
|
|
"1",
|
|
|
|
]);
|
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.info.piece_length, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn name() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&[
|
2019-05-24 01:25:55 -07:00
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"http://bar",
|
|
|
|
"--piece-length",
|
|
|
|
"1",
|
|
|
|
]);
|
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.info.name, "foo");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn name_subdir() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&[
|
2019-05-24 01:25:55 -07:00
|
|
|
"--input",
|
|
|
|
"foo/bar",
|
|
|
|
"--announce",
|
|
|
|
"http://bar",
|
|
|
|
"--piece-length",
|
|
|
|
"1",
|
|
|
|
]);
|
|
|
|
let dir = env.resolve("foo");
|
|
|
|
fs::create_dir(&dir).unwrap();
|
|
|
|
fs::write(dir.join("bar"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = dir.join("bar.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.info.name, "bar");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn destination_override() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&[
|
2019-05-24 01:25:55 -07:00
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--output",
|
|
|
|
"x.torrent",
|
|
|
|
"--announce",
|
|
|
|
"http://bar",
|
|
|
|
]);
|
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("x.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn created_by_default() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.created_by.unwrap(), consts::CREATED_BY_DEFAULT);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn created_by_unset() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&[
|
2019-05-24 01:25:55 -07:00
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"http://bar",
|
|
|
|
"--no-created-by",
|
|
|
|
]);
|
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.created_by, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn encoding() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.encoding, "UTF-8");
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn created_date_default() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
let now = SystemTime::now()
|
|
|
|
.duration_since(SystemTime::UNIX_EPOCH)
|
|
|
|
.unwrap()
|
|
|
|
.as_secs();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert!(metainfo.creation_date.unwrap() < now + 10);
|
|
|
|
assert!(metainfo.creation_date.unwrap() > now - 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn created_date_unset() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&[
|
2019-05-24 01:25:55 -07:00
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"http://bar",
|
|
|
|
"--no-creation-date",
|
|
|
|
]);
|
|
|
|
fs::write(env.resolve("foo"), "").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.creation_date, None);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn single_small() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
let contents = "bar";
|
|
|
|
fs::write(env.resolve("foo"), contents).unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.info.pieces, Sha1::from(contents).digest().bytes());
|
|
|
|
assert_eq!(
|
|
|
|
metainfo.info.mode,
|
|
|
|
Mode::Single {
|
|
|
|
length: contents.len() as u64,
|
|
|
|
md5sum: None,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn single_one_byte_piece() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&[
|
2019-05-24 01:25:55 -07:00
|
|
|
"--input",
|
|
|
|
"foo",
|
|
|
|
"--announce",
|
|
|
|
"http://bar",
|
|
|
|
"--piece-length",
|
|
|
|
"1",
|
|
|
|
]);
|
|
|
|
let contents = "bar";
|
|
|
|
fs::write(env.resolve("foo"), contents).unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
let pieces = Sha1::from("b")
|
|
|
|
.digest()
|
|
|
|
.bytes()
|
|
|
|
.iter()
|
|
|
|
.chain(Sha1::from("a").digest().bytes().iter())
|
|
|
|
.chain(Sha1::from("r").digest().bytes().iter())
|
|
|
|
.cloned()
|
|
|
|
.collect::<Vec<u8>>();
|
|
|
|
|
|
|
|
assert_eq!(metainfo.info.pieces, pieces);
|
|
|
|
assert_eq!(
|
|
|
|
metainfo.info.mode,
|
|
|
|
Mode::Single {
|
|
|
|
length: contents.len() as u64,
|
|
|
|
md5sum: None,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn single_empty() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
let contents = "";
|
|
|
|
fs::write(env.resolve("foo"), contents).unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.info.pieces.len(), 0);
|
|
|
|
assert_eq!(
|
|
|
|
metainfo.info.mode,
|
|
|
|
Mode::Single {
|
|
|
|
length: 0,
|
|
|
|
md5sum: None,
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn multiple_no_files() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
let dir = env.resolve("foo");
|
|
|
|
fs::create_dir(&dir).unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.info.pieces.len(), 0);
|
|
|
|
assert_eq!(metainfo.info.mode, Mode::Multiple { files: Vec::new() })
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn multiple_one_file() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
let dir = env.resolve("foo");
|
|
|
|
fs::create_dir(&dir).unwrap();
|
|
|
|
let file = dir.join("bar");
|
|
|
|
let contents = "bar";
|
|
|
|
fs::write(file, contents).unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(metainfo.info.pieces, Sha1::from(contents).digest().bytes());
|
|
|
|
assert_eq!(metainfo.info.mode, Mode::Multiple { files: Vec::new() })
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn multiple_three_files() {
|
2020-01-04 18:58:42 -08:00
|
|
|
let mut env = environment(&["--input", "foo", "--announce", "http://bar"]);
|
2019-05-24 01:25:55 -07:00
|
|
|
let dir = env.resolve("foo");
|
|
|
|
fs::create_dir(&dir).unwrap();
|
|
|
|
fs::write(dir.join("a"), "abc").unwrap();
|
|
|
|
fs::write(dir.join("x"), "xyz").unwrap();
|
|
|
|
fs::write(dir.join("h"), "hij").unwrap();
|
|
|
|
env.run().unwrap();
|
|
|
|
let torrent = env.resolve("foo.torrent");
|
|
|
|
let bytes = fs::read(torrent).unwrap();
|
|
|
|
let metainfo = serde_bencode::de::from_bytes::<Metainfo>(&bytes).unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
metainfo.info.pieces,
|
|
|
|
Sha1::from("abchijxyz").digest().bytes()
|
|
|
|
);
|
|
|
|
assert_eq!(metainfo.info.mode, Mode::Multiple { files: Vec::new() })
|
|
|
|
}
|
|
|
|
}
|