1use autoagents_llm::chat::{FunctionTool, Tool};
2pub use autoagents_protocol::ToolCallResult;
3use schemars::JsonSchema;
4use serde::{Serialize, de::DeserializeOwned};
5use serde_json::Value;
6use std::fmt::Debug;
7use std::sync::Arc;
8mod runtime;
9use async_trait::async_trait;
10pub use runtime::ToolRuntime;
11
12#[cfg(feature = "wasmtime")]
13pub use runtime::{WasmRuntime, WasmRuntimeError};
14
15#[derive(Debug, thiserror::Error)]
16pub enum ToolCallError {
17 #[error("Runtime Error {0}")]
18 RuntimeError(#[from] Box<dyn std::error::Error + Sync + Send>),
19
20 #[error("Serde Error {0}")]
21 SerdeError(#[from] serde_json::Error),
22}
23
24pub trait ToolT: Send + Sync + Debug + ToolRuntime {
25 fn name(&self) -> &str;
27 fn description(&self) -> &str;
29 fn args_schema(&self) -> Value;
31 fn output_schema(&self) -> Option<Value> {
33 None
34 }
35}
36
37pub trait ToolInputT {
39 fn io_schema() -> &'static str;
40}
41
42#[doc(hidden)]
47pub trait ToolInputSchema: ToolInputT {
48 fn io_schema_value() -> &'static Value;
49}
50
51pub trait ToolOutputT: Serialize + DeserializeOwned + Send + Sync + JsonSchema {
53 fn io_schema() -> Value {
54 let schema = schemars::r#gen::SchemaSettings::draft07()
55 .into_generator()
56 .into_root_schema_for::<Self>();
57 serde_json::to_value(schema.schema).unwrap_or(Value::Null)
58 }
59}
60
61impl<T> ToolOutputT for T where T: Serialize + DeserializeOwned + Send + Sync + JsonSchema {}
62
63#[derive(Debug)]
68pub struct SharedTool {
69 inner: Arc<dyn ToolT>,
70}
71
72impl SharedTool {
73 pub fn new(tool: Arc<dyn ToolT>) -> Self {
75 Self { inner: tool }
76 }
77}
78
79#[async_trait]
80impl ToolRuntime for SharedTool {
81 async fn execute(&self, args: Value) -> Result<Value, ToolCallError> {
82 self.inner.execute(args).await
83 }
84}
85
86impl ToolT for SharedTool {
87 fn name(&self) -> &str {
88 self.inner.name()
89 }
90
91 fn description(&self) -> &str {
92 self.inner.description()
93 }
94
95 fn args_schema(&self) -> Value {
96 self.inner.args_schema()
97 }
98
99 fn output_schema(&self) -> Option<Value> {
100 self.inner.output_schema()
101 }
102}
103
104pub fn shared_tools_to_boxes(tools: &[Arc<dyn ToolT>]) -> Vec<Box<dyn ToolT>> {
109 tools
110 .iter()
111 .map(|t| Box::new(SharedTool::new(Arc::clone(t))) as Box<dyn ToolT>)
112 .collect()
113}
114
115#[allow(clippy::borrowed_box)]
117pub fn to_llm_tool(tool: &Box<dyn ToolT>) -> Tool {
118 Tool {
119 tool_type: "function".to_string(),
120 function: FunctionTool {
121 name: tool.name().to_string(),
122 description: tool.description().to_string(),
123 parameters: tool.args_schema(),
124 },
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use autoagents_llm::chat::Tool;
132 use schemars::JsonSchema;
133 use serde::{Deserialize, Serialize};
134 use serde_json::json;
135 use std::sync::Arc;
136
137 #[derive(Debug, Serialize, Deserialize)]
138 struct TestInput {
139 name: String,
140 value: i32,
141 }
142
143 #[derive(Debug, Serialize, Deserialize, JsonSchema)]
144 struct TestOutput {
145 processed_name: String,
146 doubled_value: i32,
147 }
148
149 impl ToolInputT for TestInput {
150 fn io_schema() -> &'static str {
151 r#"{"type":"object","properties":{"name":{"type":"string"},"value":{"type":"integer"}},"required":["name","value"]}"#
152 }
153 }
154
155 #[derive(Debug)]
156 struct MockTool {
157 name: &'static str,
158 description: &'static str,
159 should_fail: bool,
160 }
161
162 impl MockTool {
163 fn new(name: &'static str, description: &'static str) -> Self {
164 Self {
165 name,
166 description,
167 should_fail: false,
168 }
169 }
170
171 fn with_failure(name: &'static str, description: &'static str) -> Self {
172 Self {
173 name,
174 description,
175 should_fail: true,
176 }
177 }
178 }
179
180 impl ToolT for MockTool {
181 fn name(&self) -> &'static str {
182 self.name
183 }
184
185 fn description(&self) -> &'static str {
186 self.description
187 }
188
189 fn args_schema(&self) -> Value {
190 json!({
191 "type": "object",
192 "properties": {
193 "name": {"type": "string"},
194 "value": {"type": "integer"}
195 },
196 "required": ["name", "value"]
197 })
198 }
199 }
200
201 #[async_trait]
202 impl ToolRuntime for MockTool {
203 async fn execute(
204 &self,
205 args: serde_json::Value,
206 ) -> Result<serde_json::Value, ToolCallError> {
207 if self.should_fail {
208 return Err(ToolCallError::RuntimeError(
209 "Mock tool failure".to_string().into(),
210 ));
211 }
212
213 let input: TestInput = serde_json::from_value(args)?;
214 Ok(json!({
215 "processed_name": input.name,
216 "doubled_value": input.value * 2
217 }))
218 }
219 }
220
221 #[test]
222 fn test_tool_call_error_runtime_error() {
223 let error = ToolCallError::RuntimeError("Runtime error".to_string().into());
224 assert_eq!(error.to_string(), "Runtime Error Runtime error");
225 }
226
227 #[test]
228 fn test_tool_call_error_serde_error() {
229 let json_error = serde_json::from_str::<Value>("invalid json").unwrap_err();
230 let error = ToolCallError::SerdeError(json_error);
231 assert!(error.to_string().contains("Serde Error"));
232 }
233
234 #[test]
235 fn test_tool_call_error_debug() {
236 let error = ToolCallError::RuntimeError("Debug test".to_string().into());
237 let debug_str = format!("{error:?}");
238 assert!(debug_str.contains("RuntimeError"));
239 }
240
241 #[test]
242 fn test_tool_call_error_from_serde() {
243 let json_error = serde_json::from_str::<Value>("invalid json").unwrap_err();
244 let error: ToolCallError = json_error.into();
245 assert!(matches!(error, ToolCallError::SerdeError(_)));
246 }
247
248 #[test]
249 fn test_tool_call_error_from_box_error() {
250 let box_error: Box<dyn std::error::Error + Send + Sync> = "Test error".into();
251 let error: ToolCallError = box_error.into();
252 assert!(matches!(error, ToolCallError::RuntimeError(_)));
253 }
254
255 #[test]
256 fn test_mock_tool_creation() {
257 let tool = MockTool::new("test_tool", "A test tool");
258 assert_eq!(tool.name(), "test_tool");
259 assert_eq!(tool.description(), "A test tool");
260 assert!(!tool.should_fail);
261 }
262
263 #[test]
264 fn test_mock_tool_with_failure() {
265 let tool = MockTool::with_failure("failing_tool", "A failing tool");
266 assert_eq!(tool.name(), "failing_tool");
267 assert_eq!(tool.description(), "A failing tool");
268 assert!(tool.should_fail);
269 }
270
271 #[test]
272 fn test_mock_tool_args_schema() {
273 let tool = MockTool::new("schema_tool", "Schema test");
274 let schema = tool.args_schema();
275
276 assert_eq!(schema["type"], "object");
277 assert!(schema["properties"].is_object());
278 assert!(schema["properties"]["name"].is_object());
279 assert!(schema["properties"]["value"].is_object());
280 assert_eq!(schema["properties"]["name"]["type"], "string");
281 assert_eq!(schema["properties"]["value"]["type"], "integer");
282 }
283
284 #[tokio::test]
285 async fn test_mock_tool_run_success() {
286 let tool = MockTool::new("success_tool", "Success test");
287 let input = json!({
288 "name": "test",
289 "value": 42
290 });
291
292 let result = tool.execute(input).await;
293 assert!(result.is_ok());
294
295 let output = result.unwrap();
296 assert_eq!(output["processed_name"], "test");
297 assert_eq!(output["doubled_value"], 84);
298 }
299
300 #[tokio::test]
301 async fn test_mock_tool_run_failure() {
302 let tool = MockTool::with_failure("failure_tool", "Failure test");
303 let input = json!({
304 "name": "test",
305 "value": 42
306 });
307
308 let result = tool.execute(input).await;
309 assert!(result.is_err());
310 assert!(
311 result
312 .unwrap_err()
313 .to_string()
314 .contains("Mock tool failure")
315 );
316 }
317
318 #[tokio::test]
319 async fn test_mock_tool_run_invalid_input() {
320 let tool = MockTool::new("invalid_input_tool", "Invalid input test");
321 let input = json!({
322 "invalid_field": "test"
323 });
324
325 let result = tool.execute(input).await;
326 assert!(result.is_err());
327 assert!(matches!(result.unwrap_err(), ToolCallError::SerdeError(_)));
328 }
329
330 #[tokio::test]
331 async fn test_mock_tool_run_with_extra_fields() {
332 let tool = MockTool::new("extra_fields_tool", "Extra fields test");
333 let input = json!({
334 "name": "test",
335 "value": 42,
336 "extra_field": "ignored"
337 });
338
339 let result = tool.execute(input).await;
340 assert!(result.is_ok());
341
342 let output = result.unwrap();
343 assert_eq!(output["processed_name"], "test");
344 assert_eq!(output["doubled_value"], 84);
345 }
346
347 #[test]
348 fn test_mock_tool_debug() {
349 let tool = MockTool::new("debug_tool", "Debug test");
350 let debug_str = format!("{tool:?}");
351 assert!(debug_str.contains("MockTool"));
352 assert!(debug_str.contains("debug_tool"));
353 }
354
355 #[test]
356 fn test_tool_input_trait() {
357 let schema = TestInput::io_schema();
358 assert!(schema.contains("object"));
359 assert!(schema.contains("name"));
360 assert!(schema.contains("value"));
361 assert!(schema.contains("string"));
362 assert!(schema.contains("integer"));
363 }
364
365 #[test]
366 fn test_tool_output_trait() {
367 let schema = TestOutput::io_schema();
368 assert_eq!(schema["type"], "object");
369 assert_eq!(schema["properties"]["processed_name"]["type"], "string");
370 assert_eq!(schema["properties"]["doubled_value"]["type"], "integer");
371 let required = schema["required"]
372 .as_array()
373 .expect("required fields should be serialized as an array");
374 assert_eq!(required.len(), 2);
375 assert!(required.iter().any(|value| value == "processed_name"));
376 assert!(required.iter().any(|value| value == "doubled_value"));
377 }
378
379 #[test]
380 fn test_test_input_serialization() {
381 let input = TestInput {
382 name: "test".to_string(),
383 value: 42,
384 };
385 let serialized = serde_json::to_string(&input).unwrap();
386 assert!(serialized.contains("test"));
387 assert!(serialized.contains("42"));
388 }
389
390 #[test]
391 fn test_test_input_deserialization() {
392 let json = r#"{"name":"test","value":42}"#;
393 let input: TestInput = serde_json::from_str(json).unwrap();
394 assert_eq!(input.name, "test");
395 assert_eq!(input.value, 42);
396 }
397
398 #[test]
399 fn test_test_input_debug() {
400 let input = TestInput {
401 name: "debug".to_string(),
402 value: 123,
403 };
404 let debug_str = format!("{input:?}");
405 assert!(debug_str.contains("TestInput"));
406 assert!(debug_str.contains("debug"));
407 assert!(debug_str.contains("123"));
408 }
409
410 #[test]
411 fn test_boxed_tool_to_tool_conversion() {
412 let mock_tool = MockTool::new("convert_tool", "Conversion test");
413 let boxed_tool: Box<dyn ToolT> = Box::new(mock_tool);
414
415 let tool: Tool = to_llm_tool(&boxed_tool);
416 assert_eq!(tool.tool_type, "function");
417 assert_eq!(tool.function.name, "convert_tool");
418 assert_eq!(tool.function.description, "Conversion test");
419 assert_eq!(tool.function.parameters["type"], "object");
420 }
421
422 #[tokio::test]
423 async fn test_shared_tool_delegates_execution_and_metadata() {
424 let shared = SharedTool::new(Arc::new(MockTool::new("shared_tool", "Shared tool")));
425
426 assert_eq!(shared.name(), "shared_tool");
427 assert_eq!(shared.description(), "Shared tool");
428
429 let result = shared
430 .execute(json!({
431 "name": "shared",
432 "value": 21
433 }))
434 .await
435 .expect("shared tool executes");
436
437 assert_eq!(result["processed_name"], "shared");
438 assert_eq!(result["doubled_value"], 42);
439 }
440
441 #[test]
442 fn test_shared_tools_to_boxes_preserves_tool_metadata() {
443 let tools: Vec<Arc<dyn ToolT>> = vec![
444 Arc::new(MockTool::new("tool1", "First tool")),
445 Arc::new(MockTool::new("tool2", "Second tool")),
446 ];
447
448 let boxed_tools = shared_tools_to_boxes(&tools);
449
450 assert_eq!(boxed_tools.len(), 2);
451 assert_eq!(boxed_tools[0].name(), "tool1");
452 assert_eq!(boxed_tools[1].description(), "Second tool");
453 }
454
455 #[test]
456 fn test_tool_conversion_preserves_schema() {
457 let mock_tool = MockTool::new("schema_tool", "Schema preservation test");
458 let boxed_tool: Box<dyn ToolT> = Box::new(mock_tool);
459
460 let tool: Tool = to_llm_tool(&boxed_tool);
461 let schema = &tool.function.parameters;
462
463 assert_eq!(schema["type"], "object");
464 assert_eq!(schema["properties"]["name"]["type"], "string");
465 assert_eq!(schema["properties"]["value"]["type"], "integer");
466 let required = schema["required"]
467 .as_array()
468 .expect("required fields should be serialized as an array");
469 assert_eq!(required.len(), 2);
470 assert!(required.iter().any(|value| value == "name"));
471 assert!(required.iter().any(|value| value == "value"));
472 }
473
474 #[test]
475 fn test_tool_trait_object_usage() {
476 let tools: Vec<Box<dyn ToolT>> = vec![
477 Box::new(MockTool::new("tool1", "First tool")),
478 Box::new(MockTool::new("tool2", "Second tool")),
479 Box::new(MockTool::with_failure("tool3", "Third tool")),
480 ];
481
482 for tool in &tools {
483 assert!(!tool.name().is_empty());
484 assert!(!tool.description().is_empty());
485 assert!(tool.args_schema().is_object());
486 }
487 }
488
489 #[tokio::test]
490 async fn test_tool_run_with_different_inputs() {
491 let tool = MockTool::new("varied_input_tool", "Varied input test");
492
493 let inputs = vec![
494 json!({"name": "test1", "value": 1}),
495 json!({"name": "test2", "value": -5}),
496 json!({"name": "", "value": 0}),
497 json!({"name": "long_name_test", "value": 999999}),
498 ];
499
500 for input in inputs {
501 let result = tool.execute(input.clone()).await;
502 assert!(result.is_ok());
503
504 let output = result.unwrap();
505 assert_eq!(output["processed_name"], input["name"]);
506 assert_eq!(
507 output["doubled_value"],
508 input["value"].as_i64().unwrap() * 2
509 );
510 }
511 }
512
513 #[test]
514 fn test_tool_error_chaining() {
515 let json_error = serde_json::from_str::<Value>("invalid").unwrap_err();
516 let tool_error = ToolCallError::SerdeError(json_error);
517
518 use std::error::Error;
520 assert!(tool_error.source().is_some());
521 }
522
523 #[test]
524 fn test_tool_with_empty_name() {
525 let tool = MockTool::new("", "Empty name test");
526 assert_eq!(tool.name(), "");
527 assert_eq!(tool.description(), "Empty name test");
528 }
529
530 #[test]
531 fn test_tool_with_empty_description() {
532 let tool = MockTool::new("empty_desc", "");
533 assert_eq!(tool.name(), "empty_desc");
534 assert_eq!(tool.description(), "");
535 }
536
537 #[test]
538 fn test_tool_schema_complex() {
539 let tool = MockTool::new("complex_tool", "Complex schema test");
540 let schema = tool.args_schema();
541
542 assert!(schema.is_object());
544 assert!(schema["properties"].is_object());
545 assert!(schema["required"].is_array());
546 assert_eq!(schema["required"].as_array().unwrap().len(), 2);
547 }
548
549 #[test]
550 fn test_multiple_tool_instances() {
551 let tool1 = MockTool::new("tool1", "First instance");
552 let tool2 = MockTool::new("tool2", "Second instance");
553
554 assert_ne!(tool1.name(), tool2.name());
555 assert_ne!(tool1.description(), tool2.description());
556
557 assert_eq!(tool1.args_schema(), tool2.args_schema());
559 }
560
561 #[test]
562 fn test_tool_send_sync() {
563 fn assert_send_sync<T: Send + Sync>() {}
564 assert_send_sync::<MockTool>();
565 }
566
567 #[test]
568 fn test_tool_trait_object_send_sync() {
569 fn assert_send_sync<T: Send + Sync>() {}
570 assert_send_sync::<Box<dyn ToolT>>();
571 }
572
573 #[test]
574 fn test_tool_call_result_creation() {
575 let result = ToolCallResult {
576 tool_name: "test_tool".to_string(),
577 success: true,
578 arguments: json!({"param": "value"}),
579 result: json!({"output": "success"}),
580 };
581
582 assert_eq!(result.tool_name, "test_tool");
583 assert!(result.success);
584 assert_eq!(result.arguments, json!({"param": "value"}));
585 assert_eq!(result.result, json!({"output": "success"}));
586 }
587
588 #[test]
589 fn test_tool_call_result_serialization() {
590 let result = ToolCallResult {
591 tool_name: "serialize_tool".to_string(),
592 success: false,
593 arguments: json!({"input": "test"}),
594 result: json!({"error": "failed"}),
595 };
596
597 let serialized = serde_json::to_string(&result).unwrap();
598 let deserialized: ToolCallResult = serde_json::from_str(&serialized).unwrap();
599
600 assert_eq!(deserialized.tool_name, "serialize_tool");
601 assert!(!deserialized.success);
602 assert_eq!(deserialized.arguments, json!({"input": "test"}));
603 assert_eq!(deserialized.result, json!({"error": "failed"}));
604 }
605
606 #[test]
607 fn test_tool_call_result_clone() {
608 let result = ToolCallResult {
609 tool_name: "clone_tool".to_string(),
610 success: true,
611 arguments: json!({"data": [1, 2, 3]}),
612 result: json!({"processed": [2, 4, 6]}),
613 };
614
615 let cloned = result.clone();
616 assert_eq!(result.tool_name, cloned.tool_name);
617 assert_eq!(result.success, cloned.success);
618 assert_eq!(result.arguments, cloned.arguments);
619 assert_eq!(result.result, cloned.result);
620 }
621
622 #[test]
623 fn test_tool_call_result_debug() {
624 let result = ToolCallResult {
625 tool_name: "debug_tool".to_string(),
626 success: true,
627 arguments: json!({}),
628 result: json!(null),
629 };
630
631 let debug_str = format!("{result:?}");
632 assert!(debug_str.contains("ToolCallResult"));
633 assert!(debug_str.contains("debug_tool"));
634 }
635
636 #[test]
637 fn test_tool_call_result_with_null_values() {
638 let result = ToolCallResult {
639 tool_name: "null_tool".to_string(),
640 success: false,
641 arguments: json!(null),
642 result: json!(null),
643 };
644
645 let serialized = serde_json::to_string(&result).unwrap();
646 let deserialized: ToolCallResult = serde_json::from_str(&serialized).unwrap();
647
648 assert_eq!(deserialized.tool_name, "null_tool");
649 assert!(!deserialized.success);
650 assert_eq!(deserialized.arguments, json!(null));
651 assert_eq!(deserialized.result, json!(null));
652 }
653
654 #[test]
655 fn test_tool_call_result_with_complex_data() {
656 let complex_args = json!({
657 "nested": {
658 "array": [1, 2, {"key": "value"}],
659 "string": "test",
660 "number": 42.5
661 }
662 });
663
664 let complex_result = json!({
665 "status": "completed",
666 "data": {
667 "items": ["a", "b", "c"],
668 "count": 3
669 }
670 });
671
672 let result = ToolCallResult {
673 tool_name: "complex_tool".to_string(),
674 success: true,
675 arguments: complex_args.clone(),
676 result: complex_result.clone(),
677 };
678
679 let serialized = serde_json::to_string(&result).unwrap();
680 let deserialized: ToolCallResult = serde_json::from_str(&serialized).unwrap();
681
682 assert_eq!(deserialized.arguments, complex_args);
683 assert_eq!(deserialized.result, complex_result);
684 }
685
686 #[test]
687 fn test_tool_call_result_empty_tool_name() {
688 let result = ToolCallResult {
689 tool_name: String::default(),
690 success: true,
691 arguments: json!({}),
692 result: json!({}),
693 };
694
695 assert!(result.tool_name.is_empty());
696 assert!(result.success);
697 }
698
699 #[test]
700 fn test_tool_call_result_large_data() {
701 let large_string = "x".repeat(10000);
702 let result = ToolCallResult {
703 tool_name: "large_tool".to_string(),
704 success: true,
705 arguments: json!({"large_param": large_string}),
706 result: json!({"processed": true}),
707 };
708
709 let serialized = serde_json::to_string(&result).unwrap();
710 let deserialized: ToolCallResult = serde_json::from_str(&serialized).unwrap();
711
712 assert_eq!(deserialized.tool_name, "large_tool");
713 assert!(deserialized.success);
714 assert!(
715 deserialized.arguments["large_param"]
716 .as_str()
717 .unwrap()
718 .len()
719 == 10000
720 );
721 }
722
723 #[test]
724 fn test_tool_call_result_equality() {
725 let result1 = ToolCallResult {
726 tool_name: "equal_tool".to_string(),
727 success: true,
728 arguments: json!({"param": "value"}),
729 result: json!({"output": "result"}),
730 };
731
732 let result2 = ToolCallResult {
733 tool_name: "equal_tool".to_string(),
734 success: true,
735 arguments: json!({"param": "value"}),
736 result: json!({"output": "result"}),
737 };
738
739 let result3 = ToolCallResult {
740 tool_name: "different_tool".to_string(),
741 success: true,
742 arguments: json!({"param": "value"}),
743 result: json!({"output": "result"}),
744 };
745
746 let serialized1 = serde_json::to_string(&result1).unwrap();
748 let serialized2 = serde_json::to_string(&result2).unwrap();
749 let serialized3 = serde_json::to_string(&result3).unwrap();
750
751 assert_eq!(serialized1, serialized2);
752 assert_ne!(serialized1, serialized3);
753 }
754
755 #[test]
756 fn test_tool_call_result_with_unicode() {
757 let result = ToolCallResult {
758 tool_name: "unicode_tool".to_string(),
759 success: true,
760 arguments: json!({"message": "Hello δΈη! π"}),
761 result: json!({"response": "Processed: Hello δΈη! π"}),
762 };
763
764 let serialized = serde_json::to_string(&result).unwrap();
765 let deserialized: ToolCallResult = serde_json::from_str(&serialized).unwrap();
766
767 assert_eq!(deserialized.arguments["message"], "Hello δΈη! π");
768 assert_eq!(deserialized.result["response"], "Processed: Hello δΈη! π");
769 }
770
771 #[test]
772 fn test_tool_call_result_with_arrays() {
773 let result = ToolCallResult {
774 tool_name: "array_tool".to_string(),
775 success: true,
776 arguments: json!({"numbers": [1, 2, 3, 4, 5]}),
777 result: json!({"sum": 15, "count": 5}),
778 };
779
780 let serialized = serde_json::to_string(&result).unwrap();
781 let deserialized: ToolCallResult = serde_json::from_str(&serialized).unwrap();
782
783 assert_eq!(deserialized.arguments["numbers"], json!([1, 2, 3, 4, 5]));
784 assert_eq!(deserialized.result["sum"], 15);
785 assert_eq!(deserialized.result["count"], 5);
786 }
787
788 #[test]
789 fn test_tool_call_result_boolean_values() {
790 let result = ToolCallResult {
791 tool_name: "bool_tool".to_string(),
792 success: false,
793 arguments: json!({"enabled": true, "debug": false}),
794 result: json!({"valid": false, "error": true}),
795 };
796
797 let serialized = serde_json::to_string(&result).unwrap();
798 let deserialized: ToolCallResult = serde_json::from_str(&serialized).unwrap();
799
800 assert!(!deserialized.success);
801 assert_eq!(deserialized.arguments["enabled"], true);
802 assert_eq!(deserialized.arguments["debug"], false);
803 assert_eq!(deserialized.result["valid"], false);
804 assert_eq!(deserialized.result["error"], true);
805 }
806}