1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
#!/usr/bin/env bats
#
# Input Validation Tests Fragment
# CLI Testing Specialist Agent v2.5.0
#
# This fragment contains test templates for:
# - Numeric option validation
# - Path option validation
# - Enum option validation
# - Boundary value testing
#
# ========================================
# Numeric Option Validation Tests
# ========================================
@test "[input-validation] ${OPTION_NAME} accepts valid value in range" {
# Test valid numeric value within acceptable range
run "$CLI_BINARY" ${OPTION_NAME} ${VALID_VALUE}
# Should succeed
[ "$status" -eq 0 ] || [ "$status" -eq 1 ] # Some CLIs return 1 for help
}
@test "[input-validation] ${OPTION_NAME} rejects negative value" {
# Test rejection of negative numbers (if min >= 0)
skip_if_negative_allowed "${MIN_VALUE}"
run "$CLI_BINARY" ${OPTION_NAME} -1
# Should fail with error
[ "$status" -ne 0 ]
# Check error message mentions invalid value
[[ "$output" =~ (invalid|error|out of range|negative) ]] || \
[[ "$stderr" =~ (invalid|error|out of range|negative) ]] || \
skip "No specific error message for negative values"
}
@test "[input-validation] ${OPTION_NAME} rejects out-of-range high value" {
# Test rejection of values above maximum
local invalid_value=$((${MAX_VALUE} + 1000))
run "$CLI_BINARY" ${OPTION_NAME} "$invalid_value"
# Should fail
[ "$status" -ne 0 ] || \
skip "CLI does not validate maximum value"
}
@test "[input-validation] ${OPTION_NAME} rejects out-of-range low value (below min)" {
# Test rejection of values below minimum
skip_if "${MIN_VALUE}" -le 0
local invalid_value=$((${MIN_VALUE} - 1))
run "$CLI_BINARY" ${OPTION_NAME} "$invalid_value"
# Should fail
[ "$status" -ne 0 ] || \
skip "CLI does not validate minimum value"
}
@test "[input-validation] ${OPTION_NAME} rejects non-numeric value" {
# Test rejection of non-numeric input
run "$CLI_BINARY" ${OPTION_NAME} "not-a-number"
# Should fail
[ "$status" -ne 0 ]
# Check error message
[[ "$output" =~ (invalid|error|not a number|numeric|integer) ]] || \
[[ "$stderr" =~ (invalid|error|not a number|numeric|integer) ]] || \
skip "No specific error message for non-numeric input"
}
@test "[input-validation] ${OPTION_NAME} rejects float when integer required" {
# Test rejection of floating point when integer is required
skip_if_float_allowed "${OPTION_TYPE}"
run "$CLI_BINARY" ${OPTION_NAME} "3.14"
# Should fail
[ "$status" -ne 0 ] || \
skip "CLI accepts float values for this option"
}
# Boundary value tests
@test "[input-validation] ${OPTION_NAME} accepts minimum boundary value" {
# Test minimum acceptable value
run "$CLI_BINARY" ${OPTION_NAME} ${MIN_VALUE}
[ "$status" -eq 0 ] || [ "$status" -eq 1 ]
}
@test "[input-validation] ${OPTION_NAME} accepts maximum boundary value" {
# Test maximum acceptable value
run "$CLI_BINARY" ${OPTION_NAME} ${MAX_VALUE}
[ "$status" -eq 0 ] || [ "$status" -eq 1 ]
}
@test "[input-validation] ${OPTION_NAME} rejects min-1 boundary value" {
# Test just below minimum
skip_if "${MIN_VALUE}" -le 0
local boundary_value=$((${MIN_VALUE} - 1))
run "$CLI_BINARY" ${OPTION_NAME} "$boundary_value"
[ "$status" -ne 0 ] || \
skip "CLI accepts values below stated minimum"
}
@test "[input-validation] ${OPTION_NAME} rejects max+1 boundary value" {
# Test just above maximum
local boundary_value=$((${MAX_VALUE} + 1))
run "$CLI_BINARY" ${OPTION_NAME} "$boundary_value"
[ "$status" -ne 0 ] || \
skip "CLI accepts values above stated maximum"
}
# ========================================
# Path Option Validation Tests
# ========================================
@test "[input-validation] ${PATH_OPTION} validates file existence" {
# Test that CLI checks if input file exists
local nonexistent_file="/tmp/nonexistent-file-$(date +%s)-$RANDOM.txt"
run "$CLI_BINARY" ${PATH_OPTION} "$nonexistent_file"
# Should either fail or warn about non-existent file
if [ "$status" -ne 0 ]; then
# Failed as expected
[[ "$output" =~ (not found|does not exist|no such file|cannot find) ]] || \
[[ "$stderr" =~ (not found|does not exist|no such file|cannot find) ]] || \
skip "No specific error for missing file"
else
# Some CLIs accept non-existent files for output options
skip "CLI accepts non-existent file (may be output option)"
fi
}
@test "[input-validation] ${PATH_OPTION} rejects path traversal attack" {
# Test protection against path traversal
run "$CLI_BINARY" ${PATH_OPTION} "../../../etc/passwd"
# Should either fail or not leak sensitive data
[ "$status" -ne 0 ] || ! [[ "$output" =~ root: ]] || \
skip "CLI accepts path traversal but may sanitize"
}
@test "[input-validation] ${PATH_OPTION} handles relative paths correctly" {
# Test relative path handling
local test_file="./test-file-$RANDOM.txt"
touch "$test_file"
run "$CLI_BINARY" ${PATH_OPTION} "$test_file"
local exit_status=$status
rm -f "$test_file"
[ "$exit_status" -eq 0 ] || [ "$exit_status" -eq 1 ]
}
@test "[input-validation] ${PATH_OPTION} handles absolute paths correctly" {
# Test absolute path handling
local test_file="/tmp/test-file-$RANDOM.txt"
touch "$test_file"
run "$CLI_BINARY" ${PATH_OPTION} "$test_file"
local exit_status=$status
rm -f "$test_file"
[ "$exit_status" -eq 0 ] || [ "$exit_status" -eq 1 ]
}
@test "[input-validation] ${PATH_OPTION} handles paths with spaces" {
# Test path with spaces
local test_dir="/tmp/test dir with spaces-$RANDOM"
mkdir -p "$test_dir"
local test_file="$test_dir/file.txt"
touch "$test_file"
run "$CLI_BINARY" ${PATH_OPTION} "$test_file"
local exit_status=$status
rm -rf "$test_dir"
[ "$exit_status" -eq 0 ] || [ "$exit_status" -eq 1 ] || \
skip "CLI may not support paths with spaces"
}
@test "[input-validation] ${PATH_OPTION} handles Unicode in paths" {
# Test Unicode characters in path
local test_file="/tmp/テスト-файл-$RANDOM.txt"
touch "$test_file" 2>/dev/null || skip "Filesystem does not support Unicode"
run "$CLI_BINARY" ${PATH_OPTION} "$test_file"
local exit_status=$status
rm -f "$test_file" 2>/dev/null
[ "$exit_status" -eq 0 ] || [ "$exit_status" -eq 1 ] || \
skip "CLI may not support Unicode paths"
}
@test "[input-validation] ${PATH_OPTION} rejects null byte injection" {
# Test protection against null byte injection
run "$CLI_BINARY" ${PATH_OPTION} $'/tmp/file\x00malicious.txt'
# Should fail
[ "$status" -ne 0 ] || \
skip "CLI may accept null bytes (potential security issue)"
}
@test "[input-validation] ${PATH_OPTION} handles symbolic links" {
# Test symbolic link handling
local test_file="/tmp/real-file-$RANDOM.txt"
local link_file="/tmp/link-file-$RANDOM.txt"
touch "$test_file"
ln -s "$test_file" "$link_file"
run "$CLI_BINARY" ${PATH_OPTION} "$link_file"
local exit_status=$status
rm -f "$test_file" "$link_file"
[ "$exit_status" -eq 0 ] || [ "$exit_status" -eq 1 ]
}
# ========================================
# Enum Option Validation Tests
# ========================================
@test "[input-validation] ${ENUM_OPTION} accepts first valid value" {
# Test first value from allowed list
run "$CLI_BINARY" ${ENUM_OPTION} "${VALID_ENUM_VALUE_1}"
[ "$status" -eq 0 ] || [ "$status" -eq 1 ]
}
@test "[input-validation] ${ENUM_OPTION} accepts second valid value" {
# Test another valid value
skip_if_undefined "${VALID_ENUM_VALUE_2}"
run "$CLI_BINARY" ${ENUM_OPTION} "${VALID_ENUM_VALUE_2}"
[ "$status" -eq 0 ] || [ "$status" -eq 1 ]
}
@test "[input-validation] ${ENUM_OPTION} rejects invalid value" {
# Test rejection of value not in allowed list
run "$CLI_BINARY" ${ENUM_OPTION} "invalid-value-xyz-12345"
# Should fail
[ "$status" -ne 0 ]
# Check error message
[[ "$output" =~ (invalid|unknown|unsupported|not allowed|not recognized) ]] || \
[[ "$stderr" =~ (invalid|unknown|unsupported|not allowed|not recognized) ]] || \
skip "No specific error message for invalid enum value"
}
@test "[input-validation] ${ENUM_OPTION} handles case sensitivity correctly" {
# Test case sensitivity (uppercase variant)
local uppercase_value
uppercase_value=$(echo "${VALID_ENUM_VALUE_1}" | tr '[:lower:]' '[:upper:]')
run "$CLI_BINARY" ${ENUM_OPTION} "$uppercase_value"
if [ "${CASE_SENSITIVE}" = "true" ]; then
# Should fail if case-sensitive
[ "$status" -ne 0 ] || \
skip "CLI accepts different case (not case-sensitive)"
else
# Should succeed if case-insensitive
[ "$status" -eq 0 ] || [ "$status" -eq 1 ] || \
skip "CLI is case-sensitive for this option"
fi
}
@test "[input-validation] ${ENUM_OPTION} provides helpful error with suggestions" {
# Test that invalid value error includes suggestions
run "$CLI_BINARY" ${ENUM_OPTION} "typo-value"
# Should fail
[ "$status" -ne 0 ]
# Check if error message includes valid options or suggestions
[[ "$output" =~ (valid values|allowed values|choose from|available|options are) ]] || \
[[ "$stderr" =~ (valid values|allowed values|choose from|available|options are) ]] || \
skip "CLI does not provide helpful error with valid options"
}
# ========================================
# Helper Functions
# ========================================
skip_if_negative_allowed() {
local min_value="$1"
if [[ "$min_value" -lt 0 ]]; then
skip "Negative values are allowed (min=$min_value)"
fi
}
skip_if_float_allowed() {
local option_type="$1"
if [[ "$option_type" == "float" || "$option_type" == "double" ]]; then
skip "Float values are allowed for this option"
fi
}
skip_if_undefined() {
local value="$1"
if [[ -z "$value" || "$value" == "undefined" ]]; then
skip "Value is undefined"
fi
}
skip_if() {
local condition="$@"
if eval "$condition"; then
skip "Condition met: $condition"
fi
}