package net.objectlab.kit.pf.cuke; import static org.assertj.core.api.Assertions.assertThat; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import net.objectlab.kit.util.StringUtil; import org.apache.commons.lang.builder.CompareToBuilder; import org.junit.ComparisonFailure; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; import org.springframework.beans.NullValueInNestedPathException; import cucumber.api.DataTable; public class CukeUtils { public static final Map<String, Object> VALUEHOLDER = new HashMap<>(); public static <T> T copyFieldValues(final List<String> fieldsToCopy, final T source, final Class<T> typeOfT) { try { final BeanWrapper src = new BeanWrapperImpl(source); final BeanWrapper target = new BeanWrapperImpl(typeOfT.newInstance()); fieldsToCopy.forEach(t -> { try { Object propertyValue = src.getPropertyValue(t); if (propertyValue instanceof String) { propertyValue = ((String) propertyValue).trim(); } target.setPropertyValue(t, propertyValue); } catch (final NullValueInNestedPathException ignore) { } }); return (T) target.getWrappedInstance(); } catch (InstantiationException | IllegalAccessException e) { return null; } } public static <T> void compareResults(final Class<T> classType, final List<T> actual, final DataTable expected) { final List<String> fieldsToCompare = expected.topCells(); final T[] expectedEntities = convertDataTableToExpected(classType, expected, fieldsToCompare); final List<T> actualEntities = actual.stream().map(sea -> copyFieldValues(fieldsToCompare, sea, classType)).collect(Collectors.toList()); try { assertThat(actualEntities).usingElementComparator(comparator(buildExclusionFields(classType, fieldsToCompare))).containsOnly( expectedEntities); } catch (final java.lang.AssertionError e) { final String actualDataAsStr = convertToString(actual, fieldsToCompare); throw new ComparisonFailure("Table comparison for " + classType.getSimpleName() + " does not match\n", expected.toString(), actualDataAsStr); } } private static <T> String convertToString(final List<T> actualRowValues, final List<String> propertiesToCompare) { final List<List<Object>> rawRows = new ArrayList<>(); rawRows.add(propertiesToCompare.stream().collect(Collectors.toList())); for (final T actualRow : actualRowValues) { final BeanWrapper src = new BeanWrapperImpl(actualRow); rawRows.add(propertiesToCompare.stream().map(p -> { final Object propertyValue = src.getPropertyValue(p); if (propertyValue == null) { return ""; } else if (src.getPropertyTypeDescriptor(p).getObjectType().isAssignableFrom(BigDecimal.class)) { return ((BigDecimal) propertyValue).stripTrailingZeros().toPlainString(); } return propertyValue; }).collect(Collectors.toList())); } return DataTable.create(rawRows).toString(); } @SuppressWarnings("unchecked") private static <T> T[] convertDataTableToExpected(final Class<T> typeOfT, final DataTable expectedValues, final List<String> propertiesToCompare) { return (T[]) convertDataTable(expectedValues, typeOfT, propertiesToCompare).toArray(); } public static <T> List<T> convertDataTable(final DataTable table, final Class<T> typeOfT, final List<String> propertiesToCopy) { return table.asList(typeOfT).stream().map(t -> copyFields(t, typeOfT, propertiesToCopy)).collect(Collectors.toList()); } @SuppressWarnings({ "unchecked" }) public static <T> T copyFields(final T source, final Class<T> typeOfT, final List<String> propertiesToCopy) { try { final BeanWrapper src = new BeanWrapperImpl(source); final BeanWrapper target = new BeanWrapperImpl(typeOfT.newInstance()); Arrays.stream(src.getPropertyDescriptors()).forEach( property -> { final String propertyName = property.getName(); if (propertiesToCopy.contains(propertyName)) { final Object propertyValue = String.class.isAssignableFrom(property.getPropertyType()) ? StringUtil .nullIfEmpty((String) src.getPropertyValue(propertyName)) : src.getPropertyValue(propertyName); target.setPropertyValue(propertyName, propertyValue); } }); return (T) target.getWrappedInstance(); } catch (InstantiationException | IllegalAccessException e) { return null; } } public static <T> Comparator<T> comparator(final List<String> excludes) { return (o1, o2) -> CompareToBuilder.reflectionCompare(o1, o2, excludes); } public static List<String> buildExclusionFields(final Class<?> clazz, final List<String> includes) { final List<String> excludes = new ArrayList<>(); Class<?> claz = clazz; do { excludes.addAll(Arrays.stream(claz.getDeclaredFields()).map(f -> f.getName()).filter(name -> !includes.contains(name)) .collect(Collectors.toList())); claz = claz.getSuperclass(); } while (claz != null); return excludes; } }