wrong 0.4.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +300 -0
- data/lib/wrong.rb +27 -0
- data/lib/wrong/adapters/minitest.rb +14 -0
- data/lib/wrong/adapters/rspec.rb +21 -0
- data/lib/wrong/adapters/test_unit.rb +9 -0
- data/lib/wrong/assert.rb +105 -0
- data/lib/wrong/chunk.rb +233 -0
- data/lib/wrong/close_to.rb +9 -0
- data/lib/wrong/config.rb +29 -0
- data/lib/wrong/d.rb +42 -0
- data/lib/wrong/failure_message.rb +43 -0
- data/lib/wrong/helpers.rb +66 -0
- data/lib/wrong/irb.rb +16 -0
- data/lib/wrong/message/array_diff.rb +69 -0
- data/lib/wrong/message/string_comparison.rb +88 -0
- data/lib/wrong/message/test_context.rb +28 -0
- data/lib/wrong/rainbow.rb +127 -0
- data/lib/wrong/ruby2ruby_patch.rb +37 -0
- data/lib/wrong/sexp_ext.rb +49 -0
- data/lib/wrong/version.rb +3 -0
- data/test/adapters/minitest_test.rb +97 -0
- data/test/adapters/rspec1/failing_spec.rb +23 -0
- data/test/adapters/rspec2/failing_spec.rb +26 -0
- data/test/adapters/rspec_test.rb +104 -0
- data/test/adapters/test_unit_test.rb +59 -0
- data/test/assert_advanced_test.rb +51 -0
- data/test/assert_test.rb +76 -0
- data/test/capturing_test.rb +59 -0
- data/test/chunk_test.rb +264 -0
- data/test/close_to_test.rb +39 -0
- data/test/config_test.rb +89 -0
- data/test/d_test.rb +64 -0
- data/test/failure_message_test.rb +40 -0
- data/test/failures_test.rb +157 -0
- data/test/message/array_diff_test.rb +79 -0
- data/test/message/test_context_test.rb +69 -0
- data/test/rescuing_test.rb +17 -0
- data/test/separate.rb +4 -0
- data/test/sexp_ext_test.rb +80 -0
- data/test/string_comparison_test.rb +159 -0
- data/test/suite.rb +7 -0
- data/test/test_helper.rb +64 -0
- data/test/wrong_test.rb +60 -0
- metadata +215 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
require "diff/lcs"
|
2
|
+
require "wrong/failure_message"
|
3
|
+
|
4
|
+
module Wrong
|
5
|
+
class ArrayDiff < FailureMessage::Formatter
|
6
|
+
register # tell FailureMessage::Formatter about us
|
7
|
+
|
8
|
+
def match?
|
9
|
+
predicate.is_a?(Predicated::Equal) &&
|
10
|
+
arrayish?(predicate.left) &&
|
11
|
+
arrayish?(predicate.right)
|
12
|
+
end
|
13
|
+
|
14
|
+
def arrayish?(object)
|
15
|
+
# in some Rubies, String is Enumerable
|
16
|
+
object.is_a?(Enumerable) && !object.is_a?(String)
|
17
|
+
end
|
18
|
+
|
19
|
+
def describe
|
20
|
+
left_str, right_str, diff_str = compute_and_format(predicate.left, predicate.right)
|
21
|
+
|
22
|
+
message = "\n"
|
23
|
+
message << left_str + "\n"
|
24
|
+
message << right_str + "\n"
|
25
|
+
message << diff_str + "\n"
|
26
|
+
message
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
def compute_and_format(left, right)
|
31
|
+
diffs = Diff::LCS.sdiff(left, right)
|
32
|
+
|
33
|
+
left_arr = []
|
34
|
+
right_arr = []
|
35
|
+
diff_arr = []
|
36
|
+
|
37
|
+
diffs.each do |diff|
|
38
|
+
left_elem = diff.old_element.nil? ? "nil" : diff.old_element.inspect
|
39
|
+
right_elem = diff.new_element.nil? ? "nil" : diff.new_element.inspect
|
40
|
+
|
41
|
+
max_length = [left_elem.length, right_elem.length].max
|
42
|
+
left_arr << left_elem.ljust(max_length) unless diff.action == "+"
|
43
|
+
right_arr << right_elem.ljust(max_length) unless diff.action == "-"
|
44
|
+
diff_arr << (diff.action == "=" ? " ".ljust(max_length) : "^".ljust(max_length))
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
diff_str = " " + diff_arr.join(" ") + " "
|
49
|
+
|
50
|
+
[format(left_arr), format(right_arr), diff_str]
|
51
|
+
end
|
52
|
+
|
53
|
+
def format(thing)
|
54
|
+
str = ""
|
55
|
+
if thing.is_a?(Array)
|
56
|
+
str << "["
|
57
|
+
thing.each_with_index do |item, i|
|
58
|
+
str << format(item)
|
59
|
+
str << ", " unless i == thing.length-1
|
60
|
+
end
|
61
|
+
str << "]"
|
62
|
+
else
|
63
|
+
str << thing
|
64
|
+
end
|
65
|
+
str
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require "wrong/failure_message"
|
2
|
+
|
3
|
+
module Wrong
|
4
|
+
class StringComparison
|
5
|
+
@@window = 64
|
6
|
+
@@prelude = 12
|
7
|
+
|
8
|
+
def self.window
|
9
|
+
@@window
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.window=(val)
|
13
|
+
@@window = val
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.prelude
|
17
|
+
@@prelude
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.prelude=(val)
|
21
|
+
@@prelude = val
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(first, second)
|
25
|
+
@first = first
|
26
|
+
@second = second
|
27
|
+
end
|
28
|
+
|
29
|
+
def same?
|
30
|
+
@first == @second
|
31
|
+
end
|
32
|
+
|
33
|
+
def different_at
|
34
|
+
if (@first.nil? || @second.nil?)
|
35
|
+
0
|
36
|
+
else
|
37
|
+
i = 0
|
38
|
+
while (i < @first.size && i < @second.size)
|
39
|
+
if @first[i] != @second[i]
|
40
|
+
break
|
41
|
+
end
|
42
|
+
i += 1
|
43
|
+
end
|
44
|
+
return i
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def message
|
49
|
+
"Strings differ at position #{different_at}:\n" +
|
50
|
+
" first: #{chunk(@first)}\n" +
|
51
|
+
"second: #{chunk(@second)}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def chunk(s)
|
55
|
+
prefix, middle, suffix = "...", "", "..."
|
56
|
+
|
57
|
+
start = different_at - @@prelude
|
58
|
+
if start < 0
|
59
|
+
prefix = ""
|
60
|
+
start = 0
|
61
|
+
end
|
62
|
+
|
63
|
+
stop = start + @@window
|
64
|
+
if stop >= s.size
|
65
|
+
suffix = ""
|
66
|
+
stop = s.size
|
67
|
+
end
|
68
|
+
|
69
|
+
[prefix, s[start...stop].inspect, suffix].join
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class StringComparisonFormatter < FailureMessage::Formatter
|
74
|
+
register # tell FailureMessage::Formatter about us
|
75
|
+
|
76
|
+
def match?
|
77
|
+
predicate.is_a?(Predicated::Equal) &&
|
78
|
+
predicate.left.is_a?(String) &&
|
79
|
+
predicate.right.is_a?(String)
|
80
|
+
end
|
81
|
+
|
82
|
+
def describe
|
83
|
+
comparison = Wrong::StringComparison.new(predicate.left, predicate.right)
|
84
|
+
"\n" + comparison.message
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Wrong
|
2
|
+
module Assert
|
3
|
+
# todo: integrate with / use Chunk somehow?
|
4
|
+
#
|
5
|
+
def failure_message(method_sym, block, predicate)
|
6
|
+
upper_portion = super
|
7
|
+
|
8
|
+
first_test_line = caller.find{|line|line =~ /(_test.rb|_spec.rb)/}
|
9
|
+
raise "Can't find test or spec in call chain: #{caller.join('|')}" if first_test_line.nil?
|
10
|
+
file, failure_line_number = first_test_line.split(":",2)
|
11
|
+
|
12
|
+
lines = File.readlines(file)
|
13
|
+
line_number = failure_line_number.to_i - 1
|
14
|
+
to_show = []
|
15
|
+
begin
|
16
|
+
line = lines[line_number]
|
17
|
+
to_show.unshift(line)
|
18
|
+
line_number -= 1
|
19
|
+
end while !(line =~ /^\s+(test|it)[ ]+/ || line =~ /^\s+def test_\w+/)
|
20
|
+
|
21
|
+
to_show[to_show.length-1] = to_show[to_show.length-1].chomp +
|
22
|
+
" ASSERTION FAILURE #{file}:#{failure_line_number.to_i}\n"
|
23
|
+
|
24
|
+
upper_portion + "\n\n" + to_show.join
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
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,37 @@
|
|
1
|
+
class ::Ruby2Ruby < ::SexpProcessor
|
2
|
+
# see http://gist.github.com/321038
|
3
|
+
# Monkey-patch to have Ruby2Ruby#translate with r2r >= 1.2.3, from
|
4
|
+
# http://seattlerb.rubyforge.org/svn/ruby2ruby/1.2.2/lib/ruby2ruby.rb
|
5
|
+
def self.translate(klass_or_str, method = nil)
|
6
|
+
sexp = ParseTree.translate(klass_or_str, method)
|
7
|
+
unifier = Unifier.new
|
8
|
+
unifier.processors.each do |p|
|
9
|
+
p.unsupported.delete :cfunc # HACK
|
10
|
+
end
|
11
|
+
sexp = unifier.process(sexp)
|
12
|
+
self.new.process(sexp)
|
13
|
+
end
|
14
|
+
|
15
|
+
#sconover - 7/2010 - monkey-patch
|
16
|
+
#{1=>2}=={1=>2}
|
17
|
+
#The right side was having its braces cut off because of
|
18
|
+
#special handling of hashes within arglists within the seattlerb code.
|
19
|
+
#I tried to fork r2r and add a test, but a lot of other tests
|
20
|
+
#broke, and I just dont understand the test in ruby2ruby.
|
21
|
+
#So I'm emailing the author...
|
22
|
+
def process_hash(exp)
|
23
|
+
result = []
|
24
|
+
until exp.empty?
|
25
|
+
lhs = process(exp.shift)
|
26
|
+
rhs = exp.shift
|
27
|
+
t = rhs.first
|
28
|
+
rhs = process rhs
|
29
|
+
rhs = "(#{rhs})" unless [:lit, :str].include? t # TODO: verify better!
|
30
|
+
|
31
|
+
result << "#{lhs} => #{rhs}"
|
32
|
+
end
|
33
|
+
|
34
|
+
return "{ #{result.join(', ')} }"
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'ruby_parser'
|
2
|
+
require 'ruby2ruby'
|
3
|
+
require 'wrong/config'
|
4
|
+
|
5
|
+
class Sexp < Array
|
6
|
+
|
7
|
+
def to_ruby
|
8
|
+
d = self.deep_clone
|
9
|
+
ruby = Ruby2Ruby.new.process(d)
|
10
|
+
ruby
|
11
|
+
end
|
12
|
+
|
13
|
+
# visit every node in the tree, including the root, that is an Sexp
|
14
|
+
# todo: test
|
15
|
+
def each_subexp(&block)
|
16
|
+
yield self
|
17
|
+
each do |child|
|
18
|
+
if child.is_a?(Sexp)
|
19
|
+
child.each_subexp(&block)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def assertion?
|
25
|
+
self.is_a? Sexp and
|
26
|
+
self[0] == :iter and
|
27
|
+
self[1].is_a? Sexp and
|
28
|
+
self[1][0] == :call and
|
29
|
+
Wrong.config.assert_methods.include? self[1][2] # todo: allow aliases for assert (e.g. "is")
|
30
|
+
end
|
31
|
+
|
32
|
+
def assertion
|
33
|
+
sexp = self
|
34
|
+
assertion = if sexp.assertion?
|
35
|
+
sexp
|
36
|
+
else
|
37
|
+
nested_assertions.first
|
38
|
+
end
|
39
|
+
assertion
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def nested_assertions
|
44
|
+
assertions = []
|
45
|
+
self.each_of_type(:iter) { |sexp| assertions << sexp if sexp.assertion? }
|
46
|
+
assertions
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require "./test/test_helper"
|
2
|
+
|
3
|
+
require "minitest/spec"
|
4
|
+
require "minitest/unit"
|
5
|
+
|
6
|
+
require "wrong/assert"
|
7
|
+
require "wrong/adapters/minitest"
|
8
|
+
|
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")
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_fail
|
49
|
+
assert { 1==2 }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
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
|
61
|
+
end
|
62
|
+
|
63
|
+
msg = rescuing { MyFailingAssertTest.new.test_fail }.message
|
64
|
+
|
65
|
+
assert { msg.include?("1 is not equal to 2") }
|
66
|
+
|
67
|
+
msg = rescuing { MyFailingDenyTest.new.test_fail }.message
|
68
|
+
assert { msg.include?("1 is equal to 1") }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'reports number of assertions' do
|
73
|
+
before do
|
74
|
+
@test = Class.new(MiniTest::Unit::TestCase).new("x")
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'assert{} should bump number of assertions' do
|
78
|
+
@test.assert {true}
|
79
|
+
assert {@test._assertions == 1}
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'assert() should not bump twice number of assertions' do
|
83
|
+
@test.assert(true)
|
84
|
+
assert {@test._assertions == 1}
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'deny{} should bump number of assertions' do
|
88
|
+
@test.deny {false}
|
89
|
+
assert {@test._assertions == 1}
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'deny() should bump once number of assertions' do
|
93
|
+
@test.deny(false)
|
94
|
+
assert {@test._assertions == 1}
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|