Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve StreamEx coverage #201

Merged
merged 5 commits into from
Aug 31, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions src/main/java/one/util/streamex/StreamEx.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
Expand Down Expand Up @@ -1028,7 +1028,7 @@ public <C extends Collection<? super T>> C into(C collection) {
Spliterator<T> spltr = spliterator();
if (collection instanceof ArrayList) {
long size = spltr.getExactSizeIfKnown();
if (size >= 0 && size < Integer.MAX_VALUE - collection.size())
if (size > 0 && size <= Integer.MAX_VALUE - collection.size())
((ArrayList<?>) collection).ensureCapacity((int) (collection.size() + size));
}
spltr.forEachRemaining(collection::add);
Expand Down Expand Up @@ -2589,18 +2589,27 @@ public static StreamEx<String> split(CharSequence str, String regex) {
return IntStreamEx.ofChars(str).mapToObj(ch -> new String(new char[] { (char) ch }));
}
char ch = regex.charAt(0);
if (regex.length() == 1 && ".$|()[{^?*+\\".indexOf(ch) == -1) {
if (regex.length() == 1 && isNotRegexSpecialCaseStarter(ch)) {
return split(str, ch);
} else if (regex.length() == 2 && ch == '\\') {
ch = regex.charAt(1);
if ((ch < '0' || ch > '9') && (ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')
&& (ch < Character.MIN_HIGH_SURROGATE || ch > Character.MAX_LOW_SURROGATE)) {
if (isTransparentlyQuotableCharacter(ch)) {
return split(str, ch);
}
}
return new StreamEx<>(Pattern.compile(regex).splitAsStream(str), StreamContext.SEQUENTIAL);
}

private static boolean isNotRegexSpecialCaseStarter(char ch) {
/* @see java.util.regex.Pattern#atom() */
return ".$|()[{^?*+\\".indexOf(ch) == -1;
}

private static boolean isTransparentlyQuotableCharacter(char ch) {
/* @see java.util.regex.Pattern#escape(boolean,boolean,boolean) */
return (ch < '0' || ch > '9') && (ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z');
errandir marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Creates a stream from the given input sequence around matches of the
* given character.
Expand Down
8 changes: 3 additions & 5 deletions src/test/java/one/util/streamex/EntryStreamTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,10 @@ public void testWithIndex() {
// Test equals contract
assertNotEquals(new Object(), entry);
assertNotEquals(entry, new Object());
assertEquals(entry, new AbstractMap.SimpleImmutableEntry<>(0, "a"));
}
assertEquals(new AbstractMap.SimpleImmutableEntry<>(0, "a"), entry);
errandir marked this conversation as resolved.
Show resolved Hide resolved

@Test(expected = UnsupportedOperationException.class)
public void testWithIndexModify() {
EntryStream.of(Collections.singletonList("1")).forEach(entry -> entry.setValue("2"));
assertThrows(UnsupportedOperationException.class, () ->
EntryStream.of(Collections.singletonList("1")).forEach(e -> e.setValue("2")));
}

@Test
Expand Down
23 changes: 4 additions & 19 deletions src/test/java/one/util/streamex/IntStreamExTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.IntStream.Builder;
import java.util.stream.StreamSupport;

import static one.util.streamex.TestHelpers.*;
import static org.junit.Assert.*;
Expand Down Expand Up @@ -165,11 +164,8 @@ public void testRangeStep() {

assertEquals(0, IntStreamEx.range(0, Integer.MIN_VALUE, 2).spliterator().getExactSizeIfKnown());
assertEquals(0, IntStreamEx.range(0, Integer.MAX_VALUE, -2).spliterator().getExactSizeIfKnown());
}

@Test(expected = IllegalArgumentException.class)
public void testRangeIllegalStep() {
IntStreamEx.range(0, 1000, 0);
assertThrows(IllegalArgumentException.class, () -> IntStreamEx.range(0, 1000, 0));
}

@Test
Expand Down Expand Up @@ -219,21 +215,10 @@ public void testRangeClosedStep() {
assertEquals(0, IntStreamEx.rangeClosed(0, 1000, -2).count());
assertEquals(0, IntStreamEx.rangeClosed(0, 1, -2).count());
assertEquals(0, IntStreamEx.rangeClosed(0, -1, 2).count());
}

@Test(expected = ArrayIndexOutOfBoundsException.class)
public void testArrayOffsetUnderflow() {
IntStreamEx.of(EVEN_BYTES, -1, 3).findAny();
}

@Test(expected = ArrayIndexOutOfBoundsException.class)
public void testArrayOffsetWrong() {
IntStreamEx.of(EVEN_BYTES, 3, 1).findAny();
}

@Test(expected = ArrayIndexOutOfBoundsException.class)
public void testArrayLengthOverflow() {
IntStreamEx.of(EVEN_BYTES, 3, 6).findAny();
assertThrows(ArrayIndexOutOfBoundsException.class, () -> IntStreamEx.of(EVEN_BYTES, -1, 3).findAny());
assertThrows(ArrayIndexOutOfBoundsException.class, () -> IntStreamEx.of(EVEN_BYTES, 3, 1).findAny());
assertThrows(ArrayIndexOutOfBoundsException.class, () -> IntStreamEx.of(EVEN_BYTES, 3, 6).findAny());
}

@Test
Expand Down
6 changes: 2 additions & 4 deletions src/test/java/one/util/streamex/LongStreamExTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import java.util.stream.LongStream;
import java.util.stream.LongStream.Builder;

import static one.util.streamex.TestHelpers.assertThrows;
import static one.util.streamex.TestHelpers.checkSpliterator;
import static org.junit.Assert.*;

Expand Down Expand Up @@ -151,11 +152,8 @@ public void testRangeStep() {

assertEquals(0, LongStreamEx.range(0, Long.MIN_VALUE, 2).spliterator().getExactSizeIfKnown());
assertEquals(0, LongStreamEx.range(0, Long.MAX_VALUE, -2).spliterator().getExactSizeIfKnown());
}

@Test(expected = IllegalArgumentException.class)
public void testRangeIllegalStep() {
LongStreamEx.range(0, 1000, 0);
assertThrows(IllegalArgumentException.class, () -> LongStreamEx.range(0, 1000, 0));
}

@Test
Expand Down
81 changes: 59 additions & 22 deletions src/test/java/one/util/streamex/StreamExTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import java.util.function.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
Expand Down Expand Up @@ -139,9 +140,9 @@ public void testReader() {
assertEquals(expectedSet, actualSet);
}

@Test(expected = IllegalArgumentException.class)
public void testZipThrows() {
StreamEx.zip(asList("A"), asList("b", "c"), String::concat);
@Test
public void testZip() {
assertThrows(IllegalArgumentException.class, () -> StreamEx.zip(asList("A"), asList("b", "c"), String::concat));
}

@Test
Expand Down Expand Up @@ -218,6 +219,7 @@ public void testToArray() {
Integer[] emptyArray = {};
assertSame(emptyArray, StreamEx.of(1, 2, 3).filter(x -> x > 3).toArray(emptyArray));
assertArrayEquals(new Integer[] { 1, 2, 3 }, StreamEx.of(1, 2, 3).remove(x -> x > 3).toArray(emptyArray));
assertThrows(IllegalArgumentException.class, () -> StreamEx.of().toArray(new Integer[1]));
errandir marked this conversation as resolved.
Show resolved Hide resolved
}

@Test
Expand Down Expand Up @@ -1368,11 +1370,9 @@ public void testRunLenghts() {
assertNotEquals(entry, new Object());
assertNotEquals(new Object(), entry);
assertEquals(entry, new AbstractMap.SimpleImmutableEntry<>(1, 1L));
}

@Test(expected = UnsupportedOperationException.class)
public void testRunLengthsModify() {
StreamEx.of("1", "1", "1").runLengths().forEach(e -> e.setValue(5L));
assertThrows(UnsupportedOperationException.class, () ->
StreamEx.of("1", "1", "1").runLengths().forEach(e -> e.setValue(5L)));
}

@Test
Expand Down Expand Up @@ -1472,6 +1472,7 @@ public void testSubLists() {
@Test
public void testSubListsStep() {
List<Integer> input = IntStreamEx.range(12).boxed().toList();
assertThrows(IllegalArgumentException.class, () -> StreamEx.ofSubLists(input, 0, Integer.MAX_VALUE));
assertEquals("[0, 1, 2, 3, 4]", StreamEx.ofSubLists(input, 5, Integer.MAX_VALUE).joining("-"));
assertEquals("[0, 1, 2, 3, 4]", StreamEx.ofSubLists(input, 5, 12).joining("-"));
assertEquals("[0, 1, 2, 3, 4]-[11]", StreamEx.ofSubLists(input, 5, 11).joining("-"));
Expand Down Expand Up @@ -1501,16 +1502,9 @@ public void testSubListsStep() {
assertEquals(1, StreamEx.ofSubLists(myList, Integer.MAX_VALUE - 2, 1).count());
assertEquals(998, StreamEx.ofSubLists(myList, Integer.MAX_VALUE - 3, Integer.MAX_VALUE - 1000).skip(1)
.findFirst().get().size());
}

@Test(expected = IllegalArgumentException.class)
public void testSubListsArg() {
StreamEx.ofSubLists(Collections.emptyList(), 0);
}

@Test(expected = IllegalArgumentException.class)
public void testSubListsStepArg() {
StreamEx.ofSubLists(Collections.emptyList(), 1, 0);
assertThrows(IllegalArgumentException.class, () -> StreamEx.ofSubLists(Collections.emptyList(), 0));
assertThrows(IllegalArgumentException.class, () -> StreamEx.ofSubLists(Collections.emptyList(), 1, 0));
}

@Test
Expand Down Expand Up @@ -1764,6 +1758,13 @@ public void testSplit() {
streamEx(() -> StreamEx.split("ab.cd...", "\\w"), s -> assertEquals("||.||...", s.get().joining("|")));
streamEx(() -> StreamEx.split("ab.cd...", "\\W"), s -> assertEquals("ab|cd", s.get().joining("|")));
streamEx(() -> StreamEx.split("ab|cd|e", "\\|"), s -> assertEquals("ab,cd,e", s.get().joining(",")));
assertEquals(CharSpliterator.class, StreamEx.split("a#a", "\\#").spliterator().getClass());
assertThrows(PatternSyntaxException.class, () -> StreamEx.split("a", "\\0"));
asList('9', 'A', 'Z', 'z').forEach(ch ->
assertEquals(asList("a" + ch + "a"), StreamEx.split("a" + ch + "a", "\\" + ch).toList()));
assertEquals(asList("aaa"), StreamEx.split("aaa", "\\a").toList());
asList(Character.MIN_HIGH_SURROGATE, Character.MAX_HIGH_SURROGATE).forEach(ch ->
assertEquals(asList("a", "a"), StreamEx.split("a" + ch + "a", "\\" + ch).toList()));
}

@Test
Expand Down Expand Up @@ -2020,6 +2021,37 @@ public int size() {
assertEquals(Integer.MAX_VALUE + 10, c.size());
}

@Test
public void testIntoArrayListEnsureCapacityOptimization() {
CapacityEnsuredAssertingArrayList<Integer> list = new CapacityEnsuredAssertingArrayList<>();
Collection<Integer> collection = list;
StreamEx.<Integer>of().into(collection);
StreamEx.of(asList(1)).into(collection);
int maxAvailableSize = Integer.MAX_VALUE - collection.size();
StreamEx.<Integer>of(emptySpliteratorWithExactSize(maxAvailableSize + 1)).into(collection);
StreamEx.<Integer>of(emptySpliteratorWithExactSize(Long.MAX_VALUE)).into(collection);
StreamEx.<Integer>of(emptySpliteratorWithExactSize(maxAvailableSize)).into(collection);
assertEquals(Integer.MAX_VALUE, list.ensuredCapacity);
}

private static class CapacityEnsuredAssertingArrayList<E> extends ArrayList<E> {
private int ensuredCapacity = 0;

@Override
public boolean add(E element) {
if (size() >= ensuredCapacity)
fail("ArrayList capacity was not ensured");
return super.add(element);
}

@Override
public void ensureCapacity(int minCapacity) {
if (minCapacity <= ensuredCapacity)
fail("Not required ensureCapacity call");
ensuredCapacity = minCapacity;
}
}

@Test
public void testFilterBy() {
assertEquals(3, StreamEx.of("a", "bb", "c", "e", "ddd").filterBy(String::length, 1).count());
Expand Down Expand Up @@ -2082,16 +2114,21 @@ public void testOfCombinations() {
assertEquals(asList("[]"), s.get().map(Arrays::toString).collect(Collectors.toList())));
streamEx(() -> StreamEx.ofCombinations(5, 5), s ->
assertEquals(asList("[0, 1, 2, 3, 4]"), s.get().map(Arrays::toString).collect(Collectors.toList())));

assertThrows(IllegalArgumentException.class, () -> StreamEx.ofCombinations(-1, 0));
assertThrows(IllegalArgumentException.class, () -> StreamEx.ofCombinations(0, -1));
}

@Test(expected = IllegalArgumentException.class)
public void testOfCombinationsNegativeN() {
StreamEx.ofCombinations(-1, 0);
@Test
public void testMapToEntry() {
assertEquals(Collections.singletonMap(1, "a"),
StreamEx.of("a").mapToEntry(String::length, Function.identity()).toMap());
}

@Test(expected = IllegalArgumentException.class)
public void testOfCombinationsNegativeK() {
StreamEx.ofCombinations(0, -1);
@Test
public void testFlatMapToEntry() {
assertEquals(Collections.singletonMap(1, "a"),
StreamEx.of("a").flatMapToEntry(s -> Collections.singletonMap(s.length(), s)).toMap());
}

@Test
Expand Down
41 changes: 37 additions & 4 deletions src/test/java/one/util/streamex/TestHelpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,16 @@
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Semaphore;
errandir marked this conversation as resolved.
Show resolved Hide resolved
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntConsumer;
import java.util.function.Supplier;
import java.util.function.*;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.concurrent.TimeUnit.SECONDS;
import static one.util.streamex.StreamExInternals.TailSpliterator;
import static one.util.streamex.StreamExInternals.finished;
import static org.junit.Assert.*;
Expand All @@ -39,6 +38,7 @@
* @author Tagir Valeev
*/
public class TestHelpers {

enum Mode {
NORMAL, SPLITERATOR, PARALLEL, APPEND, PREPEND, RANDOM
}
Expand Down Expand Up @@ -415,4 +415,37 @@ static void checkIllegalStateException(Runnable r, String key, String value1, St
fail("wrong exception message: " + exmsg);
}
}

@FunctionalInterface
interface Statement {
void evaluate() throws Throwable;
}

static void assertThrows(Class<? extends Throwable> expected, Statement statement) {
try {
statement.evaluate();
fail("Expected exception: " + expected.getName());
} catch (Throwable e) {
if (!expected.isAssignableFrom(e.getClass())) {
fail("Unexpected exception, " +
"expected<" + expected.getName() + "> " +
"but was<" + e.getClass().getName() + ">");
}
}
}

static <T> Spliterator<T> emptySpliteratorWithExactSize(long exactSize) {
return new Spliterators.AbstractSpliterator<T>(0, Spliterator.SIZED) {

@Override
public long getExactSizeIfKnown() {
return exactSize;
}

@Override
public boolean tryAdvance(Consumer<? super T> ignored) {
return false;
}
};
}
}