1// Copyright 2020 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 main 16 17import ( 18 "strings" 19 "testing" 20 21 "github.com/google/blueprint/parser" 22 "github.com/google/blueprint/proptools" 23) 24 25var testCases = []struct { 26 name string 27 input string 28 output string 29 property string 30 addSet string 31 removeSet string 32 addLiteral *string 33 setString *string 34 removeProperty bool 35}{ 36 { 37 name: "add", 38 input: ` 39 cc_foo { 40 name: "foo", 41 } 42 `, 43 output: ` 44 cc_foo { 45 name: "foo", 46 deps: ["bar"], 47 } 48 `, 49 property: "deps", 50 addSet: "bar", 51 }, 52 { 53 name: "remove", 54 input: ` 55 cc_foo { 56 name: "foo", 57 deps: ["bar"], 58 } 59 `, 60 output: ` 61 cc_foo { 62 name: "foo", 63 deps: [], 64 } 65 `, 66 property: "deps", 67 removeSet: "bar", 68 }, 69 { 70 name: "nested add", 71 input: ` 72 cc_foo { 73 name: "foo", 74 } 75 `, 76 output: ` 77 cc_foo { 78 name: "foo", 79 arch: { 80 arm: { 81 deps: [ 82 "dep2", 83 "nested_dep",], 84 }, 85 }, 86 } 87 `, 88 property: "arch.arm.deps", 89 addSet: "nested_dep,dep2", 90 }, 91 { 92 name: "nested remove", 93 input: ` 94 cc_foo { 95 name: "foo", 96 arch: { 97 arm: { 98 deps: [ 99 "dep2", 100 "nested_dep", 101 ], 102 }, 103 }, 104 } 105 `, 106 output: ` 107 cc_foo { 108 name: "foo", 109 arch: { 110 arm: { 111 deps: [ 112 ], 113 }, 114 }, 115 } 116 `, 117 property: "arch.arm.deps", 118 removeSet: "nested_dep,dep2", 119 }, 120 { 121 name: "add existing", 122 input: ` 123 cc_foo { 124 name: "foo", 125 arch: { 126 arm: { 127 deps: [ 128 "nested_dep", 129 "dep2", 130 ], 131 }, 132 }, 133 } 134 `, 135 output: ` 136 cc_foo { 137 name: "foo", 138 arch: { 139 arm: { 140 deps: [ 141 "nested_dep", 142 "dep2", 143 ], 144 }, 145 }, 146 } 147 `, 148 property: "arch.arm.deps", 149 addSet: "dep2,dep2", 150 }, 151 { 152 name: "remove missing", 153 input: ` 154 cc_foo { 155 name: "foo", 156 arch: { 157 arm: { 158 deps: [ 159 "nested_dep", 160 "dep2", 161 ], 162 }, 163 }, 164 } 165 `, 166 output: ` 167 cc_foo { 168 name: "foo", 169 arch: { 170 arm: { 171 deps: [ 172 "nested_dep", 173 "dep2", 174 ], 175 }, 176 }, 177 } 178 `, 179 property: "arch.arm.deps", 180 removeSet: "dep3,dep4", 181 }, 182 { 183 name: "remove non existent", 184 input: ` 185 cc_foo { 186 name: "foo", 187 } 188 `, 189 output: ` 190 cc_foo { 191 name: "foo", 192 } 193 `, 194 property: "deps", 195 removeSet: "bar", 196 }, 197 { 198 name: "remove non existent nested", 199 input: ` 200 cc_foo { 201 name: "foo", 202 arch: {}, 203 } 204 `, 205 output: ` 206 cc_foo { 207 name: "foo", 208 arch: {}, 209 } 210 `, 211 property: "arch.arm.deps", 212 removeSet: "dep3,dep4", 213 }, 214 { 215 name: "add numeric sorted", 216 input: ` 217 cc_foo { 218 name: "foo", 219 versions: ["1", "2"], 220 } 221 `, 222 output: ` 223 cc_foo { 224 name: "foo", 225 versions: [ 226 "1", 227 "2", 228 "10", 229 ], 230 } 231 `, 232 property: "versions", 233 addSet: "10", 234 }, 235 { 236 name: "add mixed sorted", 237 input: ` 238 cc_foo { 239 name: "foo", 240 deps: ["bar-v1-bar", "bar-v2-bar"], 241 } 242 `, 243 output: ` 244 cc_foo { 245 name: "foo", 246 deps: [ 247 "bar-v1-bar", 248 "bar-v2-bar", 249 "bar-v10-bar", 250 ], 251 } 252 `, 253 property: "deps", 254 addSet: "bar-v10-bar", 255 }, 256 { 257 name: "add a struct with literal", 258 input: `cc_foo {name: "foo"}`, 259 output: `cc_foo { 260 name: "foo", 261 structs: [ 262 { 263 version: "1", 264 imports: [ 265 "bar1", 266 "bar2", 267 ], 268 }, 269 ], 270} 271`, 272 property: "structs", 273 addLiteral: proptools.StringPtr(`{version: "1", imports: ["bar1", "bar2"]}`), 274 }, 275 { 276 name: "set string", 277 input: ` 278 cc_foo { 279 name: "foo", 280 } 281 `, 282 output: ` 283 cc_foo { 284 name: "foo", 285 foo: "bar", 286 } 287 `, 288 property: "foo", 289 setString: proptools.StringPtr("bar"), 290 }, 291 { 292 name: "set existing string", 293 input: ` 294 cc_foo { 295 name: "foo", 296 foo: "baz", 297 } 298 `, 299 output: ` 300 cc_foo { 301 name: "foo", 302 foo: "bar", 303 } 304 `, 305 property: "foo", 306 setString: proptools.StringPtr("bar"), 307 }, 308 { 309 name: "remove existing property", 310 input: ` 311 cc_foo { 312 name: "foo", 313 foo: "baz", 314 } 315 `, 316 output: ` 317 cc_foo { 318 name: "foo", 319 } 320 `, 321 property: "foo", 322 removeProperty: true, 323 }, { 324 name: "remove nested property", 325 input: ` 326 cc_foo { 327 name: "foo", 328 foo: { 329 bar: "baz", 330 }, 331 } 332 `, 333 output: ` 334 cc_foo { 335 name: "foo", 336 foo: {}, 337 } 338 `, 339 property: "foo.bar", 340 removeProperty: true, 341 }, { 342 name: "remove non-existing property", 343 input: ` 344 cc_foo { 345 name: "foo", 346 foo: "baz", 347 } 348 `, 349 output: ` 350 cc_foo { 351 name: "foo", 352 foo: "baz", 353 } 354 `, 355 property: "bar", 356 removeProperty: true, 357 }, 358} 359 360func simplifyModuleDefinition(def string) string { 361 var result string 362 for _, line := range strings.Split(def, "\n") { 363 result += strings.TrimSpace(line) 364 } 365 return result 366} 367 368func TestProcessModule(t *testing.T) { 369 for i, testCase := range testCases { 370 t.Run(testCase.name, func(t *testing.T) { 371 targetedProperty.Set(testCase.property) 372 addIdents.Set(testCase.addSet) 373 removeIdents.Set(testCase.removeSet) 374 removeProperty = &testCase.removeProperty 375 setString = testCase.setString 376 addLiteral = testCase.addLiteral 377 378 inAst, errs := parser.ParseAndEval("", strings.NewReader(testCase.input), parser.NewScope(nil)) 379 if len(errs) > 0 { 380 for _, err := range errs { 381 t.Errorf(" %s", err) 382 } 383 t.Errorf("failed to parse:") 384 t.Errorf("%+v", testCase) 385 t.FailNow() 386 } 387 388 if inModule, ok := inAst.Defs[0].(*parser.Module); !ok { 389 t.Fatalf(" input must only contain a single module definition: %s", testCase.input) 390 } else { 391 _, errs := processModule(inModule, "", inAst) 392 if len(errs) > 0 { 393 t.Errorf("test case %d:", i) 394 for _, err := range errs { 395 t.Errorf(" %s", err) 396 } 397 } 398 inModuleText, _ := parser.Print(inAst) 399 inModuleString := string(inModuleText) 400 if simplifyModuleDefinition(inModuleString) != simplifyModuleDefinition(testCase.output) { 401 t.Errorf("test case %d:", i) 402 t.Errorf("expected module definition:") 403 t.Errorf(" %s", testCase.output) 404 t.Errorf("actual module definition:") 405 t.Errorf(" %s", inModuleString) 406 } 407 } 408 }) 409 } 410 411} 412