2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2018-2019 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;
28 import java.util.Properties;
29 import java.util.TreeMap;
30 import java.util.function.Function;
31 import org.junit.Before;
32 import org.junit.Test;
34 public class ClassExtractorsTest {
36 private static final int NTIMES = 5;
38 private static final String MY_TYPE = "theType";
39 private static final String PROP_PREFIX = "extractor." + MY_TYPE + ".";
41 private static final String VALUE = "a value";
42 private static final Integer INT_VALUE = 10;
43 private static final Integer INT_VALUE2 = 20;
45 private Properties props;
46 private ClassExtractors map;
54 props = new Properties();
56 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${intValue}");
57 props.setProperty(PROP_PREFIX + WithString.class.getName(), "${strValue}");
59 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
63 public void testExtract() {
64 Simple obj = new Simple();
65 assertEquals(INT_VALUE, map.extract(obj));
68 assertEquals(VALUE, tryIt(Simple.class, "${strValue}", xxx -> new Simple()));
71 assertNull(map.extract(null));
73 // values from two different kinds of objects
74 props = new Properties();
75 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${intValue}");
76 props.setProperty(PROP_PREFIX + WithString.class.getName(), "${strValue}");
77 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
79 assertEquals(INT_VALUE, map.extract(new Simple()));
80 assertEquals(VALUE, map.extract(new Sub()));
82 // values from a superclass method, but property defined for subclass
83 props = new Properties();
84 props.setProperty(PROP_PREFIX + Sub.class.getName(), "${strValue}");
85 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
87 assertEquals(VALUE, map.extract(new Sub()));
89 // values from a superclass field, but property defined for subclass
90 props = new Properties();
91 props.setProperty(PROP_PREFIX + Sub.class.getName(), "${intValue}");
92 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
94 assertEquals(INT_VALUE, map.extract(new Sub()));
97 // prefix includes trailing "."
98 props = new Properties();
99 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${intValue}");
100 map = new ClassExtractors(props, PROP_PREFIX.substring(0, PROP_PREFIX.length() - 1), MY_TYPE);
101 assertEquals(INT_VALUE, map.extract(new Simple()));
104 // values from an class in a different file
105 props = new Properties();
106 props.setProperty(PROP_PREFIX + ClassExtractorsTestSupport.class.getName(), "${nested.theValue}");
107 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
109 assertEquals(ClassExtractorsTestSupport2.NESTED_VALUE, map.extract(new ClassExtractorsTestSupport()));
113 public void testGetExtractor() {
114 Simple obj = new Simple();
116 // repeat - shouldn't re-create the extractor
117 for (int x = 0; x < NTIMES; ++x) {
118 assertEquals("x=" + x, INT_VALUE, map.extract(obj));
119 assertEquals("x=" + x, 1, map.size());
124 public void testBuildExtractorClass_TopLevel() {
125 // extractor defined for top-level class
126 props = new Properties();
127 props.setProperty(PROP_PREFIX + Sub.class.getName(), "${strValue}");
129 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
130 assertEquals(VALUE, map.extract(new Sub()));
132 // one extractor for top-level class
133 assertEquals(1, map.size());
137 public void testBuildExtractorClass_SuperClass() {
138 // extractor defined for superclass (interface)
139 assertEquals(VALUE, map.extract(new Sub()));
141 // one extractor for top-level class and one for interface
142 assertEquals(2, map.size());
146 public void testBuildExtractorClass_NotDefined() {
147 // no extractor defined for "this" class
148 assertNull(map.extract(this));
150 // one NULL extractor for top-level class
151 assertEquals(1, map.size());
155 public void testBuildExtractorClassString() {
157 assertNull(tryIt(Simple.class, "intValue}", xxx -> new Simple()));
160 assertNull(tryIt(Simple.class, "${intValue", xxx -> new Simple()));
163 assertNull(tryIt(Sub.class, "${.simple.strValue}", xxx -> new Sub()));
166 assertNull(tryIt(Sub.class, "${simple.strValue.}", xxx -> new Sub()));
169 assertEquals(VALUE, tryIt(Sub.class, "${strValue}", xxx -> new Sub()));
172 assertEquals(VALUE, tryIt(Sub.class, "${simple.strValue}", xxx -> new Sub()));
175 assertNull(tryIt(Sub.class, "${unknown}", xxx -> new Sub()));
179 public void testGetClassExtractor_InSuper() {
180 // field in the superclass
181 assertEquals(INT_VALUE, tryIt(Super.class, "${intValue}", xxx -> new Sub()));
185 public void testGetClassExtractor_InInterface() {
186 // defined in the interface
187 assertEquals(VALUE, map.extract(new Sub()));
191 public void testNullExtractorExtract() {
192 // empty properties - should only create NullExtractor
193 map = new ClassExtractors(new Properties(), PROP_PREFIX, MY_TYPE);
195 Simple obj = new Simple();
197 // repeat - shouldn't re-create the extractor
198 for (int x = 0; x < NTIMES; ++x) {
199 assertNull("x=" + x, map.extract(obj));
200 assertEquals("x=" + x, 1, map.size());
205 public void testComponetizedExtractor() {
207 assertEquals(VALUE, tryIt(Sub.class, "${strValue}", xxx -> new Sub()));
210 assertEquals(VALUE, tryIt(Sub.class, "${cont.data.strValue}", xxx -> new Sub()));
214 public void testComponetizedExtractorBuildExtractor_Method() {
215 assertEquals(INT_VALUE, tryIt(Simple.class, "${intValue}", xxx -> new Simple()));
219 public void testComponetizedExtractorBuildExtractor_Field() {
220 assertEquals(VALUE, tryIt(Simple.class, "${strValue}", xxx -> new Simple()));
224 public void testComponetizedExtractorBuildExtractor_Map() {
225 Map<String, Object> inner = new TreeMap<>();
226 inner.put("inner1", "abc1");
227 inner.put("inner2", "abc2");
229 Map<String, Object> outer = new TreeMap<>();
230 outer.put("outer1", "def1");
231 outer.put("outer2", inner);
233 Simple obj = new Simple();
235 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${mapValue}");
236 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
237 assertEquals(null, map.extract(obj));
239 obj.mapValue = outer;
240 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${mapValue.outer2.inner2}");
241 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
242 assertEquals("abc2", map.extract(obj));
246 public void testComponetizedExtractorBuildExtractor_Unknown() {
247 assertNull(tryIt(Simple.class, "${unknown2}", xxx -> new Simple()));
251 public void testComponetizedExtractorExtract_MiddleNull() {
252 // data component is null
253 assertEquals(null, tryIt(Sub.class, "${cont.data.strValue}", xxx -> {
255 obj.cont.simpleValue = null;
261 public void testComponetizedExtractorGetMethodExtractor_VoidMethod() {
262 // tell it to use getVoidValue()
263 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${voidValue}");
264 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
266 Simple obj = new Simple();
267 assertNull(map.extract(obj));
269 assertFalse(obj.voidInvoked);
273 public void testComponetizedExtractorGetMethodExtractor() {
274 assertEquals(INT_VALUE, map.extract(new Simple()));
278 public void testComponetizedExtractorGetFieldExtractor() {
280 assertEquals(VALUE, tryIt(Simple.class, "${strValue}", xxx -> new Simple()));
284 public void testComponetizedExtractorGetMapExtractor() {
285 Map<String, Object> inner = new TreeMap<>();
286 inner.put("inner1", "abc1");
287 inner.put("inner2", "abc2");
289 Map<String, Object> outer = new TreeMap<>();
290 outer.put("outer1", "def1");
291 outer.put("outer2", inner);
293 Simple obj = new Simple();
295 obj.mapValue = outer;
296 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${mapValue.outer2.inner2}");
297 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
298 assertEquals("abc2", map.extract(obj));
302 public void testComponetizedExtractorGetMapExtractor_MapSubclass() {
303 Map<String, Object> inner = new TreeMap<>();
304 inner.put("inner1", "abc1");
305 inner.put("inner2", "abc2");
307 MapSubclass outer = new MapSubclass();
308 outer.put("outer1", "def1");
309 outer.put("outer2", inner);
311 Simple obj = new Simple();
313 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${mapValue}");
314 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
315 assertEquals(null, map.extract(obj));
317 obj.mapValue = outer;
318 props.setProperty(PROP_PREFIX + Simple.class.getName(), "${mapValue.outer2.inner2}");
319 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
320 assertEquals("abc2", map.extract(obj));
324 * Sets a property for the given class, makes an object, and then returns
325 * the value extracted.
327 * @param clazz class whose property is to be set
328 * @param propval value to which to set the property
329 * @param makeObj function to create the object whose data is to be
331 * @return the extracted data, or {@code null} if nothing was extracted
333 private Object tryIt(Class<?> clazz, String propval, Function<Void, Object> makeObj) {
334 Properties props = new Properties();
335 props.setProperty(PROP_PREFIX + clazz.getName(), propval);
337 map = new ClassExtractors(props, PROP_PREFIX, MY_TYPE);
339 return map.extract(makeObj.apply(null));
343 * A Map subclass, used to verify that getMapExtractor() still handles it.
345 private static class MapSubclass extends TreeMap<String, Object> {
346 private static final long serialVersionUID = 1L;
353 private static class Simple {
356 * This will not be used because getIntValue() will override it.
358 @SuppressWarnings("unused")
359 public final int intValue = INT_VALUE2;
362 * Used to verify retrieval via a field name.
364 @SuppressWarnings("unused")
365 public final String strValue = VALUE;
368 * Used to verify retrieval within maps.
370 @SuppressWarnings("unused")
371 public Map<String, Object> mapValue = null;
374 * {@code True} if {@link #getVoidValue()} was invoked, {@code false}
377 private boolean voidInvoked = false;
380 * This function will supercede the value in the "intValue" field.
384 @SuppressWarnings("unused")
385 public Integer getIntValue() {
390 * Used to verify that void functions are not invoked.
392 @SuppressWarnings("unused")
393 public void getVoidValue() {
399 * Used to verify multi-component retrieval.
401 private static class Container {
402 public Simple simpleValue = new Simple();
404 @SuppressWarnings("unused")
405 public Simple getData() {
411 * Used to verify extraction when the property refers to an interface.
413 private static interface WithString {
415 String getStrValue();
419 * Used to verify retrieval within a superclass.
421 private static class Super implements WithString {
423 @SuppressWarnings("unused")
424 public final int intValue = INT_VALUE;
427 public String getStrValue() {
433 * Used to verify retrieval within a subclass.
435 private static class Sub extends Super {
437 @SuppressWarnings("unused")
438 public final Simple simple = new Simple();
441 * Used to verify multi-component retrieval.
443 public final Container cont = new Container();