Skip to content

Commit 6b880bf

Browse files
author
jbrown
committed
Added matchers to check the visibility (public/private) of various reflective elements.
This is helpful, for example, when enforcing the scope of a public-facing API with a test, and provides stronger documentation for the future than mere comments.
1 parent 5dd6a62 commit 6b880bf

File tree

11 files changed

+801
-0
lines changed

11 files changed

+801
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.hamcrest.visibility;
2+
3+
import org.hamcrest.BaseMatcher;
4+
import org.hamcrest.Description;
5+
6+
import java.lang.reflect.Member;
7+
8+
abstract class AbstractVisibilityMatcher<T> extends BaseMatcher<T>
9+
{
10+
/**
11+
* Should only ever be one of the values returned from
12+
* {@link VisibilityUtils#describeVisibility(Member)} and {@link VisibilityUtils#describeVisibility(Class)}
13+
**/
14+
private final String expectedVisibility;
15+
16+
AbstractVisibilityMatcher(String expectedVisibility)
17+
{
18+
this.expectedVisibility = expectedVisibility;
19+
}
20+
21+
@Override public void describeTo(Description description)
22+
{
23+
description.appendText("is ").appendText(expectedVisibility);
24+
}
25+
26+
@Override public void describeMismatch(Object item, Description description)
27+
{
28+
if (item == null)
29+
{
30+
description.appendText("was null");
31+
}
32+
else if (item instanceof Class)
33+
{
34+
description.appendText("was a ")
35+
.appendText(VisibilityUtils.describeVisibility((Class<?>) item))
36+
.appendText(" class");
37+
}
38+
else if (item instanceof Member)
39+
{
40+
description.appendText("was a ")
41+
.appendText(VisibilityUtils.describeVisibility((Member) item))
42+
.appendText(" ")
43+
.appendText(item.getClass().getName());
44+
}
45+
else
46+
{
47+
description.appendText("was "+item.getClass().getName()+" instead of a reflective element like a Class<T>, Constructor<T>, or Method");
48+
}
49+
}
50+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.hamcrest.visibility;
2+
3+
import org.hamcrest.Matcher;
4+
5+
import java.lang.reflect.Member;
6+
7+
public class IsPackageProtected<T> extends AbstractVisibilityMatcher<T>
8+
{
9+
public IsPackageProtected()
10+
{
11+
super(VisibilityUtils.PACKAGE_PROTECTED_DESCRIPTION);
12+
}
13+
14+
@Override
15+
public boolean matches(Object actual)
16+
{
17+
if (actual == null)
18+
{
19+
return false;
20+
}
21+
if (actual instanceof Class)
22+
{
23+
return VisibilityUtils.isPackageProtected((Class<?>) actual);
24+
}
25+
if (actual instanceof Member)
26+
{
27+
return VisibilityUtils.isPackageProtected((Member) actual);
28+
}
29+
return false;
30+
}
31+
32+
public static <T> Matcher<T> isPackageProtected()
33+
{
34+
return new IsPackageProtected<>();
35+
}
36+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.hamcrest.visibility;
2+
3+
import org.hamcrest.Matcher;
4+
5+
import java.lang.reflect.Member;
6+
7+
public class IsPrivate<T> extends AbstractVisibilityMatcher<T>
8+
{
9+
public IsPrivate(){
10+
super(VisibilityUtils.PRIVATE_DESCRIPTION);
11+
}
12+
13+
@Override
14+
public boolean matches(Object actual)
15+
{
16+
if (actual == null)
17+
{
18+
return false;
19+
}
20+
if (actual instanceof Class)
21+
{
22+
return VisibilityUtils.isPrivate((Class<?>) actual);
23+
}
24+
if (actual instanceof Member)
25+
{
26+
return VisibilityUtils.isPrivate((Member) actual);
27+
}
28+
return false;
29+
}
30+
31+
public static <T> Matcher<T> isPrivate()
32+
{
33+
return new IsPrivate<>();
34+
}
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.hamcrest.visibility;
2+
3+
import org.hamcrest.Matcher;
4+
5+
import java.lang.reflect.Member;
6+
7+
public class IsProtected<T> extends AbstractVisibilityMatcher<T>
8+
{
9+
public IsProtected(){
10+
super(VisibilityUtils.PROTECTED_DESCRIPTION);
11+
}
12+
13+
@Override
14+
public boolean matches(Object actual)
15+
{
16+
if (actual == null)
17+
{
18+
return false;
19+
}
20+
if (actual instanceof Class)
21+
{
22+
return VisibilityUtils.isProtected((Class<?>) actual);
23+
}
24+
if (actual instanceof Member)
25+
{
26+
return VisibilityUtils.isProtected((Member) actual);
27+
}
28+
return false;
29+
}
30+
31+
public static <T> Matcher<T> isProtected()
32+
{
33+
return new IsProtected<>();
34+
}
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.hamcrest.visibility;
2+
3+
import org.hamcrest.Matcher;
4+
5+
import java.lang.reflect.Member;
6+
7+
public class IsPublic<T> extends AbstractVisibilityMatcher<T>
8+
{
9+
public IsPublic(){
10+
super(VisibilityUtils.PUBLIC_DESCRIPTION);
11+
}
12+
13+
@Override
14+
public boolean matches(Object actual)
15+
{
16+
if (actual == null)
17+
{
18+
return false;
19+
}
20+
if (actual instanceof Class)
21+
{
22+
return VisibilityUtils.isPublic((Class<?>) actual);
23+
}
24+
if (actual instanceof Member)
25+
{
26+
return VisibilityUtils.isPublic((Member) actual);
27+
}
28+
return false;
29+
}
30+
31+
public static <T> Matcher<T> isPublic()
32+
{
33+
return new IsPublic<>();
34+
}
35+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package org.hamcrest.visibility;
2+
3+
import java.lang.reflect.Member;
4+
import java.lang.reflect.Modifier;
5+
6+
class VisibilityUtils
7+
{
8+
9+
static final String PUBLIC_DESCRIPTION = "public";
10+
static final String PROTECTED_DESCRIPTION = "protected";
11+
static final String PACKAGE_PROTECTED_DESCRIPTION = "package-protected (no modifiers)";
12+
static final String PRIVATE_DESCRIPTION = "private";
13+
14+
static boolean isPublic(Class<?> clazz)
15+
{
16+
return clazz != null && Modifier.isPublic(clazz.getModifiers());
17+
}
18+
19+
static boolean isProtected(Class<?> clazz)
20+
{
21+
return clazz != null && Modifier.isProtected(clazz.getModifiers());
22+
}
23+
24+
static boolean isPackageProtected(Class<?> clazz)
25+
{
26+
return clazz != null && !isPublic(clazz) && !isProtected(clazz) && !isPrivate(clazz);
27+
}
28+
29+
static boolean isPrivate(Class<?> clazz)
30+
{
31+
return clazz != null && Modifier.isPrivate(clazz.getModifiers());
32+
}
33+
34+
35+
static boolean isPublic(Member member)
36+
{
37+
return member != null && Modifier.isPublic(member.getModifiers());
38+
}
39+
40+
static boolean isProtected(Member member)
41+
{
42+
return member != null && Modifier.isProtected(member.getModifiers());
43+
}
44+
45+
static boolean isPackageProtected(Member member)
46+
{
47+
return member != null && !isPublic(member) && !isProtected(member) && !isPrivate(member);
48+
}
49+
50+
static boolean isPrivate(Member member)
51+
{
52+
return member != null && Modifier.isPrivate(member.getModifiers());
53+
}
54+
55+
56+
static String describeVisibility(Class<?> clazz)
57+
{
58+
if (isPublic(clazz))
59+
{
60+
return PUBLIC_DESCRIPTION;
61+
}
62+
if (isProtected(clazz))
63+
{
64+
return PROTECTED_DESCRIPTION;
65+
}
66+
if (isPackageProtected(clazz))
67+
{
68+
return PACKAGE_PROTECTED_DESCRIPTION;
69+
}
70+
if (isPrivate(clazz))
71+
{
72+
return PRIVATE_DESCRIPTION;
73+
}
74+
throw new IllegalArgumentException("Encountered unexpected visibility! This should NEVER happen.");
75+
}
76+
77+
static String describeVisibility(Member member)
78+
{
79+
if (isPublic(member))
80+
{
81+
return PUBLIC_DESCRIPTION;
82+
}
83+
if (isProtected(member))
84+
{
85+
return PROTECTED_DESCRIPTION;
86+
}
87+
if (isPackageProtected(member))
88+
{
89+
return PACKAGE_PROTECTED_DESCRIPTION;
90+
}
91+
if (isPrivate(member))
92+
{
93+
return PRIVATE_DESCRIPTION;
94+
}
95+
throw new IllegalArgumentException("Encountered unexpected visibility! This should NEVER happen.");
96+
}
97+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
</head>
6+
<body>
7+
<p>Matchers that perform checks on the visibility of reflective elements, such as Class&lt;?&gt; objects</p>
8+
</body>
9+
</html>

0 commit comments

Comments
 (0)