3 require File.dirname(__FILE__) + '/test'
4 require 'voodoo/parser'
6 # Class that provides a getc method that reads from a string.
24 # Like StringReader, but will throw an error after n characters.
25 class BrokenStringReader < StringReader
33 raise StandardError, "Error generated by BrokenStringReader"
39 # Runs a test on the parser.
41 # +name+ Name of the test
42 # +input+ Input to the test
44 # If given a block, returns the result of yielding to the block.
45 # The block receives two arguments:
46 # +result+ Result from the parser (nil if an error was raised)
47 # +error+ Error that was raised (nil if no error was raised)
48 def parser_test_ex name, input
54 if input.respond_to? :getc
57 reader = StringReader.new input
59 parser = Voodoo::Parser.new reader
60 while (x = parser.parse_top_level) != nil
71 # Runs a test on the parser.
73 # +name+ Name of the test
74 # +input+ Input to the test
75 # +expected+ Expected return value from the parser
76 # +exception+ Expected exception class, or nil if no exception expected
77 def parser_test name, input, expected, exception = nil
78 parser_test_ex(name, input) do |result, error|
80 # Not expecting exception.
86 fail_test("result did not match expected result",
87 "Got:\n#{result.inspect}\nExpected:\n#{expected.inspect}")
90 # Wasnt't expecting exception, but got one.
91 fail_test("unexpected exception of type #{error.class}",
92 "#{error.class}:#{error.message}\n" +
93 error.backtrace.join("\n"))
96 # Expecting exception.
99 fail_test "expected exception of class #{exception.class}, " +
101 elsif error.class != exception.class
102 # Got exception, but of wrong type.
103 fail_test("expected exception of class #{exception.class}, " +
104 "but got one of type #{error.class}",
105 "#{error.class}:#{error.message}\n" +
106 error.backtrace.join("\n"))
108 # Got exception of expected type.
115 # Runs a test on the parser and verifies that the parser
116 # throws an exception of the expected type, with the expected
117 # line and column information.
119 # +name+ Name of the test
120 # +input+ Input to the test
121 # +error_type+ Expected error type
122 # +line+ Expected line number
123 # +column+ Expected column number
124 def parser_test_error name, input, error_type, line, column
125 # Test I/O error on the first character.
126 parser_test_ex(name, input) do |result, error|
127 if error.class != error_type
128 fail_test("expecting exception of class #{error_type}, " +
129 "but got #{error.class}",
130 "#{error.class}:#{error.message}\n" +
131 error.backtrace.join("\n"))
132 elsif error.start_line != line || error.start_column != column
133 fail_test("wrong position. Expected line #{line}, column #{column}" +
134 "; got line #{error.start_line}, column #{error.start_column}")
142 parser_test "empty", "", []
144 parser_test "newline", "\n", []
146 parser_test "comment", "# only a comment", []
148 parser_test "comment_newline", "# only a comment\n", []
150 parser_test "multiline_comment", "# only a comment\n# multiline", []
152 parser_test "multiline_comment_newline",
153 "# only a comment\n# multiline\n", []
155 parser_test "section", "section functions", [[:section, :functions]]
157 parser_test "section_newline", "section functions\n",
158 [[:section, :functions]]
160 parser_test "section_comment", "section functions # functions section",
161 [[:section, :functions]]
163 parser_test "function_noargs", "function\nreturn 0\nend function\n",
164 [[:function, [], [:return, 0]]]
166 parser_test "function_onearg", "function x\nreturn x\nend function\n",
167 [[:function, [:x], [:return, :x]]]
169 parser_test "function_twoargs",
170 "function x y\nreturn add x y\nend function\n",
171 [[:function, [:x, :y], [:return, :add, :x, :y]]]
173 parser_test_error("io_error_start",
174 BrokenStringReader.new("section data", 0),
175 Voodoo::Parser::ParserInternalError,
178 parser_test_error("io_error_first_char",
179 BrokenStringReader.new("section data", 1),
180 Voodoo::Parser::ParserInternalError,
183 parser_test_error("io_error_second_line",
184 BrokenStringReader.new("section data\nfoo:", 13),
185 Voodoo::Parser::ParserInternalError,
188 parser_test_ex("multiple_errors", "block\nlet\nset\n") do |result,error|
189 expected_message = <<EOT
192 2: let requires a symbol and an expression
196 3: set requires a symbol and an expression
200 4: End of input while inside block
202 expected_text = <<EOT
209 if !error.kind_of? Voodoo::Parser::MultipleErrors
210 fail_test "Expected MultipleErrors, but got #{error.class}"
211 elsif error.errors.length != 3
212 fail_test "Expected 3 errors, but got #{error.errors.length}"
213 elsif error.errors[0].start_line != 2
214 fail_test "Expected first error on line 2" +
215 ", but got it on line #{error.errors[0].start_line}"
216 elsif error.errors[1].start_line != 3
217 fail_test "Expected second error on line 3" +
218 ", but got it on line #{error.errors[1].start_line}"
219 elsif error.errors[2].start_line != 4
220 fail_test "Expected third error on line 4" +
221 ", but got it on line #{error.errors[2].start_line}"
222 elsif error.message != expected_message
223 fail_test("Error message differs from expected",
224 "===== ACTUAL =====\n#{error.message}\n" +
225 "===== EXPECTED =====\n#{expected_message}\n")
226 elsif error.text != expected_text
227 fail_test("Error text differs from expected",
228 "===== ACTUAL =====\n#{error.text}\n" +
229 "===== EXPECTED =====\n#{expected_text}\n")
238 exit report_test_results