1 // Copyright 2022 Code Intelligence GmbH 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.code_intelligence.jazzer.junit; 16 17 import static com.code_intelligence.jazzer.junit.Utils.durationStringToSeconds; 18 import static com.code_intelligence.jazzer.junit.Utils.getMarkedArguments; 19 import static com.code_intelligence.jazzer.junit.Utils.getMarkedInstance; 20 import static com.code_intelligence.jazzer.junit.Utils.isMarkedInstance; 21 import static com.code_intelligence.jazzer.junit.Utils.isMarkedInvocation; 22 import static com.google.common.truth.Truth.assertThat; 23 import static com.google.common.truth.Truth8.assertThat; 24 import static java.nio.file.Files.createDirectories; 25 import static java.nio.file.Files.createFile; 26 import static java.util.Arrays.stream; 27 import static java.util.Collections.singletonList; 28 import static java.util.stream.Collectors.joining; 29 import static org.junit.jupiter.params.provider.Arguments.arguments; 30 31 import java.io.File; 32 import java.io.IOException; 33 import java.lang.reflect.Method; 34 import java.nio.file.Path; 35 import java.util.AbstractList; 36 import java.util.AbstractMap; 37 import java.util.Arrays; 38 import java.util.HashMap; 39 import java.util.LinkedHashMap; 40 import java.util.List; 41 import java.util.Map; 42 import java.util.stream.Stream; 43 import org.junit.jupiter.api.Test; 44 import org.junit.jupiter.api.extension.ExtendWith; 45 import org.junit.jupiter.api.extension.ExtensionContext; 46 import org.junit.jupiter.api.extension.InvocationInterceptor; 47 import org.junit.jupiter.api.extension.ReflectiveInvocationContext; 48 import org.junit.jupiter.api.io.TempDir; 49 import org.junit.jupiter.params.ParameterizedTest; 50 import org.junit.jupiter.params.provider.Arguments; 51 import org.junit.jupiter.params.provider.MethodSource; 52 import org.junit.jupiter.params.provider.ValueSource; 53 54 public class UtilsTest implements InvocationInterceptor { 55 @TempDir Path temp; 56 57 @Test testDurationStringToSeconds()58 void testDurationStringToSeconds() { 59 assertThat(durationStringToSeconds("1m")).isEqualTo(60); 60 assertThat(durationStringToSeconds("1min")).isEqualTo(60); 61 assertThat(durationStringToSeconds("1h")).isEqualTo(60 * 60); 62 assertThat(durationStringToSeconds("1h 2m 30s")).isEqualTo(60 * 60 + 2 * 60 + 30); 63 assertThat(durationStringToSeconds("1hr2min30sec")).isEqualTo(60 * 60 + 2 * 60 + 30); 64 assertThat(durationStringToSeconds("1h2m30s")).isEqualTo(60 * 60 + 2 * 60 + 30); 65 } 66 67 @ValueSource(classes = {int.class, Class.class, Object.class, String.class, HashMap.class, 68 Map.class, int[].class, int[][].class, AbstractMap.class, AbstractList.class}) 69 @ParameterizedTest 70 void testMarkedInstances(Class<?> clazz)71 testMarkedInstances(Class<?> clazz) { 72 Object instance = getMarkedInstance(clazz); 73 if (clazz == int.class) { 74 assertThat(instance).isInstanceOf(Integer.class); 75 } else { 76 assertThat(instance).isInstanceOf(clazz); 77 } 78 assertThat(isMarkedInstance(instance)).isTrue(); 79 assertThat(getMarkedInstance(clazz)).isSameInstanceAs(instance); 80 } 81 testWithMarkedNamedParametersSource()82 static Stream<Arguments> testWithMarkedNamedParametersSource() { 83 Method testMethod = 84 stream(UtilsTest.class.getDeclaredMethods()) 85 .filter(method -> method.getName().equals("testWithMarkedNamedParameters")) 86 .findFirst() 87 .get(); 88 return Stream.of( 89 arguments("foo", 0, new HashMap<>(), singletonList(5), UtilsTest.class, new int[] {1}), 90 getMarkedArguments(testMethod, "some name"), 91 arguments("baz", 1, new LinkedHashMap<>(), Arrays.asList(5, 7), String.class, new int[0]), 92 getMarkedArguments(testMethod, "some other name")); 93 } 94 95 @MethodSource("testWithMarkedNamedParametersSource") 96 @ExtendWith(UtilsTest.class) 97 @ParameterizedTest testWithMarkedNamedParameters(String str, int num, AbstractMap<String, String> map, List<Integer> list, Class<?> clazz, int[] array)98 void testWithMarkedNamedParameters(String str, int num, AbstractMap<String, String> map, 99 List<Integer> list, Class<?> clazz, int[] array) {} 100 101 boolean argumentsExpectedToBeMarked = false; 102 103 @Override interceptTestTemplateMethod(Invocation<Void> invocation, ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext)104 public void interceptTestTemplateMethod(Invocation<Void> invocation, 105 ReflectiveInvocationContext<Method> invocationContext, ExtensionContext extensionContext) 106 throws Throwable { 107 assertThat(isMarkedInvocation(invocationContext)).isEqualTo(argumentsExpectedToBeMarked); 108 argumentsExpectedToBeMarked = !argumentsExpectedToBeMarked; 109 invocation.proceed(); 110 } 111 112 @Test testGetClassPathBasedInstrumentationFilter()113 public void testGetClassPathBasedInstrumentationFilter() throws IOException { 114 Path firstDir = createDirectories(temp.resolve("first_dir")); 115 Path orgExample = createDirectories(firstDir.resolve("org").resolve("example")); 116 createFile(orgExample.resolve("Application.class")); 117 118 Path nonExistentDir = temp.resolve("does not exist"); 119 120 Path secondDir = createDirectories(temp.resolve("second").resolve("dir")); 121 createFile(secondDir.resolve("Root.class")); 122 Path comExampleProject = 123 createDirectories(secondDir.resolve("com").resolve("example").resolve("project")); 124 createFile(comExampleProject.resolve("Main.class")); 125 Path comExampleOtherProject = 126 createDirectories(secondDir.resolve("com").resolve("example").resolve("other_project")); 127 createFile(comExampleOtherProject.resolve("Lib.class")); 128 129 Path emptyDir = createDirectories(temp.resolve("some").resolve("empty").resolve("dir")); 130 131 Path firstJar = createFile(temp.resolve("first.jar")); 132 Path secondJar = createFile(temp.resolve("second.jar")); 133 134 assertThat(Utils.getClassPathBasedInstrumentationFilter(makeClassPath( 135 firstDir, firstJar, nonExistentDir, secondDir, secondJar, emptyDir))) 136 .hasValue("*,com.example.other_project.**,com.example.project.**,org.example.**"); 137 } 138 139 @Test testGetClassPathBasedInstrumentationFilter_noDirs()140 public void testGetClassPathBasedInstrumentationFilter_noDirs() throws IOException { 141 Path firstJar = createFile(temp.resolve("first.jar")); 142 Path secondJar = createFile(temp.resolve("second.jar")); 143 144 assertThat(Utils.getClassPathBasedInstrumentationFilter(makeClassPath(firstJar, secondJar))) 145 .isEmpty(); 146 } 147 makeClassPath(Path... paths)148 private static String makeClassPath(Path... paths) { 149 return Arrays.stream(paths).map(Path::toString).collect(joining(File.pathSeparator)); 150 } 151 } 152