mspec 1.5.14 → 1.5.15

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -18,7 +18,7 @@ spec = Gem::Specification.new do |s|
18
18
 
19
19
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
20
20
  s.authors = ["Brian Ford"]
21
- s.date = %q{2010-01-05}
21
+ s.date = %q{2010-02-04}
22
22
  s.email = %q{bford@engineyard.com}
23
23
  s.has_rdoc = true
24
24
  s.extra_rdoc_files = %w[ README LICENSE ]
@@ -66,8 +66,11 @@ class MSpecCI < MSpecScript
66
66
  def run
67
67
  MSpec.register_tags_patterns config[:tags_patterns]
68
68
  MSpec.register_files @files
69
- filter = TagFilter.new(:exclude,
70
- "fails", "critical", "unstable", "incomplete", "unsupported")
69
+
70
+ tags = ["fails", "critical", "unstable", "incomplete", "unsupported"]
71
+ tags += Array(config[:ci_xtags])
72
+
73
+ filter = TagFilter.new(:exclude, *tags)
71
74
  filter.register
72
75
 
73
76
  MSpec.process
data/lib/mspec/guards.rb CHANGED
@@ -5,6 +5,7 @@ require 'mspec/guards/compliance'
5
5
  require 'mspec/guards/conflict'
6
6
  require 'mspec/guards/endian'
7
7
  require 'mspec/guards/extensions'
8
+ require 'mspec/guards/feature'
8
9
  require 'mspec/guards/guard'
9
10
  require 'mspec/guards/noncompliance'
10
11
  require 'mspec/guards/platform'
@@ -2,12 +2,17 @@ require 'mspec/guards/guard'
2
2
 
3
3
  class ConflictsGuard < SpecGuard
4
4
  def match?
5
- constants = Object.constants
6
- @args.any? { |mod| constants.include? mod.to_s }
5
+ # Always convert constants to symbols regardless of version.
6
+ constants = Object.constants.map { |x| x.to_sym }
7
+ @args.any? { |mod| constants.include? mod }
7
8
  end
8
9
  end
9
10
 
10
11
  class Object
12
+ # In some cases, libraries will modify another Ruby method's
13
+ # behavior. The specs for the method's behavior will then fail
14
+ # if that library is loaded. This guard will not run if any of
15
+ # the specified constants exist in Object.constants.
11
16
  def conflicts_with(*modules)
12
17
  g = ConflictsGuard.new(*modules)
13
18
  g.name = :conflicts_with
@@ -0,0 +1,47 @@
1
+ require 'mspec/guards/guard'
2
+
3
+ class FeatureGuard < SpecGuard
4
+ def self.enabled?(*features)
5
+ new(*features).match?
6
+ end
7
+
8
+ def match?
9
+ @parameters.all? { |f| MSpec.feature_enabled? f }
10
+ end
11
+ end
12
+
13
+ class Object
14
+ # Provides better documentation in the specs by
15
+ # naming sets of features that work together as
16
+ # a whole. Examples include :encoding, :fiber,
17
+ # :continuation, :fork.
18
+ #
19
+ # Usage example:
20
+ #
21
+ # with_feature :encoding do
22
+ # # specs for a method that provides aspects
23
+ # # of the encoding feature
24
+ # end
25
+ #
26
+ # Multiple features must all be enabled for the
27
+ # guard to run:
28
+ #
29
+ # with_feature :one, :two do
30
+ # # these specs will run if features :one AND
31
+ # # :two are enabled.
32
+ # end
33
+ #
34
+ # The implementation must explicitly enable a feature
35
+ # by adding code like the following to the .mspec
36
+ # configuration file:
37
+ #
38
+ # MSpec.enable_feature :encoding
39
+ #
40
+ def with_feature(*features)
41
+ g = FeatureGuard.new(*features)
42
+ g.name = :with_feature
43
+ yield if g.yield?
44
+ ensure
45
+ g.unregister
46
+ end
47
+ end
@@ -1,6 +1,8 @@
1
1
  require 'mspec/runner/mspec'
2
2
  require 'mspec/runner/actions/tally'
3
3
 
4
+ require 'rbconfig'
5
+
4
6
  class SpecGuard
5
7
  def self.report
6
8
  @report ||= Hash.new { |h,k| h[k] = [] }
@@ -56,10 +58,6 @@ class SpecGuard
56
58
  version.split('.')[0,n].join('.')
57
59
  end
58
60
 
59
- def self.windows?(key = RUBY_PLATFORM)
60
- !!key.match(/(mswin|mingw)/)
61
- end
62
-
63
61
  attr_accessor :name, :parameters
64
62
 
65
63
  def initialize(*args)
@@ -136,7 +134,7 @@ class SpecGuard
136
134
  end
137
135
 
138
136
  def windows?(sym, key)
139
- sym == :windows && SpecGuard.windows?(key)
137
+ sym == :windows && !key.match(/(mswin|mingw)/).nil?
140
138
  end
141
139
 
142
140
  def platform?(*args)
@@ -154,7 +152,6 @@ class SpecGuard
154
152
  end
155
153
 
156
154
  def os?(*oses)
157
- require 'rbconfig'
158
155
  oses.any? do |os|
159
156
  host_os = Config::CONFIG['host_os'] || RUBY_PLATFORM
160
157
  host_os.downcase!
@@ -1,6 +1,10 @@
1
1
  require 'mspec/guards/guard'
2
2
 
3
3
  class PlatformGuard < SpecGuard
4
+ def self.windows?
5
+ PlatformGuard.new(:os => :windows).match?
6
+ end
7
+
4
8
  def initialize(*args)
5
9
  if args.last.is_a?(Hash)
6
10
  @options, @platforms = args.last, args[0..-2]
data/lib/mspec/helpers.rb CHANGED
@@ -2,6 +2,7 @@ require 'mspec/helpers/argv'
2
2
  require 'mspec/helpers/bignum'
3
3
  require 'mspec/helpers/const_lookup'
4
4
  require 'mspec/helpers/ducktype'
5
+ require 'mspec/helpers/encode'
5
6
  require 'mspec/helpers/enumerator_class'
6
7
  require 'mspec/helpers/environment'
7
8
  require 'mspec/helpers/fixture'
@@ -0,0 +1,21 @@
1
+ require 'mspec/guards/feature'
2
+
3
+ class Object
4
+ # Helper to handle String encodings. The +str+ and +encoding+ parameters
5
+ # must be Strings and an ArgumentError will be raised if not. This ensures
6
+ # that the encode() helper can be used regardless of whether Encoding exits.
7
+ # The helper is a no-op (i.e. passes through +str+ unmodified) if the
8
+ # :encoding feature is not enabled (see with_feature guard). If the
9
+ # :encoding feature is enabled, +str+.force_encoding(+encoding+) is called.
10
+ def encode(str, encoding)
11
+ unless str.is_a? String and encoding.is_a? String
12
+ raise ArgumentError, "encoding name must be a String"
13
+ end
14
+
15
+ if FeatureGuard.enabled? :encoding
16
+ str.force_encoding encoding
17
+ end
18
+
19
+ str
20
+ end
21
+ end
@@ -3,7 +3,7 @@ require 'mspec/guards/guard'
3
3
  class Object
4
4
  def env
5
5
  env = ""
6
- if SpecGuard.windows?
6
+ if PlatformGuard.windows?
7
7
  env = Hash[*`cmd.exe /C set`.split("\n").map { |e| e.split("=", 2) }.flatten]
8
8
  else
9
9
  env = Hash[*`env`.split("\n").map { |e| e.split("=", 2) }.flatten]
@@ -17,7 +17,7 @@ class Object
17
17
 
18
18
  def username
19
19
  user = ""
20
- if SpecGuard.windows?
20
+ if PlatformGuard.windows?
21
21
  user = windows_env_echo('USERNAME')
22
22
  else
23
23
  user = `whoami`.strip
@@ -26,7 +26,7 @@ class Object
26
26
  end
27
27
 
28
28
  def home_directory
29
- return ENV['HOME'] unless SpecGuard.windows?
29
+ return ENV['HOME'] unless PlatformGuard.windows?
30
30
  windows_env_echo('HOMEDRIVE') + windows_env_echo('HOMEPATH')
31
31
  end
32
32
  end
@@ -1,5 +1,5 @@
1
1
  require 'mspec/utils/ruby_name'
2
- require 'mspec/guards/guard'
2
+ require 'mspec/guards/platform'
3
3
 
4
4
  # The ruby_exe helper provides a wrapper for invoking the
5
5
  # same Ruby interpreter as the one running the specs and
@@ -99,7 +99,7 @@ class Object
99
99
  # It has been reported that File.executable is not reliable
100
100
  # on Windows platforms (see commit 56bc555c). So, we check the
101
101
  # platform.
102
- if File.exists?(exe) and (SpecGuard.windows? or File.executable?(exe))
102
+ if File.exists?(exe) and (PlatformGuard.windows? or File.executable?(exe))
103
103
  return cmd
104
104
  end
105
105
  end
@@ -1,19 +1,17 @@
1
+ require 'mspec/helpers/encode'
2
+
1
3
  class EqualUtf16Matcher
2
4
  def initialize(expected)
3
- @expected = expected
5
+ @expected = Array(expected).map { |x| encode x, "binary" }
4
6
  end
5
7
 
6
8
  def matches?(actual)
7
- @actual = actual
9
+ @actual = Array(actual).map { |x| encode x, "binary" }
8
10
  @actual == @expected || @actual == expected_swapped
9
11
  end
10
12
 
11
13
  def expected_swapped
12
- if @expected.respond_to?(:to_str)
13
- @expected_swapped ||= @expected.to_str.gsub(/(.)(.)/, '\2\1')
14
- else
15
- @expected_swapped ||= @expected.collect { |s| s.to_str.gsub(/(.)(.)/, '\2\1') }
16
- end
14
+ @expected_swapped ||= @expected.map { |x| x.to_str.gsub(/(.)(.)/, '\2\1') }
17
15
  end
18
16
 
19
17
  def failure_message
@@ -38,6 +38,11 @@ module Mock
38
38
  has_key?(mocks.keys, sym) or has_key?(stubs.keys, sym)
39
39
  end
40
40
 
41
+ def self.clear_replaced(key)
42
+ mocks.delete key
43
+ stubs.delete key
44
+ end
45
+
41
46
  def self.mock_respond_to?(obj, sym)
42
47
  name = replaced_name(obj, :respond_to?)
43
48
  if replaced? name
@@ -176,7 +181,10 @@ module Mock
176
181
  else
177
182
  meta.__send__ :remove_method, sym
178
183
  end
184
+
185
+ clear_replaced key
179
186
  end
187
+ ensure
180
188
  reset
181
189
  end
182
190
  end
@@ -37,6 +37,12 @@ class ContextState
37
37
  @expectation_missing = Proc.new { raise SpecExpectationNotFoundError }
38
38
  end
39
39
 
40
+ # Remove caching when a ContextState is dup'd for shared specs.
41
+ def initialize_copy(other)
42
+ @pre = {}
43
+ @post = {}
44
+ end
45
+
40
46
  # Returns true if this is a shared +ContextState+. Essentially, when
41
47
  # created with: describe "Something", :shared => true { ... }
42
48
  def shared?
@@ -47,28 +53,51 @@ class ContextState
47
53
  # the +parents+ list.
48
54
  def parent=(parent)
49
55
  @description = nil
50
- @parent = parent
51
- parent.child self if parent and not shared?
52
56
 
53
- state = parent
54
- while state
55
- parents.unshift state
56
- state = state.parent
57
+ if shared?
58
+ @parent = nil
59
+ else
60
+ @parent = parent
61
+ parent.child self if parent
62
+
63
+ @parents = [self]
64
+ state = parent
65
+ while state
66
+ @parents.unshift state
67
+ state = state.parent
68
+ end
57
69
  end
58
70
  end
59
71
 
60
- def replace_parent(parent)
61
- @parents[0] = parent
62
-
63
- children.each { |child| child.replace_parent parent }
64
- end
65
-
66
72
  # Add the ContextState instance +child+ to the list of nested
67
73
  # describe blocks.
68
74
  def child(child)
69
75
  @children << child
70
76
  end
71
77
 
78
+ # Adds a nested ContextState in a shared ContextState to a containing
79
+ # ContextState.
80
+ #
81
+ # Normal adoption is from the parent's perspective. But adopt is a good
82
+ # verb and it's reasonable for the child to adopt the parent as well. In
83
+ # this case, manipulating state from inside the child avoids needlessly
84
+ # exposing the state to manipulate it externally in the dup. (See
85
+ # #it_should_behave_like)
86
+ def adopt(parent)
87
+ self.parent = parent
88
+
89
+ @examples = @examples.map do |example|
90
+ example = example.dup
91
+ example.context = self
92
+ example
93
+ end
94
+
95
+ children = @children
96
+ @children = []
97
+
98
+ children.each { |child| child.dup.adopt self }
99
+ end
100
+
72
101
  # Returns a list of all before(+what+) blocks from self and any parents.
73
102
  def pre(what)
74
103
  @pre[what] ||= parents.inject([]) { |l, s| l.push(*s.before(what)) }
@@ -113,7 +142,7 @@ class ContextState
113
142
 
114
143
  # Returns a description string generated from self and all parents
115
144
  def description
116
- @description ||= parents.map { |p| p.to_s }.join(" ")
145
+ @description ||= parents.map { |p| p.to_s }.compact.join(" ")
117
146
  end
118
147
 
119
148
  # Injects the before/after blocks and examples from the shared
@@ -125,18 +154,19 @@ class ContextState
125
154
  raise Exception, "Unable to find shared 'describe' for #{desc}"
126
155
  end
127
156
 
128
- state.examples.each { |ex| ex.context = self; @examples << ex }
129
157
  state.before(:all).each { |b| before :all, &b }
130
158
  state.before(:each).each { |b| before :each, &b }
131
159
  state.after(:each).each { |b| after :each, &b }
132
160
  state.after(:all).each { |b| after :all, &b }
133
161
 
134
- # There is a potential race here if mspec ever implements concurrency
135
- # in process. Right now, the only way to run specs concurrently is
136
- # with multiple processes, so we ignore this for the sake of simplicity.
162
+ state.examples.each do |example|
163
+ example = example.dup
164
+ example.context = self
165
+ @examples << example
166
+ end
167
+
137
168
  state.children.each do |child|
138
- child.replace_parent self
139
- @children << child
169
+ child.dup.adopt self
140
170
  end
141
171
  end
142
172
 
@@ -21,6 +21,7 @@ module MSpec
21
21
  @modes = []
22
22
  @shared = {}
23
23
  @guarded = []
24
+ @features = {}
24
25
  @exception = nil
25
26
  @randomize = nil
26
27
  @expectation = nil
@@ -162,6 +163,18 @@ module MSpec
162
163
  retrieve(:modes).include? mode
163
164
  end
164
165
 
166
+ def self.enable_feature(feature)
167
+ retrieve(:features)[feature] = true
168
+ end
169
+
170
+ def self.disable_feature(feature)
171
+ retrieve(:features)[feature] = false
172
+ end
173
+
174
+ def self.feature_enabled?(feature)
175
+ retrieve(:features)[feature] || false
176
+ end
177
+
165
178
  def self.retrieve(symbol)
166
179
  instance_variable_get :"@#{symbol}"
167
180
  end
data/lib/mspec/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'mspec/utils/version'
2
2
 
3
3
  module MSpec
4
- VERSION = SpecVersion.new "1.5.14"
4
+ VERSION = SpecVersion.new "1.5.15"
5
5
  end
@@ -107,6 +107,8 @@ describe MSpecCI, "#run" do
107
107
  TagFilter.stub!(:new).and_return(@filter)
108
108
  @filter.stub!(:register)
109
109
 
110
+ @tags = ["fails", "critical", "unstable", "incomplete", "unsupported"]
111
+
110
112
  @config = { :ci_files => ["one", "two"] }
111
113
  @script = MSpecCI.new
112
114
  @script.stub!(:exit)
@@ -127,9 +129,25 @@ describe MSpecCI, "#run" do
127
129
  end
128
130
 
129
131
  it "registers a tag filter for 'fails', 'unstable', 'incomplete', 'critical', 'unsupported'" do
132
+ filter = mock("fails filter")
133
+ TagFilter.should_receive(:new).with(:exclude, *@tags).and_return(filter)
134
+ filter.should_receive(:register)
135
+ @script.run
136
+ end
137
+
138
+ it "registers an additional exclude tag specified by :ci_xtags" do
139
+ @config[:ci_xtags] = "windows"
140
+ filter = mock("fails filter")
141
+ TagFilter.should_receive(:new).with(:exclude, *(@tags + ["windows"])).and_return(filter)
142
+ filter.should_receive(:register)
143
+ @script.run
144
+ end
145
+
146
+ it "registers additional exclude tags specified by a :ci_xtags array" do
147
+ @config[:ci_xtags] = ["windows", "windoze"]
130
148
  filter = mock("fails filter")
131
149
  TagFilter.should_receive(:new).with(:exclude,
132
- "fails", "critical", "unstable", "incomplete", "unsupported").and_return(filter)
150
+ *(@tags + ["windows", "windoze"])).and_return(filter)
133
151
  filter.should_receive(:register)
134
152
  @script.run
135
153
  end
@@ -12,11 +12,23 @@ describe Object, "#conflicts_with" do
12
12
  ScratchPad.recorded.should_not == :yield
13
13
  end
14
14
 
15
+ it "does not yield if Object.constants (as Symbols) includes any of the arguments" do
16
+ Object.stub!(:constants).and_return([:SomeClass, :OtherClass])
17
+ conflicts_with(:SomeClass, :AClass, :BClass) { ScratchPad.record :yield }
18
+ ScratchPad.recorded.should_not == :yield
19
+ end
20
+
15
21
  it "yields if Object.constants does not include any of the arguments" do
16
22
  Object.stub!(:constants).and_return(["SomeClass", "OtherClass"])
17
23
  conflicts_with(:AClass, :BClass) { ScratchPad.record :yield }
18
24
  ScratchPad.recorded.should == :yield
19
25
  end
26
+
27
+ it "yields if Object.constants (as Symbols) does not include any of the arguments" do
28
+ Object.stub!(:constants).and_return([:SomeClass, :OtherClass])
29
+ conflicts_with(:AClass, :BClass) { ScratchPad.record :yield }
30
+ ScratchPad.recorded.should == :yield
31
+ end
20
32
  end
21
33
 
22
34
  describe Object, "#conflicts_with" do
@@ -0,0 +1,80 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'mspec/guards/feature'
3
+
4
+ describe FeatureGuard, ".enabled?" do
5
+ it "returns true if the feature is enabled" do
6
+ MSpec.should_receive(:feature_enabled?).with(:encoding).and_return(true)
7
+ FeatureGuard.enabled?(:encoding).should be_true
8
+ end
9
+
10
+ it "returns false if the feature is not enabled" do
11
+ MSpec.should_receive(:feature_enabled?).with(:encoding).and_return(false)
12
+ FeatureGuard.enabled?(:encoding).should be_false
13
+ end
14
+
15
+ it "returns true if all the features are enabled" do
16
+ MSpec.should_receive(:feature_enabled?).with(:one).and_return(true)
17
+ MSpec.should_receive(:feature_enabled?).with(:two).and_return(true)
18
+ FeatureGuard.enabled?(:one, :two).should be_true
19
+ end
20
+
21
+ it "returns false if any of the features are not enabled" do
22
+ MSpec.should_receive(:feature_enabled?).with(:one).and_return(true)
23
+ MSpec.should_receive(:feature_enabled?).with(:two).and_return(false)
24
+ FeatureGuard.enabled?(:one, :two).should be_false
25
+ end
26
+ end
27
+
28
+ describe Object, "#with_feature" do
29
+ before :each do
30
+ ScratchPad.clear
31
+
32
+ @guard = FeatureGuard.new :encoding
33
+ FeatureGuard.stub!(:new).and_return(@guard)
34
+ end
35
+
36
+ it "sets the name of the guard to :with_feature" do
37
+ with_feature(:encoding) { }
38
+ @guard.name.should == :with_feature
39
+ end
40
+
41
+ it "calls #unregister even when an exception is raised in the guard block" do
42
+ @guard.should_receive(:match?).and_return(true)
43
+ @guard.should_receive(:unregister)
44
+ lambda do
45
+ with_feature { raise Exception }
46
+ end.should raise_error(Exception)
47
+ end
48
+ end
49
+
50
+ describe Object, "#with_feature" do
51
+ before :each do
52
+ ScratchPad.clear
53
+ end
54
+
55
+ it "yields if the feature is enabled" do
56
+ MSpec.should_receive(:feature_enabled?).with(:encoding).and_return(true)
57
+ with_feature(:encoding) { ScratchPad.record :yield }
58
+ ScratchPad.recorded.should == :yield
59
+ end
60
+
61
+ it "yields if all the features are enabled" do
62
+ MSpec.should_receive(:feature_enabled?).with(:one).and_return(true)
63
+ MSpec.should_receive(:feature_enabled?).with(:two).and_return(true)
64
+ with_feature(:one, :two) { ScratchPad.record :yield }
65
+ ScratchPad.recorded.should == :yield
66
+ end
67
+
68
+ it "does not yield if the feature is not enabled" do
69
+ MSpec.should_receive(:feature_enabled?).with(:encoding).and_return(false)
70
+ with_feature(:encoding) { ScratchPad.record :yield }
71
+ ScratchPad.recorded.should be_nil
72
+ end
73
+
74
+ it "does not yield if any of the features are not enabled" do
75
+ MSpec.should_receive(:feature_enabled?).with(:one).and_return(true)
76
+ MSpec.should_receive(:feature_enabled?).with(:two).and_return(false)
77
+ with_feature(:one, :two) { ScratchPad.record :yield }
78
+ ScratchPad.recorded.should be_nil
79
+ end
80
+ end
@@ -47,33 +47,6 @@ describe SpecGuard, ".ruby_version" do
47
47
  end
48
48
  end
49
49
 
50
- describe SpecGuard, ".windows?" do
51
- before :all do
52
- @ruby_platform = Object.const_get :RUBY_PLATFORM
53
- end
54
-
55
- after :all do
56
- Object.const_set :RUBY_PLATFORM, @ruby_platform
57
- end
58
-
59
- it "returns true if key is mswin32" do
60
- SpecGuard.windows?("mswin32").should be_true
61
- end
62
-
63
- it "returns true if key is mingw" do
64
- SpecGuard.windows?("mingw").should be_true
65
- end
66
-
67
- it "returns false for non-windows" do
68
- SpecGuard.windows?("notwindows").should be_false
69
- end
70
-
71
- it "uses RUBY_PLATFORM by default" do
72
- Object.const_set :RUBY_PLATFORM, "mswin32"
73
- SpecGuard.windows?.should be_true
74
- end
75
- end
76
-
77
50
  describe SpecGuard, "#yield?" do
78
51
  before :each do
79
52
  MSpec.clear_modes
@@ -367,7 +340,7 @@ describe SpecGuard, "#os?" do
367
340
  end
368
341
  end
369
342
 
370
- describe SpecGuard, "windows?" do
343
+ describe SpecGuard, "#windows?" do
371
344
  before :each do
372
345
  @guard = SpecGuard.new
373
346
  end
@@ -0,0 +1,26 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'mspec/helpers/encode'
3
+
4
+ describe Object, "#encode" do
5
+ it "raises an ArgumentError if the str parameter is not a String" do
6
+ lambda { encode(Object.new, "utf-8") }.should raise_error(ArgumentError)
7
+ end
8
+
9
+ it "raises an ArgumentError if the encoding parameter is not a String" do
10
+ lambda { encode("some str", Object.new) }.should raise_error(ArgumentError)
11
+ end
12
+
13
+ it "calls #force_encoding if the :encoding feature is enabled" do
14
+ FeatureGuard.should_receive(:enabled?).with(:encoding).and_return(true)
15
+ str = "some text"
16
+ str.should_receive(:force_encoding).with("utf-8")
17
+ encode(str, "utf-8")
18
+ end
19
+
20
+ it "does not call #force_encoding if the :encoding feature is not enabled" do
21
+ FeatureGuard.should_receive(:enabled?).with(:encoding).and_return(false)
22
+ str = "some text"
23
+ str.should_not_receive(:force_encoding)
24
+ encode(str, "utf-8")
25
+ end
26
+ end
@@ -1,43 +1,30 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'mspec/guards/platform'
2
3
  require 'mspec/helpers/environment'
3
4
 
4
5
  describe "#env" do
5
- before(:all) do
6
- @ruby_platform = Object.const_get :RUBY_PLATFORM
7
- end
8
-
9
- after(:all) do
10
- Object.const_set :RUBY_PLATFORM, @ruby_platform
11
- end
12
-
13
6
  it "returns a hash of variables" do
14
7
  env.class.should == Hash
15
8
  end
16
-
9
+
17
10
  it "calls `env` on non-Windows" do
18
- Object.const_set :RUBY_PLATFORM, "notwindows"
11
+ PlatformGuard.stub!(:windows?).and_return(false)
19
12
  should_receive(:`).with("env").and_return("one=two\nthree=four")
20
13
  env
21
14
  end
22
15
 
23
- it "calls `cmd.exe /C set` on Windows (mswin32)" do
24
- Object.const_set :RUBY_PLATFORM, "mswin32"
25
- should_receive(:`).with("cmd.exe /C set").and_return("one=two\nthree=four")
26
- env
27
- end
28
-
29
- it "calls `cmd.exe /C set` on Windows (mingw)" do
30
- Object.const_set :RUBY_PLATFORM, "mingw"
16
+ it "calls `cmd.exe /C set` on Windows" do
17
+ PlatformGuard.stub!(:windows?).and_return(true)
31
18
  should_receive(:`).with("cmd.exe /C set").and_return("one=two\nthree=four")
32
19
  env
33
20
  end
34
21
 
35
22
  it "returns the current user's environment variables" do
36
- Object.const_set :RUBY_PLATFORM, "notwindows"
23
+ PlatformGuard.stub!(:windows?).and_return(false)
37
24
  should_receive(:`).with("env").and_return("one=two\nthree=four")
38
25
  env.should == {"one" => "two", "three" => "four"}
39
26
 
40
- Object.const_set :RUBY_PLATFORM, "mswin32"
27
+ PlatformGuard.stub!(:windows?).and_return(true)
41
28
  should_receive(:`).with("cmd.exe /C set").and_return("five=six\nseven=eight")
42
29
  env.should == {"five" => "six", "seven" => "eight"}
43
30
  end
@@ -52,30 +39,24 @@ describe "#username" do
52
39
  Object.const_set :RUBY_PLATFORM, @ruby_platform
53
40
  end
54
41
 
55
- it "calls `cmd.exe /C ECHO %USERNAME%` on Windows (mswin32)" do
56
- Object.const_set :RUBY_PLATFORM, "mswin32"
57
- should_receive(:`).with("cmd.exe /C ECHO %USERNAME%").and_return("john")
58
- username
59
- end
60
-
61
- it "calls `cmd.exe /C ECHO %USERNAME%` on Windows (mingw)" do
62
- Object.const_set :RUBY_PLATFORM, "mingw"
42
+ it "calls `cmd.exe /C ECHO %USERNAME%` on Windows" do
43
+ PlatformGuard.stub!(:windows?).and_return(true)
63
44
  should_receive(:`).with("cmd.exe /C ECHO %USERNAME%").and_return("john")
64
45
  username
65
46
  end
66
47
 
67
48
  it "calls `env` on non-Windows" do
68
- Object.const_set :RUBY_PLATFORM, "notwindows"
49
+ PlatformGuard.stub!(:windows?).and_return(false)
69
50
  should_receive(:`).with("whoami").and_return("john")
70
51
  username
71
52
  end
72
53
 
73
54
  it "returns the user's username" do
74
- Object.const_set :RUBY_PLATFORM, "mswin32"
55
+ PlatformGuard.stub!(:windows?).and_return(true)
75
56
  should_receive(:`).with("cmd.exe /C ECHO %USERNAME%").and_return("johnonwin")
76
57
  username.should == "johnonwin"
77
58
 
78
- Object.const_set :RUBY_PLATFORM, "notwindows"
59
+ PlatformGuard.stub!(:windows?).and_return(false)
79
60
  should_receive(:`).with("whoami").and_return("john")
80
61
  username.should == "john"
81
62
  end
@@ -73,21 +73,15 @@ describe "#resolve_ruby_exe" do
73
73
  end
74
74
 
75
75
  before :each do
76
- @ruby_platform = Object.const_get :RUBY_PLATFORM
77
-
78
76
  @script = RubyExeSpecs.new
79
77
  end
80
78
 
81
- after :each do
82
- Object.const_set :RUBY_PLATFORM, @ruby_platform
83
- end
84
-
85
79
  after :all do
86
80
  $VERBOSE = @verbose
87
81
  end
88
82
 
89
83
  it "returns the value returned by #ruby_exe_options if it exists and is executable" do
90
- Object.const_set :RUBY_PLATFORM, "notwindows"
84
+ PlatformGuard.stub!(:windows?).and_return(false)
91
85
  @script.should_receive(:ruby_exe_options).and_return(@name)
92
86
  File.should_receive(:exists?).with(@name).and_return(true)
93
87
  File.should_receive(:executable?).with(@name).and_return(true)
@@ -95,7 +89,7 @@ describe "#resolve_ruby_exe" do
95
89
  end
96
90
 
97
91
  it "returns the value returned by #ruby_exe_options if it exists on Windows platforms" do
98
- Object.const_set :RUBY_PLATFORM, "mswin"
92
+ PlatformGuard.stub!(:windows?).and_return(true)
99
93
  @script.should_receive(:ruby_exe_options).and_return(@name)
100
94
  File.should_receive(:exists?).with(@name).and_return(true)
101
95
  File.should_not_receive(:executable?)
@@ -43,15 +43,15 @@ describe EqualUtf16Matcher do
43
43
  matcher = EqualUtf16Matcher.new("a\0b\0")
44
44
  matcher.matches?("a\0b\0c\0")
45
45
  matcher.failure_message.should == [
46
- "Expected \"a#{@null}b#{@null}c#{@null}\"\n",
47
- "to equal \"a#{@null}b#{@null}\"\n or \"#{@null}a#{@null}b\"\n"]
46
+ "Expected [\"a#{@null}b#{@null}c#{@null}\"]\n",
47
+ "to equal [\"a#{@null}b#{@null}\"]\n or [\"#{@null}a#{@null}b\"]\n"]
48
48
  end
49
49
 
50
50
  it "provides a useful negative failure message" do
51
51
  matcher = EqualUtf16Matcher.new("a\0b\0")
52
52
  matcher.matches?("\0a\0b")
53
53
  matcher.negative_failure_message.should == [
54
- "Expected \"#{@null}a#{@null}b\"\n",
55
- "not to equal \"a#{@null}b#{@null}\"\n nor \"#{@null}a#{@null}b\"\n"]
54
+ "Expected [\"#{@null}a#{@null}b\"]\n",
55
+ "not to equal [\"a#{@null}b#{@null}\"]\n nor [\"#{@null}a#{@null}b\"]\n"]
56
56
  end
57
57
  end
@@ -446,4 +446,15 @@ describe Mock, ".cleanup" do
446
446
  Mock.cleanup
447
447
  Mock.stubs.should == {}
448
448
  end
449
+
450
+ it "removes the replaced name for mocks" do
451
+ replaced_key = Mock.replaced_key(@mock, :method_call)
452
+ Mock.should_receive(:clear_replaced).with(replaced_key)
453
+
454
+ replaced_name = Mock.replaced_name(@mock, :method_call)
455
+ Mock.replaced?(replaced_name).should be_true
456
+
457
+ Mock.cleanup
458
+ Mock.replaced?(replaced_name).should be_false
459
+ end
449
460
  end
@@ -262,6 +262,12 @@ describe ContextState, "#parent=" do
262
262
  state.parent = @parent
263
263
  end
264
264
 
265
+ it "does not set parents if shared" do
266
+ state = ContextState.new "", :shared => true
267
+ state.parent = @parent
268
+ state.parents.should == [state]
269
+ end
270
+
265
271
  it "sets self as a child of parent" do
266
272
  @parent.should_receive(:child).with(@state)
267
273
  @state.parent = @parent
@@ -910,11 +916,11 @@ end
910
916
 
911
917
  describe ContextState, "#it_should_behave_like" do
912
918
  before :each do
913
- @shared_desc = "shared context"
919
+ @shared_desc = :shared_context
914
920
  @shared = ContextState.new(@shared_desc, :shared => true)
915
921
  MSpec.stub!(:retrieve_shared).and_return(@shared)
916
922
 
917
- @state = ContextState.new ""
923
+ @state = ContextState.new "Top level"
918
924
  @a = lambda { }
919
925
  @b = lambda { }
920
926
  end
@@ -926,36 +932,57 @@ describe ContextState, "#it_should_behave_like" do
926
932
 
927
933
  describe "for nested ContextState instances" do
928
934
  before :each do
929
- @nested = ContextState.new ""
935
+ @nested = ContextState.new "nested context"
930
936
  @nested.parents.unshift @shared
937
+
931
938
  @shared.children << @nested
939
+
940
+ @nested_dup = @nested.dup
941
+ @nested.stub!(:dup).and_return(@nested_dup)
932
942
  end
933
943
 
934
- it "adds nested describe blocks to the invoking ContextState" do
944
+ it "duplicates the nested ContextState" do
935
945
  @state.it_should_behave_like @shared_desc
936
- @shared.children.should_not be_empty
937
- @state.children.should include(*@shared.children)
946
+ @state.children.first.should equal(@nested_dup)
938
947
  end
939
948
 
940
- it "changes the parent ContextState" do
941
- @shared.children.first.parents.first.should equal(@shared)
949
+ it "sets the parent of the nested ContextState to the containing ContextState" do
942
950
  @state.it_should_behave_like @shared_desc
943
- @shared.children.first.parents.first.should equal(@state)
951
+ @nested_dup.parent.should equal(@state)
952
+ end
953
+
954
+ it "sets the context for nested examples to the nested ContextState's dup" do
955
+ @shared.it "an example", &@a
956
+ @shared.it "another example", &@b
957
+ @state.it_should_behave_like @shared_desc
958
+ @nested_dup.examples.each { |x| x.context.should equal(@nested_dup) }
959
+ end
960
+
961
+ it "omits the shored ContextState's description" do
962
+ @nested.it "an example", &@a
963
+ @nested.it "another example", &@b
964
+ @state.it_should_behave_like @shared_desc
965
+
966
+ @nested_dup.description.should == "Top level nested context"
967
+ @nested_dup.examples.first.description.should == "Top level nested context an example"
968
+ @nested_dup.examples.last.description.should == "Top level nested context another example"
944
969
  end
945
970
  end
946
971
 
947
- it "adds examples from the shared ContextState" do
948
- @shared.it "some", &@a
949
- @shared.it "thing", &@b
972
+ it "adds duped examples from the shared ContextState" do
973
+ @shared.it "some method", &@a
974
+ ex_dup = @shared.examples.first.dup
975
+ @shared.examples.first.stub!(:dup).and_return(ex_dup)
976
+
950
977
  @state.it_should_behave_like @shared_desc
951
- @state.examples.should include(*@shared.examples)
978
+ @state.examples.should == [ex_dup]
952
979
  end
953
980
 
954
- it "sets the containing ContextState for the examples" do
955
- @shared.it "some", &@a
956
- @shared.it "thing", &@b
957
- @shared.examples.each { |ex| ex.should_receive(:context=).with(@state) }
981
+ it "sets the context for examples to the containing ContextState" do
982
+ @shared.it "an example", &@a
983
+ @shared.it "another example", &@b
958
984
  @state.it_should_behave_like @shared_desc
985
+ @state.examples.each { |x| x.context.should equal(@state) }
959
986
  end
960
987
 
961
988
  it "adds before(:all) blocks from the shared ContextState" do
@@ -71,6 +71,11 @@ describe ExampleState, "#filtered?" do
71
71
  @filter = mock("filter")
72
72
  end
73
73
 
74
+ after :each do
75
+ MSpec.store :include, nil
76
+ MSpec.store :exclude, nil
77
+ end
78
+
74
79
  it "returns false if MSpec include filters list is empty" do
75
80
  @state.filtered?.should == false
76
81
  end
@@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../../spec_helper'
2
2
  require 'mspec/runner/formatters/dotted'
3
3
  require 'mspec/runner/mspec'
4
4
  require 'mspec/runner/example'
5
+ require 'mspec/utils/script'
5
6
 
6
7
  describe DottedFormatter, "#initialize" do
7
8
  it "permits zero arguments" do
@@ -16,10 +17,10 @@ end
16
17
  describe DottedFormatter, "#register" do
17
18
  before :each do
18
19
  @formatter = DottedFormatter.new
20
+ MSpec.stub!(:register)
19
21
  end
20
22
 
21
23
  it "registers self with MSpec for appropriate actions" do
22
- MSpec.stub!(:register)
23
24
  MSpec.should_receive(:register).with(:exception, @formatter)
24
25
  MSpec.should_receive(:register).with(:before, @formatter)
25
26
  MSpec.should_receive(:register).with(:after, @formatter)
@@ -6,17 +6,17 @@ require 'mspec/runner/example'
6
6
  describe FileFormatter, "#register" do
7
7
  before :each do
8
8
  @formatter = FileFormatter.new
9
+ MSpec.stub!(:register)
10
+ MSpec.stub!(:unregister)
9
11
  end
10
12
 
11
13
  it "registers self with MSpec for :load, :unload actions" do
12
- MSpec.stub!(:register)
13
14
  MSpec.should_receive(:register).with(:load, @formatter)
14
15
  MSpec.should_receive(:register).with(:unload, @formatter)
15
16
  @formatter.register
16
17
  end
17
18
 
18
19
  it "unregisters self with MSpec for :before, :after actions" do
19
- MSpec.stub!(:unregister)
20
20
  MSpec.should_receive(:unregister).with(:before, @formatter)
21
21
  MSpec.should_receive(:unregister).with(:after, @formatter)
22
22
  @formatter.register
@@ -4,6 +4,7 @@ require 'mspec/guards/guard'
4
4
  require 'mspec/runner/formatters/html'
5
5
  require 'mspec/runner/mspec'
6
6
  require 'mspec/runner/example'
7
+ require 'mspec/utils/script'
7
8
 
8
9
  describe HtmlFormatter do
9
10
  before :each do
@@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../../spec_helper'
2
2
  require 'mspec/runner/formatters/method'
3
3
  require 'mspec/runner/mspec'
4
4
  require 'mspec/runner/example'
5
+ require 'mspec/utils/script'
5
6
 
6
7
  describe MethodFormatter, "#method_type" do
7
8
  before :each do
@@ -16,10 +16,10 @@ end
16
16
  describe SpinnerFormatter, "#register" do
17
17
  before :each do
18
18
  @formatter = SpinnerFormatter.new
19
+ MSpec.stub!(:register)
19
20
  end
20
21
 
21
22
  it "registers self with MSpec for appropriate actions" do
22
- MSpec.stub!(:register)
23
23
  MSpec.should_receive(:register).with(:start, @formatter)
24
24
  MSpec.should_receive(:register).with(:load, @formatter)
25
25
  MSpec.should_receive(:register).with(:after, @formatter)
@@ -1,6 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/../../spec_helper'
2
2
  require 'mspec/runner/formatters/unit'
3
3
  require 'mspec/runner/example'
4
+ require 'mspec/utils/script'
4
5
 
5
6
  describe UnitdiffFormatter, "#finish" do
6
7
  before :each do
@@ -1,27 +1,78 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
2
  require 'mspec/runner/shared'
3
+ require 'mspec/runner/context'
4
+ require 'mspec/runner/example'
3
5
 
4
6
  describe Object, "#it_behaves_like" do
5
7
  before :each do
6
- @recv = Object.new
7
- def @recv.before(what)
8
- yield
9
- end
10
- @recv.stub!(:it_should_behave_like)
8
+ ScratchPad.clear
9
+
10
+ @state = ContextState.new "Top level"
11
+ @state.instance_variable_set :@parsed, true
12
+
13
+ @shared = ContextState.new :shared_spec, :shared => true
14
+ MSpec.stub!(:retrieve_shared).and_return(@shared)
11
15
  end
12
16
 
13
17
  it "creates @method set to the name of the aliased method" do
14
- @recv.it_behaves_like "something", :some_method
15
- @recv.instance_variable_get(:@method).should == :some_method
18
+ @shared.it("an example") { ScratchPad.record @method }
19
+ @state.it_behaves_like :shared_spec, :some_method
20
+ @state.process
21
+ ScratchPad.recorded.should == :some_method
16
22
  end
17
23
 
18
- it "creates @object if the passed object is not nil" do
19
- @recv.it_behaves_like "something", :some_method, :some_object
20
- @recv.instance_variable_get(:@object).should == :some_object
24
+ it "creates @object if the passed object" do
25
+ object = Object.new
26
+ @shared.it("an example") { ScratchPad.record @object }
27
+ @state.it_behaves_like :shared_spec, :some_method, object
28
+ @state.process
29
+ ScratchPad.recorded.should == object
21
30
  end
22
31
 
23
32
  it "sends :it_should_behave_like" do
24
- @recv.should_receive(:it_should_behave_like)
25
- @recv.it_behaves_like "something", :some_method
33
+ @state.should_receive(:it_should_behave_like)
34
+ @state.it_behaves_like :shared_spec, :some_method
35
+ end
36
+
37
+ describe "with multiple shared contexts" do
38
+ before :each do
39
+ @obj = Object.new
40
+ @obj2 = Object.new
41
+
42
+ @state2 = ContextState.new "Second top level"
43
+ @state2.instance_variable_set :@parsed, true
44
+ end
45
+
46
+ it "ensures the shared spec state is distinct" do
47
+ @shared.it("an example") { ScratchPad.record [@method, @object] }
48
+
49
+ @state.it_behaves_like :shared_spec, :some_method, @obj
50
+
51
+ @state.process
52
+ ScratchPad.recorded.should == [:some_method, @obj]
53
+
54
+ @state2.it_behaves_like :shared_spec, :another_method, @obj2
55
+
56
+ @state2.process
57
+ ScratchPad.recorded.should == [:another_method, @obj2]
58
+ end
59
+
60
+ it "ensures the shared spec state is distinct for nested shared specs" do
61
+ nested = ContextState.new "nested context"
62
+ nested.instance_variable_set :@parsed, true
63
+ nested.parent = @shared
64
+
65
+ nested.it("another example") { ScratchPad.record [:shared, @method, @object] }
66
+
67
+ @state.it_behaves_like :shared_spec, :some_method, @obj
68
+
69
+ @state.process
70
+ ScratchPad.recorded.should == [:shared, :some_method, @obj]
71
+
72
+ @state2.it_behaves_like :shared_spec, :another_method, @obj2
73
+
74
+ @state2.process
75
+ ScratchPad.recorded.should == [:shared, :another_method, @obj2]
76
+ end
26
77
  end
27
78
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mspec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.14
4
+ version: 1.5.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Ford
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-05 00:00:00 -08:00
12
+ date: 2010-02-04 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -41,6 +41,7 @@ files:
41
41
  - lib/mspec/guards/conflict.rb
42
42
  - lib/mspec/guards/endian.rb
43
43
  - lib/mspec/guards/extensions.rb
44
+ - lib/mspec/guards/feature.rb
44
45
  - lib/mspec/guards/guard.rb
45
46
  - lib/mspec/guards/noncompliance.rb
46
47
  - lib/mspec/guards/platform.rb
@@ -56,6 +57,7 @@ files:
56
57
  - lib/mspec/helpers/bignum.rb
57
58
  - lib/mspec/helpers/const_lookup.rb
58
59
  - lib/mspec/helpers/ducktype.rb
60
+ - lib/mspec/helpers/encode.rb
59
61
  - lib/mspec/helpers/enumerator_class.rb
60
62
  - lib/mspec/helpers/environment.rb
61
63
  - lib/mspec/helpers/fixture.rb
@@ -170,6 +172,7 @@ files:
170
172
  - spec/guards/conflict_spec.rb
171
173
  - spec/guards/endian_spec.rb
172
174
  - spec/guards/extensions_spec.rb
175
+ - spec/guards/feature_spec.rb
173
176
  - spec/guards/guard_spec.rb
174
177
  - spec/guards/noncompliance_spec.rb
175
178
  - spec/guards/platform_spec.rb
@@ -184,6 +187,7 @@ files:
184
187
  - spec/helpers/bignum_spec.rb
185
188
  - spec/helpers/const_lookup_spec.rb
186
189
  - spec/helpers/ducktype_spec.rb
190
+ - spec/helpers/encode_spec.rb
187
191
  - spec/helpers/enumerator_class_spec.rb
188
192
  - spec/helpers/environment_spec.rb
189
193
  - spec/helpers/fixture_spec.rb