wrong 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,16 +1,10 @@
1
- "Feels so right, it can't be Wrong"
1
+ ## "Feels so right, it can't be Wrong"
2
2
 
3
3
  ## Abstract ##
4
4
 
5
- Wrong provides a general assert method that takes a predicate block. Assertion failure
6
- messages are rich in detail. The Wrong idea is to replace all those countless assert_this,
7
- assert_that library methods which only exist to give a more useful failure message than
8
- "assertion failed". Wrong replaces all of them in one fell swoop, since if you can write it
9
- in Ruby, Wrong can make a sensible failure message out of it.
5
+ Wrong provides a general assert method that takes a predicate block. Assertion failure messages are rich in detail. The Wrong idea is to replace all those countless assert\_this, assert\_that, should\_something library methods which only exist to give a more useful failure message than "assertion failed". Wrong replaces all of them in one fell swoop, since if you can write it in Ruby, Wrong can make a sensible failure message out of it.
10
6
 
11
- Wrong is alpha-quality. We'd very much appreciate feedback and bug reports. There are plenty of things left to be done
12
- to make the results look uniformly clean and beautiful. We want your feedback, and especially to give us cases where
13
- either it blows up or the output is ugly or uninformative.
7
+ Wrong is alpha-quality. We'd very much appreciate feedback and bug reports. There are plenty of things left to be done to make the results look uniformly clean and beautiful. We want your feedback, and especially to give us cases where either it blows up or the output is ugly or uninformative.
14
8
 
15
9
  It relies on [Predicated](http://github.com/sconover/predicated) for its main failure message.
16
10
 
@@ -28,13 +22,13 @@ Wrong provides a simple assert method that takes a block:
28
22
  ==> nil
29
23
 
30
24
  assert {2==1}
31
- ==> Wrong::Assert::AssertionFailedError: Expected (2 == 1), but 2 is not equal to 1
25
+ ==> Expected (2 == 1), but 2 is not equal to 1
32
26
 
33
27
  If your assertion is more than a simple predicate, then Wrong will split it into parts and show you the values of all the relevant subexpressions.
34
28
 
35
29
  x = 7; y = 10; assert { x == 7 && y == 11 }
36
30
  ==>
37
- Wrong::Assert::AssertionFailedError: Expected ((x == 7) and (y == 11)), but
31
+ Expected ((x == 7) and (y == 11)), but
38
32
  (x == 7) is true
39
33
  x is 7
40
34
  (y == 11) is false
@@ -43,19 +37,27 @@ If your assertion is more than a simple predicate, then Wrong will split it into
43
37
  And a companion, 'deny':
44
38
 
45
39
  deny{'abc'.include?('bc')}
46
- ==> Wrong::Assert::AssertionFailedError: Didn't expect "abc".include?("bc"), but 'abc' includes 'bc'
40
+ ==> Didn't expect "abc".include?("bc"), but 'abc' includes 'bc'
47
41
 
48
42
  There's also a convenience method for catching errors:
49
43
 
50
- assert{ catch_raise{raise "vanilla"}.message == "chocolate" }
44
+ assert{ rescuing{raise "vanilla"}.message == "chocolate" }
51
45
  ==>
52
- Wrong::Assert::AssertionFailedError: Expected (catch_raise { raise("vanilla") }.message == "chocolate"), but 'vanilla' is not equal to 'chocolate'
46
+ Expected (rescuing { raise("vanilla") }.message == "chocolate"), but 'vanilla' is not equal to 'chocolate'
47
+
48
+ And one for capturing output streams:
49
+
50
+ assert { capturing { puts "hi" } == "hi\n" }
51
+ assert { capturing(:stderr) { $stderr.puts "hi" } == "hi\n" }
52
+ out, err = capturing(:stdout, :stderr) { ... }
53
+
54
+ More examples are in the file `examples.rb` <http://github.com/alexch/wrong/blob/master/examples.rb>
53
55
 
54
56
  ## Apology ##
55
57
 
56
58
  So does the world need another assertion framework? In fact, it does not! We actually believe the world needs **fewer** assert methods.
57
59
 
58
- The Wrong idea is to replace all those countless assert\_this, assert\_that library methods which only exist to give a more useful failure message than "assertion failed". Wrong replaces all of them in one fell swoop, since if you can write it in Ruby, Wrong can make a sensible failure message out of it.
60
+ The Wrong idea is to replace all those countless assert\_this, assert\_that, should\_something library methods which only exist to give a more useful failure message than "assertion failed". Wrong replaces all of them in one fell swoop, since if you can write it in Ruby, Wrong can make a sensible failure message out of it.
59
61
 
60
62
  Even the lowly workhorse `assert_equal` is bloated compared to Wrong: would you rather write this
61
63
 
@@ -97,13 +99,11 @@ Adapters for various test frameworks sit under wrong/adapters.
97
99
 
98
100
  Currently we support
99
101
 
100
- * Test::Unit
101
- * Minitest
102
-
103
- Coming soon
102
+ * Test::Unit - `require 'wrong/adapters/test_unit'`
103
+ * Minitest - `require 'wrong/adapters/minitest'`
104
+ * RSpec - `require 'wrong/adapters/rspec'`
104
105
 
105
- * RSpec
106
- * ???
106
+ To use these, put the appropriate `require` in your helper; it should extend the framework enough that you can use `assert { }` in your test cases without extra fussing around.
107
107
 
108
108
  ## Explanations ##
109
109
 
@@ -115,7 +115,7 @@ Since the point of Wrong is to make asserts self-explanatory, you should feel fr
115
115
 
116
116
  assert("the sky should be blue") { sky.blue? } # redundant
117
117
 
118
- The failure message of the above would be something like "Expected sky.blue? but sky is :green" which is not made clearer by the addition of "the sky should be blue". We already know it should be blue since we see right there that we're expecting it to be blue.
118
+ The failure message of the above would be something like "Expected sky.blue? but sky is :green" which is not made clearer by the addition of "the sky should be blue". We already know it should be blue since we see right there ("`Expected (sky.blue?)`") that we're expecting it to be blue.
119
119
 
120
120
  And if your assertion code isn't self-explanatory, then that's a hint that you might need to do some refactoring until it is. (Yes, even test code should be clean as a whistle. **Especially** test code.)
121
121
 
@@ -129,6 +129,14 @@ Currently we support special messages for
129
129
  * Enumerable ==
130
130
  * including nested string elements
131
131
 
132
+ ## Color ##
133
+
134
+ Apparently, no test framework is successful unless and until it supports console colors. So now we do. Put
135
+
136
+ Wrong.config[:color] = true
137
+
138
+ in your test helper or rakefile or wherever and get ready to be **bedazzled**.
139
+
132
140
  ## Helper Assert Methods ##
133
141
 
134
142
  If you really want to, you can define your procs in one method, pass it in to another method, and have that method assert it. This is very bizarre and you probably shouldn't do it. Wrong will do its best to figure out where the actual assertion code is but it might not succeed.
@@ -142,4 +150,5 @@ If you're in Ruby 1.8, you **really** shouldn't do it! But if you do, you can us
142
150
 
143
151
  ## Etc ##
144
152
 
145
- Tracker project: <http://www.pivotaltracker.com/projects/109993>
153
+ * Github projects: <http://github.com/alexch/wrong>, <http://github.com/sconover/wrong>
154
+ * Tracker project: <http://www.pivotaltracker.com/projects/109993>
@@ -20,7 +20,7 @@ regarding "part one: selectors on an array (simple enumerable). proving them ou
20
20
  assert{ @arr.select(:numbers).select(:less_than_3) == [1,2] }
21
21
 
22
22
  assert do
23
- catch_raise{ @arr.select(:less_than_3) }.is_a?(ArgumentError)
23
+ rescuing{ @arr.select(:less_than_3) }.is_a?(ArgumentError)
24
24
  #because strings don't respond to <
25
25
  #...there's no substitute for knowing what you're doing.
26
26
  end
@@ -3,3 +3,6 @@ require "predicated/lib/predicated"
3
3
 
4
4
  require "wrong/assert"
5
5
  require "wrong/chunk"
6
+ require "wrong/sexp_ext"
7
+ require "wrong/version"
8
+ require "wrong/config"
@@ -0,0 +1,10 @@
1
+ require "spec"
2
+ require "wrong/assert"
3
+
4
+ Spec::Runner.configure do |config|
5
+ include Wrong::Assert
6
+
7
+ def failure_class
8
+ Spec::Expectations::ExpectationNotMetError
9
+ end
10
+ end
@@ -2,6 +2,7 @@ require "predicated/predicate"
2
2
  require "predicated/from/callable_object"
3
3
  require "predicated/to/sentence"
4
4
  require "wrong/chunk"
5
+ require "wrong/config"
5
6
 
6
7
  #see http://yehudakatz.com/2009/01/18/other-ways-to-wrap-a-method/
7
8
  class Module
@@ -29,7 +30,7 @@ module Wrong
29
30
  aver(:deny, explanation, depth, &block)
30
31
  end
31
32
 
32
- def catch_raise
33
+ def rescuing
33
34
  error = nil
34
35
  begin
35
36
  yield
@@ -39,6 +40,56 @@ module Wrong
39
40
  error
40
41
  end
41
42
 
43
+ # Usage:
44
+ # capturing { puts "hi" } => "hi\n"
45
+ # capturing(:stderr) { $stderr.puts "hi" } => "hi\n"
46
+ # out, err = capturing(:stdout, :stderr) { ... }
47
+ #
48
+ # see http://www.justskins.com/forums/closing-stderr-105096.html for more explanation
49
+ def capturing(*streams)
50
+ streams = [:stdout] if streams.empty?
51
+ original = {}
52
+ captured = {}
53
+
54
+ # reassign the $ variable (which is used by well-behaved code e.g. puts)
55
+ streams.each do |stream|
56
+ original[stream] = (stream == :stdout ? $stdout : $stderr)
57
+ captured[stream] = StringIO.new
58
+ case stream
59
+ when :stdout
60
+ $stdout = captured[stream]
61
+ when :stderr
62
+ $stderr = captured[stream]
63
+ end
64
+ end
65
+
66
+ yield
67
+
68
+ # return either one string, or an array of two strings
69
+ if streams.size == 1
70
+ captured[streams.first].string
71
+ else
72
+ [captured[streams[0]].string, captured[streams[1]].string]
73
+ end
74
+
75
+ ensure
76
+
77
+ streams.each do |stream|
78
+ # bail if stream was reassigned inside the block
79
+ if (stream == :stdout ? $stdout : $stderr) != captured[stream]
80
+ raise "#{stream} was reassigned while being captured"
81
+ end
82
+ # support nested calls to capturing
83
+ original[stream] << captured[stream].string if original[stream].is_a? StringIO
84
+ case stream
85
+ when :stdout
86
+ $stdout = original[stream]
87
+ when :stderr
88
+ $stderr = original[stream]
89
+ end
90
+ end
91
+ end
92
+
42
93
  overridable do
43
94
  def failure_message(method_sym, block, predicate)
44
95
  method_sym == :deny ? predicate.to_sentence : predicate.to_negative_sentence
@@ -59,46 +110,9 @@ module Wrong
59
110
 
60
111
  private
61
112
 
62
- def indent(indent)
63
- (" " * indent)
64
- end
65
-
66
- def newline(indent)
67
- "\n" + self.indent(indent)
68
- end
69
-
70
- # todo: test
71
- def details(block, chunk)
72
- # p chunk.claim
73
- details = ""
74
- parts = chunk.parts
75
- parts.shift # remove the first part, since it's the same as the code
76
- if parts.size > 0
77
- details = "\n"
78
- parts.each do |part|
79
- begin
80
- value = eval(part, block.binding)
81
- unless part == value.inspect
82
- if part =~ /\n/m
83
- part.gsub!(/\n/, newline(2))
84
- part += newline(3)
85
- end
86
- value = value.inspect.gsub("\n", "\n#{indent(3)}")
87
- details << indent(2) << "#{part} is #{value}\n"
88
- end
89
- rescue Exception => e
90
- details << indent(2) << "#{part} raises #{e.class}: #{e.message.gsub("\n", "\n#{indent(3)}")}\n"
91
- if false
92
- puts "#{e.class}: #{e.message} evaluating #{part.inspect}"
93
- puts "\t" + e.backtrace.join("\n\t")
94
- end
95
- end
96
- end
97
- end
98
- details
99
- end
100
-
101
113
  def aver(valence, explanation = nil, depth = 0, &block)
114
+ require "wrong/rainbow" if Wrong.config[:color]
115
+
102
116
  value = block.call
103
117
  value = !value if valence == :deny
104
118
  unless value
@@ -111,11 +125,17 @@ module Wrong
111
125
  rescue Exception
112
126
  nil
113
127
  end
128
+
129
+ code = code.color(:blue) if Wrong.config[:color]
114
130
  message = ""
115
131
  message << "#{explanation}: " if explanation
116
- message << "#{valence == :deny ? "Didn't expect" : "Expected"} #{code}, but"
117
- message << " #{failure_message(valence, block, predicate)}" if predicate
118
- message << details(block, chunk)
132
+ message << "#{valence == :deny ? "Didn't expect" : "Expected"} #{code}, but "
133
+ if predicate
134
+ failure = failure_message(valence, block, predicate)
135
+ failure = failure.bold if Wrong.config[:color]
136
+ message << failure
137
+ end
138
+ message << chunk.details
119
139
  raise failure_class.new(message)
120
140
  end
121
141
  end
@@ -1,5 +1,7 @@
1
1
  require 'ruby_parser'
2
2
  require 'ruby2ruby'
3
+ require "wrong/config"
4
+ require "wrong/sexp_ext"
3
5
 
4
6
  module Wrong
5
7
  class Chunk
@@ -11,15 +13,16 @@ module Wrong
11
13
  # in Ruby 1.8, it reads the source location from the call stack
12
14
  caller[depth].split(":")
13
15
  end
14
- new(file, line)
16
+ new(file, line, block)
15
17
  end
16
18
 
17
- attr_reader :file, :line_number
19
+ attr_reader :file, :line_number, :block
18
20
 
19
21
  # line parameter is 1-based
20
- def initialize(file, line_number)
22
+ def initialize(file, line_number, block = nil)
21
23
  @file = file
22
24
  @line_number = line_number.to_i
25
+ @block = block
23
26
  end
24
27
 
25
28
  def line_index
@@ -80,7 +83,7 @@ module Wrong
80
83
  if sexp.nil?
81
84
  parts(self.claim).compact.uniq
82
85
  else
83
- # todo: extract into Sexp, once I have more unit tests
86
+ # todo: extract some of this into Sexp
84
87
  parts_list = []
85
88
  begin
86
89
  unless sexp.first == :arglist
@@ -100,46 +103,64 @@ module Wrong
100
103
  end
101
104
  end
102
105
 
103
- end
104
-
105
- end
106
+ def details
107
+ require "wrong/rainbow" if Wrong.config[:color]
108
+ s = ""
109
+ parts = self.parts
110
+ parts.shift # remove the first part, since it's the same as the code
111
+
112
+ details = []
113
+
114
+ if parts.size > 0
115
+ parts.each do |part|
116
+ begin
117
+ value = eval(part, block.binding)
118
+ unless part == value.inspect # this skips literals or tautologies
119
+ if part =~ /\n/m
120
+ part.gsub!(/\n/, newline(2))
121
+ part += newline(3)
122
+ end
123
+ value = indent_all(3, value.inspect)
124
+ if Wrong.config[:color]
125
+ part = part.color(:blue)
126
+ value = value.color(:magenta)
127
+ end
128
+ details << indent(2, part, " is ", value)
129
+ end
130
+ rescue Exception => e
131
+ raises = "raises #{e.class}"
132
+ if Wrong.config[:color]
133
+ part = part.color(:blue)
134
+ raises = raises.bold.color(:red)
135
+ end
136
+ details << indent(2, part, " ", raises, ": ", indent_all(3, e.message))
137
+ end
138
+ end
139
+ end
106
140
 
107
- # todo: move to separate monkey patch file
108
- class Sexp < Array
109
- def doop
110
- Marshal.load(Marshal.dump(self))
111
- end
141
+ details.uniq!
142
+ if details.empty?
143
+ ""
144
+ else
145
+ "\n" + details.join("\n") + "\n"
146
+ end
147
+
148
+ end
112
149
 
113
- def to_ruby
114
- d = self.doop
115
- x = Ruby2Ruby.new.process(d)
116
- x
117
- end
150
+ private
151
+
152
+ def indent(indent, *s)
153
+ "#{" " * indent}#{s.join('')}"
154
+ end
118
155
 
119
- def assertion?
120
- self.is_a? Sexp and
121
- self[0] == :iter and
122
- self[1].is_a? Sexp and
123
- self[1][0] == :call and
124
- [:assert, :deny].include? self[1][2] # todo: allow aliases for assert (e.g. "is")
125
- end
156
+ def newline(indent)
157
+ "\n" + self.indent(indent)
158
+ end
126
159
 
127
- def assertion
128
- sexp = self
129
- assertion = if sexp.assertion?
130
- sexp
131
- else
132
- # todo: extract into sexp
133
- nested_assertions.first
134
- end
135
- assertion
136
- end
160
+ def indent_all(amount, s)
161
+ s.gsub("\n", "\n#{indent(amount)}")
162
+ end
137
163
 
138
- private
139
- def nested_assertions
140
- assertions = []
141
- self.each_of_type(:iter) { |sexp| assertions << sexp if sexp.assertion? }
142
- assertions
143
164
  end
144
165
 
145
166
  end
@@ -0,0 +1,13 @@
1
+ # TODO: make it a module, and optionally include it into Float and Fixnum if asked
2
+
3
+ class Float
4
+ def close_to?(other, tolerance = 0.001)
5
+ (self - other.to_f).abs < tolerance
6
+ end
7
+ end
8
+
9
+ class Fixnum
10
+ def close_to?(*args)
11
+ self.to_f.close_to?(*args)
12
+ end
13
+ end
@@ -0,0 +1,8 @@
1
+ module Wrong
2
+ def self.config
3
+ @config ||= Config.new
4
+ end
5
+
6
+ class Config < Hash
7
+ end
8
+ end
@@ -0,0 +1,127 @@
1
+ # Lifted from Rainbow gem, http://sickill.net/blog/2009/03/24/colorizing-console-output-with-rainbow-ruby-gem.html
2
+
3
+ module Sickill
4
+ module Rainbow
5
+ class << self; attr_accessor :enabled; end
6
+ @enabled = STDOUT.tty? && ENV['TERM'] != 'dumb'
7
+
8
+ TERM_COLORS = {
9
+ :black => 0,
10
+ :red => 1,
11
+ :green => 2,
12
+ :yellow => 3,
13
+ :blue => 4,
14
+ :magenta => 5,
15
+ :cyan => 6,
16
+ :white => 7,
17
+ :default => 9,
18
+ }
19
+
20
+ TERM_EFFECTS = {
21
+ :reset => 0,
22
+ :bright => 1,
23
+ :italic => 3,
24
+ :underline => 4,
25
+ :blink => 5,
26
+ :inverse => 7,
27
+ :hide => 8,
28
+ }
29
+
30
+ # Sets foreground color of this text.
31
+ def foreground(*color)
32
+ color = color.first if color.size == 1
33
+ wrap_with_code(get_color_code(color, :foreground))
34
+ end
35
+ alias_method :color, :foreground
36
+ alias_method :colour, :foreground
37
+
38
+ # Sets background color of this text.
39
+ def background(*color)
40
+ color = color.first if color.size == 1
41
+ wrap_with_code(get_color_code(color, :background))
42
+ end
43
+
44
+ # Resets terminal to default colors/backgrounds.
45
+ #
46
+ # It shouldn't be needed to use this method because all methods append terminal reset code to end of string.
47
+ def reset
48
+ wrap_with_code(TERM_EFFECTS[:reset])
49
+ end
50
+
51
+ # Turns on bright/bold for this text.
52
+ def bright
53
+ wrap_with_code(TERM_EFFECTS[:bright])
54
+ end
55
+ alias_method :bold, :bright
56
+
57
+ # Turns on italic style for this text (not well supported by terminal emulators).
58
+ def italic
59
+ wrap_with_code(TERM_EFFECTS[:italic])
60
+ end
61
+
62
+ # Turns on underline decoration for this text.
63
+ def underline
64
+ wrap_with_code(TERM_EFFECTS[:underline])
65
+ end
66
+
67
+ # Turns on blinking attribute for this text (not well supported by terminal emulators).
68
+ def blink
69
+ wrap_with_code(TERM_EFFECTS[:blink])
70
+ end
71
+
72
+ # Inverses current foreground/background colors.
73
+ def inverse
74
+ wrap_with_code(TERM_EFFECTS[:inverse])
75
+ end
76
+
77
+ # Hides this text (set its color to the same as background).
78
+ def hide
79
+ wrap_with_code(TERM_EFFECTS[:hide])
80
+ end
81
+
82
+ protected
83
+ def wrap_with_code(code) #:nodoc:
84
+ return self unless Sickill::Rainbow.enabled
85
+
86
+ out = "#{self}"
87
+ match = out.match(/^(\e\[([\d;]+)m)*/)
88
+ out.insert(match.end(0), "\e[#{code}m")
89
+ out.concat("\e[0m") unless out =~ /\e\[0m$/
90
+ out
91
+ end
92
+
93
+ def get_color_code(color, type) #:nodoc:
94
+ case color
95
+ when Symbol
96
+ validate_color(color)
97
+ TERM_COLORS[color] + (type == :foreground ? 30 : 40)
98
+ when String
99
+ color = color.gsub("#", "")
100
+ r, g, b = color[0..1].to_i(16), color[2..3].to_i(16), color[4..5].to_i(16)
101
+ get_rgb_code(r, g, b, type)
102
+ when Array
103
+ raise ArgumentError.new("Bad number of arguments for RGB color definition, should be 3") unless color.size == 3
104
+ get_rgb_code(color[0], color[1], color[2], type)
105
+ end
106
+ end
107
+
108
+ def get_rgb_code(r, g, b, type) #:nodoc:
109
+ raise ArgumentError.new("RGB value outside 0-255 range") if [r, g, b].min < 0 || [r, g, b].max > 255
110
+ code = { :foreground => 38, :background => 48 }[type]
111
+ index = 16 + (6 * (r / 256.0)).to_i * 36 + (6 * (g / 256.0)).to_i * 6 + (6 * (b / 256.0)).to_i
112
+ "#{code};5;#{index}"
113
+ end
114
+
115
+ def validate_color(color) #:nodoc:
116
+ raise ArgumentError.new("Unknown color, valid colors: #{TERM_COLORS.keys.join(', ')}") unless TERM_COLORS.keys.include?(color)
117
+ end
118
+ end
119
+ end
120
+
121
+ String.send(:include, Sickill::Rainbow)
122
+
123
+ begin
124
+ require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32/
125
+ rescue LoadError
126
+ Sickill::Rainbow.enabled = false
127
+ end
@@ -0,0 +1,40 @@
1
+ require 'ruby_parser'
2
+ require 'ruby2ruby'
3
+
4
+ class Sexp < Array
5
+ def doop
6
+ Marshal.load(Marshal.dump(self))
7
+ end
8
+
9
+ def to_ruby
10
+ d = self.doop
11
+ ruby = Ruby2Ruby.new.process(d)
12
+ ruby
13
+ end
14
+
15
+ def assertion?
16
+ self.is_a? Sexp and
17
+ self[0] == :iter and
18
+ self[1].is_a? Sexp and
19
+ self[1][0] == :call and
20
+ [:assert, :deny].include? self[1][2] # todo: allow aliases for assert (e.g. "is")
21
+ end
22
+
23
+ def assertion
24
+ sexp = self
25
+ assertion = if sexp.assertion?
26
+ sexp
27
+ else
28
+ nested_assertions.first
29
+ end
30
+ assertion
31
+ end
32
+
33
+ private
34
+ def nested_assertions
35
+ assertions = []
36
+ self.each_of_type(:iter) { |sexp| assertions << sexp if sexp.assertion? }
37
+ assertions
38
+ end
39
+
40
+ end
@@ -1,3 +1,3 @@
1
1
  module Wrong
2
- VERSION = "0.2.0" unless defined?(Wrong::VERSION)
2
+ VERSION = "0.3.0" unless defined?(Wrong::VERSION)
3
3
  end
@@ -12,7 +12,7 @@ regarding "basic assert features" do
12
12
  test "disables other assert methods" do
13
13
  test_case_instance = Class.new(MiniTest::Unit::TestCase).new("x")
14
14
  assert{
15
- catch_raise{
15
+ rescuing{
16
16
  test_case_instance.assert_equal(1,1)
17
17
  }.message.include?("has been disabled")
18
18
  }
@@ -21,7 +21,7 @@ regarding "basic assert features" do
21
21
  test "raises minitest assertion failures" do
22
22
  test_case_instance = Class.new(MiniTest::Unit::TestCase).new("x")
23
23
  assert{
24
- catch_raise{
24
+ rescuing{
25
25
  test_case_instance.assert{1==2}
26
26
  }.is_a?(MiniTest::Assertion)
27
27
  }
@@ -48,10 +48,10 @@ regarding "basic assert features" do
48
48
  end
49
49
  end
50
50
 
51
- msg = catch_raise{MyFailingAssertTest.new.test_fail}.message
51
+ msg = rescuing{MyFailingAssertTest.new.test_fail}.message
52
52
  assert{ msg.include?("1 is not equal to 2") }
53
53
 
54
- msg = catch_raise{MyFailingDenyTest.new.test_fail}.message
54
+ msg = rescuing{MyFailingDenyTest.new.test_fail}.message
55
55
  assert{ msg.include?("1 is equal to 1") }
56
56
  end
57
57
 
@@ -0,0 +1,41 @@
1
+ require "./test/test_helper"
2
+ require "wrong/adapters/rspec"
3
+
4
+ regarding "testing rspec" do
5
+ it "works" do
6
+ # I would use
7
+ # out, err = capturing(:stdout, :stderr) do
8
+ # but minitest does its own arcane stream munging and it's not working
9
+
10
+ out = StringIO.new
11
+ err = StringIO.new
12
+ Spec::Runner.use(Spec::Runner::Options.new(out, err))
13
+
14
+ module RSpecWrapper
15
+ include Spec::DSL::Main
16
+ describe "inside rspec land" do
17
+ it "works" do
18
+ sky = "blue"
19
+ assert { sky == "green" }
20
+ end
21
+ end
22
+ end
23
+
24
+ Spec::Runner.options.parse_format("nested")
25
+ Spec::Runner.options.run_examples
26
+
27
+ assert(err.string.index(<<-RSPEC) == 0, "make sure the rspec formatter was used")
28
+ inside rspec land
29
+ works (FAILED - 1)
30
+
31
+ 1)
32
+ 'inside rspec land works' FAILED
33
+ RSPEC
34
+
35
+ failures = Spec::Runner.options.reporter.instance_variable_get(:@failures) # todo: use my own reporter?
36
+ assert !failures.empty?
37
+ exception = failures.first.exception
38
+ assert(exception.is_a? Spec::Expectations::ExpectationNotMetError)
39
+ assert(exception.message == "Expected (sky == \"green\"), but \"blue\" is not equal to \"green\"\n sky is \"blue\"\n")
40
+ end
41
+ end
@@ -78,7 +78,7 @@ regarding "advanced assert features" do
78
78
 
79
79
  test "it's possible (but not advisable) to define procs in different places from the assert call" do
80
80
  x = 10
81
- e = catch_raise do
81
+ e = rescuing do
82
82
  assert_many(lambda { x == 10 })
83
83
  assert_many(lambda { x > 10 })
84
84
  end
@@ -0,0 +1,57 @@
1
+ require "./test/test_helper"
2
+
3
+ require "wrong/assert"
4
+ require "wrong/adapters/minitest"
5
+
6
+ regarding "a tool for capturing output" do
7
+
8
+ test "captures stdout" do
9
+ assert {
10
+ capturing { puts "hi" } == "hi\n"
11
+ }
12
+ end
13
+
14
+ test "captures stderr" do
15
+ assert {
16
+ capturing(:stderr) { $stderr.puts "hi" } == "hi\n"
17
+ }
18
+ end
19
+
20
+ test "captures both" do
21
+ out, err = capturing(:stdout, :stderr) do
22
+ $stdout.puts "hi"
23
+ $stderr.puts "bye"
24
+ end
25
+
26
+ assert { out == "hi\n"}
27
+ assert { err == "bye\n"}
28
+
29
+ end
30
+
31
+ test "supports nesting" do
32
+ outside = nil
33
+ inside = nil
34
+ outside = capturing do
35
+ puts "bread"
36
+ inside = capturing do
37
+ puts "ham"
38
+ end
39
+ puts "more bread"
40
+ end
41
+
42
+ assert { inside == "ham\n"}
43
+ assert { outside == "bread\nham\nmore bread\n"}
44
+ end
45
+
46
+
47
+ test "bails if stream was reassigned" do
48
+ e = rescuing do
49
+ capturing do
50
+ $stdout = StringIO.new # uh-oh!
51
+ end
52
+ end
53
+ assert { e.message =~ /^stdout was reassigned/ }
54
+ end
55
+
56
+
57
+ end
@@ -136,7 +136,7 @@ regarding Chunk do
136
136
  error = get_error {
137
137
  chunk.claim
138
138
  }
139
- assert error.message.include?("Could not parse")
139
+ assert error.message.include?("Could not parse")
140
140
  end
141
141
  end
142
142
 
@@ -159,78 +159,81 @@ z
159
159
  PARTS
160
160
  end
161
161
  end
162
- end
163
162
 
164
- regarding Sexp do
165
- regarding "#doop" do
166
- test "deeply duplicates the sexp" do
167
- original = RubyParser.new.parse("x == 5")
168
- duplicate = original.doop
169
- assert(original.object_id != duplicate.object_id)
170
- assert(original[1].object_id != duplicate[1].object_id)
171
- assert(original[1][3].object_id != duplicate[1][3].object_id)
172
- assert(original[3].object_id != duplicate[3].object_id)
163
+ regarding "#details" do
164
+ def details(&block)
165
+ chunk = Chunk.from_block(block, 1)
166
+ d = chunk.details
167
+ # puts d
168
+ d
173
169
  end
174
- end
175
170
 
176
- regarding "#to_ruby" do
177
- test "converts the sexp to ruby code" do
178
- sexp = RubyParser.new.parse("x == 5")
179
- assert sexp.to_ruby == "(x == 5)"
171
+ test "returns an empty string if there are no parts" do
172
+ d = details { assert { true } }
173
+ assert d == ""
180
174
  end
181
175
 
182
- test "leaves the original sexp alone" do
183
- sexp = RubyParser.new.parse("x == 5")
184
- assert sexp.to_ruby == "(x == 5)"
185
- assert sexp.to_ruby == "(x == 5)"
176
+ test "returns an string beginning with a newline if there are parts" do
177
+ x = 10
178
+ d = details { assert { x == 10 } }
179
+ assert d == "\n x is 10\n"
186
180
  end
187
- end
188
181
 
189
- regarding "#assertion? with a question mark" do
190
- test "matches an sexp that looks like assert { }" do
191
- sexp = RubyParser.new.parse("assert { true }")
192
- assert sexp.assertion?
193
- end
194
-
195
- test "matches an sexp that looks like assert(message) { }" do
196
- sexp = RubyParser.new.parse("assert('hi') { true }")
197
- assert sexp.assertion?
182
+ test "skips literals" do
183
+ d = details { assert { 10 == 11 } }
184
+ assert d == ""
198
185
  end
199
186
 
200
- test "matches an sexp that looks like deny { }" do
201
- sexp = RubyParser.new.parse("deny { false }")
202
- assert sexp.assertion?
187
+ test "shows lots of details" do
188
+ x = 10
189
+ d = details { assert { (x * (x - 10)) == (x / (x + 10)) } }
190
+ assert d == <<-DETAILS
191
+
192
+ (x * (x - 10)) is 0
193
+ x is 10
194
+ (x - 10) is 0
195
+ (x / (x + 10)) is 0
196
+ (x + 10) is 20
197
+ DETAILS
203
198
  end
204
199
 
205
- test "doesn't match an sexp that calls assert without a block" do
206
- sexp = RubyParser.new.parse("assert(true)")
207
- assert !sexp.assertion?
200
+ test "skips duplicates" do
201
+ x = 10
202
+ d = details { assert { (x + 5) == 1 + (x + 5) } }
203
+ assert d == <<-DETAILS
204
+
205
+ (x + 5) is 15
206
+ x is 10
207
+ (1 + (x + 5)) is 16
208
+ DETAILS
208
209
  end
209
210
 
210
- test "doesn't match a normal sexp" do
211
- sexp = RubyParser.new.parse("x == 5")
212
- assert !sexp.assertion?
211
+ test "shows exceptions" do
212
+ d = details { assert { (raise "hi") == 1} }
213
+ assert d == "\n raise(\"hi\") raises RuntimeError: hi\n"
213
214
  end
214
- end
215
215
 
216
- regarding "#assertion" do
217
- test "matches a top-level sexp that looks like assert { }" do
218
- sexp = RubyParser.new.parse("assert { true }")
219
- code = sexp.assertion.to_ruby
220
- assert code == "assert { true }"
216
+ test "indents newlines inside the exception message" do
217
+ d = details { assert { (raise "hello\nsailor") == 1} }
218
+ assert d == "\n raise(\"hello\\nsailor\") raises RuntimeError: hello\n sailor\n"
221
219
  end
222
-
223
- test "matches a nested sexp that looks like assert { }" do
224
- sexp = RubyParser.new.parse("nesting { assert { true } }")
225
- code = sexp.assertion.to_ruby
226
- assert code == "assert { true }"
220
+
221
+ test "inspects values" do
222
+ x = "flavor:\tvanilla"
223
+ d = details { assert { x == "flavor:\tchocolate" } }
224
+ # this means it's a literal slash plus t inside double quotes -- i.e. it shows the escaped (inspected) string
225
+ assert d == "\n" + ' x is "flavor:\tvanilla"' + "\n"
227
226
  end
228
227
 
229
- test "matches the first nested sexp that looks like assert { }" do
230
- sexp = RubyParser.new.parse("nesting { assert { true } or assert { false } }")
231
- code = sexp.assertion.to_ruby
232
- assert code == "assert { true }"
228
+ test "indents unescaped newlines inside the inspected value" do
229
+ weirdo = Object.new
230
+ def weirdo.inspect
231
+ "first\nsecond\nthird"
232
+ end
233
+ x = weirdo
234
+ d = details { assert { x == "foo" }}
235
+ assert d == "\n x is first\n second\n third\n"
233
236
  end
234
- end
235
237
 
238
+ end
236
239
  end
@@ -0,0 +1,39 @@
1
+ require "./test/test_helper"
2
+ require "wrong/close_to"
3
+ require "wrong/assert"
4
+
5
+ regarding "#close_to? (monkey patch for float comparison)" do
6
+ include Wrong::Assert
7
+
8
+ it "says two equal floats are equal" do
9
+ assert { 5.0.close_to? 5.0 }
10
+ end
11
+
12
+ it "says two unequal floats are unequal" do
13
+ deny { 5.0.close_to? 6.0 }
14
+ end
15
+
16
+ it "has a default tolerance of 0.001" do
17
+ assert { 5.0.close_to? 5.0001 }
18
+ assert { 5.0.close_to? 5.0009 }
19
+ deny { 5.0.close_to? 5.001 }
20
+ deny { 5.0.close_to? 5.01 }
21
+ end
22
+
23
+ it "takes a tolerance parameter" do
24
+ assert { 5.0.close_to? 5.01, 0.1 }
25
+ end
26
+
27
+ it "excludes the tolerance maximum" do
28
+ assert { 5.0.close_to? 5.9999, 1.0 }
29
+ deny { 5.0.close_to? 6.00, 1.0 }
30
+ end
31
+
32
+ it "works for integers too" do
33
+ assert { 5.close_to? 5 }
34
+ assert { 5.close_to? 5.0001 }
35
+ deny { 5.close_to? 5.1 }
36
+ assert { 5.close_to? 5.1, 0.5 }
37
+ end
38
+
39
+ end
@@ -0,0 +1,32 @@
1
+ require "./test/test_helper"
2
+ require "wrong/config"
3
+ require "wrong/assert"
4
+
5
+ regarding Wrong::Config do
6
+
7
+ # hope this doesn't blow up, but I'll try to use Wrong to test the Config object
8
+ include Wrong::Assert
9
+
10
+ before do
11
+ Wrong.config.clear
12
+ end
13
+
14
+ test "singleton" do
15
+ c = Wrong.config
16
+ assert { c.is_a?(Wrong::Config) }
17
+ c2 = Wrong.config
18
+ assert { c.object_id == c2.object_id }
19
+ end
20
+
21
+ # test "reading from a .wrong file"
22
+
23
+ test "getting an undeclared setting" do
24
+ assert { Wrong.config[:foo].nil? }
25
+ end
26
+
27
+ test "setting and getting" do
28
+ Wrong.config[:foo] = "bar"
29
+ assert { Wrong.config[:foo] == "bar" }
30
+ end
31
+
32
+ end
@@ -7,7 +7,7 @@ regarding "when you're comparing strings and they don't match, show me the diff
7
7
 
8
8
  def assert_string_diff_message(first_array, second_array, expected_error_message)
9
9
  assert {
10
- catch_raise {
10
+ rescuing {
11
11
  assert { first_array == second_array }
12
12
  }.message.include?(expected_error_message)
13
13
  }
@@ -15,12 +15,12 @@ regarding "when you're comparing strings and they don't match, show me the diff
15
15
 
16
16
  test "don't attempt to do this if the assertion is not of the form a_array==b_array" do
17
17
  deny {
18
- catch_raise {
18
+ rescuing {
19
19
  assert { [1]==2 }
20
20
  }.message.include?("diff")
21
21
  }
22
22
  deny {
23
- catch_raise {
23
+ rescuing {
24
24
  assert { nil==[1] }
25
25
  }.message.include?("diff")
26
26
  }
@@ -28,7 +28,7 @@ regarding "when you're comparing strings and they don't match, show me the diff
28
28
 
29
29
  test "simple" do
30
30
  assert {
31
- catch_raise {
31
+ rescuing {
32
32
  assert { ["a"]==["b"] }
33
33
  }.message.include?("diff")
34
34
  }
@@ -7,7 +7,7 @@ regarding "when you're comparing strings and they don't match, show me the diff
7
7
 
8
8
  def assert_string_diff_message(first_string, second_string, str)
9
9
  assert{
10
- catch_raise{
10
+ rescuing{
11
11
  assert{first_string == second_string}
12
12
  }.message.include?(str)
13
13
  }
@@ -15,22 +15,22 @@ regarding "when you're comparing strings and they don't match, show me the diff
15
15
 
16
16
  test "don't attempt to do this if the assertion is not of the form a_string==b_string" do
17
17
  deny{
18
- catch_raise{
18
+ rescuing{
19
19
  assert{1==2}
20
20
  }.message.include?("diff")
21
21
  }
22
22
  deny{
23
- catch_raise{
23
+ rescuing{
24
24
  assert{"a"==2}
25
25
  }.message.include?("diff")
26
26
  }
27
27
  deny{
28
- catch_raise{
28
+ rescuing{
29
29
  assert{1=="a"}
30
30
  }.message.include?("diff")
31
31
  }
32
32
  deny{
33
- catch_raise{
33
+ rescuing{
34
34
  assert{nil=="a"}
35
35
  }.message.include?("diff")
36
36
  }
@@ -38,7 +38,7 @@ regarding "when you're comparing strings and they don't match, show me the diff
38
38
 
39
39
  test "simple" do
40
40
  assert{
41
- catch_raise{
41
+ rescuing{
42
42
  assert{"a"=="b"}
43
43
  }.message.include?("diff")
44
44
  }
@@ -9,8 +9,8 @@ regarding "a tool for rescuing errors" do
9
9
  class BlueError < StandardError; end
10
10
 
11
11
  test "catch the error and assert on it" do
12
- assert{ catch_raise{raise RedError.new}.is_a?(RedError) }
13
- assert{ catch_raise{"x"}.nil? }
12
+ assert{ rescuing{raise RedError.new}.is_a?(RedError) }
13
+ assert{ rescuing{"x"}.nil? }
14
14
  end
15
15
 
16
- end
16
+ end
@@ -0,0 +1,80 @@
1
+ require "./test/test_helper"
2
+ require "wrong/sexp_ext"
3
+
4
+ regarding Sexp do
5
+ regarding "#doop" do
6
+ test "deeply duplicates the sexp" do
7
+ original = RubyParser.new.parse("x == 5")
8
+ duplicate = original.doop
9
+ assert(original.object_id != duplicate.object_id)
10
+ assert(original[1].object_id != duplicate[1].object_id)
11
+ assert(original[1][3].object_id != duplicate[1][3].object_id)
12
+ assert(original[3].object_id != duplicate[3].object_id)
13
+ end
14
+ end
15
+
16
+ def parse(ruby)
17
+ RubyParser.new.parse(ruby)
18
+ end
19
+
20
+ regarding "#to_ruby" do
21
+ test "converts the sexp to ruby code" do
22
+ sexp = parse("x == 5")
23
+ assert sexp.to_ruby == "(x == 5)"
24
+ end
25
+
26
+ test "leaves the original sexp alone" do
27
+ sexp = parse("x == 5")
28
+ assert sexp.to_ruby == "(x == 5)"
29
+ assert sexp.to_ruby == "(x == 5)" # intended
30
+ end
31
+ end
32
+
33
+ regarding "#assertion? with a question mark" do
34
+ test "matches an sexp that looks like assert { }" do
35
+ sexp = parse("assert { true }")
36
+ assert sexp.assertion?
37
+ end
38
+
39
+ test "matches an sexp that looks like assert(message) { }" do
40
+ sexp = parse("assert('hi') { true }")
41
+ assert sexp.assertion?
42
+ end
43
+
44
+ test "matches an sexp that looks like deny { }" do
45
+ sexp = parse("deny { false }")
46
+ assert sexp.assertion?
47
+ end
48
+
49
+ test "doesn't match an sexp that calls assert without a block" do
50
+ sexp = parse("assert(true)")
51
+ assert !sexp.assertion?
52
+ end
53
+
54
+ test "doesn't match a normal sexp" do
55
+ sexp = parse("x == 5")
56
+ assert !sexp.assertion?
57
+ end
58
+ end
59
+
60
+ regarding "#assertion" do
61
+ test "matches a top-level sexp that looks like assert { }" do
62
+ sexp = parse("assert { true }")
63
+ code = sexp.assertion.to_ruby
64
+ assert code == "assert { true }"
65
+ end
66
+
67
+ test "matches a nested sexp that looks like assert { }" do
68
+ sexp = parse("nesting { assert { true } }")
69
+ code = sexp.assertion.to_ruby
70
+ assert code == "assert { true }"
71
+ end
72
+
73
+ test "matches the first nested sexp that looks like assert { }" do
74
+ sexp = parse("nesting { assert { true } or assert { false } }")
75
+ code = sexp.assertion.to_ruby
76
+ assert code == "assert { true }"
77
+ end
78
+ end
79
+
80
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wrong
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 2
8
+ - 3
9
9
  - 0
10
- version: 0.2.0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Steve Conover
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-08-22 00:00:00 -07:00
19
+ date: 2010-08-26 00:00:00 -07:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -174,24 +174,34 @@ files:
174
174
  - lib/predicated/test_integration/suite.rb
175
175
  - lib/predicated/test_integration/usage_test.rb
176
176
  - lib/wrong/adapters/minitest.rb
177
+ - lib/wrong/adapters/rspec.rb
177
178
  - lib/wrong/adapters/test_unit.rb
178
179
  - lib/wrong/assert.rb
179
180
  - lib/wrong/chunk.rb
181
+ - lib/wrong/close_to.rb
182
+ - lib/wrong/config.rb
180
183
  - lib/wrong/message/array_diff.rb
181
184
  - lib/wrong/message/string_diff.rb
182
185
  - lib/wrong/message/test_context.rb
186
+ - lib/wrong/rainbow.rb
187
+ - lib/wrong/sexp_ext.rb
183
188
  - lib/wrong/version.rb
184
189
  - lib/wrong.rb
185
190
  - README.markdown
186
191
  - test/adapters/minitest_test.rb
192
+ - test/adapters/rspec_test.rb
187
193
  - test/adapters/test_unit_test.rb
188
194
  - test/assert_test.rb
189
- - test/catch_raise_test.rb
195
+ - test/capturing_test.rb
190
196
  - test/chunk_test.rb
197
+ - test/close_to_test.rb
198
+ - test/config_test.rb
191
199
  - test/failures_test.rb
192
200
  - test/message/array_diff_test.rb
193
201
  - test/message/string_diff_test.rb
194
202
  - test/message/test_context_text.rb
203
+ - test/rescuing_test.rb
204
+ - test/sexp_ext_test.rb
195
205
  - test/suite.rb
196
206
  - test/test_helper.rb
197
207
  has_rdoc: true
@@ -230,13 +240,18 @@ specification_version: 3
230
240
  summary: Wrong provides a general assert method that takes a predicate block. Assertion failure messages are rich in detail.
231
241
  test_files:
232
242
  - test/adapters/minitest_test.rb
243
+ - test/adapters/rspec_test.rb
233
244
  - test/adapters/test_unit_test.rb
234
245
  - test/assert_test.rb
235
- - test/catch_raise_test.rb
246
+ - test/capturing_test.rb
236
247
  - test/chunk_test.rb
248
+ - test/close_to_test.rb
249
+ - test/config_test.rb
237
250
  - test/failures_test.rb
238
251
  - test/message/array_diff_test.rb
239
252
  - test/message/string_diff_test.rb
240
253
  - test/message/test_context_text.rb
254
+ - test/rescuing_test.rb
255
+ - test/sexp_ext_test.rb
241
256
  - test/suite.rb
242
257
  - test/test_helper.rb