1use serde::{Deserialize, Deserializer, Serialize};
4
5fn null_as_default<'de, D, T>(deserializer: D) -> Result<T, D::Error>
11where
12 D: Deserializer<'de>,
13 T: Default + Deserialize<'de>,
14{
15 Ok(Option::<T>::deserialize(deserializer)?.unwrap_or_default())
16}
17
18#[derive(Debug, Clone, Deserialize, Serialize)]
24pub struct SearchResult<T> {
25 #[serde(rename = "searchRecords")]
27 pub search_records: Vec<T>,
28}
29
30#[derive(Debug, Clone, Deserialize, Serialize)]
36pub struct ExecuteAnonymousResult {
37 #[serde(default)]
39 pub compiled: bool,
40
41 #[serde(rename = "compileProblem")]
43 pub compile_problem: Option<String>,
44
45 #[serde(default)]
47 pub success: bool,
48
49 #[serde(rename = "exceptionStackTrace")]
51 pub exception_stack_trace: Option<String>,
52
53 #[serde(rename = "exceptionMessage")]
55 pub exception_message: Option<String>,
56
57 pub column: Option<i32>,
59
60 pub line: Option<i32>,
62}
63
64#[derive(Debug, Clone, Deserialize, Serialize)]
70pub struct ApexClass {
71 #[serde(rename = "Id")]
72 pub id: String,
73
74 #[serde(rename = "Name")]
75 pub name: String,
76
77 #[serde(rename = "Body")]
78 pub body: Option<String>,
79
80 #[serde(rename = "Status")]
81 pub status: Option<String>,
82
83 #[serde(rename = "IsValid")]
84 pub is_valid: Option<bool>,
85
86 #[serde(rename = "ApiVersion")]
87 pub api_version: Option<f64>,
88
89 #[serde(rename = "LengthWithoutComments")]
90 pub length_without_comments: Option<i32>,
91
92 #[serde(rename = "NamespacePrefix")]
93 pub namespace_prefix: Option<String>,
94
95 #[serde(rename = "CreatedDate")]
96 pub created_date: Option<String>,
97
98 #[serde(rename = "LastModifiedDate")]
99 pub last_modified_date: Option<String>,
100}
101
102#[derive(Debug, Clone, Deserialize, Serialize)]
104pub struct ApexTrigger {
105 #[serde(rename = "Id")]
106 pub id: String,
107
108 #[serde(rename = "Name")]
109 pub name: String,
110
111 #[serde(rename = "Body")]
112 pub body: Option<String>,
113
114 #[serde(rename = "Status")]
115 pub status: Option<String>,
116
117 #[serde(rename = "IsValid")]
118 pub is_valid: Option<bool>,
119
120 #[serde(rename = "ApiVersion")]
121 pub api_version: Option<f64>,
122
123 #[serde(rename = "TableEnumOrId")]
124 pub table_enum_or_id: Option<String>,
125
126 #[serde(rename = "UsageBeforeInsert")]
127 pub usage_before_insert: Option<bool>,
128
129 #[serde(rename = "UsageAfterInsert")]
130 pub usage_after_insert: Option<bool>,
131
132 #[serde(rename = "UsageBeforeUpdate")]
133 pub usage_before_update: Option<bool>,
134
135 #[serde(rename = "UsageAfterUpdate")]
136 pub usage_after_update: Option<bool>,
137
138 #[serde(rename = "UsageBeforeDelete")]
139 pub usage_before_delete: Option<bool>,
140
141 #[serde(rename = "UsageAfterDelete")]
142 pub usage_after_delete: Option<bool>,
143
144 #[serde(rename = "UsageAfterUndelete")]
145 pub usage_after_undelete: Option<bool>,
146}
147
148#[derive(Debug, Clone, Deserialize, Serialize)]
154pub struct ApexLog {
155 #[serde(rename = "Id")]
156 pub id: String,
157
158 #[serde(rename = "LogUser")]
159 pub log_user: Option<LogUser>,
160
161 #[serde(rename = "LogUserId")]
162 pub log_user_id: Option<String>,
163
164 #[serde(rename = "LogLength")]
165 pub log_length: Option<i64>,
166
167 #[serde(rename = "LastModifiedDate")]
168 pub last_modified_date: Option<String>,
169
170 #[serde(rename = "StartTime")]
171 pub start_time: Option<String>,
172
173 #[serde(rename = "Status")]
174 pub status: Option<String>,
175
176 #[serde(rename = "Operation")]
177 pub operation: Option<String>,
178
179 #[serde(rename = "Request")]
180 pub request: Option<String>,
181
182 #[serde(rename = "Application")]
183 pub application: Option<String>,
184
185 #[serde(rename = "DurationMilliseconds")]
186 pub duration_milliseconds: Option<i64>,
187
188 #[serde(rename = "Location")]
189 pub location: Option<String>,
190}
191
192#[derive(Debug, Clone, Deserialize, Serialize)]
194pub struct LogUser {
195 #[serde(rename = "Name")]
196 pub name: Option<String>,
197}
198
199#[derive(Debug, Clone, Deserialize, Serialize)]
205pub struct TraceFlag {
206 #[serde(rename = "Id")]
207 pub id: Option<String>,
208
209 #[serde(rename = "TracedEntityId")]
210 pub traced_entity_id: String,
211
212 #[serde(rename = "LogType")]
213 pub log_type: String,
214
215 #[serde(rename = "DebugLevelId")]
216 pub debug_level_id: String,
217
218 #[serde(rename = "StartDate")]
219 pub start_date: Option<String>,
220
221 #[serde(rename = "ExpirationDate")]
222 pub expiration_date: Option<String>,
223}
224
225#[derive(Debug, Clone, Deserialize, Serialize)]
227pub struct DebugLevel {
228 #[serde(rename = "Id")]
229 pub id: Option<String>,
230
231 #[serde(rename = "DeveloperName")]
232 pub developer_name: String,
233
234 #[serde(rename = "MasterLabel")]
235 pub master_label: String,
236
237 #[serde(rename = "ApexCode")]
238 pub apex_code: Option<String>,
239
240 #[serde(rename = "ApexProfiling")]
241 pub apex_profiling: Option<String>,
242
243 #[serde(rename = "Callout")]
244 pub callout: Option<String>,
245
246 #[serde(rename = "Database")]
247 pub database: Option<String>,
248
249 #[serde(rename = "System")]
250 pub system: Option<String>,
251
252 #[serde(rename = "Validation")]
253 pub validation: Option<String>,
254
255 #[serde(rename = "Visualforce")]
256 pub visualforce: Option<String>,
257
258 #[serde(rename = "Workflow")]
259 pub workflow: Option<String>,
260}
261
262#[derive(Debug, Clone, Copy, PartialEq, Eq)]
264pub enum LogLevel {
265 None,
266 Error,
267 Warn,
268 Info,
269 Debug,
270 Fine,
271 Finer,
272 Finest,
273}
274
275impl std::fmt::Display for LogLevel {
276 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277 match self {
278 LogLevel::None => write!(f, "NONE"),
279 LogLevel::Error => write!(f, "ERROR"),
280 LogLevel::Warn => write!(f, "WARN"),
281 LogLevel::Info => write!(f, "INFO"),
282 LogLevel::Debug => write!(f, "DEBUG"),
283 LogLevel::Fine => write!(f, "FINE"),
284 LogLevel::Finer => write!(f, "FINER"),
285 LogLevel::Finest => write!(f, "FINEST"),
286 }
287 }
288}
289
290#[derive(Debug, Clone, Deserialize, Serialize)]
296pub struct ApexCodeCoverage {
297 #[serde(rename = "Id")]
298 pub id: String,
299
300 #[serde(rename = "ApexClassOrTriggerId")]
301 pub apex_class_or_trigger_id: String,
302
303 #[serde(rename = "ApexClassOrTrigger")]
304 pub apex_class_or_trigger: Option<ApexClassOrTriggerRef>,
305
306 #[serde(rename = "TestMethodName")]
307 pub test_method_name: Option<String>,
308
309 #[serde(rename = "NumLinesCovered")]
310 pub num_lines_covered: Option<i32>,
311
312 #[serde(rename = "NumLinesUncovered")]
313 pub num_lines_uncovered: Option<i32>,
314
315 #[serde(rename = "Coverage")]
316 pub coverage: Option<CoverageDetail>,
317}
318
319#[derive(Debug, Clone, Deserialize, Serialize)]
321pub struct ApexClassOrTriggerRef {
322 #[serde(rename = "Name")]
323 pub name: Option<String>,
324}
325
326#[derive(Debug, Clone, Deserialize, Serialize)]
328pub struct CoverageDetail {
329 #[serde(rename = "coveredLines", default)]
330 pub covered_lines: Vec<i32>,
331
332 #[serde(rename = "uncoveredLines", default)]
333 pub uncovered_lines: Vec<i32>,
334}
335
336#[derive(Debug, Clone, Deserialize, Serialize)]
338pub struct ApexCodeCoverageAggregate {
339 #[serde(rename = "Id")]
340 pub id: String,
341
342 #[serde(rename = "ApexClassOrTriggerId")]
343 pub apex_class_or_trigger_id: String,
344
345 #[serde(rename = "ApexClassOrTrigger")]
346 pub apex_class_or_trigger: Option<ApexClassOrTriggerRef>,
347
348 #[serde(rename = "NumLinesCovered")]
349 pub num_lines_covered: i32,
350
351 #[serde(rename = "NumLinesUncovered")]
352 pub num_lines_uncovered: i32,
353
354 #[serde(rename = "Coverage")]
355 pub coverage: Option<CoverageDetail>,
356}
357
358#[derive(Debug, Clone, Default, Serialize, Deserialize)]
367pub struct RunTestsAsyncRequest {
368 #[serde(skip_serializing_if = "Option::is_none")]
370 #[serde(rename = "classids")]
371 pub class_ids: Option<String>,
372
373 #[serde(skip_serializing_if = "Option::is_none")]
375 #[serde(rename = "classNames")]
376 pub class_names: Option<String>,
377
378 #[serde(skip_serializing_if = "Option::is_none")]
380 #[serde(rename = "suiteids")]
381 pub suite_ids: Option<String>,
382
383 #[serde(skip_serializing_if = "Option::is_none")]
385 #[serde(rename = "suiteNames")]
386 pub suite_names: Option<String>,
387
388 #[serde(skip_serializing_if = "Option::is_none")]
390 #[serde(rename = "maxFailedTests")]
391 pub max_failed_tests: Option<i32>,
392
393 #[serde(skip_serializing_if = "Option::is_none")]
395 #[serde(rename = "testLevel")]
396 pub test_level: Option<String>,
397
398 #[serde(skip_serializing_if = "Option::is_none")]
400 #[serde(rename = "skipCodeCoverage")]
401 pub skip_code_coverage: Option<bool>,
402}
403
404#[derive(Debug, Clone, Serialize, Deserialize)]
409pub struct SyncTestItem {
410 #[serde(rename = "className")]
412 pub class_name: String,
413
414 #[serde(skip_serializing_if = "Option::is_none")]
416 #[serde(rename = "testMethods")]
417 pub test_methods: Option<Vec<String>>,
418
419 #[serde(skip_serializing_if = "Option::is_none")]
421 pub namespace: Option<String>,
422}
423
424#[derive(Debug, Clone, Default, Serialize, Deserialize)]
430pub struct RunTestsSyncRequest {
431 #[serde(skip_serializing_if = "Option::is_none")]
433 pub tests: Option<Vec<SyncTestItem>>,
434
435 #[serde(skip_serializing_if = "Option::is_none")]
437 #[serde(rename = "maxFailedTests")]
438 pub max_failed_tests: Option<i32>,
439
440 #[serde(skip_serializing_if = "Option::is_none")]
442 #[serde(rename = "skipCodeCoverage")]
443 pub skip_code_coverage: Option<bool>,
444}
445
446#[derive(Debug, Clone, Default, Deserialize, Serialize)]
448#[serde(default)]
449pub struct RunTestsSyncResult {
450 #[serde(alias = "numTestsRun", default)]
451 pub num_tests_run: u32,
452
453 #[serde(alias = "numFailures", default)]
454 pub num_failures: u32,
455
456 #[serde(alias = "totalTime", default)]
457 pub total_time: f64,
458
459 #[serde(default)]
460 pub successes: Vec<TestSuccess>,
461
462 #[serde(default)]
463 pub failures: Vec<TestFailure>,
464
465 #[serde(alias = "codeCoverage", default)]
466 pub code_coverage: Vec<CodeCoverageResult>,
467
468 #[serde(alias = "codeCoverageWarnings", default)]
469 pub code_coverage_warnings: Vec<CodeCoverageWarning>,
470}
471
472#[derive(Debug, Clone, Default, Deserialize, Serialize)]
474#[serde(default)]
475pub struct TestSuccess {
476 #[serde(alias = "Id", alias = "id", default)]
477 pub id: String,
478
479 #[serde(alias = "MethodName", alias = "methodName", default)]
480 pub method_name: String,
481
482 #[serde(alias = "Name", alias = "name", default)]
483 pub name: String,
484
485 #[serde(alias = "NamespacePrefix", alias = "namespacePrefix")]
486 pub namespace_prefix: Option<String>,
487
488 #[serde(alias = "Time", alias = "time", default)]
489 pub time: f64,
490}
491
492#[derive(Debug, Clone, Default, Deserialize, Serialize)]
494#[serde(default)]
495pub struct TestFailure {
496 #[serde(alias = "Id", alias = "id", default)]
497 pub id: String,
498
499 #[serde(alias = "MethodName", alias = "methodName", default)]
500 pub method_name: String,
501
502 #[serde(alias = "Name", alias = "name", default)]
503 pub name: String,
504
505 #[serde(alias = "NamespacePrefix", alias = "namespacePrefix")]
506 pub namespace_prefix: Option<String>,
507
508 #[serde(alias = "Time", alias = "time", default)]
509 pub time: f64,
510
511 #[serde(alias = "Message", alias = "message", default)]
512 pub message: String,
513
514 #[serde(alias = "StackTrace", alias = "stackTrace")]
515 pub stack_trace: Option<String>,
516
517 #[serde(alias = "Type", rename = "type")]
518 pub failure_type: Option<String>,
519}
520
521#[derive(Debug, Clone, Default, Deserialize, Serialize)]
523#[serde(default)]
524pub struct CodeCoverageResult {
525 #[serde(default)]
526 pub id: String,
527 #[serde(default)]
528 pub name: String,
529 pub namespace: Option<String>,
530
531 #[serde(alias = "numLocations", default)]
532 pub num_locations: u32,
533
534 #[serde(alias = "numLocationsNotCovered", default)]
535 pub num_locations_not_covered: u32,
536
537 #[serde(rename = "type", default)]
538 pub coverage_type: String,
539
540 #[serde(alias = "locationsNotCovered", default)]
541 pub locations_not_covered: Vec<CodeLocation>,
542}
543
544#[derive(Debug, Clone, Default, Deserialize, Serialize)]
546#[serde(default)]
547pub struct CodeLocation {
548 #[serde(default)]
549 pub line: u32,
550 #[serde(default)]
551 pub column: u32,
552
553 #[serde(alias = "numExecutions", default)]
554 pub num_executions: u32,
555
556 #[serde(default)]
557 pub time: f64,
558}
559
560#[derive(Debug, Clone, Deserialize, Serialize)]
562pub struct CodeCoverageWarning {
563 pub message: String,
564 pub name: Option<String>,
565 pub namespace: Option<String>,
566}
567
568#[derive(Debug, Clone, Deserialize, Serialize)]
574pub struct TestDiscoveryResult {
575 pub tests: Vec<TestItem>,
576}
577
578#[derive(Debug, Clone, Deserialize, Serialize)]
580pub struct TestItem {
581 pub id: String,
582 pub name: String,
583
584 #[serde(rename = "className")]
585 pub class_name: Option<String>,
586
587 pub namespace: Option<String>,
588 pub category: String,
589}
590
591#[derive(Debug, Clone, Default, Serialize, Deserialize)]
597pub struct RunTestsRequest {
598 #[serde(skip_serializing_if = "Option::is_none")]
599 #[serde(rename = "classIds")]
600 pub class_ids: Option<Vec<String>>,
601
602 #[serde(skip_serializing_if = "Option::is_none")]
603 #[serde(rename = "suiteIds")]
604 pub suite_ids: Option<Vec<String>>,
605
606 #[serde(skip_serializing_if = "Option::is_none")]
607 #[serde(rename = "testIds")]
608 pub test_ids: Option<Vec<String>>,
609
610 #[serde(skip_serializing_if = "Option::is_none")]
611 #[serde(rename = "testLevel")]
612 pub test_level: Option<String>,
613
614 #[serde(skip_serializing_if = "Option::is_none")]
615 #[serde(rename = "skipCodeCoverage")]
616 pub skip_code_coverage: Option<bool>,
617}
618
619#[derive(Debug, Clone, Deserialize, Serialize)]
621pub struct RunTestsResponse {
622 #[serde(rename = "testRunId")]
624 pub test_run_id: String,
625}
626
627#[derive(Debug, Clone, Deserialize, Serialize)]
636pub struct CompletionsResult {
637 #[serde(rename = "publicDeclarations")]
638 pub public_declarations: std::collections::HashMap<String, Vec<CompletionItem>>,
639}
640
641#[derive(Debug, Clone, Default, Deserialize, Serialize)]
643#[serde(default)]
644pub struct CompletionItem {
645 pub name: String,
646
647 #[serde(rename = "type")]
648 pub symbol_type: Option<String>,
649
650 pub namespace: Option<String>,
651
652 pub signature: Option<String>,
653
654 #[serde(rename = "returnType")]
655 pub return_type: Option<String>,
656
657 #[serde(default, deserialize_with = "null_as_default")]
658 pub parameters: Vec<Parameter>,
659
660 #[serde(default, deserialize_with = "null_as_default")]
661 pub references: Vec<Reference>,
662}
663
664#[derive(Debug, Clone, Default, Deserialize, Serialize)]
666#[serde(default)]
667pub struct Parameter {
668 pub name: String,
669
670 #[serde(rename = "type")]
671 pub param_type: Option<String>,
672}
673
674#[derive(Debug, Clone, Default, Deserialize, Serialize)]
676#[serde(default)]
677pub struct Reference {
678 pub name: String,
679
680 #[serde(rename = "type")]
681 pub ref_type: Option<String>,
682}
683
684#[cfg(feature = "dependencies")]
689pub use busbar_sf_client::MetadataComponentDependency;
690
691#[cfg(test)]
692mod tests {
693 use super::*;
694
695 #[test]
696 fn test_execute_anonymous_result_deser() {
697 let json = r#"{
698 "compiled": true,
699 "success": true
700 }"#;
701
702 let result: ExecuteAnonymousResult = serde_json::from_str(json).unwrap();
703 assert!(result.compiled);
704 assert!(result.success);
705 }
706
707 #[test]
708 fn test_apex_class_deser() {
709 let json = r#"{
710 "Id": "01pxx00000000001AAA",
711 "Name": "TestClass",
712 "Status": "Active",
713 "IsValid": true,
714 "ApiVersion": 62.0
715 }"#;
716
717 let class: ApexClass = serde_json::from_str(json).unwrap();
718 assert_eq!(class.name, "TestClass");
719 assert_eq!(class.is_valid, Some(true));
720 assert_eq!(class.api_version, Some(62.0));
721 }
722
723 #[test]
724 fn test_apex_log_deser() {
725 let json = r#"{
726 "Id": "07Lxx00000000001AAA",
727 "LogLength": 12345,
728 "Status": "Success",
729 "Operation": "Apex",
730 "DurationMilliseconds": 150
731 }"#;
732
733 let log: ApexLog = serde_json::from_str(json).unwrap();
734 assert_eq!(log.id, "07Lxx00000000001AAA");
735 assert_eq!(log.log_length, Some(12345));
736 assert_eq!(log.duration_milliseconds, Some(150));
737 }
738
739 #[test]
740 fn test_log_level_display() {
741 assert_eq!(LogLevel::Debug.to_string(), "DEBUG");
742 assert_eq!(LogLevel::Finest.to_string(), "FINEST");
743 }
744
745 #[test]
746 fn test_run_tests_async_request_ser() {
747 let req = RunTestsAsyncRequest {
748 class_names: Some("TestClass1".to_string()),
749 test_level: Some("RunSpecifiedTests".to_string()),
750 skip_code_coverage: Some(false),
751 ..Default::default()
752 };
753
754 let json = serde_json::to_string(&req).unwrap();
755 assert!(json.contains("classNames"));
756 assert!(json.contains("\"TestClass1\""));
757 assert!(json.contains("testLevel"));
758 assert!(json.contains("skipCodeCoverage"));
759 assert!(!json.contains("classids"));
760 }
761
762 #[test]
763 fn test_run_tests_async_request_multiple_classes() {
764 let req = RunTestsAsyncRequest {
765 class_names: Some("TestClass1,TestClass2,TestClass3".to_string()),
766 test_level: Some("RunSpecifiedTests".to_string()),
767 ..Default::default()
768 };
769
770 let json = serde_json::to_string(&req).unwrap();
771 assert!(json.contains("TestClass1,TestClass2,TestClass3"));
772 }
773
774 #[test]
775 fn test_run_tests_sync_request_ser() {
776 let req = RunTestsSyncRequest {
777 tests: Some(vec![SyncTestItem {
778 class_name: "MyTestClass".to_string(),
779 test_methods: Some(vec!["testMethod1".to_string()]),
780 namespace: None,
781 }]),
782 ..Default::default()
783 };
784
785 let json = serde_json::to_string(&req).unwrap();
786 assert!(json.contains("className"));
787 assert!(json.contains("MyTestClass"));
788 assert!(json.contains("testMethods"));
789 assert!(json.contains("testMethod1"));
790 }
791
792 #[test]
793 fn test_run_tests_sync_result_deser() {
794 let json = r#"{
795 "numTestsRun": 5,
796 "numFailures": 1,
797 "totalTime": 1234.5,
798 "successes": [
799 {
800 "Id": "01p001",
801 "MethodName": "testMethod1",
802 "Name": "TestClass1",
803 "NamespacePrefix": null,
804 "Time": 100.0
805 }
806 ],
807 "failures": [
808 {
809 "Id": "01p002",
810 "MethodName": "testFailing",
811 "Name": "TestClass2",
812 "NamespacePrefix": null,
813 "Time": 200.0,
814 "Message": "Assertion failed",
815 "StackTrace": "Class.TestClass2.testFailing: line 5"
816 }
817 ],
818 "codeCoverage": [],
819 "codeCoverageWarnings": []
820 }"#;
821
822 let result: RunTestsSyncResult = serde_json::from_str(json).unwrap();
823 assert_eq!(result.num_tests_run, 5);
824 assert_eq!(result.num_failures, 1);
825 assert_eq!(result.successes.len(), 1);
826 assert_eq!(result.successes[0].method_name, "testMethod1");
827 assert_eq!(result.failures.len(), 1);
828 assert_eq!(result.failures[0].message, "Assertion failed");
829 }
830
831 #[test]
832 fn test_test_discovery_result_deser() {
833 let json = r#"{
834 "tests": [
835 {
836 "id": "01pxx00000000001",
837 "name": "testMethod1",
838 "className": "TestClass1",
839 "namespace": null,
840 "category": "apex"
841 },
842 {
843 "id": "300xx00000000001",
844 "name": "MyFlowTest",
845 "namespace": null,
846 "category": "flow"
847 }
848 ]
849 }"#;
850
851 let result: TestDiscoveryResult = serde_json::from_str(json).unwrap();
852 assert_eq!(result.tests.len(), 2);
853 assert_eq!(result.tests[0].category, "apex");
854 assert_eq!(result.tests[1].category, "flow");
855 }
856
857 #[test]
858 fn test_run_tests_request_ser() {
859 let req = RunTestsRequest {
860 test_ids: Some(vec!["01pxx00000000001".to_string()]),
861 test_level: Some("RunSpecifiedTests".to_string()),
862 skip_code_coverage: Some(true),
863 ..Default::default()
864 };
865
866 let json = serde_json::to_string(&req).unwrap();
867 assert!(json.contains("testIds"));
868 assert!(json.contains("skipCodeCoverage"));
869 }
870
871 #[test]
872 fn test_completions_result_deser() {
873 let json = r#"{
874 "publicDeclarations": {
875 "System": [
876 {
877 "name": "debug",
878 "type": "Method",
879 "namespace": "System",
880 "returnType": "void",
881 "parameters": [
882 {
883 "name": "message",
884 "type": "Object"
885 }
886 ]
887 }
888 ],
889 "Database": [
890 {
891 "name": "query",
892 "type": "Method",
893 "namespace": "Database"
894 }
895 ]
896 }
897 }"#;
898
899 let result: CompletionsResult = serde_json::from_str(json).unwrap();
900 assert_eq!(result.public_declarations.len(), 2);
901 assert!(result.public_declarations.contains_key("System"));
902 assert!(result.public_declarations.contains_key("Database"));
903 let system_items = &result.public_declarations["System"];
904 assert_eq!(system_items.len(), 1);
905 assert_eq!(system_items[0].name, "debug");
906 assert_eq!(system_items[0].return_type, Some("void".to_string()));
907 assert_eq!(system_items[0].parameters.len(), 1);
908 }
909
910 #[test]
911 fn test_completions_result_null_fields() {
912 let json = r#"{
914 "publicDeclarations": {
915 "System": [
916 {
917 "name": "debug",
918 "parameters": null,
919 "references": null
920 },
921 {
922 "name": "assert"
923 }
924 ]
925 }
926 }"#;
927
928 let result: CompletionsResult = serde_json::from_str(json).unwrap();
929 let items = &result.public_declarations["System"];
930 assert_eq!(items.len(), 2);
931 assert_eq!(items[0].name, "debug");
932 assert!(items[0].parameters.is_empty());
933 assert!(items[0].references.is_empty());
934 assert_eq!(items[1].name, "assert");
935 assert!(items[1].parameters.is_empty());
936 }
937}