blob: 9ab7eb26a336e4fcf5fd576458842de3a5d63068 [file] [log] [blame]
// 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.collect.nestedset;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
/**
* Base class for tests of {@link NestedSet} iteration behavior.
*
* <p>This class provides test cases for representative nested set structures; the expected results
* must be provided by overriding the corresponding methods.
*/
public abstract class ExpanderTestBase {
/**
* Returns the type of the expander under test.
*/
protected abstract Order expanderOrder();
@Test
public void simple() {
NestedSet<String> s = prepareBuilder("c", "a", "b").build();
assertThat(s.toList()).isEqualTo(simpleResult());
assertSetContents(simpleResult(), s);
}
@Test
public void simpleNoDuplicates() {
NestedSet<String> s = prepareBuilder("c", "a", "a", "a", "b").build();
assertThat(s.toList()).isEqualTo(simpleResult());
assertSetContents(simpleResult(), s);
}
@Test
public void nesting() {
NestedSet<String> subset = prepareBuilder("c", "a", "e").build();
NestedSet<String> s = prepareBuilder("b", "d").addTransitive(subset).build();
assertSetContents(nestedResult(), s);
}
@Test
public void builderReuse() {
NestedSetBuilder<String> builder = prepareBuilder();
assertSetContents(Collections.<String>emptyList(), builder.build());
builder.add("b");
assertSetContents(ImmutableList.of("b"), builder.build());
builder.addAll(ImmutableList.of("d"));
List<String> expected = prepareBuilder("b", "d").build().toList();
assertSetContents(expected, builder.build());
NestedSet<String> child = prepareBuilder("c", "a", "e").build();
builder.addTransitive(child);
assertSetContents(nestedResult(), builder.build());
}
@Test
public void builderChaining() {
NestedSet<String> s = prepareBuilder().add("b").addAll(ImmutableList.of("d"))
.addTransitive(prepareBuilder("c", "a", "e").build()).build();
assertSetContents(nestedResult(), s);
}
@Test
public void addAllOrdering() {
NestedSet<String> s1 = prepareBuilder().add("a").add("c").add("b").build();
NestedSet<String> s2 = prepareBuilder().addAll(ImmutableList.of("a", "c", "b")).build();
assertCollectionsEqual(s1.toList(), s2.toList());
}
@Test
public void mixedAddAllOrdering() {
NestedSet<String> s1 = prepareBuilder().add("a").add("b").add("c").add("d").build();
NestedSet<String> s2 = prepareBuilder().add("a").addAll(ImmutableList.of("b", "c")).add("d")
.build();
assertCollectionsEqual(s1.toList(), s2.toList());
}
@Test
public void transitiveDepsHandledSeparately() {
NestedSet<String> subset = prepareBuilder("c", "a", "e").build();
NestedSetBuilder<String> b = prepareBuilder();
// The fact that we add the transitive subset between the add("b") and add("d") calls should
// not change the result.
b.add("b");
b.addTransitive(subset);
b.add("d");
NestedSet<String> s = b.build();
assertSetContents(nestedResult(), s);
}
@Test
public void nestingNoDuplicates() {
NestedSet<String> subset = prepareBuilder("c", "a", "e").build();
NestedSet<String> s = prepareBuilder("b", "d", "e").addTransitive(subset).build();
assertSetContents(nestedDuplicatesResult(), s);
}
@Test
public void chain() {
NestedSet<String> c = prepareBuilder("c").build();
NestedSet<String> b = prepareBuilder("b").addTransitive(c).build();
NestedSet<String> a = prepareBuilder("a").addTransitive(b).build();
assertSetContents(chainResult(), a);
}
@Test
public void diamond() {
NestedSet<String> d = prepareBuilder("d").build();
NestedSet<String> c = prepareBuilder("c").addTransitive(d).build();
NestedSet<String> b = prepareBuilder("b").addTransitive(d).build();
NestedSet<String> a = prepareBuilder("a").addTransitive(b).addTransitive(c).build();
assertSetContents(diamondResult(), a);
}
@Test
public void extendedDiamond() {
NestedSet<String> d = prepareBuilder("d").build();
NestedSet<String> e = prepareBuilder("e").build();
NestedSet<String> b = prepareBuilder("b").addTransitive(d).addTransitive(e).build();
NestedSet<String> c = prepareBuilder("c").addTransitive(e).addTransitive(d).build();
NestedSet<String> a = prepareBuilder("a").addTransitive(b).addTransitive(c).build();
assertSetContents(extendedDiamondResult(), a);
}
@Test
public void extendedDiamondRightArm() {
NestedSet<String> d = prepareBuilder("d").build();
NestedSet<String> e = prepareBuilder("e").build();
NestedSet<String> b = prepareBuilder("b").addTransitive(d).addTransitive(e).build();
NestedSet<String> c2 = prepareBuilder("c2").addTransitive(e).addTransitive(d).build();
NestedSet<String> c = prepareBuilder("c").addTransitive(c2).build();
NestedSet<String> a = prepareBuilder("a").addTransitive(b).addTransitive(c).build();
assertSetContents(extendedDiamondRightArmResult(), a);
}
@Test
public void orderConflict() {
NestedSet<String> child1 = prepareBuilder("a", "b").build();
NestedSet<String> child2 = prepareBuilder("b", "a").build();
NestedSet<String> parent = prepareBuilder().addTransitive(child1).addTransitive(child2).build();
assertSetContents(orderConflictResult(), parent);
}
@Test
public void orderConflictNested() {
NestedSet<String> a = prepareBuilder("a").build();
NestedSet<String> b = prepareBuilder("b").build();
NestedSet<String> child1 = prepareBuilder().addTransitive(a).addTransitive(b).build();
NestedSet<String> child2 = prepareBuilder().addTransitive(b).addTransitive(a).build();
NestedSet<String> parent = prepareBuilder().addTransitive(child1).addTransitive(child2).build();
assertSetContents(orderConflictResult(), parent);
}
@Test
public void getOrderingEmpty() {
NestedSet<String> s = prepareBuilder().build();
assertThat(s.isEmpty()).isTrue();
assertThat(s.getOrder()).isEqualTo(expanderOrder());
}
@Test
public void getOrdering() {
NestedSet<String> s = prepareBuilder("a", "b").build();
assertThat(s.isEmpty()).isFalse();
assertThat(s.getOrder()).isEqualTo(expanderOrder());
}
@Test
public void nestingValidation() {
for (Order ordering : Order.values()) {
NestedSet<String> a = prepareBuilder("a", "b").build();
NestedSetBuilder<String> b = new NestedSetBuilder<>(ordering);
try {
b.addTransitive(a);
if (ordering != expanderOrder() && ordering != Order.STABLE_ORDER) {
fail(); // An exception was expected.
}
} catch (IllegalArgumentException e) {
if (ordering == expanderOrder() || ordering == Order.STABLE_ORDER) {
fail(); // No exception was expected.
}
}
}
}
private NestedSetBuilder<String> prepareBuilder(String... directMembers) {
NestedSetBuilder<String> builder = new NestedSetBuilder<>(expanderOrder());
builder.addAll(Lists.newArrayList(directMembers));
return builder;
}
protected final void assertSetContents(List<String> expected, NestedSet<String> set) {
assertThat(Lists.newArrayList(set.toList())).isEqualTo(expected);
assertThat(Lists.newArrayList(set.toSet())).isEqualTo(expected);
}
protected final void assertCollectionsEqual(
Collection<String> expected, Collection<String> actual) {
assertThat(Lists.newArrayList(actual)).isEqualTo(Lists.newArrayList(expected));
}
/**
* Returns the enumeration of the nested set {"c", "a", "b"} in the implementation's enumeration
* order.
*
* @see #simple()
* @see #simpleNoDuplicates()
*/
protected List<String> simpleResult() {
return ImmutableList.of("c", "a", "b");
}
/**
* Returns the enumeration of the nested set {"b", "d", {"c", "a", "e"}} in the implementation's
* enumeration order.
*
* @see #nesting()
*/
protected abstract List<String> nestedResult();
/**
* Returns the enumeration of the nested set {"b", "d", "e", {"c", "a", "e"}} in the
* implementation's enumeration order.
*
* @see #nestingNoDuplicates()
*/
protected abstract List<String> nestedDuplicatesResult();
/**
* Returns the enumeration of nested set {"a", {"b", {"c"}}} in the implementation's enumeration
* order.
*
* @see #chain()
*/
protected abstract List<String> chainResult();
/**
* Returns the enumeration of the nested set {"a", {"b", D}, {"c", D}}, where D is {"d"}, in the
* implementation's enumeration order.
*
* @see #diamond()
*/
protected abstract List<String> diamondResult();
/**
* Returns the enumeration of the nested set {"a", {"b", E, D}, {"c", D, E}}, where D is {"d"} and
* E is {"e"}, in the implementation's enumeration order.
*
* @see #extendedDiamond()
*/
protected abstract List<String> extendedDiamondResult();
/**
* Returns the enumeration of the nested set {"a", {"b", E, D}, {"c", C2}}, where D is {"d"}, E is
* {"e"} and C2 is {"c2", D, E}, in the implementation's enumeration order.
*
* @see #extendedDiamondRightArm()
*/
protected abstract List<String> extendedDiamondRightArmResult();
/**
* Returns the enumeration of the nested set {{"a", "b"}, {"b", "a"}}.
*
* @see #orderConflict()
* @see #orderConflictNested()
*/
protected List<String> orderConflictResult() {
return ImmutableList.of("a", "b");
}
}