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 android 16 17import ( 18 "fmt" 19 "io" 20 "reflect" 21 "testing" 22) 23 24type customModule struct { 25 ModuleBase 26 data AndroidMkData 27 distFiles TaggedDistFiles 28} 29 30func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) { 31 m.distFiles = m.GenerateTaggedDistFiles(ctx) 32} 33 34func (m *customModule) AndroidMk() AndroidMkData { 35 return AndroidMkData{ 36 Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) { 37 m.data = data 38 }, 39 } 40} 41 42func (m *customModule) OutputFiles(tag string) (Paths, error) { 43 switch tag { 44 case "": 45 return PathsForTesting("one.out"), nil 46 case ".multiple": 47 return PathsForTesting("two.out", "three/four.out"), nil 48 case ".another-tag": 49 return PathsForTesting("another.out"), nil 50 default: 51 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 52 } 53} 54 55func (m *customModule) AndroidMkEntries() []AndroidMkEntries { 56 return []AndroidMkEntries{ 57 { 58 Class: "CUSTOM_MODULE", 59 DistFiles: m.distFiles, 60 }, 61 } 62} 63 64func customModuleFactory() Module { 65 module := &customModule{} 66 InitAndroidModule(module) 67 return module 68} 69 70func TestAndroidMkSingleton_PassesUpdatedAndroidMkDataToCustomCallback(t *testing.T) { 71 bp := ` 72 custom { 73 name: "foo", 74 required: ["bar"], 75 host_required: ["baz"], 76 target_required: ["qux"], 77 } 78 ` 79 80 config := TestConfig(buildDir, nil, bp, nil) 81 config.inMake = true // Enable androidmk Singleton 82 83 ctx := NewTestContext() 84 ctx.RegisterSingletonType("androidmk", AndroidMkSingleton) 85 ctx.RegisterModuleType("custom", customModuleFactory) 86 ctx.Register(config) 87 88 _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) 89 FailIfErrored(t, errs) 90 _, errs = ctx.PrepareBuildActions(config) 91 FailIfErrored(t, errs) 92 93 m := ctx.ModuleForTests("foo", "").Module().(*customModule) 94 95 assertEqual := func(expected interface{}, actual interface{}) { 96 if !reflect.DeepEqual(expected, actual) { 97 t.Errorf("%q expected, but got %q", expected, actual) 98 } 99 } 100 assertEqual([]string{"bar"}, m.data.Required) 101 assertEqual([]string{"baz"}, m.data.Host_required) 102 assertEqual([]string{"qux"}, m.data.Target_required) 103} 104 105func TestGetDistForGoals(t *testing.T) { 106 testCases := []struct { 107 bp string 108 expectedAndroidMkLines []string 109 }{ 110 { 111 bp: ` 112 custom { 113 name: "foo", 114 dist: { 115 targets: ["my_goal"] 116 } 117 } 118 `, 119 expectedAndroidMkLines: []string{ 120 ".PHONY: my_goal\n", 121 "$(call dist-for-goals,my_goal,one.out:one.out)\n", 122 }, 123 }, 124 { 125 bp: ` 126 custom { 127 name: "foo", 128 dist: { 129 targets: ["my_goal"], 130 tag: ".another-tag", 131 } 132 } 133 `, 134 expectedAndroidMkLines: []string{ 135 ".PHONY: my_goal\n", 136 "$(call dist-for-goals,my_goal,another.out:another.out)\n", 137 }, 138 }, 139 { 140 bp: ` 141 custom { 142 name: "foo", 143 dists: [ 144 { 145 targets: ["my_goal"], 146 tag: ".another-tag", 147 }, 148 ], 149 } 150 `, 151 expectedAndroidMkLines: []string{ 152 ".PHONY: my_goal\n", 153 "$(call dist-for-goals,my_goal,another.out:another.out)\n", 154 }, 155 }, 156 { 157 bp: ` 158 custom { 159 name: "foo", 160 dists: [ 161 { 162 targets: ["my_goal"], 163 }, 164 { 165 targets: ["my_second_goal", "my_third_goal"], 166 }, 167 ], 168 } 169 `, 170 expectedAndroidMkLines: []string{ 171 ".PHONY: my_goal\n", 172 "$(call dist-for-goals,my_goal,one.out:one.out)\n", 173 ".PHONY: my_second_goal my_third_goal\n", 174 "$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n", 175 }, 176 }, 177 { 178 bp: ` 179 custom { 180 name: "foo", 181 dist: { 182 targets: ["my_goal"], 183 }, 184 dists: [ 185 { 186 targets: ["my_second_goal", "my_third_goal"], 187 }, 188 ], 189 } 190 `, 191 expectedAndroidMkLines: []string{ 192 ".PHONY: my_second_goal my_third_goal\n", 193 "$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n", 194 ".PHONY: my_goal\n", 195 "$(call dist-for-goals,my_goal,one.out:one.out)\n", 196 }, 197 }, 198 { 199 bp: ` 200 custom { 201 name: "foo", 202 dist: { 203 targets: ["my_goal", "my_other_goal"], 204 tag: ".multiple", 205 }, 206 dists: [ 207 { 208 targets: ["my_second_goal"], 209 tag: ".multiple", 210 }, 211 { 212 targets: ["my_third_goal"], 213 dir: "test/dir", 214 }, 215 { 216 targets: ["my_fourth_goal"], 217 suffix: ".suffix", 218 }, 219 { 220 targets: ["my_fifth_goal"], 221 dest: "new-name", 222 }, 223 { 224 targets: ["my_sixth_goal"], 225 dest: "new-name", 226 dir: "some/dir", 227 suffix: ".suffix", 228 }, 229 ], 230 } 231 `, 232 expectedAndroidMkLines: []string{ 233 ".PHONY: my_second_goal\n", 234 "$(call dist-for-goals,my_second_goal,two.out:two.out)\n", 235 "$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n", 236 ".PHONY: my_third_goal\n", 237 "$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n", 238 ".PHONY: my_fourth_goal\n", 239 "$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n", 240 ".PHONY: my_fifth_goal\n", 241 "$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n", 242 ".PHONY: my_sixth_goal\n", 243 "$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n", 244 ".PHONY: my_goal my_other_goal\n", 245 "$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n", 246 "$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n", 247 }, 248 }, 249 } 250 251 for _, testCase := range testCases { 252 config := TestConfig(buildDir, nil, testCase.bp, nil) 253 config.inMake = true // Enable androidmk Singleton 254 255 ctx := NewTestContext() 256 ctx.RegisterSingletonType("androidmk", AndroidMkSingleton) 257 ctx.RegisterModuleType("custom", customModuleFactory) 258 ctx.Register(config) 259 260 _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) 261 FailIfErrored(t, errs) 262 _, errs = ctx.PrepareBuildActions(config) 263 FailIfErrored(t, errs) 264 265 module := ctx.ModuleForTests("foo", "").Module().(*customModule) 266 entries := AndroidMkEntriesForTest(t, config, "", module) 267 if len(entries) != 1 { 268 t.Errorf("Expected a single AndroidMk entry, got %d", len(entries)) 269 } 270 androidMkLines := entries[0].GetDistForGoals(module) 271 272 if len(androidMkLines) != len(testCase.expectedAndroidMkLines) { 273 t.Errorf( 274 "Expected %d AndroidMk lines, got %d:\n%v", 275 len(testCase.expectedAndroidMkLines), 276 len(androidMkLines), 277 androidMkLines, 278 ) 279 } 280 for idx, line := range androidMkLines { 281 expectedLine := testCase.expectedAndroidMkLines[idx] 282 if line != expectedLine { 283 t.Errorf( 284 "Expected AndroidMk line to be '%s', got '%s'", 285 line, 286 expectedLine, 287 ) 288 } 289 } 290 } 291} 292