From 0f12449954723de5e3168eddec9037be14d56c9e Mon Sep 17 00:00:00 2001 From: Oshgnacknak Date: Sun, 29 Aug 2021 19:02:44 +0200 Subject: [PATCH] Introduce SequenceProcessor as a way to work with anything sequence related --- src/aud/exam/prep/Pair.java | 6 + src/aud/exam/prep/SequenceProcessor.java | 68 +++ test/aud/exam/prep/DoubleLatinProvider.java | 28 ++ test/aud/exam/prep/DuplicateListProvider.java | 35 ++ test/aud/exam/prep/ListProvider.java | 28 ++ test/aud/exam/prep/SequenceProcessorTest.java | 419 ++++++++++++++++++ test/aud/exam/prep/Tests.java | 10 + 7 files changed, 594 insertions(+) create mode 100644 src/aud/exam/prep/Pair.java create mode 100644 src/aud/exam/prep/SequenceProcessor.java create mode 100644 test/aud/exam/prep/DoubleLatinProvider.java create mode 100644 test/aud/exam/prep/DuplicateListProvider.java create mode 100644 test/aud/exam/prep/ListProvider.java create mode 100644 test/aud/exam/prep/SequenceProcessorTest.java create mode 100644 test/aud/exam/prep/Tests.java diff --git a/src/aud/exam/prep/Pair.java b/src/aud/exam/prep/Pair.java new file mode 100644 index 0000000..842eeb9 --- /dev/null +++ b/src/aud/exam/prep/Pair.java @@ -0,0 +1,6 @@ +package aud.exam.prep; + +public class Pair { + public T fst; + public S snd; +} diff --git a/src/aud/exam/prep/SequenceProcessor.java b/src/aud/exam/prep/SequenceProcessor.java new file mode 100644 index 0000000..f73372a --- /dev/null +++ b/src/aud/exam/prep/SequenceProcessor.java @@ -0,0 +1,68 @@ +package aud.exam.prep; + +import java.util.Comparator; + +public interface SequenceProcessor { + + boolean find(S s, T t); + + boolean findBinary(S s, T t, Comparator cmp); + + boolean override(S s, T from, T to); + + boolean overrideAll(S s, T from, T to); + + boolean overrideAt(S s, T to, int index); + + void insertInOrder(S s, T t, Comparator cmp); + + boolean remove(S s, T t); + + boolean removeAll(S s, T t); + + boolean isAscending(S s, Comparator cmp); + + T max(S s, Comparator cmp); + + T secondMax(S s, Comparator cmp); + + boolean check(S s); + + boolean isItemWiseLessOrEqual(S a, S b, Comparator cmp); + + boolean isItemWiseLess(S a, S b, Comparator cmp); + + boolean isLexSmaller(S a, S b, Comparator cmp); + + void exchangePairs(S s); + + void rotateTriples(S s); + + void removeEverySecond(S s); + + void doubleAllKeys(S s); + + S rotateRight(S s); + + S rotateLeft(S s); + + void removeDuplicates(S s); + + S invert(S s); + + S clone(S s); + + S alternate(S a, S b); + + S merge(S a, S b, Comparator cmp); + + Pair divideAlternating(S s); + + Pair divideAlternatingByRuns(S s, Comparator cmp); + + Pair divideByPivot(S s, T pivot, Comparator cmp); + + S create(Iterable iterable); + + Iterable iterate(S s); +} diff --git a/test/aud/exam/prep/DoubleLatinProvider.java b/test/aud/exam/prep/DoubleLatinProvider.java new file mode 100644 index 0000000..2ca29ff --- /dev/null +++ b/test/aud/exam/prep/DoubleLatinProvider.java @@ -0,0 +1,28 @@ +package aud.exam.prep; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class DoubleLatinProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) throws Exception { + return Stream + .generate(() -> + Arguments.of(randomLatin(), randomLatin())) + .limit(Tests.STEAM_SIZE); + } + + private String randomLatin() { + var size = Tests.RANDOM.nextInt(100); + return Tests.RANDOM + .ints(size, 'A', 'Z'+1) + .mapToObj(n -> + String.valueOf((char) n)) + .collect(Collectors.joining()); + } +} diff --git a/test/aud/exam/prep/DuplicateListProvider.java b/test/aud/exam/prep/DuplicateListProvider.java new file mode 100644 index 0000000..cf083a0 --- /dev/null +++ b/test/aud/exam/prep/DuplicateListProvider.java @@ -0,0 +1,35 @@ +package aud.exam.prep; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class DuplicateListProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) { + return Stream + .generate(this::randomListWithDuplicates) + .map(Arguments::of) + .limit(Tests.STEAM_SIZE); + } + + private List randomListWithDuplicates() { + var size = Tests.RANDOM.nextInt(50); + return Tests.RANDOM + .ints(size, 0, 100) + .boxed() + .flatMap(n -> { + var count = Tests.RANDOM.nextInt(10); + return Collections + .nCopies(count, n) + .stream(); + }) + .collect(Collectors.toList()); + } +} diff --git a/test/aud/exam/prep/ListProvider.java b/test/aud/exam/prep/ListProvider.java new file mode 100644 index 0000000..caafa3f --- /dev/null +++ b/test/aud/exam/prep/ListProvider.java @@ -0,0 +1,28 @@ +package aud.exam.prep; + +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ListProvider implements ArgumentsProvider { + + @Override + public Stream provideArguments(ExtensionContext extensionContext) { + return Stream + .generate(this::randomList) + .map(Arguments::of) + .limit(Tests.STEAM_SIZE); + } + + private List randomList() { + var size = Tests.RANDOM.nextInt(50); + return Tests.RANDOM + .ints(size, 0, 100) + .boxed() + .collect(Collectors.toList()); + } +} diff --git a/test/aud/exam/prep/SequenceProcessorTest.java b/test/aud/exam/prep/SequenceProcessorTest.java new file mode 100644 index 0000000..4fd202d --- /dev/null +++ b/test/aud/exam/prep/SequenceProcessorTest.java @@ -0,0 +1,419 @@ +package aud.exam.prep; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +public abstract class SequenceProcessorTest { + + protected final Comparator cmp = Integer::compareTo; + + protected final SequenceProcessor processor; + + protected SequenceProcessorTest(SequenceProcessor processor) { + this.processor = processor; + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_createAndIterateWork(List list) { + S s = processor.create(list); + assertIterableEquals(list, processor.iterate(s)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_findOfNonExistsIsFalse(List list) { + S s = processor.create(list); + assertFalse(processor.find(s, -1)); + assertFalse(processor.find(s, 999)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_findOfExistsIsTrue(List list) { + S s = processor.create(list); + for (var n : list) { + assertTrue(processor.find(s, n)); + } + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_findBinaryOfNonExistsIsFalse(List list) { + list.sort(cmp); + S s = processor.create(list); + assertFalse(processor.findBinary(s, -1, cmp)); + assertFalse(processor.findBinary(s, 999, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_findBinaryOfExistsIsTrue(List list) { + list.sort(Comparable::compareTo); + S s = processor.create(list); + for (var n : list) { + assertTrue(processor.findBinary(s, n, cmp)); + } + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_overrideOfNotExistsIsFalseAndDoesNotModify(List list) { + S s = processor.create(list); + assertFalse(processor.override(s, -1, -5)); + assertFalse(processor.override(s, 999, -5)); + assertIterableEquals(list, processor.iterate(s)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_overrideOfExistsIsTrueAndDoesModify(List list) { + S s = processor.create(list); + for (int i = 0; i < list.size(); i++) { + var to = -(i*i) - 5; + + assertTrue(processor.override(s, list.get(i), to)); + list.set(i, to); + + assertIterableEquals(list, processor.iterate(s)); + } + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_overrideAllOfNotExistsIsFalseAndDoesNotModify(List list) { + S s = processor.create(list); + assertFalse(processor.overrideAll(s, -1, -5)); + assertFalse(processor.overrideAll(s, 999, -5)); + assertIterableEquals(list, processor.iterate(s)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_overrideAllOfExistsIsTrueAndDoesModify(List list) { + S s = processor.create(list); + for (int i = 0; i < list.size(); i++) { + var from = list.get(i); + var to = -(i*i) - 5; + + assertTrue(processor.overrideAll(s, from, to)); + list.replaceAll(k -> + Objects.equals(k, from) ? to : k); + + assertIterableEquals(list, processor.iterate(s)); + } + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_overrideAtOfBadIndexIsFalseAndDoesNotModify(List list) { + S s = processor.create(list); + assertFalse(processor.overrideAt(s, -5, -1)); + assertFalse(processor.overrideAt(s, -5, 999)); + assertIterableEquals(list, processor.iterate(s)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_overrideAtOfExistsIsTrueAndDoesModify(List list) { + S s = processor.create(list); + for (int i = 0; i < list.size(); i++) { + var to = -(i*i) - 5; + + assertTrue(processor.overrideAt(s, to, i)); + list.set(i, to); + + assertIterableEquals(list, processor.iterate(s)); + } + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_insertInOrderWorks(List list) { + list.sort(cmp); + S s = processor.create(list); + + for (int i = -1; i < 110; i++) { + processor.insertInOrder(s, i, cmp); + + list.add(i); + list.sort(cmp); + + assertIterableEquals(list, processor.iterate(s)); + } + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_removeOfNonExistsIsFalseAndDoesNotModify(List list) { + S s = processor.create(list); + assertFalse(processor.remove(s, -1)); + assertFalse(processor.remove(s, 999)); + assertIterableEquals(list, processor.iterate(s)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_removeOfExistsIsTrueAndDoesModify(List list) { + S s = processor.create(list); + + while (!list.isEmpty()) { + var toRemove = list.get(list.size()/2); + + list.remove(toRemove); + assertTrue(processor.remove(s, toRemove)); + + assertIterableEquals(list, processor.iterate(s)); + } + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_removeAllOfNonExistsIsFalseAndDoesNotModify(List list) { + S s = processor.create(list); + assertFalse(processor.removeAll(s, -1)); + assertFalse(processor.removeAll(s, 999)); + assertIterableEquals(list, processor.iterate(s)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_removeAllOfExistsIsTrueAndDoesModify(List list) { + S s = processor.create(list); + + while (!list.isEmpty()) { + var toRemove = list.get(list.size()/2); + + list.removeAll(Collections.singleton(toRemove)); + assertTrue(processor.removeAll(s, toRemove)); + + assertIterableEquals(list, processor.iterate(s)); + } + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_ifAscendingOfUnsortedIsFalse(List list) { + assumeTrue(list.size() > 2, "The list is to small"); + + list.add(list.size()/2, -1); + S s = processor.create(list); + assertFalse(processor.isAscending(s, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_ifAscendingOfSortedIsTrue(List list) { + list.sort(cmp); + S s = processor.create(list); + assertTrue(processor.isAscending(s, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_maxWorks(List list) { + list.add(-1); + S s = processor.create(list); + var max = list + .stream() + .max(cmp) + .orElseThrow(); + assertEquals(max, processor.max(s, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_secondMaxWorks(List list) { + list.add(-1); + list.add(-2); + S s = processor.create(list); + var max = list + .stream() + .sorted(cmp.reversed()) + .skip(1) + .findFirst() + .orElseThrow(); + assertEquals(max, processor.secondMax(s, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_isItemWiseLessOrEqualOfSameIsTrue(List list) { + S s = processor.create(list); + assertTrue(processor.isItemWiseLessOrEqual(s, s, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_isItemWiseLessOrEqualWithPlus5Works(List list) { + S a = processor.create(list); + + for (int i = 0; i < list.size(); i++) { + if (i % 2 == 0) { + list.set(i, list.get(i)+5); + } + } + S b = processor.create(list); + + assertTrue(processor.isItemWiseLessOrEqual(a, b, cmp)); + + assumeTrue(!list.isEmpty(), "List must not be empty to be less then"); + assertFalse(processor.isItemWiseLessOrEqual(b, a, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_isItemWiseLessOrEqualWithMoreElementsWorks(List list) { + S a = processor.create(list); + + for (int i = 1; i < 4; i++) { + list.add(-i); + } + S b = processor.create(list); + + assertTrue(processor.isItemWiseLessOrEqual(a, b, cmp)); + assertFalse(processor.isItemWiseLessOrEqual(b, a, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_isItemWiseLessOfSameIsFalse(List list) { + S s = processor.create(list); + assertFalse(processor.isItemWiseLess(s, s, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_isItemWiseLessWithAlmostSameIsTrue(List list) { + S a = processor.create(list); + + var index = list.size()/2; + if (list.isEmpty()) { + list.add(1); + } else { + list.set(index, list.get(index)+1); + } + S b = processor.create(list); + + assertTrue(processor.isItemWiseLess(a, b, cmp)); + assertFalse(processor.isItemWiseLess(b, a, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_isItemWiseLessWithPlus5Works(List list) { + S a = processor.create(list); + + for (int i = 0; i < list.size(); i++) { + if (i % 2 == 0) { + list.set(i, list.get(i)+5); + } + } + if (list.isEmpty()) { + list.add(1); + } + S b = processor.create(list); + + assertTrue(processor.isItemWiseLess(a, b, cmp)); + assertFalse(processor.isItemWiseLess(b, a, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_isLexSmallerOfSameIfFalse(List list) { + S s = processor.create(list); + assertFalse(processor.isLexSmaller(s, s, cmp)); + } + + @ParameterizedTest + @ArgumentsSource(DoubleLatinProvider.class) + void testThat_isLexSmallerWithWorksLikeStrings(String stringA, String stringB) { + S a = toSequenceByAscii(stringA); + S b = toSequenceByAscii(stringB); + + assertEquals( + stringA.compareTo(stringB) < 0, + processor.isLexSmaller(a, b, cmp)); + + assertEquals( + stringB.compareTo(stringA) < 0, + processor.isLexSmaller(b, a, cmp)); + } + + protected S toSequenceByAscii(String string) { + var list = string + .chars() + .boxed() + .collect(Collectors.toList()); + return processor.create(list); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_doubleAllKeysWorks(List list) { + S s = processor.create(list); + + list = list + .stream() + .flatMap(n -> + Stream.of(n, n)) + .collect(Collectors.toList()); + + processor.doubleAllKeys(s); + assertIterableEquals(list, processor.iterate(s)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_rotateRightWorks(List list) { + S s = processor.create(list); + + if (list.size() > 1) { + var right = list.remove(list.size()-1); + list.add(0, right); + } + + s = processor.rotateRight(s); + + assertIterableEquals(list, processor.iterate(s)); + } + + @ParameterizedTest + @ArgumentsSource(ListProvider.class) + void testThat_rotateLeftWorks(List list) { + S s = processor.create(list); + + if (list.size() > 1) { + var left = list.remove(0); + list.add(left); + } + + s = processor.rotateLeft(s); + + assertIterableEquals(list, processor.iterate(s)); + } + + @ParameterizedTest + @ArgumentsSource(DuplicateListProvider.class) + void testThat_removeDuplicatesWorks(List list) { + S s = processor.create(list); + + var noDuplicatesList = new ArrayList(); + for (var n : list) { + if (noDuplicatesList.isEmpty() || !Objects.equals(n, noDuplicatesList.get(noDuplicatesList.size()-1))) { + noDuplicatesList.add(n); + } + } + + processor.removeDuplicates(s); + + assertIterableEquals(noDuplicatesList, processor.iterate(s)); + } +} \ No newline at end of file diff --git a/test/aud/exam/prep/Tests.java b/test/aud/exam/prep/Tests.java new file mode 100644 index 0000000..360f829 --- /dev/null +++ b/test/aud/exam/prep/Tests.java @@ -0,0 +1,10 @@ +package aud.exam.prep; + +import java.util.Random; + +public class Tests { + + public static final int STEAM_SIZE = 50; + + public static final Random RANDOM = new Random(); +}