assert_value 1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +7 -0
- data/LICENSE +19 -0
- data/README.md +100 -0
- data/Rakefile +31 -0
- data/assert_value.gemspec +19 -0
- data/assert_value.kdev4 +3 -0
- data/lib/array_diff.rb +331 -0
- data/lib/assert_value.rb +414 -0
- data/lib/text_diff.rb +109 -0
- data/test/assert_value_spec.rb +28 -0
- data/test/assert_value_test.rb +101 -0
- data/test/logs/assert_value_exception_with_files.log.ref +1 -0
- data/test/logs/assert_value_with_files.log.ref +1 -0
- metadata +65 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010-2011 Pluron, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
# assert_value
|
2
|
+
|
3
|
+
Checks that two values are same and "magically" replaces expected value
|
4
|
+
with the actual in case the new behavior (and new actual value) is correct.
|
5
|
+
Support two kind of arguments: string and code block.
|
6
|
+
|
7
|
+
## String Example:
|
8
|
+
|
9
|
+
It is better to start with no expected value
|
10
|
+
|
11
|
+
assert_value "foo"
|
12
|
+
|
13
|
+
Then run tests as usual with "rake test". As a result you will see
|
14
|
+
diff between expected and actual values:
|
15
|
+
|
16
|
+
Failure:
|
17
|
+
@@ -1,0, +1,1 @@
|
18
|
+
+foo
|
19
|
+
Accept the new value: yes to all, no to all, yes, no? [Y/N/y/n] (y):
|
20
|
+
|
21
|
+
If you accept the new value your test will be automatically modified to
|
22
|
+
|
23
|
+
assert_value "foo", <<-END
|
24
|
+
foo
|
25
|
+
END
|
26
|
+
|
27
|
+
## Block Example:
|
28
|
+
|
29
|
+
assert_value supports code block as argument. If executed block raises exception then
|
30
|
+
exception message is returned as actual value:
|
31
|
+
|
32
|
+
assert_value do
|
33
|
+
nil+1
|
34
|
+
end
|
35
|
+
|
36
|
+
Run tests
|
37
|
+
|
38
|
+
Failure:
|
39
|
+
@@ -1,0, +1,1 @@
|
40
|
+
+Exception NoMethodError: undefined method `+' for nil:NilClass
|
41
|
+
Accept the new value: yes to all, no to all, yes, no? [Y/N/y/n] (y):
|
42
|
+
|
43
|
+
After the new value is accepted you get
|
44
|
+
|
45
|
+
assert_value(<<-END) do
|
46
|
+
Exception NoMethodError: undefined method `+' for nil:NilClass
|
47
|
+
END
|
48
|
+
nil + 1
|
49
|
+
end
|
50
|
+
|
51
|
+
## Options:
|
52
|
+
|
53
|
+
--no-interactive skips all questions and just reports failures
|
54
|
+
--autoaccept prints diffs and automatically accepts all new actual values
|
55
|
+
--no-canonicalize turns off expected and actual value canonicalization (see below for details)
|
56
|
+
|
57
|
+
Additional options can be passed during both single test file run and rake test run:
|
58
|
+
|
59
|
+
In Ruby 1.8:
|
60
|
+
|
61
|
+
ruby test/unit/foo_test.rb -- --autoaccept
|
62
|
+
rake test TESTOPTS="-- --autoaccept"
|
63
|
+
|
64
|
+
In Ruby 1.9:
|
65
|
+
|
66
|
+
ruby test/unit/foo_test.rb --autoaccept
|
67
|
+
rake test TESTOPTS="--autoaccept"
|
68
|
+
|
69
|
+
## Canonicalization:
|
70
|
+
|
71
|
+
Before comparing expected and actual strings, assert_value canonicalizes both using these rules:
|
72
|
+
|
73
|
+
- indentation is ignored (except for indentation relative to the first line of the expected/actual string)
|
74
|
+
- ruby-style comments after "#" are ignored
|
75
|
+
- empty lines are ignored
|
76
|
+
- trailing whitespaces are ignored
|
77
|
+
|
78
|
+
You can turn canonicalization off with --no-canonicalize option. This is useful
|
79
|
+
when you need to regenerate expected test strings.
|
80
|
+
To regenerate the whole test suite, run:
|
81
|
+
|
82
|
+
In Ruby 1.8:
|
83
|
+
|
84
|
+
rake test TESTOPTS="-- --no-canonicalize --autoaccept"
|
85
|
+
|
86
|
+
In Ruby 1.9:
|
87
|
+
|
88
|
+
rake test TESTOPTS="--no-canonicalize --autoaccept"
|
89
|
+
|
90
|
+
|
91
|
+
## Changelog
|
92
|
+
|
93
|
+
- 1.0: Rename to assert_value
|
94
|
+
- 0.7: Support Ruby 1.9's MiniTest
|
95
|
+
- 0.6: Support test execution on Mac
|
96
|
+
- 0.5: Support code blocks to assert_same
|
97
|
+
- 0.4: Added support for code blocks as argument
|
98
|
+
- 0.3: Ruby 1.9 is supported
|
99
|
+
- 0.2: Make assert_same useful as a standalone gem. Bugfixes
|
100
|
+
- 0.1: Initial release
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rdoc/task'
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
|
7
|
+
Bundler::GemHelper.install_tasks
|
8
|
+
|
9
|
+
desc 'Default: run unit tests.'
|
10
|
+
task :default => :test
|
11
|
+
|
12
|
+
desc 'Test assert_value.'
|
13
|
+
Rake::TestTask.new(:test) do |t|
|
14
|
+
t.libs << 'lib'
|
15
|
+
t.pattern = 'test/**/*_test.rb'
|
16
|
+
t.verbose = true
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Run the specs."
|
20
|
+
RSpec::Core::RakeTask.new do |t|
|
21
|
+
t.pattern = "test/**/*_spec.rb"
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Generate documentation for assert_value.'
|
25
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
26
|
+
rdoc.rdoc_dir = 'rdoc'
|
27
|
+
rdoc.title = 'assert_value'
|
28
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
29
|
+
rdoc.rdoc_files.include('README')
|
30
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
SPEC = Gem::Specification.new do |s|
|
4
|
+
s.name = "assert_value"
|
5
|
+
s.version = "1.0"
|
6
|
+
s.author = "Pluron, Inc."
|
7
|
+
s.email = "support@pluron.com"
|
8
|
+
s.homepage = "http://github.com/acunote/assert_value"
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.license = 'MIT'
|
11
|
+
s.description = "assert_value assertion"
|
12
|
+
s.summary = "Assert that checks that two values (strings, expected and actual) are same and which can magically replace expected value with the actual in case the new behavior (and new actual value) is correct"
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- test/*`.split("\n")
|
16
|
+
|
17
|
+
s.require_path = "lib"
|
18
|
+
s.has_rdoc = true
|
19
|
+
end
|
data/assert_value.kdev4
ADDED
data/lib/array_diff.rb
ADDED
@@ -0,0 +1,331 @@
|
|
1
|
+
class ArrayDiff
|
2
|
+
|
3
|
+
VERSION = 0.3
|
4
|
+
|
5
|
+
def ArrayDiff.lcs(a, b)
|
6
|
+
astart = 0
|
7
|
+
bstart = 0
|
8
|
+
afinish = a.length-1
|
9
|
+
bfinish = b.length-1
|
10
|
+
mvector = []
|
11
|
+
|
12
|
+
# First we prune off any common elements at the beginning
|
13
|
+
while (astart <= afinish && bstart <= afinish && a[astart] == b[bstart])
|
14
|
+
mvector[astart] = bstart
|
15
|
+
astart += 1
|
16
|
+
bstart += 1
|
17
|
+
end
|
18
|
+
|
19
|
+
# now the end
|
20
|
+
while (astart <= afinish && bstart <= bfinish && a[afinish] == b[bfinish])
|
21
|
+
mvector[afinish] = bfinish
|
22
|
+
afinish -= 1
|
23
|
+
bfinish -= 1
|
24
|
+
end
|
25
|
+
|
26
|
+
bmatches = b.reverse_hash(bstart..bfinish)
|
27
|
+
thresh = []
|
28
|
+
links = []
|
29
|
+
|
30
|
+
(astart..afinish).each { |aindex|
|
31
|
+
aelem = a[aindex]
|
32
|
+
next unless bmatches.has_key? aelem
|
33
|
+
k = nil
|
34
|
+
bmatches[aelem].reverse.each { |bindex|
|
35
|
+
if k && (thresh[k] > bindex) && (thresh[k-1] < bindex)
|
36
|
+
thresh[k] = bindex
|
37
|
+
else
|
38
|
+
k = thresh.replacenextlarger(bindex, k)
|
39
|
+
end
|
40
|
+
links[k] = [ (k==0) ? nil : links[k-1], aindex, bindex ] if k
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
if !thresh.empty?
|
45
|
+
link = links[thresh.length-1]
|
46
|
+
while link
|
47
|
+
mvector[link[1]] = link[2]
|
48
|
+
link = link[0]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
return mvector
|
53
|
+
end
|
54
|
+
|
55
|
+
def makediff(a, b)
|
56
|
+
mvector = ArrayDiff.lcs(a, b)
|
57
|
+
ai = bi = 0
|
58
|
+
while ai < mvector.length
|
59
|
+
bline = mvector[ai]
|
60
|
+
if bline
|
61
|
+
while bi < bline
|
62
|
+
discardb(bi, b[bi])
|
63
|
+
bi += 1
|
64
|
+
end
|
65
|
+
match(ai, bi)
|
66
|
+
bi += 1
|
67
|
+
else
|
68
|
+
discarda(ai, a[ai])
|
69
|
+
end
|
70
|
+
ai += 1
|
71
|
+
end
|
72
|
+
while ai < a.length
|
73
|
+
discarda(ai, a[ai])
|
74
|
+
ai += 1
|
75
|
+
end
|
76
|
+
while bi < b.length
|
77
|
+
discardb(bi, b[bi])
|
78
|
+
bi += 1
|
79
|
+
end
|
80
|
+
match(ai, bi)
|
81
|
+
1
|
82
|
+
end
|
83
|
+
|
84
|
+
def compactdiffs
|
85
|
+
diffs = []
|
86
|
+
@diffs.each { |df|
|
87
|
+
i = 0
|
88
|
+
curdiff = []
|
89
|
+
while i < df.length
|
90
|
+
whot = df[i][0]
|
91
|
+
s = @isstring ? df[i][2].chr : [df[i][2]]
|
92
|
+
p = df[i][1]
|
93
|
+
last = df[i][1]
|
94
|
+
i += 1
|
95
|
+
while df[i] && df[i][0] == whot && df[i][1] == last+1
|
96
|
+
s << df[i][2]
|
97
|
+
last = df[i][1]
|
98
|
+
i += 1
|
99
|
+
end
|
100
|
+
curdiff.push [whot, p, s]
|
101
|
+
end
|
102
|
+
diffs.push curdiff
|
103
|
+
}
|
104
|
+
return diffs
|
105
|
+
end
|
106
|
+
|
107
|
+
attr_reader :diffs, :difftype
|
108
|
+
|
109
|
+
def initialize(diffs_or_a, b = nil, isstring = nil)
|
110
|
+
if b.nil?
|
111
|
+
@diffs = diffs_or_a
|
112
|
+
@isstring = isstring
|
113
|
+
else
|
114
|
+
@diffs = []
|
115
|
+
@curdiffs = []
|
116
|
+
makediff(diffs_or_a, b)
|
117
|
+
@difftype = diffs_or_a.class
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def match(ai, bi)
|
122
|
+
@diffs.push @curdiffs unless @curdiffs.empty?
|
123
|
+
@curdiffs = []
|
124
|
+
end
|
125
|
+
|
126
|
+
def discarda(i, elem)
|
127
|
+
@curdiffs.push ['-', i, elem]
|
128
|
+
end
|
129
|
+
|
130
|
+
def discardb(i, elem)
|
131
|
+
@curdiffs.push ['+', i, elem]
|
132
|
+
end
|
133
|
+
|
134
|
+
def compact
|
135
|
+
return Diff.new(compactdiffs)
|
136
|
+
end
|
137
|
+
|
138
|
+
def compact!
|
139
|
+
@diffs = compactdiffs
|
140
|
+
end
|
141
|
+
|
142
|
+
def inspect
|
143
|
+
@diffs.inspect
|
144
|
+
end
|
145
|
+
|
146
|
+
def diffrange(a, b)
|
147
|
+
if (a == b)
|
148
|
+
"#{a}"
|
149
|
+
else
|
150
|
+
"#{a},#{b}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def to_diff
|
155
|
+
offset = 0
|
156
|
+
@diffs.each { |b|
|
157
|
+
first = b[0][1]
|
158
|
+
length = b.length
|
159
|
+
action = b[0][0]
|
160
|
+
addcount = 0
|
161
|
+
remcount = 0
|
162
|
+
b.each { |l|
|
163
|
+
if l[0] == "+"
|
164
|
+
addcount += 1
|
165
|
+
elsif l[0] == "-"
|
166
|
+
remcount += 1
|
167
|
+
end
|
168
|
+
}
|
169
|
+
if addcount == 0
|
170
|
+
puts "#{diffrange(first+1, first+remcount)}d#{first+offset}"
|
171
|
+
elsif remcount == 0
|
172
|
+
puts "#{first-offset}a#{diffrange(first+1, first+addcount)}"
|
173
|
+
else
|
174
|
+
puts "#{diffrange(first+1, first+remcount)}c#{diffrange(first+offset+1, first+offset+addcount)}"
|
175
|
+
end
|
176
|
+
lastdel = (b[0][0] == "-")
|
177
|
+
b.each { |l|
|
178
|
+
if l[0] == "-"
|
179
|
+
offset -= 1
|
180
|
+
print "< "
|
181
|
+
elsif l[0] == "+"
|
182
|
+
offset += 1
|
183
|
+
if lastdel
|
184
|
+
lastdel = false
|
185
|
+
puts "---"
|
186
|
+
end
|
187
|
+
print "> "
|
188
|
+
end
|
189
|
+
print l[2]
|
190
|
+
print "\n"
|
191
|
+
}
|
192
|
+
}
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
module Diffable
|
199
|
+
def diff(b)
|
200
|
+
ArrayDiff.new(self, b)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Create a hash that maps elements of the array to arrays of indices
|
204
|
+
# where the elements are found.
|
205
|
+
|
206
|
+
def reverse_hash(range = (0...self.length))
|
207
|
+
revmap = {}
|
208
|
+
range.each { |i|
|
209
|
+
elem = self[i]
|
210
|
+
if revmap.has_key? elem
|
211
|
+
revmap[elem].push i
|
212
|
+
else
|
213
|
+
revmap[elem] = [i]
|
214
|
+
end
|
215
|
+
}
|
216
|
+
return revmap
|
217
|
+
end
|
218
|
+
|
219
|
+
def replacenextlarger(value, high = nil)
|
220
|
+
high ||= self.length
|
221
|
+
if self.empty? || value > self[-1]
|
222
|
+
push value
|
223
|
+
return high
|
224
|
+
end
|
225
|
+
# binary search for replacement point
|
226
|
+
low = 0
|
227
|
+
while low < high
|
228
|
+
index = (high+low)/2
|
229
|
+
found = self[index]
|
230
|
+
return nil if value == found
|
231
|
+
if value > found
|
232
|
+
low = index + 1
|
233
|
+
else
|
234
|
+
high = index
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
self[low] = value
|
239
|
+
# $stderr << "replace #{value} : 0/#{low}/#{init_high} (#{steps} steps) (#{init_high-low} off )\n"
|
240
|
+
# $stderr.puts self.inspect
|
241
|
+
#gets
|
242
|
+
#p length - low
|
243
|
+
return low
|
244
|
+
end
|
245
|
+
|
246
|
+
def patch(diff)
|
247
|
+
newary = nil
|
248
|
+
if diff.difftype == String
|
249
|
+
newary = diff.difftype.new('')
|
250
|
+
else
|
251
|
+
newary = diff.difftype.new
|
252
|
+
end
|
253
|
+
ai = 0
|
254
|
+
bi = 0
|
255
|
+
diff.diffs.each { |d|
|
256
|
+
d.each { |mod|
|
257
|
+
case mod[0]
|
258
|
+
when '-'
|
259
|
+
while ai < mod[1]
|
260
|
+
newary << self[ai]
|
261
|
+
ai += 1
|
262
|
+
bi += 1
|
263
|
+
end
|
264
|
+
ai += 1
|
265
|
+
when '+'
|
266
|
+
while bi < mod[1]
|
267
|
+
newary << self[ai]
|
268
|
+
ai += 1
|
269
|
+
bi += 1
|
270
|
+
end
|
271
|
+
newary << mod[2]
|
272
|
+
bi += 1
|
273
|
+
else
|
274
|
+
raise "Unknown diff action"
|
275
|
+
end
|
276
|
+
}
|
277
|
+
}
|
278
|
+
while ai < self.length
|
279
|
+
newary << self[ai]
|
280
|
+
ai += 1
|
281
|
+
bi += 1
|
282
|
+
end
|
283
|
+
return newary
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
class Array
|
288
|
+
include Diffable
|
289
|
+
end
|
290
|
+
|
291
|
+
class String
|
292
|
+
include Diffable
|
293
|
+
end
|
294
|
+
|
295
|
+
=begin
|
296
|
+
= ArrayDiff
|
297
|
+
(({diff.rb})) - computes the differences between two arrays or
|
298
|
+
strings. Copyright (C) 2001 Lars Christensen
|
299
|
+
http://users.cybercity.dk/~dsl8950/ruby/diff.html
|
300
|
+
|
301
|
+
== Synopsis
|
302
|
+
|
303
|
+
diff = ArrayDiff.new(a, b)
|
304
|
+
b = a.patch(diff)
|
305
|
+
|
306
|
+
== Class ArrayDiff
|
307
|
+
=== Class Methods
|
308
|
+
--- ArrayDiff.new(a, b)
|
309
|
+
--- a.diff(b)
|
310
|
+
Creates a Diff object which represent the differences between
|
311
|
+
((|a|)) and ((|b|)). ((|a|)) and ((|b|)) can be either be arrays
|
312
|
+
of any objects, strings, or object of any class that include
|
313
|
+
module ((|Diffable|))
|
314
|
+
|
315
|
+
== Module Diffable
|
316
|
+
The module ((|Diffable|)) is intended to be included in any class for
|
317
|
+
which differences are to be computed. Diffable is included into String
|
318
|
+
and Array when (({diff.rb})) is (({require}))'d.
|
319
|
+
|
320
|
+
Classes including Diffable should implement (({[]})) to get element at
|
321
|
+
integer indices, (({<<})) to append elements to the object and
|
322
|
+
(({ClassName#new})) should accept 0 arguments to create a new empty
|
323
|
+
object.
|
324
|
+
|
325
|
+
=== Instance Methods
|
326
|
+
--- Diffable#patch(diff)
|
327
|
+
Applies the differences from ((|diff|)) to the object ((|obj|))
|
328
|
+
and return the result. ((|obj|)) is not changed. ((|obj|)) and
|
329
|
+
can be either an array or a string, but must match the object
|
330
|
+
from which the ((|diff|)) was created.
|
331
|
+
=end
|
data/lib/assert_value.rb
ADDED
@@ -0,0 +1,414 @@
|
|
1
|
+
# Copyright (c) 2010-2011 Pluron, Inc.
|
2
|
+
require 'test/unit/testcase'
|
3
|
+
require 'text_diff'
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
$assert_value_options = []
|
7
|
+
|
8
|
+
if RUBY_VERSION >= "1.9.0"
|
9
|
+
|
10
|
+
# Test/Unit from Ruby 1.9 can't accept additional options like it did in 1.8:
|
11
|
+
# ruby test.rb -- --foo
|
12
|
+
# Now it has a strict option parser that considers all additional options as files.
|
13
|
+
# The right way to have an option now is to explicitly add it to Test/Unit parser.
|
14
|
+
module Test::Unit
|
15
|
+
|
16
|
+
module AssertValueOption
|
17
|
+
def setup_options(parser, options)
|
18
|
+
super
|
19
|
+
parser.on '--no-interactive', 'assert_value: non-interactive mode' do |flag|
|
20
|
+
$assert_value_options << "--no-interactive"
|
21
|
+
end
|
22
|
+
parser.on '--no-canonicalize', 'assert_value: turn off canonicalization' do |flag|
|
23
|
+
$assert_value_options << "--no-canonicalize"
|
24
|
+
end
|
25
|
+
parser.on '--autoaccept', 'assert_value: automatically accept new actual values' do |flag|
|
26
|
+
$assert_value_options << "--autoaccept"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def non_options(files, options)
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Runner < MiniTest::Unit
|
36
|
+
include Test::Unit::AssertValueOption
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
else
|
42
|
+
|
43
|
+
# In Ruby 1.8 additional test options are simply passed via ARGV
|
44
|
+
$assert_value_options << "--no-interactive" if ARGV.include?("--no-interactive")
|
45
|
+
$assert_value_options << "--no-canonicalize" if ARGV.include?("--no-canonicalize")
|
46
|
+
$assert_value_options << "--autoaccept" if ARGV.include?("--autoaccept")
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
#Use this to raise internal error with a given message
|
52
|
+
#You can define your own method for your application
|
53
|
+
unless defined? internal_error
|
54
|
+
def internal_error(message = 'internal error')
|
55
|
+
raise message
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
module AssertValueAssertion
|
61
|
+
|
62
|
+
def file_offsets
|
63
|
+
@file_offsets ||= Hash.new { |hash, key| hash[key] = {} }
|
64
|
+
end
|
65
|
+
|
66
|
+
# assert_value: assert which checks that two strings (expected and actual) are same
|
67
|
+
# and which can "magically" replace expected value with the actual in case
|
68
|
+
# the new behavior (and new actual value) is correct
|
69
|
+
#
|
70
|
+
# == Usage ==
|
71
|
+
#
|
72
|
+
# Write this in the test source:
|
73
|
+
# assert_value something, <<-END
|
74
|
+
# foo
|
75
|
+
# bar
|
76
|
+
# zee
|
77
|
+
# END
|
78
|
+
#
|
79
|
+
# You can also use assert_value for blocks. Then you can assert block result or raised exception
|
80
|
+
# assert_value(<<-END) do
|
81
|
+
# Exception NoMethodError: undefined method `+' for nil:NilClass
|
82
|
+
# END
|
83
|
+
# # Code block starts here
|
84
|
+
# c = nil + 1
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# Then run tests as usual:
|
88
|
+
# rake test:units
|
89
|
+
# ruby test/unit/foo_test.rb
|
90
|
+
# ...
|
91
|
+
#
|
92
|
+
# When assert_value fails, you'll be able to:
|
93
|
+
# - review diff
|
94
|
+
# - (optionally) accept new actual value (this modifies the test source file)
|
95
|
+
#
|
96
|
+
# Additional options for test runs:
|
97
|
+
# --no-interactive skips all questions and just reports failures
|
98
|
+
# --autoaccept prints diffs and automatically accepts all new actual values
|
99
|
+
# --no-canonicalize turns off expected and actual value canonicalization (see below for details)
|
100
|
+
#
|
101
|
+
# Additional options can be passed during both single test file run and rake test run:
|
102
|
+
# In Ruby 1.8:
|
103
|
+
# ruby test/unit/foo_test.rb -- --autoaccept
|
104
|
+
# ruby test/unit/foo_test.rb -- --no-interactive
|
105
|
+
#
|
106
|
+
# rake test TESTOPTS="-- --autoaccept"
|
107
|
+
# rake test:units TESTOPTS="-- --no-canonicalize --autoaccept"
|
108
|
+
#
|
109
|
+
# In Ruby 1.9:
|
110
|
+
# ruby test/unit/foo_test.rb --autoaccept
|
111
|
+
# ruby test/unit/foo_test.rb --no-interactive
|
112
|
+
#
|
113
|
+
# rake test TESTOPTS="--autoaccept"
|
114
|
+
# rake test:units TESTOPTS="--no-canonicalize --autoaccept"
|
115
|
+
#
|
116
|
+
#
|
117
|
+
# == Canonicalization ==
|
118
|
+
#
|
119
|
+
# Before comparing expected and actual strings, assert_value canonicalizes both using these rules:
|
120
|
+
# - indentation is ignored (except for indentation
|
121
|
+
# relative to the first line of the expected/actual string)
|
122
|
+
# - ruby-style comments after "#" are ignored:
|
123
|
+
# both whole-line and end-of-line comments are supported
|
124
|
+
# - empty lines are ignored
|
125
|
+
# - trailing whitespaces are ignored
|
126
|
+
#
|
127
|
+
# You can turn canonicalization off with --no-canonicalize option. This is useful
|
128
|
+
# when you need to regenerate expected test strings.
|
129
|
+
# To regenerate the whole test suite, run:
|
130
|
+
# In Ruby 1.8:
|
131
|
+
# rake test TESTOPTS="-- --no-canonicalize --autoaccept"
|
132
|
+
# In Ruby 1.9:
|
133
|
+
# rake test TESTOPTS="--no-canonicalize --autoaccept"
|
134
|
+
#
|
135
|
+
# Example of assert_value with comments:
|
136
|
+
# assert_value something, <<-END
|
137
|
+
# # some tree
|
138
|
+
# foo 1
|
139
|
+
# foo 1.1
|
140
|
+
# foo 1.2 # some node
|
141
|
+
# bar 2
|
142
|
+
# bar 2.1
|
143
|
+
# END
|
144
|
+
#
|
145
|
+
#
|
146
|
+
#
|
147
|
+
# == Umportant Usage Rules ==
|
148
|
+
#
|
149
|
+
# Restrictions:
|
150
|
+
# - only END and EOS are supported as end of string sequence
|
151
|
+
# - it's a requirement that you have <<-END at the same line as assert_value
|
152
|
+
# - assert_value can't be within a block
|
153
|
+
#
|
154
|
+
# Storing expected output in files:
|
155
|
+
# - assert_value something, :log => <path_to_file>
|
156
|
+
# - path to file is relative to:
|
157
|
+
# - RAILS_ROOT (if that is defined)
|
158
|
+
# - current dir (if no RAILS_ROOT is defined)
|
159
|
+
# - file doesn't have to exist, it will be created if necessary
|
160
|
+
#
|
161
|
+
# Misc:
|
162
|
+
# - it's ok to have several assert_value's in the same test method, assert_value.
|
163
|
+
# correctly updates all assert_value's in the test file
|
164
|
+
# - it's ok to omit expected string, like this:
|
165
|
+
# assert_value something
|
166
|
+
# in fact, this is the preferred way to create assert_value tests - you write empty
|
167
|
+
# assert_value, run tests and they will fill expected values for you automatically
|
168
|
+
def assert_value(*args)
|
169
|
+
if block_given?
|
170
|
+
mode = :block
|
171
|
+
expected = args[0]
|
172
|
+
actual = ""
|
173
|
+
begin
|
174
|
+
actual = yield.to_s
|
175
|
+
rescue Exception => e
|
176
|
+
actual = "Exception #{e.class}: #{e.message}"
|
177
|
+
end
|
178
|
+
else
|
179
|
+
mode = :scalar
|
180
|
+
expected = args[1]
|
181
|
+
actual = args[0]
|
182
|
+
end
|
183
|
+
|
184
|
+
if expected.nil?
|
185
|
+
expected = ""
|
186
|
+
change = :create_expected_string
|
187
|
+
elsif expected.class == String
|
188
|
+
change = :update_expected_string
|
189
|
+
elsif expected.class == Hash
|
190
|
+
raise ":log key is missing" unless expected.has_key? :log
|
191
|
+
log_file = expected[:log]
|
192
|
+
if defined? RAILS_ROOT
|
193
|
+
log_file = File.expand_path(log_file, RAILS_ROOT)
|
194
|
+
else
|
195
|
+
log_file = File.expand_path(log_file, Dir.pwd)
|
196
|
+
end
|
197
|
+
expected = File.exists?(log_file) ? File.read(log_file) : ""
|
198
|
+
change = :update_file_with_expected_string
|
199
|
+
else
|
200
|
+
internal_error("Invalid expected class #{excepted.class}")
|
201
|
+
end
|
202
|
+
|
203
|
+
# interactive mode is turned on by default, except when
|
204
|
+
# - --no-interactive is given
|
205
|
+
# - CIRCLECI is set (CircleCI captures test output, but doesn't interact with user)
|
206
|
+
# - STDIN is not a terminal device (i.e. we can't ask any questions)
|
207
|
+
interactive = !$assert_value_options.include?("--no-interactive") && !ENV["CIRCLECI"] && STDIN.tty?
|
208
|
+
canonicalize = !$assert_value_options.include?("--no-canonicalize")
|
209
|
+
autoaccept = $assert_value_options.include?("--autoaccept")
|
210
|
+
|
211
|
+
is_same_canonicalized, is_same, diff_canonicalized, diff = compare_for_assert_value(expected, actual)
|
212
|
+
|
213
|
+
if (canonicalize and !is_same_canonicalized) or (!canonicalize and !is_same)
|
214
|
+
diff_to_report = canonicalize ? diff_canonicalized : diff
|
215
|
+
if interactive
|
216
|
+
# print method name and short backtrace
|
217
|
+
soft_fail(diff_to_report)
|
218
|
+
|
219
|
+
if autoaccept
|
220
|
+
accept = true
|
221
|
+
else
|
222
|
+
print "Accept the new value: yes to all, no to all, yes, no? [Y/N/y/n] (y): "
|
223
|
+
STDOUT.flush
|
224
|
+
response = STDIN.gets.strip
|
225
|
+
accept = ["", "y", "Y"].include? response
|
226
|
+
$assert_value_options << "--autoaccept" if response == "Y"
|
227
|
+
$assert_value_options << "--no-interactive" if response == "N"
|
228
|
+
end
|
229
|
+
|
230
|
+
if accept
|
231
|
+
if [:create_expected_string, :update_expected_string].include? change
|
232
|
+
accept_string(actual, change, mode)
|
233
|
+
elsif change == :update_file_with_expected_string
|
234
|
+
accept_file(actual, log_file)
|
235
|
+
else
|
236
|
+
internal_error("Invalid change #{change}")
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
if accept
|
241
|
+
# when change is accepted, we should not report it as a failure because
|
242
|
+
# we want the test method to continue executing (in case there're more
|
243
|
+
# assert_value's in the method)
|
244
|
+
succeed
|
245
|
+
else
|
246
|
+
fail(diff)
|
247
|
+
end
|
248
|
+
else
|
249
|
+
succeed
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
private
|
254
|
+
|
255
|
+
def succeed
|
256
|
+
if RUBY_VERSION < "1.9.0"
|
257
|
+
add_assertion
|
258
|
+
else
|
259
|
+
true
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def soft_fail(diff)
|
264
|
+
if RUBY_VERSION < "1.9.0"
|
265
|
+
failure = Test::Unit::Failure.new(name, filter_backtrace(caller(0)), diff)
|
266
|
+
puts "\n#{failure}"
|
267
|
+
else
|
268
|
+
failure = MiniTest::Assertion.new(diff)
|
269
|
+
puts "\n#{failure}"
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
def fail(diff)
|
274
|
+
if RUBY_VERSION < "1.9.0"
|
275
|
+
raise Test::Unit::AssertionFailedError.new(diff)
|
276
|
+
else
|
277
|
+
raise MiniTest::Assertion.new(diff)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
# actual - actual value of the scalar or result of the executed block
|
282
|
+
# change - what to do with expected value (:create_expected_string or :update_expected_string)
|
283
|
+
# mode - describes signature of assert_value call by type of main argument (:block or :scalar)
|
284
|
+
def accept_string(actual, change, mode)
|
285
|
+
file, method, line = get_caller_location(:depth => 3)
|
286
|
+
|
287
|
+
# read source file, construct the new source, replacing everything
|
288
|
+
# between "do" and "end" in assert_value's block
|
289
|
+
# using File::expand_path here because "file" can be either
|
290
|
+
# absolute path (when test is run with "rake test" runs)
|
291
|
+
# or relative path (when test is run via ruby <path_to_test_file>)
|
292
|
+
source = File.readlines(File::expand_path(file))
|
293
|
+
|
294
|
+
# file may be changed by previous accepted assert_value's, adjust line numbers
|
295
|
+
offset = file_offsets[file].keys.inject(0) do |sum, i|
|
296
|
+
line.to_i >= i ? sum + file_offsets[file][i] : sum
|
297
|
+
end
|
298
|
+
|
299
|
+
expected_text_end_line = expected_text_start_line = line.to_i + offset
|
300
|
+
if change == :update_expected_string
|
301
|
+
#search for the end of expected value in code
|
302
|
+
expected_text_end_line += 1 while !["END", "EOS"].include?(source[expected_text_end_line].strip)
|
303
|
+
elsif change == :create_expected_string
|
304
|
+
# The is no expected value yet. expected_text_end_line is unknown
|
305
|
+
else
|
306
|
+
internal_error("Invalid change #{change}")
|
307
|
+
end
|
308
|
+
|
309
|
+
expected_length = expected_text_end_line - expected_text_start_line
|
310
|
+
|
311
|
+
# indentation is the indentation of assert_value call + 4
|
312
|
+
indentation = source[expected_text_start_line-1] =~ /^(\s+)/ ? $1.length : 0
|
313
|
+
indentation += 4
|
314
|
+
|
315
|
+
if change == :create_expected_string
|
316
|
+
if mode == :scalar
|
317
|
+
# add second argument to assert_value if it's omitted
|
318
|
+
source[expected_text_start_line-1] = "#{source[expected_text_start_line-1].chop}, <<-END\n"
|
319
|
+
elsif mode == :block
|
320
|
+
# add expected value as argument to assert_value before block call
|
321
|
+
source[expected_text_start_line-1] = source[expected_text_start_line-1].sub(/assert_value(\(.*?\))*/, "assert_value(<<-END)")
|
322
|
+
else
|
323
|
+
internal_error("Invalid mode #{mode}")
|
324
|
+
end
|
325
|
+
end
|
326
|
+
source = source[0, expected_text_start_line] +
|
327
|
+
actual.split("\n").map { |l| "#{" "*(indentation)}#{l}\n"} +
|
328
|
+
(change == :create_expected_string ? ["#{" "*(indentation-4)}END\n"] : [])+
|
329
|
+
source[expected_text_end_line, source.length]
|
330
|
+
|
331
|
+
# recalculate line number adjustments
|
332
|
+
actual_length = actual.split("\n").length
|
333
|
+
actual_length += 1 if change == :create_expected_string # END marker after expected value
|
334
|
+
file_offsets[file][line.to_i] = actual_length - expected_length
|
335
|
+
|
336
|
+
source_file = File.open(file, "w+")
|
337
|
+
source_file.write(source.join(''))
|
338
|
+
source_file.fsync
|
339
|
+
source_file.close
|
340
|
+
end
|
341
|
+
|
342
|
+
def accept_file(actual, log_file)
|
343
|
+
log = File.open(log_file, "w+")
|
344
|
+
log.write(actual)
|
345
|
+
log.fsync
|
346
|
+
log.close
|
347
|
+
end
|
348
|
+
|
349
|
+
def compare_for_assert_value(expected_verbatim, actual_verbatim)
|
350
|
+
expected_canonicalized, expected = canonicalize_for_assert_value(expected_verbatim)
|
351
|
+
actual_canonicalized, actual = canonicalize_for_assert_value(actual_verbatim)
|
352
|
+
diff_canonicalized = AssertValue::TextDiff.array_diff(expected_canonicalized, actual_canonicalized)
|
353
|
+
diff = AssertValue::TextDiff.array_diff(expected, actual)
|
354
|
+
[expected_canonicalized == actual_canonicalized, expected == actual, diff_canonicalized, diff]
|
355
|
+
end
|
356
|
+
|
357
|
+
def canonicalize_for_assert_value(text)
|
358
|
+
# make array of lines out of the text
|
359
|
+
result = text.split("\n")
|
360
|
+
|
361
|
+
# ignore leading newlines if any (trailing will be automatically ignored by split())
|
362
|
+
result.delete_at(0) if result[0] == ""
|
363
|
+
|
364
|
+
indentation = $1.length if result[0] and result[0] =~ /^(\s+)/
|
365
|
+
|
366
|
+
result.map! do |line|
|
367
|
+
# ignore indentation: we assume that the first line defines indentation
|
368
|
+
line.gsub!(/^\s{#{indentation}}/, '') if indentation
|
369
|
+
# ignore trailing spaces
|
370
|
+
line.gsub(/\s*$/, '')
|
371
|
+
end
|
372
|
+
|
373
|
+
# ignore comments
|
374
|
+
result_canonicalized= result.map do |line|
|
375
|
+
line.gsub(/\s*(#.*)?$/, '')
|
376
|
+
end
|
377
|
+
# ignore blank lines (usually they are lines with comments only)
|
378
|
+
result_canonicalized.delete_if { |line| line.nil? or line.empty? }
|
379
|
+
|
380
|
+
[result_canonicalized, result]
|
381
|
+
end
|
382
|
+
|
383
|
+
def get_caller_location(options = {:depth => 2})
|
384
|
+
caller_method = caller(options[:depth])[0]
|
385
|
+
|
386
|
+
#Sample output is:
|
387
|
+
#either full path when run as "rake test"
|
388
|
+
# /home/user/assert_value/test/unit/assure_test.rb:9:in `test_assure
|
389
|
+
#or relative path when run as ruby test/unit/assure_test.rb
|
390
|
+
# test/unit/assure_test.rb:9:in `test_assure
|
391
|
+
caller_method =~ /([^:]+):([0-9]+):in `(.+)'/
|
392
|
+
file = $1
|
393
|
+
line = $2
|
394
|
+
method = $3
|
395
|
+
[file, method, line]
|
396
|
+
end
|
397
|
+
|
398
|
+
end
|
399
|
+
|
400
|
+
if RUBY_VERSION >= "1.9.0"
|
401
|
+
class MiniTest::Unit::TestCase
|
402
|
+
include AssertValueAssertion
|
403
|
+
end
|
404
|
+
else
|
405
|
+
class Test::Unit::TestCase
|
406
|
+
include AssertValueAssertion
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
if defined?(RSpec)
|
411
|
+
RSpec.configure do |c|
|
412
|
+
c.include AssertValueAssertion
|
413
|
+
end
|
414
|
+
end
|
data/lib/text_diff.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# Copyright (c) 2008 Pluron, Inc.
|
2
|
+
|
3
|
+
require 'array_diff'
|
4
|
+
|
5
|
+
module AssertValue
|
6
|
+
|
7
|
+
class TextDiff
|
8
|
+
|
9
|
+
def self.mapped_chunk(arr, from, to)
|
10
|
+
return [] if to < from
|
11
|
+
arr[from, to-from+1].map{|x| [' ', x]}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.chunk(arr, from, to)
|
15
|
+
result = []
|
16
|
+
if to - from > 2
|
17
|
+
result += self.mapped_chunk(arr, from, from+2) if from > 0
|
18
|
+
result << ['@', to-2]
|
19
|
+
result += self.mapped_chunk(arr, to-2, to)
|
20
|
+
else
|
21
|
+
result << ['@', from] if from == 0
|
22
|
+
result += self.mapped_chunk(arr, from, to)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.record_stat(arr, at, remcount, addcount, linecount, offset)
|
27
|
+
index = arr[at][1]+1
|
28
|
+
['', "@@ -#{index},#{linecount-addcount}, +#{index+offset},#{linecount-remcount} @@"]
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.diff(a_text, b_text)
|
32
|
+
a = a_text.split("\n")
|
33
|
+
b = b_text.split("\n")
|
34
|
+
self.array_diff(a, b)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.array_diff(a, b)
|
38
|
+
diff = ArrayDiff.new(a, b)
|
39
|
+
|
40
|
+
return nil if diff.diffs.empty?
|
41
|
+
|
42
|
+
result = []
|
43
|
+
|
44
|
+
from = to = nextfrom = 0
|
45
|
+
offset = 0
|
46
|
+
diff.diffs.each do |tuple|
|
47
|
+
first = tuple[0][1]
|
48
|
+
length = tuple.length
|
49
|
+
action = tuple[0][0]
|
50
|
+
addcount = 0
|
51
|
+
remcount = 0
|
52
|
+
tuple.each do |l|
|
53
|
+
if l[0] == "+"
|
54
|
+
addcount += 1
|
55
|
+
elsif l[0] == "-"
|
56
|
+
remcount += 1
|
57
|
+
end
|
58
|
+
end
|
59
|
+
if remcount == 0
|
60
|
+
to = first-offset-1
|
61
|
+
nextfrom = to+1
|
62
|
+
else
|
63
|
+
to = first-1
|
64
|
+
nextfrom = to+remcount+1
|
65
|
+
end
|
66
|
+
result += self.chunk(a, from, to)
|
67
|
+
from = nextfrom
|
68
|
+
lastdel = (tuple[0][0] == "-")
|
69
|
+
tuple.each do |l|
|
70
|
+
if l[0] == "-"
|
71
|
+
offset -= 1
|
72
|
+
else
|
73
|
+
offset += 1
|
74
|
+
end
|
75
|
+
result << [l[0], l[2]]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
if (a.length - from) > 2
|
79
|
+
result += self.chunk(a, from, from+2)
|
80
|
+
elsif a.length > 0
|
81
|
+
result += self.chunk(a, from, a.length-1)
|
82
|
+
end
|
83
|
+
linecount = addcount = remcount = offset = current_offset = 0
|
84
|
+
info_index = nil
|
85
|
+
result.each_with_index do |l, i|
|
86
|
+
if l[0] == '@'
|
87
|
+
result[info_index] = self.record_stat(result, info_index, remcount, addcount,
|
88
|
+
linecount, offset) if info_index
|
89
|
+
info_index = i
|
90
|
+
offset += addcount - remcount
|
91
|
+
linecount = 0
|
92
|
+
addcount = remcount = 0
|
93
|
+
elsif l[0] == '-'
|
94
|
+
remcount += 1
|
95
|
+
linecount += 1
|
96
|
+
elsif l[0] == '+'
|
97
|
+
addcount += 1
|
98
|
+
linecount += 1
|
99
|
+
else
|
100
|
+
linecount += 1
|
101
|
+
end
|
102
|
+
end
|
103
|
+
result[info_index] = self.record_stat(result, info_index, remcount, addcount, linecount, offset) if info_index
|
104
|
+
return result.map{|x| x.join('')}.join("\n")
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'assert_value'
|
2
|
+
|
3
|
+
describe "Assert Value" do
|
4
|
+
|
5
|
+
it "compares with value in file" do
|
6
|
+
assert_value("foo", :log => 'test/logs/assert_value_with_files.log.ref')
|
7
|
+
expect(assert_value("foo", :log => 'test/logs/assert_value_with_files.log.ref')).to eq(true)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "compares with value inlined in source file" do
|
11
|
+
assert_value "foo", <<-END
|
12
|
+
foo
|
13
|
+
END
|
14
|
+
|
15
|
+
expect(
|
16
|
+
assert_value "foo", <<-END
|
17
|
+
foo
|
18
|
+
END
|
19
|
+
).to eq(true)
|
20
|
+
|
21
|
+
expect(assert_value(<<-END) do
|
22
|
+
foo
|
23
|
+
END
|
24
|
+
"foo"
|
25
|
+
end).to eq(true)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# Copyright (c) 2011 Pluron, Inc.
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
require 'assert_value'
|
5
|
+
|
6
|
+
class AssertValueTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_basic_assert_value
|
9
|
+
assert_value "foo", <<-END
|
10
|
+
foo
|
11
|
+
END
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_assert_value_with_files
|
15
|
+
assert_value "foo", :log => 'test/logs/assert_value_with_files.log.ref'
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_assert_value_empty_string
|
19
|
+
# These two calls are the same
|
20
|
+
assert_value ""
|
21
|
+
assert_value "", <<-END
|
22
|
+
END
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_assert_value_exception
|
26
|
+
assert_value(<<-END) do
|
27
|
+
Exception NoMethodError: undefined method `+' for nil:NilClass
|
28
|
+
END
|
29
|
+
nil + 1
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_assert_value_for_block_value
|
34
|
+
assert_value(<<-END) do
|
35
|
+
All Ok!
|
36
|
+
END
|
37
|
+
a = "All Ok!"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_assert_value_exception_with_files
|
42
|
+
assert_value(:log => 'test/logs/assert_value_exception_with_files.log.ref') do
|
43
|
+
nil + 1
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_assert_value_block_alternative_syntax
|
48
|
+
assert_value(<<-END) {
|
49
|
+
Exception NoMethodError: undefined method `+' for nil:NilClass
|
50
|
+
END
|
51
|
+
nil + 1
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_assert_value_block_alternative_syntax_one_liner
|
56
|
+
assert_value(<<-END) { nil + 1 }
|
57
|
+
Exception NoMethodError: undefined method `+' for nil:NilClass
|
58
|
+
END
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_assert_value_for_empty_block
|
62
|
+
# These calls are the same
|
63
|
+
assert_value { }
|
64
|
+
|
65
|
+
assert_value do end
|
66
|
+
|
67
|
+
assert_value(<<-END) { }
|
68
|
+
END
|
69
|
+
|
70
|
+
assert_value(<<-END) do end
|
71
|
+
END
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_assert_value_for_nil_block_result
|
75
|
+
# These calls are the same
|
76
|
+
assert_value { nil }
|
77
|
+
|
78
|
+
assert_value do nil end
|
79
|
+
|
80
|
+
assert_value(<<-END) { nil }
|
81
|
+
END
|
82
|
+
|
83
|
+
assert_value(<<-END) do nil end
|
84
|
+
END
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
if RUBY_VERSION >= "1.9.0"
|
90
|
+
|
91
|
+
class AssertValueMiniTest < MiniTest::Unit::TestCase
|
92
|
+
|
93
|
+
def test_basic_assert_value
|
94
|
+
assert_value "foo", <<-END
|
95
|
+
foo
|
96
|
+
END
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Exception NoMethodError: undefined method `+' for nil:NilClass
|
@@ -0,0 +1 @@
|
|
1
|
+
foo
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: assert_value
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Pluron, Inc.
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-24 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: assert_value assertion
|
15
|
+
email: support@pluron.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- .gitignore
|
21
|
+
- Gemfile
|
22
|
+
- LICENSE
|
23
|
+
- README.md
|
24
|
+
- Rakefile
|
25
|
+
- assert_value.gemspec
|
26
|
+
- assert_value.kdev4
|
27
|
+
- lib/array_diff.rb
|
28
|
+
- lib/assert_value.rb
|
29
|
+
- lib/text_diff.rb
|
30
|
+
- test/assert_value_spec.rb
|
31
|
+
- test/assert_value_test.rb
|
32
|
+
- test/logs/assert_value_exception_with_files.log.ref
|
33
|
+
- test/logs/assert_value_with_files.log.ref
|
34
|
+
homepage: http://github.com/acunote/assert_value
|
35
|
+
licenses:
|
36
|
+
- MIT
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
requirements: []
|
54
|
+
rubyforge_project:
|
55
|
+
rubygems_version: 1.8.23
|
56
|
+
signing_key:
|
57
|
+
specification_version: 3
|
58
|
+
summary: Assert that checks that two values (strings, expected and actual) are same
|
59
|
+
and which can magically replace expected value with the actual in case the new behavior
|
60
|
+
(and new actual value) is correct
|
61
|
+
test_files:
|
62
|
+
- test/assert_value_spec.rb
|
63
|
+
- test/assert_value_test.rb
|
64
|
+
- test/logs/assert_value_exception_with_files.log.ref
|
65
|
+
- test/logs/assert_value_with_files.log.ref
|