1 /* 2 * Copyright (C) 2019 Google, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.escapevelocity; 17 18 import static com.google.common.truth.Truth.assertThat; 19 import static java.util.stream.Collectors.toSet; 20 21 import com.google.common.collect.ImmutableMap; 22 import java.lang.reflect.Method; 23 import java.lang.reflect.Modifier; 24 import java.util.Collections; 25 import java.util.List; 26 import java.util.Map; 27 import java.util.Set; 28 import org.junit.Test; 29 import org.junit.runner.RunWith; 30 import org.junit.runners.JUnit4; 31 32 @RunWith(JUnit4.class) 33 public class MethodFinderTest { 34 @Test visibleMethodFromClass()35 public void visibleMethodFromClass() throws Exception { 36 Map<String, String> map = Collections.singletonMap("foo", "bar"); 37 Class<?> mapClass = map.getClass(); 38 assertThat(Modifier.isPublic(mapClass.getModifiers())).isFalse(); 39 40 Method size = mapClass.getMethod("size"); 41 Method visibleSize = MethodFinder.visibleMethod(size, mapClass); 42 assertThat(visibleSize.getDeclaringClass().isInterface()).isFalse(); 43 assertThat(visibleSize.invoke(map)).isEqualTo(1); 44 } 45 46 @Test visibleMethodFromInterface()47 public void visibleMethodFromInterface() throws Exception { 48 Map<String, String> map = ImmutableMap.of("foo", "bar"); 49 Map.Entry<String, String> entry = map.entrySet().iterator().next(); 50 Class<?> entryClass = entry.getClass(); 51 assertThat(Modifier.isPublic(entryClass.getModifiers())).isFalse(); 52 53 Method getValue = entryClass.getMethod("getValue"); 54 Method visibleGetValue = MethodFinder.visibleMethod(getValue, entryClass); 55 assertThat(visibleGetValue.getDeclaringClass().isInterface()).isTrue(); 56 assertThat(visibleGetValue.invoke(entry)).isEqualTo("bar"); 57 } 58 59 @Test publicMethodsWithName()60 public void publicMethodsWithName() { 61 List<String> list = Collections.singletonList("foo"); 62 Class<?> listClass = list.getClass(); 63 assertThat(Modifier.isPublic(listClass.getModifiers())).isFalse(); 64 65 MethodFinder methodFinder = new MethodFinder(); 66 Set<Method> methods = methodFinder.publicMethodsWithName(listClass, "remove"); 67 // This should find at least remove(int) and remove(Object). 68 assertThat(methods.size()).isAtLeast(2); 69 assertThat(methods.stream().map(Method::getName).collect(toSet())).containsExactly("remove"); 70 assertThat(methods.stream().allMatch(MethodFinderTest::isPublic)).isTrue(); 71 72 // We should cache the result, meaning we get back the same result if we ask a second time. 73 Set<Method> methods2 = methodFinder.publicMethodsWithName(listClass, "remove"); 74 assertThat(methods2).isSameInstanceAs(methods); 75 } 76 77 @Test publicMethodsWithName_Nonexistent()78 public void publicMethodsWithName_Nonexistent() { 79 List<String> list = Collections.singletonList("foo"); 80 Class<?> listClass = list.getClass(); 81 assertThat(Modifier.isPublic(listClass.getModifiers())).isFalse(); 82 83 MethodFinder methodFinder = new MethodFinder(); 84 Set<Method> methods = methodFinder.publicMethodsWithName(listClass, "nonexistentMethod"); 85 assertThat(methods).isEmpty(); 86 } 87 isPublic(Method method)88 private static boolean isPublic(Method method) { 89 return Modifier.isPublic(method.getModifiers()) 90 && Modifier.isPublic(method.getDeclaringClass().getModifiers()); 91 } 92 } 93