1// Copyright 2021 Google LLC 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 "bufio" 19 "bytes" 20 "encoding/xml" 21 "fmt" 22 "os" 23 "reflect" 24 "regexp" 25 "strings" 26 "testing" 27 28 "android/soong/tools/compliance" 29) 30 31var ( 32 installTarget = regexp.MustCompile(`^<file-name contentId="[^"]{32}" lib="([^"]*)">([^<]+)</file-name>`) 33 licenseText = regexp.MustCompile(`^<file-content contentId="[^"]{32}"><![[]CDATA[[]([^]]*)[]][]]></file-content>`) 34) 35 36func TestMain(m *testing.M) { 37 // Change into the parent directory before running the tests 38 // so they can find the testdata directory. 39 if err := os.Chdir(".."); err != nil { 40 fmt.Printf("failed to change to testdata directory: %s\n", err) 41 os.Exit(1) 42 } 43 os.Exit(m.Run()) 44} 45 46func Test(t *testing.T) { 47 tests := []struct { 48 condition string 49 name string 50 outDir string 51 roots []string 52 stripPrefix string 53 expectedOut []matcher 54 expectedDeps []string 55 }{ 56 { 57 condition: "firstparty", 58 name: "apex", 59 roots: []string{"highest.apex.meta_lic"}, 60 expectedOut: []matcher{ 61 target{"highest.apex", "Android"}, 62 target{"highest.apex/bin/bin1", "Android"}, 63 target{"highest.apex/bin/bin2", "Android"}, 64 target{"highest.apex/lib/liba.so", "Android"}, 65 target{"highest.apex/lib/libb.so", "Android"}, 66 firstParty{}, 67 }, 68 expectedDeps: []string{ 69 "testdata/firstparty/FIRST_PARTY_LICENSE", 70 "testdata/firstparty/bin/bin1.meta_lic", 71 "testdata/firstparty/bin/bin2.meta_lic", 72 "testdata/firstparty/highest.apex.meta_lic", 73 "testdata/firstparty/lib/liba.so.meta_lic", 74 "testdata/firstparty/lib/libb.so.meta_lic", 75 "testdata/firstparty/lib/libc.a.meta_lic", 76 "testdata/firstparty/lib/libd.so.meta_lic", 77 }, 78 }, 79 { 80 condition: "firstparty", 81 name: "container", 82 roots: []string{"container.zip.meta_lic"}, 83 expectedOut: []matcher{ 84 target{"container.zip", "Android"}, 85 target{"container.zip/bin1", "Android"}, 86 target{"container.zip/bin2", "Android"}, 87 target{"container.zip/liba.so", "Android"}, 88 target{"container.zip/libb.so", "Android"}, 89 firstParty{}, 90 }, 91 expectedDeps: []string{ 92 "testdata/firstparty/FIRST_PARTY_LICENSE", 93 "testdata/firstparty/bin/bin1.meta_lic", 94 "testdata/firstparty/bin/bin2.meta_lic", 95 "testdata/firstparty/container.zip.meta_lic", 96 "testdata/firstparty/lib/liba.so.meta_lic", 97 "testdata/firstparty/lib/libb.so.meta_lic", 98 "testdata/firstparty/lib/libc.a.meta_lic", 99 "testdata/firstparty/lib/libd.so.meta_lic", 100 }, 101 }, 102 { 103 condition: "firstparty", 104 name: "application", 105 roots: []string{"application.meta_lic"}, 106 expectedOut: []matcher{ 107 target{"application", "Android"}, 108 firstParty{}, 109 }, 110 expectedDeps: []string{ 111 "testdata/firstparty/FIRST_PARTY_LICENSE", 112 "testdata/firstparty/application.meta_lic", 113 "testdata/firstparty/bin/bin3.meta_lic", 114 "testdata/firstparty/lib/liba.so.meta_lic", 115 "testdata/firstparty/lib/libb.so.meta_lic", 116 }, 117 }, 118 { 119 condition: "firstparty", 120 name: "binary", 121 roots: []string{"bin/bin1.meta_lic"}, 122 expectedOut: []matcher{ 123 target{"bin/bin1", "Android"}, 124 firstParty{}, 125 }, 126 expectedDeps: []string{ 127 "testdata/firstparty/FIRST_PARTY_LICENSE", 128 "testdata/firstparty/bin/bin1.meta_lic", 129 "testdata/firstparty/lib/liba.so.meta_lic", 130 "testdata/firstparty/lib/libc.a.meta_lic", 131 }, 132 }, 133 { 134 condition: "firstparty", 135 name: "library", 136 roots: []string{"lib/libd.so.meta_lic"}, 137 expectedOut: []matcher{ 138 target{"lib/libd.so", "Android"}, 139 firstParty{}, 140 }, 141 expectedDeps: []string{ 142 "testdata/firstparty/FIRST_PARTY_LICENSE", 143 "testdata/firstparty/lib/libd.so.meta_lic", 144 }, 145 }, 146 { 147 condition: "notice", 148 name: "apex", 149 roots: []string{"highest.apex.meta_lic"}, 150 expectedOut: []matcher{ 151 target{"highest.apex", "Android"}, 152 target{"highest.apex/bin/bin1", "Android"}, 153 target{"highest.apex/bin/bin1", "Device"}, 154 target{"highest.apex/bin/bin1", "External"}, 155 target{"highest.apex/bin/bin2", "Android"}, 156 target{"highest.apex/lib/liba.so", "Device"}, 157 target{"highest.apex/lib/libb.so", "Android"}, 158 firstParty{}, 159 notice{}, 160 }, 161 expectedDeps: []string{ 162 "testdata/firstparty/FIRST_PARTY_LICENSE", 163 "testdata/notice/NOTICE_LICENSE", 164 "testdata/notice/bin/bin1.meta_lic", 165 "testdata/notice/bin/bin2.meta_lic", 166 "testdata/notice/highest.apex.meta_lic", 167 "testdata/notice/lib/liba.so.meta_lic", 168 "testdata/notice/lib/libb.so.meta_lic", 169 "testdata/notice/lib/libc.a.meta_lic", 170 "testdata/notice/lib/libd.so.meta_lic", 171 }, 172 }, 173 { 174 condition: "notice", 175 name: "container", 176 roots: []string{"container.zip.meta_lic"}, 177 expectedOut: []matcher{ 178 target{"container.zip", "Android"}, 179 target{"container.zip/bin1", "Android"}, 180 target{"container.zip/bin1", "Device"}, 181 target{"container.zip/bin1", "External"}, 182 target{"container.zip/bin2", "Android"}, 183 target{"container.zip/liba.so", "Device"}, 184 target{"container.zip/libb.so", "Android"}, 185 firstParty{}, 186 notice{}, 187 }, 188 expectedDeps: []string{ 189 "testdata/firstparty/FIRST_PARTY_LICENSE", 190 "testdata/notice/NOTICE_LICENSE", 191 "testdata/notice/bin/bin1.meta_lic", 192 "testdata/notice/bin/bin2.meta_lic", 193 "testdata/notice/container.zip.meta_lic", 194 "testdata/notice/lib/liba.so.meta_lic", 195 "testdata/notice/lib/libb.so.meta_lic", 196 "testdata/notice/lib/libc.a.meta_lic", 197 "testdata/notice/lib/libd.so.meta_lic", 198 }, 199 }, 200 { 201 condition: "notice", 202 name: "application", 203 roots: []string{"application.meta_lic"}, 204 expectedOut: []matcher{ 205 target{"application", "Android"}, 206 target{"application", "Device"}, 207 firstParty{}, 208 notice{}, 209 }, 210 expectedDeps: []string{ 211 "testdata/firstparty/FIRST_PARTY_LICENSE", 212 "testdata/notice/NOTICE_LICENSE", 213 "testdata/notice/application.meta_lic", 214 "testdata/notice/bin/bin3.meta_lic", 215 "testdata/notice/lib/liba.so.meta_lic", 216 "testdata/notice/lib/libb.so.meta_lic", 217 }, 218 }, 219 { 220 condition: "notice", 221 name: "binary", 222 roots: []string{"bin/bin1.meta_lic"}, 223 expectedOut: []matcher{ 224 target{"bin/bin1", "Android"}, 225 target{"bin/bin1", "Device"}, 226 target{"bin/bin1", "External"}, 227 firstParty{}, 228 notice{}, 229 }, 230 expectedDeps: []string{ 231 "testdata/firstparty/FIRST_PARTY_LICENSE", 232 "testdata/notice/NOTICE_LICENSE", 233 "testdata/notice/bin/bin1.meta_lic", 234 "testdata/notice/lib/liba.so.meta_lic", 235 "testdata/notice/lib/libc.a.meta_lic", 236 }, 237 }, 238 { 239 condition: "notice", 240 name: "library", 241 roots: []string{"lib/libd.so.meta_lic"}, 242 expectedOut: []matcher{ 243 target{"lib/libd.so", "External"}, 244 notice{}, 245 }, 246 expectedDeps: []string{ 247 "testdata/notice/NOTICE_LICENSE", 248 "testdata/notice/lib/libd.so.meta_lic", 249 }, 250 }, 251 { 252 condition: "reciprocal", 253 name: "apex", 254 roots: []string{"highest.apex.meta_lic"}, 255 expectedOut: []matcher{ 256 target{"highest.apex", "Android"}, 257 target{"highest.apex/bin/bin1", "Android"}, 258 target{"highest.apex/bin/bin1", "Device"}, 259 target{"highest.apex/bin/bin1", "External"}, 260 target{"highest.apex/bin/bin2", "Android"}, 261 target{"highest.apex/lib/liba.so", "Device"}, 262 target{"highest.apex/lib/libb.so", "Android"}, 263 firstParty{}, 264 reciprocal{}, 265 }, 266 expectedDeps: []string{ 267 "testdata/firstparty/FIRST_PARTY_LICENSE", 268 "testdata/reciprocal/RECIPROCAL_LICENSE", 269 "testdata/reciprocal/bin/bin1.meta_lic", 270 "testdata/reciprocal/bin/bin2.meta_lic", 271 "testdata/reciprocal/highest.apex.meta_lic", 272 "testdata/reciprocal/lib/liba.so.meta_lic", 273 "testdata/reciprocal/lib/libb.so.meta_lic", 274 "testdata/reciprocal/lib/libc.a.meta_lic", 275 "testdata/reciprocal/lib/libd.so.meta_lic", 276 }, 277 }, 278 { 279 condition: "reciprocal", 280 name: "container", 281 roots: []string{"container.zip.meta_lic"}, 282 expectedOut: []matcher{ 283 target{"container.zip", "Android"}, 284 target{"container.zip/bin1", "Android"}, 285 target{"container.zip/bin1", "Device"}, 286 target{"container.zip/bin1", "External"}, 287 target{"container.zip/bin2", "Android"}, 288 target{"container.zip/liba.so", "Device"}, 289 target{"container.zip/libb.so", "Android"}, 290 firstParty{}, 291 reciprocal{}, 292 }, 293 expectedDeps: []string{ 294 "testdata/firstparty/FIRST_PARTY_LICENSE", 295 "testdata/reciprocal/RECIPROCAL_LICENSE", 296 "testdata/reciprocal/bin/bin1.meta_lic", 297 "testdata/reciprocal/bin/bin2.meta_lic", 298 "testdata/reciprocal/container.zip.meta_lic", 299 "testdata/reciprocal/lib/liba.so.meta_lic", 300 "testdata/reciprocal/lib/libb.so.meta_lic", 301 "testdata/reciprocal/lib/libc.a.meta_lic", 302 "testdata/reciprocal/lib/libd.so.meta_lic", 303 }, 304 }, 305 { 306 condition: "reciprocal", 307 name: "application", 308 roots: []string{"application.meta_lic"}, 309 expectedOut: []matcher{ 310 target{"application", "Android"}, 311 target{"application", "Device"}, 312 firstParty{}, 313 reciprocal{}, 314 }, 315 expectedDeps: []string{ 316 "testdata/firstparty/FIRST_PARTY_LICENSE", 317 "testdata/reciprocal/RECIPROCAL_LICENSE", 318 "testdata/reciprocal/application.meta_lic", 319 "testdata/reciprocal/bin/bin3.meta_lic", 320 "testdata/reciprocal/lib/liba.so.meta_lic", 321 "testdata/reciprocal/lib/libb.so.meta_lic", 322 }, 323 }, 324 { 325 condition: "reciprocal", 326 name: "binary", 327 roots: []string{"bin/bin1.meta_lic"}, 328 expectedOut: []matcher{ 329 target{"bin/bin1", "Android"}, 330 target{"bin/bin1", "Device"}, 331 target{"bin/bin1", "External"}, 332 firstParty{}, 333 reciprocal{}, 334 }, 335 expectedDeps: []string{ 336 "testdata/firstparty/FIRST_PARTY_LICENSE", 337 "testdata/reciprocal/RECIPROCAL_LICENSE", 338 "testdata/reciprocal/bin/bin1.meta_lic", 339 "testdata/reciprocal/lib/liba.so.meta_lic", 340 "testdata/reciprocal/lib/libc.a.meta_lic", 341 }, 342 }, 343 { 344 condition: "reciprocal", 345 name: "library", 346 roots: []string{"lib/libd.so.meta_lic"}, 347 expectedOut: []matcher{ 348 target{"lib/libd.so", "External"}, 349 notice{}, 350 }, 351 expectedDeps: []string{ 352 "testdata/notice/NOTICE_LICENSE", 353 "testdata/reciprocal/lib/libd.so.meta_lic", 354 }, 355 }, 356 { 357 condition: "restricted", 358 name: "apex", 359 roots: []string{"highest.apex.meta_lic"}, 360 expectedOut: []matcher{ 361 target{"highest.apex", "Android"}, 362 target{"highest.apex/bin/bin1", "Android"}, 363 target{"highest.apex/bin/bin1", "Device"}, 364 target{"highest.apex/bin/bin1", "External"}, 365 target{"highest.apex/bin/bin2", "Android"}, 366 target{"highest.apex/bin/bin2", "Android"}, 367 target{"highest.apex/lib/liba.so", "Device"}, 368 target{"highest.apex/lib/libb.so", "Android"}, 369 firstParty{}, 370 restricted{}, 371 reciprocal{}, 372 }, 373 expectedDeps: []string{ 374 "testdata/firstparty/FIRST_PARTY_LICENSE", 375 "testdata/reciprocal/RECIPROCAL_LICENSE", 376 "testdata/restricted/RESTRICTED_LICENSE", 377 "testdata/restricted/bin/bin1.meta_lic", 378 "testdata/restricted/bin/bin2.meta_lic", 379 "testdata/restricted/highest.apex.meta_lic", 380 "testdata/restricted/lib/liba.so.meta_lic", 381 "testdata/restricted/lib/libb.so.meta_lic", 382 "testdata/restricted/lib/libc.a.meta_lic", 383 "testdata/restricted/lib/libd.so.meta_lic", 384 }, 385 }, 386 { 387 condition: "restricted", 388 name: "container", 389 roots: []string{"container.zip.meta_lic"}, 390 expectedOut: []matcher{ 391 target{"container.zip", "Android"}, 392 target{"container.zip/bin1", "Android"}, 393 target{"container.zip/bin1", "Device"}, 394 target{"container.zip/bin1", "External"}, 395 target{"container.zip/bin2", "Android"}, 396 target{"container.zip/bin2", "Android"}, 397 target{"container.zip/liba.so", "Device"}, 398 target{"container.zip/libb.so", "Android"}, 399 firstParty{}, 400 restricted{}, 401 reciprocal{}, 402 }, 403 expectedDeps: []string{ 404 "testdata/firstparty/FIRST_PARTY_LICENSE", 405 "testdata/reciprocal/RECIPROCAL_LICENSE", 406 "testdata/restricted/RESTRICTED_LICENSE", 407 "testdata/restricted/bin/bin1.meta_lic", 408 "testdata/restricted/bin/bin2.meta_lic", 409 "testdata/restricted/container.zip.meta_lic", 410 "testdata/restricted/lib/liba.so.meta_lic", 411 "testdata/restricted/lib/libb.so.meta_lic", 412 "testdata/restricted/lib/libc.a.meta_lic", 413 "testdata/restricted/lib/libd.so.meta_lic", 414 }, 415 }, 416 { 417 condition: "restricted", 418 name: "application", 419 roots: []string{"application.meta_lic"}, 420 expectedOut: []matcher{ 421 target{"application", "Android"}, 422 target{"application", "Device"}, 423 firstParty{}, 424 restricted{}, 425 }, 426 expectedDeps: []string{ 427 "testdata/firstparty/FIRST_PARTY_LICENSE", 428 "testdata/restricted/RESTRICTED_LICENSE", 429 "testdata/restricted/application.meta_lic", 430 "testdata/restricted/bin/bin3.meta_lic", 431 "testdata/restricted/lib/liba.so.meta_lic", 432 "testdata/restricted/lib/libb.so.meta_lic", 433 }, 434 }, 435 { 436 condition: "restricted", 437 name: "binary", 438 roots: []string{"bin/bin1.meta_lic"}, 439 expectedOut: []matcher{ 440 target{"bin/bin1", "Android"}, 441 target{"bin/bin1", "Device"}, 442 target{"bin/bin1", "External"}, 443 firstParty{}, 444 restricted{}, 445 reciprocal{}, 446 }, 447 expectedDeps: []string{ 448 "testdata/firstparty/FIRST_PARTY_LICENSE", 449 "testdata/reciprocal/RECIPROCAL_LICENSE", 450 "testdata/restricted/RESTRICTED_LICENSE", 451 "testdata/restricted/bin/bin1.meta_lic", 452 "testdata/restricted/lib/liba.so.meta_lic", 453 "testdata/restricted/lib/libc.a.meta_lic", 454 }, 455 }, 456 { 457 condition: "restricted", 458 name: "library", 459 roots: []string{"lib/libd.so.meta_lic"}, 460 expectedOut: []matcher{ 461 target{"lib/libd.so", "External"}, 462 notice{}, 463 }, 464 expectedDeps: []string{ 465 "testdata/notice/NOTICE_LICENSE", 466 "testdata/restricted/lib/libd.so.meta_lic", 467 }, 468 }, 469 { 470 condition: "proprietary", 471 name: "apex", 472 roots: []string{"highest.apex.meta_lic"}, 473 expectedOut: []matcher{ 474 target{"highest.apex", "Android"}, 475 target{"highest.apex/bin/bin1", "Android"}, 476 target{"highest.apex/bin/bin1", "Device"}, 477 target{"highest.apex/bin/bin1", "External"}, 478 target{"highest.apex/bin/bin2", "Android"}, 479 target{"highest.apex/bin/bin2", "Android"}, 480 target{"highest.apex/lib/liba.so", "Device"}, 481 target{"highest.apex/lib/libb.so", "Android"}, 482 restricted{}, 483 firstParty{}, 484 proprietary{}, 485 }, 486 expectedDeps: []string{ 487 "testdata/firstparty/FIRST_PARTY_LICENSE", 488 "testdata/proprietary/PROPRIETARY_LICENSE", 489 "testdata/proprietary/bin/bin1.meta_lic", 490 "testdata/proprietary/bin/bin2.meta_lic", 491 "testdata/proprietary/highest.apex.meta_lic", 492 "testdata/proprietary/lib/liba.so.meta_lic", 493 "testdata/proprietary/lib/libb.so.meta_lic", 494 "testdata/proprietary/lib/libc.a.meta_lic", 495 "testdata/proprietary/lib/libd.so.meta_lic", 496 "testdata/restricted/RESTRICTED_LICENSE", 497 }, 498 }, 499 { 500 condition: "proprietary", 501 name: "container", 502 roots: []string{"container.zip.meta_lic"}, 503 expectedOut: []matcher{ 504 target{"container.zip", "Android"}, 505 target{"container.zip/bin1", "Android"}, 506 target{"container.zip/bin1", "Device"}, 507 target{"container.zip/bin1", "External"}, 508 target{"container.zip/bin2", "Android"}, 509 target{"container.zip/bin2", "Android"}, 510 target{"container.zip/liba.so", "Device"}, 511 target{"container.zip/libb.so", "Android"}, 512 restricted{}, 513 firstParty{}, 514 proprietary{}, 515 }, 516 expectedDeps: []string{ 517 "testdata/firstparty/FIRST_PARTY_LICENSE", 518 "testdata/proprietary/PROPRIETARY_LICENSE", 519 "testdata/proprietary/bin/bin1.meta_lic", 520 "testdata/proprietary/bin/bin2.meta_lic", 521 "testdata/proprietary/container.zip.meta_lic", 522 "testdata/proprietary/lib/liba.so.meta_lic", 523 "testdata/proprietary/lib/libb.so.meta_lic", 524 "testdata/proprietary/lib/libc.a.meta_lic", 525 "testdata/proprietary/lib/libd.so.meta_lic", 526 "testdata/restricted/RESTRICTED_LICENSE", 527 }, 528 }, 529 { 530 condition: "proprietary", 531 name: "application", 532 roots: []string{"application.meta_lic"}, 533 expectedOut: []matcher{ 534 target{"application", "Android"}, 535 target{"application", "Device"}, 536 firstParty{}, 537 proprietary{}, 538 }, 539 expectedDeps: []string{ 540 "testdata/firstparty/FIRST_PARTY_LICENSE", 541 "testdata/proprietary/PROPRIETARY_LICENSE", 542 "testdata/proprietary/application.meta_lic", 543 "testdata/proprietary/bin/bin3.meta_lic", 544 "testdata/proprietary/lib/liba.so.meta_lic", 545 "testdata/proprietary/lib/libb.so.meta_lic", 546 }, 547 }, 548 { 549 condition: "proprietary", 550 name: "binary", 551 roots: []string{"bin/bin1.meta_lic"}, 552 expectedOut: []matcher{ 553 target{"bin/bin1", "Android"}, 554 target{"bin/bin1", "Device"}, 555 target{"bin/bin1", "External"}, 556 firstParty{}, 557 proprietary{}, 558 }, 559 expectedDeps: []string{ 560 "testdata/firstparty/FIRST_PARTY_LICENSE", 561 "testdata/proprietary/PROPRIETARY_LICENSE", 562 "testdata/proprietary/bin/bin1.meta_lic", 563 "testdata/proprietary/lib/liba.so.meta_lic", 564 "testdata/proprietary/lib/libc.a.meta_lic", 565 }, 566 }, 567 { 568 condition: "proprietary", 569 name: "library", 570 roots: []string{"lib/libd.so.meta_lic"}, 571 expectedOut: []matcher{ 572 target{"lib/libd.so", "External"}, 573 notice{}, 574 }, 575 expectedDeps: []string{ 576 "testdata/notice/NOTICE_LICENSE", 577 "testdata/proprietary/lib/libd.so.meta_lic", 578 }, 579 }, 580 } 581 for _, tt := range tests { 582 t.Run(tt.condition+" "+tt.name, func(t *testing.T) { 583 stdout := &bytes.Buffer{} 584 stderr := &bytes.Buffer{} 585 586 rootFiles := make([]string, 0, len(tt.roots)) 587 for _, r := range tt.roots { 588 rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r) 589 } 590 591 var deps []string 592 593 ctx := context{stdout, stderr, compliance.GetFS(tt.outDir), "", []string{tt.stripPrefix}, "", &deps} 594 595 err := xmlNotice(&ctx, rootFiles...) 596 if err != nil { 597 t.Fatalf("xmlnotice: error = %v, stderr = %v", err, stderr) 598 return 599 } 600 if stderr.Len() > 0 { 601 t.Errorf("xmlnotice: gotStderr = %v, want none", stderr) 602 } 603 604 t.Logf("got stdout: %s", stdout.String()) 605 606 t.Logf("want stdout: %s", matcherList(tt.expectedOut).String()) 607 608 out := bufio.NewScanner(stdout) 609 lineno := 0 610 inBody := false 611 outOfBody := true 612 for out.Scan() { 613 line := out.Text() 614 if strings.TrimLeft(line, " ") == "" { 615 continue 616 } 617 if lineno == 0 && !inBody && `<?xml version="1.0" encoding="utf-8"?>` == line { 618 continue 619 } 620 if !inBody { 621 if "<licenses>" == line { 622 inBody = true 623 outOfBody = false 624 } 625 continue 626 } else if "</licenses>" == line { 627 outOfBody = true 628 continue 629 } 630 631 if len(tt.expectedOut) <= lineno { 632 t.Errorf("xmlnotice: unexpected output at line %d: got %q, want nothing (wanted %d lines)", lineno+1, line, len(tt.expectedOut)) 633 } else if !tt.expectedOut[lineno].isMatch(line) { 634 t.Errorf("xmlnotice: unexpected output at line %d: got %q, want %q", lineno+1, line, tt.expectedOut[lineno].String()) 635 } 636 lineno++ 637 } 638 if !inBody { 639 t.Errorf("xmlnotice: missing <licenses> tag: got no <licenses> tag, want <licenses> tag on 2nd line") 640 } 641 if !outOfBody { 642 t.Errorf("xmlnotice: missing </licenses> tag: got no </licenses> tag, want </licenses> tag on last line") 643 } 644 for ; lineno < len(tt.expectedOut); lineno++ { 645 t.Errorf("xmlnotice: missing output line %d: ended early, want %q", lineno+1, tt.expectedOut[lineno].String()) 646 } 647 648 t.Logf("got deps: %q", deps) 649 650 t.Logf("want deps: %q", tt.expectedDeps) 651 652 if g, w := deps, tt.expectedDeps; !reflect.DeepEqual(g, w) { 653 t.Errorf("unexpected deps, wanted:\n%s\ngot:\n%s\n", 654 strings.Join(w, "\n"), strings.Join(g, "\n")) 655 } 656 }) 657 } 658} 659 660func escape(s string) string { 661 b := &bytes.Buffer{} 662 xml.EscapeText(b, []byte(s)) 663 return b.String() 664} 665 666type matcher interface { 667 isMatch(line string) bool 668 String() string 669} 670 671type target struct { 672 name string 673 lib string 674} 675 676func (m target) isMatch(line string) bool { 677 groups := installTarget.FindStringSubmatch(line) 678 if len(groups) != 3 { 679 return false 680 } 681 return groups[1] == escape(m.lib) && strings.HasPrefix(groups[2], "out/") && strings.HasSuffix(groups[2], "/"+escape(m.name)) 682} 683 684func (m target) String() string { 685 return `<file-name contentId="hash" lib="` + escape(m.lib) + `">` + escape(m.name) + `</file-name>` 686} 687 688func matchesText(line, text string) bool { 689 groups := licenseText.FindStringSubmatch(line) 690 if len(groups) != 2 { 691 return false 692 } 693 return groups[1] == escape(text + "\n") 694} 695 696func expectedText(text string) string { 697 return `<file-content contentId="hash"><![CDATA[` + escape(text + "\n") + `]]></file-content>` 698} 699 700type firstParty struct{} 701 702func (m firstParty) isMatch(line string) bool { 703 return matchesText(line, "&&&First Party License&&&") 704} 705 706func (m firstParty) String() string { 707 return expectedText("&&&First Party License&&&") 708} 709 710type notice struct{} 711 712func (m notice) isMatch(line string) bool { 713 return matchesText(line, "%%%Notice License%%%") 714} 715 716func (m notice) String() string { 717 return expectedText("%%%Notice License%%%") 718} 719 720type reciprocal struct{} 721 722func (m reciprocal) isMatch(line string) bool { 723 return matchesText(line, "$$$Reciprocal License$$$") 724} 725 726func (m reciprocal) String() string { 727 return expectedText("$$$Reciprocal License$$$") 728} 729 730type restricted struct{} 731 732func (m restricted) isMatch(line string) bool { 733 return matchesText(line, "###Restricted License###") 734} 735 736func (m restricted) String() string { 737 return expectedText("###Restricted License###") 738} 739 740type proprietary struct{} 741 742func (m proprietary) isMatch(line string) bool { 743 return matchesText(line, "@@@Proprietary License@@@") 744} 745 746func (m proprietary) String() string { 747 return expectedText("@@@Proprietary License@@@") 748} 749 750type matcherList []matcher 751 752func (l matcherList) String() string { 753 var sb strings.Builder 754 fmt.Fprintln(&sb, `<?xml version="1.0" encoding="utf-8"?>`) 755 fmt.Fprintln(&sb, `<licenses>`) 756 for _, m := range l { 757 s := m.String() 758 fmt.Fprintln(&sb, s) 759 if _, ok := m.(target); !ok { 760 fmt.Fprintln(&sb) 761 } 762 } 763 fmt.Fprintln(&sb, `/<licenses>`) 764 return sb.String() 765} 766