Module: LeftRight
- Defined in:
- lib/leftright/color.rb,
lib/leftright.rb,
lib/leftright/tty.rb,
lib/leftright/runner.rb,
lib/leftright/version.rb,
lib/leftright/force_tty.rb
Overview
This is the replacement for Test::Unit::UI::Console::TestRunner
Defined Under Namespace
Constant Summary collapse
- MID_SEPARATOR =
In counts of ‘ ’:
1- RIGHT_MARGIN =
1- LEFT_MARGIN =
1- VERSION =
'0.9.1'- LOCATION =
:nodoc:
File.dirname __FILE__
Class Method Summary collapse
-
.E ⇒ Object
Returns the current fault as a formatted error message.
-
.extract_class_name(test_name) ⇒ Object
This gets the class name from the ‘test_name’ method on a Test::Unit Failure or Error.
-
.F(color = C.red) ⇒ Object
Returns the current fault as a formatted failure message.
-
.format_class_name(class_name) ⇒ Object
Formats a class name to display on the left side.
-
.justify_left_side(str = '') ⇒ Object
Returns the given string, right-justified onto the left side.
-
.left_side_width ⇒ Object
Tries to get the left side width in columns.
-
.ncurses_terminal_width ⇒ Object
Uses ffi-ncurses to determine terminal width.
-
.P ⇒ Object
Returns a passing dot, aware of how many to print per-line.
-
.right_side_width ⇒ Object
Tries to get the right side width in columns.
-
.skip_testing_class(klass) ⇒ Object
Replaces all instance methods beginning with ‘test’ in the given class with stubs that skip testing.
-
.state ⇒ Object
This whole thing is fairly gnarly, needing to keep state across multiple parts of the crazyness that is Test::Unit, so we keep it all here.
-
.stty_terminal_width ⇒ Object
Uses stty to determine terminal width.
-
.terminal_width ⇒ Object
Tries to get the terminal width in columns.
-
.testcase_classes ⇒ Object
Gets all descendants of Class that also descend from Test::Unit::TestCase.
-
.tty? ⇒ Boolean
Are we running under a terminal? YES.
-
.wrap(line) ⇒ Object
Wraps the given lines at word boundaries.
Class Method Details
.E ⇒ Object
Returns the current fault as a formatted error message.
194 195 196 |
# File 'lib/leftright.rb', line 194 def self.E F C.yellow end |
.extract_class_name(test_name) ⇒ Object
This gets the class name from the ‘test_name’ method on a Test::Unit Failure or Error. They look like test_method_name(TestCase),
142 143 144 |
# File 'lib/leftright.rb', line 142 def self.extract_class_name(test_name) test_name.scan(/\(([^(|)]+)\)/x).flatten.last end |
.F(color = C.red) ⇒ Object
Returns the current fault as a formatted failure message.
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/leftright.rb', line 157 def self.F(color = C.red) # First, we wrap each line individually, to keep existing line breaks: lines = state.fault.long_display.split("\n") # Drop the redundant "Failure: ", "test: " (shoulda), "test_", etc lines.shift if lines.first.match /Failure:|Error:/ lines.first.sub! /^test[\ |:|_]?/i, '' # Drop the class name in () from the test method name lines.first.sub! /\(#{state.class}\)/, '' # shoulda puts '. :' at the end of method names lines.first.sub! /\.\ :\s?/, ':' # Wrap lines before coloring, since the wrapping would get confused # by non-printables. buffer = lines.map { |line| wrap line.strip }.join.strip # We make interesting parts of the failure message bold: [ /(`[^']+')/m, # Stuff in `quotes' /("[^"]+")/m, # Stuff in "quotes" /([^\/|\[]+\.rb:\d+)/, # Filenames with line numbers (without [box]) /(\s+undefined\s+)/ ].each do |interesting| buffer.gsub! interesting, ( C.bold + '\0' + C.reset + color ) end # These are great for assert_equal and similar: buffer.sub! /(<)(.*)(>\s+expected)/, '\1' + C.bold + '\2' + C.reset + color + '\3' buffer.sub! /(but\s+was\s+<)(.*)(>\.)/, '\1' + C.bold + '\2' + C.reset + color + '\3' color + buffer + C.reset + "\n" end |
.format_class_name(class_name) ⇒ Object
Formats a class name to display on the left side.
77 78 79 |
# File 'lib/leftright.rb', line 77 def self.format_class_name(class_name) class_name.chomp 'Test' end |
.justify_left_side(str = '') ⇒ Object
Returns the given string, right-justified onto the left side.
135 136 137 |
# File 'lib/leftright.rb', line 135 def self.justify_left_side(str = '') str.to_s.rjust(left_side_width) + (' ' * MID_SEPARATOR) end |
.left_side_width ⇒ Object
Tries to get the left side width in columns.
119 120 121 122 123 124 125 |
# File 'lib/leftright.rb', line 119 def self.left_side_width @left_side_width ||= begin testcase_classes.map do |c| format_class_name(c.name).size + LEFT_MARGIN end.max end end |
.ncurses_terminal_width ⇒ Object
Uses ffi-ncurses to determine terminal width
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/leftright.rb', line 100 def self.ncurses_terminal_width require 'ffi-ncurses' begin FFI::NCurses.initscr FFI::NCurses.getmaxyx(FFI::NCurses._initscr).reverse.first.to_i rescue 0 ensure FFI::NCurses.endwin end rescue LoadError puts %{ Under JRuby, you need to install the 'ffi-ncurses' gem, since `stty` is not available. }.strip.gsub(/\s+/, ' ') exit 1 end |
.P ⇒ Object
Returns a passing dot, aware of how many to print per-line.
200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/leftright.rb', line 200 def self.P return '.' unless tty? state.dots += 1 max_dots = right_side_width - RIGHT_MARGIN - MID_SEPARATOR if state.dots >= max_dots state.dots = 1 "\n" + C.green('.') else C.green '.' end end |
.right_side_width ⇒ Object
Tries to get the right side width in columns.
129 130 131 |
# File 'lib/leftright.rb', line 129 def self.right_side_width terminal_width - left_side_width end |
.skip_testing_class(klass) ⇒ Object
Replaces all instance methods beginning with ‘test’ in the given class with stubs that skip testing.
64 65 66 67 68 69 70 71 72 73 |
# File 'lib/leftright.rb', line 64 def self.skip_testing_class(klass) klass.instance_methods.each do |m| if 'test' == m.to_s[0,4] klass.send :define_method, m.to_sym do ::LeftRight.state.skip = true ::LeftRight.state.skipped_count += 1 end end end end |
.state ⇒ Object
This whole thing is fairly gnarly, needing to keep state across multiple parts of the crazyness that is Test::Unit, so we keep it all here.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/leftright.rb', line 20 def self.state @state ||= begin fields = [ :dots, # the number of dots ('.') printed on this line :class, # the TestCase-extending class being tested :fault, # the current Test::Unit Failure/Error object :last_class_printed, # last class printed on the left side :previous_failed, # true if the previous test failed/exceptioned :skip, # true if the current test was a skip :skipped_count # total number of skipped tests so far ] state = Struct.new(*fields).new state.skipped_count = 0 state.dots = 0 state end end |
.stty_terminal_width ⇒ Object
Uses stty to determine terminal width
92 93 94 95 96 |
# File 'lib/leftright.rb', line 92 def self.stty_terminal_width `stty size`.split[-1].to_i rescue 0 end |
.terminal_width ⇒ Object
Tries to get the terminal width in columns.
83 84 85 86 87 88 89 |
# File 'lib/leftright.rb', line 83 def self.terminal_width @terminal_width ||= if defined?(RUBY_ENGINE) && RUBY_ENGINE.match('jruby') ncurses_terminal_width else stty_terminal_width end end |
.testcase_classes ⇒ Object
Gets all descendants of Class that also descend from Test::Unit::TestCase
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/leftright.rb', line 41 def self.testcase_classes @testcase_classes ||= begin found = [] ObjectSpace.each_object(Class) do |klass| found << klass if Test::Unit::TestCase > klass end # Rails 2.3.5 defines these, and they cramp up my style. found.reject! { |k| k.to_s == 'ActiveRecord::TestCase' } found.reject! { |k| k.to_s == 'ActionMailer::TestCase' } found.reject! { |k| k.to_s == 'ActionView::TestCase' } found.reject! { |k| k.to_s == 'ActionController::TestCase' } found.reject! { |k| k.to_s == 'ActionController::IntegrationTest' } found.reject! { |k| k.to_s == 'ActiveSupport::TestCase' } found end end |
.tty? ⇒ Boolean
Are we running under a terminal? YES.
3 4 5 |
# File 'lib/leftright/tty.rb', line 3 def self.tty? STDOUT.tty? end |
.wrap(line) ⇒ Object
Wraps the given lines at word boundaries. Ripped right out of blog.macromates.com/2006/wrapping-text-with-regular-expressions/
149 150 151 152 153 |
# File 'lib/leftright.rb', line 149 def self.wrap(line) return line unless tty? width = right_side_width - MID_SEPARATOR - RIGHT_MARGIN line.gsub /(.{1,#{width}})( +|$)\n?|(.{#{width}})/, "\\1\\3\n" end |