blob: 16c52cff2c6d3f10026d0af40d5650df95e49ca2 [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"
Jeff Gastonc3e28442017-08-09 15:13:12 -070021
22 "github.com/google/blueprint/parser"
Jamie Gennis1bc967e2014-05-27 16:34:41 -070023)
24
Yuchen Wuf9958462015-10-09 17:31:27 -070025type Walker interface {
26 Walk() bool
27}
28
Jamie Gennis1bc967e2014-05-27 16:34:41 -070029type fooModule struct {
Colin Cross0b7e83e2016-05-17 14:58:05 -070030 SimpleName
Jamie Gennis1bc967e2014-05-27 16:34:41 -070031 properties struct {
Colin Cross0b7e83e2016-05-17 14:58:05 -070032 Deps []string
33 Foo string
Jamie Gennis1bc967e2014-05-27 16:34:41 -070034 }
35}
36
Jamie Gennis68540da2014-10-06 09:10:40 -070037func newFooModule() (Module, []interface{}) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070038 m := &fooModule{}
Colin Cross0b7e83e2016-05-17 14:58:05 -070039 return m, []interface{}{&m.properties, &m.SimpleName.Properties}
Jamie Gennis1bc967e2014-05-27 16:34:41 -070040}
41
42func (f *fooModule) GenerateBuildActions(ModuleContext) {
43}
44
Colin Cross0b7e83e2016-05-17 14:58:05 -070045func (f *fooModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string {
46 return f.properties.Deps
47}
48
Jamie Gennis1bc967e2014-05-27 16:34:41 -070049func (f *fooModule) Foo() string {
50 return f.properties.Foo
51}
52
Yuchen Wuf9958462015-10-09 17:31:27 -070053func (f *fooModule) Walk() bool {
54 return true
55}
56
Jamie Gennis1bc967e2014-05-27 16:34:41 -070057type barModule struct {
Colin Cross0b7e83e2016-05-17 14:58:05 -070058 SimpleName
Jamie Gennis1bc967e2014-05-27 16:34:41 -070059 properties struct {
Colin Cross0b7e83e2016-05-17 14:58:05 -070060 Deps []string
61 Bar bool
Jamie Gennis1bc967e2014-05-27 16:34:41 -070062 }
63}
64
Jamie Gennis68540da2014-10-06 09:10:40 -070065func newBarModule() (Module, []interface{}) {
Jamie Gennis1bc967e2014-05-27 16:34:41 -070066 m := &barModule{}
Colin Cross0b7e83e2016-05-17 14:58:05 -070067 return m, []interface{}{&m.properties, &m.SimpleName.Properties}
68}
69
70func (b *barModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string {
71 return b.properties.Deps
Jamie Gennis1bc967e2014-05-27 16:34:41 -070072}
73
74func (b *barModule) GenerateBuildActions(ModuleContext) {
75}
76
77func (b *barModule) Bar() bool {
78 return b.properties.Bar
79}
80
Yuchen Wuf9958462015-10-09 17:31:27 -070081func (b *barModule) Walk() bool {
82 return false
83}
84
Jamie Gennis1bc967e2014-05-27 16:34:41 -070085func TestContextParse(t *testing.T) {
86 ctx := NewContext()
Jamie Gennis68540da2014-10-06 09:10:40 -070087 ctx.RegisterModuleType("foo_module", newFooModule)
88 ctx.RegisterModuleType("bar_module", newBarModule)
Jamie Gennis1bc967e2014-05-27 16:34:41 -070089
90 r := bytes.NewBufferString(`
91 foo_module {
Colin Cross0b7e83e2016-05-17 14:58:05 -070092 name: "MyFooModule",
Jamie Gennis1bc967e2014-05-27 16:34:41 -070093 deps: ["MyBarModule"],
94 }
95
96 bar_module {
Colin Cross0b7e83e2016-05-17 14:58:05 -070097 name: "MyBarModule",
Jamie Gennis1bc967e2014-05-27 16:34:41 -070098 }
99 `)
100
Jeff Gastonc3e28442017-08-09 15:13:12 -0700101 _, _, errs := ctx.parseOne(".", "Blueprint", r, parser.NewScope(nil))
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700102 if len(errs) > 0 {
103 t.Errorf("unexpected parse errors:")
104 for _, err := range errs {
105 t.Errorf(" %s", err)
106 }
107 t.FailNow()
108 }
109
Colin Cross874a3462017-07-31 17:26:06 -0700110 _, errs = ctx.ResolveDependencies(nil)
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700111 if len(errs) > 0 {
112 t.Errorf("unexpected dep errors:")
113 for _, err := range errs {
114 t.Errorf(" %s", err)
115 }
116 t.FailNow()
117 }
Jamie Gennis1bc967e2014-05-27 16:34:41 -0700118}
Yuchen Wuf9958462015-10-09 17:31:27 -0700119
120// |---B===D - represents a non-walkable edge
121// A = represents a walkable edge
122// |===C---E===G
123// | | A should not be visited because it's the root node.
124// |===F===| B, D and E should not be walked.
125func TestWalkDeps(t *testing.T) {
126 ctx := NewContext()
Colin Crossd7b0f602016-06-02 15:30:20 -0700127 ctx.MockFileSystem(map[string][]byte{
128 "Blueprints": []byte(`
129 foo_module {
130 name: "A",
131 deps: ["B", "C"],
132 }
133
134 bar_module {
135 name: "B",
136 deps: ["D"],
137 }
138
139 foo_module {
140 name: "C",
141 deps: ["E", "F"],
142 }
143
144 foo_module {
145 name: "D",
146 }
147
148 bar_module {
149 name: "E",
150 deps: ["G"],
151 }
152
153 foo_module {
154 name: "F",
155 deps: ["G"],
156 }
157
158 foo_module {
159 name: "G",
160 }
161 `),
162 })
163
Yuchen Wuf9958462015-10-09 17:31:27 -0700164 ctx.RegisterModuleType("foo_module", newFooModule)
165 ctx.RegisterModuleType("bar_module", newBarModule)
Colin Crossd7b0f602016-06-02 15:30:20 -0700166 _, errs := ctx.ParseBlueprintsFiles("Blueprints")
167 if len(errs) > 0 {
168 t.Errorf("unexpected parse errors:")
169 for _, err := range errs {
170 t.Errorf(" %s", err)
171 }
172 t.FailNow()
173 }
174
Colin Cross874a3462017-07-31 17:26:06 -0700175 _, errs = ctx.ResolveDependencies(nil)
Colin Crossd7b0f602016-06-02 15:30:20 -0700176 if len(errs) > 0 {
177 t.Errorf("unexpected dep errors:")
178 for _, err := range errs {
179 t.Errorf(" %s", err)
180 }
181 t.FailNow()
182 }
Yuchen Wuf9958462015-10-09 17:31:27 -0700183
Colin Crossbafd5f52016-08-06 22:52:01 -0700184 var outputDown string
185 var outputUp string
Jeff Gastond70bf752017-11-10 15:12:08 -0800186 topModule := ctx.modulesFromName("A", nil)[0]
Yuchen Wuf9958462015-10-09 17:31:27 -0700187 ctx.walkDeps(topModule,
Colin Crossbafd5f52016-08-06 22:52:01 -0700188 func(dep depInfo, parent *moduleInfo) bool {
189 if dep.module.logicModule.(Walker).Walk() {
190 outputDown += ctx.ModuleName(dep.module.logicModule)
Yuchen Wuf9958462015-10-09 17:31:27 -0700191 return true
192 }
193 return false
Colin Crossbafd5f52016-08-06 22:52:01 -0700194 },
195 func(dep depInfo, parent *moduleInfo) {
196 if dep.module.logicModule.(Walker).Walk() {
197 outputUp += ctx.ModuleName(dep.module.logicModule)
198 }
Yuchen Wuf9958462015-10-09 17:31:27 -0700199 })
Colin Crossbafd5f52016-08-06 22:52:01 -0700200 if outputDown != "CFG" {
201 t.Fatalf("unexpected walkDeps behaviour: %s\ndown should be: CFG", outputDown)
202 }
203 if outputUp != "GFC" {
204 t.Fatalf("unexpected walkDeps behaviour: %s\nup should be: GFC", outputUp)
Yuchen Wuf9958462015-10-09 17:31:27 -0700205 }
206}
Colin Crossaf4fd212017-07-28 14:32:36 -0700207
208func TestCreateModule(t *testing.T) {
209 ctx := newContext()
210 ctx.MockFileSystem(map[string][]byte{
211 "Blueprints": []byte(`
212 foo_module {
213 name: "A",
214 deps: ["B", "C"],
215 }
216 `),
217 })
218
219 ctx.RegisterTopDownMutator("create", createTestMutator)
220 ctx.RegisterBottomUpMutator("deps", blueprintDepsMutator)
221
222 ctx.RegisterModuleType("foo_module", newFooModule)
223 ctx.RegisterModuleType("bar_module", newBarModule)
224 _, errs := ctx.ParseBlueprintsFiles("Blueprints")
225 if len(errs) > 0 {
226 t.Errorf("unexpected parse errors:")
227 for _, err := range errs {
228 t.Errorf(" %s", err)
229 }
230 t.FailNow()
231 }
232
Colin Cross874a3462017-07-31 17:26:06 -0700233 _, errs = ctx.ResolveDependencies(nil)
Colin Crossaf4fd212017-07-28 14:32:36 -0700234 if len(errs) > 0 {
235 t.Errorf("unexpected dep errors:")
236 for _, err := range errs {
237 t.Errorf(" %s", err)
238 }
239 t.FailNow()
240 }
241
Jeff Gastond70bf752017-11-10 15:12:08 -0800242 a := ctx.modulesFromName("A", nil)[0].logicModule.(*fooModule)
243 b := ctx.modulesFromName("B", nil)[0].logicModule.(*barModule)
244 c := ctx.modulesFromName("C", nil)[0].logicModule.(*barModule)
245 d := ctx.modulesFromName("D", nil)[0].logicModule.(*fooModule)
Colin Crossaf4fd212017-07-28 14:32:36 -0700246
247 checkDeps := func(m Module, expected string) {
248 var deps []string
249 ctx.VisitDirectDeps(m, func(m Module) {
250 deps = append(deps, ctx.ModuleName(m))
251 })
252 got := strings.Join(deps, ",")
253 if got != expected {
254 t.Errorf("unexpected %q dependencies, got %q expected %q",
255 ctx.ModuleName(m), got, expected)
256 }
257 }
258
259 checkDeps(a, "B,C")
260 checkDeps(b, "D")
261 checkDeps(c, "D")
262 checkDeps(d, "")
263}
264
265func createTestMutator(ctx TopDownMutatorContext) {
266 type props struct {
267 Name string
268 Deps []string
269 }
270
271 ctx.CreateModule(newBarModule, &props{
272 Name: "B",
273 Deps: []string{"D"},
274 })
275
276 ctx.CreateModule(newBarModule, &props{
277 Name: "C",
278 Deps: []string{"D"},
279 })
280
281 ctx.CreateModule(newFooModule, &props{
282 Name: "D",
283 })
284}