2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.drools.pooling.extractor;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNull;
27 import java.util.Properties;
28 import java.util.TreeMap;
29 import java.util.function.Function;
30 import org.junit.Before;
31 import org.junit.Test;
33 public class ClassExtractorsTest {
35 private static final int NTIMES = 5;
37 private static final String MY_TYPE = "theType";
38 private static final String PROP_PREFIX = "extractor." + MY_TYPE + ".";
40 private static final String VALUE = "a value";
41 private static final Integer INT_VALUE = 10;
42 private static final Integer INT_VALUE2 = 20;
44 private Properties props;
45 private ClassExtractors map;
49 props = new Properties();
51 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${intValue}");
52 props.setProperty(PROP_PREFIX + WithString.class.getName(), "${strValue}");
54 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
58 public void testExtract() {
59 Simple obj = new Simple();
60 assertEquals(INT_VALUE, map.extract(obj));
63 assertEquals(VALUE, tryIt(Simple.class, "${strValue}", xxx -> new Simple()));
66 assertNull(map.extract(null));
68 // values from two different kinds of objects
69 props = new Properties();
70 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${intValue}");
71 props.setProperty(PROP_PREFIX + WithString.class.getName(), "${strValue}");
72 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
74 assertEquals(INT_VALUE, map.extract(new Simple()));
75 assertEquals(VALUE, map.extract(new Sub()));
77 // values from a superclass method, but property defined for subclass
78 props = new Properties();
79 props.setProperty(PROP_PREFIX + Sub.class.getName(), "${strValue}");
80 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
82 assertEquals(VALUE, map.extract(new Sub()));
84 // values from a superclass field, but property defined for subclass
85 props = new Properties();
86 props.setProperty(PROP_PREFIX + Sub.class.getName(), "${intValue}");
87 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
89 assertEquals(INT_VALUE, map.extract(new Sub()));
92 // prefix includes trailing "."
93 props = new Properties();
94 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${intValue}");
95 map = new ClassExtractors(props, PROP_PREFIX.substring(0, PROP_PREFIX.length() - 1), MY_TYPE);
96 assertEquals(INT_VALUE, map.extract(new Simple()));
99 // values from an class in a different file
100 props = new Properties();
101 props.setProperty(PROP_PREFIX + ClassExtractorsTestSupport.class.getName(), "${nested.theValue}");
102 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
104 assertEquals(ClassExtractorsTestSupport2.NESTED_VALUE, map.extract(new ClassExtractorsTestSupport()));
108 public void testGetExtractor() {
109 Simple obj = new Simple();
111 // repeat - shouldn't re-create the extractor
112 for (int x = 0; x < NTIMES; ++x) {
113 assertEquals("x=" + x, INT_VALUE, map.extract(obj));
114 assertEquals("x=" + x, 1, map.size());
119 public void testBuildExtractorClass_TopLevel() {
120 // extractor defined for top-level class
121 props = new Properties();
122 props.setProperty(PROP_PREFIX + Sub.class.getName(), "${strValue}");
124 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
125 assertEquals(VALUE, map.extract(new Sub()));
127 // one extractor for top-level class
128 assertEquals(1, map.size());
132 public void testBuildExtractorClass_SuperClass() {
133 // extractor defined for superclass (interface)
134 assertEquals(VALUE, map.extract(new Sub()));
136 // one extractor for top-level class and one for interface
137 assertEquals(2, map.size());
141 public void testBuildExtractorClass_NotDefined() {
142 // no extractor defined for "this" class
143 assertNull(map.extract(this));
145 // one NULL extractor for top-level class
146 assertEquals(1, map.size());
150 public void testBuildExtractorClassString() {
152 assertNull(tryIt(Simple.class, "intValue}", xxx -> new Simple()));
155 assertNull(tryIt(Simple.class, "${intValue", xxx -> new Simple()));
158 assertNull(tryIt(Sub.class, "${.simple.strValue}", xxx -> new Sub()));
161 assertNull(tryIt(Sub.class, "${simple.strValue.}", xxx -> new Sub()));
164 assertEquals(VALUE, tryIt(Sub.class, "${strValue}", xxx -> new Sub()));
167 assertEquals(VALUE, tryIt(Sub.class, "${simple.strValue}", xxx -> new Sub()));
170 assertNull(tryIt(Sub.class, "${unknown}", xxx -> new Sub()));
174 public void testGetClassExtractor_InSuper() {
175 // field in the superclass
176 assertEquals(INT_VALUE, tryIt(Super.class, "${intValue}", xxx -> new Sub()));
180 public void testGetClassExtractor_InInterface() {
181 // defined in the interface
182 assertEquals(VALUE, map.extract(new Sub()));
186 public void testNullExtractorExtract() {
187 // empty properties - should only create NullExtractor
188 map = new ClassExtractors(new Properties(), PROP_PREFIX, MY_TYPE);
190 Simple obj = new Simple();
192 // repeat - shouldn't re-create the extractor
193 for (int x = 0; x < NTIMES; ++x) {
194 assertNull("x=" + x, map.extract(obj));
195 assertEquals("x=" + x, 1, map.size());
200 public void testComponetizedExtractor() {
202 assertEquals(VALUE, tryIt(Sub.class, "${strValue}", xxx -> new Sub()));
205 assertEquals(VALUE, tryIt(Sub.class, "${cont.data.strValue}", xxx -> new Sub()));
209 public void testComponetizedExtractorBuildExtractor_Method() {
210 assertEquals(INT_VALUE, tryIt(Simple.class, "${intValue}", xxx -> new Simple()));
214 public void testComponetizedExtractorBuildExtractor_Field() {
215 assertEquals(VALUE, tryIt(Simple.class, "${strValue}", xxx -> new Simple()));
219 public void testComponetizedExtractorBuildExtractor_Map() {
220 Map<String, Object> inner = new TreeMap<>();
221 inner.put("inner1", "abc1");
222 inner.put("inner2", "abc2");
224 Map<String, Object> outer = new TreeMap<>();
225 outer.put("outer1", "def1");
226 outer.put("outer2", inner);
228 Simple obj = new Simple();
230 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${mapValue}");
231 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
232 assertEquals(null, map.extract(obj));
234 obj.mapValue = outer;
235 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${mapValue.outer2.inner2}");
236 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
237 assertEquals("abc2", map.extract(obj));
241 public void testComponetizedExtractorBuildExtractor_Unknown() {
242 assertNull(tryIt(Simple.class, "${unknown2}", xxx -> new Simple()));
246 public void testComponetizedExtractorExtract_MiddleNull() {
247 // data component is null
248 assertEquals(null, tryIt(Sub.class, "${cont.data.strValue}", xxx -> {
250 obj.cont.simpleValue = null;
256 public void testComponetizedExtractorGetMethodExtractor_VoidMethod() {
257 // tell it to use getVoidValue()
258 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${voidValue}");
259 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
261 Simple obj = new Simple();
262 assertNull(map.extract(obj));
264 assertFalse(obj.voidInvoked);
268 public void testComponetizedExtractorGetMethodExtractor() {
269 assertEquals(INT_VALUE, map.extract(new Simple()));
273 public void testComponetizedExtractorGetFieldExtractor() {
275 assertEquals(VALUE, tryIt(Simple.class, "${strValue}", xxx -> new Simple()));
279 public void testComponetizedExtractorGetMapExtractor() {
280 Map<String, Object> inner = new TreeMap<>();
281 inner.put("inner1", "abc1");
282 inner.put("inner2", "abc2");
284 Map<String, Object> outer = new TreeMap<>();
285 outer.put("outer1", "def1");
286 outer.put("outer2", inner);
288 Simple obj = new Simple();
290 obj.mapValue = outer;
291 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${mapValue.outer2.inner2}");
292 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
293 assertEquals("abc2", map.extract(obj));
297 public void testComponetizedExtractorGetMapExtractor_MapSubclass() {
298 Map<String, Object> inner = new TreeMap<>();
299 inner.put("inner1", "abc1");
300 inner.put("inner2", "abc2");
302 MapSubclass outer = new MapSubclass();
303 outer.put("outer1", "def1");
304 outer.put("outer2", inner);
306 Simple obj = new Simple();
308 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${mapValue}");
309 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
310 assertEquals(null, map.extract(obj));
312 obj.mapValue = outer;
313 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${mapValue.outer2.inner2}");
314 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
315 assertEquals("abc2", map.extract(obj));
319 * Sets a property for the given class, makes an object, and then returns
320 * the value extracted.
322 * @param clazz class whose property is to be set
323 * @param propval value to which to set the property
324 * @param makeObj function to create the object whose data is to be
326 * @return the extracted data, or {@code null} if nothing was extracted
328 private Object tryIt(Class<?> clazz, String propval, Function<Void, Object> makeObj) {
329 Properties props = new Properties();
330 props.setProperty(PROP_PREFIX + clazz.getName(), propval);
332 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
334 return map.extract(makeObj.apply(null));
338 * A Map subclass, used to verify that getMapExtractor() still handles it.
340 private static class MapSubclass extends TreeMap<String, Object> {
341 private static final long serialVersionUID = 1L;
348 private static class Simple {
351 * This will not be used because getIntValue() will override it.
353 @SuppressWarnings("unused")
354 public final int intValue = INT_VALUE2;
357 * Used to verify retrieval via a field name.
359 @SuppressWarnings("unused")
360 public final String strValue = VALUE;
363 * Used to verify retrieval within maps.
365 @SuppressWarnings("unused")
366 public Map<String, Object> mapValue = null;
369 * {@code True} if {@link #getVoidValue()} was invoked, {@code false}
372 private boolean voidInvoked = false;
375 * This function will supercede the value in the "intValue" field.
379 @SuppressWarnings("unused")
380 public Integer getIntValue() {
385 * Used to verify that void functions are not invoked.
387 @SuppressWarnings("unused")
388 public void getVoidValue() {
394 * Used to verify multi-component retrieval.
396 private static class Container {
397 public Simple simpleValue = new Simple();
399 @SuppressWarnings("unused")
400 public Simple getData() {
406 * Used to verify extraction when the property refers to an interface.
408 private static interface WithString {
410 public String getStrValue();
414 * Used to verify retrieval within a superclass.
416 private static class Super implements WithString {
418 @SuppressWarnings("unused")
419 public final int intValue = INT_VALUE;
422 public String getStrValue() {
428 * Used to verify retrieval within a subclass.
430 private static class Sub extends Super {
432 @SuppressWarnings("unused")
433 public final Simple simple = new Simple();
436 * Used to verify multi-component retrieval.
438 public final Container cont = new Container();