blob: 376dffad1b77f5ae5147dd6acb328c4023c736ee [file] [log] [blame]
Colin Cross9e44e212020-07-14 15:02:16 -07001// Copyright 2020 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
18 "fmt"
19 "reflect"
20 "strings"
21 "testing"
22)
23
24func ExampleDepSet_ToList_postordered() {
Colin Crossc85750b2022-04-21 12:50:51 -070025 a := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("a")).Build()
26 b := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("b")).Transitive(a).Build()
27 c := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("c")).Transitive(a).Build()
28 d := NewDepSetBuilder[Path](POSTORDER).Direct(PathForTesting("d")).Transitive(b, c).Build()
Colin Cross9e44e212020-07-14 15:02:16 -070029
Colin Crossc85750b2022-04-21 12:50:51 -070030 fmt.Println(Paths(d.ToList()).Strings())
Colin Cross9e44e212020-07-14 15:02:16 -070031 // Output: [a b c d]
32}
33
34func ExampleDepSet_ToList_preordered() {
Colin Crossc85750b2022-04-21 12:50:51 -070035 a := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("a")).Build()
36 b := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("b")).Transitive(a).Build()
37 c := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("c")).Transitive(a).Build()
38 d := NewDepSetBuilder[Path](PREORDER).Direct(PathForTesting("d")).Transitive(b, c).Build()
Colin Cross9e44e212020-07-14 15:02:16 -070039
Colin Crossc85750b2022-04-21 12:50:51 -070040 fmt.Println(Paths(d.ToList()).Strings())
Colin Cross9e44e212020-07-14 15:02:16 -070041 // Output: [d b a c]
42}
43
44func ExampleDepSet_ToList_topological() {
Colin Crossc85750b2022-04-21 12:50:51 -070045 a := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("a")).Build()
46 b := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("b")).Transitive(a).Build()
47 c := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("c")).Transitive(a).Build()
48 d := NewDepSetBuilder[Path](TOPOLOGICAL).Direct(PathForTesting("d")).Transitive(b, c).Build()
Colin Cross9e44e212020-07-14 15:02:16 -070049
Colin Crossc85750b2022-04-21 12:50:51 -070050 fmt.Println(Paths(d.ToList()).Strings())
Colin Cross9e44e212020-07-14 15:02:16 -070051 // Output: [d b c a]
52}
53
Colin Cross9e44e212020-07-14 15:02:16 -070054// Tests based on Bazel's ExpanderTestBase.java to ensure compatibility
55// https://github.com/bazelbuild/bazel/blob/master/src/test/java/com/google/devtools/build/lib/collect/nestedset/ExpanderTestBase.java
56func TestDepSet(t *testing.T) {
57 a := PathForTesting("a")
58 b := PathForTesting("b")
59 c := PathForTesting("c")
60 c2 := PathForTesting("c2")
61 d := PathForTesting("d")
62 e := PathForTesting("e")
63
64 tests := []struct {
65 name string
Colin Crossc85750b2022-04-21 12:50:51 -070066 depSet func(t *testing.T, order DepSetOrder) *DepSet[Path]
Colin Cross9e44e212020-07-14 15:02:16 -070067 postorder, preorder, topological []string
68 }{
69 {
70 name: "simple",
Colin Crossc85750b2022-04-21 12:50:51 -070071 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
72 return NewDepSet[Path](order, Paths{c, a, b}, nil)
Colin Cross9e44e212020-07-14 15:02:16 -070073 },
74 postorder: []string{"c", "a", "b"},
75 preorder: []string{"c", "a", "b"},
76 topological: []string{"c", "a", "b"},
77 },
78 {
79 name: "simpleNoDuplicates",
Colin Crossc85750b2022-04-21 12:50:51 -070080 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
81 return NewDepSet[Path](order, Paths{c, a, a, a, b}, nil)
Colin Cross9e44e212020-07-14 15:02:16 -070082 },
83 postorder: []string{"c", "a", "b"},
84 preorder: []string{"c", "a", "b"},
85 topological: []string{"c", "a", "b"},
86 },
87 {
88 name: "nesting",
Colin Crossc85750b2022-04-21 12:50:51 -070089 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
90 subset := NewDepSet[Path](order, Paths{c, a, e}, nil)
91 return NewDepSet[Path](order, Paths{b, d}, []*DepSet[Path]{subset})
Colin Cross9e44e212020-07-14 15:02:16 -070092 },
93 postorder: []string{"c", "a", "e", "b", "d"},
94 preorder: []string{"b", "d", "c", "a", "e"},
95 topological: []string{"b", "d", "c", "a", "e"},
96 },
97 {
98 name: "builderReuse",
Colin Crossc85750b2022-04-21 12:50:51 -070099 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
Colin Cross9e44e212020-07-14 15:02:16 -0700100 assertEquals := func(t *testing.T, w, g Paths) {
Colin Cross96c44122020-11-25 14:29:50 -0800101 t.Helper()
Colin Cross9e44e212020-07-14 15:02:16 -0700102 if !reflect.DeepEqual(w, g) {
103 t.Errorf("want %q, got %q", w, g)
104 }
105 }
Colin Crossc85750b2022-04-21 12:50:51 -0700106 builder := NewDepSetBuilder[Path](order)
Colin Cross9e44e212020-07-14 15:02:16 -0700107 assertEquals(t, nil, builder.Build().ToList())
108
109 builder.Direct(b)
110 assertEquals(t, Paths{b}, builder.Build().ToList())
111
112 builder.Direct(d)
113 assertEquals(t, Paths{b, d}, builder.Build().ToList())
114
Colin Crossc85750b2022-04-21 12:50:51 -0700115 child := NewDepSetBuilder[Path](order).Direct(c, a, e).Build()
Colin Cross9e44e212020-07-14 15:02:16 -0700116 builder.Transitive(child)
117 return builder.Build()
118 },
119 postorder: []string{"c", "a", "e", "b", "d"},
120 preorder: []string{"b", "d", "c", "a", "e"},
121 topological: []string{"b", "d", "c", "a", "e"},
122 },
123 {
124 name: "builderChaining",
Colin Crossc85750b2022-04-21 12:50:51 -0700125 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
126 return NewDepSetBuilder[Path](order).Direct(b).Direct(d).
127 Transitive(NewDepSetBuilder[Path](order).Direct(c, a, e).Build()).Build()
Colin Cross9e44e212020-07-14 15:02:16 -0700128 },
129 postorder: []string{"c", "a", "e", "b", "d"},
130 preorder: []string{"b", "d", "c", "a", "e"},
131 topological: []string{"b", "d", "c", "a", "e"},
132 },
133 {
134 name: "transitiveDepsHandledSeparately",
Colin Crossc85750b2022-04-21 12:50:51 -0700135 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
136 subset := NewDepSetBuilder[Path](order).Direct(c, a, e).Build()
137 builder := NewDepSetBuilder[Path](order)
Colin Cross9e44e212020-07-14 15:02:16 -0700138 // The fact that we add the transitive subset between the Direct(b) and Direct(d)
139 // calls should not change the result.
140 builder.Direct(b)
141 builder.Transitive(subset)
142 builder.Direct(d)
143 return builder.Build()
144 },
145 postorder: []string{"c", "a", "e", "b", "d"},
146 preorder: []string{"b", "d", "c", "a", "e"},
147 topological: []string{"b", "d", "c", "a", "e"},
148 },
149 {
150 name: "nestingNoDuplicates",
Colin Crossc85750b2022-04-21 12:50:51 -0700151 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
152 subset := NewDepSetBuilder[Path](order).Direct(c, a, e).Build()
153 return NewDepSetBuilder[Path](order).Direct(b, d, e).Transitive(subset).Build()
Colin Cross9e44e212020-07-14 15:02:16 -0700154 },
155 postorder: []string{"c", "a", "e", "b", "d"},
156 preorder: []string{"b", "d", "e", "c", "a"},
157 topological: []string{"b", "d", "c", "a", "e"},
158 },
159 {
160 name: "chain",
Colin Crossc85750b2022-04-21 12:50:51 -0700161 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
162 c := NewDepSetBuilder[Path](order).Direct(c).Build()
163 b := NewDepSetBuilder[Path](order).Direct(b).Transitive(c).Build()
164 a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Build()
Colin Cross9e44e212020-07-14 15:02:16 -0700165
166 return a
167 },
168 postorder: []string{"c", "b", "a"},
169 preorder: []string{"a", "b", "c"},
170 topological: []string{"a", "b", "c"},
171 },
172 {
173 name: "diamond",
Colin Crossc85750b2022-04-21 12:50:51 -0700174 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
175 d := NewDepSetBuilder[Path](order).Direct(d).Build()
176 c := NewDepSetBuilder[Path](order).Direct(c).Transitive(d).Build()
177 b := NewDepSetBuilder[Path](order).Direct(b).Transitive(d).Build()
178 a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Transitive(c).Build()
Colin Cross9e44e212020-07-14 15:02:16 -0700179
180 return a
181 },
182 postorder: []string{"d", "b", "c", "a"},
183 preorder: []string{"a", "b", "d", "c"},
184 topological: []string{"a", "b", "c", "d"},
185 },
186 {
187 name: "extendedDiamond",
Colin Crossc85750b2022-04-21 12:50:51 -0700188 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
189 d := NewDepSetBuilder[Path](order).Direct(d).Build()
190 e := NewDepSetBuilder[Path](order).Direct(e).Build()
191 b := NewDepSetBuilder[Path](order).Direct(b).Transitive(d).Transitive(e).Build()
192 c := NewDepSetBuilder[Path](order).Direct(c).Transitive(e).Transitive(d).Build()
193 a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Transitive(c).Build()
Colin Cross9e44e212020-07-14 15:02:16 -0700194 return a
195 },
196 postorder: []string{"d", "e", "b", "c", "a"},
197 preorder: []string{"a", "b", "d", "e", "c"},
198 topological: []string{"a", "b", "c", "e", "d"},
199 },
200 {
201 name: "extendedDiamondRightArm",
Colin Crossc85750b2022-04-21 12:50:51 -0700202 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
203 d := NewDepSetBuilder[Path](order).Direct(d).Build()
204 e := NewDepSetBuilder[Path](order).Direct(e).Build()
205 b := NewDepSetBuilder[Path](order).Direct(b).Transitive(d).Transitive(e).Build()
206 c2 := NewDepSetBuilder[Path](order).Direct(c2).Transitive(e).Transitive(d).Build()
207 c := NewDepSetBuilder[Path](order).Direct(c).Transitive(c2).Build()
208 a := NewDepSetBuilder[Path](order).Direct(a).Transitive(b).Transitive(c).Build()
Colin Cross9e44e212020-07-14 15:02:16 -0700209 return a
210 },
211 postorder: []string{"d", "e", "b", "c2", "c", "a"},
212 preorder: []string{"a", "b", "d", "e", "c", "c2"},
213 topological: []string{"a", "b", "c", "c2", "e", "d"},
214 },
215 {
216 name: "orderConflict",
Colin Crossc85750b2022-04-21 12:50:51 -0700217 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
218 child1 := NewDepSetBuilder[Path](order).Direct(a, b).Build()
219 child2 := NewDepSetBuilder[Path](order).Direct(b, a).Build()
220 parent := NewDepSetBuilder[Path](order).Transitive(child1).Transitive(child2).Build()
Colin Cross9e44e212020-07-14 15:02:16 -0700221 return parent
222 },
223 postorder: []string{"a", "b"},
224 preorder: []string{"a", "b"},
225 topological: []string{"b", "a"},
226 },
227 {
228 name: "orderConflictNested",
Colin Crossc85750b2022-04-21 12:50:51 -0700229 depSet: func(t *testing.T, order DepSetOrder) *DepSet[Path] {
230 a := NewDepSetBuilder[Path](order).Direct(a).Build()
231 b := NewDepSetBuilder[Path](order).Direct(b).Build()
232 child1 := NewDepSetBuilder[Path](order).Transitive(a).Transitive(b).Build()
233 child2 := NewDepSetBuilder[Path](order).Transitive(b).Transitive(a).Build()
234 parent := NewDepSetBuilder[Path](order).Transitive(child1).Transitive(child2).Build()
Colin Cross9e44e212020-07-14 15:02:16 -0700235 return parent
236 },
237 postorder: []string{"a", "b"},
238 preorder: []string{"a", "b"},
239 topological: []string{"b", "a"},
240 },
241 }
242
243 for _, tt := range tests {
244 t.Run(tt.name, func(t *testing.T) {
245 t.Run("postorder", func(t *testing.T) {
246 depSet := tt.depSet(t, POSTORDER)
Colin Crossc85750b2022-04-21 12:50:51 -0700247 if g, w := Paths(depSet.ToList()).Strings(), tt.postorder; !reflect.DeepEqual(g, w) {
Colin Cross9e44e212020-07-14 15:02:16 -0700248 t.Errorf("expected ToList() = %q, got %q", w, g)
249 }
250 })
251 t.Run("preorder", func(t *testing.T) {
252 depSet := tt.depSet(t, PREORDER)
Colin Crossc85750b2022-04-21 12:50:51 -0700253 if g, w := Paths(depSet.ToList()).Strings(), tt.preorder; !reflect.DeepEqual(g, w) {
Colin Cross9e44e212020-07-14 15:02:16 -0700254 t.Errorf("expected ToList() = %q, got %q", w, g)
255 }
256 })
257 t.Run("topological", func(t *testing.T) {
258 depSet := tt.depSet(t, TOPOLOGICAL)
Colin Crossc85750b2022-04-21 12:50:51 -0700259 if g, w := Paths(depSet.ToList()).Strings(), tt.topological; !reflect.DeepEqual(g, w) {
Colin Cross9e44e212020-07-14 15:02:16 -0700260 t.Errorf("expected ToList() = %q, got %q", w, g)
261 }
262 })
263 })
264 }
265}
266
267func TestDepSetInvalidOrder(t *testing.T) {
Colin Cross9e44e212020-07-14 15:02:16 -0700268 orders := []DepSetOrder{POSTORDER, PREORDER, TOPOLOGICAL}
269
270 run := func(t *testing.T, order1, order2 DepSetOrder) {
271 defer func() {
272 if r := recover(); r != nil {
273 if err, ok := r.(error); !ok {
274 t.Fatalf("expected panic error, got %v", err)
275 } else if !strings.Contains(err.Error(), "incompatible order") {
276 t.Fatalf("expected incompatible order error, got %v", err)
277 }
278 }
279 }()
Colin Crossc85750b2022-04-21 12:50:51 -0700280 NewDepSet(order1, nil, []*DepSet[Path]{NewDepSet[Path](order2, nil, nil)})
Colin Cross9e44e212020-07-14 15:02:16 -0700281 t.Fatal("expected panic")
282 }
283
284 for _, order1 := range orders {
285 t.Run(order1.String(), func(t *testing.T) {
286 for _, order2 := range orders {
287 t.Run(order2.String(), func(t *testing.T) {
288 if order1 != order2 {
289 run(t, order1, order2)
290 }
291 })
292 }
293 })
294 }
295}