Find and remove dead code and unused APIs in OCaml projects
1(* Tests for the cache module *)
2open Alcotest
3open Prune
4
5let temp_file_fn content =
6 let file = Filename.temp_file "cache_test" ".txt" in
7 let oc = open_out file in
8 output_string oc content;
9 close_out oc;
10 file
11
12let read_file file =
13 let ic = open_in file in
14 let content = really_input_string ic (in_channel_length ic) in
15 close_in ic;
16 content
17
18let test_create_and_clear () =
19 let cache = Cache.v () in
20 let make_temp_file = temp_file_fn "line1\nline2\nline3" in
21
22 (* Load file into cache *)
23 (match Cache.load cache make_temp_file with
24 | Ok () -> ()
25 | Error (`Msg msg) -> fail msg);
26
27 (* Verify file is loaded *)
28 check (option string) "line 1" (Some "line1")
29 (Cache.line cache make_temp_file 1);
30 check (option string) "line 2" (Some "line2")
31 (Cache.line cache make_temp_file 2);
32
33 (* Clear cache *)
34 Cache.clear cache;
35
36 (* Verify cache is empty *)
37 check (option string) "after clear" None (Cache.line cache make_temp_file 1);
38
39 Sys.remove make_temp_file
40
41let test_load_and_get_line () =
42 let cache = Cache.v () in
43 let content = "first line\nsecond line\nthird line" in
44 let make_temp_file = temp_file_fn content in
45
46 (* Test get_line before loading *)
47 check (option string) "before load" None (Cache.line cache make_temp_file 1);
48
49 (* Load file *)
50 (match Cache.load cache make_temp_file with
51 | Ok () -> ()
52 | Error (`Msg msg) -> fail msg);
53
54 (* Test get_line after loading *)
55 check (option string) "line 1" (Some "first line")
56 (Cache.line cache make_temp_file 1);
57 check (option string) "line 2" (Some "second line")
58 (Cache.line cache make_temp_file 2);
59 check (option string) "line 3" (Some "third line")
60 (Cache.line cache make_temp_file 3);
61
62 (* Test out of bounds *)
63 check (option string) "line 0" None (Cache.line cache make_temp_file 0);
64 check (option string) "line 4" None (Cache.line cache make_temp_file 4);
65
66 Sys.remove make_temp_file
67
68let test_replace_line () =
69 let cache = Cache.v () in
70 let content = "AAA\nBBB\nCCC" in
71 let make_temp_file = temp_file_fn content in
72
73 (* Load file *)
74 (match Cache.load cache make_temp_file with
75 | Ok () -> ()
76 | Error (`Msg msg) -> fail msg);
77
78 (* Replace line 2 *)
79 Cache.replace_line cache make_temp_file 2 "XXX";
80
81 (* Verify replacement *)
82 check (option string) "line 1 unchanged" (Some "AAA")
83 (Cache.line cache make_temp_file 1);
84 check (option string) "line 2 replaced" (Some "XXX")
85 (Cache.line cache make_temp_file 2);
86 check (option string) "line 3 unchanged" (Some "CCC")
87 (Cache.line cache make_temp_file 3);
88
89 (* Test out of bounds replace *)
90 Cache.replace_line cache make_temp_file 0 "invalid";
91 Cache.replace_line cache make_temp_file 4 "invalid";
92
93 (* Lines should be unchanged *)
94 check (option string) "after invalid replace" (Some "XXX")
95 (Cache.line cache make_temp_file 2);
96
97 Sys.remove make_temp_file
98
99let test_clear_line () =
100 let cache = Cache.v () in
101 let content = "line1\nline2\nline3" in
102 let make_temp_file = temp_file_fn content in
103
104 (* Load file *)
105 (match Cache.load cache make_temp_file with
106 | Ok () -> ()
107 | Error (`Msg msg) -> fail msg);
108
109 (* Clear line 2 *)
110 Cache.clear_line cache make_temp_file 2;
111
112 (* Verify clearing *)
113 check (option string) "line 1 unchanged" (Some "line1")
114 (Cache.line cache make_temp_file 1);
115 check (option string) "line 2 cleared" (Some "")
116 (Cache.line cache make_temp_file 2);
117 check (option string) "line 3 unchanged" (Some "line3")
118 (Cache.line cache make_temp_file 3);
119
120 Sys.remove make_temp_file
121
122let test_get_line_count () =
123 let cache = Cache.v () in
124
125 (* Test non-existent file *)
126 check (option int) "non-existent file" None
127 (Cache.line_count cache "nonexistent.txt");
128
129 let content = "one\ntwo\nthree\nfour" in
130 let make_temp_file = temp_file_fn content in
131
132 (* Load file *)
133 (match Cache.load cache make_temp_file with
134 | Ok () -> ()
135 | Error (`Msg msg) -> fail msg);
136
137 (* Check line count *)
138 check (option int) "line count" (Some 4)
139 (Cache.line_count cache make_temp_file);
140
141 (* Test empty file *)
142 let empty_file = temp_file_fn "" in
143 (match Cache.load cache empty_file with
144 | Ok () -> ()
145 | Error (`Msg msg) -> fail msg);
146 check (option int) "empty file" (Some 1) (Cache.line_count cache empty_file);
147
148 Sys.remove make_temp_file;
149 Sys.remove empty_file
150
151let test_write_with_changes () =
152 let cache = Cache.v () in
153 let content = "original1\noriginal2\noriginal3" in
154 let make_temp_file = temp_file_fn content in
155
156 (* Load file *)
157 (match Cache.load cache make_temp_file with
158 | Ok () -> ()
159 | Error (`Msg msg) -> fail msg);
160
161 (* Make changes *)
162 Cache.replace_line cache make_temp_file 1 "modified1";
163 Cache.clear_line cache make_temp_file 2;
164 Cache.replace_line cache make_temp_file 3 "modified3";
165
166 (* Write to disk *)
167 (match Cache.write cache make_temp_file with
168 | Ok () -> ()
169 | Error (`Msg msg) -> fail msg);
170
171 (* Read file and verify *)
172 let new_content = read_file make_temp_file in
173 check string "written content" "modified1\n\nmodified3" new_content;
174
175 Sys.remove make_temp_file
176
177let test_write_without_changes_fails () =
178 let cache = Cache.v () in
179 let content = "line1\nline2" in
180 let make_temp_file = temp_file_fn content in
181
182 (* Load file *)
183 (match Cache.load cache make_temp_file with
184 | Ok () -> ()
185 | Error (`Msg msg) -> fail msg);
186
187 (* Try to write without making changes - should fail *)
188 let write_result =
189 try
190 let _ = Cache.write cache make_temp_file in
191 false
192 with Failure msg ->
193 (* Check the error message *)
194 check bool "error message contains BUG" true
195 (String.starts_with ~prefix:"BUG: Attempted to write file" msg);
196 true
197 in
198
199 check bool "write without changes fails" true write_result;
200
201 Sys.remove make_temp_file
202
203let test_no_change_tracking () =
204 let cache = Cache.v () in
205 let content = "AAA\nBBB\nCCC" in
206 let make_temp_file = temp_file_fn content in
207
208 (* Load file *)
209 (match Cache.load cache make_temp_file with
210 | Ok () -> ()
211 | Error (`Msg msg) -> fail msg);
212
213 (* Replace with same content - should not track as diff *)
214 Cache.replace_line cache make_temp_file 2 "BBB";
215
216 (* Try to write - should fail since no actual changes *)
217 let write_result =
218 try
219 let _ = Cache.write cache make_temp_file in
220 false
221 with Failure _ -> true
222 in
223
224 check bool "write with no-op change fails" true write_result;
225
226 Sys.remove make_temp_file
227
228let test_multiple_files () =
229 let cache = Cache.v () in
230 let file1 = temp_file_fn "file1_line1\nfile1_line2" in
231 let file2 = temp_file_fn "file2_line1\nfile2_line2" in
232
233 (* Load both files *)
234 (match Cache.load cache file1 with
235 | Ok () -> ()
236 | Error (`Msg msg) -> fail msg);
237
238 (match Cache.load cache file2 with
239 | Ok () -> ()
240 | Error (`Msg msg) -> fail msg);
241
242 (* Modify different files *)
243 Cache.replace_line cache file1 1 "modified_file1";
244 Cache.replace_line cache file2 2 "modified_file2";
245
246 (* Check independence *)
247 check (option string) "file1 line 1" (Some "modified_file1")
248 (Cache.line cache file1 1);
249 check (option string) "file1 line 2" (Some "file1_line2")
250 (Cache.line cache file1 2);
251 check (option string) "file2 line 1" (Some "file2_line1")
252 (Cache.line cache file2 1);
253 check (option string) "file2 line 2" (Some "modified_file2")
254 (Cache.line cache file2 2);
255
256 Sys.remove file1;
257 Sys.remove file2
258
259let suite =
260 ( "cache",
261 [
262 test_case "create and clear" `Quick test_create_and_clear;
263 test_case "load and get_line" `Quick test_load_and_get_line;
264 test_case "replace_line" `Quick test_replace_line;
265 test_case "clear_line" `Quick test_clear_line;
266 test_case "get_line_count" `Quick test_get_line_count;
267 test_case "write with changes" `Quick test_write_with_changes;
268 test_case "write without changes fails" `Quick
269 test_write_without_changes_fails;
270 test_case "no change tracking" `Quick test_no_change_tracking;
271 test_case "multiple files" `Quick test_multiple_files;
272 ] )