1
2
3
4
5 package com.qulice.pmd;
6
7 import com.qulice.spi.Environment;
8 import com.qulice.spi.Violation;
9 import java.io.File;
10 import java.util.Collections;
11 import java.util.List;
12 import java.util.stream.Collectors;
13 import org.cactoos.text.TextOf;
14 import org.hamcrest.MatcherAssert;
15 import org.hamcrest.Matchers;
16 import org.junit.jupiter.api.Test;
17
18
19
20
21
22
23 final class UnnecessaryLocalRuleTest {
24
25
26
27
28 private static final String RULE = "UnnecessaryLocalRule";
29
30 @Test
31 void detectsUnnecessaryLocalVariableOnReturn() throws Exception {
32 MatcherAssert.assertThat(
33 "UnnecessaryLocalRule should fire on a local variable used only in return",
34 this.violations("UnnecessaryLocal.java"),
35 Matchers.hasItem(UnnecessaryLocalRuleTest.RULE)
36 );
37 }
38
39 @Test
40 void doesNotFireWhenVariableIsUsedInLoop() throws Exception {
41 MatcherAssert.assertThat(
42 "UnnecessaryLocalRule should not fire when variable is used in a loop",
43 this.violations("UnnecessaryLocalInLoop.java"),
44 Matchers.not(Matchers.hasItem(UnnecessaryLocalRuleTest.RULE))
45 );
46 }
47
48 @Test
49 void doesNotFireWhenVariableIsUsedMoreThanOnce() throws Exception {
50 MatcherAssert.assertThat(
51 "UnnecessaryLocalRule should not fire when variable is used more than once",
52 this.violations("UnnecessaryLocalUsedTwice.java"),
53 Matchers.not(Matchers.hasItem(UnnecessaryLocalRuleTest.RULE))
54 );
55 }
56
57 @Test
58 void doesNotFireWhenUseIsAcrossAnonymousClassOrLambda() throws Exception {
59 MatcherAssert.assertThat(
60 "UnnecessaryLocalRule should not fire when the only use is inside an anonymous class or lambda body",
61 this.violations("UnnecessaryLocalAcrossAnonymousClass.java"),
62 Matchers.not(Matchers.hasItem(UnnecessaryLocalRuleTest.RULE))
63 );
64 }
65
66 @Test
67 void doesNotFireWhenInitialiserCapturesFreshState() throws Exception {
68 MatcherAssert.assertThat(
69 "UnnecessaryLocalRule should not fire when the initialiser captures a clock or randomness source",
70 this.violations("UnnecessaryLocalCapturedTimestamp.java"),
71 Matchers.not(Matchers.hasItem(UnnecessaryLocalRuleTest.RULE))
72 );
73 }
74
75 @Test
76 void doesNotFireWhenInterveningCallMutatesSameTarget() throws Exception {
77 MatcherAssert.assertThat(
78 "UnnecessaryLocalRule should not fire when a later statement calls the same target",
79 this.violations("UnnecessaryLocalDestructiveCleanup.java"),
80 Matchers.not(Matchers.hasItem(UnnecessaryLocalRuleTest.RULE))
81 );
82 }
83
84 @Test
85 void doesNotFireWhenFieldAccessQualifierIsMutated() throws Exception {
86 MatcherAssert.assertThat(
87 "UnnecessaryLocalRule should not fire when a later call mutates the field-access initialiser's qualifier",
88 this.violations("UnnecessaryLocalCapturedFieldAccess.java"),
89 Matchers.not(Matchers.hasItem(UnnecessaryLocalRuleTest.RULE))
90 );
91 }
92
93 @Test
94 void doesNotFireWhenLocalCapturedBeforeUnrelatedCall() throws Exception {
95 MatcherAssert.assertThat(
96 "UnnecessaryLocalRule should not fire when the local pins evaluation order before an unrelated side-effecting call",
97 this.violations("UnnecessaryLocalCapturedBeforeCall.java"),
98 Matchers.not(Matchers.hasItem(UnnecessaryLocalRuleTest.RULE))
99 );
100 }
101
102 @Test
103 void doesNotFireWhenInterveningCallSitsBeforeNestedUse() throws Exception {
104 MatcherAssert.assertThat(
105 "UnnecessaryLocalRule should not fire when a side-effecting statement intervenes before a use nested in an if block",
106 this.violations("UnnecessaryLocalInterveningNestedBlock.java"),
107 Matchers.not(Matchers.hasItem(UnnecessaryLocalRuleTest.RULE))
108 );
109 }
110
111 @Test
112 void doesNotFireWhenConstructorCapturedBeforeCall() throws Exception {
113 MatcherAssert.assertThat(
114 "UnnecessaryLocalRule should not fire when a constructor-call local pins evaluation order before an intervening call",
115 this.violations("UnnecessaryLocalConstructorBeforeCall.java"),
116 Matchers.not(Matchers.hasItem(UnnecessaryLocalRuleTest.RULE))
117 );
118 }
119
120 @Test
121 void doesNotFireOnTryWithResourcesResource() throws Exception {
122 MatcherAssert.assertThat(
123 "UnnecessaryLocalRule should not fire on a try-with-resources resource variable",
124 this.violations("UnnecessaryLocalTryWithResources.java"),
125 Matchers.not(Matchers.hasItem(UnnecessaryLocalRuleTest.RULE))
126 );
127 }
128
129 private List<String> violations(final String file) throws Exception {
130 final String name = String.format("src/main/java/foo/%s", file);
131 final Environment env = new Environment.Mock().withFile(
132 name,
133 new TextOf(this.getClass().getResourceAsStream(file)).asString()
134 );
135 return new PmdValidator(env).validate(
136 Collections.singletonList(new File(env.basedir(), name))
137 ).stream().map(Violation::name).collect(Collectors.toList());
138 }
139 }