Skip to content

Commit d5f1bc5

Browse files
committed
add Sys.rename and refactor a bit
1 parent 4d858ff commit d5f1bc5

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
@@ -76,6 +77,7 @@ struct
7677
map (fun path -> File_exists path) (path_gen s);
7778
map (fun path -> Is_directory path) (path_gen s);
7879
map (fun (path,new_dir_name) -> Remove (path, new_dir_name)) (pair_gen s);
80+
map2 (fun old_path new_path -> Rename (old_path, new_path)) (path_gen s) (path_gen s);
7981
map (fun (path,new_dir_name) -> Mkdir (path, new_dir_name)) (pair_gen s);
8082
map (fun (path,delete_dir_name) -> Rmdir (path, delete_dir_name)) (pair_gen s);
8183
map (fun path -> Readdir path) (path_gen s);
@@ -102,6 +104,35 @@ struct
102104

103105
let mem_model fs path = find_opt_model fs path <> None
104106

107+
let path_is_a_dir fs path =
108+
match find_opt_model fs path with
109+
| None
110+
| Some File -> false
111+
| Some (Directory _) -> true
112+
113+
let path_is_a_file fs path =
114+
match find_opt_model fs path with
115+
| None
116+
| Some (Directory _) -> false
117+
| Some File -> true
118+
119+
let rec path_prefixes path = match path with
120+
| [] -> []
121+
| [_] -> []
122+
| n::ns -> [n]::(List.map (fun p -> n::p) (path_prefixes ns))
123+
124+
let separate_path path =
125+
match List.rev path with
126+
| [] -> None
127+
| name::rev_path -> Some (List.rev rev_path, name)
128+
129+
let rec is_true_prefix path1 path2 = match path1, path2 with
130+
| [], [] -> false
131+
| [], _::_ -> true
132+
| _::_, [] -> false
133+
| n1::p1, n2::p2 -> n1=n2 && is_true_prefix p1 p2
134+
135+
(* generic removal function *)
105136
let rec remove_model fs path file_name =
106137
match fs with
107138
| File -> fs
@@ -110,46 +141,14 @@ struct
110141
| [] ->
111142
(match Map_names.find_opt file_name d.fs_map with
112143
| None
113-
| Some (Directory _) -> fs
114-
| Some File -> Directory { fs_map = Map_names.remove file_name d.fs_map }
115-
)
144+
| Some _ -> Directory { fs_map = Map_names.remove file_name d.fs_map })
116145
| dir::dirs ->
117146
Directory
118147
{ fs_map = Map_names.update dir (function
119148
| None -> None
120149
| Some File -> Some File
121150
| Some (Directory _ as d') -> Some (remove_model d' dirs file_name)) d.fs_map
122-
}
123-
(*
124-
(match Map_names.find_opt dir d.fs_map with
125-
| None
126-
| Some File -> fs
127-
| Some (Directory _ as d') ->
128-
let fs' = remove_model d' dirs file_name in
129-
Directory { fs_map = Map_names.update dir d.fs_map }
130-
)
131-
*)
132-
)
133-
134-
let rec mkdir_model fs path new_dir_name =
135-
match fs with
136-
| File -> fs
137-
| Directory d ->
138-
(match path with
139-
| [] ->
140-
let new_dir = Directory {fs_map = Map_names.empty} in
141-
Directory {fs_map = Map_names.add new_dir_name new_dir d.fs_map}
142-
| next_in_path :: tl_path ->
143-
(match Map_names.find_opt next_in_path d.fs_map with
144-
| None -> fs
145-
| Some sub_fs ->
146-
let nfs = mkdir_model sub_fs tl_path new_dir_name in
147-
if nfs = sub_fs
148-
then fs
149-
else
150-
let new_map = Map_names.remove next_in_path d.fs_map in
151-
let new_map = Map_names.add next_in_path nfs new_map in
152-
Directory {fs_map = new_map}))
151+
})
153152

154153
let readdir_model fs path =
155154
match find_opt_model fs path with
@@ -159,60 +158,70 @@ struct
159158
| File -> None
160159
| Directory d -> Some (Map_names.fold (fun k _ l -> k::l) d.fs_map []))
161160

162-
let rec rmdir_model fs path delete_dir_name =
161+
(* generic insertion function *)
162+
let rec insert_model fs path new_file_name sub_tree =
163163
match fs with
164164
| File -> fs
165165
| Directory d ->
166166
(match path with
167167
| [] ->
168-
(match Map_names.find_opt delete_dir_name d.fs_map with
169-
| Some (Directory target) when Map_names.is_empty target.fs_map ->
170-
Directory {fs_map = Map_names.remove delete_dir_name d.fs_map}
171-
| None | Some File | Some (Directory _) -> fs)
168+
Directory {fs_map = Map_names.add new_file_name sub_tree d.fs_map}
172169
| next_in_path :: tl_path ->
173170
(match Map_names.find_opt next_in_path d.fs_map with
174171
| None -> fs
175172
| Some sub_fs ->
176-
let nfs = rmdir_model sub_fs tl_path delete_dir_name in
177-
if nfs = sub_fs
178-
then fs
179-
else Directory {fs_map = (update_map_name d.fs_map next_in_path nfs)}))
180-
181-
let rec mkfile_model fs path new_file_name =
182-
match fs with
183-
| File -> fs
184-
| Directory d ->
185-
(match path with
186-
| [] ->
187-
let new_file = File in
188-
Directory {fs_map = Map_names.add new_file_name new_file d.fs_map}
189-
| next_in_path :: tl_path ->
190-
(match Map_names.find_opt next_in_path d.fs_map with
191-
| None -> fs
192-
| Some sub_fs ->
193-
let nfs = mkfile_model sub_fs tl_path new_file_name in
173+
let nfs = insert_model sub_fs tl_path new_file_name sub_tree in
194174
if nfs = sub_fs
195175
then fs
196176
else Directory {fs_map = update_map_name d.fs_map next_in_path nfs}))
197177

178+
let rename_model fs old_path new_path =
179+
match separate_path old_path, separate_path new_path with
180+
| None, _
181+
| _, None -> fs
182+
| Some (old_path_pref, old_name), Some (new_path_pref, new_name) ->
183+
(match find_opt_model fs new_path_pref with
184+
| None
185+
| Some File -> fs
186+
| Some (Directory _) ->
187+
(match find_opt_model fs old_path with
188+
| None -> fs
189+
| Some sub_fs ->
190+
let fs' = remove_model fs old_path_pref old_name in
191+
insert_model fs' new_path_pref new_name sub_fs))
192+
198193
let next_state c fs =
199194
match c with
200195
| File_exists _path -> fs
201196
| Mkdir (path, new_dir_name) ->
202197
if mem_model fs (path @ [new_dir_name])
203198
then fs
204-
else mkdir_model fs path new_dir_name
205-
| Remove (path, file_name) -> remove_model fs path file_name
199+
else insert_model fs path new_dir_name (Directory {fs_map = Map_names.empty})
200+
| Remove (path, file_name) ->
201+
if find_opt_model fs (path @ [file_name]) = Some File
202+
then remove_model fs path file_name
203+
else fs
204+
| Rename (old_path, new_path) ->
205+
if is_true_prefix old_path new_path
206+
then fs
207+
else
208+
(match find_opt_model fs old_path with
209+
| None -> fs
210+
| Some File ->
211+
if (not (mem_model fs new_path) || path_is_a_file fs new_path) then rename_model fs old_path new_path else fs
212+
| Some (Directory _) ->
213+
if (not (mem_model fs new_path) || readdir_model fs new_path = Some []) then rename_model fs old_path new_path else fs)
206214
| Is_directory _path -> fs
207215
| Rmdir (path,delete_dir_name) ->
208-
if mem_model fs (path @ [delete_dir_name])
209-
then rmdir_model fs path delete_dir_name
216+
let complete_path = path @ [delete_dir_name] in
217+
if mem_model fs complete_path && readdir_model fs complete_path = Some []
218+
then remove_model fs path delete_dir_name
210219
else fs
211220
| Readdir _path -> fs
212221
| Mkfile (path, new_file_name) ->
213222
if mem_model fs (path @ [new_file_name])
214223
then fs
215-
else mkfile_model fs path new_file_name
224+
else insert_model fs path new_file_name File
216225

217226
let init_sut () =
218227
try Sys.mkdir sandbox_root 0o700
@@ -237,6 +246,7 @@ struct
237246
| File_exists path -> Res (bool, Sys.file_exists (p path))
238247
| Is_directory path -> Res (result bool exn, protect Sys.is_directory (p path))
239248
| Remove (path, file_name) -> Res (result unit exn, protect Sys.remove ((p path) / file_name))
249+
| Rename (old_path, new_path) -> Res (result unit exn, protect (Sys.rename (p old_path)) (p new_path))
240250
| Mkdir (path, new_dir_name) ->
241251
Res (result unit exn, protect (Sys.mkdir ((p path) / new_dir_name)) 0o755)
242252
| Rmdir (path, delete_dir_name) ->
@@ -246,18 +256,6 @@ struct
246256
| Mkfile (path, new_file_name) ->
247257
Res (result unit exn, protect mkfile (p path / new_file_name))
248258

249-
let fs_is_a_dir fs = match fs with | Directory _ -> true | File -> false
250-
251-
let path_is_a_dir fs path =
252-
match find_opt_model fs path with
253-
| None -> false
254-
| Some target_fs -> fs_is_a_dir target_fs
255-
256-
let rec path_prefixes path = match path with
257-
| [] -> []
258-
| [_] -> []
259-
| n::ns -> [n]::(List.map (fun p -> n::p) (path_prefixes ns))
260-
261259
let postcond c (fs: filesys) res =
262260
match c, res with
263261
| File_exists path, Res ((Bool,_),b) -> b = mem_model fs path
@@ -269,19 +267,34 @@ struct
269267
| Some File -> b = false
270268
| None -> false)
271269
| Error (Sys_error s) ->
272-
(s = (p path) ^ ": No such file or directory" && find_opt_model fs path = None) ||
273-
(s = p path ^ ": Not a directory" && List.exists (fun pref -> Some File = find_opt_model fs pref) (path_prefixes path))
270+
(s = (p path) ^ ": No such file or directory" && not (mem_model fs path)) ||
271+
(s = p path ^ ": Not a directory" && List.exists (fun pref -> not (path_is_a_dir fs pref)) (path_prefixes path))
274272
| _ -> false)
275273
| Remove (path, file_name), Res ((Result (Unit,Exn),_), res) ->
276274
let complete_path = (path @ [file_name]) in
277275
(match res with
278276
| Ok () -> mem_model fs complete_path && path_is_a_dir fs path && not (path_is_a_dir fs complete_path)
279277
| Error (Sys_error s) ->
280-
(s = (p complete_path) ^ ": No such file or directory" && find_opt_model fs complete_path = None) ||
278+
(s = (p complete_path) ^ ": No such file or directory" && not (mem_model fs complete_path)) ||
281279
(s = (p complete_path) ^ ": Is a directory" && path_is_a_dir fs complete_path) ||
282280
(s = (p complete_path) ^ ": Not a directory" && not (path_is_a_dir fs path))
283281
| Error _ -> false
284282
)
283+
| Rename (old_path, new_path), Res ((Result (Unit,Exn),_), res) ->
284+
(match res with
285+
| Ok () -> mem_model fs old_path
286+
| Error (Sys_error s) ->
287+
(s = "No such file or directory" &&
288+
not (mem_model fs old_path) || List.exists (fun pref -> not (path_is_a_dir fs pref)) (path_prefixes new_path)) ||
289+
(s = "Invalid argument" && is_true_prefix old_path new_path) ||
290+
(s = "Not a directory" &&
291+
List.exists (path_is_a_file fs) (path_prefixes old_path) ||
292+
List.exists (path_is_a_file fs) (path_prefixes new_path) ||
293+
path_is_a_dir fs old_path && mem_model fs new_path && not (path_is_a_dir fs new_path)) ||
294+
(s = "Is a directory" && path_is_a_dir fs new_path) ||
295+
(s = "Directory not empty" &&
296+
is_true_prefix new_path old_path || (path_is_a_dir fs new_path && not (readdir_model fs new_path = Some [])))
297+
| Error _ -> false)
285298
| Mkdir (path, new_dir_name), Res ((Result (Unit,Exn),_), res) ->
286299
let complete_path = (path @ [new_dir_name]) in
287300
(match res with

0 commit comments

Comments
 (0)