minitest-holdify 1.0.3 → 1.1.0
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.
- checksums.yaml +4 -4
- data/lib/holdify/hold.rb +24 -11
- data/lib/holdify/pretty.rb +90 -0
- data/lib/holdify/store.rb +30 -16
- data/lib/holdify.rb +9 -1
- data/lib/minitest/holdify_plugin.rb +18 -4
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c91100bb90de5695419fdb279520529462f67f37d2e580ce6d61c496cf43cbcb
|
|
4
|
+
data.tar.gz: 48b9d63b74bdea68de55c7a2790e8fb1fef59dc1eb956bce96b02d7ef0b141b3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c17c6cfea957cbad41b2f272da130226a1c878546b46559ec80ccb1f939cb8c395c3b91a91e98ada8a1760bf3b661568364f6ca22f2e34ac957961c6011b4a40
|
|
7
|
+
data.tar.gz: 89f7c53a3ae05ef7e302efff24398e1579067d246a913c2ca91029185e08af9d8b4dae35da3a6686def351ce6fa89b0b9da1a34d388526dfa1455f5a5950e170
|
data/lib/holdify/hold.rb
CHANGED
|
@@ -9,26 +9,35 @@ module Holdify
|
|
|
9
9
|
@test = test
|
|
10
10
|
@path, = test.method(test.name).source_location
|
|
11
11
|
@store = Holdify.stores[@path] ||= Store.new(@path)
|
|
12
|
-
@session = Hash.new { |h, k| h[k] = [] }
|
|
13
|
-
@forced = []
|
|
14
|
-
@added = []
|
|
12
|
+
@session = Hash.new { |h, k| h[k] = [] } # { lineno => [values] }
|
|
13
|
+
@forced = [] # [ "file:lineno" ]
|
|
14
|
+
@added = [] # [ "file:lineno" ]
|
|
15
|
+
@index = {} # { lineno => index }
|
|
16
|
+
@counts = Hash.new(0) # { id => count }
|
|
15
17
|
end
|
|
16
18
|
|
|
17
19
|
def call(actual, force: false)
|
|
18
20
|
location = find_location
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
lineno = location.lineno
|
|
22
|
+
id = @store.id_at(lineno)
|
|
23
|
+
raise "Could not find holdify statement at line #{lineno}" unless id
|
|
21
24
|
|
|
22
|
-
@
|
|
23
|
-
|
|
25
|
+
unless @index.key?(lineno)
|
|
26
|
+
@index[lineno] = @counts[id]
|
|
27
|
+
@counts[id] += 1
|
|
28
|
+
end
|
|
29
|
+
index = @index[lineno]
|
|
30
|
+
|
|
31
|
+
@session[lineno] << actual
|
|
32
|
+
@forced << "#{location.path}:#{lineno}" if force
|
|
24
33
|
|
|
25
34
|
return actual if force || Holdify.reconcile
|
|
26
35
|
|
|
27
|
-
stored = @store.stored(id)
|
|
28
|
-
index = @session[
|
|
36
|
+
stored = @store.stored(id, index)
|
|
37
|
+
index = @session[lineno].size - 1
|
|
29
38
|
return stored[index] if stored && index < stored.size
|
|
30
39
|
|
|
31
|
-
@added << "#{location.path}:#{
|
|
40
|
+
@added << "#{location.path}:#{lineno}"
|
|
32
41
|
actual
|
|
33
42
|
end
|
|
34
43
|
|
|
@@ -36,7 +45,11 @@ module Holdify
|
|
|
36
45
|
return unless @test.failures.empty?
|
|
37
46
|
|
|
38
47
|
@added.each { |loc| warn "[holdify] Held new value for #{loc}" } unless Holdify.quiet
|
|
39
|
-
@session.each
|
|
48
|
+
@session.each do |lineno, values|
|
|
49
|
+
id = @store.id_at(lineno)
|
|
50
|
+
index = @index[lineno]
|
|
51
|
+
@store.update(lineno, id, values, index)
|
|
52
|
+
end
|
|
40
53
|
@store.save
|
|
41
54
|
end
|
|
42
55
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require 'tempfile'
|
|
5
|
+
require 'open3'
|
|
6
|
+
|
|
7
|
+
module Holdify
|
|
8
|
+
# Generates a pretty diff using git
|
|
9
|
+
module Pretty
|
|
10
|
+
RESET = "\e[0m"
|
|
11
|
+
RED_FG = "\e[31m"
|
|
12
|
+
GREEN_FG = "\e[32m"
|
|
13
|
+
|
|
14
|
+
G_BASE = "\e[100m #{RESET} ".freeze
|
|
15
|
+
G_EXP = "\e[41m\e[97m\e[1m-#{RESET} ".freeze
|
|
16
|
+
G_ACT = "\e[42m\e[97m\e[1m+#{RESET} ".freeze
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def call(expected, actual)
|
|
20
|
+
exp_file = create_tempfile(expected)
|
|
21
|
+
act_file = create_tempfile(actual)
|
|
22
|
+
|
|
23
|
+
cmd = %W[git diff --no-index --word-diff=porcelain --unified=1000 #{exp_file.path} #{act_file.path}]
|
|
24
|
+
stdout, _stderr, _status = Open3.capture3(*cmd)
|
|
25
|
+
|
|
26
|
+
return nil if stdout.empty?
|
|
27
|
+
|
|
28
|
+
format(stdout)
|
|
29
|
+
rescue Errno::ENOENT
|
|
30
|
+
nil
|
|
31
|
+
ensure
|
|
32
|
+
exp_file&.close!
|
|
33
|
+
act_file&.close!
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def format(diff)
|
|
39
|
+
lines = diff.lines.map(&:chomp)
|
|
40
|
+
start = lines.index { |l| l.start_with?('@@') }
|
|
41
|
+
return nil unless start
|
|
42
|
+
|
|
43
|
+
output = ["#{G_EXP}#{RED_FG}Held (Expected)#{RESET}", "#{G_ACT}#{GREEN_FG}Current (Actual)#{RESET}"]
|
|
44
|
+
exp_buf = +''
|
|
45
|
+
act_buf = +''
|
|
46
|
+
|
|
47
|
+
lines[(start + 1)..].each do |line|
|
|
48
|
+
char = line[0]
|
|
49
|
+
text = line[1..]
|
|
50
|
+
|
|
51
|
+
# :nocov:
|
|
52
|
+
case char
|
|
53
|
+
# :nocov:
|
|
54
|
+
when ' '
|
|
55
|
+
exp_buf << text
|
|
56
|
+
act_buf << text
|
|
57
|
+
when '-'
|
|
58
|
+
exp_buf << RED_FG << text << RESET
|
|
59
|
+
when '+'
|
|
60
|
+
act_buf << GREEN_FG << text << RESET
|
|
61
|
+
when '~'
|
|
62
|
+
flush_buffers(output, exp_buf, act_buf)
|
|
63
|
+
exp_buf.clear
|
|
64
|
+
act_buf.clear
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
flush_buffers(output, exp_buf, act_buf) unless exp_buf.empty? && act_buf.empty?
|
|
69
|
+
|
|
70
|
+
output.join("\n")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def flush_buffers(output, exp, act)
|
|
74
|
+
if exp == act
|
|
75
|
+
output << "#{G_BASE}#{exp}"
|
|
76
|
+
else
|
|
77
|
+
output << "#{G_EXP}#{exp}"
|
|
78
|
+
output << "#{G_ACT}#{act}"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def create_tempfile(obj)
|
|
83
|
+
Tempfile.new(%w[holdify .yaml]).tap do |file|
|
|
84
|
+
file.write(YAML.dump(obj, line_width: 78)) # Ensure 80 columns (including gutter)
|
|
85
|
+
file.flush
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
data/lib/holdify/store.rb
CHANGED
|
@@ -17,38 +17,52 @@ module Holdify
|
|
|
17
17
|
@source[lineno] = Digest::SHA1.hexdigest(content) unless content.empty?
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
@index = Hash.new { |h, k| h[k] = [] } # { id => ["L123 id", "L124 id"] }
|
|
20
21
|
@data = (File.exist?(@path) && YAML.unsafe_load_file(@path)) || {} # { key => [values] }
|
|
21
|
-
@index = {} # { id => "L123 id" }
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
@data.keep_if do |key, _|
|
|
25
|
-
id = key.split.last
|
|
26
|
-
next false unless valid_ids.include?(id)
|
|
27
|
-
|
|
28
|
-
@index[id] = key
|
|
29
|
-
true
|
|
30
|
-
end
|
|
23
|
+
organize_data
|
|
31
24
|
end
|
|
32
25
|
|
|
33
|
-
def id_at(lineno)
|
|
34
|
-
def stored(id)
|
|
26
|
+
def id_at(lineno) = @source[lineno]
|
|
27
|
+
def stored(id, index) = @data[@index[id][index]]
|
|
35
28
|
|
|
36
29
|
# Overwrite the entry for a given ID with a new list of values
|
|
37
|
-
def update(id, values)
|
|
38
|
-
new_key = "L#{
|
|
39
|
-
old_key = @index[id]
|
|
30
|
+
def update(lineno, id, values, index)
|
|
31
|
+
new_key = "L#{lineno} #{id}"
|
|
32
|
+
old_key = @index[id][index]
|
|
40
33
|
@data.delete(old_key) if old_key && old_key != new_key
|
|
41
|
-
@data[
|
|
34
|
+
@data[new_key] = values
|
|
35
|
+
@index[id][index] = new_key
|
|
42
36
|
end
|
|
43
37
|
|
|
44
38
|
def save
|
|
45
39
|
return FileUtils.rm_f(@path) if @data.empty?
|
|
46
40
|
|
|
47
41
|
sorted = @data.sort_by { |k, _| k[/\d+/].to_i }.to_h
|
|
48
|
-
content = YAML.dump(sorted, line_width:
|
|
42
|
+
content = YAML.dump(sorted, line_width: 78)
|
|
49
43
|
return if File.exist?(@path) && File.read(@path) == content
|
|
50
44
|
|
|
51
45
|
File.write(@path, content)
|
|
52
46
|
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def organize_data
|
|
51
|
+
source_counts = @source.values.tally
|
|
52
|
+
sorted_keys = @data.keys.sort_by { |k| k[/\d+/].to_i }
|
|
53
|
+
|
|
54
|
+
sorted_keys.each do |key|
|
|
55
|
+
id = key.split.last
|
|
56
|
+
next unless source_counts[id]
|
|
57
|
+
|
|
58
|
+
if @index[id].size < source_counts[id]
|
|
59
|
+
@index[id] << key
|
|
60
|
+
else
|
|
61
|
+
@data.delete(key)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
@data.keep_if { |key, _| source_counts[key.split.last] }
|
|
66
|
+
end
|
|
53
67
|
end
|
|
54
68
|
end
|
data/lib/holdify.rb
CHANGED
|
@@ -5,12 +5,20 @@ require_relative 'holdify/hold'
|
|
|
5
5
|
|
|
6
6
|
# Add description
|
|
7
7
|
module Holdify
|
|
8
|
-
VERSION = '1.0
|
|
8
|
+
VERSION = '1.1.0'
|
|
9
9
|
CONFIG = { ext: '.yaml' }.freeze
|
|
10
10
|
|
|
11
11
|
class << self
|
|
12
12
|
attr_accessor :reconcile, :quiet
|
|
13
|
+
attr_writer :pretty
|
|
13
14
|
|
|
14
15
|
def stores = @stores ||= {}
|
|
16
|
+
|
|
17
|
+
def pretty
|
|
18
|
+
return @pretty unless @pretty.nil?
|
|
19
|
+
|
|
20
|
+
@pretty = $stdout.tty? && !ENV.key?('NO_COLOR') && ENV['TERM'] != 'dumb' &&
|
|
21
|
+
system('git --version', out: File::NULL, err: File::NULL)
|
|
22
|
+
end
|
|
15
23
|
end
|
|
16
24
|
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'holdify'
|
|
4
|
+
require 'holdify/pretty'
|
|
4
5
|
|
|
5
6
|
# Implement the minitest plugin
|
|
6
7
|
module Minitest
|
|
@@ -13,6 +14,9 @@ module Minitest
|
|
|
13
14
|
opts.on '--holdify-quiet', 'Skip the warning on storing a new value' do
|
|
14
15
|
Holdify.quiet = true
|
|
15
16
|
end
|
|
17
|
+
opts.on '--holdify-pretty', 'Format the stored values with pretty print' do
|
|
18
|
+
Holdify.pretty = true
|
|
19
|
+
end
|
|
16
20
|
end
|
|
17
21
|
|
|
18
22
|
# Reopen the minitest class
|
|
@@ -40,10 +44,20 @@ module Minitest
|
|
|
40
44
|
assertion, message = message, assertion unless assertion.nil? || assertion.is_a?(Symbol)
|
|
41
45
|
expected = @hold.(actual, **)
|
|
42
46
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
begin
|
|
48
|
+
if actual.nil?
|
|
49
|
+
assert_nil expected, message
|
|
50
|
+
else
|
|
51
|
+
send(assertion || :assert_equal, expected, actual, message)
|
|
52
|
+
end
|
|
53
|
+
rescue Minitest::Assertion
|
|
54
|
+
raise unless Holdify.pretty
|
|
55
|
+
|
|
56
|
+
diff = Holdify::Pretty.call(expected, actual)
|
|
57
|
+
raise unless diff
|
|
58
|
+
|
|
59
|
+
msg = message ? "#{message}\n#{diff}" : diff
|
|
60
|
+
raise Minitest::Assertion, msg
|
|
47
61
|
end
|
|
48
62
|
|
|
49
63
|
if inspect
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: minitest-holdify
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Domizio Demichelis
|
|
@@ -34,6 +34,7 @@ files:
|
|
|
34
34
|
- LICENSE.txt
|
|
35
35
|
- lib/holdify.rb
|
|
36
36
|
- lib/holdify/hold.rb
|
|
37
|
+
- lib/holdify/pretty.rb
|
|
37
38
|
- lib/holdify/store.rb
|
|
38
39
|
- lib/minitest-holdify.rb
|
|
39
40
|
- lib/minitest/holdify_plugin.rb
|
|
@@ -59,7 +60,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
59
60
|
- !ruby/object:Gem::Version
|
|
60
61
|
version: '0'
|
|
61
62
|
requirements: []
|
|
62
|
-
rubygems_version:
|
|
63
|
+
rubygems_version: 4.0.3
|
|
63
64
|
specification_version: 4
|
|
64
65
|
summary: Hardcoded values suck! Holdify them.
|
|
65
66
|
test_files: []
|