OCaml codecs for the Citation File Format (CFF)
1(*---------------------------------------------------------------------------
2 Copyright (c) 2026 The ocaml-cff programmers. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6(* Test the CFF Eio backend *)
7
8let minimal_cff =
9 {|
10cff-version: 1.2.0
11message: If you use this software, please cite it
12title: Test Software
13authors:
14- family-names: Smith
15 given-names: Jane
16|}
17;;
18
19let simple_cff =
20 {|
21cff-version: 1.2.0
22message: Please cite this software using these metadata.
23title: My Research Software
24authors:
25 - family-names: Druskat
26 given-names: Stephan
27 orcid: https://orcid.org/0000-0003-4925-7248
28version: 1.0.0
29doi: 10.5281/zenodo.1234567
30date-released: 2021-08-11
31|}
32;;
33
34let test_parse_string () =
35 let cff = Cff_eio.of_yaml_string minimal_cff in
36 Alcotest.(check string) "cff-version" "1.2.0" (Cff.cff_version cff);
37 Alcotest.(check string) "title" "Test Software" (Cff.title cff);
38 Alcotest.(check int) "authors count" 1 (List.length (Cff.authors cff))
39;;
40
41let test_roundtrip_string () =
42 let cff1 = Cff_eio.of_yaml_string simple_cff in
43 let yaml = Cff_eio.to_yaml_string cff1 in
44 let cff2 = Cff_eio.of_yaml_string yaml in
45 Alcotest.(check string) "title preserved" (Cff.title cff1) (Cff.title cff2);
46 Alcotest.(check string)
47 "cff-version preserved"
48 (Cff.cff_version cff1)
49 (Cff.cff_version cff2)
50;;
51
52let test_parse_error () =
53 let invalid_yaml =
54 {|
55cff-version: 1.2.0
56title: Missing authors field
57|}
58 in
59 match Cff_eio.of_yaml_string invalid_yaml with
60 | _ -> Alcotest.fail "Expected parse error"
61 | exception Eio.Exn.Io (Cff_eio.E _, _) -> ()
62 | exception ex ->
63 Alcotest.fail (Printf.sprintf "Wrong exception type: %s" (Printexc.to_string ex))
64;;
65
66let test_file_read env =
67 let fs = Eio.Stdenv.fs env in
68 let cff =
69 Cff_eio.of_file
70 ~fs
71 "../vendor/git/citation-file-format/examples/1.2.0/pass/minimal/CITATION.cff"
72 in
73 Alcotest.(check string) "cff-version" "1.2.0" (Cff.cff_version cff);
74 Alcotest.(check bool) "has title" true (String.length (Cff.title cff) > 0);
75 Alcotest.(check bool) "has authors" true (List.length (Cff.authors cff) > 0)
76;;
77
78let test_file_not_found env =
79 let fs = Eio.Stdenv.fs env in
80 match Cff_eio.of_file ~fs "nonexistent_file.cff" with
81 | _ -> Alcotest.fail "Expected file not found error"
82 | exception Eio.Exn.Io _ -> ()
83 | exception ex ->
84 Alcotest.fail (Printf.sprintf "Wrong exception type: %s" (Printexc.to_string ex))
85;;
86
87let test_file_roundtrip env =
88 let fs = Eio.Stdenv.fs env in
89 let cff1 =
90 Cff_eio.of_file
91 ~fs
92 "../vendor/git/citation-file-format/examples/1.2.0/pass/simple/CITATION.cff"
93 in
94 let tmp_path = "_build/test_roundtrip.cff" in
95 Cff_eio.to_file ~fs tmp_path cff1;
96 let cff2 = Cff_eio.of_file ~fs tmp_path in
97 Alcotest.(check string) "title preserved" (Cff.title cff1) (Cff.title cff2);
98 Alcotest.(check string)
99 "cff-version preserved"
100 (Cff.cff_version cff1)
101 (Cff.cff_version cff2)
102;;
103
104let () =
105 Eio_main.run
106 @@ fun env ->
107 Alcotest.run
108 "CFF Eio"
109 [ ( "string parsing"
110 , [ Alcotest.test_case "parse string" `Quick test_parse_string
111 ; Alcotest.test_case "roundtrip string" `Quick test_roundtrip_string
112 ; Alcotest.test_case "parse error" `Quick test_parse_error
113 ] )
114 ; ( "file operations"
115 , [ Alcotest.test_case "read file" `Quick (fun () -> test_file_read env)
116 ; Alcotest.test_case "file not found" `Quick (fun () -> test_file_not_found env)
117 ; Alcotest.test_case "file roundtrip" `Quick (fun () -> test_file_roundtrip env)
118 ] )
119 ]
120;;