1// Copyright 2016 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	"fmt"
19	"testing"
20)
21
22type visitModule struct {
23	SimpleName
24	properties struct {
25		Visit                 []string
26		VisitDepsDepthFirst   string `blueprint:"mutated"`
27		VisitDepsDepthFirstIf string `blueprint:"mutated"`
28		VisitDirectDeps       string `blueprint:"mutated"`
29		VisitDirectDepsIf     string `blueprint:"mutated"`
30	}
31}
32
33func newVisitModule() (Module, []interface{}) {
34	m := &visitModule{}
35	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
36}
37
38func (f *visitModule) GenerateBuildActions(ModuleContext) {
39}
40
41type visitTag struct {
42	BaseDependencyTag
43}
44
45var visitTagDep visitTag
46
47func visitDepsMutator(ctx BottomUpMutatorContext) {
48	if m, ok := ctx.Module().(*visitModule); ok {
49		ctx.AddDependency(ctx.Module(), visitTagDep, m.properties.Visit...)
50	}
51}
52
53func visitMutator(ctx TopDownMutatorContext) {
54	if m, ok := ctx.Module().(*visitModule); ok {
55		ctx.VisitDepsDepthFirst(func(dep Module) {
56			if ctx.OtherModuleDependencyTag(dep) != visitTagDep {
57				panic(fmt.Errorf("unexpected dependency tag on %q", ctx.OtherModuleName(dep)))
58			}
59			m.properties.VisitDepsDepthFirst = m.properties.VisitDepsDepthFirst + ctx.OtherModuleName(dep)
60		})
61		ctx.VisitDepsDepthFirstIf(func(dep Module) bool {
62			return ctx.OtherModuleName(dep) != "B"
63		}, func(dep Module) {
64			m.properties.VisitDepsDepthFirstIf = m.properties.VisitDepsDepthFirstIf + ctx.OtherModuleName(dep)
65		})
66		ctx.VisitDirectDeps(func(dep Module) {
67			m.properties.VisitDirectDeps = m.properties.VisitDirectDeps + ctx.OtherModuleName(dep)
68		})
69		ctx.VisitDirectDepsIf(func(dep Module) bool {
70			return ctx.OtherModuleName(dep) != "B"
71		}, func(dep Module) {
72			m.properties.VisitDirectDepsIf = m.properties.VisitDirectDepsIf + ctx.OtherModuleName(dep)
73		})
74	}
75}
76
77// A
78// |
79// B
80// |\
81// C \
82//  \|
83//   D
84//   |
85//   E
86//  / \
87//  \ /
88//   F
89func setupVisitTest(t *testing.T) *Context {
90	ctx := NewContext()
91	ctx.RegisterModuleType("visit_module", newVisitModule)
92	ctx.RegisterBottomUpMutator("visit_deps", visitDepsMutator)
93	ctx.RegisterTopDownMutator("visit", visitMutator)
94
95	ctx.MockFileSystem(map[string][]byte{
96		"Blueprints": []byte(`
97			visit_module {
98				name: "A",
99				visit: ["B"],
100			}
101
102			visit_module {
103				name: "B",
104				visit: ["C", "D"],
105			}
106
107			visit_module {
108				name: "C",
109				visit: ["D"],
110			}
111
112			visit_module {
113				name: "D",
114				visit: ["E"],
115			}
116
117			visit_module {
118				name: "E",
119				visit: ["F", "F"],
120			}
121
122			visit_module {
123				name: "F",
124			}
125		`),
126	})
127
128	_, errs := ctx.ParseBlueprintsFiles("Blueprints", nil)
129	if len(errs) > 0 {
130		t.Errorf("unexpected parse errors:")
131		for _, err := range errs {
132			t.Errorf("  %s", err)
133		}
134		t.FailNow()
135	}
136
137	_, errs = ctx.ResolveDependencies(nil)
138	if len(errs) > 0 {
139		t.Errorf("unexpected dep errors:")
140		for _, err := range errs {
141			t.Errorf("  %s", err)
142		}
143		t.FailNow()
144	}
145
146	return ctx
147}
148
149func TestVisit(t *testing.T) {
150	ctx := setupVisitTest(t)
151
152	topModule := ctx.moduleGroupFromName("A", nil).modules[0].logicModule.(*visitModule)
153	assertString(t, topModule.properties.VisitDepsDepthFirst, "FEDCB")
154	assertString(t, topModule.properties.VisitDepsDepthFirstIf, "FEDC")
155	assertString(t, topModule.properties.VisitDirectDeps, "B")
156	assertString(t, topModule.properties.VisitDirectDepsIf, "")
157
158	eModule := ctx.moduleGroupFromName("E", nil).modules[0].logicModule.(*visitModule)
159	assertString(t, eModule.properties.VisitDepsDepthFirst, "F")
160	assertString(t, eModule.properties.VisitDepsDepthFirstIf, "F")
161	assertString(t, eModule.properties.VisitDirectDeps, "FF")
162	assertString(t, eModule.properties.VisitDirectDepsIf, "FF")
163}
164
165func assertString(t *testing.T, got, expected string) {
166	if got != expected {
167		t.Errorf("expected %q got %q", expected, got)
168	}
169}
170