1use dyn_clone::{DynClone, clone_trait_object};
2use erased_serde::serialize_trait_object;
3use indexmap::IndexMap;
4use serde::Serialize;
5
6mod types;
7pub use types::*;
8
9#[derive(Default, Debug, Clone, PartialEq)]
10pub struct Inventory {
11 pub name: String,
12 pub root: InventoryRoot,
13}
14
15impl Inventory {
16 pub fn dump_json(&self) -> serde_json::Result<String> {
18 serde_json::to_string(&self.root)
19 }
20}
21
22#[derive(Default, Debug, Clone, PartialEq, Serialize)]
23pub struct InventoryRoot {
24 pub all: InventoryChild,
25}
26
27#[derive(Default, Debug, Clone, PartialEq, Serialize)]
28pub struct InventoryChild {
29 #[serde(skip_serializing_if = "OptU::is_unset")]
30 pub hosts: OptU<InventoryHosts>,
31 #[serde(skip_serializing_if = "OptU::is_unset")]
32 pub children: OptU<IndexMap<String, InventoryChild>>,
33 #[serde(skip_serializing_if = "OptU::is_unset")]
34 pub vars: OptU<InventoryVars>,
35}
36
37pub type InventoryHosts = IndexMap<String, Option<InventoryVars>>;
38pub type InventoryVars = IndexMap<String, serde_json::Value>;
39
40#[derive(Clone, Debug)]
41pub struct Playbook {
42 pub name: String,
45 pub plays: Vec<Play>,
46}
47
48#[derive(Clone, Debug, PartialEq, Default, Serialize)]
59#[serde(untagged)]
60pub enum OptU<T: Serialize> {
61 Some(T),
62 #[default]
63 Unset,
64}
65
66impl<T: Serialize> OptU<T> {
68 pub fn is_unset(&self) -> bool {
69 matches!(self, OptU::Unset)
70 }
71}
72
73#[derive(Serialize, Clone, Debug)]
76pub struct Play {
77 pub name: String,
79 pub hosts: StringOrVecString,
81 #[serde(flatten)]
82 pub options: PlayOptions,
83 pub tasks: Vec<Task>,
85}
86
87#[derive(Serialize, Default, Clone, Debug)]
89pub struct PlayOptions {
90 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
92 pub any_errors_fatal: OptU<BoolOrString>,
93 #[serde(
96 rename = "become",
97 default = "OptU::default",
98 skip_serializing_if = "OptU::is_unset"
99 )]
100 pub become_: OptU<BoolOrString>,
101 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
103 pub become_exe: OptU<String>,
104 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
106 pub become_flags: OptU<String>,
107 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
109 pub become_method: OptU<String>,
110 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
112 pub become_user: OptU<String>,
113 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
115 pub check_mode: OptU<BoolOrString>,
116 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
118 pub collections: OptU<Vec<String>>,
119 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
121 pub connection: OptU<String>,
122 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
124 pub debugger: OptU<BoolOrString>,
125 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
127 pub diff: OptU<BoolOrString>,
128 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
133 pub environment: OptU<IndexMap<String, String>>,
134 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
136 pub fact_path: OptU<String>,
137 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
140 pub force_handlers: OptU<BoolOrString>,
141 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
143 pub gather_facts: OptU<BoolOrString>,
144 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
146 pub gather_subset: OptU<Vec<String>>,
147 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
149 pub gather_timeout: OptU<IntOrString>,
150 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
154 pub handlers: OptU<Vec<Task>>,
155 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
157 pub ignore_errors: OptU<BoolOrString>,
158 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
161 pub ignore_unreachable: OptU<BoolOrString>,
162 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
165 pub max_fail_percentage: OptU<IntOrString>,
166 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
168 pub module_defaults: OptU<IndexMap<String, serde_json::Value>>,
169 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
171 pub no_log: OptU<BoolOrString>,
172 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
175 pub order: OptU<String>,
176 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
178 pub port: OptU<IntOrString>,
179 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
181 pub post_tasks: OptU<Vec<Task>>,
182 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
184 pub pre_tasks: OptU<Vec<Task>>,
185 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
187 pub remote_user: OptU<String>,
188 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
190 pub roles: OptU<Vec<String>>,
191 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
194 pub run_once: OptU<BoolOrString>,
195 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
197 pub serial: OptU<IntOrString>,
198 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
200 pub strategy: OptU<String>,
201 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
203 pub tags: OptU<Vec<String>>,
204 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
206 pub throttle: OptU<IntOrString>,
207 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
209 pub timeout: OptU<IntOrString>,
210 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
212 pub vars: OptU<IndexMap<String, serde_json::Value>>,
213 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
215 pub vars_files: OptU<Vec<String>>,
216 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
218 pub vars_prompt: OptU<Vec<String>>,
219}
220
221#[derive(Serialize, Clone, Debug)]
222pub struct Task {
223 pub name: String,
225 #[serde(flatten)]
226 pub options: TaskOptions,
227 #[serde(flatten)]
228 pub command: Box<dyn TaskModule>,
229}
230
231pub trait TaskModule: erased_serde::Serialize + DynClone + std::fmt::Debug + Send + Sync {}
247
248serialize_trait_object!(TaskModule);
249clone_trait_object!(TaskModule);
250
251#[derive(Serialize, Default, Clone, Debug, PartialEq)]
253pub struct TaskOptions {
254 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
256 pub action: OptU<String>,
257 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
259 pub any_errors_fatal: OptU<BoolOrString>,
260 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
262 pub args: OptU<IndexMap<String, serde_json::Value>>,
263 #[serde(
265 rename = "async",
266 default = "OptU::default",
267 skip_serializing_if = "OptU::is_unset"
268 )]
269 pub async_: OptU<IntOrString>,
270 #[serde(
273 rename = "become",
274 default = "OptU::default",
275 skip_serializing_if = "OptU::is_unset"
276 )]
277 pub become_: OptU<BoolOrString>,
278 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
280 pub become_exe: OptU<String>,
281 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
283 pub become_flags: OptU<String>,
284 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
286 pub become_method: OptU<String>,
287 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
289 pub become_user: OptU<String>,
290 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
295 pub changed_when: OptU<BoolOrStringOrVecString>,
296 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
298 pub check_mode: OptU<BoolOrString>,
299 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
301 pub collections: OptU<Vec<String>>,
302 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
304 pub connection: OptU<String>,
305 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
307 pub debugger: OptU<BoolOrString>,
308 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
312 pub delay: OptU<IntOrString>,
313 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
317 pub delegate_facts: OptU<BoolOrString>,
318 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
321 pub delegate_to: OptU<String>,
322
323 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
325 pub diff: OptU<BoolOrString>,
326
327 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
332 pub environment: OptU<IndexMap<String, String>>,
333 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
335 pub failed_when: OptU<BoolOrStringOrVecString>,
336
337 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
339 pub ignore_errors: OptU<BoolOrString>,
340
341 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
344 pub ignore_unreachable: OptU<BoolOrString>,
345
346 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
348 pub local_action: OptU<String>,
349 #[serde(
351 rename = "loop",
352 default = "OptU::default",
353 skip_serializing_if = "OptU::is_unset"
354 )]
355 pub loop_: OptU<StringOrVec>,
356
357 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
359 pub loop_control: OptU<IndexMap<String, serde_json::Value>>,
360
361 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
363 pub module_defaults: OptU<IndexMap<String, serde_json::Value>>,
364
365 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
367 pub no_log: OptU<BoolOrString>,
368 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
370 pub notify: OptU<Vec<String>>,
371
372 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
374 pub poll: OptU<IntOrString>,
375
376 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
378 pub port: OptU<IntOrString>,
379
380 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
382 pub register: OptU<String>,
383
384 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
386 pub remote_user: OptU<String>,
387
388 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
390 pub retries: OptU<IntOrString>,
391 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
394 pub run_once: OptU<BoolOrString>,
395
396 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
398 pub tags: OptU<Vec<String>>,
399
400 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
404 pub throttle: OptU<IntOrString>,
405
406 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
409 pub timeout: OptU<IntOrString>,
410
411 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
413 pub until: OptU<String>,
414
415 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
417 pub vars: OptU<IndexMap<String, serde_json::Value>>,
418
419 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
421 pub when: OptU<BoolOrStringOrVecString>,
422 }
426
427#[cfg(test)]
428mod tests {
429 use super::*;
430
431 #[derive(Serialize, Clone, Debug, PartialEq)]
432 struct SampleTaskModule {
433 x1: String,
434 }
435
436 impl TaskModule for SampleTaskModule {}
437
438 #[test]
439 fn test_play_minimum() {
440 assert_eq!(
441 serde_json::to_string(&Play {
442 name: "play1".to_string(),
443 hosts: vec!["host1".to_string()].into(),
444 tasks: vec![Task {
445 name: "task1".to_string(),
446 options: TaskOptions::default(),
447 command: Box::new(SampleTaskModule {
448 x1: "x1".to_string(),
449 }),
450 }],
451 options: PlayOptions::default(),
452 })
453 .expect("failed to serialize"),
454 r#"{"name":"play1","hosts":["host1"],"tasks":[{"name":"task1","x1":"x1"}]}"#
455 );
456 }
457
458 #[test]
459 fn test_play_with_all_fields() {
460 assert_eq!(
461 serde_json::to_string(&Play {
462 name: "play1".to_string(),
463 hosts: vec!["host1".to_string()].into(),
464 tasks: vec![Task {
465 name: "task1".to_string(),
466 options: TaskOptions::default(),
467 command: Box::new(SampleTaskModule {
468 x1: "x1".to_string(),
469 }),
470 }],
471 options: PlayOptions {
472 any_errors_fatal: OptU::Some(true.into()),
473 become_: OptU::Some(true.into()),
474 become_exe: OptU::Some("become_exe".to_string()),
475 become_flags: OptU::Some("become_flags".to_string()),
476 become_method: OptU::Some("become_method".to_string()),
477 become_user: OptU::Some("become_user".to_string()),
478 check_mode: OptU::Some(true.into()),
479 collections: OptU::Some(vec!["collection1".to_string()]),
480 connection: OptU::Some("connection1".to_string()),
481 debugger: OptU::Some(true.into()),
482 diff: OptU::Some(true.into()),
483 environment: OptU::Some(IndexMap::from([(
484 "env1".to_string(),
485 "value1".to_string()
486 )])),
487 fact_path: OptU::Some("fact_path".to_string()),
488 force_handlers: OptU::Some(true.into()),
489 gather_facts: OptU::Some(true.into()),
490 gather_subset: OptU::Some(vec!["gather_subset1".to_string()]),
491 gather_timeout: OptU::Some(10.into()),
492 handlers: OptU::Some(vec![Task {
493 name: "handler1".to_string(),
494 options: TaskOptions::default(),
495 command: Box::new(SampleTaskModule {
496 x1: "x1".to_string(),
497 }),
498 }]),
499 ignore_errors: OptU::Some(true.into()),
500 ignore_unreachable: OptU::Some(true.into()),
501 max_fail_percentage: OptU::Some(10.into()),
502 module_defaults: OptU::Some(IndexMap::from([(
503 "module1".to_string(),
504 serde_json::Value::String("value1".to_string())
505 )])),
506 no_log: OptU::Some(true.into()),
507 order: OptU::Some("order".to_string()),
508 port: OptU::Some(10.into()),
509 post_tasks: OptU::Some(vec![Task {
510 name: "post_task1".to_string(),
511 options: TaskOptions::default(),
512 command: Box::new(SampleTaskModule {
513 x1: "x1".to_string(),
514 }),
515 }]),
516 pre_tasks: OptU::Some(vec![Task {
517 name: "pre_task1".to_string(),
518 options: TaskOptions::default(),
519 command: Box::new(SampleTaskModule {
520 x1: "x1".to_string(),
521 }),
522 }]),
523 remote_user: OptU::Some("remote_user".to_string()),
524 roles: OptU::Some(vec!["role1".to_string()]),
525 run_once: OptU::Some(true.into()),
526 serial: OptU::Some(10.into()),
527 strategy: OptU::Some("strategy".to_string()),
528 tags: OptU::Some(vec!["tag1".to_string()]),
529 throttle: OptU::Some(10.into()),
530 timeout: OptU::Some(10.into()),
531 vars: OptU::Some(IndexMap::from([(
532 "var1".to_string(),
533 serde_json::Value::String("value1".to_string())
534 )])),
535 vars_files: OptU::Some(vec!["vars_file1".to_string()]),
536 vars_prompt: OptU::Some(vec!["vars_prompt1".to_string()]),
537 }
538 })
539 .expect("failed to serialize"),
540 String::new()
541 + "{"
542 + r#""name":"play1","#
543 + r#""hosts":["host1"],"#
544 + r#""any_errors_fatal":true,"#
545 + r#""become":true,"#
546 + r#""become_exe":"become_exe","#
547 + r#""become_flags":"become_flags","#
548 + r#""become_method":"become_method","#
549 + r#""become_user":"become_user","#
550 + r#""check_mode":true,"#
551 + r#""collections":["collection1"],"#
552 + r#""connection":"connection1","#
553 + r#""debugger":true,"#
554 + r#""diff":true,"#
555 + r#""environment":{"env1":"value1"},"#
556 + r#""fact_path":"fact_path","#
557 + r#""force_handlers":true,"#
558 + r#""gather_facts":true,"#
559 + r#""gather_subset":["gather_subset1"],"#
560 + r#""gather_timeout":10,"#
561 + r#""handlers":[{"name":"handler1","x1":"x1"}],"#
562 + r#""ignore_errors":true,"#
563 + r#""ignore_unreachable":true,"#
564 + r#""max_fail_percentage":10,"#
565 + r#""module_defaults":{"module1":"value1"},"#
566 + r#""no_log":true,"#
567 + r#""order":"order","#
568 + r#""port":10,"#
569 + r#""post_tasks":[{"name":"post_task1","x1":"x1"}],"#
570 + r#""pre_tasks":[{"name":"pre_task1","x1":"x1"}],"#
571 + r#""remote_user":"remote_user","#
572 + r#""roles":["role1"],"#
573 + r#""run_once":true,"#
574 + r#""serial":10,"#
575 + r#""strategy":"strategy","#
576 + r#""tags":["tag1"],"#
577 + r#""throttle":10,"#
578 + r#""timeout":10,"#
579 + r#""vars":{"var1":"value1"},"#
580 + r#""vars_files":["vars_file1"],"#
581 + r#""vars_prompt":["vars_prompt1"],"#
582 + r#""tasks":[{"name":"task1","x1":"x1"}]"#
583 + r#"}"#
584 );
585 }
586
587 #[test]
588 fn test_task_options_with_all_fields() {
590 assert_eq!(
591 serde_json::to_string(&TaskOptions {
592 action: OptU::Some("action1".to_string()),
593 any_errors_fatal: OptU::Some(true.into()),
594 args: OptU::Some(IndexMap::from([(
595 "arg1".to_string(),
596 serde_json::Value::String("value1".to_string())
597 )])),
598 async_: OptU::Some(10.into()),
599 become_: OptU::Some(true.into()),
600 become_exe: OptU::Some("become_exe".to_string()),
601 become_flags: OptU::Some("become_flags".to_string()),
602 become_method: OptU::Some("become_method".to_string()),
603 become_user: OptU::Some("become_user".to_string()),
604 changed_when: OptU::Some("changed_when".to_string().into()),
605 check_mode: OptU::Some(true.into()),
606 collections: OptU::Some(vec!["collection1".to_string()]),
607 connection: OptU::Some("connection1".to_string()),
608 debugger: OptU::Some(true.into()),
609 delay: OptU::Some(
610 "{{ 10 | ansible.builtin.random(seed=inventory_hostname) }}".into(),
613 ),
614 delegate_facts: OptU::Some(true.into()),
615 delegate_to: OptU::Some("delegate_to".to_string()),
616 diff: OptU::Some(true.into()),
617 environment: OptU::Some(IndexMap::from([(
618 "env1".to_string(),
619 "value1".to_string()
620 )])),
621 failed_when: OptU::Some("failed_when".to_string().into()),
622 ignore_errors: OptU::Some(true.into()),
623 ignore_unreachable: OptU::Some(true.into()),
624 local_action: OptU::Some("local_action".to_string()),
625 loop_: OptU::Some(vec!["loop1".into()].into()),
626 loop_control: OptU::Some(IndexMap::from([(
627 "loop_control1".to_string(),
628 serde_json::Value::String("value1".to_string())
629 )])),
630 module_defaults: OptU::Some(IndexMap::from([(
631 "module1".to_string(),
632 serde_json::Value::String("value1".to_string())
633 )])),
634 no_log: OptU::Some(true.into()),
635 notify: OptU::Some(vec!["notify1".to_string()]),
636 poll: OptU::Some(10.into()),
637 port: OptU::Some(10.into()),
638 register: OptU::Some("register".to_string()),
639 remote_user: OptU::Some("remote_user".to_string()),
640 retries: OptU::Some(10.into()),
641 run_once: OptU::Some(true.into()),
642 tags: OptU::Some(vec!["tag1".to_string()]),
643 throttle: OptU::Some(10.into()),
644 timeout: OptU::Some(10.into()),
645 until: OptU::Some("until".to_string()),
646 vars: OptU::Some(IndexMap::from([(
647 "var1".to_string(),
648 serde_json::Value::String("value1".to_string())
649 )])),
650 when: OptU::Some("when".to_string().into()),
651 })
652 .expect("failed to serialize"),
653 String::new()
654 + r#"{""#
655 + r#"action":"action1","#
656 + r#""any_errors_fatal":true,"#
657 + r#""args":{"arg1":"value1"},"#
658 + r#""async":10,"#
659 + r#""become":true,"#
660 + r#""become_exe":"become_exe","#
661 + r#""become_flags":"become_flags","#
662 + r#""become_method":"become_method","#
663 + r#""become_user":"become_user","#
664 + r#""changed_when":"changed_when","#
665 + r#""check_mode":true,"#
666 + r#""collections":["collection1"],"#
667 + r#""connection":"connection1","#
668 + r#""debugger":true,"#
669 + r#""delay":"{{ 10 | ansible.builtin.random(seed=inventory_hostname) }}","#
670 + r#""delegate_facts":true,"#
671 + r#""delegate_to":"delegate_to","#
672 + r#""diff":true,"#
673 + r#""environment":{"env1":"value1"},"#
674 + r#""failed_when":"failed_when","#
675 + r#""ignore_errors":true,"#
676 + r#""ignore_unreachable":true,"#
677 + r#""local_action":"local_action","#
678 + r#""loop":["loop1"],"#
679 + r#""loop_control":{"loop_control1":"value1"},"#
680 + r#""module_defaults":{"module1":"value1"},"#
681 + r#""no_log":true,"#
682 + r#""notify":["notify1"],"#
683 + r#""poll":10,"#
684 + r#""port":10,"#
685 + r#""register":"register","#
686 + r#""remote_user":"remote_user","#
687 + r#""retries":10,"#
688 + r#""run_once":true,"#
689 + r#""tags":["tag1"],"#
690 + r#""throttle":10,"#
691 + r#""timeout":10,"#
692 + r#""until":"until","#
693 + r#""vars":{"var1":"value1"},"#
694 + r#""when":"when""#
695 + r#"}"#
696 );
697 }
698
699 #[test]
700 fn test_changed_when_bool() {
701 assert_eq!(
702 serde_json::to_string(&TaskOptions {
703 changed_when: OptU::Some(true.into()),
704 ..Default::default()
705 })
706 .expect("failed to serialize"),
707 String::new() + r#"{"changed_when":true}"#
708 );
709 }
710
711 #[test]
712 fn test_changed_when_string() {
713 assert_eq!(
714 serde_json::to_string(&TaskOptions {
715 changed_when: OptU::Some("changed_when".to_string().into()),
716 ..Default::default()
717 })
718 .expect("failed to serialize"),
719 String::new() + r#"{"changed_when":"changed_when"}"#
720 );
721 }
722 #[test]
723 fn test_changed_when_vec_string() {
724 assert_eq!(
725 serde_json::to_string(&TaskOptions {
726 changed_when: OptU::Some(
727 vec!["changed_when1".to_string(), "changed_when2".to_string()].into()
728 ),
729 ..Default::default()
730 })
731 .expect("failed to serialize"),
732 String::new() + r#"{"changed_when":["changed_when1","changed_when2"]}"#
733 );
734 }
735
736 #[test]
737 fn test_failed_when_bool() {
738 assert_eq!(
739 serde_json::to_string(&TaskOptions {
740 failed_when: OptU::Some(true.into()),
741 ..Default::default()
742 })
743 .expect("failed to serialize"),
744 String::new() + r#"{"failed_when":true}"#
745 );
746 }
747
748 #[test]
749 fn test_failed_when_string() {
750 assert_eq!(
751 serde_json::to_string(&TaskOptions {
752 failed_when: OptU::Some("failed_when".to_string().into()),
753 ..Default::default()
754 })
755 .expect("failed to serialize"),
756 String::new() + r#"{"failed_when":"failed_when"}"#
757 );
758 }
759
760 #[test]
761 fn test_failed_when_vec_string() {
762 assert_eq!(
763 serde_json::to_string(&TaskOptions {
764 failed_when: OptU::Some(
765 vec!["failed_when1".to_string(), "failed_when2".to_string()].into()
766 ),
767 ..Default::default()
768 })
769 .expect("failed to serialize"),
770 String::new() + r#"{"failed_when":["failed_when1","failed_when2"]}"#
771 );
772 }
773
774 #[test]
775 fn test_when_bool() {
776 assert_eq!(
777 serde_json::to_string(&TaskOptions {
778 when: OptU::Some(true.into()),
779 ..Default::default()
780 })
781 .expect("failed to serialize"),
782 String::new() + r#"{"when":true}"#
783 );
784 }
785
786 #[test]
787 fn test_when_string() {
788 assert_eq!(
789 serde_json::to_string(&TaskOptions {
790 when: OptU::Some("1 == 1".to_string().into()),
791 ..Default::default()
792 })
793 .expect("failed to serialize"),
794 String::new() + r#"{"when":"1 == 1"}"#
795 );
796 }
797
798 #[test]
799 fn test_when_vec_string() {
800 assert_eq!(
801 serde_json::to_string(&TaskOptions {
802 when: OptU::Some(vec!["1 == 1".to_string(), "2 == 2".to_string()].into()),
803 ..Default::default()
804 })
805 .expect("failed to serialize"),
806 String::new() + r#"{"when":["1 == 1","2 == 2"]}"#
807 );
808 }
809}