diff --git a/src/opt/torrent/show.rs b/src/opt/torrent/show.rs index e3d31be..a88913d 100644 --- a/src/opt/torrent/show.rs +++ b/src/opt/torrent/show.rs @@ -117,6 +117,189 @@ Piece Size\t16384 Piece Count\t1 File Count\t1 Files\tfoo +"; + + assert_eq!(have, want); + } + } + + #[test] + fn tier_list_with_main() { + let metainfo = Metainfo { + announce: "a".into(), + announce_list: Some(vec![vec!["x".into()], vec!["y".into()], vec!["z".into()]]), + comment: Some("comment".into()), + created_by: Some("created by".into()), + creation_date: Some(1), + encoding: Some("UTF-8".into()), + info: Info { + private: Some(1), + piece_length: 16 * 1024, + source: Some("source".into()), + name: "foo".into(), + pieces: vec![ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + ], + mode: Mode::Single { + length: 20, + md5sum: None, + }, + }, + }; + + { + let mut env = TestEnvBuilder::new() + .arg_slice(&["imdl", "torrent", "show", "--input", "foo.torrent"]) + .out_is_term() + .build(); + + let path = env.resolve("foo.torrent"); + + metainfo.dump(path).unwrap(); + + env.run().unwrap(); + + let have = env.out(); + let want = " Name foo + Comment comment + Created 1970-01-01 00:00:01 UTC + Created By created by + Source source + Info Hash b7595205a46491b3e8686e10b28efe7144d066cc +Torrent Size 240 bytes +Content Size 20 bytes + Private yes + Trackers a + x + y + z + Piece Size 16 KiB + Piece Count 1 + File Count 1 + Files foo +"; + + assert_eq!(have, want); + } + + { + let mut env = TestEnvBuilder::new() + .arg_slice(&["imdl", "torrent", "show", "--input", "foo.torrent"]) + .build(); + + let path = env.resolve("foo.torrent"); + + metainfo.dump(path).unwrap(); + + env.run().unwrap(); + + let have = env.out(); + let want = "\ +Name\tfoo +Comment\tcomment +Created\t1970-01-01 00:00:01 UTC +Created By\tcreated by +Source\tsource +Info Hash\tb7595205a46491b3e8686e10b28efe7144d066cc +Torrent Size\t240 +Content Size\t20 +Private\tyes +Trackers\ta\tx\ty\tz +Piece Size\t16384 +Piece Count\t1 +File Count\t1 +Files\tfoo +"; + + assert_eq!(have, want); + } + } + + #[test] + fn tier_list_without_main() { + let metainfo = Metainfo { + announce: "a".into(), + announce_list: Some(vec![vec!["b".into()], vec!["c".into()], vec!["a".into()]]), + comment: Some("comment".into()), + created_by: Some("created by".into()), + creation_date: Some(1), + encoding: Some("UTF-8".into()), + info: Info { + private: Some(1), + piece_length: 16 * 1024, + source: Some("source".into()), + name: "foo".into(), + pieces: vec![ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + ], + mode: Mode::Single { + length: 20, + md5sum: None, + }, + }, + }; + + { + let mut env = TestEnvBuilder::new() + .arg_slice(&["imdl", "torrent", "show", "--input", "foo.torrent"]) + .out_is_term() + .build(); + + let path = env.resolve("foo.torrent"); + + metainfo.dump(path).unwrap(); + + env.run().unwrap(); + + let have = env.out(); + let want = " Name foo + Comment comment + Created 1970-01-01 00:00:01 UTC + Created By created by + Source source + Info Hash b7595205a46491b3e8686e10b28efe7144d066cc +Torrent Size 240 bytes +Content Size 20 bytes + Private yes + Trackers b + c + a + Piece Size 16 KiB + Piece Count 1 + File Count 1 + Files foo +"; + + assert_eq!(have, want); + } + + { + let mut env = TestEnvBuilder::new() + .arg_slice(&["imdl", "torrent", "show", "--input", "foo.torrent"]) + .build(); + + let path = env.resolve("foo.torrent"); + + metainfo.dump(path).unwrap(); + + env.run().unwrap(); + + let have = env.out(); + let want = "\ +Name\tfoo +Comment\tcomment +Created\t1970-01-01 00:00:01 UTC +Created By\tcreated by +Source\tsource +Info Hash\tb7595205a46491b3e8686e10b28efe7144d066cc +Torrent Size\t240 +Content Size\t20 +Private\tyes +Trackers\tb\tc\ta +Piece Size\t16384 +Piece Count\t1 +File Count\t1 +Files\tfoo "; assert_eq!(have, want); diff --git a/src/table.rs b/src/table.rs index dbd871b..3da3aad 100644 --- a/src/table.rs +++ b/src/table.rs @@ -17,6 +17,10 @@ impl Table { self.rows.push((name, Value::Size(bytes))); } + pub(crate) fn list(&mut self, name: &'static str, list: Vec) { + self.rows.push((name, Value::List(list))); + } + pub(crate) fn tiers( &mut self, name: &'static str, @@ -79,6 +83,16 @@ impl Table { )?; match value { + Value::List(list) => { + for (i, value) in list.iter().enumerate() { + if i == 0 { + padding(out, 2)?; + } else { + padding(out, name_width + 2)?; + } + writeln!(out, "{}", value)?; + } + } Value::Directory { root, files } => { let mut tree = Tree::new(&root); for file in files { @@ -151,6 +165,15 @@ impl Table { for (name, value) in self.rows() { write!(out, "{}\t", name)?; match value { + Value::List(list) => { + for (i, value) in list.iter().enumerate() { + if i > 0 { + write!(out, "\t")?; + } + write!(out, "{}", value)?; + } + writeln!(out)?; + } Value::Directory { root, files } => { for (i, file) in files.iter().enumerate() { if i > 0 { @@ -182,6 +205,7 @@ enum Value { Scalar(String), Tiers(Vec<(String, Vec)>), Size(Bytes), + List(Vec), Directory { root: String, files: Vec }, } @@ -321,6 +345,31 @@ Files Foo tab_delimited(&table, "Foo\tbar\nX\ty\n"); } + #[test] + fn list() { + let mut table = Table::new(); + table.list("Something", vec!["a".into(), "b".into(), "c".into()]); + table.list("Other", vec!["x".into(), "y".into(), "z".into()]); + human_readable( + &table, + "\ +Something a + b + c + Other x + y + z +", + ); + tab_delimited( + &table, + "\ +Something\ta\tb\tc +Other\tx\ty\tz +", + ); + } + #[test] fn tiers_aligned() { let mut table = Table::new(); diff --git a/src/torrent_summary.rs b/src/torrent_summary.rs index 4246acd..df5729a 100644 --- a/src/torrent_summary.rs +++ b/src/torrent_summary.rs @@ -107,20 +107,36 @@ impl TorrentSummary { match &self.metainfo.announce_list { Some(tiers) => { - let mut value = Vec::new(); + if tiers.iter().all(|tier| tier.len() == 1) { + let mut list = Vec::new(); + if !tiers + .iter() + .any(|tier| tier.contains(&self.metainfo.announce)) + { + list.push(self.metainfo.announce.clone()); + } - if !tiers - .iter() - .any(|tier| tier.contains(&self.metainfo.announce)) - { - value.push(("Main".to_owned(), vec![self.metainfo.announce.clone()])); + for tier in tiers { + list.push(tier[0].clone()); + } + + table.list("Trackers", list); + } else { + let mut value = Vec::new(); + + if !tiers + .iter() + .any(|tier| tier.contains(&self.metainfo.announce)) + { + value.push(("Main".to_owned(), vec![self.metainfo.announce.clone()])); + } + + for (i, tier) in tiers.iter().enumerate() { + value.push((format!("Tier {}", i + 1), tier.clone())); + } + + table.tiers("Trackers", value); } - - for (i, tier) in tiers.iter().enumerate() { - value.push((format!("Tier {}", i + 1), tier.clone())); - } - - table.tiers("Trackers", value); } None => table.row("Tracker", &self.metainfo.announce), }