-
-
Notifications
You must be signed in to change notification settings - Fork 924
/
Copy pathspec_helper.rb
69 lines (59 loc) · 1.79 KB
/
spec_helper.rb
1
2
3
4
5
6
7
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
require 'java'
$CLASSPATH << File.expand_path('../../../build/classes/test', __FILE__)
require 'rspec'
RSpec.configure do |config|
require File.expand_path('../../../test/test_helper', __FILE__)
config.include TestHelper
end
# Works like 'should include('str1', 'str2') but for arrays of
# strings. Reports closest matches using Levenshtein distance when a
# string is not found instead of dumping a huge inspect string.
RSpec::Matchers.define :have_strings do |*strings|
match do |container|
@included, @missing = [], []
strings.flatten.each do |s|
if container.include?(s)
@included << s
else
@missing << s
end
end
@missing.empty?
end
failure_message_for_should do |container|
"expected array of #{container.length} elements to include #{@missing.inspect}.\n" +
"#{closest_match_message(@missing, container)}"
end
failure_message_for_should_not do |container|
"expected array of #{container.length} elements to not include #{@included.inspect}."
end
# from http://en.wikipedia.org/wiki/Levenshtein_distance
def levenshtein(s, t)
m, n = s.length, t.length
d = Array.new(m) { Array.new(n) { 0 } }
0.upto(m-1) do |i|
d[i][0] = i
end
0.upto(n-1) do |j|
d[0][j] = j
end
1.upto(n-1) do |j|
1.upto(m-1) do |i|
d[i][j] = if s[i] == t[j]
d[i-1][j-1]
else
[d[i-1][j] + 1, # deletion
d[i][j-1] + 1, # insertion
d[i-1][j-1] + 1].min # substitution
end
end
end
d[m-1][n-1]
end
def closest_match_message(missing, container)
missing.map do |m|
groups = container.group_by {|x| levenshtein(m, x) }
" closest match for #{m.inspect}: #{groups[groups.keys.min].inspect}"
end.join("\n")
end
end