Skip to content

Commit cdb9262

Browse files
committed
Calculate diffs for config errors
1 parent b94e552 commit cdb9262

File tree

6 files changed

+131
-56
lines changed

6 files changed

+131
-56
lines changed

lib/pmdtester/parsers/pmd_report_document.rb

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class PmdReportDocument < Nokogiri::XML::SAX::Document
1313
def initialize(branch_name, working_dir, filter_set = nil)
1414
@violations = CollectionByFile.new
1515
@errors = CollectionByFile.new
16-
@configerrors = {}
16+
@configerrors = Hash.new { |hash, key| hash[key] = [] }
1717

1818
@infos_by_rules = {}
1919
@current_violations = []
@@ -32,35 +32,16 @@ def start_element(name, attrs = [])
3232

3333
case name
3434
when 'file'
35-
@current_filename = remove_work_dir!(attrs['name'])
36-
@current_violations = []
35+
handle_start_file attrs
3736
when 'violation'
38-
@current_violation = PmdViolation.new(
39-
branch: @branch_name,
40-
fname: @current_filename,
41-
info_url: attrs['externalInfoUrl'],
42-
bline: attrs['beginline'].to_i,
43-
rule_name: attrs['rule'],
44-
ruleset_name: attrs['ruleset'].freeze
45-
)
37+
handle_start_violation attrs
4638
when 'error'
47-
@current_filename = remove_work_dir!(attrs['filename'])
48-
49-
@current_error = PmdError.new(
50-
branch: @branch_name,
51-
filename: @current_filename,
52-
short_message: remove_work_dir!(attrs['msg'])
53-
)
39+
handle_start_error attrs
40+
when 'configerror'
41+
handle_start_configerror attrs
5442
end
5543
end
5644

57-
# Modifies the string in place and returns it
58-
# (this is what sub! does, except it returns nil if no replacement occurred)
59-
def remove_work_dir!(str)
60-
str.sub!(/#{@working_dir}/, '')
61-
str
62-
end
63-
6445
def characters(string)
6546
@cur_text << remove_work_dir!(string)
6647
end
@@ -85,10 +66,22 @@ def end_element(name)
8566
@errors.add_all(@current_filename, [@current_error])
8667
@current_filename = nil
8768
@current_error = nil
69+
when 'configerror'
70+
@configerrors[@current_configerror.rulename].push(@current_configerror)
71+
@current_configerror = nil
8872
end
8973
@cur_text.clear
9074
end
9175

76+
private
77+
78+
# Modifies the string in place and returns it
79+
# (this is what sub! does, except it returns nil if no replacement occurred)
80+
def remove_work_dir!(str)
81+
str.sub!(/#{@working_dir}/, '')
82+
str
83+
end
84+
9285
def finish_text!
9386
res = @cur_text.strip!.dup.freeze
9487
@cur_text.clear
@@ -105,5 +98,35 @@ def match_filter_set?(violation)
10598

10699
@filter_set.include?(rule_ref)
107100
end
101+
102+
def handle_start_file(attrs)
103+
@current_filename = remove_work_dir!(attrs['name'])
104+
@current_violations = []
105+
end
106+
107+
def handle_start_violation(attrs)
108+
@current_violation = PmdViolation.new(
109+
branch: @branch_name,
110+
fname: @current_filename,
111+
info_url: attrs['externalInfoUrl'],
112+
bline: attrs['beginline'].to_i,
113+
rule_name: attrs['rule'],
114+
ruleset_name: attrs['ruleset'].freeze
115+
)
116+
end
117+
118+
def handle_start_error(attrs)
119+
@current_filename = remove_work_dir!(attrs['filename'])
120+
121+
@current_error = PmdError.new(
122+
branch: @branch_name,
123+
filename: @current_filename,
124+
short_message: remove_work_dir!(attrs['msg'])
125+
)
126+
end
127+
128+
def handle_start_configerror(attrs)
129+
@current_configerror = PmdConfigError.new(attrs, @branch_name)
130+
end
108131
end
109132
end

lib/pmdtester/pmd_configerror.rb

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ class PmdConfigError
1313
# <xs:attribute name="msg" type="xs:string" use="required" />
1414
# </xs:complexType>
1515
attr_reader :attrs
16-
attr_accessor :text
16+
attr_accessor :old_error
1717

1818
def initialize(attrs, branch)
1919
@attrs = attrs
2020

21+
@changed = false
2122
@branch = branch
22-
@text = ''
2323
end
2424

2525
def rulename
@@ -30,14 +30,31 @@ def msg
3030
@attrs['msg']
3131
end
3232

33+
def sort_key
34+
rulename
35+
end
36+
3337
def changed?
34-
false
38+
@changed
3539
end
3640

3741
def eql?(other)
3842
rulename.eql?(other.rulename) && msg.eql?(other.msg)
3943
end
4044

45+
def try_merge?(other)
46+
if branch != BASE &&
47+
branch != other.branch &&
48+
rulename == other.rulename &&
49+
!changed? # not already changed
50+
@changed = true
51+
@old_error = other
52+
true
53+
end
54+
55+
false
56+
end
57+
4158
def hash
4259
[rulename, msg].hash
4360
end

lib/pmdtester/pmd_tester_utils.rb

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@ def parse_pmd_report(report_file, branch, report_details, filter_set = nil)
2828
parser = Nokogiri::XML::SAX::Parser.new(doc)
2929
parser.parse_file(report_file) if File.exist?(report_file)
3030
Report.new(
31-
violations_by_file: doc.violations,
32-
errors_by_file: doc.errors,
33-
infos_by_rule: doc.infos_by_rules,
31+
report_document: doc,
3432

3533
timestamp: report_details.timestamp,
3634
exec_time: report_details.execution_time

lib/pmdtester/report_diff.rb

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -50,30 +50,38 @@ def initialize(name, info_url)
5050
class Report
5151
attr_reader :violations_by_file,
5252
:errors_by_file,
53+
:configerrors_by_rule,
5354
:exec_time,
5455
:timestamp,
5556
:infos_by_rule
5657

57-
def initialize(violations_by_file:,
58-
errors_by_file:,
59-
exec_time:,
60-
timestamp:,
61-
infos_by_rule:)
62-
@violations_by_file = violations_by_file
63-
@errors_by_file = errors_by_file
58+
def initialize(report_document: nil,
59+
exec_time: 0,
60+
timestamp: '0')
61+
initialize_empty
62+
initialize_with_report_document report_document unless report_document.nil?
6463
@exec_time = exec_time
6564
@timestamp = timestamp
66-
@infos_by_rule = infos_by_rule
6765
end
6866

6967
def self.empty
70-
new(
71-
violations_by_file: CollectionByFile.new,
72-
errors_by_file: CollectionByFile.new,
73-
exec_time: 0,
74-
timestamp: '0',
75-
infos_by_rule: {}
76-
)
68+
new
69+
end
70+
71+
private
72+
73+
def initialize_with_report_document(report_document)
74+
@violations_by_file = report_document.violations
75+
@errors_by_file = report_document.errors
76+
@configerrors_by_rule = report_document.configerrors
77+
@infos_by_rule = report_document.infos_by_rules
78+
end
79+
80+
def initialize_empty
81+
@violations_by_file = CollectionByFile.new
82+
@errors_by_file = CollectionByFile.new
83+
@configerrors_by_rule = {}
84+
@infos_by_rule = {}
7785
end
7886
end
7987

@@ -85,9 +93,11 @@ class ReportDiff
8593

8694
attr_reader :error_counts
8795
attr_reader :violation_counts
96+
attr_reader :configerror_counts
8897

8998
attr_accessor :violation_diffs_by_file
9099
attr_accessor :error_diffs_by_file
100+
attr_accessor :configerror_diffs_by_rule
91101

92102
attr_accessor :rule_infos_union
93103
attr_accessor :base_report
@@ -96,15 +106,17 @@ class ReportDiff
96106
def initialize(base_report:, patch_report:)
97107
@violation_counts = RunningDiffCounters.new(base_report.violations_by_file.total_size)
98108
@error_counts = RunningDiffCounters.new(base_report.errors_by_file.total_size)
99-
@violation_diffs_by_rule = {}
100-
101-
@base_report = base_report
102-
@patch_report = patch_report
109+
@configerror_counts = RunningDiffCounters.new(base_report.configerrors_by_rule.values.flatten.length)
103110

104-
@rule_infos_union = base_report.infos_by_rule.dup
105111
@violation_diffs_by_file = {}
106112
@error_diffs_by_file = {}
113+
@configerror_diffs_by_rule = {}
114+
115+
@rule_infos_union = base_report.infos_by_rule.dup
116+
@base_report = base_report
117+
@patch_report = patch_report
107118

119+
@violation_diffs_by_rule = {}
108120
diff_with(patch_report)
109121
end
110122

@@ -123,11 +135,13 @@ def rule_summaries
123135
def diff_with(patch_report)
124136
@violation_counts.patch_total = patch_report.violations_by_file.total_size
125137
@error_counts.patch_total = patch_report.errors_by_file.total_size
138+
@configerror_counts.patch_total = patch_report.configerrors_by_rule.values.flatten.length
126139

127140
@violation_diffs_by_file = build_diffs(@violation_counts, &:violations_by_file)
128141
count(@violation_diffs_by_file) { |v| getvdiff(v.rule_name) } # record the diffs in the rule counter
129142

130143
@error_diffs_by_file = build_diffs(@error_counts, &:errors_by_file)
144+
@configerror_diffs_by_rule = build_diffs(@configerror_counts, &:configerrors_by_rule)
131145

132146
count_by_rule(@base_report.violations_by_file, base: true)
133147
count_by_rule(@patch_report.violations_by_file, base: false)
@@ -178,6 +192,7 @@ def build_diffs(counters, &getter)
178192
end
179193

180194
# @param diff_h a hash { filename => list[violation]}, containing those that changed
195+
# in case of config errors it's a hash { rulename => list[configerror] }
181196
def merge_changed_items(diff_h)
182197
diff_h.each do |fname, different|
183198
different.sort_by!(&:sort_key)

lib/pmdtester/runner.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,21 +126,23 @@ def get_projects(file_path)
126126
def summarize_diffs
127127
error_total = RunningDiffCounters.new(0)
128128
violations_total = RunningDiffCounters.new(0)
129+
configerrors_total = RunningDiffCounters.new(0)
129130

130131
@projects.each do |project|
131132
diff = project.report_diff
132133

133134
# in case we are in single mode, there might be no diffs (only the patch branch is available)
134-
unless diff.nil?
135-
error_total.merge!(diff.error_counts)
136-
violations_total.merge!(diff.violation_counts)
137-
end
135+
next if diff.nil?
136+
137+
error_total.merge!(diff.error_counts)
138+
violations_total.merge!(diff.violation_counts)
139+
configerrors_total.merge!(diff.configerror_counts)
138140
end
139141

140142
{
141143
errors: error_total.to_h,
142144
violations: violations_total.to_h,
143-
configerrors: RunningDiffCounters.new(0).to_h # note: this is now ignored
145+
configerrors: configerrors_total.to_h
144146
}
145147
end
146148

test/test_diff_builder.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,26 @@ def test_error_diffs
5959
assert_equal(1, error_diffs['Patch1.java'].size)
6060
end
6161

62+
def test_configerrors_diffs
63+
base_report_path = 'test/resources/diff_builder/test_configerrors_diffs_base.xml'
64+
patch_report_path = 'test/resources/diff_builder/test_configerrors_diffs_patch.xml'
65+
diffs_report = build_report_diff(base_report_path, patch_report_path,
66+
BASE_REPORT_INFO_PATH, PATCH_REPORT_INFO_PATH)
67+
configerrors_diffs = diffs_report.configerror_diffs_by_rule
68+
keys = configerrors_diffs.keys
69+
70+
assert_counters_empty(diffs_report.violation_counts)
71+
assert_counters_empty(diffs_report.error_counts)
72+
assert_counters_eq(diffs_report.configerror_counts,
73+
base_total: 4, patch_total: 3, changed_total: 5)
74+
assert_changes_eq(diffs_report.configerror_counts,
75+
removed: 3, added: 1, changed: 1)
76+
77+
assert_equal(%w[RuleBase1 RuleBoth2 RulePatch1], keys)
78+
assert_equal(2, configerrors_diffs['RuleBase1'].size)
79+
assert_equal(2, configerrors_diffs['RuleBoth2'].size)
80+
end
81+
6282
private
6383

6484
def assert_counters_empty(counters)

0 commit comments

Comments
 (0)