Skip to content

Commit 6153f42

Browse files
committed
fix: add a custom deserializer to TaskDefinition, and fix ForLoopDefinition bug
1 parent 295051a commit 6153f42

File tree

2 files changed

+532
-273
lines changed

2 files changed

+532
-273
lines changed

core/src/lib.rs

Lines changed: 234 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ pub mod models;
44
mod unit_tests {
55

66
use crate::models::duration::*;
7-
use crate::models::workflow::*;
8-
use crate::models::task::*;
97
use crate::models::map::*;
8+
use crate::models::task::*;
9+
use crate::models::workflow::*;
10+
use serde_json::json;
1011

1112
#[test]
1213
fn create_workflow() {
@@ -15,19 +16,43 @@ mod unit_tests {
1516
let version = "1.0.0";
1617
let title = Some("fake-title".to_string());
1718
let summary = Some("fake-summary".to_string());
18-
let document = WorkflowDefinitionMetadata::new(namespace, name, version, title.clone(), summary.clone(), None);
19+
let document = WorkflowDefinitionMetadata::new(
20+
namespace,
21+
name,
22+
version,
23+
title.clone(),
24+
summary.clone(),
25+
None,
26+
);
1927
let mut call_task = CallTaskDefinition::new("http", None, Some(true));
2028
call_task.common.then = Some("continue".to_string());
21-
let do_task = DoTaskDefinition::new(Map::from(vec![("set".to_string(), TaskDefinition::Wait(WaitTaskDefinition::new(OneOfDurationOrIso8601Expression::Duration(Duration::from_milliseconds(200)))))]));
29+
let do_task = DoTaskDefinition::new(Map::from(vec![(
30+
"set".to_string(),
31+
TaskDefinition::Wait(WaitTaskDefinition::new(
32+
OneOfDurationOrIso8601Expression::Duration(Duration::from_milliseconds(200)),
33+
)),
34+
)]));
2235
let mut workflow = WorkflowDefinition::new(document);
2336
workflow.do_ = Map::new();
24-
workflow.do_.add("callTask".to_string(), TaskDefinition::Call(call_task));
25-
workflow.do_.add("doTask".to_string(), TaskDefinition::Do(do_task));
37+
workflow
38+
.do_
39+
.add("callTask".to_string(), TaskDefinition::Call(call_task));
40+
workflow
41+
.do_
42+
.add("doTask".to_string(), TaskDefinition::Do(do_task));
2643
let json_serialization_result = serde_json::to_string_pretty(&workflow);
2744
let yaml_serialization_result = serde_yaml::to_string(&workflow);
28-
assert!(json_serialization_result.is_ok(), "JSON Serialization failed: {:?}", json_serialization_result.err());
29-
assert!(yaml_serialization_result.is_ok(), "YAML Serialization failed: {:?}", yaml_serialization_result.err());
30-
if let Result::Ok(yaml) = yaml_serialization_result{
45+
assert!(
46+
json_serialization_result.is_ok(),
47+
"JSON Serialization failed: {:?}",
48+
json_serialization_result.err()
49+
);
50+
assert!(
51+
yaml_serialization_result.is_ok(),
52+
"YAML Serialization failed: {:?}",
53+
yaml_serialization_result.err()
54+
);
55+
if let Result::Ok(yaml) = yaml_serialization_result {
3156
println!("{}", yaml)
3257
}
3358
assert_eq!(workflow.document.namespace, namespace);
@@ -37,4 +62,203 @@ mod unit_tests {
3762
assert_eq!(workflow.document.summary, summary);
3863
}
3964

40-
}
65+
#[test]
66+
fn test_for_loop_definition_each_field_deserialization() {
67+
// This test verifies that ForLoopDefinition correctly deserializes "each"
68+
let for_loop_json = serde_json::json!({
69+
"each": "item",
70+
"in": ".items"
71+
});
72+
73+
let result: Result<ForLoopDefinition, _> = serde_json::from_value(for_loop_json);
74+
75+
match result {
76+
Ok(for_loop) => {
77+
assert_eq!(for_loop.each, "item", "The 'each' field should be 'item'");
78+
assert_eq!(for_loop.in_, ".items", "The 'in' field should be '.items'");
79+
}
80+
Err(e) => {
81+
panic!(
82+
"Failed to deserialize ForLoopDefinition with 'each' field: {}",
83+
e
84+
);
85+
}
86+
}
87+
}
88+
89+
#[test]
90+
fn test_for_task_deserialization() {
91+
// This is a valid For task - it has a "for" field and a "do" field
92+
let for_task_json = json!({
93+
"for": {
94+
"each": "item",
95+
"in": ".items"
96+
},
97+
"do": [
98+
{
99+
"processItem": {
100+
"call": "processFunction",
101+
"with": {
102+
"item": "${ .item }"
103+
}
104+
}
105+
}
106+
]
107+
});
108+
109+
let result: Result<TaskDefinition, _> = serde_json::from_value(for_task_json.clone());
110+
111+
match result {
112+
Ok(TaskDefinition::For(for_def)) => {
113+
assert_eq!(for_def.for_.each, "item");
114+
assert_eq!(for_def.for_.in_, ".items");
115+
assert_eq!(for_def.do_.entries.len(), 1);
116+
let has_process_item = for_def
117+
.do_
118+
.entries
119+
.iter()
120+
.any(|entry| entry.contains_key("processItem"));
121+
assert!(
122+
has_process_item,
123+
"For task should contain processItem subtask"
124+
);
125+
}
126+
Ok(TaskDefinition::Do(_)) => {
127+
panic!("For task incorrectly deserialized as DoTaskDefinition");
128+
}
129+
Ok(other) => {
130+
panic!("For task deserialized as unexpected variant: {:?}", other);
131+
}
132+
Err(e) => {
133+
panic!("Failed to deserialize For task: {}", e);
134+
}
135+
}
136+
}
137+
138+
#[test]
139+
fn test_do_task_deserialization() {
140+
// This is a valid Do task
141+
let do_task_json = json!({
142+
"do": [
143+
{
144+
"step1": {
145+
"call": "function1"
146+
}
147+
},
148+
{
149+
"step2": {
150+
"call": "function2"
151+
}
152+
}
153+
]
154+
});
155+
156+
let result: Result<TaskDefinition, _> = serde_json::from_value(do_task_json);
157+
158+
match result {
159+
Ok(TaskDefinition::Do(do_def)) => {
160+
assert_eq!(do_def.do_.entries.len(), 2);
161+
let has_step1 = do_def
162+
.do_
163+
.entries
164+
.iter()
165+
.any(|entry| entry.contains_key("step1"));
166+
let has_step2 = do_def
167+
.do_
168+
.entries
169+
.iter()
170+
.any(|entry| entry.contains_key("step2"));
171+
assert!(has_step1, "Do task should contain step1");
172+
assert!(has_step2, "Do task should contain step2");
173+
}
174+
Ok(other) => {
175+
panic!("Do task deserialized as unexpected variant: {:?}", other);
176+
}
177+
Err(e) => {
178+
panic!("Failed to deserialize Do task: {}", e);
179+
}
180+
}
181+
}
182+
183+
#[test]
184+
fn test_for_task_with_while_condition() {
185+
// TestFor task with a while condition
186+
let for_task_json = json!({
187+
"for": {
188+
"each": "user",
189+
"in": ".users",
190+
"at": "index"
191+
},
192+
"while": "${ .index < 10 }",
193+
"do": [
194+
{
195+
"notifyUser": {
196+
"call": "notifyUser",
197+
"with": {
198+
"user": "${ .user }",
199+
"index": "${ .index }"
200+
}
201+
}
202+
}
203+
]
204+
});
205+
206+
let result: Result<TaskDefinition, _> = serde_json::from_value(for_task_json.clone());
207+
208+
match result {
209+
Ok(TaskDefinition::For(for_def)) => {
210+
assert_eq!(for_def.for_.each, "user");
211+
assert_eq!(for_def.for_.in_, ".users");
212+
assert_eq!(for_def.for_.at, Some("index".to_string()));
213+
assert_eq!(for_def.while_, Some("${ .index < 10 }".to_string()));
214+
assert_eq!(for_def.do_.entries.len(), 1);
215+
}
216+
Ok(TaskDefinition::Do(_)) => {
217+
panic!("For task incorrectly deserialized as DoTaskDefinition");
218+
}
219+
Ok(other) => {
220+
panic!("For task deserialized as unexpected variant: {:?}", other);
221+
}
222+
Err(e) => {
223+
panic!("Failed to deserialize For task with while: {}", e);
224+
}
225+
}
226+
}
227+
228+
#[test]
229+
fn test_roundtrip_serialization() {
230+
// Create a ForTaskDefinition programmatically
231+
232+
let for_loop = ForLoopDefinition::new("item", ".collection", None, None);
233+
let mut do_tasks = Map::new();
234+
do_tasks.add(
235+
"task1".to_string(),
236+
TaskDefinition::Call(CallTaskDefinition::new("someFunction", None, None)),
237+
);
238+
239+
let for_task = ForTaskDefinition::new(for_loop, do_tasks, None);
240+
let task_def = TaskDefinition::For(for_task);
241+
242+
// Serialize to JSON
243+
let json_str = serde_json::to_string(&task_def).expect("Failed to serialize");
244+
println!("Serialized: {}", json_str);
245+
246+
// Deserialize back
247+
let deserialized: TaskDefinition =
248+
serde_json::from_str(&json_str).expect("Failed to deserialize");
249+
250+
// Should still be a For task
251+
match deserialized {
252+
TaskDefinition::For(for_def) => {
253+
assert_eq!(for_def.for_.each, "item");
254+
assert_eq!(for_def.for_.in_, ".collection");
255+
}
256+
TaskDefinition::Do(_) => {
257+
panic!("After roundtrip serialization, For task became a Do task");
258+
}
259+
other => {
260+
panic!("Unexpected variant after roundtrip: {:?}", other);
261+
}
262+
}
263+
}
264+
}

0 commit comments

Comments
 (0)