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,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