mspec 1.0.0

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.
Files changed (162) hide show
  1. data/LICENSE +22 -0
  2. data/README +101 -0
  3. data/Rakefile +44 -0
  4. data/bin/mkspec +7 -0
  5. data/bin/mspec +7 -0
  6. data/bin/mspec-ci +8 -0
  7. data/bin/mspec-run +8 -0
  8. data/bin/mspec-tag +8 -0
  9. data/lib/mspec.rb +6 -0
  10. data/lib/mspec/commands/mkspec.rb +147 -0
  11. data/lib/mspec/commands/mspec-ci.rb +71 -0
  12. data/lib/mspec/commands/mspec-run.rb +80 -0
  13. data/lib/mspec/commands/mspec-tag.rb +87 -0
  14. data/lib/mspec/commands/mspec.rb +143 -0
  15. data/lib/mspec/expectations.rb +2 -0
  16. data/lib/mspec/expectations/expectations.rb +12 -0
  17. data/lib/mspec/expectations/should.rb +23 -0
  18. data/lib/mspec/guards.rb +13 -0
  19. data/lib/mspec/guards/bug.rb +27 -0
  20. data/lib/mspec/guards/compliance.rb +18 -0
  21. data/lib/mspec/guards/conflict.rb +16 -0
  22. data/lib/mspec/guards/endian.rb +40 -0
  23. data/lib/mspec/guards/extensions.rb +12 -0
  24. data/lib/mspec/guards/guard.rb +120 -0
  25. data/lib/mspec/guards/noncompliance.rb +12 -0
  26. data/lib/mspec/guards/platform.rb +38 -0
  27. data/lib/mspec/guards/quarantine.rb +15 -0
  28. data/lib/mspec/guards/runner.rb +30 -0
  29. data/lib/mspec/guards/superuser.rb +15 -0
  30. data/lib/mspec/guards/support.rb +12 -0
  31. data/lib/mspec/guards/version.rb +40 -0
  32. data/lib/mspec/helpers.rb +6 -0
  33. data/lib/mspec/helpers/bignum.rb +5 -0
  34. data/lib/mspec/helpers/const_lookup.rb +5 -0
  35. data/lib/mspec/helpers/flunk.rb +5 -0
  36. data/lib/mspec/helpers/io.rb +13 -0
  37. data/lib/mspec/helpers/scratch.rb +17 -0
  38. data/lib/mspec/helpers/tmp.rb +32 -0
  39. data/lib/mspec/matchers.rb +16 -0
  40. data/lib/mspec/matchers/base.rb +95 -0
  41. data/lib/mspec/matchers/be_ancestor_of.rb +24 -0
  42. data/lib/mspec/matchers/be_close.rb +27 -0
  43. data/lib/mspec/matchers/be_empty.rb +20 -0
  44. data/lib/mspec/matchers/be_false.rb +20 -0
  45. data/lib/mspec/matchers/be_kind_of.rb +24 -0
  46. data/lib/mspec/matchers/be_nil.rb +20 -0
  47. data/lib/mspec/matchers/be_true.rb +20 -0
  48. data/lib/mspec/matchers/complain.rb +56 -0
  49. data/lib/mspec/matchers/eql.rb +26 -0
  50. data/lib/mspec/matchers/equal.rb +26 -0
  51. data/lib/mspec/matchers/equal_utf16.rb +34 -0
  52. data/lib/mspec/matchers/include.rb +32 -0
  53. data/lib/mspec/matchers/output.rb +67 -0
  54. data/lib/mspec/matchers/output_to_fd.rb +71 -0
  55. data/lib/mspec/matchers/raise_error.rb +48 -0
  56. data/lib/mspec/mocks.rb +3 -0
  57. data/lib/mspec/mocks/mock.rb +123 -0
  58. data/lib/mspec/mocks/object.rb +28 -0
  59. data/lib/mspec/mocks/proxy.rb +112 -0
  60. data/lib/mspec/runner.rb +13 -0
  61. data/lib/mspec/runner/actions.rb +6 -0
  62. data/lib/mspec/runner/actions/debug.rb +17 -0
  63. data/lib/mspec/runner/actions/filter.rb +40 -0
  64. data/lib/mspec/runner/actions/gdb.rb +17 -0
  65. data/lib/mspec/runner/actions/tag.rb +97 -0
  66. data/lib/mspec/runner/actions/tally.rb +80 -0
  67. data/lib/mspec/runner/actions/timer.rb +22 -0
  68. data/lib/mspec/runner/filters.rb +4 -0
  69. data/lib/mspec/runner/filters/match.rb +22 -0
  70. data/lib/mspec/runner/filters/profile.rb +54 -0
  71. data/lib/mspec/runner/filters/regexp.rb +7 -0
  72. data/lib/mspec/runner/filters/tag.rb +29 -0
  73. data/lib/mspec/runner/formatters.rb +7 -0
  74. data/lib/mspec/runner/formatters/dotted.rb +81 -0
  75. data/lib/mspec/runner/formatters/html.rb +87 -0
  76. data/lib/mspec/runner/formatters/specdoc.rb +27 -0
  77. data/lib/mspec/runner/formatters/spinner.rb +89 -0
  78. data/lib/mspec/runner/formatters/summary.rb +8 -0
  79. data/lib/mspec/runner/formatters/unit.rb +25 -0
  80. data/lib/mspec/runner/formatters/yaml.rb +43 -0
  81. data/lib/mspec/runner/mspec.rb +232 -0
  82. data/lib/mspec/runner/object.rb +20 -0
  83. data/lib/mspec/runner/shared.rb +12 -0
  84. data/lib/mspec/runner/state.rb +116 -0
  85. data/lib/mspec/runner/tag.rb +20 -0
  86. data/lib/mspec/utils/name_map.rb +130 -0
  87. data/lib/mspec/utils/options.rb +344 -0
  88. data/lib/mspec/utils/script.rb +77 -0
  89. data/lib/mspec/version.rb +3 -0
  90. data/spec/commands/mkspec_spec.rb +321 -0
  91. data/spec/commands/mspec_ci_spec.rb +139 -0
  92. data/spec/commands/mspec_run_spec.rb +146 -0
  93. data/spec/commands/mspec_spec.rb +359 -0
  94. data/spec/commands/mspec_tag_spec.rb +131 -0
  95. data/spec/expectations/expectations_spec.rb +16 -0
  96. data/spec/expectations/should_spec.rb +99 -0
  97. data/spec/guards/bug_spec.rb +137 -0
  98. data/spec/guards/compliance_spec.rb +70 -0
  99. data/spec/guards/conflict_spec.rb +20 -0
  100. data/spec/guards/endian_spec.rb +42 -0
  101. data/spec/guards/extensions_spec.rb +36 -0
  102. data/spec/guards/guard_spec.rb +355 -0
  103. data/spec/guards/noncompliance_spec.rb +36 -0
  104. data/spec/guards/platform_spec.rb +84 -0
  105. data/spec/guards/quarantine_spec.rb +19 -0
  106. data/spec/guards/runner_spec.rb +75 -0
  107. data/spec/guards/superuser_spec.rb +22 -0
  108. data/spec/guards/support_spec.rb +22 -0
  109. data/spec/guards/version_spec.rb +133 -0
  110. data/spec/helpers/bignum_spec.rb +11 -0
  111. data/spec/helpers/const_lookup_spec.rb +19 -0
  112. data/spec/helpers/flunk_spec.rb +15 -0
  113. data/spec/helpers/io_spec.rb +34 -0
  114. data/spec/helpers/scratch_spec.rb +22 -0
  115. data/spec/helpers/tmp_spec.rb +72 -0
  116. data/spec/matchers/base_spec.rb +180 -0
  117. data/spec/matchers/be_ancestor_of_spec.rb +28 -0
  118. data/spec/matchers/be_close_spec.rb +46 -0
  119. data/spec/matchers/be_empty_spec.rb +26 -0
  120. data/spec/matchers/be_false_spec.rb +28 -0
  121. data/spec/matchers/be_kind_of_spec.rb +29 -0
  122. data/spec/matchers/be_nil_spec.rb +27 -0
  123. data/spec/matchers/be_true_spec.rb +28 -0
  124. data/spec/matchers/complain_spec.rb +52 -0
  125. data/spec/matchers/eql_spec.rb +33 -0
  126. data/spec/matchers/equal_spec.rb +33 -0
  127. data/spec/matchers/equal_utf16_spec.rb +47 -0
  128. data/spec/matchers/include_spec.rb +37 -0
  129. data/spec/matchers/output_spec.rb +74 -0
  130. data/spec/matchers/output_to_fd_spec.rb +33 -0
  131. data/spec/matchers/raise_error_spec.rb +56 -0
  132. data/spec/mocks/mock_spec.rb +272 -0
  133. data/spec/mocks/proxy_spec.rb +259 -0
  134. data/spec/runner/actions/debug_spec.rb +61 -0
  135. data/spec/runner/actions/filter_spec.rb +84 -0
  136. data/spec/runner/actions/gdb_spec.rb +61 -0
  137. data/spec/runner/actions/tag_spec.rb +253 -0
  138. data/spec/runner/actions/tally_spec.rb +107 -0
  139. data/spec/runner/actions/timer_spec.rb +42 -0
  140. data/spec/runner/filters/a.yaml +4 -0
  141. data/spec/runner/filters/b.yaml +11 -0
  142. data/spec/runner/filters/match_spec.rb +44 -0
  143. data/spec/runner/filters/profile_spec.rb +117 -0
  144. data/spec/runner/filters/regexp_spec.rb +13 -0
  145. data/spec/runner/filters/tag_spec.rb +77 -0
  146. data/spec/runner/formatters/dotted_spec.rb +184 -0
  147. data/spec/runner/formatters/html_spec.rb +191 -0
  148. data/spec/runner/formatters/specdoc_spec.rb +57 -0
  149. data/spec/runner/formatters/spinner_spec.rb +78 -0
  150. data/spec/runner/formatters/summary_spec.rb +29 -0
  151. data/spec/runner/formatters/unit_spec.rb +71 -0
  152. data/spec/runner/formatters/yaml_spec.rb +123 -0
  153. data/spec/runner/mspec_spec.rb +393 -0
  154. data/spec/runner/shared_spec.rb +41 -0
  155. data/spec/runner/state_spec.rb +535 -0
  156. data/spec/runner/tag_spec.rb +93 -0
  157. data/spec/runner/tags.txt +3 -0
  158. data/spec/spec_helper.rb +46 -0
  159. data/spec/utils/name_map_spec.rb +178 -0
  160. data/spec/utils/options_spec.rb +862 -0
  161. data/spec/utils/script_spec.rb +240 -0
  162. metadata +217 -0
@@ -0,0 +1,8 @@
1
+ require 'mspec/expectations/expectations'
2
+ require 'mspec/runner/formatters/dotted'
3
+
4
+ class SummaryFormatter < DottedFormatter
5
+ def after(state)
6
+ @states << state if state.exception?
7
+ end
8
+ end
@@ -0,0 +1,25 @@
1
+ require 'mspec/expectations/expectations'
2
+ require 'mspec/runner/formatters/dotted'
3
+
4
+ class UnitdiffFormatter < DottedFormatter
5
+ def finish
6
+ print "\n\n#{@timer.format}\n"
7
+ count = 0
8
+ @states.each do |state|
9
+ state.exceptions.each do |msg, exc|
10
+ outcome = failure?(state) ? "FAILED" : "ERROR"
11
+ print "\n#{count += 1})\n#{state.description} #{outcome}\n"
12
+ print "Exception occurred during: #{msg}\n" if msg
13
+ print((exc.message.empty? ? "<No message>" : exc.message) + ": \n")
14
+ print backtrace(exc)
15
+ print "\n"
16
+ end
17
+ end
18
+ print "\n#{@tally.format}\n"
19
+ end
20
+
21
+ def backtrace(exc)
22
+ exc.backtrace && exc.backtrace.join("\n")
23
+ end
24
+ private :backtrace
25
+ end
@@ -0,0 +1,43 @@
1
+ require 'mspec/expectations/expectations'
2
+ require 'mspec/runner/formatters/dotted'
3
+
4
+ class YamlFormatter < DottedFormatter
5
+ def initialize(out=nil)
6
+ @states = []
7
+ @out = $stdout
8
+
9
+ if out.nil?
10
+ @finish = $stdout
11
+ else
12
+ @finish = File.open out, "w"
13
+ end
14
+ end
15
+
16
+ def switch
17
+ @out = @finish
18
+ end
19
+
20
+ def finish
21
+ switch
22
+
23
+ print "---\n"
24
+ print "exceptions:\n"
25
+ @states.each do |state|
26
+ state.exceptions.each do |msg, exc|
27
+ outcome = failure?(state) ? "FAILED" : "ERROR"
28
+ str = "#{state.description} #{outcome}\n"
29
+ str << "#{exc.class.name} occurred during: #{msg}\n" if msg
30
+ str << message(exc)
31
+ str << backtrace(exc)
32
+ print "- ", str.inspect, "\n"
33
+ end
34
+ end
35
+
36
+ print "time: ", @timer.elapsed, "\n"
37
+ print "files: ", @tally.counter.files, "\n"
38
+ print "examples: ", @tally.counter.examples, "\n"
39
+ print "expectations: ", @tally.counter.expectations, "\n"
40
+ print "failures: ", @tally.counter.failures, "\n"
41
+ print "errors: ", @tally.counter.errors, "\n"
42
+ end
43
+ end
@@ -0,0 +1,232 @@
1
+
2
+ require 'mspec/runner/state'
3
+ require 'mspec/runner/tag'
4
+ require 'fileutils'
5
+
6
+ module MSpec
7
+
8
+ @exit = nil
9
+ @start = nil
10
+ @enter = nil
11
+ @before = nil
12
+ @after = nil
13
+ @leave = nil
14
+ @finish = nil
15
+ @exclude = nil
16
+ @include = nil
17
+ @leave = nil
18
+ @mode = nil
19
+ @load = nil
20
+ @unload = nil
21
+ @randomize = nil
22
+ @expectation = nil
23
+
24
+ def self.describe(mod, msg=nil, &block)
25
+ stack.push RunState.new
26
+
27
+ current.describe(mod, msg, &block)
28
+ current.process
29
+
30
+ stack.pop
31
+ end
32
+
33
+ def self.process
34
+ actions :start
35
+ files
36
+ actions :finish
37
+ end
38
+
39
+ def self.files
40
+ return unless files = retrieve(:files)
41
+
42
+ shuffle files if randomize?
43
+ files.each do |file|
44
+ store :file, file
45
+ actions :load
46
+ protect("loading #{file}") { Kernel.load file }
47
+ actions :unload
48
+ end
49
+ end
50
+
51
+ def self.actions(action, *args)
52
+ actions = retrieve(action)
53
+ actions.each { |obj| obj.send action, *args } if actions
54
+ end
55
+
56
+ def self.register_exit(code)
57
+ store :exit, code
58
+ end
59
+
60
+ def self.exit_code
61
+ retrieve(:exit).to_i
62
+ end
63
+
64
+ def self.register_files(files)
65
+ store :files, files
66
+ end
67
+
68
+ def self.register_tags_path(path)
69
+ store :tags_path, path
70
+ end
71
+
72
+ def self.register_mode(mode)
73
+ store :mode, mode
74
+ end
75
+
76
+ def self.retrieve(symbol)
77
+ instance_variable_get :"@#{symbol}"
78
+ end
79
+
80
+ def self.store(symbol, value)
81
+ instance_variable_set :"@#{symbol}", value
82
+ end
83
+
84
+ # This method is used for registering actions that are
85
+ # run at particular points in the spec cycle:
86
+ # :start before any specs are run
87
+ # :load before a spec file is loaded
88
+ # :enter before a describe block is run
89
+ # :before before a single spec is run
90
+ # :expectation before a 'should', 'should_receive', etc.
91
+ # :after after a single spec is run
92
+ # :leave after a describe block is run
93
+ # :unload after a spec file is run
94
+ # :finish after all specs are run
95
+ #
96
+ # Objects registered as actions above should respond to
97
+ # a method of the same name. For example, if an object
98
+ # is registered as a :start action, it should respond to
99
+ # a #start method call.
100
+ #
101
+ # Additionally, there are two "action" lists for
102
+ # filtering specs:
103
+ # :include return true if the spec should be run
104
+ # :exclude return true if the spec should NOT be run
105
+ #
106
+ def self.register(symbol, action)
107
+ unless value = retrieve(symbol)
108
+ value = store symbol, []
109
+ end
110
+ value << action unless value.include? action
111
+ end
112
+
113
+ def self.unregister(symbol, action)
114
+ if value = retrieve(symbol)
115
+ value.delete action
116
+ end
117
+ end
118
+
119
+ def self.protect(msg, &block)
120
+ begin
121
+ instance_eval(&block)
122
+ rescue Exception => e
123
+ register_exit 1
124
+ if current and current.state
125
+ current.state.exceptions << [msg, e]
126
+ else
127
+ STDERR.write "\nAn exception occurred in #{msg}:\n#{e.class}: #{e.message.inspect}\n"
128
+ STDERR.write "#{e.backtrace.join "\n"}"
129
+ end
130
+ end
131
+ end
132
+
133
+ def self.stack
134
+ @stack ||= []
135
+ end
136
+
137
+ def self.current
138
+ stack.last
139
+ end
140
+
141
+ def self.verify_mode?
142
+ @mode == :verify
143
+ end
144
+
145
+ def self.report_mode?
146
+ @mode == :report
147
+ end
148
+
149
+ def self.pretend_mode?
150
+ @mode == :pretend
151
+ end
152
+
153
+ def self.randomize(flag=true)
154
+ @randomize = flag
155
+ end
156
+
157
+ def self.randomize?
158
+ @randomize == true
159
+ end
160
+
161
+ def self.shuffle(ary)
162
+ return if ary.empty?
163
+
164
+ size = ary.size
165
+ size.times do |i|
166
+ r = rand(size - i - 1)
167
+ ary[i], ary[r] = ary[r], ary[i]
168
+ end
169
+ end
170
+
171
+ def self.tags_path
172
+ retrieve(:tags_path) || "spec/tags"
173
+ end
174
+
175
+ def self.tags_file
176
+ path = tags_path
177
+ file = retrieve :file
178
+ tags_file = File.basename(file, '.*').sub(/_spec$/, '_tags') + '.txt'
179
+
180
+ m = file.match %r[.*spec/(.*)/.*_spec.rb]
181
+ path = File.join(path, m[1]) if m
182
+ File.join path, tags_file
183
+ end
184
+
185
+ def self.read_tags(*keys)
186
+ tags = []
187
+ file = tags_file
188
+ if File.exist? file
189
+ File.open(file, "r") do |f|
190
+ f.each_line do |line|
191
+ tag = SpecTag.new line.chomp
192
+ tags << tag if keys.include? tag.tag
193
+ end
194
+ end
195
+ end
196
+ tags
197
+ end
198
+
199
+ def self.write_tag(tag)
200
+ string = tag.to_s
201
+ file = tags_file
202
+ path = File.dirname file
203
+ FileUtils.mkdir_p(path) unless File.exist?(path)
204
+ if File.exist? file
205
+ File.open(file, "r") do |f|
206
+ f.each_line { |line| return false if line.chomp == string }
207
+ end
208
+ end
209
+ File.open(file, "a") { |f| f.puts string }
210
+ return true
211
+ end
212
+
213
+ def self.delete_tag(tag)
214
+ deleted = false
215
+ pattern = /#{tag.tag}.*#{Regexp.escape tag.description}/
216
+ file = tags_file
217
+ if File.exist? file
218
+ lines = IO.readlines(file)
219
+ File.open(file, "w") do |f|
220
+ lines.each do |line|
221
+ unless pattern =~ line.chomp
222
+ f.puts line
223
+ else
224
+ deleted = true
225
+ end
226
+ end
227
+ end
228
+ File.delete file unless File.size? file
229
+ end
230
+ return deleted
231
+ end
232
+ end
@@ -0,0 +1,20 @@
1
+ class Object
2
+ def before(at=:each, &block)
3
+ MSpec.current.before at, &block
4
+ end
5
+
6
+ def after(at=:each, &block)
7
+ MSpec.current.after at, &block
8
+ end
9
+
10
+ def describe(mod, msg=nil, &block)
11
+ MSpec.describe mod, msg, &block
12
+ end
13
+
14
+ def it(msg, &block)
15
+ MSpec.current.it msg, &block
16
+ end
17
+
18
+ alias_method :context, :describe
19
+ alias_method :specify, :it
20
+ end
@@ -0,0 +1,12 @@
1
+ require 'mspec/runner/mspec'
2
+
3
+ class Object
4
+ def shared(msg, &block)
5
+ MSpec.store msg.to_sym, block
6
+ end
7
+
8
+ def it_behaves_like(behavior, *args)
9
+ p = MSpec.retrieve behavior.to_sym
10
+ p[*args]
11
+ end
12
+ end
@@ -0,0 +1,116 @@
1
+ require 'mspec/runner/mspec'
2
+
3
+ class RunState
4
+ def initialize
5
+ @start = []
6
+ @before = []
7
+ @after = []
8
+ @finish = []
9
+ @spec = []
10
+ end
11
+
12
+ def state
13
+ @state
14
+ end
15
+
16
+ def before(at=:each, &block)
17
+ case at
18
+ when :each
19
+ @before << block
20
+ when :all
21
+ @start << block
22
+ end
23
+ end
24
+
25
+ def after(at=:each, &block)
26
+ case at
27
+ when :each
28
+ @after << block
29
+ when :all
30
+ @finish << block
31
+ end
32
+ end
33
+
34
+ def it(desc, &block)
35
+ state = SpecState.new @describe, desc
36
+ @spec << [desc, block, state] unless state.filtered?
37
+ end
38
+
39
+ def describe(mod, desc=nil, &block)
40
+ @describe = desc ? "#{mod} #{desc}" : mod.to_s
41
+ @block = block
42
+ end
43
+
44
+ def protect(what, blocks, check=true)
45
+ return if check and MSpec.pretend_mode?
46
+ Array(blocks).each { |block| MSpec.protect what, &block }
47
+ end
48
+
49
+ def process
50
+ protect @describe, @block, false
51
+ return unless @spec.any? { |desc, spec, state| state.unfiltered? }
52
+
53
+ MSpec.shuffle @spec if MSpec.randomize?
54
+ MSpec.actions :enter, @describe
55
+ protect "before :all", @start
56
+ @spec.each do |desc, spec, state|
57
+ @state = state
58
+ MSpec.actions :before, state
59
+ protect "before :each", @before
60
+ protect nil, spec
61
+ protect "after :each", @after
62
+ protect "Mock.verify_count", lambda { Mock.verify_count }
63
+ protect "Mock.cleanup", lambda { Mock.cleanup }
64
+ MSpec.actions :after, state
65
+ @state = nil
66
+ end
67
+ protect "after :all", @finish
68
+ MSpec.actions :leave
69
+ end
70
+ end
71
+
72
+ class SpecState
73
+ def initialize(describe, it)
74
+ @describe = describe
75
+ @it = it
76
+ @unfiltered = nil
77
+ end
78
+
79
+ def describe
80
+ @describe
81
+ end
82
+
83
+ def it
84
+ @it
85
+ end
86
+
87
+ def description
88
+ @description ||= "#{@describe} #{@it}"
89
+ end
90
+
91
+ def exceptions
92
+ @exceptions ||= []
93
+ end
94
+
95
+ def exception?
96
+ not exceptions.empty?
97
+ end
98
+
99
+ def unfiltered?
100
+ unless @unfiltered
101
+ incl = MSpec.retrieve(:include) || []
102
+ excl = MSpec.retrieve(:exclude) || []
103
+ @unfiltered = incl.empty? || incl.any? { |f| f === description }
104
+ @unfiltered &&= excl.empty? || !excl.any? { |f| f === description }
105
+ end
106
+ @unfiltered
107
+ end
108
+
109
+ def filtered?
110
+ not unfiltered?
111
+ end
112
+
113
+ def failure?(exception)
114
+ exception.is_a?(ExpectationNotMetError)
115
+ end
116
+ end