• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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
15package blueprint
16
17import (
18	"bytes"
19	"testing"
20)
21
22type Walker interface {
23	Walk() bool
24}
25
26type fooModule struct {
27	SimpleName
28	properties struct {
29		Deps []string
30		Foo  string
31	}
32}
33
34func newFooModule() (Module, []interface{}) {
35	m := &fooModule{}
36	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
37}
38
39func (f *fooModule) GenerateBuildActions(ModuleContext) {
40}
41
42func (f *fooModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string {
43	return f.properties.Deps
44}
45
46func (f *fooModule) Foo() string {
47	return f.properties.Foo
48}
49
50func (f *fooModule) Walk() bool {
51	return true
52}
53
54type barModule struct {
55	SimpleName
56	properties struct {
57		Deps []string
58		Bar  bool
59	}
60}
61
62func newBarModule() (Module, []interface{}) {
63	m := &barModule{}
64	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
65}
66
67func (b *barModule) DynamicDependencies(ctx DynamicDependerModuleContext) []string {
68	return b.properties.Deps
69}
70
71func (b *barModule) GenerateBuildActions(ModuleContext) {
72}
73
74func (b *barModule) Bar() bool {
75	return b.properties.Bar
76}
77
78func (b *barModule) Walk() bool {
79	return false
80}
81
82func TestContextParse(t *testing.T) {
83	ctx := NewContext()
84	ctx.RegisterModuleType("foo_module", newFooModule)
85	ctx.RegisterModuleType("bar_module", newBarModule)
86
87	r := bytes.NewBufferString(`
88		foo_module {
89	        name: "MyFooModule",
90			deps: ["MyBarModule"],
91		}
92
93		bar_module {
94	        name: "MyBarModule",
95		}
96	`)
97
98	_, _, errs := ctx.parse(".", "Blueprint", r, nil)
99	if len(errs) > 0 {
100		t.Errorf("unexpected parse errors:")
101		for _, err := range errs {
102			t.Errorf("  %s", err)
103		}
104		t.FailNow()
105	}
106
107	errs = ctx.ResolveDependencies(nil)
108	if len(errs) > 0 {
109		t.Errorf("unexpected dep errors:")
110		for _, err := range errs {
111			t.Errorf("  %s", err)
112		}
113		t.FailNow()
114	}
115}
116
117// |---B===D       - represents a non-walkable edge
118// A               = represents a walkable edge
119// |===C---E===G
120//     |       |   A should not be visited because it's the root node.
121//     |===F===|   B, D and E should not be walked.
122func TestWalkDeps(t *testing.T) {
123	ctx := NewContext()
124	ctx.MockFileSystem(map[string][]byte{
125		"Blueprints": []byte(`
126			foo_module {
127			    name: "A",
128			    deps: ["B", "C"],
129			}
130
131			bar_module {
132			    name: "B",
133			    deps: ["D"],
134			}
135
136			foo_module {
137			    name: "C",
138			    deps: ["E", "F"],
139			}
140
141			foo_module {
142			    name: "D",
143			}
144
145			bar_module {
146			    name: "E",
147			    deps: ["G"],
148			}
149
150			foo_module {
151			    name: "F",
152			    deps: ["G"],
153			}
154
155			foo_module {
156			    name: "G",
157			}
158		`),
159	})
160
161	ctx.RegisterModuleType("foo_module", newFooModule)
162	ctx.RegisterModuleType("bar_module", newBarModule)
163	_, errs := ctx.ParseBlueprintsFiles("Blueprints")
164	if len(errs) > 0 {
165		t.Errorf("unexpected parse errors:")
166		for _, err := range errs {
167			t.Errorf("  %s", err)
168		}
169		t.FailNow()
170	}
171
172	errs = ctx.ResolveDependencies(nil)
173	if len(errs) > 0 {
174		t.Errorf("unexpected dep errors:")
175		for _, err := range errs {
176			t.Errorf("  %s", err)
177		}
178		t.FailNow()
179	}
180
181	var outputDown string
182	var outputUp string
183	topModule := ctx.modulesFromName("A")[0]
184	ctx.walkDeps(topModule,
185		func(dep depInfo, parent *moduleInfo) bool {
186			if dep.module.logicModule.(Walker).Walk() {
187				outputDown += ctx.ModuleName(dep.module.logicModule)
188				return true
189			}
190			return false
191		},
192		func(dep depInfo, parent *moduleInfo) {
193			if dep.module.logicModule.(Walker).Walk() {
194				outputUp += ctx.ModuleName(dep.module.logicModule)
195			}
196		})
197	if outputDown != "CFG" {
198		t.Fatalf("unexpected walkDeps behaviour: %s\ndown should be: CFG", outputDown)
199	}
200	if outputUp != "GFC" {
201		t.Fatalf("unexpected walkDeps behaviour: %s\nup should be: GFC", outputUp)
202	}
203}
204