mspec 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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