jleo-leftright 0.9.1

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.
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009, 2010 Jordi Bunster <jordi@bunster.org>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,46 @@
1
+ = leftright
2
+
3
+ leftright is kind of like the redgreen gem. It makes passing tests look
4
+ green, exceptions yellow, and failures red. But then there's more:
5
+
6
+ * It lets you know which TestCase class is being tested
7
+ * It shows you the full text of failures and exceptions as they happen
8
+ * It skips all remaining tests for a TestCase class if one fails
9
+
10
+ This release was tested under:
11
+
12
+ * Rubinius 1.0.1
13
+ * REE 1.8.7
14
+ * MRI 1.8.6 and 1.8.7
15
+ * JRuby 1.4.0 and 1.5.2 (both in 1.8.7 mode)
16
+
17
+ == Dependencies
18
+
19
+ Right now this is pretty heavily dependent on Test::Unit, so it won't work
20
+ in Ruby 1.9+ using MiniTest. Support is planned as soon as I find myself
21
+ using the Ruby 1.9 + Rails 3 combo day to day.
22
+
23
+ == Installation instructions
24
+
25
+ gem install leftright
26
+
27
+ If you're on JRuby, you'll need to install ffi-ncurses to format properly:
28
+
29
+ jruby -S gem install ffi-ncurses
30
+
31
+ == Example usage
32
+
33
+ require 'leftright'
34
+
35
+ class SomeTest < Test::Unit::TestCase
36
+ def test_that_true_is_indeed_true
37
+ assert_equal true, true
38
+ end
39
+ end
40
+
41
+ Then run the file with ruby. Mind you, it gets a lot more exciting with
42
+ your own tests, specially if they fail. :)
43
+
44
+ == Legal
45
+
46
+ Copyright (c) 2009, 2010 Jordi Bunster, released under the MIT license
@@ -0,0 +1,29 @@
1
+ * 0.9.0 (2010-08-27):
2
+ - Fixed "leftright.rb:113: warning: parenthesize argument(s) for future
3
+ version" in 1.8.6 (2007-03-13 patchlevel 0) and possibly other
4
+ versions (Mike Naberezny).
5
+ - Fixed a bug when running under non-ttys (Erik Peterson).
6
+
7
+ * 0.0.6 (2010-08-02):
8
+ - Added the 'lr' binary to run foreign test suites using leftright.
9
+
10
+ * 0.0.5 (2010-07-31):
11
+ - Fixed a ginormous bug when running under non-REE CRUBY. Yipes.
12
+
13
+ * 0.0.4 (2010-07-31):
14
+ - Ignoring certain testcases (like ActionController::IntegrationTest) when
15
+ calculating the left margin. Does not break if Rails is not present.
16
+ - Added support for JRuby (using ffi-ncurses instead of stty (Zach Holman))
17
+ - Added (very basic) tests
18
+
19
+ * 0.0.3 (2009-11-03):
20
+ - Removed 'XMLOBJECT_GEMSPEC' from gemspec (copy & paste gone wrong) :(
21
+ - Changed the TestCase collector to work like Test::Unit's.
22
+
23
+ * 0.0.2 (2009-10-28):
24
+ - Added this file. :)
25
+ - Fixed http://github.com/jordi/leftright/issues/#issue/1 which prevented
26
+ this from working in 1.8.6 (thanks technoweenie).
27
+
28
+ * 0.0.1 (2009-10-28):
29
+ - First release.
data/bin/lr ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'leftright'
3
+ require $0 = ARGV.first
@@ -0,0 +1,37 @@
1
+ require 'lib/leftright/version'
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'jleo-leftright'
5
+ gem.version = LeftRight::VERSION
6
+
7
+ gem.author, gem.email = 'Joe Leo', 'jleo3@cyrusinnovation.com'
8
+
9
+ gem.summary = "Jordi Bunster's leftright gem with a couple of tweaks."
10
+ gem.description = %{ leftright is kind of like the redgreen gem. It makes
11
+ passing tests look green, exceptions yellow, and failures red. It also
12
+ has a few features that make your workflow a bit faster (see README).
13
+ }.strip!.gsub! /\s+/, ' '
14
+
15
+ gem.has_rdoc = false
16
+
17
+ gem.date = Date.today
18
+ gem.files = %w[
19
+ MIT-LICENSE
20
+ README.rdoc
21
+ WHATSNEW
22
+ bin
23
+ bin/lr
24
+ leftright.gemspec
25
+ lib
26
+ lib/leftright.rb
27
+ lib/leftright
28
+ lib/leftright/autorun.rb
29
+ lib/leftright/color.rb
30
+ lib/leftright/runner.rb
31
+ lib/leftright/tty.rb
32
+ lib/leftright/version.rb
33
+ lib/leftright/force_tty.rb
34
+ ]
35
+
36
+ gem.executables = 'lr'
37
+ end
@@ -0,0 +1,214 @@
1
+ require 'test/unit'
2
+ require 'test/unit/ui/console/testrunner'
3
+
4
+ require 'leftright/version' # to open the module
5
+
6
+ require 'leftright/tty'
7
+ require 'leftright/color'
8
+ require 'leftright/runner'
9
+ require 'leftright/autorun'
10
+
11
+ module LeftRight
12
+ # In counts of ' ':
13
+ MID_SEPARATOR = 1
14
+ RIGHT_MARGIN = 1
15
+ LEFT_MARGIN = 1
16
+
17
+ # This whole thing is fairly gnarly, needing to keep state across multiple
18
+ # parts of the crazyness that is Test::Unit, so we keep it all here.
19
+ #
20
+ def self.state
21
+ @state ||= begin
22
+ fields = [
23
+ :dots, # the number of dots ('.') printed on this line
24
+ :class, # the TestCase-extending class being tested
25
+ :fault, # the current Test::Unit Failure/Error object
26
+ :last_class_printed, # last class printed on the left side
27
+ :previous_failed, # true if the previous test failed/exceptioned
28
+ :skip, # true if the current test was a skip
29
+ :skipped_count # total number of skipped tests so far
30
+ ]
31
+
32
+ state = Struct.new(*fields).new
33
+ state.skipped_count = 0
34
+ state.dots = 0
35
+ state
36
+ end
37
+ end
38
+
39
+ # Gets all descendants of Class that also descend from Test::Unit::TestCase
40
+ #
41
+ def self.testcase_classes
42
+ @testcase_classes ||= begin
43
+ found = []
44
+
45
+ ObjectSpace.each_object(Class) do |klass|
46
+ found << klass if Test::Unit::TestCase > klass
47
+ end
48
+
49
+ # Rails 2.3.5 defines these, and they cramp up my style.
50
+ found.reject! { |k| k.to_s == 'ActiveRecord::TestCase' }
51
+ found.reject! { |k| k.to_s == 'ActionMailer::TestCase' }
52
+ found.reject! { |k| k.to_s == 'ActionView::TestCase' }
53
+ found.reject! { |k| k.to_s == 'ActionController::TestCase' }
54
+ found.reject! { |k| k.to_s == 'ActionController::IntegrationTest' }
55
+ found.reject! { |k| k.to_s == 'ActiveSupport::TestCase' }
56
+
57
+ found
58
+ end
59
+ end
60
+
61
+ # Replaces all instance methods beginning with 'test' in the given class
62
+ # with stubs that skip testing.
63
+ #
64
+ def self.skip_testing_class(klass)
65
+ klass.instance_methods.each do |m|
66
+ if 'test' == m.to_s[0,4]
67
+ klass.send :define_method, m.to_sym do
68
+ ::LeftRight.state.skip = true
69
+ ::LeftRight.state.skipped_count += 1
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ # Formats a class name to display on the left side.
76
+ #
77
+ def self.format_class_name(class_name)
78
+ class_name.chomp 'Test'
79
+ end
80
+
81
+ # Tries to get the terminal width in columns.
82
+ #
83
+ def self.terminal_width
84
+ @terminal_width ||= if defined?(RUBY_ENGINE) && RUBY_ENGINE.match('jruby')
85
+ ncurses_terminal_width
86
+ else
87
+ stty_terminal_width
88
+ end
89
+ end
90
+
91
+ # Uses stty to determine terminal width
92
+ def self.stty_terminal_width
93
+ `stty size`.split[-1].to_i
94
+ rescue
95
+ 0
96
+ end
97
+
98
+ # Uses ffi-ncurses to determine terminal width
99
+ #
100
+ def self.ncurses_terminal_width
101
+ require 'ffi-ncurses'
102
+
103
+ begin
104
+ FFI::NCurses.initscr
105
+ FFI::NCurses.getmaxyx(FFI::NCurses._initscr).reverse.first.to_i
106
+ rescue
107
+ 0
108
+ ensure
109
+ FFI::NCurses.endwin
110
+ end
111
+ rescue LoadError
112
+ puts %{ Under JRuby, you need to install the 'ffi-ncurses' gem,
113
+ since `stty` is not available. }.strip.gsub(/\s+/, ' ')
114
+ exit 1
115
+ end
116
+
117
+ # Tries to get the left side width in columns.
118
+ #
119
+ def self.left_side_width
120
+ @left_side_width ||= begin
121
+ testcase_classes.map do |c|
122
+ format_class_name(c.name).size + LEFT_MARGIN
123
+ end.max
124
+ end
125
+ end
126
+
127
+ # Tries to get the right side width in columns.
128
+ #
129
+ def self.right_side_width
130
+ terminal_width - left_side_width
131
+ end
132
+
133
+ # Returns the given string, right-justified onto the left side.
134
+ #
135
+ def self.justify_left_side(str = '')
136
+ str.to_s.rjust(left_side_width) + (' ' * MID_SEPARATOR)
137
+ end
138
+
139
+ # This gets the class name from the 'test_name' method on a
140
+ # Test::Unit Failure or Error. They look like test_method_name(TestCase),
141
+ #
142
+ def self.extract_class_name(test_name)
143
+ test_name.scan(/\(([^(|)]+)\)/x).flatten.last
144
+ end
145
+
146
+ # Wraps the given lines at word boundaries. Ripped right out of
147
+ # http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/
148
+ #
149
+ def self.wrap(line)
150
+ return line unless tty?
151
+ width = right_side_width - MID_SEPARATOR - RIGHT_MARGIN
152
+ line.gsub /(.{1,#{width}})( +|$)\n?|(.{#{width}})/, "\\1\\3\n"
153
+ end
154
+
155
+ # Returns the current fault as a formatted failure message.
156
+ #
157
+ def self.F(color = C.red)
158
+ # First, we wrap each line individually, to keep existing line breaks:
159
+ lines = state.fault.long_display.split("\n")
160
+
161
+ # Drop the redundant "Failure: ", "test: " (shoulda), "test_", etc
162
+ lines.shift if lines.first.match /Failure:|Error:/
163
+ lines.first.sub! /^test[\ |:|_]?/i, ''
164
+
165
+ # Drop the class name in () from the test method name
166
+ lines.first.sub! /\(#{state.class}\)/, ''
167
+
168
+ # shoulda puts '. :' at the end of method names
169
+ lines.first.sub! /\.\ :\s?/, ':'
170
+
171
+ # Wrap lines before coloring, since the wrapping would get confused
172
+ # by non-printables.
173
+ buffer = lines.map { |line| wrap line.strip }.join.strip
174
+
175
+ # We make interesting parts of the failure message bold:
176
+ [ /(`[^']+')/m, # Stuff in `quotes'
177
+ /("[^"]+")/m, # Stuff in "quotes"
178
+ /([^\/|\[]+\.rb:\d+)/, # Filenames with line numbers (without [box])
179
+ /(\s+undefined\s+)/ ].each do |interesting|
180
+ buffer.gsub! interesting, ( C.bold + '\0' + C.reset + color )
181
+ end
182
+
183
+ # These are great for assert_equal and similar:
184
+ buffer.sub! /(<)(.*)(>\s+expected)/,
185
+ '\1' + C.bold + '\2' + C.reset + color + '\3'
186
+ buffer.sub! /(but\s+was\s+<)(.*)(>\.)/,
187
+ '\1' + C.bold + '\2' + C.reset + color + '\3'
188
+
189
+ color + buffer + C.reset + "\n"
190
+ end
191
+
192
+ # Returns the current fault as a formatted error message.
193
+ #
194
+ def self.E
195
+ F C.red
196
+ end
197
+
198
+ # Returns a passing dot, aware of how many to print per-line.
199
+ #
200
+ def self.P
201
+ return '.' unless tty?
202
+
203
+ state.dots += 1
204
+
205
+ max_dots = right_side_width - RIGHT_MARGIN - MID_SEPARATOR
206
+
207
+ if state.dots >= max_dots
208
+ state.dots = 1
209
+ "\n" + C.green('.')
210
+ else
211
+ C.green '.'
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,12 @@
1
+ # This is the only monkeypatching we do in LeftRight, since
2
+ # Test::Unit::AutoRunner has no API for changing which runner to use. In
3
+ # fact, it has a hardcoded list of runners.
4
+
5
+ class Test::Unit::AutoRunner
6
+ alias :initialize_without_leftright :initialize
7
+
8
+ def initialize(*args)
9
+ initialize_without_leftright *args
10
+ @runner = lambda { |r| LeftRight::Runner }
11
+ end
12
+ end
@@ -0,0 +1,39 @@
1
+ # This is just here to avoid depending on Term::ANSIColor and such, since
2
+ # we need so little, and need it to transparently do nothing when
3
+ # STDOUT is not a terminal.
4
+
5
+ module LeftRight
6
+ module C
7
+ def self.color(string = nil, code = nil)
8
+ if ::LeftRight::tty?
9
+ string.nil? ? "\e[#{code}m" : "\e[#{code}m" + string + "\e[0m"
10
+ else
11
+ string || ''
12
+ end
13
+ end
14
+
15
+ def self.reset(string = nil)
16
+ color string, 0
17
+ end
18
+
19
+ def self.bold(string = nil)
20
+ color string, 1
21
+ end
22
+
23
+ def self.red(string = nil)
24
+ color string, 31
25
+ end
26
+
27
+ def self.green(string = nil)
28
+ color string, 32
29
+ end
30
+
31
+ def self.yellow(string = nil)
32
+ color string, 33
33
+ end
34
+
35
+ def self.cyan(string = nil)
36
+ color string, 36
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,6 @@
1
+ module LeftRight
2
+ # Are we running under a terminal? YES.
3
+ def self.tty?
4
+ true
5
+ end
6
+ end
@@ -0,0 +1,108 @@
1
+ # This is the replacement for Test::Unit::UI::Console::TestRunner
2
+
3
+ module LeftRight
4
+ class Runner < Test::Unit::UI::Console::TestRunner
5
+ # Access to the LeftRight module from the Runner instance. Hopefully to
6
+ # reduce the likelyhood of future name clashes.
7
+ #
8
+ def lr
9
+ LeftRight
10
+ end
11
+
12
+ # We intercept this to be able to set some pertinent state.
13
+ #
14
+ def test_started(test_name)
15
+ name = lr.extract_class_name test_name
16
+ lr.state.class = lr.testcase_classes.detect { |c| c.name == name }
17
+
18
+ super
19
+ end
20
+
21
+ # We intercept this to be able to set some pertinent state
22
+ def add_fault(fault)
23
+ lr.state.fault = fault
24
+ super
25
+ end
26
+
27
+ # Test::Unit uses this method to print '.', 'F', 'E', and possibly
28
+ # others. We do most of the work here, using the state saved in
29
+ # 'add_fault' and 'test_finished'.
30
+ #
31
+ def output_single(captured, *etc)
32
+ # Make sure we are printing a test result
33
+ return super unless %w[ . F E ].include? captured
34
+
35
+ # Do nothing if the method was a skipper
36
+ return if lr.state.skip && '.' == captured
37
+
38
+ output = case captured
39
+ when '.' then lr.P
40
+ when 'F' then lr.F
41
+ when 'E' then lr.E
42
+ end
43
+
44
+ if lr.state.last_class_printed != lr.state.class
45
+ # If we're here, we need to print a new class name on the left side
46
+ lr.state.last_class_printed = lr.state.class
47
+ lr.state.dots = 0
48
+ @io.write "\n"
49
+ @io.write lr.justify_left_side(
50
+ lr.format_class_name(lr.state.class.name))
51
+ elsif captured != '.'
52
+ # This handles the edge case when the first test for a class fails
53
+ @io.write "\n"
54
+ @io.write lr.justify_left_side
55
+ end
56
+
57
+ # Justify all lines but first:
58
+ output.gsub! "\n", "\n" + lr.justify_left_side
59
+
60
+ @io.write output
61
+ ensure # reset all of the nasty state stuff
62
+ @io.flush
63
+ lr.state.previous_failed = captured != '.'
64
+ lr.state.skip = false
65
+ end
66
+
67
+ # This prints the final summary at the end of all tests.
68
+ #
69
+ def finished(elapsed_time)
70
+ passed_count = @result.run_count -
71
+ @result.failure_count -
72
+ @result.error_count - lr.state.skipped_count
73
+
74
+ total = { :passed => passed_count,
75
+ :failed => @result.failure_count,
76
+ :errors => @result.error_count,
77
+ :tests => @result.run_count,
78
+ :skipped => lr.state.skipped_count }
79
+
80
+ results = []
81
+
82
+ unless passed_count.zero?
83
+ total[:passed] = 'all' if passed_count == @result.run_count
84
+ results << lr::C.green("#{total[:passed]} passed")
85
+ end
86
+
87
+ unless lr.state.skipped_count.zero?
88
+ results << lr::C.cyan("#{total[:skipped]} skipped")
89
+ end
90
+
91
+ unless @result.failure_count.zero?
92
+ results << lr::C.red("#{total[:failed]} failed")
93
+ end
94
+
95
+ unless @result.error_count.zero?
96
+ plural = @result.error_count > 1 ? 'errors' : 'error'
97
+ results << lr::C.yellow("#{total[:errors]} #{plural}")
98
+ end
99
+
100
+ @io.write "\n"
101
+ @io.write "\n" unless lr.state.previous_failed
102
+ @io.write "#{total[:tests]} test#{'s' if @result.run_count > 1}: "
103
+ @io.write results.join(', ').reverse.sub(',', 'dna ').reverse # :(
104
+ @io.write "\n" + "\n"
105
+ @io.puts "(#{elapsed_time} seconds)"
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,6 @@
1
+ module LeftRight
2
+ # Are we running under a terminal?
3
+ def self.tty?
4
+ STDOUT.tty?
5
+ end
6
+ end
@@ -0,0 +1,3 @@
1
+ module LeftRight
2
+ VERSION = '0.9.1'
3
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jleo-leftright
3
+ version: !ruby/object:Gem::Version
4
+ hash: 57
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 9
9
+ - 1
10
+ version: 0.9.1
11
+ platform: ruby
12
+ authors:
13
+ - Joe Leo
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-13 00:00:00 -05:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: leftright is kind of like the redgreen gem. It makes passing tests look green, exceptions yellow, and failures red. It also has a few features that make your workflow a bit faster (see README).
23
+ email: jleo3@cyrusinnovation.com
24
+ executables:
25
+ - lr
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - MIT-LICENSE
32
+ - README.rdoc
33
+ - WHATSNEW
34
+ - bin/lr
35
+ - leftright.gemspec
36
+ - lib/leftright.rb
37
+ - lib/leftright/autorun.rb
38
+ - lib/leftright/color.rb
39
+ - lib/leftright/runner.rb
40
+ - lib/leftright/tty.rb
41
+ - lib/leftright/version.rb
42
+ - lib/leftright/force_tty.rb
43
+ has_rdoc: true
44
+ homepage:
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ hash: 3
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.7
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Jordi Bunster's leftright gem with a couple of tweaks.
77
+ test_files: []
78
+