New Environment class. Tests pass on AMD64
[voodoo-lang.git] / test / test.rb
blob9af1c4e72d18f6effd7850c61aa913c7be73396f
1 #### Common functionality for running tests.
3 # Make sure that the lib directory is in $LOAD_PATH
4 $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
6 require 'thread'
8 $errors = 0
9 $errors_mutex = Mutex.new
10 $tests = Queue.new
12 # Fails a test.
13 # +reason+ Should be a short message describing the reason for failure.
14 # +stderr+ If not empty, this text is written to standard error.
15 def fail_test reason, stderr = ''
16   increment_errors
17   puts "FAIL: #{reason}"
18   $stdout.flush
19   unless stderr.empty?
20     $stderr.puts stderr
21     $stderr.flush
22   end
23   false
24 end
26 # Atomically increment $errors
27 def increment_errors
28   $errors_mutex.synchronize { $errors = $errors + 1 }
29 end
31 # Passes a test.
32 def pass_test
33   puts "pass"
34   $stdout.flush
35   true
36 end
38 # Runs block and verifies that it returns the given value.
39 # If it doesn't, prints an error message and increments $errors.
40 def expect name, value, &block
41   begin
42     print "#{name}..."
43     result = yield
44     if result == value
45       pass_test
46     else
47       fail_test "expected #{value.inspect}, but got #{result.inspect}"
48     end
49   rescue Exception => e
50     fail_test "Unexpected #{e.class}\n#{e.message}"
51   end
52 end
54 # Runs block and verifies that it returns true.
55 # If it doesn't, prints an error message and increments $errors.
56 def expect_true name, &block
57   expect name, true, &block
58 end
60 # Runs block and verifies that it throws an exception of type
61 # +exception_type+. If the block doesn't throw such an exception,
62 # prints an error message and increments $errors.
63 def expect_exception name, exception_type, &block
64   begin
65     print "#{name}..."
66     yield
67     fail_test "Expected exception of type #{exception_type}," +
68       " but no exception was raised"
69   rescue Exception => e
70     if e.kind_of? exception_type
71       pass_test
72     else
73       fail_test "Expected #{exception_type}, but got #{e.class}"
74     end
75   end
76 end
78 $RUBY = ENV['RUBY'] || 'ruby'
79 $VOODOOC = 'env RUBYLIB=../lib ../bin/voodooc'
81 # Runs a command with exec.
82 # With no block given, returns
83 # [status, stdin, stdout, stderr]
84 # With block given, passes
85 # status, stdin, stdout, stderr to block
86 def popen4 *command
87   pw = IO::pipe   # pipe[0] for read, pipe[1] for write
88   pr = IO::pipe
89   pe = IO::pipe
90   
91   pid = fork do
92     # child
93     pw[1].close
94     STDIN.reopen(pw[0])
95     pw[0].close
96     
97     pr[0].close
98     STDOUT.reopen(pr[1])
99     pr[1].close
100     
101     pe[0].close
102     STDERR.reopen(pe[1])
103     pe[1].close
104     
105     exec *command
106   end
108   # parent
109   pw[0].close
110   pr[1].close
111   pe[1].close
112   dummy, status = Process.wait2 pid
113   result = [status, pw[1], pr[0], pe[0]]
114   pw[1].sync = true
115   if block_given?
116     begin
117       return yield(*result)
118     ensure
119       [pw[1], pr[0], pe[0]].each { |p| p.close unless p.closed? }
120     end
121   end
122   result
125 def add_test program, command, expected_output = '', params = {}
126   $tests << [program, command, expected_output, params]
129 def run_test program, command, expected_output = '', params = {}
130   input = params.has_key?(:input) ? params[:input] : nil
131   expected_status = params.has_key?(:expected_status) ?
132     params[:expected_status] : 0
133   expected_errors = params.has_key?(:expected_errors) ?
134     params[:expected_errors] : ''
136   message = "#{program}..."
137   status, stdin, stdout, stderr = popen4 command
138   if input
139     stdin.write input
140   end
141   exitstatus = status.exitstatus
142   output = stdout.read
143   err_output = stderr.read
144   if exitstatus != expected_status
145     message << "FAIL: exit status is #{exitstatus}, expected #{expected_status}"
146     increment_errors
147   elsif output != expected_output
148     message << "FAIL: wrong output"
149     increment_errors
150   elsif err_output != expected_errors
151     message << "FAIL: wrong error output"
152     $stderr.puts "--- ERRORS ---\n#{err_output}\n--- EXPECTED ---\n#{expected_errors}\n--- END ERRORS ---"
153     increment_errors
154   else
155     message << 'pass'
156   end
157   puts message
160 def add_test2 program, expected_output
161   add_test program, "./#{program}", expected_output
164 def add_test1 program
165   add_test2 program, `cat #{program}.out`
168 # Reports tests results.
169 # Returns 0 if all tests passed, 1 if some failed.
170 def report_test_results
171   if $errors == 0
172     puts "All tests passed"
173     return 0
174   else
175     puts "#{$errors} tests failed"
176     return 1
177   end
180 # Runs all tests in the given queue.
181 # Each test is described by a list
182 # [name, command, expected_output, params].
183 # Those parameters are passed to run_test.
184 def run_tests queue, nthreads = 1
185   threads = []
186   nthreads.times do
187     threads << Thread.new do
188       until queue.empty?
189         name, command, output, params = queue.pop
190         run_test name, command, output, params
191       end
192     end
193   end
194   threads.each { |t| t.join }