objective categorical abstract machine language personal data server
at main 377 lines 10 kB view raw
1open Alcotest 2open Hermes_cli 3 4(** helpers *) 5let test_string = testable Fmt.string String.equal 6 7(* parsing a simple object type *) 8let test_parse_simple_object () = 9 let json = 10 {|{ 11 "lexicon": 1, 12 "id": "com.example.test", 13 "defs": { 14 "main": { 15 "type": "object", 16 "properties": { 17 "name": {"type": "string"}, 18 "count": {"type": "integer"} 19 }, 20 "required": ["name"] 21 } 22 } 23 }|} 24 in 25 match Parser.parse_string json with 26 | Ok doc -> 27 check test_string "id matches" "com.example.test" doc.id ; 28 check int "lexicon version" 1 doc.lexicon ; 29 check int "one definition" 1 (List.length doc.defs) 30 | Error e -> 31 fail ("parse failed: " ^ e) 32 33(* parsing string type with constraints *) 34let test_parse_string_type () = 35 let json = 36 {|{ 37 "lexicon": 1, 38 "id": "com.example.string", 39 "defs": { 40 "main": { 41 "type": "object", 42 "properties": { 43 "handle": { 44 "type": "string", 45 "format": "handle", 46 "minLength": 3, 47 "maxLength": 50 48 } 49 } 50 } 51 } 52 }|} 53 in 54 match Parser.parse_string json with 55 | Ok doc -> ( 56 check int "one definition" 1 (List.length doc.defs) ; 57 let def = List.hd doc.defs in 58 match def.type_def with 59 | Lexicon_types.Object spec -> ( 60 check int "one property" 1 (List.length spec.properties) ; 61 let _, prop = List.hd spec.properties in 62 match prop.type_def with 63 | Lexicon_types.String s -> 64 check (option test_string) "format" (Some "handle") s.format ; 65 check (option int) "minLength" (Some 3) s.min_length ; 66 check (option int) "maxLength" (Some 50) s.max_length 67 | _ -> 68 fail "expected string type" ) 69 | _ -> 70 fail "expected object type" ) 71 | Error e -> 72 fail ("parse failed: " ^ e) 73 74(* parsing array type *) 75let test_parse_array_type () = 76 let json = 77 {|{ 78 "lexicon": 1, 79 "id": "com.example.array", 80 "defs": { 81 "main": { 82 "type": "object", 83 "properties": { 84 "items": { 85 "type": "array", 86 "items": {"type": "string"}, 87 "maxLength": 100 88 } 89 } 90 } 91 } 92 }|} 93 in 94 match Parser.parse_string json with 95 | Ok doc -> ( 96 let def = List.hd doc.defs in 97 match def.type_def with 98 | Lexicon_types.Object spec -> ( 99 let _, prop = List.hd spec.properties in 100 match prop.type_def with 101 | Lexicon_types.Array arr -> ( 102 check (option int) "maxLength" (Some 100) arr.max_length ; 103 match arr.items with 104 | Lexicon_types.String _ -> 105 () 106 | _ -> 107 fail "expected string items" ) 108 | _ -> 109 fail "expected array type" ) 110 | _ -> 111 fail "expected object type" ) 112 | Error e -> 113 fail ("parse failed: " ^ e) 114 115(* parsing ref type *) 116let test_parse_ref_type () = 117 let json = 118 {|{ 119 "lexicon": 1, 120 "id": "com.example.ref", 121 "defs": { 122 "main": { 123 "type": "object", 124 "properties": { 125 "user": { 126 "type": "ref", 127 "ref": "com.example.defs#user" 128 } 129 } 130 } 131 } 132 }|} 133 in 134 match Parser.parse_string json with 135 | Ok doc -> ( 136 let def = List.hd doc.defs in 137 match def.type_def with 138 | Lexicon_types.Object spec -> ( 139 let _, prop = List.hd spec.properties in 140 match prop.type_def with 141 | Lexicon_types.Ref r -> 142 check test_string "ref value" "com.example.defs#user" r.ref_ 143 | _ -> 144 fail "expected ref type" ) 145 | _ -> 146 fail "expected object type" ) 147 | Error e -> 148 fail ("parse failed: " ^ e) 149 150(* parsing union type *) 151let test_parse_union_type () = 152 let json = 153 {|{ 154 "lexicon": 1, 155 "id": "com.example.union", 156 "defs": { 157 "main": { 158 "type": "union", 159 "refs": ["#typeA", "#typeB"], 160 "closed": true 161 } 162 } 163 }|} 164 in 165 match Parser.parse_string json with 166 | Ok doc -> ( 167 let def = List.hd doc.defs in 168 match def.type_def with 169 | Lexicon_types.Union u -> 170 check int "two refs" 2 (List.length u.refs) ; 171 check (option bool) "closed" (Some true) u.closed 172 | _ -> 173 fail "expected union type" ) 174 | Error e -> 175 fail ("parse failed: " ^ e) 176 177(* parsing query type *) 178let test_parse_query_type () = 179 let json = 180 {|{ 181 "lexicon": 1, 182 "id": "com.example.getUser", 183 "defs": { 184 "main": { 185 "type": "query", 186 "description": "Get a user", 187 "parameters": { 188 "type": "params", 189 "properties": { 190 "userId": {"type": "string"} 191 }, 192 "required": ["userId"] 193 }, 194 "output": { 195 "encoding": "application/json", 196 "schema": { 197 "type": "object", 198 "properties": { 199 "name": {"type": "string"} 200 } 201 } 202 } 203 } 204 } 205 }|} 206 in 207 match Parser.parse_string json with 208 | Ok doc -> ( 209 let def = List.hd doc.defs in 210 match def.type_def with 211 | Lexicon_types.Query q -> ( 212 check (option test_string) "description" (Some "Get a user") 213 q.description ; 214 ( match q.parameters with 215 | Some params -> 216 check int "one param" 1 (List.length params.properties) 217 | None -> 218 fail "expected parameters" ) ; 219 match q.output with 220 | Some output -> 221 check test_string "encoding" "application/json" output.encoding 222 | None -> 223 fail "expected output" ) 224 | _ -> 225 fail "expected query type" ) 226 | Error e -> 227 fail ("parse failed: " ^ e) 228 229(* parsing procedure type *) 230let test_parse_procedure_type () = 231 let json = 232 {|{ 233 "lexicon": 1, 234 "id": "com.example.createUser", 235 "defs": { 236 "main": { 237 "type": "procedure", 238 "input": { 239 "encoding": "application/json", 240 "schema": { 241 "type": "object", 242 "properties": { 243 "name": {"type": "string"} 244 }, 245 "required": ["name"] 246 } 247 }, 248 "output": { 249 "encoding": "application/json", 250 "schema": { 251 "type": "object", 252 "properties": { 253 "id": {"type": "string"} 254 } 255 } 256 } 257 } 258 } 259 }|} 260 in 261 match Parser.parse_string json with 262 | Ok doc -> ( 263 let def = List.hd doc.defs in 264 match def.type_def with 265 | Lexicon_types.Procedure p -> ( 266 ( match p.input with 267 | Some input -> 268 check test_string "input encoding" "application/json" 269 input.encoding 270 | None -> 271 fail "expected input" ) ; 272 match p.output with 273 | Some output -> 274 check test_string "output encoding" "application/json" 275 output.encoding 276 | None -> 277 fail "expected output" ) 278 | _ -> 279 fail "expected procedure type" ) 280 | Error e -> 281 fail ("parse failed: " ^ e) 282 283(* parsing permission-set type *) 284let test_parse_permission_set () = 285 let json = 286 {|{ 287 "lexicon": 1, 288 "id": "com.example.auth", 289 "defs": { 290 "main": { 291 "type": "permission-set", 292 "title": "Example Auth", 293 "title:de": "Beispiel Auth", 294 "detail": "Access to authentication features", 295 "permissions": [ 296 { 297 "resource": "rpc", 298 "lxm": ["com.example.auth.login", "com.example.auth.logout"], 299 "inheritAud": true 300 }, 301 { 302 "resource": "repo", 303 "collection": ["com.example.auth.session"], 304 "action": ["create", "delete"] 305 } 306 ] 307 } 308 } 309 }|} 310 in 311 match Parser.parse_string json with 312 | Ok doc -> ( 313 check test_string "id matches" "com.example.auth" doc.id ; 314 check int "one definition" 1 (List.length doc.defs) ; 315 let def = List.hd doc.defs in 316 match def.type_def with 317 | Lexicon_types.PermissionSet spec -> 318 check (option test_string) "title" (Some "Example Auth") spec.title ; 319 check (option test_string) "detail" 320 (Some "Access to authentication features") spec.detail ; 321 check int "two permissions" 2 (List.length spec.permissions) ; 322 let perm1 = List.hd spec.permissions in 323 check test_string "first resource" "rpc" perm1.resource ; 324 (* check extra fields are captured *) 325 check bool "has lxm in extra" true (List.mem_assoc "lxm" perm1.extra) 326 | _ -> 327 fail "expected permission-set type" ) 328 | Error e -> 329 fail ("parse failed: " ^ e) 330 331(* parsing invalid JSON *) 332let test_parse_invalid_json () = 333 let json = {|{ invalid json }|} in 334 match Parser.parse_string json with 335 | Ok _ -> 336 fail "should have failed" 337 | Error e -> 338 check bool "has error message" true (String.length e > 0) 339 340(* parsing missing required field *) 341let test_parse_missing_field () = 342 let json = {|{ 343 "lexicon": 1, 344 "defs": {} 345 }|} in 346 match Parser.parse_string json with 347 | Ok _ -> 348 fail "should have failed (missing id)" 349 | Error _ -> 350 () 351 352(** tests *) 353 354let object_tests = 355 [ ("simple object", `Quick, test_parse_simple_object) 356 ; ("string with constraints", `Quick, test_parse_string_type) 357 ; ("array type", `Quick, test_parse_array_type) 358 ; ("ref type", `Quick, test_parse_ref_type) ] 359 360let complex_type_tests = 361 [ ("union type", `Quick, test_parse_union_type) 362 ; ("query type", `Quick, test_parse_query_type) 363 ; ("procedure type", `Quick, test_parse_procedure_type) ] 364 365let error_tests = 366 [ ("invalid json", `Quick, test_parse_invalid_json) 367 ; ("missing field", `Quick, test_parse_missing_field) ] 368 369let permission_set_tests = 370 [("parse permission-set", `Quick, test_parse_permission_set)] 371 372let () = 373 run "Parser" 374 [ ("objects", object_tests) 375 ; ("complex_types", complex_type_tests) 376 ; ("errors", error_tests) 377 ; ("permission-set", permission_set_tests) ]