Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.github.selcukes.collections.DataComparator Maven / Gradle / Ivy
/*
* Copyright (c) Ramesh Babu Prudhvi.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.selcukes.collections;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
import static java.util.Optional.ofNullable;
public class DataComparator {
private final BiPredicate valueComparator;
/**
* Constructs a DataComparator with the specified value comparator.
*
* @param valueComparator the value comparator to be used for comparing
* values.
*/
private DataComparator(BiPredicate valueComparator) {
this.valueComparator = valueComparator;
}
/**
* Creates a new DataComparator with the default value comparator that uses
* the {@link Objects#equals} method.
*
* @return a new DataComparator instance.
*/
public static DataComparator create() {
return new DataComparator(Objects::equals);
}
/**
* Creates a new DataComparator with the specified value comparator.
*
* @param valueComparator the new value comparator to be used for comparing
* values.
* @return a new DataComparator instance with the updated
* value comparator.
*/
public static DataComparator create(BiPredicate valueComparator) {
return new DataComparator(valueComparator);
}
/**
* Compares the data in two tables and returns a table of differences.
*
* @param expected the expected table data
* @param actual the actual table data
* @param foreignKey the foreign key to use for comparing rows
* @param ignoreColumns a list of column keys to ignore when comparing
* @param the type of the key
* @param the type of the value
* @return a table of differences between the expected and
* actual tables
*/
public DataTable diff(
final DataTable expected, final DataTable actual, final K foreignKey,
final List ignoreColumns
) {
return expected.stream()
.map(expectedMap -> ofNullable(expectedMap.get(foreignKey))
.map(foreignKeyValue -> actual
.findFirst(actualMap -> foreignKeyValue.equals(actualMap.get(foreignKey)))
.map(actualMap -> diff(expectedMap, actualMap, ignoreColumns))
.orElseGet(() -> DataTable
.of(rowStatus(foreignKey.toString(), foreignKeyValue.toString(), "", "Fail"))))
.orElseThrow(() -> new IllegalArgumentException(String.format(
"The expected table does not contain the foreign key [%s] column.", foreignKey))))
.flatMap(Collection::stream)
.collect(Collectors.toCollection(DataTable::new));
}
/**
* Compares the data in two tables using a default empty list of ignored
* columns and returns a table of differences.
*
* @param expected the expected table data
* @param actual the actual table data
* @param foreignKey the foreign key to use for comparing rows
* @param the type of the key
* @param the type of the value
* @return a table of differences between the expected and actual
* tables
*/
public DataTable diff(
DataTable expected, DataTable actual, K foreignKey
) {
return diff(expected, actual, foreignKey, Collections.emptyList());
}
/**
* Compares the data in two rows and returns a table of differences.
*
* @param expected the expected row data
* @param actual the actual row data
* @param ignoreColumns a list of column keys to ignore when comparing
* @param the type of the key
* @param the type of the value
* @return a table of differences between the expected and
* actual rows
*/
public DataTable diff(
final Map expected, final Map actual, final List ignoreColumns
) {
return expected.entrySet().stream()
.filter(entry -> !ignoreColumns.contains(entry.getKey()))
.map(entry -> {
var expectedValue = entry.getValue();
var actualValue = actual.get(entry.getKey());
String status = valueComparator.test(expectedValue, actualValue) ? "Pass" : "Fail";
return rowStatus(entry.getKey().toString(), expectedValue.toString(),
actualValue != null ? actualValue.toString() : "", status);
})
.collect(Collectors.toCollection(DataTable::new));
}
/**
* Compares the data in two rows using a default empty list of ignored
* columns and returns a table of differences.
*
* @param expected the expected row data
* @param actual the actual row data
* @param the type of the key
* @param the type of the value
* @return a table of differences between the expected and actual
* rows
*/
public DataTable diff(Map expected, Map actual) {
return diff(expected, actual, Collections.emptyList());
}
/**
* Compares two lists of column data in a DataTable and returns a DataTable
* containing the differences.
*
* @param expected a List of expected values
* @param actual a List of actual values
* @param the value type of the DataTable
* @return a DataTable containing the differences between the two
* input lists
*/
public DataTable diff(
final List expected, final List actual
) {
List sortedExpected = Lists.sortWithNulls(expected);
List sortedActual = Lists.sortWithNulls(actual);
return Streams.of(0, Math.max(sortedExpected.size(), sortedActual.size()))
.mapToObj(i -> {
var expectedValue = i < sortedExpected.size() ? sortedExpected.get(i) : null;
var actualValue = i < sortedActual.size() ? sortedActual.get(i) : null;
String status = valueComparator.test(expectedValue, actualValue) ? "Pass" : "Fail";
return rowStatus("Row " + i, expectedValue != null ? expectedValue.toString() : "",
actualValue != null ? actualValue.toString() : "", status);
})
.collect(Collectors.toCollection(DataTable::new));
}
private Map rowStatus(String fieldName, String expected, String actual, String status) {
var row = new LinkedHashMap();
row.put("Field", fieldName);
row.put("Expected", expected);
row.put("Actual", actual);
row.put("Status", status);
return row;
}
}