keydata/
section.rs

1use std::collections::HashMap;
2/// A Section to hold keynote file entries (key-value pairs)
3pub struct Section {
4    /// name of the Section
5    pub name : String,
6    /// hashmap to hold key value pairs that make up entries
7    pub data : HashMap<String, String>
8}
9
10impl Section {
11    /// Returns a Section with the name given
12    ///
13    /// # Arguments
14    ///
15    /// * `name` - section name as string slice
16    ///
17    /// # Examples    ///
18    /// ```
19    /// use keydata::Section; 
20    /// let s = Section::new("test_section");
21    /// assert_eq!(s.name, "test_section");
22    /// assert_eq!(s.data.len(), 0);
23    /// ```
24    pub fn new(name : &str) -> Section {
25        Section {
26            name: name.to_string(),
27            data : HashMap::new()
28        }
29    }
30
31    /// Formats a string into the form it appears as in the data file
32    ///
33    /// # Arguments
34    ///
35    /// * `section_name` - name of section to format as string slice
36    ///
37    /// # Examples    ///
38    /// ```
39    /// use keydata::Section; 
40    /// let s = Section::build_section_string("test_section");
41    /// assert_eq!(s, "<test_section>\n"); 
42    /// ```
43    pub fn build_section_string(section_name: &str) -> String {
44        let mut header_string = String::new();
45        header_string.push('<');
46        header_string.push_str(section_name);
47        header_string.push_str(">\n");
48
49        header_string
50    } 
51    
52    /// Returns name of a section from formatted section string. None if line is not valid section string;
53    ///
54    /// # Arguments
55    ///
56    /// * `line` - string slice containing section string
57    ///
58    /// # Examples    ///
59    /// ```
60    /// use keydata::Section; 
61    /// let line = "<test_section>\n";
62    /// let sn = Section::get_section_name_from_string(line);
63    /// assert!(sn.is_some());
64    /// assert_eq!(sn.unwrap(), "test_section"); 
65    /// ```
66    pub fn get_section_name_from_string(line : &str) -> Option<&str> {
67        if !line.starts_with("<") || !line.contains(">") || line.contains("\t") {  // not a valid section name
68            return None
69        }
70        
71        let chars_to_subtract = if line.ends_with("\n") {   2   } else {    1   };
72
73        // len - 2 excludes the newline and the '>'
74        Some(&line[1..line.len()-chars_to_subtract])
75    } 
76
77    /// Adds a key-value pair entry to the Sections data
78    ///
79    /// # Arguments
80    ///
81    /// * `key` - entry key as string slice
82    /// * `value` - entry value as string slice
83    ///
84    /// # Examples    ///
85    /// ```
86    /// use keydata::Section; 
87    /// let mut s = Section::new("test_section");
88    /// assert_eq!(s.data.len(), 0);
89    /// 
90    /// s.add_entry("theKey", "theValue");
91    /// assert_eq!(s.data.len(), 1);
92    /// assert_eq!(s.data.get("theKey").unwrap(), "theValue"); 
93    /// ```
94    pub fn add_entry(&mut self, key: &str, value: &str) {
95        self.data.insert(key.to_string(), value.to_string());
96    }
97}
98
99#[cfg(test)]
100mod tests {            
101    use super::*;
102
103    #[test]
104    fn new_success() {
105        let name = "section_name";
106        
107        let section = Section::new(name);
108        
109        assert_eq!(section.name, name);
110        assert!(section.data.len() == 0); 
111    }
112
113    #[test]
114    fn build_section_string_success() {
115        let result = Section::build_section_string("test");
116        assert_eq!(result, "<test>\n");
117    }
118
119    #[test]
120    fn get_section_name_from_string_success() {       
121        let result = Section::get_section_name_from_string("<test_section>\n");
122        assert!(result.is_some());
123        assert_eq!(result.unwrap(), "test_section");        
124    }
125
126    #[test]
127    fn get_section_name_from_string_no_newline_expect_none() {
128        let result = Section::get_section_name_from_string("<test_section>");
129        assert!(result.is_some());
130        assert_eq!(result.unwrap(), "test_section");
131    }
132
133    #[test]
134    fn get_section_name_from_string_invalid_start_expect_none() {
135        let result = Section::get_section_name_from_string("test_section>");
136        assert!(result.is_none());
137    }
138
139    #[test]
140    fn get_section_name_from_string_missing_piece_expect_none() {
141        let result = Section::get_section_name_from_string("<test_section\n");
142        assert!(result.is_none());
143    }
144
145    #[test]
146    fn add_entry_success() {
147        let mut section = Section::new("test_section");
148        assert!(section.data.len() == 0);
149
150        section.add_entry("test_key", "test_value");
151
152        assert!(section.data.len() == 1);
153        assert_eq!(section.data.get("test_key").unwrap(), "test_value");
154    }
155}