treetop 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. data/README +3 -0
  2. data/Rakefile +35 -0
  3. data/bin/tt +25 -0
  4. data/lib/treetop.rb +10 -6
  5. data/lib/treetop/compiler.rb +7 -0
  6. data/lib/treetop/compiler/grammar_compiler.rb +21 -0
  7. data/lib/treetop/compiler/lexical_address_space.rb +17 -0
  8. data/lib/treetop/compiler/load_grammar.rb +7 -0
  9. data/lib/treetop/compiler/metagrammar.rb +2441 -0
  10. data/lib/treetop/compiler/metagrammar.treetop +384 -0
  11. data/lib/treetop/compiler/node_classes.rb +18 -0
  12. data/lib/treetop/compiler/node_classes/anything_symbol.rb +10 -0
  13. data/lib/treetop/compiler/node_classes/atomic_expression.rb +9 -0
  14. data/lib/treetop/compiler/node_classes/character_class.rb +10 -0
  15. data/lib/treetop/compiler/node_classes/choice.rb +31 -0
  16. data/lib/treetop/compiler/node_classes/declaration_sequence.rb +24 -0
  17. data/lib/treetop/compiler/node_classes/grammar.rb +28 -0
  18. data/lib/treetop/compiler/node_classes/inline_module.rb +27 -0
  19. data/lib/treetop/compiler/node_classes/nonterminal.rb +11 -0
  20. data/lib/treetop/compiler/node_classes/optional.rb +19 -0
  21. data/lib/treetop/compiler/node_classes/parenthesized_expression.rb +9 -0
  22. data/lib/treetop/compiler/node_classes/parsing_expression.rb +132 -0
  23. data/lib/treetop/compiler/node_classes/parsing_rule.rb +55 -0
  24. data/lib/treetop/compiler/node_classes/predicate.rb +45 -0
  25. data/lib/treetop/compiler/node_classes/repetition.rb +56 -0
  26. data/lib/treetop/compiler/node_classes/sequence.rb +64 -0
  27. data/lib/treetop/compiler/node_classes/terminal.rb +10 -0
  28. data/lib/treetop/compiler/node_classes/treetop_file.rb +9 -0
  29. data/lib/treetop/compiler/ruby_builder.rb +109 -0
  30. data/lib/treetop/ruby_extensions.rb +2 -0
  31. data/lib/treetop/ruby_extensions/string.rb +19 -0
  32. data/lib/treetop/runtime.rb +9 -0
  33. data/lib/treetop/runtime/compiled_parser.rb +66 -0
  34. data/lib/treetop/runtime/node_cache.rb +27 -0
  35. data/lib/treetop/runtime/parse_cache.rb +19 -0
  36. data/lib/treetop/runtime/parse_failure.rb +32 -0
  37. data/lib/treetop/runtime/parse_result.rb +30 -0
  38. data/lib/treetop/runtime/syntax_node.rb +53 -0
  39. data/lib/treetop/runtime/terminal_parse_failure.rb +33 -0
  40. data/lib/treetop/runtime/terminal_syntax_node.rb +12 -0
  41. data/test/compilation_target/target.rb +143 -0
  42. data/test/compilation_target/target.treetop +15 -0
  43. data/test/compilation_target/target_test.rb +56 -0
  44. data/test/compiler/and_predicate_test.rb +33 -0
  45. data/test/compiler/anything_symbol_test.rb +24 -0
  46. data/test/compiler/character_class_test.rb +45 -0
  47. data/test/compiler/choice_test.rb +49 -0
  48. data/test/compiler/circular_compilation_test.rb +20 -0
  49. data/test/compiler/failure_propagation_functional_test.rb +20 -0
  50. data/test/compiler/grammar_compiler_test.rb +58 -0
  51. data/test/compiler/grammar_test.rb +33 -0
  52. data/test/compiler/nonterminal_symbol_test.rb +15 -0
  53. data/test/compiler/not_predicate_test.rb +35 -0
  54. data/test/compiler/one_or_more_test.rb +30 -0
  55. data/test/compiler/optional_test.rb +32 -0
  56. data/test/compiler/parsing_rule_test.rb +30 -0
  57. data/test/compiler/sequence_test.rb +68 -0
  58. data/test/compiler/terminal_symbol_test.rb +35 -0
  59. data/test/compiler/test_grammar.treetop +7 -0
  60. data/test/compiler/zero_or_more_test.rb +51 -0
  61. data/test/composition/a.treetop +11 -0
  62. data/test/composition/b.treetop +11 -0
  63. data/test/composition/c.treetop +10 -0
  64. data/test/composition/d.treetop +10 -0
  65. data/test/composition/grammar_composition_test.rb +23 -0
  66. data/test/parser/syntax_node_test.rb +53 -0
  67. data/test/parser/terminal_parse_failure_test.rb +22 -0
  68. data/test/ruby_extensions/string_test.rb +33 -0
  69. data/test/screw/Rakefile +16 -0
  70. data/test/screw/unit.rb +37 -0
  71. data/test/screw/unit/assertion_failed_error.rb +14 -0
  72. data/test/screw/unit/assertions.rb +615 -0
  73. data/test/screw/unit/auto_runner.rb +227 -0
  74. data/test/screw/unit/collector.rb +45 -0
  75. data/test/screw/unit/collector/dir.rb +107 -0
  76. data/test/screw/unit/collector/objectspace.rb +28 -0
  77. data/test/screw/unit/error.rb +48 -0
  78. data/test/screw/unit/failure.rb +45 -0
  79. data/test/screw/unit/sugar.rb +25 -0
  80. data/test/screw/unit/test_case.rb +176 -0
  81. data/test/screw/unit/test_result.rb +73 -0
  82. data/test/screw/unit/test_suite.rb +70 -0
  83. data/test/screw/unit/ui.rb +4 -0
  84. data/test/screw/unit/ui/console/test_runner.rb +118 -0
  85. data/test/screw/unit/ui/fox/test_runner.rb +268 -0
  86. data/test/screw/unit/ui/gtk/test_runner.rb +416 -0
  87. data/test/screw/unit/ui/gtk2/testrunner.rb +465 -0
  88. data/test/screw/unit/ui/test_runner_mediator.rb +58 -0
  89. data/test/screw/unit/ui/test_runner_utilities.rb +46 -0
  90. data/test/screw/unit/ui/tk/test_runner.rb +260 -0
  91. data/test/screw/unit/util.rb +4 -0
  92. data/test/screw/unit/util/backtrace_filter.rb +40 -0
  93. data/test/screw/unit/util/observable.rb +82 -0
  94. data/test/screw/unit/util/proc_wrapper.rb +48 -0
  95. data/test/test_helper.rb +89 -0
  96. metadata +127 -69
  97. data/lib/treetop/api.rb +0 -3
  98. data/lib/treetop/api/load_grammar.rb +0 -16
  99. data/lib/treetop/api/malformed_grammar_exception.rb +0 -9
  100. data/lib/treetop/grammar.rb +0 -7
  101. data/lib/treetop/grammar/grammar.rb +0 -48
  102. data/lib/treetop/grammar/grammar_builder.rb +0 -35
  103. data/lib/treetop/grammar/parsing_expression_builder.rb +0 -5
  104. data/lib/treetop/grammar/parsing_expression_builder_helper.rb +0 -121
  105. data/lib/treetop/grammar/parsing_expressions.rb +0 -18
  106. data/lib/treetop/grammar/parsing_expressions/and_predicate.rb +0 -17
  107. data/lib/treetop/grammar/parsing_expressions/anything_symbol.rb +0 -20
  108. data/lib/treetop/grammar/parsing_expressions/character_class.rb +0 -24
  109. data/lib/treetop/grammar/parsing_expressions/node_instantiating_parsing_expression.rb +0 -14
  110. data/lib/treetop/grammar/parsing_expressions/node_propagating_parsing_expression.rb +0 -4
  111. data/lib/treetop/grammar/parsing_expressions/nonterminal_symbol.rb +0 -42
  112. data/lib/treetop/grammar/parsing_expressions/not_predicate.rb +0 -18
  113. data/lib/treetop/grammar/parsing_expressions/one_or_more.rb +0 -12
  114. data/lib/treetop/grammar/parsing_expressions/optional.rb +0 -14
  115. data/lib/treetop/grammar/parsing_expressions/ordered_choice.rb +0 -27
  116. data/lib/treetop/grammar/parsing_expressions/parsing_expression.rb +0 -36
  117. data/lib/treetop/grammar/parsing_expressions/predicate.rb +0 -25
  118. data/lib/treetop/grammar/parsing_expressions/repeating_parsing_expression.rb +0 -29
  119. data/lib/treetop/grammar/parsing_expressions/sequence.rb +0 -41
  120. data/lib/treetop/grammar/parsing_expressions/terminal_parsing_expression.rb +0 -11
  121. data/lib/treetop/grammar/parsing_expressions/terminal_symbol.rb +0 -31
  122. data/lib/treetop/grammar/parsing_expressions/zero_or_more.rb +0 -11
  123. data/lib/treetop/grammar/parsing_rule.rb +0 -10
  124. data/lib/treetop/metagrammar.rb +0 -2
  125. data/lib/treetop/metagrammar/metagrammar.rb +0 -14
  126. data/lib/treetop/metagrammar/metagrammar.treetop +0 -320
  127. data/lib/treetop/parser.rb +0 -11
  128. data/lib/treetop/parser/node_cache.rb +0 -25
  129. data/lib/treetop/parser/parse_cache.rb +0 -17
  130. data/lib/treetop/parser/parse_failure.rb +0 -22
  131. data/lib/treetop/parser/parse_result.rb +0 -26
  132. data/lib/treetop/parser/parser.rb +0 -24
  133. data/lib/treetop/parser/sequence_syntax_node.rb +0 -14
  134. data/lib/treetop/parser/syntax_node.rb +0 -31
  135. data/lib/treetop/parser/terminal_parse_failure.rb +0 -18
  136. data/lib/treetop/parser/terminal_syntax_node.rb +0 -7
  137. data/lib/treetop/protometagrammar.rb +0 -16
  138. data/lib/treetop/protometagrammar/anything_symbol_expression_builder.rb +0 -13
  139. data/lib/treetop/protometagrammar/block_expression_builder.rb +0 -17
  140. data/lib/treetop/protometagrammar/character_class_expression_builder.rb +0 -25
  141. data/lib/treetop/protometagrammar/grammar_expression_builder.rb +0 -38
  142. data/lib/treetop/protometagrammar/nonterminal_symbol_expression_builder.rb +0 -45
  143. data/lib/treetop/protometagrammar/ordered_choice_expression_builder.rb +0 -21
  144. data/lib/treetop/protometagrammar/parsing_rule_expression_builder.rb +0 -23
  145. data/lib/treetop/protometagrammar/parsing_rule_sequence_expression_builder.rb +0 -14
  146. data/lib/treetop/protometagrammar/prefix_expression_builder.rb +0 -25
  147. data/lib/treetop/protometagrammar/primary_expression_builder.rb +0 -71
  148. data/lib/treetop/protometagrammar/protometagrammar.rb +0 -25
  149. data/lib/treetop/protometagrammar/sequence_expression_builder.rb +0 -37
  150. data/lib/treetop/protometagrammar/suffix_expression_builder.rb +0 -33
  151. data/lib/treetop/protometagrammar/terminal_symbol_expression_builder.rb +0 -52
  152. data/lib/treetop/protometagrammar/trailing_block_expression_builder.rb +0 -30
  153. data/lib/treetop/ruby_extension.rb +0 -11
@@ -0,0 +1,22 @@
1
+ dir = File.dirname(__FILE__)
2
+ require "#{dir}/../test_helper"
3
+
4
+ describe "A terminal parse failure" do
5
+ def setup
6
+ @input = "test input"
7
+ @failure = Runtime::TerminalParseFailure.new(@input, 1, "foo")
8
+ end
9
+
10
+ it "is == to a parse failure at the same index expecting the same string" do
11
+ @failure.should == Runtime::TerminalParseFailure.new(@input, 1, "foo")
12
+ end
13
+
14
+ it "is eql to a parse failure at the same index expecting the same string" do
15
+ @failure.should eql(Runtime::TerminalParseFailure.new(@input, 1, "foo"))
16
+ @failure.hash.should == Runtime::TerminalParseFailure.new(@input, 1, "foo").hash
17
+ end
18
+
19
+ it "is considered identical to another failure with the same index and expected string in an array" do
20
+ [Runtime::TerminalParseFailure.new(@input, 1, "foo"), Runtime::TerminalParseFailure.new(@input, 1, "foo")].uniq.size.should == 1
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'test_helper')
2
+
3
+ class StringTest < Screw::Unit::TestCase
4
+
5
+ def setup
6
+ @string = %{
7
+ 0123456789
8
+ 012345
9
+ 01234567
10
+ 0123
11
+ }.tabto(0).strip
12
+ end
13
+
14
+ test "column numbers" do
15
+ @string.column_of(0).should == 1
16
+ @string.column_of(5).should == 6
17
+ @string.column_of(10).should == 11
18
+ @string.column_of(11).should == 1
19
+ @string.column_of(17).should == 7
20
+ @string.column_of(18).should == 1
21
+ @string.column_of(24).should == 7
22
+ end
23
+
24
+ test "line numbers" do
25
+ @string.line_of(0).should == 1
26
+ @string.line_of(5).should == 1
27
+ @string.line_of(10).should == 1
28
+ @string.line_of(11).should == 2
29
+ @string.line_of(17).should == 2
30
+ @string.line_of(18).should == 3
31
+ @string.line_of(24).should == 3
32
+ end
33
+ end
@@ -0,0 +1,16 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = "Screw::Unit"
3
+ s.version = "0.0.1"
4
+ s.author = "Nathan Sobo"
5
+ s.email = "nathansobo@gmail.com"
6
+ s.homepage = "http://screwunit.rubyforge.org"
7
+ s.platform = Gem::Platform::RUBY
8
+ s.summary = "RSpec-style syntactic sugar that is backward compatible with Test::Unit"
9
+ s.files = FileList["{unit}/**/*"].to_a
10
+ s.require_path = "lib"
11
+ s.autorequire = "name"
12
+ s.test_files = FileList["{test}/**/*test.rb"].to_a
13
+ s.has_rdoc = true
14
+ s.extra_rdoc_files = ["README"]
15
+ s.add_dependency("dependency", ">= 0.x.x")
16
+ end
@@ -0,0 +1,37 @@
1
+ dir = File.dirname(__FILE__)
2
+ require 'rubygems'
3
+ require 'spec/expectations'
4
+ require 'spec/matchers'
5
+
6
+ require File.join(dir, 'unit', 'util')
7
+ require File.join(dir, 'unit', 'assertion_failed_error')
8
+ require File.join(dir, 'unit', 'assertions')
9
+ require File.join(dir, 'unit', 'collector')
10
+ require File.join(dir, 'unit', 'error')
11
+ require File.join(dir, 'unit', 'failure')
12
+ require File.join(dir, 'unit', 'test_case')
13
+ require File.join(dir, 'unit', 'test_result')
14
+ require File.join(dir, 'unit', 'test_suite')
15
+ require File.join(dir, 'unit', 'ui')
16
+ require File.join(dir, 'unit', 'auto_runner')
17
+ require File.join(dir, 'unit', 'sugar')
18
+
19
+ module Screw
20
+ module Unit
21
+ # If set to false Screw::Unit will not automatically run at exit.
22
+ def self.run=(flag)
23
+ @run = flag
24
+ end
25
+
26
+ # Automatically run tests at exit?
27
+ def self.run?
28
+ @run ||= false
29
+ end
30
+ end
31
+ end
32
+
33
+ at_exit do
34
+ unless $! || Screw::Unit.run?
35
+ exit Screw::Unit::AutoRunner.run
36
+ end
37
+ end
@@ -0,0 +1,14 @@
1
+ #--
2
+ #
3
+ # Author:: Nathaniel Talbott.
4
+ # Copyright:: Copyright (c) 2000-2002 Nathaniel Talbott. All rights reserved.
5
+ # License:: Ruby license.
6
+
7
+ module Screw
8
+ module Unit
9
+
10
+ # Thrown by Screw::Unit::Assertions when an assertion fails.
11
+ class AssertionFailedError < StandardError
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,615 @@
1
+ module Screw
2
+ module Unit
3
+
4
+ ##
5
+ # Screw::Unit::Assertions contains the standard Screw::Unit assertions.
6
+ # Assertions is included in Screw::Unit::TestCase.
7
+ #
8
+ # To include it in your own code and use its functionality, you simply
9
+ # need to rescue Screw::Unit::AssertionFailedError. Additionally you may
10
+ # override add_assertion to get notified whenever an assertion is made.
11
+ #
12
+ # Notes:
13
+ # * The message to each assertion, if given, will be propagated with the
14
+ # failure.
15
+ # * It is easy to add your own assertions based on assert_block().
16
+ #
17
+ # = Example Custom Assertion
18
+ #
19
+ # def deny(boolean, message = nil)
20
+ # message = build_message message, '<?> is not false or nil.', boolean
21
+ # assert_block message do
22
+ # not boolean
23
+ # end
24
+ # end
25
+
26
+ module Assertions
27
+
28
+ ##
29
+ # The assertion upon which all other assertions are based. Passes if the
30
+ # block yields true.
31
+ #
32
+ # Example:
33
+ # assert_block "Couldn't do the thing" do
34
+ # do_the_thing
35
+ # end
36
+
37
+ public
38
+ def assert_block(message="assert_block failed.") # :yields:
39
+ _wrap_assertion do
40
+ if (! yield)
41
+ raise AssertionFailedError.new(message.to_s)
42
+ end
43
+ end
44
+ end
45
+
46
+ ##
47
+ # Asserts that +boolean+ is not false or nil.
48
+ #
49
+ # Example:
50
+ # assert [1, 2].include?(5)
51
+
52
+ public
53
+ def assert(boolean, message=nil)
54
+ _wrap_assertion do
55
+ assert_block("assert should not be called with a block.") { !block_given? }
56
+ assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
57
+ end
58
+ end
59
+
60
+ ##
61
+ # Passes if +expected+ == +actual.
62
+ #
63
+ # Note that the ordering of arguments is important, since a helpful
64
+ # error message is generated when this one fails that tells you the
65
+ # values of expected and actual.
66
+ #
67
+ # Example:
68
+ # assert_equal 'MY STRING', 'my string'.upcase
69
+
70
+ public
71
+ def assert_equal(expected, actual, message=nil)
72
+ full_message = build_message(message, <<EOT, expected, actual)
73
+ <?> expected but was
74
+ <?>.
75
+ EOT
76
+ assert_block(full_message) { expected == actual }
77
+ end
78
+
79
+ private
80
+ def _check_exception_class(args) # :nodoc:
81
+ args.partition do |klass|
82
+ next if klass.instance_of?(Module)
83
+ assert(Exception >= klass, "Should expect a class of exception, #{klass}")
84
+ true
85
+ end
86
+ end
87
+
88
+ private
89
+ def _expected_exception?(actual_exception, exceptions, modules) # :nodoc:
90
+ exceptions.include?(actual_exception.class) or
91
+ modules.any? {|mod| actual_exception.is_a?(mod)}
92
+ end
93
+
94
+ ##
95
+ # Passes if the block raises one of the given exceptions.
96
+ #
97
+ # Example:
98
+ # assert_raise RuntimeError, LoadError do
99
+ # raise 'Boom!!!'
100
+ # end
101
+
102
+ public
103
+ def assert_raise(*args)
104
+ _wrap_assertion do
105
+ if Module === args.last
106
+ message = ""
107
+ else
108
+ message = args.pop
109
+ end
110
+ exceptions, modules = _check_exception_class(args)
111
+ expected = args.size == 1 ? args.first : args
112
+ actual_exception = nil
113
+ full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
114
+ assert_block(full_message) do
115
+ begin
116
+ yield
117
+ rescue Exception => actual_exception
118
+ break
119
+ end
120
+ false
121
+ end
122
+ full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
123
+ assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)}
124
+ actual_exception
125
+ end
126
+ end
127
+
128
+ ##
129
+ # Alias of assert_raise.
130
+ #
131
+ # Will be deprecated in 1.9, and removed in 2.0.
132
+
133
+ public
134
+ def assert_raises(*args, &block)
135
+ assert_raise(*args, &block)
136
+ end
137
+
138
+ ##
139
+ # Passes if +object+ .instance_of? +klass+
140
+ #
141
+ # Example:
142
+ # assert_instance_of String, 'foo'
143
+
144
+ public
145
+ def assert_instance_of(klass, object, message="")
146
+ _wrap_assertion do
147
+ assert_equal(Class, klass.class, "assert_instance_of takes a Class as its first argument")
148
+ full_message = build_message(message, <<EOT, object, klass, object.class)
149
+ <?> expected to be an instance of
150
+ <?> but was
151
+ <?>.
152
+ EOT
153
+ assert_block(full_message){object.instance_of?(klass)}
154
+ end
155
+ end
156
+
157
+ ##
158
+ # Passes if +object+ is nil.
159
+ #
160
+ # Example:
161
+ # assert_nil [1, 2].uniq!
162
+
163
+ public
164
+ def assert_nil(object, message="")
165
+ assert_equal(nil, object, message)
166
+ end
167
+
168
+ ##
169
+ # Passes if +object+ .kind_of? +klass+
170
+ #
171
+ # Example:
172
+ # assert_kind_of Object, 'foo'
173
+
174
+ public
175
+ def assert_kind_of(klass, object, message="")
176
+ _wrap_assertion do
177
+ assert(klass.kind_of?(Module), "The first parameter to assert_kind_of should be a kind_of Module.")
178
+ full_message = build_message(message, "<?>\nexpected to be kind_of\\?\n<?> but was\n<?>.", object, klass, object.class)
179
+ assert_block(full_message){object.kind_of?(klass)}
180
+ end
181
+ end
182
+
183
+ ##
184
+ # Passes if +object+ .respond_to? +method+
185
+ #
186
+ # Example:
187
+ # assert_respond_to 'bugbear', :slice
188
+
189
+ public
190
+ def assert_respond_to(object, method, message="")
191
+ _wrap_assertion do
192
+ full_message = build_message(nil, "<?>\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to\\?(:to_str).", method)
193
+
194
+ assert_block(full_message) do
195
+ method.kind_of?(Symbol) || method.respond_to?(:to_str)
196
+ end
197
+ full_message = build_message(message, <<EOT, object, object.class, method)
198
+ <?>
199
+ of type <?>
200
+ expected to respond_to\\?<?>.
201
+ EOT
202
+ assert_block(full_message) { object.respond_to?(method) }
203
+ end
204
+ end
205
+
206
+ ##
207
+ # Passes if +string+ =~ +pattern+.
208
+ #
209
+ # Example:
210
+ # assert_match(/\d+/, 'five, 6, seven')
211
+
212
+ public
213
+ def assert_match(pattern, string, message="")
214
+ _wrap_assertion do
215
+ pattern = case(pattern)
216
+ when String
217
+ Regexp.new(Regexp.escape(pattern))
218
+ else
219
+ pattern
220
+ end
221
+ full_message = build_message(message, "<?> expected to be =~\n<?>.", string, pattern)
222
+ assert_block(full_message) { string =~ pattern }
223
+ end
224
+ end
225
+
226
+ ##
227
+ # Passes if +actual+ .equal? +expected+ (i.e. they are the same
228
+ # instance).
229
+ #
230
+ # Example:
231
+ # o = Object.new
232
+ # assert_same o, o
233
+
234
+ public
235
+ def assert_same(expected, actual, message="")
236
+ full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
237
+ <?>
238
+ with id <?> expected to be equal\\? to
239
+ <?>
240
+ with id <?>.
241
+ EOT
242
+ assert_block(full_message) { actual.equal?(expected) }
243
+ end
244
+
245
+ ##
246
+ # Compares the +object1+ with +object2+ using +operator+.
247
+ #
248
+ # Passes if object1.__send__(operator, object2) is true.
249
+ #
250
+ # Example:
251
+ # assert_operator 5, :>=, 4
252
+
253
+ public
254
+ def assert_operator(object1, operator, object2, message="")
255
+ _wrap_assertion do
256
+ full_message = build_message(nil, "<?>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator)
257
+ assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)}
258
+ full_message = build_message(message, <<EOT, object1, AssertionMessage.literal(operator), object2)
259
+ <?> expected to be
260
+ ?
261
+ <?>.
262
+ EOT
263
+ assert_block(full_message) { object1.__send__(operator, object2) }
264
+ end
265
+ end
266
+
267
+ ##
268
+ # Passes if block does not raise an exception.
269
+ #
270
+ # Example:
271
+ # assert_nothing_raised do
272
+ # [1, 2].uniq
273
+ # end
274
+
275
+ public
276
+ def assert_nothing_raised(*args)
277
+ _wrap_assertion do
278
+ if Module === args.last
279
+ message = ""
280
+ else
281
+ message = args.pop
282
+ end
283
+ exceptions, modules = _check_exception_class(args)
284
+ begin
285
+ yield
286
+ rescue Exception => e
287
+ if ((args.empty? && !e.instance_of?(AssertionFailedError)) ||
288
+ _expected_exception?(e, exceptions, modules))
289
+ assert_block(build_message(message, "Exception raised:\n?", e)){false}
290
+ else
291
+ raise
292
+ end
293
+ end
294
+ nil
295
+ end
296
+ end
297
+
298
+ ##
299
+ # Flunk always fails.
300
+ #
301
+ # Example:
302
+ # flunk 'Not done testing yet.'
303
+
304
+ public
305
+ def flunk(message="Flunked")
306
+ assert_block(build_message(message)){false}
307
+ end
308
+
309
+ ##
310
+ # Passes if ! +actual+ .equal? +expected+
311
+ #
312
+ # Example:
313
+ # assert_not_same Object.new, Object.new
314
+
315
+ public
316
+ def assert_not_same(expected, actual, message="")
317
+ full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
318
+ <?>
319
+ with id <?> expected to not be equal\\? to
320
+ <?>
321
+ with id <?>.
322
+ EOT
323
+ assert_block(full_message) { !actual.equal?(expected) }
324
+ end
325
+
326
+ ##
327
+ # Passes if +expected+ != +actual+
328
+ #
329
+ # Example:
330
+ # assert_not_equal 'some string', 5
331
+
332
+ public
333
+ def assert_not_equal(expected, actual, message="")
334
+ full_message = build_message(message, "<?> expected to be != to\n<?>.", expected, actual)
335
+ assert_block(full_message) { expected != actual }
336
+ end
337
+
338
+ ##
339
+ # Passes if ! +object+ .nil?
340
+ #
341
+ # Example:
342
+ # assert_not_nil '1 two 3'.sub!(/two/, '2')
343
+
344
+ public
345
+ def assert_not_nil(object, message="")
346
+ full_message = build_message(message, "<?> expected to not be nil.", object)
347
+ assert_block(full_message){!object.nil?}
348
+ end
349
+
350
+ ##
351
+ # Passes if +regexp+ !~ +string+
352
+ #
353
+ # Example:
354
+ # assert_no_match(/two/, 'one 2 three')
355
+
356
+ public
357
+ def assert_no_match(regexp, string, message="")
358
+ _wrap_assertion do
359
+ assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
360
+ full_message = build_message(message, "<?> expected to not match\n<?>.", regexp, string)
361
+ assert_block(full_message) { regexp !~ string }
362
+ end
363
+ end
364
+
365
+ UncaughtThrow = {NameError => /^uncaught throw \`(.+)\'$/,
366
+ ThreadError => /^uncaught throw \`(.+)\' in thread /} #`
367
+
368
+ ##
369
+ # Passes if the block throws +expected_symbol+
370
+ #
371
+ # Example:
372
+ # assert_throws :done do
373
+ # throw :done
374
+ # end
375
+
376
+ public
377
+ def assert_throws(expected_symbol, message="", &proc)
378
+ _wrap_assertion do
379
+ assert_instance_of(Symbol, expected_symbol, "assert_throws expects the symbol that should be thrown for its first argument")
380
+ assert_block("Should have passed a block to assert_throws."){block_given?}
381
+ caught = true
382
+ begin
383
+ catch(expected_symbol) do
384
+ proc.call
385
+ caught = false
386
+ end
387
+ full_message = build_message(message, "<?> should have been thrown.", expected_symbol)
388
+ assert_block(full_message){caught}
389
+ rescue NameError, ThreadError => error
390
+ if UncaughtThrow[error.class] !~ error.message
391
+ raise error
392
+ end
393
+ full_message = build_message(message, "<?> expected to be thrown but\n<?> was thrown.", expected_symbol, $1.intern)
394
+ flunk(full_message)
395
+ end
396
+ end
397
+ end
398
+
399
+ ##
400
+ # Passes if block does not throw anything.
401
+ #
402
+ # Example:
403
+ # assert_nothing_thrown do
404
+ # [1, 2].uniq
405
+ # end
406
+
407
+ public
408
+ def assert_nothing_thrown(message="", &proc)
409
+ _wrap_assertion do
410
+ assert(block_given?, "Should have passed a block to assert_nothing_thrown")
411
+ begin
412
+ proc.call
413
+ rescue NameError, ThreadError => error
414
+ if UncaughtThrow[error.class] !~ error.message
415
+ raise error
416
+ end
417
+ full_message = build_message(message, "<?> was thrown when nothing was expected", $1.intern)
418
+ flunk(full_message)
419
+ end
420
+ assert(true, "Expected nothing to be thrown")
421
+ end
422
+ end
423
+
424
+ ##
425
+ # Passes if +expected_float+ and +actual_float+ are equal
426
+ # within +delta+ tolerance.
427
+ #
428
+ # Example:
429
+ # assert_in_delta 0.05, (50000.0 / 10**6), 0.00001
430
+
431
+ public
432
+ def assert_in_delta(expected_float, actual_float, delta, message="")
433
+ _wrap_assertion do
434
+ {expected_float => "first float", actual_float => "second float", delta => "delta"}.each do |float, name|
435
+ assert_respond_to(float, :to_f, "The arguments must respond to to_f; the #{name} did not")
436
+ end
437
+ assert_operator(delta, :>=, 0.0, "The delta should not be negative")
438
+ full_message = build_message(message, <<EOT, expected_float, actual_float, delta)
439
+ <?> and
440
+ <?> expected to be within
441
+ <?> of each other.
442
+ EOT
443
+ assert_block(full_message) { (expected_float.to_f - actual_float.to_f).abs <= delta.to_f }
444
+ end
445
+ end
446
+
447
+ ##
448
+ # Passes if the method send returns a true value.
449
+ #
450
+ # +send_array+ is composed of:
451
+ # * A receiver
452
+ # * A method
453
+ # * Arguments to the method
454
+ #
455
+ # Example:
456
+ # assert_send [[1, 2], :include?, 4]
457
+
458
+ public
459
+ def assert_send(send_array, message="")
460
+ _wrap_assertion do
461
+ assert_instance_of(Array, send_array, "assert_send requires an array of send information")
462
+ assert(send_array.size >= 2, "assert_send requires at least a receiver and a message name")
463
+ full_message = build_message(message, <<EOT, send_array[0], AssertionMessage.literal(send_array[1].to_s), send_array[2..-1])
464
+ <?> expected to respond to
465
+ <?(?)> with a true value.
466
+ EOT
467
+ assert_block(full_message) { send_array[0].__send__(send_array[1], *send_array[2..-1]) }
468
+ end
469
+ end
470
+
471
+ ##
472
+ # Builds a failure message. +head+ is added before the +template+ and
473
+ # +arguments+ replaces the '?'s positionally in the template.
474
+
475
+ public
476
+ def build_message(head, template=nil, *arguments)
477
+ template &&= template.chomp
478
+ return AssertionMessage.new(head, template, arguments)
479
+ end
480
+
481
+ private
482
+ def _wrap_assertion
483
+ @_assertion_wrapped ||= false
484
+ unless (@_assertion_wrapped)
485
+ @_assertion_wrapped = true
486
+ begin
487
+ add_assertion
488
+ return yield
489
+ ensure
490
+ @_assertion_wrapped = false
491
+ end
492
+ else
493
+ return yield
494
+ end
495
+ end
496
+
497
+ ##
498
+ # Called whenever an assertion is made. Define this in classes that
499
+ # include Screw::Unit::Assertions to record assertion counts.
500
+
501
+ private
502
+ def add_assertion
503
+ end
504
+
505
+ ##
506
+ # Select whether or not to use the pretty-printer. If this option is set
507
+ # to false before any assertions are made, pp.rb will not be required.
508
+
509
+ public
510
+ def self.use_pp=(value)
511
+ AssertionMessage.use_pp = value
512
+ end
513
+
514
+ # :stopdoc:
515
+
516
+ class AssertionMessage
517
+ @use_pp = true
518
+ class << self
519
+ attr_accessor :use_pp
520
+ end
521
+
522
+ class Literal
523
+ def initialize(value)
524
+ @value = value
525
+ end
526
+
527
+ def inspect
528
+ @value.to_s
529
+ end
530
+ end
531
+
532
+ class Template
533
+ def self.create(string)
534
+ parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : [])
535
+ self.new(parts)
536
+ end
537
+
538
+ attr_reader :count
539
+
540
+ def initialize(parts)
541
+ @parts = parts
542
+ @count = parts.find_all{|e| e == '?'}.size
543
+ end
544
+
545
+ def result(parameters)
546
+ raise "The number of parameters does not match the number of substitutions." if(parameters.size != count)
547
+ params = parameters.dup
548
+ @parts.collect{|e| e == '?' ? params.shift : e.gsub(/\\\?/m, '?')}.join('')
549
+ end
550
+ end
551
+
552
+ def self.literal(value)
553
+ Literal.new(value)
554
+ end
555
+
556
+ include Util::BacktraceFilter
557
+
558
+ def initialize(head, template_string, parameters)
559
+ @head = head
560
+ @template_string = template_string
561
+ @parameters = parameters
562
+ end
563
+
564
+ def convert(object)
565
+ case object
566
+ when Exception
567
+ <<EOM.chop
568
+ Class: <#{convert(object.class)}>
569
+ Message: <#{convert(object.message)}>
570
+ ---Backtrace---
571
+ #{filter_backtrace(object.backtrace).join("\n")}
572
+ ---------------
573
+ EOM
574
+ else
575
+ if(self.class.use_pp)
576
+ begin
577
+ require 'pp'
578
+ rescue LoadError
579
+ self.class.use_pp = false
580
+ return object.inspect
581
+ end unless(defined?(PP))
582
+ PP.pp(object, '').chomp
583
+ else
584
+ object.inspect
585
+ end
586
+ end
587
+ end
588
+
589
+ def template
590
+ @template ||= Template.create(@template_string)
591
+ end
592
+
593
+ def add_period(string)
594
+ (string =~ /\.\Z/ ? string : string + '.')
595
+ end
596
+
597
+ def to_s
598
+ message_parts = []
599
+ if (@head)
600
+ head = @head.to_s
601
+ unless(head.empty?)
602
+ message_parts << add_period(head)
603
+ end
604
+ end
605
+ tail = template.result(@parameters.collect{|e| convert(e)})
606
+ message_parts << tail unless(tail.empty?)
607
+ message_parts.join("\n")
608
+ end
609
+ end
610
+
611
+ # :startdoc:
612
+
613
+ end
614
+ end
615
+ end