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,80 @@
1
+ class Tally
2
+ attr_reader :files, :examples, :expectations, :failures, :errors
3
+
4
+ def initialize
5
+ @files = @examples = @expectations = @failures = @errors = 0
6
+ end
7
+
8
+ def files!(add=1)
9
+ @files += add
10
+ end
11
+
12
+ def examples!(add=1)
13
+ @examples += add
14
+ end
15
+
16
+ def expectations!(add=1)
17
+ @expectations += add
18
+ end
19
+
20
+ def failures!(add=1)
21
+ @failures += add
22
+ end
23
+
24
+ def errors!(add=1)
25
+ @errors += add
26
+ end
27
+
28
+ 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(", ")
35
+ end
36
+
37
+ def pluralize(count, singular)
38
+ "#{count} #{singular}#{'s' unless count == 1}"
39
+ end
40
+ private :pluralize
41
+ end
42
+
43
+ class TallyAction
44
+ attr_reader :counter
45
+
46
+ def initialize
47
+ @counter = Tally.new
48
+ end
49
+
50
+ def register
51
+ MSpec.register :load, self
52
+ MSpec.register :after, self
53
+ MSpec.register :expectation, self
54
+ end
55
+
56
+ def unregister
57
+ MSpec.unregister :load, self
58
+ MSpec.unregister :after, self
59
+ MSpec.unregister :expectation, self
60
+ end
61
+
62
+ def load
63
+ @counter.files!
64
+ end
65
+
66
+ def expectation(state)
67
+ @counter.expectations!
68
+ end
69
+
70
+ def after(state)
71
+ @counter.examples!
72
+ state.exceptions.each do |msg, exc|
73
+ state.failure?(exc) ? @counter.failures! : @counter.errors!
74
+ end
75
+ end
76
+
77
+ def format
78
+ @counter.format
79
+ end
80
+ end
@@ -0,0 +1,22 @@
1
+ class TimerAction
2
+ def register
3
+ MSpec.register :start, self
4
+ MSpec.register :finish, self
5
+ end
6
+
7
+ def start
8
+ @start = Time.now
9
+ end
10
+
11
+ def finish
12
+ @stop = Time.now
13
+ end
14
+
15
+ def elapsed
16
+ @stop - @start
17
+ end
18
+
19
+ def format
20
+ "Finished in %f seconds" % elapsed
21
+ end
22
+ end
@@ -0,0 +1,4 @@
1
+ require 'mspec/runner/filters/match'
2
+ require 'mspec/runner/filters/regexp'
3
+ require 'mspec/runner/filters/tag'
4
+ require 'mspec/runner/filters/profile'
@@ -0,0 +1,22 @@
1
+ class MatchFilter
2
+ def initialize(what, *strings)
3
+ @what = what
4
+ @descriptions = to_regexp(*strings)
5
+ end
6
+
7
+ def to_regexp(*strings)
8
+ strings.map { |str| Regexp.new Regexp.escape(str) }
9
+ end
10
+
11
+ def ===(string)
12
+ @descriptions.any? { |d| d === string }
13
+ end
14
+
15
+ def register
16
+ MSpec.register @what, self
17
+ end
18
+
19
+ def unregister
20
+ MSpec.unregister @what, self
21
+ end
22
+ end
@@ -0,0 +1,54 @@
1
+ class ProfileFilter
2
+ def initialize(what, *files)
3
+ @what = what
4
+ @methods = load(*files)
5
+ @pattern = /([^ .#]+[.#])([^ ]+)/
6
+ end
7
+
8
+ def find(name)
9
+ return name if File.exist?(File.expand_path(name))
10
+
11
+ ["spec/profiles", "spec", "profiles", "."].each do |dir|
12
+ file = File.join dir, name
13
+ return file if File.exist? file
14
+ end
15
+ end
16
+
17
+ def parse(file)
18
+ pattern = /(\S+):\s*/
19
+ key = ""
20
+ file.inject(Hash.new { |h,k| h[k] = [] }) do |hash, line|
21
+ line.chomp!
22
+ if line[0,2] == "- "
23
+ hash[key] << line[2..-1].gsub(/[ '"]/, "")
24
+ elsif m = pattern.match(line)
25
+ key = m[1]
26
+ end
27
+ hash
28
+ end
29
+ end
30
+
31
+ def load(*files)
32
+ files.inject({}) do |hash, file|
33
+ next hash unless name = find(file)
34
+
35
+ File.open name, "r" do |f|
36
+ hash.merge parse(f)
37
+ end
38
+ end
39
+ end
40
+
41
+ def ===(string)
42
+ return false unless m = @pattern.match(string)
43
+ return false unless l = @methods[m[1]]
44
+ l.include? m[2]
45
+ end
46
+
47
+ def register
48
+ MSpec.register @what, self
49
+ end
50
+
51
+ def unregister
52
+ MSpec.unregister @what, self
53
+ end
54
+ end
@@ -0,0 +1,7 @@
1
+ require 'mspec/runner/filters/match'
2
+
3
+ class RegexpFilter < MatchFilter
4
+ def to_regexp(*strings)
5
+ strings.map { |str| Regexp.new str }
6
+ end
7
+ end
@@ -0,0 +1,29 @@
1
+ require 'mspec/runner/filters/match'
2
+
3
+ class TagFilter
4
+ def initialize(what, *tags)
5
+ @what = what
6
+ @tags = tags
7
+ end
8
+
9
+ def load
10
+ desc = MSpec.read_tags(*@tags).map { |t| t.description }
11
+
12
+ @filter = MatchFilter.new(@what, *desc)
13
+ @filter.register
14
+ end
15
+
16
+ def unload
17
+ @filter.unregister if @filter
18
+ end
19
+
20
+ def register
21
+ MSpec.register :load, self
22
+ MSpec.register :unload, self
23
+ end
24
+
25
+ def unregister
26
+ MSpec.unregister :load, self
27
+ MSpec.unregister :unload, self
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ require 'mspec/runner/formatters/dotted'
2
+ require 'mspec/runner/formatters/specdoc'
3
+ require 'mspec/runner/formatters/html'
4
+ require 'mspec/runner/formatters/summary'
5
+ require 'mspec/runner/formatters/unit'
6
+ require 'mspec/runner/formatters/spinner'
7
+ require 'mspec/runner/formatters/yaml'
@@ -0,0 +1,81 @@
1
+ require 'mspec/expectations/expectations'
2
+ require 'mspec/runner/actions/timer'
3
+ require 'mspec/runner/actions/tally'
4
+
5
+ class DottedFormatter
6
+ attr_reader :timer, :tally
7
+
8
+ def initialize(out=nil)
9
+ @states = []
10
+ if out.nil?
11
+ @out = $stdout
12
+ else
13
+ @out = File.open out, "w"
14
+ end
15
+ end
16
+
17
+ def register
18
+ @timer = TimerAction.new
19
+ @timer.register
20
+ @tally = TallyAction.new
21
+ @tally.register
22
+ @counter = @tally.counter
23
+
24
+ MSpec.register :after, self
25
+ MSpec.register :finish, self
26
+ end
27
+
28
+ def after(state)
29
+ unless state.exception?
30
+ print "."
31
+ else
32
+ @states << state
33
+ print failure?(state) ? "F" : "E"
34
+ end
35
+ end
36
+
37
+ def finish
38
+ print "\n"
39
+ count = 0
40
+ @states.each do |state|
41
+ state.exceptions.each do |msg, exc|
42
+ outcome = failure?(state) ? "FAILED" : "ERROR"
43
+ print "\n#{count += 1})\n#{state.description} #{outcome}\n"
44
+ print "#{exc.class.name} occurred during: #{msg}\n" if msg
45
+ print message(exc)
46
+ print "\n"
47
+ print backtrace(exc)
48
+ print "\n"
49
+ end
50
+ end
51
+ print "\n#{@timer.format}\n\n#{@tally.format}\n"
52
+ end
53
+
54
+ def print(*args)
55
+ @out.print(*args)
56
+ end
57
+
58
+ def message(exc)
59
+ if exc.message.empty?
60
+ "<No message>"
61
+ elsif exc.class == ExpectationNotMetError
62
+ exc.message
63
+ else
64
+ "#{exc.class}: #{exc.message}"
65
+ end
66
+ end
67
+
68
+ def failure?(state)
69
+ state.exceptions.all? { |msg, exc| state.failure?(exc) }
70
+ end
71
+ private :failure?
72
+
73
+ def backtrace(exc)
74
+ begin
75
+ return exc.awesome_backtrace.show
76
+ rescue Exception
77
+ return exc.backtrace && exc.backtrace.join("\n")
78
+ end
79
+ end
80
+ private :backtrace
81
+ end
@@ -0,0 +1,87 @@
1
+ require 'mspec/expectations/expectations'
2
+ require 'mspec/runner/formatters/dotted'
3
+
4
+ class HtmlFormatter < DottedFormatter
5
+ def register
6
+ super
7
+ MSpec.register :start, self
8
+ MSpec.register :enter, self
9
+ MSpec.register :leave, self
10
+ end
11
+
12
+ def start
13
+ print <<-EOH
14
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
15
+ "http://www.w3.org/TR/html4/strict.dtd">
16
+ <html>
17
+ <head>
18
+ <title>Spec Output For #{RUBY_NAME} (#{RUBY_VERSION})</title>
19
+ <style type="text/css">
20
+ ul {
21
+ list-style: none;
22
+ }
23
+ .fail {
24
+ color: red;
25
+ }
26
+ .pass {
27
+ color: green;
28
+ }
29
+ #details :target {
30
+ background-color: #ffffe0;
31
+ }
32
+ </style>
33
+ </head>
34
+ <body>
35
+ EOH
36
+ end
37
+
38
+ def enter(describe)
39
+ print "<div><p>#{describe}</p>\n<ul>\n"
40
+ end
41
+
42
+ def leave
43
+ print "</ul>\n</div>\n"
44
+ end
45
+
46
+ def after(state)
47
+ desc = "- #{state.it}"
48
+ if state.exception?
49
+ @states << state
50
+ count = @counter.failures + @counter.errors - state.exceptions.size
51
+ state.exceptions.each do |msg, exc|
52
+ outcome = state.failure?(exc) ? "FAILED" : "ERROR"
53
+ count += 1
54
+ print %[<li class="fail">#{desc} (<a href="#details-#{count}">#{outcome} - #{count}</a>)</li>\n]
55
+ end
56
+ else
57
+ print %[<li class="pass">#{desc}</li>\n]
58
+ end
59
+ end
60
+
61
+ def finish
62
+ success = @states.empty?
63
+ unless success
64
+ print "<hr>\n"
65
+ print %[<ol id="details">]
66
+ count = 0
67
+ @states.each do |state|
68
+ state.exceptions.each do |msg, exc|
69
+ outcome = failure?(state) ? "FAILED" : "ERROR"
70
+ print %[\n<li id="details-#{count += 1}"><p>#{escape(state.description)} #{outcome}</p>\n<p>]
71
+ print escape(message(exc))
72
+ print "</p>\n<pre>\n"
73
+ print escape(backtrace(exc))
74
+ print "</pre>\n</li>\n"
75
+ end
76
+ end
77
+ print "</ol>\n"
78
+ end
79
+ print %[<p>#{@timer.format}</p>\n]
80
+ print %[<p class="#{success ? "pass" : "fail"}">#{@tally.format}</p>\n]
81
+ print "</body>\n</html>\n"
82
+ end
83
+
84
+ def escape(string)
85
+ string.gsub("&", "&nbsp;").gsub("<", "&lt;").gsub(">", "&gt;")
86
+ end
87
+ end
@@ -0,0 +1,27 @@
1
+ require 'mspec/expectations/expectations'
2
+ require 'mspec/runner/formatters/dotted'
3
+
4
+ class SpecdocFormatter < DottedFormatter
5
+ def register
6
+ super
7
+ MSpec.register :enter, self
8
+ end
9
+
10
+ def enter(describe)
11
+ print "\n#{describe}\n"
12
+ end
13
+
14
+ def after(state)
15
+ desc = "- #{state.it}"
16
+ if state.exception?
17
+ @states << state
18
+ count = @counter.failures + @counter.errors - state.exceptions.size
19
+ state.exceptions.each do |msg, exc|
20
+ outcome = state.failure?(exc) ? "FAILED" : "ERROR"
21
+ print "#{desc} (#{outcome} - #{count += 1})\n"
22
+ end
23
+ else
24
+ print "#{desc}\n"
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,89 @@
1
+ require 'mspec/expectations/expectations'
2
+ require 'mspec/runner/formatters/dotted'
3
+
4
+ class SpinnerFormatter < DottedFormatter
5
+ attr_reader :length
6
+
7
+ Spins = %w!| / - \\!
8
+ HOUR = 3600
9
+ MIN = 60
10
+
11
+ def initialize(out=nil)
12
+ @out = $stdout
13
+
14
+ @states = []
15
+ @which = 0
16
+ @count = 0
17
+ self.length = 40
18
+ @percent = 0
19
+ @start = Time.now
20
+
21
+ term = ENV['TERM']
22
+ @color = (term != "dumb")
23
+ @fail_color = "32"
24
+ @error_color = "32"
25
+ end
26
+
27
+ def register
28
+ super
29
+
30
+ MSpec.register :start, self
31
+ MSpec.register :load, self
32
+ end
33
+
34
+ def length=(length)
35
+ @length = length
36
+ @ratio = 100.0 / length
37
+ @position = length / 2 - 2
38
+ end
39
+
40
+ def etr
41
+ return "00:00:00" if @percent == 0
42
+ elapsed = Time.now - @start
43
+ remain = (100 * elapsed / @percent) - elapsed
44
+
45
+ hour = remain >= HOUR ? (remain / HOUR).to_i : 0
46
+ remain -= hour * HOUR
47
+ min = remain >= MIN ? (remain / MIN).to_i : 0
48
+ sec = remain - min * MIN
49
+
50
+ "%02d:%02d:%02d" % [hour, min, sec]
51
+ end
52
+
53
+ def percentage
54
+ @percent = @count * 100 / @total
55
+ bar = ("=" * (@percent / @ratio)).ljust @length
56
+ label = "%d%%" % @percent
57
+ bar[@position, label.size] = label
58
+ bar
59
+ end
60
+
61
+ def spin
62
+ @which = (@which + 1) % Spins.size
63
+ if @color
64
+ print "\r[%s | %s | %s] \033[0;#{@fail_color}m%6dF \033[0;#{@error_color}m%6dE\033[0m" %
65
+ [Spins[@which], percentage, etr, @counter.failures, @counter.errors]
66
+ else
67
+ print "\r[%s | %s | %s] %6dF %6dE" %
68
+ [Spins[@which], percentage, etr, @counter.failures, @counter.errors]
69
+ end
70
+ end
71
+
72
+ def start
73
+ @total = MSpec.retrieve(:files).size
74
+ end
75
+
76
+ def load
77
+ @count += 1
78
+ end
79
+
80
+ def after(state)
81
+ if state.exception?
82
+ @fail_color = "31" if @counter.failures > 0
83
+ @error_color = "33" if @counter.errors > 0
84
+ @states << state
85
+ end
86
+
87
+ spin
88
+ end
89
+ end