mspec 1.5.14 → 1.5.15

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