shoulda-context 1.0.0.beta1
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.
- data/CONTRIBUTION_GUIDELINES.rdoc +10 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +20 -0
- data/MIT-LICENSE +22 -0
- data/README.rdoc +53 -0
- data/Rakefile +44 -0
- data/bin/convert_to_should_syntax +42 -0
- data/lib/shoulda-context.rb +12 -0
- data/lib/shoulda/context/assertions.rb +81 -0
- data/lib/shoulda/context/autoload_macros.rb +46 -0
- data/lib/shoulda/context/context.rb +446 -0
- data/lib/shoulda/context/proc_extensions.rb +14 -0
- data/lib/shoulda/context/tasks.rb +3 -0
- data/lib/shoulda/context/tasks/list_tests.rake +29 -0
- data/lib/shoulda/context/tasks/yaml_to_shoulda.rake +28 -0
- data/lib/shoulda/context/version.rb +5 -0
- data/rails/init.rb +4 -0
- data/test/fake_rails_root/test/shoulda_macros/custom_macro.rb +6 -0
- data/test/fake_rails_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +6 -0
- data/test/fake_rails_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +6 -0
- data/test/shoulda/autoload_macro_test.rb +18 -0
- data/test/shoulda/context_test.rb +368 -0
- data/test/shoulda/convert_to_should_syntax_test.rb +63 -0
- data/test/shoulda/helpers_test.rb +124 -0
- data/test/shoulda/should_test.rb +271 -0
- data/test/test_helper.rb +11 -0
- metadata +101 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
# Stolen straight from ActiveSupport
|
2
|
+
|
3
|
+
class Proc #:nodoc:
|
4
|
+
def bind(object)
|
5
|
+
block, time = self, Time.now
|
6
|
+
(class << object; self end).class_eval do
|
7
|
+
method_name = "__bind_#{time.to_i}_#{time.usec}"
|
8
|
+
define_method(method_name, &block)
|
9
|
+
method = instance_method(method_name)
|
10
|
+
remove_method(method_name)
|
11
|
+
method
|
12
|
+
end.bind(object)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
namespace :shoulda do
|
2
|
+
desc "List the names of the test methods in a specification like format"
|
3
|
+
task :list do
|
4
|
+
$LOAD_PATH.unshift("test")
|
5
|
+
|
6
|
+
require 'test/unit'
|
7
|
+
require 'rubygems'
|
8
|
+
require 'active_support'
|
9
|
+
|
10
|
+
# bug in test unit. Set to true to stop from running.
|
11
|
+
Test::Unit.run = true
|
12
|
+
|
13
|
+
test_files = Dir.glob(File.join('test', '**', '*_test.rb'))
|
14
|
+
test_files.each do |file|
|
15
|
+
load file
|
16
|
+
klass = File.basename(file, '.rb').classify
|
17
|
+
unless Object.const_defined?(klass.to_s)
|
18
|
+
puts "Skipping #{klass} because it doesn't map to a Class"
|
19
|
+
next
|
20
|
+
end
|
21
|
+
klass = klass.constantize
|
22
|
+
|
23
|
+
puts klass.name.gsub('Test', '')
|
24
|
+
|
25
|
+
test_methods = klass.instance_methods.grep(/^test/).map {|s| s.gsub(/^test: /, '')}.sort
|
26
|
+
test_methods.each {|m| puts " " + m }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
namespace :shoulda do
|
2
|
+
# From http://blog.internautdesign.com/2007/11/2/a-yaml_to_shoulda-rake-task
|
3
|
+
# David.Lowenfels@gmail.com
|
4
|
+
desc "Converts a YAML file (FILE=./path/to/yaml) into a Shoulda skeleton"
|
5
|
+
task :from_yaml do
|
6
|
+
require 'yaml'
|
7
|
+
|
8
|
+
def yaml_to_context(hash, indent = 0)
|
9
|
+
indent1 = ' ' * indent
|
10
|
+
indent2 = ' ' * (indent + 1)
|
11
|
+
hash.each_pair do |context, shoulds|
|
12
|
+
puts indent1 + "context \"#{context}\" do"
|
13
|
+
puts
|
14
|
+
shoulds.each do |should|
|
15
|
+
yaml_to_context( should, indent + 1 ) and next if should.is_a?( Hash )
|
16
|
+
puts indent2 + "should_eventually \"" + should.gsub(/^should +/,'') + "\" do"
|
17
|
+
puts indent2 + "end"
|
18
|
+
puts
|
19
|
+
end
|
20
|
+
puts indent1 + "end"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
puts("Please pass in a FILE argument.") and exit unless ENV['FILE']
|
25
|
+
|
26
|
+
yaml_to_context( YAML.load_file( ENV['FILE'] ) )
|
27
|
+
end
|
28
|
+
end
|
data/rails/init.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AutoloadMacroTest < Test::Unit::TestCase # :nodoc:
|
4
|
+
context "The macro auto-loader" do
|
5
|
+
should "load macros from the plugins" do
|
6
|
+
assert self.class.respond_to?('plugin_macro')
|
7
|
+
end
|
8
|
+
|
9
|
+
should "load macros from the gems" do
|
10
|
+
assert self.class.respond_to?('gem_macro')
|
11
|
+
end
|
12
|
+
|
13
|
+
should "load custom macros from ROOT/test/shoulda_macros" do
|
14
|
+
assert self.class.respond_to?('custom_macro')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,368 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ContextTest < Test::Unit::TestCase # :nodoc:
|
4
|
+
|
5
|
+
def self.context_macro(&blk)
|
6
|
+
context "with a subcontext made by a macro" do
|
7
|
+
setup { @context_macro = :foo }
|
8
|
+
|
9
|
+
merge_block &blk
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# def self.context_macro(&blk)
|
14
|
+
# context "with a subcontext made by a macro" do
|
15
|
+
# setup { @context_macro = :foo }
|
16
|
+
# yield # <- this doesn't work.
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
|
20
|
+
context "context with setup block" do
|
21
|
+
setup do
|
22
|
+
@blah = "blah"
|
23
|
+
end
|
24
|
+
|
25
|
+
should "run the setup block" do
|
26
|
+
assert_equal "blah", @blah
|
27
|
+
end
|
28
|
+
|
29
|
+
should "have name set right" do
|
30
|
+
assert_match(/^test: context with setup block/, self.to_s)
|
31
|
+
end
|
32
|
+
|
33
|
+
context "and a subcontext" do
|
34
|
+
setup do
|
35
|
+
@blah = "#{@blah} twice"
|
36
|
+
end
|
37
|
+
|
38
|
+
should "be named correctly" do
|
39
|
+
assert_match(/^test: context with setup block and a subcontext should be named correctly/, self.to_s)
|
40
|
+
end
|
41
|
+
|
42
|
+
should "run the setup blocks in order" do
|
43
|
+
assert_equal @blah, "blah twice"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context_macro do
|
48
|
+
should "have name set right" do
|
49
|
+
assert_match(/^test: context with setup block with a subcontext made by a macro should have name set right/, self.to_s)
|
50
|
+
end
|
51
|
+
|
52
|
+
should "run the setup block of that context macro" do
|
53
|
+
assert_equal :foo, @context_macro
|
54
|
+
end
|
55
|
+
|
56
|
+
should "run the setup block of the main context" do
|
57
|
+
assert_equal "blah", @blah
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
context "another context with setup block" do
|
64
|
+
setup do
|
65
|
+
@blah = "foo"
|
66
|
+
end
|
67
|
+
|
68
|
+
should "have @blah == 'foo'" do
|
69
|
+
assert_equal "foo", @blah
|
70
|
+
end
|
71
|
+
|
72
|
+
should "have name set right" do
|
73
|
+
assert_match(/^test: another context with setup block/, self.to_s)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "context with method definition" do
|
78
|
+
setup do
|
79
|
+
def hello; "hi"; end
|
80
|
+
end
|
81
|
+
|
82
|
+
should "be able to read that method" do
|
83
|
+
assert_equal "hi", hello
|
84
|
+
end
|
85
|
+
|
86
|
+
should "have name set right" do
|
87
|
+
assert_match(/^test: context with method definition/, self.to_s)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "another context" do
|
92
|
+
should "not define @blah" do
|
93
|
+
assert_nil @blah
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "context with multiple setups and/or teardowns" do
|
98
|
+
|
99
|
+
cleanup_count = 0
|
100
|
+
|
101
|
+
2.times do |i|
|
102
|
+
setup { cleanup_count += 1 }
|
103
|
+
teardown { cleanup_count -= 1 }
|
104
|
+
end
|
105
|
+
|
106
|
+
2.times do |i|
|
107
|
+
should "call all setups and all teardowns (check ##{i + 1})" do
|
108
|
+
assert_equal 2, cleanup_count
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "subcontexts" do
|
113
|
+
|
114
|
+
2.times do |i|
|
115
|
+
setup { cleanup_count += 1 }
|
116
|
+
teardown { cleanup_count -= 1 }
|
117
|
+
end
|
118
|
+
|
119
|
+
2.times do |i|
|
120
|
+
should "also call all setups and all teardowns in parent and subcontext (check ##{i + 1})" do
|
121
|
+
assert_equal 4, cleanup_count
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
should_eventually "pass, since it's unimplemented" do
|
130
|
+
flunk "what?"
|
131
|
+
end
|
132
|
+
|
133
|
+
should_eventually "not require a block when using should_eventually"
|
134
|
+
should "pass without a block, as that causes it to piggyback to should_eventually"
|
135
|
+
|
136
|
+
context "context for testing should piggybacking" do
|
137
|
+
should "call should_eventually as we are not passing a block"
|
138
|
+
end
|
139
|
+
|
140
|
+
context "context" do
|
141
|
+
context "with nested subcontexts" do
|
142
|
+
should_eventually "only print this statement once for a should_eventually"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class ::SomeModel; end
|
147
|
+
|
148
|
+
context "given a test named after a class" do
|
149
|
+
setup do
|
150
|
+
self.class.stubs(:name).returns("SomeModelTest")
|
151
|
+
end
|
152
|
+
|
153
|
+
should "determine the described type" do
|
154
|
+
assert_equal SomeModel, self.class.described_type
|
155
|
+
end
|
156
|
+
|
157
|
+
should "return a new instance of the described type as the subject if none exists" do
|
158
|
+
assert_kind_of SomeModel, subject
|
159
|
+
end
|
160
|
+
|
161
|
+
context "with an explicit subject block" do
|
162
|
+
setup { @expected = SomeModel.new }
|
163
|
+
subject { @expected }
|
164
|
+
should "return the result of the block as the subject" do
|
165
|
+
assert_equal @expected, subject
|
166
|
+
end
|
167
|
+
|
168
|
+
context "nested context block without a subject block" do
|
169
|
+
should "return the result of the parent context's subject block" do
|
170
|
+
assert_equal @expected, subject
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
class ::Some
|
179
|
+
class NestedModel; end
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
class Some::NestedModelTest < Test::Unit::TestCase
|
184
|
+
should "determine the described type for a nested model" do
|
185
|
+
assert_equal Some::NestedModel, self.class.described_type
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
class ShouldMatcherTest < Test::Unit::TestCase
|
190
|
+
class FakeMatcher
|
191
|
+
attr_reader :subject
|
192
|
+
attr_accessor :fail
|
193
|
+
|
194
|
+
def description
|
195
|
+
"do something"
|
196
|
+
end
|
197
|
+
|
198
|
+
def matches?(subject)
|
199
|
+
@subject = subject
|
200
|
+
!@fail
|
201
|
+
end
|
202
|
+
|
203
|
+
def failure_message
|
204
|
+
"a failure message"
|
205
|
+
end
|
206
|
+
|
207
|
+
def negative_failure_message
|
208
|
+
"not a failure message"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def run_test
|
213
|
+
@test_suite.run(@test_result) { |event, name |}
|
214
|
+
end
|
215
|
+
|
216
|
+
def setup
|
217
|
+
@matcher = FakeMatcher.new
|
218
|
+
@test_result = Test::Unit::TestResult.new
|
219
|
+
class << @test_result
|
220
|
+
def failure_messages
|
221
|
+
@failures.map { |failure| failure.message }
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def create_test_suite(&definition)
|
227
|
+
test_class = Class.new(Test::Unit::TestCase, &definition)
|
228
|
+
test_class.suite
|
229
|
+
end
|
230
|
+
|
231
|
+
def assert_failed_with(message, test_result)
|
232
|
+
assert_equal 1, test_result.failure_count
|
233
|
+
assert_equal [message], test_result.failure_messages
|
234
|
+
end
|
235
|
+
|
236
|
+
def assert_passed(test_result)
|
237
|
+
assert_equal 0, test_result.failure_count
|
238
|
+
end
|
239
|
+
|
240
|
+
def assert_test_named(expected_name, test_suite)
|
241
|
+
name = test_suite.tests.map { |test| test.method_name }.first
|
242
|
+
assert name.include?(expected_name), "Expected #{name} to include #{expected_name}"
|
243
|
+
end
|
244
|
+
|
245
|
+
def self.should_use_positive_matcher
|
246
|
+
should "generate a test using the matcher's description" do
|
247
|
+
assert_test_named "should #{@matcher.description}", @test_suite
|
248
|
+
end
|
249
|
+
|
250
|
+
should "pass with a passing matcher" do
|
251
|
+
@matcher.fail = false
|
252
|
+
run_test
|
253
|
+
assert_passed @test_result
|
254
|
+
end
|
255
|
+
|
256
|
+
should "fail with a failing matcher" do
|
257
|
+
@matcher.fail = true
|
258
|
+
run_test
|
259
|
+
assert_failed_with @matcher.failure_message, @test_result
|
260
|
+
end
|
261
|
+
|
262
|
+
should "provide the subject" do
|
263
|
+
@matcher.fail = false
|
264
|
+
run_test
|
265
|
+
assert_equal 'a subject', @matcher.subject
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def self.should_use_negative_matcher
|
270
|
+
should "generate a test using the matcher's description" do
|
271
|
+
assert_test_named "should not #{@matcher.description}", @test_suite
|
272
|
+
end
|
273
|
+
|
274
|
+
should "pass with a failing matcher" do
|
275
|
+
@matcher.fail = true
|
276
|
+
run_test
|
277
|
+
assert_passed @test_result
|
278
|
+
end
|
279
|
+
|
280
|
+
should "fail with a passing matcher" do
|
281
|
+
@matcher.fail = false
|
282
|
+
run_test
|
283
|
+
assert_failed_with @matcher.negative_failure_message, @test_result
|
284
|
+
end
|
285
|
+
|
286
|
+
should "provide the subject" do
|
287
|
+
@matcher.fail = false
|
288
|
+
run_test
|
289
|
+
assert_equal 'a subject', @matcher.subject
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
293
|
+
context "a should block with a matcher" do
|
294
|
+
setup do
|
295
|
+
matcher = @matcher
|
296
|
+
@test_suite = create_test_suite do
|
297
|
+
subject { 'a subject' }
|
298
|
+
should matcher
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
should_use_positive_matcher
|
303
|
+
end
|
304
|
+
|
305
|
+
context "a should block with a matcher within a context" do
|
306
|
+
setup do
|
307
|
+
matcher = @matcher
|
308
|
+
@test_suite = create_test_suite do
|
309
|
+
context "in context" do
|
310
|
+
subject { 'a subject' }
|
311
|
+
should matcher
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
should_use_positive_matcher
|
317
|
+
end
|
318
|
+
|
319
|
+
context "a should_not block with a matcher" do
|
320
|
+
setup do
|
321
|
+
matcher = @matcher
|
322
|
+
@test_suite = create_test_suite do
|
323
|
+
subject { 'a subject' }
|
324
|
+
should_not matcher
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
should_use_negative_matcher
|
329
|
+
end
|
330
|
+
|
331
|
+
context "a should_not block with a matcher within a context" do
|
332
|
+
setup do
|
333
|
+
matcher = @matcher
|
334
|
+
@test_suite = create_test_suite do
|
335
|
+
context "in context" do
|
336
|
+
subject { 'a subject' }
|
337
|
+
should_not matcher
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
should_use_negative_matcher
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
class Subject; end
|
347
|
+
|
348
|
+
class SubjectTest < Test::Unit::TestCase
|
349
|
+
|
350
|
+
def setup
|
351
|
+
@expected = Subject.new
|
352
|
+
end
|
353
|
+
|
354
|
+
subject { @expected }
|
355
|
+
|
356
|
+
should "return a specified subject" do
|
357
|
+
assert_equal @expected, subject
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
class SubjectLazinessTest < Test::Unit::TestCase
|
362
|
+
subject { Subject.new }
|
363
|
+
|
364
|
+
should "only build the subject once" do
|
365
|
+
assert_equal subject, subject
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|