scope 0.2.1 → 0.2.2

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 (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