/******************************************************************************* * 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() { } } }