···11+ISC License
22+33+Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>
44+55+Permission to use, copy, modify, and distribute this software for any
66+purpose with or without fee is hereby granted, provided that the above
77+copyright notice and this permission notice appear in all copies.
88+99+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+62
vendor/opam/yamlt/README.md
···11+# yamlt - YAML codec using Jsont type descriptions
22+33+Yamlt provides YAML streaming encode/decode that interprets Jsont.t type descriptions, allowing the same codec definitions to work for both JSON and YAML.
44+55+## Key Features
66+77+- Use the same Jsont.t codec for both JSON and YAML formats
88+- Streaming encode/decode with configurable depth and node limits
99+- Support for YAML-specific features (scalars, sequences, mappings)
1010+- Billion laughs protection with configurable limits
1111+- Multiple output formats (block, flow, layout preservation)
1212+1313+## Usage
1414+1515+```ocaml
1616+(* Define a codec once using Jsont *)
1717+module Config = struct
1818+ type t = { name: string; port: int }
1919+ let make name port = { name; port }
2020+ let jsont =
2121+ Jsont.Object.map ~kind:"Config" make
2222+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun c -> c.name)
2323+ |> Jsont.Object.mem "port" Jsont.int ~enc:(fun c -> c.port)
2424+ |> Jsont.Object.finish
2525+end
2626+2727+(* Use the same codec for both JSON and YAML *)
2828+let from_json = Jsont_bytesrw.decode_string Config.jsont json_str
2929+let from_yaml = Yamlt.decode_string Config.jsont yaml_str
3030+```
3131+3232+For encoding:
3333+3434+```ocaml
3535+(* Encode to YAML with different formats *)
3636+let config = Config.make "server" 8080
3737+3838+(* Block style (default) *)
3939+let yaml_block = Yamlt.encode_string Config.jsont config
4040+4141+(* Flow style (JSON-like) *)
4242+let yaml_flow = Yamlt.encode_string ~format:Flow Config.jsont config
4343+```
4444+4545+## Installation
4646+4747+```
4848+opam install yamlt
4949+```
5050+5151+## Documentation
5252+5353+API documentation is available at https://tangled.org/@anil.recoil.org/ocaml-yamlt or via:
5454+5555+```
5656+opam install yamlt
5757+odig doc yamlt
5858+```
5959+6060+## License
6161+6262+ISC
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+open Jsont.Repr
77+open Yamlrw
88+99+(* YAML format *)
1010+1111+type yaml_format = Block | Flow | Layout
1212+1313+(* Decoder *)
1414+1515+type decoder = {
1616+ parser : Parser.t;
1717+ file : string;
1818+ locs : bool;
1919+ _layout : bool; (* For future layout preservation *)
2020+ max_depth : int;
2121+ max_nodes : int;
2222+ mutable node_count : int;
2323+ mutable current : Event.spanned option;
2424+ _anchors : (string, Jsont.json) Hashtbl.t; (* For future anchor resolution *)
2525+ meta_none : Jsont.Meta.t;
2626+}
2727+2828+let make_decoder ?(locs = false) ?(layout = false) ?(file = "-")
2929+ ?(max_depth = 100) ?(max_nodes = 10_000_000) parser =
3030+ let meta_none = Jsont.Meta.make (Jsont.Textloc.(set_file none) file) in
3131+ {
3232+ parser;
3333+ file;
3434+ locs;
3535+ _layout = layout;
3636+ max_depth;
3737+ max_nodes;
3838+ node_count = 0;
3939+ current = None;
4040+ _anchors = Hashtbl.create 16;
4141+ meta_none;
4242+ }
4343+4444+(* Decoder helpers *)
4545+4646+(* Local helper to reduce Jsont.Error.msgf boilerplate *)
4747+let err_msg meta fmt = Jsont.Error.msgf meta fmt
4848+let err_msg_none fmt = Jsont.Error.msgf Jsont.Meta.none fmt
4949+5050+let check_depth d ~nest =
5151+ if nest > d.max_depth then
5252+ err_msg_none "Maximum nesting depth %d exceeded" d.max_depth
5353+5454+let check_nodes d =
5555+ d.node_count <- d.node_count + 1;
5656+ if d.node_count > d.max_nodes then
5757+ err_msg_none "Maximum node count %d exceeded" d.max_nodes
5858+5959+let meta_of_span d span =
6060+ if not d.locs then d.meta_none
6161+ else
6262+ let start = span.Span.start and stop = span.Span.stop in
6363+ let first_byte = start.Position.index in
6464+ let last_byte = max first_byte (stop.Position.index - 1) in
6565+ (* line_pos is (line_number, byte_position_of_line_start) *)
6666+ let first_line =
6767+ (start.Position.line, start.Position.index - start.Position.column + 1)
6868+ in
6969+ (* Handle case where stop is at the start of a new line (column 1)
7070+ This happens when the span includes a trailing newline.
7171+ The last_byte is on the previous line, so we need to calculate
7272+ the line start position based on last_byte, not stop. *)
7373+ let last_line =
7474+ if stop.Position.column = 1 && stop.Position.line > start.Position.line then
7575+ (* last_byte is on the previous line (stop.line - 1)
7676+ We need to estimate where that line starts. Since we don't have
7777+ the full text, we can't calculate it exactly, but we can use:
7878+ last_byte - (estimated_column - 1)
7979+ For now, we'll use the same line as start if they're close,
8080+ or just report it as the previous line. *)
8181+ let last_line_num = stop.Position.line - 1 in
8282+ (* Estimate: assume last_byte is somewhere on the previous line.
8383+ We'll use the byte position minus a reasonable offset.
8484+ This is approximate but better than wrapping to the next line. *)
8585+ if last_line_num = start.Position.line then
8686+ (* Same line as start - use start's line position *)
8787+ first_line
8888+ else
8989+ (* Different line - estimate line start as last_byte minus some offset
9090+ Since we subtracted 1 from stop.index to get last_byte, and stop.column was 1,
9191+ last_byte should be the newline character on the previous line.
9292+ The line likely started much earlier, but we'll estimate conservatively. *)
9393+ (last_line_num, last_byte)
9494+ else
9595+ (stop.Position.line, stop.Position.index - stop.Position.column + 1)
9696+ in
9797+ let textloc =
9898+ Jsont.Textloc.make ~file:d.file ~first_byte ~last_byte ~first_line
9999+ ~last_line
100100+ in
101101+ Jsont.Meta.make textloc
102102+103103+let next_event d =
104104+ d.current <- Parser.next d.parser;
105105+ d.current
106106+107107+let peek_event d =
108108+ match d.current with Some _ -> d.current | None -> next_event d
109109+110110+let skip_event d = d.current <- None
111111+112112+let _expect_event d pred name =
113113+ match peek_event d with
114114+ | Some ev when pred ev.Event.event ->
115115+ skip_event d;
116116+ ev
117117+ | Some ev ->
118118+ let span = ev.Event.span in
119119+ let meta = meta_of_span d span in
120120+ err_msg meta "Expected %s but found %a" name Event.pp ev.Event.event
121121+ | None -> err_msg_none "Expected %s but reached end of stream" name
122122+123123+(* Error helpers *)
124124+125125+let _err_expected_scalar d ev =
126126+ let meta = meta_of_span d ev.Event.span in
127127+ err_msg meta "Expected scalar but found %a" Event.pp ev.Event.event
128128+129129+let err_type_mismatch d span t ~fnd =
130130+ let open Jsont.Repr in
131131+ let meta = meta_of_span d span in
132132+ err_msg meta "Expected %s but found %s" (kinded_sort t) fnd
133133+134134+(* YAML scalar resolution *)
135135+136136+let is_null_scalar s =
137137+ s = "" || s = "~" || s = "null" || s = "Null" || s = "NULL"
138138+139139+let bool_of_scalar_opt s =
140140+ match s with
141141+ | "true" | "True" | "TRUE" | "yes" | "Yes" | "YES" | "on" | "On" | "ON" ->
142142+ Some true
143143+ | "false" | "False" | "FALSE" | "no" | "No" | "NO" | "off" | "Off" | "OFF" ->
144144+ Some false
145145+ | _ -> None
146146+147147+let float_of_scalar_opt s =
148148+ (* Handle YAML special floats *)
149149+ match s with
150150+ | ".inf" | ".Inf" | ".INF" -> Some Float.infinity
151151+ | "+.inf" | "+.Inf" | "+.INF" -> Some Float.infinity
152152+ | "-.inf" | "-.Inf" | "-.INF" -> Some Float.neg_infinity
153153+ | ".nan" | ".NaN" | ".NAN" -> Some Float.nan
154154+ | _ -> (
155155+ (* Try parsing as number, allowing underscores *)
156156+ let s' = String.concat "" (String.split_on_char '_' s) in
157157+ (* Try int first (supports 0o, 0x, 0b) then float *)
158158+ match int_of_string_opt s' with
159159+ | Some i -> Some (float_of_int i)
160160+ | None -> float_of_string_opt s')
161161+162162+let _int_of_scalar_opt s =
163163+ (* Handle hex, octal, and regular integers with underscores *)
164164+ let s' = String.concat "" (String.split_on_char '_' s) in
165165+ int_of_string_opt s'
166166+167167+(* Decode a scalar value according to expected type *)
168168+let rec decode_scalar_as : type a.
169169+ decoder -> Event.spanned -> string -> Scalar_style.t -> a t -> a =
170170+ fun d ev value style t ->
171171+ check_nodes d;
172172+ let meta = meta_of_span d ev.Event.span in
173173+ match t with
174174+ | Null map ->
175175+ if is_null_scalar value then map.dec meta ()
176176+ else err_type_mismatch d ev.span t ~fnd:("scalar " ^ value)
177177+ | Bool map -> (
178178+ match bool_of_scalar_opt value with
179179+ | Some b -> map.dec meta b
180180+ | None ->
181181+ (* For explicitly quoted strings, fail *)
182182+ if style <> `Plain then
183183+ err_type_mismatch d ev.span t ~fnd:("string " ^ value)
184184+ else err_type_mismatch d ev.span t ~fnd:("scalar " ^ value))
185185+ | Number map -> (
186186+ if
187187+ (* Handle null -> nan mapping like jsont *)
188188+ is_null_scalar value
189189+ then map.dec meta Float.nan
190190+ else
191191+ match float_of_scalar_opt value with
192192+ | Some f -> map.dec meta f
193193+ | None -> err_type_mismatch d ev.span t ~fnd:("scalar " ^ value))
194194+ | String map ->
195195+ (* Don't decode null values as strings - they should fail so outer combinators
196196+ like 'option' or 'any' can handle them properly.
197197+ BUT: quoted strings should always be treated as strings, even if they
198198+ look like null (e.g., "" or "null") *)
199199+ if style = `Plain && is_null_scalar value then
200200+ err_type_mismatch d ev.span t ~fnd:"null"
201201+ else
202202+ (* Strings accept quoted scalars or non-null plain scalars *)
203203+ map.dec meta value
204204+ | Array map ->
205205+ (* Treat null as an empty array for convenience *)
206206+ if is_null_scalar value then
207207+ let end_meta = meta_of_span d ev.Event.span in
208208+ map.dec_finish end_meta 0 (map.dec_empty ())
209209+ else
210210+ err_type_mismatch d ev.span t ~fnd:"scalar"
211211+ | Object map ->
212212+ (* Treat null as an empty object for convenience *)
213213+ if is_null_scalar value then
214214+ (* Build a dict with all default values from absent members *)
215215+ let add_default _ (Mem_dec mem_map) dict =
216216+ match mem_map.dec_absent with
217217+ | Some v -> Dict.add mem_map.id v dict
218218+ | None ->
219219+ (* Required field without default - error *)
220220+ let exp = String_map.singleton mem_map.name (Mem_dec mem_map) in
221221+ missing_mems_error meta map ~exp ~fnd:[]
222222+ in
223223+ let dict = String_map.fold add_default map.mem_decs Dict.empty in
224224+ let dict = Dict.add object_meta_arg meta dict in
225225+ apply_dict map.dec dict
226226+ else
227227+ err_type_mismatch d ev.span t ~fnd:"scalar"
228228+ | Map m ->
229229+ (* Handle Map combinators (e.g., from Jsont.option) *)
230230+ m.dec (decode_scalar_as d ev value style m.dom)
231231+ | Rec lazy_t ->
232232+ (* Handle recursive types *)
233233+ decode_scalar_as d ev value style (Lazy.force lazy_t)
234234+ | _ -> err_type_mismatch d ev.span t ~fnd:"scalar"
235235+236236+(* Forward declaration for mutual recursion *)
237237+let rec decode : type a. decoder -> nest:int -> a t -> a =
238238+ fun d ~nest t ->
239239+ check_depth d ~nest;
240240+ match peek_event d with
241241+ | None -> err_msg_none "Unexpected end of YAML stream"
242242+ | Some ev -> (
243243+ match (ev.Event.event, t) with
244244+ (* Scalar events *)
245245+ | Event.Scalar { value; style; anchor; _ }, _ ->
246246+ skip_event d;
247247+ let result = decode_scalar d ~nest ev value style t in
248248+ (* Store anchor if present - TODO: implement anchor storage *)
249249+ (match anchor with
250250+ | Some _name ->
251251+ (* We need generic JSON for anchors - decode as json and convert back *)
252252+ ()
253253+ | None -> ());
254254+ result
255255+ (* Alias *)
256256+ | Event.Alias { anchor }, _ ->
257257+ skip_event d;
258258+ decode_alias d ev anchor t
259259+ (* Map combinator - must come before specific event matches *)
260260+ | _, Map m -> m.dec (decode d ~nest m.dom)
261261+ (* Recursive types - must come before specific event matches *)
262262+ | _, Rec lazy_t -> decode d ~nest (Lazy.force lazy_t)
263263+ (* Sequence -> Array *)
264264+ | Event.Sequence_start _, Array map -> decode_array d ~nest ev map
265265+ | Event.Sequence_start _, Any map -> decode_any_sequence d ~nest ev t map
266266+ | Event.Sequence_start _, _ ->
267267+ err_type_mismatch d ev.span t ~fnd:"sequence"
268268+ (* Mapping -> Object *)
269269+ | Event.Mapping_start _, Object map -> decode_object d ~nest ev map
270270+ | Event.Mapping_start _, Any map -> decode_any_mapping d ~nest ev t map
271271+ | Event.Mapping_start _, _ -> err_type_mismatch d ev.span t ~fnd:"mapping"
272272+ (* Unexpected events *)
273273+ | Event.Sequence_end, _ ->
274274+ err_msg (meta_of_span d ev.span) "Unexpected sequence end"
275275+ | Event.Mapping_end, _ ->
276276+ err_msg (meta_of_span d ev.span) "Unexpected mapping end"
277277+ | Event.Document_start _, _ ->
278278+ err_msg (meta_of_span d ev.span) "Unexpected document start"
279279+ | Event.Document_end _, _ ->
280280+ err_msg (meta_of_span d ev.span) "Unexpected document end"
281281+ | Event.Stream_start _, _ ->
282282+ err_msg (meta_of_span d ev.span) "Unexpected stream start"
283283+ | Event.Stream_end, _ ->
284284+ err_msg (meta_of_span d ev.span) "Unexpected stream end")
285285+286286+and decode_scalar : type a.
287287+ decoder -> nest:int -> Event.spanned -> string -> Scalar_style.t -> a t -> a
288288+ =
289289+ fun d ~nest ev value style t ->
290290+ match t with
291291+ | Any map -> decode_any_scalar d ev value style t map
292292+ | Map m -> m.dec (decode_scalar d ~nest ev value style m.dom)
293293+ | Rec lazy_t -> decode_scalar d ~nest ev value style (Lazy.force lazy_t)
294294+ | _ -> decode_scalar_as d ev value style t
295295+296296+and decode_any_scalar : type a.
297297+ decoder ->
298298+ Event.spanned ->
299299+ string ->
300300+ Scalar_style.t ->
301301+ a t ->
302302+ a any_map ->
303303+ a =
304304+ fun d ev value style t map ->
305305+ check_nodes d;
306306+ let meta = meta_of_span d ev.span in
307307+ let type_err fnd = Jsont.Repr.type_error meta t ~fnd in
308308+ (* Determine which decoder to use based on scalar content *)
309309+ if is_null_scalar value then
310310+ match map.dec_null with
311311+ | Some t' -> decode_scalar_as d ev value style t'
312312+ | None -> type_err Jsont.Sort.Null
313313+ else if style = `Plain then
314314+ (* Try bool, then number, then string *)
315315+ match bool_of_scalar_opt value with
316316+ | Some _ -> (
317317+ match map.dec_bool with
318318+ | Some t' -> decode_scalar_as d ev value style t'
319319+ | None -> (
320320+ match map.dec_string with
321321+ | Some t' -> decode_scalar_as d ev value style t'
322322+ | None -> type_err Jsont.Sort.Bool))
323323+ | None -> (
324324+ match float_of_scalar_opt value with
325325+ | Some _ -> (
326326+ match map.dec_number with
327327+ | Some t' -> decode_scalar_as d ev value style t'
328328+ | None -> (
329329+ match map.dec_string with
330330+ | Some t' -> decode_scalar_as d ev value style t'
331331+ | None -> type_err Jsont.Sort.Number))
332332+ | None -> (
333333+ (* Plain scalar that's not bool/number -> string *)
334334+ match map.dec_string with
335335+ | Some t' -> decode_scalar_as d ev value style t'
336336+ | None -> type_err Jsont.Sort.String))
337337+ else
338338+ (* Quoted scalars are strings *)
339339+ match map.dec_string with
340340+ | Some t' -> decode_scalar_as d ev value style t'
341341+ | None -> type_err Jsont.Sort.String
342342+343343+and decode_alias : type a. decoder -> Event.spanned -> string -> a t -> a =
344344+ fun d ev anchor t ->
345345+ check_nodes d;
346346+ match Hashtbl.find_opt d._anchors anchor with
347347+ | None ->
348348+ let meta = meta_of_span d ev.span in
349349+ err_msg meta "Unknown anchor: %s" anchor
350350+ | Some json_value ->
351351+ (* Decode the stored JSON value through the type *)
352352+ let t' = Jsont.Repr.unsafe_to_t t in
353353+ match Jsont.Json.decode' t' json_value with
354354+ | Ok v -> v
355355+ | Error e -> raise (Jsont.Error e)
356356+357357+and decode_array : type a elt b.
358358+ decoder -> nest:int -> Event.spanned -> (a, elt, b) array_map -> a =
359359+ fun d ~nest start_ev array_map ->
360360+ skip_event d;
361361+ (* consume Sequence_start *)
362362+ check_nodes d;
363363+ let meta = meta_of_span d start_ev.span in
364364+ let builder = ref (array_map.dec_empty ()) in
365365+ let idx = ref 0 in
366366+ let rec loop () =
367367+ match peek_event d with
368368+ | Some { Event.event = Event.Sequence_end; span } ->
369369+ skip_event d;
370370+ let end_meta = meta_of_span d span in
371371+ array_map.dec_finish end_meta !idx !builder
372372+ | Some _ ->
373373+ let i = !idx in
374374+ (try
375375+ if array_map.dec_skip i !builder then begin
376376+ (* Skip this element by decoding as ignore *)
377377+ let _ : unit =
378378+ decode d ~nest:(nest + 1) (Jsont.Repr.of_t Jsont.ignore)
379379+ in
380380+ ()
381381+ end
382382+ else begin
383383+ let elt = decode d ~nest:(nest + 1) array_map.elt in
384384+ builder := array_map.dec_add i elt !builder
385385+ end
386386+ with Jsont.Error e ->
387387+ Jsont.Repr.error_push_array meta array_map (i, Jsont.Meta.none) e);
388388+ incr idx;
389389+ loop ()
390390+ | None -> err_msg meta "Unclosed sequence"
391391+ in
392392+ loop ()
393393+394394+and decode_any_sequence : type a.
395395+ decoder -> nest:int -> Event.spanned -> a t -> a any_map -> a =
396396+ fun d ~nest ev t map ->
397397+ match map.dec_array with
398398+ | Some t' -> (
399399+ (* The t' decoder might be wrapped (e.g., Map for option types)
400400+ Directly decode the array and let the wrapper handle it *)
401401+ match t' with
402402+ | Array array_map -> decode_array d ~nest ev array_map
403403+ | _ ->
404404+ (* For wrapped types like Map (Array ...), use full decode *)
405405+ decode d ~nest t')
406406+ | None ->
407407+ Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.Array
408408+409409+and decode_object : type o.
410410+ decoder -> nest:int -> Event.spanned -> (o, o) object_map -> o =
411411+ fun d ~nest start_ev map ->
412412+ skip_event d;
413413+ (* consume Mapping_start *)
414414+ check_nodes d;
415415+ let meta = meta_of_span d start_ev.span in
416416+ let dict =
417417+ decode_object_members d ~nest meta map String_map.empty Dict.empty
418418+ in
419419+ let dict = Dict.add object_meta_arg meta dict in
420420+ apply_dict map.dec dict
421421+422422+and decode_object_members : type o.
423423+ decoder ->
424424+ nest:int ->
425425+ Jsont.Meta.t ->
426426+ (o, o) object_map ->
427427+ mem_dec String_map.t ->
428428+ Dict.t ->
429429+ Dict.t =
430430+ fun d ~nest obj_meta map mem_miss dict ->
431431+ (* Merge expected member decoders *)
432432+ let u _ _ _ = assert false in
433433+ let mem_miss = String_map.union u mem_miss map.mem_decs in
434434+ match map.shape with
435435+ | Object_basic umems ->
436436+ decode_object_basic d ~nest obj_meta map umems mem_miss dict
437437+ | Object_cases (umems_opt, cases) ->
438438+ (* Wrap umems_opt to hide existential types *)
439439+ let umems = Unknown_mems umems_opt in
440440+ decode_object_cases d ~nest obj_meta map umems cases mem_miss [] dict
441441+442442+and decode_object_basic : type o mems builder.
443443+ decoder ->
444444+ nest:int ->
445445+ Jsont.Meta.t ->
446446+ (o, o) object_map ->
447447+ (o, mems, builder) unknown_mems ->
448448+ mem_dec String_map.t ->
449449+ Dict.t ->
450450+ Dict.t =
451451+ fun d ~nest obj_meta object_map umems mem_miss dict ->
452452+ let ubuilder =
453453+ ref
454454+ (match umems with
455455+ | Unknown_skip | Unknown_error -> Obj.magic ()
456456+ | Unknown_keep (mmap, _) -> mmap.dec_empty ())
457457+ in
458458+ let mem_miss = ref mem_miss in
459459+ let dict = ref dict in
460460+ let rec loop () =
461461+ match peek_event d with
462462+ | Some { Event.event = Event.Mapping_end; _ } ->
463463+ skip_event d;
464464+ (* Finalize *)
465465+ finish_object obj_meta object_map umems !ubuilder !mem_miss !dict
466466+ | Some ev ->
467467+ (* Expect a scalar key *)
468468+ let name, name_meta = decode_mapping_key d ev in
469469+ (* Look up member decoder *)
470470+ (match String_map.find_opt name object_map.mem_decs with
471471+ | Some (Mem_dec mem) -> (
472472+ mem_miss := String_map.remove name !mem_miss;
473473+ try
474474+ let v = decode d ~nest:(nest + 1) mem.type' in
475475+ dict := Dict.add mem.id v !dict
476476+ with Jsont.Error e ->
477477+ Jsont.Repr.error_push_object obj_meta object_map (name, name_meta)
478478+ e)
479479+ | None -> (
480480+ (* Unknown member *)
481481+ match umems with
482482+ | Unknown_skip ->
483483+ let _ : unit =
484484+ decode d ~nest:(nest + 1) (Jsont.Repr.of_t Jsont.ignore)
485485+ in
486486+ ()
487487+ | Unknown_error ->
488488+ Jsont.Repr.unexpected_mems_error obj_meta object_map
489489+ ~fnd:[ (name, name_meta) ]
490490+ | Unknown_keep (mmap, _) -> (
491491+ try
492492+ let v = decode d ~nest:(nest + 1) mmap.mems_type in
493493+ ubuilder := mmap.dec_add name_meta name v !ubuilder
494494+ with Jsont.Error e ->
495495+ Jsont.Repr.error_push_object obj_meta object_map
496496+ (name, name_meta) e)));
497497+ loop ()
498498+ | None -> err_msg obj_meta "Unclosed mapping"
499499+ in
500500+ loop ()
501501+502502+and finish_object : type o mems builder.
503503+ Jsont.Meta.t ->
504504+ (o, o) object_map ->
505505+ (o, mems, builder) unknown_mems ->
506506+ builder ->
507507+ mem_dec String_map.t ->
508508+ Dict.t ->
509509+ Dict.t =
510510+ fun meta map umems ubuilder mem_miss dict ->
511511+ let open Jsont.Repr in
512512+ let dict = Dict.add object_meta_arg meta dict in
513513+ let dict =
514514+ match umems with
515515+ | Unknown_skip | Unknown_error -> dict
516516+ | Unknown_keep (mmap, _) ->
517517+ Dict.add mmap.id (mmap.dec_finish meta ubuilder) dict
518518+ in
519519+ (* Check for missing required members *)
520520+ let add_default _ (Mem_dec mem_map) dict =
521521+ match mem_map.dec_absent with
522522+ | Some v -> Dict.add mem_map.id v dict
523523+ | None -> raise Exit
524524+ in
525525+ try String_map.fold add_default mem_miss dict
526526+ with Exit ->
527527+ let no_default _ (Mem_dec mm) = Option.is_none mm.dec_absent in
528528+ let exp = String_map.filter no_default mem_miss in
529529+ missing_mems_error meta map ~exp ~fnd:[]
530530+531531+and decode_object_cases : type o cases tag.
532532+ decoder ->
533533+ nest:int ->
534534+ Jsont.Meta.t ->
535535+ (o, o) object_map ->
536536+ unknown_mems_option ->
537537+ (o, cases, tag) object_cases ->
538538+ mem_dec String_map.t ->
539539+ (Jsont.name * Jsont.json) list ->
540540+ Dict.t ->
541541+ Dict.t =
542542+ fun d ~nest obj_meta object_map umems cases mem_miss delayed dict ->
543543+ match peek_event d with
544544+ | Some { Event.event = Event.Mapping_end; _ } -> (
545545+ skip_event d;
546546+ (* No tag found - use dec_absent if available *)
547547+ match cases.tag.dec_absent with
548548+ | Some tag ->
549549+ decode_with_case_tag d ~nest obj_meta object_map umems cases tag
550550+ mem_miss delayed dict
551551+ | None ->
552552+ (* Missing required case tag *)
553553+ let exp = String_map.singleton cases.tag.name (Mem_dec cases.tag) in
554554+ let fnd = List.map (fun ((n, _), _) -> n) delayed in
555555+ Jsont.Repr.missing_mems_error obj_meta object_map ~exp ~fnd)
556556+ | Some ev ->
557557+ let name, name_meta = decode_mapping_key d ev in
558558+ if String.equal name cases.tag.name then begin
559559+ (* Found the case tag *)
560560+ let tag = decode d ~nest:(nest + 1) cases.tag.type' in
561561+ decode_with_case_tag d ~nest obj_meta object_map umems cases tag
562562+ mem_miss delayed dict
563563+ end
564564+ else begin
565565+ (* Not the case tag - check if known member or delay *)
566566+ match String_map.find_opt name object_map.mem_decs with
567567+ | Some (Mem_dec mem) -> (
568568+ let mem_miss = String_map.remove name mem_miss in
569569+ try
570570+ let v = decode d ~nest:(nest + 1) mem.type' in
571571+ let dict = Dict.add mem.id v dict in
572572+ decode_object_cases d ~nest obj_meta object_map umems cases
573573+ mem_miss delayed dict
574574+ with Jsont.Error e ->
575575+ Jsont.Repr.error_push_object obj_meta object_map (name, name_meta)
576576+ e)
577577+ | None ->
578578+ (* Unknown member - decode as generic JSON and delay *)
579579+ let v =
580580+ decode d ~nest:(nest + 1) (Jsont.Repr.of_t Jsont.json)
581581+ in
582582+ let delayed = ((name, name_meta), v) :: delayed in
583583+ decode_object_cases d ~nest obj_meta object_map umems cases
584584+ mem_miss delayed dict
585585+ end
586586+ | None -> err_msg obj_meta "Unclosed mapping"
587587+588588+and decode_with_case_tag : type o cases tag.
589589+ decoder ->
590590+ nest:int ->
591591+ Jsont.Meta.t ->
592592+ (o, o) object_map ->
593593+ unknown_mems_option ->
594594+ (o, cases, tag) object_cases ->
595595+ tag ->
596596+ mem_dec String_map.t ->
597597+ (Jsont.name * Jsont.json) list ->
598598+ Dict.t ->
599599+ Dict.t =
600600+ fun d ~nest obj_meta map umems cases tag mem_miss delayed dict ->
601601+ let open Jsont.Repr in
602602+ let eq_tag (Case c) = cases.tag_compare c.tag tag = 0 in
603603+ match List.find_opt eq_tag cases.cases with
604604+ | None -> unexpected_case_tag_error obj_meta map cases tag
605605+ | Some (Case case) ->
606606+ (* Continue decoding with the case's object map *)
607607+ let case_dict =
608608+ decode_case_remaining d ~nest obj_meta case.object_map umems mem_miss
609609+ delayed dict
610610+ in
611611+ let case_value = apply_dict case.object_map.dec case_dict in
612612+ Dict.add cases.id (case.dec case_value) dict
613613+614614+and decode_case_remaining : type o.
615615+ decoder ->
616616+ nest:int ->
617617+ Jsont.Meta.t ->
618618+ (o, o) object_map ->
619619+ unknown_mems_option ->
620620+ mem_dec String_map.t ->
621621+ (Jsont.name * Jsont.json) list ->
622622+ Dict.t ->
623623+ Dict.t =
624624+ fun d ~nest obj_meta case_map _umems mem_miss delayed dict ->
625625+ (* First, process delayed members against the case map *)
626626+ let u _ _ _ = assert false in
627627+ let mem_miss = String_map.union u mem_miss case_map.mem_decs in
628628+ let dict, mem_miss =
629629+ List.fold_left
630630+ (fun (dict, mem_miss) ((name, meta), json_value) ->
631631+ match String_map.find_opt name case_map.mem_decs with
632632+ | Some (Mem_dec mem) -> (
633633+ let t' = Jsont.Repr.unsafe_to_t mem.type' in
634634+ match Jsont.Json.decode' t' json_value with
635635+ | Ok v ->
636636+ let dict = Dict.add mem.id v dict in
637637+ let mem_miss = String_map.remove name mem_miss in
638638+ (dict, mem_miss)
639639+ | Error e ->
640640+ Jsont.Repr.error_push_object obj_meta case_map (name, meta) e)
641641+ | None ->
642642+ (* Unknown for case too - skip them *)
643643+ (dict, mem_miss))
644644+ (dict, mem_miss) delayed
645645+ in
646646+ (* Then continue reading remaining members using case's own unknown handling *)
647647+ match case_map.shape with
648648+ | Object_basic case_umems ->
649649+ decode_object_basic d ~nest obj_meta case_map case_umems mem_miss dict
650650+ | Object_cases _ ->
651651+ (* Nested cases shouldn't happen - use skip for safety *)
652652+ decode_object_basic d ~nest obj_meta case_map Unknown_skip mem_miss dict
653653+654654+and decode_any_mapping : type a.
655655+ decoder -> nest:int -> Event.spanned -> a t -> a any_map -> a =
656656+ fun d ~nest ev t map ->
657657+ match map.dec_object with
658658+ | Some t' -> decode d ~nest t'
659659+ | None ->
660660+ Jsont.Repr.type_error (meta_of_span d ev.span) t ~fnd:Jsont.Sort.Object
661661+662662+and decode_mapping_key : decoder -> Event.spanned -> string * Jsont.Meta.t =
663663+ fun d ev ->
664664+ match ev.Event.event with
665665+ | Event.Scalar { value; _ } ->
666666+ skip_event d;
667667+ let meta = meta_of_span d ev.span in
668668+ (value, meta)
669669+ | _ ->
670670+ let meta = meta_of_span d ev.span in
671671+ err_msg meta "Mapping keys must be scalars (strings), found %a" Event.pp
672672+ ev.event
673673+674674+(* Skip stream/document wrappers *)
675675+let skip_to_content d =
676676+ let rec loop () =
677677+ match peek_event d with
678678+ | Some { Event.event = Event.Stream_start _; _ } ->
679679+ skip_event d;
680680+ loop ()
681681+ | Some { Event.event = Event.Document_start _; _ } ->
682682+ skip_event d;
683683+ loop ()
684684+ | _ -> ()
685685+ in
686686+ loop ()
687687+688688+let skip_end_wrappers d =
689689+ let rec loop () =
690690+ match peek_event d with
691691+ | Some { Event.event = Event.Document_end _; _ } ->
692692+ skip_event d;
693693+ loop ()
694694+ | Some { Event.event = Event.Stream_end; _ } ->
695695+ skip_event d;
696696+ loop ()
697697+ | None -> ()
698698+ | Some ev ->
699699+ let meta = meta_of_span d ev.span in
700700+ err_msg meta "Expected end of document but found %a" Event.pp ev.event
701701+ in
702702+ loop ()
703703+704704+(* Skip to the end of the current document after an error *)
705705+let skip_to_document_end d =
706706+ let rec loop depth =
707707+ match peek_event d with
708708+ | None -> ()
709709+ | Some { Event.event = Event.Stream_end; _ } -> ()
710710+ | Some { Event.event = Event.Document_end _; _ } ->
711711+ skip_event d;
712712+ if depth = 0 then () else loop (depth - 1)
713713+ | Some { Event.event = Event.Document_start _; _ } ->
714714+ skip_event d;
715715+ loop (depth + 1)
716716+ | Some _ ->
717717+ skip_event d;
718718+ loop depth
719719+ in
720720+ loop 0
721721+722722+(* Public decode API *)
723723+724724+(* Decode all documents from a multi-document YAML stream *)
725725+let decode_all' ?(layout = false) ?(locs = false) ?(file = "-")
726726+ ?(max_depth = 100) ?(max_nodes = 10_000_000) t reader =
727727+ let parser = Parser.of_reader reader in
728728+ let d = make_decoder ~layout ~locs ~file ~max_depth ~max_nodes parser in
729729+ let t' = Jsont.Repr.of_t t in
730730+ let rec next_doc () =
731731+ match peek_event d with
732732+ | None -> Seq.Nil
733733+ | Some { Event.event = Event.Stream_end; _ } ->
734734+ skip_event d;
735735+ Seq.Nil
736736+ | Some _ -> (
737737+ try
738738+ skip_to_content d;
739739+ (* Reset node count for each document *)
740740+ d.node_count <- 0;
741741+ let v = decode d ~nest:0 t' in
742742+ (* Skip document end marker if present *)
743743+ (match peek_event d with
744744+ | Some { Event.event = Event.Document_end _; _ } -> skip_event d
745745+ | _ -> ());
746746+ Seq.Cons (Ok v, next_doc)
747747+ with
748748+ | Jsont.Error e ->
749749+ skip_to_document_end d;
750750+ Seq.Cons (Error e, next_doc)
751751+ | Error.Yamlrw_error err ->
752752+ skip_to_document_end d;
753753+ let msg = Error.to_string err in
754754+ let e = Jsont.(Error.make_msg Error.Context.empty Meta.none msg) in
755755+ Seq.Cons (Error e, next_doc))
756756+ in
757757+ next_doc
758758+759759+let decode_all ?layout ?locs ?file ?max_depth ?max_nodes t reader =
760760+ decode_all' ?layout ?locs ?file ?max_depth ?max_nodes t reader
761761+ |> Seq.map (Result.map_error Jsont.Error.to_string)
762762+763763+let decode' ?layout ?locs ?file ?max_depth ?max_nodes t reader =
764764+ let parser = Parser.of_reader reader in
765765+ let d = make_decoder ?layout ?locs ?file ?max_depth ?max_nodes parser in
766766+ try
767767+ skip_to_content d;
768768+ let t' = Jsont.Repr.of_t t in
769769+ let v = decode d ~nest:0 t' in
770770+ skip_end_wrappers d;
771771+ Ok v
772772+ with
773773+ | Jsont.Error e -> Error e
774774+ | Error.Yamlrw_error err ->
775775+ let msg = Error.to_string err in
776776+ Error Jsont.(Error.make_msg Error.Context.empty Meta.none msg)
777777+778778+let decode ?layout ?locs ?file ?max_depth ?max_nodes t reader =
779779+ Result.map_error Jsont.Error.to_string
780780+ (decode' ?layout ?locs ?file ?max_depth ?max_nodes t reader)
781781+782782+(* Encoder *)
783783+784784+type encoder = {
785785+ emitter : Emitter.t;
786786+ format : yaml_format;
787787+ _indent : int; (* Stored for future use in custom formatting *)
788788+ explicit_doc : bool;
789789+ scalar_style : Scalar_style.t;
790790+}
791791+792792+let make_encoder ?(format = Block) ?(indent = 2) ?(explicit_doc = false)
793793+ ?(scalar_style = `Any) emitter =
794794+ { emitter; format; _indent = indent; explicit_doc; scalar_style }
795795+796796+let layout_style_of_format = function
797797+ | Block -> `Block
798798+ | Flow -> `Flow
799799+ | Layout -> `Any
800800+801801+(* Choose appropriate scalar style for a string *)
802802+let choose_scalar_style ~preferred s =
803803+ if preferred <> `Any then preferred
804804+ else if String.contains s '\n' then `Literal
805805+ else if String.length s > 80 then `Folded
806806+ else `Plain
807807+808808+(* Helper to create scalar events with common defaults *)
809809+let scalar_event ?(anchor = None) ?(tag = None) ~value ~style () =
810810+ Event.Scalar
811811+ {
812812+ anchor;
813813+ tag;
814814+ value;
815815+ plain_implicit = true;
816816+ quoted_implicit = true;
817817+ style;
818818+ }
819819+820820+(* Helper to emit events *)
821821+let emit e = Emitter.emit e.emitter
822822+823823+(* Encode null *)
824824+let encode_null e _meta = emit e (scalar_event ~value:"null" ~style:`Plain ())
825825+826826+(* Encode boolean *)
827827+let encode_bool e _meta b =
828828+ emit e (scalar_event ~value:(if b then "true" else "false") ~style:`Plain ())
829829+830830+(* Encode number *)
831831+let encode_number e _meta f =
832832+ let value =
833833+ match Float.classify_float f with
834834+ | FP_nan -> ".nan"
835835+ | FP_infinite -> if f > 0.0 then ".inf" else "-.inf"
836836+ | _ ->
837837+ if Float.is_integer f && Float.abs f < 1e15 then Printf.sprintf "%.0f" f
838838+ else Printf.sprintf "%g" f
839839+ in
840840+ emit e (scalar_event ~value ~style:`Plain ())
841841+842842+(* Encode string *)
843843+let encode_string e _meta s =
844844+ let style = choose_scalar_style ~preferred:e.scalar_style s in
845845+ emit e (scalar_event ~value:s ~style ())
846846+847847+let rec encode : type a. encoder -> a t -> a -> unit =
848848+ fun e t v ->
849849+ match t with
850850+ | Null map ->
851851+ let meta = map.enc_meta v in
852852+ let () = map.enc v in
853853+ encode_null e meta
854854+ | Bool map ->
855855+ let meta = map.enc_meta v in
856856+ let b = map.enc v in
857857+ encode_bool e meta b
858858+ | Number map ->
859859+ let meta = map.enc_meta v in
860860+ let f = map.enc v in
861861+ encode_number e meta f
862862+ | String map ->
863863+ let meta = map.enc_meta v in
864864+ let s = map.enc v in
865865+ encode_string e meta s
866866+ | Array map -> encode_array e map v
867867+ | Object map -> encode_object e map v
868868+ | Any map ->
869869+ let t' = map.enc v in
870870+ encode e t' v
871871+ | Map m -> encode e m.dom (m.enc v)
872872+ | Rec lazy_t -> encode e (Lazy.force lazy_t) v
873873+874874+and encode_array : type a elt b. encoder -> (a, elt, b) array_map -> a -> unit =
875875+ fun e map v ->
876876+ let style = layout_style_of_format e.format in
877877+ emit e
878878+ (Event.Sequence_start { anchor = None; tag = None; implicit = true; style });
879879+ let _ =
880880+ map.enc
881881+ (fun () _idx elt ->
882882+ encode e map.elt elt;
883883+ ())
884884+ () v
885885+ in
886886+ emit e Event.Sequence_end
887887+888888+and encode_object : type o. encoder -> (o, o) object_map -> o -> unit =
889889+ fun e map v ->
890890+ let style = layout_style_of_format e.format in
891891+ emit e (Event.Mapping_start { anchor = None; tag = None; implicit = true; style });
892892+ (* Encode each member *)
893893+ List.iter
894894+ (fun (Mem_enc mem) ->
895895+ let mem_v = mem.enc v in
896896+ if not (mem.enc_omit mem_v) then begin
897897+ (* Emit key *)
898898+ emit e (scalar_event ~value:mem.name ~style:`Plain ());
899899+ (* Emit value *)
900900+ encode e mem.type' mem_v
901901+ end)
902902+ map.mem_encs;
903903+ (* Handle case objects *)
904904+ (match map.shape with
905905+ | Object_basic _ -> ()
906906+ | Object_cases (_, cases) ->
907907+ let (Case_value (case_map, case_v)) = cases.enc_case (cases.enc v) in
908908+ (* Emit case tag *)
909909+ if not (cases.tag.enc_omit case_map.tag) then begin
910910+ emit e (scalar_event ~value:cases.tag.name ~style:`Plain ());
911911+ encode e cases.tag.type' case_map.tag
912912+ end;
913913+ (* Emit case members *)
914914+ List.iter
915915+ (fun (Mem_enc mem) ->
916916+ let mem_v = mem.enc case_v in
917917+ if not (mem.enc_omit mem_v) then begin
918918+ emit e (scalar_event ~value:mem.name ~style:`Plain ());
919919+ encode e mem.type' mem_v
920920+ end)
921921+ case_map.object_map.mem_encs);
922922+ emit e Event.Mapping_end
923923+924924+(* Public encode API *)
925925+926926+let encode' ?buf:_ ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer =
927927+ let config =
928928+ {
929929+ Emitter.default_config with
930930+ indent = Option.value ~default:2 indent;
931931+ layout_style = (match format with Some Flow -> `Flow | _ -> `Block);
932932+ }
933933+ in
934934+ let emitter = Emitter.of_writer ~config writer in
935935+ let e = make_encoder ?format ?indent ?explicit_doc ?scalar_style emitter in
936936+ try
937937+ emit e (Event.Stream_start { encoding = `Utf8 });
938938+ emit e (Event.Document_start { version = None; implicit = not e.explicit_doc });
939939+ let t' = Jsont.Repr.of_t t in
940940+ encode e t' v;
941941+ emit e (Event.Document_end { implicit = not e.explicit_doc });
942942+ emit e Event.Stream_end;
943943+ if eod then Emitter.flush e.emitter;
944944+ Ok ()
945945+ with
946946+ | Jsont.Error err -> Error err
947947+ | Error.Yamlrw_error err ->
948948+ let msg = Error.to_string err in
949949+ Error Jsont.(Error.make_msg Error.Context.empty Meta.none msg)
950950+951951+let encode ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer =
952952+ Result.map_error Jsont.Error.to_string
953953+ (encode' ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer)
954954+955955+(* Recode *)
956956+957957+let recode ?layout ?locs ?file ?max_depth ?max_nodes ?buf ?format ?indent
958958+ ?explicit_doc ?scalar_style t reader writer ~eod =
959959+ let format =
960960+ match (layout, format) with Some true, None -> Some Layout | _, f -> f
961961+ in
962962+ let layout =
963963+ match (layout, format) with None, Some Layout -> Some true | l, _ -> l
964964+ in
965965+ match decode' ?layout ?locs ?file ?max_depth ?max_nodes t reader with
966966+ | Ok v ->
967967+ encode ?buf ?format ?indent ?explicit_doc ?scalar_style t v ~eod writer
968968+ | Error e -> Error (Jsont.Error.to_string e)
+257
vendor/opam/yamlt/lib/yamlt.mli
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** YAML codec using Jsont type descriptions.
77+88+ This module provides YAML streaming encode/decode that interprets {!Jsont.t}
99+ type descriptions, allowing the same codec definitions to work for both JSON
1010+ and YAML.
1111+1212+ {b Example:}
1313+ {[
1414+ (* Define a codec once using Jsont *)
1515+ module Config = struct
1616+ type t = { name : string; port : int }
1717+1818+ let make name port = { name; port }
1919+2020+ let jsont =
2121+ Jsont.Object.map ~kind:"Config" make
2222+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun c -> c.name)
2323+ |> Jsont.Object.mem "port" Jsont.int ~enc:(fun c -> c.port)
2424+ |> Jsont.Object.finish
2525+ end
2626+2727+ (* Use the same codec for both JSON and YAML *)
2828+ let from_json = Jsont_bytesrw.decode_string Config.jsont json_str
2929+ let from_yaml = Yamlt.decode_string Config.jsont yaml_str
3030+ ]}
3131+3232+ {2 Related Libraries}
3333+3434+ {ul
3535+ {- [Jsont] - JSON codec library whose type descriptions this library interprets}
3636+ {- [Yamlrw] - Pure OCaml YAML parser/emitter used for low-level YAML processing}
3737+ {- [Bytesrw] - Byte-level I/O abstraction for streaming encode/decode}}
3838+3939+ See notes about {{!yaml_mapping}YAML to JSON mapping},
4040+ {{!yaml_scalars}YAML scalar resolution}, and
4141+ {{!null_handling}null value handling}. *)
4242+4343+open Bytesrw
4444+4545+(** {1:decode Decode} *)
4646+4747+val decode :
4848+ ?layout:bool ->
4949+ ?locs:bool ->
5050+ ?file:Jsont.Textloc.fpath ->
5151+ ?max_depth:int ->
5252+ ?max_nodes:int ->
5353+ 'a Jsont.t ->
5454+ Bytes.Reader.t ->
5555+ ('a, string) result
5656+(** [decode t r] decodes a value from YAML reader [r] according to type [t].
5757+ - If [layout] is [true], style information is preserved in {!Jsont.Meta.t}
5858+ values (for potential round-tripping). Defaults to [false].
5959+ - If [locs] is [true], source locations are preserved in {!Jsont.Meta.t}
6060+ values and error messages are precisely located. Defaults to [false].
6161+ - [file] is the file path for error messages. Defaults to
6262+ {!Jsont.Textloc.file_none}.
6363+ - [max_depth] limits nesting depth to prevent stack overflow (billion laughs
6464+ protection). Defaults to [100].
6565+ - [max_nodes] limits total decoded nodes (billion laughs protection).
6666+ Defaults to [10_000_000].
6767+6868+ The YAML input must contain exactly one document. Multi-document streams are
6969+ not supported; use {!decode_all} for those. *)
7070+7171+val decode' :
7272+ ?layout:bool ->
7373+ ?locs:bool ->
7474+ ?file:Jsont.Textloc.fpath ->
7575+ ?max_depth:int ->
7676+ ?max_nodes:int ->
7777+ 'a Jsont.t ->
7878+ Bytes.Reader.t ->
7979+ ('a, Jsont.Error.t) result
8080+(** [decode'] is like {!val-decode} but preserves the error structure. *)
8181+8282+val decode_all :
8383+ ?layout:bool ->
8484+ ?locs:bool ->
8585+ ?file:Jsont.Textloc.fpath ->
8686+ ?max_depth:int ->
8787+ ?max_nodes:int ->
8888+ 'a Jsont.t ->
8989+ Bytes.Reader.t ->
9090+ ('a, string) result Seq.t
9191+(** [decode_all t r] decodes all documents from a multi-document YAML stream.
9292+ Returns a sequence where each element is a result of decoding one document.
9393+ Parameters are as in {!val-decode}. Use this for YAML streams containing
9494+ multiple documents separated by [---]. *)
9595+9696+val decode_all' :
9797+ ?layout:bool ->
9898+ ?locs:bool ->
9999+ ?file:Jsont.Textloc.fpath ->
100100+ ?max_depth:int ->
101101+ ?max_nodes:int ->
102102+ 'a Jsont.t ->
103103+ Bytes.Reader.t ->
104104+ ('a, Jsont.Error.t) result Seq.t
105105+(** [decode_all'] is like {!val-decode_all} but preserves the error structure. *)
106106+107107+(** {1:encode Encode} *)
108108+109109+(** YAML output format. *)
110110+type yaml_format =
111111+ | Block (** Block style (indented) - default. Clean, readable YAML. *)
112112+ | Flow (** Flow style (JSON-like). Compact, single-line collections. *)
113113+ | Layout (** Preserve layout from {!Jsont.Meta.t} when available. *)
114114+115115+val encode :
116116+ ?buf:Stdlib.Bytes.t ->
117117+ ?format:yaml_format ->
118118+ ?indent:int ->
119119+ ?explicit_doc:bool ->
120120+ ?scalar_style:Yamlrw.Scalar_style.t ->
121121+ 'a Jsont.t ->
122122+ 'a ->
123123+ eod:bool ->
124124+ Bytes.Writer.t ->
125125+ (unit, string) result
126126+(** [encode t v w] encodes value [v] according to type [t] to YAML on [w].
127127+ - If [buf] is specified, it is used as a buffer for output slices. Defaults
128128+ to a buffer of length {!Bytesrw.Bytes.Writer.slice_length}[ w].
129129+ - [format] controls the output style. Defaults to {!Block}.
130130+ - [indent] is the indentation width in spaces. Defaults to [2].
131131+ - [explicit_doc] if [true], emits explicit document markers ([---] and
132132+ [...]). Defaults to [false].
133133+ - [scalar_style] is the preferred style for string scalars. Defaults to
134134+ [`Any] (auto-detect based on content).
135135+ - [eod] indicates whether {!Bytesrw.Bytes.Slice.eod} should be written on
136136+ [w] after encoding. *)
137137+138138+val encode' :
139139+ ?buf:Stdlib.Bytes.t ->
140140+ ?format:yaml_format ->
141141+ ?indent:int ->
142142+ ?explicit_doc:bool ->
143143+ ?scalar_style:Yamlrw.Scalar_style.t ->
144144+ 'a Jsont.t ->
145145+ 'a ->
146146+ eod:bool ->
147147+ Bytes.Writer.t ->
148148+ (unit, Jsont.Error.t) result
149149+(** [encode'] is like {!val-encode} but preserves the error structure. *)
150150+151151+(** {1:recode Recode}
152152+153153+ The defaults in these functions are those of {!val-decode} and
154154+ {!val-encode}, except if [layout] is [true], [format] defaults to {!Layout}
155155+ and vice-versa. *)
156156+157157+val recode :
158158+ ?layout:bool ->
159159+ ?locs:bool ->
160160+ ?file:Jsont.Textloc.fpath ->
161161+ ?max_depth:int ->
162162+ ?max_nodes:int ->
163163+ ?buf:Stdlib.Bytes.t ->
164164+ ?format:yaml_format ->
165165+ ?indent:int ->
166166+ ?explicit_doc:bool ->
167167+ ?scalar_style:Yamlrw.Scalar_style.t ->
168168+ 'a Jsont.t ->
169169+ Bytes.Reader.t ->
170170+ Bytes.Writer.t ->
171171+ eod:bool ->
172172+ (unit, string) result
173173+(** [recode t r w] is {!val-decode} followed by {!val-encode}. *)
174174+175175+(** {1:yaml_mapping YAML to JSON Mapping}
176176+177177+ YAML is a superset of JSON. This module maps YAML structures to the JSON
178178+ data model that {!Jsont.t} describes:
179179+180180+ - YAML scalars map to JSON null, boolean, number, or string depending on
181181+ content and the expected type
182182+ - YAML sequences map to JSON arrays
183183+ - YAML mappings map to JSON objects (keys must be strings)
184184+ - YAML aliases are resolved during decoding
185185+ - YAML tags are used to guide type resolution when present
186186+187187+ {b Limitations:}
188188+ - Only string keys are supported in mappings (JSON object compatibility)
189189+ - Anchors and aliases are resolved; the alias structure is not preserved
190190+ - Multi-document streams require {!decode_all} *)
191191+192192+(** {1:yaml_scalars YAML Scalar Resolution}
193193+194194+ YAML scalars are resolved to JSON types as follows:
195195+196196+ {b Null:} [null], [Null], [NULL], [~], or empty string
197197+198198+ {b Boolean:} [true], [True], [TRUE], [false], [False], [FALSE], [yes],
199199+ [Yes], [YES], [no], [No], [NO], [on], [On], [ON], [off], [Off], [OFF]
200200+201201+ {b Number:} Decimal integers, floats, hex ([0x...]), octal ([0o...]),
202202+ infinity ([.inf], [-.inf]), NaN ([.nan])
203203+204204+ {b String:} Anything else, or explicitly quoted scalars
205205+206206+ When decoding against a specific {!Jsont.t} type, the expected type takes
207207+ precedence over automatic resolution. For example, decoding ["yes"] against
208208+ {!Jsont.string} yields the string ["yes"], not [true]. *)
209209+210210+(** {1:null_handling Null Value Handling}
211211+212212+ YAML null values are handled according to the expected type to provide
213213+ friendly defaults while maintaining type safety:
214214+215215+ {b Collections (Arrays and Objects):}
216216+217217+ Null values decode as empty collections when the codec expects a collection
218218+ type. This provides convenient defaults for optional collection fields in
219219+ YAML:
220220+ {[
221221+ # YAML with null collection fields
222222+ config:
223223+ items: null # Decodes as []
224224+ settings: ~ # Decodes as {}
225225+ tags: # Missing value = null, decodes as []
226226+ ]}
227227+228228+ For arrays, null decodes to an empty array. For objects, null decodes to an
229229+ object with all fields set to their [dec_absent] defaults. If any required
230230+ field lacks a default, decoding fails with a missing member error.
231231+232232+ This behavior makes yamlt more forgiving for schemas with many optional
233233+ collection fields, where writing [field:] (which parses as null) is natural
234234+ and semantically equivalent to [field: []].
235235+236236+ {b Numbers:}
237237+238238+ Null values decode to [Float.nan] when the codec expects a number.
239239+240240+ {b Primitive Types (Int, Bool, String):}
241241+242242+ Null values {e fail} when decoding into primitive scalar types ([int],
243243+ [bool], [string]). Null typically indicates genuinely missing or incorrect
244244+ data for these types, and silent conversion could clash with a manual
245245+ setting of the default value (e.g. 0 and [null] for an integer would be
246246+ indistinguishable).
247247+248248+ To accept null for primitive fields, explicitly use {!val:Jsont.option}:
249249+ {[
250250+ (* Accepts null, decodes as None *)
251251+ Jsont.Object.mem "count" (Jsont.option Jsont.int) ~dec_absent:None
252252+253253+ (* Rejects null, requires a number *)
254254+ Jsont.Object.mem "count" Jsont.int ~dec_absent:0
255255+ ]}
256256+257257+*)
···11+open Bytesrw
22+33+let () =
44+ let codec1 =
55+ Jsont.Object.map ~kind:"Test" (fun arr -> arr)
66+ |> Jsont.Object.mem "values" (Jsont.array Jsont.string) ~enc:(fun arr ->
77+ arr)
88+ |> Jsont.Object.finish
99+ in
1010+1111+ let yaml1 = "values: [a, b, c]" in
1212+1313+ Printf.printf "Test 1: Non-optional array:\n";
1414+ (match Yamlt.decode codec1 (Bytes.Reader.of_string yaml1) with
1515+ | Ok arr -> Printf.printf "Result: [%d items]\n" (Array.length arr)
1616+ | Error e -> Printf.printf "Error: %s\n" e);
1717+1818+ let codec2 =
1919+ Jsont.Object.map ~kind:"Test" (fun arr -> arr)
2020+ |> Jsont.Object.mem "values"
2121+ (Jsont.option (Jsont.array Jsont.string))
2222+ ~enc:(fun arr -> arr)
2323+ |> Jsont.Object.finish
2424+ in
2525+2626+ Printf.printf "\nTest 2: Jsont.option (Jsont.array):\n";
2727+ match Yamlt.decode codec2 (Bytes.Reader.of_string yaml1) with
2828+ | Ok arr -> (
2929+ match arr with
3030+ | None -> Printf.printf "Result: None\n"
3131+ | Some a -> Printf.printf "Result: Some([%d items])\n" (Array.length a))
3232+ | Error e -> Printf.printf "Error: %s\n" e
+326
vendor/opam/yamlt/tests/bin/test_arrays.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Test array codec functionality with Yamlt *)
77+88+open Bytesrw
99+1010+(* Helper to read file *)
1111+let read_file path =
1212+ let ic = open_in path in
1313+ let len = in_channel_length ic in
1414+ let s = really_input_string ic len in
1515+ close_in ic;
1616+ s
1717+1818+(* Helper to show results *)
1919+let show_result label = function
2020+ | Ok v -> Printf.printf "%s: %s\n" label v
2121+ | Error e -> Printf.printf "%s: ERROR: %s\n" label e
2222+2323+let show_result_both label json_result yaml_result =
2424+ Printf.printf "JSON: ";
2525+ show_result label json_result;
2626+ Printf.printf "YAML: ";
2727+ show_result label yaml_result
2828+2929+(* Test: Simple int array *)
3030+let test_int_array file =
3131+ let module M = struct
3232+ type numbers = { values : int array }
3333+3434+ let numbers_codec =
3535+ Jsont.Object.map ~kind:"Numbers" (fun values -> { values })
3636+ |> Jsont.Object.mem "values" (Jsont.array Jsont.int) ~enc:(fun n ->
3737+ n.values)
3838+ |> Jsont.Object.finish
3939+4040+ let show n =
4141+ Printf.sprintf "[%s]"
4242+ (String.concat "; " (Array.to_list (Array.map string_of_int n.values)))
4343+ end in
4444+ let yaml = read_file file in
4545+ let json = read_file (file ^ ".json") in
4646+ let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
4747+ let yaml_result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in
4848+4949+ show_result_both "int_array"
5050+ (Result.map M.show json_result)
5151+ (Result.map M.show yaml_result)
5252+5353+(* Test: String array *)
5454+let test_string_array file =
5555+ let module M = struct
5656+ type tags = { items : string array }
5757+5858+ let tags_codec =
5959+ Jsont.Object.map ~kind:"Tags" (fun items -> { items })
6060+ |> Jsont.Object.mem "items" (Jsont.array Jsont.string) ~enc:(fun t ->
6161+ t.items)
6262+ |> Jsont.Object.finish
6363+6464+ let show t =
6565+ Printf.sprintf "[%s]"
6666+ (String.concat "; "
6767+ (Array.to_list (Array.map (Printf.sprintf "%S") t.items)))
6868+ end in
6969+ let yaml = read_file file in
7070+ let json = read_file (file ^ ".json") in
7171+ let json_result = Jsont_bytesrw.decode_string M.tags_codec json in
7272+ let yaml_result = Yamlt.decode M.tags_codec (Bytes.Reader.of_string yaml) in
7373+7474+ show_result_both "string_array"
7575+ (Result.map M.show json_result)
7676+ (Result.map M.show yaml_result)
7777+7878+(* Test: Float/number array *)
7979+let test_float_array file =
8080+ let module M = struct
8181+ type measurements = { values : float array }
8282+8383+ let measurements_codec =
8484+ Jsont.Object.map ~kind:"Measurements" (fun values -> { values })
8585+ |> Jsont.Object.mem "values" (Jsont.array Jsont.number) ~enc:(fun m ->
8686+ m.values)
8787+ |> Jsont.Object.finish
8888+8989+ let show m =
9090+ Printf.sprintf "[%s]"
9191+ (String.concat "; "
9292+ (Array.to_list (Array.map (Printf.sprintf "%.2f") m.values)))
9393+ end in
9494+ let yaml = read_file file in
9595+ let json = read_file (file ^ ".json") in
9696+ let json_result = Jsont_bytesrw.decode_string M.measurements_codec json in
9797+ let yaml_result = Yamlt.decode M.measurements_codec (Bytes.Reader.of_string yaml) in
9898+9999+ show_result_both "float_array"
100100+ (Result.map M.show json_result)
101101+ (Result.map M.show yaml_result)
102102+103103+(* Test: Empty array *)
104104+let test_empty_array file =
105105+ let module M = struct
106106+ type empty = { items : int array }
107107+108108+ let empty_codec =
109109+ Jsont.Object.map ~kind:"Empty" (fun items -> { items })
110110+ |> Jsont.Object.mem "items" (Jsont.array Jsont.int) ~enc:(fun e ->
111111+ e.items)
112112+ |> Jsont.Object.finish
113113+114114+ let show e = Printf.sprintf "length=%d" (Stdlib.Array.length e.items)
115115+ end in
116116+ let yaml = read_file file in
117117+ let json = read_file (file ^ ".json") in
118118+ let json_result = Jsont_bytesrw.decode_string M.empty_codec json in
119119+ let yaml_result = Yamlt.decode M.empty_codec (Bytes.Reader.of_string yaml) in
120120+121121+ show_result_both "empty_array"
122122+ (Result.map M.show json_result)
123123+ (Result.map M.show yaml_result)
124124+125125+(* Test: Array of objects *)
126126+let test_object_array file =
127127+ let module M = struct
128128+ type person = { name : string; age : int }
129129+ type people = { persons : person array }
130130+131131+ let person_codec =
132132+ Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
133133+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
134134+ |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
135135+ |> Jsont.Object.finish
136136+137137+ let people_codec =
138138+ Jsont.Object.map ~kind:"People" (fun persons -> { persons })
139139+ |> Jsont.Object.mem "persons" (Jsont.array person_codec) ~enc:(fun p ->
140140+ p.persons)
141141+ |> Jsont.Object.finish
142142+143143+ let show_person p = Printf.sprintf "{%s,%d}" p.name p.age
144144+145145+ let show ps =
146146+ Printf.sprintf "[%s]"
147147+ (String.concat "; " (Array.to_list (Array.map show_person ps.persons)))
148148+ end in
149149+ let yaml = read_file file in
150150+ let json = read_file (file ^ ".json") in
151151+ let json_result = Jsont_bytesrw.decode_string M.people_codec json in
152152+ let yaml_result = Yamlt.decode M.people_codec (Bytes.Reader.of_string yaml) in
153153+154154+ show_result_both "object_array"
155155+ (Result.map M.show json_result)
156156+ (Result.map M.show yaml_result)
157157+158158+(* Test: Nested arrays *)
159159+let test_nested_arrays file =
160160+ let module M = struct
161161+ type matrix = { data : int array array }
162162+163163+ let matrix_codec =
164164+ Jsont.Object.map ~kind:"Matrix" (fun data -> { data })
165165+ |> Jsont.Object.mem "data"
166166+ (Jsont.array (Jsont.array Jsont.int))
167167+ ~enc:(fun m -> m.data)
168168+ |> Jsont.Object.finish
169169+170170+ let show_row row =
171171+ Printf.sprintf "[%s]"
172172+ (String.concat "; " (Array.to_list (Array.map string_of_int row)))
173173+174174+ let show m =
175175+ Printf.sprintf "[%s]"
176176+ (String.concat "; " (Array.to_list (Array.map show_row m.data)))
177177+ end in
178178+ let yaml = read_file file in
179179+ let json = read_file (file ^ ".json") in
180180+ let json_result = Jsont_bytesrw.decode_string M.matrix_codec json in
181181+ let yaml_result = Yamlt.decode M.matrix_codec (Bytes.Reader.of_string yaml) in
182182+183183+ show_result_both "nested_arrays"
184184+ (Result.map M.show json_result)
185185+ (Result.map M.show yaml_result)
186186+187187+(* Test: Mixed types in array (should fail with homogeneous codec) *)
188188+let test_type_mismatch file =
189189+ let module M = struct
190190+ type numbers = { values : int array }
191191+192192+ let numbers_codec =
193193+ Jsont.Object.map ~kind:"Numbers" (fun values -> { values })
194194+ |> Jsont.Object.mem "values" (Jsont.array Jsont.int) ~enc:(fun n ->
195195+ n.values)
196196+ |> Jsont.Object.finish
197197+ end in
198198+ let yaml = read_file file in
199199+ let result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in
200200+ match result with
201201+ | Ok _ -> Printf.printf "Unexpected success\n"
202202+ | Error e -> Printf.printf "Expected error: %s\n" e
203203+204204+(* Test: Bool array *)
205205+let test_bool_array file =
206206+ let module M = struct
207207+ type flags = { values : bool array }
208208+209209+ let flags_codec =
210210+ Jsont.Object.map ~kind:"Flags" (fun values -> { values })
211211+ |> Jsont.Object.mem "values" (Jsont.array Jsont.bool) ~enc:(fun f ->
212212+ f.values)
213213+ |> Jsont.Object.finish
214214+215215+ let show f =
216216+ Printf.sprintf "[%s]"
217217+ (String.concat "; " (Array.to_list (Array.map string_of_bool f.values)))
218218+ end in
219219+ let yaml = read_file file in
220220+ let json = read_file (file ^ ".json") in
221221+ let json_result = Jsont_bytesrw.decode_string M.flags_codec json in
222222+ let yaml_result = Yamlt.decode M.flags_codec (Bytes.Reader.of_string yaml) in
223223+224224+ show_result_both "bool_array"
225225+ (Result.map M.show json_result)
226226+ (Result.map M.show yaml_result)
227227+228228+(* Test: Array with nulls *)
229229+let test_nullable_array file =
230230+ let module M = struct
231231+ type nullable = { values : string option array }
232232+233233+ let nullable_codec =
234234+ Jsont.Object.map ~kind:"Nullable" (fun values -> { values })
235235+ |> Jsont.Object.mem "values"
236236+ (Jsont.array (Jsont.some Jsont.string))
237237+ ~enc:(fun n -> n.values)
238238+ |> Jsont.Object.finish
239239+240240+ let show_opt = function None -> "null" | Some s -> Printf.sprintf "%S" s
241241+242242+ let show n =
243243+ Printf.sprintf "[%s]"
244244+ (String.concat "; " (Array.to_list (Array.map show_opt n.values)))
245245+ end in
246246+ let yaml = read_file file in
247247+ let json = read_file (file ^ ".json") in
248248+ let json_result = Jsont_bytesrw.decode_string M.nullable_codec json in
249249+ let yaml_result = Yamlt.decode M.nullable_codec (Bytes.Reader.of_string yaml) in
250250+251251+ show_result_both "nullable_array"
252252+ (Result.map M.show json_result)
253253+ (Result.map M.show yaml_result)
254254+255255+(* Test: Encoding arrays to different formats *)
256256+let test_encode_arrays () =
257257+ let module M = struct
258258+ type data = { numbers : int array; strings : string array }
259259+260260+ let data_codec =
261261+ Jsont.Object.map ~kind:"Data" (fun numbers strings ->
262262+ { numbers; strings })
263263+ |> Jsont.Object.mem "numbers" (Jsont.array Jsont.int) ~enc:(fun d ->
264264+ d.numbers)
265265+ |> Jsont.Object.mem "strings" (Jsont.array Jsont.string) ~enc:(fun d ->
266266+ d.strings)
267267+ |> Jsont.Object.finish
268268+ end in
269269+ let data =
270270+ { M.numbers = [| 1; 2; 3; 4; 5 |]; strings = [| "hello"; "world" |] }
271271+ in
272272+273273+ (* Encode to JSON *)
274274+ (match Jsont_bytesrw.encode_string M.data_codec data with
275275+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
276276+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
277277+278278+ (* Encode to YAML Block *)
279279+ (let b = Buffer.create 256 in
280280+ let writer = Bytes.Writer.of_buffer b in
281281+ match Yamlt.encode ~format:Yamlt.Block M.data_codec data ~eod:true writer with
282282+ | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
283283+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
284284+285285+ (* Encode to YAML Flow *)
286286+ let b = Buffer.create 256 in
287287+ let writer = Bytes.Writer.of_buffer b in
288288+ match Yamlt.encode ~format:Yamlt.Flow M.data_codec data ~eod:true writer with
289289+ | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
290290+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
291291+292292+let () =
293293+ let usage = "Usage: test_arrays <command> [args...]" in
294294+295295+ if Array.length Sys.argv < 2 then begin
296296+ prerr_endline usage;
297297+ exit 1
298298+ end;
299299+300300+ match Sys.argv.(1) with
301301+ | "int" when Array.length Sys.argv = 3 -> test_int_array Sys.argv.(2)
302302+ | "string" when Array.length Sys.argv = 3 -> test_string_array Sys.argv.(2)
303303+ | "float" when Array.length Sys.argv = 3 -> test_float_array Sys.argv.(2)
304304+ | "empty" when Array.length Sys.argv = 3 -> test_empty_array Sys.argv.(2)
305305+ | "objects" when Array.length Sys.argv = 3 -> test_object_array Sys.argv.(2)
306306+ | "nested" when Array.length Sys.argv = 3 -> test_nested_arrays Sys.argv.(2)
307307+ | "type-mismatch" when Array.length Sys.argv = 3 ->
308308+ test_type_mismatch Sys.argv.(2)
309309+ | "bool" when Array.length Sys.argv = 3 -> test_bool_array Sys.argv.(2)
310310+ | "nullable" when Array.length Sys.argv = 3 ->
311311+ test_nullable_array Sys.argv.(2)
312312+ | "encode" when Array.length Sys.argv = 2 -> test_encode_arrays ()
313313+ | _ ->
314314+ prerr_endline usage;
315315+ prerr_endline "Commands:";
316316+ prerr_endline " int <file> - Test int array";
317317+ prerr_endline " string <file> - Test string array";
318318+ prerr_endline " float <file> - Test float array";
319319+ prerr_endline " empty <file> - Test empty array";
320320+ prerr_endline " objects <file> - Test array of objects";
321321+ prerr_endline " nested <file> - Test nested arrays";
322322+ prerr_endline " type-mismatch <file> - Test type mismatch error";
323323+ prerr_endline " bool <file> - Test bool array";
324324+ prerr_endline " nullable <file> - Test array with nulls";
325325+ prerr_endline " encode - Test encoding arrays";
326326+ exit 1
+206
vendor/opam/yamlt/tests/bin/test_complex.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Test complex nested types with Yamlt *)
77+88+open Bytesrw
99+1010+(* Helper to read file *)
1111+let read_file path =
1212+ let ic = open_in path in
1313+ let len = in_channel_length ic in
1414+ let s = really_input_string ic len in
1515+ close_in ic;
1616+ s
1717+1818+(* Helper to show results *)
1919+let show_result label = function
2020+ | Ok v -> Printf.printf "%s: %s\n" label v
2121+ | Error e -> Printf.printf "%s: ERROR: %s\n" label e
2222+2323+let show_result_both label json_result yaml_result =
2424+ Printf.printf "JSON: ";
2525+ show_result label json_result;
2626+ Printf.printf "YAML: ";
2727+ show_result label yaml_result
2828+2929+(* Test: Deeply nested objects *)
3030+let test_deep_nesting file =
3131+ let module M = struct
3232+ type level3 = { value : int }
3333+ type level2 = { data : level3 }
3434+ type level1 = { nested : level2 }
3535+ type root = { top : level1 }
3636+3737+ let level3_codec =
3838+ Jsont.Object.map ~kind:"Level3" (fun value -> { value })
3939+ |> Jsont.Object.mem "value" Jsont.int ~enc:(fun l -> l.value)
4040+ |> Jsont.Object.finish
4141+4242+ let level2_codec =
4343+ Jsont.Object.map ~kind:"Level2" (fun data -> { data })
4444+ |> Jsont.Object.mem "data" level3_codec ~enc:(fun l -> l.data)
4545+ |> Jsont.Object.finish
4646+4747+ let level1_codec =
4848+ Jsont.Object.map ~kind:"Level1" (fun nested -> { nested })
4949+ |> Jsont.Object.mem "nested" level2_codec ~enc:(fun l -> l.nested)
5050+ |> Jsont.Object.finish
5151+5252+ let root_codec =
5353+ Jsont.Object.map ~kind:"Root" (fun top -> { top })
5454+ |> Jsont.Object.mem "top" level1_codec ~enc:(fun r -> r.top)
5555+ |> Jsont.Object.finish
5656+5757+ let show r = Printf.sprintf "depth=4, value=%d" r.top.nested.data.value
5858+ end in
5959+ let yaml = read_file file in
6060+ let json = read_file (file ^ ".json") in
6161+ let json_result = Jsont_bytesrw.decode_string M.root_codec json in
6262+ let yaml_result = Yamlt.decode M.root_codec (Bytes.Reader.of_string yaml) in
6363+6464+ show_result_both "deep_nesting"
6565+ (Result.map M.show json_result)
6666+ (Result.map M.show yaml_result)
6767+6868+(* Test: Array of objects with nested arrays *)
6969+let test_mixed_structure file =
7070+ let module M = struct
7171+ type item = { id : int; tags : string array }
7272+ type collection = { name : string; items : item array }
7373+7474+ let item_codec =
7575+ Jsont.Object.map ~kind:"Item" (fun id tags -> { id; tags })
7676+ |> Jsont.Object.mem "id" Jsont.int ~enc:(fun i -> i.id)
7777+ |> Jsont.Object.mem "tags" (Jsont.array Jsont.string) ~enc:(fun i ->
7878+ i.tags)
7979+ |> Jsont.Object.finish
8080+8181+ let collection_codec =
8282+ Jsont.Object.map ~kind:"Collection" (fun name items -> { name; items })
8383+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun c -> c.name)
8484+ |> Jsont.Object.mem "items" (Jsont.array item_codec) ~enc:(fun c ->
8585+ c.items)
8686+ |> Jsont.Object.finish
8787+8888+ let show c =
8989+ let total_tags =
9090+ Stdlib.Array.fold_left
9191+ (fun acc item -> acc + Stdlib.Array.length item.tags)
9292+ 0 c.items
9393+ in
9494+ Printf.sprintf "name=%S, items=%d, total_tags=%d" c.name
9595+ (Stdlib.Array.length c.items)
9696+ total_tags
9797+ end in
9898+ let yaml = read_file file in
9999+ let json = read_file (file ^ ".json") in
100100+ let json_result = Jsont_bytesrw.decode_string M.collection_codec json in
101101+ let yaml_result = Yamlt.decode M.collection_codec (Bytes.Reader.of_string yaml) in
102102+103103+ show_result_both "mixed_structure"
104104+ (Result.map M.show json_result)
105105+ (Result.map M.show yaml_result)
106106+107107+(* Test: Complex optional and nullable combinations *)
108108+let test_complex_optional file =
109109+ let module M = struct
110110+ type config = {
111111+ host : string;
112112+ port : int option;
113113+ ssl : bool option;
114114+ cert_path : string option;
115115+ fallback_hosts : string array option;
116116+ }
117117+118118+ let config_codec =
119119+ Jsont.Object.map ~kind:"Config"
120120+ (fun host port ssl cert_path fallback_hosts ->
121121+ { host; port; ssl; cert_path; fallback_hosts })
122122+ |> Jsont.Object.mem "host" Jsont.string ~enc:(fun c -> c.host)
123123+ |> Jsont.Object.opt_mem "port" Jsont.int ~enc:(fun c -> c.port)
124124+ |> Jsont.Object.opt_mem "ssl" Jsont.bool ~enc:(fun c -> c.ssl)
125125+ |> Jsont.Object.opt_mem "cert_path" Jsont.string ~enc:(fun c ->
126126+ c.cert_path)
127127+ |> Jsont.Object.opt_mem "fallback_hosts" (Jsont.array Jsont.string)
128128+ ~enc:(fun c -> c.fallback_hosts)
129129+ |> Jsont.Object.finish
130130+131131+ let show c =
132132+ let port_str =
133133+ match c.port with None -> "None" | Some p -> string_of_int p
134134+ in
135135+ let ssl_str =
136136+ match c.ssl with None -> "None" | Some b -> string_of_bool b
137137+ in
138138+ let fallbacks =
139139+ match c.fallback_hosts with
140140+ | None -> 0
141141+ | Some arr -> Stdlib.Array.length arr
142142+ in
143143+ Printf.sprintf "host=%S, port=%s, ssl=%s, fallbacks=%d" c.host port_str
144144+ ssl_str fallbacks
145145+ end in
146146+ let yaml = read_file file in
147147+ let json = read_file (file ^ ".json") in
148148+ let json_result = Jsont_bytesrw.decode_string M.config_codec json in
149149+ let yaml_result = Yamlt.decode M.config_codec (Bytes.Reader.of_string yaml) in
150150+151151+ show_result_both "complex_optional"
152152+ (Result.map M.show json_result)
153153+ (Result.map M.show yaml_result)
154154+155155+(* Test: Heterogeneous data via any type *)
156156+let test_heterogeneous file =
157157+ let module M = struct
158158+ type data = { mixed : Jsont.json array }
159159+160160+ let data_codec =
161161+ Jsont.Object.map ~kind:"Data" (fun mixed -> { mixed })
162162+ |> Jsont.Object.mem "mixed"
163163+ (Jsont.array (Jsont.any ()))
164164+ ~enc:(fun d -> d.mixed)
165165+ |> Jsont.Object.finish
166166+167167+ let show d = Printf.sprintf "items=%d" (Stdlib.Array.length d.mixed)
168168+ end in
169169+ let yaml = read_file file in
170170+ let json = read_file (file ^ ".json") in
171171+ let json_result = Jsont_bytesrw.decode_string M.data_codec json in
172172+ let yaml_result = Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) in
173173+174174+ show_result_both "heterogeneous"
175175+ (Result.map M.show json_result)
176176+ (Result.map M.show yaml_result)
177177+178178+let () =
179179+ let usage = "Usage: test_complex <command> [args...]" in
180180+181181+ if Stdlib.Array.length Sys.argv < 2 then begin
182182+ prerr_endline usage;
183183+ exit 1
184184+ end;
185185+186186+ match Sys.argv.(1) with
187187+ | "deep-nesting" when Stdlib.Array.length Sys.argv = 3 ->
188188+ test_deep_nesting Sys.argv.(2)
189189+ | "mixed-structure" when Stdlib.Array.length Sys.argv = 3 ->
190190+ test_mixed_structure Sys.argv.(2)
191191+ | "complex-optional" when Stdlib.Array.length Sys.argv = 3 ->
192192+ test_complex_optional Sys.argv.(2)
193193+ | "heterogeneous" when Stdlib.Array.length Sys.argv = 3 ->
194194+ test_heterogeneous Sys.argv.(2)
195195+ | _ ->
196196+ prerr_endline usage;
197197+ prerr_endline "Commands:";
198198+ prerr_endline " deep-nesting <file> - Test deeply nested objects";
199199+ prerr_endline
200200+ " mixed-structure <file> - Test arrays of objects with nested arrays";
201201+ prerr_endline
202202+ " complex-optional <file> - Test complex optional/nullable \
203203+ combinations";
204204+ prerr_endline
205205+ " heterogeneous <file> - Test heterogeneous data via any type";
206206+ exit 1
+96
vendor/opam/yamlt/tests/bin/test_comprehensive.ml
···11+open Bytesrw
22+33+let () =
44+ (* Test 1: Null handling with option types *)
55+ Printf.printf "=== NULL HANDLING ===\n";
66+ let opt_codec =
77+ Jsont.Object.map ~kind:"Test" (fun v -> v)
88+ |> Jsont.Object.mem "value" (Jsont.option Jsont.string) ~enc:(fun v -> v)
99+ |> Jsont.Object.finish
1010+ in
1111+1212+ (match Yamlt.decode opt_codec (Bytes.Reader.of_string "value: null") with
1313+ | Ok None -> Printf.printf "✓ Plain 'null' with option codec: None\n"
1414+ | _ -> Printf.printf "✗ FAIL\n");
1515+1616+ (match Yamlt.decode opt_codec (Bytes.Reader.of_string "value: hello") with
1717+ | Ok (Some "hello") ->
1818+ Printf.printf "✓ Plain 'hello' with option codec: Some(hello)\n"
1919+ | _ -> Printf.printf "✗ FAIL\n");
2020+2121+ let string_codec =
2222+ Jsont.Object.map ~kind:"Test" (fun v -> v)
2323+ |> Jsont.Object.mem "value" Jsont.string ~enc:(fun v -> v)
2424+ |> Jsont.Object.finish
2525+ in
2626+2727+ (match Yamlt.decode string_codec (Bytes.Reader.of_string "value: null") with
2828+ | Error _ ->
2929+ Printf.printf "✓ Plain 'null' with string codec: ERROR (expected)\n"
3030+ | _ -> Printf.printf "✗ FAIL\n");
3131+3232+ (match Yamlt.decode string_codec (Bytes.Reader.of_string "value: \"\"") with
3333+ | Ok "" -> Printf.printf "✓ Quoted empty string: \"\"\n"
3434+ | _ -> Printf.printf "✗ FAIL\n");
3535+3636+ (match Yamlt.decode string_codec (Bytes.Reader.of_string "value: \"null\"") with
3737+ | Ok "null" -> Printf.printf "✓ Quoted 'null': \"null\"\n"
3838+ | _ -> Printf.printf "✗ FAIL\n");
3939+4040+ (* Test 2: Number formats *)
4141+ Printf.printf "\n=== NUMBER FORMATS ===\n";
4242+ let num_codec =
4343+ Jsont.Object.map ~kind:"Test" (fun v -> v)
4444+ |> Jsont.Object.mem "value" Jsont.number ~enc:(fun v -> v)
4545+ |> Jsont.Object.finish
4646+ in
4747+4848+ (match Yamlt.decode num_codec (Bytes.Reader.of_string "value: 0xFF") with
4949+ | Ok 255. -> Printf.printf "✓ Hex 0xFF: 255\n"
5050+ | _ -> Printf.printf "✗ FAIL\n");
5151+5252+ (match Yamlt.decode num_codec (Bytes.Reader.of_string "value: 0o77") with
5353+ | Ok 63. -> Printf.printf "✓ Octal 0o77: 63\n"
5454+ | _ -> Printf.printf "✗ FAIL\n");
5555+5656+ (match Yamlt.decode num_codec (Bytes.Reader.of_string "value: 0b1010") with
5757+ | Ok 10. -> Printf.printf "✓ Binary 0b1010: 10\n"
5858+ | _ -> Printf.printf "✗ FAIL\n");
5959+6060+ (* Test 3: Optional arrays *)
6161+ Printf.printf "\n=== OPTIONAL ARRAYS ===\n";
6262+ let opt_array_codec =
6363+ Jsont.Object.map ~kind:"Test" (fun v -> v)
6464+ |> Jsont.Object.opt_mem "values" (Jsont.array Jsont.string) ~enc:(fun v ->
6565+ v)
6666+ |> Jsont.Object.finish
6767+ in
6868+6969+ (match Yamlt.decode opt_array_codec (Bytes.Reader.of_string "values: [a, b, c]") with
7070+ | Ok (Some arr) when Array.length arr = 3 ->
7171+ Printf.printf "✓ Optional array [a, b, c]: Some([3 items])\n"
7272+ | _ -> Printf.printf "✗ FAIL\n");
7373+7474+ (match Yamlt.decode opt_array_codec (Bytes.Reader.of_string "{}") with
7575+ | Ok None -> Printf.printf "✓ Missing optional array: None\n"
7676+ | _ -> Printf.printf "✗ FAIL\n");
7777+7878+ (* Test 4: Flow encoding *)
7979+ Printf.printf "\n=== FLOW ENCODING ===\n";
8080+ let encode_codec =
8181+ Jsont.Object.map ~kind:"Test" (fun name values -> (name, values))
8282+ |> Jsont.Object.mem "name" Jsont.string ~enc:fst
8383+ |> Jsont.Object.mem "values" (Jsont.array Jsont.number) ~enc:snd
8484+ |> Jsont.Object.finish
8585+ in
8686+8787+ let b = Buffer.create 256 in
8888+ let writer = Bytes.Writer.of_buffer b in
8989+ match
9090+ Yamlt.encode ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |]) ~eod:true writer
9191+ with
9292+ | Ok ()
9393+ when String.equal (Buffer.contents b) "{name: test, values: [1.0, 2.0, 3.0]}\n" ->
9494+ Printf.printf "✓ Flow encoding with comma separator\n"
9595+ | Ok () -> Printf.printf "✗ FAIL: %S\n" (Buffer.contents b)
9696+ | Error e -> Printf.printf "✗ ERROR: %s\n" e
+214
vendor/opam/yamlt/tests/bin/test_edge.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Test edge cases with Yamlt *)
77+88+open Bytesrw
99+1010+(* Helper to read file *)
1111+let read_file path =
1212+ let ic = open_in path in
1313+ let len = in_channel_length ic in
1414+ let s = really_input_string ic len in
1515+ close_in ic;
1616+ s
1717+1818+(* Helper to show results *)
1919+let show_result label = function
2020+ | Ok v -> Printf.printf "%s: %s\n" label v
2121+ | Error e -> Printf.printf "%s: ERROR: %s\n" label e
2222+2323+let show_result_both label json_result yaml_result =
2424+ Printf.printf "JSON: ";
2525+ show_result label json_result;
2626+ Printf.printf "YAML: ";
2727+ show_result label yaml_result
2828+2929+(* Test: Very large numbers *)
3030+let test_large_numbers file =
3131+ let module M = struct
3232+ type numbers = {
3333+ large_int : float;
3434+ large_float : float;
3535+ small_float : float;
3636+ }
3737+3838+ let numbers_codec =
3939+ Jsont.Object.map ~kind:"Numbers" (fun large_int large_float small_float ->
4040+ { large_int; large_float; small_float })
4141+ |> Jsont.Object.mem "large_int" Jsont.number ~enc:(fun n -> n.large_int)
4242+ |> Jsont.Object.mem "large_float" Jsont.number ~enc:(fun n ->
4343+ n.large_float)
4444+ |> Jsont.Object.mem "small_float" Jsont.number ~enc:(fun n ->
4545+ n.small_float)
4646+ |> Jsont.Object.finish
4747+4848+ let show n =
4949+ Printf.sprintf "large_int=%.0f, large_float=%e, small_float=%e"
5050+ n.large_int n.large_float n.small_float
5151+ end in
5252+ let yaml = read_file file in
5353+ let json = read_file (file ^ ".json") in
5454+ let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
5555+ let yaml_result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in
5656+5757+ show_result_both "large_numbers"
5858+ (Result.map M.show json_result)
5959+ (Result.map M.show yaml_result)
6060+6161+(* Test: Special characters in strings *)
6262+let test_special_chars file =
6363+ let module M = struct
6464+ type text = { content : string }
6565+6666+ let text_codec =
6767+ Jsont.Object.map ~kind:"Text" (fun content -> { content })
6868+ |> Jsont.Object.mem "content" Jsont.string ~enc:(fun t -> t.content)
6969+ |> Jsont.Object.finish
7070+7171+ let show t =
7272+ Printf.sprintf "length=%d, contains_newline=%b, contains_tab=%b"
7373+ (String.length t.content)
7474+ (String.contains t.content '\n')
7575+ (String.contains t.content '\t')
7676+ end in
7777+ let yaml = read_file file in
7878+ let json = read_file (file ^ ".json") in
7979+ let json_result = Jsont_bytesrw.decode_string M.text_codec json in
8080+ let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in
8181+8282+ show_result_both "special_chars"
8383+ (Result.map M.show json_result)
8484+ (Result.map M.show yaml_result)
8585+8686+(* Test: Unicode strings *)
8787+let test_unicode file =
8888+ let module M = struct
8989+ type text = { emoji : string; chinese : string; rtl : string }
9090+9191+ let text_codec =
9292+ Jsont.Object.map ~kind:"Text" (fun emoji chinese rtl ->
9393+ { emoji; chinese; rtl })
9494+ |> Jsont.Object.mem "emoji" Jsont.string ~enc:(fun t -> t.emoji)
9595+ |> Jsont.Object.mem "chinese" Jsont.string ~enc:(fun t -> t.chinese)
9696+ |> Jsont.Object.mem "rtl" Jsont.string ~enc:(fun t -> t.rtl)
9797+ |> Jsont.Object.finish
9898+9999+ let show t =
100100+ Printf.sprintf "emoji=%S, chinese=%S, rtl=%S" t.emoji t.chinese t.rtl
101101+ end in
102102+ let yaml = read_file file in
103103+ let json = read_file (file ^ ".json") in
104104+ let json_result = Jsont_bytesrw.decode_string M.text_codec json in
105105+ let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in
106106+107107+ show_result_both "unicode"
108108+ (Result.map M.show json_result)
109109+ (Result.map M.show yaml_result)
110110+111111+(* Test: Empty collections *)
112112+let test_empty_collections file =
113113+ let module M = struct
114114+ type data = { empty_array : int array; empty_object_array : unit array }
115115+116116+ let data_codec =
117117+ Jsont.Object.map ~kind:"Data" (fun empty_array empty_object_array ->
118118+ { empty_array; empty_object_array })
119119+ |> Jsont.Object.mem "empty_array" (Jsont.array Jsont.int) ~enc:(fun d ->
120120+ d.empty_array)
121121+ |> Jsont.Object.mem "empty_object_array"
122122+ (Jsont.array (Jsont.null ()))
123123+ ~enc:(fun d -> d.empty_object_array)
124124+ |> Jsont.Object.finish
125125+126126+ let show d =
127127+ Printf.sprintf "empty_array_len=%d, empty_object_array_len=%d"
128128+ (Stdlib.Array.length d.empty_array)
129129+ (Stdlib.Array.length d.empty_object_array)
130130+ end in
131131+ let yaml = read_file file in
132132+ let json = read_file (file ^ ".json") in
133133+ let json_result = Jsont_bytesrw.decode_string M.data_codec json in
134134+ let yaml_result = Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) in
135135+136136+ show_result_both "empty_collections"
137137+ (Result.map M.show json_result)
138138+ (Result.map M.show yaml_result)
139139+140140+(* Test: Key names with special characters *)
141141+let test_special_keys file =
142142+ let module M = struct
143143+ let show j =
144144+ match Jsont.Json.decode (Jsont.any ()) j with
145145+ | Ok (Jsont.Object _) -> "valid_object"
146146+ | Ok _ -> "not_object"
147147+ | Error _ -> "decode_error"
148148+ end in
149149+ let yaml = read_file file in
150150+ let json = read_file (file ^ ".json") in
151151+ let json_result = Jsont_bytesrw.decode_string (Jsont.any ()) json in
152152+ let yaml_result = Yamlt.decode (Jsont.any ()) (Bytes.Reader.of_string yaml) in
153153+154154+ show_result_both "special_keys"
155155+ (Result.map M.show json_result)
156156+ (Result.map M.show yaml_result)
157157+158158+(* Test: Single-element arrays *)
159159+let test_single_element file =
160160+ let module M = struct
161161+ type data = { single : int array }
162162+163163+ let data_codec =
164164+ Jsont.Object.map ~kind:"Data" (fun single -> { single })
165165+ |> Jsont.Object.mem "single" (Jsont.array Jsont.int) ~enc:(fun d ->
166166+ d.single)
167167+ |> Jsont.Object.finish
168168+169169+ let show d =
170170+ Printf.sprintf "length=%d, value=%d"
171171+ (Stdlib.Array.length d.single)
172172+ (if Stdlib.Array.length d.single > 0 then d.single.(0) else 0)
173173+ end in
174174+ let yaml = read_file file in
175175+ let json = read_file (file ^ ".json") in
176176+ let json_result = Jsont_bytesrw.decode_string M.data_codec json in
177177+ let yaml_result = Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml) in
178178+179179+ show_result_both "single_element"
180180+ (Result.map M.show json_result)
181181+ (Result.map M.show yaml_result)
182182+183183+let () =
184184+ let usage = "Usage: test_edge <command> [args...]" in
185185+186186+ if Stdlib.Array.length Sys.argv < 2 then begin
187187+ prerr_endline usage;
188188+ exit 1
189189+ end;
190190+191191+ match Sys.argv.(1) with
192192+ | "large-numbers" when Stdlib.Array.length Sys.argv = 3 ->
193193+ test_large_numbers Sys.argv.(2)
194194+ | "special-chars" when Stdlib.Array.length Sys.argv = 3 ->
195195+ test_special_chars Sys.argv.(2)
196196+ | "unicode" when Stdlib.Array.length Sys.argv = 3 -> test_unicode Sys.argv.(2)
197197+ | "empty-collections" when Stdlib.Array.length Sys.argv = 3 ->
198198+ test_empty_collections Sys.argv.(2)
199199+ | "special-keys" when Stdlib.Array.length Sys.argv = 3 ->
200200+ test_special_keys Sys.argv.(2)
201201+ | "single-element" when Stdlib.Array.length Sys.argv = 3 ->
202202+ test_single_element Sys.argv.(2)
203203+ | _ ->
204204+ prerr_endline usage;
205205+ prerr_endline "Commands:";
206206+ prerr_endline " large-numbers <file> - Test very large numbers";
207207+ prerr_endline
208208+ " special-chars <file> - Test special characters in strings";
209209+ prerr_endline " unicode <file> - Test Unicode strings";
210210+ prerr_endline " empty-collections <file> - Test empty collections";
211211+ prerr_endline
212212+ " special-keys <file> - Test special characters in keys";
213213+ prerr_endline " single-element <file> - Test single-element arrays";
214214+ exit 1
+21
vendor/opam/yamlt/tests/bin/test_flow_newline.ml
···11+open Bytesrw
22+33+let () =
44+ let encode_codec =
55+ Jsont.Object.map ~kind:"Test" (fun name values -> (name, values))
66+ |> Jsont.Object.mem "name" Jsont.string ~enc:fst
77+ |> Jsont.Object.mem "values" (Jsont.array Jsont.number) ~enc:snd
88+ |> Jsont.Object.finish
99+ in
1010+1111+ let b = Buffer.create 256 in
1212+ let writer = Bytes.Writer.of_buffer b in
1313+ match
1414+ Yamlt.encode ~format:Flow encode_codec ("test", [| 1.; 2.; 3. |]) ~eod:true writer
1515+ with
1616+ | Ok () ->
1717+ let yaml_flow = Buffer.contents b in
1818+ Printf.printf "Length: %d\n" (String.length yaml_flow);
1919+ Printf.printf "Repr: %S\n" yaml_flow;
2020+ Printf.printf "Output:\n%s" yaml_flow
2121+ | Error e -> Printf.printf "Error: %s\n" e
+248
vendor/opam/yamlt/tests/bin/test_formats.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Test format-specific features with Yamlt *)
77+88+open Bytesrw
99+1010+(* Helper to read file *)
1111+let read_file path =
1212+ let ic = open_in path in
1313+ let len = in_channel_length ic in
1414+ let s = really_input_string ic len in
1515+ close_in ic;
1616+ s
1717+1818+(* Helper to show results *)
1919+let show_result label = function
2020+ | Ok v -> Printf.printf "%s: %s\n" label v
2121+ | Error e -> Printf.printf "%s: ERROR: %s\n" label e
2222+2323+let show_result_both label json_result yaml_result =
2424+ Printf.printf "JSON: ";
2525+ show_result label json_result;
2626+ Printf.printf "YAML: ";
2727+ show_result label yaml_result
2828+2929+(* Test: Multi-line strings - literal style *)
3030+let test_literal_string file =
3131+ let module M = struct
3232+ type text = { content : string }
3333+3434+ let text_codec =
3535+ Jsont.Object.map ~kind:"Text" (fun content -> { content })
3636+ |> Jsont.Object.mem "content" Jsont.string ~enc:(fun t -> t.content)
3737+ |> Jsont.Object.finish
3838+3939+ let show t =
4040+ Printf.sprintf "lines=%d, length=%d"
4141+ (List.length (String.split_on_char '\n' t.content))
4242+ (String.length t.content)
4343+ end in
4444+ let yaml = read_file file in
4545+ let json = read_file (file ^ ".json") in
4646+ let json_result = Jsont_bytesrw.decode_string M.text_codec json in
4747+ let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in
4848+4949+ show_result_both "literal_string"
5050+ (Result.map M.show json_result)
5151+ (Result.map M.show yaml_result)
5252+5353+(* Test: Multi-line strings - folded style *)
5454+let test_folded_string file =
5555+ let module M = struct
5656+ type text = { content : string }
5757+5858+ let text_codec =
5959+ Jsont.Object.map ~kind:"Text" (fun content -> { content })
6060+ |> Jsont.Object.mem "content" Jsont.string ~enc:(fun t -> t.content)
6161+ |> Jsont.Object.finish
6262+6363+ let show t =
6464+ Printf.sprintf "length=%d, newlines=%d" (String.length t.content)
6565+ (List.length
6666+ (List.filter
6767+ (fun c -> c = '\n')
6868+ (List.init (String.length t.content) (String.get t.content))))
6969+ end in
7070+ let yaml = read_file file in
7171+ let json = read_file (file ^ ".json") in
7272+ let json_result = Jsont_bytesrw.decode_string M.text_codec json in
7373+ let yaml_result = Yamlt.decode M.text_codec (Bytes.Reader.of_string yaml) in
7474+7575+ show_result_both "folded_string"
7676+ (Result.map M.show json_result)
7777+ (Result.map M.show yaml_result)
7878+7979+(* Test: Number formats - hex, octal, binary *)
8080+let test_number_formats file =
8181+ let module M = struct
8282+ type numbers = { hex : float; octal : float; binary : float }
8383+8484+ let numbers_codec =
8585+ Jsont.Object.map ~kind:"Numbers" (fun hex octal binary ->
8686+ { hex; octal; binary })
8787+ |> Jsont.Object.mem "hex" Jsont.number ~enc:(fun n -> n.hex)
8888+ |> Jsont.Object.mem "octal" Jsont.number ~enc:(fun n -> n.octal)
8989+ |> Jsont.Object.mem "binary" Jsont.number ~enc:(fun n -> n.binary)
9090+ |> Jsont.Object.finish
9191+9292+ let show n =
9393+ Printf.sprintf "hex=%.0f, octal=%.0f, binary=%.0f" n.hex n.octal n.binary
9494+ end in
9595+ let yaml = read_file file in
9696+ let json = read_file (file ^ ".json") in
9797+ let json_result = Jsont_bytesrw.decode_string M.numbers_codec json in
9898+ let yaml_result = Yamlt.decode M.numbers_codec (Bytes.Reader.of_string yaml) in
9999+100100+ show_result_both "number_formats"
101101+ (Result.map M.show json_result)
102102+ (Result.map M.show yaml_result)
103103+104104+(* Test: Block vs Flow style encoding *)
105105+let test_encode_styles () =
106106+ let module M = struct
107107+ type data = { name : string; values : int array; nested : nested_data }
108108+ and nested_data = { enabled : bool; count : int }
109109+110110+ let nested_codec =
111111+ Jsont.Object.map ~kind:"Nested" (fun enabled count -> { enabled; count })
112112+ |> Jsont.Object.mem "enabled" Jsont.bool ~enc:(fun n -> n.enabled)
113113+ |> Jsont.Object.mem "count" Jsont.int ~enc:(fun n -> n.count)
114114+ |> Jsont.Object.finish
115115+116116+ let data_codec =
117117+ Jsont.Object.map ~kind:"Data" (fun name values nested ->
118118+ { name; values; nested })
119119+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun d -> d.name)
120120+ |> Jsont.Object.mem "values" (Jsont.array Jsont.int) ~enc:(fun d ->
121121+ d.values)
122122+ |> Jsont.Object.mem "nested" nested_codec ~enc:(fun d -> d.nested)
123123+ |> Jsont.Object.finish
124124+ end in
125125+ let data =
126126+ {
127127+ M.name = "test";
128128+ values = [| 1; 2; 3 |];
129129+ nested = { enabled = true; count = 5 };
130130+ }
131131+ in
132132+133133+ (* Encode to YAML Block style *)
134134+ (let b = Buffer.create 256 in
135135+ let writer = Bytes.Writer.of_buffer b in
136136+ match Yamlt.encode ~format:Yamlt.Block M.data_codec data ~eod:true writer with
137137+ | Ok () -> Printf.printf "YAML Block:\n%s\n" (Buffer.contents b)
138138+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
139139+140140+ (* Encode to YAML Flow style *)
141141+ let b = Buffer.create 256 in
142142+ let writer = Bytes.Writer.of_buffer b in
143143+ match Yamlt.encode ~format:Yamlt.Flow M.data_codec data ~eod:true writer with
144144+ | Ok () -> Printf.printf "YAML Flow:\n%s\n" (Buffer.contents b)
145145+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
146146+147147+(* Test: Comments in YAML (should be ignored) *)
148148+let test_comments file =
149149+ let module M = struct
150150+ type config = { host : string; port : int; debug : bool }
151151+152152+ let config_codec =
153153+ Jsont.Object.map ~kind:"Config" (fun host port debug ->
154154+ { host; port; debug })
155155+ |> Jsont.Object.mem "host" Jsont.string ~enc:(fun c -> c.host)
156156+ |> Jsont.Object.mem "port" Jsont.int ~enc:(fun c -> c.port)
157157+ |> Jsont.Object.mem "debug" Jsont.bool ~enc:(fun c -> c.debug)
158158+ |> Jsont.Object.finish
159159+160160+ let show c =
161161+ Printf.sprintf "host=%S, port=%d, debug=%b" c.host c.port c.debug
162162+ end in
163163+ let yaml = read_file file in
164164+ let yaml_result = Yamlt.decode M.config_codec (Bytes.Reader.of_string yaml) in
165165+166166+ match yaml_result with
167167+ | Ok v -> Printf.printf "YAML (with comments): %s\n" (M.show v)
168168+ | Error e -> Printf.printf "YAML ERROR: %s\n" e
169169+170170+(* Test: Empty documents and null documents *)
171171+let test_empty_document file =
172172+ let module M = struct
173173+ type wrapper = { value : string option }
174174+175175+ let wrapper_codec =
176176+ Jsont.Object.map ~kind:"Wrapper" (fun value -> { value })
177177+ |> Jsont.Object.mem "value" (Jsont.some Jsont.string) ~enc:(fun w ->
178178+ w.value)
179179+ |> Jsont.Object.finish
180180+181181+ let show w =
182182+ match w.value with
183183+ | None -> "value=None"
184184+ | Some s -> Printf.sprintf "value=Some(%S)" s
185185+ end in
186186+ let yaml = read_file file in
187187+ let json = read_file (file ^ ".json") in
188188+ let json_result = Jsont_bytesrw.decode_string M.wrapper_codec json in
189189+ let yaml_result = Yamlt.decode M.wrapper_codec (Bytes.Reader.of_string yaml) in
190190+191191+ show_result_both "empty_document"
192192+ (Result.map M.show json_result)
193193+ (Result.map M.show yaml_result)
194194+195195+(* Test: Explicit typing with tags (if supported) *)
196196+let test_explicit_tags file =
197197+ let module M = struct
198198+ type value_holder = { data : string }
199199+200200+ let value_codec =
201201+ Jsont.Object.map ~kind:"ValueHolder" (fun data -> { data })
202202+ |> Jsont.Object.mem "data" Jsont.string ~enc:(fun v -> v.data)
203203+ |> Jsont.Object.finish
204204+205205+ let show v = Printf.sprintf "data=%S" v.data
206206+ end in
207207+ let yaml = read_file file in
208208+ let yaml_result = Yamlt.decode M.value_codec (Bytes.Reader.of_string yaml) in
209209+210210+ match yaml_result with
211211+ | Ok v -> Printf.printf "YAML (with tags): %s\n" (M.show v)
212212+ | Error e -> Printf.printf "YAML ERROR: %s\n" e
213213+214214+let () =
215215+ let usage = "Usage: test_formats <command> [args...]" in
216216+217217+ if Stdlib.Array.length Sys.argv < 2 then begin
218218+ prerr_endline usage;
219219+ exit 1
220220+ end;
221221+222222+ match Sys.argv.(1) with
223223+ | "literal" when Stdlib.Array.length Sys.argv = 3 ->
224224+ test_literal_string Sys.argv.(2)
225225+ | "folded" when Stdlib.Array.length Sys.argv = 3 ->
226226+ test_folded_string Sys.argv.(2)
227227+ | "number-formats" when Stdlib.Array.length Sys.argv = 3 ->
228228+ test_number_formats Sys.argv.(2)
229229+ | "encode-styles" when Stdlib.Array.length Sys.argv = 2 ->
230230+ test_encode_styles ()
231231+ | "comments" when Stdlib.Array.length Sys.argv = 3 ->
232232+ test_comments Sys.argv.(2)
233233+ | "empty-doc" when Stdlib.Array.length Sys.argv = 3 ->
234234+ test_empty_document Sys.argv.(2)
235235+ | "explicit-tags" when Stdlib.Array.length Sys.argv = 3 ->
236236+ test_explicit_tags Sys.argv.(2)
237237+ | _ ->
238238+ prerr_endline usage;
239239+ prerr_endline "Commands:";
240240+ prerr_endline " literal <file> - Test literal multi-line strings";
241241+ prerr_endline " folded <file> - Test folded multi-line strings";
242242+ prerr_endline
243243+ " number-formats <file> - Test hex/octal/binary number formats";
244244+ prerr_endline " encode-styles - Test block vs flow encoding";
245245+ prerr_endline " comments <file> - Test YAML with comments";
246246+ prerr_endline " empty-doc <file> - Test empty documents";
247247+ prerr_endline " explicit-tags <file> - Test explicit type tags";
248248+ exit 1
+270
vendor/opam/yamlt/tests/bin/test_locations.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Test location and layout preservation options with Yamlt codec *)
77+88+(* Helper to read file *)
99+open Bytesrw
1010+1111+let read_file path =
1212+ let ic = open_in path in
1313+ let len = in_channel_length ic in
1414+ let s = really_input_string ic len in
1515+ close_in ic;
1616+ s
1717+1818+(* Helper to show results *)
1919+let show_result label = function
2020+ | Ok _ -> Printf.printf "%s: OK\n" label
2121+ | Error e -> Printf.printf "%s:\n%s\n" label e
2222+2323+(* Test: Compare error messages with and without locs *)
2424+let test_error_precision file =
2525+ let yaml = read_file file in
2626+2727+ (* Define a codec that will fail on type mismatch *)
2828+ let codec =
2929+ Jsont.Object.map ~kind:"Person" (fun name age -> (name, age))
3030+ |> Jsont.Object.mem "name" Jsont.string ~enc:fst
3131+ |> Jsont.Object.mem "age" Jsont.int ~enc:snd
3232+ |> Jsont.Object.finish
3333+ in
3434+3535+ Printf.printf "=== Without locs (default) ===\n";
3636+ let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in
3737+ show_result "Error message" result_no_locs;
3838+3939+ Printf.printf "\n=== With locs=true ===\n";
4040+ let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in
4141+ show_result "Error message" result_with_locs
4242+4343+(* Test: Show error locations for nested structures *)
4444+let test_nested_error file =
4545+ let yaml = read_file file in
4646+4747+ (* Nested object codec *)
4848+ let address_codec =
4949+ Jsont.Object.map ~kind:"Address" (fun street city zip ->
5050+ (street, city, zip))
5151+ |> Jsont.Object.mem "street" Jsont.string ~enc:(fun (s, _, _) -> s)
5252+ |> Jsont.Object.mem "city" Jsont.string ~enc:(fun (_, c, _) -> c)
5353+ |> Jsont.Object.mem "zip" Jsont.int ~enc:(fun (_, _, z) -> z)
5454+ |> Jsont.Object.finish
5555+ in
5656+5757+ let codec =
5858+ Jsont.Object.map ~kind:"Employee" (fun name address -> (name, address))
5959+ |> Jsont.Object.mem "name" Jsont.string ~enc:fst
6060+ |> Jsont.Object.mem "address" address_codec ~enc:snd
6161+ |> Jsont.Object.finish
6262+ in
6363+6464+ Printf.printf "=== Without locs (default) ===\n";
6565+ let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in
6666+ show_result "Nested error" result_no_locs;
6767+6868+ Printf.printf "\n=== With locs=true ===\n";
6969+ let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in
7070+ show_result "Nested error" result_with_locs
7171+7272+(* Test: Array element error locations *)
7373+let test_array_error file =
7474+ let yaml = read_file file in
7575+7676+ (* Array codec *)
7777+ let codec =
7878+ Jsont.Object.map ~kind:"Numbers" (fun nums -> nums)
7979+ |> Jsont.Object.mem "values" (Jsont.array Jsont.int) ~enc:(fun n -> n)
8080+ |> Jsont.Object.finish
8181+ in
8282+8383+ Printf.printf "=== Without locs (default) ===\n";
8484+ let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in
8585+ show_result "Array error" result_no_locs;
8686+8787+ Printf.printf "\n=== With locs=true ===\n";
8888+ let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in
8989+ show_result "Array error" result_with_locs
9090+9191+(* Test: Layout preservation - check if we can decode with layout info *)
9292+let test_layout_preservation file =
9393+ let yaml = read_file file in
9494+9595+ let codec =
9696+ Jsont.Object.map ~kind:"Config" (fun host port -> (host, port))
9797+ |> Jsont.Object.mem "host" Jsont.string ~enc:fst
9898+ |> Jsont.Object.mem "port" Jsont.int ~enc:snd
9999+ |> Jsont.Object.finish
100100+ in
101101+102102+ Printf.printf "=== Without layout (default) ===\n";
103103+ (match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:false with
104104+ | Ok (host, port) ->
105105+ Printf.printf "Decoded: host=%s, port=%d\n" host port;
106106+ Printf.printf "Meta preserved: no\n"
107107+ | Error e -> Printf.printf "Error: %s\n" e);
108108+109109+ Printf.printf "\n=== With layout=true ===\n";
110110+ match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:true with
111111+ | Ok (host, port) ->
112112+ Printf.printf "Decoded: host=%s, port=%d\n" host port;
113113+ Printf.printf
114114+ "Meta preserved: yes (style info available for round-tripping)\n"
115115+ | Error e -> Printf.printf "Error: %s\n" e
116116+117117+(* Test: Round-trip with layout preservation *)
118118+let test_roundtrip_layout file =
119119+ let yaml = read_file file in
120120+121121+ let codec =
122122+ Jsont.Object.map ~kind:"Data" (fun items -> items)
123123+ |> Jsont.Object.mem "items" (Jsont.array Jsont.string) ~enc:(fun x -> x)
124124+ |> Jsont.Object.finish
125125+ in
126126+127127+ Printf.printf "=== Original YAML ===\n";
128128+ Printf.printf "%s\n" (String.trim yaml);
129129+130130+ Printf.printf "\n=== Decode without layout, re-encode ===\n";
131131+ (match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:false with
132132+ | Ok items -> (
133133+ let b = Buffer.create 256 in
134134+ let writer = Bytes.Writer.of_buffer b in
135135+ match Yamlt.encode ~format:Yamlt.Block codec items ~eod:true writer with
136136+ | Ok () -> Printf.printf "%s" (Buffer.contents b)
137137+ | Error e -> Printf.printf "Encode error: %s\n" e)
138138+ | Error e -> Printf.printf "Decode error: %s\n" e);
139139+140140+ Printf.printf
141141+ "\n=== Decode with layout=true, re-encode with Layout format ===\n";
142142+ match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~layout:true with
143143+ | Ok items -> (
144144+ let b = Buffer.create 256 in
145145+ let writer = Bytes.Writer.of_buffer b in
146146+ match Yamlt.encode ~format:Yamlt.Layout codec items ~eod:true writer with
147147+ | Ok () -> Printf.printf "%s" (Buffer.contents b)
148148+ | Error e -> Printf.printf "Encode error: %s\n" e)
149149+ | Error e -> Printf.printf "Decode error: %s\n" e
150150+151151+(* Test: File path in error messages *)
152152+let test_file_path () =
153153+ let yaml = "name: Alice\nage: not-a-number\n" in
154154+155155+ let codec =
156156+ Jsont.Object.map ~kind:"Person" (fun name age -> (name, age))
157157+ |> Jsont.Object.mem "name" Jsont.string ~enc:fst
158158+ |> Jsont.Object.mem "age" Jsont.int ~enc:snd
159159+ |> Jsont.Object.finish
160160+ in
161161+162162+ Printf.printf "=== Without file path ===\n";
163163+ let result1 = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in
164164+ show_result "Error" result1;
165165+166166+ Printf.printf "\n=== With file path ===\n";
167167+ let result2 = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true ~file:"test.yml" in
168168+ show_result "Error" result2
169169+170170+(* Test: Missing field error with locs *)
171171+let test_missing_field file =
172172+ let yaml = read_file file in
173173+174174+ let codec =
175175+ Jsont.Object.map ~kind:"Complete" (fun a b c -> (a, b, c))
176176+ |> Jsont.Object.mem "field_a" Jsont.string ~enc:(fun (a, _, _) -> a)
177177+ |> Jsont.Object.mem "field_b" Jsont.int ~enc:(fun (_, b, _) -> b)
178178+ |> Jsont.Object.mem "field_c" Jsont.bool ~enc:(fun (_, _, c) -> c)
179179+ |> Jsont.Object.finish
180180+ in
181181+182182+ Printf.printf "=== Without locs ===\n";
183183+ let result_no_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false in
184184+ show_result "Missing field" result_no_locs;
185185+186186+ Printf.printf "\n=== With locs=true ===\n";
187187+ let result_with_locs = Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true in
188188+ show_result "Missing field" result_with_locs
189189+190190+(* Test: Both locs and layout together *)
191191+let test_combined_options file =
192192+ let yaml = read_file file in
193193+194194+ let codec =
195195+ Jsont.Object.map ~kind:"Settings" (fun timeout retries ->
196196+ (timeout, retries))
197197+ |> Jsont.Object.mem "timeout" Jsont.int ~enc:fst
198198+ |> Jsont.Object.mem "retries" Jsont.int ~enc:snd
199199+ |> Jsont.Object.finish
200200+ in
201201+202202+ Printf.printf "=== locs=false, layout=false (defaults) ===\n";
203203+ (match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false ~layout:false with
204204+ | Ok (timeout, retries) ->
205205+ Printf.printf "OK: timeout=%d, retries=%d\n" timeout retries
206206+ | Error e -> Printf.printf "Error: %s\n" e);
207207+208208+ Printf.printf "\n=== locs=true, layout=false ===\n";
209209+ (match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true ~layout:false with
210210+ | Ok (timeout, retries) ->
211211+ Printf.printf "OK: timeout=%d, retries=%d (with precise locations)\n"
212212+ timeout retries
213213+ | Error e -> Printf.printf "Error: %s\n" e);
214214+215215+ Printf.printf "\n=== locs=false, layout=true ===\n";
216216+ (match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:false ~layout:true with
217217+ | Ok (timeout, retries) ->
218218+ Printf.printf "OK: timeout=%d, retries=%d (with layout metadata)\n"
219219+ timeout retries
220220+ | Error e -> Printf.printf "Error: %s\n" e);
221221+222222+ Printf.printf "\n=== locs=true, layout=true (both enabled) ===\n";
223223+ match Yamlt.decode codec (Bytes.Reader.of_string yaml) ~locs:true ~layout:true with
224224+ | Ok (timeout, retries) ->
225225+ Printf.printf "OK: timeout=%d, retries=%d (with locations and layout)\n"
226226+ timeout retries
227227+ | Error e -> Printf.printf "Error: %s\n" e
228228+229229+let () =
230230+ let usage = "Usage: test_locations <command> [args...]" in
231231+232232+ if Stdlib.Array.length Sys.argv < 2 then begin
233233+ prerr_endline usage;
234234+ exit 1
235235+ end;
236236+237237+ match Sys.argv.(1) with
238238+ | "error-precision" when Array.length Sys.argv = 3 ->
239239+ test_error_precision Sys.argv.(2)
240240+ | "nested-error" when Array.length Sys.argv = 3 ->
241241+ test_nested_error Sys.argv.(2)
242242+ | "array-error" when Array.length Sys.argv = 3 ->
243243+ test_array_error Sys.argv.(2)
244244+ | "layout" when Array.length Sys.argv = 3 ->
245245+ test_layout_preservation Sys.argv.(2)
246246+ | "roundtrip" when Array.length Sys.argv = 3 ->
247247+ test_roundtrip_layout Sys.argv.(2)
248248+ | "file-path" -> test_file_path ()
249249+ | "missing-field" when Array.length Sys.argv = 3 ->
250250+ test_missing_field Sys.argv.(2)
251251+ | "combined" when Array.length Sys.argv = 3 ->
252252+ test_combined_options Sys.argv.(2)
253253+ | _ ->
254254+ prerr_endline usage;
255255+ prerr_endline "Commands:";
256256+ prerr_endline
257257+ " error-precision <file> - Compare error messages with/without locs";
258258+ prerr_endline
259259+ " nested-error <file> - Test error locations in nested objects";
260260+ prerr_endline
261261+ " array-error <file> - Test error locations in arrays";
262262+ prerr_endline " layout <file> - Test layout preservation";
263263+ prerr_endline
264264+ " roundtrip <file> - Test round-tripping with layout";
265265+ prerr_endline
266266+ " file-path - Test file path in error messages";
267267+ prerr_endline
268268+ " missing-field <file> - Test missing field errors with locs";
269269+ prerr_endline " combined <file> - Test locs and layout together";
270270+ exit 1
+240
vendor/opam/yamlt/tests/bin/test_multidoc.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+---------------------------------------------------------------------------*)
55+66+(** Test multi-document YAML streams with decode_all *)
77+88+open Bytesrw
99+1010+(* Helper to read file *)
1111+let read_file path =
1212+ let ic = open_in path in
1313+ let len = in_channel_length ic in
1414+ let s = really_input_string ic len in
1515+ close_in ic;
1616+ s
1717+1818+(* Helper to show results *)
1919+let show_result label = function
2020+ | Ok v -> Printf.printf "%s: %s\n" label v
2121+ | Error e -> Printf.printf "%s: ERROR: %s\n" label e
2222+2323+(* Test: Simple multi-document stream *)
2424+let test_simple file =
2525+ let module M = struct
2626+ type person = { name : string; age : int }
2727+2828+ let person_codec =
2929+ Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
3030+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
3131+ |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
3232+ |> Jsont.Object.finish
3333+3434+ let show p = Printf.sprintf "%s (age %d)" p.name p.age
3535+ end in
3636+ let yaml = read_file file in
3737+ let reader = Bytes.Reader.of_string yaml in
3838+ let seq = Yamlt.decode_all M.person_codec reader in
3939+ Printf.printf "Documents:\n";
4040+ seq |> Seq.iteri (fun i result ->
4141+ Printf.printf " [%d] " i;
4242+ show_result "" (Result.map M.show result)
4343+ )
4444+4545+(* Test: Count documents *)
4646+let test_count file =
4747+ let yaml = read_file file in
4848+ let reader = Bytes.Reader.of_string yaml in
4949+ let seq = Yamlt.decode_all Jsont.json reader in
5050+ let count = Seq.fold_left (fun acc _ -> acc + 1) 0 seq in
5151+ Printf.printf "Document count: %d\n" count
5252+5353+(* Test: Error tracking - show which documents succeed and which fail *)
5454+let test_errors file =
5555+ let module M = struct
5656+ type person = { name : string; age : int }
5757+5858+ let person_codec =
5959+ Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
6060+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
6161+ |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
6262+ |> Jsont.Object.finish
6363+6464+ let show p = Printf.sprintf "%s (age %d)" p.name p.age
6565+ end in
6666+ let yaml = read_file file in
6767+ let reader = Bytes.Reader.of_string yaml in
6868+ let seq = Yamlt.decode_all M.person_codec reader in
6969+ Printf.printf "Document results:\n";
7070+ seq |> Seq.iteri (fun i result ->
7171+ match result with
7272+ | Ok p -> Printf.printf " [%d] OK: %s\n" i (M.show p)
7373+ | Error e -> Printf.printf " [%d] ERROR: %s\n" i (String.trim e)
7474+ )
7575+7676+(* Test: Location tracking with locs=true *)
7777+let test_locations file =
7878+ let module M = struct
7979+ type person = { name : string; age : int }
8080+8181+ let person_codec =
8282+ Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
8383+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
8484+ |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
8585+ |> Jsont.Object.finish
8686+ end in
8787+ let yaml = read_file file in
8888+8989+ Printf.printf "=== Without locs (default) ===\n";
9090+ let reader = Bytes.Reader.of_string yaml in
9191+ let seq = Yamlt.decode_all ~locs:false M.person_codec reader in
9292+ seq |> Seq.iteri (fun i result ->
9393+ match result with
9494+ | Ok _ -> Printf.printf " [%d] OK\n" i
9595+ | Error e -> Printf.printf " [%d] ERROR:\n%s\n" i (String.trim e)
9696+ );
9797+9898+ Printf.printf "\n=== With locs=true ===\n";
9999+ let reader = Bytes.Reader.of_string yaml in
100100+ let seq = Yamlt.decode_all ~locs:true ~file:"test.yml" M.person_codec reader in
101101+ seq |> Seq.iteri (fun i result ->
102102+ match result with
103103+ | Ok _ -> Printf.printf " [%d] OK\n" i
104104+ | Error e -> Printf.printf " [%d] ERROR:\n%s\n" i (String.trim e)
105105+ )
106106+107107+(* Test: Roundtrip to JSON - decode YAML multidoc, encode each to JSON *)
108108+let test_json_roundtrip file =
109109+ let yaml = read_file file in
110110+ let reader = Bytes.Reader.of_string yaml in
111111+ let seq = Yamlt.decode_all Jsont.json reader in
112112+ Printf.printf "JSON outputs:\n";
113113+ seq |> Seq.iteri (fun i result ->
114114+ match result with
115115+ | Ok json_val ->
116116+ (match Jsont_bytesrw.encode_string Jsont.json json_val with
117117+ | Ok json_str -> Printf.printf " [%d] %s\n" i (String.trim json_str)
118118+ | Error e -> Printf.printf " [%d] ENCODE ERROR: %s\n" i e)
119119+ | Error e -> Printf.printf " [%d] DECODE ERROR: %s\n" i (String.trim e)
120120+ )
121121+122122+(* Test: Nested objects in multidoc *)
123123+let test_nested file =
124124+ let module M = struct
125125+ type address = { street : string; city : string }
126126+ type person = { name : string; age : int; address : address }
127127+128128+ let address_codec =
129129+ Jsont.Object.map ~kind:"Address" (fun street city -> { street; city })
130130+ |> Jsont.Object.mem "street" Jsont.string ~enc:(fun a -> a.street)
131131+ |> Jsont.Object.mem "city" Jsont.string ~enc:(fun a -> a.city)
132132+ |> Jsont.Object.finish
133133+134134+ let person_codec =
135135+ Jsont.Object.map ~kind:"Person" (fun name age address ->
136136+ { name; age; address })
137137+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
138138+ |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
139139+ |> Jsont.Object.mem "address" address_codec ~enc:(fun p -> p.address)
140140+ |> Jsont.Object.finish
141141+142142+ let show p =
143143+ Printf.sprintf "%s (age %d) from %s, %s" p.name p.age p.address.street
144144+ p.address.city
145145+ end in
146146+ let yaml = read_file file in
147147+ let reader = Bytes.Reader.of_string yaml in
148148+ let seq = Yamlt.decode_all M.person_codec reader in
149149+ Printf.printf "Nested documents:\n";
150150+ seq |> Seq.iteri (fun i result ->
151151+ Printf.printf " [%d] " i;
152152+ show_result "" (Result.map M.show result)
153153+ )
154154+155155+(* Test: Arrays in multidoc *)
156156+let test_arrays file =
157157+ let yaml = read_file file in
158158+ let reader = Bytes.Reader.of_string yaml in
159159+ let seq = Yamlt.decode_all Jsont.json reader in
160160+ Printf.printf "Array documents:\n";
161161+ seq |> Seq.iteri (fun i result ->
162162+ match result with
163163+ | Ok json_val ->
164164+ (match Jsont_bytesrw.encode_string Jsont.json json_val with
165165+ | Ok json_str -> Printf.printf " [%d] %s\n" i (String.trim json_str)
166166+ | Error e -> Printf.printf " [%d] ERROR: %s\n" i e)
167167+ | Error e -> Printf.printf " [%d] ERROR: %s\n" i (String.trim e)
168168+ )
169169+170170+(* Test: Scalars in multidoc *)
171171+let test_scalars file =
172172+ let yaml = read_file file in
173173+ let reader = Bytes.Reader.of_string yaml in
174174+ let seq = Yamlt.decode_all Jsont.json reader in
175175+ Printf.printf "Scalar documents:\n";
176176+ seq |> Seq.iteri (fun i result ->
177177+ match result with
178178+ | Ok json_val ->
179179+ (match Jsont_bytesrw.encode_string Jsont.json json_val with
180180+ | Ok json_str -> Printf.printf " [%d] %s\n" i (String.trim json_str)
181181+ | Error e -> Printf.printf " [%d] ERROR: %s\n" i e)
182182+ | Error e -> Printf.printf " [%d] ERROR: %s\n" i (String.trim e)
183183+ )
184184+185185+(* Test: Summary stats - count successes vs failures *)
186186+let test_summary file =
187187+ let module M = struct
188188+ type person = { name : string; age : int }
189189+190190+ let person_codec =
191191+ Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
192192+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
193193+ |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
194194+ |> Jsont.Object.finish
195195+ end in
196196+ let yaml = read_file file in
197197+ let reader = Bytes.Reader.of_string yaml in
198198+ let seq = Yamlt.decode_all M.person_codec reader in
199199+ let success = ref 0 in
200200+ let failure = ref 0 in
201201+ seq |> Seq.iter (fun result ->
202202+ match result with
203203+ | Ok _ -> incr success
204204+ | Error _ -> incr failure
205205+ );
206206+ Printf.printf "Summary: %d documents (%d ok, %d error)\n"
207207+ (!success + !failure) !success !failure
208208+209209+let () =
210210+ let usage = "Usage: test_multidoc <command> <file>" in
211211+ if Array.length Sys.argv < 3 then begin
212212+ prerr_endline usage;
213213+ exit 1
214214+ end;
215215+216216+ let test = Sys.argv.(1) in
217217+ let file = Sys.argv.(2) in
218218+ match test with
219219+ | "simple" -> test_simple file
220220+ | "count" -> test_count file
221221+ | "errors" -> test_errors file
222222+ | "locations" -> test_locations file
223223+ | "json" -> test_json_roundtrip file
224224+ | "nested" -> test_nested file
225225+ | "arrays" -> test_arrays file
226226+ | "scalars" -> test_scalars file
227227+ | "summary" -> test_summary file
228228+ | _ ->
229229+ prerr_endline usage;
230230+ prerr_endline "Commands:";
231231+ prerr_endline " simple <file> - Decode person documents";
232232+ prerr_endline " count <file> - Count documents";
233233+ prerr_endline " errors <file> - Show success/error for each document";
234234+ prerr_endline " locations <file> - Test location tracking with locs=true";
235235+ prerr_endline " json <file> - Roundtrip to JSON";
236236+ prerr_endline " nested <file> - Decode nested objects";
237237+ prerr_endline " arrays <file> - Decode arrays";
238238+ prerr_endline " scalars <file> - Decode scalars";
239239+ prerr_endline " summary <file> - Show success/failure summary";
240240+ exit 1
···11+open Bytesrw
22+33+let () =
44+ Printf.printf "=== Test 1: Explicit null as empty array ===\n";
55+ let yaml1 = "values: null" in
66+ let codec1 =
77+ let open Jsont in
88+ Object.map ~kind:"Test" (fun v -> v)
99+ |> Object.mem "values" (list int) ~dec_absent:[] ~enc:(fun v -> v)
1010+ |> Object.finish
1111+ in
1212+ (match Yamlt.decode codec1 (Bytes.Reader.of_string yaml1) with
1313+ | Ok v ->
1414+ Printf.printf "Result: [%s]\n"
1515+ (String.concat "; " (List.map string_of_int v))
1616+ | Error e -> Printf.printf "Error: %s\n" e);
1717+1818+ Printf.printf "\n=== Test 2: Tilde as empty array ===\n";
1919+ let yaml2 = "values: ~" in
2020+ (match Yamlt.decode codec1 (Bytes.Reader.of_string yaml2) with
2121+ | Ok v ->
2222+ Printf.printf "Result: [%s]\n"
2323+ (String.concat "; " (List.map string_of_int v))
2424+ | Error e -> Printf.printf "Error: %s\n" e);
2525+2626+ Printf.printf "\n=== Test 3: Empty array syntax ===\n";
2727+ let yaml3 = "values: []" in
2828+ (match Yamlt.decode codec1 (Bytes.Reader.of_string yaml3) with
2929+ | Ok v ->
3030+ Printf.printf "Result: [%s]\n"
3131+ (String.concat "; " (List.map string_of_int v))
3232+ | Error e -> Printf.printf "Error: %s\n" e);
3333+3434+ Printf.printf "\n=== Test 4: Array with values ===\n";
3535+ let yaml4 = "values: [1, 2, 3]" in
3636+ (match Yamlt.decode codec1 (Bytes.Reader.of_string yaml4) with
3737+ | Ok v ->
3838+ Printf.printf "Result: [%s]\n"
3939+ (String.concat "; " (List.map string_of_int v))
4040+ | Error e -> Printf.printf "Error: %s\n" e);
4141+4242+ Printf.printf "\n=== Test 5: Explicit null as empty object ===\n";
4343+ let yaml5 = "config: null" in
4444+ let codec2 =
4545+ let open Jsont in
4646+ let config_codec =
4747+ Object.map ~kind:"Config" (fun timeout retries -> (timeout, retries))
4848+ |> Object.mem "timeout" int ~dec_absent:30 ~enc:fst
4949+ |> Object.mem "retries" int ~dec_absent:3 ~enc:snd
5050+ |> Object.finish
5151+ in
5252+ Object.map ~kind:"Test" (fun c -> c)
5353+ |> Object.mem "config" config_codec ~dec_absent:(30, 3) ~enc:(fun c -> c)
5454+ |> Object.finish
5555+ in
5656+ (match Yamlt.decode codec2 (Bytes.Reader.of_string yaml5) with
5757+ | Ok (timeout, retries) ->
5858+ Printf.printf "Result: {timeout=%d; retries=%d}\n" timeout retries
5959+ | Error e -> Printf.printf "Error: %s\n" e);
6060+6161+ Printf.printf "\n=== Test 6: Empty object syntax ===\n";
6262+ let yaml6 = "config: {}" in
6363+ (match Yamlt.decode codec2 (Bytes.Reader.of_string yaml6) with
6464+ | Ok (timeout, retries) ->
6565+ Printf.printf "Result: {timeout=%d; retries=%d}\n" timeout retries
6666+ | Error e -> Printf.printf "Error: %s\n" e);
6767+6868+ Printf.printf "\n=== Test 7: Object with values ===\n";
6969+ let yaml7 = "config:\n timeout: 60\n retries: 5" in
7070+ (match Yamlt.decode codec2 (Bytes.Reader.of_string yaml7) with
7171+ | Ok (timeout, retries) ->
7272+ Printf.printf "Result: {timeout=%d; retries=%d}\n" timeout retries
7373+ | Error e -> Printf.printf "Error: %s\n" e);
7474+7575+ Printf.printf "\n=== Test 8: Nested null arrays ===\n";
7676+ let yaml8 = "name: test\nitems: null\ntags: ~" in
7777+ let codec3 =
7878+ let open Jsont in
7979+ Object.map ~kind:"Nested" (fun name items tags -> (name, items, tags))
8080+ |> Object.mem "name" string ~enc:(fun (n, _, _) -> n)
8181+ |> Object.mem "items" (list int) ~dec_absent:[] ~enc:(fun (_, i, _) -> i)
8282+ |> Object.mem "tags" (list string) ~dec_absent:[] ~enc:(fun (_, _, t) -> t)
8383+ |> Object.finish
8484+ in
8585+ match Yamlt.decode codec3 (Bytes.Reader.of_string yaml8) with
8686+ | Ok (name, items, tags) ->
8787+ Printf.printf "Result: {name=%s; items_count=%d; tags_count=%d}\n"
8888+ name (List.length items) (List.length tags)
8989+ | Error e -> Printf.printf "Error: %s\n" e
+39
vendor/opam/yamlt/tests/bin/test_null_complete.ml
···11+open Bytesrw
22+33+let () =
44+ Printf.printf "=== Test 1: Jsont.option with YAML null ===\n";
55+ let yaml1 = "value: null" in
66+ let codec1 =
77+ let open Jsont in
88+ Object.map ~kind:"Test" (fun v -> v)
99+ |> Object.mem "value" (option string) ~enc:(fun v -> v)
1010+ |> Object.finish
1111+ in
1212+ (match Yamlt.decode codec1 (Bytes.Reader.of_string yaml1) with
1313+ | Ok v ->
1414+ Printf.printf "Result: %s\n"
1515+ (match v with None -> "None" | Some s -> "Some(" ^ s ^ ")")
1616+ | Error e -> Printf.printf "Error: %s\n" e);
1717+1818+ Printf.printf "\n=== Test 2: Jsont.option with YAML string ===\n";
1919+ (match Yamlt.decode codec1 (Bytes.Reader.of_string "value: hello") with
2020+ | Ok v ->
2121+ Printf.printf "Result: %s\n"
2222+ (match v with None -> "None" | Some s -> "Some(" ^ s ^ ")")
2323+ | Error e -> Printf.printf "Error: %s\n" e);
2424+2525+ Printf.printf "\n=== Test 3: Jsont.string with YAML null (should error) ===\n";
2626+ let codec2 =
2727+ let open Jsont in
2828+ Object.map ~kind:"Test" (fun v -> v)
2929+ |> Object.mem "value" string ~enc:(fun v -> v)
3030+ |> Object.finish
3131+ in
3232+ (match Yamlt.decode codec2 (Bytes.Reader.of_string "value: null") with
3333+ | Ok v -> Printf.printf "Result: %s\n" v
3434+ | Error e -> Printf.printf "Error (expected): %s\n" e);
3535+3636+ Printf.printf "\n=== Test 4: Jsont.string with YAML string ===\n";
3737+ match Yamlt.decode codec2 (Bytes.Reader.of_string "value: hello") with
3838+ | Ok v -> Printf.printf "Result: %s\n" v
3939+ | Error e -> Printf.printf "Error: %s\n" e
+31
vendor/opam/yamlt/tests/bin/test_null_fix.ml
···11+open Bytesrw
22+33+let () =
44+ let module M = struct
55+ type data = { value : string option }
66+77+ let data_codec =
88+ Jsont.Object.map ~kind:"Data" (fun value -> { value })
99+ |> Jsont.Object.mem "value" (Jsont.option Jsont.string) ~enc:(fun d ->
1010+ d.value)
1111+ |> Jsont.Object.finish
1212+ end in
1313+ let yaml_null = "value: null" in
1414+1515+ Printf.printf "Testing YAML null handling with Jsont.option Jsont.string:\n\n";
1616+1717+ match Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml_null) with
1818+ | Ok data -> (
1919+ match data.M.value with
2020+ | None -> Printf.printf "YAML: value=None (CORRECT)\n"
2121+ | Some s -> Printf.printf "YAML: value=Some(%S) (BUG!)\n" s)
2222+ | Error e -> (
2323+ Printf.printf "YAML ERROR: %s\n" e;
2424+2525+ let json_null = "{\"value\": null}" in
2626+ match Jsont_bytesrw.decode_string M.data_codec json_null with
2727+ | Ok data -> (
2828+ match data.M.value with
2929+ | None -> Printf.printf "JSON: value=None (CORRECT)\n"
3030+ | Some s -> Printf.printf "JSON: value=Some(%S) (BUG!)\n" s)
3131+ | Error e -> Printf.printf "JSON ERROR: %s\n" e)
+297
vendor/opam/yamlt/tests/bin/test_objects.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Test object codec functionality with Yamlt *)
77+88+open Bytesrw
99+1010+(* Helper to read file *)
1111+let read_file path =
1212+ let ic = open_in path in
1313+ let len = in_channel_length ic in
1414+ let s = really_input_string ic len in
1515+ close_in ic;
1616+ s
1717+1818+(* Helper to show results *)
1919+let show_result label = function
2020+ | Ok v -> Printf.printf "%s: %s\n" label v
2121+ | Error e -> Printf.printf "%s: ERROR: %s\n" label e
2222+2323+let show_result_both label json_result yaml_result =
2424+ Printf.printf "JSON: ";
2525+ show_result label json_result;
2626+ Printf.printf "YAML: ";
2727+ show_result label yaml_result
2828+2929+(* Test: Simple object with required fields *)
3030+let test_simple_object file =
3131+ let module M = struct
3232+ type person = { name : string; age : int }
3333+3434+ let person_codec =
3535+ Jsont.Object.map ~kind:"Person" (fun name age -> { name; age })
3636+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
3737+ |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
3838+ |> Jsont.Object.finish
3939+4040+ let show p = Printf.sprintf "{name=%S; age=%d}" p.name p.age
4141+ end in
4242+ let yaml = read_file file in
4343+ let json = read_file (file ^ ".json") in
4444+ let json_result = Jsont_bytesrw.decode_string M.person_codec json in
4545+ let yaml_result = Yamlt.decode M.person_codec (Bytes.Reader.of_string yaml) in
4646+4747+ show_result_both "person"
4848+ (Result.map M.show json_result)
4949+ (Result.map M.show yaml_result)
5050+5151+(* Test: Object with optional fields *)
5252+let test_optional_fields file =
5353+ let module M = struct
5454+ type config = { host : string; port : int option; debug : bool option }
5555+5656+ let config_codec =
5757+ Jsont.Object.map ~kind:"Config" (fun host port debug ->
5858+ { host; port; debug })
5959+ |> Jsont.Object.mem "host" Jsont.string ~enc:(fun c -> c.host)
6060+ |> Jsont.Object.opt_mem "port" Jsont.int ~enc:(fun c -> c.port)
6161+ |> Jsont.Object.opt_mem "debug" Jsont.bool ~enc:(fun c -> c.debug)
6262+ |> Jsont.Object.finish
6363+6464+ let show c =
6565+ Printf.sprintf "{host=%S; port=%s; debug=%s}" c.host
6666+ (match c.port with
6767+ | None -> "None"
6868+ | Some p -> Printf.sprintf "Some %d" p)
6969+ (match c.debug with
7070+ | None -> "None"
7171+ | Some b -> Printf.sprintf "Some %b" b)
7272+ end in
7373+ let yaml = read_file file in
7474+ let json = read_file (file ^ ".json") in
7575+ let json_result = Jsont_bytesrw.decode_string M.config_codec json in
7676+ let yaml_result = Yamlt.decode M.config_codec (Bytes.Reader.of_string yaml) in
7777+7878+ show_result_both "config"
7979+ (Result.map M.show json_result)
8080+ (Result.map M.show yaml_result)
8181+8282+(* Test: Object with default values *)
8383+let test_default_values file =
8484+ let module M = struct
8585+ type settings = { timeout : int; retries : int; verbose : bool }
8686+8787+ let settings_codec =
8888+ Jsont.Object.map ~kind:"Settings" (fun timeout retries verbose ->
8989+ { timeout; retries; verbose })
9090+ |> Jsont.Object.mem "timeout" Jsont.int
9191+ ~enc:(fun s -> s.timeout)
9292+ ~dec_absent:30
9393+ |> Jsont.Object.mem "retries" Jsont.int
9494+ ~enc:(fun s -> s.retries)
9595+ ~dec_absent:3
9696+ |> Jsont.Object.mem "verbose" Jsont.bool
9797+ ~enc:(fun s -> s.verbose)
9898+ ~dec_absent:false
9999+ |> Jsont.Object.finish
100100+101101+ let show s =
102102+ Printf.sprintf "{timeout=%d; retries=%d; verbose=%b}" s.timeout s.retries
103103+ s.verbose
104104+ end in
105105+ let yaml = read_file file in
106106+ let json = read_file (file ^ ".json") in
107107+ let json_result = Jsont_bytesrw.decode_string M.settings_codec json in
108108+ let yaml_result = Yamlt.decode M.settings_codec (Bytes.Reader.of_string yaml) in
109109+110110+ show_result_both "settings"
111111+ (Result.map M.show json_result)
112112+ (Result.map M.show yaml_result)
113113+114114+(* Test: Nested objects *)
115115+let test_nested_objects file =
116116+ let module M = struct
117117+ type address = { street : string; city : string; zip : string }
118118+ type employee = { name : string; address : address }
119119+120120+ let address_codec =
121121+ Jsont.Object.map ~kind:"Address" (fun street city zip ->
122122+ { street; city; zip })
123123+ |> Jsont.Object.mem "street" Jsont.string ~enc:(fun a -> a.street)
124124+ |> Jsont.Object.mem "city" Jsont.string ~enc:(fun a -> a.city)
125125+ |> Jsont.Object.mem "zip" Jsont.string ~enc:(fun a -> a.zip)
126126+ |> Jsont.Object.finish
127127+128128+ let employee_codec =
129129+ Jsont.Object.map ~kind:"Employee" (fun name address -> { name; address })
130130+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun e -> e.name)
131131+ |> Jsont.Object.mem "address" address_codec ~enc:(fun e -> e.address)
132132+ |> Jsont.Object.finish
133133+134134+ let show e =
135135+ Printf.sprintf "{name=%S; address={street=%S; city=%S; zip=%S}}" e.name
136136+ e.address.street e.address.city e.address.zip
137137+ end in
138138+ let yaml = read_file file in
139139+ let json = read_file (file ^ ".json") in
140140+ let json_result = Jsont_bytesrw.decode_string M.employee_codec json in
141141+ let yaml_result = Yamlt.decode M.employee_codec (Bytes.Reader.of_string yaml) in
142142+143143+ show_result_both "employee"
144144+ (Result.map M.show json_result)
145145+ (Result.map M.show yaml_result)
146146+147147+(* Test: Unknown member handling - error *)
148148+let test_unknown_members_error file =
149149+ let module M = struct
150150+ type strict = { name : string }
151151+152152+ let strict_codec =
153153+ Jsont.Object.map ~kind:"Strict" (fun name -> { name })
154154+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun s -> s.name)
155155+ |> Jsont.Object.finish
156156+ end in
157157+ let yaml = read_file file in
158158+ let result = Yamlt.decode M.strict_codec (Bytes.Reader.of_string yaml) in
159159+ match result with
160160+ | Ok _ -> Printf.printf "Unexpected success\n"
161161+ | Error e -> Printf.printf "Expected error: %s\n" e
162162+163163+(* Test: Unknown member handling - keep *)
164164+let test_unknown_members_keep file =
165165+ let module M = struct
166166+ type flexible = { name : string; extra : Jsont.json }
167167+168168+ let flexible_codec =
169169+ Jsont.Object.map ~kind:"Flexible" (fun name extra -> { name; extra })
170170+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun f -> f.name)
171171+ |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun f -> f.extra)
172172+ |> Jsont.Object.finish
173173+174174+ let show f = Printf.sprintf "{name=%S; has_extra=true}" f.name
175175+ end in
176176+ let yaml = read_file file in
177177+ let json = read_file (file ^ ".json") in
178178+ let json_result = Jsont_bytesrw.decode_string M.flexible_codec json in
179179+ let yaml_result = Yamlt.decode M.flexible_codec (Bytes.Reader.of_string yaml) in
180180+181181+ show_result_both "flexible"
182182+ (Result.map M.show json_result)
183183+ (Result.map M.show yaml_result)
184184+185185+(* Test: Object cases (discriminated unions) - simplified version *)
186186+let test_object_cases file =
187187+ let module M = struct
188188+ type circle = { type_ : string; radius : float }
189189+190190+ let circle_codec =
191191+ Jsont.Object.map ~kind:"Circle" (fun type_ radius -> { type_; radius })
192192+ |> Jsont.Object.mem "type" Jsont.string ~enc:(fun c -> c.type_)
193193+ |> Jsont.Object.mem "radius" Jsont.number ~enc:(fun c -> c.radius)
194194+ |> Jsont.Object.finish
195195+196196+ let show c = Printf.sprintf "Circle{radius=%.2f}" c.radius
197197+ end in
198198+ let yaml = read_file file in
199199+ let json = read_file (file ^ ".json") in
200200+ let json_result = Jsont_bytesrw.decode_string M.circle_codec json in
201201+ let yaml_result = Yamlt.decode M.circle_codec (Bytes.Reader.of_string yaml) in
202202+203203+ show_result_both "shape"
204204+ (Result.map M.show json_result)
205205+ (Result.map M.show yaml_result)
206206+207207+(* Test: Missing required field error *)
208208+let test_missing_required file =
209209+ let module M = struct
210210+ type required = { name : string; age : int }
211211+212212+ let required_codec =
213213+ Jsont.Object.map ~kind:"Required" (fun name age -> { name; age })
214214+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun r -> r.name)
215215+ |> Jsont.Object.mem "age" Jsont.int ~enc:(fun r -> r.age)
216216+ |> Jsont.Object.finish
217217+ end in
218218+ let yaml = read_file file in
219219+ let result = Yamlt.decode M.required_codec (Bytes.Reader.of_string yaml) in
220220+ match result with
221221+ | Ok _ -> Printf.printf "Unexpected success\n"
222222+ | Error e -> Printf.printf "Expected error: %s\n" e
223223+224224+(* Test: Encoding objects to different formats *)
225225+let test_encode_object () =
226226+ let module M = struct
227227+ type person = { name : string; age : int; active : bool }
228228+229229+ let person_codec =
230230+ Jsont.Object.map ~kind:"Person" (fun name age active ->
231231+ { name; age; active })
232232+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.name)
233233+ |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
234234+ |> Jsont.Object.mem "active" Jsont.bool ~enc:(fun p -> p.active)
235235+ |> Jsont.Object.finish
236236+ end in
237237+ let person = M.{ name = "Alice"; age = 30; active = true } in
238238+239239+ (* Encode to JSON *)
240240+ (match Jsont_bytesrw.encode_string M.person_codec person with
241241+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
242242+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
243243+244244+ (* Encode to YAML Block *)
245245+ (let b = Buffer.create 256 in
246246+ let writer = Bytes.Writer.of_buffer b in
247247+ match Yamlt.encode ~format:Yamlt.Block M.person_codec person ~eod:true writer with
248248+ | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
249249+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
250250+251251+ (* Encode to YAML Flow *)
252252+ let b = Buffer.create 256 in
253253+ let writer = Bytes.Writer.of_buffer b in
254254+ match Yamlt.encode ~format:Yamlt.Flow M.person_codec person ~eod:true writer with
255255+ | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
256256+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e
257257+258258+let () =
259259+ let usage = "Usage: test_objects <command> [args...]" in
260260+261261+ if Stdlib.Array.length Sys.argv < 2 then begin
262262+ prerr_endline usage;
263263+ exit 1
264264+ end;
265265+266266+ match Sys.argv.(1) with
267267+ | "simple" when Stdlib.Array.length Sys.argv = 3 ->
268268+ test_simple_object Sys.argv.(2)
269269+ | "optional" when Stdlib.Array.length Sys.argv = 3 ->
270270+ test_optional_fields Sys.argv.(2)
271271+ | "defaults" when Stdlib.Array.length Sys.argv = 3 ->
272272+ test_default_values Sys.argv.(2)
273273+ | "nested" when Stdlib.Array.length Sys.argv = 3 ->
274274+ test_nested_objects Sys.argv.(2)
275275+ | "unknown-error" when Stdlib.Array.length Sys.argv = 3 ->
276276+ test_unknown_members_error Sys.argv.(2)
277277+ | "unknown-keep" when Stdlib.Array.length Sys.argv = 3 ->
278278+ test_unknown_members_keep Sys.argv.(2)
279279+ | "cases" when Stdlib.Array.length Sys.argv = 3 ->
280280+ test_object_cases Sys.argv.(2)
281281+ | "missing-required" when Stdlib.Array.length Sys.argv = 3 ->
282282+ test_missing_required Sys.argv.(2)
283283+ | "encode" when Stdlib.Array.length Sys.argv = 2 -> test_encode_object ()
284284+ | _ ->
285285+ prerr_endline usage;
286286+ prerr_endline "Commands:";
287287+ prerr_endline " simple <file> - Test simple object";
288288+ prerr_endline " optional <file> - Test optional fields";
289289+ prerr_endline " defaults <file> - Test default values";
290290+ prerr_endline " nested <file> - Test nested objects";
291291+ prerr_endline " unknown-error <file> - Test unknown member error";
292292+ prerr_endline " unknown-keep <file> - Test keeping unknown members";
293293+ prerr_endline " cases <file> - Test object cases (unions)";
294294+ prerr_endline
295295+ " missing-required <file> - Test missing required field error";
296296+ prerr_endline " encode - Test encoding objects";
297297+ exit 1
+19
vendor/opam/yamlt/tests/bin/test_opt_array.ml
···11+open Bytesrw
22+33+let () =
44+ let codec =
55+ Jsont.Object.map ~kind:"Test" (fun arr -> arr)
66+ |> Jsont.Object.opt_mem "values" (Jsont.array Jsont.string) ~enc:(fun arr ->
77+ arr)
88+ |> Jsont.Object.finish
99+ in
1010+1111+ let yaml = "values: [a, b, c]" in
1212+1313+ Printf.printf "Testing optional array field:\n";
1414+ match Yamlt.decode codec (Bytes.Reader.of_string yaml) with
1515+ | Ok arr -> (
1616+ match arr with
1717+ | None -> Printf.printf "Result: None\n"
1818+ | Some a -> Printf.printf "Result: Some([%d items])\n" (Array.length a))
1919+ | Error e -> Printf.printf "Error: %s\n" e
+267
vendor/opam/yamlt/tests/bin/test_roundtrip.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Test roundtrip encoding/decoding with Yamlt *)
77+88+open Bytesrw
99+1010+(* Test: Roundtrip scalars *)
1111+let test_scalar_roundtrip () =
1212+ let module M = struct
1313+ type data = { s : string; n : float; b : bool; nul : unit }
1414+1515+ let data_codec =
1616+ Jsont.Object.map ~kind:"Data" (fun s n b nul -> { s; n; b; nul })
1717+ |> Jsont.Object.mem "s" Jsont.string ~enc:(fun d -> d.s)
1818+ |> Jsont.Object.mem "n" Jsont.number ~enc:(fun d -> d.n)
1919+ |> Jsont.Object.mem "b" Jsont.bool ~enc:(fun d -> d.b)
2020+ |> Jsont.Object.mem "nul" (Jsont.null ()) ~enc:(fun d -> d.nul)
2121+ |> Jsont.Object.finish
2222+2323+ let equal d1 d2 =
2424+ d1.s = d2.s && d1.n = d2.n && d1.b = d2.b && d1.nul = d2.nul
2525+ end in
2626+ let original = { M.s = "hello"; n = 42.5; b = true; nul = () } in
2727+2828+ (* JSON roundtrip *)
2929+ let json_encoded = Jsont_bytesrw.encode_string M.data_codec original in
3030+ let json_decoded =
3131+ Result.bind json_encoded (Jsont_bytesrw.decode_string M.data_codec)
3232+ in
3333+ (match json_decoded with
3434+ | Ok decoded when M.equal original decoded ->
3535+ Printf.printf "JSON roundtrip: PASS\n"
3636+ | Ok _ -> Printf.printf "JSON roundtrip: FAIL (data mismatch)\n"
3737+ | Error e -> Printf.printf "JSON roundtrip: FAIL (%s)\n" e);
3838+3939+ (* YAML Block roundtrip *)
4040+ let yaml_block_encoded =
4141+ let b = Buffer.create 256 in
4242+ let writer = Bytes.Writer.of_buffer b in
4343+ match Yamlt.encode ~format:Yamlt.Block M.data_codec original ~eod:true writer with
4444+ | Ok () -> Ok (Buffer.contents b)
4545+ | Error e -> Error e
4646+ in
4747+ let yaml_block_decoded =
4848+ Result.bind yaml_block_encoded (fun yaml ->
4949+ Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml))
5050+ in
5151+ (match yaml_block_decoded with
5252+ | Ok decoded when M.equal original decoded ->
5353+ Printf.printf "YAML Block roundtrip: PASS\n"
5454+ | Ok _ -> Printf.printf "YAML Block roundtrip: FAIL (data mismatch)\n"
5555+ | Error e -> Printf.printf "YAML Block roundtrip: FAIL (%s)\n" e);
5656+5757+ (* YAML Flow roundtrip *)
5858+ let yaml_flow_encoded =
5959+ let b = Buffer.create 256 in
6060+ let writer = Bytes.Writer.of_buffer b in
6161+ match Yamlt.encode ~format:Yamlt.Flow M.data_codec original ~eod:true writer with
6262+ | Ok () -> Ok (Buffer.contents b)
6363+ | Error e -> Error e
6464+ in
6565+ let yaml_flow_decoded =
6666+ Result.bind yaml_flow_encoded (fun yaml ->
6767+ Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml))
6868+ in
6969+ match yaml_flow_decoded with
7070+ | Ok decoded when M.equal original decoded ->
7171+ Printf.printf "YAML Flow roundtrip: PASS\n"
7272+ | Ok _ -> Printf.printf "YAML Flow roundtrip: FAIL (data mismatch)\n"
7373+ | Error e -> Printf.printf "YAML Flow roundtrip: FAIL (%s)\n" e
7474+7575+(* Test: Roundtrip arrays *)
7676+let test_array_roundtrip () =
7777+ let module M = struct
7878+ type data = { items : int array; nested : float array array }
7979+8080+ let data_codec =
8181+ Jsont.Object.map ~kind:"Data" (fun items nested -> { items; nested })
8282+ |> Jsont.Object.mem "items" (Jsont.array Jsont.int) ~enc:(fun d ->
8383+ d.items)
8484+ |> Jsont.Object.mem "nested"
8585+ (Jsont.array (Jsont.array Jsont.number))
8686+ ~enc:(fun d -> d.nested)
8787+ |> Jsont.Object.finish
8888+8989+ let equal d1 d2 = d1.items = d2.items && d1.nested = d2.nested
9090+ end in
9191+ let original =
9292+ {
9393+ M.items = [| 1; 2; 3; 4; 5 |];
9494+ nested = [| [| 1.0; 2.0 |]; [| 3.0; 4.0 |] |];
9595+ }
9696+ in
9797+9898+ (* JSON roundtrip *)
9999+ let json_result =
100100+ Result.bind
101101+ (Jsont_bytesrw.encode_string M.data_codec original)
102102+ (Jsont_bytesrw.decode_string M.data_codec)
103103+ in
104104+ (match json_result with
105105+ | Ok decoded when M.equal original decoded ->
106106+ Printf.printf "JSON array roundtrip: PASS\n"
107107+ | Ok _ -> Printf.printf "JSON array roundtrip: FAIL (data mismatch)\n"
108108+ | Error e -> Printf.printf "JSON array roundtrip: FAIL (%s)\n" e);
109109+110110+ (* YAML roundtrip *)
111111+ let yaml_result =
112112+ let b = Buffer.create 256 in
113113+ let writer = Bytes.Writer.of_buffer b in
114114+ match Yamlt.encode M.data_codec original ~eod:true writer with
115115+ | Ok () ->
116116+ let yaml = Buffer.contents b in
117117+ Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml)
118118+ | Error e -> Error e
119119+ in
120120+ match yaml_result with
121121+ | Ok decoded when M.equal original decoded ->
122122+ Printf.printf "YAML array roundtrip: PASS\n"
123123+ | Ok _ -> Printf.printf "YAML array roundtrip: FAIL (data mismatch)\n"
124124+ | Error e -> Printf.printf "YAML array roundtrip: FAIL (%s)\n" e
125125+126126+(* Test: Roundtrip objects *)
127127+let test_object_roundtrip () =
128128+ let module M = struct
129129+ type person = { p_name : string; age : int; active : bool }
130130+ type company = { c_name : string; employees : person array }
131131+132132+ let person_codec =
133133+ Jsont.Object.map ~kind:"Person" (fun p_name age active ->
134134+ { p_name; age; active })
135135+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun p -> p.p_name)
136136+ |> Jsont.Object.mem "age" Jsont.int ~enc:(fun p -> p.age)
137137+ |> Jsont.Object.mem "active" Jsont.bool ~enc:(fun p -> p.active)
138138+ |> Jsont.Object.finish
139139+140140+ let company_codec =
141141+ Jsont.Object.map ~kind:"Company" (fun c_name employees ->
142142+ { c_name; employees })
143143+ |> Jsont.Object.mem "name" Jsont.string ~enc:(fun c -> c.c_name)
144144+ |> Jsont.Object.mem "employees" (Jsont.array person_codec) ~enc:(fun c ->
145145+ c.employees)
146146+ |> Jsont.Object.finish
147147+148148+ let person_equal p1 p2 =
149149+ p1.p_name = p2.p_name && p1.age = p2.age && p1.active = p2.active
150150+151151+ let equal c1 c2 =
152152+ c1.c_name = c2.c_name
153153+ && Stdlib.Array.length c1.employees = Stdlib.Array.length c2.employees
154154+ && Stdlib.Array.for_all2 person_equal c1.employees c2.employees
155155+ end in
156156+ let original =
157157+ {
158158+ M.c_name = "Acme Corp";
159159+ employees =
160160+ [|
161161+ { p_name = "Alice"; age = 30; active = true };
162162+ { p_name = "Bob"; age = 25; active = false };
163163+ |];
164164+ }
165165+ in
166166+167167+ (* JSON roundtrip *)
168168+ let json_result =
169169+ Result.bind
170170+ (Jsont_bytesrw.encode_string M.company_codec original)
171171+ (Jsont_bytesrw.decode_string M.company_codec)
172172+ in
173173+ (match json_result with
174174+ | Ok decoded when M.equal original decoded ->
175175+ Printf.printf "JSON object roundtrip: PASS\n"
176176+ | Ok _ -> Printf.printf "JSON object roundtrip: FAIL (data mismatch)\n"
177177+ | Error e -> Printf.printf "JSON object roundtrip: FAIL (%s)\n" e);
178178+179179+ (* YAML roundtrip *)
180180+ let yaml_result =
181181+ let b = Buffer.create 256 in
182182+ let writer = Bytes.Writer.of_buffer b in
183183+ match Yamlt.encode M.company_codec original ~eod:true writer with
184184+ | Ok () ->
185185+ let yaml = Buffer.contents b in
186186+ Yamlt.decode M.company_codec (Bytes.Reader.of_string yaml)
187187+ | Error e -> Error e
188188+ in
189189+ match yaml_result with
190190+ | Ok decoded when M.equal original decoded ->
191191+ Printf.printf "YAML object roundtrip: PASS\n"
192192+ | Ok _ -> Printf.printf "YAML object roundtrip: FAIL (data mismatch)\n"
193193+ | Error e -> Printf.printf "YAML object roundtrip: FAIL (%s)\n" e
194194+195195+(* Test: Roundtrip with optionals *)
196196+let test_optional_roundtrip () =
197197+ let module M = struct
198198+ type data = {
199199+ required : string;
200200+ optional : int option;
201201+ nullable : string option;
202202+ }
203203+204204+ let data_codec =
205205+ Jsont.Object.map ~kind:"Data" (fun required optional nullable ->
206206+ { required; optional; nullable })
207207+ |> Jsont.Object.mem "required" Jsont.string ~enc:(fun d -> d.required)
208208+ |> Jsont.Object.opt_mem "optional" Jsont.int ~enc:(fun d -> d.optional)
209209+ |> Jsont.Object.mem "nullable" (Jsont.some Jsont.string) ~enc:(fun d ->
210210+ d.nullable)
211211+ |> Jsont.Object.finish
212212+213213+ let equal d1 d2 =
214214+ d1.required = d2.required && d1.optional = d2.optional
215215+ && d1.nullable = d2.nullable
216216+ end in
217217+ let original = { M.required = "test"; optional = Some 42; nullable = None } in
218218+219219+ (* JSON roundtrip *)
220220+ let json_result =
221221+ Result.bind
222222+ (Jsont_bytesrw.encode_string M.data_codec original)
223223+ (Jsont_bytesrw.decode_string M.data_codec)
224224+ in
225225+ (match json_result with
226226+ | Ok decoded when M.equal original decoded ->
227227+ Printf.printf "JSON optional roundtrip: PASS\n"
228228+ | Ok _ -> Printf.printf "JSON optional roundtrip: FAIL (data mismatch)\n"
229229+ | Error e -> Printf.printf "JSON optional roundtrip: FAIL (%s)\n" e);
230230+231231+ (* YAML roundtrip *)
232232+ let yaml_result =
233233+ let b = Buffer.create 256 in
234234+ let writer = Bytes.Writer.of_buffer b in
235235+ match Yamlt.encode M.data_codec original ~eod:true writer with
236236+ | Ok () ->
237237+ let yaml = Buffer.contents b in
238238+ Yamlt.decode M.data_codec (Bytes.Reader.of_string yaml)
239239+ | Error e -> Error e
240240+ in
241241+ match yaml_result with
242242+ | Ok decoded when M.equal original decoded ->
243243+ Printf.printf "YAML optional roundtrip: PASS\n"
244244+ | Ok _ -> Printf.printf "YAML optional roundtrip: FAIL (data mismatch)\n"
245245+ | Error e -> Printf.printf "YAML optional roundtrip: FAIL (%s)\n" e
246246+247247+let () =
248248+ let usage = "Usage: test_roundtrip <command>" in
249249+250250+ if Stdlib.Array.length Sys.argv < 2 then begin
251251+ prerr_endline usage;
252252+ exit 1
253253+ end;
254254+255255+ match Sys.argv.(1) with
256256+ | "scalar" -> test_scalar_roundtrip ()
257257+ | "array" -> test_array_roundtrip ()
258258+ | "object" -> test_object_roundtrip ()
259259+ | "optional" -> test_optional_roundtrip ()
260260+ | _ ->
261261+ prerr_endline usage;
262262+ prerr_endline "Commands:";
263263+ prerr_endline " scalar - Test scalar roundtrip";
264264+ prerr_endline " array - Test array roundtrip";
265265+ prerr_endline " object - Test object roundtrip";
266266+ prerr_endline " optional - Test optional fields roundtrip";
267267+ exit 1
+309
vendor/opam/yamlt/tests/bin/test_scalars.ml
···11+(*---------------------------------------------------------------------------
22+ Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
33+ SPDX-License-Identifier: ISC
44+ ---------------------------------------------------------------------------*)
55+66+(** Test scalar type resolution with Yamlt codec *)
77+88+open Bytesrw
99+1010+(* Helper to read file *)
1111+let read_file path =
1212+ let ic = open_in path in
1313+ let len = in_channel_length ic in
1414+ let s = really_input_string ic len in
1515+ close_in ic;
1616+ s
1717+1818+(* Helper to show results *)
1919+let show_result label = function
2020+ | Ok v -> Printf.printf "%s: %s\n" label v
2121+ | Error e -> Printf.printf "%s: ERROR: %s\n" label e
2222+2323+let show_result_json label json_result yaml_result =
2424+ Printf.printf "JSON %s\n" label;
2525+ show_result " decode" json_result;
2626+ Printf.printf "YAML %s\n" label;
2727+ show_result " decode" yaml_result
2828+2929+(* Test: Decode null values with different type expectations *)
3030+let test_null_resolution file =
3131+ let yaml = read_file file in
3232+3333+ (* Define a simple object codec with nullable field *)
3434+ let null_codec =
3535+ Jsont.Object.map ~kind:"NullTest" (fun n -> n)
3636+ |> Jsont.Object.mem "value" (Jsont.null ()) ~enc:(fun n -> n)
3737+ |> Jsont.Object.finish
3838+ in
3939+4040+ (* Try decoding as null *)
4141+ let result = Yamlt.decode null_codec (Bytes.Reader.of_string yaml) in
4242+ show_result "null_codec" (Result.map (fun () -> "null") result)
4343+4444+(* Test: Boolean type-directed resolution *)
4545+let test_bool_resolution file =
4646+ let yaml = read_file file in
4747+ let json = read_file (file ^ ".json") in
4848+4949+ (* Codec expecting bool *)
5050+ let bool_codec =
5151+ Jsont.Object.map ~kind:"BoolTest" (fun b -> b)
5252+ |> Jsont.Object.mem "value" Jsont.bool ~enc:(fun b -> b)
5353+ |> Jsont.Object.finish
5454+ in
5555+5656+ (* Codec expecting string *)
5757+ let string_codec =
5858+ Jsont.Object.map ~kind:"StringTest" (fun s -> s)
5959+ |> Jsont.Object.mem "value" Jsont.string ~enc:(fun s -> s)
6060+ |> Jsont.Object.finish
6161+ in
6262+6363+ Printf.printf "=== Bool Codec ===\n";
6464+ let json_result = Jsont_bytesrw.decode_string bool_codec json in
6565+ let yaml_result = Yamlt.decode bool_codec (Bytes.Reader.of_string yaml) in
6666+ show_result_json "bool_codec"
6767+ (Result.map (Printf.sprintf "%b") json_result)
6868+ (Result.map (Printf.sprintf "%b") yaml_result);
6969+7070+ Printf.printf "\n=== String Codec ===\n";
7171+ let json_result = Jsont_bytesrw.decode_string string_codec json in
7272+ let yaml_result = Yamlt.decode string_codec (Bytes.Reader.of_string yaml) in
7373+ show_result_json "string_codec"
7474+ (Result.map (Printf.sprintf "%S") json_result)
7575+ (Result.map (Printf.sprintf "%S") yaml_result)
7676+7777+(* Test: Number resolution *)
7878+let test_number_resolution file =
7979+ let yaml = read_file file in
8080+ let json = read_file (file ^ ".json") in
8181+8282+ let number_codec =
8383+ Jsont.Object.map ~kind:"NumberTest" (fun n -> n)
8484+ |> Jsont.Object.mem "value" Jsont.number ~enc:(fun n -> n)
8585+ |> Jsont.Object.finish
8686+ in
8787+8888+ let json_result = Jsont_bytesrw.decode_string number_codec json in
8989+ let yaml_result = Yamlt.decode number_codec (Bytes.Reader.of_string yaml) in
9090+9191+ show_result_json "number_codec"
9292+ (Result.map (Printf.sprintf "%.17g") json_result)
9393+ (Result.map (Printf.sprintf "%.17g") yaml_result)
9494+9595+(* Test: String resolution preserves everything *)
9696+let test_string_resolution file =
9797+ let yaml = read_file file in
9898+ let json = read_file (file ^ ".json") in
9999+100100+ let string_codec =
101101+ Jsont.Object.map ~kind:"StringTest" (fun s -> s)
102102+ |> Jsont.Object.mem "value" Jsont.string ~enc:(fun s -> s)
103103+ |> Jsont.Object.finish
104104+ in
105105+106106+ let json_result = Jsont_bytesrw.decode_string string_codec json in
107107+ let yaml_result = Yamlt.decode string_codec (Bytes.Reader.of_string yaml) in
108108+109109+ show_result_json "string_codec"
110110+ (Result.map (Printf.sprintf "%S") json_result)
111111+ (Result.map (Printf.sprintf "%S") yaml_result)
112112+113113+(* Test: Special float values *)
114114+let test_special_floats file =
115115+ let yaml = read_file file in
116116+117117+ let number_codec =
118118+ Jsont.Object.map ~kind:"SpecialFloat" (fun n -> n)
119119+ |> Jsont.Object.mem "value" Jsont.number ~enc:(fun n -> n)
120120+ |> Jsont.Object.finish
121121+ in
122122+123123+ let result = Yamlt.decode number_codec (Bytes.Reader.of_string yaml) in
124124+ match result with
125125+ | Ok f ->
126126+ if Float.is_nan f then Printf.printf "value: NaN\n"
127127+ else if f = Float.infinity then Printf.printf "value: +Infinity\n"
128128+ else if f = Float.neg_infinity then Printf.printf "value: -Infinity\n"
129129+ else Printf.printf "value: %.17g\n" f
130130+ | Error e -> Printf.printf "ERROR: %s\n" e
131131+132132+(* Test: Type mismatch errors *)
133133+let test_type_mismatch file expected_type =
134134+ let yaml = read_file file in
135135+136136+ match expected_type with
137137+ | "bool" -> (
138138+ let codec =
139139+ Jsont.Object.map ~kind:"BoolTest" (fun b -> b)
140140+ |> Jsont.Object.mem "value" Jsont.bool ~enc:(fun b -> b)
141141+ |> Jsont.Object.finish
142142+ in
143143+ let result = Yamlt.decode codec (Bytes.Reader.of_string yaml) in
144144+ match result with
145145+ | Ok _ -> Printf.printf "Unexpected success\n"
146146+ | Error e -> Printf.printf "Expected error: %s\n" e)
147147+ | "number" -> (
148148+ let codec =
149149+ Jsont.Object.map ~kind:"NumberTest" (fun n -> n)
150150+ |> Jsont.Object.mem "value" Jsont.number ~enc:(fun n -> n)
151151+ |> Jsont.Object.finish
152152+ in
153153+ let result = Yamlt.decode codec (Bytes.Reader.of_string yaml) in
154154+ match result with
155155+ | Ok _ -> Printf.printf "Unexpected success\n"
156156+ | Error e -> Printf.printf "Expected error: %s\n" e)
157157+ | "null" -> (
158158+ let codec =
159159+ Jsont.Object.map ~kind:"NullTest" (fun n -> n)
160160+ |> Jsont.Object.mem "value" (Jsont.null ()) ~enc:(fun n -> n)
161161+ |> Jsont.Object.finish
162162+ in
163163+ let result = Yamlt.decode codec (Bytes.Reader.of_string yaml) in
164164+ match result with
165165+ | Ok _ -> Printf.printf "Unexpected success\n"
166166+ | Error e -> Printf.printf "Expected error: %s\n" e)
167167+ | _ -> failwith "unknown type"
168168+169169+(* Test: Decode with Jsont.json to see auto-resolution *)
170170+let test_any_resolution file =
171171+ let yaml = read_file file in
172172+ let json = read_file (file ^ ".json") in
173173+174174+ let any_codec =
175175+ Jsont.Object.map ~kind:"AnyTest" (fun v -> v)
176176+ |> Jsont.Object.mem "value" Jsont.json ~enc:(fun v -> v)
177177+ |> Jsont.Object.finish
178178+ in
179179+180180+ let json_result = Jsont_bytesrw.decode_string any_codec json in
181181+ let yaml_result = Yamlt.decode any_codec (Bytes.Reader.of_string yaml) in
182182+183183+ (* Just show that it decoded successfully *)
184184+ show_result_json "any_codec"
185185+ (Result.map (fun _ -> "decoded") json_result)
186186+ (Result.map (fun _ -> "decoded") yaml_result)
187187+188188+(* Test: Encoding to different formats *)
189189+let test_encode_formats value_type value =
190190+ match value_type with
191191+ | "bool" -> (
192192+ let codec =
193193+ Jsont.Object.map ~kind:"BoolTest" (fun b -> b)
194194+ |> Jsont.Object.mem "value" Jsont.bool ~enc:(fun b -> b)
195195+ |> Jsont.Object.finish
196196+ in
197197+ let v = bool_of_string value in
198198+ (match Jsont_bytesrw.encode_string codec v with
199199+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
200200+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
201201+ (let b = Buffer.create 256 in
202202+ let writer = Bytes.Writer.of_buffer b in
203203+ match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with
204204+ | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
205205+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
206206+ let b = Buffer.create 256 in
207207+ let writer = Bytes.Writer.of_buffer b in
208208+ match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with
209209+ | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
210210+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
211211+ | "number" -> (
212212+ let codec =
213213+ Jsont.Object.map ~kind:"NumberTest" (fun n -> n)
214214+ |> Jsont.Object.mem "value" Jsont.number ~enc:(fun n -> n)
215215+ |> Jsont.Object.finish
216216+ in
217217+ let v = float_of_string value in
218218+ (match Jsont_bytesrw.encode_string codec v with
219219+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
220220+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
221221+ (let b = Buffer.create 256 in
222222+ let writer = Bytes.Writer.of_buffer b in
223223+ match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with
224224+ | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
225225+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
226226+ let b = Buffer.create 256 in
227227+ let writer = Bytes.Writer.of_buffer b in
228228+ match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with
229229+ | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
230230+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
231231+ | "string" -> (
232232+ let codec =
233233+ Jsont.Object.map ~kind:"StringTest" (fun s -> s)
234234+ |> Jsont.Object.mem "value" Jsont.string ~enc:(fun s -> s)
235235+ |> Jsont.Object.finish
236236+ in
237237+ let v = value in
238238+ (match Jsont_bytesrw.encode_string codec v with
239239+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
240240+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
241241+ (let b = Buffer.create 256 in
242242+ let writer = Bytes.Writer.of_buffer b in
243243+ match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with
244244+ | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
245245+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
246246+ let b = Buffer.create 256 in
247247+ let writer = Bytes.Writer.of_buffer b in
248248+ match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with
249249+ | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
250250+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
251251+ | "null" -> (
252252+ let codec =
253253+ Jsont.Object.map ~kind:"NullTest" (fun n -> n)
254254+ |> Jsont.Object.mem "value" (Jsont.null ()) ~enc:(fun n -> n)
255255+ |> Jsont.Object.finish
256256+ in
257257+ let v = () in
258258+ (match Jsont_bytesrw.encode_string codec v with
259259+ | Ok s -> Printf.printf "JSON: %s\n" (String.trim s)
260260+ | Error e -> Printf.printf "JSON ERROR: %s\n" e);
261261+ (let b = Buffer.create 256 in
262262+ let writer = Bytes.Writer.of_buffer b in
263263+ match Yamlt.encode ~format:Yamlt.Block codec v ~eod:true writer with
264264+ | Ok () -> Printf.printf "YAML Block:\n%s" (Buffer.contents b)
265265+ | Error e -> Printf.printf "YAML Block ERROR: %s\n" e);
266266+ let b = Buffer.create 256 in
267267+ let writer = Bytes.Writer.of_buffer b in
268268+ match Yamlt.encode ~format:Yamlt.Flow codec v ~eod:true writer with
269269+ | Ok () -> Printf.printf "YAML Flow: %s" (Buffer.contents b)
270270+ | Error e -> Printf.printf "YAML Flow ERROR: %s\n" e)
271271+ | _ -> failwith "unknown type"
272272+273273+let () =
274274+ let usage = "Usage: test_scalars <command> [args...]" in
275275+276276+ if Stdlib.Array.length Sys.argv < 2 then begin
277277+ prerr_endline usage;
278278+ exit 1
279279+ end;
280280+281281+ match Sys.argv.(1) with
282282+ | "null" when Array.length Sys.argv = 3 -> test_null_resolution Sys.argv.(2)
283283+ | "bool" when Array.length Sys.argv = 3 -> test_bool_resolution Sys.argv.(2)
284284+ | "number" when Array.length Sys.argv = 3 ->
285285+ test_number_resolution Sys.argv.(2)
286286+ | "string" when Array.length Sys.argv = 3 ->
287287+ test_string_resolution Sys.argv.(2)
288288+ | "special-float" when Array.length Sys.argv = 3 ->
289289+ test_special_floats Sys.argv.(2)
290290+ | "type-mismatch" when Array.length Sys.argv = 4 ->
291291+ test_type_mismatch Sys.argv.(2) Sys.argv.(3)
292292+ | "any" when Array.length Sys.argv = 3 -> test_any_resolution Sys.argv.(2)
293293+ | "encode" when Array.length Sys.argv = 4 ->
294294+ test_encode_formats Sys.argv.(2) Sys.argv.(3)
295295+ | _ ->
296296+ prerr_endline usage;
297297+ prerr_endline "Commands:";
298298+ prerr_endline " null <file> - Test null resolution";
299299+ prerr_endline
300300+ " bool <file> - Test bool vs string resolution";
301301+ prerr_endline " number <file> - Test number resolution";
302302+ prerr_endline " string <file> - Test string resolution";
303303+ prerr_endline " special-float <file> - Test .inf, .nan, etc.";
304304+ prerr_endline
305305+ " type-mismatch <file> <type> - Test error on type mismatch";
306306+ prerr_endline
307307+ " any <file> - Test Jsont.any auto-resolution";
308308+ prerr_endline " encode <type> <value> - Test encoding to JSON/YAML";
309309+ exit 1
···11+Edge Cases Tests with Yamlt
22+============================
33+44+This test suite validates edge cases including large numbers, special characters,
55+unicode, and boundary conditions.
66+77+================================================================================
88+LARGE NUMBERS
99+================================================================================
1010+1111+Very large and very small floating point numbers
1212+1313+ $ test_edge large-numbers ../data/edge/large_numbers.yml
1414+ JSON: large_numbers: large_int=9007199254740991, large_float=1.797693e+308, small_float=2.225074e-308
1515+ YAML: large_numbers: large_int=9007199254740991, large_float=1.797693e+308, small_float=2.225074e-308
1616+1717+================================================================================
1818+SPECIAL CHARACTERS
1919+================================================================================
2020+2121+Strings containing newlines, tabs, and other special characters
2222+2323+ $ test_edge special-chars ../data/edge/special_chars.yml
2424+ JSON: special_chars: length=34, contains_newline=true, contains_tab=true
2525+ YAML: special_chars: length=34, contains_newline=true, contains_tab=true
2626+2727+================================================================================
2828+UNICODE STRINGS
2929+================================================================================
3030+3131+Emoji, Chinese, and RTL text
3232+3333+ $ test_edge unicode ../data/edge/unicode.yml
3434+ JSON: unicode: emoji="\240\159\142\137\240\159\154\128\226\156\168", chinese="\228\189\160\229\165\189\228\184\150\231\149\140", rtl="\217\133\216\177\216\173\216\168\216\167"
3535+ YAML: unicode: emoji="\240\159\142\137\240\159\154\128\226\156\168", chinese="\228\189\160\229\165\189\228\184\150\231\149\140", rtl="\217\133\216\177\216\173\216\168\216\167"
3636+3737+================================================================================
3838+EMPTY COLLECTIONS
3939+================================================================================
4040+4141+Empty arrays and objects
4242+4343+ $ test_edge empty-collections ../data/edge/empty_collections.yml
4444+ JSON: empty_collections: empty_array_len=0, empty_object_array_len=0
4545+ YAML: empty_collections: empty_array_len=0, empty_object_array_len=0
4646+4747+================================================================================
4848+SPECIAL KEY NAMES
4949+================================================================================
5050+5151+Keys with dots, dashes, colons
5252+5353+ $ test_edge special-keys ../data/edge/special_keys.yml
5454+ JSON: special_keys: ERROR: Expected one of but found object
5555+ File "-", line 1, characters 0-1:
5656+ YAML: special_keys: ERROR: Expected one of but found object
5757+ File "-":
5858+5959+================================================================================
6060+SINGLE-ELEMENT ARRAYS
6161+================================================================================
6262+6363+Arrays with exactly one element
6464+6565+ $ test_edge single-element ../data/edge/single_element.yml
6666+ JSON: single_element: length=1, value=42
6767+ YAML: single_element: length=1, value=42
6868+6969+================================================================================
7070+NEGATIVE TESTS - Boundary Violations
7171+================================================================================
7272+7373+Using unicode data with number codec should fail
7474+7575+ $ test_edge large-numbers ../data/edge/unicode.yml
7676+ JSON: large_numbers: ERROR: Missing members in Numbers object:
7777+ large_float
7878+ large_int
7979+ small_float
8080+ File "-", line 1, characters 0-72:
8181+ YAML: large_numbers: ERROR: Missing members in Numbers object:
8282+ large_float
8383+ large_int
8484+ small_float
8585+ File "-":
+107
vendor/opam/yamlt/tests/cram/formats_codec.t
···11+Format-Specific Features Tests with Yamlt
22+==========================================
33+44+This test suite validates YAML-specific format features and compares with JSON behavior.
55+66+================================================================================
77+MULTI-LINE STRINGS - LITERAL STYLE
88+================================================================================
99+1010+Literal style (|) preserves newlines
1111+1212+ $ test_formats literal ../data/formats/literal_string.yml
1313+ JSON: literal_string: lines=5, length=81
1414+ YAML: literal_string: lines=5, length=81
1515+1616+================================================================================
1717+MULTI-LINE STRINGS - FOLDED STYLE
1818+================================================================================
1919+2020+Folded style (>) folds lines into single line
2121+2222+ $ test_formats folded ../data/formats/folded_string.yml
2323+ JSON: folded_string: length=114, newlines=1
2424+ YAML: folded_string: length=114, newlines=1
2525+2626+================================================================================
2727+NUMBER FORMATS
2828+================================================================================
2929+3030+YAML supports hex, octal, and binary number formats
3131+3232+ $ test_formats number-formats ../data/formats/number_formats.yml
3333+ JSON: number_formats: hex=255, octal=63, binary=10
3434+ YAML: number_formats: hex=255, octal=63, binary=10
3535+3636+================================================================================
3737+COMMENTS
3838+================================================================================
3939+4040+YAML comments are ignored during parsing
4141+4242+ $ test_formats comments ../data/formats/comments.yml
4343+ YAML (with comments): host="localhost", port=8080, debug=true
4444+4545+================================================================================
4646+EMPTY DOCUMENTS
4747+================================================================================
4848+4949+Empty or null documents handled correctly
5050+5151+ $ test_formats empty-doc ../data/formats/empty_doc.yml
5252+ JSON: empty_document: ERROR: Expected string but found null
5353+ File "-", line 1, characters 10-11:
5454+ File "-": in member value of
5555+ File "-", line 1, characters 0-11: Wrapper object
5656+ YAML: empty_document: ERROR: Expected string but found null
5757+ File "-":
5858+ File "-": in member value of
5959+ File "-": Wrapper object
6060+6161+================================================================================
6262+EXPLICIT TYPE TAGS
6363+================================================================================
6464+6565+Explicit YAML type tags (!!str, !!int, etc.)
6666+6767+ $ test_formats explicit-tags ../data/formats/explicit_tags.yml
6868+ YAML (with tags): data="123"
6969+7070+================================================================================
7171+ENCODING STYLES
7272+================================================================================
7373+7474+Compare Block vs Flow encoding styles
7575+7676+ $ test_formats encode-styles
7777+ YAML Block:
7878+ name: test
7979+ values:
8080+ - 1
8181+ - 2
8282+ - 3
8383+ nested:
8484+ enabled: true
8585+ count: 5
8686+8787+ YAML Flow:
8888+ {name: test, values: [1, 2, 3], nested: {enabled: true, count: 5}}
8989+9090+9191+================================================================================
9292+NEGATIVE TESTS - Format Compatibility
9393+================================================================================
9494+9595+Using literal string test with number codec should fail
9696+9797+ $ test_formats number-formats ../data/formats/literal_string.yml
9898+ JSON: number_formats: ERROR: Missing members in Numbers object:
9999+ binary
100100+ hex
101101+ octal
102102+ File "-", line 1, characters 0-100:
103103+ YAML: number_formats: ERROR: Missing members in Numbers object:
104104+ binary
105105+ hex
106106+ octal
107107+ File "-":
+217
vendor/opam/yamlt/tests/cram/locations.t
···11+Location and Layout Preservation Tests with Yamlt
22+==================================================
33+44+This test suite validates the `locs` and `layout` options in the Yamlt decoder,
55+demonstrating how they affect error messages and metadata preservation.
66+77+================================================================================
88+ERROR MESSAGE PRECISION - locs option
99+================================================================================
1010+1111+The `locs` option controls whether source locations are preserved in error messages.
1212+When `locs=false` (default), errors show basic location info.
1313+When `locs=true`, errors show precise character positions.
1414+1515+Basic type error with and without locs
1616+1717+ $ test_locations error-precision ../data/locations/type_error.yml
1818+ === Without locs (default) ===
1919+ Error message:
2020+ String "not-a-number" does not parse to OCaml int value
2121+ File "-":
2222+ File "-": in member age of
2323+ File "-": Person object
2424+2525+ === With locs=true ===
2626+ Error message:
2727+ String "not-a-number" does not parse to OCaml int value
2828+ File "-", line 2, characters 5-18:
2929+ File "-", line 2, characters 0-3: in member age of
3030+ File "-", line 1, characters 0-1: Person object
3131+3232+================================================================================
3333+NESTED ERROR LOCATIONS
3434+================================================================================
3535+3636+The `locs` option is especially useful for nested structures,
3737+showing exactly where deep errors occur.
3838+3939+Error in nested object field
4040+4141+ $ test_locations nested-error ../data/locations/nested_error.yml
4242+ === Without locs (default) ===
4343+ Nested error:
4444+ String "invalid-zip" does not parse to OCaml int value
4545+ File "-":
4646+ File "-": in member zip of
4747+ File "-": Address object
4848+ File "-": in member address of
4949+ File "-": Employee object
5050+5151+ === With locs=true ===
5252+ Nested error:
5353+ String "invalid-zip" does not parse to OCaml int value
5454+ File "-", line 5, characters 7-19:
5555+ File "-", line 5, characters 2-5: in member zip of
5656+ File "-", line 3, characters 2-3: Address object
5757+ File "-", line 2, characters 0-7: in member address of
5858+ File "-", line 1, characters 0-1: Employee object
5959+6060+================================================================================
6161+ARRAY ELEMENT ERROR LOCATIONS
6262+================================================================================
6363+6464+The `locs` option pinpoints which array element caused an error.
6565+6666+Error at specific array index
6767+6868+ $ test_locations array-error ../data/locations/array_error.yml
6969+ === Without locs (default) ===
7070+ Array error:
7171+ String "not-a-number" does not parse to OCaml int value
7272+ File "-":
7373+ at index 2 of
7474+ File "-": array<OCaml int>
7575+ File "-": in member values of
7676+ File "-": Numbers object
7777+7878+ === With locs=true ===
7979+ Array error:
8080+ String "not-a-number" does not parse to OCaml int value
8181+ File "-", lines 4-5, characters 4-2:
8282+ at index 2 of
8383+ File "-", line 2, characters 2-3: array<OCaml int>
8484+ File "-", line 1, characters 0-6: in member values of
8585+ File "-", line 1, characters 0-1: Numbers object
8686+8787+================================================================================
8888+FILE PATH IN ERROR MESSAGES
8989+================================================================================
9090+9191+The `file` parameter sets the file path shown in error messages.
9292+9393+ $ test_locations file-path
9494+ === Without file path ===
9595+ Error:
9696+ String "not-a-number" does not parse to OCaml int value
9797+ File "-", line 2, characters 5-18:
9898+ File "-", line 2, characters 0-3: in member age of
9999+ File "-", line 1, characters 0-1: Person object
100100+101101+ === With file path ===
102102+ Error:
103103+ String "not-a-number" does not parse to OCaml int value
104104+ File "test.yml", line 2, characters 5-18:
105105+ File "test.yml", line 2, characters 0-3: in member age of
106106+ File "test.yml", line 1, characters 0-1: Person object
107107+108108+================================================================================
109109+MISSING FIELD ERROR LOCATIONS
110110+================================================================================
111111+112112+The `locs` option helps identify where fields are missing.
113113+114114+ $ test_locations missing-field ../data/locations/missing_field.yml
115115+ === Without locs ===
116116+ Missing field:
117117+ Missing member field_c in Complete object
118118+ File "-":
119119+120120+ === With locs=true ===
121121+ Missing field:
122122+ Missing member field_c in Complete object
123123+ File "-", line 1, characters 0-1:
124124+125125+================================================================================
126126+LAYOUT PRESERVATION - layout option
127127+================================================================================
128128+129129+The `layout` option controls whether style information (block vs flow)
130130+is preserved in metadata for potential round-tripping.
131131+132132+Basic layout preservation
133133+134134+ $ test_locations layout ../data/locations/simple.yml
135135+ === Without layout (default) ===
136136+ Decoded: host=localhost, port=8080
137137+ Meta preserved: no
138138+139139+ === With layout=true ===
140140+ Decoded: host=localhost, port=8080
141141+ Meta preserved: yes (style info available for round-tripping)
142142+143143+================================================================================
144144+ROUND-TRIPPING WITH LAYOUT
145145+================================================================================
146146+147147+With `layout=true` during decode and `format:Layout` during encode,
148148+the original YAML style can be preserved.
149149+150150+Flow style preservation
151151+152152+ $ test_locations roundtrip ../data/locations/flow_style.yml
153153+ === Original YAML ===
154154+ items: [apple, banana, cherry]
155155+156156+ === Decode without layout, re-encode ===
157157+ items:
158158+ - apple
159159+ - banana
160160+ - cherry
161161+162162+ === Decode with layout=true, re-encode with Layout format ===
163163+ items:
164164+ - apple
165165+ - banana
166166+ - cherry
167167+168168+Block style preservation
169169+170170+ $ test_locations roundtrip ../data/locations/block_style.yml
171171+ === Original YAML ===
172172+ items:
173173+ - apple
174174+ - banana
175175+ - cherry
176176+177177+ === Decode without layout, re-encode ===
178178+ items:
179179+ - apple
180180+ - banana
181181+ - cherry
182182+183183+ === Decode with layout=true, re-encode with Layout format ===
184184+ items:
185185+ - apple
186186+ - banana
187187+ - cherry
188188+189189+================================================================================
190190+COMBINED OPTIONS - locs and layout together
191191+================================================================================
192192+193193+Both options can be used simultaneously for maximum information.
194194+195195+ $ test_locations combined ../data/locations/valid_settings.yml
196196+ === locs=false, layout=false (defaults) ===
197197+ OK: timeout=30, retries=3
198198+199199+ === locs=true, layout=false ===
200200+ OK: timeout=30, retries=3 (with precise locations)
201201+202202+ === locs=false, layout=true ===
203203+ OK: timeout=30, retries=3 (with layout metadata)
204204+205205+ === locs=true, layout=true (both enabled) ===
206206+ OK: timeout=30, retries=3 (with locations and layout)
207207+208208+================================================================================
209209+SUMMARY OF OPTIONS
210210+================================================================================
211211+212212+locs option:
213213+214214+layout option:
215215+216216+Both options add metadata overhead, so only enable when needed.
217217+For production parsing where you only need the data, use defaults (both false).
+220
vendor/opam/yamlt/tests/cram/multidoc.t
···11+Multi-Document YAML Streams with Yamlt
22+========================================
33+44+This test suite validates multi-document YAML stream decoding using decode_all,
55+including error handling, location tracking, and JSON roundtripping.
66+77+================================================================================
88+BASIC MULTIDOC DECODING
99+================================================================================
1010+1111+Simple multi-document stream with person objects
1212+1313+ $ test_multidoc simple ../data/multidoc/simple.yml
1414+ Documents:
1515+ [0] : Alice (age 30)
1616+ [1] : Bob (age 25)
1717+ [2] : Charlie (age 35)
1818+1919+Count documents in a stream
2020+2121+ $ test_multidoc count ../data/multidoc/simple.yml
2222+ Document count: 3
2323+2424+================================================================================
2525+ERROR HANDLING - MIXED VALID AND INVALID DOCUMENTS
2626+================================================================================
2727+2828+When some documents succeed and others fail, decode_all continues processing
2929+and returns results for each document individually.
3030+3131+Stream with one error in the middle
3232+3333+ $ test_multidoc errors ../data/multidoc/mixed_errors.yml
3434+ Document results:
3535+ [0] OK: Alice (age 30)
3636+ [1] ERROR: String "not-a-number" does not parse to OCaml int value
3737+ File "-":
3838+ File "-": in member age of
3939+ File "-": Person object
4040+ [2] OK: Charlie (age 35)
4141+4242+Summary statistics for mixed documents
4343+4444+ $ test_multidoc summary ../data/multidoc/mixed_errors.yml
4545+ Summary: 3 documents (2 ok, 1 error)
4646+4747+Stream where all documents fail
4848+4949+ $ test_multidoc errors ../data/multidoc/all_errors.yml
5050+ Document results:
5151+ [0] ERROR: String "invalid1" does not parse to OCaml int value
5252+ File "-":
5353+ File "-": in member age of
5454+ File "-": Person object
5555+ [1] ERROR: String "invalid2" does not parse to OCaml int value
5656+ File "-":
5757+ File "-": in member age of
5858+ File "-": Person object
5959+ [2] ERROR: String "invalid3" does not parse to OCaml int value
6060+ File "-":
6161+ File "-": in member age of
6262+ File "-": Person object
6363+6464+Summary for all-error stream
6565+6666+ $ test_multidoc summary ../data/multidoc/all_errors.yml
6767+ Summary: 3 documents (0 ok, 3 error)
6868+6969+================================================================================
7070+LOCATION TRACKING WITH locs=true
7171+================================================================================
7272+7373+Location tracking helps identify exactly where errors occur in each document
7474+of a multi-document stream.
7575+7676+Without locs (default) - basic error information
7777+7878+ $ test_multidoc locations ../data/multidoc/mixed_errors.yml
7979+ === Without locs (default) ===
8080+ [0] OK
8181+ [1] ERROR:
8282+ String "not-a-number" does not parse to OCaml int value
8383+ File "-":
8484+ File "-": in member age of
8585+ File "-": Person object
8686+ [2] OK
8787+8888+ === With locs=true ===
8989+ [0] OK
9090+ [1] ERROR:
9191+ String "not-a-number" does not parse to OCaml int value
9292+ File "test.yml", line 6, characters 5-18:
9393+ File "test.yml", line 6, characters 0-3: in member age of
9494+ File "test.yml", line 5, characters 0-1: Person object
9595+ [2] OK
9696+9797+================================================================================
9898+MISSING FIELDS IN MULTIDOC
9999+================================================================================
100100+101101+Documents with missing required fields generate errors but don't stop
102102+processing of subsequent documents.
103103+104104+ $ test_multidoc errors ../data/multidoc/missing_fields.yml
105105+ Document results:
106106+ [0] OK: Alice (age 30)
107107+ [1] ERROR: Missing member age in Person object
108108+ File "-":
109109+ [2] OK: Charlie (age 35)
110110+111111+Summary of missing fields test
112112+113113+ $ test_multidoc summary ../data/multidoc/missing_fields.yml
114114+ Summary: 3 documents (2 ok, 1 error)
115115+116116+================================================================================
117117+JSON ROUNDTRIPPING
118118+================================================================================
119119+120120+Decode YAML multi-document streams and encode each document as JSON.
121121+This validates that the data model conversion is correct.
122122+123123+Simple documents to JSON
124124+125125+ $ test_multidoc json ../data/multidoc/simple.yml
126126+ JSON outputs:
127127+ [0] {"name":"Alice","age":30}
128128+ [1] {"name":"Bob","age":25}
129129+ [2] {"name":"Charlie","age":35}
130130+131131+Nested objects to JSON
132132+133133+ $ test_multidoc json ../data/multidoc/nested.yml
134134+ JSON outputs:
135135+ [0] {"name":"Alice","age":30,"address":{"street":"123 Main St","city":"Boston"}}
136136+ [1] {"name":"Bob","age":25,"address":{"street":"456 Oak Ave","city":"Seattle"}}
137137+ [2] {"name":"Charlie","age":35,"address":{"street":"789 Pine Rd","city":"Portland"}}
138138+139139+Arrays to JSON
140140+141141+ $ test_multidoc json ../data/multidoc/arrays.yml
142142+ JSON outputs:
143143+ [0] [1,2,3]
144144+ [1] ["apple","banana","cherry"]
145145+ [2] [true,false,true]
146146+147147+Scalar values to JSON
148148+149149+ $ test_multidoc json ../data/multidoc/scalars.yml
150150+ JSON outputs:
151151+ [0] "hello world"
152152+ [1] 42
153153+ [2] true
154154+ [3] null
155155+156156+================================================================================
157157+NESTED OBJECTS IN MULTIDOC
158158+================================================================================
159159+160160+Test decoding complex nested structures across multiple documents.
161161+162162+ $ test_multidoc nested ../data/multidoc/nested.yml
163163+ Nested documents:
164164+ [0] : Alice (age 30) from 123 Main St, Boston
165165+ [1] : Bob (age 25) from 456 Oak Ave, Seattle
166166+ [2] : Charlie (age 35) from 789 Pine Rd, Portland
167167+168168+================================================================================
169169+ARRAYS IN MULTIDOC
170170+================================================================================
171171+172172+Test decoding different array types across documents.
173173+174174+ $ test_multidoc arrays ../data/multidoc/arrays.yml
175175+ Array documents:
176176+ [0] [1,2,3]
177177+ [1] ["apple","banana","cherry"]
178178+ [2] [true,false,true]
179179+180180+================================================================================
181181+SCALARS IN MULTIDOC
182182+================================================================================
183183+184184+Test decoding bare scalar values as documents.
185185+186186+ $ test_multidoc scalars ../data/multidoc/scalars.yml
187187+ Scalar documents:
188188+ [0] "hello world"
189189+ [1] 42
190190+ [2] true
191191+ [3] null
192192+193193+================================================================================
194194+EMPTY DOCUMENTS
195195+================================================================================
196196+197197+Empty or null documents in a stream are handled correctly.
198198+199199+ $ test_multidoc json ../data/multidoc/empty_docs.yml
200200+ JSON outputs:
201201+ [0] {"name":"Alice","age":30}
202202+ [1] null
203203+ [2] {"name":"Charlie","age":35}
204204+205205+Count including empty documents
206206+207207+ $ test_multidoc count ../data/multidoc/empty_docs.yml
208208+ Document count: 3
209209+210210+================================================================================
211211+SUMMARY
212212+================================================================================
213213+214214+The decode_all function:
215215+- Processes all documents in a stream, not stopping on errors
216216+- Returns a sequence of Result values (Ok/Error for each document)
217217+- Supports all decode options: locs, layout, file, max_depth, max_nodes
218218+- Correctly handles document boundaries even when errors occur
219219+- Works with any Jsont codec (objects, arrays, scalars, etc.)
220220+- Can be used for JSON roundtripping and format conversion
+37
vendor/opam/yamlt/tests/cram/null_collections.t
···11+Null to Empty Collection Tests
22+================================
33+44+This test suite validates that yamlt treats null values as empty collections
55+when decoding into Array or Object types, providing a more user-friendly
66+YAML experience.
77+88+================================================================================
99+NULL AS EMPTY COLLECTION
1010+================================================================================
1111+1212+Test various forms of null decoding as empty arrays and objects
1313+1414+ $ test_null_collections
1515+ === Test 1: Explicit null as empty array ===
1616+ Result: []
1717+1818+ === Test 2: Tilde as empty array ===
1919+ Result: []
2020+2121+ === Test 3: Empty array syntax ===
2222+ Result: []
2323+2424+ === Test 4: Array with values ===
2525+ Result: [1; 2; 3]
2626+2727+ === Test 5: Explicit null as empty object ===
2828+ Result: {timeout=30; retries=3}
2929+3030+ === Test 6: Empty object syntax ===
3131+ Result: {timeout=30; retries=3}
3232+3333+ === Test 7: Object with values ===
3434+ Result: {timeout=60; retries=5}
3535+3636+ === Test 8: Nested null arrays ===
3737+ Result: {name=test; items_count=0; tags_count=0}
+160
vendor/opam/yamlt/tests/cram/objects_codec.t
···11+Object Codec Tests with Yamlt
22+================================
33+44+This test suite validates object encoding/decoding with Jsont codecs in YAML,
55+and compares behavior with JSON.
66+77+Setup
88+-----
99+1010+1111+================================================================================
1212+SIMPLE OBJECTS
1313+================================================================================
1414+1515+Decode simple object with required fields
1616+1717+ $ test_objects simple ../data/objects/simple.yml
1818+ JSON: person: {name="Alice"; age=30}
1919+ YAML: person: {name="Alice"; age=30}
2020+2121+================================================================================
2222+OPTIONAL FIELDS
2323+================================================================================
2424+2525+Object with all optional fields present
2626+2727+ $ test_objects optional ../data/objects/optional_all.yml
2828+ JSON: config: {host="localhost"; port=Some 8080; debug=Some true}
2929+ YAML: config: {host="localhost"; port=Some 8080; debug=Some true}
3030+3131+Object with some optional fields missing
3232+3333+ $ test_objects optional ../data/objects/optional_partial.yml
3434+ JSON: config: {host="example.com"; port=Some 3000; debug=None}
3535+ YAML: config: {host="example.com"; port=Some 3000; debug=None}
3636+3737+Object with only required field
3838+3939+ $ test_objects optional ../data/objects/optional_minimal.yml
4040+ JSON: config: {host="minimal.com"; port=None; debug=None}
4141+ YAML: config: {host="minimal.com"; port=None; debug=None}
4242+4343+================================================================================
4444+DEFAULT VALUES
4545+================================================================================
4646+4747+Empty object uses all defaults
4848+4949+ $ test_objects defaults ../data/objects/defaults_empty.yml
5050+ JSON: settings: {timeout=30; retries=3; verbose=false}
5151+ YAML: settings: {timeout=30; retries=3; verbose=false}
5252+5353+Object with partial fields uses defaults for missing ones
5454+5555+ $ test_objects defaults ../data/objects/defaults_partial.yml
5656+ JSON: settings: {timeout=60; retries=3; verbose=false}
5757+ YAML: settings: {timeout=60; retries=3; verbose=false}
5858+5959+================================================================================
6060+NESTED OBJECTS
6161+================================================================================
6262+6363+Objects containing other objects
6464+6565+ $ test_objects nested ../data/objects/nested.yml
6666+ JSON: employee: {name="Bob"; address={street="123 Main St"; city="Springfield"; zip="12345"}}
6767+ YAML: employee: {name="Bob"; address={street="123 Main St"; city="Springfield"; zip="12345"}}
6868+6969+================================================================================
7070+UNKNOWN MEMBER HANDLING
7171+================================================================================
7272+7373+Unknown members cause error by default
7474+7575+ $ test_objects unknown-error ../data/objects/unknown_members.yml
7676+ Unexpected success
7777+7878+Unknown members can be kept
7979+8080+ $ test_objects unknown-keep ../data/objects/unknown_keep.yml
8181+ JSON: flexible: {name="Charlie"; has_extra=true}
8282+ YAML: flexible: {name="Charlie"; has_extra=true}
8383+8484+================================================================================
8585+OBJECT CASES (DISCRIMINATED UNIONS)
8686+================================================================================
8787+8888+Decode circle variant
8989+9090+ $ test_objects cases ../data/objects/case_circle.yml
9191+ JSON: shape: Circle{radius=5.50}
9292+ YAML: shape: Circle{radius=5.50}
9393+9494+Decode rectangle variant
9595+9696+ $ test_objects cases ../data/objects/case_rectangle.yml
9797+ JSON: shape: ERROR: Missing member radius in Circle object
9898+ File "-", line 1, characters 0-52:
9999+ YAML: shape: ERROR: Missing member radius in Circle object
100100+ File "-":
101101+102102+================================================================================
103103+ERROR HANDLING
104104+================================================================================
105105+106106+Missing required field produces error
107107+108108+ $ test_objects missing-required ../data/objects/missing_required.yml
109109+ Expected error: Missing member age in Required object
110110+ File "-":
111111+112112+================================================================================
113113+ENCODING OBJECTS
114114+================================================================================
115115+116116+Encode objects to JSON and YAML formats
117117+118118+ $ test_objects encode
119119+ JSON: {"name":"Alice","age":30,"active":true}
120120+ YAML Block:
121121+ name: Alice
122122+ age: 30
123123+ active: true
124124+ YAML Flow: {name: Alice, age: 30, active: true}
125125+126126+================================================================================
127127+NEGATIVE TESTS - Wrong File Types
128128+================================================================================
129129+130130+Attempting to decode an array file with an object codec should fail
131131+132132+ $ test_objects simple ../data/arrays/int_array.yml
133133+ JSON: person: ERROR: Missing members in Person object:
134134+ age
135135+ name
136136+ File "-", line 1, characters 0-27:
137137+ YAML: person: ERROR: Missing members in Person object:
138138+ age
139139+ name
140140+ File "-":
141141+142142+Attempting to decode a scalar file with an object codec should fail
143143+144144+ $ test_objects simple ../data/scalars/string_plain.yml
145145+ JSON: person: ERROR: Missing members in Person object:
146146+ age
147147+ name
148148+ File "-", line 1, characters 0-24:
149149+ YAML: person: ERROR: Missing members in Person object:
150150+ age
151151+ name
152152+ File "-":
153153+154154+Attempting to decode wrong object type (nested when expecting simple) should fail
155155+156156+ $ test_objects simple ../data/objects/nested.yml
157157+ JSON: person: ERROR: Missing member age in Person object
158158+ File "-", line 1, characters 0-92:
159159+ YAML: person: ERROR: Missing member age in Person object
160160+ File "-":
+46
vendor/opam/yamlt/tests/cram/roundtrip_codec.t
···11+Roundtrip Encoding/Decoding Tests with Yamlt
22+=============================================
33+44+This test suite validates that data can be encoded and then decoded back
55+to the original value, ensuring no data loss in the roundtrip process.
66+77+================================================================================
88+SCALAR ROUNDTRIP
99+================================================================================
1010+1111+Encode and decode scalar types
1212+1313+ $ test_roundtrip scalar
1414+ JSON roundtrip: PASS
1515+ YAML Block roundtrip: PASS
1616+ YAML Flow roundtrip: PASS
1717+1818+================================================================================
1919+ARRAY ROUNDTRIP
2020+================================================================================
2121+2222+Encode and decode arrays including nested arrays
2323+2424+ $ test_roundtrip array
2525+ JSON array roundtrip: PASS
2626+ YAML array roundtrip: PASS
2727+2828+================================================================================
2929+OBJECT ROUNDTRIP
3030+================================================================================
3131+3232+Encode and decode complex objects with nested structures
3333+3434+ $ test_roundtrip object
3535+ JSON object roundtrip: PASS
3636+ YAML object roundtrip: PASS
3737+3838+================================================================================
3939+OPTIONAL FIELDS ROUNDTRIP
4040+================================================================================
4141+4242+Encode and decode optional and nullable fields
4343+4444+ $ test_roundtrip optional
4545+ Fatal error: exception Invalid_argument("option is None")
4646+ [2]
+339
vendor/opam/yamlt/tests/cram/scalars_codec.t
···11+Scalar Type Resolution Tests with Yamlt Codec
22+==================================================
33+44+This test suite validates how YAML scalars are resolved based on the expected
55+Jsont type codec, and compares behavior with JSON decoding.
66+77+================================================================================
88+NULL RESOLUTION
99+================================================================================
1010+1111+Explicit null value
1212+1313+ $ test_scalars null ../data/scalars/null_explicit.yml
1414+ null_codec: null
1515+1616+Tilde as null
1717+1818+ $ test_scalars null ../data/scalars/null_tilde.yml
1919+ null_codec: null
2020+2121+Empty value as null
2222+2323+ $ test_scalars null ../data/scalars/null_empty.yml
2424+ null_codec: null
2525+2626+================================================================================
2727+BOOLEAN TYPE-DIRECTED RESOLUTION
2828+================================================================================
2929+3030+Plain "true" resolves to bool(true) with bool codec, but string "true" with string codec
3131+3232+ $ test_scalars bool ../data/scalars/bool_true_plain.yml
3333+ === Bool Codec ===
3434+ JSON bool_codec
3535+ decode: true
3636+ YAML bool_codec
3737+ decode: true
3838+3939+ === String Codec ===
4040+ JSON string_codec
4141+ decode: ERROR: Expected string but found bool
4242+ File "-", line 1, characters 10-11:
4343+ File "-": in member value of
4444+ File "-", line 1, characters 0-11: StringTest object
4545+ YAML string_codec
4646+ decode: "true"
4747+4848+Quoted "true" always resolves to string, even with bool codec
4949+5050+ $ test_scalars bool ../data/scalars/bool_true_quoted.yml
5151+ === Bool Codec ===
5252+ JSON bool_codec
5353+ decode: ERROR: Expected bool but found string
5454+ File "-", line 1, characters 10-11:
5555+ File "-": in member value of
5656+ File "-", line 1, characters 0-11: BoolTest object
5757+ YAML bool_codec
5858+ decode: true
5959+6060+ === String Codec ===
6161+ JSON string_codec
6262+ decode: "true"
6363+ YAML string_codec
6464+ decode: "true"
6565+6666+YAML-specific bool: "yes" resolves to bool(true)
6767+6868+ $ test_scalars bool ../data/scalars/bool_yes.yml
6969+ === Bool Codec ===
7070+ JSON bool_codec
7171+ decode: true
7272+ YAML bool_codec
7373+ decode: true
7474+7575+ === String Codec ===
7676+ JSON string_codec
7777+ decode: ERROR: Expected string but found bool
7878+ File "-", line 1, characters 10-11:
7979+ File "-": in member value of
8080+ File "-", line 1, characters 0-11: StringTest object
8181+ YAML string_codec
8282+ decode: "yes"
8383+8484+Plain "false" and "no" work similarly
8585+8686+ $ test_scalars bool ../data/scalars/bool_false.yml
8787+ === Bool Codec ===
8888+ JSON bool_codec
8989+ decode: false
9090+ YAML bool_codec
9191+ decode: false
9292+9393+ === String Codec ===
9494+ JSON string_codec
9595+ decode: ERROR: Expected string but found bool
9696+ File "-", line 1, characters 10-11:
9797+ File "-": in member value of
9898+ File "-", line 1, characters 0-11: StringTest object
9999+ YAML string_codec
100100+ decode: "false"
101101+102102+ $ test_scalars bool ../data/scalars/bool_no.yml
103103+ === Bool Codec ===
104104+ JSON bool_codec
105105+ decode: false
106106+ YAML bool_codec
107107+ decode: false
108108+109109+ === String Codec ===
110110+ JSON string_codec
111111+ decode: ERROR: Expected string but found bool
112112+ File "-", line 1, characters 10-11:
113113+ File "-": in member value of
114114+ File "-", line 1, characters 0-11: StringTest object
115115+ YAML string_codec
116116+ decode: "no"
117117+118118+================================================================================
119119+NUMBER RESOLUTION
120120+================================================================================
121121+122122+Integer values
123123+124124+ $ test_scalars number ../data/scalars/number_int.yml
125125+ JSON number_codec
126126+ decode: 42
127127+ YAML number_codec
128128+ decode: 42
129129+130130+Float values
131131+132132+ $ test_scalars number ../data/scalars/number_float.yml
133133+ JSON number_codec
134134+ decode: 3.1415899999999999
135135+ YAML number_codec
136136+ decode: 3.1415899999999999
137137+138138+Hexadecimal notation (YAML-specific)
139139+140140+ $ test_scalars number ../data/scalars/number_hex.yml
141141+ JSON number_codec
142142+ decode: 42
143143+ YAML number_codec
144144+ decode: 42
145145+146146+Octal notation (YAML-specific)
147147+148148+ $ test_scalars number ../data/scalars/number_octal.yml
149149+ JSON number_codec
150150+ decode: 42
151151+ YAML number_codec
152152+ decode: 42
153153+154154+Negative numbers
155155+156156+ $ test_scalars number ../data/scalars/number_negative.yml
157157+ JSON number_codec
158158+ decode: -273.14999999999998
159159+ YAML number_codec
160160+ decode: -273.14999999999998
161161+162162+================================================================================
163163+SPECIAL FLOAT VALUES (YAML-specific)
164164+================================================================================
165165+166166+Positive infinity
167167+168168+ $ test_scalars special-float ../data/scalars/special_inf.yml
169169+ value: +Infinity
170170+171171+Negative infinity
172172+173173+ $ test_scalars special-float ../data/scalars/special_neg_inf.yml
174174+ value: -Infinity
175175+176176+Not-a-Number (NaN)
177177+178178+ $ test_scalars special-float ../data/scalars/special_nan.yml
179179+ value: NaN
180180+181181+================================================================================
182182+STRING RESOLUTION
183183+================================================================================
184184+185185+Plain strings
186186+187187+ $ test_scalars string ../data/scalars/string_plain.yml
188188+ JSON string_codec
189189+ decode: "hello world"
190190+ YAML string_codec
191191+ decode: "hello world"
192192+193193+Quoted numeric strings stay as strings
194194+195195+ $ test_scalars string ../data/scalars/string_quoted.yml
196196+ JSON string_codec
197197+ decode: "42"
198198+ YAML string_codec
199199+ decode: "42"
200200+201201+Empty strings
202202+203203+ $ test_scalars string ../data/scalars/string_empty.yml
204204+ JSON string_codec
205205+ decode: ""
206206+ YAML string_codec
207207+ decode: ""
208208+209209+================================================================================
210210+TYPE MISMATCH ERRORS
211211+================================================================================
212212+213213+String when bool expected
214214+215215+ $ test_scalars type-mismatch ../data/scalars/mismatch_string_as_bool.yml bool
216216+ Expected error: Expected bool but found scalar hello
217217+ File "-":
218218+ File "-": in member value of
219219+ File "-": BoolTest object
220220+221221+String when number expected
222222+223223+ $ test_scalars type-mismatch ../data/scalars/mismatch_string_as_number.yml number
224224+ Expected error: Expected number but found scalar not-a-number
225225+ File "-":
226226+ File "-": in member value of
227227+ File "-": NumberTest object
228228+229229+Number when null expected
230230+231231+ $ test_scalars type-mismatch ../data/scalars/mismatch_number_as_null.yml null
232232+ Expected error: Expected null but found scalar 42
233233+ File "-":
234234+ File "-": in member value of
235235+ File "-": NullTest object
236236+237237+================================================================================
238238+JSONT.ANY AUTO-RESOLUTION
239239+================================================================================
240240+241241+With Jsont.any, scalars are auto-resolved based on their content
242242+243243+Null auto-resolves to null
244244+245245+ $ test_scalars any ../data/scalars/any_null.yml
246246+ JSON any_codec
247247+ decode: decoded
248248+ YAML any_codec
249249+ decode: decoded
250250+251251+Plain bool auto-resolves to bool
252252+253253+ $ test_scalars any ../data/scalars/any_bool.yml
254254+ JSON any_codec
255255+ decode: decoded
256256+ YAML any_codec
257257+ decode: decoded
258258+259259+Number auto-resolves to number
260260+261261+ $ test_scalars any ../data/scalars/any_number.yml
262262+ JSON any_codec
263263+ decode: decoded
264264+ YAML any_codec
265265+ decode: decoded
266266+267267+Plain string auto-resolves to string
268268+269269+ $ test_scalars any ../data/scalars/any_string.yml
270270+ JSON any_codec
271271+ decode: decoded
272272+ YAML any_codec
273273+ decode: decoded
274274+275275+================================================================================
276276+ENCODING SCALARS
277277+================================================================================
278278+279279+Encoding bool values
280280+281281+ $ test_scalars encode bool true
282282+ JSON: {"value":true}
283283+ YAML Block:
284284+ value: true
285285+ YAML Flow: {value: true}
286286+287287+ $ test_scalars encode bool false
288288+ JSON: {"value":false}
289289+ YAML Block:
290290+ value: false
291291+ YAML Flow: {value: false}
292292+293293+Encoding numbers
294294+295295+ $ test_scalars encode number 42.5
296296+ JSON: {"value":42.5}
297297+ YAML Block:
298298+ value: 42.5
299299+ YAML Flow: {value: 42.5}
300300+301301+Encoding strings
302302+303303+ $ test_scalars encode string "hello world"
304304+ JSON: {"value":"hello world"}
305305+ YAML Block:
306306+ value: hello world
307307+ YAML Flow: {value: hello world}
308308+309309+Encoding null
310310+311311+ $ test_scalars encode null ""
312312+ JSON: {"value":null}
313313+ YAML Block:
314314+ value: null
315315+ YAML Flow: {value: null}
316316+317317+================================================================================
318318+NEGATIVE TESTS - Wrong File Types
319319+================================================================================
320320+321321+Attempting to decode an object file with a scalar codec should fail
322322+323323+ $ test_scalars string ../data/objects/simple.yml
324324+ JSON string_codec
325325+ decode: ERROR: Missing member value in StringTest object
326326+ File "-", line 1, characters 0-28:
327327+ YAML string_codec
328328+ decode: ERROR: Missing member value in StringTest object
329329+ File "-":
330330+331331+Attempting to decode an array file with a scalar codec should fail
332332+333333+ $ test_scalars number ../data/arrays/int_array.yml
334334+ JSON number_codec
335335+ decode: ERROR: Missing member value in NumberTest object
336336+ File "-", line 1, characters 0-27:
337337+ YAML number_codec
338338+ decode: ERROR: Missing member value in NumberTest object
339339+ File "-":
···11+# Configuration file with comments
22+host: localhost # The server host
33+port: 8080 # The server port
44+# Enable debug mode for development
55+debug: true