package org.keycloak.client.registration.cli.util;
import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import org.keycloak.client.registration.cli.common.AttributeKey;
import org.keycloak.client.registration.cli.common.AttributeKey.Component;
import org.keycloak.client.registration.cli.common.AttributeOperation;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static org.keycloak.client.registration.cli.common.AttributeOperation.Type.DELETE;
import static org.keycloak.client.registration.cli.common.AttributeOperation.Type.SET;
/**
* @author <a href="mailto:mstrukel@redhat.com">Marko Strukelj</a>
*/
public class ReflectionUtilTest {
@Ignore
@Test
public void testListAttributes() {
LinkedHashMap<String, String> items = null;
/*
items = getAttributeListWithJSonTypes(Data.class, new AttributeKey(""));
for (Map.Entry<String, String> item: items.entrySet()) {
System.out.printf("%-40s %s\n", item.getKey(), item.getValue());
}
*/
/*
System.out.println("\n-- nested ------------------------\n");
items = getAttributeListWithJSonTypes(Data.class, new AttributeKey("nested"));
for (Map.Entry<String, String> item: items.entrySet()) {
System.out.printf("%-40s %s\n", item.getKey(), item.getValue());
}
*/
System.out.println("\n-- dataList ----------------------\n");
items = ReflectionUtil.getAttributeListWithJSonTypes(Data.class, new AttributeKey("dataList"));
for (Map.Entry<String, String> item: items.entrySet()) {
System.out.printf("%-40s %s\n", item.getKey(), item.getValue());
}
if (items.size() == 0) {
Field f = ReflectionUtil.resolveField(Data.class, new AttributeKey("dataList"));
String ts = ReflectionUtil.getTypeString(null, f);
Type t = f.getGenericType();
if ((List.class.isAssignableFrom(f.getType()) || f.getType().isArray()) && t instanceof ParameterizedType) {
System.out.printf("%s, where object is:\n", ts);
}
t = ((ParameterizedType) t).getActualTypeArguments()[0];
if (t instanceof Class) {
items = ReflectionUtil.getAttributeListWithJSonTypes((Class) t, null);
for (Map.Entry<String, String> item: items.entrySet()) {
System.out.printf(" %-37s %s\n", item.getKey(), item.getValue());
}
}
}
}
@Test
public void testSettingAttibutes() {
Data data = new Data();
LinkedList<AttributeOperation> attrs = new LinkedList<>();
attrs.add(new AttributeOperation(SET, "longAttr", "42"));
attrs.add(new AttributeOperation(SET, "strAttr", "not null"));
attrs.add(new AttributeOperation(SET, "strList+", "two"));
attrs.add(new AttributeOperation(SET, "strList+", "three"));
attrs.add(new AttributeOperation(SET, "strList[0]+", "one"));
attrs.add(new AttributeOperation(SET, "config", "{\"key1\": \"value1\"}"));
attrs.add(new AttributeOperation(SET, "config.key2", "value2"));
attrs.add(new AttributeOperation(SET, "nestedConfig", "{\"key1\": {\"sub key1\": \"sub value1\"}}"));
attrs.add(new AttributeOperation(SET, "nestedConfig.key1.\"sub key2\"", "sub value2"));
attrs.add(new AttributeOperation(SET, "nested.strList", "[1,2,3,4]"));
attrs.add(new AttributeOperation(SET, "nested.dataList+", "{\"baseAttr\": \"item1\", \"strList\": [\"confidential\", \"public\"]}"));
attrs.add(new AttributeOperation(SET, "nested.dataList+", "{\"baseAttr\": \"item2\", \"strList\": [\"external\"]}"));
attrs.add(new AttributeOperation(SET, "nested.dataList[1].baseAttr", "changed item2"));
attrs.add(new AttributeOperation(SET, "nested.nested.strList", "[\"first\",\"second\"]"));
attrs.add(new AttributeOperation(DELETE, "nested.strList[1]"));
attrs.add(new AttributeOperation(SET, "nested.nested.nested", "{\"baseAttr\": \"NEW VALUE\", \"strList\": [true, false]}"));
attrs.add(new AttributeOperation(SET, "nested.strAttr", "NOT NULL"));
attrs.add(new AttributeOperation(DELETE, "nested.strAttr"));
ReflectionUtil.setAttributes(data, attrs);
Assert.assertEquals("longAttr", Long.valueOf(42), data.getLongAttr());
Assert.assertEquals("strAttr", "not null", data.getStrAttr());
Assert.assertEquals("strList", Arrays.asList("one", "two", "three"), data.getStrList());
Map<String, String> expectedMap = new HashMap<>();
expectedMap.put("key1", "value1");
expectedMap.put("key2", "value2");
Assert.assertEquals("config", expectedMap, data.getConfig());
expectedMap = new HashMap<>();
expectedMap.put("sub key1", "sub value1");
expectedMap.put("sub key2", "sub value2");
Assert.assertNotNull("nestedConfig", data.getNestedConfig());
Assert.assertEquals("nestedConfig has one element", 1, data.getNestedConfig().size());
Assert.assertEquals("nestedConfig.key1", expectedMap, data.getNestedConfig().get("key1"));
Data nested = data.getNested();
Assert.assertEquals("nested.strAttr", null, nested.getStrAttr());
Assert.assertEquals("nested.strList", Arrays.asList("1", "3", "4"), nested.getStrList());
Assert.assertEquals("nested.dataList[0].baseAttr", "item1", nested.getDataList().get(0).getBaseAttr());
Assert.assertEquals("nested.dataList[0].strList", Arrays.asList("confidential", "public"), nested.getDataList().get(0).getStrList());
Assert.assertEquals("nested.dataList[1].baseAttr", "changed item2", nested.getDataList().get(1).getBaseAttr());
Assert.assertEquals("nested.dataList[1].strList", Arrays.asList("external"), nested.getDataList().get(1).getStrList());
nested = nested.getNested();
Assert.assertEquals("nested.nested.strList", Arrays.asList("first", "second"), nested.getStrList());
nested = nested.getNested();
Assert.assertEquals("nested.nested.nested.baseAttr", "NEW VALUE", nested.getBaseAttr());
Assert.assertEquals("nested.nested.nested.strList", Arrays.asList("true", "false"), nested.getStrList());
}
@Test
public void testKeyParsing() {
assertAttributeKey(new AttributeKey("am.bam.pet"), "am", -1, "bam", -1, "pet", -1);
assertAttributeKey(new AttributeKey("a"), "a", -1);
assertAttributeKey(new AttributeKey("a.b"), "a", -1, "b", -1);
assertAttributeKey(new AttributeKey("a.b[1]"), "a", -1, "b", 1);
assertAttributeKey(new AttributeKey("a[12].b"), "a", 12, "b", -1);
assertAttributeKey(new AttributeKey("a[10].b[20]"), "a", 10, "b", 20);
assertAttributeKey(new AttributeKey("\"am\".\"bam\".\"pet\""), "am", -1, "bam", -1, "pet", -1);
assertAttributeKey(new AttributeKey("\"am\".bam.\"pet\""), "am", -1, "bam", -1, "pet", -1);
assertAttributeKey(new AttributeKey("\"am.bam\".\"pet\""), "am.bam", -1, "pet", -1);
assertAttributeKey(new AttributeKey("\"am.bam[2]\".\"pet[6]\""), "am.bam", 2, "pet", 6);
try {
new AttributeKey("a.");
Assert.fail("Should have failed");
} catch (RuntimeException expected) {
}
try {
new AttributeKey("a[]");
Assert.fail("Should have failed");
} catch (RuntimeException expected) {
}
try {
new AttributeKey("a[lala]");
Assert.fail("Should have failed");
} catch (RuntimeException expected) {
}
try {
new AttributeKey("a[\"lala\"]");
Assert.fail("Should have failed");
} catch (RuntimeException expected) {
}
try {
new AttributeKey(".a");
Assert.fail("Should have failed");
} catch (RuntimeException expected) {
}
try {
new AttributeKey("\"am\"..\"bam\".\"pet\"");
Assert.fail("Should have failed");
} catch (RuntimeException expected) {
}
try {
new AttributeKey("\"am\"ups.\"bam\".\"pet\"");
Assert.fail("Should have failed");
} catch (RuntimeException expected) {
}
try {
new AttributeKey("ups\"am\"ups.\"bam\".\"pet\"");
Assert.fail("Should have failed");
} catch (RuntimeException expected) {
}
}
private void assertAttributeKey(AttributeKey key, Object ... args) {
Iterator<Component> it = key.getComponents().iterator();
for (int i = 0; i < args.length; i++) {
String name = String.valueOf(args[i++]);
int idx = Integer.valueOf(String.valueOf(args[i]));
Component component = it.next();
Assert.assertEquals(name, component.getName());
Assert.assertEquals(idx, component.getIndex());
}
}
public static class BaseData {
String baseAttr;
public String getBaseAttr() {
return baseAttr;
}
public void setBaseAttr(String baseAttr) {
this.baseAttr = baseAttr;
}
}
public static class Data extends BaseData {
String strAttr;
Integer intAttr;
Long longAttr;
Boolean boolAttr;
List<String> strList;
List<Integer> intList;
List<Data> dataList;
List<List<String>> deepList;
Data nested;
Map<String, String> config;
Map<String, Map<String, Data>> nestedConfig;
public String getStrAttr() {
return strAttr;
}
public void setStrAttr(String strAttr) {
this.strAttr = strAttr;
}
public Integer getIntAttr() {
return intAttr;
}
public void setIntAttr(Integer intAttr) {
this.intAttr = intAttr;
}
public Long getLongAttr() {
return longAttr;
}
public void setLongAttr(Long longAttr) {
this.longAttr = longAttr;
}
public Boolean getBoolAttr() {
return boolAttr;
}
public void setBoolAttr(Boolean boolAttr) {
this.boolAttr = boolAttr;
}
public List<String> getStrList() {
return strList;
}
public void setStrList(List<String> strList) {
this.strList = strList;
}
public List<Integer> getIntList() {
return intList;
}
public void setIntList(List<Integer> intList) {
this.intList = intList;
}
public List<Data> getDataList() {
return dataList;
}
public void setDataList(List<Data> dataList) {
this.dataList = dataList;
}
public Data getNested() {
return nested;
}
public void setNested(Data nested) {
this.nested = nested;
}
public List<List<String>> getDeepList() {
return deepList;
}
public void setDeepList(List<List<String>> deepList) {
this.deepList = deepList;
}
public void setConfig(Map<String, String> config) {
this.config = config;
}
public Map<String, String> getConfig() {
return config;
}
public void setNestedConfig(Map<String, Map<String, Data>> nestedConfig) {
this.nestedConfig = nestedConfig;
}
public Map<String, Map<String, Data>> getNestedConfig() {
return nestedConfig;
}
}
}