1use std::{fs, path::PathBuf};
4
5use serde_json::Value;
6use spinne_logger::Logger;
7
8#[derive(Debug, PartialEq)]
9pub struct ConfigValues {
10 pub exclude: Option<Vec<String>>,
11 pub include: Option<Vec<String>>,
12}
13
14pub struct Config {
15 pub path: PathBuf,
16}
17
18impl Config {
19 pub fn read(path: PathBuf) -> Option<ConfigValues> {
21 let config = fs::read_to_string(path);
22
23 if config.is_err() {
24 Logger::error("Failed to read config file");
25 return None;
26 }
27
28 match serde_json::from_str::<Value>(&config.unwrap()) {
29 Ok(value) => {
30 let exclude_value = value.get("exclude");
31 let include_value = value.get("include");
32
33 let exclude = match exclude_value {
34 Some(value) => Some(Self::get_array_of_strings(value)),
35 None => None,
36 };
37
38 let include = match include_value {
39 Some(value) => Some(Self::get_array_of_strings(value)),
40 None => None,
41 };
42
43 Some(ConfigValues { exclude, include })
44 }
45 Err(err) => {
46 Logger::error("Failed to parse config file");
47 Logger::error(&err.to_string());
48 return None;
49 }
50 }
51 }
52
53 fn get_array_of_strings(value: &Value) -> Vec<String> {
55 value
56 .as_array()
57 .unwrap_or(&vec![])
58 .iter()
59 .map(|v| v.as_str().unwrap_or("").to_string())
60 .collect::<Vec<String>>()
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use crate::util::test_utils::create_mock_project;
67
68 use super::*;
69
70 #[test]
71 fn test_config_read() {
72 let temp_dir = create_mock_project(&vec![(
73 "spinne.json",
74 r#"{"exclude": ["test.tsx"], "include": ["test.tsx"]}"#,
75 )]);
76 let config = Config::read(temp_dir.path().join("spinne.json"));
77
78 assert_eq!(
79 config,
80 Some(ConfigValues {
81 exclude: Some(vec!["test.tsx".to_string()]),
82 include: Some(vec!["test.tsx".to_string()])
83 })
84 );
85 }
86
87 #[test]
88 fn test_config_read_no_config() {
89 let temp_dir = create_mock_project(&vec![]);
90 let config = Config::read(temp_dir.path().join("spinne.json"));
91
92 assert_eq!(config, None);
93 }
94
95 #[test]
96 fn test_config_read_invalid_config() {
97 let temp_dir = create_mock_project(&vec![("spinne.json", r#"{"]ht["te)}"#)]);
98 let config = Config::read(temp_dir.path().join("spinne.json"));
99
100 assert_eq!(config, None);
101 }
102
103 #[test]
104 fn test_config_without_include() {
105 let temp_dir = create_mock_project(&vec![("spinne.json", r#"{"exclude": ["test.tsx"]}"#)]);
106 let config = Config::read(temp_dir.path().join("spinne.json"));
107
108 assert_eq!(
109 config,
110 Some(ConfigValues {
111 exclude: Some(vec!["test.tsx".to_string()]),
112 include: None
113 })
114 );
115 }
116
117 #[test]
118 fn test_config_without_exclude() {
119 let temp_dir = create_mock_project(&vec![("spinne.json", r#"{"include": ["test.tsx"]}"#)]);
120 let config = Config::read(temp_dir.path().join("spinne.json"));
121
122 assert_eq!(
123 config,
124 Some(ConfigValues {
125 exclude: None,
126 include: Some(vec!["test.tsx".to_string()])
127 })
128 );
129 }
130}