mspec 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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