xref: /aosp_15_r20/external/spdx-tools/idsearcher/idsearcher_test.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2
3package idsearcher
4
5import (
6	"testing"
7)
8
9// ===== 2.1 Searcher top-level function tests =====
10func Test2_1SearcherCanFillInIDs(t *testing.T) {
11	packageName := "project2"
12	dirRoot := "../testdata/project2/"
13	config := &Config2_1{
14		NamespacePrefix: "https://github.com/swinslow/spdx-docs/spdx-go/testdata-",
15	}
16
17	doc, err := BuildIDsDocument2_1(packageName, dirRoot, config)
18	if err != nil {
19		t.Fatalf("expected nil error, got %v", err)
20	}
21	if doc == nil {
22		t.Fatalf("expected non-nil Document, got nil")
23	}
24
25	// not checking all contents of doc, see builder tests for those
26
27	// get the package and its files, checking size of each
28	if doc.Packages == nil {
29		t.Fatalf("expected non-nil Packages, got nil")
30	}
31	if len(doc.Packages) != 1 {
32		t.Fatalf("expected Packages len to be 1, got %d", len(doc.Packages))
33	}
34	pkg := doc.Packages[0]
35	if pkg == nil {
36		t.Fatalf("expected non-nil pkg, got nil")
37	}
38
39	if pkg.Files == nil {
40		t.Fatalf("expected non-nil Files, got nil")
41	}
42	if len(pkg.Files) != 6 {
43		t.Fatalf("expected Files len to be 6, got %d", len(pkg.Files))
44	}
45
46	fileInFolder := pkg.Files[0]
47	if fileInFolder.LicenseInfoInFiles == nil {
48		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
49	}
50	if len(fileInFolder.LicenseInfoInFiles) != 1 {
51		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileInFolder.LicenseInfoInFiles))
52	}
53	if fileInFolder.LicenseInfoInFiles[0] != "MIT" {
54		t.Errorf("expected %v, got %v", "MIT", fileInFolder.LicenseInfoInFiles[0])
55	}
56	if fileInFolder.LicenseConcluded != "MIT" {
57		t.Errorf("expected %v, got %v", "MIT", fileInFolder.LicenseConcluded)
58	}
59
60	fileTrailingComment := pkg.Files[1]
61	if fileTrailingComment.LicenseInfoInFiles == nil {
62		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
63	}
64	if len(fileTrailingComment.LicenseInfoInFiles) != 1 {
65		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileTrailingComment.LicenseInfoInFiles))
66	}
67	if fileTrailingComment.LicenseInfoInFiles[0] != "GPL-2.0-or-later" {
68		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", fileTrailingComment.LicenseInfoInFiles[0])
69	}
70	if fileTrailingComment.LicenseConcluded != "GPL-2.0-or-later" {
71		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", fileTrailingComment.LicenseConcluded)
72	}
73
74	fileHasDuplicateID := pkg.Files[2]
75	if fileHasDuplicateID.LicenseInfoInFiles == nil {
76		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
77	}
78	if len(fileHasDuplicateID.LicenseInfoInFiles) != 1 {
79		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileHasDuplicateID.LicenseInfoInFiles))
80	}
81	if fileHasDuplicateID.LicenseInfoInFiles[0] != "MIT" {
82		t.Errorf("expected %v, got %v", "MIT", fileHasDuplicateID.LicenseInfoInFiles[0])
83	}
84	if fileHasDuplicateID.LicenseConcluded != "MIT" {
85		t.Errorf("expected %v, got %v", "MIT", fileHasDuplicateID.LicenseConcluded)
86	}
87
88	fileHasID := pkg.Files[3]
89	if fileHasID.LicenseInfoInFiles == nil {
90		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
91	}
92	if len(fileHasID.LicenseInfoInFiles) != 2 {
93		t.Fatalf("expected LicenseInfoInFiles len to be 2, got %d", len(fileHasID.LicenseInfoInFiles))
94	}
95	if fileHasID.LicenseInfoInFiles[0] != "Apache-2.0" {
96		t.Errorf("expected %v, got %v", "Apache-2.0", fileHasID.LicenseInfoInFiles[0])
97	}
98	if fileHasID.LicenseInfoInFiles[1] != "GPL-2.0-or-later" {
99		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", fileHasID.LicenseInfoInFiles[1])
100	}
101	if fileHasID.LicenseConcluded != "Apache-2.0 OR GPL-2.0-or-later" {
102		t.Errorf("expected %v, got %v", "Apache-2.0 OR GPL-2.0-or-later", fileHasID.LicenseConcluded)
103	}
104
105	fileMultipleIDs := pkg.Files[4]
106	if fileMultipleIDs.LicenseInfoInFiles == nil {
107		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
108	}
109	if len(fileMultipleIDs.LicenseInfoInFiles) != 5 {
110		t.Fatalf("expected LicenseInfoInFiles len to be 5, got %d", len(fileMultipleIDs.LicenseInfoInFiles))
111	}
112	if fileMultipleIDs.LicenseInfoInFiles[0] != "BSD-2-Clause" {
113		t.Errorf("expected %v, got %v", "BSD-2-Clause", fileMultipleIDs.LicenseInfoInFiles[0])
114	}
115	if fileMultipleIDs.LicenseInfoInFiles[1] != "BSD-3-Clause" {
116		t.Errorf("expected %v, got %v", "BSD-3-Clause", fileMultipleIDs.LicenseInfoInFiles[1])
117	}
118	// here, DO NOT keep the +
119	if fileMultipleIDs.LicenseInfoInFiles[2] != "EPL-1.0" {
120		t.Errorf("expected %v, got %v", "EPL-1.0", fileMultipleIDs.LicenseInfoInFiles[2])
121	}
122	if fileMultipleIDs.LicenseInfoInFiles[3] != "ISC" {
123		t.Errorf("expected %v, got %v", "ISC", fileMultipleIDs.LicenseInfoInFiles[3])
124	}
125	if fileMultipleIDs.LicenseInfoInFiles[4] != "MIT" {
126		t.Errorf("expected %v, got %v", "MIT", fileMultipleIDs.LicenseInfoInFiles[4])
127	}
128	if fileMultipleIDs.LicenseConcluded != "((MIT AND BSD-3-Clause) OR ISC) AND BSD-2-Clause AND EPL-1.0+" {
129		t.Errorf("expected %v, got %v", "((MIT AND BSD-3-Clause) OR ISC) AND BSD-2-Clause AND EPL-1.0+", fileMultipleIDs.LicenseConcluded)
130	}
131
132	fileNoID := pkg.Files[5]
133	if fileNoID.LicenseInfoInFiles == nil {
134		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
135	}
136	if len(fileNoID.LicenseInfoInFiles) != 1 {
137		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileNoID.LicenseInfoInFiles))
138	}
139	if fileNoID.LicenseInfoInFiles[0] != "NOASSERTION" {
140		t.Errorf("expected %v, got %v", "NOASSERTION", fileNoID.LicenseInfoInFiles[0])
141	}
142	if fileNoID.LicenseConcluded != "NOASSERTION" {
143		t.Errorf("expected %v, got %v", "NOASSERTION", fileNoID.LicenseConcluded)
144	}
145
146	// and finally, the package should have all of these licenses
147	if pkg.PackageLicenseInfoFromFiles == nil {
148		t.Fatalf("expected non-nil PackageLicenseInfoFromFiles, got nil")
149	}
150	if len(pkg.PackageLicenseInfoFromFiles) != 7 {
151		t.Fatalf("expected PackageLicenseInfoFromFiles len to be 7, got %d", len(pkg.PackageLicenseInfoFromFiles))
152	}
153	if pkg.PackageLicenseInfoFromFiles[0] != "Apache-2.0" {
154		t.Errorf("expected %v, got %v", "Apache-2.0", pkg.PackageLicenseInfoFromFiles[0])
155	}
156	if pkg.PackageLicenseInfoFromFiles[1] != "BSD-2-Clause" {
157		t.Errorf("expected %v, got %v", "BSD-2-Clause", pkg.PackageLicenseInfoFromFiles[1])
158	}
159	if pkg.PackageLicenseInfoFromFiles[2] != "BSD-3-Clause" {
160		t.Errorf("expected %v, got %v", "BSD-3-Clause", pkg.PackageLicenseInfoFromFiles[2])
161	}
162	// here, DO NOT keep the +
163	if pkg.PackageLicenseInfoFromFiles[3] != "EPL-1.0" {
164		t.Errorf("expected %v, got %v", "EPL-1.0", pkg.PackageLicenseInfoFromFiles[3])
165	}
166	if pkg.PackageLicenseInfoFromFiles[4] != "GPL-2.0-or-later" {
167		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", pkg.PackageLicenseInfoFromFiles[4])
168	}
169	if pkg.PackageLicenseInfoFromFiles[5] != "ISC" {
170		t.Errorf("expected %v, got %v", "ISC", pkg.PackageLicenseInfoFromFiles[5])
171	}
172	if pkg.PackageLicenseInfoFromFiles[6] != "MIT" {
173		t.Errorf("expected %v, got %v", "MIT", pkg.PackageLicenseInfoFromFiles[6])
174	}
175
176}
177
178func Test2_1SearcherCanFillInIDsAndIgnorePaths(t *testing.T) {
179	packageName := "project3"
180	dirRoot := "../testdata/project3/"
181	config := &Config2_1{
182		NamespacePrefix: "https://github.com/swinslow/spdx-docs/spdx-go/testdata-",
183		BuilderPathsIgnored: []string{
184			"**/ignoredir/",
185			"/excludedir/",
186			"**/ignorefile.txt",
187			"/alsoEXCLUDEthis.txt",
188		},
189		SearcherPathsIgnored: []string{
190			"**/dontscan.txt",
191		},
192	}
193
194	doc, err := BuildIDsDocument2_1(packageName, dirRoot, config)
195	if err != nil {
196		t.Fatalf("expected nil error, got %v", err)
197	}
198	if doc == nil {
199		t.Fatalf("expected non-nil Document, got nil")
200	}
201
202	// not checking all contents of doc, see builder tests for those
203
204	// get the package and its files, checking licenses for each, and
205	// confirming NOASSERTION for those that are skipped
206	pkg := doc.Packages[0]
207	if pkg == nil {
208		t.Fatalf("expected non-nil pkg, got nil")
209	}
210	if len(pkg.Files) != 5 {
211		t.Fatalf("expected len %d, got %d", 5, len(pkg.Files))
212	}
213
214	f := pkg.Files[0]
215	if f.FileName != "./dontscan.txt" {
216		t.Errorf("expected %v, got %v", "./dontscan.txt", f.FileName)
217	}
218	if len(f.LicenseInfoInFiles) != 1 {
219		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
220	}
221	if f.LicenseInfoInFiles[0] != "NOASSERTION" {
222		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseInfoInFiles[0])
223	}
224	if f.LicenseConcluded != "NOASSERTION" {
225		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseConcluded)
226	}
227
228	f = pkg.Files[1]
229	if f.FileName != "./keep/keep.txt" {
230		t.Errorf("expected %v, got %v", "./keep/keep.txt", f.FileName)
231	}
232	if len(f.LicenseInfoInFiles) != 1 {
233		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
234	}
235	if f.LicenseInfoInFiles[0] != "MIT" {
236		t.Errorf("expected %s, got %s", "MIT", f.LicenseInfoInFiles[0])
237	}
238	if f.LicenseConcluded != "MIT" {
239		t.Errorf("expected %s, got %s", "MIT", f.LicenseConcluded)
240	}
241
242	f = pkg.Files[2]
243	if f.FileName != "./keep.txt" {
244		t.Errorf("expected %v, got %v", "./keep.txt", f.FileName)
245	}
246	if len(f.LicenseInfoInFiles) != 1 {
247		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
248	}
249	if f.LicenseInfoInFiles[0] != "NOASSERTION" {
250		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseInfoInFiles[0])
251	}
252	if f.LicenseConcluded != "NOASSERTION" {
253		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseConcluded)
254	}
255
256	f = pkg.Files[3]
257	if f.FileName != "./subdir/keep/dontscan.txt" {
258		t.Errorf("expected %v, got %v", "./subdir/keep/dontscan.txt", f.FileName)
259	}
260	if len(f.LicenseInfoInFiles) != 1 {
261		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
262	}
263	if f.LicenseInfoInFiles[0] != "NOASSERTION" {
264		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseInfoInFiles[0])
265	}
266	if f.LicenseConcluded != "NOASSERTION" {
267		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseConcluded)
268	}
269
270	f = pkg.Files[4]
271	if f.FileName != "./subdir/keep/keep.txt" {
272		t.Errorf("expected %v, got %v", "./subdir/keep/keep.txt", f.FileName)
273	}
274	if len(f.LicenseInfoInFiles) != 1 {
275		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
276	}
277	if f.LicenseInfoInFiles[0] != "MIT" {
278		t.Errorf("expected %s, got %s", "MIT", f.LicenseInfoInFiles[0])
279	}
280	if f.LicenseConcluded != "MIT" {
281		t.Errorf("expected %s, got %s", "MIT", f.LicenseConcluded)
282	}
283}
284
285func Test2_1SearcherFailsWithInvalidPath(t *testing.T) {
286	packageName := "project2"
287	dirRoot := "./oops/invalid"
288	config := &Config2_1{
289		NamespacePrefix: "whatever",
290	}
291
292	_, err := BuildIDsDocument2_1(packageName, dirRoot, config)
293	if err == nil {
294		t.Fatalf("expected non-nil error, got nil")
295	}
296}
297
298// ===== 2.2 Searcher top-level function tests =====
299func Test2_2SearcherCanFillInIDs(t *testing.T) {
300	packageName := "project2"
301	dirRoot := "../testdata/project2/"
302	config := &Config2_2{
303		NamespacePrefix: "https://github.com/swinslow/spdx-docs/spdx-go/testdata-",
304	}
305
306	doc, err := BuildIDsDocument2_2(packageName, dirRoot, config)
307	if err != nil {
308		t.Fatalf("expected nil error, got %v", err)
309	}
310	if doc == nil {
311		t.Fatalf("expected non-nil Document, got nil")
312	}
313
314	// not checking all contents of doc, see builder tests for those
315
316	// get the package and its files, checking size of each
317	if doc.Packages == nil {
318		t.Fatalf("expected non-nil Packages, got nil")
319	}
320	if len(doc.Packages) != 1 {
321		t.Fatalf("expected Packages len to be 1, got %d", len(doc.Packages))
322	}
323	pkg := doc.Packages[0]
324	if pkg == nil {
325		t.Fatalf("expected non-nil pkg, got nil")
326	}
327
328	if pkg.Files == nil {
329		t.Fatalf("expected non-nil Files, got nil")
330	}
331	if len(pkg.Files) != 6 {
332		t.Fatalf("expected Files len to be 6, got %d", len(pkg.Files))
333	}
334
335	fileInFolder := pkg.Files[0]
336	if fileInFolder.LicenseInfoInFiles == nil {
337		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
338	}
339	if len(fileInFolder.LicenseInfoInFiles) != 1 {
340		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileInFolder.LicenseInfoInFiles))
341	}
342	if fileInFolder.LicenseInfoInFiles[0] != "MIT" {
343		t.Errorf("expected %v, got %v", "MIT", fileInFolder.LicenseInfoInFiles[0])
344	}
345	if fileInFolder.LicenseConcluded != "MIT" {
346		t.Errorf("expected %v, got %v", "MIT", fileInFolder.LicenseConcluded)
347	}
348
349	fileTrailingComment := pkg.Files[1]
350	if fileTrailingComment.LicenseInfoInFiles == nil {
351		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
352	}
353	if len(fileTrailingComment.LicenseInfoInFiles) != 1 {
354		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileTrailingComment.LicenseInfoInFiles))
355	}
356	if fileTrailingComment.LicenseInfoInFiles[0] != "GPL-2.0-or-later" {
357		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", fileTrailingComment.LicenseInfoInFiles[0])
358	}
359	if fileTrailingComment.LicenseConcluded != "GPL-2.0-or-later" {
360		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", fileTrailingComment.LicenseConcluded)
361	}
362
363	fileHasDuplicateID := pkg.Files[2]
364	if fileHasDuplicateID.LicenseInfoInFiles == nil {
365		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
366	}
367	if len(fileHasDuplicateID.LicenseInfoInFiles) != 1 {
368		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileHasDuplicateID.LicenseInfoInFiles))
369	}
370	if fileHasDuplicateID.LicenseInfoInFiles[0] != "MIT" {
371		t.Errorf("expected %v, got %v", "MIT", fileHasDuplicateID.LicenseInfoInFiles[0])
372	}
373	if fileHasDuplicateID.LicenseConcluded != "MIT" {
374		t.Errorf("expected %v, got %v", "MIT", fileHasDuplicateID.LicenseConcluded)
375	}
376
377	fileHasID := pkg.Files[3]
378	if fileHasID.LicenseInfoInFiles == nil {
379		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
380	}
381	if len(fileHasID.LicenseInfoInFiles) != 2 {
382		t.Fatalf("expected LicenseInfoInFiles len to be 2, got %d", len(fileHasID.LicenseInfoInFiles))
383	}
384	if fileHasID.LicenseInfoInFiles[0] != "Apache-2.0" {
385		t.Errorf("expected %v, got %v", "Apache-2.0", fileHasID.LicenseInfoInFiles[0])
386	}
387	if fileHasID.LicenseInfoInFiles[1] != "GPL-2.0-or-later" {
388		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", fileHasID.LicenseInfoInFiles[1])
389	}
390	if fileHasID.LicenseConcluded != "Apache-2.0 OR GPL-2.0-or-later" {
391		t.Errorf("expected %v, got %v", "Apache-2.0 OR GPL-2.0-or-later", fileHasID.LicenseConcluded)
392	}
393
394	fileMultipleIDs := pkg.Files[4]
395	if fileMultipleIDs.LicenseInfoInFiles == nil {
396		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
397	}
398	if len(fileMultipleIDs.LicenseInfoInFiles) != 5 {
399		t.Fatalf("expected LicenseInfoInFiles len to be 5, got %d", len(fileMultipleIDs.LicenseInfoInFiles))
400	}
401	if fileMultipleIDs.LicenseInfoInFiles[0] != "BSD-2-Clause" {
402		t.Errorf("expected %v, got %v", "BSD-2-Clause", fileMultipleIDs.LicenseInfoInFiles[0])
403	}
404	if fileMultipleIDs.LicenseInfoInFiles[1] != "BSD-3-Clause" {
405		t.Errorf("expected %v, got %v", "BSD-3-Clause", fileMultipleIDs.LicenseInfoInFiles[1])
406	}
407	// here, DO NOT keep the +
408	if fileMultipleIDs.LicenseInfoInFiles[2] != "EPL-1.0" {
409		t.Errorf("expected %v, got %v", "EPL-1.0", fileMultipleIDs.LicenseInfoInFiles[2])
410	}
411	if fileMultipleIDs.LicenseInfoInFiles[3] != "ISC" {
412		t.Errorf("expected %v, got %v", "ISC", fileMultipleIDs.LicenseInfoInFiles[3])
413	}
414	if fileMultipleIDs.LicenseInfoInFiles[4] != "MIT" {
415		t.Errorf("expected %v, got %v", "MIT", fileMultipleIDs.LicenseInfoInFiles[4])
416	}
417	if fileMultipleIDs.LicenseConcluded != "((MIT AND BSD-3-Clause) OR ISC) AND BSD-2-Clause AND EPL-1.0+" {
418		t.Errorf("expected %v, got %v", "((MIT AND BSD-3-Clause) OR ISC) AND BSD-2-Clause AND EPL-1.0+", fileMultipleIDs.LicenseConcluded)
419	}
420
421	fileNoID := pkg.Files[5]
422	if fileNoID.LicenseInfoInFiles == nil {
423		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
424	}
425	if len(fileNoID.LicenseInfoInFiles) != 1 {
426		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileNoID.LicenseInfoInFiles))
427	}
428	if fileNoID.LicenseInfoInFiles[0] != "NOASSERTION" {
429		t.Errorf("expected %v, got %v", "NOASSERTION", fileNoID.LicenseInfoInFiles[0])
430	}
431	if fileNoID.LicenseConcluded != "NOASSERTION" {
432		t.Errorf("expected %v, got %v", "NOASSERTION", fileNoID.LicenseConcluded)
433	}
434
435	// and finally, the package should have all of these licenses
436	if pkg.PackageLicenseInfoFromFiles == nil {
437		t.Fatalf("expected non-nil PackageLicenseInfoFromFiles, got nil")
438	}
439	if len(pkg.PackageLicenseInfoFromFiles) != 7 {
440		t.Fatalf("expected PackageLicenseInfoFromFiles len to be 7, got %d", len(pkg.PackageLicenseInfoFromFiles))
441	}
442	if pkg.PackageLicenseInfoFromFiles[0] != "Apache-2.0" {
443		t.Errorf("expected %v, got %v", "Apache-2.0", pkg.PackageLicenseInfoFromFiles[0])
444	}
445	if pkg.PackageLicenseInfoFromFiles[1] != "BSD-2-Clause" {
446		t.Errorf("expected %v, got %v", "BSD-2-Clause", pkg.PackageLicenseInfoFromFiles[1])
447	}
448	if pkg.PackageLicenseInfoFromFiles[2] != "BSD-3-Clause" {
449		t.Errorf("expected %v, got %v", "BSD-3-Clause", pkg.PackageLicenseInfoFromFiles[2])
450	}
451	// here, DO NOT keep the +
452	if pkg.PackageLicenseInfoFromFiles[3] != "EPL-1.0" {
453		t.Errorf("expected %v, got %v", "EPL-1.0", pkg.PackageLicenseInfoFromFiles[3])
454	}
455	if pkg.PackageLicenseInfoFromFiles[4] != "GPL-2.0-or-later" {
456		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", pkg.PackageLicenseInfoFromFiles[4])
457	}
458	if pkg.PackageLicenseInfoFromFiles[5] != "ISC" {
459		t.Errorf("expected %v, got %v", "ISC", pkg.PackageLicenseInfoFromFiles[5])
460	}
461	if pkg.PackageLicenseInfoFromFiles[6] != "MIT" {
462		t.Errorf("expected %v, got %v", "MIT", pkg.PackageLicenseInfoFromFiles[6])
463	}
464
465}
466
467func Test2_2SearcherCanFillInIDsAndIgnorePaths(t *testing.T) {
468	packageName := "project3"
469	dirRoot := "../testdata/project3/"
470	config := &Config2_2{
471		NamespacePrefix: "https://github.com/swinslow/spdx-docs/spdx-go/testdata-",
472		BuilderPathsIgnored: []string{
473			"**/ignoredir/",
474			"/excludedir/",
475			"**/ignorefile.txt",
476			"/alsoEXCLUDEthis.txt",
477		},
478		SearcherPathsIgnored: []string{
479			"**/dontscan.txt",
480		},
481	}
482
483	doc, err := BuildIDsDocument2_2(packageName, dirRoot, config)
484	if err != nil {
485		t.Fatalf("expected nil error, got %v", err)
486	}
487	if doc == nil {
488		t.Fatalf("expected non-nil Document, got nil")
489	}
490
491	// not checking all contents of doc, see builder tests for those
492
493	// get the package and its files, checking licenses for each, and
494	// confirming NOASSERTION for those that are skipped
495	pkg := doc.Packages[0]
496	if pkg == nil {
497		t.Fatalf("expected non-nil pkg, got nil")
498	}
499	if len(pkg.Files) != 5 {
500		t.Fatalf("expected len %d, got %d", 5, len(pkg.Files))
501	}
502
503	f := pkg.Files[0]
504	if f.FileName != "./dontscan.txt" {
505		t.Errorf("expected %v, got %v", "./dontscan.txt", f.FileName)
506	}
507	if len(f.LicenseInfoInFiles) != 1 {
508		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
509	}
510	if f.LicenseInfoInFiles[0] != "NOASSERTION" {
511		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseInfoInFiles[0])
512	}
513	if f.LicenseConcluded != "NOASSERTION" {
514		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseConcluded)
515	}
516
517	f = pkg.Files[1]
518	if f.FileName != "./keep/keep.txt" {
519		t.Errorf("expected %v, got %v", "./keep/keep.txt", f.FileName)
520	}
521	if len(f.LicenseInfoInFiles) != 1 {
522		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
523	}
524	if f.LicenseInfoInFiles[0] != "MIT" {
525		t.Errorf("expected %s, got %s", "MIT", f.LicenseInfoInFiles[0])
526	}
527	if f.LicenseConcluded != "MIT" {
528		t.Errorf("expected %s, got %s", "MIT", f.LicenseConcluded)
529	}
530
531	f = pkg.Files[2]
532	if f.FileName != "./keep.txt" {
533		t.Errorf("expected %v, got %v", "./keep.txt", f.FileName)
534	}
535	if len(f.LicenseInfoInFiles) != 1 {
536		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
537	}
538	if f.LicenseInfoInFiles[0] != "NOASSERTION" {
539		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseInfoInFiles[0])
540	}
541	if f.LicenseConcluded != "NOASSERTION" {
542		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseConcluded)
543	}
544
545	f = pkg.Files[3]
546	if f.FileName != "./subdir/keep/dontscan.txt" {
547		t.Errorf("expected %v, got %v", "./subdir/keep/dontscan.txt", f.FileName)
548	}
549	if len(f.LicenseInfoInFiles) != 1 {
550		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
551	}
552	if f.LicenseInfoInFiles[0] != "NOASSERTION" {
553		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseInfoInFiles[0])
554	}
555	if f.LicenseConcluded != "NOASSERTION" {
556		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseConcluded)
557	}
558
559	f = pkg.Files[4]
560	if f.FileName != "./subdir/keep/keep.txt" {
561		t.Errorf("expected %v, got %v", "./subdir/keep/keep.txt", f.FileName)
562	}
563	if len(f.LicenseInfoInFiles) != 1 {
564		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
565	}
566	if f.LicenseInfoInFiles[0] != "MIT" {
567		t.Errorf("expected %s, got %s", "MIT", f.LicenseInfoInFiles[0])
568	}
569	if f.LicenseConcluded != "MIT" {
570		t.Errorf("expected %s, got %s", "MIT", f.LicenseConcluded)
571	}
572}
573
574func Test2_2SearcherFailsWithInvalidPath(t *testing.T) {
575	packageName := "project2"
576	dirRoot := "./oops/invalid"
577	config := &Config2_2{
578		NamespacePrefix: "whatever",
579	}
580
581	_, err := BuildIDsDocument2_2(packageName, dirRoot, config)
582	if err == nil {
583		t.Fatalf("expected non-nil error, got nil")
584	}
585}
586
587// ===== 2.3 Searcher top-level function tests =====
588func Test2_3SearcherCanFillInIDs(t *testing.T) {
589	packageName := "project2"
590	dirRoot := "../testdata/project2/"
591	config := &Config2_3{
592		NamespacePrefix: "https://github.com/swinslow/spdx-docs/spdx-go/testdata-",
593	}
594
595	doc, err := BuildIDsDocument2_3(packageName, dirRoot, config)
596	if err != nil {
597		t.Fatalf("expected nil error, got %v", err)
598	}
599	if doc == nil {
600		t.Fatalf("expected non-nil Document, got nil")
601	}
602
603	// not checking all contents of doc, see builder tests for those
604
605	// get the package and its files, checking size of each
606	if doc.Packages == nil {
607		t.Fatalf("expected non-nil Packages, got nil")
608	}
609	if len(doc.Packages) != 1 {
610		t.Fatalf("expected Packages len to be 1, got %d", len(doc.Packages))
611	}
612	pkg := doc.Packages[0]
613	if pkg == nil {
614		t.Fatalf("expected non-nil pkg, got nil")
615	}
616
617	if pkg.Files == nil {
618		t.Fatalf("expected non-nil Files, got nil")
619	}
620	if len(pkg.Files) != 6 {
621		t.Fatalf("expected Files len to be 6, got %d", len(pkg.Files))
622	}
623
624	fileInFolder := pkg.Files[0]
625	if fileInFolder.LicenseInfoInFiles == nil {
626		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
627	}
628	if len(fileInFolder.LicenseInfoInFiles) != 1 {
629		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileInFolder.LicenseInfoInFiles))
630	}
631	if fileInFolder.LicenseInfoInFiles[0] != "MIT" {
632		t.Errorf("expected %v, got %v", "MIT", fileInFolder.LicenseInfoInFiles[0])
633	}
634	if fileInFolder.LicenseConcluded != "MIT" {
635		t.Errorf("expected %v, got %v", "MIT", fileInFolder.LicenseConcluded)
636	}
637
638	fileTrailingComment := pkg.Files[1]
639	if fileTrailingComment.LicenseInfoInFiles == nil {
640		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
641	}
642	if len(fileTrailingComment.LicenseInfoInFiles) != 1 {
643		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileTrailingComment.LicenseInfoInFiles))
644	}
645	if fileTrailingComment.LicenseInfoInFiles[0] != "GPL-2.0-or-later" {
646		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", fileTrailingComment.LicenseInfoInFiles[0])
647	}
648	if fileTrailingComment.LicenseConcluded != "GPL-2.0-or-later" {
649		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", fileTrailingComment.LicenseConcluded)
650	}
651
652	fileHasDuplicateID := pkg.Files[2]
653	if fileHasDuplicateID.LicenseInfoInFiles == nil {
654		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
655	}
656	if len(fileHasDuplicateID.LicenseInfoInFiles) != 1 {
657		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileHasDuplicateID.LicenseInfoInFiles))
658	}
659	if fileHasDuplicateID.LicenseInfoInFiles[0] != "MIT" {
660		t.Errorf("expected %v, got %v", "MIT", fileHasDuplicateID.LicenseInfoInFiles[0])
661	}
662	if fileHasDuplicateID.LicenseConcluded != "MIT" {
663		t.Errorf("expected %v, got %v", "MIT", fileHasDuplicateID.LicenseConcluded)
664	}
665
666	fileHasID := pkg.Files[3]
667	if fileHasID.LicenseInfoInFiles == nil {
668		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
669	}
670	if len(fileHasID.LicenseInfoInFiles) != 2 {
671		t.Fatalf("expected LicenseInfoInFiles len to be 2, got %d", len(fileHasID.LicenseInfoInFiles))
672	}
673	if fileHasID.LicenseInfoInFiles[0] != "Apache-2.0" {
674		t.Errorf("expected %v, got %v", "Apache-2.0", fileHasID.LicenseInfoInFiles[0])
675	}
676	if fileHasID.LicenseInfoInFiles[1] != "GPL-2.0-or-later" {
677		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", fileHasID.LicenseInfoInFiles[1])
678	}
679	if fileHasID.LicenseConcluded != "Apache-2.0 OR GPL-2.0-or-later" {
680		t.Errorf("expected %v, got %v", "Apache-2.0 OR GPL-2.0-or-later", fileHasID.LicenseConcluded)
681	}
682
683	fileMultipleIDs := pkg.Files[4]
684	if fileMultipleIDs.LicenseInfoInFiles == nil {
685		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
686	}
687	if len(fileMultipleIDs.LicenseInfoInFiles) != 5 {
688		t.Fatalf("expected LicenseInfoInFiles len to be 5, got %d", len(fileMultipleIDs.LicenseInfoInFiles))
689	}
690	if fileMultipleIDs.LicenseInfoInFiles[0] != "BSD-2-Clause" {
691		t.Errorf("expected %v, got %v", "BSD-2-Clause", fileMultipleIDs.LicenseInfoInFiles[0])
692	}
693	if fileMultipleIDs.LicenseInfoInFiles[1] != "BSD-3-Clause" {
694		t.Errorf("expected %v, got %v", "BSD-3-Clause", fileMultipleIDs.LicenseInfoInFiles[1])
695	}
696	// here, DO NOT keep the +
697	if fileMultipleIDs.LicenseInfoInFiles[2] != "EPL-1.0" {
698		t.Errorf("expected %v, got %v", "EPL-1.0", fileMultipleIDs.LicenseInfoInFiles[2])
699	}
700	if fileMultipleIDs.LicenseInfoInFiles[3] != "ISC" {
701		t.Errorf("expected %v, got %v", "ISC", fileMultipleIDs.LicenseInfoInFiles[3])
702	}
703	if fileMultipleIDs.LicenseInfoInFiles[4] != "MIT" {
704		t.Errorf("expected %v, got %v", "MIT", fileMultipleIDs.LicenseInfoInFiles[4])
705	}
706	if fileMultipleIDs.LicenseConcluded != "((MIT AND BSD-3-Clause) OR ISC) AND BSD-2-Clause AND EPL-1.0+" {
707		t.Errorf("expected %v, got %v", "((MIT AND BSD-3-Clause) OR ISC) AND BSD-2-Clause AND EPL-1.0+", fileMultipleIDs.LicenseConcluded)
708	}
709
710	fileNoID := pkg.Files[5]
711	if fileNoID.LicenseInfoInFiles == nil {
712		t.Fatalf("expected non-nil LicenseInfoInFiles, got nil")
713	}
714	if len(fileNoID.LicenseInfoInFiles) != 1 {
715		t.Fatalf("expected LicenseInfoInFiles len to be 1, got %d", len(fileNoID.LicenseInfoInFiles))
716	}
717	if fileNoID.LicenseInfoInFiles[0] != "NOASSERTION" {
718		t.Errorf("expected %v, got %v", "NOASSERTION", fileNoID.LicenseInfoInFiles[0])
719	}
720	if fileNoID.LicenseConcluded != "NOASSERTION" {
721		t.Errorf("expected %v, got %v", "NOASSERTION", fileNoID.LicenseConcluded)
722	}
723
724	// and finally, the package should have all of these licenses
725	if pkg.PackageLicenseInfoFromFiles == nil {
726		t.Fatalf("expected non-nil PackageLicenseInfoFromFiles, got nil")
727	}
728	if len(pkg.PackageLicenseInfoFromFiles) != 7 {
729		t.Fatalf("expected PackageLicenseInfoFromFiles len to be 7, got %d", len(pkg.PackageLicenseInfoFromFiles))
730	}
731	if pkg.PackageLicenseInfoFromFiles[0] != "Apache-2.0" {
732		t.Errorf("expected %v, got %v", "Apache-2.0", pkg.PackageLicenseInfoFromFiles[0])
733	}
734	if pkg.PackageLicenseInfoFromFiles[1] != "BSD-2-Clause" {
735		t.Errorf("expected %v, got %v", "BSD-2-Clause", pkg.PackageLicenseInfoFromFiles[1])
736	}
737	if pkg.PackageLicenseInfoFromFiles[2] != "BSD-3-Clause" {
738		t.Errorf("expected %v, got %v", "BSD-3-Clause", pkg.PackageLicenseInfoFromFiles[2])
739	}
740	// here, DO NOT keep the +
741	if pkg.PackageLicenseInfoFromFiles[3] != "EPL-1.0" {
742		t.Errorf("expected %v, got %v", "EPL-1.0", pkg.PackageLicenseInfoFromFiles[3])
743	}
744	if pkg.PackageLicenseInfoFromFiles[4] != "GPL-2.0-or-later" {
745		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", pkg.PackageLicenseInfoFromFiles[4])
746	}
747	if pkg.PackageLicenseInfoFromFiles[5] != "ISC" {
748		t.Errorf("expected %v, got %v", "ISC", pkg.PackageLicenseInfoFromFiles[5])
749	}
750	if pkg.PackageLicenseInfoFromFiles[6] != "MIT" {
751		t.Errorf("expected %v, got %v", "MIT", pkg.PackageLicenseInfoFromFiles[6])
752	}
753
754}
755
756func Test2_3SearcherCanFillInIDsAndIgnorePaths(t *testing.T) {
757	packageName := "project3"
758	dirRoot := "../testdata/project3/"
759	config := &Config2_3{
760		NamespacePrefix: "https://github.com/swinslow/spdx-docs/spdx-go/testdata-",
761		BuilderPathsIgnored: []string{
762			"**/ignoredir/",
763			"/excludedir/",
764			"**/ignorefile.txt",
765			"/alsoEXCLUDEthis.txt",
766		},
767		SearcherPathsIgnored: []string{
768			"**/dontscan.txt",
769		},
770	}
771
772	doc, err := BuildIDsDocument2_3(packageName, dirRoot, config)
773	if err != nil {
774		t.Fatalf("expected nil error, got %v", err)
775	}
776	if doc == nil {
777		t.Fatalf("expected non-nil Document, got nil")
778	}
779
780	// not checking all contents of doc, see builder tests for those
781
782	// get the package and its files, checking licenses for each, and
783	// confirming NOASSERTION for those that are skipped
784	pkg := doc.Packages[0]
785	if pkg == nil {
786		t.Fatalf("expected non-nil pkg, got nil")
787	}
788	if len(pkg.Files) != 5 {
789		t.Fatalf("expected len %d, got %d", 5, len(pkg.Files))
790	}
791
792	f := pkg.Files[0]
793	if f.FileName != "./dontscan.txt" {
794		t.Errorf("expected %v, got %v", "./dontscan.txt", f.FileName)
795	}
796	if len(f.LicenseInfoInFiles) != 1 {
797		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
798	}
799	if f.LicenseInfoInFiles[0] != "NOASSERTION" {
800		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseInfoInFiles[0])
801	}
802	if f.LicenseConcluded != "NOASSERTION" {
803		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseConcluded)
804	}
805
806	f = pkg.Files[1]
807	if f.FileName != "./keep/keep.txt" {
808		t.Errorf("expected %v, got %v", "./keep/keep.txt", f.FileName)
809	}
810	if len(f.LicenseInfoInFiles) != 1 {
811		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
812	}
813	if f.LicenseInfoInFiles[0] != "MIT" {
814		t.Errorf("expected %s, got %s", "MIT", f.LicenseInfoInFiles[0])
815	}
816	if f.LicenseConcluded != "MIT" {
817		t.Errorf("expected %s, got %s", "MIT", f.LicenseConcluded)
818	}
819
820	f = pkg.Files[2]
821	if f.FileName != "./keep.txt" {
822		t.Errorf("expected %v, got %v", "./keep.txt", f.FileName)
823	}
824	if len(f.LicenseInfoInFiles) != 1 {
825		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
826	}
827	if f.LicenseInfoInFiles[0] != "NOASSERTION" {
828		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseInfoInFiles[0])
829	}
830	if f.LicenseConcluded != "NOASSERTION" {
831		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseConcluded)
832	}
833
834	f = pkg.Files[3]
835	if f.FileName != "./subdir/keep/dontscan.txt" {
836		t.Errorf("expected %v, got %v", "./subdir/keep/dontscan.txt", f.FileName)
837	}
838	if len(f.LicenseInfoInFiles) != 1 {
839		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
840	}
841	if f.LicenseInfoInFiles[0] != "NOASSERTION" {
842		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseInfoInFiles[0])
843	}
844	if f.LicenseConcluded != "NOASSERTION" {
845		t.Errorf("expected %s, got %s", "NOASSERTION", f.LicenseConcluded)
846	}
847
848	f = pkg.Files[4]
849	if f.FileName != "./subdir/keep/keep.txt" {
850		t.Errorf("expected %v, got %v", "./subdir/keep/keep.txt", f.FileName)
851	}
852	if len(f.LicenseInfoInFiles) != 1 {
853		t.Errorf("expected len to be %d, got %d", 1, len(f.LicenseInfoInFiles))
854	}
855	if f.LicenseInfoInFiles[0] != "MIT" {
856		t.Errorf("expected %s, got %s", "MIT", f.LicenseInfoInFiles[0])
857	}
858	if f.LicenseConcluded != "MIT" {
859		t.Errorf("expected %s, got %s", "MIT", f.LicenseConcluded)
860	}
861}
862
863func Test2_3SearcherFailsWithInvalidPath(t *testing.T) {
864	packageName := "project2"
865	dirRoot := "./oops/invalid"
866	config := &Config2_3{
867		NamespacePrefix: "whatever",
868	}
869
870	_, err := BuildIDsDocument2_3(packageName, dirRoot, config)
871	if err == nil {
872		t.Fatalf("expected non-nil error, got nil")
873	}
874}
875
876// ===== Searcher utility tests =====
877func TestCanFindShortFormIDWhenPresent(t *testing.T) {
878	filePath := "../testdata/project2/has-id.txt"
879
880	ids, err := searchFileIDs(filePath)
881	if err != nil {
882		t.Fatalf("expected nil error, got %v", err)
883	}
884
885	if len(ids) != 1 {
886		t.Fatalf("expected len 1, got %d", len(ids))
887	}
888
889	if ids[0] != "Apache-2.0 OR GPL-2.0-or-later" {
890		t.Errorf("expected %v, got %v", "Apache-2.0 OR GPL-2.0-or-later", ids[0])
891	}
892}
893
894func TestCanFindMultipleShortFormIDsWhenPresent(t *testing.T) {
895	filePath := "../testdata/project2/has-multiple-ids.txt"
896
897	ids, err := searchFileIDs(filePath)
898	if err != nil {
899		t.Fatalf("expected nil error, got %v", err)
900	}
901
902	if len(ids) != 3 {
903		t.Fatalf("expected len 3, got %d", len(ids))
904	}
905
906	if ids[0] != "(MIT AND BSD-3-Clause) OR ISC" {
907		t.Errorf("expected %v, got %v", "(MIT AND BSD-3-Clause) OR ISC", ids[0])
908	}
909	if ids[1] != "BSD-2-Clause" {
910		t.Errorf("expected %v, got %v", "BSD-2-Clause", ids[1])
911	}
912	if ids[2] != "EPL-1.0+" {
913		t.Errorf("expected %v, got %v", "EPL-1.0+", ids[2])
914	}
915}
916
917func TestCanCollapseDuplicateShortFormIDsWhenPresent(t *testing.T) {
918	filePath := "../testdata/project2/has-duplicate-ids.txt"
919
920	ids, err := searchFileIDs(filePath)
921	if err != nil {
922		t.Fatalf("expected nil error, got %v", err)
923	}
924
925	if len(ids) != 1 {
926		t.Fatalf("expected len 1, got %d", len(ids))
927	}
928
929	if ids[0] != "MIT" {
930		t.Errorf("expected %v, got %v", "MIT", ids[0])
931	}
932}
933
934func TestCanStripTrailingStarSlash(t *testing.T) {
935	filePath := "../testdata/project2/folder/has-trailing-comment-marker.c"
936
937	ids, err := searchFileIDs(filePath)
938	if err != nil {
939		t.Fatalf("expected nil error, got %v", err)
940	}
941
942	if len(ids) != 1 {
943		t.Fatalf("expected len 1, got %d", len(ids))
944	}
945
946	if ids[0] != "GPL-2.0-or-later" {
947		t.Errorf("expected %v, got %v", "GPL-2.0-or-later", ids[0])
948	}
949}
950
951func TestCanIgnoreShortFormIDWhenTooManyPrefixChars(t *testing.T) {
952	filePath := "../testdata/project4/has-id-to-ignore.txt"
953
954	ids, err := searchFileIDs(filePath)
955	if err != nil {
956		t.Fatalf("expected nil error, got %v", err)
957	}
958
959	if len(ids) != 0 {
960		t.Fatalf("expected len 0, got %d", len(ids))
961	}
962}
963
964func TestCanPickJustTheRightID(t *testing.T) {
965	filePath := "../testdata/project4/has-mix-of-ids.txt"
966
967	ids, err := searchFileIDs(filePath)
968	if err != nil {
969		t.Fatalf("expected nil error, got %v", err)
970	}
971
972	if len(ids) != 1 {
973		t.Fatalf("expected len 1, got %d", len(ids))
974	}
975
976	if ids[0] != "MIT" {
977		t.Errorf("expected %v, got %v", "MIT", ids[0])
978	}
979}
980
981func TestCannotFindShortFormIDWhenAbsent(t *testing.T) {
982	filePath := "../testdata/project2/no-id.txt"
983
984	ids, err := searchFileIDs(filePath)
985	if err != nil {
986		t.Fatalf("expected nil error, got %v", err)
987	}
988
989	if len(ids) != 0 {
990		t.Fatalf("expected len 0, got %d", len(ids))
991	}
992}
993
994func TestCanExcludeTrashCharactersFromID(t *testing.T) {
995	lid := "Apac\",he-2.0"
996	want := "Apache-2.0"
997	got := stripTrash(lid)
998	if want != got {
999		t.Errorf("expected %v, got %v", want, got)
1000	}
1001
1002	lid = "Apache-2.0"
1003	want = "Apache-2.0"
1004	got = stripTrash(lid)
1005	if want != got {
1006		t.Errorf("expected %v, got %v", want, got)
1007	}
1008}
1009
1010func TestSearchFileIDsFailsWithInvalidFilePath(t *testing.T) {
1011	filePath := "./oops/nm/invalid"
1012
1013	_, err := searchFileIDs(filePath)
1014	if err == nil {
1015		t.Fatalf("expected non-nil error, got nil")
1016	}
1017}
1018
1019func TestWillParenthesizeIfNeeded(t *testing.T) {
1020	licID := "MIT OR BSD-3-Clause"
1021	retval := makeElement(licID)
1022	if retval != "(MIT OR BSD-3-Clause)" {
1023		t.Errorf("expected %v, got %v", "(MIT OR BSD-3-Clause)", retval)
1024	}
1025
1026	licID = "ISC AND HPND"
1027	retval = makeElement(licID)
1028	if retval != "(ISC AND HPND)" {
1029		t.Errorf("expected %v, got %v", "(ISC AND HPND)", retval)
1030	}
1031}
1032
1033func TestWillNotParenthesizeIfNotNeeded(t *testing.T) {
1034	lic := "MIT"
1035	retval := makeElement(lic)
1036	if retval != "MIT" {
1037		t.Errorf("expected %v, got %v", "MIT", retval)
1038	}
1039
1040	lic = "GPL-2.0-only WITH Classpath-exception-2.0"
1041	retval = makeElement(lic)
1042	if retval != "GPL-2.0-only WITH Classpath-exception-2.0" {
1043		t.Errorf("expected %v, got %v", "GPL-2.0-only WITH Classpath-exception-2.0", retval)
1044	}
1045}
1046
1047func TestCanGetIndividualLicenses(t *testing.T) {
1048	// single license
1049	lic := "MIT"
1050	lics := getIndividualLicenses(lic)
1051	if lics == nil {
1052		t.Fatalf("expected non-nil lics, got nil")
1053	}
1054	if len(lics) != 1 {
1055		t.Fatalf("expected lics to have len 1, got %d", len(lics))
1056	}
1057	if lics[0] != "MIT" {
1058		t.Errorf("expected %v, got %v", "MIT", lics[0])
1059	}
1060
1061	// two-license combo
1062	lic = "ISC AND BSD-3-Clause"
1063	lics = getIndividualLicenses(lic)
1064	if lics == nil {
1065		t.Fatalf("expected non-nil lics, got nil")
1066	}
1067	if len(lics) != 2 {
1068		t.Fatalf("expected lics to have len 2, got %d", len(lics))
1069	}
1070	// should be sorted alphabetically
1071	if lics[0] != "BSD-3-Clause" {
1072		t.Errorf("expected %v, got %v", "BSD-3-Clause", lics[0])
1073	}
1074	if lics[1] != "ISC" {
1075		t.Errorf("expected %v, got %v", "ISC", lics[1])
1076	}
1077
1078	// license WITH exception
1079	lic = "GPL-2.0-only WITH Classpath-exception-2.0"
1080	lics = getIndividualLicenses(lic)
1081	if lics == nil {
1082		t.Fatalf("expected non-nil lics, got nil")
1083	}
1084	if len(lics) != 2 {
1085		t.Fatalf("expected lics to have len 2, got %d", len(lics))
1086	}
1087	// exception should be listed separately
1088	if lics[0] != "Classpath-exception-2.0" {
1089		t.Errorf("expected %v, got %v", "Classpath-exception-2.0", lics[0])
1090	}
1091	if lics[1] != "GPL-2.0-only" {
1092		t.Errorf("expected %v, got %v", "GPL-2.0-only", lics[1])
1093	}
1094
1095	// two-license combo with parens
1096	lic = "(JSON OR BSD-2-Clause)"
1097	lics = getIndividualLicenses(lic)
1098	if lics == nil {
1099		t.Fatalf("expected non-nil lics, got nil")
1100	}
1101	if len(lics) != 2 {
1102		t.Fatalf("expected lics to have len 2, got %d", len(lics))
1103	}
1104	// parens should get dropped
1105	if lics[0] != "BSD-2-Clause" {
1106		t.Errorf("expected %v, got %v", "BSD-2-Clause", lics[0])
1107	}
1108	if lics[1] != "JSON" {
1109		t.Errorf("expected %v, got %v", "JSON", lics[1])
1110	}
1111
1112	// multi-license combo with nested parens
1113	lic = "GPL-2.0-only AND ((EPL-1.0 AND BSD-4-Clause) OR MIT)"
1114	lics = getIndividualLicenses(lic)
1115	if lics == nil {
1116		t.Fatalf("expected non-nil lics, got nil")
1117	}
1118	if len(lics) != 4 {
1119		t.Fatalf("expected lics to have len 4, got %d", len(lics))
1120	}
1121	if lics[0] != "BSD-4-Clause" {
1122		t.Errorf("expected %v, got %v", "BSD-4-Clause", lics[0])
1123	}
1124	if lics[1] != "EPL-1.0" {
1125		t.Errorf("expected %v, got %v", "EPL-1.0", lics[1])
1126	}
1127	if lics[2] != "GPL-2.0-only" {
1128		t.Errorf("expected %v, got %v", "GPL-2.0-only", lics[2])
1129	}
1130	if lics[3] != "MIT" {
1131		t.Errorf("expected %v, got %v", "MIT", lics[3])
1132	}
1133}
1134
1135func TestCanGetIndividualLicensesIgnoringOperatorCase(t *testing.T) {
1136	// two-license combo with lowercase 'and'
1137	lic := "ISC and BSD-3-Clause"
1138	lics := getIndividualLicenses(lic)
1139	if lics == nil {
1140		t.Fatalf("expected non-nil lics, got nil")
1141	}
1142	// should be sorted alphabetically; 'and' should not appear
1143	if len(lics) != 2 {
1144		t.Fatalf("expected lics to have len 2, got %d", len(lics))
1145	}
1146	if lics[0] != "BSD-3-Clause" {
1147		t.Errorf("expected %v, got %v", "BSD-3-Clause", lics[0])
1148	}
1149	if lics[1] != "ISC" {
1150		t.Errorf("expected %v, got %v", "ISC", lics[1])
1151	}
1152
1153	// two-license combo with lowercase 'or'
1154	lic = "ISC or BSD-3-Clause"
1155	lics = getIndividualLicenses(lic)
1156	if lics == nil {
1157		t.Fatalf("expected non-nil lics, got nil")
1158	}
1159	// should be sorted alphabetically; 'or' should not appear
1160	if len(lics) != 2 {
1161		t.Fatalf("expected lics to have len 2, got %d", len(lics))
1162	}
1163	if lics[0] != "BSD-3-Clause" {
1164		t.Errorf("expected %v, got %v", "BSD-3-Clause", lics[0])
1165	}
1166	if lics[1] != "ISC" {
1167		t.Errorf("expected %v, got %v", "ISC", lics[1])
1168	}
1169
1170	// two-license combo with lowercase 'with'
1171	lic = "GPL-2.0-only with Classpath-exception-2.0"
1172	lics = getIndividualLicenses(lic)
1173	if lics == nil {
1174		t.Fatalf("expected non-nil lics, got nil")
1175	}
1176	// should be sorted alphabetically; 'with' should not appear
1177	if len(lics) != 2 {
1178		t.Fatalf("expected lics to have len 2, got %d", len(lics))
1179	}
1180	if lics[0] != "Classpath-exception-2.0" {
1181		t.Errorf("expected %v, got %v", "Classpath-exception-2.0", lics[0])
1182	}
1183	if lics[1] != "GPL-2.0-only" {
1184		t.Errorf("expected %v, got %v", "GPL-2.0-only", lics[1])
1185	}
1186
1187}
1188