Skip to content

Commit 6909b05

Browse files
committed
Harden argument validation and test coverage
Make command argument handling consistent by rejecting unknown options and wrong arity in core bookmark commands. Expand integration tests to cover command contracts, help behavior, and doctor validation scenarios.
1 parent 010decb commit 6909b05

4 files changed

Lines changed: 198 additions & 0 deletions

File tree

functions/delete_bookmark.fish

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@ function delete_bookmark --description "Delete a bookmark"
44
return 1
55
end
66

7+
if _check_help "$argv[1]"
8+
return 0
9+
end
10+
11+
if test (count $argv) -ne 1
12+
_fishmarks_print_error "exactly one bookmark name is required"
13+
return 1
14+
end
15+
16+
if string match -q -- '--*' "$argv[1]"
17+
_fishmarks_print_error "unknown option '$argv[1]'"
18+
return 1
19+
end
20+
721
set -l removed 0
822
set -l updated_entries
923
for entry in (_fishmarks_entries)

functions/go_to_bookmark.fish

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ function go_to_bookmark --description "Go to (cd) to the directory associated wi
1010
return 0
1111
end
1212

13+
if test (count $argv) -ne 1
14+
_fishmarks_print_error "exactly one bookmark name is required"
15+
return 1
16+
end
17+
18+
if string match -q -- '--*' "$bookmark_name"
19+
_fishmarks_print_error "unknown option '$bookmark_name'"
20+
return 1
21+
end
22+
1323
set -l target (_fishmarks_find_path "$bookmark_name")
1424
if test -z "$target"
1525
_fishmarks_print_error "'$bookmark_name' bookmark does not exist"

functions/print_bookmark.fish

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ function print_bookmark --description "Print the directory associated with a boo
1010
return 0
1111
end
1212

13+
if test (count $argv) -ne 1
14+
_fishmarks_print_error "exactly one bookmark name is required"
15+
return 1
16+
end
17+
18+
if string match -q -- '--*' "$bookmark_name"
19+
_fishmarks_print_error "unknown option '$bookmark_name'"
20+
return 1
21+
end
22+
1323
set -l target (_fishmarks_find_path "$bookmark_name")
1424
if test -z "$target"
1525
_fishmarks_print_error "'$bookmark_name' bookmark does not exist"

tests/run.fish

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,27 @@ function _test_default_name_generation
5555
_assert_eq "$HOME/work/my-app.v2" "$location" 'default bookmark name is sanitized basename'
5656
end
5757

58+
function _test_save_requires_force_to_overwrite
59+
_prepare_dir "$HOME/work/overwrite-one"
60+
save_bookmark overwrite_target
61+
_assert_status 0 $status 'first save for overwrite_target succeeds'
62+
63+
_prepare_dir "$HOME/work/overwrite-two"
64+
save_bookmark overwrite_target >/dev/null 2>/dev/null
65+
_assert_status 1 $status 'save_bookmark rejects overwrite without --force'
66+
67+
set -l location (print_bookmark overwrite_target)
68+
_assert_status 0 $status 'existing bookmark remains after rejected overwrite'
69+
_assert_eq "$HOME/work/overwrite-one" "$location" 'rejected overwrite keeps original path'
70+
71+
save_bookmark --force overwrite_target
72+
_assert_status 0 $status 'save_bookmark --force overwrites existing bookmark'
73+
74+
set -l updated_location (print_bookmark overwrite_target)
75+
_assert_status 0 $status 'forced overwrite is readable'
76+
_assert_eq "$HOME/work/overwrite-two" "$updated_location" 'forced overwrite updates bookmark path'
77+
end
78+
5879
function _test_go_to_and_delete
5980
_prepare_dir "$HOME/projects/alpha"
6081
save_bookmark alpha
@@ -72,6 +93,36 @@ function _test_go_to_and_delete
7293
_assert_status 1 $status 'deleted bookmark no longer resolves'
7394
end
7495

96+
function _test_rename_bookmark
97+
_prepare_dir "$HOME/projects/rename-path"
98+
save_bookmark rename_old
99+
_assert_status 0 $status 'save bookmark for rename succeeds'
100+
101+
rename_bookmark rename_old rename_new
102+
_assert_status 0 $status 'rename_bookmark succeeds'
103+
104+
print_bookmark rename_old >/dev/null 2>/dev/null
105+
_assert_status 1 $status 'old bookmark name is removed after rename'
106+
107+
set -l new_location (print_bookmark rename_new)
108+
_assert_status 0 $status 'new bookmark name resolves after rename'
109+
_assert_eq "$HOME/projects/rename-path" "$new_location" 'rename_bookmark preserves original path'
110+
end
111+
112+
function _test_bookmark_exists
113+
_prepare_dir "$HOME/projects/exists-path"
114+
save_bookmark exists_target
115+
_assert_status 0 $status 'save bookmark for exists test succeeds'
116+
117+
set -l existing_output (bookmark_exists exists_target)
118+
_assert_status 0 $status 'bookmark_exists returns success for existing bookmark'
119+
_assert_eq '' "$existing_output" 'bookmark_exists does not print output for existing bookmark'
120+
121+
set -l missing_output (bookmark_exists missing_target)
122+
_assert_status 1 $status 'bookmark_exists returns failure for missing bookmark'
123+
_assert_eq '' "$missing_output" 'bookmark_exists does not print output for missing bookmark'
124+
end
125+
75126
function _test_legacy_file_compatibility
76127
command mkdir -p -- "$HOME/legacy/location"
77128
printf 'export DIR_legacy="\\$HOME/legacy/location"\n' >"$SDIRS"
@@ -93,6 +144,91 @@ function _test_invalid_name_rejected
93144
_assert_status 1 $status 'invalid bookmark names are rejected'
94145
end
95146

147+
function _test_list_names_only
148+
_prepare_dir "$HOME/work/names-one"
149+
save_bookmark names_only_a
150+
_assert_status 0 $status 'save first names-only bookmark succeeds'
151+
152+
_prepare_dir "$HOME/work/names-two"
153+
save_bookmark names_only_b
154+
_assert_status 0 $status 'save second names-only bookmark succeeds'
155+
156+
set -l names_output (list_bookmarks --names-only)
157+
_assert_status 0 $status 'list_bookmarks --names-only succeeds'
158+
159+
contains -- names_only_a $names_output
160+
_assert_true $status 'names-only output includes first bookmark name'
161+
162+
contains -- names_only_b $names_output
163+
_assert_true $status 'names-only output includes second bookmark name'
164+
165+
string match -q '*/*' -- "$names_output"
166+
_assert_status 1 $status 'names-only output does not include paths'
167+
end
168+
169+
function _test_argument_validation
170+
print_bookmark one two >/dev/null 2>/dev/null
171+
_assert_status 1 $status 'print_bookmark rejects extra arguments'
172+
173+
print_bookmark --unknown >/dev/null 2>/dev/null
174+
_assert_status 1 $status 'print_bookmark rejects unknown options'
175+
176+
go_to_bookmark one two >/dev/null 2>/dev/null
177+
_assert_status 1 $status 'go_to_bookmark rejects extra arguments'
178+
179+
go_to_bookmark --unknown >/dev/null 2>/dev/null
180+
_assert_status 1 $status 'go_to_bookmark rejects unknown options'
181+
182+
delete_bookmark one two >/dev/null 2>/dev/null
183+
_assert_status 1 $status 'delete_bookmark rejects extra arguments'
184+
185+
delete_bookmark --unknown >/dev/null 2>/dev/null
186+
_assert_status 1 $status 'delete_bookmark rejects unknown options'
187+
188+
bookmark_exists one two >/dev/null 2>/dev/null
189+
_assert_status 1 $status 'bookmark_exists rejects extra arguments'
190+
191+
bookmark_exists --unknown >/dev/null 2>/dev/null
192+
_assert_status 1 $status 'bookmark_exists rejects unknown options'
193+
194+
rename_bookmark old --unknown >/dev/null 2>/dev/null
195+
_assert_status 1 $status 'rename_bookmark rejects unknown options'
196+
197+
rename_bookmark bad-name new_name >/dev/null 2>/dev/null
198+
_assert_status 1 $status 'rename_bookmark validates old bookmark names'
199+
200+
save_bookmark first second >/dev/null 2>/dev/null
201+
_assert_status 1 $status 'save_bookmark rejects extra positional arguments'
202+
203+
save_bookmark --unknown >/dev/null 2>/dev/null
204+
_assert_status 1 $status 'save_bookmark rejects unknown options'
205+
206+
list_bookmarks extra >/dev/null 2>/dev/null
207+
_assert_status 1 $status 'list_bookmarks rejects unexpected arguments'
208+
209+
fishmarks_doctor --unknown >/dev/null 2>/dev/null
210+
_assert_status 1 $status 'fishmarks_doctor rejects unknown options'
211+
end
212+
213+
function _test_help_output
214+
set -l commands \
215+
save_bookmark \
216+
rename_bookmark \
217+
bookmark_exists \
218+
go_to_bookmark \
219+
print_bookmark \
220+
delete_bookmark \
221+
list_bookmarks \
222+
fishmarks_doctor
223+
224+
for command_name in $commands
225+
set -l help_output ($command_name --help)
226+
_assert_status 0 $status "$command_name --help succeeds"
227+
string match -q '*save_bookmark*' -- "$help_output"
228+
_assert_true $status "$command_name --help includes command list"
229+
end
230+
end
231+
96232
function _test_shell_escaped_paths
97233
set -l special_path "$HOME/work/special \"q\" \$d\\b"
98234
_prepare_dir "$special_path"
@@ -161,15 +297,43 @@ function _test_conf_aliases
161297
_assert_status 0 $status 'alias l is configured by conf.d script'
162298
end
163299

300+
function _test_fishmarks_doctor
301+
set -l original_sdirs "$SDIRS"
302+
303+
set -gx SDIRS "$HOME/.sdirs_doctor_ok"
304+
command mkdir -p -- "$HOME/doctor/ok"
305+
printf '\n' >"$SDIRS"
306+
printf '# fishmarks comments are ignored\n' >>"$SDIRS"
307+
printf 'export DIR_ok="\\$HOME/doctor/ok"\n' >>"$SDIRS"
308+
fishmarks_doctor >/dev/null
309+
_assert_status 0 $status 'fishmarks_doctor succeeds for clean bookmark file'
310+
311+
set -gx SDIRS "$HOME/.sdirs_doctor_bad"
312+
printf 'not a bookmark\n' >"$SDIRS"
313+
printf 'export DIR_dup="\\$HOME/doctor/missing"\n' >>"$SDIRS"
314+
printf 'export DIR_dup="\\$HOME/doctor/missing-two"\n' >>"$SDIRS"
315+
fishmarks_doctor >/dev/null 2>/dev/null
316+
_assert_status 1 $status 'fishmarks_doctor reports malformed, duplicate, or missing directories'
317+
318+
set -gx SDIRS "$original_sdirs"
319+
end
320+
164321
_test_save_and_print
165322
_test_default_name_generation
323+
_test_save_requires_force_to_overwrite
166324
_test_go_to_and_delete
325+
_test_rename_bookmark
326+
_test_bookmark_exists
167327
_test_legacy_file_compatibility
168328
_test_invalid_name_rejected
329+
_test_list_names_only
330+
_test_argument_validation
169331
_test_shell_escaped_paths
170332
_test_rejects_newline_paths
171333
_test_version_command
172334
_test_conf_aliases
335+
_test_fishmarks_doctor
336+
_test_help_output
173337

174338
if test $failures -gt 0
175339
printf '\n%d of %d assertions failed\n' "$failures" "$assertions"

0 commit comments

Comments
 (0)