github.com/westcoastroms/westcoastroms-build@v0.0.0-20190928114312-2350e5a73030/build/soong/android/testing.go (about) 1 // Copyright 2017 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 15 package android 16 17 import ( 18 "fmt" 19 "path/filepath" 20 "regexp" 21 "strings" 22 "testing" 23 24 "github.com/google/blueprint" 25 ) 26 27 func NewTestContext() *TestContext { 28 namespaceExportFilter := func(namespace *Namespace) bool { 29 return true 30 } 31 32 nameResolver := NewNameResolver(namespaceExportFilter) 33 ctx := &TestContext{ 34 Context: blueprint.NewContext(), 35 NameResolver: nameResolver, 36 } 37 38 ctx.SetNameInterface(nameResolver) 39 40 return ctx 41 } 42 43 func NewTestArchContext() *TestContext { 44 ctx := NewTestContext() 45 ctx.preDeps = append(ctx.preDeps, registerArchMutator) 46 return ctx 47 } 48 49 type TestContext struct { 50 *blueprint.Context 51 preArch, preDeps, postDeps []RegisterMutatorFunc 52 NameResolver *NameResolver 53 } 54 55 func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) { 56 ctx.preArch = append(ctx.preArch, f) 57 } 58 59 func (ctx *TestContext) PreDepsMutators(f RegisterMutatorFunc) { 60 ctx.preDeps = append(ctx.preDeps, f) 61 } 62 63 func (ctx *TestContext) PostDepsMutators(f RegisterMutatorFunc) { 64 ctx.postDeps = append(ctx.postDeps, f) 65 } 66 67 func (ctx *TestContext) Register() { 68 registerMutators(ctx.Context, ctx.preArch, ctx.preDeps, ctx.postDeps) 69 70 ctx.RegisterSingletonType("env", SingletonFactoryAdaptor(EnvSingleton)) 71 } 72 73 func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule { 74 var module Module 75 ctx.VisitAllModules(func(m blueprint.Module) { 76 if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant { 77 module = m.(Module) 78 } 79 }) 80 81 if module == nil { 82 // find all the modules that do exist 83 allModuleNames := []string{} 84 ctx.VisitAllModules(func(m blueprint.Module) { 85 allModuleNames = append(allModuleNames, m.(Module).Name()+"("+ctx.ModuleSubDir(m)+")") 86 }) 87 88 panic(fmt.Errorf("failed to find module %q variant %q."+ 89 "\nall modules: %v", name, variant, allModuleNames)) 90 } 91 92 return TestingModule{module} 93 } 94 95 // MockFileSystem causes the Context to replace all reads with accesses to the provided map of 96 // filenames to contents stored as a byte slice. 97 func (ctx *TestContext) MockFileSystem(files map[string][]byte) { 98 // no module list file specified; find every file named Blueprints or Android.bp 99 pathsToParse := []string{} 100 for candidate := range files { 101 base := filepath.Base(candidate) 102 if base == "Blueprints" || base == "Android.bp" { 103 pathsToParse = append(pathsToParse, candidate) 104 } 105 } 106 if len(pathsToParse) < 1 { 107 panic(fmt.Sprintf("No Blueprint or Android.bp files found in mock filesystem: %v\n", files)) 108 } 109 files[blueprint.MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n")) 110 111 ctx.Context.MockFileSystem(files) 112 } 113 114 type TestingModule struct { 115 module Module 116 } 117 118 func (m TestingModule) Module() Module { 119 return m.module 120 } 121 122 func (m TestingModule) Rule(rule string) BuildParams { 123 for _, p := range m.module.BuildParamsForTests() { 124 if strings.Contains(p.Rule.String(), rule) { 125 return p 126 } 127 } 128 panic(fmt.Errorf("couldn't find rule %q", rule)) 129 } 130 131 func (m TestingModule) Description(desc string) BuildParams { 132 for _, p := range m.module.BuildParamsForTests() { 133 if p.Description == desc { 134 return p 135 } 136 } 137 panic(fmt.Errorf("couldn't find description %q", desc)) 138 } 139 140 func (m TestingModule) Output(file string) BuildParams { 141 var searchedOutputs []string 142 for _, p := range m.module.BuildParamsForTests() { 143 outputs := append(WritablePaths(nil), p.Outputs...) 144 if p.Output != nil { 145 outputs = append(outputs, p.Output) 146 } 147 for _, f := range outputs { 148 if f.String() == file || f.Rel() == file { 149 return p 150 } 151 searchedOutputs = append(searchedOutputs, f.Rel()) 152 } 153 } 154 panic(fmt.Errorf("couldn't find output %q.\nall outputs: %v", 155 file, searchedOutputs)) 156 } 157 158 func FailIfErrored(t *testing.T, errs []error) { 159 t.Helper() 160 if len(errs) > 0 { 161 for _, err := range errs { 162 t.Error(err) 163 } 164 t.FailNow() 165 } 166 } 167 168 func FailIfNoMatchingErrors(t *testing.T, pattern string, errs []error) { 169 t.Helper() 170 171 matcher, err := regexp.Compile(pattern) 172 if err != nil { 173 t.Errorf("failed to compile regular expression %q because %s", pattern, err) 174 } 175 176 found := false 177 for _, err := range errs { 178 if matcher.FindStringIndex(err.Error()) != nil { 179 found = true 180 break 181 } 182 } 183 if !found { 184 t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs)) 185 for i, err := range errs { 186 t.Errorf("errs[%d] = %s", i, err) 187 } 188 } 189 }