1// Copyright 2024 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 "bytes" 19 "strings" 20 "testing" 21 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 setBool *string 35 removeProperty bool 36 replaceProperty string 37 moveProperty bool 38 newLocation string 39}{ 40 { 41 name: "add", 42 input: ` 43 cc_foo { 44 name: "foo", 45 } 46 `, 47 output: ` 48 cc_foo { 49 name: "foo", 50 deps: ["bar"], 51 } 52 `, 53 property: "deps", 54 addSet: "bar", 55 }, 56 { 57 name: "remove", 58 input: ` 59 cc_foo { 60 name: "foo", 61 deps: ["bar"], 62 } 63 `, 64 output: ` 65 cc_foo { 66 name: "foo", 67 deps: [], 68 } 69 `, 70 property: "deps", 71 removeSet: "bar", 72 }, 73 { 74 name: "nested add", 75 input: ` 76 cc_foo { 77 name: "foo", 78 } 79 `, 80 output: ` 81 cc_foo { 82 name: "foo", 83 arch: { 84 arm: { 85 deps: [ 86 "dep2", 87 "nested_dep",], 88 }, 89 }, 90 } 91 `, 92 property: "arch.arm.deps", 93 addSet: "nested_dep,dep2", 94 }, 95 { 96 name: "nested remove", 97 input: ` 98 cc_foo { 99 name: "foo", 100 arch: { 101 arm: { 102 deps: [ 103 "dep2", 104 "nested_dep", 105 ], 106 }, 107 }, 108 } 109 `, 110 output: ` 111 cc_foo { 112 name: "foo", 113 arch: { 114 arm: { 115 deps: [ 116 ], 117 }, 118 }, 119 } 120 `, 121 property: "arch.arm.deps", 122 removeSet: "nested_dep,dep2", 123 }, 124 { 125 name: "add existing", 126 input: ` 127 cc_foo { 128 name: "foo", 129 arch: { 130 arm: { 131 deps: [ 132 "nested_dep", 133 "dep2", 134 ], 135 }, 136 }, 137 } 138 `, 139 output: ` 140 cc_foo { 141 name: "foo", 142 arch: { 143 arm: { 144 deps: [ 145 "nested_dep", 146 "dep2", 147 ], 148 }, 149 }, 150 } 151 `, 152 property: "arch.arm.deps", 153 addSet: "dep2,dep2", 154 }, 155 { 156 name: "remove missing", 157 input: ` 158 cc_foo { 159 name: "foo", 160 arch: { 161 arm: { 162 deps: [ 163 "nested_dep", 164 "dep2", 165 ], 166 }, 167 }, 168 } 169 `, 170 output: ` 171 cc_foo { 172 name: "foo", 173 arch: { 174 arm: { 175 deps: [ 176 "nested_dep", 177 "dep2", 178 ], 179 }, 180 }, 181 } 182 `, 183 property: "arch.arm.deps", 184 removeSet: "dep3,dep4", 185 }, 186 { 187 name: "remove non existent", 188 input: ` 189 cc_foo { 190 name: "foo", 191 } 192 `, 193 output: ` 194 cc_foo { 195 name: "foo", 196 } 197 `, 198 property: "deps", 199 removeSet: "bar", 200 }, 201 { 202 name: "remove non existent nested", 203 input: ` 204 cc_foo { 205 name: "foo", 206 arch: {}, 207 } 208 `, 209 output: ` 210 cc_foo { 211 name: "foo", 212 arch: {}, 213 } 214 `, 215 property: "arch.arm.deps", 216 removeSet: "dep3,dep4", 217 }, 218 { 219 name: "add numeric sorted", 220 input: ` 221 cc_foo { 222 name: "foo", 223 versions: ["1", "2"], 224 } 225 `, 226 output: ` 227 cc_foo { 228 name: "foo", 229 versions: [ 230 "1", 231 "2", 232 "10", 233 ], 234 } 235 `, 236 property: "versions", 237 addSet: "10", 238 }, 239 { 240 name: "add mixed sorted", 241 input: ` 242 cc_foo { 243 name: "foo", 244 deps: ["bar-v1-bar", "bar-v2-bar"], 245 } 246 `, 247 output: ` 248 cc_foo { 249 name: "foo", 250 deps: [ 251 "bar-v1-bar", 252 "bar-v2-bar", 253 "bar-v10-bar", 254 ], 255 } 256 `, 257 property: "deps", 258 addSet: "bar-v10-bar", 259 }, 260 { 261 name: "add a struct with literal", 262 input: `cc_foo {name: "foo"}`, 263 output: `cc_foo { 264 name: "foo", 265 structs: [ 266 { 267 version: "1", 268 imports: [ 269 "bar1", 270 "bar2", 271 ], 272 }, 273 ], 274} 275`, 276 property: "structs", 277 addLiteral: proptools.StringPtr(`{version: "1", imports: ["bar1", "bar2"]}`), 278 }, 279 { 280 name: "set string", 281 input: ` 282 cc_foo { 283 name: "foo", 284 } 285 `, 286 output: ` 287 cc_foo { 288 name: "foo", 289 foo: "bar", 290 } 291 `, 292 property: "foo", 293 setString: proptools.StringPtr("bar"), 294 }, 295 { 296 name: "set existing string", 297 input: ` 298 cc_foo { 299 name: "foo", 300 foo: "baz", 301 } 302 `, 303 output: ` 304 cc_foo { 305 name: "foo", 306 foo: "bar", 307 } 308 `, 309 property: "foo", 310 setString: proptools.StringPtr("bar"), 311 }, 312 { 313 name: "set bool", 314 input: ` 315 cc_foo { 316 name: "foo", 317 } 318 `, 319 output: ` 320 cc_foo { 321 name: "foo", 322 foo: true, 323 } 324 `, 325 property: "foo", 326 setBool: proptools.StringPtr("true"), 327 }, 328 { 329 name: "set existing bool", 330 input: ` 331 cc_foo { 332 name: "foo", 333 foo: true, 334 } 335 `, 336 output: ` 337 cc_foo { 338 name: "foo", 339 foo: false, 340 } 341 `, 342 property: "foo", 343 setBool: proptools.StringPtr("false"), 344 }, 345 { 346 name: "remove existing property", 347 input: ` 348 cc_foo { 349 name: "foo", 350 foo: "baz", 351 } 352 `, 353 output: ` 354 cc_foo { 355 name: "foo", 356 } 357 `, 358 property: "foo", 359 removeProperty: true, 360 }, { 361 name: "remove nested property", 362 input: ` 363 cc_foo { 364 name: "foo", 365 foo: { 366 bar: "baz", 367 }, 368 } 369 `, 370 output: ` 371 cc_foo { 372 name: "foo", 373 foo: {}, 374 } 375 `, 376 property: "foo.bar", 377 removeProperty: true, 378 }, { 379 name: "remove non-existing property", 380 input: ` 381 cc_foo { 382 name: "foo", 383 foo: "baz", 384 } 385 `, 386 output: ` 387 cc_foo { 388 name: "foo", 389 foo: "baz", 390 } 391 `, 392 property: "bar", 393 removeProperty: true, 394 }, { 395 name: "replace property", 396 property: "deps", 397 input: ` 398 cc_foo { 399 name: "foo", 400 deps: ["baz", "unchanged"], 401 } 402 `, 403 output: ` 404 cc_foo { 405 name: "foo", 406 deps: [ 407 "baz_lib", 408 "unchanged", 409 ], 410 } 411 `, 412 replaceProperty: "baz=baz_lib,foobar=foobar_lib", 413 }, { 414 name: "replace property multiple modules", 415 property: "deps,required", 416 input: ` 417 cc_foo { 418 name: "foo", 419 deps: ["baz", "unchanged"], 420 unchanged: ["baz"], 421 required: ["foobar"], 422 } 423 `, 424 output: ` 425 cc_foo { 426 name: "foo", 427 deps: [ 428 "baz_lib", 429 "unchanged", 430 ], 431 unchanged: ["baz"], 432 required: ["foobar_lib"], 433 } 434 `, 435 replaceProperty: "baz=baz_lib,foobar=foobar_lib", 436 }, { 437 name: "replace property string value", 438 property: "name", 439 input: ` 440 cc_foo { 441 name: "foo", 442 deps: ["baz"], 443 unchanged: ["baz"], 444 required: ["foobar"], 445 } 446 `, 447 output: ` 448 cc_foo { 449 name: "foo_lib", 450 deps: ["baz"], 451 unchanged: ["baz"], 452 required: ["foobar"], 453 } 454 `, 455 replaceProperty: "foo=foo_lib", 456 }, { 457 name: "replace property string and list values", 458 property: "name,deps", 459 input: ` 460 cc_foo { 461 name: "foo", 462 deps: ["baz"], 463 unchanged: ["baz"], 464 required: ["foobar"], 465 } 466 `, 467 output: ` 468 cc_foo { 469 name: "foo_lib", 470 deps: ["baz_lib"], 471 unchanged: ["baz"], 472 required: ["foobar"], 473 } 474 `, 475 replaceProperty: "foo=foo_lib,baz=baz_lib", 476 }, { 477 name: "move contents of property into non-existing property", 478 input: ` 479 cc_foo { 480 name: "foo", 481 bar: ["barContents"], 482 } 483`, 484 output: ` 485 cc_foo { 486 name: "foo", 487 baz: ["barContents"], 488 } 489 `, 490 property: "bar", 491 moveProperty: true, 492 newLocation: "baz", 493 }, { 494 name: "move contents of property into existing property", 495 input: ` 496 cc_foo { 497 name: "foo", 498 baz: ["bazContents"], 499 bar: ["barContents"], 500 } 501 `, 502 output: ` 503 cc_foo { 504 name: "foo", 505 baz: [ 506 "bazContents", 507 "barContents", 508 ], 509 510 } 511 `, 512 property: "bar", 513 moveProperty: true, 514 newLocation: "baz", 515 }, { 516 name: "replace nested", 517 input: ` 518 cc_foo { 519 name: "foo", 520 foo: { 521 bar: "baz", 522 }, 523 } 524 `, 525 output: ` 526 cc_foo { 527 name: "foo", 528 foo: { 529 bar: "baz2", 530 }, 531 } 532 `, 533 property: "foo.bar", 534 replaceProperty: "baz=baz2", 535 }, 536} 537 538func simplifyModuleDefinition(def string) string { 539 var result string 540 for _, line := range strings.Split(def, "\n") { 541 result += strings.TrimSpace(line) 542 } 543 return result 544} 545func TestProcessModule(t *testing.T) { 546 for _, testCase := range testCases { 547 t.Run(testCase.name, func(t *testing.T) { 548 targetedProperties.Set(testCase.property) 549 addIdents.Set(testCase.addSet) 550 removeIdents.Set(testCase.removeSet) 551 removeProperty = &testCase.removeProperty 552 moveProperty = &testCase.moveProperty 553 newLocation = testCase.newLocation 554 setString = testCase.setString 555 setBool = testCase.setBool 556 addLiteral = testCase.addLiteral 557 replaceProperty.Set(testCase.replaceProperty) 558 559 targetedModules.Set("foo") 560 561 out := &bytes.Buffer{} 562 err := processFile("", strings.NewReader(testCase.input), out) 563 if err != nil { 564 t.Fatalf("unexpected error: %s", err.Error()) 565 } 566 if simplifyModuleDefinition(out.String()) != simplifyModuleDefinition(testCase.output) { 567 t.Errorf("expected module definition:") 568 t.Errorf(" %s", testCase.output) 569 t.Errorf("actual module definition:") 570 t.Errorf(" %s", out.String()) 571 } 572 }) 573 } 574} 575 576func TestReplacementsCycleError(t *testing.T) { 577 cycleString := "old1=new1,new1=old1" 578 err := replaceProperty.Set(cycleString) 579 580 if err.Error() != "Duplicated replacement name new1" { 581 t.Errorf("Error message did not match") 582 t.Errorf("Expected ") 583 t.Errorf(" Duplicated replacement name new1") 584 t.Errorf("actual error:") 585 t.Errorf(" %s", err.Error()) 586 t.FailNow() 587 } 588} 589 590func TestReplacementsDuplicatedError(t *testing.T) { 591 cycleString := "a=b,a=c" 592 err := replaceProperty.Set(cycleString) 593 594 if err.Error() != "Duplicated replacement name a" { 595 t.Errorf("Error message did not match") 596 t.Errorf("Expected ") 597 t.Errorf(" Duplicated replacement name a") 598 t.Errorf("actual error:") 599 t.Errorf(" %s", err.Error()) 600 t.FailNow() 601 } 602} 603 604func TestReplacementsMultipleReplacedToSame(t *testing.T) { 605 cycleString := "a=c,d=c" 606 err := replaceProperty.Set(cycleString) 607 608 if err.Error() != "Duplicated replacement name c" { 609 t.Errorf("Error message did not match") 610 t.Errorf("Expected ") 611 t.Errorf(" Duplicated replacement name c") 612 t.Errorf("actual error:") 613 t.Errorf(" %s", err.Error()) 614 t.FailNow() 615 } 616} 617