Yaml encoder/decoder for OCaml jsont codecs

remove of_string functions, add multidoc and fix location eol

+85 -34
lib/yamlt.ml
···
SPDX-License-Identifier: ISC
---------------------------------------------------------------------------*)
-
open Bytesrw
open Jsont.Repr
open Yamlrw
···
let first_line =
(start.Position.line, start.Position.index - start.Position.column + 1)
in
let last_line =
-
(stop.Position.line, stop.Position.index - stop.Position.column + 1)
in
let textloc =
Jsont.Textloc.make ~file:d.file ~first_byte ~last_byte ~first_line
···
in
loop ()
(* Public decode API *)
let decode' ?layout ?locs ?file ?max_depth ?max_nodes t reader =
let parser = Parser.of_reader reader in
let d = make_decoder ?layout ?locs ?file ?max_depth ?max_nodes parser in
···
let decode ?layout ?locs ?file ?max_depth ?max_nodes t reader =
Result.map_error Jsont.Error.to_string
(decode' ?layout ?locs ?file ?max_depth ?max_nodes t reader)
-
-
let decode_string' ?layout ?locs ?file ?max_depth ?max_nodes t s =
-
decode' ?layout ?locs ?file ?max_depth ?max_nodes t (Bytes.Reader.of_string s)
-
-
let decode_string ?layout ?locs ?file ?max_depth ?max_nodes t s =
-
decode ?layout ?locs ?file ?max_depth ?max_nodes t (Bytes.Reader.of_string s)
(* Encoder *)
···
Result.map_error Jsont.Error.to_string
(encode' ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer)
-
let encode_string' ?buf ?format ?indent ?explicit_doc ?scalar_style t v =
-
let b = Buffer.create 256 in
-
let writer = Bytes.Writer.of_buffer b in
-
match
-
encode' ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod:true
-
writer
-
with
-
| Ok () -> Ok (Buffer.contents b)
-
| Error e -> Error e
-
-
let encode_string ?buf ?format ?indent ?explicit_doc ?scalar_style t v =
-
Result.map_error Jsont.Error.to_string
-
(encode_string' ?buf ?format ?indent ?explicit_doc ?scalar_style t v)
-
(* Recode *)
let recode ?layout ?locs ?file ?max_depth ?max_nodes ?buf ?format ?indent
···
| Ok v ->
encode ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer
| Error e -> Error (Jsont.Error.to_string e)
-
-
let recode_string ?layout ?locs ?file ?max_depth ?max_nodes ?buf ?format ?indent
-
?explicit_doc ?scalar_style t s =
-
let format =
-
match (layout, format) with Some true, None -> Some Layout | _, f -> f
-
in
-
let layout =
-
match (layout, format) with None, Some Layout -> Some true | l, _ -> l
-
in
-
match decode_string' ?layout ?locs ?file ?max_depth ?max_nodes t s with
-
| Ok v -> encode_string ?buf ?format ?indent ?explicit_doc ?scalar_style t v
-
| Error e -> Error (Jsont.Error.to_string e)
···
SPDX-License-Identifier: ISC
---------------------------------------------------------------------------*)
open Jsont.Repr
open Yamlrw
···
let first_line =
(start.Position.line, start.Position.index - start.Position.column + 1)
in
+
(* Handle case where stop is at the start of a new line (column 1)
+
This happens when the span includes a trailing newline.
+
The last_byte is on the previous line, so we need to calculate
+
the line start position based on last_byte, not stop. *)
let last_line =
+
if stop.Position.column = 1 && stop.Position.line > start.Position.line then
+
(* last_byte is on the previous line (stop.line - 1)
+
We need to estimate where that line starts. Since we don't have
+
the full text, we can't calculate it exactly, but we can use:
+
last_byte - (estimated_column - 1)
+
For now, we'll use the same line as start if they're close,
+
or just report it as the previous line. *)
+
let last_line_num = stop.Position.line - 1 in
+
(* Estimate: assume last_byte is somewhere on the previous line.
+
We'll use the byte position minus a reasonable offset.
+
This is approximate but better than wrapping to the next line. *)
+
if last_line_num = start.Position.line then
+
(* Same line as start - use start's line position *)
+
first_line
+
else
+
(* Different line - estimate line start as last_byte minus some offset
+
Since we subtracted 1 from stop.index to get last_byte, and stop.column was 1,
+
last_byte should be the newline character on the previous line.
+
The line likely started much earlier, but we'll estimate conservatively. *)
+
(last_line_num, last_byte)
+
else
+
(stop.Position.line, stop.Position.index - stop.Position.column + 1)
in
let textloc =
Jsont.Textloc.make ~file:d.file ~first_byte ~last_byte ~first_line
···
in
loop ()
+
(* Skip to the end of the current document after an error *)
+
let skip_to_document_end d =
+
let rec loop depth =
+
match peek_event d with
+
| None -> ()
+
| Some { Event.event = Event.Stream_end; _ } -> ()
+
| Some { Event.event = Event.Document_end _; _ } ->
+
skip_event d;
+
if depth = 0 then () else loop (depth - 1)
+
| Some { Event.event = Event.Document_start _; _ } ->
+
skip_event d;
+
loop (depth + 1)
+
| Some _ ->
+
skip_event d;
+
loop depth
+
in
+
loop 0
+
(* Public decode API *)
+
(* Decode all documents from a multi-document YAML stream *)
+
let decode_all' ?(layout = false) ?(locs = false) ?(file = "-")
+
?(max_depth = 100) ?(max_nodes = 10_000_000) t reader =
+
let parser = Parser.of_reader reader in
+
let d = make_decoder ~layout ~locs ~file ~max_depth ~max_nodes parser in
+
let t' = Jsont.Repr.of_t t in
+
let rec next_doc () =
+
match peek_event d with
+
| None -> Seq.Nil
+
| Some { Event.event = Event.Stream_end; _ } ->
+
skip_event d;
+
Seq.Nil
+
| Some _ -> (
+
try
+
skip_to_content d;
+
(* Reset node count for each document *)
+
d.node_count <- 0;
+
let v = decode d ~nest:0 t' in
+
(* Skip document end marker if present *)
+
(match peek_event d with
+
| Some { Event.event = Event.Document_end _; _ } -> skip_event d
+
| _ -> ());
+
Seq.Cons (Ok v, next_doc)
+
with
+
| Jsont.Error e ->
+
skip_to_document_end d;
+
Seq.Cons (Error e, next_doc)
+
| Error.Yamlrw_error err ->
+
skip_to_document_end d;
+
let msg = Error.to_string err in
+
let e =
+
Jsont.Error.make_msg Jsont.Error.Context.empty Jsont.Meta.none msg
+
in
+
Seq.Cons (Error e, next_doc))
+
in
+
next_doc
+
+
let decode_all ?layout ?locs ?file ?max_depth ?max_nodes t reader =
+
decode_all' ?layout ?locs ?file ?max_depth ?max_nodes t reader
+
|> Seq.map (Result.map_error Jsont.Error.to_string)
+
let decode' ?layout ?locs ?file ?max_depth ?max_nodes t reader =
let parser = Parser.of_reader reader in
let d = make_decoder ?layout ?locs ?file ?max_depth ?max_nodes parser in
···
let decode ?layout ?locs ?file ?max_depth ?max_nodes t reader =
Result.map_error Jsont.Error.to_string
(decode' ?layout ?locs ?file ?max_depth ?max_nodes t reader)
(* Encoder *)
···
Result.map_error Jsont.Error.to_string
(encode' ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer)
(* Recode *)
let recode ?layout ?locs ?file ?max_depth ?max_nodes ?buf ?format ?indent
···
| Ok v ->
encode ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer
| Error e -> Error (Jsont.Error.to_string e)
+11 -47
lib/yamlt.mli
···
('a, Jsont.Error.t) result
(** [decode'] is like {!val-decode} but preserves the error structure. *)
-
val decode_string :
?layout:bool ->
?locs:bool ->
?file:Jsont.Textloc.fpath ->
?max_depth:int ->
?max_nodes:int ->
'a Jsont.t ->
-
string ->
-
('a, string) result
-
(** [decode_string] is like {!val-decode} but decodes directly from a string. *)
-
val decode_string' :
?layout:bool ->
?locs:bool ->
?file:Jsont.Textloc.fpath ->
?max_depth:int ->
?max_nodes:int ->
'a Jsont.t ->
-
string ->
-
('a, Jsont.Error.t) result
-
(** [decode_string'] is like {!val-decode'} but decodes directly from a string.
-
*)
(** {1:encode Encode} *)
···
(unit, Jsont.Error.t) result
(** [encode'] is like {!val-encode} but preserves the error structure. *)
-
val encode_string :
-
?buf:Stdlib.Bytes.t ->
-
?format:yaml_format ->
-
?indent:int ->
-
?explicit_doc:bool ->
-
?scalar_style:Yamlrw.Scalar_style.t ->
-
'a Jsont.t ->
-
'a ->
-
(string, string) result
-
(** [encode_string] is like {!val-encode} but writes to a string. *)
-
-
val encode_string' :
-
?buf:Stdlib.Bytes.t ->
-
?format:yaml_format ->
-
?indent:int ->
-
?explicit_doc:bool ->
-
?scalar_style:Yamlrw.Scalar_style.t ->
-
'a Jsont.t ->
-
'a ->
-
(string, Jsont.Error.t) result
-
(** [encode_string'] is like {!val-encode'} but writes to a string. *)
-
(** {1:recode Recode}
The defaults in these functions are those of {!val-decode} and
···
eod:bool ->
(unit, string) result
(** [recode t r w] is {!val-decode} followed by {!val-encode}. *)
-
-
val recode_string :
-
?layout:bool ->
-
?locs:bool ->
-
?file:Jsont.Textloc.fpath ->
-
?max_depth:int ->
-
?max_nodes:int ->
-
?buf:Stdlib.Bytes.t ->
-
?format:yaml_format ->
-
?indent:int ->
-
?explicit_doc:bool ->
-
?scalar_style:Yamlrw.Scalar_style.t ->
-
'a Jsont.t ->
-
string ->
-
(string, string) result
-
(** [recode_string] is like {!val-recode} but operates on strings. *)
(** {1:yaml_mapping YAML to JSON Mapping}
···
('a, Jsont.Error.t) result
(** [decode'] is like {!val-decode} but preserves the error structure. *)
+
val decode_all :
?layout:bool ->
?locs:bool ->
?file:Jsont.Textloc.fpath ->
?max_depth:int ->
?max_nodes:int ->
'a Jsont.t ->
+
Bytes.Reader.t ->
+
('a, string) result Seq.t
+
(** [decode_all t r] decodes all documents from a multi-document YAML stream.
+
Returns a sequence where each element is a result of decoding one document.
+
Parameters are as in {!val-decode}. Use this for YAML streams containing
+
multiple documents separated by [---]. *)
+
val decode_all' :
?layout:bool ->
?locs:bool ->
?file:Jsont.Textloc.fpath ->
?max_depth:int ->
?max_nodes:int ->
'a Jsont.t ->
+
Bytes.Reader.t ->
+
('a, Jsont.Error.t) result Seq.t
+
(** [decode_all'] is like {!val-decode_all} but preserves the error structure. *)
(** {1:encode Encode} *)
···
(unit, Jsont.Error.t) result
(** [encode'] is like {!val-encode} but preserves the error structure. *)
(** {1:recode Recode}
The defaults in these functions are those of {!val-decode} and
···
eod:bool ->
(unit, string) result
(** [recode t r w] is {!val-decode} followed by {!val-encode}. *)
(** {1:yaml_mapping YAML to JSON Mapping}
+5
tests/bin/dune
···
(name test_locations)
(public_name test_locations)
(libraries yamlt jsont jsont.bytesrw bytesrw))
···
(name test_locations)
(public_name test_locations)
(libraries yamlt jsont jsont.bytesrw bytesrw))
+
+
(executable
+
(name test_multidoc)
+
(public_name test_multidoc)
+
(libraries yamlt jsont jsont.bytesrw bytesrw))
+4 -2
tests/bin/test_array_variants.ml
···
let () =
let codec1 =
Jsont.Object.map ~kind:"Test" (fun arr -> arr)
···
let yaml1 = "values: [a, b, c]" in
Printf.printf "Test 1: Non-optional array:\n";
-
(match Yamlt.decode_string codec1 yaml1 with
| Ok arr -> Printf.printf "Result: [%d items]\n" (Array.length arr)
| Error e -> Printf.printf "Error: %s\n" e);
···
in
Printf.printf "\nTest 2: Jsont.option (Jsont.array):\n";
-
match Yamlt.decode_string codec2 yaml1 with
| Ok arr -> (
match arr with
| None -> Printf.printf "Result: None\n"
···
+
open Bytesrw
+
let () =
let codec1 =
Jsont.Object.map ~kind:"Test" (fun arr -> arr)
···
let yaml1 = "values: [a, b, c]" in
Printf.printf "Test 1: Non-optional array:\n";
+
(match Yamlt.decode codec1 (Bytes.Reader.of_string yaml1) with
| Ok arr -> Printf.printf "Result: [%d items]\n" (Array.length arr)
| Error e -> Printf.printf "Error: %s\n" e);
···
in
Printf.printf "\nTest 2: Jsont.option (Jsont.array):\n";
+
match Yamlt.decode codec2 (Bytes.Reader.of_string yaml1) with
| Ok arr -> (
match arr with
| None -> Printf.printf "Result: None\n"
+20 -14
tests/bin/test_arrays.ml
···
(** Test array codec functionality with Yamlt *)
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
-
let yaml_result = Yamlt.decode_string M.numbers_codec yaml in
show_result_both "int_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.tags_codec json in
-
let yaml_result = Yamlt.decode_string M.tags_codec yaml in
show_result_both "string_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.measurements_codec json in
-
let yaml_result = Yamlt.decode_string M.measurements_codec yaml in
show_result_both "float_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.empty_codec json in
-
let yaml_result = Yamlt.decode_string M.empty_codec yaml in
show_result_both "empty_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.people_codec json in
-
let yaml_result = Yamlt.decode_string M.people_codec yaml in
show_result_both "object_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.matrix_codec json in
-
let yaml_result = Yamlt.decode_string M.matrix_codec yaml in
show_result_both "nested_arrays"
(Result.map M.show json_result)
···
|> Jsont.Object.finish
end in
let yaml = read_file file in
-
let result = Yamlt.decode_string M.numbers_codec yaml in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.flags_codec json in
-
let yaml_result = Yamlt.decode_string M.flags_codec yaml in
show_result_both "bool_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.nullable_codec json in
-
let yaml_result = Yamlt.decode_string M.nullable_codec yaml in
show_result_both "nullable_array"
(Result.map M.show json_result)
···
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
(* Encode to YAML Block *)
-
(match Yamlt.encode_string ~format:Yamlt.Block M.data_codec data with
-
| Ok s -> Printf.printf "YAML Block:\n%s" s
-
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
(* Encode to YAML Flow *)
-
match Yamlt.encode_string ~format:Yamlt.Flow M.data_codec data with
-
| Ok s -> Printf.printf "YAML Flow: %s" s
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
let () =
···
(** Test array codec functionality with Yamlt *)
+
open Bytesrw
+
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
+
let yaml_result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in
show_result_both "int_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.tags_codec json in
+
let yaml_result = Yamlt.decode M.tags_codec (Bytes.Reader.of_string yaml) in
show_result_both "string_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.measurements_codec json in
+
let yaml_result = Yamlt.decode M.measurements_codec (Bytes.Reader.of_string yaml) in
show_result_both "float_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.empty_codec json in
+
let yaml_result = Yamlt.decode M.empty_codec (Bytes.Reader.of_string yaml) in
show_result_both "empty_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.people_codec json in
+
let yaml_result = Yamlt.decode M.people_codec (Bytes.Reader.of_string yaml) in
show_result_both "object_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.matrix_codec json in
+
let yaml_result = Yamlt.decode M.matrix_codec (Bytes.Reader.of_string yaml) in
show_result_both "nested_arrays"
(Result.map M.show json_result)
···
|> Jsont.Object.finish
end in
let yaml = read_file file in
+
let result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.flags_codec json in
+
let yaml_result = Yamlt.decode M.flags_codec (Bytes.Reader.of_string yaml) in
show_result_both "bool_array"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.nullable_codec json in
+
let yaml_result = Yamlt.decode M.nullable_codec (Bytes.Reader.of_string yaml) in
show_result_both "nullable_array"
(Result.map M.show json_result)
···
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
(* Encode to YAML Block *)
+
(let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Block M.data_codec data ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
+
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
(* Encode to YAML Flow *)
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Flow M.data_codec data ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
let () =
+6 -4
tests/bin/test_complex.ml
···
(** Test complex nested types with Yamlt *)
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.root_codec json in
-
let yaml_result = Yamlt.decode_string M.root_codec yaml in
show_result_both "deep_nesting"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.collection_codec json in
-
let yaml_result = Yamlt.decode_string M.collection_codec yaml in
show_result_both "mixed_structure"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.config_codec json in
-
let yaml_result = Yamlt.decode_string M.config_codec yaml in
show_result_both "complex_optional"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.data_codec json in
-
let yaml_result = Yamlt.decode_string M.data_codec yaml in
show_result_both "heterogeneous"
(Result.map M.show json_result)
···
(** Test complex nested types with Yamlt *)
+
open Bytesrw
+
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.root_codec json in
+
let yaml_result = Yamlt.decode M.root_codec (Bytes.Reader.of_string yaml) in
show_result_both "deep_nesting"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.collection_codec json in
+
let yaml_result = Yamlt.decode M.collection_codec (Bytes.Reader.of_string yaml) in
show_result_both "mixed_structure"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.config_codec json in
+
let yaml_result = Yamlt.decode M.config_codec (Bytes.Reader.of_string yaml) in
show_result_both "complex_optional"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.data_codec json in
+
let yaml_result = Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) in
show_result_both "heterogeneous"
(Result.map M.show json_result)
+18 -14
tests/bin/test_comprehensive.ml
···
let () =
(* Test 1: Null handling with option types *)
Printf.printf "=== NULL HANDLING ===\n";
···
|> Jsont.Object.finish
in
-
(match Yamlt.decode_string opt_codec "value: null" with
| Ok None -> Printf.printf "✓ Plain 'null' with option codec: None\n"
| _ -> Printf.printf "✗ FAIL\n");
-
(match Yamlt.decode_string opt_codec "value: hello" with
| Ok (Some "hello") ->
Printf.printf "✓ Plain 'hello' with option codec: Some(hello)\n"
| _ -> Printf.printf "✗ FAIL\n");
···
|> Jsont.Object.finish
in
-
(match Yamlt.decode_string string_codec "value: null" with
| Error _ ->
Printf.printf "✓ Plain 'null' with string codec: ERROR (expected)\n"
| _ -> Printf.printf "✗ FAIL\n");
-
(match Yamlt.decode_string string_codec "value: \"\"" with
| Ok "" -> Printf.printf "✓ Quoted empty string: \"\"\n"
| _ -> Printf.printf "✗ FAIL\n");
-
(match Yamlt.decode_string string_codec "value: \"null\"" with
| Ok "null" -> Printf.printf "✓ Quoted 'null': \"null\"\n"
| _ -> Printf.printf "✗ FAIL\n");
···
|> Jsont.Object.finish
in
-
(match Yamlt.decode_string num_codec "value: 0xFF" with
| Ok 255. -> Printf.printf "✓ Hex 0xFF: 255\n"
| _ -> Printf.printf "✗ FAIL\n");
-
(match Yamlt.decode_string num_codec "value: 0o77" with
| Ok 63. -> Printf.printf "✓ Octal 0o77: 63\n"
| _ -> Printf.printf "✗ FAIL\n");
-
(match Yamlt.decode_string num_codec "value: 0b1010" with
| Ok 10. -> Printf.printf "✓ Binary 0b1010: 10\n"
| _ -> Printf.printf "✗ FAIL\n");
···
|> Jsont.Object.finish
in
-
(match Yamlt.decode_string opt_array_codec "values: [a, b, c]" with
| Ok (Some arr) when Array.length arr = 3 ->
Printf.printf "✓ Optional array [a, b, c]: Some([3 items])\n"
| _ -> Printf.printf "✗ FAIL\n");
-
(match Yamlt.decode_string opt_array_codec "{}" with
| Ok None -> Printf.printf "✓ Missing optional array: None\n"
| _ -> Printf.printf "✗ FAIL\n");
···
|> Jsont.Object.finish
in
match
-
Yamlt.encode_string ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |])
with
-
| Ok yaml_flow
-
when String.equal yaml_flow "{name: test, values: [1.0, 2.0, 3.0]}\n" ->
Printf.printf "✓ Flow encoding with comma separator\n"
-
| Ok yaml_flow -> Printf.printf "✗ FAIL: %S\n" yaml_flow
| Error e -> Printf.printf "✗ ERROR: %s\n" e
···
+
open Bytesrw
+
let () =
(* Test 1: Null handling with option types *)
Printf.printf "=== NULL HANDLING ===\n";
···
|> Jsont.Object.finish
in
+
(match Yamlt.decode opt_codec (Bytes.Reader.of_string "value: null") with
| Ok None -> Printf.printf "✓ Plain 'null' with option codec: None\n"
| _ -> Printf.printf "✗ FAIL\n");
+
(match Yamlt.decode opt_codec (Bytes.Reader.of_string "value: hello") with
| Ok (Some "hello") ->
Printf.printf "✓ Plain 'hello' with option codec: Some(hello)\n"
| _ -> Printf.printf "✗ FAIL\n");
···
|> Jsont.Object.finish
in
+
(match Yamlt.decode string_codec (Bytes.Reader.of_string "value: null") with
| Error _ ->
Printf.printf "✓ Plain 'null' with string codec: ERROR (expected)\n"
| _ -> Printf.printf "✗ FAIL\n");
+
(match Yamlt.decode string_codec (Bytes.Reader.of_string "value: \"\"") with
| Ok "" -> Printf.printf "✓ Quoted empty string: \"\"\n"
| _ -> Printf.printf "✗ FAIL\n");
+
(match Yamlt.decode string_codec (Bytes.Reader.of_string "value: \"null\"") with
| Ok "null" -> Printf.printf "✓ Quoted 'null': \"null\"\n"
| _ -> Printf.printf "✗ FAIL\n");
···
|> Jsont.Object.finish
in
+
(match Yamlt.decode num_codec (Bytes.Reader.of_string "value: 0xFF") with
| Ok 255. -> Printf.printf "✓ Hex 0xFF: 255\n"
| _ -> Printf.printf "✗ FAIL\n");
+
(match Yamlt.decode num_codec (Bytes.Reader.of_string "value: 0o77") with
| Ok 63. -> Printf.printf "✓ Octal 0o77: 63\n"
| _ -> Printf.printf "✗ FAIL\n");
+
(match Yamlt.decode num_codec (Bytes.Reader.of_string "value: 0b1010") with
| Ok 10. -> Printf.printf "✓ Binary 0b1010: 10\n"
| _ -> Printf.printf "✗ FAIL\n");
···
|> Jsont.Object.finish
in
+
(match Yamlt.decode opt_array_codec (Bytes.Reader.of_string "values: [a, b, c]") with
| Ok (Some arr) when Array.length arr = 3 ->
Printf.printf "✓ Optional array [a, b, c]: Some([3 items])\n"
| _ -> Printf.printf "✗ FAIL\n");
+
(match Yamlt.decode opt_array_codec (Bytes.Reader.of_string "{}") with
| Ok None -> Printf.printf "✓ Missing optional array: None\n"
| _ -> Printf.printf "✗ FAIL\n");
···
|> Jsont.Object.finish
in
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
match
+
Yamlt.encode ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |]) ~eod:true writer
with
+
| Ok ()
+
when String.equal (Buffer.contents b) "{name: test, values: [1.0, 2.0, 3.0]}\n" ->
Printf.printf "✓ Flow encoding with comma separator\n"
+
| Ok () -> Printf.printf "✗ FAIL: %S\n" (Buffer.contents b)
| Error e -> Printf.printf "✗ ERROR: %s\n" e
+8 -6
tests/bin/test_edge.ml
···
(** Test edge cases with Yamlt *)
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
-
let yaml_result = Yamlt.decode_string M.numbers_codec yaml in
show_result_both "large_numbers"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.text_codec json in
-
let yaml_result = Yamlt.decode_string M.text_codec yaml in
show_result_both "special_chars"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.text_codec json in
-
let yaml_result = Yamlt.decode_string M.text_codec yaml in
show_result_both "unicode"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.data_codec json in
-
let yaml_result = Yamlt.decode_string M.data_codec yaml in
show_result_both "empty_collections"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string (Jsont.any ()) json in
-
let yaml_result = Yamlt.decode_string (Jsont.any ()) yaml in
show_result_both "special_keys"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.data_codec json in
-
let yaml_result = Yamlt.decode_string M.data_codec yaml in
show_result_both "single_element"
(Result.map M.show json_result)
···
(** Test edge cases with Yamlt *)
+
open Bytesrw
+
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
+
let yaml_result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in
show_result_both "large_numbers"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.text_codec json in
+
let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in
show_result_both "special_chars"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.text_codec json in
+
let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in
show_result_both "unicode"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.data_codec json in
+
let yaml_result = Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) in
show_result_both "empty_collections"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string (Jsont.any ()) json in
+
let yaml_result = Yamlt.decode (Jsont.any ()) (Bytes.Reader.of_string yaml) in
show_result_both "special_keys"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.data_codec json in
+
let yaml_result = Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) in
show_result_both "single_element"
(Result.map M.show json_result)
+7 -2
tests/bin/test_flow_newline.ml
···
let () =
let encode_codec =
Jsont.Object.map ~kind:"Test" (fun name values -> (name, values))
···
|> Jsont.Object.finish
in
match
-
Yamlt.encode_string ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |])
with
-
| Ok yaml_flow ->
Printf.printf "Length: %d\n" (String.length yaml_flow);
Printf.printf "Repr: %S\n" yaml_flow;
Printf.printf "Output:\n%s" yaml_flow
···
+
open Bytesrw
+
let () =
let encode_codec =
Jsont.Object.map ~kind:"Test" (fun name values -> (name, values))
···
|> Jsont.Object.finish
in
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
match
+
Yamlt.encode ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |]) ~eod:true writer
with
+
| Ok () ->
+
let yaml_flow = Buffer.contents b in
Printf.printf "Length: %d\n" (String.length yaml_flow);
Printf.printf "Repr: %S\n" yaml_flow;
Printf.printf "Output:\n%s" yaml_flow
+17 -11
tests/bin/test_formats.ml
···
(** Test format-specific features with Yamlt *)
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.text_codec json in
-
let yaml_result = Yamlt.decode_string M.text_codec yaml in
show_result_both "literal_string"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.text_codec json in
-
let yaml_result = Yamlt.decode_string M.text_codec yaml in
show_result_both "folded_string"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
-
let yaml_result = Yamlt.decode_string M.numbers_codec yaml in
show_result_both "number_formats"
(Result.map M.show json_result)
···
in
(* Encode to YAML Block style *)
-
(match Yamlt.encode_string ~format:Yamlt.Block M.data_codec data with
-
| Ok s -> Printf.printf "YAML Block:\n%s\n" s
-
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
(* Encode to YAML Flow style *)
-
match Yamlt.encode_string ~format:Yamlt.Flow M.data_codec data with
-
| Ok s -> Printf.printf "YAML Flow:\n%s\n" s
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
(* Test: Comments in YAML (should be ignored) *)
···
Printf.sprintf "host=%S, port=%d, debug=%b" c.host c.port c.debug
end in
let yaml = read_file file in
-
let yaml_result = Yamlt.decode_string M.config_codec yaml in
match yaml_result with
| Ok v -> Printf.printf "YAML (with comments): %s\n" (M.show v)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.wrapper_codec json in
-
let yaml_result = Yamlt.decode_string M.wrapper_codec yaml in
show_result_both "empty_document"
(Result.map M.show json_result)
···
let show v = Printf.sprintf "data=%S" v.data
end in
let yaml = read_file file in
-
let yaml_result = Yamlt.decode_string M.value_codec yaml in
match yaml_result with
| Ok v -> Printf.printf "YAML (with tags): %s\n" (M.show v)
···
(** Test format-specific features with Yamlt *)
+
open Bytesrw
+
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.text_codec json in
+
let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in
show_result_both "literal_string"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.text_codec json in
+
let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in
show_result_both "folded_string"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
+
let yaml_result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in
show_result_both "number_formats"
(Result.map M.show json_result)
···
in
(* Encode to YAML Block style *)
+
(let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Block M.data_codec data ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Block:\n%s\n" (Buffer.contents b)
+
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
(* Encode to YAML Flow style *)
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Flow M.data_codec data ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Flow:\n%s\n" (Buffer.contents b)
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
(* Test: Comments in YAML (should be ignored) *)
···
Printf.sprintf "host=%S, port=%d, debug=%b" c.host c.port c.debug
end in
let yaml = read_file file in
+
let yaml_result = Yamlt.decode M.config_codec (Bytes.Reader.of_string yaml) in
match yaml_result with
| Ok v -> Printf.printf "YAML (with comments): %s\n" (M.show v)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.wrapper_codec json in
+
let yaml_result = Yamlt.decode M.wrapper_codec (Bytes.Reader.of_string yaml) in
show_result_both "empty_document"
(Result.map M.show json_result)
···
let show v = Printf.sprintf "data=%S" v.data
end in
let yaml = read_file file in
+
let yaml_result = Yamlt.decode M.value_codec (Bytes.Reader.of_string yaml) in
match yaml_result with
| Ok v -> Printf.printf "YAML (with tags): %s\n" (M.show v)
+28 -22
tests/bin/test_locations.ml
···
(** Test location and layout preservation options with Yamlt codec *)
(* Helper to read file *)
let read_file path =
let ic = open_in path in
let len = in_channel_length ic in
···
in
Printf.printf "=== Without locs (default) ===\n";
-
let result_no_locs = Yamlt.decode_string ~locs:false codec yaml in
show_result "Error message" result_no_locs;
Printf.printf "\n=== With locs=true ===\n";
-
let result_with_locs = Yamlt.decode_string ~locs:true codec yaml in
show_result "Error message" result_with_locs
(* Test: Show error locations for nested structures *)
···
in
Printf.printf "=== Without locs (default) ===\n";
-
let result_no_locs = Yamlt.decode_string ~locs:false codec yaml in
show_result "Nested error" result_no_locs;
Printf.printf "\n=== With locs=true ===\n";
-
let result_with_locs = Yamlt.decode_string ~locs:true codec yaml in
show_result "Nested error" result_with_locs
(* Test: Array element error locations *)
···
in
Printf.printf "=== Without locs (default) ===\n";
-
let result_no_locs = Yamlt.decode_string ~locs:false codec yaml in
show_result "Array error" result_no_locs;
Printf.printf "\n=== With locs=true ===\n";
-
let result_with_locs = Yamlt.decode_string ~locs:true codec yaml in
show_result "Array error" result_with_locs
(* Test: Layout preservation - check if we can decode with layout info *)
···
in
Printf.printf "=== Without layout (default) ===\n";
-
(match Yamlt.decode_string ~layout:false codec yaml with
| Ok (host, port) ->
Printf.printf "Decoded: host=%s, port=%d\n" host port;
Printf.printf "Meta preserved: no\n"
| Error e -> Printf.printf "Error: %s\n" e);
Printf.printf "\n=== With layout=true ===\n";
-
match Yamlt.decode_string ~layout:true codec yaml with
| Ok (host, port) ->
Printf.printf "Decoded: host=%s, port=%d\n" host port;
Printf.printf
···
Printf.printf "%s\n" (String.trim yaml);
Printf.printf "\n=== Decode without layout, re-encode ===\n";
-
(match Yamlt.decode_string ~layout:false codec yaml with
| Ok items -> (
-
match Yamlt.encode_string ~format:Yamlt.Block codec items with
-
| Ok yaml_out -> Printf.printf "%s" yaml_out
| Error e -> Printf.printf "Encode error: %s\n" e)
| Error e -> Printf.printf "Decode error: %s\n" e);
Printf.printf
"\n=== Decode with layout=true, re-encode with Layout format ===\n";
-
match Yamlt.decode_string ~layout:true codec yaml with
| Ok items -> (
-
match Yamlt.encode_string ~format:Yamlt.Layout codec items with
-
| Ok yaml_out -> Printf.printf "%s" yaml_out
| Error e -> Printf.printf "Encode error: %s\n" e)
| Error e -> Printf.printf "Decode error: %s\n" e
···
in
Printf.printf "=== Without file path ===\n";
-
let result1 = Yamlt.decode_string ~locs:true codec yaml in
show_result "Error" result1;
Printf.printf "\n=== With file path ===\n";
-
let result2 = Yamlt.decode_string ~locs:true ~file:"test.yml" codec yaml in
show_result "Error" result2
(* Test: Missing field error with locs *)
···
in
Printf.printf "=== Without locs ===\n";
-
let result_no_locs = Yamlt.decode_string ~locs:false codec yaml in
show_result "Missing field" result_no_locs;
Printf.printf "\n=== With locs=true ===\n";
-
let result_with_locs = Yamlt.decode_string ~locs:true codec yaml in
show_result "Missing field" result_with_locs
(* Test: Both locs and layout together *)
···
in
Printf.printf "=== locs=false, layout=false (defaults) ===\n";
-
(match Yamlt.decode_string ~locs:false ~layout:false codec yaml with
| Ok (timeout, retries) ->
Printf.printf "OK: timeout=%d, retries=%d\n" timeout retries
| Error e -> Printf.printf "Error: %s\n" e);
Printf.printf "\n=== locs=true, layout=false ===\n";
-
(match Yamlt.decode_string ~locs:true ~layout:false codec yaml with
| Ok (timeout, retries) ->
Printf.printf "OK: timeout=%d, retries=%d (with precise locations)\n"
timeout retries
| Error e -> Printf.printf "Error: %s\n" e);
Printf.printf "\n=== locs=false, layout=true ===\n";
-
(match Yamlt.decode_string ~locs:false ~layout:true codec yaml with
| Ok (timeout, retries) ->
Printf.printf "OK: timeout=%d, retries=%d (with layout metadata)\n"
timeout retries
| Error e -> Printf.printf "Error: %s\n" e);
Printf.printf "\n=== locs=true, layout=true (both enabled) ===\n";
-
match Yamlt.decode_string ~locs:true ~layout:true codec yaml with
| Ok (timeout, retries) ->
Printf.printf "OK: timeout=%d, retries=%d (with locations and layout)\n"
timeout retries
···
(** Test location and layout preservation options with Yamlt codec *)
(* Helper to read file *)
+
open Bytesrw
+
let read_file path =
let ic = open_in path in
let len = in_channel_length ic in
···
in
Printf.printf "=== Without locs (default) ===\n";
+
let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in
show_result "Error message" result_no_locs;
Printf.printf "\n=== With locs=true ===\n";
+
let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in
show_result "Error message" result_with_locs
(* Test: Show error locations for nested structures *)
···
in
Printf.printf "=== Without locs (default) ===\n";
+
let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in
show_result "Nested error" result_no_locs;
Printf.printf "\n=== With locs=true ===\n";
+
let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in
show_result "Nested error" result_with_locs
(* Test: Array element error locations *)
···
in
Printf.printf "=== Without locs (default) ===\n";
+
let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in
show_result "Array error" result_no_locs;
Printf.printf "\n=== With locs=true ===\n";
+
let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in
show_result "Array error" result_with_locs
(* Test: Layout preservation - check if we can decode with layout info *)
···
in
Printf.printf "=== Without layout (default) ===\n";
+
(match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:false with
| Ok (host, port) ->
Printf.printf "Decoded: host=%s, port=%d\n" host port;
Printf.printf "Meta preserved: no\n"
| Error e -> Printf.printf "Error: %s\n" e);
Printf.printf "\n=== With layout=true ===\n";
+
match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:true with
| Ok (host, port) ->
Printf.printf "Decoded: host=%s, port=%d\n" host port;
Printf.printf
···
Printf.printf "%s\n" (String.trim yaml);
Printf.printf "\n=== Decode without layout, re-encode ===\n";
+
(match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:false with
| Ok items -> (
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Block codec items ~eod:true writer with
+
| Ok () -> Printf.printf "%s" (Buffer.contents b)
| Error e -> Printf.printf "Encode error: %s\n" e)
| Error e -> Printf.printf "Decode error: %s\n" e);
Printf.printf
"\n=== Decode with layout=true, re-encode with Layout format ===\n";
+
match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:true with
| Ok items -> (
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Layout codec items ~eod:true writer with
+
| Ok () -> Printf.printf "%s" (Buffer.contents b)
| Error e -> Printf.printf "Encode error: %s\n" e)
| Error e -> Printf.printf "Decode error: %s\n" e
···
in
Printf.printf "=== Without file path ===\n";
+
let result1 = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in
show_result "Error" result1;
Printf.printf "\n=== With file path ===\n";
+
let result2 = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true ~file:"test.yml" in
show_result "Error" result2
(* Test: Missing field error with locs *)
···
in
Printf.printf "=== Without locs ===\n";
+
let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in
show_result "Missing field" result_no_locs;
Printf.printf "\n=== With locs=true ===\n";
+
let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in
show_result "Missing field" result_with_locs
(* Test: Both locs and layout together *)
···
in
Printf.printf "=== locs=false, layout=false (defaults) ===\n";
+
(match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false ~layout:false with
| Ok (timeout, retries) ->
Printf.printf "OK: timeout=%d, retries=%d\n" timeout retries
| Error e -> Printf.printf "Error: %s\n" e);
Printf.printf "\n=== locs=true, layout=false ===\n";
+
(match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true ~layout:false with
| Ok (timeout, retries) ->
Printf.printf "OK: timeout=%d, retries=%d (with precise locations)\n"
timeout retries
| Error e -> Printf.printf "Error: %s\n" e);
Printf.printf "\n=== locs=false, layout=true ===\n";
+
(match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false ~layout:true with
| Ok (timeout, retries) ->
Printf.printf "OK: timeout=%d, retries=%d (with layout metadata)\n"
timeout retries
| Error e -> Printf.printf "Error: %s\n" e);
Printf.printf "\n=== locs=true, layout=true (both enabled) ===\n";
+
match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true ~layout:true with
| Ok (timeout, retries) ->
Printf.printf "OK: timeout=%d, retries=%d (with locations and layout)\n"
timeout retries
+240
tests/bin/test_multidoc.ml
···
···
+
(*---------------------------------------------------------------------------
+
Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
+
SPDX-License-Identifier: ISC
+
---------------------------------------------------------------------------*)
+
+
(** Test multi-document YAML streams with decode_all *)
+
+
open Bytesrw
+
+
(* Helper to read file *)
+
let read_file path =
+
let ic = open_in path in
+
let len = in_channel_length ic in
+
let s = really_input_string ic len in
+
close_in ic;
+
s
+
+
(* Helper to show results *)
+
let show_result label = function
+
| Ok v -> Printf.printf "%s: %s\n" label v
+
| Error e -> Printf.printf "%s: ERROR: %s\n" label e
+
+
(* Test: Simple multi-document stream *)
+
let test_simple file =
+
let module M = struct
+
type person = { name : string; age : int }
+
+
let person_codec =
+
Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
+
|> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
+
|> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
+
|> Jsont.Object.finish
+
+
let show p = Printf.sprintf "%s (age %d)" p.name p.age
+
end in
+
let yaml = read_file file in
+
let reader = Bytes.Reader.of_string yaml in
+
let seq = Yamlt.decode_all M.person_codec reader in
+
Printf.printf "Documents:\n";
+
seq |> Seq.iteri (fun i result ->
+
Printf.printf " [%d] " i;
+
show_result "" (Result.map M.show result)
+
)
+
+
(* Test: Count documents *)
+
let test_count file =
+
let yaml = read_file file in
+
let reader = Bytes.Reader.of_string yaml in
+
let seq = Yamlt.decode_all Jsont.json reader in
+
let count = Seq.fold_left (fun acc _ -> acc + 1) 0 seq in
+
Printf.printf "Document count: %d\n" count
+
+
(* Test: Error tracking - show which documents succeed and which fail *)
+
let test_errors file =
+
let module M = struct
+
type person = { name : string; age : int }
+
+
let person_codec =
+
Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
+
|> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
+
|> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
+
|> Jsont.Object.finish
+
+
let show p = Printf.sprintf "%s (age %d)" p.name p.age
+
end in
+
let yaml = read_file file in
+
let reader = Bytes.Reader.of_string yaml in
+
let seq = Yamlt.decode_all M.person_codec reader in
+
Printf.printf "Document results:\n";
+
seq |> Seq.iteri (fun i result ->
+
match result with
+
| Ok p -> Printf.printf " [%d] OK: %s\n" i (M.show p)
+
| Error e -> Printf.printf " [%d] ERROR: %s\n" i (String.trim e)
+
)
+
+
(* Test: Location tracking with locs=true *)
+
let test_locations file =
+
let module M = struct
+
type person = { name : string; age : int }
+
+
let person_codec =
+
Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
+
|> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
+
|> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
+
|> Jsont.Object.finish
+
end in
+
let yaml = read_file file in
+
+
Printf.printf "=== Without locs (default) ===\n";
+
let reader = Bytes.Reader.of_string yaml in
+
let seq = Yamlt.decode_all ~locs:false M.person_codec reader in
+
seq |> Seq.iteri (fun i result ->
+
match result with
+
| Ok _ -> Printf.printf " [%d] OK\n" i
+
| Error e -> Printf.printf " [%d] ERROR:\n%s\n" i (String.trim e)
+
);
+
+
Printf.printf "\n=== With locs=true ===\n";
+
let reader = Bytes.Reader.of_string yaml in
+
let seq = Yamlt.decode_all ~locs:true ~file:"test.yml" M.person_codec reader in
+
seq |> Seq.iteri (fun i result ->
+
match result with
+
| Ok _ -> Printf.printf " [%d] OK\n" i
+
| Error e -> Printf.printf " [%d] ERROR:\n%s\n" i (String.trim e)
+
)
+
+
(* Test: Roundtrip to JSON - decode YAML multidoc, encode each to JSON *)
+
let test_json_roundtrip file =
+
let yaml = read_file file in
+
let reader = Bytes.Reader.of_string yaml in
+
let seq = Yamlt.decode_all Jsont.json reader in
+
Printf.printf "JSON outputs:\n";
+
seq |> Seq.iteri (fun i result ->
+
match result with
+
| Ok json_val ->
+
(match Jsont_bytesrw.encode_string Jsont.json json_val with
+
| Ok json_str -> Printf.printf " [%d] %s\n" i (String.trim json_str)
+
| Error e -> Printf.printf " [%d] ENCODE ERROR: %s\n" i e)
+
| Error e -> Printf.printf " [%d] DECODE ERROR: %s\n" i (String.trim e)
+
)
+
+
(* Test: Nested objects in multidoc *)
+
let test_nested file =
+
let module M = struct
+
type address = { street : string; city : string }
+
type person = { name : string; age : int; address : address }
+
+
let address_codec =
+
Jsont.Object.map ~kind:"Address" (fun street city -> { street; city })
+
|> Jsont.Object.mem "street" Jsont.string ~enc:(fun a -> a.street)
+
|> Jsont.Object.mem "city" Jsont.string ~enc:(fun a -> a.city)
+
|> Jsont.Object.finish
+
+
let person_codec =
+
Jsont.Object.map ~kind:"Person" (fun name age address ->
+
{ name; age; address })
+
|> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
+
|> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
+
|> Jsont.Object.mem "address" address_codec ~enc:(fun p -> p.address)
+
|> Jsont.Object.finish
+
+
let show p =
+
Printf.sprintf "%s (age %d) from %s, %s" p.name p.age p.address.street
+
p.address.city
+
end in
+
let yaml = read_file file in
+
let reader = Bytes.Reader.of_string yaml in
+
let seq = Yamlt.decode_all M.person_codec reader in
+
Printf.printf "Nested documents:\n";
+
seq |> Seq.iteri (fun i result ->
+
Printf.printf " [%d] " i;
+
show_result "" (Result.map M.show result)
+
)
+
+
(* Test: Arrays in multidoc *)
+
let test_arrays file =
+
let yaml = read_file file in
+
let reader = Bytes.Reader.of_string yaml in
+
let seq = Yamlt.decode_all Jsont.json reader in
+
Printf.printf "Array documents:\n";
+
seq |> Seq.iteri (fun i result ->
+
match result with
+
| Ok json_val ->
+
(match Jsont_bytesrw.encode_string Jsont.json json_val with
+
| Ok json_str -> Printf.printf " [%d] %s\n" i (String.trim json_str)
+
| Error e -> Printf.printf " [%d] ERROR: %s\n" i e)
+
| Error e -> Printf.printf " [%d] ERROR: %s\n" i (String.trim e)
+
)
+
+
(* Test: Scalars in multidoc *)
+
let test_scalars file =
+
let yaml = read_file file in
+
let reader = Bytes.Reader.of_string yaml in
+
let seq = Yamlt.decode_all Jsont.json reader in
+
Printf.printf "Scalar documents:\n";
+
seq |> Seq.iteri (fun i result ->
+
match result with
+
| Ok json_val ->
+
(match Jsont_bytesrw.encode_string Jsont.json json_val with
+
| Ok json_str -> Printf.printf " [%d] %s\n" i (String.trim json_str)
+
| Error e -> Printf.printf " [%d] ERROR: %s\n" i e)
+
| Error e -> Printf.printf " [%d] ERROR: %s\n" i (String.trim e)
+
)
+
+
(* Test: Summary stats - count successes vs failures *)
+
let test_summary file =
+
let module M = struct
+
type person = { name : string; age : int }
+
+
let person_codec =
+
Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
+
|> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
+
|> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
+
|> Jsont.Object.finish
+
end in
+
let yaml = read_file file in
+
let reader = Bytes.Reader.of_string yaml in
+
let seq = Yamlt.decode_all M.person_codec reader in
+
let success = ref 0 in
+
let failure = ref 0 in
+
seq |> Seq.iter (fun result ->
+
match result with
+
| Ok _ -> incr success
+
| Error _ -> incr failure
+
);
+
Printf.printf "Summary: %d documents (%d ok, %d error)\n"
+
(!success + !failure) !success !failure
+
+
let () =
+
let usage = "Usage: test_multidoc <command> <file>" in
+
if Array.length Sys.argv < 3 then begin
+
prerr_endline usage;
+
exit 1
+
end;
+
+
let test = Sys.argv.(1) in
+
let file = Sys.argv.(2) in
+
match test with
+
| "simple" -> test_simple file
+
| "count" -> test_count file
+
| "errors" -> test_errors file
+
| "locations" -> test_locations file
+
| "json" -> test_json_roundtrip file
+
| "nested" -> test_nested file
+
| "arrays" -> test_arrays file
+
| "scalars" -> test_scalars file
+
| "summary" -> test_summary file
+
| _ ->
+
prerr_endline usage;
+
prerr_endline "Commands:";
+
prerr_endline " simple <file> - Decode person documents";
+
prerr_endline " count <file> - Count documents";
+
prerr_endline " errors <file> - Show success/error for each document";
+
prerr_endline " locations <file> - Test location tracking with locs=true";
+
prerr_endline " json <file> - Roundtrip to JSON";
+
prerr_endline " nested <file> - Decode nested objects";
+
prerr_endline " arrays <file> - Decode arrays";
+
prerr_endline " scalars <file> - Decode scalars";
+
prerr_endline " summary <file> - Show success/failure summary";
+
exit 1
+6 -4
tests/bin/test_null_complete.ml
···
let () =
Printf.printf "=== Test 1: Jsont.option with YAML null ===\n";
let yaml1 = "value: null" in
···
|> Object.mem "value" (option string) ~enc:(fun v -> v)
|> Object.finish
in
-
(match Yamlt.decode_string codec1 yaml1 with
| Ok v ->
Printf.printf "Result: %s\n"
(match v with None -> "None" | Some s -> "Some(" ^ s ^ ")")
| Error e -> Printf.printf "Error: %s\n" e);
Printf.printf "\n=== Test 2: Jsont.option with YAML string ===\n";
-
(match Yamlt.decode_string codec1 "value: hello" with
| Ok v ->
Printf.printf "Result: %s\n"
(match v with None -> "None" | Some s -> "Some(" ^ s ^ ")")
···
|> Object.mem "value" string ~enc:(fun v -> v)
|> Object.finish
in
-
(match Yamlt.decode_string codec2 "value: null" with
| Ok v -> Printf.printf "Result: %s\n" v
| Error e -> Printf.printf "Error (expected): %s\n" e);
Printf.printf "\n=== Test 4: Jsont.string with YAML string ===\n";
-
match Yamlt.decode_string codec2 "value: hello" with
| Ok v -> Printf.printf "Result: %s\n" v
| Error e -> Printf.printf "Error: %s\n" e
···
+
open Bytesrw
+
let () =
Printf.printf "=== Test 1: Jsont.option with YAML null ===\n";
let yaml1 = "value: null" in
···
|> Object.mem "value" (option string) ~enc:(fun v -> v)
|> Object.finish
in
+
(match Yamlt.decode codec1 (Bytes.Reader.of_string yaml1) with
| Ok v ->
Printf.printf "Result: %s\n"
(match v with None -> "None" | Some s -> "Some(" ^ s ^ ")")
| Error e -> Printf.printf "Error: %s\n" e);
Printf.printf "\n=== Test 2: Jsont.option with YAML string ===\n";
+
(match Yamlt.decode codec1 (Bytes.Reader.of_string "value: hello") with
| Ok v ->
Printf.printf "Result: %s\n"
(match v with None -> "None" | Some s -> "Some(" ^ s ^ ")")
···
|> Object.mem "value" string ~enc:(fun v -> v)
|> Object.finish
in
+
(match Yamlt.decode codec2 (Bytes.Reader.of_string "value: null") with
| Ok v -> Printf.printf "Result: %s\n" v
| Error e -> Printf.printf "Error (expected): %s\n" e);
Printf.printf "\n=== Test 4: Jsont.string with YAML string ===\n";
+
match Yamlt.decode codec2 (Bytes.Reader.of_string "value: hello") with
| Ok v -> Printf.printf "Result: %s\n" v
| Error e -> Printf.printf "Error: %s\n" e
+2 -2
tests/bin/test_null_fix.ml
···
-
open Jsont
let () =
let module M = struct
···
Printf.printf "Testing YAML null handling with Jsont.option Jsont.string:\n\n";
-
match Yamlt.decode_string M.data_codec yaml_null with
| Ok data -> (
match data.M.value with
| None -> Printf.printf "YAML: value=None (CORRECT)\n"
···
+
open Bytesrw
let () =
let module M = struct
···
Printf.printf "Testing YAML null handling with Jsont.option Jsont.string:\n\n";
+
match Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml_null) with
| Ok data -> (
match data.M.value with
| None -> Printf.printf "YAML: value=None (CORRECT)\n"
+19 -13
tests/bin/test_objects.ml
···
(** Test object codec functionality with Yamlt *)
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.person_codec json in
-
let yaml_result = Yamlt.decode_string M.person_codec yaml in
show_result_both "person"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.config_codec json in
-
let yaml_result = Yamlt.decode_string M.config_codec yaml in
show_result_both "config"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.settings_codec json in
-
let yaml_result = Yamlt.decode_string M.settings_codec yaml in
show_result_both "settings"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.employee_codec json in
-
let yaml_result = Yamlt.decode_string M.employee_codec yaml in
show_result_both "employee"
(Result.map M.show json_result)
···
|> Jsont.Object.finish
end in
let yaml = read_file file in
-
let result = Yamlt.decode_string M.strict_codec yaml in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.flexible_codec json in
-
let yaml_result = Yamlt.decode_string M.flexible_codec yaml in
show_result_both "flexible"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.circle_codec json in
-
let yaml_result = Yamlt.decode_string M.circle_codec yaml in
show_result_both "shape"
(Result.map M.show json_result)
···
|> Jsont.Object.finish
end in
let yaml = read_file file in
-
let result = Yamlt.decode_string M.required_codec yaml in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e
···
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
(* Encode to YAML Block *)
-
(match Yamlt.encode_string ~format:Yamlt.Block M.person_codec person with
-
| Ok s -> Printf.printf "YAML Block:\n%s" s
-
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
(* Encode to YAML Flow *)
-
match Yamlt.encode_string ~format:Yamlt.Flow M.person_codec person with
-
| Ok s -> Printf.printf "YAML Flow: %s" s
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
let () =
···
(** Test object codec functionality with Yamlt *)
+
open Bytesrw
+
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.person_codec json in
+
let yaml_result = Yamlt.decode M.person_codec (Bytes.Reader.of_string yaml) in
show_result_both "person"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.config_codec json in
+
let yaml_result = Yamlt.decode M.config_codec (Bytes.Reader.of_string yaml) in
show_result_both "config"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.settings_codec json in
+
let yaml_result = Yamlt.decode M.settings_codec (Bytes.Reader.of_string yaml) in
show_result_both "settings"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.employee_codec json in
+
let yaml_result = Yamlt.decode M.employee_codec (Bytes.Reader.of_string yaml) in
show_result_both "employee"
(Result.map M.show json_result)
···
|> Jsont.Object.finish
end in
let yaml = read_file file in
+
let result = Yamlt.decode M.strict_codec (Bytes.Reader.of_string yaml) in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.flexible_codec json in
+
let yaml_result = Yamlt.decode M.flexible_codec (Bytes.Reader.of_string yaml) in
show_result_both "flexible"
(Result.map M.show json_result)
···
let yaml = read_file file in
let json = read_file (file ^ ".json") in
let json_result = Jsont_bytesrw.decode_string M.circle_codec json in
+
let yaml_result = Yamlt.decode M.circle_codec (Bytes.Reader.of_string yaml) in
show_result_both "shape"
(Result.map M.show json_result)
···
|> Jsont.Object.finish
end in
let yaml = read_file file in
+
let result = Yamlt.decode M.required_codec (Bytes.Reader.of_string yaml) in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e
···
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
(* Encode to YAML Block *)
+
(let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Block M.person_codec person ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
+
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
(* Encode to YAML Flow *)
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Flow M.person_codec person ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
let () =
+3 -1
tests/bin/test_opt_array.ml
···
let () =
let codec =
Jsont.Object.map ~kind:"Test" (fun arr -> arr)
···
let yaml = "values: [a, b, c]" in
Printf.printf "Testing optional array field:\n";
-
match Yamlt.decode_string codec yaml with
| Ok arr -> (
match arr with
| None -> Printf.printf "Result: None\n"
···
+
open Bytesrw
+
let () =
let codec =
Jsont.Object.map ~kind:"Test" (fun arr -> arr)
···
let yaml = "values: [a, b, c]" in
Printf.printf "Testing optional array field:\n";
+
match Yamlt.decode codec (Bytes.Reader.of_string yaml) with
| Ok arr -> (
match arr with
| None -> Printf.printf "Result: None\n"
+37 -13
tests/bin/test_roundtrip.ml
···
(** Test roundtrip encoding/decoding with Yamlt *)
(* Test: Roundtrip scalars *)
let test_scalar_roundtrip () =
let module M = struct
···
(* YAML Block roundtrip *)
let yaml_block_encoded =
-
Yamlt.encode_string ~format:Yamlt.Block M.data_codec original
in
let yaml_block_decoded =
-
Result.bind yaml_block_encoded (Yamlt.decode_string M.data_codec)
in
(match yaml_block_decoded with
| Ok decoded when M.equal original decoded ->
···
(* YAML Flow roundtrip *)
let yaml_flow_encoded =
-
Yamlt.encode_string ~format:Yamlt.Flow M.data_codec original
in
let yaml_flow_decoded =
-
Result.bind yaml_flow_encoded (Yamlt.decode_string M.data_codec)
in
match yaml_flow_decoded with
| Ok decoded when M.equal original decoded ->
···
(* YAML roundtrip *)
let yaml_result =
-
Result.bind
-
(Yamlt.encode_string M.data_codec original)
-
(Yamlt.decode_string M.data_codec)
in
match yaml_result with
| Ok decoded when M.equal original decoded ->
···
(* YAML roundtrip *)
let yaml_result =
-
Result.bind
-
(Yamlt.encode_string M.company_codec original)
-
(Yamlt.decode_string M.company_codec)
in
match yaml_result with
| Ok decoded when M.equal original decoded ->
···
(* YAML roundtrip *)
let yaml_result =
-
Result.bind
-
(Yamlt.encode_string M.data_codec original)
-
(Yamlt.decode_string M.data_codec)
in
match yaml_result with
| Ok decoded when M.equal original decoded ->
···
(** Test roundtrip encoding/decoding with Yamlt *)
+
open Bytesrw
+
(* Test: Roundtrip scalars *)
let test_scalar_roundtrip () =
let module M = struct
···
(* YAML Block roundtrip *)
let yaml_block_encoded =
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Block M.data_codec original ~eod:true writer with
+
| Ok () -> Ok (Buffer.contents b)
+
| Error e -> Error e
in
let yaml_block_decoded =
+
Result.bind yaml_block_encoded (fun yaml ->
+
Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml))
in
(match yaml_block_decoded with
| Ok decoded when M.equal original decoded ->
···
(* YAML Flow roundtrip *)
let yaml_flow_encoded =
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Flow M.data_codec original ~eod:true writer with
+
| Ok () -> Ok (Buffer.contents b)
+
| Error e -> Error e
in
let yaml_flow_decoded =
+
Result.bind yaml_flow_encoded (fun yaml ->
+
Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml))
in
match yaml_flow_decoded with
| Ok decoded when M.equal original decoded ->
···
(* YAML roundtrip *)
let yaml_result =
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode M.data_codec original ~eod:true writer with
+
| Ok () ->
+
let yaml = Buffer.contents b in
+
Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml)
+
| Error e -> Error e
in
match yaml_result with
| Ok decoded when M.equal original decoded ->
···
(* YAML roundtrip *)
let yaml_result =
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode M.company_codec original ~eod:true writer with
+
| Ok () ->
+
let yaml = Buffer.contents b in
+
Yamlt.decode M.company_codec (Bytes.Reader.of_string yaml)
+
| Error e -> Error e
in
match yaml_result with
| Ok decoded when M.equal original decoded ->
···
(* YAML roundtrip *)
let yaml_result =
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode M.data_codec original ~eod:true writer with
+
| Ok () ->
+
let yaml = Buffer.contents b in
+
Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml)
+
| Error e -> Error e
in
match yaml_result with
| Ok decoded when M.equal original decoded ->
+48 -30
tests/bin/test_scalars.ml
···
(** Test scalar type resolution with Yamlt codec *)
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
in
(* Try decoding as null *)
-
let result = Yamlt.decode_string null_codec yaml in
show_result "null_codec" (Result.map (fun () -> "null") result)
(* Test: Boolean type-directed resolution *)
···
Printf.printf "=== Bool Codec ===\n";
let json_result = Jsont_bytesrw.decode_string bool_codec json in
-
let yaml_result = Yamlt.decode_string bool_codec yaml in
show_result_json "bool_codec"
(Result.map (Printf.sprintf "%b") json_result)
(Result.map (Printf.sprintf "%b") yaml_result);
Printf.printf "\n=== String Codec ===\n";
let json_result = Jsont_bytesrw.decode_string string_codec json in
-
let yaml_result = Yamlt.decode_string string_codec yaml in
show_result_json "string_codec"
(Result.map (Printf.sprintf "%S") json_result)
(Result.map (Printf.sprintf "%S") yaml_result)
···
in
let json_result = Jsont_bytesrw.decode_string number_codec json in
-
let yaml_result = Yamlt.decode_string number_codec yaml in
show_result_json "number_codec"
(Result.map (Printf.sprintf "%.17g") json_result)
···
in
let json_result = Jsont_bytesrw.decode_string string_codec json in
-
let yaml_result = Yamlt.decode_string string_codec yaml in
show_result_json "string_codec"
(Result.map (Printf.sprintf "%S") json_result)
···
|> Jsont.Object.finish
in
-
let result = Yamlt.decode_string number_codec yaml in
match result with
| Ok f ->
if Float.is_nan f then Printf.printf "value: NaN\n"
···
|> Jsont.Object.mem "value" Jsont.bool ~enc:(fun b -> b)
|> Jsont.Object.finish
in
-
let result = Yamlt.decode_string codec yaml in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e)
···
|> Jsont.Object.mem "value" Jsont.number ~enc:(fun n -> n)
|> Jsont.Object.finish
in
-
let result = Yamlt.decode_string codec yaml in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e)
···
|> Jsont.Object.mem "value" (Jsont.null ()) ~enc:(fun n -> n)
|> Jsont.Object.finish
in
-
let result = Yamlt.decode_string codec yaml in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e)
···
in
let json_result = Jsont_bytesrw.decode_string any_codec json in
-
let yaml_result = Yamlt.decode_string any_codec yaml in
(* Just show that it decoded successfully *)
show_result_json "any_codec"
···
(match Jsont_bytesrw.encode_string codec v with
| Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
-
(match Yamlt.encode_string ~format:Yamlt.Block codec v with
-
| Ok s -> Printf.printf "YAML Block:\n%s" s
-
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
-
match Yamlt.encode_string ~format:Yamlt.Flow codec v with
-
| Ok s -> Printf.printf "YAML Flow: %s" s
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
| "number" -> (
let codec =
···
(match Jsont_bytesrw.encode_string codec v with
| Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
-
(match Yamlt.encode_string ~format:Yamlt.Block codec v with
-
| Ok s -> Printf.printf "YAML Block:\n%s" s
-
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
-
match Yamlt.encode_string ~format:Yamlt.Flow codec v with
-
| Ok s -> Printf.printf "YAML Flow: %s" s
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
| "string" -> (
let codec =
···
(match Jsont_bytesrw.encode_string codec v with
| Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
-
(match Yamlt.encode_string ~format:Yamlt.Block codec v with
-
| Ok s -> Printf.printf "YAML Block:\n%s" s
-
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
-
match Yamlt.encode_string ~format:Yamlt.Flow codec v with
-
| Ok s -> Printf.printf "YAML Flow: %s" s
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
| "null" -> (
let codec =
···
(match Jsont_bytesrw.encode_string codec v with
| Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
-
(match Yamlt.encode_string ~format:Yamlt.Block codec v with
-
| Ok s -> Printf.printf "YAML Block:\n%s" s
-
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
-
match Yamlt.encode_string ~format:Yamlt.Flow codec v with
-
| Ok s -> Printf.printf "YAML Flow: %s" s
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
| _ -> failwith "unknown type"
···
(** Test scalar type resolution with Yamlt codec *)
+
open Bytesrw
+
(* Helper to read file *)
let read_file path =
let ic = open_in path in
···
in
(* Try decoding as null *)
+
let result = Yamlt.decode null_codec (Bytes.Reader.of_string yaml) in
show_result "null_codec" (Result.map (fun () -> "null") result)
(* Test: Boolean type-directed resolution *)
···
Printf.printf "=== Bool Codec ===\n";
let json_result = Jsont_bytesrw.decode_string bool_codec json in
+
let yaml_result = Yamlt.decode bool_codec (Bytes.Reader.of_string yaml) in
show_result_json "bool_codec"
(Result.map (Printf.sprintf "%b") json_result)
(Result.map (Printf.sprintf "%b") yaml_result);
Printf.printf "\n=== String Codec ===\n";
let json_result = Jsont_bytesrw.decode_string string_codec json in
+
let yaml_result = Yamlt.decode string_codec (Bytes.Reader.of_string yaml) in
show_result_json "string_codec"
(Result.map (Printf.sprintf "%S") json_result)
(Result.map (Printf.sprintf "%S") yaml_result)
···
in
let json_result = Jsont_bytesrw.decode_string number_codec json in
+
let yaml_result = Yamlt.decode number_codec (Bytes.Reader.of_string yaml) in
show_result_json "number_codec"
(Result.map (Printf.sprintf "%.17g") json_result)
···
in
let json_result = Jsont_bytesrw.decode_string string_codec json in
+
let yaml_result = Yamlt.decode string_codec (Bytes.Reader.of_string yaml) in
show_result_json "string_codec"
(Result.map (Printf.sprintf "%S") json_result)
···
|> Jsont.Object.finish
in
+
let result = Yamlt.decode number_codec (Bytes.Reader.of_string yaml) in
match result with
| Ok f ->
if Float.is_nan f then Printf.printf "value: NaN\n"
···
|> Jsont.Object.mem "value" Jsont.bool ~enc:(fun b -> b)
|> Jsont.Object.finish
in
+
let result = Yamlt.decode codec (Bytes.Reader.of_string yaml) in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e)
···
|> Jsont.Object.mem "value" Jsont.number ~enc:(fun n -> n)
|> Jsont.Object.finish
in
+
let result = Yamlt.decode codec (Bytes.Reader.of_string yaml) in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e)
···
|> Jsont.Object.mem "value" (Jsont.null ()) ~enc:(fun n -> n)
|> Jsont.Object.finish
in
+
let result = Yamlt.decode codec (Bytes.Reader.of_string yaml) in
match result with
| Ok _ -> Printf.printf "Unexpected success\n"
| Error e -> Printf.printf "Expected error: %s\n" e)
···
in
let json_result = Jsont_bytesrw.decode_string any_codec json in
+
let yaml_result = Yamlt.decode any_codec (Bytes.Reader.of_string yaml) in
(* Just show that it decoded successfully *)
show_result_json "any_codec"
···
(match Jsont_bytesrw.encode_string codec v with
| Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
+
(let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
+
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
| "number" -> (
let codec =
···
(match Jsont_bytesrw.encode_string codec v with
| Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
+
(let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
+
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
| "string" -> (
let codec =
···
(match Jsont_bytesrw.encode_string codec v with
| Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
+
(let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
+
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
| "null" -> (
let codec =
···
(match Jsont_bytesrw.encode_string codec v with
| Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
| Error e -> Printf.printf "JSON ERROR: %s\n" e);
+
(let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
+
| Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
+
let b = Buffer.create 256 in
+
let writer = Bytes.Writer.of_buffer b in
+
match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with
+
| Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
| Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
| _ -> failwith "unknown type"
+4 -2
tests/bin/test_some_vs_option.ml
···
let () =
(* Using Jsont.some like opt_mem does *)
let codec1 =
···
let yaml = "values: [a, b, c]" in
Printf.printf "Test 1: Jsont.some (Jsont.array) - like opt_mem:\n";
-
(match Yamlt.decode_string codec1 yaml with
| Ok arr -> (
match arr with
| None -> Printf.printf "Result: None\n"
···
in
Printf.printf "\nTest 2: Jsont.option (Jsont.array):\n";
-
match Yamlt.decode_string codec2 yaml with
| Ok arr -> (
match arr with
| None -> Printf.printf "Result: None\n"
···
+
open Bytesrw
+
let () =
(* Using Jsont.some like opt_mem does *)
let codec1 =
···
let yaml = "values: [a, b, c]" in
Printf.printf "Test 1: Jsont.some (Jsont.array) - like opt_mem:\n";
+
(match Yamlt.decode codec1 (Bytes.Reader.of_string yaml) with
| Ok arr -> (
match arr with
| None -> Printf.printf "Result: None\n"
···
in
Printf.printf "\nTest 2: Jsont.option (Jsont.array):\n";
+
match Yamlt.decode codec2 (Bytes.Reader.of_string yaml) with
| Ok arr -> (
match arr with
| None -> Printf.printf "Result: None\n"
+1
tests/cram/dune
···
(glob_files ../data/complex/*.json)
(glob_files ../data/edge/*.yml)
(glob_files ../data/edge/*.json)
(glob_files ../data/locations/*.yml)))
···
(glob_files ../data/complex/*.json)
(glob_files ../data/edge/*.yml)
(glob_files ../data/edge/*.json)
+
(glob_files ../data/multidoc/*.yml)
(glob_files ../data/locations/*.yml)))
+4 -4
tests/cram/locations.t
···
=== With locs=true ===
Error message:
String "not-a-number" does not parse to OCaml int value
-
File "-", lines 2-3, characters 5-0:
File "-", line 2, characters 0-3: in member age of
File "-", line 1, characters 0-1: Person object
···
=== With locs=true ===
Nested error:
String "invalid-zip" does not parse to OCaml int value
-
File "-", lines 5-6, characters 7-0:
File "-", line 5, characters 2-5: in member zip of
File "-", line 3, characters 2-3: Address object
File "-", line 2, characters 0-7: in member address of
···
=== Without file path ===
Error:
String "not-a-number" does not parse to OCaml int value
-
File "-", lines 2-3, characters 5-0:
File "-", line 2, characters 0-3: in member age of
File "-", line 1, characters 0-1: Person object
=== With file path ===
Error:
String "not-a-number" does not parse to OCaml int value
-
File "test.yml", lines 2-3, characters 5-0:
File "test.yml", line 2, characters 0-3: in member age of
File "test.yml", line 1, characters 0-1: Person object
···
=== With locs=true ===
Error message:
String "not-a-number" does not parse to OCaml int value
+
File "-", line 2, characters 5-18:
File "-", line 2, characters 0-3: in member age of
File "-", line 1, characters 0-1: Person object
···
=== With locs=true ===
Nested error:
String "invalid-zip" does not parse to OCaml int value
+
File "-", line 5, characters 7-19:
File "-", line 5, characters 2-5: in member zip of
File "-", line 3, characters 2-3: Address object
File "-", line 2, characters 0-7: in member address of
···
=== Without file path ===
Error:
String "not-a-number" does not parse to OCaml int value
+
File "-", line 2, characters 5-18:
File "-", line 2, characters 0-3: in member age of
File "-", line 1, characters 0-1: Person object
=== With file path ===
Error:
String "not-a-number" does not parse to OCaml int value
+
File "test.yml", line 2, characters 5-18:
File "test.yml", line 2, characters 0-3: in member age of
File "test.yml", line 1, characters 0-1: Person object
+220
tests/cram/multidoc.t
···
···
+
Multi-Document YAML Streams with Yamlt
+
========================================
+
+
This test suite validates multi-document YAML stream decoding using decode_all,
+
including error handling, location tracking, and JSON roundtripping.
+
+
================================================================================
+
BASIC MULTIDOC DECODING
+
================================================================================
+
+
Simple multi-document stream with person objects
+
+
$ test_multidoc simple ../data/multidoc/simple.yml
+
Documents:
+
[0] : Alice (age 30)
+
[1] : Bob (age 25)
+
[2] : Charlie (age 35)
+
+
Count documents in a stream
+
+
$ test_multidoc count ../data/multidoc/simple.yml
+
Document count: 3
+
+
================================================================================
+
ERROR HANDLING - MIXED VALID AND INVALID DOCUMENTS
+
================================================================================
+
+
When some documents succeed and others fail, decode_all continues processing
+
and returns results for each document individually.
+
+
Stream with one error in the middle
+
+
$ test_multidoc errors ../data/multidoc/mixed_errors.yml
+
Document results:
+
[0] OK: Alice (age 30)
+
[1] ERROR: String "not-a-number" does not parse to OCaml int value
+
File "-":
+
File "-": in member age of
+
File "-": Person object
+
[2] OK: Charlie (age 35)
+
+
Summary statistics for mixed documents
+
+
$ test_multidoc summary ../data/multidoc/mixed_errors.yml
+
Summary: 3 documents (2 ok, 1 error)
+
+
Stream where all documents fail
+
+
$ test_multidoc errors ../data/multidoc/all_errors.yml
+
Document results:
+
[0] ERROR: String "invalid1" does not parse to OCaml int value
+
File "-":
+
File "-": in member age of
+
File "-": Person object
+
[1] ERROR: String "invalid2" does not parse to OCaml int value
+
File "-":
+
File "-": in member age of
+
File "-": Person object
+
[2] ERROR: String "invalid3" does not parse to OCaml int value
+
File "-":
+
File "-": in member age of
+
File "-": Person object
+
+
Summary for all-error stream
+
+
$ test_multidoc summary ../data/multidoc/all_errors.yml
+
Summary: 3 documents (0 ok, 3 error)
+
+
================================================================================
+
LOCATION TRACKING WITH locs=true
+
================================================================================
+
+
Location tracking helps identify exactly where errors occur in each document
+
of a multi-document stream.
+
+
Without locs (default) - basic error information
+
+
$ test_multidoc locations ../data/multidoc/mixed_errors.yml
+
=== Without locs (default) ===
+
[0] OK
+
[1] ERROR:
+
String "not-a-number" does not parse to OCaml int value
+
File "-":
+
File "-": in member age of
+
File "-": Person object
+
[2] OK
+
+
=== With locs=true ===
+
[0] OK
+
[1] ERROR:
+
String "not-a-number" does not parse to OCaml int value
+
File "test.yml", line 6, characters 5-18:
+
File "test.yml", line 6, characters 0-3: in member age of
+
File "test.yml", line 5, characters 0-1: Person object
+
[2] OK
+
+
================================================================================
+
MISSING FIELDS IN MULTIDOC
+
================================================================================
+
+
Documents with missing required fields generate errors but don't stop
+
processing of subsequent documents.
+
+
$ test_multidoc errors ../data/multidoc/missing_fields.yml
+
Document results:
+
[0] OK: Alice (age 30)
+
[1] ERROR: Missing member age in Person object
+
File "-":
+
[2] OK: Charlie (age 35)
+
+
Summary of missing fields test
+
+
$ test_multidoc summary ../data/multidoc/missing_fields.yml
+
Summary: 3 documents (2 ok, 1 error)
+
+
================================================================================
+
JSON ROUNDTRIPPING
+
================================================================================
+
+
Decode YAML multi-document streams and encode each document as JSON.
+
This validates that the data model conversion is correct.
+
+
Simple documents to JSON
+
+
$ test_multidoc json ../data/multidoc/simple.yml
+
JSON outputs:
+
[0] {"name":"Alice","age":30}
+
[1] {"name":"Bob","age":25}
+
[2] {"name":"Charlie","age":35}
+
+
Nested objects to JSON
+
+
$ test_multidoc json ../data/multidoc/nested.yml
+
JSON outputs:
+
[0] {"name":"Alice","age":30,"address":{"street":"123 Main St","city":"Boston"}}
+
[1] {"name":"Bob","age":25,"address":{"street":"456 Oak Ave","city":"Seattle"}}
+
[2] {"name":"Charlie","age":35,"address":{"street":"789 Pine Rd","city":"Portland"}}
+
+
Arrays to JSON
+
+
$ test_multidoc json ../data/multidoc/arrays.yml
+
JSON outputs:
+
[0] [1,2,3]
+
[1] ["apple","banana","cherry"]
+
[2] [true,false,true]
+
+
Scalar values to JSON
+
+
$ test_multidoc json ../data/multidoc/scalars.yml
+
JSON outputs:
+
[0] "hello world"
+
[1] 42
+
[2] true
+
[3] null
+
+
================================================================================
+
NESTED OBJECTS IN MULTIDOC
+
================================================================================
+
+
Test decoding complex nested structures across multiple documents.
+
+
$ test_multidoc nested ../data/multidoc/nested.yml
+
Nested documents:
+
[0] : Alice (age 30) from 123 Main St, Boston
+
[1] : Bob (age 25) from 456 Oak Ave, Seattle
+
[2] : Charlie (age 35) from 789 Pine Rd, Portland
+
+
================================================================================
+
ARRAYS IN MULTIDOC
+
================================================================================
+
+
Test decoding different array types across documents.
+
+
$ test_multidoc arrays ../data/multidoc/arrays.yml
+
Array documents:
+
[0] [1,2,3]
+
[1] ["apple","banana","cherry"]
+
[2] [true,false,true]
+
+
================================================================================
+
SCALARS IN MULTIDOC
+
================================================================================
+
+
Test decoding bare scalar values as documents.
+
+
$ test_multidoc scalars ../data/multidoc/scalars.yml
+
Scalar documents:
+
[0] "hello world"
+
[1] 42
+
[2] true
+
[3] null
+
+
================================================================================
+
EMPTY DOCUMENTS
+
================================================================================
+
+
Empty or null documents in a stream are handled correctly.
+
+
$ test_multidoc json ../data/multidoc/empty_docs.yml
+
JSON outputs:
+
[0] {"name":"Alice","age":30}
+
[1] null
+
[2] {"name":"Charlie","age":35}
+
+
Count including empty documents
+
+
$ test_multidoc count ../data/multidoc/empty_docs.yml
+
Document count: 3
+
+
================================================================================
+
SUMMARY
+
================================================================================
+
+
The decode_all function:
+
- Processes all documents in a stream, not stopping on errors
+
- Returns a sequence of Result values (Ok/Error for each document)
+
- Supports all decode options: locs, layout, file, max_depth, max_nodes
+
- Correctly handles document boundaries even when errors occur
+
- Works with any Jsont codec (objects, arrays, scalars, etc.)
+
- Can be used for JSON roundtripping and format conversion
+9
tests/data/multidoc/all_errors.yml
···
···
+
---
+
name: Alice
+
age: invalid1
+
---
+
name: Bob
+
age: invalid2
+
---
+
name: Charlie
+
age: invalid3
+12
tests/data/multidoc/arrays.yml
···
···
+
---
+
- 1
+
- 2
+
- 3
+
---
+
- apple
+
- banana
+
- cherry
+
---
+
- true
+
- false
+
- true
+7
tests/data/multidoc/empty_docs.yml
···
···
+
---
+
name: Alice
+
age: 30
+
---
+
---
+
name: Charlie
+
age: 35
+9
tests/data/multidoc/missing_fields.yml
···
···
+
---
+
name: Alice
+
age: 30
+
---
+
name: Bob
+
---
+
name: Charlie
+
age: 35
+
city: Springfield
+9
tests/data/multidoc/mixed_errors.yml
···
···
+
---
+
name: Alice
+
age: 30
+
---
+
name: Bob
+
age: not-a-number
+
---
+
name: Charlie
+
age: 35
+18
tests/data/multidoc/nested.yml
···
···
+
---
+
name: Alice
+
age: 30
+
address:
+
street: 123 Main St
+
city: Boston
+
---
+
name: Bob
+
age: 25
+
address:
+
street: 456 Oak Ave
+
city: Seattle
+
---
+
name: Charlie
+
age: 35
+
address:
+
street: 789 Pine Rd
+
city: Portland
+8
tests/data/multidoc/scalars.yml
···
···
+
---
+
hello world
+
---
+
42
+
---
+
true
+
---
+
null
+9
tests/data/multidoc/simple.yml
···
···
+
---
+
name: Alice
+
age: 30
+
---
+
name: Bob
+
age: 25
+
---
+
name: Charlie
+
age: 35