| // Copyright 2015 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.syntax; | |
| import static com.google.common.truth.Truth.assertThat; | |
| import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows; | |
| import com.google.common.collect.ImmutableList; | |
| import com.google.devtools.build.lib.collect.nestedset.NestedSet; | |
| import com.google.devtools.build.lib.collect.nestedset.Order; | |
| import com.google.devtools.build.lib.syntax.SkylarkList.MutableList; | |
| import com.google.devtools.build.lib.syntax.util.EvaluationTestCase; | |
| import java.util.Arrays; | |
| import java.util.HashMap; | |
| import java.util.List; | |
| import java.util.Map; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.junit.runners.JUnit4; | |
| /** | |
| * Tests for SkylarkNestedSet. | |
| */ | |
| @RunWith(JUnit4.class) | |
| public class SkylarkNestedSetTest extends EvaluationTestCase { | |
| @Test | |
| public void testConstructor() throws Exception { | |
| exec("s = depset(order='default')"); | |
| assertThat(lookup("s")).isInstanceOf(SkylarkNestedSet.class); | |
| } | |
| @Test | |
| public void testTuplePairs() throws Exception { | |
| exec( | |
| // Depsets with tuple-pairs | |
| "s_one = depset([('1', '2'), ('3', '4')])", | |
| "s_two = depset(direct = [('1', '2'), ('3', '4'), ('5', '6')])", | |
| "s_three = depset(transitive = [s_one, s_two])", | |
| "s_four = depset(direct = [('1', '3')], transitive = [s_one, s_two])", | |
| // Depsets with tuple-pairs and non-pair tuples are considered just tuple depsets. | |
| "s_five = depset(direct = [('1', '3', '5')], transitive = [s_one, s_two])", | |
| "s_six = depset(transitive = [s_one, s_five])", | |
| "s_seven = depset(direct = [('1', '3')], transitive = [s_one, s_five])", | |
| "s_eight = depset(direct = [(1, 3)], transitive = [s_one, s_two])"); | |
| assertThat(get("s_one").getContentType()).isEqualTo(SkylarkType.STRING_PAIR); | |
| assertThat(get("s_two").getContentType()).isEqualTo(SkylarkType.STRING_PAIR); | |
| assertThat(get("s_three").getContentType()).isEqualTo(SkylarkType.STRING_PAIR); | |
| assertThat(get("s_four").getContentType()).isEqualTo(SkylarkType.STRING_PAIR); | |
| assertThat(get("s_five").getContentType()).isEqualTo(SkylarkType.TUPLE); | |
| assertThat(get("s_six").getContentType()).isEqualTo(SkylarkType.TUPLE); | |
| assertThat(get("s_seven").getContentType()).isEqualTo(SkylarkType.TUPLE); | |
| assertThat(get("s_eight").getContentType()).isEqualTo(SkylarkType.TUPLE); | |
| assertThat(get("s_four").getSet(Tuple.class)) | |
| .containsExactly( | |
| Tuple.of("1", "3"), Tuple.of("1", "2"), Tuple.of("3", "4"), Tuple.of("5", "6")); | |
| assertThat(get("s_five").getSet(Tuple.class)) | |
| .containsExactly( | |
| Tuple.of("1", "3", "5"), Tuple.of("1", "2"), Tuple.of("3", "4"), Tuple.of("5", "6")); | |
| assertThat(get("s_eight").getSet(Tuple.class)) | |
| .containsExactly( | |
| Tuple.of(1, 3), Tuple.of("1", "2"), Tuple.of("3", "4"), Tuple.of("5", "6")); | |
| } | |
| @Test | |
| public void testGetSet() throws Exception { | |
| exec("s = depset(['a', 'b'])"); | |
| assertThat(get("s").getSet(String.class)).containsExactly("a", "b").inOrder(); | |
| assertThat(get("s").getSet(Object.class)).containsExactly("a", "b").inOrder(); | |
| assertThrows(SkylarkNestedSet.TypeException.class, () -> get("s").getSet(Integer.class)); | |
| } | |
| @Test | |
| public void testGetSetDirect() throws Exception { | |
| exec("s = depset(direct = ['a', 'b'])"); | |
| assertThat(get("s").getSet(String.class)).containsExactly("a", "b").inOrder(); | |
| assertThat(get("s").getSet(Object.class)).containsExactly("a", "b").inOrder(); | |
| assertThrows(SkylarkNestedSet.TypeException.class, () -> get("s").getSet(Integer.class)); | |
| } | |
| @Test | |
| public void testGetSetItems() throws Exception { | |
| exec("s = depset(items = ['a', 'b'])"); | |
| assertThat(get("s").getSet(String.class)).containsExactly("a", "b").inOrder(); | |
| assertThat(get("s").getSet(Object.class)).containsExactly("a", "b").inOrder(); | |
| assertThrows(SkylarkNestedSet.TypeException.class, () -> get("s").getSet(Integer.class)); | |
| } | |
| @Test | |
| public void testToCollection() throws Exception { | |
| exec("s = depset(['a', 'b'])"); | |
| assertThat(get("s").toCollection(String.class)).containsExactly("a", "b").inOrder(); | |
| assertThat(get("s").toCollection(Object.class)).containsExactly("a", "b").inOrder(); | |
| assertThat(get("s").toCollection()).containsExactly("a", "b").inOrder(); | |
| assertThrows(SkylarkNestedSet.TypeException.class, () -> get("s").toCollection(Integer.class)); | |
| } | |
| @Test | |
| public void testToCollectionDirect() throws Exception { | |
| exec("s = depset(direct = ['a', 'b'])"); | |
| assertThat(get("s").toCollection(String.class)).containsExactly("a", "b").inOrder(); | |
| assertThat(get("s").toCollection(Object.class)).containsExactly("a", "b").inOrder(); | |
| assertThat(get("s").toCollection()).containsExactly("a", "b").inOrder(); | |
| assertThrows(SkylarkNestedSet.TypeException.class, () -> get("s").toCollection(Integer.class)); | |
| } | |
| @Test | |
| public void testToCollectionItems() throws Exception { | |
| exec("s = depset(items = ['a', 'b'])"); | |
| assertThat(get("s").toCollection(String.class)).containsExactly("a", "b").inOrder(); | |
| assertThat(get("s").toCollection(Object.class)).containsExactly("a", "b").inOrder(); | |
| assertThat(get("s").toCollection()).containsExactly("a", "b").inOrder(); | |
| assertThrows(SkylarkNestedSet.TypeException.class, () -> get("s").toCollection(Integer.class)); | |
| } | |
| @Test | |
| public void testOrder() throws Exception { | |
| exec("s = depset(['a', 'b'], order='postorder')"); | |
| assertThat(get("s").getSet(String.class).getOrder()).isEqualTo(Order.COMPILE_ORDER); | |
| } | |
| @Test | |
| public void testOrderDirect() throws Exception { | |
| exec("s = depset(direct = ['a', 'b'], order='postorder')"); | |
| assertThat(get("s").getSet(String.class).getOrder()).isEqualTo(Order.COMPILE_ORDER); | |
| } | |
| @Test | |
| public void testOrderItems() throws Exception { | |
| exec("s = depset(items = ['a', 'b'], order='postorder')"); | |
| assertThat(get("s").getSet(String.class).getOrder()).isEqualTo(Order.COMPILE_ORDER); | |
| } | |
| @Test | |
| public void testBadOrder() throws Exception { | |
| new BothModesTest().testIfExactError( | |
| "Invalid order: non_existing", | |
| "depset(['a'], order='non_existing')"); | |
| } | |
| @Test | |
| public void testBadOrderDirect() throws Exception { | |
| new BothModesTest().testIfExactError( | |
| "Invalid order: non_existing", | |
| "depset(direct = ['a'], order='non_existing')"); | |
| } | |
| @Test | |
| public void testBadOrderItems() throws Exception { | |
| new BothModesTest().testIfExactError( | |
| "Invalid order: non_existing", | |
| "depset(items = ['a'], order='non_existing')"); | |
| } | |
| @Test | |
| public void testEmptyGenericType() throws Exception { | |
| exec("s = depset()"); | |
| assertThat(get("s").getContentType()).isEqualTo(SkylarkType.TOP); | |
| } | |
| @Test | |
| public void testHomogeneousGenericType() throws Exception { | |
| exec("s = depset(['a', 'b', 'c'])"); | |
| assertThat(get("s").getContentType()).isEqualTo(SkylarkType.of(String.class)); | |
| } | |
| @Test | |
| public void testHomogeneousGenericTypeDirect() throws Exception { | |
| exec("s = depset(['a', 'b', 'c'], transitive = [])"); | |
| assertThat(get("s").getContentType()).isEqualTo(SkylarkType.of(String.class)); | |
| } | |
| @Test | |
| public void testHomogeneousGenericTypeItems() throws Exception { | |
| exec("s = depset(items = ['a', 'b', 'c'], transitive = [])"); | |
| assertThat(get("s").getContentType()).isEqualTo(SkylarkType.of(String.class)); | |
| } | |
| @Test | |
| public void testHomogeneousGenericTypeTransitive() throws Exception { | |
| exec("s = depset(['a', 'b', 'c'], transitive = [depset(['x'])])"); | |
| assertThat(get("s").getContentType()).isEqualTo(SkylarkType.of(String.class)); | |
| } | |
| @Test | |
| public void testTransitiveIncompatibleOrder() throws Exception { | |
| checkEvalError( | |
| "Order 'postorder' is incompatible with order 'topological'", | |
| "depset(['a', 'b'], order='postorder',", | |
| " transitive = [depset(['c', 'd'], order='topological')])"); | |
| } | |
| @Test | |
| public void testBadGenericType() throws Exception { | |
| new BothModesTest().testIfExactError( | |
| "cannot add an item of type 'int' to a depset of 'string'", | |
| "depset(['a', 5])"); | |
| } | |
| @Test | |
| public void testBadGenericTypeDirect() throws Exception { | |
| new BothModesTest().testIfExactError( | |
| "cannot add an item of type 'int' to a depset of 'string'", | |
| "depset(direct = ['a', 5])"); | |
| } | |
| @Test | |
| public void testBadGenericTypeItems() throws Exception { | |
| new BothModesTest().testIfExactError( | |
| "cannot add an item of type 'int' to a depset of 'string'", | |
| "depset(items = ['a', 5])"); | |
| } | |
| @Test | |
| public void testBadGenericTypeTransitive() throws Exception { | |
| new BothModesTest().testIfExactError( | |
| "cannot add an item of type 'int' to a depset of 'string'", | |
| "depset(['a', 'b'], transitive=[depset([1])])"); | |
| } | |
| @Test | |
| public void testLegacyAndNewApi() throws Exception { | |
| new BothModesTest().testIfExactError( | |
| "Do not pass both 'direct' and 'items' argument to depset constructor.", | |
| "depset(['a', 'b'], direct = ['c', 'd'])"); | |
| } | |
| @Test | |
| public void testItemsAndTransitive() throws Exception { | |
| new BothModesTest().testIfExactError( | |
| "expected type 'sequence' for items but got type 'depset' instead", | |
| "depset(items = depset(), transitive = [depset()])"); | |
| } | |
| @Test | |
| public void testTooManyPositionals() throws Exception { | |
| new BothModesTest() | |
| .testIfErrorContains( | |
| "expected no more than 2 positional arguments, but got 3", "depset([], 'default', [])"); | |
| } | |
| @Test | |
| public void testTransitiveOrder() throws Exception { | |
| assertContainsInOrder("depset([], transitive=[depset(['a', 'b', 'c'])])", "a", "b", "c"); | |
| assertContainsInOrder("depset(['a'], transitive = [depset(['b', 'c'])])", "b", "c", "a"); | |
| assertContainsInOrder("depset(['a', 'b'], transitive = [depset(['c'])])", "c", "a", "b"); | |
| assertContainsInOrder("depset(['a', 'b', 'c'], transitive = [depset([])])", "a", "b", "c"); | |
| } | |
| @Test | |
| public void testTransitiveOrderItems() throws Exception { | |
| assertContainsInOrder("depset(items=[], transitive=[depset(['a', 'b', 'c'])])", "a", "b", "c"); | |
| assertContainsInOrder("depset(items=['a'], transitive = [depset(['b', 'c'])])", "b", "c", "a"); | |
| assertContainsInOrder("depset(items=['a', 'b'], transitive = [depset(['c'])])", "c", "a", "b"); | |
| assertContainsInOrder("depset(items=['a', 'b', 'c'], transitive = [depset([])])", | |
| "a", "b", "c"); | |
| } | |
| @Test | |
| public void testTransitiveOrderDirect() throws Exception { | |
| assertContainsInOrder("depset(direct=[], transitive=[depset(['a', 'b', 'c'])])", "a", "b", "c"); | |
| assertContainsInOrder("depset(direct=['a'], transitive = [depset(['b', 'c'])])", "b", "c", "a"); | |
| assertContainsInOrder("depset(direct=['a', 'b'], transitive = [depset(['c'])])", "c", "a", "b"); | |
| assertContainsInOrder("depset(direct=['a', 'b', 'c'], transitive = [depset([])])", | |
| "a", "b", "c"); | |
| } | |
| @Test | |
| public void testIncompatibleUnion() throws Exception { | |
| new BothModesTest("--incompatible_depset_union=true") | |
| .testIfErrorContains( | |
| "depset method `.union` has been removed", "depset([]).union(['a', 'b', 'c'])"); | |
| new BothModesTest("--incompatible_depset_union=true") | |
| .testIfErrorContains("`+` operator on a depset is forbidden", "depset([]) + ['a']"); | |
| new BothModesTest("--incompatible_depset_union=true") | |
| .testIfErrorContains("`|` operator on a depset is forbidden", "depset([]) | ['a']"); | |
| } | |
| @Test | |
| public void testUnionWithList() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| assertContainsInOrder("depset([]).union(['a', 'b', 'c'])", "a", "b", "c"); | |
| assertContainsInOrder("depset(['a']).union(['b', 'c'])", "a", "b", "c"); | |
| assertContainsInOrder("depset(['a', 'b']).union(['c'])", "a", "b", "c"); | |
| assertContainsInOrder("depset(['a', 'b', 'c']).union([])", "a", "b", "c"); | |
| } | |
| @Test | |
| public void testUnionWithDepset() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| assertContainsInOrder("depset([]).union(depset(['a', 'b', 'c']))", "a", "b", "c"); | |
| assertContainsInOrder("depset(['a']).union(depset(['b', 'c']))", "b", "c", "a"); | |
| assertContainsInOrder("depset(['a', 'b']).union(depset(['c']))", "c", "a", "b"); | |
| assertContainsInOrder("depset(['a', 'b', 'c']).union(depset([]))", "a", "b", "c"); | |
| } | |
| @Test | |
| public void testUnionDuplicates() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| assertContainsInOrder("depset(['a', 'b', 'c']).union(['a', 'b', 'c'])", "a", "b", "c"); | |
| assertContainsInOrder("depset(['a', 'a', 'a']).union(['a', 'a'])", "a"); | |
| assertContainsInOrder("depset(['a', 'b', 'c']).union(depset(['a', 'b', 'c']))", "a", "b", "c"); | |
| assertContainsInOrder("depset(['a', 'a', 'a']).union(depset(['a', 'a']))", "a"); | |
| } | |
| private void assertContainsInOrder(String statement, Object... expectedElements) | |
| throws Exception { | |
| assertThat(((SkylarkNestedSet) eval(statement)).toCollection()) | |
| .containsExactly(expectedElements) | |
| .inOrder(); | |
| } | |
| @Test | |
| public void testUnionOrder() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "def func():", | |
| " s1 = depset()", | |
| " s2 = depset()", | |
| " s1 += ['a']", | |
| " s2 += ['b']", | |
| " s1 += s2", | |
| " return s1", | |
| "s = func()"); | |
| assertThat(get("s").toCollection()).containsExactly("b", "a").inOrder(); | |
| } | |
| @Test | |
| public void testUnionIncompatibleOrder() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| checkEvalError( | |
| "Order mismatch: topological != postorder", | |
| "depset(['a', 'b'], order='postorder') + depset(['c', 'd'], order='topological')"); | |
| } | |
| @Test | |
| public void testUnionWithNonsequence() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| checkEvalError("cannot union value of type 'int' to a depset", "depset([]).union(5)"); | |
| checkEvalError("cannot union value of type 'string' to a depset", "depset(['a']).union('b')"); | |
| } | |
| @Test | |
| public void testUnionWrongNumArgs() throws Exception { | |
| new BothModesTest() | |
| .testIfErrorContains( | |
| "parameter 'new_elements' has no default value, " | |
| + "for call to method union(new_elements) of 'depset'", | |
| "depset(['a']).union()"); | |
| } | |
| @Test | |
| public void testUnionNoSideEffects() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "def func():", | |
| " s1 = depset(['a'])", | |
| " s2 = s1.union(['b'])", | |
| " return s1", | |
| "s = func()"); | |
| assertThat(((SkylarkNestedSet) lookup("s")).toCollection()).isEqualTo(ImmutableList.of("a")); | |
| } | |
| @Test | |
| public void testFunctionReturnsDepset() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "def func():", // | |
| " t = depset()", | |
| " t += ['a']", | |
| " return t", | |
| "s = func()"); | |
| assertThat(get("s")).isInstanceOf(SkylarkNestedSet.class); | |
| assertThat(get("s").toCollection()).containsExactly("a"); | |
| } | |
| @Test | |
| public void testPlusEqualsWithList() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "def func():", // | |
| " t = depset()", | |
| " t += ['a', 'b']", | |
| " return t", | |
| "s = func()"); | |
| assertThat(get("s").toCollection()).containsExactly("a", "b").inOrder(); | |
| } | |
| @Test | |
| public void testPlusEqualsNoSideEffects() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "def func():", | |
| " s1 = depset()", | |
| " s1 += ['a']", | |
| " s2 = s1", | |
| " s2 += ['b']", | |
| " return s1", | |
| "s = func()"); | |
| assertThat(get("s").toCollection()).containsExactly("a"); | |
| } | |
| @Test | |
| public void testFuncParamNoSideEffects() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "def func1(t):", | |
| " t += ['b']", | |
| "def func2():", | |
| " u = depset()", | |
| " u += ['a']", | |
| " func1(u)", | |
| " return u", | |
| "s = func2()"); | |
| assertThat(get("s").toCollection()).containsExactly("a"); | |
| } | |
| @Test | |
| public void testTransitiveOrdering() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "def func():", | |
| " sa = depset(['a'], order='postorder')", | |
| " sb = depset(['b'], order='postorder')", | |
| " sc = depset(['c'], order='postorder') + sa", | |
| " return depset() + sb + sc", | |
| "s = func()"); | |
| // The iterator lists the Transitive sets first | |
| assertThat(get("s").toCollection()).containsExactly("b", "a", "c").inOrder(); | |
| } | |
| @Test | |
| public void testLeftRightDirectOrdering() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "def func():", | |
| " t = depset()", | |
| " t += [4]", | |
| " t += [2, 4]", | |
| " t += [3, 4, 5]", | |
| " return t", | |
| "s = func()"); | |
| // All elements are direct. The iterator lists them left-to-right. | |
| assertThat(get("s").toCollection()).containsExactly(4, 2, 3, 5).inOrder(); | |
| } | |
| @Test | |
| public void testToString() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "s = depset() + [2, 4, 6] + [3, 4, 5]", // | |
| "x = str(s)"); | |
| assertThat(lookup("x")).isEqualTo("depset([2, 4, 6, 3, 5])"); | |
| } | |
| @Test | |
| public void testToStringWithOrder() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "s = depset(order = 'topological') + [2, 4, 6] + [3, 4, 5]", // | |
| "x = str(s)"); | |
| assertThat(lookup("x")).isEqualTo("depset([2, 4, 6, 3, 5], order = \"topological\")"); | |
| } | |
| @SuppressWarnings("unchecked") | |
| private SkylarkNestedSet get(String varname) throws Exception { | |
| return (SkylarkNestedSet) lookup(varname); | |
| } | |
| @Test | |
| public void testToList() throws Exception { | |
| thread = newStarlarkThreadWithSkylarkOptions("--incompatible_depset_union=false"); | |
| exec( | |
| "s = depset() + [2, 4, 6] + [3, 4, 5]", // | |
| "x = s.to_list()"); | |
| Object value = lookup("x"); | |
| assertThat(value).isInstanceOf(MutableList.class); | |
| assertThat((Iterable<?>) value).containsExactly(2, 4, 6, 3, 5).inOrder(); | |
| } | |
| @Test | |
| public void testOrderCompatibility() throws Exception { | |
| // Two sets are compatible if | |
| // (a) both have the same order or | |
| // (b) at least one order is "default" | |
| for (Order first : Order.values()) { | |
| SkylarkNestedSet s1 = SkylarkNestedSet.of(first, Tuple.of("1", "11"), null); | |
| for (Order second : Order.values()) { | |
| SkylarkNestedSet s2 = SkylarkNestedSet.of(second, Tuple.of("2", "22"), null); | |
| boolean compatible = true; | |
| try { | |
| SkylarkNestedSet.of(s1, s2, null); | |
| } catch (Exception ex) { | |
| compatible = false; | |
| } | |
| assertThat(compatible).isEqualTo(areOrdersCompatible(first, second)); | |
| } | |
| } | |
| } | |
| private boolean areOrdersCompatible(Order first, Order second) { | |
| return first == Order.STABLE_ORDER || second == Order.STABLE_ORDER || first == second; | |
| } | |
| @Test | |
| public void testOrderComplexUnion() throws Exception { | |
| // {1, 11, {2, 22}, {3, 33}, {4, 44}} | |
| List<String> preOrder = Arrays.asList("1", "11", "2", "22", "3", "33", "4", "44"); | |
| List<String> postOrder = Arrays.asList("2", "22", "3", "33", "4", "44", "1", "11"); | |
| MergeStrategy strategy = | |
| new MergeStrategy() { | |
| @Override | |
| public SkylarkNestedSet merge(SkylarkNestedSet[] sets) throws Exception { | |
| SkylarkNestedSet union = SkylarkNestedSet.of(sets[0], sets[1], null); | |
| union = SkylarkNestedSet.of(union, sets[2], null); | |
| union = SkylarkNestedSet.of(union, sets[3], null); | |
| return union; | |
| } | |
| }; | |
| runComplexOrderTest(strategy, preOrder, postOrder); | |
| } | |
| @Test | |
| public void testOrderBalancedTree() throws Exception { | |
| // {{1, 11, {2, 22}}, {3, 33, {4, 44}}} | |
| List<String> preOrder = Arrays.asList("1", "11", "2", "22", "3", "33", "4", "44"); | |
| List<String> postOrder = Arrays.asList("2", "22", "4", "44", "3", "33", "1", "11"); | |
| MergeStrategy strategy = | |
| new MergeStrategy() { | |
| @Override | |
| public SkylarkNestedSet merge(SkylarkNestedSet[] sets) throws Exception { | |
| SkylarkNestedSet leftUnion = SkylarkNestedSet.of(sets[0], sets[1], null); | |
| SkylarkNestedSet rightUnion = SkylarkNestedSet.of(sets[2], sets[3], null); | |
| SkylarkNestedSet union = SkylarkNestedSet.of(leftUnion, rightUnion, null); | |
| return union; | |
| } | |
| }; | |
| runComplexOrderTest(strategy, preOrder, postOrder); | |
| } | |
| @Test | |
| public void testOrderManyLevelsOfNesting() throws Exception { | |
| // {1, 11, {2, 22, {3, 33, {4, 44}}}} | |
| List<String> preOrder = Arrays.asList("1", "11", "2", "22", "3", "33", "4", "44"); | |
| List<String> postOrder = Arrays.asList("4", "44", "3", "33", "2", "22", "1", "11"); | |
| MergeStrategy strategy = | |
| new MergeStrategy() { | |
| @Override | |
| public SkylarkNestedSet merge(SkylarkNestedSet[] sets) throws Exception { | |
| SkylarkNestedSet union = SkylarkNestedSet.of(sets[2], sets[3], null); | |
| union = SkylarkNestedSet.of(sets[1], union, null); | |
| union = SkylarkNestedSet.of(sets[0], union, null); | |
| return union; | |
| } | |
| }; | |
| runComplexOrderTest(strategy, preOrder, postOrder); | |
| } | |
| @Test | |
| public void testDepthExceedsLimitDuringIteration() throws Exception { | |
| NestedSet.setApplicationDepthLimit(2000); | |
| new SkylarkTest("--incompatible_depset_is_not_iterable=false") | |
| .setUp( | |
| "def create_depset(depth):", | |
| " x = depset([0])", | |
| " for i in range(1, depth):", | |
| " x = depset([i], transitive = [x])", | |
| " for element in x:", | |
| " str(x)", | |
| " return None") | |
| .testEval("create_depset(1000)", "None") | |
| .testIfErrorContains("depset exceeded maximum depth 2000", "create_depset(3000)"); | |
| } | |
| @Test | |
| public void testListComprehensionsWithNestedSet() throws Exception { | |
| new SkylarkTest("--incompatible_depset_is_not_iterable=false") | |
| .testEval("[x + x for x in depset([1, 2, 3])]", "[2, 4, 6]"); | |
| } | |
| private interface MergeStrategy { | |
| SkylarkNestedSet merge(SkylarkNestedSet[] sets) throws Exception; | |
| } | |
| private void runComplexOrderTest( | |
| MergeStrategy strategy, List<String> preOrder, List<String> postOrder) throws Exception { | |
| Map<Order, List<String>> expected = createExpectedMap(preOrder, postOrder); | |
| for (Order order : Order.values()) { | |
| SkylarkNestedSet union = strategy.merge(makeFourSets(order)); | |
| assertThat(union.toCollection()).containsExactlyElementsIn(expected.get(order)).inOrder(); | |
| } | |
| } | |
| private Map<Order, List<String>> createExpectedMap( | |
| List<String> preOrder, List<String> postOrder) { | |
| Map<Order, List<String>> expected = new HashMap<>(); | |
| for (Order order : Order.values()) { | |
| expected.put(order, isPostOrder(order) ? postOrder : preOrder); | |
| } | |
| return expected; | |
| } | |
| private boolean isPostOrder(Order order) { | |
| return order == Order.STABLE_ORDER || order == Order.COMPILE_ORDER; | |
| } | |
| private SkylarkNestedSet[] makeFourSets(Order order) throws Exception { | |
| return new SkylarkNestedSet[] { | |
| SkylarkNestedSet.of(order, Tuple.of("1", "11"), null), | |
| SkylarkNestedSet.of(order, Tuple.of("2", "22"), null), | |
| SkylarkNestedSet.of(order, Tuple.of("3", "33"), null), | |
| SkylarkNestedSet.of(order, Tuple.of("4", "44"), null) | |
| }; | |
| } | |
| } |