mspec 1.3.1 → 1.4.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.
@@ -18,18 +18,21 @@ module MSpec
18
18
  @mode = nil
19
19
  @load = nil
20
20
  @unload = nil
21
+ @current = nil
22
+ @shared = {}
21
23
  @exception = nil
22
24
  @randomize = nil
23
25
  @expectation = nil
24
26
  @expectations = false
25
27
 
26
- def self.describe(mod, msg=nil, &block)
27
- stack.push ContextState.new
28
+ def self.describe(mod, options=nil, &block)
29
+ state = ContextState.new mod, options
30
+ state.parent = current
28
31
 
29
- current.describe(mod, msg, &block)
30
- current.process
32
+ MSpec.register_current state
33
+ state.describe(&block)
31
34
 
32
- stack.pop
35
+ state.process unless state.shared? or current
33
36
  end
34
37
 
35
38
  def self.process
@@ -62,6 +65,8 @@ module MSpec
62
65
  begin
63
66
  @env.instance_eval(&block)
64
67
  return true
68
+ rescue SystemExit
69
+ raise
65
70
  rescue Exception => exc
66
71
  register_exit 1
67
72
  actions :exception, ExceptionState.new(current && current.state, location, exc)
@@ -69,14 +74,42 @@ module MSpec
69
74
  end
70
75
  end
71
76
 
77
+ # Sets the toplevel ContextState to +state+.
78
+ def self.register_current(state)
79
+ store :current, state
80
+ end
81
+
82
+ # Sets the toplevel ContextState to +nil+.
83
+ def self.clear_current
84
+ store :current, nil
85
+ end
86
+
87
+ # Returns the toplevel ContextState.
88
+ def self.current
89
+ retrieve :current
90
+ end
91
+
92
+ # Stores the shared ContextState keyed by description.
93
+ def self.register_shared(state)
94
+ @shared[state.to_s] = state
95
+ end
96
+
97
+ # Returns the shared ContextState matching description.
98
+ def self.retrieve_shared(desc)
99
+ @shared[desc.to_s]
100
+ end
101
+
102
+ # Stores the exit code used by the runner scripts.
72
103
  def self.register_exit(code)
73
104
  store :exit, code
74
105
  end
75
106
 
107
+ # Retrieves the stored exit code.
76
108
  def self.exit_code
77
109
  retrieve(:exit).to_i
78
110
  end
79
111
 
112
+ # Stores the list of files to be evaluated.
80
113
  def self.register_files(files)
81
114
  store :files, files
82
115
  end
@@ -141,14 +174,6 @@ module MSpec
141
174
  end
142
175
  end
143
176
 
144
- def self.stack
145
- @stack ||= []
146
- end
147
-
148
- def self.current
149
- stack.last
150
- end
151
-
152
177
  def self.verify_mode?
153
178
  @mode == :verify
154
179
  end
@@ -7,7 +7,7 @@ class Object
7
7
  MSpec.current.after at, &block
8
8
  end
9
9
 
10
- def describe(mod, msg=nil, &block)
10
+ def describe(mod, msg=nil, options=nil, &block)
11
11
  MSpec.describe mod, msg, &block
12
12
  end
13
13
 
@@ -15,6 +15,10 @@ class Object
15
15
  MSpec.current.it msg, &block
16
16
  end
17
17
 
18
+ def it_should_behave_like(desc)
19
+ MSpec.current.it_should_behave_like desc
20
+ end
21
+
18
22
  alias_method :context, :describe
19
23
  alias_method :specify, :it
20
24
  end
@@ -1,12 +1,12 @@
1
1
  require 'mspec/runner/mspec'
2
2
 
3
3
  class Object
4
- def shared(msg, &block)
5
- MSpec.store msg.to_sym, block
6
- end
4
+ def it_behaves_like(desc, meth, obj=nil)
5
+ send :before, :all do
6
+ @method = meth
7
+ @object = obj if obj
8
+ end
7
9
 
8
- def it_behaves_like(behavior, *args)
9
- p = MSpec.retrieve behavior.to_sym
10
- p[*args]
10
+ send :it_should_behave_like, desc.to_s
11
11
  end
12
12
  end
@@ -1,3 +1,3 @@
1
1
  module MSpec
2
- VERSION = '1.3.1'
2
+ VERSION = '1.4.0'
3
3
  end
@@ -121,6 +121,20 @@ describe MSpecCI, "#run" do
121
121
  @script.run
122
122
  end
123
123
 
124
+ it "registers a tag filter for 'critical'" do
125
+ filter = mock("critical filter")
126
+ TagFilter.should_receive(:new).with(:exclude, 'critical').and_return(filter)
127
+ filter.should_receive(:register)
128
+ @script.run
129
+ end
130
+
131
+ it "registers a tag filter for 'unsupported'" do
132
+ filter = mock("unsupported filter")
133
+ TagFilter.should_receive(:new).with(:exclude, 'unsupported').and_return(filter)
134
+ filter.should_receive(:register)
135
+ @script.run
136
+ end
137
+
124
138
  it "processes the files" do
125
139
  MSpec.should_receive(:process)
126
140
  @script.run
@@ -0,0 +1,75 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'mspec/expectations/expectations'
3
+ require 'mspec/matchers/equal_element'
4
+
5
+ describe EqualElementMatcher do
6
+ it "matches if it finds an element with the passed name, no matter what attributes/content" do
7
+ EqualElementMatcher.new("A").matches?('<A></A>').should be_true
8
+ EqualElementMatcher.new("A").matches?('<A HREF="http://example.com"></A>').should be_true
9
+ EqualElementMatcher.new("A").matches?('<A HREF="http://example.com"></A>').should be_true
10
+
11
+ EqualElementMatcher.new("BASE").matches?('<BASE></A>').should be_false
12
+ EqualElementMatcher.new("BASE").matches?('<A></BASE>').should be_false
13
+ EqualElementMatcher.new("BASE").matches?('<A></A>').should be_false
14
+ EqualElementMatcher.new("BASE").matches?('<A HREF="http://example.com"></A>').should be_false
15
+ EqualElementMatcher.new("BASE").matches?('<A HREF="http://example.com"></A>').should be_false
16
+ end
17
+
18
+ it "matches if it finds an element with the passed name and the passed attributes" do
19
+ EqualElementMatcher.new("A", {}).matches?('<A></A>').should be_true
20
+ EqualElementMatcher.new("A", nil).matches?('<A HREF="http://example.com"></A>').should be_true
21
+ EqualElementMatcher.new("A", "HREF" => "http://example.com").matches?('<A HREF="http://example.com"></A>').should be_true
22
+
23
+ EqualElementMatcher.new("A", {}).matches?('<A HREF="http://example.com"></A>').should be_false
24
+ EqualElementMatcher.new("A", "HREF" => "http://example.com").matches?('<A></A>').should be_false
25
+ EqualElementMatcher.new("A", "HREF" => "http://example.com").matches?('<A HREF="http://test.com"></A>').should be_false
26
+ EqualElementMatcher.new("A", "HREF" => "http://example.com").matches?('<A HREF="http://example.com" HREF="http://example.com"></A>').should be_false
27
+ end
28
+
29
+ it "matches if it finds an element with the passed name, the passed attributes and the passed content" do
30
+ EqualElementMatcher.new("A", {}, "").matches?('<A></A>').should be_true
31
+ EqualElementMatcher.new("A", {"HREF" => "http://example.com"}, "Example").matches?('<A HREF="http://example.com">Example</A>').should be_true
32
+
33
+ EqualElementMatcher.new("A", {}, "Test").matches?('<A></A>').should be_false
34
+ EqualElementMatcher.new("A", {"HREF" => "http://example.com"}, "Example").matches?('<A HREF="http://example.com"></A>').should be_false
35
+ EqualElementMatcher.new("A", {"HREF" => "http://example.com"}, "Example").matches?('<A HREF="http://example.com">Test</A>').should be_false
36
+ end
37
+
38
+ it "can match unclosed elements" do
39
+ EqualElementMatcher.new("BASE", nil, nil, :not_closed => true).matches?('<BASE>').should be_true
40
+ EqualElementMatcher.new("BASE", {"HREF" => "http://example.com"}, nil, :not_closed => true).matches?('<BASE HREF="http://example.com">').should be_true
41
+ EqualElementMatcher.new("BASE", {"HREF" => "http://example.com"}, "Example", :not_closed => true).matches?('<BASE HREF="http://example.com">Example').should be_true
42
+
43
+ EqualElementMatcher.new("BASE", {}, nil, :not_closed => true).matches?('<BASE HREF="http://example.com">').should be_false
44
+ EqualElementMatcher.new("BASE", {"HREF" => "http://example.com"}, "", :not_closed => true).matches?('<BASE HREF="http://example.com">Example').should be_false
45
+ EqualElementMatcher.new("BASE", {"HREF" => "http://example.com"}, "Test", :not_closed => true).matches?('<BASE HREF="http://example.com">Example').should be_false
46
+ end
47
+
48
+ it "provides a useful failure message" do
49
+ equal_element = EqualElementMatcher.new("A", {}, "Test")
50
+ equal_element.matches?('<A></A>').should be_false
51
+ equal_element.failure_message.should == [%{Expected "<A></A>"\n}, %{to be a 'A' element with no attributes and "Test" as content}]
52
+
53
+ equal_element = EqualElementMatcher.new("A", {}, "")
54
+ equal_element.matches?('<A>Test</A>').should be_false
55
+ equal_element.failure_message.should == [%{Expected "<A>Test</A>"\n}, %{to be a 'A' element with no attributes and no content}]
56
+
57
+ equal_element = EqualElementMatcher.new("A", "HREF" => "http://www.example.com")
58
+ equal_element.matches?('<A>Test</A>').should be_false
59
+ equal_element.failure_message.should == [%{Expected "<A>Test</A>"\n}, %{to be a 'A' element with HREF="http://www.example.com" and any content}]
60
+ end
61
+
62
+ it "provides a useful negative failure message" do
63
+ equal_element = EqualElementMatcher.new("A", {}, "Test")
64
+ equal_element.matches?('<A></A>').should be_false
65
+ equal_element.negative_failure_message.should == [%{Expected "<A></A>"\n}, %{not to be a 'A' element with no attributes and "Test" as content}]
66
+
67
+ equal_element = EqualElementMatcher.new("A", {}, "")
68
+ equal_element.matches?('<A>Test</A>').should be_false
69
+ equal_element.negative_failure_message.should == [%{Expected "<A>Test</A>"\n}, %{not to be a 'A' element with no attributes and no content}]
70
+
71
+ equal_element = EqualElementMatcher.new("A", "HREF" => "http://www.example.com")
72
+ equal_element.matches?('<A>Test</A>').should be_false
73
+ equal_element.negative_failure_message.should == [%{Expected "<A>Test</A>"\n}, %{not to be a 'A' element with HREF="http://www.example.com" and any content}]
74
+ end
75
+ end
@@ -1,6 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/../../spec_helper'
2
2
  require 'mspec/runner/actions/debug'
3
3
  require 'mspec/runner/mspec'
4
+ require 'mspec/runner/context'
4
5
  require 'mspec/runner/example'
5
6
 
6
7
  describe DebugAction do
@@ -18,7 +19,7 @@ end
18
19
  describe DebugAction, "#before" do
19
20
  before :each do
20
21
  MSpec.stub!(:read_tags).and_return([])
21
- @state = ExampleState.new "Catch#me", "if you can"
22
+ @state = ExampleState.new ContextState.new("Catch#me"), "if you can"
22
23
  end
23
24
 
24
25
  it "does not invoke the debugger if the description does not match" do
@@ -18,7 +18,7 @@ end
18
18
  describe GdbAction, "#before" do
19
19
  before :each do
20
20
  MSpec.stub!(:read_tags).and_return([])
21
- @state = ExampleState.new "Catch#me", "if you can"
21
+ @state = ExampleState.new ContextState.new("Catch#me"), "if you can"
22
22
  end
23
23
 
24
24
  it "does not invoke the debugger if the description does not match" do
@@ -94,7 +94,7 @@ describe TagAction, "#before" do
94
94
  action.exception?.should be_false
95
95
  action.exception ExceptionState.new(nil, nil, Exception.new("Fail!"))
96
96
  action.exception?.should be_true
97
- action.before(ExampleState.new("describe", "it"))
97
+ action.before(ExampleState.new(ContextState.new("describe"), "it"))
98
98
  action.exception?.should be_false
99
99
  end
100
100
  end
@@ -111,7 +111,8 @@ end
111
111
  describe TagAction, "#after when action is :add" do
112
112
  before :each do
113
113
  MSpec.stub!(:read_tags).and_return([])
114
- @state = ExampleState.new "Catch#me", "if you can"
114
+ context = ContextState.new "Catch#me"
115
+ @state = ExampleState.new context, "if you can"
115
116
  @tag = SpecTag.new "tag(comment):Catch#me if you can"
116
117
  SpecTag.stub!(:new).and_return(@tag)
117
118
  @exception = ExceptionState.new nil, nil, Exception.new("failed")
@@ -159,7 +160,8 @@ end
159
160
  describe TagAction, "#after when action is :del" do
160
161
  before :each do
161
162
  MSpec.stub!(:read_tags).and_return([])
162
- @state = ExampleState.new "Catch#me", "if you can"
163
+ context = ContextState.new "Catch#me"
164
+ @state = ExampleState.new context, "if you can"
163
165
  @tag = SpecTag.new "tag(comment):Catch#me if you can"
164
166
  SpecTag.stub!(:new).and_return(@tag)
165
167
  @exception = ExceptionState.new nil, nil, Exception.new("failed")
@@ -207,7 +209,8 @@ end
207
209
  describe TagAction, "#finish" do
208
210
  before :each do
209
211
  $stdout = @out = IOStub.new
210
- @state = ExampleState.new "Catch#me", "if you can"
212
+ context = ContextState.new "Catch#me"
213
+ @state = ExampleState.new context, "if you can"
211
214
  MSpec.stub!(:write_tag).and_return(true)
212
215
  MSpec.stub!(:delete_tag).and_return(true)
213
216
  end
@@ -5,43 +5,198 @@ require 'mspec/runner/mspec'
5
5
  require 'mspec/mocks/mock'
6
6
  require 'mspec/runner/context'
7
7
 
8
- describe ContextState do
8
+ describe ContextState, "#describe" do
9
9
  before :each do
10
- @state = ContextState.new
10
+ @state = ContextState.new "C#m"
11
+ @proc = lambda { ScratchPad.record :a }
12
+ ScratchPad.clear
13
+ end
14
+
15
+ it "evaluates the passed block" do
16
+ @state.describe(&@proc)
17
+ ScratchPad.recorded.should == :a
18
+ end
19
+
20
+ it "evaluates the passed block via #protect" do
21
+ @state.should_receive(:protect).with("C#m", @proc, false)
22
+ @state.describe(&@proc)
23
+ end
24
+
25
+ it "registers #parent as the current MSpec ContextState" do
26
+ parent = ContextState.new ""
27
+ @state.parent = parent
28
+ MSpec.should_receive(:register_current).with(parent)
29
+ @state.describe { }
30
+ end
31
+
32
+ it "registers self with MSpec when #shared? is true" do
33
+ state = ContextState.new "something shared", :shared => true
34
+ MSpec.should_receive(:register_shared).with(state)
35
+ state.describe { }
36
+ end
37
+ end
38
+
39
+ describe ContextState, "#shared?" do
40
+ it "returns false when the ContextState is not shared" do
41
+ ContextState.new("").shared?.should be_false
42
+ end
43
+
44
+ it "returns true when the ContextState is shared" do
45
+ ContextState.new("", {:shared => true}).shared?.should be_true
46
+ end
47
+ end
48
+
49
+ describe ContextState, "#to_s" do
50
+ it "returns a description string for self when passed a Module" do
51
+ ContextState.new(Object).to_s.should == "Object"
52
+ end
53
+
54
+ it "returns a description string for self when passed a String" do
55
+ ContextState.new("SomeClass").to_s.should == "SomeClass"
56
+ end
57
+
58
+ it "returns a description string for self when passed a Module, String" do
59
+ ContextState.new(Object, "when empty").to_s.should == "Object when empty"
60
+ end
61
+
62
+ it "returns a description string for self when passed a Module and String beginning with '#'" do
63
+ ContextState.new(Object, "#to_s").to_s.should == "Object#to_s"
64
+ end
65
+
66
+ it "returns a description string for self when passed a Module and String beginning with '.'" do
67
+ ContextState.new(Object, ".to_s").to_s.should == "Object.to_s"
68
+ end
69
+
70
+ it "returns a description string for self when passed a Module and String beginning with '::'" do
71
+ ContextState.new(Object, "::to_s").to_s.should == "Object::to_s"
72
+ end
73
+ end
74
+
75
+ describe ContextState, "#description" do
76
+ before :each do
77
+ @state = ContextState.new "when empty"
78
+ @parent = ContextState.new "Toplevel"
79
+ end
80
+
81
+ it "returns a composite description string from self and all parents" do
82
+ @parent.description.should == "Toplevel"
83
+ @state.description.should == "when empty"
84
+ @state.parent = @parent
85
+ @state.description.should == "Toplevel when empty"
86
+ end
87
+ end
88
+
89
+ describe ContextState, "#it" do
90
+ before :each do
91
+ @state = ContextState.new ""
11
92
  @proc = lambda { }
12
93
  end
13
94
 
14
- it "records before(:all) blocks" do
15
- @state.before(:all, &@proc)
16
- @state.instance_variable_get(:@start).should == [@proc]
95
+ it "creates an ExampleState instance for the block" do
96
+ ex = ExampleState.new("", "", &@proc)
97
+ ExampleState.should_receive(:new).with(@state, "it", @proc).and_return(ex)
98
+ @state.describe(&@proc)
99
+ @state.it("it", &@proc)
100
+ end
101
+ end
102
+
103
+ describe ContextState, "#examples" do
104
+ before :each do
105
+ @state = ContextState.new ""
106
+ end
107
+
108
+ it "returns a list of all examples in this ContextState" do
109
+ @state.it("first") { }
110
+ @state.it("second") { }
111
+ @state.examples.size.should == 2
112
+ end
113
+ end
114
+
115
+ describe ContextState, "#before" do
116
+ before :each do
117
+ @state = ContextState.new ""
118
+ @proc = lambda { }
17
119
  end
18
120
 
19
- it "records before(:each) blocks" do
121
+ it "records the block for :each" do
20
122
  @state.before(:each, &@proc)
21
- @state.instance_variable_get(:@before).should == [@proc]
123
+ @state.before(:each).should == [@proc]
22
124
  end
23
125
 
24
- it "records after(:all) blocks" do
25
- @state.after(:all, &@proc)
26
- @state.instance_variable_get(:@finish).should == [@proc]
126
+ it "records the block for :all" do
127
+ @state.before(:all, &@proc)
128
+ @state.before(:all).should == [@proc]
129
+ end
130
+ end
131
+
132
+ describe ContextState, "#after" do
133
+ before :each do
134
+ @state = ContextState.new ""
135
+ @proc = lambda { }
27
136
  end
28
137
 
29
- it "records after(:each) blocks" do
138
+ it "records the block for :each" do
30
139
  @state.after(:each, &@proc)
31
- @state.instance_variable_get(:@after).should == [@proc]
140
+ @state.after(:each).should == [@proc]
141
+ end
142
+
143
+ it "records the block for :all" do
144
+ @state.after(:all, &@proc)
145
+ @state.after(:all).should == [@proc]
146
+ end
147
+ end
148
+
149
+ describe ContextState, "#pre" do
150
+ before :each do
151
+ @a = lambda { }
152
+ @b = lambda { }
153
+ @c = lambda { }
154
+
155
+ parent = ContextState.new ""
156
+ parent.before(:each, &@c)
157
+ parent.before(:all, &@c)
158
+
159
+ @state = ContextState.new ""
160
+ @state.parent = parent
161
+ end
162
+
163
+ it "returns before(:each) actions in the order they were defined" do
164
+ @state.before(:each, &@a)
165
+ @state.before(:each, &@b)
166
+ @state.pre(:each).should == [@c, @a, @b]
167
+ end
168
+
169
+ it "returns before(:all) actions in the order they were defined" do
170
+ @state.before(:all, &@a)
171
+ @state.before(:all, &@b)
172
+ @state.pre(:all).should == [@c, @a, @b]
173
+ end
174
+ end
175
+
176
+ describe ContextState, "#post" do
177
+ before :each do
178
+ @a = lambda { }
179
+ @b = lambda { }
180
+ @c = lambda { }
181
+
182
+ parent = ContextState.new ""
183
+ parent.after(:each, &@c)
184
+ parent.after(:all, &@c)
185
+
186
+ @state = ContextState.new ""
187
+ @state.parent = parent
32
188
  end
33
189
 
34
- it "records it blocks" do
35
- @state.it("message", &@proc)
36
- msg, proc = @state.instance_variable_get(:@spec)[0]
37
- msg.should == "message"
38
- proc.should == @proc
190
+ it "returns after(:each) actions in the reverse order they were defined" do
191
+ @state.after(:each, &@a)
192
+ @state.after(:each, &@b)
193
+ @state.post(:each).should == [@b, @a, @c]
39
194
  end
40
195
 
41
- it "records describe blocks" do
42
- @state.describe(Object, "message", &@proc)
43
- @state.instance_variable_get(:@describe).should == "Object message"
44
- @state.instance_variable_get(:@block).should == @proc
196
+ it "returns after(:all) actions in the reverse order they were defined" do
197
+ @state.after(:all, &@a)
198
+ @state.after(:all, &@b)
199
+ @state.post(:all).should == [@b, @a, @c]
45
200
  end
46
201
  end
47
202
 
@@ -55,27 +210,116 @@ describe ContextState, "#protect" do
55
210
 
56
211
  it "returns true and does execute any blocks if check is true and MSpec.pretend_mode? is true" do
57
212
  MSpec.stub!(:pretend_mode?).and_return(true)
58
- ContextState.new.protect("message", [@a, @b]).should be_true
213
+ ContextState.new("").protect("message", [@a, @b]).should be_true
59
214
  ScratchPad.recorded.should == []
60
215
  end
61
216
 
62
217
  it "executes the blocks if MSpec.pretend_mode? is false" do
63
218
  MSpec.stub!(:pretend_mode?).and_return(false)
64
- ContextState.new.protect("message", [@a, @b])
219
+ ContextState.new("").protect("message", [@a, @b])
65
220
  ScratchPad.recorded.should == [:a, :b]
66
221
  end
67
222
 
68
223
  it "executes the blocks if check is false" do
69
- ContextState.new.protect("message", [@a, @b], false)
224
+ ContextState.new("").protect("message", [@a, @b], false)
70
225
  ScratchPad.recorded.should == [:a, :b]
71
226
  end
72
227
 
73
228
  it "returns true if none of the blocks raise an exception" do
74
- ContextState.new.protect("message", [@a, @b]).should be_true
229
+ ContextState.new("").protect("message", [@a, @b]).should be_true
75
230
  end
76
231
 
77
232
  it "returns false if any of the blocks raise an exception" do
78
- ContextState.new.protect("message", [@a, @c, @b]).should be_false
233
+ ContextState.new("").protect("message", [@a, @c, @b]).should be_false
234
+ end
235
+ end
236
+
237
+ describe ContextState, "#parent=" do
238
+ before :each do
239
+ @state = ContextState.new ""
240
+ @parent = mock("describe")
241
+ @parent.stub!(:parent).and_return(nil)
242
+ @parent.stub!(:child)
243
+ end
244
+
245
+ it "does not set self as a child of parent if shared" do
246
+ @parent.should_not_receive(:child)
247
+ state = ContextState.new "", :shared => true
248
+ state.parent = @parent
249
+ end
250
+
251
+ it "sets self as a child of parent" do
252
+ @parent.should_receive(:child).with(@state)
253
+ @state.parent = @parent
254
+ end
255
+
256
+ it "creates the list of parents" do
257
+ @state.parent = @parent
258
+ @state.parents.should == [@parent, @state]
259
+ end
260
+ end
261
+
262
+ describe ContextState, "#parent" do
263
+ before :each do
264
+ @state = ContextState.new ""
265
+ @parent = mock("describe")
266
+ @parent.stub!(:parent).and_return(nil)
267
+ @parent.stub!(:child)
268
+ end
269
+
270
+ it "returns nil if parent has not been set" do
271
+ @state.parent.should be_nil
272
+ end
273
+
274
+ it "returns the parent" do
275
+ @state.parent = @parent
276
+ @state.parent.should == @parent
277
+ end
278
+ end
279
+
280
+ describe ContextState, "#parents" do
281
+ before :each do
282
+ @first = ContextState.new ""
283
+ @second = ContextState.new ""
284
+ @parent = mock("describe")
285
+ @parent.stub!(:parent).and_return(nil)
286
+ @parent.stub!(:child)
287
+ end
288
+
289
+ it "returns a list of all enclosing ContextState instances" do
290
+ @first.parent = @parent
291
+ @second.parent = @first
292
+ @second.parents.should == [@parent, @first, @second]
293
+ end
294
+ end
295
+
296
+ describe ContextState, "#child" do
297
+ before :each do
298
+ @first = ContextState.new ""
299
+ @second = ContextState.new ""
300
+ @parent = mock("describe")
301
+ @parent.stub!(:parent).and_return(nil)
302
+ @parent.stub!(:child)
303
+ end
304
+
305
+ it "adds the ContextState to the list of contained ContextStates" do
306
+ @first.child @second
307
+ @first.children.should == [@second]
308
+ end
309
+ end
310
+
311
+ describe ContextState, "#children" do
312
+ before :each do
313
+ @parent = ContextState.new ""
314
+ @first = ContextState.new ""
315
+ @second = ContextState.new ""
316
+ end
317
+
318
+ it "returns the list of directly contained ContextStates" do
319
+ @first.parent = @parent
320
+ @second.parent = @first
321
+ @parent.children.should == [@first]
322
+ @first.children.should == [@second]
79
323
  end
80
324
  end
81
325
 
@@ -84,7 +328,7 @@ describe ContextState, "#state" do
84
328
  MSpec.store :before, []
85
329
  MSpec.store :after, []
86
330
 
87
- @state = ContextState.new
331
+ @state = ContextState.new ""
88
332
  end
89
333
 
90
334
  it "returns nil if no spec is being executed" do
@@ -93,7 +337,7 @@ describe ContextState, "#state" do
93
337
 
94
338
  it "returns a ExampleState instance if an example is being executed" do
95
339
  ScratchPad.record @state
96
- @state.describe("") { }
340
+ @state.describe { }
97
341
  @state.it("") { ScratchPad.record ScratchPad.recorded.state }
98
342
  @state.process
99
343
  @state.state.should == nil
@@ -105,9 +349,10 @@ describe ContextState, "#process" do
105
349
  before :each do
106
350
  MSpec.store :before, []
107
351
  MSpec.store :after, []
352
+ MSpec.stub!(:register_current)
108
353
 
109
- @state = ContextState.new
110
- @state.describe("") { }
354
+ @state = ContextState.new ""
355
+ @state.describe { }
111
356
 
112
357
  @a = lambda { ScratchPad << :a }
113
358
  @b = lambda { ScratchPad << :b }
@@ -127,7 +372,7 @@ describe ContextState, "#process" do
127
372
  @state.after(:all, &@b)
128
373
  @state.it("") { }
129
374
  @state.process
130
- ScratchPad.recorded.should == [:a, :b]
375
+ ScratchPad.recorded.should == [:b, :a]
131
376
  end
132
377
 
133
378
  it "calls each it block" do
@@ -137,6 +382,14 @@ describe ContextState, "#process" do
137
382
  ScratchPad.recorded.should == [:a, :b]
138
383
  end
139
384
 
385
+ it "does not call the #it block if #filtered? returns true" do
386
+ @state.it("one", &@a)
387
+ @state.it("two", &@b)
388
+ @state.examples.first.stub!(:filtered?).and_return(true)
389
+ @state.process
390
+ ScratchPad.recorded.should == [:b]
391
+ end
392
+
140
393
  it "calls each before(:each) block" do
141
394
  @state.before(:each, &@a)
142
395
  @state.before(:each, &@b)
@@ -150,7 +403,7 @@ describe ContextState, "#process" do
150
403
  @state.after(:each, &@b)
151
404
  @state.it("") { }
152
405
  @state.process
153
- ScratchPad.recorded.should == [:a, :b]
406
+ ScratchPad.recorded.should == [:b, :a]
154
407
  end
155
408
 
156
409
  it "calls Mock.cleanup for each it block" do
@@ -169,14 +422,14 @@ describe ContextState, "#process" do
169
422
 
170
423
  it "calls the describe block" do
171
424
  ScratchPad.record []
172
- @state.describe(Object, "msg") { ScratchPad << :a }
425
+ @state.describe { ScratchPad << :a }
173
426
  @state.process
174
427
  ScratchPad.recorded.should == [:a]
175
428
  end
176
429
 
177
430
  it "creates a new ExampleState instance for each example" do
178
431
  ScratchPad.record @state
179
- @state.describe("desc") { }
432
+ @state.describe { }
180
433
  @state.it("it") { ScratchPad.record ScratchPad.recorded.state }
181
434
  @state.process
182
435
  ScratchPad.recorded.should be_kind_of(ExampleState)
@@ -197,14 +450,45 @@ describe ContextState, "#process" do
197
450
  @state.process
198
451
  MSpec.randomize false
199
452
  end
453
+
454
+ it "sets the current MSpec ContextState" do
455
+ MSpec.should_receive(:register_current).with(@state)
456
+ @state.process
457
+ end
458
+
459
+ it "resets the current MSpec ContextState to nil when there are examples" do
460
+ MSpec.should_receive(:register_current).with(nil)
461
+ @state.it("") { }
462
+ @state.process
463
+ end
464
+
465
+ it "resets the current MSpec ContextState to nil when there are no examples" do
466
+ MSpec.should_receive(:register_current).with(nil)
467
+ @state.process
468
+ end
469
+
470
+ it "call #process on children when there are examples" do
471
+ child = ContextState.new ""
472
+ child.should_receive(:process)
473
+ @state.child child
474
+ @state.it("") { }
475
+ @state.process
476
+ end
477
+
478
+ it "call #process on children when there are no examples" do
479
+ child = ContextState.new ""
480
+ child.should_receive(:process)
481
+ @state.child child
482
+ @state.process
483
+ end
200
484
  end
201
485
 
202
486
  describe ContextState, "#process" do
203
487
  before :each do
204
488
  MSpec.store :exception, []
205
489
 
206
- @state = ContextState.new
207
- @state.describe("") { }
490
+ @state = ContextState.new ""
491
+ @state.describe { }
208
492
 
209
493
  action = mock("action")
210
494
  def action.exception(exc)
@@ -243,8 +527,8 @@ describe ContextState, "#process" do
243
527
  before :each do
244
528
  MSpec.store :example, []
245
529
 
246
- @state = ContextState.new
247
- @state.describe("") { }
530
+ @state = ContextState.new ""
531
+ @state.describe { }
248
532
 
249
533
  example = mock("example")
250
534
  def example.example(state, spec)
@@ -279,8 +563,8 @@ describe ContextState, "#process" do
279
563
  MSpec.store :before, []
280
564
  MSpec.store :after, []
281
565
 
282
- @state = ContextState.new
283
- @state.describe("") { }
566
+ @state = ContextState.new ""
567
+ @state.describe { }
284
568
  @state.it("") { MSpec.expectation }
285
569
  end
286
570
 
@@ -314,16 +598,13 @@ describe ContextState, "#process" do
314
598
  end
315
599
  end
316
600
 
317
- describe ContextState, "#process" do
318
- end
319
-
320
601
  describe ContextState, "#process" do
321
602
  before :each do
322
603
  MSpec.store :enter, []
323
604
  MSpec.store :leave, []
324
605
 
325
- @state = ContextState.new
326
- @state.describe("") { }
606
+ @state = ContextState.new "C#m"
607
+ @state.describe { }
327
608
  @state.it("") { MSpec.expectation }
328
609
  end
329
610
 
@@ -334,7 +615,7 @@ describe ContextState, "#process" do
334
615
 
335
616
  it "calls registered enter actions with the current #describe string" do
336
617
  enter = mock("enter")
337
- enter.should_receive(:enter).and_return { ScratchPad.record :enter }
618
+ enter.should_receive(:enter).with("C#m").and_return { ScratchPad.record :enter }
338
619
  MSpec.register :enter, enter
339
620
  @state.process
340
621
  ScratchPad.recorded.should == :enter
@@ -354,8 +635,8 @@ describe ContextState, "#process when an exception is raised in before(:all)" do
354
635
  MSpec.store :before, []
355
636
  MSpec.store :after, []
356
637
 
357
- @state = ContextState.new
358
- @state.describe("") { }
638
+ @state = ContextState.new ""
639
+ @state.describe { }
359
640
 
360
641
  @a = lambda { ScratchPad << :a }
361
642
  @b = lambda { ScratchPad << :b }
@@ -414,8 +695,8 @@ describe ContextState, "#process when an exception is raised in before(:each)" d
414
695
  MSpec.store :before, []
415
696
  MSpec.store :after, []
416
697
 
417
- @state = ContextState.new
418
- @state.describe("") { }
698
+ @state = ContextState.new ""
699
+ @state.describe { }
419
700
 
420
701
  @a = lambda { ScratchPad << :a }
421
702
  @b = lambda { ScratchPad << :b }
@@ -463,8 +744,8 @@ describe ContextState, "#process in pretend mode" do
463
744
  MSpec.store :before, []
464
745
  MSpec.store :after, []
465
746
 
466
- @state = ContextState.new
467
- @state.describe("") { }
747
+ @state = ContextState.new ""
748
+ @state.describe { }
468
749
  @state.it("") { }
469
750
  end
470
751
 
@@ -511,8 +792,8 @@ describe ContextState, "#process in pretend mode" do
511
792
  MSpec.store :before, []
512
793
  MSpec.store :after, []
513
794
 
514
- @state = ContextState.new
515
- @state.describe("") { }
795
+ @state = ContextState.new ""
796
+ @state.describe { }
516
797
 
517
798
  @a = lambda { ScratchPad << :a }
518
799
  @b = lambda { ScratchPad << :b }
@@ -521,7 +802,7 @@ describe ContextState, "#process in pretend mode" do
521
802
 
522
803
  it "calls the describe block" do
523
804
  ScratchPad.record []
524
- @state.describe(Object, "msg") { ScratchPad << :a }
805
+ @state.describe { ScratchPad << :a }
525
806
  @state.process
526
807
  ScratchPad.recorded.should == [:a]
527
808
  end
@@ -586,8 +867,8 @@ describe ContextState, "#process in pretend mode" do
586
867
  MSpec.store :enter, []
587
868
  MSpec.store :leave, []
588
869
 
589
- @state = ContextState.new
590
- @state.describe("") { }
870
+ @state = ContextState.new ""
871
+ @state.describe { }
591
872
  @state.it("") { }
592
873
  end
593
874
 
@@ -612,3 +893,87 @@ describe ContextState, "#process in pretend mode" do
612
893
  ScratchPad.recorded.should == :leave
613
894
  end
614
895
  end
896
+
897
+ describe ContextState, "#it_should_behave_like" do
898
+ before :each do
899
+ @shared = ContextState.new("", :shared => true)
900
+ MSpec.stub!(:retrieve_shared).and_return(@shared)
901
+
902
+ @state = ContextState.new ""
903
+ @a = lambda { }
904
+ @b = lambda { }
905
+ end
906
+
907
+ it "raises an Exception if unable to find the shared ContextState" do
908
+ MSpec.should_receive(:retrieve_shared).and_return(nil)
909
+ lambda { @state.it_should_behave_like "this" }.should raise_error(Exception)
910
+ end
911
+
912
+ it "adds examples from the shared ContextState" do
913
+ @shared.it "some", &@a
914
+ @shared.it "thing", &@b
915
+ @state.it_should_behave_like ""
916
+ @state.examples.should include(*@shared.examples)
917
+ end
918
+
919
+ it "sets the containing ContextState for the examples" do
920
+ @shared.it "some", &@a
921
+ @shared.it "thing", &@b
922
+ @shared.examples.each { |ex| ex.should_receive(:context=).with(@state) }
923
+ @state.it_should_behave_like ""
924
+ end
925
+
926
+ it "adds before(:all) blocks from the shared ContextState" do
927
+ @shared.before :all, &@a
928
+ @shared.before :all, &@b
929
+ @state.it_should_behave_like ""
930
+ @state.before(:all).should include(*@shared.before(:all))
931
+ end
932
+
933
+ it "adds before(:each) blocks from the shared ContextState" do
934
+ @shared.before :each, &@a
935
+ @shared.before :each, &@b
936
+ @state.it_should_behave_like ""
937
+ @state.before(:each).should include(*@shared.before(:each))
938
+ end
939
+
940
+ it "adds after(:each) blocks from the shared ContextState" do
941
+ @shared.after :each, &@a
942
+ @shared.after :each, &@b
943
+ @state.it_should_behave_like ""
944
+ @state.after(:each).should include(*@shared.after(:each))
945
+ end
946
+
947
+ it "adds after(:all) blocks from the shared ContextState" do
948
+ @shared.after :all, &@a
949
+ @shared.after :all, &@b
950
+ @state.it_should_behave_like ""
951
+ @state.after(:all).should include(*@shared.after(:all))
952
+ end
953
+ end
954
+
955
+ describe ContextState, "#filter_examples" do
956
+ before :each do
957
+ @state = ContextState.new ""
958
+ @state.it("one") { }
959
+ @state.it("two") { }
960
+ end
961
+
962
+ it "removes examples that are filtered" do
963
+ @state.examples.first.stub!(:filtered?).and_return(true)
964
+ @state.examples.size.should == 2
965
+ @state.filter_examples
966
+ @state.examples.size.should == 1
967
+ end
968
+
969
+ it "returns true if there are remaining examples to evaluate" do
970
+ @state.examples.first.stub!(:filtered?).and_return(true)
971
+ @state.filter_examples.should be_true
972
+ end
973
+
974
+ it "returns false if there are no remaining examples to evaluate" do
975
+ @state.examples.first.stub!(:filtered?).and_return(true)
976
+ @state.examples.last.stub!(:filtered?).and_return(true)
977
+ @state.filter_examples.should be_false
978
+ end
979
+ end