// Copyright 2014 The Bazel Authors. All rights reserved. // // 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 com.google.devtools.build.lib.util; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.devtools.build.lib.util.GroupedList.GroupedListHelper; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class GroupedListTest { @Test public void empty() { createSizeN(0); } @Test public void sizeOne() { createSizeN(1); } @Test public void sizeTwo() { createSizeN(2); } @Test public void sizeN() { createSizeN(10); } private void createSizeN(int size) { List<String> list = new ArrayList<>(); for (int i = 0; i < size; i++) { list.add("test" + i); } Object compressedList = createAndCompress(list); assertTrue(Iterables.elementsEqual(iterable(compressedList), list)); assertElementsEqual(compressedList, list); } @Test public void elementsNotEqualDifferentOrder() { List<String> list = Lists.newArrayList("a", "b", "c"); Object compressedList = createAndCompress(list); ArrayList<String> reversed = new ArrayList<>(list); Collections.reverse(reversed); assertFalse(elementsEqual(compressedList, reversed)); } @Test public void elementsNotEqualDifferentSizes() { for (int size1 = 0; size1 < 10; size1++) { List<String> firstList = new ArrayList<>(); for (int i = 0; i < size1; i++) { firstList.add("test" + i); } Object array = createAndCompress(firstList); for (int size2 = 0; size2 < 10; size2++) { List<String> secondList = new ArrayList<>(); for (int i = 0; i < size2; i++) { secondList.add("test" + i); } assertEquals(GroupedList.create(array) + ", " + secondList + ", " + size1 + ", " + size2, size1 == size2, elementsEqual(array, secondList)); } } } @Test public void listWithOneUniqueElementStoredBare() { GroupedList<String> groupedListWithDuplicateInGroup = new GroupedList<>(); groupedListWithDuplicateInGroup.append(GroupedListHelper.create("a")); GroupedListHelper<String> helper = new GroupedListHelper<>(); helper.startGroup(); helper.add("b"); helper.add("b"); helper.endGroup(); groupedListWithDuplicateInGroup.append(helper); GroupedList<String> groupedListWithNoDuplicates = new GroupedList<>(); groupedListWithNoDuplicates.append(GroupedListHelper.create("a")); groupedListWithNoDuplicates.append(GroupedListHelper.create("b")); assertThat(groupedListWithNoDuplicates).isEqualTo(groupedListWithDuplicateInGroup); } @Test public void listWithNoNewElementsStoredEmpty() { GroupedList<String> groupedListWithEmptyGroup = new GroupedList<>(); GroupedListHelper<String> helper = GroupedListHelper.create("a"); helper.add("a"); groupedListWithEmptyGroup.append(helper); GroupedList<String> groupedListWithNoDuplicates = new GroupedList<>(); groupedListWithNoDuplicates.append(GroupedListHelper.create("a")); assertThat(groupedListWithNoDuplicates).isEqualTo(groupedListWithEmptyGroup); } @Test public void group() { GroupedList<String> groupedList = new GroupedList<>(); assertTrue(groupedList.isEmpty()); GroupedListHelper<String> helper = new GroupedListHelper<>(); List<ImmutableList<String>> elements = ImmutableList.of( ImmutableList.of("1"), ImmutableList.of("2a", "2b"), ImmutableList.of("3"), ImmutableList.of("4"), ImmutableList.of("5a", "5b", "5c"), ImmutableList.of("6a", "6b", "6c") ); List<String> allElts = new ArrayList<>(); for (List<String> group : elements) { if (group.size() > 1) { helper.startGroup(); } for (String elt : group) { helper.add(elt); } if (group.size() > 1) { helper.endGroup(); } allElts.addAll(group); } groupedList.append(helper); assertEquals(allElts.size(), groupedList.numElements()); assertFalse(groupedList.isEmpty()); Object compressed = groupedList.compress(); assertElementsEqual(compressed, allElts); assertElementsEqualInGroups(GroupedList.<String>create(compressed), elements); assertElementsEqualInGroups(groupedList, elements); } @Test public void singletonAndEmptyGroups() { GroupedList<String> groupedList = new GroupedList<>(); assertTrue(groupedList.isEmpty()); GroupedListHelper<String> helper = new GroupedListHelper<>(); @SuppressWarnings("unchecked") // varargs List<ImmutableList<String>> elements = Lists.newArrayList( ImmutableList.of("1"), ImmutableList.<String>of(), ImmutableList.of("2a", "2b"), ImmutableList.of("3") ); List<String> allElts = new ArrayList<>(); for (List<String> group : elements) { helper.startGroup(); // Start a group even if the group has only one element or is empty. for (String elt : group) { helper.add(elt); } helper.endGroup(); allElts.addAll(group); } groupedList.append(helper); assertEquals(allElts.size(), groupedList.numElements()); assertFalse(groupedList.isEmpty()); Object compressed = groupedList.compress(); assertElementsEqual(compressed, allElts); // Get rid of empty list -- it was not stored in groupedList. elements.remove(1); assertElementsEqualInGroups(GroupedList.<String>create(compressed), elements); assertElementsEqualInGroups(groupedList, elements); } @Test public void sizeWithDuplicatesInAndOutOfGroups() { GroupedList<String> groupedList = new GroupedList<>(); GroupedListHelper<String> helper = new GroupedListHelper<>(); helper.add("1"); helper.startGroup(); helper.add("1"); helper.add("2"); helper.add("3"); helper.endGroup(); helper.add("3"); groupedList.append(helper); assertThat(groupedList.numElements()).isEqualTo(3); assertThat(groupedList.listSize()).isEqualTo(2); } @Test public void removeMakesEmpty() { GroupedList<String> groupedList = new GroupedList<>(); assertTrue(groupedList.isEmpty()); GroupedListHelper<String> helper = new GroupedListHelper<>(); @SuppressWarnings("unchecked") // varargs List<List<String>> elements = Lists.newArrayList( (List<String>) ImmutableList.of("1"), ImmutableList.<String>of(), Lists.newArrayList("2a", "2b"), ImmutableList.of("3"), ImmutableList.of("removedGroup1", "removedGroup2"), ImmutableList.of("4") ); List<String> allElts = new ArrayList<>(); for (List<String> group : elements) { helper.startGroup(); // Start a group even if the group has only one element or is empty. for (String elt : group) { helper.add(elt); } helper.endGroup(); allElts.addAll(group); } groupedList.append(helper); Set<String> removed = ImmutableSet.of("2a", "3", "removedGroup1", "removedGroup2"); groupedList.remove(removed); Object compressed = groupedList.compress(); allElts.removeAll(removed); assertElementsEqual(compressed, allElts); elements.get(2).remove("2a"); elements.remove(ImmutableList.of("3")); elements.remove(ImmutableList.of()); elements.remove(ImmutableList.of("removedGroup1", "removedGroup2")); assertElementsEqualInGroups(GroupedList.<String>create(compressed), elements); assertElementsEqualInGroups(groupedList, elements); } @Test public void removeGroupFromSmallList() { GroupedList<String> groupedList = new GroupedList<>(); assertTrue(groupedList.isEmpty()); GroupedListHelper<String> helper = new GroupedListHelper<>(); List<List<String>> elements = new ArrayList<>(); List<String> group = Lists.newArrayList("1a", "1b", "1c", "1d"); elements.add(group); List<String> allElts = new ArrayList<>(); helper.startGroup(); for (String item : elements.get(0)) { helper.add(item); } allElts.addAll(group); helper.endGroup(); groupedList.append(helper); Set<String> removed = ImmutableSet.of("1b", "1c"); groupedList.remove(removed); Object compressed = groupedList.compress(); allElts.removeAll(removed); assertElementsEqual(compressed, allElts); elements.get(0).removeAll(removed); assertElementsEqualInGroups(GroupedList.<String>create(compressed), elements); assertElementsEqualInGroups(groupedList, elements); } private static Object createAndCompress(Collection<String> list) { GroupedList<String> result = new GroupedList<>(); GroupedListHelper<String> helper = new GroupedListHelper<>(); helper.startGroup(); for (String item : list) { helper.add(item); } helper.endGroup(); result.append(helper); return result.compress(); } private static Iterable<String> iterable(Object compressed) { return GroupedList.<String>create(compressed).toSet(); } private static boolean elementsEqual(Object compressed, Iterable<String> expected) { return Iterables.elementsEqual(GroupedList.<String>create(compressed).toSet(), expected); } private static void assertElementsEqualInGroups( GroupedList<String> groupedList, List<? extends List<String>> elements) { int i = 0; for (Iterable<String> group : groupedList) { assertThat(group).containsExactlyElementsIn(elements.get(i)); assertThat(groupedList.get(i)).containsExactlyElementsIn(elements.get(i)); i++; } assertThat(elements).hasSize(i); } private static void assertElementsEqual(Object compressed, Iterable<String> expected) { assertThat(GroupedList.<String>create(compressed).toSet()).containsExactlyElementsIn(expected); } }