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
86func setupVisitTest(t *testing.T) *Context {
87	ctx := NewContext()
88	ctx.RegisterModuleType("visit_module", newVisitModule)
89	ctx.RegisterBottomUpMutator("visit_deps", visitDepsMutator)
90	ctx.RegisterTopDownMutator("visit", visitMutator)
91
92	ctx.MockFileSystem(map[string][]byte{
93		"Blueprints": []byte(`
94			visit_module {
95				name: "A",
96				visit: ["B"],
97			}
98
99			visit_module {
100				name: "B",
101				visit: ["C", "D"],
102			}
103
104			visit_module {
105				name: "C",
106				visit: ["D"],
107			}
108
109			visit_module {
110				name: "D",
111				visit: ["E"],
112			}
113
114			visit_module {
115				name: "E",
116			}
117		`),
118	})
119
120	_, errs := ctx.ParseBlueprintsFiles("Blueprints")
121	if len(errs) > 0 {
122		t.Errorf("unexpected parse errors:")
123		for _, err := range errs {
124			t.Errorf("  %s", err)
125		}
126		t.FailNow()
127	}
128
129	_, errs = ctx.ResolveDependencies(nil)
130	if len(errs) > 0 {
131		t.Errorf("unexpected dep errors:")
132		for _, err := range errs {
133			t.Errorf("  %s", err)
134		}
135		t.FailNow()
136	}
137
138	return ctx
139}
140
141func TestVisit(t *testing.T) {
142	ctx := setupVisitTest(t)
143
144	topModule := ctx.modulesFromName("A", nil)[0].logicModule.(*visitModule)
145	assertString(t, topModule.properties.VisitDepsDepthFirst, "EDCB")
146	assertString(t, topModule.properties.VisitDepsDepthFirstIf, "EDC")
147	assertString(t, topModule.properties.VisitDirectDeps, "B")
148	assertString(t, topModule.properties.VisitDirectDepsIf, "")
149}
150
151func assertString(t *testing.T, got, expected string) {
152	if got != expected {
153		t.Errorf("expected %q got %q", expected, got)
154	}
155}
156