scope 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/scope.rb +63 -29
  2. data/scope.gemspec +1 -1
  3. metadata +4 -4
@@ -32,19 +32,26 @@ module Scope
32
32
  end
33
33
 
34
34
  def self.context(name, &block)
35
+ context_focused = false
36
+ if @focus_enabled && @focus_next_test_or_context
37
+ @focus_next_test_or_context = false
38
+ @inside_focused_context = true
39
+ context_focused = true
40
+ end
35
41
  parent = @contexts.last
36
42
  new_context = Context.new(name, parent)
37
43
  parent.tests_and_subcontexts << new_context
38
44
  @contexts << new_context
39
45
  block.call
40
46
  @contexts.pop
47
+ @inside_focused_context = false if context_focused
41
48
  end
42
49
 
43
50
  def self.should(name, &block)
44
51
  # When focus_enabled is true, we'll only be running the next should() block that gets defined.
45
52
  if @focus_enabled
46
- return unless @focus_next_test
47
- @focus_next_test = false
53
+ return unless @focus_next_test_or_context || @inside_focused_context
54
+ @focus_next_test_or_context &&= false
48
55
  end
49
56
 
50
57
  context_name = @contexts[1..-1].map { |context| context.name }.join(" ")
@@ -63,14 +70,16 @@ module Scope
63
70
  def self.setup_once(&block) @contexts.last.setup_once = block end
64
71
  def self.teardown_once(&block) @contexts.last.teardown_once = block end
65
72
 
66
- # "Focuses" the next test that's defined after this method is called, ensuring that only that test is run.
73
+ # "Focuses" the next test or context that's defined after this method is called, ensuring that only that
74
+ # test/context is run.
67
75
  def self.focus
68
- # Since we're focusing only the next test, remove any tests which were already defined.
76
+ # Since we're focusing only the next test/context, remove any tests which were already defined.
69
77
  context_for_test.values.uniq.each do |context|
70
78
  context.tests_and_subcontexts.reject! { |test| test.is_a?(String) }
71
79
  end
72
80
  @focus_enabled = true
73
- @focus_next_test = true
81
+ @focus_next_test_or_context = true
82
+ @inside_focused_context = false
74
83
  end
75
84
 
76
85
  # run() is called by the MiniTest framework. This TestCase class is instantiated once per test method
@@ -81,7 +90,7 @@ module Scope
81
90
  result = nil
82
91
  begin
83
92
  # Unit::TestCase's implementation of run() invokes the test method with exception handling.
84
- context.run_setup_and_teardown(self, test_name) { result = super }
93
+ context.run_setup_and_teardown(self, test_name) { result = super(test_runner) }
85
94
  rescue *MiniTest::Unit::TestCase::PASSTHROUGH_EXCEPTIONS
86
95
  raise
87
96
  rescue Exception => error
@@ -107,27 +116,42 @@ module Scope
107
116
 
108
117
  # Runs the setup work for this context and any parent contexts, yields to the block (which should invoke
109
118
  # the actual test method), and then completes the teardown work.
110
- def run_setup_and_teardown(test_case_instance, test_name)
119
+ def run_setup_and_teardown(test_case_instance, test_name, &runner_proc)
111
120
  contexts = ([self] + ancestor_contexts).reverse
121
+ recursively_run_setup_and_teardown(test_case_instance, test_name, contexts, runner_proc)
122
+ end
123
+
124
+ def teardown_once=(block) @teardown_once = run_only_once(block) end
125
+ def setup_once=(block) @setup_once = run_only_once(block) end
126
+
127
+ private
128
+ def recursively_run_setup_and_teardown(test_case_instance, test_name, contexts, runner_proc)
129
+ outer_context = contexts.slice! 0
112
130
  # We're using instance_eval so that instance vars set by the block are created on the test_case_instance
113
- contexts.each { |context| test_case_instance.instance_eval(&context.setup_once) if context.setup_once }
114
- contexts.each { |context| test_case_instance.instance_eval(&context.setup) if context.setup }
115
- yield
116
- contexts.reverse!
117
- contexts.each { |context| test_case_instance.instance_eval(&context.teardown) if context.teardown }
118
-
119
- # If this is the last context being run in any parent contexts, run their teardown_once blocks.
120
- if tests_and_subcontexts.last == test_name
121
- test_case_instance.instance_eval(&teardown_once) if teardown_once
122
- descendant_context = self
123
- ancestor_contexts.each do |ancestor|
124
- break unless ancestor.tests_and_subcontexts.last == descendant_context
125
- test_case_instance.instance_eval(&ancestor.teardown_once) if ancestor.teardown_once
126
- descendant_context = ancestor
131
+ test_case_instance.instance_eval(&outer_context.setup_once) if outer_context.setup_once
132
+ test_case_instance.instance_eval(&outer_context.setup) if outer_context.setup
133
+ begin
134
+ if contexts.empty?
135
+ runner_proc.call
136
+ else
137
+ recursively_run_setup_and_teardown(test_case_instance, test_name, contexts, runner_proc)
138
+ end
139
+ ensure
140
+ # The ensure block guarantees that this context's teardown blocks will be run, even in an exception
141
+ # is thrown in a descendant context or in the test itself.
142
+ test_case_instance.instance_eval(&outer_context.teardown) if outer_context.teardown
143
+ if outer_context.name_of_last_test == test_name
144
+ test_case_instance.instance_eval(&outer_context.teardown_once) if outer_context.teardown_once
127
145
  end
128
146
  end
129
147
  end
130
148
 
149
+ def run_only_once(block)
150
+ has_run = false
151
+ Proc.new { instance_eval(&block) unless has_run; has_run = true }
152
+ end
153
+
154
+ protected
131
155
  def ancestor_contexts
132
156
  ancestors = []
133
157
  parent = self
@@ -135,13 +159,23 @@ module Scope
135
159
  ancestors
136
160
  end
137
161
 
138
- def teardown_once=(block) @teardown_once = run_only_once(block) end
139
- def setup_once=(block) @setup_once = run_only_once(block) end
140
-
141
- private
142
- def run_only_once(block)
143
- has_run = false
144
- Proc.new { instance_eval(&block) unless has_run; has_run = true }
162
+ # Returns the name of the last actual test within this context (including within its descendant contexts),
163
+ # or nil if none exists.
164
+ def name_of_last_test
165
+ unless defined? @name_of_last_test
166
+ @name_of_last_test = nil
167
+ tests_and_subcontexts.reverse.each do |test_or_context|
168
+ if test_or_context.is_a? String
169
+ @name_of_last_test = test_or_context
170
+ break
171
+ end
172
+ unless test_or_context.name_of_last_test.nil?
173
+ @name_of_last_test = test_or_context.name_of_last_test
174
+ break
175
+ end
176
+ end
177
+ end
178
+ @name_of_last_test
145
179
  end
146
180
  end
147
- end
181
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "scope"
3
- s.version = "0.2.1"
3
+ s.version = "0.2.2"
4
4
 
5
5
  s.required_rubygems_version = Gem::Requirement.new(">=0") if s.respond_to? :required_rubygems_version=
6
6
  s.specification_version = 2 if s.respond_to? :specification_version=
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scope
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 1
10
- version: 0.2.1
9
+ - 2
10
+ version: 0.2.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Phil Crosby
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-05-23 00:00:00 -07:00
18
+ date: 2011-06-27 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency