blob: 6070c990c1934257c10577936e31a65a5b341055 [file] [log] [blame]
Colin Cross8e0c5112015-01-23 14:15:10 -08001// Copyright 2014 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
Jamie Gennis1bc967e2014-05-27 16:34:41 -070015package blueprint
16
17import (
18 "bytes"
Colin Crossaf4fd212017-07-28 14:32:36 -070019 "strings"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070020 "testing"
21)
22
Yuchen Wuf9958462015-10-09 17:31:27 -070023type Walker interface {
24 Walk() bool
25}
26
Jamie Gennis1bc967e2014-05-27 16:34:41 -070027type fooModule struct {
Colin Cross0b7e83e2016-05-17 14:58:05 -070028 SimpleName
Jamie Gennis1bc967e2014-05-27 16:34:41 -070029 properties struct {
Colin Cross0b7e83e2016-05-17 14:58:05 -070030 Deps []string
31 Foo string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070032 }
33}
34
Jamie Gennis68540da2014-10-06 09:10:40 -070035func newFooModule() (Module, []interface{}) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070036 m := &fooModule{}
Colin Cross0b7e83e2016-05-17 14:58:05 -070037 return m, []interface{}{&m.properties, &m.SimpleName.Properties}
Jamie Gennis1bc967e2014-05-27 16:34:41 -070038}
39
40func (f *fooModule) GenerateBuildActions(ModuleContext) {
41}
42
Colin Cross0b7e83e2016-05-17 14:58:05 -070043func (f *fooModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string {
44 return f.properties.Deps
45}
46
Jamie Gennis1bc967e2014-05-27 16:34:41 -070047func (f *fooModule) Foo() string {
48 return f.properties.Foo
49}
50
Yuchen Wuf9958462015-10-09 17:31:27 -070051func (f *fooModule) Walk() bool {
52 return true
53}
54
Jamie Gennis1bc967e2014-05-27 16:34:41 -070055type barModule struct {
Colin Cross0b7e83e2016-05-17 14:58:05 -070056 SimpleName
Jamie Gennis1bc967e2014-05-27 16:34:41 -070057 properties struct {
Colin Cross0b7e83e2016-05-17 14:58:05 -070058 Deps []string
59 Bar bool
Jamie Gennis1bc967e2014-05-27 16:34:41 -070060 }
61}
62
Jamie Gennis68540da2014-10-06 09:10:40 -070063func newBarModule() (Module, []interface{}) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070064 m := &barModule{}
Colin Cross0b7e83e2016-05-17 14:58:05 -070065 return m, []interface{}{&m.properties, &m.SimpleName.Properties}
66}
67
68func (b *barModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string {
69 return b.properties.Deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -070070}
71
72func (b *barModule) GenerateBuildActions(ModuleContext) {
73}
74
75func (b *barModule) Bar() bool {
76 return b.properties.Bar
77}
78
Yuchen Wuf9958462015-10-09 17:31:27 -070079func (b *barModule) Walk() bool {
80 return false
81}
82
Jamie Gennis1bc967e2014-05-27 16:34:41 -070083func TestContextParse(t *testing.T) {
84 ctx := NewContext()
Jamie Gennis68540da2014-10-06 09:10:40 -070085 ctx.RegisterModuleType("foo_module", newFooModule)
86 ctx.RegisterModuleType("bar_module", newBarModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -070087
88 r := bytes.NewBufferString(`
89 foo_module {
Colin Cross0b7e83e2016-05-17 14:58:05 -070090 name: "MyFooModule",
Jamie Gennis1bc967e2014-05-27 16:34:41 -070091 deps: ["MyBarModule"],
92 }
93
94 bar_module {
Colin Cross0b7e83e2016-05-17 14:58:05 -070095 name: "MyBarModule",
Jamie Gennis1bc967e2014-05-27 16:34:41 -070096 }
97 `)
98
Colin Cross127d2ea2016-11-01 11:10:51 -070099 _, _, errs := ctx.parse(".", "Blueprint", r, nil)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700100 if len(errs) > 0 {
101 t.Errorf("unexpected parse errors:")
102 for _, err := range errs {
103 t.Errorf(" %s", err)
104 }
105 t.FailNow()
106 }
107
Colin Cross763b6f12015-10-29 15:32:56 -0700108 errs = ctx.ResolveDependencies(nil)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700109 if len(errs) > 0 {
110 t.Errorf("unexpected dep errors:")
111 for _, err := range errs {
112 t.Errorf(" %s", err)
113 }
114 t.FailNow()
115 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700116}
Yuchen Wuf9958462015-10-09 17:31:27 -0700117
118// |---B===D - represents a non-walkable edge
119// A = represents a walkable edge
120// |===C---E===G
121// | | A should not be visited because it's the root node.
122// |===F===| B, D and E should not be walked.
123func TestWalkDeps(t *testing.T) {
124 ctx := NewContext()
Colin Crossd7b0f602016-06-02 15:30:20 -0700125 ctx.MockFileSystem(map[string][]byte{
126 "Blueprints": []byte(`
127 foo_module {
128 name: "A",
129 deps: ["B", "C"],
130 }
131
132 bar_module {
133 name: "B",
134 deps: ["D"],
135 }
136
137 foo_module {
138 name: "C",
139 deps: ["E", "F"],
140 }
141
142 foo_module {
143 name: "D",
144 }
145
146 bar_module {
147 name: "E",
148 deps: ["G"],
149 }
150
151 foo_module {
152 name: "F",
153 deps: ["G"],
154 }
155
156 foo_module {
157 name: "G",
158 }
159 `),
160 })
161
Yuchen Wuf9958462015-10-09 17:31:27 -0700162 ctx.RegisterModuleType("foo_module", newFooModule)
163 ctx.RegisterModuleType("bar_module", newBarModule)
Colin Crossd7b0f602016-06-02 15:30:20 -0700164 _, errs := ctx.ParseBlueprintsFiles("Blueprints")
165 if len(errs) > 0 {
166 t.Errorf("unexpected parse errors:")
167 for _, err := range errs {
168 t.Errorf(" %s", err)
169 }
170 t.FailNow()
171 }
172
173 errs = ctx.ResolveDependencies(nil)
174 if len(errs) > 0 {
175 t.Errorf("unexpected dep errors:")
176 for _, err := range errs {
177 t.Errorf(" %s", err)
178 }
179 t.FailNow()
180 }
Yuchen Wuf9958462015-10-09 17:31:27 -0700181
Colin Crossbafd5f52016-08-06 22:52:01 -0700182 var outputDown string
183 var outputUp string
Colin Cross0b7e83e2016-05-17 14:58:05 -0700184 topModule := ctx.modulesFromName("A")[0]
Yuchen Wuf9958462015-10-09 17:31:27 -0700185 ctx.walkDeps(topModule,
Colin Crossbafd5f52016-08-06 22:52:01 -0700186 func(dep depInfo, parent *moduleInfo) bool {
187 if dep.module.logicModule.(Walker).Walk() {
188 outputDown += ctx.ModuleName(dep.module.logicModule)
Yuchen Wuf9958462015-10-09 17:31:27 -0700189 return true
190 }
191 return false
Colin Crossbafd5f52016-08-06 22:52:01 -0700192 },
193 func(dep depInfo, parent *moduleInfo) {
194 if dep.module.logicModule.(Walker).Walk() {
195 outputUp += ctx.ModuleName(dep.module.logicModule)
196 }
Yuchen Wuf9958462015-10-09 17:31:27 -0700197 })
Colin Crossbafd5f52016-08-06 22:52:01 -0700198 if outputDown != "CFG" {
199 t.Fatalf("unexpected walkDeps behaviour: %s\ndown should be: CFG", outputDown)
200 }
201 if outputUp != "GFC" {
202 t.Fatalf("unexpected walkDeps behaviour: %s\nup should be: GFC", outputUp)
Yuchen Wuf9958462015-10-09 17:31:27 -0700203 }
204}
Colin Crossaf4fd212017-07-28 14:32:36 -0700205
206func TestCreateModule(t *testing.T) {
207 ctx := newContext()
208 ctx.MockFileSystem(map[string][]byte{
209 "Blueprints": []byte(`
210 foo_module {
211 name: "A",
212 deps: ["B", "C"],
213 }
214 `),
215 })
216
217 ctx.RegisterTopDownMutator("create", createTestMutator)
218 ctx.RegisterBottomUpMutator("deps", blueprintDepsMutator)
219
220 ctx.RegisterModuleType("foo_module", newFooModule)
221 ctx.RegisterModuleType("bar_module", newBarModule)
222 _, errs := ctx.ParseBlueprintsFiles("Blueprints")
223 if len(errs) > 0 {
224 t.Errorf("unexpected parse errors:")
225 for _, err := range errs {
226 t.Errorf(" %s", err)
227 }
228 t.FailNow()
229 }
230
231 errs = ctx.ResolveDependencies(nil)
232 if len(errs) > 0 {
233 t.Errorf("unexpected dep errors:")
234 for _, err := range errs {
235 t.Errorf(" %s", err)
236 }
237 t.FailNow()
238 }
239
240 a := ctx.modulesFromName("A")[0].logicModule.(*fooModule)
241 b := ctx.modulesFromName("B")[0].logicModule.(*barModule)
242 c := ctx.modulesFromName("C")[0].logicModule.(*barModule)
243 d := ctx.modulesFromName("D")[0].logicModule.(*fooModule)
244
245 checkDeps := func(m Module, expected string) {
246 var deps []string
247 ctx.VisitDirectDeps(m, func(m Module) {
248 deps = append(deps, ctx.ModuleName(m))
249 })
250 got := strings.Join(deps, ",")
251 if got != expected {
252 t.Errorf("unexpected %q dependencies, got %q expected %q",
253 ctx.ModuleName(m), got, expected)
254 }
255 }
256
257 checkDeps(a, "B,C")
258 checkDeps(b, "D")
259 checkDeps(c, "D")
260 checkDeps(d, "")
261}
262
263func createTestMutator(ctx TopDownMutatorContext) {
264 type props struct {
265 Name string
266 Deps []string
267 }
268
269 ctx.CreateModule(newBarModule, &props{
270 Name: "B",
271 Deps: []string{"D"},
272 })
273
274 ctx.CreateModule(newBarModule, &props{
275 Name: "C",
276 Deps: []string{"D"},
277 })
278
279 ctx.CreateModule(newFooModule, &props{
280 Name: "D",
281 })
282}