mspec 1.5.6 → 1.5.7

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{2008-12-29}
21
+ s.date = %q{2009-2-5}
22
22
  s.email = %q{bford@engineyard.com}
23
23
  s.has_rdoc = true
24
24
  s.extra_rdoc_files = %w[ README LICENSE ]
@@ -41,6 +41,9 @@ class MSpecCI < MSpecScript
41
41
  options.version MSpec::VERSION
42
42
  options.help
43
43
 
44
+ options.doc "\n Custom options"
45
+ custom_options options
46
+
44
47
  options.doc "\n How might this work in the real world?"
45
48
  options.doc "\n 1. To simply run the known good specs"
46
49
  options.doc "\n $ mspec ci"
@@ -53,6 +53,9 @@ class MSpecRun < MSpecScript
53
53
  options.version MSpec::VERSION
54
54
  options.help
55
55
 
56
+ options.doc "\n Custom options"
57
+ custom_options options
58
+
56
59
  options.doc "\n How might this work in the real world?"
57
60
  options.doc "\n 1. To simply run some specs"
58
61
  options.doc "\n $ mspec path/to/the/specs"
@@ -75,6 +75,9 @@ class MSpecTag < MSpecScript
75
75
  options.version MSpec::VERSION
76
76
  options.help
77
77
 
78
+ options.doc "\n Custom options"
79
+ custom_options options
80
+
78
81
  options.doc "\n How might this work in the real world?"
79
82
  options.doc "\n 1. To add the 'fails' tag to failing specs"
80
83
  options.doc "\n $ mspec tag path/to/the_file_spec.rb"
@@ -24,9 +24,9 @@ class MSpecMain < MSpecScript
24
24
 
25
25
  options = MSpecOptions.new "mspec [COMMAND] [options] (FILE|DIRECTORY|GLOB)+", 30, config
26
26
 
27
- options.doc " The mspec command sets up and invokes the sub-commands"
28
- options.doc " (see below) to enable, for instance, running the specs"
29
- options.doc " with different implementations like ruby, jruby, rbx, etc.\n"
27
+ options.doc " The mspec command sets up and invokes the sub-commands"
28
+ options.doc " (see below) to enable, for instance, running the specs"
29
+ options.doc " with different implementations like ruby, jruby, rbx, etc.\n"
30
30
 
31
31
  options.configure do |f|
32
32
  load f
@@ -66,12 +66,15 @@ class MSpecMain < MSpecScript
66
66
  end
67
67
  end
68
68
 
69
+ options.doc "\n Custom options"
70
+ custom_options options
71
+
69
72
  # The rest of the help output
70
- options.doc "\n where COMMAND is one of:\n"
71
- options.doc " run - Run the specified specs (default)"
72
- options.doc " ci - Run the known good specs"
73
- options.doc " tag - Add or remove tags\n"
74
- options.doc " mspec COMMAND -h for more options\n"
73
+ options.doc "\n where COMMAND is one of:\n"
74
+ options.doc " run - Run the specified specs (default)"
75
+ options.doc " ci - Run the known good specs"
76
+ options.doc " tag - Add or remove tags\n"
77
+ options.doc " mspec COMMAND -h for more options\n"
75
78
 
76
79
  options.on_extra { |o| config[:options] << o }
77
80
  config[:options].concat options.parse(argv)
@@ -11,6 +11,8 @@ require 'mspec/matchers/eql'
11
11
  require 'mspec/matchers/equal'
12
12
  require 'mspec/matchers/equal_element'
13
13
  require 'mspec/matchers/equal_utf16'
14
+ require 'mspec/matchers/have_instance_method'
15
+ require 'mspec/matchers/have_private_instance_method'
14
16
  require 'mspec/matchers/include'
15
17
  require 'mspec/matchers/match_yaml'
16
18
  require 'mspec/matchers/raise_error'
@@ -0,0 +1,30 @@
1
+ require 'mspec/utils/version'
2
+
3
+ class HaveInstanceMethodMatcher
4
+ def initialize(method, include_super=true)
5
+ @include_super = include_super
6
+ version = SpecVersion.new(RUBY_VERSION) <=> "1.9"
7
+ @method = version < 0 ? method.to_s : method
8
+ end
9
+
10
+ def matches?(mod)
11
+ @mod = mod
12
+ mod.instance_methods(@include_super).include? @method
13
+ end
14
+
15
+ def failure_message
16
+ ["Expected #{@mod} to have private method '#{@method.to_s}'",
17
+ "but it does not"]
18
+ end
19
+
20
+ def negative_failure_message
21
+ ["Expected #{@mod} NOT to have private method '#{@method.to_s}'",
22
+ "but it does"]
23
+ end
24
+ end
25
+
26
+ class Object
27
+ def have_instance_method(method, include_super=true)
28
+ HaveInstanceMethodMatcher.new method, include_super
29
+ end
30
+ end
@@ -0,0 +1,30 @@
1
+ require 'mspec/utils/version'
2
+
3
+ class HavePrivateInstanceMethodMatcher
4
+ def initialize(method, include_super=true)
5
+ @include_super = include_super
6
+ version = SpecVersion.new(RUBY_VERSION) <=> "1.9"
7
+ @method = version < 0 ? method.to_s : method
8
+ end
9
+
10
+ def matches?(mod)
11
+ @mod = mod
12
+ mod.private_instance_methods(@include_super).include? @method
13
+ end
14
+
15
+ def failure_message
16
+ ["Expected #{@mod} to have private method '#{@method.to_s}'",
17
+ "but it does not"]
18
+ end
19
+
20
+ def negative_failure_message
21
+ ["Expected #{@mod} NOT to have private method '#{@method.to_s}'",
22
+ "but it does"]
23
+ end
24
+ end
25
+
26
+ class Object
27
+ def have_private_instance_method(method, include_super=true)
28
+ HavePrivateInstanceMethodMatcher.new method, include_super
29
+ end
30
+ end
data/lib/mspec/runner.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'mspec/mocks'
2
2
  require 'mspec/runner/mspec'
3
+ require 'mspec/runner/context'
4
+ require 'mspec/runner/example'
3
5
  require 'mspec/runner/object'
4
6
  require 'mspec/runner/formatters'
5
7
  require 'mspec/runner/actions'
@@ -25,15 +25,32 @@ class Tally
25
25
  @errors += add
26
26
  end
27
27
 
28
+ def file
29
+ pluralize files, "file"
30
+ end
31
+
32
+ def example
33
+ pluralize examples, "example"
34
+ end
35
+
36
+ def expectation
37
+ pluralize expectations, "expectation"
38
+ end
39
+
40
+ def failure
41
+ pluralize failures, "failure"
42
+ end
43
+
44
+ def error
45
+ pluralize errors, "error"
46
+ end
47
+
28
48
  def format
29
- [ [@files, 'file'],
30
- [@examples, 'example'],
31
- [@expectations, 'expectation'],
32
- [@failures, 'failure'],
33
- [@errors, 'error']
34
- ].map { |count, word| pluralize count, word }.join(", ")
49
+ [ file, example, expectation, failure, error ].join(", ")
35
50
  end
36
51
 
52
+ alias_method :to_s, :format
53
+
37
54
  def pluralize(count, singular)
38
55
  "#{count} #{singular}#{'s' unless count == 1}"
39
56
  end
@@ -1,6 +1,3 @@
1
- require 'mspec/runner/mspec'
2
- require 'mspec/runner/example'
3
-
4
1
  # Holds the state of the +describe+ block that is being
5
2
  # evaluated. Every example (i.e. +it+ block) is evaluated
6
3
  # in a context, which may include state set up in <tt>before
@@ -1,3 +1,4 @@
1
+ require 'mspec/runner/formatters/describe'
1
2
  require 'mspec/runner/formatters/dotted'
2
3
  require 'mspec/runner/formatters/file'
3
4
  require 'mspec/runner/formatters/specdoc'
@@ -0,0 +1,24 @@
1
+ require 'mspec/runner/formatters/dotted'
2
+ require 'mspec/runner/actions/tally'
3
+
4
+ class DescribeFormatter < DottedFormatter
5
+ # Callback for the MSpec :finish event. Prints a summary of
6
+ # the number of errors and failures for each +describe+ block.
7
+ def finish
8
+ describes = Hash.new { |h,k| h[k] = Tally.new }
9
+
10
+ @exceptions.each do |exc|
11
+ desc = describes[exc.describe]
12
+ exc.failure? ? desc.failures! : desc.errors!
13
+ end
14
+
15
+ print "\n"
16
+ describes.each do |d, t|
17
+ text = d.size > 40 ? "#{d[0,37]}..." : d.ljust(40)
18
+ print "\n#{text} #{t.failure}, #{t.error}"
19
+ end
20
+ print "\n" unless describes.empty?
21
+
22
+ print "\n#{@timer.format}\n\n#{@tally.format}\n"
23
+ end
24
+ end
@@ -293,7 +293,7 @@ module MSpec
293
293
  # file if it is empty.
294
294
  def self.delete_tag(tag)
295
295
  deleted = false
296
- pattern = /#{tag.tag}.*#{Regexp.escape tag.description}/
296
+ pattern = /#{tag.tag}.*#{Regexp.escape(tag.escape(tag.description))}/
297
297
  file = tags_file
298
298
  if File.exist? file
299
299
  lines = IO.readlines(file)
@@ -6,12 +6,24 @@ class SpecTag
6
6
  end
7
7
 
8
8
  def parse(string)
9
- m = /^([^()#:]+)(\(([^)]+)?\))?:(.*)/.match string
10
- @tag, @comment, @description = m.values_at(1, 3, 4) if m
9
+ m = /^([^()#:]+)(\(([^)]+)?\))?:(.*)$/.match string
10
+ @tag, @comment, description = m.values_at(1, 3, 4) if m
11
+ @description = unescape description
12
+ end
13
+
14
+ def unescape(str)
15
+ return unless str
16
+ str = str[1..-2] if str[0] == ?" and str[-1] == ?"
17
+ str.gsub(/\\n/, "\n")
18
+ end
19
+
20
+ def escape(str)
21
+ str = %["#{str.gsub(/\n/, '\n')}"] if /\n/ =~ str
22
+ str
11
23
  end
12
24
 
13
25
  def to_s
14
- "#{@tag}#{ "(#{@comment})" if @comment }:#{@description}"
26
+ "#{@tag}#{ "(#{@comment})" if @comment }:#{escape @description}"
15
27
  end
16
28
 
17
29
  def ==(o)
@@ -210,7 +210,7 @@ class MSpecOptions
210
210
  when 'r', 'ruby'
211
211
  config[:target] = 'ruby'
212
212
  when 'r19', 'ruby19'
213
- config[:target] = 'ruby19'
213
+ config[:target] = 'ruby1.9'
214
214
  when 'x', 'rubinius'
215
215
  config[:target] = './bin/rbx'
216
216
  when 'X', 'rbx'
@@ -225,12 +225,12 @@ class MSpecOptions
225
225
  end
226
226
 
227
227
  doc ""
228
- doc " r or ruby invokes ruby in PATH"
229
- doc " r19 or ruby19 invokes ruby19 in PATH"
230
- doc " x or rubinius invokes ./bin/rbx"
231
- doc " X or rbx invokes rbx in PATH"
232
- doc " j or jruby invokes jruby in PATH"
233
- doc " i or ironruby invokes ir in PATH\n"
228
+ doc " r or ruby invokes ruby in PATH"
229
+ doc " r19, ruby19 or ruby1.9 invokes ruby1.9 in PATH"
230
+ doc " x or rubinius invokes ./bin/rbx"
231
+ doc " X or rbx invokes rbx in PATH"
232
+ doc " j or jruby invokes jruby in PATH"
233
+ doc " i or ironruby invokes ir in PATH\n"
234
234
 
235
235
  on("-T", "--target-opt", "OPT",
236
236
  "Pass OPT as a flag to the target implementation") do |t|
@@ -256,6 +256,8 @@ class MSpecOptions
256
256
  config[:formatter] = HtmlFormatter
257
257
  when 'd', 'dot', 'dotted'
258
258
  config[:formatter] = DottedFormatter
259
+ when 'b', 'describe'
260
+ config[:formatter] = DescribeFormatter
259
261
  when 'f', 'file'
260
262
  config[:formatter] = FileFormatter
261
263
  when 'u', 'unit', 'unitdiff'
@@ -96,12 +96,24 @@ class MSpecScript
96
96
  load "#{engine}.#{SpecGuard.ruby_version}.mspec"
97
97
  end
98
98
 
99
+ # Callback for enabling custom options. This version is a no-op.
100
+ # Provide an implementation specific version in a config file.
101
+ # Called by #options after the MSpec-provided options are added.
102
+ def custom_options(options)
103
+ options.doc " No custom options registered"
104
+ end
105
+
99
106
  # Registers all filters and actions.
100
107
  def register
101
108
  if config[:formatter].nil?
102
109
  config[:formatter] = @files.size < 50 ? DottedFormatter : FileFormatter
103
110
  end
104
- config[:formatter].new(config[:output]).register if config[:formatter]
111
+
112
+ if config[:formatter]
113
+ formatter = config[:formatter].new(config[:output])
114
+ formatter.register
115
+ MSpec.store :formatter, formatter
116
+ end
105
117
 
106
118
  MatchFilter.new(:include, *config[:includes]).register unless config[:includes].empty?
107
119
  MatchFilter.new(:exclude, *config[:excludes]).register unless config[:excludes].empty?
@@ -114,6 +126,14 @@ class MSpecScript
114
126
 
115
127
  DebugAction.new(config[:atags], config[:astrings]).register if config[:debugger]
116
128
  GdbAction.new(config[:atags], config[:astrings]).register if config[:gdb]
129
+
130
+ custom_register
131
+ end
132
+
133
+ # Callback for enabling custom actions, etc. This version is a
134
+ # no-op. Provide an implementation specific version in a config
135
+ # file. Called by #register.
136
+ def custom_register
117
137
  end
118
138
 
119
139
  # Sets up signal handlers. Only a handler for SIGINT is
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.6"
4
+ VERSION = SpecVersion.new "1.5.7"
5
5
  end
@@ -87,6 +87,11 @@ describe MSpecCI, "#options" do
87
87
  @options.should_receive(:help)
88
88
  @script.options
89
89
  end
90
+
91
+ it "calls #custom_options" do
92
+ @script.should_receive(:custom_options).with(@options)
93
+ @script.options
94
+ end
90
95
  end
91
96
 
92
97
  describe MSpecCI, "#run" do
@@ -124,6 +124,11 @@ describe MSpecRun, "#options" do
124
124
  @script.options
125
125
  $stdout.should =~ /No files specified/
126
126
  end
127
+
128
+ it "calls #custom_options" do
129
+ @script.should_receive(:custom_options).with(@options)
130
+ @script.options @argv
131
+ end
127
132
  end
128
133
 
129
134
  describe MSpecRun, "#run" do
@@ -37,6 +37,11 @@ describe MSpecMain, "#options" do
37
37
  @script.options [".", "-G", "fail", "-X", "ARG", "--list", "unstable", "some/file.rb"]
38
38
  @config[:options].should == [".", "-G", "fail", "--list", "unstable", "some/file.rb"]
39
39
  end
40
+
41
+ it "calls #custom_options" do
42
+ @script.should_receive(:custom_options).with(@options)
43
+ @script.options
44
+ end
40
45
  end
41
46
 
42
47
  describe MSpecMain, "#parallel" do
@@ -98,6 +98,11 @@ describe MSpecTag, "#options" do
98
98
  @script.options @argv
99
99
  end
100
100
 
101
+ it "calls #custom_options" do
102
+ @script.should_receive(:custom_options).with(@options)
103
+ @script.options @argv
104
+ end
105
+
101
106
  it "exits if there are no files to process" do
102
107
  @options.should_receive(:parse).and_return([])
103
108
  @script.should_receive(:exit)
@@ -110,7 +110,7 @@ describe Object, "#should_not" do
110
110
  end
111
111
 
112
112
  it "returns a NegativeOperatorMatcher instance when not passed a matcher" do
113
- matcher = should_not
113
+ matcher = should_not nil
114
114
  class Object; alias_method :should, :rspec_should; end
115
115
  matcher.should be_instance_of(NegativeOperatorMatcher)
116
116
  end
@@ -1,4 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'mspec/utils/ruby_name'
2
3
  require 'mspec/guards/bug'
3
4
 
4
5
  describe BugGuard, "#match? when #implementation? is 'ruby'" do
@@ -0,0 +1,82 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'mspec/expectations/expectations'
3
+ require 'mspec/matchers/have_instance_method'
4
+
5
+ class HIMMSpecs
6
+ def instance_method
7
+ end
8
+
9
+ class Subclass < HIMMSpecs
10
+ def instance_sub_method
11
+ end
12
+ end
13
+ end
14
+
15
+ describe HaveInstanceMethodMatcher do
16
+ it "matches when mod has the private instance method" do
17
+ matcher = HaveInstanceMethodMatcher.new :instance_method
18
+ matcher.matches?(HIMMSpecs).should be_true
19
+ matcher.matches?(HIMMSpecs::Subclass).should be_true
20
+ end
21
+
22
+ it "does not match when mod does not have the private instance method" do
23
+ matcher = HaveInstanceMethodMatcher.new :another_method
24
+ matcher.matches?(HIMMSpecs).should be_false
25
+ end
26
+
27
+ it "does not match if the method is in a superclass and include_super is false" do
28
+ matcher = HaveInstanceMethodMatcher.new :instance_method, false
29
+ matcher.matches?(HIMMSpecs::Subclass).should be_false
30
+ end
31
+
32
+ it "provides a failure message for #should" do
33
+ matcher = HaveInstanceMethodMatcher.new :some_method
34
+ matcher.matches?(HIMMSpecs)
35
+ matcher.failure_message.should == [
36
+ "Expected HIMMSpecs to have private method 'some_method'",
37
+ "but it does not"
38
+ ]
39
+ end
40
+
41
+ it "provides a failure messoge for #should_not" do
42
+ matcher = HaveInstanceMethodMatcher.new :some_method
43
+ matcher.matches?(HIMMSpecs)
44
+ matcher.negative_failure_message.should == [
45
+ "Expected HIMMSpecs NOT to have private method 'some_method'",
46
+ "but it does"
47
+ ]
48
+ end
49
+ end
50
+
51
+ describe HaveInstanceMethodMatcher do
52
+ before :all do
53
+ @verbose = $VERBOSE
54
+ $VERBOSE = nil
55
+ end
56
+
57
+ after :all do
58
+ $VERBOSE = @verbose
59
+ end
60
+
61
+ before :each do
62
+ @ruby_version = Object.const_get :RUBY_VERSION
63
+
64
+ @method = mock("method name")
65
+ end
66
+
67
+ after :each do
68
+ Object.const_set :RUBY_VERSION, @ruby_version
69
+ end
70
+
71
+ it "converts the method name to a string if RUBY_VERSION < 1.9" do
72
+ Object.const_set :RUBY_VERSION, "1.8.6"
73
+ @method.should_receive(:to_s).and_return("method_name")
74
+ HaveInstanceMethodMatcher.new @method
75
+ end
76
+
77
+ it "does not convert the method name to a string if RUBY_VERSION >= 1.9" do
78
+ Object.const_set :RUBY_VERSION, "1.9.0"
79
+ @method.should_not_receive(:to_s)
80
+ HaveInstanceMethodMatcher.new @method
81
+ end
82
+ end
@@ -0,0 +1,86 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+ require 'mspec/expectations/expectations'
3
+ require 'mspec/matchers/have_private_instance_method'
4
+
5
+ class HPIMMSpecs
6
+ private
7
+
8
+ def private_method
9
+ end
10
+
11
+ class Subclass < HPIMMSpecs
12
+ private
13
+
14
+ def private_sub_method
15
+ end
16
+ end
17
+ end
18
+
19
+ describe HavePrivateInstanceMethodMatcher do
20
+ it "matches when mod has the private instance method" do
21
+ matcher = HavePrivateInstanceMethodMatcher.new :private_method
22
+ matcher.matches?(HPIMMSpecs).should be_true
23
+ matcher.matches?(HPIMMSpecs::Subclass).should be_true
24
+ end
25
+
26
+ it "does not match when mod does not have the private instance method" do
27
+ matcher = HavePrivateInstanceMethodMatcher.new :another_method
28
+ matcher.matches?(HPIMMSpecs).should be_false
29
+ end
30
+
31
+ it "does not match if the method is in a superclass and include_super is false" do
32
+ matcher = HavePrivateInstanceMethodMatcher.new :private_method, false
33
+ matcher.matches?(HPIMMSpecs::Subclass).should be_false
34
+ end
35
+
36
+ it "provides a failure message for #should" do
37
+ matcher = HavePrivateInstanceMethodMatcher.new :some_method
38
+ matcher.matches?(HPIMMSpecs)
39
+ matcher.failure_message.should == [
40
+ "Expected HPIMMSpecs to have private method 'some_method'",
41
+ "but it does not"
42
+ ]
43
+ end
44
+
45
+ it "provides a failure messoge for #should_not" do
46
+ matcher = HavePrivateInstanceMethodMatcher.new :some_method
47
+ matcher.matches?(HPIMMSpecs)
48
+ matcher.negative_failure_message.should == [
49
+ "Expected HPIMMSpecs NOT to have private method 'some_method'",
50
+ "but it does"
51
+ ]
52
+ end
53
+ end
54
+
55
+ describe HavePrivateInstanceMethodMatcher do
56
+ before :all do
57
+ @verbose = $VERBOSE
58
+ $VERBOSE = nil
59
+ end
60
+
61
+ after :all do
62
+ $VERBOSE = @verbose
63
+ end
64
+
65
+ before :each do
66
+ @ruby_version = Object.const_get :RUBY_VERSION
67
+
68
+ @method = mock("method name")
69
+ end
70
+
71
+ after :each do
72
+ Object.const_set :RUBY_VERSION, @ruby_version
73
+ end
74
+
75
+ it "converts the method name to a string if RUBY_VERSION < 1.9" do
76
+ Object.const_set :RUBY_VERSION, "1.8.6"
77
+ @method.should_receive(:to_s).and_return("method_name")
78
+ HavePrivateInstanceMethodMatcher.new @method
79
+ end
80
+
81
+ it "does not convert the method name to a string if RUBY_VERSION >= 1.9" do
82
+ Object.const_set :RUBY_VERSION, "1.9.0"
83
+ @method.should_not_receive(:to_s)
84
+ HavePrivateInstanceMethodMatcher.new @method
85
+ end
86
+ end
@@ -4,47 +4,147 @@ require 'mspec/runner/actions/tally'
4
4
  require 'mspec/runner/mspec'
5
5
  require 'mspec/runner/example'
6
6
 
7
- describe Tally do
7
+ describe Tally, "#files!" do
8
8
  before :each do
9
9
  @tally = Tally.new
10
10
  end
11
11
 
12
- it "responds to #files! by incrementing the count returned by #files" do
12
+ it "increments the count returned by #files" do
13
13
  @tally.files! 3
14
14
  @tally.files.should == 3
15
15
  @tally.files!
16
16
  @tally.files.should == 4
17
17
  end
18
+ end
19
+
20
+ describe Tally, "#examples!" do
21
+ before :each do
22
+ @tally = Tally.new
23
+ end
18
24
 
19
- it "responds to #examples! by incrementing the count returned by #examples" do
25
+ it "increments the count returned by #examples" do
20
26
  @tally.examples! 2
21
27
  @tally.examples.should == 2
22
28
  @tally.examples! 2
23
29
  @tally.examples.should == 4
24
30
  end
31
+ end
25
32
 
26
- it "responds to #expectations! by incrementing the count returned by #expectations" do
33
+ describe Tally, "#expectations!" do
34
+ before :each do
35
+ @tally = Tally.new
36
+ end
37
+
38
+ it "increments the count returned by #expectations" do
27
39
  @tally.expectations!
28
40
  @tally.expectations.should == 1
29
41
  @tally.expectations! 3
30
42
  @tally.expectations.should == 4
31
43
  end
44
+ end
45
+
46
+ describe Tally, "#failures!" do
47
+ before :each do
48
+ @tally = Tally.new
49
+ end
32
50
 
33
- it "responds to #failures! by incrementing the count returned by #failures" do
51
+ it "increments the count returned by #failures" do
34
52
  @tally.failures! 1
35
53
  @tally.failures.should == 1
36
54
  @tally.failures!
37
55
  @tally.failures.should == 2
38
56
  end
57
+ end
39
58
 
40
- it "responds to #errors! by incrementing the count returned by #errors" do
59
+ describe Tally, "#errors!" do
60
+ before :each do
61
+ @tally = Tally.new
62
+ end
63
+
64
+ it "increments the count returned by #errors" do
41
65
  @tally.errors!
42
66
  @tally.errors.should == 1
43
67
  @tally.errors! 2
44
68
  @tally.errors.should == 3
45
69
  end
70
+ end
71
+
72
+ describe Tally, "#file" do
73
+ before :each do
74
+ @tally = Tally.new
75
+ end
76
+
77
+ it "returns a formatted string of the number of #files" do
78
+ @tally.file.should == "0 files"
79
+ @tally.files!
80
+ @tally.file.should == "1 file"
81
+ @tally.files!
82
+ @tally.file.should == "2 files"
83
+ end
84
+ end
85
+
86
+ describe Tally, "#example" do
87
+ before :each do
88
+ @tally = Tally.new
89
+ end
90
+
91
+ it "returns a formatted string of the number of #examples" do
92
+ @tally.example.should == "0 examples"
93
+ @tally.examples!
94
+ @tally.example.should == "1 example"
95
+ @tally.examples!
96
+ @tally.example.should == "2 examples"
97
+ end
98
+ end
99
+
100
+ describe Tally, "#expectation" do
101
+ before :each do
102
+ @tally = Tally.new
103
+ end
104
+
105
+ it "returns a formatted string of the number of #expectations" do
106
+ @tally.expectation.should == "0 expectations"
107
+ @tally.expectations!
108
+ @tally.expectation.should == "1 expectation"
109
+ @tally.expectations!
110
+ @tally.expectation.should == "2 expectations"
111
+ end
112
+ end
113
+
114
+ describe Tally, "#failure" do
115
+ before :each do
116
+ @tally = Tally.new
117
+ end
118
+
119
+ it "returns a formatted string of the number of #failures" do
120
+ @tally.failure.should == "0 failures"
121
+ @tally.failures!
122
+ @tally.failure.should == "1 failure"
123
+ @tally.failures!
124
+ @tally.failure.should == "2 failures"
125
+ end
126
+ end
127
+
128
+ describe Tally, "#error" do
129
+ before :each do
130
+ @tally = Tally.new
131
+ end
132
+
133
+ it "returns a formatted string of the number of #errors" do
134
+ @tally.error.should == "0 errors"
135
+ @tally.errors!
136
+ @tally.error.should == "1 error"
137
+ @tally.errors!
138
+ @tally.error.should == "2 errors"
139
+ end
140
+ end
46
141
 
47
- it "responds to #format by returning a formatted string of counts" do
142
+ describe Tally, "#format" do
143
+ before :each do
144
+ @tally = Tally.new
145
+ end
146
+
147
+ it "returns a formatted string of counts" do
48
148
  @tally.files!
49
149
  @tally.examples! 2
50
150
  @tally.expectations! 4
@@ -53,35 +153,63 @@ describe Tally do
53
153
  end
54
154
  end
55
155
 
56
- describe TallyAction do
156
+ describe TallyAction, "#counter" do
57
157
  before :each do
58
158
  @tally = TallyAction.new
59
159
  @state = ExampleState.new("describe", "it")
60
160
  end
61
161
 
62
- it "responds to #counter by returning the Tally object" do
162
+ it "returns the Tally object" do
63
163
  @tally.counter.should be_kind_of(Tally)
64
164
  end
165
+ end
65
166
 
66
- it "responds to #load by incrementing the count returned by Tally#files" do
167
+ describe TallyAction, "#load" do
168
+ before :each do
169
+ @tally = TallyAction.new
170
+ @state = ExampleState.new("describe", "it")
171
+ end
172
+
173
+ it "increments the count returned by Tally#files" do
67
174
  @tally.load
68
175
  @tally.counter.files.should == 1
69
176
  end
177
+ end
178
+
179
+ describe TallyAction, "#expectation" do
180
+ before :each do
181
+ @tally = TallyAction.new
182
+ @state = ExampleState.new("describe", "it")
183
+ end
70
184
 
71
- it "responds to #expectation by incrementing the count returned by Tally#expectations" do
185
+ it "increments the count returned by Tally#expectations" do
72
186
  @tally.expectation @state
73
187
  @tally.counter.expectations.should == 1
74
188
  end
189
+ end
75
190
 
76
- it "responds to #example by incrementing counts returned by Tally#examples" do
191
+ describe TallyAction, "#example" do
192
+ before :each do
193
+ @tally = TallyAction.new
194
+ @state = ExampleState.new("describe", "it")
195
+ end
196
+
197
+ it "increments counts returned by Tally#examples" do
77
198
  @tally.example @state, nil
78
199
  @tally.counter.examples.should == 1
79
200
  @tally.counter.expectations.should == 0
80
201
  @tally.counter.failures.should == 0
81
202
  @tally.counter.errors.should == 0
82
203
  end
204
+ end
205
+
206
+ describe TallyAction, "#exception" do
207
+ before :each do
208
+ @tally = TallyAction.new
209
+ @state = ExampleState.new("describe", "it")
210
+ end
83
211
 
84
- it "responds to #exception by incrementing counts returned by Tally#failures" do
212
+ it "increments counts returned by Tally#failures" do
85
213
  exc = ExceptionState.new nil, nil, ExpectationNotMetError.new("Failed!")
86
214
  @tally.exception exc
87
215
  @tally.counter.examples.should == 0
@@ -89,8 +217,15 @@ describe TallyAction do
89
217
  @tally.counter.failures.should == 1
90
218
  @tally.counter.errors.should == 0
91
219
  end
220
+ end
92
221
 
93
- it "responds to #exception by incrementing counts returned by Tally#errors" do
222
+ describe TallyAction, "#exception" do
223
+ before :each do
224
+ @tally = TallyAction.new
225
+ @state = ExampleState.new("describe", "it")
226
+ end
227
+
228
+ it "increments counts returned by Tally#errors" do
94
229
  exc = ExceptionState.new nil, nil, Exception.new("Error!")
95
230
  @tally.exception exc
96
231
  @tally.counter.examples.should == 0
@@ -98,8 +233,15 @@ describe TallyAction do
98
233
  @tally.counter.failures.should == 0
99
234
  @tally.counter.errors.should == 1
100
235
  end
236
+ end
101
237
 
102
- it "responds to #format by returning a readable string of counts" do
238
+ describe TallyAction, "#format" do
239
+ before :each do
240
+ @tally = TallyAction.new
241
+ @state = ExampleState.new("describe", "it")
242
+ end
243
+
244
+ it "returns a readable string of counts" do
103
245
  @tally.load
104
246
  @tally.example @state, nil
105
247
  @tally.expectation @state
@@ -108,16 +250,30 @@ describe TallyAction do
108
250
  @tally.exception exc
109
251
  @tally.format.should == "1 file, 1 example, 2 expectations, 1 failure, 0 errors"
110
252
  end
253
+ end
254
+
255
+ describe TallyAction, "#register" do
256
+ before :each do
257
+ @tally = TallyAction.new
258
+ @state = ExampleState.new("describe", "it")
259
+ end
111
260
 
112
- it "responds to #register by registering itself with MSpec for appropriate actions" do
261
+ it "registers itself with MSpec for appropriate actions" do
113
262
  MSpec.should_receive(:register).with(:load, @tally)
114
263
  MSpec.should_receive(:register).with(:example, @tally)
115
264
  MSpec.should_receive(:register).with(:exception, @tally)
116
265
  MSpec.should_receive(:register).with(:expectation, @tally)
117
266
  @tally.register
118
267
  end
268
+ end
269
+
270
+ describe TallyAction, "#unregister" do
271
+ before :each do
272
+ @tally = TallyAction.new
273
+ @state = ExampleState.new("describe", "it")
274
+ end
119
275
 
120
- it "responds to #unregister by unregistering itself with MSpec for appropriate actions" do
276
+ it "unregisters itself with MSpec for appropriate actions" do
121
277
  MSpec.should_receive(:unregister).with(:load, @tally)
122
278
  MSpec.should_receive(:unregister).with(:exception, @tally)
123
279
  MSpec.should_receive(:unregister).with(:example, @tally)
@@ -4,6 +4,7 @@ require 'mspec/matchers/base'
4
4
  require 'mspec/runner/mspec'
5
5
  require 'mspec/mocks/mock'
6
6
  require 'mspec/runner/context'
7
+ require 'mspec/runner/example'
7
8
 
8
9
  describe ContextState, "#describe" do
9
10
  before :each do
@@ -0,0 +1,67 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+ require 'mspec/runner/formatters/describe'
3
+ require 'mspec/runner/example'
4
+
5
+ describe DescribeFormatter, "#finish" do
6
+ before :each do
7
+ MSpec.stub!(:register)
8
+ MSpec.stub!(:unregister)
9
+
10
+ @timer = mock("timer", :null_object => true)
11
+ TimerAction.stub!(:new).and_return(@timer)
12
+ @timer.stub!(:format).and_return("Finished in 2.0 seconds")
13
+
14
+ $stdout = @out = IOStub.new
15
+ context = ContextState.new "Class#method"
16
+ @state = ExampleState.new(context, "runs")
17
+
18
+ @formatter = DescribeFormatter.new
19
+ @formatter.register
20
+
21
+ @tally = @formatter.tally
22
+ @counter = @tally.counter
23
+
24
+ @counter.files!
25
+ @counter.examples!
26
+ @counter.expectations! 2
27
+ end
28
+
29
+ after :each do
30
+ $stdout = STDOUT
31
+ end
32
+
33
+ it "prints a summary of elapsed time" do
34
+ @formatter.finish
35
+ @out.should =~ /^Finished in 2.0 seconds$/
36
+ end
37
+
38
+ it "prints a tally of counts" do
39
+ @formatter.finish
40
+ @out.should =~ /^1 file, 1 example, 2 expectations, 0 failures, 0 errors$/
41
+ end
42
+
43
+ it "does not print exceptions" do
44
+ @formatter.finish
45
+ @out.should == %[
46
+
47
+ Finished in 2.0 seconds
48
+
49
+ 1 file, 1 example, 2 expectations, 0 failures, 0 errors
50
+ ]
51
+ end
52
+
53
+ it "prints a summary of failures and errors for each describe block" do
54
+ exc = ExceptionState.new @state, nil, MSpecExampleError.new("broken")
55
+ exc.stub!(:backtrace).and_return("path/to/some/file.rb:35:in method")
56
+ @formatter.exception exc
57
+ @formatter.finish
58
+ @out.should == %[
59
+
60
+ Class#method 0 failures, 1 error
61
+
62
+ Finished in 2.0 seconds
63
+
64
+ 1 file, 1 example, 2 expectations, 0 failures, 0 errors
65
+ ]
66
+ end
67
+ end
@@ -2,6 +2,7 @@ require File.dirname(__FILE__) + '/../spec_helper'
2
2
  require 'mspec/helpers/tmp'
3
3
  require 'mspec/matchers/base'
4
4
  require 'mspec/runner/mspec'
5
+ require 'mspec/runner/example'
5
6
 
6
7
  describe MSpec, ".register_files" do
7
8
  it "records which spec files to run" do
@@ -415,6 +416,7 @@ describe MSpec, ".write_tags" do
415
416
  IO.read(tmp("tags.txt")).should == %[fail(broken):Some#method? works
416
417
  incomplete(20%):The#best method ever
417
418
  benchmark(0.01825):The#fastest method today
419
+ extended():\"Multi-line\\ntext\\ntag\"
418
420
  ]
419
421
  MSpec.write_tags [@tag1, @tag2]
420
422
  IO.read(tmp("tags.txt")).should == %[check(broken):Tag#rewrite works
@@ -461,6 +463,15 @@ describe MSpec, ".delete_tag" do
461
463
  MSpec.delete_tag(@tag).should == true
462
464
  IO.read(tmp("tags.txt")).should == %[incomplete(20%):The#best method ever
463
465
  benchmark(0.01825):The#fastest method today
466
+ extended():\"Multi-line\\ntext\\ntag\"
467
+ ]
468
+ end
469
+
470
+ it "deletes a tag with escaped newlines" do
471
+ MSpec.delete_tag(SpecTag.new('extended:"Multi-line\ntext\ntag"')).should == true
472
+ IO.read(tmp("tags.txt")).should == %[fail(broken):Some#method? works
473
+ incomplete(20%):The#best method ever
474
+ benchmark(0.01825):The#fastest method today
464
475
  ]
465
476
  end
466
477
 
@@ -470,6 +481,7 @@ benchmark(0.01825):The#fastest method today
470
481
  IO.read(tmp("tags.txt")).should == %[fail(broken):Some#method? works
471
482
  incomplete(20%):The#best method ever
472
483
  benchmark(0.01825):The#fastest method today
484
+ extended():\"Multi-line\\ntext\\ntag\"
473
485
  ]
474
486
  end
475
487
 
@@ -477,6 +489,7 @@ benchmark(0.01825):The#fastest method today
477
489
  MSpec.delete_tag(@tag).should == true
478
490
  MSpec.delete_tag(SpecTag.new("incomplete:The#best method ever")).should == true
479
491
  MSpec.delete_tag(SpecTag.new("benchmark:The#fastest method today")).should == true
492
+ MSpec.delete_tag(SpecTag.new("extended:\"Multi-line\ntext\ntag\"")).should == true
480
493
  File.exist?(tmp("tags.txt")).should == false
481
494
  end
482
495
  end
@@ -57,6 +57,13 @@ describe SpecTag, "#parse" do
57
57
  @tag.description.should == "Another#method"
58
58
  end
59
59
 
60
+ it "accepts 'tag(comment):\"Multi-line\\ntext\"'" do
61
+ @tag.parse 'tag(comment):"Multi-line\ntext"'
62
+ @tag.tag.should == "tag"
63
+ @tag.comment.should == "comment"
64
+ @tag.description.should == "Multi-line\ntext"
65
+ end
66
+
60
67
  it "ignores '#anything'" do
61
68
  @tag.parse "# this could be a comment"
62
69
  @tag.tag.should == nil
@@ -67,19 +74,30 @@ end
67
74
 
68
75
  describe SpecTag, "#to_s" do
69
76
  it "formats itself as 'tag(comment):description'" do
70
- tag = SpecTag.new("tag(comment):description")
77
+ txt = "tag(comment):description"
78
+ tag = SpecTag.new txt
71
79
  tag.tag.should == "tag"
72
80
  tag.comment.should == "comment"
73
81
  tag.description.should == "description"
74
- tag.to_s.should == "tag(comment):description"
82
+ tag.to_s.should == txt
75
83
  end
76
84
 
77
85
  it "formats itself as 'tag:description" do
78
- tag = SpecTag.new("tag:description")
86
+ txt = "tag:description"
87
+ tag = SpecTag.new txt
79
88
  tag.tag.should == "tag"
80
89
  tag.comment.should == nil
81
90
  tag.description.should == "description"
82
- tag.to_s.should == "tag:description"
91
+ tag.to_s.should == txt
92
+ end
93
+
94
+ it "formats itself as 'tag(comment):\"multi-line\\ntext\\ntag\"'" do
95
+ txt = 'tag(comment):"multi-line\ntext\ntag"'
96
+ tag = SpecTag.new txt
97
+ tag.tag.should == "tag"
98
+ tag.comment.should == "comment"
99
+ tag.description.should == "multi-line\ntext\ntag"
100
+ tag.to_s.should == txt
83
101
  end
84
102
  end
85
103
 
data/spec/runner/tags.txt CHANGED
@@ -1,3 +1,4 @@
1
1
  fail(broken):Some#method? works
2
2
  incomplete(20%):The#best method ever
3
3
  benchmark(0.01825):The#fastest method today
4
+ extended():"Multi-line\ntext\ntag"
@@ -549,11 +549,11 @@ describe "The -t, --target TARGET option" do
549
549
  end
550
550
  end
551
551
 
552
- it "sets the target to 'ruby19' with TARGET 'r19' or 'ruby19'" do
552
+ it "sets the target to 'ruby1.9' with TARGET 'r19', 'ruby19' or 'ruby1.9'" do
553
553
  ["-t", "--target"].each do |opt|
554
- ["r19", "ruby19"].each do |t|
554
+ ["r19", "ruby19", "ruby1.9"].each do |t|
555
555
  @options.parse [opt, t]
556
- @config[:target].should == "ruby19"
556
+ @config[:target].should == "ruby1.9"
557
557
  end
558
558
  end
559
559
  end
@@ -702,6 +702,16 @@ describe "The -f, --format FORMAT option" do
702
702
  end
703
703
  end
704
704
 
705
+ it "sets the DescribeFormatter with FORMAT 'b' or 'describe'" do
706
+ ["-f", "--format"].each do |opt|
707
+ ["b", "describe"].each do |f|
708
+ @config[:formatter] = nil
709
+ @options.parse [opt, f]
710
+ @config[:formatter].should == DescribeFormatter
711
+ end
712
+ end
713
+ end
714
+
705
715
  it "sets the FileFormatter with FORMAT 'f', 'file'" do
706
716
  ["-f", "--format"].each do |opt|
707
717
  ["f", "file"].each do |f|
@@ -193,6 +193,21 @@ describe MSpecScript, "#load" do
193
193
  end
194
194
  end
195
195
 
196
+ describe MSpecScript, "#custom_options" do
197
+ before :each do
198
+ @script = MSpecScript.new
199
+ end
200
+
201
+ after :each do
202
+ end
203
+
204
+ it "prints 'None'" do
205
+ options = mock("options")
206
+ options.should_receive(:doc).with(" No custom options registered")
207
+ @script.custom_options options
208
+ end
209
+ end
210
+
196
211
  describe MSpecScript, "#register" do
197
212
  before :each do
198
213
  @script = MSpecScript.new
@@ -211,6 +226,23 @@ describe MSpecScript, "#register" do
211
226
  @script.config[:formatter] = false
212
227
  @script.register
213
228
  end
229
+
230
+ it "calls #custom_register" do
231
+ @script.should_receive(:custom_register)
232
+ @script.register
233
+ end
234
+
235
+ it "registers :formatter with the formatter instance" do
236
+ @formatter.stub!(:new).and_return(@formatter)
237
+ MSpec.should_receive(:store).with(:formatter, @formatter)
238
+ @script.register
239
+ end
240
+
241
+ it "does not register :formatter if config[:formatter] is false" do
242
+ @script.config[:formatter] = false
243
+ MSpec.should_not_receive(:store)
244
+ @script.register
245
+ end
214
246
  end
215
247
 
216
248
  describe MSpecScript, "#register" do
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.6
4
+ version: 1.5.7
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-12-29 00:00:00 -08:00
12
+ date: 2009-02-05 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -76,6 +76,8 @@ files:
76
76
  - lib/mspec/matchers/equal.rb
77
77
  - lib/mspec/matchers/equal_element.rb
78
78
  - lib/mspec/matchers/equal_utf16.rb
79
+ - lib/mspec/matchers/have_instance_method.rb
80
+ - lib/mspec/matchers/have_private_instance_method.rb
79
81
  - lib/mspec/matchers/include.rb
80
82
  - lib/mspec/matchers/match_yaml.rb
81
83
  - lib/mspec/matchers/output.rb
@@ -104,6 +106,7 @@ files:
104
106
  - lib/mspec/runner/filters/regexp.rb
105
107
  - lib/mspec/runner/filters/tag.rb
106
108
  - lib/mspec/runner/filters.rb
109
+ - lib/mspec/runner/formatters/describe.rb
107
110
  - lib/mspec/runner/formatters/dotted.rb
108
111
  - lib/mspec/runner/formatters/file.rb
109
112
  - lib/mspec/runner/formatters/html.rb
@@ -180,6 +183,8 @@ files:
180
183
  - spec/matchers/equal_element_spec.rb
181
184
  - spec/matchers/equal_spec.rb
182
185
  - spec/matchers/equal_utf16_spec.rb
186
+ - spec/matchers/have_instance_method_spec.rb
187
+ - spec/matchers/have_private_instance_method_spec.rb
183
188
  - spec/matchers/include_spec.rb
184
189
  - spec/matchers/match_yaml_spec.rb
185
190
  - spec/matchers/output_spec.rb
@@ -203,6 +208,7 @@ files:
203
208
  - spec/runner/filters/profile_spec.rb
204
209
  - spec/runner/filters/regexp_spec.rb
205
210
  - spec/runner/filters/tag_spec.rb
211
+ - spec/runner/formatters/describe_spec.rb
206
212
  - spec/runner/formatters/dotted_spec.rb
207
213
  - spec/runner/formatters/file_spec.rb
208
214
  - spec/runner/formatters/html_spec.rb