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> {
17 serde_json::to_string(&self.root)
18 }
19}
20
21#[derive(Default, Debug, Clone, PartialEq, Serialize)]
22pub struct InventoryRoot {
23 pub all: InventoryChild,
24}
25
26#[derive(Default, Debug, Clone, PartialEq, Serialize)]
27pub struct InventoryChild {
28 #[serde(skip_serializing_if = "OptU::is_unset")]
29 pub hosts: OptU<InventoryHosts>,
30 #[serde(skip_serializing_if = "OptU::is_unset")]
31 pub children: OptU<IndexMap<String, InventoryChild>>,
32 #[serde(skip_serializing_if = "OptU::is_unset")]
33 pub vars: OptU<InventoryVars>,
34}
35
36pub type InventoryHosts = IndexMap<String, Option<InventoryVars>>;
37pub type InventoryVars = IndexMap<String, serde_json::Value>;
38
39#[derive(Clone, Debug)]
40pub struct Playbook {
41 pub name: String,
44 pub plays: Vec<Play>,
45}
46
47#[derive(Clone, Debug, PartialEq, Default, Serialize)]
58#[serde(untagged)]
59pub enum OptU<T: Serialize> {
60 Some(T),
61 #[default]
62 Unset,
63}
64
65impl<T: Serialize> OptU<T> {
67 pub fn is_unset(&self) -> bool {
68 matches!(self, OptU::Unset)
69 }
70}
71
72#[derive(Serialize, Clone, Debug)]
75pub struct Play {
76 pub name: String,
78 pub hosts: StringOrVecString,
80 #[serde(flatten)]
81 pub options: PlayOptions,
82 pub tasks: Vec<Task>,
84}
85
86#[derive(Serialize, Default, Clone, Debug)]
88pub struct PlayOptions {
89 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
91 pub any_errors_fatal: OptU<BoolOrString>,
92 #[serde(
95 rename = "become",
96 default = "OptU::default",
97 skip_serializing_if = "OptU::is_unset"
98 )]
99 pub become_: OptU<BoolOrString>,
100 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
102 pub become_exe: OptU<String>,
103 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
105 pub become_flags: OptU<String>,
106 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
108 pub become_method: OptU<String>,
109 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
111 pub become_user: OptU<String>,
112 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
114 pub check_mode: OptU<BoolOrString>,
115 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
117 pub collections: OptU<Vec<String>>,
118 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
120 pub connection: OptU<String>,
121 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
123 pub debugger: OptU<BoolOrString>,
124 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
126 pub diff: OptU<BoolOrString>,
127 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
132 pub environment: OptU<IndexMap<String, String>>,
133 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
135 pub fact_path: OptU<String>,
136 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
139 pub force_handlers: OptU<BoolOrString>,
140 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
142 pub gather_facts: OptU<BoolOrString>,
143 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
145 pub gather_subset: OptU<Vec<String>>,
146 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
148 pub gather_timeout: OptU<IntOrString>,
149 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
153 pub handlers: OptU<Vec<Task>>,
154 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
156 pub ignore_errors: OptU<BoolOrString>,
157 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
160 pub ignore_unreachable: OptU<BoolOrString>,
161 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
164 pub max_fail_percentage: OptU<IntOrString>,
165 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
167 pub module_defaults: OptU<IndexMap<String, serde_json::Value>>,
168 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
170 pub no_log: OptU<BoolOrString>,
171 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
174 pub order: OptU<String>,
175 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
177 pub port: OptU<IntOrString>,
178 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
180 pub post_tasks: OptU<Vec<Task>>,
181 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
183 pub pre_tasks: OptU<Vec<Task>>,
184 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
186 pub remote_user: OptU<String>,
187 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
189 pub roles: OptU<Vec<String>>,
190 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
193 pub run_once: OptU<BoolOrString>,
194 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
196 pub serial: OptU<IntOrString>,
197 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
199 pub strategy: OptU<String>,
200 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
202 pub tags: OptU<Vec<String>>,
203 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
205 pub throttle: OptU<IntOrString>,
206 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
208 pub timeout: OptU<IntOrString>,
209 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
211 pub vars: OptU<IndexMap<String, serde_json::Value>>,
212 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
214 pub vars_files: OptU<Vec<String>>,
215 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
217 pub vars_prompt: OptU<Vec<String>>,
218}
219
220#[derive(Serialize, Clone, Debug)]
221pub struct Task {
222 pub name: String,
224 #[serde(flatten)]
225 pub options: TaskOptions,
226 #[serde(flatten)]
227 pub command: Box<dyn TaskModule>,
228}
229
230pub trait TaskModule: erased_serde::Serialize + DynClone + std::fmt::Debug + Send + Sync {}
246
247serialize_trait_object!(TaskModule);
248clone_trait_object!(TaskModule);
249
250#[derive(Serialize, Default, Clone, Debug, PartialEq)]
252pub struct TaskOptions {
253 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
255 pub action: OptU<String>,
256 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
258 pub any_errors_fatal: OptU<BoolOrString>,
259 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
261 pub args: OptU<IndexMap<String, serde_json::Value>>,
262 #[serde(
264 rename = "async",
265 default = "OptU::default",
266 skip_serializing_if = "OptU::is_unset"
267 )]
268 pub async_: OptU<IntOrString>,
269 #[serde(
272 rename = "become",
273 default = "OptU::default",
274 skip_serializing_if = "OptU::is_unset"
275 )]
276 pub become_: OptU<BoolOrString>,
277 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
279 pub become_exe: OptU<String>,
280 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
282 pub become_flags: OptU<String>,
283 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
285 pub become_method: OptU<String>,
286 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
288 pub become_user: OptU<String>,
289 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
294 pub changed_when: OptU<BoolOrStringOrVecString>,
295 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
297 pub check_mode: OptU<BoolOrString>,
298 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
300 pub collections: OptU<Vec<String>>,
301 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
303 pub connection: OptU<String>,
304 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
306 pub debugger: OptU<BoolOrString>,
307 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
311 pub delay: OptU<IntOrString>,
312 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
316 pub delegate_facts: OptU<BoolOrString>,
317 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
320 pub delegate_to: OptU<String>,
321
322 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
324 pub diff: OptU<BoolOrString>,
325
326 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
331 pub environment: OptU<IndexMap<String, String>>,
332 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
334 pub failed_when: OptU<BoolOrStringOrVecString>,
335
336 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
338 pub ignore_errors: OptU<BoolOrString>,
339
340 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
343 pub ignore_unreachable: OptU<BoolOrString>,
344
345 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
347 pub local_action: OptU<String>,
348 #[serde(
350 rename = "loop",
351 default = "OptU::default",
352 skip_serializing_if = "OptU::is_unset"
353 )]
354 pub loop_: OptU<StringOrVec>,
355
356 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
358 pub loop_control: OptU<IndexMap<String, serde_json::Value>>,
359
360 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
362 pub module_defaults: OptU<IndexMap<String, serde_json::Value>>,
363
364 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
366 pub no_log: OptU<BoolOrString>,
367 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
369 pub notify: OptU<Vec<String>>,
370
371 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
373 pub poll: OptU<IntOrString>,
374
375 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
377 pub port: OptU<IntOrString>,
378
379 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
381 pub register: OptU<String>,
382
383 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
385 pub remote_user: OptU<String>,
386
387 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
389 pub retries: OptU<IntOrString>,
390 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
393 pub run_once: OptU<BoolOrString>,
394
395 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
397 pub tags: OptU<Vec<String>>,
398
399 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
403 pub throttle: OptU<IntOrString>,
404
405 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
408 pub timeout: OptU<IntOrString>,
409
410 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
412 pub until: OptU<String>,
413
414 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
416 pub vars: OptU<IndexMap<String, serde_json::Value>>,
417
418 #[serde(default = "OptU::default", skip_serializing_if = "OptU::is_unset")]
420 pub when: OptU<BoolOrStringOrVecString>,
421 }
425
426#[cfg(test)]
427mod tests {
428 use super::*;
429
430 #[derive(Serialize, Clone, Debug, PartialEq)]
431 struct SampleTaskModule {
432 x1: String,
433 }
434
435 impl TaskModule for SampleTaskModule {}
436
437 #[test]
438 fn test_play_minimum() {
439 assert_eq!(
440 serde_json::to_string(&Play {
441 name: "play1".to_string(),
442 hosts: vec!["host1".to_string()].into(),
443 tasks: vec![Task {
444 name: "task1".to_string(),
445 options: TaskOptions::default(),
446 command: Box::new(SampleTaskModule {
447 x1: "x1".to_string(),
448 }),
449 }],
450 options: PlayOptions::default(),
451 })
452 .expect("failed to serialize"),
453 r#"{"name":"play1","hosts":["host1"],"tasks":[{"name":"task1","x1":"x1"}]}"#
454 );
455 }
456
457 #[test]
458 fn test_play_with_all_fields() {
459 assert_eq!(
460 serde_json::to_string(&Play {
461 name: "play1".to_string(),
462 hosts: vec!["host1".to_string()].into(),
463 tasks: vec![Task {
464 name: "task1".to_string(),
465 options: TaskOptions::default(),
466 command: Box::new(SampleTaskModule {
467 x1: "x1".to_string(),
468 }),
469 }],
470 options: PlayOptions {
471 any_errors_fatal: OptU::Some(true.into()),
472 become_: OptU::Some(true.into()),
473 become_exe: OptU::Some("become_exe".to_string()),
474 become_flags: OptU::Some("become_flags".to_string()),
475 become_method: OptU::Some("become_method".to_string()),
476 become_user: OptU::Some("become_user".to_string()),
477 check_mode: OptU::Some(true.into()),
478 collections: OptU::Some(vec!["collection1".to_string()]),
479 connection: OptU::Some("connection1".to_string()),
480 debugger: OptU::Some(true.into()),
481 diff: OptU::Some(true.into()),
482 environment: OptU::Some(IndexMap::from([(
483 "env1".to_string(),
484 "value1".to_string()
485 )])),
486 fact_path: OptU::Some("fact_path".to_string()),
487 force_handlers: OptU::Some(true.into()),
488 gather_facts: OptU::Some(true.into()),
489 gather_subset: OptU::Some(vec!["gather_subset1".to_string()]),
490 gather_timeout: OptU::Some(10.into()),
491 handlers: OptU::Some(vec![Task {
492 name: "handler1".to_string(),
493 options: TaskOptions::default(),
494 command: Box::new(SampleTaskModule {
495 x1: "x1".to_string(),
496 }),
497 }]),
498 ignore_errors: OptU::Some(true.into()),
499 ignore_unreachable: OptU::Some(true.into()),
500 max_fail_percentage: OptU::Some(10.into()),
501 module_defaults: OptU::Some(IndexMap::from([(
502 "module1".to_string(),
503 serde_json::Value::String("value1".to_string())
504 )])),
505 no_log: OptU::Some(true.into()),
506 order: OptU::Some("order".to_string()),
507 port: OptU::Some(10.into()),
508 post_tasks: OptU::Some(vec![Task {
509 name: "post_task1".to_string(),
510 options: TaskOptions::default(),
511 command: Box::new(SampleTaskModule {
512 x1: "x1".to_string(),
513 }),
514 }]),
515 pre_tasks: OptU::Some(vec![Task {
516 name: "pre_task1".to_string(),
517 options: TaskOptions::default(),
518 command: Box::new(SampleTaskModule {
519 x1: "x1".to_string(),
520 }),
521 }]),
522 remote_user: OptU::Some("remote_user".to_string()),
523 roles: OptU::Some(vec!["role1".to_string()]),
524 run_once: OptU::Some(true.into()),
525 serial: OptU::Some(10.into()),
526 strategy: OptU::Some("strategy".to_string()),
527 tags: OptU::Some(vec!["tag1".to_string()]),
528 throttle: OptU::Some(10.into()),
529 timeout: OptU::Some(10.into()),
530 vars: OptU::Some(IndexMap::from([(
531 "var1".to_string(),
532 serde_json::Value::String("value1".to_string())
533 )])),
534 vars_files: OptU::Some(vec!["vars_file1".to_string()]),
535 vars_prompt: OptU::Some(vec!["vars_prompt1".to_string()]),
536 }
537 })
538 .expect("failed to serialize"),
539 String::new()
540 + "{"
541 + r#""name":"play1","#
542 + r#""hosts":["host1"],"#
543 + r#""any_errors_fatal":true,"#
544 + r#""become":true,"#
545 + r#""become_exe":"become_exe","#
546 + r#""become_flags":"become_flags","#
547 + r#""become_method":"become_method","#
548 + r#""become_user":"become_user","#
549 + r#""check_mode":true,"#
550 + r#""collections":["collection1"],"#
551 + r#""connection":"connection1","#
552 + r#""debugger":true,"#
553 + r#""diff":true,"#
554 + r#""environment":{"env1":"value1"},"#
555 + r#""fact_path":"fact_path","#
556 + r#""force_handlers":true,"#
557 + r#""gather_facts":true,"#
558 + r#""gather_subset":["gather_subset1"],"#
559 + r#""gather_timeout":10,"#
560 + r#""handlers":[{"name":"handler1","x1":"x1"}],"#
561 + r#""ignore_errors":true,"#
562 + r#""ignore_unreachable":true,"#
563 + r#""max_fail_percentage":10,"#
564 + r#""module_defaults":{"module1":"value1"},"#
565 + r#""no_log":true,"#
566 + r#""order":"order","#
567 + r#""port":10,"#
568 + r#""post_tasks":[{"name":"post_task1","x1":"x1"}],"#
569 + r#""pre_tasks":[{"name":"pre_task1","x1":"x1"}],"#
570 + r#""remote_user":"remote_user","#
571 + r#""roles":["role1"],"#
572 + r#""run_once":true,"#
573 + r#""serial":10,"#
574 + r#""strategy":"strategy","#
575 + r#""tags":["tag1"],"#
576 + r#""throttle":10,"#
577 + r#""timeout":10,"#
578 + r#""vars":{"var1":"value1"},"#
579 + r#""vars_files":["vars_file1"],"#
580 + r#""vars_prompt":["vars_prompt1"],"#
581 + r#""tasks":[{"name":"task1","x1":"x1"}]"#
582 + r#"}"#
583 );
584 }
585
586 #[test]
587 fn test_task_options_with_all_fields() {
589 assert_eq!(
590 serde_json::to_string(&TaskOptions {
591 action: OptU::Some("action1".to_string()),
592 any_errors_fatal: OptU::Some(true.into()),
593 args: OptU::Some(IndexMap::from([(
594 "arg1".to_string(),
595 serde_json::Value::String("value1".to_string())
596 )])),
597 async_: OptU::Some(10.into()),
598 become_: OptU::Some(true.into()),
599 become_exe: OptU::Some("become_exe".to_string()),
600 become_flags: OptU::Some("become_flags".to_string()),
601 become_method: OptU::Some("become_method".to_string()),
602 become_user: OptU::Some("become_user".to_string()),
603 changed_when: OptU::Some("changed_when".to_string().into()),
604 check_mode: OptU::Some(true.into()),
605 collections: OptU::Some(vec!["collection1".to_string()]),
606 connection: OptU::Some("connection1".to_string()),
607 debugger: OptU::Some(true.into()),
608 delay: OptU::Some(
609 "{{ 10 | ansible.builtin.random(seed=inventory_hostname) }}".into(),
612 ),
613 delegate_facts: OptU::Some(true.into()),
614 delegate_to: OptU::Some("delegate_to".to_string()),
615 diff: OptU::Some(true.into()),
616 environment: OptU::Some(IndexMap::from([(
617 "env1".to_string(),
618 "value1".to_string()
619 )])),
620 failed_when: OptU::Some("failed_when".to_string().into()),
621 ignore_errors: OptU::Some(true.into()),
622 ignore_unreachable: OptU::Some(true.into()),
623 local_action: OptU::Some("local_action".to_string()),
624 loop_: OptU::Some(vec!["loop1".into()].into()),
625 loop_control: OptU::Some(IndexMap::from([(
626 "loop_control1".to_string(),
627 serde_json::Value::String("value1".to_string())
628 )])),
629 module_defaults: OptU::Some(IndexMap::from([(
630 "module1".to_string(),
631 serde_json::Value::String("value1".to_string())
632 )])),
633 no_log: OptU::Some(true.into()),
634 notify: OptU::Some(vec!["notify1".to_string()]),
635 poll: OptU::Some(10.into()),
636 port: OptU::Some(10.into()),
637 register: OptU::Some("register".to_string()),
638 remote_user: OptU::Some("remote_user".to_string()),
639 retries: OptU::Some(10.into()),
640 run_once: OptU::Some(true.into()),
641 tags: OptU::Some(vec!["tag1".to_string()]),
642 throttle: OptU::Some(10.into()),
643 timeout: OptU::Some(10.into()),
644 until: OptU::Some("until".to_string()),
645 vars: OptU::Some(IndexMap::from([(
646 "var1".to_string(),
647 serde_json::Value::String("value1".to_string())
648 )])),
649 when: OptU::Some("when".to_string().into()),
650 })
651 .expect("failed to serialize"),
652 String::new()
653 + r#"{""#
654 + r#"action":"action1","#
655 + r#""any_errors_fatal":true,"#
656 + r#""args":{"arg1":"value1"},"#
657 + r#""async":10,"#
658 + r#""become":true,"#
659 + r#""become_exe":"become_exe","#
660 + r#""become_flags":"become_flags","#
661 + r#""become_method":"become_method","#
662 + r#""become_user":"become_user","#
663 + r#""changed_when":"changed_when","#
664 + r#""check_mode":true,"#
665 + r#""collections":["collection1"],"#
666 + r#""connection":"connection1","#
667 + r#""debugger":true,"#
668 + r#""delay":"{{ 10 | ansible.builtin.random(seed=inventory_hostname) }}","#
669 + r#""delegate_facts":true,"#
670 + r#""delegate_to":"delegate_to","#
671 + r#""diff":true,"#
672 + r#""environment":{"env1":"value1"},"#
673 + r#""failed_when":"failed_when","#
674 + r#""ignore_errors":true,"#
675 + r#""ignore_unreachable":true,"#
676 + r#""local_action":"local_action","#
677 + r#""loop":["loop1"],"#
678 + r#""loop_control":{"loop_control1":"value1"},"#
679 + r#""module_defaults":{"module1":"value1"},"#
680 + r#""no_log":true,"#
681 + r#""notify":["notify1"],"#
682 + r#""poll":10,"#
683 + r#""port":10,"#
684 + r#""register":"register","#
685 + r#""remote_user":"remote_user","#
686 + r#""retries":10,"#
687 + r#""run_once":true,"#
688 + r#""tags":["tag1"],"#
689 + r#""throttle":10,"#
690 + r#""timeout":10,"#
691 + r#""until":"until","#
692 + r#""vars":{"var1":"value1"},"#
693 + r#""when":"when""#
694 + r#"}"#
695 );
696 }
697
698 #[test]
699 fn test_changed_when_bool() {
700 assert_eq!(
701 serde_json::to_string(&TaskOptions {
702 changed_when: OptU::Some(true.into()),
703 ..Default::default()
704 })
705 .expect("failed to serialize"),
706 String::new() + r#"{"changed_when":true}"#
707 );
708 }
709
710 #[test]
711 fn test_changed_when_string() {
712 assert_eq!(
713 serde_json::to_string(&TaskOptions {
714 changed_when: OptU::Some("changed_when".to_string().into()),
715 ..Default::default()
716 })
717 .expect("failed to serialize"),
718 String::new() + r#"{"changed_when":"changed_when"}"#
719 );
720 }
721 #[test]
722 fn test_changed_when_vec_string() {
723 assert_eq!(
724 serde_json::to_string(&TaskOptions {
725 changed_when: OptU::Some(
726 vec!["changed_when1".to_string(), "changed_when2".to_string()].into()
727 ),
728 ..Default::default()
729 })
730 .expect("failed to serialize"),
731 String::new() + r#"{"changed_when":["changed_when1","changed_when2"]}"#
732 );
733 }
734
735 #[test]
736 fn test_failed_when_bool() {
737 assert_eq!(
738 serde_json::to_string(&TaskOptions {
739 failed_when: OptU::Some(true.into()),
740 ..Default::default()
741 })
742 .expect("failed to serialize"),
743 String::new() + r#"{"failed_when":true}"#
744 );
745 }
746
747 #[test]
748 fn test_failed_when_string() {
749 assert_eq!(
750 serde_json::to_string(&TaskOptions {
751 failed_when: OptU::Some("failed_when".to_string().into()),
752 ..Default::default()
753 })
754 .expect("failed to serialize"),
755 String::new() + r#"{"failed_when":"failed_when"}"#
756 );
757 }
758
759 #[test]
760 fn test_failed_when_vec_string() {
761 assert_eq!(
762 serde_json::to_string(&TaskOptions {
763 failed_when: OptU::Some(
764 vec!["failed_when1".to_string(), "failed_when2".to_string()].into()
765 ),
766 ..Default::default()
767 })
768 .expect("failed to serialize"),
769 String::new() + r#"{"failed_when":["failed_when1","failed_when2"]}"#
770 );
771 }
772
773 #[test]
774 fn test_when_bool() {
775 assert_eq!(
776 serde_json::to_string(&TaskOptions {
777 when: OptU::Some(true.into()),
778 ..Default::default()
779 })
780 .expect("failed to serialize"),
781 String::new() + r#"{"when":true}"#
782 );
783 }
784
785 #[test]
786 fn test_when_string() {
787 assert_eq!(
788 serde_json::to_string(&TaskOptions {
789 when: OptU::Some("1 == 1".to_string().into()),
790 ..Default::default()
791 })
792 .expect("failed to serialize"),
793 String::new() + r#"{"when":"1 == 1"}"#
794 );
795 }
796
797 #[test]
798 fn test_when_vec_string() {
799 assert_eq!(
800 serde_json::to_string(&TaskOptions {
801 when: OptU::Some(vec!["1 == 1".to_string(), "2 == 2".to_string()].into()),
802 ..Default::default()
803 })
804 .expect("failed to serialize"),
805 String::new() + r#"{"when":["1 == 1","2 == 2"]}"#
806 );
807 }
808}