Yaml encoder/decoder for OCaml jsont codecs

remove of_string functions, add multidoc and fix location eol

+874 -225
+85 -34
lib/yamlt.ml
··· 3 3 SPDX-License-Identifier: ISC 4 4 ---------------------------------------------------------------------------*) 5 5 6 - open Bytesrw 7 6 open Jsont.Repr 8 7 open Yamlrw 9 8 ··· 65 64 let first_line = 66 65 (start.Position.line, start.Position.index - start.Position.column + 1) 67 66 in 67 + (* Handle case where stop is at the start of a new line (column 1) 68 + This happens when the span includes a trailing newline. 69 + The last_byte is on the previous line, so we need to calculate 70 + the line start position based on last_byte, not stop. *) 68 71 let last_line = 69 - (stop.Position.line, stop.Position.index - stop.Position.column + 1) 72 + if stop.Position.column = 1 && stop.Position.line > start.Position.line then 73 + (* last_byte is on the previous line (stop.line - 1) 74 + We need to estimate where that line starts. Since we don't have 75 + the full text, we can't calculate it exactly, but we can use: 76 + last_byte - (estimated_column - 1) 77 + For now, we'll use the same line as start if they're close, 78 + or just report it as the previous line. *) 79 + let last_line_num = stop.Position.line - 1 in 80 + (* Estimate: assume last_byte is somewhere on the previous line. 81 + We'll use the byte position minus a reasonable offset. 82 + This is approximate but better than wrapping to the next line. *) 83 + if last_line_num = start.Position.line then 84 + (* Same line as start - use start's line position *) 85 + first_line 86 + else 87 + (* Different line - estimate line start as last_byte minus some offset 88 + Since we subtracted 1 from stop.index to get last_byte, and stop.column was 1, 89 + last_byte should be the newline character on the previous line. 90 + The line likely started much earlier, but we'll estimate conservatively. *) 91 + (last_line_num, last_byte) 92 + else 93 + (stop.Position.line, stop.Position.index - stop.Position.column + 1) 70 94 in 71 95 let textloc = 72 96 Jsont.Textloc.make ~file:d.file ~first_byte ~last_byte ~first_line ··· 656 680 in 657 681 loop () 658 682 683 + (* Skip to the end of the current document after an error *) 684 + let skip_to_document_end d = 685 + let rec loop depth = 686 + match peek_event d with 687 + | None -> () 688 + | Some { Event.event = Event.Stream_end; _ } -> () 689 + | Some { Event.event = Event.Document_end _; _ } -> 690 + skip_event d; 691 + if depth = 0 then () else loop (depth - 1) 692 + | Some { Event.event = Event.Document_start _; _ } -> 693 + skip_event d; 694 + loop (depth + 1) 695 + | Some _ -> 696 + skip_event d; 697 + loop depth 698 + in 699 + loop 0 700 + 659 701 (* Public decode API *) 660 702 703 + (* Decode all documents from a multi-document YAML stream *) 704 + let decode_all' ?(layout = false) ?(locs = false) ?(file = "-") 705 + ?(max_depth = 100) ?(max_nodes = 10_000_000) t reader = 706 + let parser = Parser.of_reader reader in 707 + let d = make_decoder ~layout ~locs ~file ~max_depth ~max_nodes parser in 708 + let t' = Jsont.Repr.of_t t in 709 + let rec next_doc () = 710 + match peek_event d with 711 + | None -> Seq.Nil 712 + | Some { Event.event = Event.Stream_end; _ } -> 713 + skip_event d; 714 + Seq.Nil 715 + | Some _ -> ( 716 + try 717 + skip_to_content d; 718 + (* Reset node count for each document *) 719 + d.node_count <- 0; 720 + let v = decode d ~nest:0 t' in 721 + (* Skip document end marker if present *) 722 + (match peek_event d with 723 + | Some { Event.event = Event.Document_end _; _ } -> skip_event d 724 + | _ -> ()); 725 + Seq.Cons (Ok v, next_doc) 726 + with 727 + | Jsont.Error e -> 728 + skip_to_document_end d; 729 + Seq.Cons (Error e, next_doc) 730 + | Error.Yamlrw_error err -> 731 + skip_to_document_end d; 732 + let msg = Error.to_string err in 733 + let e = 734 + Jsont.Error.make_msg Jsont.Error.Context.empty Jsont.Meta.none msg 735 + in 736 + Seq.Cons (Error e, next_doc)) 737 + in 738 + next_doc 739 + 740 + let decode_all ?layout ?locs ?file ?max_depth ?max_nodes t reader = 741 + decode_all' ?layout ?locs ?file ?max_depth ?max_nodes t reader 742 + |> Seq.map (Result.map_error Jsont.Error.to_string) 743 + 661 744 let decode' ?layout ?locs ?file ?max_depth ?max_nodes t reader = 662 745 let parser = Parser.of_reader reader in 663 746 let d = make_decoder ?layout ?locs ?file ?max_depth ?max_nodes parser in ··· 676 759 let decode ?layout ?locs ?file ?max_depth ?max_nodes t reader = 677 760 Result.map_error Jsont.Error.to_string 678 761 (decode' ?layout ?locs ?file ?max_depth ?max_nodes t reader) 679 - 680 - let decode_string' ?layout ?locs ?file ?max_depth ?max_nodes t s = 681 - decode' ?layout ?locs ?file ?max_depth ?max_nodes t (Bytes.Reader.of_string s) 682 - 683 - let decode_string ?layout ?locs ?file ?max_depth ?max_nodes t s = 684 - decode ?layout ?locs ?file ?max_depth ?max_nodes t (Bytes.Reader.of_string s) 685 762 686 763 (* Encoder *) 687 764 ··· 908 985 Result.map_error Jsont.Error.to_string 909 986 (encode' ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer) 910 987 911 - let encode_string' ?buf ?format ?indent ?explicit_doc ?scalar_style t v = 912 - let b = Buffer.create 256 in 913 - let writer = Bytes.Writer.of_buffer b in 914 - match 915 - encode' ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod:true 916 - writer 917 - with 918 - | Ok () -> Ok (Buffer.contents b) 919 - | Error e -> Error e 920 - 921 - let encode_string ?buf ?format ?indent ?explicit_doc ?scalar_style t v = 922 - Result.map_error Jsont.Error.to_string 923 - (encode_string' ?buf ?format ?indent ?explicit_doc ?scalar_style t v) 924 - 925 988 (* Recode *) 926 989 927 990 let recode ?layout ?locs ?file ?max_depth ?max_nodes ?buf ?format ?indent ··· 936 999 | Ok v -> 937 1000 encode ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer 938 1001 | Error e -> Error (Jsont.Error.to_string e) 939 - 940 - let recode_string ?layout ?locs ?file ?max_depth ?max_nodes ?buf ?format ?indent 941 - ?explicit_doc ?scalar_style t s = 942 - let format = 943 - match (layout, format) with Some true, None -> Some Layout | _, f -> f 944 - in 945 - let layout = 946 - match (layout, format) with None, Some Layout -> Some true | l, _ -> l 947 - in 948 - match decode_string' ?layout ?locs ?file ?max_depth ?max_nodes t s with 949 - | Ok v -> encode_string ?buf ?format ?indent ?explicit_doc ?scalar_style t v 950 - | Error e -> Error (Jsont.Error.to_string e)
+11 -47
lib/yamlt.mli
··· 71 71 ('a, Jsont.Error.t) result 72 72 (** [decode'] is like {!val-decode} but preserves the error structure. *) 73 73 74 - val decode_string : 74 + val decode_all : 75 75 ?layout:bool -> 76 76 ?locs:bool -> 77 77 ?file:Jsont.Textloc.fpath -> 78 78 ?max_depth:int -> 79 79 ?max_nodes:int -> 80 80 'a Jsont.t -> 81 - string -> 82 - ('a, string) result 83 - (** [decode_string] is like {!val-decode} but decodes directly from a string. *) 81 + Bytes.Reader.t -> 82 + ('a, string) result Seq.t 83 + (** [decode_all t r] decodes all documents from a multi-document YAML stream. 84 + Returns a sequence where each element is a result of decoding one document. 85 + Parameters are as in {!val-decode}. Use this for YAML streams containing 86 + multiple documents separated by [---]. *) 84 87 85 - val decode_string' : 88 + val decode_all' : 86 89 ?layout:bool -> 87 90 ?locs:bool -> 88 91 ?file:Jsont.Textloc.fpath -> 89 92 ?max_depth:int -> 90 93 ?max_nodes:int -> 91 94 'a Jsont.t -> 92 - string -> 93 - ('a, Jsont.Error.t) result 94 - (** [decode_string'] is like {!val-decode'} but decodes directly from a string. 95 - *) 95 + Bytes.Reader.t -> 96 + ('a, Jsont.Error.t) result Seq.t 97 + (** [decode_all'] is like {!val-decode_all} but preserves the error structure. *) 96 98 97 99 (** {1:encode Encode} *) 98 100 ··· 138 140 (unit, Jsont.Error.t) result 139 141 (** [encode'] is like {!val-encode} but preserves the error structure. *) 140 142 141 - val encode_string : 142 - ?buf:Stdlib.Bytes.t -> 143 - ?format:yaml_format -> 144 - ?indent:int -> 145 - ?explicit_doc:bool -> 146 - ?scalar_style:Yamlrw.Scalar_style.t -> 147 - 'a Jsont.t -> 148 - 'a -> 149 - (string, string) result 150 - (** [encode_string] is like {!val-encode} but writes to a string. *) 151 - 152 - val encode_string' : 153 - ?buf:Stdlib.Bytes.t -> 154 - ?format:yaml_format -> 155 - ?indent:int -> 156 - ?explicit_doc:bool -> 157 - ?scalar_style:Yamlrw.Scalar_style.t -> 158 - 'a Jsont.t -> 159 - 'a -> 160 - (string, Jsont.Error.t) result 161 - (** [encode_string'] is like {!val-encode'} but writes to a string. *) 162 - 163 143 (** {1:recode Recode} 164 144 165 145 The defaults in these functions are those of {!val-decode} and ··· 183 163 eod:bool -> 184 164 (unit, string) result 185 165 (** [recode t r w] is {!val-decode} followed by {!val-encode}. *) 186 - 187 - val recode_string : 188 - ?layout:bool -> 189 - ?locs:bool -> 190 - ?file:Jsont.Textloc.fpath -> 191 - ?max_depth:int -> 192 - ?max_nodes:int -> 193 - ?buf:Stdlib.Bytes.t -> 194 - ?format:yaml_format -> 195 - ?indent:int -> 196 - ?explicit_doc:bool -> 197 - ?scalar_style:Yamlrw.Scalar_style.t -> 198 - 'a Jsont.t -> 199 - string -> 200 - (string, string) result 201 - (** [recode_string] is like {!val-recode} but operates on strings. *) 202 166 203 167 (** {1:yaml_mapping YAML to JSON Mapping} 204 168
+5
tests/bin/dune
··· 65 65 (name test_locations) 66 66 (public_name test_locations) 67 67 (libraries yamlt jsont jsont.bytesrw bytesrw)) 68 + 69 + (executable 70 + (name test_multidoc) 71 + (public_name test_multidoc) 72 + (libraries yamlt jsont jsont.bytesrw bytesrw))
+4 -2
tests/bin/test_array_variants.ml
··· 1 + open Bytesrw 2 + 1 3 let () = 2 4 let codec1 = 3 5 Jsont.Object.map ~kind:"Test" (fun arr -> arr) ··· 9 11 let yaml1 = "values: [a, b, c]" in 10 12 11 13 Printf.printf "Test 1: Non-optional array:\n"; 12 - (match Yamlt.decode_string codec1 yaml1 with 14 + (match Yamlt.decode codec1 (Bytes.Reader.of_string yaml1) with 13 15 | Ok arr -> Printf.printf "Result: [%d items]\n" (Array.length arr) 14 16 | Error e -> Printf.printf "Error: %s\n" e); 15 17 ··· 22 24 in 23 25 24 26 Printf.printf "\nTest 2: Jsont.option (Jsont.array):\n"; 25 - match Yamlt.decode_string codec2 yaml1 with 27 + match Yamlt.decode codec2 (Bytes.Reader.of_string yaml1) with 26 28 | Ok arr -> ( 27 29 match arr with 28 30 | None -> Printf.printf "Result: None\n"
+20 -14
tests/bin/test_arrays.ml
··· 5 5 6 6 (** Test array codec functionality with Yamlt *) 7 7 8 + open Bytesrw 9 + 8 10 (* Helper to read file *) 9 11 let read_file path = 10 12 let ic = open_in path in ··· 42 44 let yaml = read_file file in 43 45 let json = read_file (file ^ ".json") in 44 46 let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in 45 - let yaml_result = Yamlt.decode_string M.numbers_codec yaml in 47 + let yaml_result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in 46 48 47 49 show_result_both "int_array" 48 50 (Result.map M.show json_result) ··· 67 69 let yaml = read_file file in 68 70 let json = read_file (file ^ ".json") in 69 71 let json_result = Jsont_bytesrw.decode_string M.tags_codec json in 70 - let yaml_result = Yamlt.decode_string M.tags_codec yaml in 72 + let yaml_result = Yamlt.decode M.tags_codec (Bytes.Reader.of_string yaml) in 71 73 72 74 show_result_both "string_array" 73 75 (Result.map M.show json_result) ··· 92 94 let yaml = read_file file in 93 95 let json = read_file (file ^ ".json") in 94 96 let json_result = Jsont_bytesrw.decode_string M.measurements_codec json in 95 - let yaml_result = Yamlt.decode_string M.measurements_codec yaml in 97 + let yaml_result = Yamlt.decode M.measurements_codec (Bytes.Reader.of_string yaml) in 96 98 97 99 show_result_both "float_array" 98 100 (Result.map M.show json_result) ··· 114 116 let yaml = read_file file in 115 117 let json = read_file (file ^ ".json") in 116 118 let json_result = Jsont_bytesrw.decode_string M.empty_codec json in 117 - let yaml_result = Yamlt.decode_string M.empty_codec yaml in 119 + let yaml_result = Yamlt.decode M.empty_codec (Bytes.Reader.of_string yaml) in 118 120 119 121 show_result_both "empty_array" 120 122 (Result.map M.show json_result) ··· 147 149 let yaml = read_file file in 148 150 let json = read_file (file ^ ".json") in 149 151 let json_result = Jsont_bytesrw.decode_string M.people_codec json in 150 - let yaml_result = Yamlt.decode_string M.people_codec yaml in 152 + let yaml_result = Yamlt.decode M.people_codec (Bytes.Reader.of_string yaml) in 151 153 152 154 show_result_both "object_array" 153 155 (Result.map M.show json_result) ··· 176 178 let yaml = read_file file in 177 179 let json = read_file (file ^ ".json") in 178 180 let json_result = Jsont_bytesrw.decode_string M.matrix_codec json in 179 - let yaml_result = Yamlt.decode_string M.matrix_codec yaml in 181 + let yaml_result = Yamlt.decode M.matrix_codec (Bytes.Reader.of_string yaml) in 180 182 181 183 show_result_both "nested_arrays" 182 184 (Result.map M.show json_result) ··· 194 196 |> Jsont.Object.finish 195 197 end in 196 198 let yaml = read_file file in 197 - let result = Yamlt.decode_string M.numbers_codec yaml in 199 + let result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in 198 200 match result with 199 201 | Ok _ -> Printf.printf "Unexpected success\n" 200 202 | Error e -> Printf.printf "Expected error: %s\n" e ··· 217 219 let yaml = read_file file in 218 220 let json = read_file (file ^ ".json") in 219 221 let json_result = Jsont_bytesrw.decode_string M.flags_codec json in 220 - let yaml_result = Yamlt.decode_string M.flags_codec yaml in 222 + let yaml_result = Yamlt.decode M.flags_codec (Bytes.Reader.of_string yaml) in 221 223 222 224 show_result_both "bool_array" 223 225 (Result.map M.show json_result) ··· 244 246 let yaml = read_file file in 245 247 let json = read_file (file ^ ".json") in 246 248 let json_result = Jsont_bytesrw.decode_string M.nullable_codec json in 247 - let yaml_result = Yamlt.decode_string M.nullable_codec yaml in 249 + let yaml_result = Yamlt.decode M.nullable_codec (Bytes.Reader.of_string yaml) in 248 250 249 251 show_result_both "nullable_array" 250 252 (Result.map M.show json_result) ··· 274 276 | Error e -> Printf.printf "JSON ERROR: %s\n" e); 275 277 276 278 (* Encode to YAML Block *) 277 - (match Yamlt.encode_string ~format:Yamlt.Block M.data_codec data with 278 - | Ok s -> Printf.printf "YAML Block:\n%s" s 279 - | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 279 + (let b = Buffer.create 256 in 280 + let writer = Bytes.Writer.of_buffer b in 281 + match Yamlt.encode ~format:Yamlt.Block M.data_codec data ~eod:true writer with 282 + | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b) 283 + | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 280 284 281 285 (* Encode to YAML Flow *) 282 - match Yamlt.encode_string ~format:Yamlt.Flow M.data_codec data with 283 - | Ok s -> Printf.printf "YAML Flow: %s" s 286 + let b = Buffer.create 256 in 287 + let writer = Bytes.Writer.of_buffer b in 288 + match Yamlt.encode ~format:Yamlt.Flow M.data_codec data ~eod:true writer with 289 + | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b) 284 290 | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e 285 291 286 292 let () =
+6 -4
tests/bin/test_complex.ml
··· 5 5 6 6 (** Test complex nested types with Yamlt *) 7 7 8 + open Bytesrw 9 + 8 10 (* Helper to read file *) 9 11 let read_file path = 10 12 let ic = open_in path in ··· 57 59 let yaml = read_file file in 58 60 let json = read_file (file ^ ".json") in 59 61 let json_result = Jsont_bytesrw.decode_string M.root_codec json in 60 - let yaml_result = Yamlt.decode_string M.root_codec yaml in 62 + let yaml_result = Yamlt.decode M.root_codec (Bytes.Reader.of_string yaml) in 61 63 62 64 show_result_both "deep_nesting" 63 65 (Result.map M.show json_result) ··· 96 98 let yaml = read_file file in 97 99 let json = read_file (file ^ ".json") in 98 100 let json_result = Jsont_bytesrw.decode_string M.collection_codec json in 99 - let yaml_result = Yamlt.decode_string M.collection_codec yaml in 101 + let yaml_result = Yamlt.decode M.collection_codec (Bytes.Reader.of_string yaml) in 100 102 101 103 show_result_both "mixed_structure" 102 104 (Result.map M.show json_result) ··· 144 146 let yaml = read_file file in 145 147 let json = read_file (file ^ ".json") in 146 148 let json_result = Jsont_bytesrw.decode_string M.config_codec json in 147 - let yaml_result = Yamlt.decode_string M.config_codec yaml in 149 + let yaml_result = Yamlt.decode M.config_codec (Bytes.Reader.of_string yaml) in 148 150 149 151 show_result_both "complex_optional" 150 152 (Result.map M.show json_result) ··· 167 169 let yaml = read_file file in 168 170 let json = read_file (file ^ ".json") in 169 171 let json_result = Jsont_bytesrw.decode_string M.data_codec json in 170 - let yaml_result = Yamlt.decode_string M.data_codec yaml in 172 + let yaml_result = Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) in 171 173 172 174 show_result_both "heterogeneous" 173 175 (Result.map M.show json_result)
+18 -14
tests/bin/test_comprehensive.ml
··· 1 + open Bytesrw 2 + 1 3 let () = 2 4 (* Test 1: Null handling with option types *) 3 5 Printf.printf "=== NULL HANDLING ===\n"; ··· 7 9 |> Jsont.Object.finish 8 10 in 9 11 10 - (match Yamlt.decode_string opt_codec "value: null" with 12 + (match Yamlt.decode opt_codec (Bytes.Reader.of_string "value: null") with 11 13 | Ok None -> Printf.printf "✓ Plain 'null' with option codec: None\n" 12 14 | _ -> Printf.printf "✗ FAIL\n"); 13 15 14 - (match Yamlt.decode_string opt_codec "value: hello" with 16 + (match Yamlt.decode opt_codec (Bytes.Reader.of_string "value: hello") with 15 17 | Ok (Some "hello") -> 16 18 Printf.printf "✓ Plain 'hello' with option codec: Some(hello)\n" 17 19 | _ -> Printf.printf "✗ FAIL\n"); ··· 22 24 |> Jsont.Object.finish 23 25 in 24 26 25 - (match Yamlt.decode_string string_codec "value: null" with 27 + (match Yamlt.decode string_codec (Bytes.Reader.of_string "value: null") with 26 28 | Error _ -> 27 29 Printf.printf "✓ Plain 'null' with string codec: ERROR (expected)\n" 28 30 | _ -> Printf.printf "✗ FAIL\n"); 29 31 30 - (match Yamlt.decode_string string_codec "value: \"\"" with 32 + (match Yamlt.decode string_codec (Bytes.Reader.of_string "value: \"\"") with 31 33 | Ok "" -> Printf.printf "✓ Quoted empty string: \"\"\n" 32 34 | _ -> Printf.printf "✗ FAIL\n"); 33 35 34 - (match Yamlt.decode_string string_codec "value: \"null\"" with 36 + (match Yamlt.decode string_codec (Bytes.Reader.of_string "value: \"null\"") with 35 37 | Ok "null" -> Printf.printf "✓ Quoted 'null': \"null\"\n" 36 38 | _ -> Printf.printf "✗ FAIL\n"); 37 39 ··· 43 45 |> Jsont.Object.finish 44 46 in 45 47 46 - (match Yamlt.decode_string num_codec "value: 0xFF" with 48 + (match Yamlt.decode num_codec (Bytes.Reader.of_string "value: 0xFF") with 47 49 | Ok 255. -> Printf.printf "✓ Hex 0xFF: 255\n" 48 50 | _ -> Printf.printf "✗ FAIL\n"); 49 51 50 - (match Yamlt.decode_string num_codec "value: 0o77" with 52 + (match Yamlt.decode num_codec (Bytes.Reader.of_string "value: 0o77") with 51 53 | Ok 63. -> Printf.printf "✓ Octal 0o77: 63\n" 52 54 | _ -> Printf.printf "✗ FAIL\n"); 53 55 54 - (match Yamlt.decode_string num_codec "value: 0b1010" with 56 + (match Yamlt.decode num_codec (Bytes.Reader.of_string "value: 0b1010") with 55 57 | Ok 10. -> Printf.printf "✓ Binary 0b1010: 10\n" 56 58 | _ -> Printf.printf "✗ FAIL\n"); 57 59 ··· 64 66 |> Jsont.Object.finish 65 67 in 66 68 67 - (match Yamlt.decode_string opt_array_codec "values: [a, b, c]" with 69 + (match Yamlt.decode opt_array_codec (Bytes.Reader.of_string "values: [a, b, c]") with 68 70 | Ok (Some arr) when Array.length arr = 3 -> 69 71 Printf.printf "✓ Optional array [a, b, c]: Some([3 items])\n" 70 72 | _ -> Printf.printf "✗ FAIL\n"); 71 73 72 - (match Yamlt.decode_string opt_array_codec "{}" with 74 + (match Yamlt.decode opt_array_codec (Bytes.Reader.of_string "{}") with 73 75 | Ok None -> Printf.printf "✓ Missing optional array: None\n" 74 76 | _ -> Printf.printf "✗ FAIL\n"); 75 77 ··· 82 84 |> Jsont.Object.finish 83 85 in 84 86 87 + let b = Buffer.create 256 in 88 + let writer = Bytes.Writer.of_buffer b in 85 89 match 86 - Yamlt.encode_string ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |]) 90 + Yamlt.encode ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |]) ~eod:true writer 87 91 with 88 - | Ok yaml_flow 89 - when String.equal yaml_flow "{name: test, values: [1.0, 2.0, 3.0]}\n" -> 92 + | Ok () 93 + when String.equal (Buffer.contents b) "{name: test, values: [1.0, 2.0, 3.0]}\n" -> 90 94 Printf.printf "✓ Flow encoding with comma separator\n" 91 - | Ok yaml_flow -> Printf.printf "✗ FAIL: %S\n" yaml_flow 95 + | Ok () -> Printf.printf "✗ FAIL: %S\n" (Buffer.contents b) 92 96 | Error e -> Printf.printf "✗ ERROR: %s\n" e
+8 -6
tests/bin/test_edge.ml
··· 5 5 6 6 (** Test edge cases with Yamlt *) 7 7 8 + open Bytesrw 9 + 8 10 (* Helper to read file *) 9 11 let read_file path = 10 12 let ic = open_in path in ··· 50 52 let yaml = read_file file in 51 53 let json = read_file (file ^ ".json") in 52 54 let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in 53 - let yaml_result = Yamlt.decode_string M.numbers_codec yaml in 55 + let yaml_result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in 54 56 55 57 show_result_both "large_numbers" 56 58 (Result.map M.show json_result) ··· 75 77 let yaml = read_file file in 76 78 let json = read_file (file ^ ".json") in 77 79 let json_result = Jsont_bytesrw.decode_string M.text_codec json in 78 - let yaml_result = Yamlt.decode_string M.text_codec yaml in 80 + let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in 79 81 80 82 show_result_both "special_chars" 81 83 (Result.map M.show json_result) ··· 100 102 let yaml = read_file file in 101 103 let json = read_file (file ^ ".json") in 102 104 let json_result = Jsont_bytesrw.decode_string M.text_codec json in 103 - let yaml_result = Yamlt.decode_string M.text_codec yaml in 105 + let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in 104 106 105 107 show_result_both "unicode" 106 108 (Result.map M.show json_result) ··· 129 131 let yaml = read_file file in 130 132 let json = read_file (file ^ ".json") in 131 133 let json_result = Jsont_bytesrw.decode_string M.data_codec json in 132 - let yaml_result = Yamlt.decode_string M.data_codec yaml in 134 + let yaml_result = Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) in 133 135 134 136 show_result_both "empty_collections" 135 137 (Result.map M.show json_result) ··· 147 149 let yaml = read_file file in 148 150 let json = read_file (file ^ ".json") in 149 151 let json_result = Jsont_bytesrw.decode_string (Jsont.any ()) json in 150 - let yaml_result = Yamlt.decode_string (Jsont.any ()) yaml in 152 + let yaml_result = Yamlt.decode (Jsont.any ()) (Bytes.Reader.of_string yaml) in 151 153 152 154 show_result_both "special_keys" 153 155 (Result.map M.show json_result) ··· 172 174 let yaml = read_file file in 173 175 let json = read_file (file ^ ".json") in 174 176 let json_result = Jsont_bytesrw.decode_string M.data_codec json in 175 - let yaml_result = Yamlt.decode_string M.data_codec yaml in 177 + let yaml_result = Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) in 176 178 177 179 show_result_both "single_element" 178 180 (Result.map M.show json_result)
+7 -2
tests/bin/test_flow_newline.ml
··· 1 + open Bytesrw 2 + 1 3 let () = 2 4 let encode_codec = 3 5 Jsont.Object.map ~kind:"Test" (fun name values -> (name, values)) ··· 6 8 |> Jsont.Object.finish 7 9 in 8 10 11 + let b = Buffer.create 256 in 12 + let writer = Bytes.Writer.of_buffer b in 9 13 match 10 - Yamlt.encode_string ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |]) 14 + Yamlt.encode ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |]) ~eod:true writer 11 15 with 12 - | Ok yaml_flow -> 16 + | Ok () -> 17 + let yaml_flow = Buffer.contents b in 13 18 Printf.printf "Length: %d\n" (String.length yaml_flow); 14 19 Printf.printf "Repr: %S\n" yaml_flow; 15 20 Printf.printf "Output:\n%s" yaml_flow
+17 -11
tests/bin/test_formats.ml
··· 5 5 6 6 (** Test format-specific features with Yamlt *) 7 7 8 + open Bytesrw 9 + 8 10 (* Helper to read file *) 9 11 let read_file path = 10 12 let ic = open_in path in ··· 42 44 let yaml = read_file file in 43 45 let json = read_file (file ^ ".json") in 44 46 let json_result = Jsont_bytesrw.decode_string M.text_codec json in 45 - let yaml_result = Yamlt.decode_string M.text_codec yaml in 47 + let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in 46 48 47 49 show_result_both "literal_string" 48 50 (Result.map M.show json_result) ··· 68 70 let yaml = read_file file in 69 71 let json = read_file (file ^ ".json") in 70 72 let json_result = Jsont_bytesrw.decode_string M.text_codec json in 71 - let yaml_result = Yamlt.decode_string M.text_codec yaml in 73 + let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in 72 74 73 75 show_result_both "folded_string" 74 76 (Result.map M.show json_result) ··· 93 95 let yaml = read_file file in 94 96 let json = read_file (file ^ ".json") in 95 97 let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in 96 - let yaml_result = Yamlt.decode_string M.numbers_codec yaml in 98 + let yaml_result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in 97 99 98 100 show_result_both "number_formats" 99 101 (Result.map M.show json_result) ··· 129 131 in 130 132 131 133 (* Encode to YAML Block style *) 132 - (match Yamlt.encode_string ~format:Yamlt.Block M.data_codec data with 133 - | Ok s -> Printf.printf "YAML Block:\n%s\n" s 134 - | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 134 + (let b = Buffer.create 256 in 135 + let writer = Bytes.Writer.of_buffer b in 136 + match Yamlt.encode ~format:Yamlt.Block M.data_codec data ~eod:true writer with 137 + | Ok () -> Printf.printf "YAML Block:\n%s\n" (Buffer.contents b) 138 + | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 135 139 136 140 (* Encode to YAML Flow style *) 137 - match Yamlt.encode_string ~format:Yamlt.Flow M.data_codec data with 138 - | Ok s -> Printf.printf "YAML Flow:\n%s\n" s 141 + let b = Buffer.create 256 in 142 + let writer = Bytes.Writer.of_buffer b in 143 + match Yamlt.encode ~format:Yamlt.Flow M.data_codec data ~eod:true writer with 144 + | Ok () -> Printf.printf "YAML Flow:\n%s\n" (Buffer.contents b) 139 145 | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e 140 146 141 147 (* Test: Comments in YAML (should be ignored) *) ··· 155 161 Printf.sprintf "host=%S, port=%d, debug=%b" c.host c.port c.debug 156 162 end in 157 163 let yaml = read_file file in 158 - let yaml_result = Yamlt.decode_string M.config_codec yaml in 164 + let yaml_result = Yamlt.decode M.config_codec (Bytes.Reader.of_string yaml) in 159 165 160 166 match yaml_result with 161 167 | Ok v -> Printf.printf "YAML (with comments): %s\n" (M.show v) ··· 180 186 let yaml = read_file file in 181 187 let json = read_file (file ^ ".json") in 182 188 let json_result = Jsont_bytesrw.decode_string M.wrapper_codec json in 183 - let yaml_result = Yamlt.decode_string M.wrapper_codec yaml in 189 + let yaml_result = Yamlt.decode M.wrapper_codec (Bytes.Reader.of_string yaml) in 184 190 185 191 show_result_both "empty_document" 186 192 (Result.map M.show json_result) ··· 199 205 let show v = Printf.sprintf "data=%S" v.data 200 206 end in 201 207 let yaml = read_file file in 202 - let yaml_result = Yamlt.decode_string M.value_codec yaml in 208 + let yaml_result = Yamlt.decode M.value_codec (Bytes.Reader.of_string yaml) in 203 209 204 210 match yaml_result with 205 211 | Ok v -> Printf.printf "YAML (with tags): %s\n" (M.show v)
+28 -22
tests/bin/test_locations.ml
··· 6 6 (** Test location and layout preservation options with Yamlt codec *) 7 7 8 8 (* Helper to read file *) 9 + open Bytesrw 10 + 9 11 let read_file path = 10 12 let ic = open_in path in 11 13 let len = in_channel_length ic in ··· 31 33 in 32 34 33 35 Printf.printf "=== Without locs (default) ===\n"; 34 - let result_no_locs = Yamlt.decode_string ~locs:false codec yaml in 36 + let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in 35 37 show_result "Error message" result_no_locs; 36 38 37 39 Printf.printf "\n=== With locs=true ===\n"; 38 - let result_with_locs = Yamlt.decode_string ~locs:true codec yaml in 40 + let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in 39 41 show_result "Error message" result_with_locs 40 42 41 43 (* Test: Show error locations for nested structures *) ··· 60 62 in 61 63 62 64 Printf.printf "=== Without locs (default) ===\n"; 63 - let result_no_locs = Yamlt.decode_string ~locs:false codec yaml in 65 + let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in 64 66 show_result "Nested error" result_no_locs; 65 67 66 68 Printf.printf "\n=== With locs=true ===\n"; 67 - let result_with_locs = Yamlt.decode_string ~locs:true codec yaml in 69 + let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in 68 70 show_result "Nested error" result_with_locs 69 71 70 72 (* Test: Array element error locations *) ··· 79 81 in 80 82 81 83 Printf.printf "=== Without locs (default) ===\n"; 82 - let result_no_locs = Yamlt.decode_string ~locs:false codec yaml in 84 + let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in 83 85 show_result "Array error" result_no_locs; 84 86 85 87 Printf.printf "\n=== With locs=true ===\n"; 86 - let result_with_locs = Yamlt.decode_string ~locs:true codec yaml in 88 + let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in 87 89 show_result "Array error" result_with_locs 88 90 89 91 (* Test: Layout preservation - check if we can decode with layout info *) ··· 98 100 in 99 101 100 102 Printf.printf "=== Without layout (default) ===\n"; 101 - (match Yamlt.decode_string ~layout:false codec yaml with 103 + (match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:false with 102 104 | Ok (host, port) -> 103 105 Printf.printf "Decoded: host=%s, port=%d\n" host port; 104 106 Printf.printf "Meta preserved: no\n" 105 107 | Error e -> Printf.printf "Error: %s\n" e); 106 108 107 109 Printf.printf "\n=== With layout=true ===\n"; 108 - match Yamlt.decode_string ~layout:true codec yaml with 110 + match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:true with 109 111 | Ok (host, port) -> 110 112 Printf.printf "Decoded: host=%s, port=%d\n" host port; 111 113 Printf.printf ··· 126 128 Printf.printf "%s\n" (String.trim yaml); 127 129 128 130 Printf.printf "\n=== Decode without layout, re-encode ===\n"; 129 - (match Yamlt.decode_string ~layout:false codec yaml with 131 + (match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:false with 130 132 | Ok items -> ( 131 - match Yamlt.encode_string ~format:Yamlt.Block codec items with 132 - | Ok yaml_out -> Printf.printf "%s" yaml_out 133 + let b = Buffer.create 256 in 134 + let writer = Bytes.Writer.of_buffer b in 135 + match Yamlt.encode ~format:Yamlt.Block codec items ~eod:true writer with 136 + | Ok () -> Printf.printf "%s" (Buffer.contents b) 133 137 | Error e -> Printf.printf "Encode error: %s\n" e) 134 138 | Error e -> Printf.printf "Decode error: %s\n" e); 135 139 136 140 Printf.printf 137 141 "\n=== Decode with layout=true, re-encode with Layout format ===\n"; 138 - match Yamlt.decode_string ~layout:true codec yaml with 142 + match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:true with 139 143 | Ok items -> ( 140 - match Yamlt.encode_string ~format:Yamlt.Layout codec items with 141 - | Ok yaml_out -> Printf.printf "%s" yaml_out 144 + let b = Buffer.create 256 in 145 + let writer = Bytes.Writer.of_buffer b in 146 + match Yamlt.encode ~format:Yamlt.Layout codec items ~eod:true writer with 147 + | Ok () -> Printf.printf "%s" (Buffer.contents b) 142 148 | Error e -> Printf.printf "Encode error: %s\n" e) 143 149 | Error e -> Printf.printf "Decode error: %s\n" e 144 150 ··· 154 160 in 155 161 156 162 Printf.printf "=== Without file path ===\n"; 157 - let result1 = Yamlt.decode_string ~locs:true codec yaml in 163 + let result1 = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in 158 164 show_result "Error" result1; 159 165 160 166 Printf.printf "\n=== With file path ===\n"; 161 - let result2 = Yamlt.decode_string ~locs:true ~file:"test.yml" codec yaml in 167 + let result2 = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true ~file:"test.yml" in 162 168 show_result "Error" result2 163 169 164 170 (* Test: Missing field error with locs *) ··· 174 180 in 175 181 176 182 Printf.printf "=== Without locs ===\n"; 177 - let result_no_locs = Yamlt.decode_string ~locs:false codec yaml in 183 + let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in 178 184 show_result "Missing field" result_no_locs; 179 185 180 186 Printf.printf "\n=== With locs=true ===\n"; 181 - let result_with_locs = Yamlt.decode_string ~locs:true codec yaml in 187 + let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in 182 188 show_result "Missing field" result_with_locs 183 189 184 190 (* Test: Both locs and layout together *) ··· 194 200 in 195 201 196 202 Printf.printf "=== locs=false, layout=false (defaults) ===\n"; 197 - (match Yamlt.decode_string ~locs:false ~layout:false codec yaml with 203 + (match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false ~layout:false with 198 204 | Ok (timeout, retries) -> 199 205 Printf.printf "OK: timeout=%d, retries=%d\n" timeout retries 200 206 | Error e -> Printf.printf "Error: %s\n" e); 201 207 202 208 Printf.printf "\n=== locs=true, layout=false ===\n"; 203 - (match Yamlt.decode_string ~locs:true ~layout:false codec yaml with 209 + (match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true ~layout:false with 204 210 | Ok (timeout, retries) -> 205 211 Printf.printf "OK: timeout=%d, retries=%d (with precise locations)\n" 206 212 timeout retries 207 213 | Error e -> Printf.printf "Error: %s\n" e); 208 214 209 215 Printf.printf "\n=== locs=false, layout=true ===\n"; 210 - (match Yamlt.decode_string ~locs:false ~layout:true codec yaml with 216 + (match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false ~layout:true with 211 217 | Ok (timeout, retries) -> 212 218 Printf.printf "OK: timeout=%d, retries=%d (with layout metadata)\n" 213 219 timeout retries 214 220 | Error e -> Printf.printf "Error: %s\n" e); 215 221 216 222 Printf.printf "\n=== locs=true, layout=true (both enabled) ===\n"; 217 - match Yamlt.decode_string ~locs:true ~layout:true codec yaml with 223 + match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true ~layout:true with 218 224 | Ok (timeout, retries) -> 219 225 Printf.printf "OK: timeout=%d, retries=%d (with locations and layout)\n" 220 226 timeout retries
+240
tests/bin/test_multidoc.ml
··· 1 + (*--------------------------------------------------------------------------- 2 + Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved. 3 + SPDX-License-Identifier: ISC 4 + ---------------------------------------------------------------------------*) 5 + 6 + (** Test multi-document YAML streams with decode_all *) 7 + 8 + open Bytesrw 9 + 10 + (* Helper to read file *) 11 + let read_file path = 12 + let ic = open_in path in 13 + let len = in_channel_length ic in 14 + let s = really_input_string ic len in 15 + close_in ic; 16 + s 17 + 18 + (* Helper to show results *) 19 + let show_result label = function 20 + | Ok v -> Printf.printf "%s: %s\n" label v 21 + | Error e -> Printf.printf "%s: ERROR: %s\n" label e 22 + 23 + (* Test: Simple multi-document stream *) 24 + let test_simple file = 25 + let module M = struct 26 + type person = { name : string; age : int } 27 + 28 + let person_codec = 29 + Jsont.Object.map ~kind:"Person" (fun name age -> { name; age }) 30 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name) 31 + |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age) 32 + |> Jsont.Object.finish 33 + 34 + let show p = Printf.sprintf "%s (age %d)" p.name p.age 35 + end in 36 + let yaml = read_file file in 37 + let reader = Bytes.Reader.of_string yaml in 38 + let seq = Yamlt.decode_all M.person_codec reader in 39 + Printf.printf "Documents:\n"; 40 + seq |> Seq.iteri (fun i result -> 41 + Printf.printf " [%d] " i; 42 + show_result "" (Result.map M.show result) 43 + ) 44 + 45 + (* Test: Count documents *) 46 + let test_count file = 47 + let yaml = read_file file in 48 + let reader = Bytes.Reader.of_string yaml in 49 + let seq = Yamlt.decode_all Jsont.json reader in 50 + let count = Seq.fold_left (fun acc _ -> acc + 1) 0 seq in 51 + Printf.printf "Document count: %d\n" count 52 + 53 + (* Test: Error tracking - show which documents succeed and which fail *) 54 + let test_errors file = 55 + let module M = struct 56 + type person = { name : string; age : int } 57 + 58 + let person_codec = 59 + Jsont.Object.map ~kind:"Person" (fun name age -> { name; age }) 60 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name) 61 + |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age) 62 + |> Jsont.Object.finish 63 + 64 + let show p = Printf.sprintf "%s (age %d)" p.name p.age 65 + end in 66 + let yaml = read_file file in 67 + let reader = Bytes.Reader.of_string yaml in 68 + let seq = Yamlt.decode_all M.person_codec reader in 69 + Printf.printf "Document results:\n"; 70 + seq |> Seq.iteri (fun i result -> 71 + match result with 72 + | Ok p -> Printf.printf " [%d] OK: %s\n" i (M.show p) 73 + | Error e -> Printf.printf " [%d] ERROR: %s\n" i (String.trim e) 74 + ) 75 + 76 + (* Test: Location tracking with locs=true *) 77 + let test_locations file = 78 + let module M = struct 79 + type person = { name : string; age : int } 80 + 81 + let person_codec = 82 + Jsont.Object.map ~kind:"Person" (fun name age -> { name; age }) 83 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name) 84 + |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age) 85 + |> Jsont.Object.finish 86 + end in 87 + let yaml = read_file file in 88 + 89 + Printf.printf "=== Without locs (default) ===\n"; 90 + let reader = Bytes.Reader.of_string yaml in 91 + let seq = Yamlt.decode_all ~locs:false M.person_codec reader in 92 + seq |> Seq.iteri (fun i result -> 93 + match result with 94 + | Ok _ -> Printf.printf " [%d] OK\n" i 95 + | Error e -> Printf.printf " [%d] ERROR:\n%s\n" i (String.trim e) 96 + ); 97 + 98 + Printf.printf "\n=== With locs=true ===\n"; 99 + let reader = Bytes.Reader.of_string yaml in 100 + let seq = Yamlt.decode_all ~locs:true ~file:"test.yml" M.person_codec reader in 101 + seq |> Seq.iteri (fun i result -> 102 + match result with 103 + | Ok _ -> Printf.printf " [%d] OK\n" i 104 + | Error e -> Printf.printf " [%d] ERROR:\n%s\n" i (String.trim e) 105 + ) 106 + 107 + (* Test: Roundtrip to JSON - decode YAML multidoc, encode each to JSON *) 108 + let test_json_roundtrip file = 109 + let yaml = read_file file in 110 + let reader = Bytes.Reader.of_string yaml in 111 + let seq = Yamlt.decode_all Jsont.json reader in 112 + Printf.printf "JSON outputs:\n"; 113 + seq |> Seq.iteri (fun i result -> 114 + match result with 115 + | Ok json_val -> 116 + (match Jsont_bytesrw.encode_string Jsont.json json_val with 117 + | Ok json_str -> Printf.printf " [%d] %s\n" i (String.trim json_str) 118 + | Error e -> Printf.printf " [%d] ENCODE ERROR: %s\n" i e) 119 + | Error e -> Printf.printf " [%d] DECODE ERROR: %s\n" i (String.trim e) 120 + ) 121 + 122 + (* Test: Nested objects in multidoc *) 123 + let test_nested file = 124 + let module M = struct 125 + type address = { street : string; city : string } 126 + type person = { name : string; age : int; address : address } 127 + 128 + let address_codec = 129 + Jsont.Object.map ~kind:"Address" (fun street city -> { street; city }) 130 + |> Jsont.Object.mem "street" Jsont.string ~enc:(fun a -> a.street) 131 + |> Jsont.Object.mem "city" Jsont.string ~enc:(fun a -> a.city) 132 + |> Jsont.Object.finish 133 + 134 + let person_codec = 135 + Jsont.Object.map ~kind:"Person" (fun name age address -> 136 + { name; age; address }) 137 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name) 138 + |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age) 139 + |> Jsont.Object.mem "address" address_codec ~enc:(fun p -> p.address) 140 + |> Jsont.Object.finish 141 + 142 + let show p = 143 + Printf.sprintf "%s (age %d) from %s, %s" p.name p.age p.address.street 144 + p.address.city 145 + end in 146 + let yaml = read_file file in 147 + let reader = Bytes.Reader.of_string yaml in 148 + let seq = Yamlt.decode_all M.person_codec reader in 149 + Printf.printf "Nested documents:\n"; 150 + seq |> Seq.iteri (fun i result -> 151 + Printf.printf " [%d] " i; 152 + show_result "" (Result.map M.show result) 153 + ) 154 + 155 + (* Test: Arrays in multidoc *) 156 + let test_arrays file = 157 + let yaml = read_file file in 158 + let reader = Bytes.Reader.of_string yaml in 159 + let seq = Yamlt.decode_all Jsont.json reader in 160 + Printf.printf "Array documents:\n"; 161 + seq |> Seq.iteri (fun i result -> 162 + match result with 163 + | Ok json_val -> 164 + (match Jsont_bytesrw.encode_string Jsont.json json_val with 165 + | Ok json_str -> Printf.printf " [%d] %s\n" i (String.trim json_str) 166 + | Error e -> Printf.printf " [%d] ERROR: %s\n" i e) 167 + | Error e -> Printf.printf " [%d] ERROR: %s\n" i (String.trim e) 168 + ) 169 + 170 + (* Test: Scalars in multidoc *) 171 + let test_scalars file = 172 + let yaml = read_file file in 173 + let reader = Bytes.Reader.of_string yaml in 174 + let seq = Yamlt.decode_all Jsont.json reader in 175 + Printf.printf "Scalar documents:\n"; 176 + seq |> Seq.iteri (fun i result -> 177 + match result with 178 + | Ok json_val -> 179 + (match Jsont_bytesrw.encode_string Jsont.json json_val with 180 + | Ok json_str -> Printf.printf " [%d] %s\n" i (String.trim json_str) 181 + | Error e -> Printf.printf " [%d] ERROR: %s\n" i e) 182 + | Error e -> Printf.printf " [%d] ERROR: %s\n" i (String.trim e) 183 + ) 184 + 185 + (* Test: Summary stats - count successes vs failures *) 186 + let test_summary file = 187 + let module M = struct 188 + type person = { name : string; age : int } 189 + 190 + let person_codec = 191 + Jsont.Object.map ~kind:"Person" (fun name age -> { name; age }) 192 + |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name) 193 + |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age) 194 + |> Jsont.Object.finish 195 + end in 196 + let yaml = read_file file in 197 + let reader = Bytes.Reader.of_string yaml in 198 + let seq = Yamlt.decode_all M.person_codec reader in 199 + let success = ref 0 in 200 + let failure = ref 0 in 201 + seq |> Seq.iter (fun result -> 202 + match result with 203 + | Ok _ -> incr success 204 + | Error _ -> incr failure 205 + ); 206 + Printf.printf "Summary: %d documents (%d ok, %d error)\n" 207 + (!success + !failure) !success !failure 208 + 209 + let () = 210 + let usage = "Usage: test_multidoc <command> <file>" in 211 + if Array.length Sys.argv < 3 then begin 212 + prerr_endline usage; 213 + exit 1 214 + end; 215 + 216 + let test = Sys.argv.(1) in 217 + let file = Sys.argv.(2) in 218 + match test with 219 + | "simple" -> test_simple file 220 + | "count" -> test_count file 221 + | "errors" -> test_errors file 222 + | "locations" -> test_locations file 223 + | "json" -> test_json_roundtrip file 224 + | "nested" -> test_nested file 225 + | "arrays" -> test_arrays file 226 + | "scalars" -> test_scalars file 227 + | "summary" -> test_summary file 228 + | _ -> 229 + prerr_endline usage; 230 + prerr_endline "Commands:"; 231 + prerr_endline " simple <file> - Decode person documents"; 232 + prerr_endline " count <file> - Count documents"; 233 + prerr_endline " errors <file> - Show success/error for each document"; 234 + prerr_endline " locations <file> - Test location tracking with locs=true"; 235 + prerr_endline " json <file> - Roundtrip to JSON"; 236 + prerr_endline " nested <file> - Decode nested objects"; 237 + prerr_endline " arrays <file> - Decode arrays"; 238 + prerr_endline " scalars <file> - Decode scalars"; 239 + prerr_endline " summary <file> - Show success/failure summary"; 240 + exit 1
+6 -4
tests/bin/test_null_complete.ml
··· 1 + open Bytesrw 2 + 1 3 let () = 2 4 Printf.printf "=== Test 1: Jsont.option with YAML null ===\n"; 3 5 let yaml1 = "value: null" in ··· 7 9 |> Object.mem "value" (option string) ~enc:(fun v -> v) 8 10 |> Object.finish 9 11 in 10 - (match Yamlt.decode_string codec1 yaml1 with 12 + (match Yamlt.decode codec1 (Bytes.Reader.of_string yaml1) with 11 13 | Ok v -> 12 14 Printf.printf "Result: %s\n" 13 15 (match v with None -> "None" | Some s -> "Some(" ^ s ^ ")") 14 16 | Error e -> Printf.printf "Error: %s\n" e); 15 17 16 18 Printf.printf "\n=== Test 2: Jsont.option with YAML string ===\n"; 17 - (match Yamlt.decode_string codec1 "value: hello" with 19 + (match Yamlt.decode codec1 (Bytes.Reader.of_string "value: hello") with 18 20 | Ok v -> 19 21 Printf.printf "Result: %s\n" 20 22 (match v with None -> "None" | Some s -> "Some(" ^ s ^ ")") ··· 27 29 |> Object.mem "value" string ~enc:(fun v -> v) 28 30 |> Object.finish 29 31 in 30 - (match Yamlt.decode_string codec2 "value: null" with 32 + (match Yamlt.decode codec2 (Bytes.Reader.of_string "value: null") with 31 33 | Ok v -> Printf.printf "Result: %s\n" v 32 34 | Error e -> Printf.printf "Error (expected): %s\n" e); 33 35 34 36 Printf.printf "\n=== Test 4: Jsont.string with YAML string ===\n"; 35 - match Yamlt.decode_string codec2 "value: hello" with 37 + match Yamlt.decode codec2 (Bytes.Reader.of_string "value: hello") with 36 38 | Ok v -> Printf.printf "Result: %s\n" v 37 39 | Error e -> Printf.printf "Error: %s\n" e
+2 -2
tests/bin/test_null_fix.ml
··· 1 - open Jsont 1 + open Bytesrw 2 2 3 3 let () = 4 4 let module M = struct ··· 14 14 15 15 Printf.printf "Testing YAML null handling with Jsont.option Jsont.string:\n\n"; 16 16 17 - match Yamlt.decode_string M.data_codec yaml_null with 17 + match Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml_null) with 18 18 | Ok data -> ( 19 19 match data.M.value with 20 20 | None -> Printf.printf "YAML: value=None (CORRECT)\n"
+19 -13
tests/bin/test_objects.ml
··· 5 5 6 6 (** Test object codec functionality with Yamlt *) 7 7 8 + open Bytesrw 9 + 8 10 (* Helper to read file *) 9 11 let read_file path = 10 12 let ic = open_in path in ··· 40 42 let yaml = read_file file in 41 43 let json = read_file (file ^ ".json") in 42 44 let json_result = Jsont_bytesrw.decode_string M.person_codec json in 43 - let yaml_result = Yamlt.decode_string M.person_codec yaml in 45 + let yaml_result = Yamlt.decode M.person_codec (Bytes.Reader.of_string yaml) in 44 46 45 47 show_result_both "person" 46 48 (Result.map M.show json_result) ··· 71 73 let yaml = read_file file in 72 74 let json = read_file (file ^ ".json") in 73 75 let json_result = Jsont_bytesrw.decode_string M.config_codec json in 74 - let yaml_result = Yamlt.decode_string M.config_codec yaml in 76 + let yaml_result = Yamlt.decode M.config_codec (Bytes.Reader.of_string yaml) in 75 77 76 78 show_result_both "config" 77 79 (Result.map M.show json_result) ··· 103 105 let yaml = read_file file in 104 106 let json = read_file (file ^ ".json") in 105 107 let json_result = Jsont_bytesrw.decode_string M.settings_codec json in 106 - let yaml_result = Yamlt.decode_string M.settings_codec yaml in 108 + let yaml_result = Yamlt.decode M.settings_codec (Bytes.Reader.of_string yaml) in 107 109 108 110 show_result_both "settings" 109 111 (Result.map M.show json_result) ··· 136 138 let yaml = read_file file in 137 139 let json = read_file (file ^ ".json") in 138 140 let json_result = Jsont_bytesrw.decode_string M.employee_codec json in 139 - let yaml_result = Yamlt.decode_string M.employee_codec yaml in 141 + let yaml_result = Yamlt.decode M.employee_codec (Bytes.Reader.of_string yaml) in 140 142 141 143 show_result_both "employee" 142 144 (Result.map M.show json_result) ··· 153 155 |> Jsont.Object.finish 154 156 end in 155 157 let yaml = read_file file in 156 - let result = Yamlt.decode_string M.strict_codec yaml in 158 + let result = Yamlt.decode M.strict_codec (Bytes.Reader.of_string yaml) in 157 159 match result with 158 160 | Ok _ -> Printf.printf "Unexpected success\n" 159 161 | Error e -> Printf.printf "Expected error: %s\n" e ··· 174 176 let yaml = read_file file in 175 177 let json = read_file (file ^ ".json") in 176 178 let json_result = Jsont_bytesrw.decode_string M.flexible_codec json in 177 - let yaml_result = Yamlt.decode_string M.flexible_codec yaml in 179 + let yaml_result = Yamlt.decode M.flexible_codec (Bytes.Reader.of_string yaml) in 178 180 179 181 show_result_both "flexible" 180 182 (Result.map M.show json_result) ··· 196 198 let yaml = read_file file in 197 199 let json = read_file (file ^ ".json") in 198 200 let json_result = Jsont_bytesrw.decode_string M.circle_codec json in 199 - let yaml_result = Yamlt.decode_string M.circle_codec yaml in 201 + let yaml_result = Yamlt.decode M.circle_codec (Bytes.Reader.of_string yaml) in 200 202 201 203 show_result_both "shape" 202 204 (Result.map M.show json_result) ··· 214 216 |> Jsont.Object.finish 215 217 end in 216 218 let yaml = read_file file in 217 - let result = Yamlt.decode_string M.required_codec yaml in 219 + let result = Yamlt.decode M.required_codec (Bytes.Reader.of_string yaml) in 218 220 match result with 219 221 | Ok _ -> Printf.printf "Unexpected success\n" 220 222 | Error e -> Printf.printf "Expected error: %s\n" e ··· 240 242 | Error e -> Printf.printf "JSON ERROR: %s\n" e); 241 243 242 244 (* Encode to YAML Block *) 243 - (match Yamlt.encode_string ~format:Yamlt.Block M.person_codec person with 244 - | Ok s -> Printf.printf "YAML Block:\n%s" s 245 - | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 245 + (let b = Buffer.create 256 in 246 + let writer = Bytes.Writer.of_buffer b in 247 + match Yamlt.encode ~format:Yamlt.Block M.person_codec person ~eod:true writer with 248 + | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b) 249 + | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 246 250 247 251 (* Encode to YAML Flow *) 248 - match Yamlt.encode_string ~format:Yamlt.Flow M.person_codec person with 249 - | Ok s -> Printf.printf "YAML Flow: %s" s 252 + let b = Buffer.create 256 in 253 + let writer = Bytes.Writer.of_buffer b in 254 + match Yamlt.encode ~format:Yamlt.Flow M.person_codec person ~eod:true writer with 255 + | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b) 250 256 | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e 251 257 252 258 let () =
+3 -1
tests/bin/test_opt_array.ml
··· 1 + open Bytesrw 2 + 1 3 let () = 2 4 let codec = 3 5 Jsont.Object.map ~kind:"Test" (fun arr -> arr) ··· 9 11 let yaml = "values: [a, b, c]" in 10 12 11 13 Printf.printf "Testing optional array field:\n"; 12 - match Yamlt.decode_string codec yaml with 14 + match Yamlt.decode codec (Bytes.Reader.of_string yaml) with 13 15 | Ok arr -> ( 14 16 match arr with 15 17 | None -> Printf.printf "Result: None\n"
+37 -13
tests/bin/test_roundtrip.ml
··· 5 5 6 6 (** Test roundtrip encoding/decoding with Yamlt *) 7 7 8 + open Bytesrw 9 + 8 10 (* Test: Roundtrip scalars *) 9 11 let test_scalar_roundtrip () = 10 12 let module M = struct ··· 36 38 37 39 (* YAML Block roundtrip *) 38 40 let yaml_block_encoded = 39 - Yamlt.encode_string ~format:Yamlt.Block M.data_codec original 41 + let b = Buffer.create 256 in 42 + let writer = Bytes.Writer.of_buffer b in 43 + match Yamlt.encode ~format:Yamlt.Block M.data_codec original ~eod:true writer with 44 + | Ok () -> Ok (Buffer.contents b) 45 + | Error e -> Error e 40 46 in 41 47 let yaml_block_decoded = 42 - Result.bind yaml_block_encoded (Yamlt.decode_string M.data_codec) 48 + Result.bind yaml_block_encoded (fun yaml -> 49 + Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml)) 43 50 in 44 51 (match yaml_block_decoded with 45 52 | Ok decoded when M.equal original decoded -> ··· 49 56 50 57 (* YAML Flow roundtrip *) 51 58 let yaml_flow_encoded = 52 - Yamlt.encode_string ~format:Yamlt.Flow M.data_codec original 59 + let b = Buffer.create 256 in 60 + let writer = Bytes.Writer.of_buffer b in 61 + match Yamlt.encode ~format:Yamlt.Flow M.data_codec original ~eod:true writer with 62 + | Ok () -> Ok (Buffer.contents b) 63 + | Error e -> Error e 53 64 in 54 65 let yaml_flow_decoded = 55 - Result.bind yaml_flow_encoded (Yamlt.decode_string M.data_codec) 66 + Result.bind yaml_flow_encoded (fun yaml -> 67 + Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml)) 56 68 in 57 69 match yaml_flow_decoded with 58 70 | Ok decoded when M.equal original decoded -> ··· 97 109 98 110 (* YAML roundtrip *) 99 111 let yaml_result = 100 - Result.bind 101 - (Yamlt.encode_string M.data_codec original) 102 - (Yamlt.decode_string M.data_codec) 112 + let b = Buffer.create 256 in 113 + let writer = Bytes.Writer.of_buffer b in 114 + match Yamlt.encode M.data_codec original ~eod:true writer with 115 + | Ok () -> 116 + let yaml = Buffer.contents b in 117 + Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) 118 + | Error e -> Error e 103 119 in 104 120 match yaml_result with 105 121 | Ok decoded when M.equal original decoded -> ··· 162 178 163 179 (* YAML roundtrip *) 164 180 let yaml_result = 165 - Result.bind 166 - (Yamlt.encode_string M.company_codec original) 167 - (Yamlt.decode_string M.company_codec) 181 + let b = Buffer.create 256 in 182 + let writer = Bytes.Writer.of_buffer b in 183 + match Yamlt.encode M.company_codec original ~eod:true writer with 184 + | Ok () -> 185 + let yaml = Buffer.contents b in 186 + Yamlt.decode M.company_codec (Bytes.Reader.of_string yaml) 187 + | Error e -> Error e 168 188 in 169 189 match yaml_result with 170 190 | Ok decoded when M.equal original decoded -> ··· 210 230 211 231 (* YAML roundtrip *) 212 232 let yaml_result = 213 - Result.bind 214 - (Yamlt.encode_string M.data_codec original) 215 - (Yamlt.decode_string M.data_codec) 233 + let b = Buffer.create 256 in 234 + let writer = Bytes.Writer.of_buffer b in 235 + match Yamlt.encode M.data_codec original ~eod:true writer with 236 + | Ok () -> 237 + let yaml = Buffer.contents b in 238 + Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) 239 + | Error e -> Error e 216 240 in 217 241 match yaml_result with 218 242 | Ok decoded when M.equal original decoded ->
+48 -30
tests/bin/test_scalars.ml
··· 5 5 6 6 (** Test scalar type resolution with Yamlt codec *) 7 7 8 + open Bytesrw 9 + 8 10 (* Helper to read file *) 9 11 let read_file path = 10 12 let ic = open_in path in ··· 36 38 in 37 39 38 40 (* Try decoding as null *) 39 - let result = Yamlt.decode_string null_codec yaml in 41 + let result = Yamlt.decode null_codec (Bytes.Reader.of_string yaml) in 40 42 show_result "null_codec" (Result.map (fun () -> "null") result) 41 43 42 44 (* Test: Boolean type-directed resolution *) ··· 60 62 61 63 Printf.printf "=== Bool Codec ===\n"; 62 64 let json_result = Jsont_bytesrw.decode_string bool_codec json in 63 - let yaml_result = Yamlt.decode_string bool_codec yaml in 65 + let yaml_result = Yamlt.decode bool_codec (Bytes.Reader.of_string yaml) in 64 66 show_result_json "bool_codec" 65 67 (Result.map (Printf.sprintf "%b") json_result) 66 68 (Result.map (Printf.sprintf "%b") yaml_result); 67 69 68 70 Printf.printf "\n=== String Codec ===\n"; 69 71 let json_result = Jsont_bytesrw.decode_string string_codec json in 70 - let yaml_result = Yamlt.decode_string string_codec yaml in 72 + let yaml_result = Yamlt.decode string_codec (Bytes.Reader.of_string yaml) in 71 73 show_result_json "string_codec" 72 74 (Result.map (Printf.sprintf "%S") json_result) 73 75 (Result.map (Printf.sprintf "%S") yaml_result) ··· 84 86 in 85 87 86 88 let json_result = Jsont_bytesrw.decode_string number_codec json in 87 - let yaml_result = Yamlt.decode_string number_codec yaml in 89 + let yaml_result = Yamlt.decode number_codec (Bytes.Reader.of_string yaml) in 88 90 89 91 show_result_json "number_codec" 90 92 (Result.map (Printf.sprintf "%.17g") json_result) ··· 102 104 in 103 105 104 106 let json_result = Jsont_bytesrw.decode_string string_codec json in 105 - let yaml_result = Yamlt.decode_string string_codec yaml in 107 + let yaml_result = Yamlt.decode string_codec (Bytes.Reader.of_string yaml) in 106 108 107 109 show_result_json "string_codec" 108 110 (Result.map (Printf.sprintf "%S") json_result) ··· 118 120 |> Jsont.Object.finish 119 121 in 120 122 121 - let result = Yamlt.decode_string number_codec yaml in 123 + let result = Yamlt.decode number_codec (Bytes.Reader.of_string yaml) in 122 124 match result with 123 125 | Ok f -> 124 126 if Float.is_nan f then Printf.printf "value: NaN\n" ··· 138 140 |> Jsont.Object.mem "value" Jsont.bool ~enc:(fun b -> b) 139 141 |> Jsont.Object.finish 140 142 in 141 - let result = Yamlt.decode_string codec yaml in 143 + let result = Yamlt.decode codec (Bytes.Reader.of_string yaml) in 142 144 match result with 143 145 | Ok _ -> Printf.printf "Unexpected success\n" 144 146 | Error e -> Printf.printf "Expected error: %s\n" e) ··· 148 150 |> Jsont.Object.mem "value" Jsont.number ~enc:(fun n -> n) 149 151 |> Jsont.Object.finish 150 152 in 151 - let result = Yamlt.decode_string codec yaml in 153 + let result = Yamlt.decode codec (Bytes.Reader.of_string yaml) in 152 154 match result with 153 155 | Ok _ -> Printf.printf "Unexpected success\n" 154 156 | Error e -> Printf.printf "Expected error: %s\n" e) ··· 158 160 |> Jsont.Object.mem "value" (Jsont.null ()) ~enc:(fun n -> n) 159 161 |> Jsont.Object.finish 160 162 in 161 - let result = Yamlt.decode_string codec yaml in 163 + let result = Yamlt.decode codec (Bytes.Reader.of_string yaml) in 162 164 match result with 163 165 | Ok _ -> Printf.printf "Unexpected success\n" 164 166 | Error e -> Printf.printf "Expected error: %s\n" e) ··· 176 178 in 177 179 178 180 let json_result = Jsont_bytesrw.decode_string any_codec json in 179 - let yaml_result = Yamlt.decode_string any_codec yaml in 181 + let yaml_result = Yamlt.decode any_codec (Bytes.Reader.of_string yaml) in 180 182 181 183 (* Just show that it decoded successfully *) 182 184 show_result_json "any_codec" ··· 196 198 (match Jsont_bytesrw.encode_string codec v with 197 199 | Ok s -> Printf.printf "JSON: %s\n" (String.trim s) 198 200 | Error e -> Printf.printf "JSON ERROR: %s\n" e); 199 - (match Yamlt.encode_string ~format:Yamlt.Block codec v with 200 - | Ok s -> Printf.printf "YAML Block:\n%s" s 201 - | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 202 - match Yamlt.encode_string ~format:Yamlt.Flow codec v with 203 - | Ok s -> Printf.printf "YAML Flow: %s" s 201 + (let b = Buffer.create 256 in 202 + let writer = Bytes.Writer.of_buffer b in 203 + match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with 204 + | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b) 205 + | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 206 + let b = Buffer.create 256 in 207 + let writer = Bytes.Writer.of_buffer b in 208 + match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with 209 + | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b) 204 210 | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e) 205 211 | "number" -> ( 206 212 let codec = ··· 212 218 (match Jsont_bytesrw.encode_string codec v with 213 219 | Ok s -> Printf.printf "JSON: %s\n" (String.trim s) 214 220 | Error e -> Printf.printf "JSON ERROR: %s\n" e); 215 - (match Yamlt.encode_string ~format:Yamlt.Block codec v with 216 - | Ok s -> Printf.printf "YAML Block:\n%s" s 217 - | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 218 - match Yamlt.encode_string ~format:Yamlt.Flow codec v with 219 - | Ok s -> Printf.printf "YAML Flow: %s" s 221 + (let b = Buffer.create 256 in 222 + let writer = Bytes.Writer.of_buffer b in 223 + match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with 224 + | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b) 225 + | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 226 + let b = Buffer.create 256 in 227 + let writer = Bytes.Writer.of_buffer b in 228 + match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with 229 + | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b) 220 230 | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e) 221 231 | "string" -> ( 222 232 let codec = ··· 228 238 (match Jsont_bytesrw.encode_string codec v with 229 239 | Ok s -> Printf.printf "JSON: %s\n" (String.trim s) 230 240 | Error e -> Printf.printf "JSON ERROR: %s\n" e); 231 - (match Yamlt.encode_string ~format:Yamlt.Block codec v with 232 - | Ok s -> Printf.printf "YAML Block:\n%s" s 233 - | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 234 - match Yamlt.encode_string ~format:Yamlt.Flow codec v with 235 - | Ok s -> Printf.printf "YAML Flow: %s" s 241 + (let b = Buffer.create 256 in 242 + let writer = Bytes.Writer.of_buffer b in 243 + match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with 244 + | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b) 245 + | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 246 + let b = Buffer.create 256 in 247 + let writer = Bytes.Writer.of_buffer b in 248 + match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with 249 + | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b) 236 250 | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e) 237 251 | "null" -> ( 238 252 let codec = ··· 244 258 (match Jsont_bytesrw.encode_string codec v with 245 259 | Ok s -> Printf.printf "JSON: %s\n" (String.trim s) 246 260 | Error e -> Printf.printf "JSON ERROR: %s\n" e); 247 - (match Yamlt.encode_string ~format:Yamlt.Block codec v with 248 - | Ok s -> Printf.printf "YAML Block:\n%s" s 249 - | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 250 - match Yamlt.encode_string ~format:Yamlt.Flow codec v with 251 - | Ok s -> Printf.printf "YAML Flow: %s" s 261 + (let b = Buffer.create 256 in 262 + let writer = Bytes.Writer.of_buffer b in 263 + match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with 264 + | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b) 265 + | Error e -> Printf.printf "YAML Block ERROR: %s\n" e); 266 + let b = Buffer.create 256 in 267 + let writer = Bytes.Writer.of_buffer b in 268 + match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with 269 + | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b) 252 270 | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e) 253 271 | _ -> failwith "unknown type" 254 272
+4 -2
tests/bin/test_some_vs_option.ml
··· 1 + open Bytesrw 2 + 1 3 let () = 2 4 (* Using Jsont.some like opt_mem does *) 3 5 let codec1 = ··· 11 13 let yaml = "values: [a, b, c]" in 12 14 13 15 Printf.printf "Test 1: Jsont.some (Jsont.array) - like opt_mem:\n"; 14 - (match Yamlt.decode_string codec1 yaml with 16 + (match Yamlt.decode codec1 (Bytes.Reader.of_string yaml) with 15 17 | Ok arr -> ( 16 18 match arr with 17 19 | None -> Printf.printf "Result: None\n" ··· 28 30 in 29 31 30 32 Printf.printf "\nTest 2: Jsont.option (Jsont.array):\n"; 31 - match Yamlt.decode_string codec2 yaml with 33 + match Yamlt.decode codec2 (Bytes.Reader.of_string yaml) with 32 34 | Ok arr -> ( 33 35 match arr with 34 36 | None -> Printf.printf "Result: None\n"
+1
tests/cram/dune
··· 13 13 (glob_files ../data/complex/*.json) 14 14 (glob_files ../data/edge/*.yml) 15 15 (glob_files ../data/edge/*.json) 16 + (glob_files ../data/multidoc/*.yml) 16 17 (glob_files ../data/locations/*.yml)))
+4 -4
tests/cram/locations.t
··· 25 25 === With locs=true === 26 26 Error message: 27 27 String "not-a-number" does not parse to OCaml int value 28 - File "-", lines 2-3, characters 5-0: 28 + File "-", line 2, characters 5-18: 29 29 File "-", line 2, characters 0-3: in member age of 30 30 File "-", line 1, characters 0-1: Person object 31 31 ··· 51 51 === With locs=true === 52 52 Nested error: 53 53 String "invalid-zip" does not parse to OCaml int value 54 - File "-", lines 5-6, characters 7-0: 54 + File "-", line 5, characters 7-19: 55 55 File "-", line 5, characters 2-5: in member zip of 56 56 File "-", line 3, characters 2-3: Address object 57 57 File "-", line 2, characters 0-7: in member address of ··· 94 94 === Without file path === 95 95 Error: 96 96 String "not-a-number" does not parse to OCaml int value 97 - File "-", lines 2-3, characters 5-0: 97 + File "-", line 2, characters 5-18: 98 98 File "-", line 2, characters 0-3: in member age of 99 99 File "-", line 1, characters 0-1: Person object 100 100 101 101 === With file path === 102 102 Error: 103 103 String "not-a-number" does not parse to OCaml int value 104 - File "test.yml", lines 2-3, characters 5-0: 104 + File "test.yml", line 2, characters 5-18: 105 105 File "test.yml", line 2, characters 0-3: in member age of 106 106 File "test.yml", line 1, characters 0-1: Person object 107 107
+220
tests/cram/multidoc.t
··· 1 + Multi-Document YAML Streams with Yamlt 2 + ======================================== 3 + 4 + This test suite validates multi-document YAML stream decoding using decode_all, 5 + including error handling, location tracking, and JSON roundtripping. 6 + 7 + ================================================================================ 8 + BASIC MULTIDOC DECODING 9 + ================================================================================ 10 + 11 + Simple multi-document stream with person objects 12 + 13 + $ test_multidoc simple ../data/multidoc/simple.yml 14 + Documents: 15 + [0] : Alice (age 30) 16 + [1] : Bob (age 25) 17 + [2] : Charlie (age 35) 18 + 19 + Count documents in a stream 20 + 21 + $ test_multidoc count ../data/multidoc/simple.yml 22 + Document count: 3 23 + 24 + ================================================================================ 25 + ERROR HANDLING - MIXED VALID AND INVALID DOCUMENTS 26 + ================================================================================ 27 + 28 + When some documents succeed and others fail, decode_all continues processing 29 + and returns results for each document individually. 30 + 31 + Stream with one error in the middle 32 + 33 + $ test_multidoc errors ../data/multidoc/mixed_errors.yml 34 + Document results: 35 + [0] OK: Alice (age 30) 36 + [1] ERROR: String "not-a-number" does not parse to OCaml int value 37 + File "-": 38 + File "-": in member age of 39 + File "-": Person object 40 + [2] OK: Charlie (age 35) 41 + 42 + Summary statistics for mixed documents 43 + 44 + $ test_multidoc summary ../data/multidoc/mixed_errors.yml 45 + Summary: 3 documents (2 ok, 1 error) 46 + 47 + Stream where all documents fail 48 + 49 + $ test_multidoc errors ../data/multidoc/all_errors.yml 50 + Document results: 51 + [0] ERROR: String "invalid1" does not parse to OCaml int value 52 + File "-": 53 + File "-": in member age of 54 + File "-": Person object 55 + [1] ERROR: String "invalid2" does not parse to OCaml int value 56 + File "-": 57 + File "-": in member age of 58 + File "-": Person object 59 + [2] ERROR: String "invalid3" does not parse to OCaml int value 60 + File "-": 61 + File "-": in member age of 62 + File "-": Person object 63 + 64 + Summary for all-error stream 65 + 66 + $ test_multidoc summary ../data/multidoc/all_errors.yml 67 + Summary: 3 documents (0 ok, 3 error) 68 + 69 + ================================================================================ 70 + LOCATION TRACKING WITH locs=true 71 + ================================================================================ 72 + 73 + Location tracking helps identify exactly where errors occur in each document 74 + of a multi-document stream. 75 + 76 + Without locs (default) - basic error information 77 + 78 + $ test_multidoc locations ../data/multidoc/mixed_errors.yml 79 + === Without locs (default) === 80 + [0] OK 81 + [1] ERROR: 82 + String "not-a-number" does not parse to OCaml int value 83 + File "-": 84 + File "-": in member age of 85 + File "-": Person object 86 + [2] OK 87 + 88 + === With locs=true === 89 + [0] OK 90 + [1] ERROR: 91 + String "not-a-number" does not parse to OCaml int value 92 + File "test.yml", line 6, characters 5-18: 93 + File "test.yml", line 6, characters 0-3: in member age of 94 + File "test.yml", line 5, characters 0-1: Person object 95 + [2] OK 96 + 97 + ================================================================================ 98 + MISSING FIELDS IN MULTIDOC 99 + ================================================================================ 100 + 101 + Documents with missing required fields generate errors but don't stop 102 + processing of subsequent documents. 103 + 104 + $ test_multidoc errors ../data/multidoc/missing_fields.yml 105 + Document results: 106 + [0] OK: Alice (age 30) 107 + [1] ERROR: Missing member age in Person object 108 + File "-": 109 + [2] OK: Charlie (age 35) 110 + 111 + Summary of missing fields test 112 + 113 + $ test_multidoc summary ../data/multidoc/missing_fields.yml 114 + Summary: 3 documents (2 ok, 1 error) 115 + 116 + ================================================================================ 117 + JSON ROUNDTRIPPING 118 + ================================================================================ 119 + 120 + Decode YAML multi-document streams and encode each document as JSON. 121 + This validates that the data model conversion is correct. 122 + 123 + Simple documents to JSON 124 + 125 + $ test_multidoc json ../data/multidoc/simple.yml 126 + JSON outputs: 127 + [0] {"name":"Alice","age":30} 128 + [1] {"name":"Bob","age":25} 129 + [2] {"name":"Charlie","age":35} 130 + 131 + Nested objects to JSON 132 + 133 + $ test_multidoc json ../data/multidoc/nested.yml 134 + JSON outputs: 135 + [0] {"name":"Alice","age":30,"address":{"street":"123 Main St","city":"Boston"}} 136 + [1] {"name":"Bob","age":25,"address":{"street":"456 Oak Ave","city":"Seattle"}} 137 + [2] {"name":"Charlie","age":35,"address":{"street":"789 Pine Rd","city":"Portland"}} 138 + 139 + Arrays to JSON 140 + 141 + $ test_multidoc json ../data/multidoc/arrays.yml 142 + JSON outputs: 143 + [0] [1,2,3] 144 + [1] ["apple","banana","cherry"] 145 + [2] [true,false,true] 146 + 147 + Scalar values to JSON 148 + 149 + $ test_multidoc json ../data/multidoc/scalars.yml 150 + JSON outputs: 151 + [0] "hello world" 152 + [1] 42 153 + [2] true 154 + [3] null 155 + 156 + ================================================================================ 157 + NESTED OBJECTS IN MULTIDOC 158 + ================================================================================ 159 + 160 + Test decoding complex nested structures across multiple documents. 161 + 162 + $ test_multidoc nested ../data/multidoc/nested.yml 163 + Nested documents: 164 + [0] : Alice (age 30) from 123 Main St, Boston 165 + [1] : Bob (age 25) from 456 Oak Ave, Seattle 166 + [2] : Charlie (age 35) from 789 Pine Rd, Portland 167 + 168 + ================================================================================ 169 + ARRAYS IN MULTIDOC 170 + ================================================================================ 171 + 172 + Test decoding different array types across documents. 173 + 174 + $ test_multidoc arrays ../data/multidoc/arrays.yml 175 + Array documents: 176 + [0] [1,2,3] 177 + [1] ["apple","banana","cherry"] 178 + [2] [true,false,true] 179 + 180 + ================================================================================ 181 + SCALARS IN MULTIDOC 182 + ================================================================================ 183 + 184 + Test decoding bare scalar values as documents. 185 + 186 + $ test_multidoc scalars ../data/multidoc/scalars.yml 187 + Scalar documents: 188 + [0] "hello world" 189 + [1] 42 190 + [2] true 191 + [3] null 192 + 193 + ================================================================================ 194 + EMPTY DOCUMENTS 195 + ================================================================================ 196 + 197 + Empty or null documents in a stream are handled correctly. 198 + 199 + $ test_multidoc json ../data/multidoc/empty_docs.yml 200 + JSON outputs: 201 + [0] {"name":"Alice","age":30} 202 + [1] null 203 + [2] {"name":"Charlie","age":35} 204 + 205 + Count including empty documents 206 + 207 + $ test_multidoc count ../data/multidoc/empty_docs.yml 208 + Document count: 3 209 + 210 + ================================================================================ 211 + SUMMARY 212 + ================================================================================ 213 + 214 + The decode_all function: 215 + - Processes all documents in a stream, not stopping on errors 216 + - Returns a sequence of Result values (Ok/Error for each document) 217 + - Supports all decode options: locs, layout, file, max_depth, max_nodes 218 + - Correctly handles document boundaries even when errors occur 219 + - Works with any Jsont codec (objects, arrays, scalars, etc.) 220 + - Can be used for JSON roundtripping and format conversion
+9
tests/data/multidoc/all_errors.yml
··· 1 + --- 2 + name: Alice 3 + age: invalid1 4 + --- 5 + name: Bob 6 + age: invalid2 7 + --- 8 + name: Charlie 9 + age: invalid3
+12
tests/data/multidoc/arrays.yml
··· 1 + --- 2 + - 1 3 + - 2 4 + - 3 5 + --- 6 + - apple 7 + - banana 8 + - cherry 9 + --- 10 + - true 11 + - false 12 + - true
+7
tests/data/multidoc/empty_docs.yml
··· 1 + --- 2 + name: Alice 3 + age: 30 4 + --- 5 + --- 6 + name: Charlie 7 + age: 35
+9
tests/data/multidoc/missing_fields.yml
··· 1 + --- 2 + name: Alice 3 + age: 30 4 + --- 5 + name: Bob 6 + --- 7 + name: Charlie 8 + age: 35 9 + city: Springfield
+9
tests/data/multidoc/mixed_errors.yml
··· 1 + --- 2 + name: Alice 3 + age: 30 4 + --- 5 + name: Bob 6 + age: not-a-number 7 + --- 8 + name: Charlie 9 + age: 35
+18
tests/data/multidoc/nested.yml
··· 1 + --- 2 + name: Alice 3 + age: 30 4 + address: 5 + street: 123 Main St 6 + city: Boston 7 + --- 8 + name: Bob 9 + age: 25 10 + address: 11 + street: 456 Oak Ave 12 + city: Seattle 13 + --- 14 + name: Charlie 15 + age: 35 16 + address: 17 + street: 789 Pine Rd 18 + city: Portland
+8
tests/data/multidoc/scalars.yml
··· 1 + --- 2 + hello world 3 + --- 4 + 42 5 + --- 6 + true 7 + --- 8 + null
+9
tests/data/multidoc/simple.yml
··· 1 + --- 2 + name: Alice 3 + age: 30 4 + --- 5 + name: Bob 6 + age: 25 7 + --- 8 + name: Charlie 9 + age: 35