1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
mod utils;

use ignore::Walk;
use serde::Serialize;
use tempfile::{self, tempdir};

use utils::get_dir_name_from_path;

use std::fs::{self, metadata};

#[derive(Debug, Serialize)]
pub struct DiskEntry {
  pub path: String,
  pub is_dir: bool,
  pub name: String,
}

fn is_dir(file_name: String) -> crate::Result<bool> {
  match metadata(file_name) {
    Ok(md) => Result::Ok(md.is_dir()),
    Err(err) => Result::Err(err.into()),
  }
}

pub fn walk_dir(path_copy: String) -> crate::Result<Vec<DiskEntry>> {
  println!("Trying to walk: {}", path_copy.as_str());
  let mut files_and_dirs: Vec<DiskEntry> = vec![];
  for result in Walk::new(path_copy) {
    if let Ok(entry) = result {
      let display_value = entry.path().display();
      let _dir_name = display_value.to_string();

      if let Ok(flag) = is_dir(display_value.to_string()) {
        files_and_dirs.push(DiskEntry {
          path: display_value.to_string(),
          is_dir: flag,
          name: display_value.to_string(),
        });
      }
    }
  }
  Result::Ok(files_and_dirs)
}

pub fn list_dir_contents(dir_path: String) -> crate::Result<Vec<DiskEntry>> {
  let paths = fs::read_dir(dir_path)?;
  let mut dirs: Vec<DiskEntry> = vec![];
  for path in paths {
    let dir_path = path.expect("dirpath error").path();
    let _dir_name = dir_path.display();
    dirs.push(DiskEntry {
      path: format!("{}", _dir_name),
      is_dir: true,
      name: get_dir_name_from_path(_dir_name.to_string()),
    });
  }
  Ok(dirs)
}

pub fn with_temp_dir<F: FnOnce(&tempfile::TempDir) -> ()>(callback: F) -> crate::Result<()> {
  let dir = tempdir()?;
  callback(&dir);
  dir.close()?;
  Ok(())
}

#[cfg(test)]
mod test {
  use super::*;
  use quickcheck_macros::quickcheck;
  use totems::assert_ok;

  // check is dir function by passing in arbitrary strings
  #[quickcheck]
  fn qc_is_dir(f: String) -> bool {
    // is the string runs through is_dir and comes out as an OK result then it must be a DIR.
    if let Ok(_) = is_dir(f.clone()) {
      std::path::PathBuf::from(f).exists()
    } else {
      true
    }
  }

  #[test]
  // check the walk_dir function
  fn check_walk_dir() {
    // define a relative directory string test/
    let dir = String::from("test/");
    // add the files to this directory
    let file_one = format!("{}test.txt", &dir).to_string();
    let file_two = format!("{}test_binary", &dir).to_string();

    // call walk_dir on the directory
    let res = walk_dir(dir.clone());

    // assert that the result is Ok()
    assert_ok!(&res);

    // destruct the OK into a vector of DiskEntry Structs
    if let Ok(vec) = res {
      // assert that the vector length is only 3
      assert_eq!(vec.len(), 3);

      // get the first DiskEntry
      let first = &vec[0];
      // get the second DiskEntry
      let second = &vec[1];
      // get the third DiskEntry
      let third = &vec[2];

      // check the fields for the first DiskEntry
      assert_eq!(first.path, dir);
      assert_eq!(first.is_dir, true);
      assert_eq!(first.name, dir);

      if second.path.contains(".txt") {
        // check the fields for the second DiskEntry
        assert_eq!(second.path, file_one);
        assert_eq!(second.is_dir, false);
        assert_eq!(second.name, file_one);

        // check the fields for the third DiskEntry
        assert_eq!(third.path, file_two);
        assert_eq!(third.is_dir, false);
        assert_eq!(third.name, file_two);
      } else {
        // check the fields for the second DiskEntry
        assert_eq!(second.path, file_two);
        assert_eq!(second.is_dir, false);
        assert_eq!(second.name, file_two);

        // check the fields for the third DiskEntry
        assert_eq!(third.path, file_one);
        assert_eq!(third.is_dir, false);
        assert_eq!(third.name, file_one);
      }
    }
  }

  #[test]
  // check the list_dir_contents function
  fn check_list_dir_contents() {
    // define a relative directory string test/
    let dir = String::from("test/");

    // call list_dir_contents on the dir string
    let res = list_dir_contents(dir);

    // assert that the result is Ok()
    assert_ok!(&res);

    // destruct the vector from the Ok()
    if let Ok(vec) = res {
      // assert the length of the vector is 2
      assert_eq!(vec.len(), 2);

      // get the two DiskEntry structs in this vector
      let first = &vec[0];
      let second = &vec[1];

      if first.path.contains(".txt") {
        // check the fields for the first DiskEntry
        assert_eq!(first.path, "test/test.txt".to_string());
        assert_eq!(first.is_dir, true);
        assert_eq!(first.name, "test.txt".to_string());

        // check the fields for the second DiskEntry
        assert_eq!(second.path, "test/test_binary".to_string());
        assert_eq!(second.is_dir, true);
        assert_eq!(second.name, "test_binary".to_string());
      } else {
        // check the fields for the first DiskEntry
        assert_eq!(second.path, "test/test.txt".to_string());
        assert_eq!(second.is_dir, true);
        assert_eq!(second.name, "test.txt".to_string());

        // check the fields for the second DiskEntry
        assert_eq!(first.path, "test/test_binary".to_string());
        assert_eq!(first.is_dir, true);
        assert_eq!(first.name, "test_binary".to_string());
      }
    }
  }

  #[test]
  // test the with_temp_dir function
  fn check_test_dir() {
    // create a callback closure that takes in a TempDir type and prints it.
    let callback = |td: &tempfile::TempDir| {
      println!("{:?}", td);
    };

    // execute the with_temp_dir function on the callback
    let res = with_temp_dir(callback);

    // assert that the result is an OK type.
    assert_ok!(res);
  }
}