View Javadoc
1   /*-
2    * #%L
3    * io.earcam.instrumental.agent.defy
4    * %%
5    * Copyright (C) 2018 earcam
6    * %%
7    * SPDX-License-Identifier: (BSD-3-Clause OR EPL-1.0 OR Apache-2.0 OR MIT)
8    * 
9    * You <b>must</b> choose to accept, in full - any individual or combination of 
10   * the following licenses:
11   * <ul>
12   * 	<li><a href="https://opensource.org/licenses/BSD-3-Clause">BSD-3-Clause</a></li>
13   * 	<li><a href="https://www.eclipse.org/legal/epl-v10.html">EPL-1.0</a></li>
14   * 	<li><a href="https://www.apache.org/licenses/LICENSE-2.0">Apache-2.0</a></li>
15   * 	<li><a href="https://opensource.org/licenses/MIT">MIT</a></li>
16   * </ul>
17   * #L%
18   */
19  package io.earcam.instrumental.agent.defy;
20  
21  import static io.earcam.instrumental.proxy.handler.NoopInvocationHandler.NOOP_INVOCATION_HANDLER;
22  import static org.hamcrest.MatcherAssert.assertThat;
23  import static org.hamcrest.Matchers.equalTo;
24  import static org.hamcrest.Matchers.is;
25  import static org.junit.jupiter.api.Assertions.assertFalse;
26  import static org.junit.jupiter.api.Assertions.assertTrue;
27  import static org.junit.jupiter.api.Assertions.fail;
28  
29  import java.lang.instrument.Instrumentation;
30  import java.lang.reflect.Modifier;
31  
32  import org.junit.jupiter.api.Test;
33  
34  import io.earcam.acme.a.FinalClass;
35  import io.earcam.acme.a.InterfaceWithFinalField;
36  import io.earcam.acme.b.FinalClassB;
37  import io.earcam.acme.c.FinalClassC;
38  import io.earcam.instrumental.agent.junit.extension.AgentClass;
39  import io.earcam.instrumental.proxy.Proxies;
40  import io.earcam.unexceptional.Exceptional;
41  
42  @AgentClass(value = Agent.class, arguments = "io.earcam.acme.a,io.earcam.acme.c")
43  public final class AgentTest {
44  
45  	public static final Instrumentation MOCK_INSTRUMENTATION = Proxies.proxy(NOOP_INVOCATION_HANDLER, Instrumentation.class);
46  
47  
48  	@Test
49  	public void finalClassShouldNotBeFinal()
50  	{
51  		Class<?> clazz = loadClass("io.earcam.acme.a.FinalClass");
52  		assertFalse(Modifier.isFinal(clazz.getModifiers()));
53  	}
54  
55  
56  	@Test
57  	public void loadedFinalClassShouldNotBeFinal()
58  	{
59  		Class<?> clazz = FinalClass.class;
60  		assertFalse(Modifier.isFinal(clazz.getModifiers()));
61  	}
62  
63  
64  	private Class<?> loadClass(String name)
65  	{
66  		return Exceptional.apply(ClassLoader::loadClass, AgentTest.class.getClassLoader(), name);
67  	}
68  
69  
70  	@Test
71  	public void finalMethodShouldNotBeFinal() throws NoSuchMethodException, SecurityException
72  	{
73  		Class<?> clazz = loadClass("io.earcam.acme.a.FinalClass");
74  		assertFalse(Modifier.isFinal(clazz.getMethod("sayFoo").getModifiers()));
75  	}
76  
77  
78  	@Test
79  	public void finalFieldShouldNotBeFinal() throws NoSuchFieldException, SecurityException
80  	{
81  		Class<?> clazz = loadClass("io.earcam.acme.a.FinalClass");
82  		assertFalse(Modifier.isFinal(clazz.getField("field").getModifiers()));
83  	}
84  
85  
86  	@Test
87  	public void doesNotProduceInvalidInterfaces() throws NoSuchFieldException, SecurityException
88  	{
89  		assertTrue(Modifier.isFinal(InterfaceWithFinalField.class.getField("field").getModifiers()));
90  	}
91  
92  
93  	@Test
94  	public void finalSystemClassWillStillBeFinal()
95  	{
96  		Class<?> clazz = loadClass("java.lang.String");
97  		assertTrue(Modifier.isFinal(clazz.getModifiers()));
98  	}
99  
100 
101 	@Test
102 	public void otherFinalClassMatchedByPatternIsDefinalised()
103 	{
104 		Class<?> clazz = FinalClassC.class;
105 		assertFalse(Modifier.isFinal(clazz.getModifiers()));
106 	}
107 
108 
109 	@Test
110 	public void otherFinalClassNotMatchedByPatternIsStillFinal()
111 	{
112 		Class<?> clazz = FinalClassB.class;
113 		assertTrue(Modifier.isFinal(clazz.getModifiers()));
114 	}
115 
116 
117 	@Test
118 	public void agentThrowsIfArgumentIsNull()
119 	{
120 		try {
121 			Agent.premain(null, MOCK_INSTRUMENTATION);
122 			fail();
123 		} catch(IllegalArgumentException e) {}
124 	}
125 
126 
127 	@Test
128 	public void agentThrowsIfArgumentContainIllegalCharacters()
129 	{
130 		try {
131 			Agent.premain("com.acme.*", MOCK_INSTRUMENTATION);
132 			fail();
133 		} catch(IllegalArgumentException e) {}
134 	}
135 
136 
137 	@Test
138 	public void agentHoldsReferenceToInstrumentation()
139 	{
140 		Agent.premain("com.acme.boo", MOCK_INSTRUMENTATION);
141 
142 		assertThat(Agent.instrumentation, is(equalTo(MOCK_INSTRUMENTATION)));
143 	}
144 }