Skip to content

Commit d1a40e4

Browse files
committed
add Sys.rename and refactor a bit
1 parent 1855436 commit d1a40e4

File tree

1 file changed

+90
-77
lines changed

1 file changed

+90
-77
lines changed

src/sys/stm_tests.ml

Lines changed: 90 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ struct
99
| File_exists of path
1010
| Is_directory of path
1111
| Remove of path * string
12+
| Rename of path * path
1213
| Mkdir of path * string
1314
| Rmdir of path * string
1415
| Readdir of path
@@ -87,6 +88,7 @@ struct
8788
map (fun path -> File_exists path) (path_gen s);
8889
map (fun path -> Is_directory path) (path_gen s);
8990
map (fun (path,new_dir_name) -> Remove (path, new_dir_name)) (pair_gen s);
91+
map2 (fun old_path new_path -> Rename (old_path, new_path)) (path_gen s) (path_gen s);
9092
map (fun (path,new_dir_name) -> Mkdir (path, new_dir_name)) (pair_gen s);
9193
map (fun (path,delete_dir_name) -> Rmdir (path, delete_dir_name)) (pair_gen s);
9294
map (fun path -> Readdir path) (path_gen s);
@@ -113,6 +115,35 @@ struct
113115

114116
let mem_model fs path = find_opt_model fs path <> None
115117

118+
let path_is_a_dir fs path =
119+
match find_opt_model fs path with
120+
| None
121+
| Some File -> false
122+
| Some (Directory _) -> true
123+
124+
let path_is_a_file fs path =
125+
match find_opt_model fs path with
126+
| None
127+
| Some (Directory _) -> false
128+
| Some File -> true
129+
130+
let rec path_prefixes path = match path with
131+
| [] -> []
132+
| [_] -> []
133+
| n::ns -> [n]::(List.map (fun p -> n::p) (path_prefixes ns))
134+
135+
let separate_path path =
136+
match List.rev path with
137+
| [] -> None
138+
| name::rev_path -> Some (List.rev rev_path, name)
139+
140+
let rec is_true_prefix path1 path2 = match path1, path2 with
141+
| [], [] -> false
142+
| [], _::_ -> true
143+
| _::_, [] -> false
144+
| n1::p1, n2::p2 -> n1=n2 && is_true_prefix p1 p2
145+
146+
(* generic removal function *)
116147
let rec remove_model fs path file_name =
117148
match fs with
118149
| File -> fs
@@ -121,46 +152,14 @@ struct
121152
| [] ->
122153
(match Map_names.find_opt file_name d.fs_map with
123154
| None
124-
| Some (Directory _) -> fs
125-
| Some File -> Directory { fs_map = Map_names.remove file_name d.fs_map }
126-
)
155+
| Some _ -> Directory { fs_map = Map_names.remove file_name d.fs_map })
127156
| dir::dirs ->
128157
Directory
129158
{ fs_map = Map_names.update dir (function
130159
| None -> None
131160
| Some File -> Some File
132161
| Some (Directory _ as d') -> Some (remove_model d' dirs file_name)) d.fs_map
133-
}
134-
(*
135-
(match Map_names.find_opt dir d.fs_map with
136-
| None
137-
| Some File -> fs
138-
| Some (Directory _ as d') ->
139-
let fs' = remove_model d' dirs file_name in
140-
Directory { fs_map = Map_names.update dir d.fs_map }
141-
)
142-
*)
143-
)
144-
145-
let rec mkdir_model fs path new_dir_name =
146-
match fs with
147-
| File -> fs
148-
| Directory d ->
149-
(match path with
150-
| [] ->
151-
let new_dir = Directory {fs_map = Map_names.empty} in
152-
Directory {fs_map = Map_names.add new_dir_name new_dir d.fs_map}
153-
| next_in_path :: tl_path ->
154-
(match Map_names.find_opt next_in_path d.fs_map with
155-
| None -> fs
156-
| Some sub_fs ->
157-
let nfs = mkdir_model sub_fs tl_path new_dir_name in
158-
if nfs = sub_fs
159-
then fs
160-
else
161-
let new_map = Map_names.remove next_in_path d.fs_map in
162-
let new_map = Map_names.add next_in_path nfs new_map in
163-
Directory {fs_map = new_map}))
162+
})
164163

165164
let readdir_model fs path =
166165
match find_opt_model fs path with
@@ -170,60 +169,70 @@ struct
170169
| File -> None
171170
| Directory d -> Some (Map_names.fold (fun k _ l -> k::l) d.fs_map []))
172171

173-
let rec rmdir_model fs path delete_dir_name =
172+
(* generic insertion function *)
173+
let rec insert_model fs path new_file_name sub_tree =
174174
match fs with
175175
| File -> fs
176176
| Directory d ->
177177
(match path with
178178
| [] ->
179-
(match Map_names.find_opt delete_dir_name d.fs_map with
180-
| Some (Directory target) when Map_names.is_empty target.fs_map ->
181-
Directory {fs_map = Map_names.remove delete_dir_name d.fs_map}
182-
| None | Some File | Some (Directory _) -> fs)
179+
Directory {fs_map = Map_names.add new_file_name sub_tree d.fs_map}
183180
| next_in_path :: tl_path ->
184181
(match Map_names.find_opt next_in_path d.fs_map with
185182
| None -> fs
186183
| Some sub_fs ->
187-
let nfs = rmdir_model sub_fs tl_path delete_dir_name in
188-
if nfs = sub_fs
189-
then fs
190-
else Directory {fs_map = (update_map_name d.fs_map next_in_path nfs)}))
191-
192-
let rec mkfile_model fs path new_file_name =
193-
match fs with
194-
| File -> fs
195-
| Directory d ->
196-
(match path with
197-
| [] ->
198-
let new_file = File in
199-
Directory {fs_map = Map_names.add new_file_name new_file d.fs_map}
200-
| next_in_path :: tl_path ->
201-
(match Map_names.find_opt next_in_path d.fs_map with
202-
| None -> fs
203-
| Some sub_fs ->
204-
let nfs = mkfile_model sub_fs tl_path new_file_name in
184+
let nfs = insert_model sub_fs tl_path new_file_name sub_tree in
205185
if nfs = sub_fs
206186
then fs
207187
else Directory {fs_map = update_map_name d.fs_map next_in_path nfs}))
208188

189+
let rename_model fs old_path new_path =
190+
match separate_path old_path, separate_path new_path with
191+
| None, _
192+
| _, None -> fs
193+
| Some (old_path_pref, old_name), Some (new_path_pref, new_name) ->
194+
(match find_opt_model fs new_path_pref with
195+
| None
196+
| Some File -> fs
197+
| Some (Directory _) ->
198+
(match find_opt_model fs old_path with
199+
| None -> fs
200+
| Some sub_fs ->
201+
let fs' = remove_model fs old_path_pref old_name in
202+
insert_model fs' new_path_pref new_name sub_fs))
203+
209204
let next_state c fs =
210205
match c with
211206
| File_exists _path -> fs
212207
| Mkdir (path, new_dir_name) ->
213208
if mem_model fs (path @ [new_dir_name])
214209
then fs
215-
else mkdir_model fs path new_dir_name
216-
| Remove (path, file_name) -> remove_model fs path file_name
210+
else insert_model fs path new_dir_name (Directory {fs_map = Map_names.empty})
211+
| Remove (path, file_name) ->
212+
if find_opt_model fs (path @ [file_name]) = Some File
213+
then remove_model fs path file_name
214+
else fs
215+
| Rename (old_path, new_path) ->
216+
if is_true_prefix old_path new_path
217+
then fs
218+
else
219+
(match find_opt_model fs old_path with
220+
| None -> fs
221+
| Some File ->
222+
if (not (mem_model fs new_path) || path_is_a_file fs new_path) then rename_model fs old_path new_path else fs
223+
| Some (Directory _) ->
224+
if (not (mem_model fs new_path) || readdir_model fs new_path = Some []) then rename_model fs old_path new_path else fs)
217225
| Is_directory _path -> fs
218226
| Rmdir (path,delete_dir_name) ->
219-
if mem_model fs (path @ [delete_dir_name])
220-
then rmdir_model fs path delete_dir_name
227+
let complete_path = path @ [delete_dir_name] in
228+
if mem_model fs complete_path && readdir_model fs complete_path = Some []
229+
then remove_model fs path delete_dir_name
221230
else fs
222231
| Readdir _path -> fs
223232
| Mkfile (path, new_file_name) ->
224233
if mem_model fs (path @ [new_file_name])
225234
then fs
226-
else mkfile_model fs path new_file_name
235+
else insert_model fs path new_file_name File
227236

228237
let init_sut () =
229238
try Sys.mkdir sandbox_root 0o700
@@ -249,6 +258,7 @@ struct
249258
| File_exists path -> Res (bool, Sys.file_exists (p path))
250259
| Is_directory path -> Res (result bool exn, protect Sys.is_directory (p path))
251260
| Remove (path, file_name) -> Res (result unit exn, protect Sys.remove ((p path) / file_name))
261+
| Rename (old_path, new_path) -> Res (result unit exn, protect (Sys.rename (p old_path)) (p new_path))
252262
| Mkdir (path, new_dir_name) ->
253263
Res (result unit exn, protect (Sys.mkdir ((p path) / new_dir_name)) 0o755)
254264
| Rmdir (path, delete_dir_name) ->
@@ -258,18 +268,6 @@ struct
258268
| Mkfile (path, new_file_name) ->
259269
Res (result unit exn, protect mkfile (p path / new_file_name))
260270

261-
let fs_is_a_dir fs = match fs with | Directory _ -> true | File -> false
262-
263-
let path_is_a_dir fs path =
264-
match find_opt_model fs path with
265-
| None -> false
266-
| Some target_fs -> fs_is_a_dir target_fs
267-
268-
let rec path_prefixes path = match path with
269-
| [] -> []
270-
| [_] -> []
271-
| n::ns -> [n]::(List.map (fun p -> n::p) (path_prefixes ns))
272-
273271
let postcond c (fs: filesys) res =
274272
match c, res with
275273
| File_exists path, Res ((Bool,_),b) -> b = mem_model fs path
@@ -281,19 +279,34 @@ struct
281279
| Some File -> b = false
282280
| None -> false)
283281
| Error (Sys_error s) ->
284-
(s = (p path) ^ ": No such file or directory" && find_opt_model fs path = None) ||
285-
(s = p path ^ ": Not a directory" && List.exists (fun pref -> Some File = find_opt_model fs pref) (path_prefixes path))
282+
(s = (p path) ^ ": No such file or directory" && not (mem_model fs path)) ||
283+
(s = p path ^ ": Not a directory" && List.exists (fun pref -> not (path_is_a_dir fs pref)) (path_prefixes path))
286284
| _ -> false)
287285
| Remove (path, file_name), Res ((Result (Unit,Exn),_), res) ->
288286
let complete_path = (path @ [file_name]) in
289287
(match res with
290288
| Ok () -> mem_model fs complete_path && path_is_a_dir fs path && not (path_is_a_dir fs complete_path)
291289
| Error (Sys_error s) ->
292-
(s = (p complete_path) ^ ": No such file or directory" && find_opt_model fs complete_path = None) ||
290+
(s = (p complete_path) ^ ": No such file or directory" && not (mem_model fs complete_path)) ||
293291
(s = (p complete_path) ^ ": Is a directory" && path_is_a_dir fs complete_path) ||
294292
(s = (p complete_path) ^ ": Not a directory" && not (path_is_a_dir fs path))
295293
| Error _ -> false
296294
)
295+
| Rename (old_path, new_path), Res ((Result (Unit,Exn),_), res) ->
296+
(match res with
297+
| Ok () -> mem_model fs old_path
298+
| Error (Sys_error s) ->
299+
(s = "No such file or directory" &&
300+
not (mem_model fs old_path) || List.exists (fun pref -> not (path_is_a_dir fs pref)) (path_prefixes new_path)) ||
301+
(s = "Invalid argument" && is_true_prefix old_path new_path) ||
302+
(s = "Not a directory" &&
303+
List.exists (path_is_a_file fs) (path_prefixes old_path) ||
304+
List.exists (path_is_a_file fs) (path_prefixes new_path) ||
305+
path_is_a_dir fs old_path && mem_model fs new_path && not (path_is_a_dir fs new_path)) ||
306+
(s = "Is a directory" && path_is_a_dir fs new_path) ||
307+
(s = "Directory not empty" &&
308+
is_true_prefix new_path old_path || (path_is_a_dir fs new_path && not (readdir_model fs new_path = Some [])))
309+
| Error _ -> false)
297310
| Mkdir (path, new_dir_name), Res ((Result (Unit,Exn),_), res) ->
298311
let complete_path = (path @ [new_dir_name]) in
299312
(match res with

0 commit comments

Comments
 (0)