wrong 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,7 @@
1
1
  ## "Feels so right, it can't be Wrong"
2
2
 
3
+ ![Someone is Wrong on the Internet](http://imgs.xkcd.com/comics/duty_calls.png)
4
+
3
5
  ## Abstract ##
4
6
 
5
7
  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.
@@ -8,7 +10,7 @@ Wrong is alpha-quality. We'd very much appreciate feedback and bug reports. Ther
8
10
 
9
11
  It relies on [Predicated](http://github.com/sconover/predicated) for its main failure message.
10
12
 
11
- Inspired by [assert { 2.0 }](http://assert2.rubyforge.org/) but rewritten from scratch to be compatible with Ruby 1.8 and 1.9.
13
+ Inspired by [assert { 2.0 }](http://assert2.rubyforge.org/) but rewritten from scratch. Compatible with Ruby 1.8 and 1.9.
12
14
 
13
15
  ## Usage ##
14
16
 
@@ -18,10 +20,10 @@ Wrong provides a simple assert method that takes a block:
18
20
 
19
21
  include Wrong::Assert
20
22
 
21
- assert {1==1}
23
+ assert { 1 == 1 }
22
24
  ==> nil
23
25
 
24
- assert {2==1}
26
+ assert { 2 == 1 }
25
27
  ==> Expected (2 == 1), but 2 is not equal to 1
26
28
 
27
29
  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.
@@ -33,7 +35,19 @@ If your assertion is more than a simple predicate, then Wrong will split it into
33
35
  x is 7
34
36
  (y == 11) is false
35
37
  y is 10
36
-
38
+
39
+ --
40
+
41
+ age = 24
42
+ name = "Gaga"
43
+ assert { age >= 18 && ["Britney", "Snooki"].include?(name) }
44
+ ==>
45
+ Expected ((age >= 18) and ["Britney", "Snooki"].include?(name)), but
46
+ (age >= 18) is true
47
+ age is 24
48
+ ["Britney", "Snooki"].include?(name) is false
49
+ name is "Gaga"
50
+
37
51
  And a companion, 'deny':
38
52
 
39
53
  deny{'abc'.include?('bc')}
@@ -51,8 +65,19 @@ And one for capturing output streams:
51
65
  assert { capturing(:stderr) { $stderr.puts "hi" } == "hi\n" }
52
66
  out, err = capturing(:stdout, :stderr) { ... }
53
67
 
68
+ If you want to compare floats, try this:
69
+
70
+ require "wrong/close_to"
71
+
72
+ assert { 5.0.close_to?(5.0001) } # default tolerance = 0.001
73
+ assert { 5.0.close_to?(5.1, 0.5) } # optional tolerance parameter
74
+
54
75
  More examples are in the file `examples.rb` <http://github.com/alexch/wrong/blob/master/examples.rb>
55
76
 
77
+ There's also a spreadsheet showing a translation from Test::Unit and RSpec to Wrong, with notes, at [this Google Doc](https://spreadsheets.google.com/pub?key=0AouPn6oLrimWdE0tZDVOWnFGMzVPZy0tWHZwdnhFYkE&hl=en&output=html). (Ask <alexch@gmail.com> if you want editing privileges.)
78
+
79
+ And don't miss the [slideshare presentation](http://www.slideshare.net/alexchaffee/wrong-5069976).
80
+
56
81
  ## Apology ##
57
82
 
58
83
  So does the world need another assertion framework? In fact, it does not! We actually believe the world needs **fewer** assert methods.
@@ -67,7 +92,7 @@ or this
67
92
 
68
93
  assert { time == money }
69
94
 
70
- ? The Wrong version has the advantage of being plain, transparent Ruby code, not an awkward DSL that moves "equal" out of its natural place between the comparands. Plus, WYSIWYG! You know just from looking at it that "equal" means `==`, not `eql?` or `===` or `=~`.
95
+ ? The Wrong way has the advantage of being plain, transparent Ruby code, not an awkward DSL that moves "equal" out of its natural place between the comparands. Plus, WYSIWYG! You know just from looking at it that "equal" means `==`, not `eql?` or `===` or `=~`.
71
96
 
72
97
  Moreover, much like TDD itself, Wrong encourages you to write cleaner code. If your assertion messages are not clear and "Englishy", then maybe it's time for you to refactor a bit -- extract an informatively named variable or method, maybe push some function onto its natural object *a la* the [Law of Demeter](http://en.wikipedia.org/wiki/Law_of_Demeter)...
73
98
 
@@ -115,11 +140,11 @@ Since the point of Wrong is to make asserts self-explanatory, you should feel fr
115
140
 
116
141
  assert("the sky should be blue") { sky.blue? } # redundant
117
142
 
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.
143
+ 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
144
 
120
145
  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
146
 
122
- ## Special Formatting ##
147
+ ## Formatters ##
123
148
 
124
149
  Enhancements for error messages sit under wrong/message.
125
150
 
@@ -129,6 +154,34 @@ Currently we support special messages for
129
154
  * Enumerable ==
130
155
  * including nested string elements
131
156
 
157
+ To use these formatters, you have to explicitly `require` them! You may also need to `gem install diff-lcs` (since it's an optional dependency).
158
+
159
+ require "wrong/message/string_diff"
160
+ assert { "the quick brown fox jumped over the lazy dog" ==
161
+ "the quick brown hamster jumped over the lazy gerbil" }
162
+ ==>
163
+ Expected ("the quick brown fox jumped over the lazy dog" == "the quick brown hamster jumped over the lazy gerbil"), but "the quick brown fox jumped over the lazy dog" is not equal to "the quick brown hamster jumped over the lazy gerbil"
164
+
165
+ string diff:
166
+ the quick brown fox jumped over the lazy dog
167
+ ^^^
168
+ the quick brown hamster jumped over the lazy gerbil
169
+ ^^^^^^^
170
+ --
171
+
172
+ require "wrong/message/array_diff"
173
+ assert { ["venus", "mars", "pluto", "saturn"] ==
174
+ ["venus", "earth", "pluto", "neptune"] }
175
+ ==>
176
+ Expected (["venus", "mars", "pluto", "saturn"] == ["venus", "earth", "pluto", "neptune"]), but ["venus", "mars", "pluto", "saturn"] is not equal to ["venus", "earth", "pluto", "neptune"]
177
+
178
+ array diff:
179
+ ["venus", "mars" , "pluto", "saturn" ]
180
+ ["venus", "earth", "pluto", "neptune"]
181
+ ^ ^
182
+
183
+ [Bug: turns out 'diff' and 'diff-lcs' are incompatible with each other. We're working on a fix.]
184
+
132
185
  ## Color ##
133
186
 
134
187
  Apparently, no test framework is successful unless and until it supports console colors. So now we do. Put
@@ -137,6 +190,29 @@ Apparently, no test framework is successful unless and until it supports console
137
190
 
138
191
  in your test helper or rakefile or wherever and get ready to be **bedazzled**.
139
192
 
193
+ ## Aliases ##
194
+
195
+ An end to the language wars! Name your "assert" and "deny" methods anything you want. Here are some suggestions:
196
+
197
+ Wrong.config.alias_assert(:expect)
198
+ Wrong.config.alias_assert(:should) # This looks nice with RSpec
199
+ Wrong.config.alias_assert(:confirm)
200
+ Wrong.config.alias_assert(:be)
201
+
202
+ Wrong.config.alias_assert(:is)
203
+ Wrong.config.alias_deny(:aint)
204
+
205
+ Wrong.config.alias_assert(:assure)
206
+ Wrong.config.alias_deny(:refute)
207
+
208
+ Wrong.config.alias_assert(:yep)
209
+ Wrong.config.alias_deny(:nope)
210
+
211
+ Wrong.config.alias_assert(:yay!)
212
+ Wrong.config.alias_deny(:boo!)
213
+
214
+ Just don't use "`aver`" since we took that one for an internal method in `Wrong::Assert`.
215
+
140
216
  ## Helper Assert Methods ##
141
217
 
142
218
  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.
@@ -152,3 +228,5 @@ If you're in Ruby 1.8, you **really** shouldn't do it! But if you do, you can us
152
228
 
153
229
  * Github projects: <http://github.com/alexch/wrong>, <http://github.com/sconover/wrong>
154
230
  * Tracker project: <http://www.pivotaltracker.com/projects/109993>
231
+ * [Wrong way translation table (from RSpec and Test::Unit)](https://spreadsheets.google.com/pub?key=0AouPn6oLrimWdE0tZDVOWnFGMzVPZy0tWHZwdnhFYkE&hl=en&output=html). (Ask <alexch@gmail.com> if you want editing privileges.)
232
+ * [the Wrong slides I presented at Carbon Five](http://www.slideshare.net/alexchaffee/wrong-5069976)
@@ -9,27 +9,27 @@ require "predicated/from/ruby_code_string"
9
9
  #see http://blog.zenspider.com/2009/04/parsetree-eol.html
10
10
  #
11
11
  #} if RUBY_VERSION =~/^1.9/
12
-
13
- raise %{
14
-
15
- You appear to be using ruby 1.8.7 and you don't have
16
- an INLINEDIR environment variable set to a valid directory.
17
-
18
- ParseTree (used by "from_callable_object") uses RubyInline.
19
- RubyInline requires that the INLINEDIR environment variable point
20
- to a directory. The easiest thing to do is to just go
21
- create a directory somewhere - let's say, ~/inlinedir,
22
- and point the INLINEDIR at it. In bash this would be:
23
-
24
- mkdir ~/inlinedir
25
- export INLINEDIR=~/inlinedir
26
-
27
- You'll probably want to put this in .bash_profile too.
28
-
29
- Sorry for the inconvenience. I hope the value you'll
30
- get out of "from_callable_object" makes it all worth it.
31
-
32
- } if RUBY_VERSION=="1.8.7" && !ENV["INLINEDIR"]
12
+ #
13
+ #raise %{
14
+ #
15
+ #You appear to be using ruby 1.8.7 and you don't have
16
+ #an INLINEDIR environment variable set to a valid directory.
17
+ #
18
+ #ParseTree (used by "from_callable_object") uses RubyInline.
19
+ #RubyInline requires that the INLINEDIR environment variable point
20
+ #to a directory. The easiest thing to do is to just go
21
+ #create a directory somewhere - let's say, ~/inlinedir,
22
+ #and point the INLINEDIR at it. In bash this would be:
23
+ #
24
+ #mkdir ~/inlinedir
25
+ #export INLINEDIR=~/inlinedir
26
+ #
27
+ #You'll probably want to put this in .bash_profile too.
28
+ #
29
+ #Sorry for the inconvenience. I hope the value you'll
30
+ #get out of "from_callable_object" makes it all worth it.
31
+ #
32
+ #} if RUBY_VERSION=="1.8.7" && !ENV["INLINEDIR"]
33
33
  #Procs and lambdas are "callable objects"
34
34
 
35
35
  module Predicated
@@ -3,7 +3,7 @@ require "predicated/evaluate"
3
3
 
4
4
  module Predicated
5
5
 
6
- module ContainerSentence
6
+ module Conjunction
7
7
  def to_sentence
8
8
  left.to_sentence + joining_str + right.to_sentence
9
9
  end
@@ -12,9 +12,9 @@ module Predicated
12
12
  "This is not true: " + to_sentence
13
13
  end
14
14
  end
15
-
16
- class And; include ContainerSentence; def joining_str; " and " end; end
17
- class Or; include ContainerSentence; def joining_str; " or " end;end
15
+
16
+ class And; include Conjunction; def joining_str; " and " end; end
17
+ class Or; include Conjunction; def joining_str; " or " end;end
18
18
 
19
19
  class Not
20
20
  def to_sentence
@@ -249,4 +249,4 @@ regarding "prove out examples used in the README" do
249
249
  gsub(%{.gsub(/\\s/, "")}, "")
250
250
  end
251
251
 
252
- end
252
+ end
@@ -2,10 +2,7 @@ require "wrong/assert"
2
2
 
3
3
  class MiniTest::Unit::TestCase
4
4
  include Wrong::Assert
5
-
6
- Wrong::Assert.disable_existing_assert_methods(self)
7
-
8
5
  def failure_class
9
6
  MiniTest::Assertion
10
7
  end
11
- end
8
+ end
@@ -2,9 +2,7 @@ require "wrong/assert"
2
2
 
3
3
  class Test::Unit::TestCase
4
4
  include Wrong::Assert
5
-
6
- Wrong::Assert.disable_existing_assert_methods(self)
7
-
5
+
8
6
  def failure_class
9
7
  Test::Unit::AssertionFailedError
10
8
  end
@@ -22,12 +22,29 @@ module Wrong
22
22
  AssertionFailedError
23
23
  end
24
24
 
25
- def assert(explanation = nil, depth = 0, &block)
26
- aver(:assert, explanation, depth, &block)
25
+ # Actual signature: assert(explanation = nil, depth = 0, block)
26
+ def assert(*args, &block)
27
+ if block.nil?
28
+ begin
29
+ super
30
+ rescue NoMethodError => e
31
+ # note: we're not raising an AssertionFailedError because this is a programmer error, not a failed assertion
32
+ raise "You must pass a block to Wrong's assert and deny methods"
33
+ end
34
+ else
35
+ aver(:assert, *args, &block)
36
+ end
27
37
  end
28
38
 
29
- def deny(explanation = nil, depth = 0, &block)
30
- aver(:deny, explanation, depth, &block)
39
+ # Actual signature: deny(explanation = nil, depth = 0, block)
40
+ def deny(*args, &block)
41
+ if block.nil?
42
+ test = args.first
43
+ msg = args[1]
44
+ assert !test, msg # this makes it get passed up to the framework
45
+ else
46
+ aver(:deny, *args, &block)
47
+ end
31
48
  end
32
49
 
33
50
  def rescuing
@@ -96,18 +113,6 @@ module Wrong
96
113
  end
97
114
  end
98
115
 
99
- def self.disable_existing_assert_methods(the_class)
100
- (the_class.public_instance_methods.
101
- map { |m| m.to_s }.
102
- select { |m| m =~ /^assert/ } - ["assert"]).each do |old_assert_method|
103
- the_class.class_eval(%{
104
- def #{old_assert_method}(*args)
105
- raise "#{old_assert_method} has been disabled. When you use Wrong, it overrides 'assert', which most test frameworks have defined, and use internally."
106
- end
107
- })
108
- end
109
- end
110
-
111
116
  private
112
117
 
113
118
  def aver(valence, explanation = nil, depth = 0, &block)
@@ -130,7 +135,7 @@ module Wrong
130
135
  message = ""
131
136
  message << "#{explanation}: " if explanation
132
137
  message << "#{valence == :deny ? "Didn't expect" : "Expected"} #{code}, but "
133
- if predicate
138
+ if predicate && !(predicate.is_a? Predicated::Conjunction)
134
139
  failure = failure_message(valence, block, predicate)
135
140
  failure = failure.bold if Wrong.config[:color]
136
141
  message << failure
@@ -4,5 +4,26 @@ module Wrong
4
4
  end
5
5
 
6
6
  class Config < Hash
7
+ def alias_assert(method_name)
8
+ Wrong::Assert.send(:alias_method, method_name, :assert)
9
+ self.assert_method_names << method_name.to_sym unless self.assert_method_names.include?(method_name)
10
+ end
11
+
12
+ def alias_deny(method_name)
13
+ Wrong::Assert.send(:alias_method, method_name, :deny)
14
+ self.deny_method_names << method_name.to_sym unless self.deny_method_names.include?(method_name)
15
+ end
16
+
17
+ def assert_method_names
18
+ (self[:assert_method] ||= [:assert])
19
+ end
20
+
21
+ def deny_method_names
22
+ (self[:deny_method] ||= [:deny])
23
+ end
24
+
25
+ def assert_methods
26
+ assert_method_names + deny_method_names
27
+ end
7
28
  end
8
29
  end
@@ -1,5 +1,6 @@
1
1
  require 'ruby_parser'
2
2
  require 'ruby2ruby'
3
+ require 'wrong/config'
3
4
 
4
5
  class Sexp < Array
5
6
  def doop
@@ -17,7 +18,7 @@ class Sexp < Array
17
18
  self[0] == :iter and
18
19
  self[1].is_a? Sexp and
19
20
  self[1][0] == :call and
20
- [:assert, :deny].include? self[1][2] # todo: allow aliases for assert (e.g. "is")
21
+ Wrong.config.assert_methods.include? self[1][2] # todo: allow aliases for assert (e.g. "is")
21
22
  end
22
23
 
23
24
  def assertion
@@ -1,3 +1,3 @@
1
1
  module Wrong
2
- VERSION = "0.3.0" unless defined?(Wrong::VERSION)
2
+ VERSION = "0.3.1" unless defined?(Wrong::VERSION)
3
3
  end
@@ -6,55 +6,65 @@ require "minitest/unit"
6
6
  require "wrong/assert"
7
7
  require "wrong/adapters/minitest"
8
8
 
9
- regarding "basic assert features" do
10
-
11
- regarding "pass/fail basics" do
12
- test "disables other assert methods" do
13
- test_case_instance = Class.new(MiniTest::Unit::TestCase).new("x")
14
- assert{
15
- rescuing{
16
- test_case_instance.assert_equal(1,1)
17
- }.message.include?("has been disabled")
18
- }
19
- end
20
-
21
- test "raises minitest assertion failures" do
22
- test_case_instance = Class.new(MiniTest::Unit::TestCase).new("x")
23
- assert{
24
- rescuing{
25
- test_case_instance.assert{1==2}
26
- }.is_a?(MiniTest::Assertion)
27
- }
28
- end
29
-
30
- test "assert and deny are available to minitest tests" do
31
- class MyFailingAssertTest < MiniTest::Unit::TestCase
32
- def initialize
33
- super("assert test")
34
- end
35
-
36
- def test_fail
37
- assert{1==2}
38
- end
9
+ describe "basic assert features" do
10
+
11
+ before do
12
+ @test_case_instance = Class.new(MiniTest::Unit::TestCase).new("x")
13
+ end
14
+
15
+ it "raises minitest assertion failures" do
16
+ test_case_instance = Class.new(MiniTest::Unit::TestCase).new("x")
17
+ assert {
18
+ rescuing {
19
+ test_case_instance.assert { 1==2 }
20
+ }.is_a?(MiniTest::Assertion)
21
+ }
22
+ end
23
+
24
+ it "passes asserts with no block up to the framework's assert method" do
25
+ e = rescuing { assert(1 == 2) }
26
+ assert { e.message == "Failed assertion, no message given." }
27
+
28
+ e = rescuing { assert(1 == 2, "black is white") }
29
+ assert { e.message == "black is white" }
30
+ end
31
+
32
+ it "passes denys with no block up to the framework's assert method" do
33
+ e = rescuing { deny(2 + 2 == 4) }
34
+ assert { e.message == "Failed assertion, no message given." }
35
+
36
+ e = rescuing { deny(2 + 2 == 4, "up is down") }
37
+ assert { e.message == "up is down" }
38
+ end
39
+
40
+ # TODO: optionally print a warning when calling the framework assert
41
+
42
+ it "makes Wrong's assert and deny available to minitest tests" do
43
+ class MyFailingAssertTest < MiniTest::Unit::TestCase
44
+ def initialize
45
+ super("assert test")
39
46
  end
40
-
41
- class MyFailingDenyTest < MiniTest::Unit::TestCase
42
- def initialize
43
- super("deny test")
44
- end
45
-
46
- def test_fail
47
- deny{1==1}
48
- end
47
+
48
+ def test_fail
49
+ assert { 1==2 }
49
50
  end
50
-
51
- msg = rescuing{MyFailingAssertTest.new.test_fail}.message
52
- assert{ msg.include?("1 is not equal to 2") }
51
+ end
53
52
 
54
- msg = rescuing{MyFailingDenyTest.new.test_fail}.message
55
- assert{ msg.include?("1 is equal to 1") }
53
+ class MyFailingDenyTest < MiniTest::Unit::TestCase
54
+ def initialize
55
+ super("deny test")
56
+ end
57
+
58
+ def test_fail
59
+ deny { 1==1 }
60
+ end
56
61
  end
57
-
62
+
63
+ msg = rescuing { MyFailingAssertTest.new.test_fail }.message
64
+ assert { msg.include?("1 is not equal to 2") }
65
+
66
+ msg = rescuing { MyFailingDenyTest.new.test_fail }.message
67
+ assert { msg.include?("1 is equal to 1") }
58
68
  end
59
-
69
+
60
70
  end