1#!/bin/sh
2#
3# gentest @(#)gentest.sh	1.12 20/08/25 Copyright 2015-2020 J. Schilling
4#
5# Usage: gentest	---> runs 1000 test loops
6#	 gentest #	---> runs # test loops
7#
8# A random file test with 1..10 generations of patches in a single patch file.
9# A file is generated, then modified 1..10 times and every time a diff is
10# created and concatenated to a single patch file. Then the original file
11# is patched and compared to the expected result.
12#
13# The diff type is random, this allows to check the quality of the automated
14# diff type recognition.
15#
16
17[ "$NO_RANDOM" = TRUE ] && exit
18
19: ${AWK=/usr/bin/nawk}
20#$AWK 'BEGIN {print rand()}' < /dev/null > /dev/null 2> /dev/null || AWK=/usr/bin/nawk
21$AWK 'BEGIN {print rand()}' < /dev/null > /dev/null 2> /dev/null || AWK=/usr/bin/gawk
22$AWK 'BEGIN {print rand()}' < /dev/null > /dev/null 2> /dev/null || AWK=/usr/bin/awk
23$AWK 'BEGIN {print rand()}' < /dev/null > /dev/null 2> /dev/null || AWK=nawk
24$AWK 'BEGIN {print rand()}' < /dev/null > /dev/null 2> /dev/null || AWK=gawk
25$AWK 'BEGIN {print rand()}' < /dev/null > /dev/null 2> /dev/null || AWK=awk
26
27trap 'cleanup; exit' EXIT INT HUP
28
29cleanup() {
30	rm -f generation saved_orig changed patch_file expected original original.* failure xo xm xof xmf xef
31}
32
33rrand() {
34	$AWK '
35	function random(low, range) {
36		return int(range * rand()) + low
37	}
38
39	BEGIN {
40		base = ARGV[1]
41		max = ARGV[2]
42		seed = ARGV[3]
43
44		srand()		# Initialze with current time
45		s = srand()	# get previous seed
46		s = s + seed	# Current time + seed
47		srand(s)	# Better new seed
48
49		x = random(base, max)
50		print x
51	}
52	' "$@"
53}
54
55makefile() {
56	$AWK '
57	BEGIN {
58		nflines = ARGV[1]
59		for (i = 1; i <= nflines; i++) {
60			printf("This is original line %d\n", i);
61		}
62	}
63	' "$@"
64}
65
66changefile() {
67	$AWK '
68	function random(n) {
69		return int(n * rand())
70	}
71
72	BEGIN {
73		nflines = ARGV[1]
74		chlines = ARGV[2]
75		seed = chlines
76
77		ARGV[1] = ""	# Do not use as filename
78		ARGV[2] = ""	# Do not use as filename
79
80		srand()		# Initialze with current time
81		s = srand()	# get previous seed
82		s = s + seed	# Current time + seed
83		srand(s)	# Better new seed
84
85		for (i = 1; i <= nflines; i++) {
86			change_line[i] = 0
87		}
88
89		while (chlines > 0) {
90			i = random(nflines)
91			if (change_line[i] == 0) {
92				chlines--
93				change_line[i] = 1
94			}
95		}
96		i = 1;
97	}
98
99	{
100		if (change_line[i] != 0) {
101			what = random(3)
102			if (what == 0) {
103				print "Modified, was: " $0
104			} else if (what == 1) {
105				print $0
106				print "New line, inserted after: " $0
107			}
108		} else {
109			print $0
110		}
111		i++
112		next
113	}
114	' "$@"
115}
116
117
118nlines=$$	# seed startup helper, awk would get seed based on time_t
119maxlines=5000	# Longest file for our tests
120maxch=4		# Max. 25% of all lines are changed
121
122#
123# Diff Program to use. Solaris diff -U0 has bugs, so use our fixed Solaris diff
124# from the SCCS distribution.
125#
126is_bdiff=false
127: ${diff=/opt/schily/ccs/bin/diff}
128type $diff > /dev/null 2> /dev/null
129[ $? -ne 0 ] && diff=diff	# fallback to probably defective system diff
130LC_ALL=C $diff -? 2>&1 | grep -i Option > /dev/null
131if [ $? -ne 0 ]; then
132	LC_ALL=C $diff -? 2>&1 | grep -i "bdiff: arg count" > /dev/null
133	if [ $? -eq 0 ]; then
134		is_bdiff=true
135	else
136		echo "No working diff program found"
137		exit 1
138	fi
139fi
140echo "Using diff programm: $diff"
141#
142# Reference patch program, note that gpatch has problems itself
143# and fails with -diff -C0
144#
145rpatch=gpatch
146#LC_ALL=C $rpatch -? 2>&1 | grep -i Option > /dev/null
147#if [ $? -ne 0 ]; then
148#	echo "Reference patch program \"$rpatch\" not working"
149#	rpatch=/usr/bin/patch
150#	echo "Trying \"$rpatch\"..."
151#	LC_ALL=C $rpatch -? 2>&1 | grep -i Option > /dev/null
152#	if [ $? -ne 0 ]; then
153#		echo "Reference patch program \"$rpatch\" not working"
154#		rpatch=/bin/patch
155#		echo "Trying \"$rpatch\"..."
156#		LC_ALL=C $rpatch -? 2>&1 | grep -i Option > /dev/null
157#		if [ $? -ne 0 ]; then
158#			echo "Reference patch program \"$rpatch\" not working"
159#			exit 1
160#		fi
161#	fi
162#fi
163#echo "Using reference patch programm: $rpatch"
164#
165# Test patch implementation:
166# Add -W+ to permit POSIX + enhancements for "patch -s"
167#
168tpatch="eval ../../OBJ/"`../../../conf/oarch.sh`"/spatch -W+"
169silent=-s
170LC_ALL=C $tpatch -? 2>&1 | grep -i Option > /dev/null
171if [ $? -ne 0 ]; then
172	echo "Test patch program \"$tpatch\" not working"
173	exit 1
174fi
175echo "Using test patch programm: $tpatch"
176
177mod=6
178type ed > /dev/null 2> /dev/null
179[ $? -ne 0 ] && mod=5		# Skip diff -e tests
180if [ $mod = 5 ]; then
181	echo "No ed program found, skipping diff -e tests"
182fi
183
184idx=0
185total=0
186maxidx=${1:-1000}
187while [ $idx -le $maxidx ]
188do
189	nlines=`rrand 10 $maxlines $nlines`
190	generations=`rrand 1 10 $nlines`
191
192	max_changes=`expr $nlines / $maxch`
193	changes=`rrand 1 $max_changes $nlines`
194
195	makefile $nlines > original
196	cp original saved_orig
197
198	>patch_file				# avoid SVr4 :>file redirection bug
199	>generation				# avoid SVr4 :>file redirection bug
200	echo Test $idx: testing lines=$nlines changes=$changes generations=$generations
201	echo Test $idx: testing lines=$nlines changes=$changes generations=$generations >> generation
202	generation=1
203	while [ $generation -le $generations ]; do
204
205		seed=`expr $generation + $nlines`
206		dtype=`rrand 0 93983 $seed`	# rrand 0 6 would be of bad quality, so
207		dtype=`expr $dtype \% $mod`	# use "rrand 0 bigprime % 6" instead
208
209		if [ $dtype -eq 0 ]; then
210			dtype="-c"
211		elif [ $dtype -eq 1 ]; then
212			dtype="-u"
213		elif [ $dtype -eq 2 ]; then
214			dtype="-C0"
215		elif [ $dtype -eq 3 ]; then
216			dtype="-U0"
217		elif [ $dtype -eq 5 ]; then
218			dtype="-e"
219		else
220			dtype="  "
221		fi
222		if [ "$is_bdiff" = true ]; then
223			dtype="  "
224		fi
225
226
227		echo "Creating generation $generation of type ($dtype)..."
228		echo "Creating generation $generation of type ($dtype)..." >> generation
229		changefile $nlines $changes original > changed
230		echo "Generation: $generation" >> patch_file
231		echo "Index:original" >> patch_file
232		$diff $dtype original changed >> patch_file
233		mv changed original
234		generation=`expr $generation + 1`
235	done
236	cp original expected
237	cp saved_orig original
238
239	echo Patching file...
240	$tpatch original < patch_file
241	ret=$?
242	if [ $ret -ne 0 ]; then
243		echo Test $idx: Patch returned $ret
244		diff original expected > failure
245		trap 0
246		exit 1
247	fi
248
249	diff original expected > failure
250		ret=$?
251	if [ $ret -ne 0 ]; then
252		echo Test $idx: diff returned $ret
253		[ $ret -eq 1 ] && trap 0
254		exit 1
255	fi
256	idx=`expr $idx + 1`
257	total=`expr $total + $generations`
258done
259idx=`expr $idx - 1`
260echo Test succeeded after $idx runs, total of $total patches...
261