···
+
(** Test JSON serialization validation for JMAP method arguments *)
+
(** Validation helper - checks if JSON contains expected fields *)
+
let validate_json_fields expected_fields json =
+
let open Yojson.Safe.Util in
+
List.for_all (fun expected_field ->
+
List.exists (fun (field_name, _) -> field_name = expected_field) fields
+
(** Test Get_args JSON serialization validation *)
+
Printf.printf "Testing Get_args JSON validation...\n";
+
(* Test with all fields *)
+
let get_args = Get_args.v
+
~properties:["subject"; "from"]
+
let json = Get_args.to_json get_args in
+
assert (validate_json_fields ["accountId"; "ids"; "properties"] json);
+
Printf.printf "✓ Get_args with all fields - validated\n";
+
let minimal_args = Get_args.v ~account_id:"acc456" () in
+
let minimal_json = Get_args.to_json minimal_args in
+
assert (validate_json_fields ["accountId"] minimal_json);
+
Printf.printf "✓ Get_args minimal - validated\n";
+
(* Test result reference *)
+
let (_, ref_json) = Get_args.with_result_reference get_args
+
~result_of:"q1" ~name:"Email/query" ~path:"/ids" in
+
let json_with_ref = Get_args.to_json ~result_reference_ids:(Some ref_json) get_args in
+
assert (validate_json_fields ["accountId"; "ids"; "properties"] json_with_ref);
+
Printf.printf "✓ Get_args with result reference - validated\n"
+
(** Test Query_args JSON serialization validation *)
+
let test_query_args () =
+
Printf.printf "\nTesting Query_args JSON validation...\n";
+
let filter = Filter.property_equals "keywords/$seen" (`Bool false) in
+
let sort = [Comparator.v ~property:"receivedAt" ~is_ascending:false ()] in
+
let query_args = Query_args.v
+
~filter ~sort ~position:0 ~limit:50
+
~calculate_total:true ~collapse_threads:false ()
+
let json = Query_args.to_json query_args in
+
assert (validate_json_fields ["accountId"; "filter"; "sort"; "position"; "limit"; "calculateTotal"; "collapseThreads"] json);
+
Printf.printf "✓ Query_args comprehensive - validated\n";
+
let minimal_query = Query_args.v ~account_id:"acc456" () in
+
let minimal_json = Query_args.to_json minimal_query in
+
assert (validate_json_fields ["accountId"] minimal_json);
+
Printf.printf "✓ Query_args minimal - validated\n"
+
(** Test Set_args JSON serialization validation *)
+
Printf.printf "\nTesting Set_args JSON validation...\n";
+
let create_map = Hashtbl.create 1 in
+
Hashtbl.add create_map "k1" (`Assoc [("subject", `String "Test")]);
+
let update_map = Hashtbl.create 1 in
+
Hashtbl.add update_map "upd1" (`Assoc [("keywords/$seen", `Bool true)]);
+
let set_args = Set_args.v
+
~account_id:"acc123" ~if_in_state:"state456"
+
~create:create_map ~update:update_map
+
~destroy:["destroy1"] ()
+
let json = Set_args.to_json
+
~create_to_json:(fun v -> v)
+
~update_to_json:(fun v -> v) set_args
+
assert (validate_json_fields ["accountId"; "ifInState"; "create"; "update"; "destroy"] json);
+
Printf.printf "✓ Set_args comprehensive - validated\n";
+
let minimal_set = Set_args.v ~account_id:"acc456" () in
+
let minimal_json = Set_args.to_json minimal_set in
+
assert (validate_json_fields ["accountId"] minimal_json);
+
Printf.printf "✓ Set_args minimal - validated\n"
+
(** Test Changes_args JSON serialization validation *)
+
let test_changes_args () =
+
Printf.printf "\nTesting Changes_args JSON validation...\n";
+
let changes_args = Changes_args.v
+
~account_id:"acc123" ~since_state:"state789" ~max_changes:100 ()
+
let json = Changes_args.to_json changes_args in
+
assert (validate_json_fields ["accountId"; "sinceState"; "maxChanges"] json);
+
Printf.printf "✓ Changes_args with maxChanges - validated\n";
+
let minimal_changes = Changes_args.v
+
~account_id:"acc456" ~since_state:"state101" ()
+
let minimal_json = Changes_args.to_json minimal_changes in
+
assert (validate_json_fields ["accountId"; "sinceState"] minimal_json);
+
Printf.printf "✓ Changes_args minimal - validated\n"
+
(** Test Filter and Comparator JSON operations *)
+
let test_filter_comparator () =
+
Printf.printf "\nTesting Filter and Comparator JSON...\n";
+
(* Test various filter types *)
+
("text_contains", Filter.text_contains "subject" "test");
+
("property_equals", Filter.property_equals "from" (`String "user@example.com"));
+
("property_gt", Filter.property_gt "receivedAt" (`String "2023-01-01T00:00:00Z"));
+
("property_in", Filter.property_in "keywords" [`String "$flagged"; `String "$important"]);
+
("and_filter", Filter.and_ [
+
Filter.property_equals "mailboxIds/inbox" (`Bool true);
+
Filter.property_equals "keywords/$seen" (`Bool false)
+
("or_filter", Filter.or_ [
+
Filter.text_contains "subject" "urgent";
+
Filter.text_contains "subject" "important"
+
("not_filter", Filter.not_ (Filter.property_equals "keywords/$draft" (`Bool true)));
+
List.iter (fun (name, filter) ->
+
let json = Filter.to_json filter in
+
(* Basic validation - filters should produce valid JSON *)
+
| `Assoc _ | `String _ | `Int _ | `Bool _ | `List _ ->
+
Printf.printf "✓ Filter %s - valid JSON\n" name
+
| _ -> failwith ("Invalid JSON for filter: " ^ name))
+
("basic", Comparator.v ~property:"receivedAt" ~is_ascending:false ());
+
("with_collation", Comparator.v ~property:"subject" ~is_ascending:true
+
~collation:"i;ascii-casemap" ());
+
("with_keyword", Comparator.v ~property:"size" ~keyword:"numeric" ());
+
List.iter (fun (name, comp) ->
+
let json = Comparator.to_json comp in
+
assert (validate_json_fields ["property"] json);
+
Printf.printf "✓ Comparator %s - validated\n" name
+
(** Test JMAP protocol compliance examples *)
+
let test_jmap_compliance () =
+
Printf.printf "\nTesting JMAP Protocol Compliance...\n";
+
(* Real-world Email/get example *)
+
let email_get = Get_args.v
+
~account_id:"u1234567890"
+
~ids:["Mf8a6c123"; "Mf8a6c456"; "Mf8a6c789"]
+
~properties:["id"; "subject"; "from"; "to"; "receivedAt"; "size"; "preview"; "keywords"]
+
let json = Get_args.to_json email_get in
+
assert (validate_json_fields ["accountId"; "ids"; "properties"] json);
+
Printf.printf "✓ JMAP Email/get request - compliant\n";
+
(* Real-world Email/query example *)
+
let email_filter = Filter.and_ [
+
Filter.property_in "mailboxIds" [`String "Minbox123"];
+
Filter.property_equals "keywords/$seen" (`Bool false);
+
Filter.property_ge "receivedAt" (`String "2023-12-01T00:00:00Z");
+
let email_query = Query_args.v
+
~account_id:"u1234567890"
+
~sort:[Comparator.v ~property:"receivedAt" ~is_ascending:false ()]
+
~limit:50 ~calculate_total:true ()
+
let query_json = Query_args.to_json email_query in
+
assert (validate_json_fields ["accountId"; "filter"; "sort"; "limit"; "calculateTotal"] query_json);
+
Printf.printf "✓ JMAP Email/query request - compliant\n";
+
(* Real-world Email/set example *)
+
let create_emails = Hashtbl.create 1 in
+
Hashtbl.add create_emails "draft001" (`Assoc [
+
("subject", `String "Meeting Tomorrow");
+
("from", `List [`Assoc [("email", `String "sender@company.com"); ("name", `String "John Doe")]]);
+
("to", `List [`Assoc [("email", `String "recipient@company.com"); ("name", `String "Jane Smith")]]);
+
("keywords", `Assoc [("$draft", `Bool true)]);
+
("mailboxIds", `Assoc [("Mdrafts456", `Bool true)]);
+
let update_emails = Hashtbl.create 1 in
+
Hashtbl.add update_emails "Mf8a6c123" (`Assoc [
+
("keywords/$seen", `Bool true);
+
("keywords/$flagged", `Bool true)
+
let email_set = Set_args.v
+
~account_id:"u1234567890"
+
let set_json = Set_args.to_json
+
~create_to_json:(fun v -> v)
+
~update_to_json:(fun v -> v)
+
assert (validate_json_fields ["accountId"; "create"; "update"; "destroy"] set_json);
+
Printf.printf "✓ JMAP Email/set request - compliant\n"
+
(** Main test runner *)
+
Printf.printf "JMAP Method Arguments JSON Serialization Validation\n";
+
Printf.printf "===================================================\n";
+
test_filter_comparator ();
+
test_jmap_compliance ();
+
Printf.printf "\n🎉 All JSON serialization validation tests passed!\n";
+
Printf.printf " The implementation correctly supports:\n";
+
Printf.printf " • Get_args.to_json with result reference support\n";
+
Printf.printf " • Query_args.to_json with filters and sorting\n";
+
Printf.printf " • Set_args.to_json with create/update/destroy operations\n";
+
Printf.printf " • Changes_args.to_json with maxChanges parameter\n";
+
Printf.printf " • Filter.to_json with logical operations\n";
+
Printf.printf " • Comparator.to_json with sorting specifications\n";
+
Printf.printf " • Full JMAP protocol compliance\n"