blob: 4e9c43c8a453ed33e4bdaedb3855501e146cef97 [file] [log] [blame]
Bob Badour6ea14572022-01-23 17:15:46 -08001// 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 "fmt"
21 "html"
22 "os"
Colin Crossbb45f8c2022-01-28 15:18:19 -080023 "reflect"
Bob Badour6ea14572022-01-23 17:15:46 -080024 "regexp"
25 "strings"
26 "testing"
27)
28
29var (
30 horizontalRule = regexp.MustCompile(`^\s*<hr>\s*$`)
31 bodyTag = regexp.MustCompile(`^\s*<body>\s*$`)
32 boilerPlate = regexp.MustCompile(`^\s*(?:<ul class="file-list">|<ul>|</.*)\s*$`)
33 tocTag = regexp.MustCompile(`^\s*<ul class="toc">\s*$`)
34 libraryName = regexp.MustCompile(`^\s*<strong>(.*)</strong>\s\s*used\s\s*by\s*:\s*$`)
35 licenseText = regexp.MustCompile(`^\s*<a id="[^"]{32}"/><pre class="license-text">(.*)$`)
36 titleTag = regexp.MustCompile(`^\s*<title>(.*)</title>\s*$`)
37 h1Tag = regexp.MustCompile(`^\s*<h1>(.*)</h1>\s*$`)
38 usedByTarget = regexp.MustCompile(`^\s*<li>(?:<a href="#id[0-9]+">)?((?:out/(?:[^/<]*/)+)[^/<]*)(?:</a>)?\s*$`)
39 installTarget = regexp.MustCompile(`^\s*<li id="id[0-9]+"><strong>(.*)</strong>\s*$`)
40 libReference = regexp.MustCompile(`^\s*<li><a href="#[^"]{32}">(.*)</a>\s*$`)
41)
42
Colin Crossd0f05c92022-01-27 15:40:29 -080043func TestMain(m *testing.M) {
44 // Change into the parent directory before running the tests
45 // so they can find the testdata directory.
46 if err := os.Chdir(".."); err != nil {
47 fmt.Printf("failed to change to testdata directory: %s\n", err)
48 os.Exit(1)
49 }
50 os.Exit(m.Run())
51}
52
Bob Badour6ea14572022-01-23 17:15:46 -080053func Test(t *testing.T) {
54 tests := []struct {
Colin Crossbb45f8c2022-01-28 15:18:19 -080055 condition string
56 name string
57 roots []string
58 includeTOC bool
59 stripPrefix string
60 title string
61 expectedOut []matcher
62 expectedDeps []string
Bob Badour6ea14572022-01-23 17:15:46 -080063 }{
64 {
65 condition: "firstparty",
66 name: "apex",
67 roots: []string{"highest.apex.meta_lic"},
68 expectedOut: []matcher{
69 hr{},
70 library{"Android"},
71 usedBy{"highest.apex"},
72 usedBy{"highest.apex/bin/bin1"},
73 usedBy{"highest.apex/bin/bin2"},
74 usedBy{"highest.apex/lib/liba.so"},
75 usedBy{"highest.apex/lib/libb.so"},
76 firstParty{},
77 },
Colin Crossbb45f8c2022-01-28 15:18:19 -080078 expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -080079 },
80 {
81 condition: "firstparty",
82 name: "apex+toc",
83 roots: []string{"highest.apex.meta_lic"},
84 includeTOC: true,
85 expectedOut: []matcher{
86 toc{},
87 target{"highest.apex"},
88 uses{"Android"},
89 target{"highest.apex/bin/bin1"},
90 uses{"Android"},
91 target{"highest.apex/bin/bin2"},
92 uses{"Android"},
93 target{"highest.apex/lib/liba.so"},
94 uses{"Android"},
95 target{"highest.apex/lib/libb.so"},
96 uses{"Android"},
97 hr{},
98 library{"Android"},
99 usedBy{"highest.apex"},
100 usedBy{"highest.apex/bin/bin1"},
101 usedBy{"highest.apex/bin/bin2"},
102 usedBy{"highest.apex/lib/liba.so"},
103 usedBy{"highest.apex/lib/libb.so"},
104 firstParty{},
105 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800106 expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800107 },
108 {
109 condition: "firstparty",
110 name: "apex-with-title",
111 roots: []string{"highest.apex.meta_lic"},
112 title: "Emperor",
113 expectedOut: []matcher{
114 pageTitle{"Emperor"},
115 hr{},
116 library{"Android"},
117 usedBy{"highest.apex"},
118 usedBy{"highest.apex/bin/bin1"},
119 usedBy{"highest.apex/bin/bin2"},
120 usedBy{"highest.apex/lib/liba.so"},
121 usedBy{"highest.apex/lib/libb.so"},
122 firstParty{},
123 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800124 expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800125 },
126 {
127 condition: "firstparty",
128 name: "apex-with-title+toc",
129 roots: []string{"highest.apex.meta_lic"},
130 includeTOC: true,
131 title: "Emperor",
132 expectedOut: []matcher{
133 pageTitle{"Emperor"},
134 toc{},
135 target{"highest.apex"},
136 uses{"Android"},
137 target{"highest.apex/bin/bin1"},
138 uses{"Android"},
139 target{"highest.apex/bin/bin2"},
140 uses{"Android"},
141 target{"highest.apex/lib/liba.so"},
142 uses{"Android"},
143 target{"highest.apex/lib/libb.so"},
144 uses{"Android"},
145 hr{},
146 library{"Android"},
147 usedBy{"highest.apex"},
148 usedBy{"highest.apex/bin/bin1"},
149 usedBy{"highest.apex/bin/bin2"},
150 usedBy{"highest.apex/lib/liba.so"},
151 usedBy{"highest.apex/lib/libb.so"},
152 firstParty{},
153 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800154 expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800155 },
156 {
157 condition: "firstparty",
158 name: "container",
159 roots: []string{"container.zip.meta_lic"},
160 expectedOut: []matcher{
161 hr{},
162 library{"Android"},
163 usedBy{"container.zip"},
164 usedBy{"container.zip/bin1"},
165 usedBy{"container.zip/bin2"},
166 usedBy{"container.zip/liba.so"},
167 usedBy{"container.zip/libb.so"},
168 firstParty{},
169 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800170 expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800171 },
172 {
173 condition: "firstparty",
174 name: "application",
175 roots: []string{"application.meta_lic"},
176 expectedOut: []matcher{
177 hr{},
178 library{"Android"},
179 usedBy{"application"},
180 firstParty{},
181 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800182 expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800183 },
184 {
185 condition: "firstparty",
186 name: "binary",
187 roots: []string{"bin/bin1.meta_lic"},
188 expectedOut: []matcher{
189 hr{},
190 library{"Android"},
191 usedBy{"bin/bin1"},
192 firstParty{},
193 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800194 expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800195 },
196 {
197 condition: "firstparty",
198 name: "library",
199 roots: []string{"lib/libd.so.meta_lic"},
200 expectedOut: []matcher{
201 hr{},
202 library{"Android"},
203 usedBy{"lib/libd.so"},
204 firstParty{},
205 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800206 expectedDeps: []string{"testdata/firstparty/FIRST_PARTY_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800207 },
208 {
209 condition: "notice",
210 name: "apex",
211 roots: []string{"highest.apex.meta_lic"},
212 expectedOut: []matcher{
213 hr{},
214 library{"Android"},
215 usedBy{"highest.apex"},
216 usedBy{"highest.apex/bin/bin1"},
217 usedBy{"highest.apex/bin/bin2"},
218 usedBy{"highest.apex/lib/libb.so"},
219 firstParty{},
220 hr{},
221 library{"Device"},
222 usedBy{"highest.apex/bin/bin1"},
223 usedBy{"highest.apex/lib/liba.so"},
224 library{"External"},
225 usedBy{"highest.apex/bin/bin1"},
226 notice{},
227 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800228 expectedDeps: []string{
229 "testdata/firstparty/FIRST_PARTY_LICENSE",
230 "testdata/notice/NOTICE_LICENSE",
231 },
Bob Badour6ea14572022-01-23 17:15:46 -0800232 },
233 {
234 condition: "notice",
235 name: "container",
236 roots: []string{"container.zip.meta_lic"},
237 expectedOut: []matcher{
238 hr{},
239 library{"Android"},
240 usedBy{"container.zip"},
241 usedBy{"container.zip/bin1"},
242 usedBy{"container.zip/bin2"},
243 usedBy{"container.zip/libb.so"},
244 firstParty{},
245 hr{},
246 library{"Device"},
247 usedBy{"container.zip/bin1"},
248 usedBy{"container.zip/liba.so"},
249 library{"External"},
250 usedBy{"container.zip/bin1"},
251 notice{},
252 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800253 expectedDeps: []string{
254 "testdata/firstparty/FIRST_PARTY_LICENSE",
255 "testdata/notice/NOTICE_LICENSE",
256 },
Bob Badour6ea14572022-01-23 17:15:46 -0800257 },
258 {
259 condition: "notice",
260 name: "application",
261 roots: []string{"application.meta_lic"},
262 expectedOut: []matcher{
263 hr{},
264 library{"Android"},
265 usedBy{"application"},
266 firstParty{},
267 hr{},
268 library{"Device"},
269 usedBy{"application"},
270 notice{},
271 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800272 expectedDeps: []string{
273 "testdata/firstparty/FIRST_PARTY_LICENSE",
274 "testdata/notice/NOTICE_LICENSE",
275 },
Bob Badour6ea14572022-01-23 17:15:46 -0800276 },
277 {
278 condition: "notice",
279 name: "binary",
280 roots: []string{"bin/bin1.meta_lic"},
281 expectedOut: []matcher{
282 hr{},
283 library{"Android"},
284 usedBy{"bin/bin1"},
285 firstParty{},
286 hr{},
287 library{"Device"},
288 usedBy{"bin/bin1"},
289 library{"External"},
290 usedBy{"bin/bin1"},
291 notice{},
292 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800293 expectedDeps: []string{
294 "testdata/firstparty/FIRST_PARTY_LICENSE",
295 "testdata/notice/NOTICE_LICENSE",
296 },
Bob Badour6ea14572022-01-23 17:15:46 -0800297 },
298 {
299 condition: "notice",
300 name: "library",
301 roots: []string{"lib/libd.so.meta_lic"},
302 expectedOut: []matcher{
303 hr{},
304 library{"External"},
305 usedBy{"lib/libd.so"},
306 notice{},
307 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800308 expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800309 },
310 {
311 condition: "reciprocal",
312 name: "apex",
313 roots: []string{"highest.apex.meta_lic"},
314 expectedOut: []matcher{
315 hr{},
316 library{"Android"},
317 usedBy{"highest.apex"},
318 usedBy{"highest.apex/bin/bin1"},
319 usedBy{"highest.apex/bin/bin2"},
320 usedBy{"highest.apex/lib/libb.so"},
321 firstParty{},
322 hr{},
323 library{"Device"},
324 usedBy{"highest.apex/bin/bin1"},
325 usedBy{"highest.apex/lib/liba.so"},
326 library{"External"},
327 usedBy{"highest.apex/bin/bin1"},
328 reciprocal{},
329 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800330 expectedDeps: []string{
331 "testdata/firstparty/FIRST_PARTY_LICENSE",
332 "testdata/reciprocal/RECIPROCAL_LICENSE",
333 },
Bob Badour6ea14572022-01-23 17:15:46 -0800334 },
335 {
336 condition: "reciprocal",
337 name: "container",
338 roots: []string{"container.zip.meta_lic"},
339 expectedOut: []matcher{
340 hr{},
341 library{"Android"},
342 usedBy{"container.zip"},
343 usedBy{"container.zip/bin1"},
344 usedBy{"container.zip/bin2"},
345 usedBy{"container.zip/libb.so"},
346 firstParty{},
347 hr{},
348 library{"Device"},
349 usedBy{"container.zip/bin1"},
350 usedBy{"container.zip/liba.so"},
351 library{"External"},
352 usedBy{"container.zip/bin1"},
353 reciprocal{},
354 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800355 expectedDeps: []string{
356 "testdata/firstparty/FIRST_PARTY_LICENSE",
357 "testdata/reciprocal/RECIPROCAL_LICENSE",
358 },
Bob Badour6ea14572022-01-23 17:15:46 -0800359 },
360 {
361 condition: "reciprocal",
362 name: "application",
363 roots: []string{"application.meta_lic"},
364 expectedOut: []matcher{
365 hr{},
366 library{"Android"},
367 usedBy{"application"},
368 firstParty{},
369 hr{},
370 library{"Device"},
371 usedBy{"application"},
372 reciprocal{},
373 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800374 expectedDeps: []string{
375 "testdata/firstparty/FIRST_PARTY_LICENSE",
376 "testdata/reciprocal/RECIPROCAL_LICENSE",
377 },
Bob Badour6ea14572022-01-23 17:15:46 -0800378 },
379 {
380 condition: "reciprocal",
381 name: "binary",
382 roots: []string{"bin/bin1.meta_lic"},
383 expectedOut: []matcher{
384 hr{},
385 library{"Android"},
386 usedBy{"bin/bin1"},
387 firstParty{},
388 hr{},
389 library{"Device"},
390 usedBy{"bin/bin1"},
391 library{"External"},
392 usedBy{"bin/bin1"},
393 reciprocal{},
394 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800395 expectedDeps: []string{
396 "testdata/firstparty/FIRST_PARTY_LICENSE",
397 "testdata/reciprocal/RECIPROCAL_LICENSE",
398 },
Bob Badour6ea14572022-01-23 17:15:46 -0800399 },
400 {
401 condition: "reciprocal",
402 name: "library",
403 roots: []string{"lib/libd.so.meta_lic"},
404 expectedOut: []matcher{
405 hr{},
406 library{"External"},
407 usedBy{"lib/libd.so"},
408 notice{},
409 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800410 expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800411 },
412 {
413 condition: "restricted",
414 name: "apex",
415 roots: []string{"highest.apex.meta_lic"},
416 expectedOut: []matcher{
417 hr{},
418 library{"Android"},
419 usedBy{"highest.apex"},
420 usedBy{"highest.apex/bin/bin1"},
421 usedBy{"highest.apex/bin/bin2"},
422 firstParty{},
423 hr{},
424 library{"Android"},
425 usedBy{"highest.apex/bin/bin2"},
426 usedBy{"highest.apex/lib/libb.so"},
427 library{"Device"},
428 usedBy{"highest.apex/bin/bin1"},
429 usedBy{"highest.apex/lib/liba.so"},
430 restricted{},
431 hr{},
432 library{"External"},
433 usedBy{"highest.apex/bin/bin1"},
434 reciprocal{},
435 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800436 expectedDeps: []string{
437 "testdata/firstparty/FIRST_PARTY_LICENSE",
438 "testdata/reciprocal/RECIPROCAL_LICENSE",
439 "testdata/restricted/RESTRICTED_LICENSE",
440 },
Bob Badour6ea14572022-01-23 17:15:46 -0800441 },
442 {
443 condition: "restricted",
444 name: "container",
445 roots: []string{"container.zip.meta_lic"},
446 expectedOut: []matcher{
447 hr{},
448 library{"Android"},
449 usedBy{"container.zip"},
450 usedBy{"container.zip/bin1"},
451 usedBy{"container.zip/bin2"},
452 firstParty{},
453 hr{},
454 library{"Android"},
455 usedBy{"container.zip/bin2"},
456 usedBy{"container.zip/libb.so"},
457 library{"Device"},
458 usedBy{"container.zip/bin1"},
459 usedBy{"container.zip/liba.so"},
460 restricted{},
461 hr{},
462 library{"External"},
463 usedBy{"container.zip/bin1"},
464 reciprocal{},
465 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800466 expectedDeps: []string{
467 "testdata/firstparty/FIRST_PARTY_LICENSE",
468 "testdata/reciprocal/RECIPROCAL_LICENSE",
469 "testdata/restricted/RESTRICTED_LICENSE",
470 },
Bob Badour6ea14572022-01-23 17:15:46 -0800471 },
472 {
473 condition: "restricted",
474 name: "application",
475 roots: []string{"application.meta_lic"},
476 expectedOut: []matcher{
477 hr{},
478 library{"Android"},
479 usedBy{"application"},
480 firstParty{},
481 hr{},
482 library{"Device"},
483 usedBy{"application"},
484 restricted{},
485 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800486 expectedDeps: []string{
487 "testdata/firstparty/FIRST_PARTY_LICENSE",
488 "testdata/restricted/RESTRICTED_LICENSE",
489 },
Bob Badour6ea14572022-01-23 17:15:46 -0800490 },
491 {
492 condition: "restricted",
493 name: "binary",
494 roots: []string{"bin/bin1.meta_lic"},
495 expectedOut: []matcher{
496 hr{},
497 library{"Android"},
498 usedBy{"bin/bin1"},
499 firstParty{},
500 hr{},
501 library{"Device"},
502 usedBy{"bin/bin1"},
503 restricted{},
504 hr{},
505 library{"External"},
506 usedBy{"bin/bin1"},
507 reciprocal{},
508 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800509 expectedDeps: []string{
510 "testdata/firstparty/FIRST_PARTY_LICENSE",
511 "testdata/reciprocal/RECIPROCAL_LICENSE",
512 "testdata/restricted/RESTRICTED_LICENSE",
513 },
Bob Badour6ea14572022-01-23 17:15:46 -0800514 },
515 {
516 condition: "restricted",
517 name: "library",
518 roots: []string{"lib/libd.so.meta_lic"},
519 expectedOut: []matcher{
520 hr{},
521 library{"External"},
522 usedBy{"lib/libd.so"},
523 notice{},
524 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800525 expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800526 },
527 {
528 condition: "proprietary",
529 name: "apex",
530 roots: []string{"highest.apex.meta_lic"},
531 expectedOut: []matcher{
532 hr{},
533 library{"Android"},
534 usedBy{"highest.apex/bin/bin2"},
535 usedBy{"highest.apex/lib/libb.so"},
536 restricted{},
537 hr{},
538 library{"Android"},
539 usedBy{"highest.apex"},
540 usedBy{"highest.apex/bin/bin1"},
541 firstParty{},
542 hr{},
543 library{"Android"},
544 usedBy{"highest.apex/bin/bin2"},
545 library{"Device"},
546 usedBy{"highest.apex/bin/bin1"},
547 usedBy{"highest.apex/lib/liba.so"},
548 library{"External"},
549 usedBy{"highest.apex/bin/bin1"},
550 proprietary{},
551 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800552 expectedDeps: []string{
553 "testdata/firstparty/FIRST_PARTY_LICENSE",
554 "testdata/proprietary/PROPRIETARY_LICENSE",
555 "testdata/restricted/RESTRICTED_LICENSE",
556 },
Bob Badour6ea14572022-01-23 17:15:46 -0800557 },
558 {
559 condition: "proprietary",
560 name: "container",
561 roots: []string{"container.zip.meta_lic"},
562 expectedOut: []matcher{
563 hr{},
564 library{"Android"},
565 usedBy{"container.zip/bin2"},
566 usedBy{"container.zip/libb.so"},
567 restricted{},
568 hr{},
569 library{"Android"},
570 usedBy{"container.zip"},
571 usedBy{"container.zip/bin1"},
572 firstParty{},
573 hr{},
574 library{"Android"},
575 usedBy{"container.zip/bin2"},
576 library{"Device"},
577 usedBy{"container.zip/bin1"},
578 usedBy{"container.zip/liba.so"},
579 library{"External"},
580 usedBy{"container.zip/bin1"},
581 proprietary{},
582 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800583 expectedDeps: []string{
584 "testdata/firstparty/FIRST_PARTY_LICENSE",
585 "testdata/proprietary/PROPRIETARY_LICENSE",
586 "testdata/restricted/RESTRICTED_LICENSE",
587 },
Bob Badour6ea14572022-01-23 17:15:46 -0800588 },
589 {
590 condition: "proprietary",
591 name: "application",
592 roots: []string{"application.meta_lic"},
593 expectedOut: []matcher{
594 hr{},
595 library{"Android"},
596 usedBy{"application"},
597 firstParty{},
598 hr{},
599 library{"Device"},
600 usedBy{"application"},
601 proprietary{},
602 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800603 expectedDeps: []string{
604 "testdata/firstparty/FIRST_PARTY_LICENSE",
605 "testdata/proprietary/PROPRIETARY_LICENSE",
606 },
Bob Badour6ea14572022-01-23 17:15:46 -0800607 },
608 {
609 condition: "proprietary",
610 name: "binary",
611 roots: []string{"bin/bin1.meta_lic"},
612 expectedOut: []matcher{
613 hr{},
614 library{"Android"},
615 usedBy{"bin/bin1"},
616 firstParty{},
617 hr{},
618 library{"Device"},
619 usedBy{"bin/bin1"},
620 library{"External"},
621 usedBy{"bin/bin1"},
622 proprietary{},
623 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800624 expectedDeps: []string{
625 "testdata/firstparty/FIRST_PARTY_LICENSE",
626 "testdata/proprietary/PROPRIETARY_LICENSE",
627 },
Bob Badour6ea14572022-01-23 17:15:46 -0800628 },
629 {
630 condition: "proprietary",
631 name: "library",
632 roots: []string{"lib/libd.so.meta_lic"},
633 expectedOut: []matcher{
634 hr{},
635 library{"External"},
636 usedBy{"lib/libd.so"},
637 notice{},
638 },
Colin Crossbb45f8c2022-01-28 15:18:19 -0800639 expectedDeps: []string{"testdata/notice/NOTICE_LICENSE"},
Bob Badour6ea14572022-01-23 17:15:46 -0800640 },
641 }
642 for _, tt := range tests {
643 t.Run(tt.condition+" "+tt.name, func(t *testing.T) {
644 stdout := &bytes.Buffer{}
645 stderr := &bytes.Buffer{}
646
647 rootFiles := make([]string, 0, len(tt.roots))
648 for _, r := range tt.roots {
649 rootFiles = append(rootFiles, "testdata/"+tt.condition+"/"+r)
650 }
651
Colin Crossbb45f8c2022-01-28 15:18:19 -0800652 var deps []string
653
654 ctx := context{stdout, stderr, os.DirFS("."), tt.includeTOC, tt.stripPrefix, tt.title, &deps}
Bob Badour6ea14572022-01-23 17:15:46 -0800655
656 err := htmlNotice(&ctx, rootFiles...)
657 if err != nil {
Colin Cross179ec3e2022-01-27 15:47:09 -0800658 t.Fatalf("htmlnotice: error = %v, stderr = %v", err, stderr)
Bob Badour6ea14572022-01-23 17:15:46 -0800659 return
660 }
661 if stderr.Len() > 0 {
662 t.Errorf("htmlnotice: gotStderr = %v, want none", stderr)
663 }
664
665 t.Logf("got stdout: %s", stdout.String())
666
667 t.Logf("want stdout: %s", matcherList(tt.expectedOut).String())
668
669 out := bufio.NewScanner(stdout)
670 lineno := 0
671 inBody := false
672 hasTitle := false
673 ttle, expectTitle := tt.expectedOut[0].(pageTitle)
674 for out.Scan() {
675 line := out.Text()
676 if strings.TrimLeft(line, " ") == "" {
677 continue
678 }
679 if !inBody {
680 if expectTitle {
681 if tl := checkTitle(line); 0 < len(tl) {
682 if tl != ttle.t {
683 t.Errorf("htmlnotice: unexpected title: got %q, want %q", tl, ttle.t)
684 }
685 hasTitle = true
686 }
687 }
688 if bodyTag.MatchString(line) {
689 inBody = true
690 if expectTitle && !hasTitle {
691 t.Errorf("htmlnotice: missing title: got no <title> tag, want <title>%s</title>", ttle.t)
692 }
693 }
694 continue
695 }
696 if boilerPlate.MatchString(line) {
697 continue
698 }
699 if len(tt.expectedOut) <= lineno {
700 t.Errorf("htmlnotice: unexpected output at line %d: got %q, want nothing (wanted %d lines)", lineno+1, line, len(tt.expectedOut))
701 } else if !tt.expectedOut[lineno].isMatch(line) {
702 t.Errorf("htmlnotice: unexpected output at line %d: got %q, want %q", lineno+1, line, tt.expectedOut[lineno].String())
703 }
704 lineno++
705 }
706 if !inBody {
707 t.Errorf("htmlnotice: missing body: got no <body> tag, want <body> tag followed by %s", matcherList(tt.expectedOut).String())
708 return
709 }
710 for ; lineno < len(tt.expectedOut); lineno++ {
711 t.Errorf("htmlnotice: missing output line %d: ended early, want %q", lineno+1, tt.expectedOut[lineno].String())
712 }
Colin Crossbb45f8c2022-01-28 15:18:19 -0800713
714 t.Logf("got deps: %q", deps)
715
716 t.Logf("want deps: %q", tt.expectedDeps)
717
718 if g, w := deps, tt.expectedDeps; !reflect.DeepEqual(g, w) {
719 t.Errorf("unexpected deps, wanted:\n%s\ngot:\n%s\n",
720 strings.Join(w, "\n"), strings.Join(g, "\n"))
721 }
Bob Badour6ea14572022-01-23 17:15:46 -0800722 })
723 }
724}
725
726func checkTitle(line string) string {
727 groups := titleTag.FindStringSubmatch(line)
728 if len(groups) != 2 {
729 return ""
730 }
731 return groups[1]
732}
733
734type matcher interface {
735 isMatch(line string) bool
736 String() string
737}
738
739type pageTitle struct {
740 t string
741}
742
743func (m pageTitle) isMatch(line string) bool {
744 groups := h1Tag.FindStringSubmatch(line)
745 if len(groups) != 2 {
746 return false
747 }
748 return groups[1] == html.EscapeString(m.t)
749}
750
751func (m pageTitle) String() string {
752 return " <h1>" + html.EscapeString(m.t) + "</h1>"
753}
754
755type toc struct{}
756
757func (m toc) isMatch(line string) bool {
758 return tocTag.MatchString(line)
759}
760
761func (m toc) String() string {
762 return ` <ul class="toc">`
763}
764
765type target struct {
766 name string
767}
768
769func (m target) isMatch(line string) bool {
770 groups := installTarget.FindStringSubmatch(line)
771 if len(groups) != 2 {
772 return false
773 }
774 return strings.HasPrefix(groups[1], "out/") && strings.HasSuffix(groups[1], "/"+html.EscapeString(m.name))
775}
776
777func (m target) String() string {
778 return ` <li id="id#"><strong>` + html.EscapeString(m.name) + `</strong>`
779}
780
781type uses struct {
782 name string
783}
784
785func (m uses) isMatch(line string) bool {
786 groups := libReference.FindStringSubmatch(line)
787 if len(groups) != 2 {
788 return false
789 }
790 return groups[1] == html.EscapeString(m.name)
791}
792
793func (m uses) String() string {
794 return ` <li><a href="#hash">` + html.EscapeString(m.name) + `</a>`
795}
796
797type hr struct{}
798
799func (m hr) isMatch(line string) bool {
800 return horizontalRule.MatchString(line)
801}
802
803func (m hr) String() string {
804 return " <hr>"
805}
806
807type library struct {
808 name string
809}
810
811func (m library) isMatch(line string) bool {
812 groups := libraryName.FindStringSubmatch(line)
813 if len(groups) != 2 {
814 return false
815 }
816 return groups[1] == html.EscapeString(m.name)
817}
818
819func (m library) String() string {
820 return " <strong>" + html.EscapeString(m.name) + "</strong> used by:"
821}
822
823type usedBy struct {
824 name string
825}
826
827func (m usedBy) isMatch(line string) bool {
828 groups := usedByTarget.FindStringSubmatch(line)
829 if len(groups) != 2 {
830 return false
831 }
832 return strings.HasPrefix(groups[1], "out/") && strings.HasSuffix(groups[1], "/"+html.EscapeString(m.name))
833}
834
835func (m usedBy) String() string {
836 return " <li>out/.../" + html.EscapeString(m.name)
837}
838
839func matchesText(line, text string) bool {
840 groups := licenseText.FindStringSubmatch(line)
841 if len(groups) != 2 {
842 return false
843 }
844 return groups[1] == html.EscapeString(text)
845}
846
847func expectedText(text string) string {
848 return ` <a href="#hash"/><pre class="license-text">` + html.EscapeString(text)
849}
850
851type firstParty struct{}
852
853func (m firstParty) isMatch(line string) bool {
854 return matchesText(line, "&&&First Party License&&&")
855}
856
857func (m firstParty) String() string {
858 return expectedText("&&&First Party License&&&")
859}
860
861type notice struct{}
862
863func (m notice) isMatch(line string) bool {
864 return matchesText(line, "%%%Notice License%%%")
865}
866
867func (m notice) String() string {
868 return expectedText("%%%Notice License%%%")
869}
870
871type reciprocal struct{}
872
873func (m reciprocal) isMatch(line string) bool {
874 return matchesText(line, "$$$Reciprocal License$$$")
875}
876
877func (m reciprocal) String() string {
878 return expectedText("$$$Reciprocal License$$$")
879}
880
881type restricted struct{}
882
883func (m restricted) isMatch(line string) bool {
884 return matchesText(line, "###Restricted License###")
885}
886
887func (m restricted) String() string {
888 return expectedText("###Restricted License###")
889}
890
891type proprietary struct{}
892
893func (m proprietary) isMatch(line string) bool {
894 return matchesText(line, "@@@Proprietary License@@@")
895}
896
897func (m proprietary) String() string {
898 return expectedText("@@@Proprietary License@@@")
899}
900
901type matcherList []matcher
902
903func (l matcherList) String() string {
904 var sb strings.Builder
905 for _, m := range l {
906 s := m.String()
907 if s[:3] == s[len(s)-3:] {
908 fmt.Fprintln(&sb)
909 }
910 fmt.Fprintf(&sb, "%s\n", s)
911 if s[:3] == s[len(s)-3:] {
912 fmt.Fprintln(&sb)
913 }
914 }
915 return sb.String()
916}