1+ #! /bin/sh
2+ #
3+ # Copyright (c) 2025 by Zaiba Sanglikar. See LICENSE.
4+ # This script tests the password generation utility pwqgen for
5+ # basic password generation , uniqueness, error handling ,password entropy
6+ # and config file parsing .
7+
8+
9+ if [ -t 1 ]; then
10+ # Colors for better visibility
11+ GREEN=" $( printf " \033[0;32m" ) "
12+ RED=" $( printf " \033[0;31m" ) "
13+ NC=" $( printf " \033[0m" ) "
14+ else
15+ GREEN=' '
16+ RED=' '
17+ NC=' '
18+ fi
19+
20+ # Test function for password generation
21+ test_password_generation () {
22+ params=" $1 "
23+ expected=" $2 "
24+ description=" $3 "
25+
26+ PWQGEN_BIN=" $( dirname " $0 " ) /../pwqgen"
27+
28+ printf " Testing %s: " " $description " q
29+ if [ -z " $params " ]; then
30+ result=$( " $PWQGEN_BIN " 2>&1 )
31+ else
32+ result=$( " $PWQGEN_BIN " $params 2>&1 )
33+ fi
34+ exit_code=$?
35+
36+ if [ " $expected " = " pass" -a " $exit_code " -eq 0 ] || \
37+ [ " $expected " = " fail" -a " $exit_code " -ne 0 ]; then
38+ printf " %sPASS%s\n" " $GREEN " " $NC "
39+ printf " Parameters: %s\n" " ${params:- ' (none)' } "
40+ printf " Result: %s\n\n" " $result "
41+ return 0
42+ else
43+ printf " %sFAIL%s\n" " $RED " " $NC "
44+ printf " Parameters: %s\n" " ${params:- ' (none)' } "
45+ printf " Expected: %s\n" " $expected "
46+ printf " Got exit code: %d\n" " $exit_code "
47+ printf " Output: %s\n\n" " $result "
48+ return 1
49+ fi
50+ }
51+
52+ # Test function for password uniqueness
53+ test_password_uniqueness () {
54+ params=" $1 "
55+ description=" $2 "
56+
57+ PWQGEN_BIN=" $( dirname " $0 " ) /../pwqgen"
58+
59+ printf " Testing %s: " " $description "
60+ pass1=$( " $PWQGEN_BIN " $params 2>&1 )
61+ exit_code1=$?
62+ pass2=$( " $PWQGEN_BIN " $params 2>&1 )
63+ exit_code2=$?
64+
65+ if [ $exit_code1 -eq 0 ] && [ $exit_code2 -eq 0 ] && [ " $pass1 " != " $pass2 " ]; then
66+ printf " %sPASS%s\n" " $GREEN " " $NC "
67+ printf " Parameters: %s\n" " ${params:- ' (none)' } "
68+ printf " Password 1: %s\n" " $pass1 "
69+ printf " Password 2: %s\n\n" " $pass2 "
70+ return 0
71+ else
72+ printf " %sFAIL%s\n" " $RED " " $NC "
73+ printf " Parameters: %s\n" " ${params:- ' (none)' } "
74+ printf " Passwords are identical or generation failed\n"
75+ printf " Password 1: %s\n" " $pass1 "
76+ printf " Password 2: %s\n\n" " $pass2 "
77+ return 1
78+ fi
79+ }
80+
81+ # Function to test passphrase uniqueness for multiple iterations
82+ test_uniqueness () {
83+ i=0
84+ iterations=30
85+ duplicates=0
86+
87+ while [ $i -lt $iterations ]; do
88+ pass=$( $PWQGEN_BIN )
89+
90+ # Store passwords in a temporary file
91+ if [ $i -eq 0 ]; then
92+ echo " $pass " > temp_passes.txt
93+ else
94+ # Check for duplicates
95+ if grep -Fxq " $pass " temp_passes.txt; then
96+ duplicates=$(( duplicates + 1 ))
97+ fi
98+ echo " $pass " >> temp_passes.txt
99+ fi
100+
101+ i=$(( i + 1 ))
102+ done
103+
104+ rm -f temp_passes.txt
105+
106+ # check for the duplicate count
107+ if [ $duplicates -le 1 ]; then
108+ return 0
109+ else
110+ return 1
111+ fi
112+
113+ }
114+
115+ # Function to test if password contains different character classes
116+ test_password_entropy () {
117+ params=" $1 "
118+ description=" $2 "
119+
120+ printf " Testing %s: " " $description "
121+ PWQGEN_BIN=" $( dirname " $0 " ) /../pwqgen"
122+ password=$( " $PWQGEN_BIN " $params 2>&1 )
123+ exit_code=$?
124+
125+ # Check if the password has different character classes
126+ has_lower=$( printf " %s" " $password " | grep -q ' [a-z]' ; echo $? )
127+ has_upper=$( printf " %s" " $password " | grep -q ' [A-Z]' ; echo $? )
128+ has_digit=$( printf " %s" " $password " | grep -q ' [0-9]' ; echo $? )
129+ has_special=$( printf " %s" " $password " | grep -q ' [^a-zA-Z0-9]' ; echo $? )
130+
131+ if [ " $has_lower " -eq 0 ] && [ " $has_upper " -eq 0 ] && \
132+ [ " $has_digit " -eq 0 ] && [ " $has_special " -eq 0 ]; then
133+ printf " %sPASS%s\n" " $GREEN " " $NC "
134+ printf " Parameters: %s\n" " ${params:- ' (none)' } "
135+ printf " Password: %s\n\n" " $password "
136+ return 0
137+ else
138+ printf " %sFAIL%s\n" " $RED " " $NC "
139+ printf " Parameters: %s\n" " ${params:- ' (none)' } "
140+ printf " Password doesn't contain all required character classes\n"
141+ printf " Password: %s\n\n" " $password "
142+ return 1
143+ fi
144+ }
145+
146+ printf " Running Basic Password Generation Tests...\n"
147+
148+ # Test Suite 1: Basic Generation
149+ printf " \nTesting Basic Password Generation:\n"
150+ test_password_generation " " " pass" " Default password generation"
151+ test_password_generation " random=64" " pass" " 64-bit random password"
152+ test_password_generation " random=128" " pass" " 128-bit random password"
153+
154+ # Test Suite 2: Password Uniqueness
155+ printf " \nTesting Password Uniqueness:\n"
156+ test_password_uniqueness " " " Default password uniqueness"
157+ test_password_uniqueness " random=64" " 64-bit random password uniqueness"
158+ test_password_uniqueness " random=128" " 128-bit random password uniqueness"
159+
160+ # Test Suite 3: Invalid Parameters
161+ printf " \nTesting Invalid Parameters:\n"
162+ test_password_generation " random=-1" " fail" " Negative random bits"
163+ test_password_generation " random=0" " fail" " Zero random bits"
164+ test_password_generation " random=999999" " fail" " Excessive random bits"
165+ test_password_generation " random=invalid" " fail" " Invalid random value"
166+ test_password_generation " random=abc" " fail" " Non-numeric random bits"
167+ test_password_generation " random=" " fail" " Empty random value"
168+ test_password_generation " random=1.5" " fail" " Decimal random bits"
169+
170+ # Test Suite 4: Multiple Parameters
171+ printf " \nTesting Multiple Parameters:\n"
172+ test_password_generation " random=64 max=40" " pass" " Multiple valid parameters"
173+ test_password_generation " random=64 invalid=parameter" " fail" " Valid and invalid parameters"
174+
175+ # Test Suite 5: Password uniqueness over multiple iterations
176+ printf " \nPassword uniqueness over multiple iterations\n"
177+ if test_uniqueness; then
178+ printf " %sPASS%s\n" " $GREEN " " $NC "
179+ else
180+ printf " %sFAIL%s\n" " $RED " " $NC "
181+ printf " Too many duplicate passphrases generated\n"
182+ fi
183+
184+ # Test Suite 6: Test configuration files
185+ printf " \nTesting config files:\n"
186+
187+ tmp_dir=$( mktemp -d)
188+ trap ' rm -rf "${tmp_dir}"' EXIT
189+
190+ # Valid config file
191+ cat > " ${tmp_dir} /valid.conf" << EOF
192+ min=disabled,24,11,8,7
193+ max=72
194+ passphrase=3
195+ match=4
196+ similar=deny
197+ random=47
198+ enforce=everyone
199+ retry=3
200+ EOF
201+
202+ # Invalid config file
203+ cat > " ${tmp_dir} /invalid.conf" << EOF
204+ min=invalid
205+ max=abc
206+ passphrase=0000
207+ match=ccc
208+ similar=1
209+ random=0
210+ EOF
211+
212+ # Empty config file
213+ cat > " ${tmp_dir} /empty.conf" << EOF
214+ EOF
215+
216+ test_password_generation " config=${tmp_dir} /valid.conf" " pass" " Valid configuration file"
217+ test_password_generation " config=${tmp_dir} /invalid.conf" " fail" " Invalid configuration file"
218+ test_password_generation " config=${tmp_dir} /empty.conf" " pass" " Empty configuration file"
219+
220+ # Test Suite 7: Test password entropy
221+ test_password_entropy " random=128" " Password should contain various character classes"
0 commit comments