1 package org.pojomatic.internal;
2
3 import static org.testng.Assert.*;
4
5 import org.testng.annotations.Test;
6 import org.testng.annotations.BeforeMethod;
7
8 import java.lang.reflect.AnnotatedElement;
9 import java.lang.reflect.Field;
10 import java.lang.reflect.Method;
11 import java.util.Arrays;
12 import java.util.Collections;
13 import java.util.EnumMap;
14 import java.util.List;
15 import java.util.Map;
16
17 import org.pojomatic.PropertyElement;
18
19 import com.google.common.base.Function;
20 import com.google.common.collect.Maps;
21
22
23 public class PropertyClassVisitorTest {
24 static class FieldsAndGetters {
25 int field1;
26 long getter1() { return 0L; }
27 String field2;
28 long field3;
29 boolean is2() { return false; }
30 void m3(@SuppressWarnings("unused") int n) {}
31 void m4(@SuppressWarnings("unused") int n) {}
32 }
33
34 static class Other {
35 int n;
36 }
37
38 private static enum NameExtractor implements Function<PropertyElement, String> {
39 INSTANCE;
40 @Override
41 public String apply(PropertyElement p) {
42 AnnotatedElement element = p.getElement();
43 if (element instanceof Method) {
44 return ((Method) element).getName();
45 } else {
46 return ((Field) element).getName();
47 }
48 }
49 }
50
51 private PropertyElement f1;
52 private PropertyElement f2;
53 private PropertyElement f3;
54 private PropertyElement m1;
55 private PropertyElement m2;
56 private PropertyElement m3;
57 private PropertyElement m4;
58
59 private static List<PropertyElement> NO_PROPERTIES = Collections.emptyList();
60
61 @BeforeMethod
62 public void setup() throws Exception {
63
64 f1 = new PropertyField(FieldsAndGetters.class.getDeclaredField("field1"), "");
65 f2 = new PropertyField(FieldsAndGetters.class.getDeclaredField("field2"), "");
66 f3 = new PropertyField(Other.class.getDeclaredField("n"), "");
67 m1 = new PropertyAccessor(FieldsAndGetters.class.getDeclaredMethod("getter1"), "");
68 m2 = new PropertyAccessor(FieldsAndGetters.class.getDeclaredMethod("is2"), "");
69 m3 = new PropertyAccessor(FieldsAndGetters.class.getDeclaredMethod("m3", int.class), "");
70 m4 = new PropertyAccessor(FieldsAndGetters.class.getDeclaredMethod("m4", int.class), "");
71 }
72
73 @Test
74 public void testReflectionOrdering() {
75 PropertyClassVisitor visitor = PropertyClassVisitor.visitClass(
76 FieldsAndGetters.class,
77 makeRoleMaps(Arrays.asList(f1, f2), Arrays.asList(f2, f1), NO_PROPERTIES),
78 makeRoleMaps(Arrays.asList(m2, m1), Arrays.asList(m1), Arrays.asList(m2)));
79 assertNotNull(visitor);
80 assertEquals(visitor.getSortedProperties(), makeRoleLists(Arrays.asList(f1, f2, m1, m2), Arrays.asList(f1, f2, m1), Arrays.asList(m2)));
81 }
82
83 @Test
84 public void testMissingCodeSource() {
85 Map<PropertyRole, Map<String, PropertyElement>> roleMaps =
86 makeRoleMaps(NO_PROPERTIES, NO_PROPERTIES, NO_PROPERTIES);
87 PropertyClassVisitor visitor = PropertyClassVisitor.visitClass(String.class, roleMaps, roleMaps);
88 assertNull(visitor);
89 }
90
91 @Test
92 public void testMissingClassBytes() throws Exception {
93 class Bean {}
94
95 ClassOnlyClassLoader classLoader = new ClassOnlyClassLoader(Bean.class.getClassLoader());
96 Class<?> beanClass = classLoader.loadClass(Bean.class.getName());
97 assertNotSame(Bean.class, beanClass);
98 assertNotNull(beanClass.getProtectionDomain().getCodeSource().getLocation());
99 Map<PropertyRole, Map<String, PropertyElement>> roleMaps =
100 makeRoleMaps(NO_PROPERTIES, NO_PROPERTIES, NO_PROPERTIES);
101 PropertyClassVisitor visitor = PropertyClassVisitor.visitClass(String.class, roleMaps, roleMaps);
102 assertNull(visitor);
103 }
104
105 @Test
106 public void testThrowReflectionMissmatch() throws Exception {
107 try {
108
109 PropertyClassVisitor.visitClass(
110 FieldsAndGetters.class,
111 makeRoleMaps(Arrays.asList(f3), NO_PROPERTIES, NO_PROPERTIES),
112 makeRoleMaps(Arrays.asList(m3, m4), NO_PROPERTIES, NO_PROPERTIES));
113 fail("Exception expected");
114 }
115 catch (IllegalStateException e) {
116 assertEquals(e.getMessage(), "In class " + FieldsAndGetters.class.getName() + ", properties "
117 + f3.getElement().toString() + ", " + m3.getElement().toString() + ", " + m4.getElement().toString()
118 + " were found in reflection, but not when visiting the bytecode");
119 }
120 }
121
122 @Test
123 public void testNestMates() throws Exception {
124 Field field = NestParent.class.getDeclaredField("i");
125 List<PropertyElement> fields = Arrays.<PropertyElement>asList(new PropertyField(field, "i"));
126 PropertyClassVisitor propertyClassVisitor = PropertyClassVisitor.visitClass(
127 NestParent.class,
128 makeRoleMaps(fields, fields, fields),
129 makeRoleMaps(NO_PROPERTIES, NO_PROPERTIES, NO_PROPERTIES));
130 assertEquals(
131 propertyClassVisitor.getSortedProperties().get(PropertyRole.EQUALS),
132 fields);
133 }
134
135 private static Map<PropertyRole, Map<String, PropertyElement>> makeRoleMaps(
136 List<PropertyElement> forEquals,
137 List<PropertyElement> forHashCode,
138 List<PropertyElement> forToString) {
139 EnumMap<PropertyRole, Map<String, PropertyElement>> enumMap = new EnumMap<>(PropertyRole.class);
140 enumMap.put(PropertyRole.EQUALS, Maps.uniqueIndex(forEquals, NameExtractor.INSTANCE));
141 enumMap.put(PropertyRole.HASH_CODE, Maps.uniqueIndex(forHashCode, NameExtractor.INSTANCE));
142 enumMap.put(PropertyRole.TO_STRING, Maps.uniqueIndex(forToString, NameExtractor.INSTANCE));
143 return enumMap;
144 }
145
146 private static Map<PropertyRole, List<PropertyElement>> makeRoleLists(
147 List<PropertyElement> forEquals, List<PropertyElement> forHashCode, List<PropertyElement> forToString) {
148 EnumMap<PropertyRole, List<PropertyElement>> enumMap = new EnumMap<>(PropertyRole.class);
149 enumMap.put(PropertyRole.EQUALS, forEquals);
150 enumMap.put(PropertyRole.HASH_CODE, forHashCode);
151 enumMap.put(PropertyRole.TO_STRING, forToString);
152 return enumMap;
153 }
154 }