// 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 NestedSetExpander} implementations.
*
*
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 s = prepareBuilder("c", "a", "b").build();
assertThat(s.toList()).isEqualTo(simpleResult());
assertSetContents(simpleResult(), s);
}
@Test
public void simpleNoDuplicates() {
NestedSet s = prepareBuilder("c", "a", "a", "a", "b").build();
assertThat(s.toList()).isEqualTo(simpleResult());
assertSetContents(simpleResult(), s);
}
@Test
public void nesting() {
NestedSet subset = prepareBuilder("c", "a", "e").build();
NestedSet s = prepareBuilder("b", "d").addTransitive(subset).build();
assertSetContents(nestedResult(), s);
}
@Test
public void builderReuse() {
NestedSetBuilder builder = prepareBuilder();
assertSetContents(Collections.emptyList(), builder.build());
builder.add("b");
assertSetContents(ImmutableList.of("b"), builder.build());
builder.addAll(ImmutableList.of("d"));
Collection expected = ImmutableList.copyOf(prepareBuilder("b", "d").build());
assertSetContents(expected, builder.build());
NestedSet child = prepareBuilder("c", "a", "e").build();
builder.addTransitive(child);
assertSetContents(nestedResult(), builder.build());
}
@Test
public void builderChaining() {
NestedSet s = prepareBuilder().add("b").addAll(ImmutableList.of("d"))
.addTransitive(prepareBuilder("c", "a", "e").build()).build();
assertSetContents(nestedResult(), s);
}
@Test
public void addAllOrdering() {
NestedSet s1 = prepareBuilder().add("a").add("c").add("b").build();
NestedSet s2 = prepareBuilder().addAll(ImmutableList.of("a", "c", "b")).build();
assertCollectionsEqual(s1.toCollection(), s2.toCollection());
assertCollectionsEqual(s1.toList(), s2.toList());
assertCollectionsEqual(Lists.newArrayList(s1), Lists.newArrayList(s2));
}
@Test
public void mixedAddAllOrdering() {
NestedSet s1 = prepareBuilder().add("a").add("b").add("c").add("d").build();
NestedSet s2 = prepareBuilder().add("a").addAll(ImmutableList.of("b", "c")).add("d")
.build();
assertCollectionsEqual(s1.toCollection(), s2.toCollection());
assertCollectionsEqual(s1.toList(), s2.toList());
assertCollectionsEqual(Lists.newArrayList(s1), Lists.newArrayList(s2));
}
@Test
public void transitiveDepsHandledSeparately() {
NestedSet subset = prepareBuilder("c", "a", "e").build();
NestedSetBuilder 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 s = b.build();
assertSetContents(nestedResult(), s);
}
@Test
public void nestingNoDuplicates() {
NestedSet subset = prepareBuilder("c", "a", "e").build();
NestedSet s = prepareBuilder("b", "d", "e").addTransitive(subset).build();
assertSetContents(nestedDuplicatesResult(), s);
}
@Test
public void chain() {
NestedSet c = prepareBuilder("c").build();
NestedSet b = prepareBuilder("b").addTransitive(c).build();
NestedSet a = prepareBuilder("a").addTransitive(b).build();
assertSetContents(chainResult(), a);
}
@Test
public void diamond() {
NestedSet d = prepareBuilder("d").build();
NestedSet c = prepareBuilder("c").addTransitive(d).build();
NestedSet b = prepareBuilder("b").addTransitive(d).build();
NestedSet a = prepareBuilder("a").addTransitive(b).addTransitive(c).build();
assertSetContents(diamondResult(), a);
}
@Test
public void extendedDiamond() {
NestedSet d = prepareBuilder("d").build();
NestedSet e = prepareBuilder("e").build();
NestedSet b = prepareBuilder("b").addTransitive(d).addTransitive(e).build();
NestedSet c = prepareBuilder("c").addTransitive(e).addTransitive(d).build();
NestedSet a = prepareBuilder("a").addTransitive(b).addTransitive(c).build();
assertSetContents(extendedDiamondResult(), a);
}
@Test
public void extendedDiamondRightArm() {
NestedSet d = prepareBuilder("d").build();
NestedSet e = prepareBuilder("e").build();
NestedSet b = prepareBuilder("b").addTransitive(d).addTransitive(e).build();
NestedSet c2 = prepareBuilder("c2").addTransitive(e).addTransitive(d).build();
NestedSet c = prepareBuilder("c").addTransitive(c2).build();
NestedSet a = prepareBuilder("a").addTransitive(b).addTransitive(c).build();
assertSetContents(extendedDiamondRightArmResult(), a);
}
@Test
public void orderConflict() {
NestedSet child1 = prepareBuilder("a", "b").build();
NestedSet child2 = prepareBuilder("b", "a").build();
NestedSet parent = prepareBuilder().addTransitive(child1).addTransitive(child2).build();
assertSetContents(orderConflictResult(), parent);
}
@Test
public void orderConflictNested() {
NestedSet a = prepareBuilder("a").build();
NestedSet b = prepareBuilder("b").build();
NestedSet child1 = prepareBuilder().addTransitive(a).addTransitive(b).build();
NestedSet child2 = prepareBuilder().addTransitive(b).addTransitive(a).build();
NestedSet parent = prepareBuilder().addTransitive(child1).addTransitive(child2).build();
assertSetContents(orderConflictResult(), parent);
}
@Test
public void getOrderingEmpty() {
NestedSet s = prepareBuilder().build();
assertThat(s.isEmpty()).isTrue();
assertThat(s.getOrder()).isEqualTo(expanderOrder());
}
@Test
public void getOrdering() {
NestedSet s = prepareBuilder("a", "b").build();
assertThat(s.isEmpty()).isFalse();
assertThat(s.getOrder()).isEqualTo(expanderOrder());
}
@Test
public void nestingValidation() {
for (Order ordering : Order.values()) {
NestedSet a = prepareBuilder("a", "b").build();
NestedSetBuilder 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 prepareBuilder(String... directMembers) {
NestedSetBuilder builder = new NestedSetBuilder<>(expanderOrder());
builder.addAll(Lists.newArrayList(directMembers));
return builder;
}
protected final void assertSetContents(Collection expected, NestedSet set) {
assertThat(Lists.newArrayList(set)).isEqualTo(expected);
assertThat(Lists.newArrayList(set.toCollection())).isEqualTo(expected);
assertThat(Lists.newArrayList(set.toList())).isEqualTo(expected);
assertThat(Lists.newArrayList(set.toSet())).isEqualTo(expected);
}
protected final void assertCollectionsEqual(
Collection expected, Collection 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 #testSimple()
* @see #testSimpleNoDuplicates()
*/
protected List 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 #testNesting()
*/
protected abstract List nestedResult();
/**
* Returns the enumeration of the nested set {"b", "d", "e", {"c", "a", "e"}} in
* the implementation's enumeration order.
*
* @see #testNestingNoDuplicates()
*/
protected abstract List nestedDuplicatesResult();
/**
* Returns the enumeration of nested set {"a", {"b", {"c"}}} in the
* implementation's enumeration order.
*
* @see #testChain()
*/
protected abstract List chainResult();
/**
* Returns the enumeration of the nested set {"a", {"b", D}, {"c", D}}, where
* D is {"d"}, in the implementation's enumeration order.
*
* @see #testDiamond()
*/
protected abstract List 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 #testExtendedDiamond()
*/
protected abstract List 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 #testExtendedDiamondRightArm()
*/
protected abstract List extendedDiamondRightArmResult();
/**
* Returns the enumeration of the nested set {{"a", "b"}, {"b", "a"}}.
*
* @see #testOrderConflict()
* @see #testOrderConflictNested()
*/
protected List orderConflictResult() {
return ImmutableList.of("a", "b");
}
}