Skip to content

Commit e3ec836

Browse files
AndreasTuleonard84
andauthored
Increased Test Coverage for utils... (#1733)
ReflectionUtil, CollectionUtil and AutoAttachExension Co-authored-by: Leonard Brünings <leonard.bruenings@gradle.com>
1 parent 6556794 commit e3ec836

File tree

5 files changed

+216
-4
lines changed

5 files changed

+216
-4
lines changed

spock-core/src/main/java/org/spockframework/util/ReflectionUtil.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.File;
2020
import java.lang.annotation.Annotation;
2121
import java.lang.reflect.*;
22+
import java.security.CodeSource;
2223
import java.util.*;
2324

2425
import org.codehaus.groovy.runtime.MetaClassHelper;
@@ -155,8 +156,13 @@ public static Method getDeclaredMethodBySignature(Class<?> clazz, String name, C
155156
* Returns the class file for the given class (which has been verified to exist in the returned location),
156157
* or null if the class file could not be found (e.g. because it is contained in a Jar).
157158
*/
159+
@Nullable
158160
public static File getClassFile(Class<?> clazz) {
159-
File dir = new File(clazz.getProtectionDomain().getCodeSource().getLocation().getPath());
161+
CodeSource source = clazz.getProtectionDomain().getCodeSource();
162+
if (source == null) {
163+
return null;
164+
}
165+
File dir = new File(source.getLocation().getPath());
160166
if (!dir.isDirectory()) return null; // class file might be contained in Jar
161167
File clazzFile = new File(dir, clazz.getName().replace('.', File.separatorChar) + ".class");
162168
return clazzFile.isFile() ? clazzFile : null;

spock-core/src/main/java/spock/mock/AutoAttachExtension.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import spock.lang.Specification;
2121

2222
public class AutoAttachExtension implements IAnnotationDrivenExtension<AutoAttach> {
23-
private static MockUtil MOCK_UTIL = new MockUtil();
23+
private static final MockUtil MOCK_UTIL = new MockUtil();
2424

2525
@Override
2626
public void visitFieldAnnotation(AutoAttach annotation, FieldInfo field) {

spock-specs/src/test/groovy/org/spockframework/mock/AutoAttachInvalidUsageSpec.groovy

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,21 @@ package org.spockframework.mock
1717

1818
import org.spockframework.EmbeddedSpecification
1919
import org.spockframework.runtime.SpockException
20+
import spock.mock.AutoAttach
2021

2122
class AutoAttachInvalidUsageSpec extends EmbeddedSpecification {
2223

24+
def "setup"() {
25+
runner.addClassImport(AutoAttach)
26+
}
27+
28+
2329
def "not on shared"() {
2430
when:
2531
runner.runSpecBody('''
2632
27-
@spock.mock.AutoAttach
28-
@spock.lang.Shared
33+
@AutoAttach
34+
@Shared
2935
List mockShared
3036
3137
def "foo"() {
@@ -38,4 +44,36 @@ class AutoAttachInvalidUsageSpec extends EmbeddedSpecification {
3844
def ex = thrown(SpockException)
3945
ex.message == '@AutoAttach is only supported for instance fields (offending field: apackage.ASpec.mockShared)'
4046
}
47+
48+
def "null field"() {
49+
when:
50+
runner.runWithImports("""
51+
@Stepwise
52+
class NullFieldSpec extends Specification {
53+
@AutoAttach
54+
def field = null
55+
56+
def "feature"() { expect: true }
57+
}
58+
""")
59+
then:
60+
SpockException ex = thrown()
61+
ex.message == "Cannot AutoAttach 'null' for field field:3"
62+
}
63+
64+
def "No mock value for field"() {
65+
when:
66+
runner.runWithImports("""
67+
@Stepwise
68+
class NoMockSpec extends Specification {
69+
@AutoAttach
70+
def field = "Value"
71+
72+
def "feature"() { expect: true }
73+
}
74+
""")
75+
then:
76+
SpockException ex = thrown()
77+
ex.message == "AutoAttach failed 'Value' is not a mock for field field:3"
78+
}
4179
}

spock-specs/src/test/groovy/org/spockframework/util/CollectionUtilSpec.groovy

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,4 +84,45 @@ class CollectionUtilSpec extends Specification {
8484
private toList(iterable) {
8585
iterable.collect { it }
8686
}
87+
88+
def "asSet"() {
89+
when:
90+
def s = CollectionUtil.asSet(1, 3, 3, 4)
91+
then:
92+
s instanceof HashSet
93+
s.size() == 3
94+
s.contains(1)
95+
s.contains(3)
96+
s.contains(4)
97+
}
98+
99+
def "getFirstElement"() {
100+
expect:
101+
CollectionUtil.getFirstElement([1, 2, 3]) == 1
102+
when:
103+
CollectionUtil.getFirstElement([])
104+
then:
105+
thrown(InternalSpockError)
106+
}
107+
108+
def "getLastElement"() {
109+
expect:
110+
CollectionUtil.getLastElement([1, 2, 3]) == 3
111+
when:
112+
CollectionUtil.getLastElement([])
113+
then:
114+
thrown(InternalSpockError)
115+
}
116+
117+
def "addLastElement"() {
118+
when:
119+
def l = []
120+
CollectionUtil.addLastElement(l, 1)
121+
then:
122+
l == [1]
123+
when:
124+
CollectionUtil.addLastElement(l, 2)
125+
then:
126+
l == [1, 2]
127+
}
87128
}

spock-specs/src/test/groovy/org/spockframework/util/ReflectionUtilSpec.groovy

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@
1414

1515
package org.spockframework.util
1616

17+
import org.junit.platform.commons.annotation.Testable
1718
import spock.lang.*
1819

20+
import java.lang.annotation.Annotation
21+
import java.lang.reflect.Method
22+
1923
class ReflectionUtilSpec extends Specification {
2024
def "get package name"() {
2125
expect:
@@ -42,6 +46,7 @@ class ReflectionUtilSpec extends Specification {
4246
expect:
4347
ReflectionUtil.isMethodAvailable("java.util.List", "size")
4448
!ReflectionUtil.isMethodAvailable("java.util.List", "mice")
49+
!ReflectionUtil.isMethodAvailable("not.AvailableClass", "size")
4550
}
4651

4752
def "check if annotation of certain type is present"() {
@@ -200,4 +205,126 @@ class ReflectionUtilSpec extends Specification {
200205
static class Generics<T> {
201206
void foo(T one, List<T> two, List<String> three) {}
202207
}
208+
209+
def "isAnnotationPresentRecursive"(Class<?> clazz, Class<? extends Annotation> annotation, boolean expectedResult) {
210+
expect:
211+
ReflectionUtil.isAnnotationPresentRecursive(clazz, annotation) == expectedResult
212+
where:
213+
clazz | annotation | expectedResult
214+
Object | Nullable | false
215+
Specification | Testable | true
216+
ReflectionUtilSpec | Testable | true
217+
ReflectionUtilSpec | Nullable | false
218+
TypeWithAnno | Narrative | true
219+
SubTypeNoAnno | Narrative | true
220+
}
221+
222+
def "getAnnotationRecursive expecting annotation"(Class<?> clazz, Class<? extends Annotation> annotationClass) {
223+
when:
224+
def anno = ReflectionUtil.getAnnotationRecursive(clazz, annotationClass)
225+
then:
226+
clazz && annotationClass && anno != null
227+
where:
228+
clazz | annotationClass
229+
Specification | Testable
230+
ReflectionUtilSpec | Testable
231+
TypeWithAnno | Narrative
232+
SubTypeNoAnno | Narrative
233+
}
234+
235+
def "getAnnotationRecursive expecting none"(Class<?> clazz, Class<? extends Annotation> annotationClass) {
236+
when:
237+
def anno = ReflectionUtil.getAnnotationRecursive(clazz, annotationClass)
238+
then:
239+
clazz && annotationClass && anno == null
240+
where:
241+
clazz | annotationClass
242+
Object | Nullable
243+
ReflectionUtilSpec | Nullable
244+
}
245+
246+
def "collectAnnotationRecursive"(Class<?> clazz, Class<? extends Annotation> annotationClass, int expectedCount) {
247+
expect:
248+
ReflectionUtil.collectAnnotationRecursive(clazz, annotationClass).size() == expectedCount
249+
where:
250+
clazz | annotationClass | expectedCount
251+
Object | Nullable | 0
252+
Specification | Testable | 1
253+
ReflectionUtilSpec | Testable | 2
254+
ReflectionUtilSpec | Nullable | 0
255+
TypeWithAnno | Narrative | 1
256+
SubTypeNoAnno | Narrative | 1
257+
SubTypeWithAnno | Narrative | 2
258+
}
259+
260+
@Narrative
261+
private static class TypeWithAnno {}
262+
263+
@Narrative
264+
private static class SubTypeWithAnno extends TypeWithAnno {}
265+
266+
private static class SubTypeNoAnno extends TypeWithAnno {}
267+
268+
def "validateArguments - wrong argument count"() {
269+
when:
270+
ReflectionUtil.validateArguments(lookupMethod("methodNoArgs"), "Str")
271+
then:
272+
IllegalArgumentException ex = thrown()
273+
ex.message == "Method 'methodNoArgs([])' can't be called with parameters '[Str]'!"
274+
}
275+
276+
def "validateArguments - incompatible type"() {
277+
when: "Incompatible type"
278+
ReflectionUtil.validateArguments(lookupMethod("methodOneArg"), 1)
279+
then:
280+
IllegalArgumentException ex = thrown()
281+
ex.message == "Method 'methodOneArg([class java.lang.String])' can't be called with parameters '[1]'!"
282+
}
283+
284+
def "validateArguments - null value on primitive type"() {
285+
when: "Null value on primitive type"
286+
ReflectionUtil.validateArguments(lookupMethod("methodPrimitiveArg"), [null] as Object[])
287+
then:
288+
thrown(IllegalArgumentException)
289+
}
290+
291+
def "validateArguments - Correct types"() {
292+
when: "Correct types"
293+
ReflectionUtil.validateArguments(lookupMethod("methodOneArg"), "Str")
294+
then:
295+
noExceptionThrown()
296+
}
297+
298+
private Method lookupMethod(String name) {
299+
return Objects.requireNonNull(ReflectionUtilSpec.class.getMethods().find { it.name == name })
300+
}
301+
302+
@SuppressWarnings('unused')
303+
static void methodNoArgs() {}
304+
305+
@SuppressWarnings('unused')
306+
static void methodOneArg(String s) {}
307+
308+
@SuppressWarnings('unused')
309+
static void methodPrimitiveArg(int value) {}
310+
311+
def "deepCopyFields errors"() {
312+
when:
313+
ReflectionUtil.deepCopyFields("Str", 10)
314+
then:
315+
IllegalArgumentException ex = thrown()
316+
ex.message == "source and target are not compatible."
317+
}
318+
319+
def "getClassFile"() {
320+
expect:
321+
ReflectionUtil.getClassFile(String) == null
322+
ReflectionUtil.getClassFile(Specification) == null
323+
ReflectionUtil.getClassFile(ReflectionUtilSpec) != null
324+
}
325+
326+
def "isToStringOverridden error"() {
327+
expect:
328+
!ReflectionUtil.isToStringOverridden(int.class)
329+
}
203330
}

0 commit comments

Comments
 (0)