| /******************************************************************************* |
| * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Marc R. Hoffmann - initial API and implementation |
| * |
| *******************************************************************************/ |
| package org.jacoco.agent.rt.internal; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.lang.instrument.IllegalClassFormatException; |
| import java.security.CodeSource; |
| import java.security.ProtectionDomain; |
| import java.security.cert.Certificate; |
| |
| import org.jacoco.core.JaCoCo; |
| import org.jacoco.core.runtime.AbstractRuntime; |
| import org.jacoco.core.runtime.AgentOptions; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.objectweb.asm.MethodVisitor; |
| |
| /** |
| * Unit tests for {@link CoverageTransformer}. |
| */ |
| public class CoverageTransformerTest { |
| |
| private ExceptionRecorder recorder; |
| |
| private AgentOptions options; |
| |
| private ClassLoader classLoader; |
| |
| private ProtectionDomain protectionDomain; |
| |
| private StubRuntime runtime; |
| |
| @Before |
| public void setup() { |
| recorder = new ExceptionRecorder(); |
| options = new AgentOptions(); |
| classLoader = getClass().getClassLoader(); |
| protectionDomain = getClass().getProtectionDomain(); |
| runtime = new StubRuntime(); |
| } |
| |
| @After |
| public void teardown() { |
| recorder.assertNoException(); |
| } |
| |
| @Test |
| public void testFilterAgentClass() { |
| CoverageTransformer t = createTransformer(); |
| assertFalse(t.filter(classLoader, |
| "org/jacoco/agent/rt/internal/somepkg/SomeClass", |
| protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterInclBootstrapClassesPositive() { |
| options.setInclBootstrapClasses(true); |
| CoverageTransformer t = createTransformer(); |
| assertTrue(t.filter(null, "java/util/TreeSet", protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterInclBootstrapClassesNegative() { |
| options.setInclBootstrapClasses(false); |
| CoverageTransformer t = createTransformer(); |
| assertFalse(t.filter(null, "java/util/TreeSet", protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterClassLoaderPositive1() { |
| options.setInclBootstrapClasses(false); |
| options.setExclClassloader("org.jacoco.agent.SomeWhere$*"); |
| CoverageTransformer t = createTransformer(); |
| assertTrue(t.filter(classLoader, "org/example/Foo", protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterClassLoaderPositive2() { |
| options.setInclBootstrapClasses(true); |
| options.setExclClassloader("org.jacoco.agent.SomeWhere$*"); |
| CoverageTransformer t = createTransformer(); |
| assertTrue(t.filter(classLoader, "org/example/Foo", protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterClassLoaderNegative1() { |
| options.setInclBootstrapClasses(false); |
| options.setExclClassloader("org.jacoco.agent.rt.internal.CoverageTransformerTest$*"); |
| CoverageTransformer t = createTransformer(); |
| ClassLoader myClassLoader = new ClassLoader(null) { |
| }; |
| assertFalse(t |
| .filter(myClassLoader, "org/example/Foo", protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterClassLoaderNegative2() { |
| options.setInclBootstrapClasses(true); |
| options.setExclClassloader("org.jacoco.agent.rt.internal.CoverageTransformerTest$*"); |
| CoverageTransformer t = createTransformer(); |
| ClassLoader myClassLoader = new ClassLoader(null) { |
| }; |
| assertFalse(t |
| .filter(myClassLoader, "org/example/Foo", protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterIncludedClassPositive() { |
| options.setIncludes("org.jacoco.core.*:org.jacoco.agent.rt.*"); |
| CoverageTransformer t = createTransformer(); |
| assertTrue(t.filter(classLoader, "org/jacoco/core/Foo", |
| protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterIncludedClassNegative() { |
| options.setIncludes("org.jacoco.core.*:org.jacoco.agent.rt.*"); |
| CoverageTransformer t = createTransformer(); |
| assertFalse(t.filter(classLoader, "org/jacoco/report/Foo", |
| protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterExcludedClassPositive() { |
| options.setExcludes("*Test"); |
| CoverageTransformer t = createTransformer(); |
| assertFalse(t.filter(classLoader, "org/jacoco/core/FooTest", |
| protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterExcludedClassPositiveInner() { |
| options.setExcludes("org.jacoco.example.Foo$Inner"); |
| CoverageTransformer t = createTransformer(); |
| assertFalse(t.filter(classLoader, "org/jacoco/example/Foo$Inner", |
| protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterExcludedClassNegative() { |
| options.setExcludes("*Test"); |
| CoverageTransformer t = createTransformer(); |
| assertTrue(t.filter(classLoader, "org/jacoco/core/Foo", |
| protectionDomain)); |
| } |
| |
| @Test |
| public void testFilterSourceLocationPositive1() { |
| CoverageTransformer t = createTransformer(); |
| assertFalse(t.filter(classLoader, "org/jacoco/core/Foo", null)); |
| } |
| |
| @Test |
| public void testFilterSourceLocationPositive2() { |
| CoverageTransformer t = createTransformer(); |
| ProtectionDomain pd = new ProtectionDomain(null, null); |
| assertFalse(t.filter(classLoader, "org/jacoco/core/Foo", pd)); |
| } |
| |
| @Test |
| public void testFilterSourceLocationPositive3() { |
| CoverageTransformer t = createTransformer(); |
| CodeSource cs = new CodeSource(null, new Certificate[0]); |
| ProtectionDomain pd = new ProtectionDomain(cs, null); |
| assertFalse(t.filter(classLoader, "org/jacoco/core/Foo", pd)); |
| } |
| |
| @Test |
| public void testFilterSourceLocationNegative() { |
| options.setInclNoLocationClasses(true); |
| CoverageTransformer t = createTransformer(); |
| assertTrue(t.filter(classLoader, "org/jacoco/core/Foo", null)); |
| } |
| |
| @Test |
| public void testTransformFiltered1() throws IllegalClassFormatException { |
| CoverageTransformer t = createTransformer(); |
| assertNull(t.transform(classLoader, "org.jacoco.Sample", null, null, |
| new byte[0])); |
| } |
| |
| @Test |
| public void testTransformFiltered2() throws IllegalClassFormatException { |
| CoverageTransformer t = createTransformer(); |
| assertNull(t.transform((ClassLoader) null, "org.jacoco.Sample", null, |
| protectionDomain, new byte[0])); |
| } |
| |
| @Test |
| public void testTransformFailure() { |
| CoverageTransformer t = createTransformer(); |
| try { |
| t.transform(classLoader, "org.jacoco.Sample", null, |
| protectionDomain, null); |
| fail("IllegalClassFormatException expected."); |
| } catch (IllegalClassFormatException e) { |
| assertEquals("Error while instrumenting org.jacoco.Sample.", |
| e.getMessage()); |
| } |
| recorder.assertException(IllegalClassFormatException.class, |
| "Error while instrumenting org.jacoco.Sample.", |
| IOException.class); |
| recorder.clear(); |
| } |
| |
| @Test |
| public void testRedefinedClass() throws Exception { |
| CoverageTransformer t = createTransformer(); |
| // Just pick any non-system class outside our namespace |
| final Class<?> target = JaCoCo.class; |
| assertNull(t.transform(classLoader, target.getName(), target, |
| protectionDomain, getClassData(target))); |
| } |
| |
| private CoverageTransformer createTransformer() { |
| return new CoverageTransformer(runtime, options, recorder); |
| } |
| |
| private static byte[] getClassData(Class<?> clazz) throws IOException { |
| final String resource = "/" + clazz.getName().replace('.', '/') |
| + ".class"; |
| final InputStream in = clazz.getResourceAsStream(resource); |
| final ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| byte[] buffer = new byte[0x100]; |
| int len; |
| while ((len = in.read(buffer)) != -1) { |
| out.write(buffer, 0, len); |
| } |
| in.close(); |
| return out.toByteArray(); |
| } |
| |
| private static class StubRuntime extends AbstractRuntime { |
| |
| public StubRuntime() { |
| } |
| |
| public int generateDataAccessor(long classid, String classname, |
| int probecount, MethodVisitor mv) { |
| return 0; |
| } |
| |
| public void shutdown() { |
| } |
| |
| } |
| |
| } |