1// Copyright 2019 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 "reflect" 19 "strings" 20 "testing" 21) 22 23type moduleCtxTestModule struct { 24 SimpleName 25} 26 27func newModuleCtxTestModule() (Module, []interface{}) { 28 m := &moduleCtxTestModule{} 29 return m, []interface{}{&m.SimpleName.Properties} 30} 31 32func (f *moduleCtxTestModule) GenerateBuildActions(ModuleContext) { 33} 34 35func addVariantDepsResultMutator(variants []Variation, tag DependencyTag, from, to string, results map[string][]Module) func(ctx BottomUpMutatorContext) { 36 return func(ctx BottomUpMutatorContext) { 37 if ctx.ModuleName() == from { 38 ret := ctx.AddVariationDependencies(variants, tag, to) 39 results[ctx.ModuleName()] = ret 40 } 41 } 42} 43 44func expectedErrors(t *testing.T, errs []error, expectedMessages ...string) { 45 t.Helper() 46 if len(errs) != len(expectedMessages) { 47 t.Errorf("expected %d error, found: %q", len(expectedMessages), errs) 48 } else { 49 for i, expected := range expectedMessages { 50 err := errs[i] 51 if err.Error() != expected { 52 t.Errorf("expected error %q found %q", expected, err) 53 } 54 } 55 } 56} 57 58func TestAddVariationDependencies(t *testing.T) { 59 runWithFailures := func(ctx *Context, expectedErr string) { 60 t.Helper() 61 bp := ` 62 test { 63 name: "foo", 64 } 65 66 test { 67 name: "bar", 68 } 69 ` 70 71 mockFS := map[string][]byte{ 72 "Android.bp": []byte(bp), 73 } 74 75 ctx.MockFileSystem(mockFS) 76 77 _, errs := ctx.ParseFileList(".", []string{"Android.bp"}, nil) 78 if len(errs) > 0 { 79 t.Errorf("unexpected parse errors:") 80 for _, err := range errs { 81 t.Errorf(" %s", err) 82 } 83 } 84 85 _, errs = ctx.ResolveDependencies(nil) 86 if len(errs) > 0 { 87 if expectedErr == "" { 88 t.Errorf("unexpected dep errors:") 89 for _, err := range errs { 90 t.Errorf(" %s", err) 91 } 92 } else { 93 for _, err := range errs { 94 if strings.Contains(err.Error(), expectedErr) { 95 continue 96 } else { 97 t.Errorf("unexpected dep error: %s", err) 98 } 99 } 100 } 101 } else if expectedErr != "" { 102 t.Errorf("missing dep error: %s", expectedErr) 103 } 104 } 105 106 run := func(ctx *Context) { 107 t.Helper() 108 runWithFailures(ctx, "") 109 } 110 111 t.Run("parallel", func(t *testing.T) { 112 ctx := NewContext() 113 ctx.RegisterModuleType("test", newModuleCtxTestModule) 114 results := make(map[string][]Module) 115 depsMutator := addVariantDepsResultMutator(nil, nil, "foo", "bar", results) 116 ctx.RegisterBottomUpMutator("deps", depsMutator) 117 118 run(ctx) 119 120 foo := ctx.moduleGroupFromName("foo", nil).moduleByVariantName("") 121 bar := ctx.moduleGroupFromName("bar", nil).moduleByVariantName("") 122 123 if g, w := foo.forwardDeps, []*moduleInfo{bar}; !reflect.DeepEqual(g, w) { 124 t.Fatalf("expected foo deps to be %q, got %q", w, g) 125 } 126 127 if g, w := results["foo"], []Module{bar.logicModule}; !reflect.DeepEqual(g, w) { 128 t.Fatalf("expected AddVariationDependencies return value to be %q, got %q", w, g) 129 } 130 }) 131 132 t.Run("missing", func(t *testing.T) { 133 ctx := NewContext() 134 ctx.RegisterModuleType("test", newModuleCtxTestModule) 135 results := make(map[string][]Module) 136 depsMutator := addVariantDepsResultMutator(nil, nil, "foo", "baz", results) 137 ctx.RegisterBottomUpMutator("deps", depsMutator) 138 runWithFailures(ctx, `"foo" depends on undefined module "baz"`) 139 140 foo := ctx.moduleGroupFromName("foo", nil).moduleByVariantName("") 141 142 if g, w := foo.forwardDeps, []*moduleInfo(nil); !reflect.DeepEqual(g, w) { 143 t.Fatalf("expected foo deps to be %q, got %q", w, g) 144 } 145 146 if g, w := results["foo"], []Module{nil}; !reflect.DeepEqual(g, w) { 147 t.Fatalf("expected AddVariationDependencies return value to be %q, got %q", w, g) 148 } 149 }) 150 151 t.Run("allow missing", func(t *testing.T) { 152 ctx := NewContext() 153 ctx.SetAllowMissingDependencies(true) 154 ctx.RegisterModuleType("test", newModuleCtxTestModule) 155 results := make(map[string][]Module) 156 depsMutator := addVariantDepsResultMutator(nil, nil, "foo", "baz", results) 157 ctx.RegisterBottomUpMutator("deps", depsMutator) 158 run(ctx) 159 160 foo := ctx.moduleGroupFromName("foo", nil).moduleByVariantName("") 161 162 if g, w := foo.forwardDeps, []*moduleInfo(nil); !reflect.DeepEqual(g, w) { 163 t.Fatalf("expected foo deps to be %q, got %q", w, g) 164 } 165 166 if g, w := results["foo"], []Module{nil}; !reflect.DeepEqual(g, w) { 167 t.Fatalf("expected AddVariationDependencies return value to be %q, got %q", w, g) 168 } 169 }) 170 171} 172 173func TestCheckBlueprintSyntax(t *testing.T) { 174 factories := map[string]ModuleFactory{ 175 "test": newModuleCtxTestModule, 176 } 177 178 t.Run("valid", func(t *testing.T) { 179 errs := CheckBlueprintSyntax(factories, "path/Blueprint", ` 180test { 181 name: "test", 182} 183`) 184 expectedErrors(t, errs) 185 }) 186 187 t.Run("syntax error", func(t *testing.T) { 188 errs := CheckBlueprintSyntax(factories, "path/Blueprint", ` 189test { 190 name: "test", 191 192`) 193 194 expectedErrors(t, errs, `path/Blueprint:5:1: expected "}", found EOF`) 195 }) 196 197 t.Run("unknown module type", func(t *testing.T) { 198 errs := CheckBlueprintSyntax(factories, "path/Blueprint", ` 199test2 { 200 name: "test", 201} 202`) 203 204 expectedErrors(t, errs, `path/Blueprint:2:1: unrecognized module type "test2"`) 205 }) 206 207 t.Run("unknown property name", func(t *testing.T) { 208 errs := CheckBlueprintSyntax(factories, "path/Blueprint", ` 209test { 210 nam: "test", 211} 212`) 213 214 expectedErrors(t, errs, `path/Blueprint:3:5: unrecognized property "nam"`) 215 }) 216 217 t.Run("invalid property type", func(t *testing.T) { 218 errs := CheckBlueprintSyntax(factories, "path/Blueprint", ` 219test { 220 name: false, 221} 222`) 223 224 expectedErrors(t, errs, `path/Blueprint:3:8: can't assign bool value to string property "name"`) 225 }) 226 227 t.Run("multiple failures", func(t *testing.T) { 228 errs := CheckBlueprintSyntax(factories, "path/Blueprint", ` 229test { 230 name: false, 231} 232 233test2 { 234 name: false, 235} 236`) 237 238 expectedErrors(t, errs, 239 `path/Blueprint:3:8: can't assign bool value to string property "name"`, 240 `path/Blueprint:6:1: unrecognized module type "test2"`, 241 ) 242 }) 243} 244 245type addNinjaDepsTestModule struct { 246 SimpleName 247} 248 249func addNinjaDepsTestModuleFactory() (Module, []interface{}) { 250 module := &addNinjaDepsTestModule{} 251 AddLoadHook(module, func(ctx LoadHookContext) { 252 ctx.AddNinjaFileDeps("LoadHookContext") 253 }) 254 return module, []interface{}{&module.SimpleName.Properties} 255} 256 257func (m *addNinjaDepsTestModule) GenerateBuildActions(ctx ModuleContext) { 258 ctx.AddNinjaFileDeps("GenerateBuildActions") 259} 260 261func addNinjaDepsTestBottomUpMutator(ctx BottomUpMutatorContext) { 262 ctx.AddNinjaFileDeps("BottomUpMutator") 263} 264 265func addNinjaDepsTestTopDownMutator(ctx TopDownMutatorContext) { 266 ctx.AddNinjaFileDeps("TopDownMutator") 267} 268 269type addNinjaDepsTestSingleton struct{} 270 271func addNinjaDepsTestSingletonFactory() Singleton { 272 return &addNinjaDepsTestSingleton{} 273} 274 275func (s *addNinjaDepsTestSingleton) GenerateBuildActions(ctx SingletonContext) { 276 ctx.AddNinjaFileDeps("Singleton") 277} 278 279func TestAddNinjaFileDeps(t *testing.T) { 280 ctx := NewContext() 281 ctx.MockFileSystem(map[string][]byte{ 282 "Android.bp": []byte(` 283 test { 284 name: "test", 285 } 286 `), 287 }) 288 289 ctx.RegisterModuleType("test", addNinjaDepsTestModuleFactory) 290 ctx.RegisterBottomUpMutator("testBottomUpMutator", addNinjaDepsTestBottomUpMutator) 291 ctx.RegisterTopDownMutator("testTopDownMutator", addNinjaDepsTestTopDownMutator) 292 ctx.RegisterSingletonType("testSingleton", addNinjaDepsTestSingletonFactory, false) 293 parseDeps, errs := ctx.ParseBlueprintsFiles("Android.bp", nil) 294 if len(errs) > 0 { 295 t.Errorf("unexpected parse errors:") 296 for _, err := range errs { 297 t.Errorf(" %s", err) 298 } 299 t.FailNow() 300 } 301 302 resolveDeps, errs := ctx.ResolveDependencies(nil) 303 if len(errs) > 0 { 304 t.Errorf("unexpected dep errors:") 305 for _, err := range errs { 306 t.Errorf(" %s", err) 307 } 308 t.FailNow() 309 } 310 311 prepareDeps, errs := ctx.PrepareBuildActions(nil) 312 if len(errs) > 0 { 313 t.Errorf("unexpected prepare errors:") 314 for _, err := range errs { 315 t.Errorf(" %s", err) 316 } 317 t.FailNow() 318 } 319 320 if g, w := parseDeps, []string{"Android.bp", "LoadHookContext"}; !reflect.DeepEqual(g, w) { 321 t.Errorf("ParseBlueprintsFiles: wanted deps %q, got %q", w, g) 322 } 323 324 if g, w := resolveDeps, []string{"BottomUpMutator", "TopDownMutator"}; !reflect.DeepEqual(g, w) { 325 t.Errorf("ResolveDependencies: wanted deps %q, got %q", w, g) 326 } 327 328 if g, w := prepareDeps, []string{"GenerateBuildActions", "Singleton"}; !reflect.DeepEqual(g, w) { 329 t.Errorf("PrepareBuildActions: wanted deps %q, got %q", w, g) 330 } 331 332} 333