wrong 0.4.0 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/README.markdown +97 -49
  2. data/lib/wrong/adapters/minitest.rb +5 -2
  3. data/lib/wrong/adapters/rspec.rb +36 -15
  4. data/lib/wrong/assert.rb +1 -33
  5. data/lib/wrong/chunk.rb +34 -24
  6. data/lib/wrong/config.rb +42 -7
  7. data/lib/wrong/failure_message.rb +59 -0
  8. data/lib/wrong/helpers.rb +13 -12
  9. data/lib/wrong/message/array_diff.rb +1 -1
  10. data/lib/wrong/rainbow.rb +9 -4
  11. data/lib/wrong/sexp_ext.rb +6 -6
  12. data/lib/wrong/version.rb +1 -1
  13. data/lib/wrong.rb +14 -3
  14. data/test/adapters/minitest_test.rb +2 -3
  15. data/test/adapters/railsapp/app/controllers/application_controller.rb +3 -0
  16. data/test/adapters/railsapp/app/helpers/application_helper.rb +2 -0
  17. data/test/adapters/railsapp/autotest/discover.rb +2 -0
  18. data/test/adapters/railsapp/config/application.rb +42 -0
  19. data/test/adapters/railsapp/config/boot.rb +13 -0
  20. data/test/adapters/railsapp/config/environment.rb +5 -0
  21. data/test/adapters/railsapp/config/environments/development.rb +26 -0
  22. data/test/adapters/railsapp/config/environments/production.rb +49 -0
  23. data/test/adapters/railsapp/config/environments/test.rb +35 -0
  24. data/test/adapters/railsapp/config/initializers/backtrace_silencers.rb +7 -0
  25. data/test/adapters/railsapp/config/initializers/inflections.rb +10 -0
  26. data/test/adapters/railsapp/config/initializers/mime_types.rb +5 -0
  27. data/test/adapters/railsapp/config/initializers/secret_token.rb +7 -0
  28. data/test/adapters/railsapp/config/initializers/session_store.rb +8 -0
  29. data/test/adapters/railsapp/config/routes.rb +58 -0
  30. data/test/adapters/railsapp/db/seeds.rb +7 -0
  31. data/test/adapters/railsapp/spec/spec_helper.rb +28 -0
  32. data/test/adapters/railsapp/spec/wrong_spec.rb +8 -0
  33. data/test/adapters/rspec_rails_test.rb +58 -0
  34. data/test/adapters/rspec_test.rb +0 -61
  35. data/test/adapters/test_unit_test.rb +2 -2
  36. data/test/assert_advanced_test.rb +4 -4
  37. data/test/chunk_test.rb +14 -0
  38. data/test/config_test.rb +98 -51
  39. data/test/failure_message_test.rb +66 -16
  40. data/test/failures_test.rb +40 -86
  41. data/test/message/array_diff_test.rb +6 -2
  42. data/test/string_comparison_test.rb +3 -1
  43. data/test/test_helper.rb +26 -3
  44. metadata +190 -215
data/README.markdown CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  ## Abstract ##
6
6
 
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.
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 failure message that's not simply "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
8
 
9
9
  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.
10
10
 
@@ -16,11 +16,7 @@ Inspired by [assert { 2.0 }](http://assert2.rubyforge.org/) but rewritten from s
16
16
 
17
17
  gem install wrong
18
18
 
19
- Under JRuby, the above may cause errors; if so, then try
20
-
21
- gem install wrong-jruby
22
-
23
- which untangles some dependencies.
19
+ We have deployed gems for both Ruby and JRuby; if you get dependency issues on your platform, please let us know what Ruby interpreter and version you're using and what errors you get, and we'll try to track it down.
24
20
 
25
21
  ## Usage ##
26
22
 
@@ -61,13 +57,16 @@ If your assertion is more than a simple predicate, then Wrong will split it into
61
57
  And a companion, 'deny':
62
58
 
63
59
  deny{'abc'.include?('bc')}
64
- ==> Didn't expect "abc".include?("bc"), but 'abc' includes 'bc'
60
+ ==> Didn't expect "abc".include?("bc")
65
61
 
66
62
  There's also a convenience method for catching errors:
67
63
 
68
64
  assert{ rescuing{raise "vanilla"}.message == "chocolate" }
69
65
  ==>
70
- Expected (rescuing { raise("vanilla") }.message == "chocolate"), but 'vanilla' is not equal to 'chocolate'
66
+ Expected (rescuing { raise("vanilla") }.message == "chocolate"), but
67
+ rescuing { raise("vanilla") }.message is "vanilla"
68
+ rescuing { raise("vanilla") } is #<RuntimeError: vanilla>
69
+ raise("vanilla") raises RuntimeError: vanilla
71
70
 
72
71
  And one for capturing output streams:
73
72
 
@@ -93,7 +92,7 @@ We also implement the most amazing debugging method ever, `d`, which gives you a
93
92
  d { x } # => prints "x is 7" to the console
94
93
  d { x * 2 } # => prints "(x * 2) is 14" to the console
95
94
 
96
- (`d` was originally implemented by Rob Sanheim in LogBuddy; as with Assert2 this is a rewrite and homage.) Remember, if you want `d` to work at runtime (e.g. in a webapp) then you must `include 'wrong/d'` inside your app, e.g. for in your `environment.rb` file.
95
+ (`d` was originally implemented by Rob Sanheim in LogBuddy; as with Assert2 this version is a rewrite and homage.) Remember, if you want `d` to work at runtime (e.g. in a webapp) then you must `include Wrong::D` inside your app, e.g. in your `environment.rb` file.
97
96
 
98
97
  More examples are in the file `examples.rb` <http://github.com/alexch/wrong/blob/master/examples.rb>
99
98
 
@@ -118,7 +117,7 @@ will give you the `assert` and `deny` methods but not the formatters or `rescuin
118
117
  require 'wrong/d'
119
118
  include Wrong::D
120
119
 
121
- To summarize: if you do `require 'wrong'` and `include Wrong` then you will get the whole ball of wax. Most people will probably want this since it's easier, but there is an alternative, whici is to `require` and `include` only what you want.
120
+ To summarize: if you do `require 'wrong'` and `include Wrong` then you will get the whole ball of wax. Most people will probably want this since it's easier, but there is an alternative, which is to `require` and `include` only what you want.
122
121
 
123
122
  And beware: if you don't `require 'wrong'`, then `include Wrong` will not do anything at all.
124
123
 
@@ -139,13 +138,40 @@ or this
139
138
  ? 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 `=~`.
140
139
 
141
140
  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)...
141
+ Also, try not to call any methods with side effects inside an assert. In addition to being bad form, this can cause messed-up failure messages, since the side effects may occur several times in the process of building the message.
142
142
 
143
143
  Wrong also lets you put the expected and actual values in any order you want! Consider the failure messages for
144
144
 
145
145
  assert { current_user == "joe" } # => Expected (current_user == "joe") but current_user is "fred"
146
146
  assert { "joe" == current_user } # => Expected ("joe" == current_user) but current_user is "fred"
147
147
 
148
- You get just the information you want, and none you don't want. At least, that's the plan! :-)
148
+ You get all the information you want, and none you don't want. At least, that's the plan! :-)
149
+
150
+ ## BDD with Wrong ##
151
+
152
+ Wrong is compatible with RSpec and MiniTest::Spec, and probably Cucumber too, so you can use it inside your BDD framework of choice. To make your test code even BDD-er, try aliasing `assert` to either `should` or (Alex's favorite) `expect`.
153
+
154
+ Here's an RSpec example:
155
+
156
+ require "wrong"
157
+ require "wrong/adapters/rspec"
158
+ Wrong.config.alias_assert :expect
159
+
160
+ describe BleuCheese do
161
+ it "stinks" do
162
+ expect { BleuCheese.new.smell > 9000 }
163
+ end
164
+ end
165
+
166
+ This makes your code read like a BDD-style DSL, without RSpec's arcane "should" syntax (which is, let's face it, pretty weird the first few hundred times you have to use it). Compare
167
+
168
+ expect { BleuCheese.new.smell > 9000 }
169
+
170
+ to
171
+
172
+ BleuCheese.new.smell.should > 9000
173
+
174
+ and seriously, tell me which one more clearly describes the desired behavior. The object under test doesn't really have a `should` method, so why should it during a test? And in what human language is "should greater than" a valid phrase?
149
175
 
150
176
  ## Algorithm ##
151
177
 
@@ -153,16 +179,18 @@ So wait a second. How do we do it? Doesn't Ruby have [poor support for AST intro
153
179
 
154
180
  Before you get your knickers in a twist about how this is totally unacceptable because it doesn't support this or that use case, here are our caveats and excuses:
155
181
 
156
- * It works! Tested in 1.8.6, 1.8.7, 1.9.1, and 1.9.2-rc2. (Thank you, [rvm](http://rvm.beginrescueend.com/)!)
182
+ * It works! Tested in MRI 1.8.6, 1.8.7, 1.9.1, 1.9.2, and JRuby 1.5.3. (Thank you, [rvm](http://rvm.beginrescueend.com/)!)
157
183
  * Your code needs to be in a file.
158
184
  * If you're developing Ruby code without saving it to a mounted disk, then sorry, Wrong is not right for you.
159
- * We monkey-patch IRB so if you do `irb -rwrong` it'll save off your session in a place Wrong can read it.
185
+ * We monkey-patch IRB so if you do `irb -rwrong` it'll save off your session in memory where Wrong can read it.
186
+ * It'd be nice if it could work inside a `-e` block but as far as we can tell, there's no way to grab that `-e` code from inside Ruby.
160
187
  * It's a development-time testing library, not a production runtime library, so there are no security or filesystem issues.
161
188
  * `eval` isn't evil, it's just misunderstood.
162
189
  * It makes a few assumptions about the structure of your code, leading to some restrictions:
163
- * You can't have more than one call to `assert` per line. (This should not be a problem since even if you're nesting asserts for some bizarre reason, we assume you know where your Return key is. And actually, technically you can put two asserts on a line, but it always describes the first one it sees, which means that if the second one executes, its failure message will be incorrect or broken.)
190
+ * You can't have more than one call to `assert` per line. (This should not be a problem since even if you're nesting asserts for some bizarre reason, we assume you know where your Return key is.)
164
191
  * You can't use metaprogramming to write your assert blocks.
165
- * All variables and methods must be available in the binding of the assertion block.
192
+ * All variables and methods must be available in the binding of the assert block.
193
+ * Passing a proc around and eventually calling assert on it might not work in some Ruby implementations.
166
194
 
167
195
  ## Adapters ##
168
196
 
@@ -172,9 +200,9 @@ Currently we support
172
200
 
173
201
  * Test::Unit - `require 'wrong/adapters/test_unit'`
174
202
  * Minitest - `require 'wrong/adapters/minitest'`
175
- * RSpec - `require 'wrong/adapters/rspec'`
203
+ * RSpec - `require 'wrong/adapters/rspec'` (now supports both 1.3 and 2.0)
176
204
 
177
- 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.
205
+ To use these, put the appropriate `require` in your helper, **after** requiring your test framework; it should extend the framework enough that you can use `assert { }` in your test cases without extra fussing around.
178
206
 
179
207
  ## Explanations ##
180
208
 
@@ -194,13 +222,12 @@ And if your assertion code isn't self-explanatory, then that's a hint that you m
194
222
 
195
223
  When a failure occurs, the exception message contains all the details you might need to make sense of it. Here's the breakdown:
196
224
 
197
- Expected [CLAIM], but [SUMMARY]
225
+ Expected [CLAIM], but
198
226
  [FORMATTER]
199
227
  [SUBEXP] is [VALUE]
200
228
  ...
201
229
 
202
230
  * CLAIM is the code inside your assert block, normalized
203
- * SUMMARY is a to-English translation of the claim, via the Predicated library. This tries to be very intelligible; e.g. translating "include?" into "does not include" and so on.
204
231
  * If there is a formatter registered for this type of predicate, its output will come next. (See below.)
205
232
  * SUBEXP is each of the subtrees of the claim, minus duplicates and truisms (e.g. literals).
206
233
  * The word "is" is a very nice separator since it doesn't look like code, but is short enough to be easily visually parsed.
@@ -210,6 +237,8 @@ We hope this structure lets your eyes focus on the meaningful values and differe
210
237
 
211
238
  (Why does VALUE use `inspect` and not `to_s`? Because `inspect` on standard objects like String and Array are sure to show all relevant details, such as white space, in a console-safe way, and we hope other libraries follow suit. Also, `to_s` often inserts line breaks and that messes up formatting and legibility.)
212
239
 
240
+ Wrong tries to maintain indentation to improve readability. If the inspected VALUE contains newlines, the succeeding lines will be indented to the correct level.
241
+
213
242
  ## Formatters ##
214
243
 
215
244
  Enhancements for error messages sit under wrong/message.
@@ -217,22 +246,19 @@ Enhancements for error messages sit under wrong/message.
217
246
  Currently we support special messages for
218
247
 
219
248
  * String ==
220
- * Enumerable ==
249
+ * Array(ish) ==
221
250
  * including nested string elements
222
251
 
223
- 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).
252
+ To use the Array formatter, you may also need to `gem install diff-lcs` (it's an optional dependency).
224
253
 
225
- require "wrong/message/string_diff"
254
+ require "wrong/message/string_comparison"
226
255
  assert { "the quick brown fox jumped over the lazy dog" ==
227
256
  "the quick brown hamster jumped over the lazy gerbil" }
228
257
  ==>
229
- 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"
230
-
231
- string diff:
232
- the quick brown fox jumped over the lazy dog
233
- ^^^
234
- the quick brown hamster jumped over the lazy gerbil
235
- ^^^^^^^
258
+ Expected ("the quick brown fox jumped over the lazy dog" == "the quick brown hamster jumped over the lazy gerbil"), but
259
+ Strings differ at position 16:
260
+ first: ..."quick brown fox jumped over the lazy dog"
261
+ second: ..."quick brown hamster jumped over the lazy gerbil"
236
262
  --
237
263
 
238
264
  require "wrong/message/array_diff"
@@ -246,36 +272,57 @@ To use these formatters, you have to explicitly `require` them! You may also nee
246
272
  ["venus", "earth", "pluto", "neptune"]
247
273
  ^ ^
248
274
 
249
- [Bug: turns out 'diff' and 'diff-lcs' are incompatible with each other. We're working on a fix.]
275
+ ## Config ##
276
+
277
+ These settings can either be set at runtime on the `Wrong.config` singleton, or inside a `.wrong` file in the current directory or a parent. In the `.wrong` file just pretend every line is preceded with `Wrong.config.` -- e.g. if there's a setting called `ice_cream`, you can do any of these in your `.wrong` file
278
+
279
+ ice_cream # => Wrong.config[:ice_cream] => true
280
+ ice_cream = true # => Wrong.config[:ice_cream] => true
281
+ ice_cream = "vanilla" # => Wrong.config[:ice_cream] => "vanilla"
282
+
283
+ or any of these at runtime:
284
+
285
+ Wrong.config.ice_cream # => Wrong.config[:ice_cream] => true
286
+ Wrong.config.ice_cream = true # => Wrong.config[:ice_cream] => true
287
+ Wrong.config.ice_cream = "vanilla" # => Wrong.config[:ice_cream] => "vanilla"
288
+
289
+ ### Color ###
290
+
291
+ Apparently, no test framework is successful unless and until it supports console colors. So now we do. Call
292
+
293
+ Wrong.config.color
294
+
295
+ in your test helper or rakefile or wherever, or put
250
296
 
251
- ## Color ##
297
+ color
252
298
 
253
- Apparently, no test framework is successful unless and until it supports console colors. So now we do. Put
299
+ in your `.wrong` file and get ready to be **bedazzled**. If you need custom colors, let us know.
254
300
 
255
- Wrong.config[:color] = true
301
+ ### Aliases ###
256
302
 
257
- in your test helper or rakefile or wherever and get ready to be **bedazzled**. If you need custom colors, let us know.
303
+ An end to the language wars! Name your "assert" and "deny" methods anything you want.
258
304
 
259
- ## Aliases ##
305
+ * In your code, use `Wrong.config.alias_assert` and `Wrong.config.alias_deny`
306
+ * In your `.wrong` file, put `alias_assert :expect` on a line by itself
260
307
 
261
- An end to the language wars! Name your "assert" and "deny" methods anything you want. Here are some suggestions:
308
+ Here are some suggestions:
262
309
 
263
- Wrong.config.alias_assert(:expect)
264
- Wrong.config.alias_assert(:should) # This looks nice with RSpec
265
- Wrong.config.alias_assert(:confirm)
266
- Wrong.config.alias_assert(:be)
310
+ alias_assert :expect
311
+ alias_assert :should # This looks nice in RSpec
312
+ alias_assert :confirm
313
+ alias_assert :be
267
314
 
268
- Wrong.config.alias_assert(:is)
269
- Wrong.config.alias_deny(:aint)
315
+ alias_assert :is
316
+ alias_deny :aint
270
317
 
271
- Wrong.config.alias_assert(:assure)
272
- Wrong.config.alias_deny(:refute)
318
+ alias_assert :assure
319
+ alias_deny :refute
273
320
 
274
- Wrong.config.alias_assert(:yep)
275
- Wrong.config.alias_deny(:nope)
321
+ alias_assert :yep
322
+ alias_deny :nope
276
323
 
277
- Wrong.config.alias_assert(:yay!)
278
- Wrong.config.alias_deny(:boo!)
324
+ alias_assert :yay!
325
+ alias_deny :boo!
279
326
 
280
327
  Just don't use "`aver`" since we took that one for an internal method in `Wrong::Assert`.
281
328
 
@@ -294,7 +341,8 @@ If you're in Ruby 1.8, you **really** shouldn't do it! But if you do, you can us
294
341
 
295
342
  ## Etc ##
296
343
 
297
- * Github projects: <http://github.com/alexch/wrong>, <http://github.com/sconover/wrong>
344
+ * Mailing list: <http://groups.google.com/group/wrong-rb>
345
+ * Github project: <http://github.com/sconover/wrong>
298
346
  * Tracker project: <http://www.pivotaltracker.com/projects/109993>
299
347
  * the [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.)
300
348
  * the [Wrong slides](http://www.slideshare.net/alexchaffee/wrong-5069976) that Alex presented at Carbon Five and GoGaRuCo
@@ -1,7 +1,9 @@
1
- require "wrong"
1
+ require "wrong/assert"
2
+ require "wrong/helpers"
2
3
 
3
4
  class MiniTest::Unit::TestCase
4
- include Wrong
5
+ include Wrong::Assert
6
+ include Wrong::Helpers
5
7
 
6
8
  def failure_class
7
9
  MiniTest::Assertion
@@ -11,4 +13,5 @@ class MiniTest::Unit::TestCase
11
13
  self._assertions += 1 # increment minitest's assert count
12
14
  super(valence, explanation, depth + 1) # apparently this passes along the default block
13
15
  end
16
+
14
17
  end
@@ -1,21 +1,42 @@
1
1
  require "wrong"
2
2
 
3
- if Object.const_defined? :Spec
4
- Spec::Runner.configure do |config|
5
- include Wrong
3
+ if Object.const_defined? :RSpec
4
+ # RSpec 2
6
5
 
7
- def failure_class
8
- Spec::Expectations::ExpectationNotMetError
9
- end
10
- end
11
- elsif Object.const_defined? :RSpec
12
- RSpec.configure do |config|
13
- include Wrong
6
+ if RSpec.const_defined? :Rails
7
+ # RSpec 2 plus Rails 3
8
+ module RSpec::Rails::TestUnitAssertionAdapter
9
+ included do
10
+ define_assertion_delegators
11
+ class_eval do
12
+ remove_method :assert
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ module RSpec
19
+ module Core
20
+ class ExampleGroup
21
+ include Wrong
22
+
23
+ def failure_class
24
+ RSpec::Expectations::ExpectationNotMetError
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ elsif Object.const_defined? :Spec
31
+ # RSpec 1
32
+ Spec::Runner.configure do |config|
33
+ include Wrong
34
+
35
+ def failure_class
36
+ Spec::Expectations::ExpectationNotMetError
37
+ end
38
+ end
14
39
 
15
- def failure_class
16
- RSpec::Expectations::ExpectationNotMetError
17
- end
18
- end
19
40
  else
20
- raise "Wrong's RSpec adapter can't find RSpec. Please require 'spec' or 'rspec' first."
41
+ raise "Wrong's RSpec adapter can't find RSpec. Please require 'spec' or 'rspec' before requiring 'wrong/adapters/rspec'."
21
42
  end
data/lib/wrong/assert.rb CHANGED
@@ -48,10 +48,6 @@ module Wrong
48
48
  end
49
49
  end
50
50
 
51
- def summary(method_sym, predicate)
52
- method_sym == :deny ? predicate.to_sentence : predicate.to_negative_sentence
53
- end
54
-
55
51
  protected
56
52
 
57
53
  # for debugging -- if we couldn't make a predicate out of the code block, then this was why
@@ -59,34 +55,6 @@ module Wrong
59
55
  @@last_predicated_error ||= nil
60
56
  end
61
57
 
62
- # todo: move some/all of this into FailureMessage
63
- def full_message(chunk, block, valence, explanation)
64
- code = chunk.code
65
-
66
- predicate = begin
67
- Predicated::Predicate.from_ruby_code_string(code, block.binding)
68
- rescue Predicated::Predicate::DontKnowWhatToDoWithThisSexpError, Exception => e
69
- # save it off for debugging
70
- @@last_predicated_error = e
71
- nil
72
- end
73
-
74
- code = code.color(:blue) if Wrong.config[:color]
75
- message = ""
76
- message << "#{explanation}: " if explanation
77
- message << "#{valence == :deny ? "Didn't expect" : "Expected"} #{code}, but "
78
- if predicate && !(predicate.is_a? Predicated::Conjunction)
79
- message << summary(valence, predicate)
80
- if formatter = FailureMessage.formatter_for(predicate)
81
- failure = formatter.describe
82
- failure = failure.bold if Wrong.config[:color]
83
- message << failure
84
- end
85
- end
86
- message << chunk.details
87
- message
88
- end
89
-
90
58
  def aver(valence, explanation = nil, depth = 0, &block)
91
59
  require "wrong/rainbow" if Wrong.config[:color]
92
60
 
@@ -96,7 +64,7 @@ module Wrong
96
64
 
97
65
  chunk = Wrong::Chunk.from_block(block, depth + 2)
98
66
 
99
- message = full_message(chunk, block, valence, explanation)
67
+ message = FailureMessage.new(chunk, valence, explanation).full
100
68
  raise failure_class.new(message)
101
69
  end
102
70
  end
data/lib/wrong/chunk.rb CHANGED
@@ -1,17 +1,16 @@
1
1
  require 'ruby_parser'
2
2
  require 'ruby2ruby'
3
3
 
4
- begin
5
- require "ParseTree"
6
- rescue LoadError => e
7
- raise e unless e.message == "no such file to load -- ParseTree"
4
+ def require_optionally(library)
5
+ begin
6
+ require library
7
+ rescue LoadError => e
8
+ raise e unless e.message == "no such file to load -- #{library}"
9
+ end
8
10
  end
9
11
 
10
- begin
11
- require "sourcify"
12
- rescue LoadError => e
13
- raise e unless e.message == "no such file to load -- sourcify"
14
- end
12
+ require_optionally "ParseTree"
13
+ require_optionally "sourcify"
15
14
 
16
15
  require "wrong/config"
17
16
  require "wrong/sexp_ext"
@@ -27,16 +26,20 @@ module Wrong
27
26
  as_proc.source_location
28
27
  else
29
28
  # in Ruby 1.8, it reads the source location from the call stack
30
- caller[depth].split(":")
29
+ # # $stderr.puts "---"
30
+ # $stderr.puts caller.join("\n")
31
+ relevant_caller = caller[depth]
32
+ # $stderr.puts "*** #{relevant_caller}"
33
+ relevant_caller.split(":")
31
34
  end
32
35
 
33
- new(file, line, block)
36
+ new(file, line, &block)
34
37
  end
35
38
 
36
39
  attr_reader :file, :line_number, :block
37
40
 
38
41
  # line parameter is 1-based
39
- def initialize(file, line_number, block = nil)
42
+ def initialize(file, line_number, &block)
40
43
  @file = file
41
44
  @line_number = line_number.to_i
42
45
  @block = block
@@ -72,17 +75,19 @@ module Wrong
72
75
  end)
73
76
  end
74
77
 
75
- def read_source_file(file, dir = ".")
76
- File.read "#{dir}/#{file}"
78
+ def read_source_file(file)
79
+ Chunk.read_here_or_higher(file)
80
+ end
77
81
 
82
+ def self.read_here_or_higher(file, dir = ".")
83
+ File.read "#{dir}/#{file}"
78
84
  rescue Errno::ENOENT, Errno::EACCES => e
79
85
  # we may be in a chdir underneath where the file is, so move up one level and try again
80
86
  parent = "#{dir}/..".gsub(/^(\.\/)*/, '')
81
87
  if File.expand_path(dir) == File.expand_path(parent)
82
88
  raise Errno::ENOENT, "couldn't find #{file}"
83
89
  end
84
- read_source_file(file, parent)
85
-
90
+ read_here_or_higher(file, parent)
86
91
  end
87
92
 
88
93
  # Algorithm:
@@ -131,7 +136,7 @@ module Wrong
131
136
  self.claim.to_ruby
132
137
  rescue => e
133
138
  # note: this is untested; it's to recover from when we can't locate the code
134
- message = "Failed assertion at #{caller[depth + 2]} [couldn't retrieve source code due to #{e.inspect}]"
139
+ message = "Failed assertion at #{file}:#{line_number} [couldn't retrieve source code due to #{e.inspect}]"
135
140
  raise failure_class.new(message)
136
141
  end
137
142
 
@@ -142,7 +147,7 @@ module Wrong
142
147
  # todo: extract some of this into Sexp
143
148
  parts_list = []
144
149
  begin
145
- unless sexp.first == :arglist
150
+ unless [:arglist, :lasgn, :iter].include? sexp.first
146
151
  code = sexp.to_ruby.strip
147
152
  parts_list << code unless code == "" || parts_list.include?(code)
148
153
  end
@@ -166,6 +171,12 @@ module Wrong
166
171
  end
167
172
 
168
173
  def details
174
+ @details ||= build_details
175
+ end
176
+
177
+ private
178
+
179
+ def build_details
169
180
  require "wrong/rainbow" if Wrong.config[:color]
170
181
  s = ""
171
182
  parts = self.parts
@@ -196,10 +207,10 @@ module Wrong
196
207
  raises = raises.bold.color(:red)
197
208
  end
198
209
  formatted_exeption = if e.message and e.message != e.class.to_s
199
- indent(2, part, " ", raises, ": ", indent_all(3, e.message))
200
- else
201
- indent(2, part, " ", raises)
202
- end
210
+ indent(2, part, " ", raises, ": ", indent_all(3, e.message))
211
+ else
212
+ indent(2, part, " ", raises)
213
+ end
203
214
  details << formatted_exeption
204
215
  end
205
216
  end
@@ -214,8 +225,7 @@ module Wrong
214
225
 
215
226
  end
216
227
 
217
- private
218
-
228
+ public # don't know exactly why this needs to be public but eval'ed code can't find it otherwise
219
229
  def indent(indent, *s)
220
230
  "#{" " * indent}#{s.join('')}"
221
231
  end
data/lib/wrong/config.rb CHANGED
@@ -1,25 +1,60 @@
1
+ require "wrong/chunk"
2
+
1
3
  module Wrong
4
+ def self.load_config
5
+ settings = begin
6
+ Chunk.read_here_or_higher(".wrong")
7
+ rescue Errno::ENOENT => e
8
+ # couldn't find it
9
+ nil # In Ruby 1.8, "e" would be returned here otherwise
10
+ end
11
+ Config.new settings
12
+ end
13
+
2
14
  def self.config
3
- @config ||= Config.new
15
+ @config ||= load_config
16
+ end
17
+
18
+ def self.config=(new_config)
19
+ @config = load_config
4
20
  end
5
21
 
6
22
  class Config < Hash
23
+ def initialize(string = nil)
24
+ self[:aliases] = {:assert => [:assert], :deny => [:deny]}
25
+ if string
26
+ instance_eval string.gsub(/^(.*=)/, "self.\\1")
27
+ end
28
+ end
29
+
30
+ def method_missing(name, value = true)
31
+ name = name.to_s
32
+ if name =~ /=$/
33
+ name.gsub!(/=$/, '')
34
+ end
35
+ self[name.to_sym] = value
36
+ end
37
+
38
+ def alias_assert_or_deny(valence, extra_name)
39
+ Wrong::Assert.send(:alias_method, extra_name, valence)
40
+ new_method_name = extra_name.to_sym
41
+ self[:aliases][valence] << new_method_name unless self[:aliases][valence].include?(new_method_name)
42
+ end
43
+
7
44
  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)
45
+ alias_assert_or_deny(:assert, method_name)
10
46
  end
11
47
 
12
48
  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)
49
+ alias_assert_or_deny(:deny, method_name)
15
50
  end
16
51
 
17
52
  def assert_method_names
18
- (self[:assert_method] ||= [:assert])
53
+ self[:aliases][:assert]
19
54
  end
20
55
 
21
56
  def deny_method_names
22
- (self[:deny_method] ||= [:deny])
57
+ self[:aliases][:deny]
23
58
  end
24
59
 
25
60
  def assert_methods
@@ -39,5 +39,64 @@ module Wrong
39
39
  false
40
40
  end
41
41
  end
42
+
43
+
44
+ attr_accessor :chunk, :valence, :explanation
45
+
46
+ def initialize(chunk, valence, explanation)
47
+ @chunk, @valence, @explanation = chunk, valence, explanation
48
+ end
49
+
50
+ def basic
51
+ "#{valence == :deny ? "Didn't expect" : "Expected"} #{colored(:blue, chunk.code)}"
52
+ end
53
+
54
+ def full
55
+ message = ""
56
+ message << "#{explanation}: " if explanation
57
+ message << basic
58
+
59
+ formatted_message = if predicate && !(predicate.is_a? Predicated::Conjunction)
60
+ if formatter = FailureMessage.formatter_for(predicate)
61
+ colored(:bold, formatter.describe)
62
+ end
63
+ end
64
+
65
+ unless chunk.details.empty? and formatted_message.nil?
66
+ message << ", but"
67
+ end
68
+
69
+ message << formatted_message if formatted_message
70
+ message << chunk.details unless chunk.details.empty?
71
+ message
72
+ end
73
+
74
+ protected
75
+ def code
76
+ @code ||= chunk.code
77
+ end
78
+
79
+ def predicate
80
+ @predicate ||= begin
81
+ Predicated::Predicate.from_ruby_code_string(code, chunk.block.binding)
82
+ rescue Predicated::Predicate::DontKnowWhatToDoWithThisSexpError, Exception => e
83
+ # save it off for debugging
84
+ @@last_predicated_error = e
85
+ nil
86
+ end
87
+ end
88
+
89
+ def colored(color, text)
90
+ if Wrong.config[:color]
91
+ if color == :bold
92
+ text.bold
93
+ else
94
+ text.color(color)
95
+ end
96
+ else
97
+ text
98
+ end
99
+ end
100
+
42
101
  end
43
102
  end