2 # -------+---------+---------+-------- + --------+---------+---------+---------+
3 # Copyright (c) 2005 - Garance Alistair Drosehn <gad@FreeBSD.org>.
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the distribution.
15 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 # -------+---------+---------+-------- + --------+---------+---------+---------+
27 # -------+---------+---------+-------- + --------+---------+---------+---------+
28 # This script was written to provide a battery of regression-tests for some
29 # changes I am making to the `env' command. I wrote a new script for this
30 # for several reasons. 1) I needed to test all kinds of special-character
31 # combinations, and I wanted to be able to type those in exactly as they would
32 # would be in real-life situations. 2) I wanted to set environment variables
33 # before executing a test, 3) I had many different details to test, so I wanted
34 # to write up dozens of tests, without needing to create a hundred separate
35 # little tiny files, 4) I wanted to test *failure* conditions, where I expected
36 # the test would fail but I wanted to be sure that it failed the way I intended
38 # This script was written for the special "shebang-line" testing that I
39 # wanted for my changes to `env', but I expect it could be turned into a
40 # general-purpose test-suite with a little more work.
41 # Garance/June 12/2005
42 # -------+---------+---------+-------- + --------+---------+---------+---------+
45 # -------+---------+---------+-------- + --------+---------+---------+---------+
47 attr_writer :cmdvalue, :shebang_args, :user_args
50 def ExpectedResult.add_gblenv(avar, avalue)
51 @@gbl_envs[avar] = avalue
57 @clear_envs = Hash.new
61 @expect_err = Array.new
62 @expect_out = Array.new
67 def add_expecterr(aline)
71 def add_expectout(aline)
76 @script_lines += aline
77 @script_lines += "\n" if aline[-1] != "\n"
80 def add_clearenv(avar)
81 @clear_envs[avar] = true
84 def add_setenv(avar, avalue)
85 @new_envs[avar] = avalue
88 def add_symlink(srcf, newf)
89 @symlinks << Array.[](srcf, newf)
92 def check_out(name, fname, expect_arr)
96 rdata = File.open(fname)
97 rdata.each_line { |rline|
100 if idx > expect_arr.length - 1
101 if extra_lines == 0 and $verbose >= 1
102 printf "-- Extra line(s) on %s:\n", name
104 printf "-- [%d] > %s\n", idx, rline if $verbose >= 1
106 elsif rline != expect_arr[idx]
107 if all_matched and $verbose >= 1
108 printf "-- Mismatched line(s) on %s:\n", name
110 printf "-- [%d] < %s\n", idx, expect_arr[idx] if $verbose >= 2
111 printf "-- > %s\n", rline if $verbose >= 1
114 printf "-- %s[%d] = %s\n", name, idx, rline if $verbose >= 5
119 printf "-- %d extra line(s) found on %s\n", extra_lines,
120 name if $verbose == 0
124 printf "-- Mismatched line(s) found on %s\n",
125 name if $verbose == 0
132 @symlinks.each { |fnames|
134 printf "-- Creating: symlink %s %s\n", fnames[0], fnames[1]
136 symres = File.symlink(fnames[0], fnames[1])
137 return false if symres == nil
138 return false unless File.symlink?(fnames[1])
144 @symlinks.each { |fnames|
146 printf "-- Removing: %s (symlink)\n", fnames[1]
148 if File.symlink?(fnames[1])
149 if File.delete(fnames[1]) != 1
150 $stderr.printf "Warning: problem removing symlink '%s'\n",
154 $stderr.printf "Warning: Symlink '%s' does not exist?!?\n",
162 @stderr = $scriptfile + ".stderr"
163 @stdout = $scriptfile + ".stdout"
164 File.delete(@stderr) if File.exists?(@stderr)
165 File.delete(@stdout) if File.exists?(@stdout)
168 @redirs = " <" + @stdin
169 @redirs += " >" + @stdout
170 @redirs += " 2>" + @stderr
175 @new_envs.each_key { |evar|
176 if @old_envs.has_key?(evar)
177 ENV[evar] = @old_envs[evar]
185 @@gbl_envs.each_pair { |evar, eval|
188 @new_envs.each_pair { |evar, eval|
189 if ENV.has_key?(evar)
190 @old_envs[evar] = ENV[evar]
197 tscript = File.open($scriptfile, "w")
198 tscript.printf "#!%s", $testpgm
199 tscript.printf " %s", @shebang_args if @shebang_args != ""
201 tscript.printf "%s", @script_lines if @script_lines != ""
203 File.chmod(0755, $scriptfile)
205 usercmd = $scriptfile
206 usercmd += " " + @user_args if @user_args != nil
210 return 0 unless create_links
211 printf "- Executing: %s\n", usercmd if $verbose >= 1
212 printf "----- with: %s\n", @redirs if $verbose >= 6
213 sys_ok = system(usercmd + @redirs)
217 @sav_cmdvalue = $?.exitstatus
224 if @sav_cmdvalue != @cmdvalue
225 printf "-- Expecting cmdvalue of %d, but $? == %d\n", @cmdvalue,
229 sys_ok = false unless check_out("stdout", @stdout, @expect_out)
230 sys_ok = false unless check_out("stderr", @stderr, @expect_err)
236 # -------+---------+---------+-------- + --------+---------+---------+---------+
237 # Processing of the command-line options given to the regress-sb.rb script.
240 def CommandOptions.parse(command_args)
242 command_args.each { |userarg|
244 when /^--rgdata=(\S+)$/
245 parse_ok = false unless set_rgdatafile($1)
246 when /^--testpgm=(\S+)$/
247 parse_ok = false unless set_testpgm($1)
248 $cmdopt_testpgm = $testpgm
249 when "--stop-on-error", "--stop_on_error"
250 $stop_on_error = true
252 $stderr.printf "Error: Invalid long option: %s\n", userarg
255 userarg = userarg[1...userarg.length]
256 userarg.each_byte { |byte|
262 $stderr.printf "Error: Invalid short option: -%s\n", char
267 $stderr.printf "Error: Invalid request: %s\n", userarg
271 if $rgdatafile == nil
272 rgmatch = Dir.glob("regress*.rgdata")
273 if rgmatch.length == 1
274 $rgdatafile = rgmatch[0]
275 printf "Assuming --rgdata=%s\n", $rgdatafile
277 $stderr.printf "Error: The --rgdata file was not specified\n"
284 def CommandOptions.set_rgdatafile(fname)
285 if not File.exists?(fname)
286 $stderr.printf "Error: Rgdata file '%s' does not exist\n", fname
288 elsif not File.readable?(fname)
289 $stderr.printf "Error: Rgdata file '%s' is not readable\n", fname
292 $rgdatafile = File.expand_path(fname)
296 def CommandOptions.set_testpgm(fname)
297 if not File.exists?(fname)
298 $stderr.printf "Error: Testpgm file '%s' does not exist\n", fname
300 elsif not File.executable?(fname)
301 $stderr.printf "Error: Testpgm file '%s' is not executable\n", fname
304 $testpgm = File.expand_path(fname)
309 # -------+---------+---------+-------- + --------+---------+---------+---------+
310 # Processing of the test-specific options specifed in each [test]/[run]
311 # section of the regression-data file. This will set values in the
312 # global $testdata object.
317 def RGTestOptions.init_rgtopts
318 @@rgtest_opts = Hash.new
319 @@rgtest_opts["$?"] = true
320 @@rgtest_opts["clearenv"] = true
321 @@rgtest_opts["sb_args"] = true
322 @@rgtest_opts["script"] = true
323 @@rgtest_opts["setenv"] = true
324 @@rgtest_opts["stderr"] = true
325 @@rgtest_opts["stdout"] = true
326 @@rgtest_opts["symlink"] = true
327 @@rgtest_opts["user_args"] = true
330 def RGTestOptions.parse(optname, optval)
331 init_rgtopts unless @@rgtest_opts
333 if not @@rgtest_opts.has_key?(optname)
334 $stderr.printf "Error: Invalid test-option in rgdata file: %s\n",
339 # Support a few very specific substitutions in values specified
340 # for test data. Format of all recognized values should be:
342 # which is hopefully distinctive-enough that they will never
343 # conflict with any naturally-occurring string. Also note that
344 # we only match the specific values that we recognize, and not
345 # "just anything" that matches the general pattern. There are
346 # no blanks in the recognized values, but I use an x-tended
347 # regexp and then add blanks to make it more readable.
348 optval.gsub!(/\[%- testpgm\.pathname -%\]/x, $testpgm)
349 optval.gsub!(/\[%- testpgm\.basename -%\]/x, File.basename($testpgm))
350 optval.gsub!(/\[%- script\.pathname -%\]/x, $scriptfile)
352 invalid_value = false
356 $testdata.cmdvalue = optval.to_i
361 if optval =~ /^\s*([A-Za-z]\w*)\s*$/
362 $testdata.add_clearenv($1)
367 $testdata.shebang_args = optval
369 $testdata.add_script(optval)
371 if optval =~ /^\s*([A-Za-z]\w*)=(.*)$/
372 $testdata.add_setenv($1, $2)
377 $testdata.add_expecterr(optval)
379 $testdata.add_expectout(optval)
381 if optval =~ /^\s*(\S+)\s+(\S+)\s*$/
384 if not File.exists?(srcfile)
385 $stderr.printf "Error: source file '%s' does not exist.\n",
388 elsif File.exists?(newfile)
389 $stderr.printf "Error: new file '%s' already exists.\n",
393 $testdata.add_symlink(srcfile, newfile)
399 $testdata.user_args = optval
401 $stderr.printf "InternalError: Invalid test-option in rgdata file: %s\n",
407 $stderr.printf "Error: Invalid value(s) for %s: %s\n",
415 # -------+---------+---------+-------- + --------+---------+---------+---------+
416 # Here's where the "main" routine begins...
419 $cmdopt_testpgm = nil
422 $scriptfile = "/tmp/env-regress"
423 $stop_on_error = false
426 exit 1 unless CommandOptions.parse(ARGV)
433 regress_data = File.open($rgdatafile)
434 regress_data.each_line { |dline|
436 when /^\s*#/, /^\s*$/
437 # Just a comment line, ignore it.
438 when /^\s*gblenv=\s*(.+)$/
440 $stderr.printf "Error: Cannot define a global-value in the middle of a test (#5d)\n", test_lineno
441 errline = regress_data.lineno
445 if tempval !~ /^([A-Za-z]\w*)=(.*)$/
446 $stderr.printf "Error: Invalid value for 'gblenv=' request: %s\n",
448 errline = regress_data.lineno
451 ExpectedResult.add_gblenv($1, $2)
452 when /^testpgm=\s*(\S+)\s*/
453 # Set the location of the program to be tested, if it wasn't set
454 # on the command-line processing.
455 if $cmdopt_testpgm == nil
456 if not CommandOptions.set_testpgm($1)
457 errline = regress_data.lineno
463 $stderr.printf "Error: Request to define a [test], but we are still defining\n"
464 $stderr.printf " the [test] at line #%s\n", test_lineno
465 errline = regress_data.lineno
468 test_lineno = regress_data.lineno
469 max_test = test_lineno
470 printf "- Defining test at line #%s\n", test_lineno if $verbose >= 6
471 $testdata = ExpectedResult.new
473 # User wants us to ignore the remainder of the rgdata file...
477 $stderr.printf "Error: Request to [run] a test, but no test is presently defined\n"
478 errline = regress_data.lineno
481 printf "- Running test at line #%s\n", test_lineno if $verbose >= 1
482 run_result = $testdata.run_test
484 printf "[Test #%3d: ", test_count
488 printf "Failed! (line %4d)]\n", test_lineno
489 break if $stop_on_error
491 # Test ran as expected
495 # Internal error of some sort
496 printf "InternalError! (line %4d)]\n", test_lineno
497 errline = regress_data.lineno
502 when /^(\s*)([^\s:]+)\s*:(.+)$/
507 $stderr.printf "Error: No test is presently being defined\n"
508 errline = regress_data.lineno
511 # All the real work happens in RGTestOptions.parse
512 if not RGTestOptions.parse(test_lhs, test_rhs)
513 errline = regress_data.lineno
516 if blankpfx.length == 0
517 $stderr.printf "Note: You should at least one blank before:%s\n",
519 $stderr.printf " at line %d of rgdata file %s\n",
520 regress_data.lineno, $rgdatafile
524 $stderr.printf "Error: Invalid line: %s\n", dline.chomp
525 errline = regress_data.lineno
531 $stderr.printf " at line %d of rgdata file %s\n", errline, $rgdatafile
534 if testok_count != test_count
535 printf "%d of %d tests were successful.\n", testok_count, test_count
539 printf "All %d tests were successful!\n", testok_count