Added doc/features.html
[voodoo-lang.git] / test / test
blobd74a46d79509d01865bf6d4d84edc6cdb69cde00
1 #! /usr/bin/env ruby
3 require 'test_language_version'
4 require 'test_validator'
5 require 'thread'
7 $errors = 0
8 $errors_mutex = Mutex.new
9 $tests = Queue.new
11 # Atomically increment $errors
12 def increment_errors
13 $errors_mutex.synchronize { $errors = $errors + 1 }
14 end
16 # Runs block and verifies that it returns the given value.
17 # If it doesn't, prints an error message and increments $errors.
18 def expect name, value, &block
19 begin
20 print "#{name}..."
21 result = yield
22 if result == value
23 puts "pass"
24 true
25 else
26 puts "FAIL: expected #{value.inspect}, but got #{result.inspect}"
27 increment_errors
28 end
29 rescue Exception => e
30 puts "FAIL: Unexpected #{e.class}\n#{e.message}"
31 increment_errors
32 end
33 end
35 # Runs block and verifies that it returns true.
36 # If it doesn't, prints an error message and increments $errors.
37 def expect_true name, &block
38 expect name, true, &block
39 end
41 # Runs block and verifies that it throws an exception of type
42 # +exception_type+. If the block doesn't throw such an exception,
43 # prints an error message and increments $errors.
44 def expect_exception name, exception_type, &block
45 begin
46 message = "#{name}..."
47 yield
48 message << "FAIL: Expected exception of type #{exception_type}," +
49 " but no exception was raised"
50 increment_errors
51 rescue Exception => e
52 if e.kind_of? exception_type
53 message << "pass"
54 true
55 else
56 message << "FAIL: Expected #{exception_type}, but got #{e.class}"
57 increment_errors
58 end
59 end
60 puts message
61 end
63 # Runs block and verifies that it throws a ValidationError.
64 # If the block doesn't throw such an exception,
65 # prints an error message and increments $errors.
66 def expect_ValidationError name, &block
67 expect_exception name, ValidationError, &block
68 end
70 $RUBY = ENV['RUBY'] || 'ruby'
71 $VOODOOC = 'env RUBYLIB=../lib ../bin/voodooc'
73 # Runs a command with exec.
74 # With no block given, returns
75 # [status, stdin, stdout, stderr]
76 # With block given, passes
77 # status, stdin, stdout, stderr to block
78 def popen4 *command
79 pw = IO::pipe # pipe[0] for read, pipe[1] for write
80 pr = IO::pipe
81 pe = IO::pipe
83 pid = fork do
84 # child
85 pw[1].close
86 STDIN.reopen(pw[0])
87 pw[0].close
89 pr[0].close
90 STDOUT.reopen(pr[1])
91 pr[1].close
93 pe[0].close
94 STDERR.reopen(pe[1])
95 pe[1].close
97 exec *command
98 end
100 # parent
101 pw[0].close
102 pr[1].close
103 pe[1].close
104 dummy, status = Process.wait2 pid
105 result = [status, pw[1], pr[0], pe[0]]
106 pw[1].sync = true
107 if block_given?
108 begin
109 return yield(*result)
110 ensure
111 [pw[1], pr[0], pe[0]].each { |p| p.close unless p.closed? }
114 result
117 def add_test program, command, expected_output = '', params = {}
118 $tests << [program, command, expected_output, params]
121 def run_test program, command, expected_output = '', params = {}
122 input = params.has_key?(:input) ? params[:input] : nil
123 expected_status = params.has_key?(:expected_status) ?
124 params[:expected_status] : 0
125 expected_errors = params.has_key?(:expected_errors) ?
126 params[:expected_errors] : ''
128 message = "#{program}..."
129 status, stdin, stdout, stderr = popen4 command
130 if input
131 stdin.write input
133 exitstatus = status.exitstatus
134 output = stdout.read
135 err_output = stderr.read
136 if exitstatus != expected_status
137 message << "FAIL: exit status is #{exitstatus}, expected #{expected_status}"
138 increment_errors
139 elsif output != expected_output
140 message << "FAIL: wrong output"
141 increment_errors
142 elsif err_output != expected_errors
143 message << "FAIL: wrong error output"
144 $stderr.puts "--- ERRORS ---\n#{err_output}\n--- EXPECTED ---\n#{expected_errors}\n--- END ERRORS ---"
145 increment_errors
146 else
147 message << 'pass'
149 puts message
152 def add_test2 program, expected_output
153 add_test program, "./#{program}", expected_output
156 def add_test1 program
157 add_test2 program, `cat #{program}.out`
160 # Runs all tests in the given queue.
161 # Each test is described by a list
162 # [name, command, expected_output, params].
163 # Those parameters are passed to run_test.
164 def run_tests queue, nthreads = 1
165 threads = []
166 nthreads.times do
167 threads << Thread.new do
168 until queue.empty?
169 name, command, output, params = queue.pop
170 run_test name, command, output, params
174 threads.each { |t| t.join }
177 test_validator
179 test_language_version
181 add_test 'architectures', '../bin/voodooc --architecture help',
182 `cat architectures.out`
184 add_test 'features', '../bin/voodooc -a i386 --features', `cat features.out`
186 add_test 'help', '../bin/voodooc --help', `cat help.out`
188 add_test('no-input-files',
189 '../bin/voodooc',
191 :expected_status => 128,
192 :expected_errors => `cat no-input-files.err`)
194 add_test 'version', '../bin/voodooc --version',
195 "Voodoo Compiler version #{`cat ../VERSION`}"
197 add_test2 'hello', "Hello, world!\n"
199 add_test2 'tail-calls', ''
201 add_test1 'bytes'
203 add_test1 'call'
205 add_test1 'at'
207 add_test1 'block'
209 add_test1 'else-if'
211 add_test1 'if'
213 add_test1 'goto'
215 add_test2 'fact', "479001600\n"
217 add_test1 'bitwise'
219 add_test1 'plusminus'
221 add_test1 'many-vars'
223 add_test1 'mul'
225 add_test1 'div'
227 add_test1 'mod'
229 add_test1 'raw'
231 add_test1 'rotate'
233 add_test1 'set-byte'
235 add_test1 'set-word'
237 add_test1 'shift'
239 add_test1 'vtable'
241 add_test1 'gcd'
243 printf 'test_output_name...'
244 increment_errors unless system("$RUBY test_output_name.rb")
246 add_test 'errors',
247 "#{$VOODOOC} -o errors.o errors.voo",
249 :expected_status => 1,
250 :expected_errors => `cat errors.err`
252 run_tests $tests, 4
254 if $errors == 0
255 puts "All tests passed"
256 else
257 puts "#{$errors} tests failed"
258 exit 1