mspec 1.5.0 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/README +3 -0
  2. data/Rakefile +1 -1
  3. data/bin/mkspec +0 -0
  4. data/bin/mspec +0 -0
  5. data/bin/mspec-ci +0 -0
  6. data/bin/mspec-run +0 -0
  7. data/bin/mspec-tag +0 -0
  8. data/lib/mspec/commands/mspec-ci.rb +4 -3
  9. data/lib/mspec/commands/mspec-run.rb +11 -3
  10. data/lib/mspec/commands/mspec-tag.rb +5 -4
  11. data/lib/mspec/matchers.rb +1 -0
  12. data/lib/mspec/matchers/respond_to.rb +24 -0
  13. data/lib/mspec/mocks/mock.rb +3 -0
  14. data/lib/mspec/mocks/proxy.rb +3 -0
  15. data/lib/mspec/runner/actions/tally.rb +1 -1
  16. data/lib/mspec/runner/context.rb +1 -1
  17. data/lib/mspec/runner/formatters.rb +2 -0
  18. data/lib/mspec/runner/formatters/dotted.rb +3 -3
  19. data/lib/mspec/runner/formatters/file.rb +19 -0
  20. data/lib/mspec/runner/formatters/method.rb +93 -0
  21. data/lib/mspec/runner/mspec.rb +1 -1
  22. data/lib/mspec/utils/options.rb +6 -0
  23. data/lib/mspec/utils/script.rb +17 -4
  24. data/lib/mspec/version.rb +1 -1
  25. data/spec/commands/fixtures/four.txt +0 -0
  26. data/spec/commands/fixtures/level2/three_spec.rb +0 -0
  27. data/spec/commands/fixtures/one_spec.rb +0 -0
  28. data/spec/commands/fixtures/three.rb +0 -0
  29. data/spec/commands/fixtures/two_spec.rb +0 -0
  30. data/spec/commands/mspec_ci_spec.rb +2 -6
  31. data/spec/commands/mspec_run_spec.rb +29 -17
  32. data/spec/commands/mspec_tag_spec.rb +8 -10
  33. data/spec/matchers/respond_to_spec.rb +31 -0
  34. data/spec/runner/formatters/dotted_spec.rb +16 -1
  35. data/spec/runner/formatters/file_spec.rb +84 -0
  36. data/spec/runner/formatters/html_spec.rb +1 -1
  37. data/spec/runner/formatters/method_spec.rb +177 -0
  38. data/spec/spec_helper.rb +1 -0
  39. data/spec/utils/options_spec.rb +30 -0
  40. data/spec/utils/script_spec.rb +69 -19
  41. metadata +14 -3
data/README CHANGED
@@ -187,6 +187,9 @@ use nested or shared 'describe' blocks as appropriate and use the
187
187
 
188
188
  == Guards
189
189
 
190
+ Since Ruby is not completely isolated from its platform or execution environment, the spec files may contain guards: conditions placed around a spec or a set of specs to enable or disable them.
191
+
192
+ You can find an overview of the current guards and their usage in: http://rubyspec.org/wiki/mspec/Guards .
190
193
 
191
194
  == Helpers
192
195
 
data/Rakefile CHANGED
@@ -16,7 +16,7 @@ spec = Gem::Specification.new do |s|
16
16
 
17
17
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
18
18
  s.authors = ["Brian Ford"]
19
- s.date = %q{2008-05-21}
19
+ s.date = %q{2008-11-12}
20
20
  s.email = %q{bford@engineyard.com}
21
21
  s.has_rdoc = true
22
22
  s.extra_rdoc_files = %w[ README LICENSE ]
data/bin/mkspec CHANGED
File without changes
data/bin/mspec CHANGED
File without changes
data/bin/mspec-ci CHANGED
File without changes
data/bin/mspec-run CHANGED
File without changes
data/bin/mspec-tag CHANGED
File without changes
@@ -46,13 +46,14 @@ class MSpecCI < MSpecScript
46
46
  options.doc "\n $ mspec ci --spec-debug -S 'this crashes'"
47
47
  options.doc ""
48
48
 
49
- @patterns = options.parse argv
50
- @patterns = config[:ci_files] if @patterns.empty?
49
+ patterns = options.parse argv
50
+ patterns = config[:ci_files] if patterns.empty?
51
+ @files = files patterns
51
52
  end
52
53
 
53
54
  def run
54
55
  MSpec.register_tags_patterns config[:tags_patterns]
55
- MSpec.register_files files(@patterns)
56
+ MSpec.register_files @files
56
57
  filter = TagFilter.new(:exclude,
57
58
  "fails", "critical", "unstable", "incomplete", "unsupported")
58
59
  filter.register
@@ -8,6 +8,12 @@ require 'mspec/utils/script'
8
8
 
9
9
 
10
10
  class MSpecRun < MSpecScript
11
+ def initialize
12
+ super
13
+
14
+ config[:files] = []
15
+ end
16
+
11
17
  def options(argv=ARGV)
12
18
  options = MSpecOptions.new "mspec run [options] (FILE|DIRECTORY|GLOB)+", 30, config
13
19
 
@@ -53,17 +59,19 @@ class MSpecRun < MSpecScript
53
59
  options.doc "\n $ mspec --spec-debug -S 'this crashes' path/to/the_file_spec.rb"
54
60
  options.doc ""
55
61
 
56
- @patterns = options.parse argv
57
- if @patterns.empty?
62
+ patterns = options.parse argv
63
+ patterns = config[:files] if patterns.empty?
64
+ if patterns.empty?
58
65
  puts options
59
66
  puts "No files specified."
60
67
  exit 1
61
68
  end
69
+ @files = files patterns
62
70
  end
63
71
 
64
72
  def run
65
73
  MSpec.register_tags_patterns config[:tags_patterns]
66
- MSpec.register_files files(@patterns)
74
+ MSpec.register_files @files
67
75
 
68
76
  MSpec.process
69
77
  exit MSpec.exit_code
@@ -80,12 +80,13 @@ class MSpecTag < MSpecScript
80
80
  options.doc "\n $ mspec tag --list fails path/to/the/specs"
81
81
  options.doc ""
82
82
 
83
- @patterns = options.parse argv
84
- if @patterns.empty?
83
+ patterns = options.parse argv
84
+ if patterns.empty?
85
85
  puts options
86
86
  puts "No files specified."
87
87
  exit 1
88
88
  end
89
+ @files = files patterns
89
90
  end
90
91
 
91
92
  def register
@@ -97,7 +98,7 @@ class MSpecTag < MSpecScript
97
98
  when :list, :list_all
98
99
  tagger = TagListAction.new config[:tagger] == :list_all ? nil : config[:ltags]
99
100
  MSpec.register_mode :pretend
100
- config[:formatter] = nil
101
+ config[:formatter] = false
101
102
  else
102
103
  raise ArgumentError, "No recognized action given"
103
104
  end
@@ -108,7 +109,7 @@ class MSpecTag < MSpecScript
108
109
 
109
110
  def run
110
111
  MSpec.register_tags_patterns config[:tags_patterns]
111
- MSpec.register_files files(@patterns)
112
+ MSpec.register_files @files
112
113
 
113
114
  MSpec.process
114
115
  exit MSpec.exit_code
@@ -16,3 +16,4 @@ require 'mspec/matchers/match_yaml'
16
16
  require 'mspec/matchers/raise_error'
17
17
  require 'mspec/matchers/output'
18
18
  require 'mspec/matchers/output_to_fd'
19
+ require 'mspec/matchers/respond_to'
@@ -0,0 +1,24 @@
1
+ class RespondToMatcher
2
+ def initialize(expected)
3
+ @expected = expected
4
+ end
5
+
6
+ def matches?(actual)
7
+ @actual = actual
8
+ @actual.respond_to?(@expected)
9
+ end
10
+
11
+ def failure_message
12
+ ["Expected #{@actual.inspect} (#{@actual.class})", "to respond to #{@expected}"]
13
+ end
14
+
15
+ def negative_failure_message
16
+ ["Expected #{@actual.inspect} (#{@actual.class})", "not to respond to #{@expected}"]
17
+ end
18
+ end
19
+
20
+ class Object
21
+ def respond_to(expected)
22
+ RespondToMatcher.new(expected)
23
+ end
24
+ end
@@ -88,6 +88,9 @@ module Mock
88
88
 
89
89
  def self.verify_call(obj, sym, *args, &block)
90
90
  compare = *args
91
+ if RUBY_VERSION >= '1.9'
92
+ compare = compare.first if compare.length <= 1
93
+ end
91
94
 
92
95
  key = replaced_key obj, sym
93
96
  proxies = mocks[key] + stubs[key]
@@ -88,6 +88,9 @@ class MockProxy
88
88
  def with(*args)
89
89
  raise ArgumentError, "you must specify the expected arguments" if args.empty?
90
90
  @arguments = *args
91
+ if RUBY_VERSION >= '1.9'
92
+ @arguments = @arguments.first if @arguments.length <= 1
93
+ end
91
94
  self
92
95
  end
93
96
 
@@ -1,5 +1,5 @@
1
1
  class Tally
2
- attr_reader :files, :examples, :expectations, :failures, :errors
2
+ attr_accessor :files, :examples, :expectations, :failures, :errors
3
3
 
4
4
  def initialize
5
5
  @files = @examples = @expectations = @failures = @errors = 0
@@ -105,7 +105,7 @@ class ContextState
105
105
 
106
106
  # Returns a description string generated from self and all parents
107
107
  def description
108
- @description ||= parents.inject([]) { |l,s| l << s.to_s }.join(" ")
108
+ @description ||= parents.map { |p| p.to_s }.join(" ")
109
109
  end
110
110
 
111
111
  # Injects the before/after blocks and examples from the shared
@@ -1,7 +1,9 @@
1
1
  require 'mspec/runner/formatters/dotted'
2
+ require 'mspec/runner/formatters/file'
2
3
  require 'mspec/runner/formatters/specdoc'
3
4
  require 'mspec/runner/formatters/html'
4
5
  require 'mspec/runner/formatters/summary'
5
6
  require 'mspec/runner/formatters/unit'
6
7
  require 'mspec/runner/formatters/spinner'
8
+ require 'mspec/runner/formatters/method'
7
9
  require 'mspec/runner/formatters/yaml'
@@ -47,7 +47,7 @@ class DottedFormatter
47
47
 
48
48
  # Callback for the MSpec :before event. Resets the
49
49
  # +#exception?+ and +#failure+ flags.
50
- def before(state)
50
+ def before(state = nil)
51
51
  @failure = @exception = false
52
52
  end
53
53
 
@@ -67,7 +67,7 @@ class DottedFormatter
67
67
  # . = No failure or error
68
68
  # F = An ExpectationNotMetError was raised
69
69
  # E = Any exception other than ExpectationNotMetError
70
- def after(state)
70
+ def after(state = nil)
71
71
  unless exception?
72
72
  print "."
73
73
  else
@@ -93,6 +93,6 @@ class DottedFormatter
93
93
  # A convenience method to allow printing to different outputs.
94
94
  def print(*args)
95
95
  @out.print(*args)
96
- @out.flush
96
+ @out.flush rescue nil #IronRuby throws a .NET exception on IO.flush
97
97
  end
98
98
  end
@@ -0,0 +1,19 @@
1
+ require 'mspec/runner/formatters/dotted'
2
+
3
+ class FileFormatter < DottedFormatter
4
+ # Unregisters DottedFormatter#before, #after methods and
5
+ # registers #load, #unload, which perform the same duties
6
+ # as #before, #after in DottedFormatter.
7
+ def register
8
+ super
9
+
10
+ MSpec.unregister :before, self
11
+ MSpec.unregister :after, self
12
+
13
+ MSpec.register :load, self
14
+ MSpec.register :unload, self
15
+ end
16
+
17
+ alias_method :load, :before
18
+ alias_method :unload, :after
19
+ end
@@ -0,0 +1,93 @@
1
+ require 'mspec/runner/formatters/dotted'
2
+
3
+ class MethodFormatter < DottedFormatter
4
+ attr_accessor :methods
5
+
6
+ def initialize(out=nil)
7
+ super
8
+ @methods = Hash.new do |h, k|
9
+ hash = {}
10
+ hash[:examples] = 0
11
+ hash[:expectations] = 0
12
+ hash[:failures] = 0
13
+ hash[:errors] = 0
14
+ hash[:exceptions] = []
15
+ h[k] = hash
16
+ end
17
+ end
18
+
19
+ # Returns the type of method as a "class", "instance",
20
+ # or "unknown".
21
+ def method_type(sep)
22
+ case sep
23
+ when '.', '::'
24
+ "class"
25
+ when '#'
26
+ "instance"
27
+ else
28
+ "unknown"
29
+ end
30
+ end
31
+
32
+ # Callback for the MSpec :before event. Parses the
33
+ # describe string into class and method if possible.
34
+ # Resets the tallies so the counts are only for this
35
+ # example.
36
+ def before(state)
37
+ super
38
+
39
+ # The pattern for a method name is not correctly
40
+ # restrictive but it is simplistic and useful
41
+ # for our purpose.
42
+ /^([A-Za-z_]+\w*)(\.|#|::)([^ ]+)/ =~ state.describe
43
+ @key = $1 && $2 && $3 ? "#{$1}#{$2}#{$3}" : state.describe
44
+
45
+ unless methods.key? @key
46
+ h = methods[@key]
47
+ h[:class] = "#{$1}"
48
+ h[:method] = "#{$3}"
49
+ h[:type] = method_type $2
50
+ h[:description] = state.description
51
+ end
52
+
53
+ tally.counter.examples = 0
54
+ tally.counter.expectations = 0
55
+ tally.counter.failures = 0
56
+ tally.counter.errors = 0
57
+
58
+ @exceptions = []
59
+ end
60
+
61
+ # Callback for the MSpec :after event. Sets or adds to
62
+ # tallies for the example block.
63
+ def after(state)
64
+ h = methods[@key]
65
+ h[:examples] += tally.counter.examples
66
+ h[:expectations] += tally.counter.expectations
67
+ h[:failures] += tally.counter.failures
68
+ h[:errors] += tally.counter.errors
69
+ @exceptions.each do |exc|
70
+ h[:exceptions] << "#{exc.message}\n#{exc.backtrace}\n"
71
+ end
72
+ end
73
+
74
+ # Callback for the MSpec :finish event. Prints out the
75
+ # summary information in YAML format for all the methods.
76
+ def finish
77
+ print "---\n"
78
+
79
+ methods.each do |key, hash|
80
+ print key.inspect, ":\n"
81
+ print " class: ", hash[:class].inspect, "\n"
82
+ print " method: ", hash[:method].inspect, "\n"
83
+ print " type: ", hash[:type], "\n"
84
+ print " description: ", hash[:description].inspect, "\n"
85
+ print " examples: ", hash[:examples], "\n"
86
+ print " expectations: ", hash[:expectations], "\n"
87
+ print " failures: ", hash[:failures], "\n"
88
+ print " errors: ", hash[:errors], "\n"
89
+ print " exceptions:\n"
90
+ hash[:exceptions].each { |exc| print " - ", exc.inspect, "\n" }
91
+ end
92
+ end
93
+ end
@@ -276,7 +276,7 @@ module MSpec
276
276
  File.open(file, "w") do |f|
277
277
  lines.each do |line|
278
278
  unless pattern =~ line.chomp
279
- f.puts line
279
+ f.puts line unless line.empty?
280
280
  else
281
281
  deleted = true
282
282
  end
@@ -256,12 +256,16 @@ class MSpecOptions
256
256
  config[:formatter] = HtmlFormatter
257
257
  when 'd', 'dot', 'dotted'
258
258
  config[:formatter] = DottedFormatter
259
+ when 'f', 'file'
260
+ config[:formatter] = FileFormatter
259
261
  when 'u', 'unit', 'unitdiff'
260
262
  config[:formatter] = UnitdiffFormatter
261
263
  when 'm', 'summary'
262
264
  config[:formatter] = SummaryFormatter
263
265
  when 'a', '*', 'spin'
264
266
  config[:formatter] = SpinnerFormatter
267
+ when 't', 'method'
268
+ config[:formatter] = MethodFormatter
265
269
  when 'y', 'yaml'
266
270
  config[:formatter] = YamlFormatter
267
271
  else
@@ -275,9 +279,11 @@ class MSpecOptions
275
279
  doc " s, spec, specdoc SpecdocFormatter"
276
280
  doc " h, html, HtmlFormatter"
277
281
  doc " d, dot, dotted DottedFormatter"
282
+ doc " f, file FileFormatter"
278
283
  doc " u, unit, unitdiff UnitdiffFormatter"
279
284
  doc " m, summary SummaryFormatter"
280
285
  doc " a, *, spin SpinnerFormatter"
286
+ doc " t, method MethodFormatter"
281
287
  doc " y, yaml YamlFormatter\n"
282
288
 
283
289
  on("-o", "--output", "FILE",
@@ -16,7 +16,7 @@ class MSpecScript
16
16
 
17
17
  def initialize
18
18
  config[:tags_dir] = 'spec/tags'
19
- config[:formatter] = DottedFormatter
19
+ config[:formatter] = nil
20
20
  config[:includes] = []
21
21
  config[:excludes] = []
22
22
  config[:patterns] = []
@@ -52,6 +52,9 @@ class MSpecScript
52
52
  end
53
53
 
54
54
  def register
55
+ if config[:formatter].nil?
56
+ config[:formatter] = @files.size < 50 ? DottedFormatter : FileFormatter
57
+ end
55
58
  config[:formatter].new(config[:output]).register if config[:formatter]
56
59
 
57
60
  MatchFilter.new(:include, *config[:includes]).register unless config[:includes].empty?
@@ -76,11 +79,20 @@ class MSpecScript
76
79
  end
77
80
  end
78
81
 
82
+ def entries(pattern)
83
+ expanded = File.expand_path(pattern)
84
+ return [pattern] if File.file?(expanded)
85
+ return Dir[pattern+"/**/*_spec.rb"].sort if File.directory?(expanded)
86
+ Dir[pattern]
87
+ end
88
+
79
89
  def files(list)
80
90
  list.inject([]) do |files, item|
81
- stat = File.stat(File.expand_path(item))
82
- files << item if stat.file?
83
- files.concat(Dir[item+"/**/*_spec.rb"].sort) if stat.directory?
91
+ if item[0] == ?^
92
+ files -= entries(item[1..-1])
93
+ else
94
+ files += entries(item)
95
+ end
84
96
  files
85
97
  end
86
98
  end
@@ -89,6 +101,7 @@ class MSpecScript
89
101
  $VERBOSE = nil unless ENV['OUTPUT_WARNINGS']
90
102
  script = new
91
103
  script.load 'default.mspec'
104
+ script.load RUBY_VERSION.split('.')[0,2].join('.') + ".mspec"
92
105
  script.load '~/.mspecrc'
93
106
  script.options
94
107
  script.signals
data/lib/mspec/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module MSpec
2
- VERSION = '1.5.0'
2
+ VERSION = '1.5.1'
3
3
  end
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -10,6 +10,7 @@ describe MSpecCI, "#options" do
10
10
 
11
11
  @script = MSpecCI.new
12
12
  @script.stub!(:config).and_return(@config)
13
+ @script.stub!(:files).and_return([])
13
14
  end
14
15
 
15
16
  it "enables the config option" do
@@ -76,16 +77,11 @@ describe MSpecCI, "#run" do
76
77
  TagFilter.stub!(:new).and_return(@filter)
77
78
  @filter.stub!(:register)
78
79
 
79
- stat = mock("stat")
80
- stat.stub!(:file?).and_return(true)
81
- stat.stub!(:directory?).and_return(false)
82
- File.stub!(:expand_path)
83
- File.stub!(:stat).and_return(stat)
84
-
85
80
  @config = { :ci_files => ["one", "two"] }
86
81
  @script = MSpecCI.new
87
82
  @script.stub!(:exit)
88
83
  @script.stub!(:config).and_return(@config)
84
+ @script.stub!(:files).and_return(["one", "two"])
89
85
  @script.options
90
86
  end
91
87
 
@@ -2,6 +2,16 @@ require File.dirname(__FILE__) + '/../spec_helper'
2
2
  require 'mspec/runner/mspec'
3
3
  require 'mspec/commands/mspec-run'
4
4
 
5
+ describe MSpecRun, ".new" do
6
+ before :each do
7
+ @script = MSpecRun.new
8
+ end
9
+
10
+ it "sets config[:files] to an empty list" do
11
+ @script.config[:files].should == []
12
+ end
13
+ end
14
+
5
15
  describe MSpecRun, "#options" do
6
16
  before :each do
7
17
  @stdout, $stdout = $stdout, IOStub.new
@@ -98,33 +108,35 @@ end
98
108
 
99
109
  describe MSpecRun, "#run" do
100
110
  before :each do
101
- MSpec.stub!(:process)
102
-
103
- stat = mock("stat")
104
- stat.stub!(:file?).and_return(true)
105
- stat.stub!(:directory?).and_return(false)
106
- File.stub!(:expand_path)
107
- File.stub!(:stat).and_return(stat)
108
-
109
- options = mock("MSpecOptions", :null_object => true)
110
- options.stub!(:parse).and_return(["one", "two"])
111
- MSpecOptions.stub!(:new).and_return(options)
112
-
113
- @config = { }
114
111
  @script = MSpecRun.new
115
112
  @script.stub!(:exit)
116
- @script.stub!(:config).and_return(@config)
117
- @script.options
113
+ @spec_dir = File.expand_path(File.dirname(__FILE__)+"/fixtures")
114
+ @file_patterns = [
115
+ @spec_dir+"/level2",
116
+ @spec_dir+"/one_spec.rb",
117
+ @spec_dir+"/two_spec.rb"]
118
+ @files = [
119
+ @spec_dir+"/level2/three_spec.rb",
120
+ @spec_dir+"/one_spec.rb",
121
+ @spec_dir+"/two_spec.rb"]
122
+ @script.options @file_patterns
118
123
  end
119
124
 
120
125
  it "registers the tags patterns" do
121
- @config[:tags_patterns] = [/spec/, "tags"]
126
+ @script.config[:tags_patterns] = [/spec/, "tags"]
122
127
  MSpec.should_receive(:register_tags_patterns).with([/spec/, "tags"])
123
128
  @script.run
124
129
  end
125
130
 
126
131
  it "registers the files to process" do
127
- MSpec.should_receive(:register_files).with(["one", "two"])
132
+ MSpec.should_receive(:register_files).with(@files)
133
+ @script.run
134
+ end
135
+
136
+ it "uses config[:files] if no files are given on the command line" do
137
+ @script.config[:files] = @file_patterns
138
+ MSpec.should_receive(:register_files).with(@files)
139
+ @script.options []
128
140
  @script.run
129
141
  end
130
142
 
@@ -234,12 +234,6 @@ describe MSpecTag, "#run" do
234
234
  before :each do
235
235
  MSpec.stub!(:process)
236
236
 
237
- stat = mock("stat")
238
- stat.stub!(:file?).and_return(true)
239
- stat.stub!(:directory?).and_return(false)
240
- File.stub!(:expand_path)
241
- File.stub!(:stat).and_return(stat)
242
-
243
237
  options = mock("MSpecOptions", :null_object => true)
244
238
  options.stub!(:parse).and_return(["one", "two"])
245
239
  MSpecOptions.stub!(:new).and_return(options)
@@ -248,6 +242,7 @@ describe MSpecTag, "#run" do
248
242
  @script = MSpecTag.new
249
243
  @script.stub!(:exit)
250
244
  @script.stub!(:config).and_return(@config)
245
+ @script.stub!(:files).and_return(["one", "two"])
251
246
  @script.options
252
247
  end
253
248
 
@@ -283,6 +278,9 @@ describe MSpecTag, "#register" do
283
278
  @config[:astrings] = []
284
279
  @config[:ltags] = ["fails", "unstable"]
285
280
 
281
+ @script.stub!(:files).and_return([])
282
+ @script.options "fake"
283
+
286
284
  @t = mock("TagAction")
287
285
  @t.stub!(:register)
288
286
 
@@ -329,9 +327,9 @@ describe MSpecTag, "#register" do
329
327
  @script.register
330
328
  end
331
329
 
332
- it "sets config[:formatter] to nil" do
330
+ it "sets config[:formatter] to false" do
333
331
  @script.register
334
- @config[:formatter].should be_nil
332
+ @config[:formatter].should be_false
335
333
  end
336
334
  end
337
335
 
@@ -351,9 +349,9 @@ describe MSpecTag, "#register" do
351
349
  @script.register
352
350
  end
353
351
 
354
- it "sets config[:formatter] to nil" do
352
+ it "sets config[:formatter] to false" do
355
353
  @script.register
356
- @config[:formatter].should be_nil
354
+ @config[:formatter].should be_false
357
355
  end
358
356
  end
359
357
  end
@@ -0,0 +1,31 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'mspec/expectations/expectations'
3
+ require 'mspec/matchers/respond_to'
4
+
5
+ describe RespondToMatcher do
6
+ it "matches when actual does respond_to? expected" do
7
+ RespondToMatcher.new(:to_s).matches?(Object.new).should == true
8
+ RespondToMatcher.new(:inject).matches?([]).should == true
9
+ RespondToMatcher.new(:[]).matches?(1).should == true
10
+ RespondToMatcher.new(:[]=).matches?("string").should == true
11
+ end
12
+
13
+ it "does not match when actual does not respond_to? expected" do
14
+ RespondToMatcher.new(:to_i).matches?(Object.new).should == false
15
+ RespondToMatcher.new(:inject).matches?(1).should == false
16
+ RespondToMatcher.new(:non_existent_method).matches?([]).should == false
17
+ RespondToMatcher.new(:[]=).matches?(1).should == false
18
+ end
19
+
20
+ it "provides a useful failure message" do
21
+ matcher = RespondToMatcher.new(:non_existent_method)
22
+ matcher.matches?('string')
23
+ matcher.failure_message.should == ["Expected \"string\" (String)", "to respond to non_existent_method"]
24
+ end
25
+
26
+ it "provides a useful negative failure message" do
27
+ matcher = RespondToMatcher.new(:to_i)
28
+ matcher.matches?(4.2)
29
+ matcher.negative_failure_message.should == ["Expected 4.2 (Float)", "not to respond to to_i"]
30
+ end
31
+ end
@@ -40,12 +40,15 @@ describe DottedFormatter, "#register" do
40
40
  end
41
41
 
42
42
  describe DottedFormatter, "#print" do
43
+ before :each do
44
+ $stdout = IOStub.new
45
+ end
46
+
43
47
  after :each do
44
48
  $stdout = STDOUT
45
49
  end
46
50
 
47
51
  it "writes to $stdout by default" do
48
- $stdout = IOStub.new
49
52
  formatter = DottedFormatter.new
50
53
  formatter.print "begonias"
51
54
  $stdout.should == "begonias"
@@ -58,6 +61,18 @@ describe DottedFormatter, "#print" do
58
61
  formatter.print "begonias"
59
62
  out.should == "begonias"
60
63
  end
64
+
65
+ it "flushes the IO output" do
66
+ $stdout.should_receive(:flush)
67
+ formatter = DottedFormatter.new
68
+ formatter.print "begonias"
69
+ end
70
+
71
+ it "rescues errors from flush" do
72
+ $stdout.should_receive(:flush).and_raise(RuntimeError.new)
73
+ formatter = DottedFormatter.new
74
+ formatter.print("begonias").should == nil
75
+ end
61
76
  end
62
77
 
63
78
  describe DottedFormatter, "#exception" do
@@ -0,0 +1,84 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+ require 'mspec/runner/formatters/file'
3
+ require 'mspec/runner/mspec'
4
+ require 'mspec/runner/example'
5
+
6
+ describe FileFormatter, "#register" do
7
+ before :each do
8
+ @formatter = FileFormatter.new
9
+ end
10
+
11
+ it "registers self with MSpec for :load, :unload actions" do
12
+ MSpec.stub!(:register)
13
+ MSpec.should_receive(:register).with(:load, @formatter)
14
+ MSpec.should_receive(:register).with(:unload, @formatter)
15
+ @formatter.register
16
+ end
17
+
18
+ it "unregisters self with MSpec for :before, :after actions" do
19
+ MSpec.stub!(:unregister)
20
+ MSpec.should_receive(:unregister).with(:before, @formatter)
21
+ MSpec.should_receive(:unregister).with(:after, @formatter)
22
+ @formatter.register
23
+ end
24
+ end
25
+
26
+ describe FileFormatter, "#load" do
27
+ before :each do
28
+ @state = ExampleState.new ContextState.new("describe"), "it"
29
+ @formatter = FileFormatter.new
30
+ @formatter.exception ExceptionState.new(nil, nil, ExpectationNotMetError.new("Failed!"))
31
+ end
32
+
33
+ it "resets the #failure? flag to false" do
34
+ @formatter.failure?.should be_true
35
+ @formatter.load @state
36
+ @formatter.failure?.should be_false
37
+ end
38
+
39
+ it "resets the #exception? flag to false" do
40
+ @formatter.exception?.should be_true
41
+ @formatter.load @state
42
+ @formatter.exception?.should be_false
43
+ end
44
+ end
45
+
46
+ describe FileFormatter, "#unload" do
47
+ before :each do
48
+ $stdout = @out = IOStub.new
49
+ @formatter = FileFormatter.new
50
+ @state = ExampleState.new ContextState.new("describe"), "it"
51
+ end
52
+
53
+ after :each do
54
+ $stdout = STDOUT
55
+ end
56
+
57
+ it "prints a '.' if there was no exception raised" do
58
+ @formatter.unload(@state)
59
+ @out.should == "."
60
+ end
61
+
62
+ it "prints an 'F' if there was an expectation failure" do
63
+ exc = ExpectationNotMetError.new "failed"
64
+ @formatter.exception ExceptionState.new(@state, nil, exc)
65
+ @formatter.unload(@state)
66
+ @out.should == "F"
67
+ end
68
+
69
+ it "prints an 'E' if there was an exception other than expectation failure" do
70
+ exc = MSpecExampleError.new("boom!")
71
+ @formatter.exception ExceptionState.new(@state, nil, exc)
72
+ @formatter.unload(@state)
73
+ @out.should == "E"
74
+ end
75
+
76
+ it "prints an 'E' if there are mixed exceptions and exepctation failures" do
77
+ exc = ExpectationNotMetError.new "failed"
78
+ @formatter.exception ExceptionState.new(@state, nil, exc)
79
+ exc = MSpecExampleError.new("boom!")
80
+ @formatter.exception ExceptionState.new(@state, nil, exc)
81
+ @formatter.unload(@state)
82
+ @out.should == "E"
83
+ end
84
+ end
@@ -37,7 +37,7 @@ describe HtmlFormatter, "#start" do
37
37
  "http://www.w3.org/TR/html4/strict.dtd">
38
38
  <html>
39
39
  <head>
40
- <title>Spec Output For #{ruby_name} (1.8.6)</title>
40
+ <title>Spec Output For #{ruby_name} (#{RUBY_VERSION})</title>
41
41
  <style type="text/css">
42
42
  ul {
43
43
  list-style: none;
@@ -0,0 +1,177 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+ require 'mspec/runner/formatters/method'
3
+ require 'mspec/runner/mspec'
4
+ require 'mspec/runner/example'
5
+
6
+ describe MethodFormatter, "#method_type" do
7
+ before :each do
8
+ @formatter = MethodFormatter.new
9
+ end
10
+
11
+ it "returns 'class' if the separator is '.' or '::'" do
12
+ @formatter.method_type('.').should == "class"
13
+ @formatter.method_type('::').should == "class"
14
+ end
15
+
16
+ it "returns 'instance' if the separator is '#'" do
17
+ @formatter.method_type('#').should == "instance"
18
+ end
19
+
20
+ it "returns 'unknown' for all other cases" do
21
+ @formatter.method_type(nil).should == "unknown"
22
+ end
23
+ end
24
+
25
+ describe MethodFormatter, "#before" do
26
+ before :each do
27
+ @formatter = MethodFormatter.new
28
+ MSpec.stub!(:register)
29
+ @formatter.register
30
+ end
31
+
32
+ it "resets the tally counters to 0" do
33
+ @formatter.tally.counter.examples = 3
34
+ @formatter.tally.counter.expectations = 4
35
+ @formatter.tally.counter.failures = 2
36
+ @formatter.tally.counter.errors = 1
37
+
38
+ state = ExampleState.new ContextState.new("describe"), "it"
39
+ @formatter.before state
40
+ @formatter.tally.counter.examples.should == 0
41
+ @formatter.tally.counter.expectations.should == 0
42
+ @formatter.tally.counter.failures.should == 0
43
+ @formatter.tally.counter.errors.should == 0
44
+ end
45
+
46
+ it "records the class, method if available" do
47
+ state = ExampleState.new ContextState.new("Some#method"), "it"
48
+ @formatter.before state
49
+ key = "Some#method"
50
+ @formatter.methods.keys.should include(key)
51
+ h = @formatter.methods[key]
52
+ h[:class].should == "Some"
53
+ h[:method].should == "method"
54
+ h[:description].should == "Some#method it"
55
+ end
56
+
57
+ it "does not record class, method unless both are available" do
58
+ state = ExampleState.new ContextState.new("Some method"), "it"
59
+ @formatter.before state
60
+ key = "Some method"
61
+ @formatter.methods.keys.should include(key)
62
+ h = @formatter.methods[key]
63
+ h[:class].should == ""
64
+ h[:method].should == ""
65
+ h[:description].should == "Some method it"
66
+ end
67
+
68
+ it "sets the method type to unknown if class and method are not available" do
69
+ state = ExampleState.new ContextState.new("Some method"), "it"
70
+ @formatter.before state
71
+ key = "Some method"
72
+ h = @formatter.methods[key]
73
+ h[:type].should == "unknown"
74
+ end
75
+
76
+ it "sets the method type based on the class, method separator" do
77
+ [["C#m", "instance"], ["C.m", "class"], ["C::m", "class"]].each do |k, t|
78
+ state = ExampleState.new ContextState.new(k), "it"
79
+ @formatter.before state
80
+ h = @formatter.methods[k]
81
+ h[:type].should == t
82
+ end
83
+ end
84
+
85
+ it "clears the list of exceptions" do
86
+ state = ExampleState.new ContextState.new("describe"), "it"
87
+ @formatter.exceptions << "stuff"
88
+ @formatter.before state
89
+ @formatter.exceptions.should be_empty
90
+ end
91
+ end
92
+
93
+ describe MethodFormatter, "#after" do
94
+ before :each do
95
+ @formatter = MethodFormatter.new
96
+ MSpec.stub!(:register)
97
+ @formatter.register
98
+ end
99
+
100
+ it "sets the tally counts" do
101
+ state = ExampleState.new ContextState.new("Some#method"), "it"
102
+ @formatter.before state
103
+
104
+ @formatter.tally.counter.examples = 3
105
+ @formatter.tally.counter.expectations = 4
106
+ @formatter.tally.counter.failures = 2
107
+ @formatter.tally.counter.errors = 1
108
+
109
+ @formatter.after state
110
+ h = @formatter.methods["Some#method"]
111
+ h[:examples].should == 3
112
+ h[:expectations].should == 4
113
+ h[:failures].should == 2
114
+ h[:errors].should == 1
115
+ end
116
+
117
+ it "renders the list of exceptions" do
118
+ state = ExampleState.new ContextState.new("Some#method"), "it"
119
+ @formatter.before state
120
+
121
+ exc = ExpectationNotMetError.new "failed"
122
+ @formatter.exception ExceptionState.new(@state, nil, exc)
123
+ @formatter.exception ExceptionState.new(@state, nil, exc)
124
+
125
+ @formatter.after state
126
+ h = @formatter.methods["Some#method"]
127
+ h[:exceptions].should == [
128
+ %[failed\n\n],
129
+ %[failed\n\n]
130
+ ]
131
+ end
132
+ end
133
+
134
+ describe MethodFormatter, "#after" do
135
+ before :each do
136
+ $stdout = IOStub.new
137
+ context = ContextState.new "Class#method"
138
+ @state = ExampleState.new(context, "runs")
139
+ @formatter = MethodFormatter.new
140
+ MSpec.stub!(:register)
141
+ @formatter.register
142
+ end
143
+
144
+ after :each do
145
+ $stdout = STDOUT
146
+ end
147
+
148
+ it "prints a summary of the results of an example in YAML format" do
149
+ @formatter.before @state
150
+ @formatter.tally.counter.examples = 3
151
+ @formatter.tally.counter.expectations = 4
152
+ @formatter.tally.counter.failures = 2
153
+ @formatter.tally.counter.errors = 1
154
+
155
+ exc = ExpectationNotMetError.new "failed"
156
+ @formatter.exception ExceptionState.new(@state, nil, exc)
157
+ @formatter.exception ExceptionState.new(@state, nil, exc)
158
+
159
+ @formatter.after @state
160
+ @formatter.finish
161
+ $stdout.should ==
162
+ %[---
163
+ "Class#method":
164
+ class: "Class"
165
+ method: "method"
166
+ type: instance
167
+ description: "Class#method runs"
168
+ examples: 3
169
+ expectations: 4
170
+ failures: 2
171
+ errors: 1
172
+ exceptions:
173
+ - "failed\\n\\n"
174
+ - "failed\\n\\n"
175
+ ]
176
+ end
177
+ end
data/spec/spec_helper.rb CHANGED
@@ -28,6 +28,7 @@ class MOSConfig < Hash
28
28
  self[:target] = 'ruby'
29
29
  self[:command] = nil
30
30
  self[:ltags] = []
31
+ self[:files] = []
31
32
  end
32
33
  end
33
34
 
@@ -664,6 +664,16 @@ describe "The -f, --format FORMAT option" do
664
664
  end
665
665
  end
666
666
 
667
+ it "sets the FileFormatter with FORMAT 'f', 'file'" do
668
+ ["-f", "--format"].each do |opt|
669
+ ["f", "file"].each do |f|
670
+ @config[:formatter] = nil
671
+ @options.parse [opt, f]
672
+ @config[:formatter].should == FileFormatter
673
+ end
674
+ end
675
+ end
676
+
667
677
  it "sets the UnitdiffFormatter with FORMAT 'u', 'unit', or 'unitdiff'" do
668
678
  ["-f", "--format"].each do |opt|
669
679
  ["u", "unit", "unitdiff"].each do |f|
@@ -693,6 +703,26 @@ describe "The -f, --format FORMAT option" do
693
703
  end
694
704
  end
695
705
  end
706
+
707
+ it "sets the MethodFormatter with FORMAT 't' or 'method'" do
708
+ ["-f", "--format"].each do |opt|
709
+ ["t", "method"].each do |f|
710
+ @config[:formatter] = nil
711
+ @options.parse [opt, f]
712
+ @config[:formatter].should == MethodFormatter
713
+ end
714
+ end
715
+ end
716
+
717
+ it "sets the YamlFormatter with FORMAT 'y' or 'yaml'" do
718
+ ["-f", "--format"].each do |opt|
719
+ ["y", "yaml"].each do |f|
720
+ @config[:formatter] = nil
721
+ @options.parse [opt, f]
722
+ @config[:formatter].should == YamlFormatter
723
+ end
724
+ end
725
+ end
696
726
  end
697
727
 
698
728
  describe "The -o, --output FILE option" do
@@ -32,6 +32,34 @@ describe MSpecScript, "#config" do
32
32
  end
33
33
  end
34
34
 
35
+ describe MSpecScript, ".main" do
36
+ before :all do
37
+ @verbose = $VERBOSE
38
+ $VERBOSE = nil
39
+ end
40
+
41
+ after :all do
42
+ $VERBOSE = @verbose
43
+ end
44
+
45
+ before :each do
46
+ @version = RUBY_VERSION
47
+ @script = mock("MSpecScript", :null_object => true)
48
+ MSpecScript.stub!(:new).and_return(@script)
49
+ end
50
+
51
+ after :each do
52
+ Object.const_set :RUBY_VERSION, @version
53
+ end
54
+
55
+ it "attempts to load a config file based on RUBY_VERSION" do
56
+ Object.const_set :RUBY_VERSION, "1.8.9"
57
+ version = "1.8.mspec"
58
+ @script.should_receive(:load).with(version)
59
+ MSpecScript.main
60
+ end
61
+ end
62
+
35
63
  describe MSpecScript, ".main" do
36
64
  before :each do
37
65
  @script = mock("MSpecScript", :null_object => true)
@@ -81,7 +109,7 @@ describe MSpecScript, "#initialize" do
81
109
 
82
110
  it "sets the default config values" do
83
111
  @config[:tags_dir].should == 'spec/tags'
84
- @config[:formatter].should == DottedFormatter
112
+ @config[:formatter].should == nil
85
113
  @config[:includes].should == []
86
114
  @config[:excludes].should == []
87
115
  @config[:patterns].should == []
@@ -162,8 +190,8 @@ describe MSpecScript, "#register" do
162
190
  @script.register
163
191
  end
164
192
 
165
- it "does not register the formatter if config[:formatter] is nil" do
166
- @script.config[:formatter] = nil
193
+ it "does not register the formatter if config[:formatter] is false" do
194
+ @script.config[:formatter] = false
167
195
  @script.register
168
196
  end
169
197
  end
@@ -269,29 +297,51 @@ describe MSpecScript, "#signals" do
269
297
  end
270
298
  end
271
299
 
300
+ describe MSpecScript, "#entries" do
301
+ before :each do
302
+ @script = MSpecScript.new
303
+ end
304
+
305
+ it "returns the pattern in an array if it is a file" do
306
+ File.should_receive(:expand_path).with("file").and_return("file")
307
+ File.should_receive(:file?).with("file").and_return(true)
308
+ @script.entries("file").should == ["file"]
309
+ end
310
+
311
+ it "returns Dir['pattern/**/*_spec.rb'] if pattern is a directory" do
312
+ File.should_receive(:expand_path).with("dir").and_return("dir")
313
+ File.should_receive(:file?).with("dir").and_return(false)
314
+ File.should_receive(:directory?).with("dir").and_return(true)
315
+ Dir.should_receive(:[]).with("dir/**/*_spec.rb").and_return(["dir1", "dir2"])
316
+ @script.entries("dir").should == ["dir1", "dir2"]
317
+ end
318
+
319
+ it "returns Dir[pattern] if pattern is neither a file nor a directory" do
320
+ File.should_receive(:expand_path).with("pattern").and_return("pattern")
321
+ File.should_receive(:file?).with("pattern").and_return(false)
322
+ File.should_receive(:directory?).with("pattern").and_return(false)
323
+ Dir.should_receive(:[]).with("pattern").and_return(["file1", "file2"])
324
+ @script.entries("pattern").should == ["file1", "file2"]
325
+ end
326
+ end
327
+
272
328
  describe MSpecScript, "#files" do
273
329
  before :each do
274
330
  @script = MSpecScript.new
275
331
  end
276
332
 
277
- it "returns entries unchanged if they are files" do
278
- stat = mock("Stat")
279
- stat.stub!(:file?).and_return(true)
280
- stat.stub!(:directory?).and_return(false)
281
- File.stub!(:stat).and_return(stat)
282
- @script.files(["a", "b"]).should == ["a", "b"]
333
+ it "accumlates the values returned by #entries" do
334
+ @script.should_receive(:entries).and_return(["file1"], ["file2"])
335
+ @script.files(["a", "b"]).should == ["file1", "file2"]
283
336
  end
284
337
 
285
- it "searches for _spec.rb files if the entry is a directory" do
286
- File.should_receive(:expand_path).with("some/dir").and_return("some/dir")
287
- stat = mock("Stat")
288
- stat.should_receive(:file?).and_return(false)
289
- stat.should_receive(:directory?).and_return(true)
290
- File.stub!(:stat).and_return(stat)
338
+ it "strips a leading '^' and removes the values returned by #entries" do
339
+ @script.should_receive(:entries).and_return(["file1"], ["file2"], ["file1"])
340
+ @script.files(["a", "b", "^a"]).should == ["file2"]
341
+ end
291
342
 
292
- Dir.should_receive(:[]).with("some/dir/**/*_spec.rb").and_return(
293
- ["some/dir/file_spec.rb", "some/dir/other_spec.rb"])
294
- @script.files(["some/dir"]).should ==
295
- ["some/dir/file_spec.rb", "some/dir/other_spec.rb"]
343
+ it "processes the array elements in order" do
344
+ @script.should_receive(:entries).and_return(["file1"], ["file1"], ["file2"])
345
+ @script.files(["^a", "a", "b"]).should == ["file1", "file2"]
296
346
  end
297
347
  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.0
4
+ version: 1.5.1
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: 2008-05-21 00:00:00 -07:00
12
+ date: 2008-11-12 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -75,6 +75,7 @@ files:
75
75
  - lib/mspec/matchers/output.rb
76
76
  - lib/mspec/matchers/output_to_fd.rb
77
77
  - lib/mspec/matchers/raise_error.rb
78
+ - lib/mspec/matchers/respond_to.rb
78
79
  - lib/mspec/matchers.rb
79
80
  - lib/mspec/mocks/mock.rb
80
81
  - lib/mspec/mocks/object.rb
@@ -98,7 +99,9 @@ files:
98
99
  - lib/mspec/runner/filters/tag.rb
99
100
  - lib/mspec/runner/filters.rb
100
101
  - lib/mspec/runner/formatters/dotted.rb
102
+ - lib/mspec/runner/formatters/file.rb
101
103
  - lib/mspec/runner/formatters/html.rb
104
+ - lib/mspec/runner/formatters/method.rb
102
105
  - lib/mspec/runner/formatters/specdoc.rb
103
106
  - lib/mspec/runner/formatters/spinner.rb
104
107
  - lib/mspec/runner/formatters/summary.rb
@@ -117,7 +120,12 @@ files:
117
120
  - lib/mspec.rb
118
121
  - spec/runner/filters/a.yaml
119
122
  - spec/runner/filters/b.yaml
123
+ - spec/commands/fixtures/four.txt
120
124
  - spec/runner/tags.txt
125
+ - spec/commands/fixtures/level2/three_spec.rb
126
+ - spec/commands/fixtures/one_spec.rb
127
+ - spec/commands/fixtures/three.rb
128
+ - spec/commands/fixtures/two_spec.rb
121
129
  - spec/commands/mkspec_spec.rb
122
130
  - spec/commands/mspec_ci_spec.rb
123
131
  - spec/commands/mspec_run_spec.rb
@@ -163,6 +171,7 @@ files:
163
171
  - spec/matchers/output_spec.rb
164
172
  - spec/matchers/output_to_fd_spec.rb
165
173
  - spec/matchers/raise_error_spec.rb
174
+ - spec/matchers/respond_to_spec.rb
166
175
  - spec/mocks/mock_spec.rb
167
176
  - spec/mocks/proxy_spec.rb
168
177
  - spec/runner/actions/debug_spec.rb
@@ -180,7 +189,9 @@ files:
180
189
  - spec/runner/filters/regexp_spec.rb
181
190
  - spec/runner/filters/tag_spec.rb
182
191
  - spec/runner/formatters/dotted_spec.rb
192
+ - spec/runner/formatters/file_spec.rb
183
193
  - spec/runner/formatters/html_spec.rb
194
+ - spec/runner/formatters/method_spec.rb
184
195
  - spec/runner/formatters/specdoc_spec.rb
185
196
  - spec/runner/formatters/spinner_spec.rb
186
197
  - spec/runner/formatters/summary_spec.rb
@@ -222,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
233
  requirements: []
223
234
 
224
235
  rubyforge_project: http://rubyforge.org/projects/mspec
225
- rubygems_version: 1.0.1
236
+ rubygems_version: 1.2.0
226
237
  signing_key:
227
238
  specification_version: 2
228
239
  summary: MSpec is a specialized framework that is syntax-compatible with RSpec for basic things like describe, it blocks and before, after actions. MSpec contains additional features that assist in writing the RubySpecs used by multiple Ruby implementations. Also, MSpec attempts to use the simplest Ruby language features so that beginning Ruby implementations can run it.