wrong 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +85 -7
- data/lib/predicated/lib/predicated/from/callable_object.rb +21 -21
- data/lib/predicated/lib/predicated/to/sentence.rb +4 -4
- data/lib/predicated/test_integration/usage_test.rb +1 -1
- data/lib/wrong/adapters/minitest.rb +1 -4
- data/lib/wrong/adapters/test_unit.rb +1 -3
- data/lib/wrong/assert.rb +22 -17
- data/lib/wrong/config.rb +21 -0
- data/lib/wrong/sexp_ext.rb +2 -1
- data/lib/wrong/version.rb +1 -1
- data/test/adapters/minitest_test.rb +56 -46
- data/test/adapters/rspec_test.rb +1 -1
- data/test/adapters/test_unit_test.rb +18 -14
- data/test/assert_test.rb +53 -23
- data/test/capturing_test.rb +6 -6
- data/test/chunk_test.rb +32 -32
- data/test/close_to_test.rb +1 -1
- data/test/config_test.rb +63 -6
- data/test/failures_test.rb +29 -19
- data/test/message/array_diff_test.rb +6 -6
- data/test/message/string_diff_test.rb +5 -5
- data/test/message/test_context_text.rb +4 -4
- data/test/rescuing_test.rb +2 -2
- data/test/sexp_ext_test.rb +16 -16
- data/test/test_helper.rb +6 -13
- metadata +4 -4
data/README.markdown
CHANGED
@@ -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
|
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
|
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
|
-
##
|
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
|
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
|
17
|
-
class Or; include
|
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
|
data/lib/wrong/assert.rb
CHANGED
@@ -22,12 +22,29 @@ module Wrong
|
|
22
22
|
AssertionFailedError
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
|
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
|
-
|
30
|
-
|
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
|
data/lib/wrong/config.rb
CHANGED
@@ -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
|
data/lib/wrong/sexp_ext.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/wrong/version.rb
CHANGED
@@ -6,55 +6,65 @@ require "minitest/unit"
|
|
6
6
|
require "wrong/assert"
|
7
7
|
require "wrong/adapters/minitest"
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
-
|
42
|
-
|
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
|
-
|
55
|
-
|
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
|