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
#![crate_name = "fileman_rs"]
//! A high-performance file management system for working with large quantities of files written in Rust.

// declare cargo crates
use std::io;

// declare local modules
mod organize;
mod tools;

pub trait RunTask {
    /// task definition that allows Config to run a task outlined in a task module
    ///
    /// # Arguments
    ///
    /// `&self` - a reference to Config enum
    fn run_task(&self) -> Result<(), io::Error>;
}

#[derive(Debug, PartialEq, Eq)]
pub enum Config {
    /// configuration enum, all tasks are given their own variant
    // variant to run the organize task
    Organize(organize::OrganizeTask),
}

impl Config {
    /// Config enum constructor
    ///
    /// # Arguments
    ///
    /// `args` - an iterator containing Strings to be used as arguments
    ///
    /// # Errors
    ///
    /// - no task specified
    /// - provided task does not match any defined task
    /// - error propagated upward from subsequent function calls
    pub fn new(mut args: impl Iterator<Item = String>) -> Result<Config, &'static str> {
        //skips the path to the compiled file (first argument passed in)
        args.next();

        // errors if there is no task specified
        let task = match args.next() {
            Some(arg) => arg,
            None => return Err("no task specified"),
        };

        // match an all lowercase task to a set of predefined tasks
        match task.to_lowercase().as_str() {
            "organize" => {
                // ensures OrganizeTask created successfully, otherwise propagates error
                let organize_task = organize::OrganizeTask::new(args)?;

                Ok(Self::Organize(organize_task))
            }
            // errors if desired task is not defined
            _ => return Err("provided task did not match any defined tasks"),
        }
    }
}

/// RunTask trait allows for all tasks to be run from main.rs
impl RunTask for Config {
    /// run_task() matches against Config and runs the corresponding method Variant(task) => task.run_task()
    /// 
    /// # Arguments
    /// 
    /// `&self` reference to Config enum
    /// 
    /// # Errors
    /// 
    /// - if Variant(task) => task.run_task() errors
    fn run_task(&self) -> Result<(), io::Error> {
        match self {
            Config::Organize(task) => task.run_task(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    /// verifies Config::new() works correctly with valid arguments passed in
    ///
    /// # Arguments
    ///
    /// None
    ///
    /// # Errors
    ///
    /// - Config::new() doesnt error if args does not contain a task
    #[test]
    fn config_new_organize_with_valid_args() {
        // args iterator
        let args_1 = [String::from("./src"), String::from("./src/organize")].into_iter();

        let organize_task = organize::OrganizeTask::new(args_1).unwrap();

        // args iterator
        let args_2 = [
            String::from("foo"),
            String::from("organize"),
            String::from("./src"),
            String::from("./src/organize"),
        ]
        .into_iter();

        assert_eq!(Config::new(args_2), Ok(Config::Organize(organize_task)))
    }

    /// verifies Config::new() errors if args does contain a task
    ///
    /// # Arguments
    ///
    /// None
    ///
    /// # Errors
    ///
    /// - Config::new() doesnt error if args does not contain a task
    #[test]
    fn config_new_no_task() {
        // args iterator
        let args = [String::from("foo")].into_iter();

        assert!(Config::new(args).is_err());
    }

    /// verifies Config::new() errors if an invalid task is requested
    ///
    /// # Arguments
    ///
    /// None
    ///
    /// # Errors
    ///
    /// - Config::new() doesnt error if an undefined task is requested
    #[test]
    fn config_new_invalid_task() {
        // args iterator
        let args = [String::from("foo"), String::from("bar")].into_iter();
        assert!(Config::new(args).is_err());
    }
}