import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
public class MergerTest {
private static final int MIN = 1;
private static final int MAX = 10000;
@DataProvider(parallel = true)
public Object[][] data() {
int[] one = new int[]{1, 2, 3, 4, 10, 20, 30};
int[] two = new int[]{20, 30, 1, 2, 1, 3, 4, 4, 5};
int[] dynamicOne = ThreadLocalRandom
.current().ints(MIN, MAX + 1).limit(MAX).toArray();
int[] dynamicTwo = ThreadLocalRandom
.current().ints(MIN, MAX + 1).limit(MAX).toArray();
int[] sameOne = new int[]{7, 7, 7, 7, 7, 7, 7};
int[] diffOne = new int[]{1, 2, 3, 4, 5, 6, 7};
int[] minOne = new int[]{MIN, MIN, MIN, MIN, MIN};
int[] maxOne = new int[]{MAX, MAX, MAX, MAX, MAX, MAX, MAX};
int[] minMax = ThreadLocalRandom
.current().ints(MIN, MIN + 1).limit(MAX).toArray();
int[] maxMax = ThreadLocalRandom
.current().ints(MAX, MAX + 1).limit(MAX).toArray();
return new Object[][]{
{one, two},
{dynamicOne, dynamicTwo},
{dynamicOne, dynamicOne},
{sameOne, sameOne},
{diffOne, diffOne},
{minOne, minOne},
{maxOne, maxOne},
{minMax, minMax},
{maxMax, maxMax},
{minMax, maxMax}
};
}
@Test(invocationCount = 100, dataProvider = "data")
public void testMergeCounter(int[] one, int[] two) {
Map<Integer, Long> actualMap = new Merger().mergeCounter(one, two);
printMap("Actual Map", actualMap);
List<Integer> oneList = convertToList(one);
List<Integer> twoList = convertToList(two);
Collections.sort(oneList);
Collections.sort(twoList);
Map<Integer, Long> expectedMap = computeExpectedMap(oneList, twoList);
printMap("Expected Map", expectedMap);
assertEquals(expectedMap.size(), actualMap.size());
assertEquals(expectedMap, actualMap);
assertTrue(expectedMap.equals(actualMap));
}
@DataProvider(parallel = true)
public Object[][] outOfRangeGreater() {
int[] negDynamicOne = ThreadLocalRandom
.current().ints(MIN - MAX, 0).limit(MAX + 1).toArray();
int[] negDynamicTwo = ThreadLocalRandom
.current().ints(MIN - MAX, 0).limit(MAX + MAX).toArray();
return new Object[][]{
{negDynamicOne, negDynamicTwo}
};
}
@Test(invocationCount = 100, dataProvider = "outOfRangeGreater", expectedExceptions = {RuntimeException.class},
expectedExceptionsMessageRegExp = "Array length should not be greater than : " + MAX)
public void testMergeCounterOutOfRangeGreater(int[] one, int[] two) {
testMergeCounter(one, two);
}
@DataProvider
public Object[][] outOfRangeLesser() {
int[] negDynamicOne = {};
int[] negDynamicTwo = {};
return new Object[][]{
{negDynamicOne, negDynamicTwo}
};
}
@Test(invocationCount = 100, dataProvider = "outOfRangeLesser", expectedExceptions = {RuntimeException.class},
expectedExceptionsMessageRegExp = "Array length should not be lesser than : " + MIN)
public void testMergeCounterOutOfRangeLesser(int[] one, int[] two) {
testMergeCounter(one, two);
}
@DataProvider
public Object[][] nullSize() {
return new Object[][]{
{null, null}
};
}
@Test(invocationCount = 100, dataProvider = "nullSize", expectedExceptions = {NullPointerException.class})
public void testMergeCounterNullSize(int[] one, int[] two) {
testMergeCounter(one, two);
}
private List<Integer> convertToList(int[] data) {
Objects.requireNonNull(data);
List<Integer> listData = Arrays.stream(data).boxed().collect(Collectors.toList());
if (listData.size() != data.length) {
throw new RuntimeException("Issue in converting array to list, size is different!");
}
return listData;
}
private Map<Integer, Long> computeExpectedMap(List<Integer> one, List<Integer> two) {
List<Integer> combinedList = Stream.concat(one.stream(), two.stream())
.parallel().sorted().collect(Collectors.toList());
if (combinedList.size() != (one.size() + two.size())) {
throw new RuntimeException("combined list size is wrong!");
}
return incrementCount(combinedList);
}
private void printMap(String name, Map<Integer, Long> map) {
System.out.println("\n" + name);
System.out.println("Number : Count\n===============");
System.out.print("{");
map.forEach((k, v) -> System.out.print(k + " : " + v + ", "));
System.out.println("}");
}
private Map<Integer, Long> incrementCount(List<Integer> data) {
Map<Integer, Long> counterMap = new ConcurrentHashMap<>();
for (int item : data) {
counterMap.computeIfPresent(item, (key, value) -> value + 1);
counterMap.putIfAbsent(item, 1L);
}
return counterMap;
}
}
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Merger {
private static final int MIN = 1;
private static final int MAX = 10000;
public Map<Integer, Long> mergeCounter(int[] one, int[] two) {
List<Integer> oneList = convertToList(one);
List<Integer> twoList = convertToList(two);
checkLength(oneList);
checkLength(twoList);
checkRange(oneList);
checkRange(twoList);
Map<Integer, Long> counterMap = oneList.parallelStream().sorted().collect(
Collectors.groupingBy(
Function.identity(), ConcurrentHashMap::new, Collectors.counting()
)
);
twoList.parallelStream().sorted().forEach(item -> {
counterMap.computeIfPresent(item, (key, value) -> value + 1);
counterMap.putIfAbsent(item, 1L);
});
return counterMap;
}
private List<Integer> convertToList(int[] data) {
Objects.requireNonNull(data);
return Arrays.stream(data).boxed().collect(Collectors.toList());
}
private void checkRange(List<Integer> data) {
if (!data.stream().allMatch(i -> i >= MIN && i <= MAX)) {
throw new RuntimeException("Array content should be in range of : " + MIN + " and : " + MAX);
}
}
private void checkLength(List<Integer> data) {
if (data.size() != Math.min(data.size(), MAX)) {
throw new RuntimeException("Array length should not be greater than : " + MAX);
}
if (data.size() != Math.max(data.size(), MIN)) {
throw new RuntimeException("Array length should not be lesser than : " + MIN);
}
}
}
Comments
Post a Comment