···
(** JMAP Test Suite using Alcotest
This test suite validates JMAP parsing using the comprehensive
4
-
JSON test files in test/data/.
4
+
JSON test files in data/.
···
(** Helper to load JSON file *)
13
-
let ic = open_in path in
13
+
(* When running from _build/default/jmap/test, we need to go up to workspace root *)
15
+
path; (* Try direct path *)
16
+
"data/" ^ (Filename.basename path); (* Try data/ subdirectory *)
17
+
"../../../../jmap/test/" ^ path; (* From _build/default/jmap/test to jmap/test *)
19
+
let rec find_file = function
20
+
| [] -> path (* Return original path, will fail with proper error *)
21
+
| p :: rest -> if Sys.file_exists p then p else find_file rest
23
+
let full_path = find_file try_paths in
24
+
let ic = open_in full_path in
~finally:(fun () -> close_in ic)
(fun () -> Ezjsonm.from_channel ic)
···
(** Test Core Protocol *)
let test_echo_request () =
21
-
let _json = load_json "test/data/core/request_echo.json" in
32
+
let _json = load_json "data/core/request_echo.json" in
(* TODO: Parse and validate *)
check bool "Echo request loaded" true true
let test_echo_response () =
26
-
let _json = load_json "test/data/core/response_echo.json" in
37
+
let _json = load_json "data/core/response_echo.json" in
(* TODO: Parse and validate *)
check bool "Echo response loaded" true true
let test_get_request () =
31
-
let _json = load_json "test/data/core/request_get.json" in
42
+
let _json = load_json "data/core/request_get.json" in
(* TODO: Parse and validate *)
check bool "Get request loaded" true true
let test_get_response () =
36
-
let _json = load_json "test/data/core/response_get.json" in
47
+
let _json = load_json "data/core/response_get.json" in
(* TODO: Parse and validate *)
check bool "Get response loaded" true true
41
-
let _json = load_json "test/data/core/session.json" in
52
+
let _json = load_json "data/core/session.json" in
(* TODO: Parse Session object *)
check bool "Session loaded" true true
45
-
(** Test Mail Protocol *)
56
+
(** Test Mail Protocol - Mailbox *)
let test_mailbox_get_request () =
48
-
let _json = load_json "test/data/mail/mailbox_get_request.json" in
49
-
(* TODO: Parse Mailbox/get request *)
50
-
check bool "Mailbox/get request loaded" true true
59
+
let json = load_json "data/mail/mailbox_get_request.json" in
60
+
let req = Jmap_mail.Jmap_mailbox.Get.request_of_json json in
62
+
(* Verify account_id *)
63
+
let account_id = Jmap_core.Jmap_standard_methods.Get.account_id req in
64
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
66
+
(* Verify ids is null (None) *)
67
+
let ids = Jmap_core.Jmap_standard_methods.Get.ids req in
68
+
check bool "IDs should be None" true (ids = None);
70
+
(* Verify properties list *)
71
+
let props = Jmap_core.Jmap_standard_methods.Get.properties req in
74
+
check int "Properties count" 11 (List.length p);
75
+
check bool "Has id property" true (List.mem "id" p);
76
+
check bool "Has name property" true (List.mem "name" p);
77
+
check bool "Has role property" true (List.mem "role" p);
78
+
check bool "Has myRights property" true (List.mem "myRights" p)
80
+
fail "Properties should not be None"
let test_mailbox_get_response () =
53
-
let _json = load_json "test/data/mail/mailbox_get_response.json" in
54
-
(* TODO: Parse Mailbox/get response *)
55
-
check bool "Mailbox/get response loaded" true true
83
+
let json = load_json "data/mail/mailbox_get_response.json" in
84
+
let resp = Jmap_mail.Jmap_mailbox.Get.response_of_json json in
86
+
(* Verify account_id *)
87
+
let account_id = Jmap_core.Jmap_standard_methods.Get.response_account_id resp in
88
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
91
+
let state = Jmap_core.Jmap_standard_methods.Get.state resp in
92
+
check string "State" "m42:100" state;
94
+
(* Verify mailbox list *)
95
+
let mailboxes = Jmap_core.Jmap_standard_methods.Get.list resp in
96
+
check int "Mailbox count" 5 (List.length mailboxes);
98
+
(* Verify not_found is empty *)
99
+
let not_found = Jmap_core.Jmap_standard_methods.Get.not_found resp in
100
+
check int "Not found count" 0 (List.length not_found);
102
+
(* Test first mailbox (INBOX) *)
103
+
let inbox = List.hd mailboxes in
104
+
check string "INBOX id" "mb001" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_mailbox.id inbox));
105
+
check string "INBOX name" "INBOX" (Jmap_mail.Jmap_mailbox.name inbox);
106
+
check bool "INBOX parentId is None" true (Jmap_mail.Jmap_mailbox.parent_id inbox = None);
107
+
check string "INBOX role" "inbox" (match Jmap_mail.Jmap_mailbox.role inbox with Some r -> r | None -> "");
108
+
check int "INBOX sortOrder" 10 (Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_mailbox.sort_order inbox));
109
+
check int "INBOX totalEmails" 1523 (Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_mailbox.total_emails inbox));
110
+
check int "INBOX unreadEmails" 42 (Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_mailbox.unread_emails inbox));
111
+
check int "INBOX totalThreads" 987 (Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_mailbox.total_threads inbox));
112
+
check int "INBOX unreadThreads" 35 (Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_mailbox.unread_threads inbox));
113
+
check bool "INBOX isSubscribed" true (Jmap_mail.Jmap_mailbox.is_subscribed inbox);
115
+
(* Test INBOX rights *)
116
+
let inbox_rights = Jmap_mail.Jmap_mailbox.my_rights inbox in
117
+
check bool "INBOX mayReadItems" true (Jmap_mail.Jmap_mailbox.Rights.may_read_items inbox_rights);
118
+
check bool "INBOX mayAddItems" true (Jmap_mail.Jmap_mailbox.Rights.may_add_items inbox_rights);
119
+
check bool "INBOX mayRemoveItems" true (Jmap_mail.Jmap_mailbox.Rights.may_remove_items inbox_rights);
120
+
check bool "INBOX maySetSeen" true (Jmap_mail.Jmap_mailbox.Rights.may_set_seen inbox_rights);
121
+
check bool "INBOX maySetKeywords" true (Jmap_mail.Jmap_mailbox.Rights.may_set_keywords inbox_rights);
122
+
check bool "INBOX mayCreateChild" true (Jmap_mail.Jmap_mailbox.Rights.may_create_child inbox_rights);
123
+
check bool "INBOX mayRename" false (Jmap_mail.Jmap_mailbox.Rights.may_rename inbox_rights);
124
+
check bool "INBOX mayDelete" false (Jmap_mail.Jmap_mailbox.Rights.may_delete inbox_rights);
125
+
check bool "INBOX maySubmit" true (Jmap_mail.Jmap_mailbox.Rights.may_submit inbox_rights);
127
+
(* Test second mailbox (Sent) *)
128
+
let sent = List.nth mailboxes 1 in
129
+
check string "Sent id" "mb002" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_mailbox.id sent));
130
+
check string "Sent name" "Sent" (Jmap_mail.Jmap_mailbox.name sent);
131
+
check string "Sent role" "sent" (match Jmap_mail.Jmap_mailbox.role sent with Some r -> r | None -> "");
132
+
check int "Sent sortOrder" 20 (Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_mailbox.sort_order sent));
134
+
(* Test Work mailbox (no role) *)
135
+
let work = List.nth mailboxes 4 in
136
+
check string "Work id" "mb005" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_mailbox.id work));
137
+
check string "Work name" "Work" (Jmap_mail.Jmap_mailbox.name work);
138
+
check bool "Work role is None" true (Jmap_mail.Jmap_mailbox.role work = None);
139
+
check int "Work totalEmails" 342 (Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_mailbox.total_emails work));
141
+
(* Test Work rights (user-created mailbox has full permissions) *)
142
+
let work_rights = Jmap_mail.Jmap_mailbox.my_rights work in
143
+
check bool "Work mayRename" true (Jmap_mail.Jmap_mailbox.Rights.may_rename work_rights);
144
+
check bool "Work mayDelete" true (Jmap_mail.Jmap_mailbox.Rights.may_delete work_rights)
146
+
let test_mailbox_query_request () =
147
+
let json = load_json "data/mail/mailbox_query_request.json" in
148
+
let req = Jmap_mail.Jmap_mailbox.Query.request_of_json json in
150
+
(* Verify account_id *)
151
+
let account_id = Jmap_mail.Jmap_mailbox.Query.account_id req in
152
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
154
+
(* Verify filter is present *)
155
+
let filter = Jmap_mail.Jmap_mailbox.Query.filter req in
156
+
check bool "Filter should be Some" true (filter <> None);
159
+
let sort = Jmap_mail.Jmap_mailbox.Query.sort req in
162
+
check int "Sort criteria count" 2 (List.length s);
163
+
(* First sort by sortOrder ascending *)
164
+
let sort1 = List.hd s in
165
+
check string "First sort property" "sortOrder" (Jmap_core.Jmap_comparator.property sort1);
166
+
check bool "First sort ascending" true (Jmap_core.Jmap_comparator.is_ascending sort1);
167
+
(* Second sort by name ascending *)
168
+
let sort2 = List.nth s 1 in
169
+
check string "Second sort property" "name" (Jmap_core.Jmap_comparator.property sort2);
170
+
check bool "Second sort ascending" true (Jmap_core.Jmap_comparator.is_ascending sort2)
172
+
fail "Sort should not be None";
174
+
(* Verify calculateTotal *)
175
+
let calculate_total = Jmap_mail.Jmap_mailbox.Query.calculate_total req in
176
+
check bool "Calculate total should be Some true" true (calculate_total = Some true)
178
+
let test_mailbox_query_response () =
179
+
let json = load_json "data/mail/mailbox_query_response.json" in
180
+
let resp = Jmap_mail.Jmap_mailbox.Query.response_of_json json in
182
+
(* Verify account_id *)
183
+
let account_id = Jmap_core.Jmap_standard_methods.Query.response_account_id resp in
184
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
186
+
(* Verify query_state *)
187
+
let query_state = Jmap_core.Jmap_standard_methods.Query.query_state resp in
188
+
check string "Query state" "mq42:100" query_state;
190
+
(* Verify can_calculate_changes *)
191
+
let can_calc = Jmap_core.Jmap_standard_methods.Query.can_calculate_changes resp in
192
+
check bool "Can calculate changes" true can_calc;
194
+
(* Verify position *)
195
+
let position = Jmap_core.Jmap_standard_methods.Query.response_position resp in
196
+
check int "Position" 0 (Jmap_core.Jmap_primitives.UnsignedInt.to_int position);
199
+
let ids = Jmap_core.Jmap_standard_methods.Query.ids resp in
200
+
check int "IDs count" 3 (List.length ids);
201
+
check string "First ID" "mb005" (Jmap_core.Jmap_id.to_string (List.hd ids));
202
+
check string "Second ID" "mb008" (Jmap_core.Jmap_id.to_string (List.nth ids 1));
203
+
check string "Third ID" "mb012" (Jmap_core.Jmap_id.to_string (List.nth ids 2));
206
+
let total = Jmap_core.Jmap_standard_methods.Query.total resp in
208
+
| Some t -> check int "Total" 3 (Jmap_core.Jmap_primitives.UnsignedInt.to_int t)
209
+
| None -> fail "Total should not be None"
211
+
let test_mailbox_set_request () =
212
+
let json = load_json "data/mail/mailbox_set_request.json" in
213
+
let req = Jmap_mail.Jmap_mailbox.Set.request_of_json json in
215
+
(* Verify account_id *)
216
+
let account_id = Jmap_core.Jmap_standard_methods.Set.account_id req in
217
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
219
+
(* Verify if_in_state *)
220
+
let if_in_state = Jmap_core.Jmap_standard_methods.Set.if_in_state req in
221
+
check bool "If in state should be Some" true (if_in_state = Some "m42:100");
223
+
(* Verify create *)
224
+
let create = Jmap_core.Jmap_standard_methods.Set.create req in
227
+
check int "Create count" 1 (List.length c);
228
+
let (temp_id, mailbox) = List.hd c in
229
+
check string "Temp ID" "temp-mb-1" (Jmap_core.Jmap_id.to_string temp_id);
230
+
check string "Created mailbox name" "Projects" (Jmap_mail.Jmap_mailbox.name mailbox);
231
+
check bool "Created mailbox parentId is None" true (Jmap_mail.Jmap_mailbox.parent_id mailbox = None);
232
+
check bool "Created mailbox role is None" true (Jmap_mail.Jmap_mailbox.role mailbox = None);
233
+
check int "Created mailbox sortOrder" 60 (Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_mailbox.sort_order mailbox));
234
+
check bool "Created mailbox isSubscribed" true (Jmap_mail.Jmap_mailbox.is_subscribed mailbox)
236
+
fail "Create should not be None");
238
+
(* Verify update *)
239
+
let update = Jmap_core.Jmap_standard_methods.Set.update req in
242
+
check int "Update count" 1 (List.length u);
243
+
let (update_id, _patches) = List.hd u in
244
+
check string "Update ID" "mb005" (Jmap_core.Jmap_id.to_string update_id)
246
+
fail "Update should not be None");
248
+
(* Verify destroy *)
249
+
let destroy = Jmap_core.Jmap_standard_methods.Set.destroy req in
250
+
(match destroy with
252
+
check int "Destroy count" 1 (List.length d);
253
+
check string "Destroy ID" "mb012" (Jmap_core.Jmap_id.to_string (List.hd d))
255
+
fail "Destroy should not be None")
257
+
let test_mailbox_set_response () =
258
+
let json = load_json "data/mail/mailbox_set_response.json" in
259
+
let resp = Jmap_mail.Jmap_mailbox.Set.response_of_json json in
261
+
(* Verify account_id *)
262
+
let account_id = Jmap_core.Jmap_standard_methods.Set.response_account_id resp in
263
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
265
+
(* Verify old_state *)
266
+
let old_state = Jmap_core.Jmap_standard_methods.Set.old_state resp in
267
+
check bool "Old state should be Some" true (old_state = Some "m42:100");
269
+
(* Verify new_state *)
270
+
let new_state = Jmap_core.Jmap_standard_methods.Set.new_state resp in
271
+
check string "New state" "m42:103" new_state;
273
+
(* Verify created *)
274
+
let created = Jmap_core.Jmap_standard_methods.Set.created resp in
275
+
(match created with
277
+
check int "Created count" 1 (List.length c);
278
+
let (temp_id, mailbox) = List.hd c in
279
+
check string "Created temp ID" "temp-mb-1" (Jmap_core.Jmap_id.to_string temp_id);
280
+
check string "Created mailbox ID" "mb020" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_mailbox.id mailbox));
281
+
check int "Created mailbox totalEmails" 0 (Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_mailbox.total_emails mailbox));
282
+
check int "Created mailbox unreadEmails" 0 (Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_mailbox.unread_emails mailbox));
283
+
(* Verify rights of created mailbox *)
284
+
let rights = Jmap_mail.Jmap_mailbox.my_rights mailbox in
285
+
check bool "Created mailbox mayRename" true (Jmap_mail.Jmap_mailbox.Rights.may_rename rights);
286
+
check bool "Created mailbox mayDelete" true (Jmap_mail.Jmap_mailbox.Rights.may_delete rights)
288
+
fail "Created should not be None");
290
+
(* Verify updated *)
291
+
let updated = Jmap_core.Jmap_standard_methods.Set.updated resp in
292
+
(match updated with
294
+
check int "Updated count" 1 (List.length u);
295
+
let (update_id, update_val) = List.hd u in
296
+
check string "Updated ID" "mb005" (Jmap_core.Jmap_id.to_string update_id);
297
+
check bool "Updated value is None" true (update_val = None)
299
+
fail "Updated should not be None");
301
+
(* Verify destroyed *)
302
+
let destroyed = Jmap_core.Jmap_standard_methods.Set.destroyed resp in
303
+
(match destroyed with
305
+
check int "Destroyed count" 1 (List.length d);
306
+
check string "Destroyed ID" "mb012" (Jmap_core.Jmap_id.to_string (List.hd d))
308
+
fail "Destroyed should not be None");
310
+
(* Verify not_created, not_updated, not_destroyed are None *)
311
+
check bool "Not created is None" true (Jmap_core.Jmap_standard_methods.Set.not_created resp = None);
312
+
check bool "Not updated is None" true (Jmap_core.Jmap_standard_methods.Set.not_updated resp = None);
313
+
check bool "Not destroyed is None" true (Jmap_core.Jmap_standard_methods.Set.not_destroyed resp = None)
315
+
(** Test Mail Protocol - Email *)
let test_email_get_request () =
58
-
let _json = load_json "test/data/mail/email_get_request.json" in
59
-
(* TODO: Parse Email/get request *)
60
-
check bool "Email/get request loaded" true true
318
+
let json = load_json "data/mail/email_get_request.json" in
319
+
let request = Jmap_mail.Jmap_email.Get.request_of_json json in
321
+
(* Validate account_id *)
322
+
let account_id = Jmap_mail.Jmap_email.Get.account_id request in
323
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
326
+
let ids = Jmap_mail.Jmap_email.Get.ids request in
327
+
check bool "IDs present" true (Option.is_some ids);
328
+
let ids_list = Option.get ids in
329
+
check int "Two IDs requested" 2 (List.length ids_list);
330
+
check string "First ID" "e001" (Jmap_core.Jmap_id.to_string (List.nth ids_list 0));
331
+
check string "Second ID" "e002" (Jmap_core.Jmap_id.to_string (List.nth ids_list 1));
333
+
(* Validate properties *)
334
+
let properties = Jmap_mail.Jmap_email.Get.properties request in
335
+
check bool "Properties present" true (Option.is_some properties);
336
+
let props_list = Option.get properties in
337
+
check bool "Properties include 'subject'" true (List.mem "subject" props_list);
338
+
check bool "Properties include 'from'" true (List.mem "from" props_list);
339
+
check bool "Properties include 'to'" true (List.mem "to" props_list)
341
+
let test_email_get_full_request () =
342
+
let json = load_json "data/mail/email_get_full_request.json" in
343
+
let request = Jmap_mail.Jmap_email.Get.request_of_json json in
345
+
(* Validate body fetch options *)
346
+
let fetch_text = Jmap_mail.Jmap_email.Get.fetch_text_body_values request in
347
+
check bool "Fetch text body values" true (Option.value ~default:false fetch_text);
349
+
let fetch_html = Jmap_mail.Jmap_email.Get.fetch_html_body_values request in
350
+
check bool "Fetch HTML body values" true (Option.value ~default:false fetch_html);
352
+
let fetch_all = Jmap_mail.Jmap_email.Get.fetch_all_body_values request in
353
+
check bool "Fetch all body values is false" false (Option.value ~default:true fetch_all);
355
+
let max_bytes = Jmap_mail.Jmap_email.Get.max_body_value_bytes request in
356
+
check bool "Max body value bytes present" true (Option.is_some max_bytes);
357
+
check int "Max bytes is 32768" 32768
358
+
(Jmap_core.Jmap_primitives.UnsignedInt.to_int (Option.get max_bytes))
let test_email_get_response () =
63
-
let _json = load_json "test/data/mail/email_get_response.json" in
64
-
(* TODO: Parse Email/get response *)
65
-
check bool "Email/get response loaded" true true
361
+
let json = load_json "data/mail/email_get_response.json" in
362
+
let response = Jmap_mail.Jmap_email.Get.response_of_json json in
364
+
(* Validate response metadata *)
365
+
let account_id = Jmap_core.Jmap_standard_methods.Get.response_account_id response in
366
+
check string "Response account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
368
+
let state = Jmap_core.Jmap_standard_methods.Get.state response in
369
+
check string "Response state" "e42:100" state;
371
+
(* Validate emails list *)
372
+
let emails = Jmap_core.Jmap_standard_methods.Get.list response in
373
+
check int "Two emails returned" 2 (List.length emails);
375
+
(* Test first email (e001) *)
376
+
let email1 = List.nth emails 0 in
377
+
check string "Email 1 ID" "e001" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_email.id email1));
378
+
check string "Email 1 thread ID" "t001" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_email.thread_id email1));
379
+
check string "Email 1 subject" "Project Update Q4 2025"
380
+
(Option.get (Jmap_mail.Jmap_email.subject email1));
381
+
check int "Email 1 size" 15234
382
+
(Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_email.size email1));
383
+
check bool "Email 1 has no attachment" false (Jmap_mail.Jmap_email.has_attachment email1);
385
+
(* Test email 1 from address *)
386
+
let from1 = Option.get (Jmap_mail.Jmap_email.from email1) in
387
+
check int "Email 1 has one from address" 1 (List.length from1);
388
+
let from_addr = List.nth from1 0 in
389
+
check string "Email 1 from name" "Bob Smith"
390
+
(Option.get (Jmap_mail.Jmap_email.EmailAddress.name from_addr));
391
+
check string "Email 1 from email" "bob@example.com"
392
+
(Jmap_mail.Jmap_email.EmailAddress.email from_addr);
394
+
(* Test email 1 to addresses *)
395
+
let to1 = Option.get (Jmap_mail.Jmap_email.to_ email1) in
396
+
check int "Email 1 has one to address" 1 (List.length to1);
397
+
let to_addr = List.nth to1 0 in
398
+
check string "Email 1 to name" "Alice Jones"
399
+
(Option.get (Jmap_mail.Jmap_email.EmailAddress.name to_addr));
400
+
check string "Email 1 to email" "alice@example.com"
401
+
(Jmap_mail.Jmap_email.EmailAddress.email to_addr);
403
+
(* Test email 1 keywords *)
404
+
let keywords1 = Jmap_mail.Jmap_email.keywords email1 in
405
+
check bool "Email 1 has $seen keyword" true
406
+
(List.mem_assoc "$seen" keywords1);
407
+
check bool "Email 1 $seen is true" true
408
+
(List.assoc "$seen" keywords1);
410
+
(* Test second email (e002) *)
411
+
let email2 = List.nth emails 1 in
412
+
check string "Email 2 ID" "e002" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_email.id email2));
413
+
check string "Email 2 subject" "Re: Technical Requirements Review"
414
+
(Option.get (Jmap_mail.Jmap_email.subject email2));
416
+
(* Test email 2 to addresses (multiple recipients) *)
417
+
let to2 = Option.get (Jmap_mail.Jmap_email.to_ email2) in
418
+
check int "Email 2 has two to addresses" 2 (List.length to2);
420
+
(* Test email 2 keywords *)
421
+
let keywords2 = Jmap_mail.Jmap_email.keywords email2 in
422
+
check bool "Email 2 has $seen keyword" true
423
+
(List.mem_assoc "$seen" keywords2);
424
+
check bool "Email 2 has $flagged keyword" true
425
+
(List.mem_assoc "$flagged" keywords2);
427
+
(* Test email 2 replyTo *)
428
+
let reply_to2 = Jmap_mail.Jmap_email.reply_to email2 in
429
+
check bool "Email 2 has replyTo" true (Option.is_some reply_to2);
430
+
let reply_to_list = Option.get reply_to2 in
431
+
check int "Email 2 has one replyTo address" 1 (List.length reply_to_list);
432
+
let reply_addr = List.nth reply_to_list 0 in
433
+
check string "Email 2 replyTo email" "support@company.com"
434
+
(Jmap_mail.Jmap_email.EmailAddress.email reply_addr);
436
+
(* Validate notFound is empty *)
437
+
let not_found = Jmap_core.Jmap_standard_methods.Get.not_found response in
438
+
check int "No emails not found" 0 (List.length not_found)
440
+
let test_email_get_full_response () =
441
+
let json = load_json "data/mail/email_get_full_response.json" in
442
+
let response = Jmap_mail.Jmap_email.Get.response_of_json json in
444
+
let emails = Jmap_core.Jmap_standard_methods.Get.list response in
445
+
check int "One email returned" 1 (List.length emails);
447
+
let email = List.nth emails 0 in
449
+
(* Validate basic fields *)
450
+
check string "Email ID" "e001" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_email.id email));
451
+
check bool "Has attachment" true (Jmap_mail.Jmap_email.has_attachment email);
453
+
(* Validate bodyStructure (multipart/mixed with nested multipart/alternative) *)
454
+
let body_structure = Jmap_mail.Jmap_email.body_structure email in
455
+
check bool "Has bodyStructure" true (Option.is_some body_structure);
457
+
let root_part = Option.get body_structure in
458
+
check string "Root type is multipart/mixed" "multipart/mixed"
459
+
(Jmap_mail.Jmap_email.BodyPart.type_ root_part);
461
+
let sub_parts = Jmap_mail.Jmap_email.BodyPart.sub_parts root_part in
462
+
check bool "Root has subParts" true (Option.is_some sub_parts);
463
+
let parts_list = Option.get sub_parts in
464
+
check int "Root has 2 subParts" 2 (List.length parts_list);
466
+
(* First subpart: multipart/alternative *)
467
+
let alt_part = List.nth parts_list 0 in
468
+
check string "First subpart is multipart/alternative" "multipart/alternative"
469
+
(Jmap_mail.Jmap_email.BodyPart.type_ alt_part);
471
+
let alt_sub_parts = Option.get (Jmap_mail.Jmap_email.BodyPart.sub_parts alt_part) in
472
+
check int "Alternative has 2 subParts" 2 (List.length alt_sub_parts);
474
+
(* Text/plain part *)
475
+
let text_part = List.nth alt_sub_parts 0 in
476
+
check string "Text part type" "text/plain" (Jmap_mail.Jmap_email.BodyPart.type_ text_part);
477
+
check string "Text part charset" "utf-8"
478
+
(Option.get (Jmap_mail.Jmap_email.BodyPart.charset text_part));
479
+
check string "Text part ID" "1" (Option.get (Jmap_mail.Jmap_email.BodyPart.part_id text_part));
480
+
check int "Text part size" 2134
481
+
(Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_email.BodyPart.size text_part));
483
+
(* Text/html part *)
484
+
let html_part = List.nth alt_sub_parts 1 in
485
+
check string "HTML part type" "text/html" (Jmap_mail.Jmap_email.BodyPart.type_ html_part);
486
+
check string "HTML part ID" "2" (Option.get (Jmap_mail.Jmap_email.BodyPart.part_id html_part));
487
+
check int "HTML part size" 4567
488
+
(Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_email.BodyPart.size html_part));
490
+
(* Attachment part *)
491
+
let attach_part = List.nth parts_list 1 in
492
+
check string "Attachment type" "application/pdf"
493
+
(Jmap_mail.Jmap_email.BodyPart.type_ attach_part);
494
+
check string "Attachment name" "Q4_Report.pdf"
495
+
(Option.get (Jmap_mail.Jmap_email.BodyPart.name attach_part));
496
+
check string "Attachment disposition" "attachment"
497
+
(Option.get (Jmap_mail.Jmap_email.BodyPart.disposition attach_part));
498
+
check string "Attachment part ID" "3"
499
+
(Option.get (Jmap_mail.Jmap_email.BodyPart.part_id attach_part));
500
+
check int "Attachment size" 8533
501
+
(Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_email.BodyPart.size attach_part));
503
+
(* Validate textBody *)
504
+
let text_body = Jmap_mail.Jmap_email.text_body email in
505
+
check bool "Has textBody" true (Option.is_some text_body);
506
+
let text_body_list = Option.get text_body in
507
+
check int "One textBody part" 1 (List.length text_body_list);
508
+
let text_body_part = List.nth text_body_list 0 in
509
+
check string "textBody part ID" "1"
510
+
(Option.get (Jmap_mail.Jmap_email.BodyPart.part_id text_body_part));
511
+
check string "textBody type" "text/plain"
512
+
(Jmap_mail.Jmap_email.BodyPart.type_ text_body_part);
514
+
(* Validate htmlBody *)
515
+
let html_body = Jmap_mail.Jmap_email.html_body email in
516
+
check bool "Has htmlBody" true (Option.is_some html_body);
517
+
let html_body_list = Option.get html_body in
518
+
check int "One htmlBody part" 1 (List.length html_body_list);
519
+
let html_body_part = List.nth html_body_list 0 in
520
+
check string "htmlBody part ID" "2"
521
+
(Option.get (Jmap_mail.Jmap_email.BodyPart.part_id html_body_part));
522
+
check string "htmlBody type" "text/html"
523
+
(Jmap_mail.Jmap_email.BodyPart.type_ html_body_part);
525
+
(* Validate attachments *)
526
+
let attachments = Jmap_mail.Jmap_email.attachments email in
527
+
check bool "Has attachments" true (Option.is_some attachments);
528
+
let attachments_list = Option.get attachments in
529
+
check int "One attachment" 1 (List.length attachments_list);
530
+
let attachment = List.nth attachments_list 0 in
531
+
check string "Attachment name" "Q4_Report.pdf"
532
+
(Option.get (Jmap_mail.Jmap_email.BodyPart.name attachment));
534
+
(* Validate bodyValues *)
535
+
let body_values = Jmap_mail.Jmap_email.body_values email in
536
+
check bool "Has bodyValues" true (Option.is_some body_values);
537
+
let values_list = Option.get body_values in
538
+
check int "Two bodyValues" 2 (List.length values_list);
540
+
(* Text body value *)
541
+
check bool "Has bodyValue for part 1" true (List.mem_assoc "1" values_list);
542
+
let text_value = List.assoc "1" values_list in
543
+
let text_content = Jmap_mail.Jmap_email.BodyValue.value text_value in
544
+
check bool "Text content starts with 'Hi Alice'" true
545
+
(String.starts_with ~prefix:"Hi Alice" text_content);
546
+
check bool "Text not truncated" false
547
+
(Jmap_mail.Jmap_email.BodyValue.is_truncated text_value);
548
+
check bool "Text no encoding problem" false
549
+
(Jmap_mail.Jmap_email.BodyValue.is_encoding_problem text_value);
551
+
(* HTML body value *)
552
+
check bool "Has bodyValue for part 2" true (List.mem_assoc "2" values_list);
553
+
let html_value = List.assoc "2" values_list in
554
+
let html_content = Jmap_mail.Jmap_email.BodyValue.value html_value in
555
+
check bool "HTML content starts with '<html>'" true
556
+
(String.starts_with ~prefix:"<html>" html_content);
557
+
check bool "HTML not truncated" false
558
+
(Jmap_mail.Jmap_email.BodyValue.is_truncated html_value)
560
+
let test_email_query_request () =
561
+
let json = load_json "data/mail/email_query_request.json" in
562
+
let request = Jmap_mail.Jmap_email.Query.request_of_json json in
564
+
(* Validate account_id *)
565
+
let account_id = Jmap_mail.Jmap_email.Query.account_id request in
566
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
568
+
(* Validate limit *)
569
+
let limit = Jmap_mail.Jmap_email.Query.limit request in
570
+
check bool "Has limit" true (Option.is_some limit);
571
+
check int "Limit is 50" 50
572
+
(Jmap_core.Jmap_primitives.UnsignedInt.to_int (Option.get limit));
574
+
(* Validate calculateTotal *)
575
+
let calc_total = Jmap_mail.Jmap_email.Query.calculate_total request in
576
+
check bool "Calculate total is true" true (Option.value ~default:false calc_total);
578
+
(* Validate collapseThreads *)
579
+
let collapse = Jmap_mail.Jmap_email.Query.collapse_threads request in
580
+
check bool "Collapse threads is false" false (Option.value ~default:true collapse);
582
+
(* Validate position *)
583
+
let position = Jmap_mail.Jmap_email.Query.position request in
584
+
check bool "Has position" true (Option.is_some position);
585
+
check int "Position is 0" 0
586
+
(Jmap_core.Jmap_primitives.Int53.to_int (Option.get position))
588
+
let test_email_query_response () =
589
+
let json = load_json "data/mail/email_query_response.json" in
590
+
let response = Jmap_mail.Jmap_email.Query.response_of_json json in
592
+
(* Validate account_id *)
593
+
let account_id = Jmap_core.Jmap_standard_methods.Query.response_account_id response in
594
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
596
+
(* Validate query state *)
597
+
let query_state = Jmap_core.Jmap_standard_methods.Query.query_state response in
598
+
check string "Query state" "eq42:100" query_state;
600
+
(* Validate can calculate changes *)
601
+
let can_calc = Jmap_core.Jmap_standard_methods.Query.can_calculate_changes response in
602
+
check bool "Can calculate changes" true can_calc;
604
+
(* Validate position *)
605
+
let position = Jmap_core.Jmap_standard_methods.Query.response_position response in
606
+
check int "Position is 0" 0 (Jmap_core.Jmap_primitives.UnsignedInt.to_int position);
609
+
let ids = Jmap_core.Jmap_standard_methods.Query.ids response in
610
+
check int "Five IDs returned" 5 (List.length ids);
611
+
check string "First ID" "e015" (Jmap_core.Jmap_id.to_string (List.nth ids 0));
612
+
check string "Last ID" "e005" (Jmap_core.Jmap_id.to_string (List.nth ids 4));
614
+
(* Validate total *)
615
+
let total = Jmap_core.Jmap_standard_methods.Query.total response in
616
+
check bool "Has total" true (Option.is_some total);
617
+
check int "Total is 5" 5
618
+
(Jmap_core.Jmap_primitives.UnsignedInt.to_int (Option.get total))
620
+
let test_email_set_request () =
621
+
let json = load_json "data/mail/email_set_request.json" in
622
+
let request = Jmap_mail.Jmap_email.Set.request_of_json json in
624
+
(* Validate account_id *)
625
+
let account_id = Jmap_core.Jmap_standard_methods.Set.account_id request in
626
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
628
+
(* Validate ifInState *)
629
+
let if_in_state = Jmap_core.Jmap_standard_methods.Set.if_in_state request in
630
+
check bool "Has ifInState" true (Option.is_some if_in_state);
631
+
check string "ifInState value" "e42:100" (Option.get if_in_state);
633
+
(* Validate create *)
634
+
let create = Jmap_core.Jmap_standard_methods.Set.create request in
635
+
check bool "Has create" true (Option.is_some create);
636
+
let create_list = Option.get create in
637
+
check int "One email to create" 1 (List.length create_list);
638
+
let (create_id, _email) = List.nth create_list 0 in
639
+
check string "Create ID" "temp-email-1" (Jmap_core.Jmap_id.to_string create_id);
641
+
(* Validate update *)
642
+
let update = Jmap_core.Jmap_standard_methods.Set.update request in
643
+
check bool "Has update" true (Option.is_some update);
644
+
let update_list = Option.get update in
645
+
check int "Two emails to update" 2 (List.length update_list);
647
+
(* Validate destroy *)
648
+
let destroy = Jmap_core.Jmap_standard_methods.Set.destroy request in
649
+
check bool "Has destroy" true (Option.is_some destroy);
650
+
let destroy_list = Option.get destroy in
651
+
check int "One email to destroy" 1 (List.length destroy_list);
652
+
check string "Destroy ID" "e099" (Jmap_core.Jmap_id.to_string (List.nth destroy_list 0))
654
+
let test_email_set_response () =
655
+
let json = load_json "data/mail/email_set_response.json" in
656
+
let response = Jmap_mail.Jmap_email.Set.response_of_json json in
658
+
(* Validate account_id *)
659
+
let account_id = Jmap_core.Jmap_standard_methods.Set.response_account_id response in
660
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
662
+
(* Validate states *)
663
+
let old_state = Jmap_core.Jmap_standard_methods.Set.old_state response in
664
+
check bool "Has old state" true (Option.is_some old_state);
665
+
check string "Old state" "e42:100" (Option.get old_state);
667
+
let new_state = Jmap_core.Jmap_standard_methods.Set.new_state response in
668
+
check string "New state" "e42:103" new_state;
670
+
(* Validate created *)
671
+
let created = Jmap_core.Jmap_standard_methods.Set.created response in
672
+
check bool "Has created" true (Option.is_some created);
673
+
let created_list = Option.get created in
674
+
check int "One email created" 1 (List.length created_list);
675
+
let (temp_id, email) = List.nth created_list 0 in
676
+
check string "Created temp ID" "temp-email-1" (Jmap_core.Jmap_id.to_string temp_id);
677
+
check string "Created email ID" "e101" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_email.id email));
678
+
check string "Created thread ID" "t050"
679
+
(Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_email.thread_id email));
681
+
(* Validate updated *)
682
+
let updated = Jmap_core.Jmap_standard_methods.Set.updated response in
683
+
check bool "Has updated" true (Option.is_some updated);
684
+
let updated_map = Option.get updated in
685
+
check int "Two emails updated" 2 (List.length updated_map);
687
+
(* Validate destroyed *)
688
+
let destroyed = Jmap_core.Jmap_standard_methods.Set.destroyed response in
689
+
check bool "Has destroyed" true (Option.is_some destroyed);
690
+
let destroyed_list = Option.get destroyed in
691
+
check int "One email destroyed" 1 (List.length destroyed_list);
692
+
check string "Destroyed ID" "e099" (Jmap_core.Jmap_id.to_string (List.nth destroyed_list 0))
694
+
let test_email_import_request () =
695
+
let json = load_json "data/mail/email_import_request.json" in
696
+
let request = Jmap_mail.Jmap_email.Import.request_of_json json in
698
+
(* Validate account_id *)
699
+
let account_id = Jmap_mail.Jmap_email.Import.account_id request in
700
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
702
+
(* Validate ifInState *)
703
+
let if_in_state = Jmap_mail.Jmap_email.Import.if_in_state request in
704
+
check bool "Has ifInState" true (Option.is_some if_in_state);
705
+
check string "ifInState value" "e42:103" (Option.get if_in_state);
707
+
(* Validate emails *)
708
+
let emails = Jmap_mail.Jmap_email.Import.emails request in
709
+
check int "Two emails to import" 2 (List.length emails);
711
+
let (import_id1, import_email1) = List.nth emails 0 in
712
+
check string "First import ID" "temp-import-1" (Jmap_core.Jmap_id.to_string import_id1);
713
+
let blob_id1 = Jmap_mail.Jmap_email.Import.import_blob_id import_email1 in
714
+
check string "First blob ID starts correctly" "Gb5f55i6"
715
+
(String.sub (Jmap_core.Jmap_id.to_string blob_id1) 0 8);
717
+
let keywords1 = Jmap_mail.Jmap_email.Import.import_keywords import_email1 in
718
+
check bool "First email has $seen keyword" true
719
+
(List.mem_assoc "$seen" keywords1)
721
+
let test_email_import_response () =
722
+
let json = load_json "data/mail/email_import_response.json" in
723
+
let response = Jmap_mail.Jmap_email.Import.response_of_json json in
725
+
(* Validate account_id *)
726
+
let account_id = Jmap_mail.Jmap_email.Import.response_account_id response in
727
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
729
+
(* Validate states *)
730
+
let old_state = Jmap_mail.Jmap_email.Import.old_state response in
731
+
check bool "Has old state" true (Option.is_some old_state);
732
+
check string "Old state" "e42:103" (Option.get old_state);
734
+
let new_state = Jmap_mail.Jmap_email.Import.new_state response in
735
+
check string "New state" "e42:105" new_state;
737
+
(* Validate created *)
738
+
let created = Jmap_mail.Jmap_email.Import.created response in
739
+
check bool "Has created" true (Option.is_some created);
740
+
let created_list = Option.get created in
741
+
check int "Two emails imported" 2 (List.length created_list);
743
+
let (temp_id1, email1) = List.nth created_list 0 in
744
+
check string "First temp ID" "temp-import-1" (Jmap_core.Jmap_id.to_string temp_id1);
745
+
check string "First email ID" "e102" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_email.id email1));
746
+
check string "First thread ID" "t051"
747
+
(Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_email.thread_id email1));
749
+
let (temp_id2, email2) = List.nth created_list 1 in
750
+
check string "Second temp ID" "temp-import-2" (Jmap_core.Jmap_id.to_string temp_id2);
751
+
check string "Second email ID" "e103" (Jmap_core.Jmap_id.to_string (Jmap_mail.Jmap_email.id email2))
753
+
let test_email_parse_request () =
754
+
let json = load_json "data/mail/email_parse_request.json" in
755
+
let request = Jmap_mail.Jmap_email.Parse.request_of_json json in
757
+
(* Validate account_id *)
758
+
let account_id = Jmap_mail.Jmap_email.Parse.account_id request in
759
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
761
+
(* Validate blob_ids *)
762
+
let blob_ids = Jmap_mail.Jmap_email.Parse.blob_ids request in
763
+
check int "One blob ID" 1 (List.length blob_ids);
764
+
let blob_id = List.nth blob_ids 0 in
765
+
check string "Blob ID starts correctly" "Gb5f77k8"
766
+
(String.sub (Jmap_core.Jmap_id.to_string blob_id) 0 8);
768
+
(* Validate fetch options *)
769
+
let fetch_text = Jmap_mail.Jmap_email.Parse.fetch_text_body_values request in
770
+
check bool "Fetch text body values" true (Option.value ~default:false fetch_text);
772
+
let fetch_html = Jmap_mail.Jmap_email.Parse.fetch_html_body_values request in
773
+
check bool "Fetch HTML body values" true (Option.value ~default:false fetch_html);
775
+
let max_bytes = Jmap_mail.Jmap_email.Parse.max_body_value_bytes request in
776
+
check bool "Has max bytes" true (Option.is_some max_bytes);
777
+
check int "Max bytes is 16384" 16384
778
+
(Jmap_core.Jmap_primitives.UnsignedInt.to_int (Option.get max_bytes))
780
+
let test_email_parse_response () =
781
+
let json = load_json "data/mail/email_parse_response.json" in
782
+
let response = Jmap_mail.Jmap_email.Parse.response_of_json json in
784
+
(* Validate account_id *)
785
+
let account_id = Jmap_mail.Jmap_email.Parse.response_account_id response in
786
+
check string "Account ID" "u123456" (Jmap_core.Jmap_id.to_string account_id);
788
+
(* Validate parsed *)
789
+
let parsed = Jmap_mail.Jmap_email.Parse.parsed response in
790
+
check bool "Has parsed emails" true (Option.is_some parsed);
791
+
let parsed_list = Option.get parsed in
792
+
check int "One email parsed" 1 (List.length parsed_list);
794
+
let (blob_id, email) = List.nth parsed_list 0 in
795
+
check string "Blob ID starts correctly" "Gb5f77k8"
796
+
(String.sub (Jmap_core.Jmap_id.to_string blob_id) 0 8);
798
+
(* Validate parsed email *)
799
+
check string "Subject" "Important Announcement"
800
+
(Option.get (Jmap_mail.Jmap_email.subject email));
801
+
check bool "Has no attachment" false (Jmap_mail.Jmap_email.has_attachment email);
803
+
(* Validate from *)
804
+
let from = Option.get (Jmap_mail.Jmap_email.from email) in
805
+
check int "One from address" 1 (List.length from);
806
+
let from_addr = List.nth from 0 in
807
+
check string "From name" "Charlie Green"
808
+
(Option.get (Jmap_mail.Jmap_email.EmailAddress.name from_addr));
809
+
check string "From email" "charlie@company.com"
810
+
(Jmap_mail.Jmap_email.EmailAddress.email from_addr);
67
-
let test_email_full () =
68
-
let _json = load_json "test/data/mail/email_get_full_response.json" in
69
-
(* TODO: Parse full Email with bodyStructure *)
70
-
check bool "Full email loaded" true true
812
+
(* Validate bodyStructure (simple text/plain) *)
813
+
let body_structure = Jmap_mail.Jmap_email.body_structure email in
814
+
check bool "Has bodyStructure" true (Option.is_some body_structure);
815
+
let body_part = Option.get body_structure in
816
+
check string "Body type" "text/plain" (Jmap_mail.Jmap_email.BodyPart.type_ body_part);
817
+
check string "Body part ID" "1"
818
+
(Option.get (Jmap_mail.Jmap_email.BodyPart.part_id body_part));
819
+
check int "Body size" 1523
820
+
(Jmap_core.Jmap_primitives.UnsignedInt.to_int (Jmap_mail.Jmap_email.BodyPart.size body_part));
822
+
(* Validate textBody *)
823
+
let text_body = Jmap_mail.Jmap_email.text_body email in
824
+
check bool "Has textBody" true (Option.is_some text_body);
825
+
let text_body_list = Option.get text_body in
826
+
check int "One textBody part" 1 (List.length text_body_list);
828
+
(* Validate htmlBody is empty *)
829
+
let html_body = Jmap_mail.Jmap_email.html_body email in
830
+
check bool "Has htmlBody" true (Option.is_some html_body);
831
+
let html_body_list = Option.get html_body in
832
+
check int "No htmlBody parts" 0 (List.length html_body_list);
834
+
(* Validate attachments is empty *)
835
+
let attachments = Jmap_mail.Jmap_email.attachments email in
836
+
check bool "Has attachments" true (Option.is_some attachments);
837
+
let attachments_list = Option.get attachments in
838
+
check int "No attachments" 0 (List.length attachments_list);
840
+
(* Validate bodyValues *)
841
+
let body_values = Jmap_mail.Jmap_email.body_values email in
842
+
check bool "Has bodyValues" true (Option.is_some body_values);
843
+
let values_list = Option.get body_values in
844
+
check int "One bodyValue" 1 (List.length values_list);
845
+
check bool "Has bodyValue for part 1" true (List.mem_assoc "1" values_list);
846
+
let body_value = List.assoc "1" values_list in
847
+
let content = Jmap_mail.Jmap_email.BodyValue.value body_value in
848
+
check bool "Content starts with 'Team'" true
849
+
(String.starts_with ~prefix:"Team" content);
851
+
(* Validate notParsable and notFound are empty *)
852
+
let not_parsable = Jmap_mail.Jmap_email.Parse.not_parsable response in
853
+
check bool "Has notParsable" true (Option.is_some not_parsable);
854
+
check int "No unparsable blobs" 0 (List.length (Option.get not_parsable));
856
+
let not_found = Jmap_mail.Jmap_email.Parse.not_found response in
857
+
check bool "Has notFound" true (Option.is_some not_found);
858
+
check int "No blobs not found" 0 (List.length (Option.get not_found))
(** Test suite definition *)
···
test_case "Get response" `Quick test_get_response;
test_case "Session object" `Quick test_session;
870
+
"Mail Protocol - Mailbox", [
test_case "Mailbox/get request" `Quick test_mailbox_get_request;
test_case "Mailbox/get response" `Quick test_mailbox_get_response;
873
+
test_case "Mailbox/query request" `Quick test_mailbox_query_request;
874
+
test_case "Mailbox/query response" `Quick test_mailbox_query_response;
875
+
test_case "Mailbox/set request" `Quick test_mailbox_set_request;
876
+
test_case "Mailbox/set response" `Quick test_mailbox_set_response;
878
+
"Mail Protocol - Email", [
test_case "Email/get request" `Quick test_email_get_request;
880
+
test_case "Email/get full request" `Quick test_email_get_full_request;
test_case "Email/get response" `Quick test_email_get_response;
87
-
test_case "Email full body" `Quick test_email_full;
882
+
test_case "Email/get full response" `Quick test_email_get_full_response;
883
+
test_case "Email/query request" `Quick test_email_query_request;
884
+
test_case "Email/query response" `Quick test_email_query_response;
885
+
test_case "Email/set request" `Quick test_email_set_request;
886
+
test_case "Email/set response" `Quick test_email_set_response;
887
+
test_case "Email/import request" `Quick test_email_import_request;
888
+
test_case "Email/import response" `Quick test_email_import_response;
889
+
test_case "Email/parse request" `Quick test_email_parse_request;
890
+
test_case "Email/parse response" `Quick test_email_parse_response;