use serde::Deserialize;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum OnErrorStrategy {
#[default]
FailFast,
Continue,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum OutputPersistence {
#[default]
Deferred,
Progressive,
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct LoopConfig {
pub on_error: OnErrorStrategy,
pub output_persistence: OutputPersistence,
}
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct RawLoopParams {
#[serde(default)]
on_error: Option<String>,
#[serde(default)]
output_persistence: Option<String>,
}
pub fn parse_loop_config(params: &serde_json::Map<String, serde_json::Value>) -> LoopConfig {
let raw: RawLoopParams = serde_json::from_value(serde_json::Value::Object(params.clone()))
.unwrap_or(RawLoopParams {
on_error: None,
output_persistence: None,
});
let on_error = match raw.on_error.as_deref() {
Some("continue") => OnErrorStrategy::Continue,
_ => OnErrorStrategy::FailFast,
};
let output_persistence = match raw.output_persistence.as_deref() {
Some("progressive") => OutputPersistence::Progressive,
_ => OutputPersistence::Deferred,
};
LoopConfig {
on_error,
output_persistence,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_params_yields_defaults() {
let params = serde_json::Map::new();
let config = parse_loop_config(¶ms);
assert_eq!(config.on_error, OnErrorStrategy::FailFast);
assert_eq!(config.output_persistence, OutputPersistence::Deferred);
}
#[test]
fn on_error_continue_parsed() {
let mut params = serde_json::Map::new();
params.insert("onError".into(), "continue".into());
let config = parse_loop_config(¶ms);
assert_eq!(config.on_error, OnErrorStrategy::Continue);
}
#[test]
fn on_error_fail_fast_parsed() {
let mut params = serde_json::Map::new();
params.insert("onError".into(), "failFast".into());
let config = parse_loop_config(¶ms);
assert_eq!(config.on_error, OnErrorStrategy::FailFast);
}
#[test]
fn output_persistence_progressive_parsed() {
let mut params = serde_json::Map::new();
params.insert("outputPersistence".into(), "progressive".into());
let config = parse_loop_config(¶ms);
assert_eq!(config.output_persistence, OutputPersistence::Progressive);
}
#[test]
fn output_persistence_deferred_parsed() {
let mut params = serde_json::Map::new();
params.insert("outputPersistence".into(), "deferred".into());
let config = parse_loop_config(¶ms);
assert_eq!(config.output_persistence, OutputPersistence::Deferred);
}
#[test]
fn unknown_on_error_defaults_to_fail_fast() {
let mut params = serde_json::Map::new();
params.insert("onError".into(), "garbage".into());
let config = parse_loop_config(¶ms);
assert_eq!(config.on_error, OnErrorStrategy::FailFast);
}
#[test]
fn unknown_output_persistence_defaults_to_deferred() {
let mut params = serde_json::Map::new();
params.insert("outputPersistence".into(), "garbage".into());
let config = parse_loop_config(¶ms);
assert_eq!(config.output_persistence, OutputPersistence::Deferred);
}
#[test]
fn extra_params_ignored() {
let mut params = serde_json::Map::new();
params.insert("onError".into(), "continue".into());
params.insert("mode".into(), "forEach".into());
params.insert("unrelated".into(), 42.into());
let config = parse_loop_config(¶ms);
assert_eq!(config.on_error, OnErrorStrategy::Continue);
assert_eq!(config.output_persistence, OutputPersistence::Deferred);
}
#[test]
fn both_fields_parsed_together() {
let mut params = serde_json::Map::new();
params.insert("onError".into(), "continue".into());
params.insert("outputPersistence".into(), "progressive".into());
let config = parse_loop_config(¶ms);
assert_eq!(config.on_error, OnErrorStrategy::Continue);
assert_eq!(config.output_persistence, OutputPersistence::Progressive);
}
}