Explorar o código

Generify Table to be used in tests once again

Finally! The benefit of having all the field-rendering code (in details.rs) separate from the value-getting code (in file.rs) is that rendering them can be tested again.
Ben S %!s(int64=10) %!d(string=hai) anos
pai
achega
50442a0bfe
Modificáronse 2 ficheiros con 201 adicións e 10 borrados
  1. 10 4
      src/options.rs
  2. 191 6
      src/output/details.rs

+ 10 - 4
src/options.rs

@@ -81,8 +81,8 @@ impl Options {
         }
 
         let matches = match opts.parse(args) {
-            Ok(m) => m,
-            Err(e) => return Err(Misfire::InvalidOptions(e)),
+            Ok(m)   => m,
+            Err(e)  => return Err(Misfire::InvalidOptions(e)),
         };
 
         if matches.opt_present("help") {
@@ -93,8 +93,8 @@ impl Options {
         }
 
         let sort_field = match matches.opt_str("sort") {
-            Some(word) => try!(SortField::from_word(word)),
-            None => SortField::Name,
+            Some(word)  => try!(SortField::from_word(word)),
+            None        => SortField::default(),
         };
 
         let filter = FileFilter {
@@ -166,6 +166,12 @@ pub enum SortField {
     ModifiedDate, AccessedDate, CreatedDate,
 }
 
+impl Default for SortField {
+    fn default() -> SortField {
+        SortField::Name
+    }
+}
+
 impl SortField {
 
     /// Find which field to use based on a user-supplied word.

+ 191 - 6
src/output/details.rs

@@ -5,7 +5,9 @@ use dir::Dir;
 use file::File;
 use file::fields as f;
 use options::{Columns, FileFilter, RecurseOptions, SizeFormat};
+
 use users::{OSUsers, Users};
+use users::mock::MockUsers;
 
 use super::filename;
 
@@ -29,7 +31,7 @@ use datetime::format::{DateFormat};
 ///
 /// Almost all the heavy lifting is done in a Table object, which handles the
 /// columns for each row.
-#[derive(PartialEq, Debug, Copy, Clone)]
+#[derive(PartialEq, Debug, Copy, Clone, Default)]
 pub struct Details {
 
     /// A Columns object that says which columns should be included in the
@@ -67,7 +69,7 @@ impl Details {
 
     /// Adds files to the table - recursively, if the `recurse` option
     /// is present.
-    fn add_files_to_table(&self, table: &mut Table, src: &[File], depth: usize) {
+    fn add_files_to_table<U: Users>(&self, table: &mut Table<U>, src: &[File], depth: usize) {
         for (index, file) in src.iter().enumerate() {
             table.add_file(file, depth, index == src.len() - 1);
 
@@ -120,22 +122,36 @@ struct Row {
 
 /// A **Table** object gets built up by the view as it lists files and
 /// directories.
-struct Table {
+pub struct Table<U> {
     columns:  Vec<Column>,
     rows:     Vec<Row>,
 
     time:         locale::Time,
     numeric:      locale::Numeric,
-    users:        OSUsers,
+    users:        U,
     colours:      Colours,
     current_year: i64,
 }
 
-impl Table {
+impl Default for Table<MockUsers> {
+    fn default() -> Table<MockUsers> {
+        Table {
+            columns: Columns::default().for_dir(None),
+            rows:    Vec::new(),
+            time:    locale::Time::english(),
+            numeric: locale::Numeric::english(),
+            users:   MockUsers::with_current_uid(0),
+            colours: Colours::default(),
+            current_year: 1234,
+        }
+    }
+}
+
+impl Table<OSUsers> {
 
     /// Create a new, empty Table object, setting the caching fields to their
     /// empty states.
-    fn with_options(colours: Colours, columns: Vec<Column>) -> Table {
+    fn with_options(colours: Colours, columns: Vec<Column>) -> Table<OSUsers> {
         Table {
             columns: columns,
             rows:    Vec::new(),
@@ -147,6 +163,9 @@ impl Table {
             current_year: LocalDateTime::now().year(),
         }
     }
+}
+
+impl<U> Table<U> where U: Users {
 
     /// Add a dummy "header" row to the table, which contains the names of all
     /// the columns, underlined. This has dummy data for the cases that aren't
@@ -429,3 +448,169 @@ impl TreePart {
         }
     }
 }
+
+
+#[cfg(test)]
+pub mod test {
+    pub use super::Table;
+    pub use file::File;
+    pub use file::fields as f;
+
+    pub use column::{Cell, Column};
+
+    pub use users::{User, Group, uid_t, gid_t};
+    pub use users::mock::MockUsers;
+
+    pub use ansi_term::Style::Plain;
+    pub use ansi_term::Colour::*;
+
+    pub fn newser(uid: uid_t, name: &str, group: gid_t) -> User {
+        User {
+            uid: uid,
+            name: name.to_string(),
+            primary_group: group,
+            home_dir: String::new(),
+            shell: String::new(),
+        }
+    }
+
+    // These tests create a new, default Table object, then fill in the
+    // expected style in a certain way. This means we can check that the
+    // right style is being used, as otherwise, it would just be `Plain`.
+    //
+    // Doing things with fields is way easier than having to fake the entire
+    // Metadata struct, which is what I was doing before!
+
+    mod users {
+        use super::*;
+
+        #[test]
+        fn named() {
+            let mut table = Table::default();
+            table.colours.users.user_you = Red.bold();
+
+            let mut users = MockUsers::with_current_uid(1000);
+            users.add_user(newser(1000, "enoch", 100));
+            table.users = users;
+
+            let user = f::User(1000);
+            let expected = Cell::paint(Red.bold(), "enoch");
+            assert_eq!(expected, table.render_user(user))
+        }
+
+        #[test]
+        fn unnamed() {
+            let mut table = Table::default();
+            table.colours.users.user_you = Cyan.bold();
+
+            let users = MockUsers::with_current_uid(1000);
+            table.users = users;
+
+            let user = f::User(1000);
+            let expected = Cell::paint(Cyan.bold(), "1000");
+            assert_eq!(expected, table.render_user(user));
+        }
+
+        #[test]
+        fn different_named() {
+            let mut table = Table::default();
+            table.colours.users.user_someone_else = Green.bold();
+            table.users.add_user(newser(1000, "enoch", 100));
+
+            let user = f::User(1000);
+            let expected = Cell::paint(Green.bold(), "enoch");
+            assert_eq!(expected, table.render_user(user));
+        }
+
+        #[test]
+        fn different_unnamed() {
+            let mut table = Table::default();
+            table.colours.users.user_someone_else = Red.normal();
+
+            let user = f::User(1000);
+            let expected = Cell::paint(Red.normal(), "1000");
+            assert_eq!(expected, table.render_user(user));
+        }
+
+        #[test]
+        fn overflow() {
+            let mut table = Table::default();
+            table.colours.users.user_someone_else = Blue.underline();
+
+            let user = f::User(2_147_483_648);
+            let expected = Cell::paint(Blue.underline(), "2147483648");
+            assert_eq!(expected, table.render_user(user));
+        }
+    }
+
+    mod groups {
+        use super::*;
+
+        #[test]
+        fn named() {
+            let mut table = Table::default();
+            table.colours.users.group_not_yours = Fixed(101).normal();
+
+            let mut users = MockUsers::with_current_uid(1000);
+            users.add_group(Group { gid: 100, name: "folk".to_string(), members: vec![] });
+            table.users = users;
+
+            let group = f::Group(100);
+            let expected = Cell::paint(Fixed(101).normal(), "folk");
+            assert_eq!(expected, table.render_group(group))
+        }
+
+        #[test]
+        fn unnamed() {
+            let mut table = Table::default();
+            table.colours.users.group_not_yours = Fixed(87).normal();
+
+            let users = MockUsers::with_current_uid(1000);
+            table.users = users;
+
+            let group = f::Group(100);
+            let expected = Cell::paint(Fixed(87).normal(), "100");
+            assert_eq!(expected, table.render_group(group));
+        }
+
+        #[test]
+        fn primary() {
+            let mut table = Table::default();
+            table.colours.users.group_yours = Fixed(64).normal();
+
+            let mut users = MockUsers::with_current_uid(2);
+            users.add_user(newser(2, "eve", 100));
+            users.add_group(Group { gid: 100, name: "folk".to_string(), members: vec![] });
+            table.users = users;
+
+            let group = f::Group(100);
+            let expected = Cell::paint(Fixed(64).normal(), "folk");
+            assert_eq!(expected, table.render_group(group))
+        }
+
+        #[test]
+        fn secondary() {
+            let mut table = Table::default();
+            table.colours.users.group_yours = Fixed(31).normal();
+
+            let mut users = MockUsers::with_current_uid(2);
+            users.add_user(newser(2, "eve", 666));
+            users.add_group(Group { gid: 100, name: "folk".to_string(), members: vec![ "eve".to_string() ] });
+            table.users = users;
+
+            let group = f::Group(100);
+            let expected = Cell::paint(Fixed(31).normal(), "folk");
+            assert_eq!(expected, table.render_group(group))
+        }
+
+        #[test]
+        fn overflow() {
+            let mut table = Table::default();
+            table.colours.users.group_not_yours = Blue.underline();
+
+            let group = f::Group(2_147_483_648);
+            let expected = Cell::paint(Blue.underline(), "2147483648");
+            assert_eq!(expected, table.render_group(group));
+        }
+    }
+}