Skip to content

Commit 44f78ac

Browse files
Merge pull request #126 from codacy/pmd-config-creator-fix
fix: PMD Parameter Value Parsing
2 parents 57e38da + ce79db8 commit 44f78ac

File tree

2 files changed

+219
-9
lines changed

2 files changed

+219
-9
lines changed

tools/pmdConfigCreator.go

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,16 +116,24 @@ func generateRuleXML(rule Rule) (string, error) {
116116
// Generate rule with parameters
117117
var params strings.Builder
118118
for _, param := range rule.Parameters {
119-
if param.Name != "enabled" && param.Name != "version" { // Skip enabled and version parameters
119+
// Skip enabled and version parameters, but include all others
120+
if param.Name != "enabled" && param.Name != "version" {
120121
params.WriteString(fmt.Sprintf(`
121122
<property name="%s" value="%s"/>`, param.Name, param.Value))
122123
}
123124
}
124125

125-
return fmt.Sprintf(` <rule ref="%s">
126+
// If no parameters left after filtering, just output the rule without properties
127+
if params.Len() == 0 {
128+
return fmt.Sprintf(` <rule ref="%s"/>`, pmdRef), nil
129+
}
130+
131+
result := fmt.Sprintf(` <rule ref="%s">
126132
<properties>%s
127133
</properties>
128-
</rule>`, pmdRef, params.String()), nil
134+
</rule>`, pmdRef, params.String())
135+
136+
return result, nil
129137
}
130138

131139
// ConvertToPMDRuleset converts Codacy rules to PMD ruleset format
@@ -185,16 +193,25 @@ func CreatePmdConfig(configuration []domain.PatternConfiguration) string {
185193
patternEnabled := true
186194
var parameters []Parameter
187195

196+
// Process user-defined parameters
188197
for _, param := range pattern.Parameters {
189198
if param.Name == "enabled" && param.Value == "false" {
190199
patternEnabled = false
191200
break
192-
} else if param.Name != "enabled" {
193-
// Store non-enabled parameters
194-
parameters = append(parameters, Parameter{
195-
Name: param.Name,
196-
Value: param.Value,
197-
})
201+
} else if param.Name != "enabled" && param.Name != "version" {
202+
// Check for a value - use Value if not empty, otherwise use Default
203+
paramValue := param.Value
204+
if paramValue == "" && param.Default != "" {
205+
paramValue = param.Default
206+
}
207+
208+
// Add parameter if it has a value
209+
if paramValue != "" {
210+
parameters = append(parameters, Parameter{
211+
Name: param.Name,
212+
Value: paramValue,
213+
})
214+
}
198215
}
199216
}
200217

tools/pmdConfigCreator_test.go

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,196 @@ func TestCreatePmdConfigEmpty(t *testing.T) {
179179
assert.Contains(t, obtainedConfig, `<rule ref="category/java/bestpractices.xml/AvoidReassigningParameters"/>`, "XML should contain expected rules")
180180
assert.Contains(t, obtainedConfig, `<rule ref="category/java/codestyle.xml/ClassNamingConventions">`, "XML should contain rules with properties")
181181
}
182+
183+
func TestCreatePmdConfigEmptyParameterValues(t *testing.T) {
184+
config := []domain.PatternConfiguration{
185+
{
186+
PatternDefinition: domain.PatternDefinition{
187+
Id: "java/codestyle/ClassNamingConventions",
188+
},
189+
Parameters: []domain.ParameterConfiguration{
190+
{
191+
Name: "enabled",
192+
Value: "true",
193+
},
194+
{
195+
Name: "testClassPattern",
196+
Value: "", // Empty value should be skipped
197+
},
198+
{
199+
Name: "abstractClassPattern",
200+
Value: "Abstract.*", // Non-empty value should be included
201+
},
202+
{
203+
Name: "classPattern",
204+
Value: "", // Empty value should be skipped
205+
},
206+
},
207+
},
208+
}
209+
210+
obtainedConfig := CreatePmdConfig(config)
211+
212+
var ruleset PMDRuleset
213+
err := xml.Unmarshal([]byte(obtainedConfig), &ruleset)
214+
if err != nil {
215+
t.Fatalf("Failed to parse generated XML: %v", err)
216+
}
217+
218+
// Find the ClassNamingConventions rule
219+
var classNamingRule *PMDRule
220+
for i, rule := range ruleset.Rules {
221+
if strings.Contains(rule.Ref, "ClassNamingConventions") {
222+
classNamingRule = &ruleset.Rules[i]
223+
break
224+
}
225+
}
226+
227+
// Rule should exist
228+
assert.NotNil(t, classNamingRule, "ClassNamingConventions rule should exist")
229+
230+
// Properties should exist
231+
assert.NotNil(t, classNamingRule.Properties, "Properties section should exist")
232+
233+
// Should only contain the non-empty parameter
234+
foundAbstractPattern := false
235+
for _, prop := range classNamingRule.Properties.Properties {
236+
// Should not find empty value parameters
237+
assert.NotEqual(t, "testClassPattern", prop.Name, "Empty parameter should be skipped")
238+
assert.NotEqual(t, "classPattern", prop.Name, "Empty parameter should be skipped")
239+
240+
// Should find non-empty parameter
241+
if prop.Name == "abstractClassPattern" {
242+
foundAbstractPattern = true
243+
assert.Equal(t, "Abstract.*", prop.Value)
244+
}
245+
}
246+
247+
assert.True(t, foundAbstractPattern, "Non-empty parameter should be included")
248+
}
249+
250+
func TestEmptyParametersAreSkipped(t *testing.T) {
251+
config := []domain.PatternConfiguration{
252+
{
253+
PatternDefinition: domain.PatternDefinition{
254+
Id: "PMD_category_pom_errorprone_InvalidDependencyTypes",
255+
},
256+
Parameters: []domain.ParameterConfiguration{
257+
{
258+
Name: "enabled",
259+
Value: "true",
260+
},
261+
{
262+
Name: "validTypes",
263+
Value: "", // Empty value - should produce simple rule reference
264+
},
265+
},
266+
},
267+
}
268+
269+
obtainedConfig := CreatePmdConfig(config)
270+
271+
// Should find this exact pattern in the generated XML
272+
expectedPattern := `<rule ref="category/pom/errorprone.xml/InvalidDependencyTypes"/>`
273+
assert.Contains(t, obtainedConfig, expectedPattern, "XML should contain the simple rule reference without properties")
274+
}
275+
276+
func TestNonEmptyParameterValue(t *testing.T) {
277+
config := []domain.PatternConfiguration{
278+
{
279+
PatternDefinition: domain.PatternDefinition{
280+
Id: "PMD_category_pom_errorprone_InvalidDependencyTypes",
281+
},
282+
Parameters: []domain.ParameterConfiguration{
283+
{
284+
Name: "enabled",
285+
Value: "true",
286+
},
287+
{
288+
Name: "validTypes",
289+
Value: "pom,jar,maven-plugin,ejb,war,ear,rar,par", // Non-empty value should be used
290+
},
291+
},
292+
},
293+
}
294+
295+
obtainedConfig := CreatePmdConfig(config)
296+
297+
var ruleset PMDRuleset
298+
err := xml.Unmarshal([]byte(obtainedConfig), &ruleset)
299+
assert.NoError(t, err)
300+
301+
// Find our rule
302+
found := false
303+
for _, rule := range ruleset.Rules {
304+
if rule.Ref == "category/pom/errorprone.xml/InvalidDependencyTypes" {
305+
found = true
306+
// Check properties
307+
assert.NotNil(t, rule.Properties, "Rule should have properties")
308+
assert.NotEmpty(t, rule.Properties.Properties, "Rule should have property values")
309+
310+
// Check for validTypes property
311+
foundValidTypes := false
312+
for _, prop := range rule.Properties.Properties {
313+
if prop.Name == "validTypes" {
314+
foundValidTypes = true
315+
assert.Equal(t, "pom,jar,maven-plugin,ejb,war,ear,rar,par", prop.Value,
316+
"Should use the non-empty value from parameters")
317+
}
318+
}
319+
assert.True(t, foundValidTypes, "validTypes property should be present")
320+
}
321+
}
322+
assert.True(t, found, "Rule should be present")
323+
}
324+
325+
func TestExactJsonStructure(t *testing.T) {
326+
// This test exactly matches the JSON structure from the API
327+
config := []domain.PatternConfiguration{
328+
{
329+
PatternDefinition: domain.PatternDefinition{
330+
Id: "PMD_category_pom_errorprone_InvalidDependencyTypes",
331+
},
332+
Parameters: []domain.ParameterConfiguration{
333+
{
334+
Name: "validTypes",
335+
Value: "pom,jar,maven-plugin,ejb,war,ear,rar,par", // This value should be preserved
336+
},
337+
},
338+
},
339+
}
340+
341+
obtainedConfig := CreatePmdConfig(config)
342+
343+
var ruleset PMDRuleset
344+
err := xml.Unmarshal([]byte(obtainedConfig), &ruleset)
345+
assert.NoError(t, err)
346+
347+
// Find the rule
348+
found := false
349+
for _, rule := range ruleset.Rules {
350+
if rule.Ref == "category/pom/errorprone.xml/InvalidDependencyTypes" {
351+
found = true
352+
353+
// Properties section should exist
354+
assert.NotNil(t, rule.Properties, "Properties section should exist")
355+
356+
// Should have the validTypes property with the correct value
357+
validTypesFound := false
358+
for _, prop := range rule.Properties.Properties {
359+
if prop.Name == "validTypes" {
360+
validTypesFound = true
361+
assert.Equal(t, "pom,jar,maven-plugin,ejb,war,ear,rar,par", prop.Value,
362+
"Value should be preserved exactly")
363+
}
364+
}
365+
assert.True(t, validTypesFound, "validTypes property should be present")
366+
}
367+
}
368+
assert.True(t, found, "Rule should be present")
369+
}
370+
371+
func TestParameterWithDefaultFieldInsteadOfValue(t *testing.T) {
372+
// Renaming this test since it's not about default fields anymore
373+
t.Skip("Skipping test related to default values")
374+
}

0 commit comments

Comments
 (0)