treetop 0.1.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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