OCaml wire format DSL with EverParse 3D output for verified parsers
at main 648 lines 26 kB view raw
1(* Test wire library *) 2 3open Wire 4 5let contains ~sub s = Re.execp (Re.compile (Re.str sub)) s 6 7(* Helper: encode record to string using Codec API *) 8let encode_record_to_string codec v = 9 let ws = Codec.wire_size codec in 10 let buf = Bytes.create ws in 11 Codec.encode codec v buf 0; 12 Ok (Bytes.unsafe_to_string buf) 13 14(* Helper: decode record from string using Codec API *) 15let decode_record_from_string codec s = 16 let ws = Codec.wire_size codec in 17 if String.length s < ws then 18 Error (Unexpected_eof { expected = ws; got = String.length s }) 19 else Ok (Codec.decode codec (Bytes.of_string s) 0) 20 21let test_bitfields () = 22 let bf = 23 struct_ "BF" 24 [ 25 field "x" (bits ~width:6 bf_uint32); 26 field "y" 27 ~constraint_:Expr.(ref "y" <= int 900) 28 (bits ~width:10 bf_uint32); 29 field "z" 30 ~constraint_:Expr.(ref "y" + ref "z" <= int 60000) 31 (bits ~width:16 bf_uint32); 32 ] 33 in 34 let m = module_ "Bitfields" [ typedef bf ] in 35 let output = to_3d m in 36 Alcotest.(check bool) "non-empty output" true (String.length output > 0); 37 Alcotest.(check bool) "contains UINT32" true (contains ~sub:"UINT32" output); 38 Alcotest.(check bool) "contains BF" true (contains ~sub:"BF" output) 39 40let test_enumerations () = 41 let m = 42 module_ "Enumerations" 43 [ 44 enum_decl "Enum8" 45 [ ("Enum8_1", 0); ("Enum8_2", 1); ("Enum8_3", 2) ] 46 uint8; 47 ] 48 in 49 let output = to_3d m in 50 Alcotest.(check bool) "non-empty output" true (String.length output > 0); 51 Alcotest.(check bool) "contains enum" true (contains ~sub:"enum" output); 52 Alcotest.(check bool) "contains Enum8_1" true (contains ~sub:"Enum8_1" output) 53 54let test_field_dependence () = 55 let t_struct = param_struct "t" [ param "a" uint32 ] [ field "x" uint32 ] in 56 let s_struct = 57 struct_ "s" 58 [ field "a" uint32; field "b" (apply (type_ref "t") [ ref "a" ]) ] 59 in 60 let m = module_ "FieldDependence" [ typedef t_struct; typedef s_struct ] in 61 let output = to_3d m in 62 Alcotest.(check bool) "non-empty output" true (String.length output > 0); 63 Alcotest.(check bool) "contains param" true (contains ~sub:"UINT32 a" output) 64 65let test_casetype () = 66 let d_casetype = 67 casetype_decl "_D" 68 [ param "key" uint32 ] 69 uint32 70 [ decl_case 1 uint16; decl_case 2 uint32 ] 71 in 72 let m = module_ "Casetype" [ d_casetype ] in 73 let output = to_3d m in 74 Alcotest.(check bool) "non-empty output" true (String.length output > 0); 75 Alcotest.(check bool) 76 "contains casetype" true 77 (contains ~sub:"casetype" output); 78 Alcotest.(check bool) 79 "contains switch" true 80 (contains ~sub:"switch (key)" output); 81 (* Public name should not have underscore *) 82 Alcotest.(check bool) "public name is D" true (contains ~sub:"} D;" output) 83 84let test_pretty_print () = 85 let simple = 86 struct_ "Simple" [ field "a" uint8; field "b" uint16be; field "c" uint32 ] 87 in 88 let m = module_ "Simple" [ typedef simple ] in 89 let output = to_3d m in 90 Alcotest.(check bool) "contains typedef" true (String.length output > 0); 91 Alcotest.(check bool) "contains UINT8" true (contains ~sub:"UINT8" output); 92 Alcotest.(check bool) 93 "contains UINT16BE" true 94 (contains ~sub:"UINT16BE" output) 95 96(* Parsing tests *) 97 98let test_parse_uint8 () = 99 let input = "\x42" in 100 match parse_string uint8 input with 101 | Ok v -> Alcotest.(check int) "uint8 value" 0x42 v 102 | Error e -> Alcotest.failf "%a" pp_parse_error e 103 104let test_parse_uint16_le () = 105 let input = "\x01\x02" in 106 match parse_string uint16 input with 107 | Ok v -> Alcotest.(check int) "uint16 le value" 0x0201 v 108 | Error e -> Alcotest.failf "%a" pp_parse_error e 109 110let test_parse_uint16_be () = 111 let input = "\x01\x02" in 112 match parse_string uint16be input with 113 | Ok v -> Alcotest.(check int) "uint16 be value" 0x0102 v 114 | Error e -> Alcotest.failf "%a" pp_parse_error e 115 116let test_parse_uint32_le () = 117 let input = "\x01\x02\x03\x04" in 118 match parse_string uint32 input with 119 | Ok v -> Alcotest.(check int) "uint32 le value" 0x04030201 v 120 | Error e -> Alcotest.failf "%a" pp_parse_error e 121 122let test_parse_uint32_be () = 123 let input = "\x01\x02\x03\x04" in 124 match parse_string uint32be input with 125 | Ok v -> Alcotest.(check int) "uint32 be value" 0x01020304 v 126 | Error e -> Alcotest.failf "%a" pp_parse_error e 127 128let test_parse_uint64_le () = 129 let input = "\x01\x02\x03\x04\x05\x06\x07\x08" in 130 match parse_string uint64 input with 131 | Ok v -> Alcotest.(check int64) "uint64 le value" 0x0807060504030201L v 132 | Error e -> Alcotest.failf "%a" pp_parse_error e 133 134let test_parse_array () = 135 let input = "\x01\x02\x03" in 136 let t = array ~len:(int 3) uint8 in 137 match parse_string t input with 138 | Ok v -> Alcotest.(check (list int)) "array values" [ 1; 2; 3 ] v 139 | Error e -> Alcotest.failf "%a" pp_parse_error e 140 141let test_parse_byte_array () = 142 let input = "hello" in 143 let t = byte_array ~size:(int 5) in 144 match parse_string t input with 145 | Ok v -> Alcotest.(check string) "byte_array value" "hello" v 146 | Error e -> Alcotest.failf "%a" pp_parse_error e 147 148let test_parse_enum_valid () = 149 let input = "\x01" in 150 let t = enum "Test" [ ("A", 0); ("B", 1); ("C", 2) ] uint8 in 151 match parse_string t input with 152 | Ok v -> Alcotest.(check int) "enum value" 1 v 153 | Error e -> Alcotest.failf "%a" pp_parse_error e 154 155let test_parse_enum_invalid () = 156 let input = "\xFF" in 157 let t = enum "Test" [ ("A", 0); ("B", 1); ("C", 2) ] uint8 in 158 match parse_string t input with 159 | Ok _ -> Alcotest.fail "expected error for invalid enum" 160 | Error (Invalid_enum { value; _ }) -> 161 Alcotest.(check int) "invalid enum value" 255 value 162 | Error e -> Alcotest.failf "wrong error: %a" pp_parse_error e 163 164let test_parse_all_bytes () = 165 let input = "hello world" in 166 match parse_string all_bytes input with 167 | Ok v -> Alcotest.(check string) "all_bytes value" "hello world" v 168 | Error e -> Alcotest.failf "%a" pp_parse_error e 169 170let test_parse_all_zeros_valid () = 171 let input = "\x00\x00\x00" in 172 match parse_string all_zeros input with 173 | Ok _ -> () 174 | Error e -> Alcotest.failf "%a" pp_parse_error e 175 176let test_parse_all_zeros_invalid () = 177 let input = "\x00\x01\x00" in 178 match parse_string all_zeros input with 179 | Ok _ -> Alcotest.fail "expected error for non-zero byte" 180 | Error (All_zeros_failed { offset }) -> 181 Alcotest.(check int) "non-zero offset" 1 offset 182 | Error e -> Alcotest.failf "wrong error: %a" pp_parse_error e 183 184let test_parse_bitfield () = 185 let input = "\xFF\xFF\xFF\xFF" in 186 let t = bits ~width:6 bf_uint32 in 187 match parse_string t input with 188 | Ok v -> Alcotest.(check int) "bitfield value (6 bits)" 63 v 189 | Error e -> Alcotest.failf "%a" pp_parse_error e 190 191let test_parse_eof () = 192 let input = "\x01" in 193 match parse_string uint16 input with 194 | Ok _ -> Alcotest.fail "expected EOF error" 195 | Error (Unexpected_eof { expected; got }) -> 196 Alcotest.(check int) "expected bytes" 2 expected; 197 Alcotest.(check int) "got bytes" 1 got 198 | Error e -> Alcotest.failf "wrong error: %a" pp_parse_error e 199 200let test_parse_struct () = 201 let input = "\x01\x02\x03" in 202 let s = 203 struct_ "Test" [ field "a" uint8; field "b" uint8; field "c" uint8 ] 204 in 205 let t = struct_typ s in 206 match parse_string t input with 207 | Ok () -> () 208 | Error e -> Alcotest.failf "%a" pp_parse_error e 209 210let test_parse_struct_constraint () = 211 (* Test struct with constraint that should pass *) 212 let input = "\x0A" in 213 let s = 214 struct_ "Constrained" 215 [ field "x" ~constraint_:Expr.(ref "x" <= int 100) uint8 ] 216 in 217 let t = struct_typ s in 218 match parse_string t input with 219 | Ok () -> () 220 | Error e -> Alcotest.failf "%a" pp_parse_error e 221 222let test_parse_struct_constraint_fail () = 223 (* Test struct with constraint that should fail *) 224 let input = "\xFF" in 225 let s = 226 struct_ "Constrained" 227 [ field "x" ~constraint_:Expr.(ref "x" <= int 100) uint8 ] 228 in 229 let t = struct_typ s in 230 match parse_string t input with 231 | Ok _ -> Alcotest.fail "expected constraint failure" 232 | Error (Constraint_failed _) -> () 233 | Error e -> Alcotest.failf "wrong error: %a" pp_parse_error e 234 235(* Encoding tests *) 236 237let test_encode_uint8 () = 238 let encoded = encode_to_string uint8 0x42 in 239 Alcotest.(check string) "uint8 encoding" "\x42" encoded 240 241let test_encode_uint16_le () = 242 let encoded = encode_to_string uint16 0x0201 in 243 Alcotest.(check string) "uint16 le encoding" "\x01\x02" encoded 244 245let test_encode_uint16_be () = 246 let encoded = encode_to_string uint16be 0x0102 in 247 Alcotest.(check string) "uint16 be encoding" "\x01\x02" encoded 248 249let test_encode_uint32_le () = 250 let encoded = encode_to_string uint32 0x04030201 in 251 Alcotest.(check string) "uint32 le encoding" "\x01\x02\x03\x04" encoded 252 253let test_encode_uint32_be () = 254 let encoded = encode_to_string uint32be 0x01020304 in 255 Alcotest.(check string) "uint32 be encoding" "\x01\x02\x03\x04" encoded 256 257let test_encode_array () = 258 let t = array ~len:(int 3) uint8 in 259 let encoded = encode_to_string t [ 1; 2; 3 ] in 260 Alcotest.(check string) "array encoding" "\x01\x02\x03" encoded 261 262let test_encode_byte_array () = 263 let t = byte_array ~size:(int 5) in 264 let encoded = encode_to_string t "hello" in 265 Alcotest.(check string) "byte_array encoding" "hello" encoded 266 267let test_encode_enum () = 268 let t = enum "Test" [ ("A", 0); ("B", 1); ("C", 2) ] uint8 in 269 let encoded = encode_to_string t 1 in 270 Alcotest.(check string) "enum encoding" "\x01" encoded 271 272let test_encode_bitfield () = 273 let t = bits ~width:6 bf_uint32 in 274 let encoded = encode_to_string t 63 in 275 (* 63 = 0x3F, but stored in 4 bytes as uint32 LE *) 276 Alcotest.(check string) "bitfield encoding" "\x3F\x00\x00\x00" encoded 277 278(* Roundtrip tests *) 279 280let test_roundtrip_uint8 () = 281 let original = 0x42 in 282 let encoded = encode_to_string uint8 original in 283 match parse_string uint8 encoded with 284 | Ok decoded -> Alcotest.(check int) "roundtrip uint8" original decoded 285 | Error e -> Alcotest.failf "%a" pp_parse_error e 286 287let test_roundtrip_uint16 () = 288 let original = 0x1234 in 289 let encoded = encode_to_string uint16 original in 290 match parse_string uint16 encoded with 291 | Ok decoded -> Alcotest.(check int) "roundtrip uint16" original decoded 292 | Error e -> Alcotest.failf "%a" pp_parse_error e 293 294let test_roundtrip_uint32 () = 295 let original = 0x12345678 in 296 let encoded = encode_to_string uint32 original in 297 match parse_string uint32 encoded with 298 | Ok decoded -> Alcotest.(check int) "roundtrip uint32" original decoded 299 | Error e -> Alcotest.failf "%a" pp_parse_error e 300 301let test_roundtrip_array () = 302 let original = [ 1; 2; 3; 4; 5 ] in 303 let t = array ~len:(int 5) uint8 in 304 let encoded = encode_to_string t original in 305 match parse_string t encoded with 306 | Ok decoded -> Alcotest.(check (list int)) "roundtrip array" original decoded 307 | Error e -> Alcotest.failf "%a" pp_parse_error e 308 309let test_roundtrip_byte_array () = 310 let original = "hello" in 311 let t = byte_array ~size:(int 5) in 312 let encoded = encode_to_string t original in 313 match parse_string t encoded with 314 | Ok decoded -> 315 Alcotest.(check string) "roundtrip byte_array" original decoded 316 | Error e -> Alcotest.failf "%a" pp_parse_error e 317 318(* Record codec tests *) 319 320type simple_record = { a : int; b : int; c : int } 321 322let simple_record_codec = 323 let open Codec in 324 record "SimpleRecord" (fun a b c -> { a; b; c }) 325 |+ field "a" uint8 (fun r -> r.a) 326 |+ field "b" uint16 (fun r -> r.b) 327 |+ field "c" uint32 (fun r -> r.c) 328 |> seal 329 330let test_record_encode () = 331 let v = { a = 0x42; b = 0x1234; c = 0x56789ABC } in 332 match encode_record_to_string simple_record_codec v with 333 | Error e -> Alcotest.failf "%a" pp_parse_error e 334 | Ok encoded -> 335 (* uint8 + uint16_le + uint32_le *) 336 Alcotest.(check int) "length" 7 (String.length encoded); 337 Alcotest.(check int) "byte 0 (a)" 0x42 (Char.code encoded.[0]); 338 (* uint16 LE: 0x1234 -> 0x34, 0x12 *) 339 Alcotest.(check int) "byte 1 (b low)" 0x34 (Char.code encoded.[1]); 340 Alcotest.(check int) "byte 2 (b high)" 0x12 (Char.code encoded.[2]) 341 342let test_record_decode () = 343 let input = "\x42\x34\x12\xBC\x9A\x78\x56" in 344 match decode_record_from_string simple_record_codec input with 345 | Ok v -> 346 Alcotest.(check int) "a" 0x42 v.a; 347 Alcotest.(check int) "b" 0x1234 v.b; 348 Alcotest.(check int) "c" 0x56789ABC v.c 349 | Error e -> Alcotest.failf "%a" pp_parse_error e 350 351let test_record_roundtrip () = 352 let original = { a = 0xAB; b = 0xCDEF; c = 0x12345678 } in 353 match encode_record_to_string simple_record_codec original with 354 | Error e -> Alcotest.failf "encode: %a" pp_parse_error e 355 | Ok encoded -> ( 356 match decode_record_from_string simple_record_codec encoded with 357 | Ok decoded -> 358 Alcotest.(check int) "a roundtrip" original.a decoded.a; 359 Alcotest.(check int) "b roundtrip" original.b decoded.b; 360 Alcotest.(check int) "c roundtrip" original.c decoded.c 361 | Error e -> Alcotest.failf "%a" pp_parse_error e) 362 363let test_record_to_struct () = 364 let s = Codec.to_struct simple_record_codec in 365 let m = module_ "SimpleRecord" [ typedef s ] in 366 let output = to_3d m in 367 Alcotest.(check bool) "contains UINT8" true (contains ~sub:"UINT8" output); 368 Alcotest.(check bool) "contains UINT16" true (contains ~sub:"UINT16" output); 369 Alcotest.(check bool) "contains UINT32" true (contains ~sub:"UINT32" output); 370 Alcotest.(check bool) "contains field a" true (contains ~sub:"a;" output); 371 Alcotest.(check bool) "contains field b" true (contains ~sub:"b;" output); 372 Alcotest.(check bool) "contains field c" true (contains ~sub:"c;" output) 373 374(* Record with multiple uint16be fields *) 375type multi_record = { x : int; y : int } 376 377let multi_record_codec = 378 let open Codec in 379 record "MultiRecord" (fun x y -> { x; y }) 380 |+ field "x" uint16be (fun r -> r.x) 381 |+ field "y" uint16be (fun r -> r.y) 382 |> seal 383 384let test_record_with_multi () = 385 let original = { x = 0x1234; y = 0x5678 } in 386 match encode_record_to_string multi_record_codec original with 387 | Error e -> Alcotest.failf "encode: %a" pp_parse_error e 388 | Ok encoded -> ( 389 Alcotest.(check int) "length" 4 (String.length encoded); 390 match decode_record_from_string multi_record_codec encoded with 391 | Ok decoded -> 392 Alcotest.(check int) "x" original.x decoded.x; 393 Alcotest.(check int) "y" original.y decoded.y 394 | Error e -> Alcotest.failf "%a" pp_parse_error e) 395 396(* Record with byte_array field *) 397type ba_record = { id : int; uuid : string; tag : int } 398 399let ba_record_codec = 400 let open Codec in 401 record "BaRecord" (fun id uuid tag -> { id; uuid; tag }) 402 |+ field "id" uint32be (fun r -> r.id) 403 |+ field "uuid" (byte_array ~size:(int 16)) (fun r -> r.uuid) 404 |+ field "tag" uint16be (fun r -> r.tag) 405 |> seal 406 407let test_record_byte_array_roundtrip () = 408 let original = { id = 0x12345678; uuid = "0123456789abcdef"; tag = 0xABCD } in 409 match encode_record_to_string ba_record_codec original with 410 | Error e -> Alcotest.failf "encode: %a" pp_parse_error e 411 | Ok encoded -> ( 412 Alcotest.(check int) "wire size" 22 (String.length encoded); 413 match decode_record_from_string ba_record_codec encoded with 414 | Ok decoded -> 415 Alcotest.(check int) "id" original.id decoded.id; 416 Alcotest.(check string) "uuid" original.uuid decoded.uuid; 417 Alcotest.(check int) "tag" original.tag decoded.tag 418 | Error e -> Alcotest.failf "%a" pp_parse_error e) 419 420let test_record_byte_array_padding () = 421 (* Short string should be zero-padded *) 422 let original = { id = 1; uuid = "short"; tag = 2 } in 423 match encode_record_to_string ba_record_codec original with 424 | Error e -> Alcotest.failf "encode: %a" pp_parse_error e 425 | Ok encoded -> ( 426 Alcotest.(check int) "wire size" 22 (String.length encoded); 427 (* Verify zero padding: bytes 9..19 should be zero *) 428 for i = 9 to 19 do 429 Alcotest.(check int) 430 (Fmt.str "padding byte %d" i) 431 0 432 (Char.code encoded.[i]) 433 done; 434 match decode_record_from_string ba_record_codec encoded with 435 | Ok decoded -> 436 (* Decoded uuid includes the zero padding *) 437 Alcotest.(check int) "uuid length" 16 (String.length decoded.uuid); 438 Alcotest.(check string) 439 "uuid prefix" "short" 440 (String.sub decoded.uuid 0 5) 441 | Error e -> Alcotest.failf "%a" pp_parse_error e) 442 443(* Codec bitfield tests *) 444 445type bf32_record = { bf_a : int; bf_b : int; bf_c : int; bf_d : int } 446 447let bf32_codec = 448 let open Codec in 449 record "Bf32Test" (fun a b c d -> { bf_a = a; bf_b = b; bf_c = c; bf_d = d }) 450 |+ field "a" (bits ~width:3 bf_uint32be) (fun t -> t.bf_a) 451 |+ field "b" (bits ~width:5 bf_uint32be) (fun t -> t.bf_b) 452 |+ field "c" (bits ~width:16 bf_uint32be) (fun t -> t.bf_c) 453 |+ field "d" (bits ~width:8 bf_uint32be) (fun t -> t.bf_d) 454 |> seal 455 456type bf16_record = { 457 bf_ver : int; 458 bf_flags : int; 459 bf_id : int; 460 bf_count : int; 461 bf_len : int; 462} 463 464let bf16_codec = 465 let open Codec in 466 record "Bf16Test" (fun ver flags id count len -> 467 { 468 bf_ver = ver; 469 bf_flags = flags; 470 bf_id = id; 471 bf_count = count; 472 bf_len = len; 473 }) 474 |+ field "ver" (bits ~width:3 bf_uint16be) (fun t -> t.bf_ver) 475 |+ field "flags" (bits ~width:2 bf_uint16be) (fun t -> t.bf_flags) 476 |+ field "id" (bits ~width:11 bf_uint16be) (fun t -> t.bf_id) 477 |+ field "count" (bits ~width:14 bf_uint16be) (fun t -> t.bf_count) 478 |+ field "len" (bits ~width:2 bf_uint16be) (fun t -> t.bf_len) 479 |> seal 480 481let test_codec_bitfield_wire_size () = 482 Alcotest.(check int) "bf32 wire_size" 4 (Codec.wire_size bf32_codec); 483 Alcotest.(check int) "bf16 wire_size" 4 (Codec.wire_size bf16_codec) 484 485let test_codec_bitfield_roundtrip () = 486 let original = { bf_a = 5; bf_b = 20; bf_c = 0x1234; bf_d = 0xAB } in 487 match encode_record_to_string bf32_codec original with 488 | Error e -> Alcotest.failf "encode: %a" pp_parse_error e 489 | Ok encoded -> ( 490 match decode_record_from_string bf32_codec encoded with 491 | Ok decoded -> 492 Alcotest.(check int) "a" original.bf_a decoded.bf_a; 493 Alcotest.(check int) "b" original.bf_b decoded.bf_b; 494 Alcotest.(check int) "c" original.bf_c decoded.bf_c; 495 Alcotest.(check int) "d" original.bf_d decoded.bf_d 496 | Error e -> Alcotest.failf "%a" pp_parse_error e) 497 498let test_codec_bitfield_byte_layout () = 499 (* a=5 (3b), b=20 (5b), c=0x1234 (16b), d=0xAB (8b) 500 MSB-first packing: 101_10100_0001001000110100_10101011 501 = 0xB4 0x12 0x34 0xAB *) 502 let v = { bf_a = 5; bf_b = 20; bf_c = 0x1234; bf_d = 0xAB } in 503 match encode_record_to_string bf32_codec v with 504 | Error e -> Alcotest.failf "encode: %a" pp_parse_error e 505 | Ok encoded -> 506 Alcotest.(check int) "length" 4 (String.length encoded); 507 Alcotest.(check int) "byte 0" 0xB4 (Char.code encoded.[0]); 508 Alcotest.(check int) "byte 1" 0x12 (Char.code encoded.[1]); 509 Alcotest.(check int) "byte 2" 0x34 (Char.code encoded.[2]); 510 Alcotest.(check int) "byte 3" 0xAB (Char.code encoded.[3]) 511 512let test_codec_bitfield_decode () = 513 (* Decode 0xB41234AB -> a=5, b=20, c=0x1234, d=0xAB *) 514 let input = "\xB4\x12\x34\xAB" in 515 match decode_record_from_string bf32_codec input with 516 | Ok v -> 517 Alcotest.(check int) "a" 5 v.bf_a; 518 Alcotest.(check int) "b" 20 v.bf_b; 519 Alcotest.(check int) "c" 0x1234 v.bf_c; 520 Alcotest.(check int) "d" 0xAB v.bf_d 521 | Error e -> Alcotest.failf "%a" pp_parse_error e 522 523let test_codec_bitfield_multi_group () = 524 (* Two bf_uint16be groups: (3+2+11=16) + (14+2=16) = 32 bits = 4 bytes *) 525 let v = 526 { bf_ver = 5; bf_flags = 2; bf_id = 0x7FF; bf_count = 0x3FFF; bf_len = 3 } 527 in 528 match encode_record_to_string bf16_codec v with 529 | Error e -> Alcotest.failf "encode: %a" pp_parse_error e 530 | Ok encoded -> ( 531 Alcotest.(check int) "length" 4 (String.length encoded); 532 (* First group: 101_10_11111111111 = 0xB7FF *) 533 Alcotest.(check int) "byte 0" 0xB7 (Char.code encoded.[0]); 534 Alcotest.(check int) "byte 1" 0xFF (Char.code encoded.[1]); 535 (* Second group: 11111111111111_11 = 0xFFFF *) 536 Alcotest.(check int) "byte 2" 0xFF (Char.code encoded.[2]); 537 Alcotest.(check int) "byte 3" 0xFF (Char.code encoded.[3]); 538 (* Roundtrip decode *) 539 match decode_record_from_string bf16_codec encoded with 540 | Ok decoded -> 541 Alcotest.(check int) "ver" v.bf_ver decoded.bf_ver; 542 Alcotest.(check int) "flags" v.bf_flags decoded.bf_flags; 543 Alcotest.(check int) "id" v.bf_id decoded.bf_id; 544 Alcotest.(check int) "count" v.bf_count decoded.bf_count; 545 Alcotest.(check int) "len" v.bf_len decoded.bf_len 546 | Error e -> Alcotest.failf "%a" pp_parse_error e) 547 548let test_codec_bitfield_to_struct () = 549 let s = Codec.to_struct bf32_codec in 550 let m = module_ "Bf32Test" [ typedef s ] in 551 let output = to_3d m in 552 Alcotest.(check bool) 553 "contains UINT32BE" true 554 (contains ~sub:"UINT32BE" output); 555 Alcotest.(check bool) "contains field a" true (contains ~sub:"a" output); 556 Alcotest.(check bool) "contains field b" true (contains ~sub:"b" output) 557 558(* FFI stub generation tests *) 559 560let test_c_stubs () = 561 let s = 562 struct_ "SimpleHeader" 563 [ field "version" uint8; field "length" uint16; field "flags" uint8 ] 564 in 565 let stubs = to_c_stubs [ s ] in 566 Alcotest.(check bool) 567 "contains read stub" true 568 (contains ~sub:"caml_wire_SimpleHeader_read" stubs); 569 Alcotest.(check bool) 570 "contains write stub" true 571 (contains ~sub:"caml_wire_SimpleHeader_write" stubs) 572 573let suite = 574 ( "wire", 575 [ 576 (* generation *) 577 Alcotest.test_case "generation: bitfields" `Quick test_bitfields; 578 Alcotest.test_case "generation: enumerations" `Quick test_enumerations; 579 Alcotest.test_case "generation: field dependence" `Quick 580 test_field_dependence; 581 Alcotest.test_case "generation: casetype" `Quick test_casetype; 582 Alcotest.test_case "generation: pretty print" `Quick test_pretty_print; 583 (* parsing *) 584 Alcotest.test_case "parse: uint8" `Quick test_parse_uint8; 585 Alcotest.test_case "parse: uint16 le" `Quick test_parse_uint16_le; 586 Alcotest.test_case "parse: uint16 be" `Quick test_parse_uint16_be; 587 Alcotest.test_case "parse: uint32 le" `Quick test_parse_uint32_le; 588 Alcotest.test_case "parse: uint32 be" `Quick test_parse_uint32_be; 589 Alcotest.test_case "parse: uint64 le" `Quick test_parse_uint64_le; 590 Alcotest.test_case "parse: array" `Quick test_parse_array; 591 Alcotest.test_case "parse: byte_array" `Quick test_parse_byte_array; 592 Alcotest.test_case "parse: enum valid" `Quick test_parse_enum_valid; 593 Alcotest.test_case "parse: enum invalid" `Quick test_parse_enum_invalid; 594 Alcotest.test_case "parse: all_bytes" `Quick test_parse_all_bytes; 595 Alcotest.test_case "parse: all_zeros valid" `Quick 596 test_parse_all_zeros_valid; 597 Alcotest.test_case "parse: all_zeros invalid" `Quick 598 test_parse_all_zeros_invalid; 599 Alcotest.test_case "parse: bitfield" `Quick test_parse_bitfield; 600 Alcotest.test_case "parse: eof error" `Quick test_parse_eof; 601 Alcotest.test_case "parse: struct" `Quick test_parse_struct; 602 Alcotest.test_case "parse: struct constraint" `Quick 603 test_parse_struct_constraint; 604 Alcotest.test_case "parse: struct constraint fail" `Quick 605 test_parse_struct_constraint_fail; 606 (* encoding *) 607 Alcotest.test_case "encode: uint8" `Quick test_encode_uint8; 608 Alcotest.test_case "encode: uint16 le" `Quick test_encode_uint16_le; 609 Alcotest.test_case "encode: uint16 be" `Quick test_encode_uint16_be; 610 Alcotest.test_case "encode: uint32 le" `Quick test_encode_uint32_le; 611 Alcotest.test_case "encode: uint32 be" `Quick test_encode_uint32_be; 612 Alcotest.test_case "encode: array" `Quick test_encode_array; 613 Alcotest.test_case "encode: byte_array" `Quick test_encode_byte_array; 614 Alcotest.test_case "encode: enum" `Quick test_encode_enum; 615 Alcotest.test_case "encode: bitfield" `Quick test_encode_bitfield; 616 (* roundtrip *) 617 Alcotest.test_case "roundtrip: uint8" `Quick test_roundtrip_uint8; 618 Alcotest.test_case "roundtrip: uint16" `Quick test_roundtrip_uint16; 619 Alcotest.test_case "roundtrip: uint32" `Quick test_roundtrip_uint32; 620 Alcotest.test_case "roundtrip: array" `Quick test_roundtrip_array; 621 Alcotest.test_case "roundtrip: byte_array" `Quick 622 test_roundtrip_byte_array; 623 (* record *) 624 Alcotest.test_case "record: encode" `Quick test_record_encode; 625 Alcotest.test_case "record: decode" `Quick test_record_decode; 626 Alcotest.test_case "record: roundtrip" `Quick test_record_roundtrip; 627 Alcotest.test_case "record: to_struct" `Quick test_record_to_struct; 628 Alcotest.test_case "record: with_multi" `Quick test_record_with_multi; 629 Alcotest.test_case "record: byte_array roundtrip" `Quick 630 test_record_byte_array_roundtrip; 631 Alcotest.test_case "record: byte_array padding" `Quick 632 test_record_byte_array_padding; 633 (* codec bitfields *) 634 Alcotest.test_case "codec bitfield: wire_size" `Quick 635 test_codec_bitfield_wire_size; 636 Alcotest.test_case "codec bitfield: roundtrip" `Quick 637 test_codec_bitfield_roundtrip; 638 Alcotest.test_case "codec bitfield: byte layout" `Quick 639 test_codec_bitfield_byte_layout; 640 Alcotest.test_case "codec bitfield: decode" `Quick 641 test_codec_bitfield_decode; 642 Alcotest.test_case "codec bitfield: multi group" `Quick 643 test_codec_bitfield_multi_group; 644 Alcotest.test_case "codec bitfield: to_struct" `Quick 645 test_codec_bitfield_to_struct; 646 (* ffi stubs *) 647 Alcotest.test_case "ffi: c_stubs" `Quick test_c_stubs; 648 ] )