/* * SonarQube * Copyright (C) 2009-2017 SonarSource SA * mailto:info AT sonarsource DOT com * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.sonar.core.util.stream; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.IntStream; import java.util.stream.Stream; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import static java.util.function.Function.identity; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.entry; import static org.sonar.core.util.stream.MoreCollectors.index; import static org.sonar.core.util.stream.MoreCollectors.join; import static org.sonar.core.util.stream.MoreCollectors.toArrayList; import static org.sonar.core.util.stream.MoreCollectors.toHashSet; import static org.sonar.core.util.stream.MoreCollectors.toList; import static org.sonar.core.util.stream.MoreCollectors.toSet; import static org.sonar.core.util.stream.MoreCollectors.uniqueIndex; public class MoreCollectorsTest { private static final List<String> HUGE_LIST = IntStream.range(0, 2_000).mapToObj(String::valueOf).collect(java.util.stream.Collectors.toList()); private static final Set<String> HUGE_SET = new HashSet<>(HUGE_LIST); private static final MyObj MY_OBJ_1_A = new MyObj(1, "A"); private static final MyObj MY_OBJ_1_C = new MyObj(1, "C"); private static final MyObj MY_OBJ_2_B = new MyObj(2, "B"); private static final MyObj MY_OBJ_3_C = new MyObj(3, "C"); private static final List<MyObj> SINGLE_ELEMENT_LIST = Arrays.asList(MY_OBJ_1_A); private static final List<MyObj> LIST_WITH_DUPLICATE_ID = Arrays.asList(MY_OBJ_1_A, MY_OBJ_2_B, MY_OBJ_1_C); private static final List<MyObj> LIST = Arrays.asList(MY_OBJ_1_A, MY_OBJ_2_B, MY_OBJ_3_C); @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void toList_builds_an_ImmutableList() { List<Integer> res = Arrays.asList(1, 2, 3, 4, 5).stream().collect(toList()); assertThat(res).isInstanceOf(ImmutableList.class) .containsExactly(1, 2, 3, 4, 5); } @Test public void toList_parallel_stream() { assertThat(HUGE_LIST.parallelStream().collect(toList())).isEqualTo(HUGE_LIST); } @Test public void toList_with_size_builds_an_ImmutableList() { List<Integer> res = Arrays.asList(1, 2, 3, 4, 5).stream().collect(toList(30)); assertThat(res).isInstanceOf(ImmutableList.class) .containsExactly(1, 2, 3, 4, 5); } @Test public void toList_with_size_parallel_stream() { assertThat(HUGE_LIST.parallelStream().collect(toList(HUGE_LIST.size()))).isEqualTo(HUGE_LIST); } @Test public void toSet_builds_an_ImmutableSet() { Set<Integer> res = Arrays.asList(1, 2, 3, 4, 5).stream().collect(toSet()); assertThat(res).isInstanceOf(ImmutableSet.class) .containsExactly(1, 2, 3, 4, 5); } @Test public void toSet_parallel_stream() { assertThat(HUGE_SET.parallelStream().collect(toSet())).isEqualTo(HUGE_SET); } @Test public void toSet_with_size_builds_an_ImmutableSet() { Set<Integer> res = Arrays.asList(1, 2, 3, 4, 5).stream().collect(toSet(30)); assertThat(res).isInstanceOf(ImmutableSet.class) .containsExactly(1, 2, 3, 4, 5); } @Test public void toSet_with_size_parallel_stream() { assertThat(HUGE_SET.parallelStream().collect(toSet(HUGE_SET.size()))).isEqualTo(HUGE_SET); } @Test public void toArrayList_builds_an_ArrayList() { List<Integer> res = Arrays.asList(1, 2, 3, 4, 5).stream().collect(toArrayList()); assertThat(res).isInstanceOf(ArrayList.class) .containsExactly(1, 2, 3, 4, 5); } @Test public void toArrayList_parallel_stream() { assertThat(HUGE_LIST.parallelStream().collect(toArrayList())).isEqualTo(HUGE_LIST); } @Test public void toArrayList_with_size_builds_an_ArrayList() { List<Integer> res = Arrays.asList(1, 2, 3, 4, 5).stream().collect(toArrayList(30)); assertThat(res).isInstanceOf(ArrayList.class) .containsExactly(1, 2, 3, 4, 5); } @Test public void toArrayList_with_size_parallel_stream() { assertThat(HUGE_LIST.parallelStream().collect(toArrayList(HUGE_LIST.size()))).isEqualTo(HUGE_LIST); } @Test public void toHashSet_builds_an_HashSet() { Set<Integer> res = Arrays.asList(1, 2, 3, 4, 5).stream().collect(toHashSet()); assertThat(res).isInstanceOf(HashSet.class) .containsExactly(1, 2, 3, 4, 5); } @Test public void toHashSet_parallel_stream() { assertThat(HUGE_SET.parallelStream().collect(toHashSet())).isEqualTo(HUGE_SET); } @Test public void toHashSet_with_size_builds_an_ArrayList() { Set<Integer> res = Arrays.asList(1, 2, 3, 4, 5).stream().collect(toHashSet(30)); assertThat(res).isInstanceOf(HashSet.class) .containsExactly(1, 2, 3, 4, 5); } @Test public void toHashSet_with_size_parallel_stream() { assertThat(HUGE_SET.parallelStream().collect(toHashSet(HUGE_SET.size()))).isEqualTo(HUGE_SET); } @Test public void uniqueIndex_empty_stream_returns_empty_map() { assertThat(Collections.<MyObj>emptyList().stream().collect(uniqueIndex(MyObj::getId))).isEmpty(); assertThat(Collections.<MyObj>emptyList().stream().collect(uniqueIndex(MyObj::getId, 6))).isEmpty(); assertThat(Collections.<MyObj>emptyList().stream().collect(uniqueIndex(MyObj::getId, MyObj::getText))).isEmpty(); assertThat(Collections.<MyObj>emptyList().stream().collect(uniqueIndex(MyObj::getId, MyObj::getText, 10))).isEmpty(); } @Test public void uniqueIndex_fails_when_there_is_duplicate_keys() { Stream<MyObj> stream = LIST_WITH_DUPLICATE_ID.stream(); expectedDuplicateKey1IAE(); stream.collect(uniqueIndex(MyObj::getId)); } @Test public void uniqueIndex_with_expected_size_fails_when_there_is_duplicate_keys() { Stream<MyObj> stream = LIST_WITH_DUPLICATE_ID.stream(); expectedDuplicateKey1IAE(); stream.collect(uniqueIndex(MyObj::getId, 1)); } @Test public void uniqueIndex_with_valueFunction_fails_when_there_is_duplicate_keys() { Stream<MyObj> stream = LIST_WITH_DUPLICATE_ID.stream(); expectedDuplicateKey1IAE(); stream.collect(uniqueIndex(MyObj::getId, MyObj::getText)); } @Test public void uniqueIndex_with_valueFunction_and_expected_size_fails_when_there_is_duplicate_keys() { Stream<MyObj> stream = LIST_WITH_DUPLICATE_ID.stream(); expectedDuplicateKey1IAE(); stream.collect(uniqueIndex(MyObj::getId, MyObj::getText, 10)); } @Test public void uniqueIndex_fails_if_key_function_is_null() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Key function can't be null"); uniqueIndex(null); } @Test public void uniqueIndex_with_expected_size_fails_if_key_function_is_null() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Key function can't be null"); uniqueIndex(null, 2); } @Test public void uniqueIndex_with_valueFunction_fails_if_key_function_is_null() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Key function can't be null"); uniqueIndex(null, MyObj::getText); } @Test public void uniqueIndex_with_valueFunction_and_expected_size_fails_if_key_function_is_null() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Key function can't be null"); uniqueIndex(null, MyObj::getText, 9); } @Test public void uniqueIndex_with_valueFunction_fails_if_value_function_is_null() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Value function can't be null"); uniqueIndex(MyObj::getId, null); } @Test public void uniqueIndex_with_valueFunction_and_expected_size_fails_if_value_function_is_null() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Value function can't be null"); uniqueIndex(MyObj::getId, null, 9); } @Test public void uniqueIndex_fails_if_key_function_returns_null() { expectKeyFunctionCantReturnNullNPE(); SINGLE_ELEMENT_LIST.stream().collect(uniqueIndex(s -> null)); } @Test public void uniqueIndex_with_expected_size_fails_if_key_function_returns_null() { expectKeyFunctionCantReturnNullNPE(); SINGLE_ELEMENT_LIST.stream().collect(uniqueIndex(s -> null, 90)); } @Test public void uniqueIndex_with_valueFunction_fails_if_key_function_returns_null() { expectKeyFunctionCantReturnNullNPE(); SINGLE_ELEMENT_LIST.stream().collect(uniqueIndex(s -> null, MyObj::getText)); } @Test public void uniqueIndex_with_valueFunction_and_expected_size_fails_if_key_function_returns_null() { expectKeyFunctionCantReturnNullNPE(); SINGLE_ELEMENT_LIST.stream().collect(uniqueIndex(s -> null, MyObj::getText, 9)); } @Test public void uniqueIndex_with_valueFunction_fails_if_value_function_returns_null() { expectValueFunctionCantReturnNullNPE(); SINGLE_ELEMENT_LIST.stream().collect(uniqueIndex(MyObj::getId, s -> null)); } @Test public void uniqueIndex_with_valueFunction_and_expected_size_fails_if_value_function_returns_null() { expectValueFunctionCantReturnNullNPE(); SINGLE_ELEMENT_LIST.stream().collect(uniqueIndex(MyObj::getId, s -> null, 9)); } @Test public void uniqueIndex_returns_map() { assertThat(LIST.stream().collect(uniqueIndex(MyObj::getId))).containsOnly(entry(1, MY_OBJ_1_A), entry(2, MY_OBJ_2_B), entry(3, MY_OBJ_3_C)); } @Test public void uniqueIndex_with_expected_size_returns_map() { assertThat(LIST.stream().collect(uniqueIndex(MyObj::getId, 3))).containsOnly(entry(1, MY_OBJ_1_A), entry(2, MY_OBJ_2_B), entry(3, MY_OBJ_3_C)); } @Test public void uniqueIndex_with_valueFunction_returns_map() { assertThat(LIST.stream().collect(uniqueIndex(MyObj::getId, MyObj::getText))).containsOnly(entry(1, "A"), entry(2, "B"), entry(3, "C")); } @Test public void uniqueIndex_with_valueFunction_and_expected_size_returns_map() { assertThat(LIST.stream().collect(uniqueIndex(MyObj::getId, MyObj::getText, 9))).containsOnly(entry(1, "A"), entry(2, "B"), entry(3, "C")); } @Test public void uniqueIndex_parallel_stream() { Map<String, String> map = HUGE_LIST.parallelStream().collect(uniqueIndex(identity())); assertThat(map.keySet()).isEqualTo(HUGE_SET); assertThat(map.values()).containsExactlyElementsOf(HUGE_SET); } @Test public void uniqueIndex_with_expected_size_parallel_stream() { Map<String, String> map = HUGE_LIST.parallelStream().collect(uniqueIndex(identity(), HUGE_LIST.size())); assertThat(map.keySet()).isEqualTo(HUGE_SET); assertThat(map.values()).containsExactlyElementsOf(HUGE_SET); } @Test public void uniqueIndex_with_valueFunction_parallel_stream() { Map<String, String> map = HUGE_LIST.parallelStream().collect(uniqueIndex(identity(), identity())); assertThat(map.keySet()).isEqualTo(HUGE_SET); assertThat(map.values()).containsExactlyElementsOf(HUGE_SET); } @Test public void uniqueIndex_with_valueFunction_and_expected_size_parallel_stream() { Map<String, String> map = HUGE_LIST.parallelStream().collect(uniqueIndex(identity(), identity(), HUGE_LIST.size())); assertThat(map.keySet()).isEqualTo(HUGE_SET); assertThat(map.values()).containsExactlyElementsOf(HUGE_SET); } @Test public void index_empty_stream_returns_empty_map() { assertThat(Collections.<MyObj>emptyList().stream().collect(index(MyObj::getId)).size()).isEqualTo(0); assertThat(Collections.<MyObj>emptyList().stream().collect(index(MyObj::getId, MyObj::getText)).size()).isEqualTo(0); } @Test public void index_fails_if_key_function_is_null() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Key function can't be null"); index(null); } @Test public void index_with_valueFunction_fails_if_key_function_is_null() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Key function can't be null"); index(null, MyObj::getText); } @Test public void index_with_valueFunction_fails_if_value_function_is_null() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Value function can't be null"); index(MyObj::getId, null); } @Test public void index_fails_if_key_function_returns_null() { expectKeyFunctionCantReturnNullNPE(); SINGLE_ELEMENT_LIST.stream().collect(index(s -> null)); } @Test public void index_with_valueFunction_fails_if_key_function_returns_null() { expectKeyFunctionCantReturnNullNPE(); SINGLE_ELEMENT_LIST.stream().collect(index(s -> null, MyObj::getText)); } @Test public void index_with_valueFunction_fails_if_value_function_returns_null() { expectValueFunctionCantReturnNullNPE(); SINGLE_ELEMENT_LIST.stream().collect(index(MyObj::getId, s -> null)); } @Test public void index_supports_duplicate_keys() { Multimap<Integer, MyObj> multimap = LIST_WITH_DUPLICATE_ID.stream().collect(index(MyObj::getId)); assertThat(multimap.keySet()).containsOnly(1, 2); assertThat(multimap.get(1)).containsOnly(MY_OBJ_1_A, MY_OBJ_1_C); assertThat(multimap.get(2)).containsOnly(MY_OBJ_2_B); } @Test public void uniqueIndex_supports_duplicate_keys() { Multimap<Integer, String> multimap = LIST_WITH_DUPLICATE_ID.stream().collect(index(MyObj::getId, MyObj::getText)); assertThat(multimap.keySet()).containsOnly(1, 2); assertThat(multimap.get(1)).containsOnly("A", "C"); assertThat(multimap.get(2)).containsOnly("B"); } @Test public void index_returns_multimap() { Multimap<Integer, MyObj> multimap = LIST.stream().collect(index(MyObj::getId)); assertThat(multimap.size()).isEqualTo(3); Map<Integer, Collection<MyObj>> map = multimap.asMap(); assertThat(map.get(1)).containsOnly(MY_OBJ_1_A); assertThat(map.get(2)).containsOnly(MY_OBJ_2_B); assertThat(map.get(3)).containsOnly(MY_OBJ_3_C); } @Test public void index_with_valueFunction_returns_multimap() { Multimap<Integer, String> multimap = LIST.stream().collect(index(MyObj::getId, MyObj::getText)); assertThat(multimap.size()).isEqualTo(3); Map<Integer, Collection<String>> map = multimap.asMap(); assertThat(map.get(1)).containsOnly("A"); assertThat(map.get(2)).containsOnly("B"); assertThat(map.get(3)).containsOnly("C"); } @Test public void index_parallel_stream() { Multimap<String, String> multimap = HUGE_LIST.parallelStream().collect(index(identity())); assertThat(multimap.keySet()).isEqualTo(HUGE_SET); } @Test public void index_with_valueFunction_parallel_stream() { Multimap<String, String> multimap = HUGE_LIST.parallelStream().collect(index(identity(), identity())); assertThat(multimap.keySet()).isEqualTo(HUGE_SET); } @Test public void join_on_empty_stream_returns_empty_string() { assertThat(Collections.emptyList().stream().collect(join(Joiner.on(",")))).isEmpty(); } @Test public void join_fails_with_NPE_if_joiner_is_null() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Joiner can't be null"); join(null); } @Test public void join_applies_joiner_to_stream() { assertThat(Arrays.asList("1", "2", "3", "4").stream().collect(join(Joiner.on(",")))) .isEqualTo("1,2,3,4"); } @Test public void join_does_not_support_parallel_stream_and_fails_with_ISE() { Stream<String> hugeStream = HUGE_LIST.parallelStream(); expectedException.expect(IllegalStateException.class); expectedException.expectMessage("Parallel processing is not supported"); hugeStream.collect(join(Joiner.on(" "))); } @Test public void join_supports_null_if_joiner_does() { Stream<String> stream = Arrays.asList("1", null).stream(); expectedException.expect(NullPointerException.class); stream.collect(join(Joiner.on(","))); } private void expectedDuplicateKey1IAE() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage("Duplicate key 1"); } private void expectKeyFunctionCantReturnNullNPE() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Key function can't return null"); } private void expectValueFunctionCantReturnNullNPE() { expectedException.expect(NullPointerException.class); expectedException.expectMessage("Value function can't return null"); } private static final class MyObj { private final int id; private final String text; public MyObj(int id, String text) { this.id = id; this.text = text; } public int getId() { return id; } public String getText() { return text; } } }