| // 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.collect.nestedset; |
| |
| import static com.google.common.truth.Truth.assertThat; |
| import static org.junit.Assert.assertThrows; |
| |
| import com.google.common.collect.ImmutableList; |
| import com.google.devtools.build.lib.collect.nestedset.Depset.ElementType; |
| import com.google.devtools.build.lib.syntax.Dict; |
| import com.google.devtools.build.lib.syntax.Sequence; |
| import com.google.devtools.build.lib.syntax.StarlarkCallable; |
| import com.google.devtools.build.lib.syntax.StarlarkIterable; |
| import com.google.devtools.build.lib.syntax.StarlarkList; |
| import com.google.devtools.build.lib.syntax.StarlarkValue; |
| import com.google.devtools.build.lib.syntax.Tuple; |
| import com.google.devtools.build.lib.syntax.util.EvaluationTestCase; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Tests for Depset. */ |
| @RunWith(JUnit4.class) |
| public final class DepsetTest { |
| |
| private final EvaluationTestCase ev = new EvaluationTestCase(); |
| |
| @Test |
| public void testConstructor() throws Exception { |
| ev.exec("s = depset(order='default')"); |
| assertThat(ev.lookup("s")).isInstanceOf(Depset.class); |
| } |
| |
| private static final ElementType TUPLE = ElementType.of(Tuple.class); |
| |
| @Test |
| public void testTuples() throws Exception { |
| ev.exec( |
| "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])", |
| "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])"); // note, tuple of int |
| assertThat(get("s_one").getElementType()).isEqualTo(TUPLE); |
| assertThat(get("s_two").getElementType()).isEqualTo(TUPLE); |
| assertThat(get("s_three").getElementType()).isEqualTo(TUPLE); |
| assertThat(get("s_eight").getElementType()).isEqualTo(TUPLE); |
| |
| assertThat(get("s_four").getSet(Tuple.class).toList()) |
| .containsExactly( |
| Tuple.of("1", "3"), Tuple.of("1", "2"), Tuple.of("3", "4"), Tuple.of("5", "6")); |
| assertThat(get("s_five").getSet(Tuple.class).toList()) |
| .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).toList()) |
| .containsExactly( |
| Tuple.of(1, 3), Tuple.of("1", "2"), Tuple.of("3", "4"), Tuple.of("5", "6")); |
| } |
| |
| @Test |
| public void testGetSet() throws Exception { |
| ev.exec("s = depset(['a', 'b'])"); |
| assertThat(get("s").getSet(String.class).toList()).containsExactly("a", "b").inOrder(); |
| assertThat(get("s").getSet(Object.class).toList()).containsExactly("a", "b").inOrder(); |
| assertThrows(Depset.TypeException.class, () -> get("s").getSet(Integer.class)); |
| |
| // getSet argument must be a legal Starlark value class, or Object, |
| // but not some superclass that doesn't implement StarlarkValue. |
| Depset ints = Depset.legacyOf(Order.STABLE_ORDER, Tuple.of(1, 2, 3)); |
| assertThat(ints.getSet(Integer.class).toString()).isEqualTo("[1, 2, 3]"); |
| IllegalArgumentException ex = |
| assertThrows(IllegalArgumentException.class, () -> ints.getSet(Number.class)); |
| assertThat(ex.getMessage()).contains("Number is not a subclass of StarlarkValue"); |
| } |
| |
| @Test |
| public void testGetSetDirect() throws Exception { |
| ev.exec("s = depset(direct = ['a', 'b'])"); |
| assertThat(get("s").getSet(String.class).toList()).containsExactly("a", "b").inOrder(); |
| assertThat(get("s").getSet(Object.class).toList()).containsExactly("a", "b").inOrder(); |
| assertThrows(Depset.TypeException.class, () -> get("s").getSet(Integer.class)); |
| } |
| |
| @Test |
| public void testGetSetItems() throws Exception { |
| ev.exec("s = depset(items = ['a', 'b'])"); |
| assertThat(get("s").getSet(String.class).toList()).containsExactly("a", "b").inOrder(); |
| assertThat(get("s").getSet(Object.class).toList()).containsExactly("a", "b").inOrder(); |
| assertThrows(Depset.TypeException.class, () -> get("s").getSet(Integer.class)); |
| } |
| |
| @Test |
| public void testToList() throws Exception { |
| ev.exec("s = depset(['a', 'b'])"); |
| assertThat(get("s").toList(String.class)).containsExactly("a", "b").inOrder(); |
| assertThat(get("s").toList(Object.class)).containsExactly("a", "b").inOrder(); |
| assertThat(get("s").toList()).containsExactly("a", "b").inOrder(); |
| assertThrows(Depset.TypeException.class, () -> get("s").toList(Integer.class)); |
| } |
| |
| @Test |
| public void testToListDirect() throws Exception { |
| ev.exec("s = depset(direct = ['a', 'b'])"); |
| assertThat(get("s").toList(String.class)).containsExactly("a", "b").inOrder(); |
| assertThat(get("s").toList(Object.class)).containsExactly("a", "b").inOrder(); |
| assertThat(get("s").toList()).containsExactly("a", "b").inOrder(); |
| assertThrows(Depset.TypeException.class, () -> get("s").toList(Integer.class)); |
| } |
| |
| @Test |
| public void testToListItems() throws Exception { |
| ev.exec("s = depset(items = ['a', 'b'])"); |
| assertThat(get("s").toList(String.class)).containsExactly("a", "b").inOrder(); |
| assertThat(get("s").toList(Object.class)).containsExactly("a", "b").inOrder(); |
| assertThat(get("s").toList()).containsExactly("a", "b").inOrder(); |
| assertThrows(Depset.TypeException.class, () -> get("s").toList(Integer.class)); |
| } |
| |
| @Test |
| public void testOrder() throws Exception { |
| ev.exec("s = depset(['a', 'b'], order='postorder')"); |
| assertThat(get("s").getSet(String.class).getOrder()).isEqualTo(Order.COMPILE_ORDER); |
| } |
| |
| @Test |
| public void testOrderDirect() throws Exception { |
| ev.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 { |
| ev.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 { |
| ev.new Scenario() |
| .testIfExactError("Invalid order: non_existing", "depset(['a'], order='non_existing')"); |
| } |
| |
| @Test |
| public void testBadOrderDirect() throws Exception { |
| ev.new Scenario() |
| .testIfExactError( |
| "Invalid order: non_existing", "depset(direct = ['a'], order='non_existing')"); |
| } |
| |
| @Test |
| public void testBadOrderItems() throws Exception { |
| ev.new Scenario() |
| .testIfExactError( |
| "Invalid order: non_existing", "depset(items = ['a'], order='non_existing')"); |
| } |
| |
| @Test |
| public void testEmptyGenericType() throws Exception { |
| ev.exec("s = depset()"); |
| assertThat(get("s").getElementType()).isEqualTo(ElementType.EMPTY); |
| } |
| |
| @Test |
| public void testHomogeneousGenericType() throws Exception { |
| ev.exec("s = depset(['a', 'b', 'c'])"); |
| assertThat(get("s").getElementType()).isEqualTo(ElementType.STRING); |
| } |
| |
| @Test |
| public void testHomogeneousGenericTypeDirect() throws Exception { |
| ev.exec("s = depset(['a', 'b', 'c'], transitive = [])"); |
| assertThat(get("s").getElementType()).isEqualTo(ElementType.STRING); |
| } |
| |
| @Test |
| public void testHomogeneousGenericTypeItems() throws Exception { |
| ev.exec("s = depset(items = ['a', 'b', 'c'], transitive = [])"); |
| assertThat(get("s").getElementType()).isEqualTo(ElementType.STRING); |
| } |
| |
| @Test |
| public void testHomogeneousGenericTypeTransitive() throws Exception { |
| ev.exec("s = depset(['a', 'b', 'c'], transitive = [depset(['x'])])"); |
| assertThat(get("s").getElementType()).isEqualTo(ElementType.STRING); |
| } |
| |
| @Test |
| public void testTransitiveIncompatibleOrder() throws Exception { |
| ev.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 { |
| ev.new Scenario() |
| .testIfExactError( |
| "cannot add an item of type 'int' to a depset of 'string'", "depset(['a', 5])"); |
| } |
| |
| @Test |
| public void testBadGenericTypeDirect() throws Exception { |
| ev.new Scenario() |
| .testIfExactError( |
| "cannot add an item of type 'int' to a depset of 'string'", |
| "depset(direct = ['a', 5])"); |
| } |
| |
| @Test |
| public void testBadGenericTypeItems() throws Exception { |
| ev.new Scenario() |
| .testIfExactError( |
| "cannot add an item of type 'int' to a depset of 'string'", "depset(items = ['a', 5])"); |
| } |
| |
| @Test |
| public void testBadGenericTypeTransitive() throws Exception { |
| ev.new Scenario() |
| .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 { |
| ev.new Scenario() |
| .testIfExactError( |
| "Do not pass both 'direct' and 'items' argument to depset constructor.", |
| "depset(['a', 'b'], direct = ['c', 'd'])"); |
| } |
| |
| @Test |
| public void testItemsAndTransitive() throws Exception { |
| ev.new Scenario() |
| .testIfExactError( |
| "for items, got depset, want sequence", |
| "depset(items = depset(), transitive = [depset()])"); |
| } |
| |
| @Test |
| public void testTooManyPositionals() throws Exception { |
| ev.new Scenario() |
| .testIfErrorContains( |
| "depset() accepts 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 { |
| ev.new Scenario() |
| .testIfErrorContains("unsupported binary operation: depset + list", "depset([]) + ['a']"); |
| |
| ev.new Scenario() |
| .testIfErrorContains("unsupported binary operation: depset | list", "depset([]) | ['a']"); |
| } |
| |
| private void assertContainsInOrder(String statement, Object... expectedElements) |
| throws Exception { |
| assertThat(((Depset) ev.eval(statement)).toList()).containsExactly(expectedElements).inOrder(); |
| } |
| |
| @Test |
| public void testToString() throws Exception { |
| ev.exec("s = depset([3, 4, 5], transitive = [depset([2, 4, 6])])", "x = str(s)"); |
| assertThat(ev.lookup("x")).isEqualTo("depset([2, 4, 6, 3, 5])"); |
| } |
| |
| @Test |
| public void testToStringWithOrder() throws Exception { |
| ev.exec( |
| "s = depset([3, 4, 5], transitive = [depset([2, 4, 6])], ", |
| " order = 'topological')", |
| "x = str(s)"); |
| assertThat(ev.lookup("x")).isEqualTo("depset([3, 5, 6, 4, 2], order = \"topological\")"); |
| } |
| |
| private Depset get(String varname) throws Exception { |
| return (Depset) ev.lookup(varname); |
| } |
| |
| @Test |
| public void testToListForStarlark() throws Exception { |
| ev.exec("s = depset([3, 4, 5], transitive = [depset([2, 4, 6])])", "x = s.to_list()"); |
| Object value = ev.lookup("x"); |
| assertThat(value).isInstanceOf(StarlarkList.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()) { |
| Depset s1 = Depset.legacyOf(first, Tuple.of("1", "11")); |
| |
| for (Order second : Order.values()) { |
| Depset s2 = Depset.legacyOf(second, Tuple.of("2", "22")); |
| |
| boolean compatible = true; |
| |
| try { |
| // merge |
| Depset.fromDirectAndTransitive( |
| first, |
| /*direct=*/ ImmutableList.of(), |
| /*transitive=*/ ImmutableList.of(s1, s2), |
| /*strict=*/ true); |
| } catch (Exception ex) { |
| compatible = false; |
| } |
| |
| assertThat(compatible).isEqualTo(areOrdersCompatible(first, second)); |
| } |
| } |
| } |
| |
| private static boolean areOrdersCompatible(Order first, Order second) { |
| return first == Order.STABLE_ORDER || second == Order.STABLE_ORDER || first == second; |
| } |
| |
| @Test |
| public void testMutableDepsetElementsLegacyBehavior() throws Exception { |
| // See b/144992997 and github.com/bazelbuild/bazel/issues/10313. |
| ev.setSemantics("--incompatible_always_check_depset_elements=false"); |
| |
| // Test legacy depset(...) and new depset(direct=...) constructors. |
| |
| // mutable list should be an error |
| ev.checkEvalError("depset elements must not be mutable values", "depset([[1,2,3]])"); |
| ev.checkEvalError("depsets cannot contain items of type 'list'", "depset(direct=[[1,2,3]])"); |
| |
| // struct containing mutable list should be an error |
| ev.checkEvalError("depset elements must not be mutable values", "depset([struct(a=[])])"); |
| ev.eval("depset(direct=[struct(a=[])])"); // no error (!) |
| |
| // tuple of frozen list currently gives no error (this may change) |
| ev.update("x", StarlarkList.empty()); |
| ev.eval("depset([(x,)])"); |
| ev.eval("depset(direct=[(x,)])"); |
| |
| // any list (even frozen) is an error, even with legacy constructor |
| ev.checkEvalError("depsets cannot contain items of type 'list'", "depset([x])"); |
| ev.checkEvalError("depsets cannot contain items of type 'list'", "depset(direct=[x])"); |
| |
| // toplevel dict is an error, even with legacy constructor |
| ev.checkEvalError("depset elements must not be mutable values", "depset([{}])"); |
| ev.checkEvalError("depsets cannot contain items of type 'dict'", "depset(direct=[{}])"); |
| |
| // struct containing dict should be an error |
| ev.checkEvalError("depset elements must not be mutable values", "depset([struct(a={})])"); |
| ev.eval("depset(direct=[struct(a={})])"); // no error (!) |
| } |
| |
| @Test |
| public void testMutableDepsetElementsDesiredBehavior() throws Exception { |
| // See b/144992997 and github.com/bazelbuild/bazel/issues/10313. |
| ev.setSemantics("--incompatible_always_check_depset_elements=true"); |
| |
| // Test legacy depset(...) and new depset(direct=...) constructors. |
| |
| // mutable list should be an error |
| ev.checkEvalError("depset elements must not be mutable values", "depset([[1,2,3]])"); |
| ev.checkEvalError("depset elements must not be mutable values", "depset(direct=[[1,2,3]])"); |
| |
| // struct containing mutable list should be an error |
| ev.checkEvalError("depset elements must not be mutable values", "depset([struct(a=[])])"); |
| ev.checkEvalError( |
| "depset elements must not be mutable values", "depset(direct=[struct(a=[])])"); |
| |
| // tuple of frozen list currently gives no error (this may change) |
| ev.update("x", StarlarkList.empty()); |
| ev.eval("depset([(x,)])"); |
| ev.eval("depset(direct=[(x,)])"); |
| |
| // any list (even frozen) is an error, even with legacy constructor |
| ev.checkEvalError("depsets cannot contain items of type 'list'", "depset([x,])"); |
| ev.checkEvalError("depsets cannot contain items of type 'list'", "depset(direct=[x,])"); |
| |
| // toplevel dict is an error, even with legacy constructor |
| ev.checkEvalError("depset elements must not be mutable values", "depset([{}])"); |
| ev.checkEvalError("depset elements must not be mutable values", "depset(direct=[{}])"); |
| |
| // struct containing dict should be an error |
| ev.checkEvalError("depset elements must not be mutable values", "depset([struct(a={})])"); |
| ev.checkEvalError( |
| "depset elements must not be mutable values", "depset(direct=[struct(a={})])"); |
| } |
| |
| @Test |
| public void testDepthExceedsLimitDuringIteration() throws Exception { |
| NestedSet.setApplicationDepthLimit(2000); |
| ev.new Scenario() |
| .setUp( |
| "def create_depset(depth):", |
| " x = depset([0])", |
| " for i in range(1, depth):", |
| " x = depset([i], transitive = [x])", |
| " for element in x.to_list():", |
| " str(x)", |
| " return None") |
| .testEval("create_depset(1000)", "None") |
| .testIfErrorContains("depset exceeded maximum depth", "create_depset(3000)"); |
| } |
| |
| @Test |
| public void testElementTypeOf() { |
| // legal values |
| assertThat(ElementType.of(String.class).toString()).isEqualTo("string"); |
| assertThat(ElementType.of(Integer.class).toString()).isEqualTo("int"); |
| assertThat(ElementType.of(Boolean.class).toString()).isEqualTo("bool"); |
| |
| // concrete non-values |
| assertThrows(IllegalArgumentException.class, () -> ElementType.of(Float.class)); |
| |
| // concrete classes that implement StarlarkValue |
| assertThat(ElementType.of(StarlarkList.class).toString()).isEqualTo("list"); |
| assertThat(ElementType.of(Tuple.class).toString()).isEqualTo("tuple"); |
| assertThat(ElementType.of(Dict.class).toString()).isEqualTo("dict"); |
| class V implements StarlarkValue {} // no StarlarkModule annotation |
| assertThat(ElementType.of(V.class).toString()).isEqualTo("V"); |
| |
| // abstract classes that implement StarlarkValue |
| assertThat(ElementType.of(Sequence.class).toString()).isEqualTo("sequence"); |
| assertThat(ElementType.of(StarlarkCallable.class).toString()).isEqualTo("function"); |
| assertThat(ElementType.of(StarlarkIterable.class).toString()).isEqualTo("StarlarkIterable"); |
| |
| // superclasses of legal values that aren't values themselves |
| assertThrows(IllegalArgumentException.class, () -> ElementType.of(Number.class)); |
| assertThrows(IllegalArgumentException.class, () -> ElementType.of(CharSequence.class)); |
| assertThrows(IllegalArgumentException.class, () -> ElementType.of(Object.class)); |
| } |
| |
| @Test |
| public void testSetComparison() throws Exception { |
| ev.new Scenario() |
| .testIfExactError("Cannot compare depset with depset", "depset([1, 2]) < depset([3, 4])"); |
| } |
| |
| @Test |
| public void testDepsetItemsKeywordAndPositional() throws Exception { |
| ev.new Scenario("--incompatible_disable_depset_items=false") |
| .testIfErrorContains( |
| "parameter 'items' cannot be specified both positionally and by keyword", |
| "depset([0, 1], 'default', items=[0,1])"); |
| } |
| |
| @Test |
| public void testDepsetDirectInvalidType() throws Exception { |
| ev.new Scenario() |
| .testIfErrorContains("for direct, got string, want sequence", "depset(direct='hello')"); |
| } |
| |
| @Test |
| public void testDisableDepsetItems() throws Exception { |
| ev.new Scenario("--incompatible_disable_depset_items") |
| .setUp("x = depset([0])", "y = depset(direct = [1])") |
| .testEval("depset([2, 3], transitive = [x, y]).to_list()", "[0, 1, 2, 3]") |
| .testIfErrorContains( |
| "parameter 'direct' cannot be specified both positionally and by keyword", |
| "depset([0, 1], 'default', direct=[0,1])") |
| .testIfErrorContains( |
| "in call to depset(), parameter 'items' is deprecated and will be removed soon. " |
| + "It may be temporarily re-enabled by setting " |
| + "--incompatible_disable_depset_inputs=false", |
| "depset(items=[0,1])"); |
| } |
| |
| @Test |
| public void testDepsetDepthLimit() throws Exception { |
| NestedSet.setApplicationDepthLimit(2000); |
| ev.new Scenario() |
| .setUp( |
| "def create_depset(depth):", |
| " x = depset([0])", |
| " for i in range(1, depth):", |
| " x = depset([i], transitive = [x])", |
| " return x", |
| "too_deep_depset = create_depset(3000)", |
| "fine_depset = create_depset(900)") |
| .testEval("fine_depset.to_list()[0]", "0") |
| .testEval("str(fine_depset)[0:6]", "'depset'") |
| .testIfErrorContains("depset exceeded maximum depth", "print(too_deep_depset)") |
| .testIfErrorContains("depset exceeded maximum depth", "str(too_deep_depset)") |
| .testIfErrorContains("depset exceeded maximum depth", "too_deep_depset.to_list()"); |
| } |
| |
| @Test |
| public void testDepsetDebugDepth() throws Exception { |
| NestedSet.setApplicationDepthLimit(2000); |
| ev.new Scenario("--debug_depset_depth=true") |
| .setUp( |
| "def create_depset(depth):", |
| " x = depset([0])", |
| " for i in range(1, depth):", |
| " x = depset([i], transitive = [x])", |
| " return x") |
| .testEval("str(create_depset(900))[0:6]", "'depset'") |
| .testIfErrorContains("depset exceeded maximum depth", "create_depset(3000)"); |
| } |
| } |