edgeparse_core/api/
config_loader.rs1use std::path::Path;
4
5use crate::api::config::ProcessingConfig;
6use crate::EdgePdfError;
7
8pub fn load_config_from_file(path: &Path) -> Result<ProcessingConfig, EdgePdfError> {
16 let content = std::fs::read_to_string(path)?;
17 parse_config_json(&content)
18}
19
20pub fn parse_config_json(json: &str) -> Result<ProcessingConfig, EdgePdfError> {
25 serde_json::from_str(json)
26 .map_err(|e| EdgePdfError::OutputError(format!("Failed to parse config JSON: {}", e)))
27}
28
29pub fn config_to_json(config: &ProcessingConfig) -> Result<String, EdgePdfError> {
34 serde_json::to_string_pretty(config)
35 .map_err(|e| EdgePdfError::OutputError(format!("Failed to serialize config: {}", e)))
36}
37
38pub fn merge_configs(
43 base: &ProcessingConfig,
44 overlay_json: &str,
45) -> Result<ProcessingConfig, EdgePdfError> {
46 let base_json = serde_json::to_value(base)
47 .map_err(|e| EdgePdfError::OutputError(format!("config serialization error: {}", e)))?;
48 let overlay_val: serde_json::Value = serde_json::from_str(overlay_json)
49 .map_err(|e| EdgePdfError::OutputError(format!("overlay parse error: {}", e)))?;
50
51 let merged = merge_json(base_json, overlay_val);
52 serde_json::from_value(merged)
53 .map_err(|e| EdgePdfError::OutputError(format!("merged config parse error: {}", e)))
54}
55
56fn merge_json(base: serde_json::Value, overlay: serde_json::Value) -> serde_json::Value {
57 use serde_json::Value;
58 match (base, overlay) {
59 (Value::Object(mut base_map), Value::Object(overlay_map)) => {
60 for (key, val) in overlay_map {
61 if val.is_null() {
62 continue;
63 }
64 let entry = base_map.remove(&key).unwrap_or(Value::Null);
65 base_map.insert(key, merge_json(entry, val));
66 }
67 Value::Object(base_map)
68 }
69 (_, overlay) => overlay,
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use crate::api::config::{OutputFormat, ReadingOrder};
77
78 #[test]
79 fn test_parse_default_config() {
80 let config = ProcessingConfig::default();
81 let json = config_to_json(&config).unwrap();
82 let parsed = parse_config_json(&json).unwrap();
83 assert_eq!(parsed.formats, config.formats);
84 assert_eq!(parsed.quiet, config.quiet);
85 }
86
87 #[test]
88 fn test_parse_partial_config() {
89 let base = ProcessingConfig::default();
91 let overlay = r#"{"quiet": true, "sanitize": true}"#;
92 let config = merge_configs(&base, overlay).unwrap();
93 assert!(config.quiet);
94 assert!(config.sanitize);
95 }
96
97 #[test]
98 fn test_merge_configs() {
99 let base = ProcessingConfig::default();
100 let overlay = r#"{"quiet": true, "reading_order": "Off"}"#;
101 let merged = merge_configs(&base, overlay).unwrap();
102 assert!(merged.quiet);
103 assert_eq!(merged.reading_order, ReadingOrder::Off);
104 assert_eq!(merged.formats, vec![OutputFormat::Json]);
106 }
107
108 #[test]
109 fn test_config_roundtrip() {
110 let mut config = ProcessingConfig::default();
111 config.quiet = true;
112 config.sanitize = true;
113 config.pages = Some("1-5".to_string());
114
115 let json = config_to_json(&config).unwrap();
116 let parsed = parse_config_json(&json).unwrap();
117 assert_eq!(parsed.quiet, true);
118 assert_eq!(parsed.sanitize, true);
119 assert_eq!(parsed.pages, Some("1-5".to_string()));
120 }
121
122 #[test]
123 fn test_invalid_json() {
124 let result = parse_config_json("not json");
125 assert!(result.is_err());
126 }
127}