objective categorical abstract machine language personal data server
at main 325 lines 8.5 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 invalid JSON *) 284let test_parse_invalid_json () = 285 let json = {|{ invalid json }|} in 286 match Parser.parse_string json with 287 | Ok _ -> 288 fail "should have failed" 289 | Error e -> 290 check bool "has error message" true (String.length e > 0) 291 292(* parsing missing required field *) 293let test_parse_missing_field () = 294 let json = {|{ 295 "lexicon": 1, 296 "defs": {} 297 }|} in 298 match Parser.parse_string json with 299 | Ok _ -> 300 fail "should have failed (missing id)" 301 | Error _ -> 302 () 303 304(** tests *) 305 306let object_tests = 307 [ ("simple object", `Quick, test_parse_simple_object) 308 ; ("string with constraints", `Quick, test_parse_string_type) 309 ; ("array type", `Quick, test_parse_array_type) 310 ; ("ref type", `Quick, test_parse_ref_type) ] 311 312let complex_type_tests = 313 [ ("union type", `Quick, test_parse_union_type) 314 ; ("query type", `Quick, test_parse_query_type) 315 ; ("procedure type", `Quick, test_parse_procedure_type) ] 316 317let error_tests = 318 [ ("invalid json", `Quick, test_parse_invalid_json) 319 ; ("missing field", `Quick, test_parse_missing_field) ] 320 321let () = 322 run "Parser" 323 [ ("objects", object_tests) 324 ; ("complex_types", complex_type_tests) 325 ; ("errors", error_tests) ]