package fitnesse.slim.converters; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import fitnesse.html.HtmlTag; import fitnesse.slim.Converter; import org.apache.commons.lang.StringUtils; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; public class MapConverterTest { private MapConverter converter; private Map<String, String> result; @Before public void setup() { converter = new MapConverter(); } @Test public void fromNull_shouldCreateNullString() { assertEquals(Converter.NULL_VALUE, converter.toString(null)); } @Test public void fromNestedMap_shouldCreateString() { Map nestedMap = new LinkedHashMap(); nestedMap.put("a", null); nestedMap.put(Arrays.asList("b", "c", "d"), "listValue"); nestedMap.put("listKey", Arrays.asList("e", "f")); nestedMap.put(null, true); String actual = converter.toString(nestedMap); // check without considering whitespace assertEquals("<table class=\"hash_table\"> <tr class=\"hash_row\"> <td class=\"hash_key\">a</td> <td class=\"hash_value\">null</td> </tr> <tr class=\"hash_row\"> <td class=\"hash_key\">[b, c, d]</td> <td class=\"hash_value\">listValue</td> </tr> <tr class=\"hash_row\"> <td class=\"hash_key\">listKey</td> <td class=\"hash_value\">[e, f]</td> </tr> <tr class=\"hash_row\"> <td class=\"hash_key\">null</td> <td class=\"hash_value\">true</td> </tr> </table>", actual.replaceAll("\\s+", " ")); } @Test public void fromNestedMap_shouldCreateStringWithCustomElementConvertor() throws NoSuchMethodException { try { // use custom convertor for Lists, to output HTML ordered lists Class<? extends List<Object>> listObjectClass; listObjectClass = (Class<List<Object>>) NumberedListConverter.class .getMethod("toString", List.class).getParameterTypes()[0]; NumberedListConverter listConverter = new NumberedListConverter(); ConverterRegistry.addConverter(listObjectClass, listConverter); Map nestedMap = new LinkedHashMap(); nestedMap.put("a", null); nestedMap.put(Arrays.asList("b", "c", "d"), "listValue"); nestedMap.put("listKey", Arrays.asList("e", "f")); nestedMap.put(null, true); String actual = converter.toString(nestedMap); // check without considering whitespace assertEquals("<table class=\"hash_table\"> <tr class=\"hash_row\"> <td class=\"hash_key\">a</td> <td class=\"hash_value\">null</td> </tr> <tr class=\"hash_row\"> <td class=\"hash_key\"><ol start=\"0\"><li>b</li><li>c</li><li>d</li></ol></td> <td class=\"hash_value\">listValue</td> </tr> <tr class=\"hash_row\"> <td class=\"hash_key\">listKey</td> <td class=\"hash_value\"><ol start=\"0\"><li>e</li><li>f</li></ol></td> </tr> <tr class=\"hash_row\"> <td class=\"hash_key\">null</td> <td class=\"hash_value\">true</td> </tr> </table>", actual.replaceAll("\\s+", " ")); } finally { ConverterRegistry.resetToStandardConverters(); } } @Test public void fromEmptyString_shouldCreateEmptyMap() throws Exception { makeMap(""); assertEquals(0, result.size()); } @SuppressWarnings("unchecked") private void makeMap(String inputString) { result = converter.fromString(inputString); } @Test public void fromGarbageString_shouldCreateEmptyMap() throws Exception { makeMap("sdfwewdfsdfwefsdfsdfswe"); assertEquals(0, result.size()); } @Test public void fromEmptyTable_shouldCreateEmptyMap() throws Exception { makeMap("<table></table>"); assertEquals(0, result.size()); } @Test public void fromTableWithNoColumns_shouldCreateEmptyMap() throws Exception { makeMap("<table><tr></tr><tr></tr></table>"); assertEquals(0, result.size()); } @Test public void fromTableWithOneColumn_shouldCreateEmptyMap() throws Exception { makeMap("<table><tr><td>0</td></tr></table>"); assertEquals(0, result.size()); } @Test public void fromTableWithMoreThanTwoColumns_shouldCreateEmptyMap() throws Exception { makeMap("<table>" + "<tr>" + " <td>0</td>" + " <td>0</td>" + " <td>0</td>" + "</tr>" + "</table>"); assertEquals(0, result.size()); } @Test public void fromTableWithTwoColumnsAndOneRow_shouldCreateMapWithOneEntry() throws Exception { makeMap("<table>" + "<tr>" + " <td>name</td>" + " <td>Bob</td>" + "</tr>" + "</table>"); assertEquals(1, result.size()); assertEquals("Bob", result.get("name")); } @Test public void fromTableWithTwoColumnsAndTwoRows_shouldCreateMapWithTwoEntries() throws Exception { makeMap("<table>" + "<tr>" + " <td>name</td>" + " <td>Bob</td>" + "</tr>" + "<tr>" + " <td>address</td>" + " <td>here</td>" + "</tr>" + "</table>"); assertEquals(2, result.size()); assertEquals("Bob", result.get("name")); assertEquals("here", result.get("address")); } @Test public void fromTwoValidTables_shouldCreateEmptyMap() throws Exception { makeMap("<table>" + "<tr>" + " <td>name</td>" + " <td>Bob</td>" + "</tr>" + "</table>" + "<table>" + "<tr>" + " <td>name</td>" + " <td>Bob</td>" + "</tr>" + "</table>"); assertEquals(0, result.size()); } @Test public void shouldRenderTableAsHtml() { MapConverter editor = new MapConverter(); assertEquals(StringUtils.join(Arrays.asList("<table class=\"hash_table\">", "\t<tr class=\"hash_row\">", "\t\t<td class=\"hash_key\">a</td>", "\t\t<td class=\"hash_value\">b</td>", "\t</tr>", "\t<tr class=\"hash_row\">", "\t\t<td class=\"hash_key\">c</td>", "\t\t<td class=\"hash_value\">d</td>", "\t</tr>", "</table>"), HtmlTag.endl), editor.toString(aMap())); } private Map<Object, Object> aMap() { Map<Object, Object> map = new TreeMap<>(); map.put("a", "b"); map.put("c", "d"); return map; } private static class NumberedListConverter extends fitnesse.slim.converters.GenericCollectionConverter<Object, List<Object>> { private static final Pattern LIST_PATTERN = Pattern.compile( "<ol( start=\"\\d+\")?\\s*>\\s*((<li>\\s*.*?\\s*</li>\\s*)*)</ol>", Pattern.DOTALL); private static final Converter<Object> OBJ_CONVERTER = new ObjectConverter(); public NumberedListConverter() { super(ArrayList.class, OBJ_CONVERTER); } @Override public String toString(List<Object> list) { if (list == null) { return super.toString(list); } StringBuilder messageList = new StringBuilder("<ol start=\"0\">"); for (Object element : list) { messageList.append("<li>"); String formattedElement = ElementConverterHelper.elementToString(element); messageList.append(formattedElement); messageList.append("</li>"); } messageList.append("</ol>"); return messageList.toString(); } @Override public ArrayList<Object> fromString(String arg) { ArrayList<Object> result; Matcher matcher = LIST_PATTERN.matcher(arg); if (matcher.matches()) { result = new ArrayList<>(); String items = matcher.group(2); if (!"".equals(items)) { items = items.replaceFirst("^\\s*<li>\\s*", ""); items = items.replaceFirst("\\s*</li>\\s*$", ""); String[] elements = items.split("\\s*</li>\\s*<li>\\s*"); result.addAll(Arrays.asList(elements)); } } else { result = new ArrayList<>(super.fromString(arg)); } return result; } } private static class ObjectConverter extends DefaultConverter { @Override public String toString(Object o) { return o == null ? super.toString(o) : ElementConverterHelper.elementToString(o); } } }