xref: /aosp_15_r20/external/spdx-tools/licensediff/licensediff_test.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2
3package licensediff
4
5import (
6	"testing"
7
8	"github.com/spdx/tools-golang/spdx/common"
9	"github.com/spdx/tools-golang/spdx/v2_1"
10	"github.com/spdx/tools-golang/spdx/v2_2"
11	"github.com/spdx/tools-golang/spdx/v2_3"
12)
13
14// ===== 2.1 License diff top-level function tests =====
15func Test2_1DifferCanCreateDiffPairs(t *testing.T) {
16	// create files to be used in diff
17	// f1 will be identical in both
18	f1 := &v2_1.File{
19		FileName:           "/project/file1.txt",
20		FileSPDXIdentifier: common.ElementID("File561"),
21		Checksums:          []common.Checksum{{Value: "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3", Algorithm: common.SHA1}},
22		LicenseConcluded:   "Apache-2.0",
23		LicenseInfoInFiles: []string{
24			"LicenseRef-We-will-ignore-LicenseInfoInFiles",
25		},
26		FileCopyrightText: "We'll ignore copyright values",
27	}
28
29	// f2 will only appear in the first Package
30	f2 := &v2_1.File{
31		FileName:           "/project/file2.txt",
32		FileSPDXIdentifier: common.ElementID("File562"),
33		Checksums:          []common.Checksum{{Value: "066c5139bd9a43d15812ec1a1755b08ccf199824", Algorithm: common.SHA1}},
34		LicenseConcluded:   "GPL-2.0-or-later",
35		LicenseInfoInFiles: []string{
36			"NOASSERTION",
37		},
38		FileCopyrightText: "NOASSERTION",
39	}
40
41	// f3 will only appear in the second Package
42	f3 := &v2_1.File{
43		FileName:           "/project/file3.txt",
44		FileSPDXIdentifier: common.ElementID("File563"),
45		Checksums:          []common.Checksum{{Value: "bd0f4863b15fad2b79b35303af54fcb5baaf7c68", Algorithm: common.SHA1}},
46		LicenseConcluded:   "MPL-2.0",
47		LicenseInfoInFiles: []string{
48			"NOASSERTION",
49		},
50		FileCopyrightText: "NOASSERTION",
51	}
52
53	// f4_1 and f4_2 will appear in first and second,
54	// with same name, same hash and different license
55	f4_1 := &v2_1.File{
56		FileName:           "/project/file4.txt",
57		FileSPDXIdentifier: common.ElementID("File564"),
58		Checksums:          []common.Checksum{{Value: "bc417a575ceae93435bcb7bfd382ac28cbdaa8b5", Algorithm: common.SHA1}},
59		LicenseConcluded:   "MIT",
60		LicenseInfoInFiles: []string{
61			"NOASSERTION",
62		},
63		FileCopyrightText: "NOASSERTION",
64	}
65	f4_2 := &v2_1.File{
66		FileName:           "/project/file4.txt",
67		FileSPDXIdentifier: common.ElementID("File564"),
68		Checksums:          []common.Checksum{{Value: "bc417a575ceae93435bcb7bfd382ac28cbdaa8b5", Algorithm: common.SHA1}},
69		LicenseConcluded:   "Apache-2.0 AND MIT",
70		LicenseInfoInFiles: []string{
71			"NOASSERTION",
72		},
73		FileCopyrightText: "NOASSERTION",
74	}
75
76	// f5_1 and f5_2 will appear in first and second,
77	// with same name, different hash and same license
78	f5_1 := &v2_1.File{
79		FileName:           "/project/file5.txt",
80		FileSPDXIdentifier: common.ElementID("File565"),
81		Checksums:          []common.Checksum{{Value: "ba226db943bbbf455da77afab6f16dbab156d000", Algorithm: common.SHA1}},
82		LicenseConcluded:   "BSD-3-Clause",
83		LicenseInfoInFiles: []string{
84			"NOASSERTION",
85		},
86		FileCopyrightText: "NOASSERTION",
87	}
88	f5_2 := &v2_1.File{
89		FileName:           "/project/file5.txt",
90		FileSPDXIdentifier: common.ElementID("File565"),
91		Checksums:          []common.Checksum{{Value: "b6e0ec7d085c5699b46f6f8d425413702652874d", Algorithm: common.SHA1}},
92		LicenseConcluded:   "BSD-3-Clause",
93		LicenseInfoInFiles: []string{
94			"NOASSERTION",
95		},
96		FileCopyrightText: "NOASSERTION",
97	}
98
99	// f6_1 and f6_2 will appear in first and second,
100	// with same name, different hash and different license
101	f6_1 := &v2_1.File{
102		FileName:           "/project/file6.txt",
103		FileSPDXIdentifier: common.ElementID("File566"),
104		Checksums:          []common.Checksum{{Value: "ba226db943bbbf455da77afab6f16dbab156d000", Algorithm: common.SHA1}},
105		LicenseConcluded:   "CC0-1.0",
106		LicenseInfoInFiles: []string{
107			"NOASSERTION",
108		},
109		FileCopyrightText: "NOASSERTION",
110	}
111	f6_2 := &v2_1.File{
112		FileName:           "/project/file6.txt",
113		FileSPDXIdentifier: common.ElementID("File566"),
114		Checksums:          []common.Checksum{{Value: "b6e0ec7d085c5699b46f6f8d425413702652874d", Algorithm: common.SHA1}},
115		LicenseConcluded:   "Unlicense",
116		LicenseInfoInFiles: []string{
117			"NOASSERTION",
118		},
119		FileCopyrightText: "NOASSERTION",
120	}
121
122	// create Packages
123	p1 := &v2_1.Package{
124		PackageName:               "p1",
125		PackageSPDXIdentifier:     common.ElementID("p1"),
126		PackageDownloadLocation:   "NOASSERTION",
127		FilesAnalyzed:             true,
128		IsFilesAnalyzedTagPresent: true,
129		// fake the verification code for present purposes
130		PackageVerificationCode: common.PackageVerificationCode{Value: "abc123abc123"},
131		PackageLicenseConcluded: "NOASSERTION",
132		PackageLicenseInfoFromFiles: []string{
133			"NOASSERTION",
134		},
135		PackageLicenseDeclared: "NOASSERTION",
136		PackageCopyrightText:   "NOASSERTION",
137		Files: []*v2_1.File{
138			f1,
139			f2,
140			f4_1,
141			f5_1,
142			f6_1,
143		},
144	}
145	p2 := &v2_1.Package{
146		PackageName:               "p2",
147		PackageSPDXIdentifier:     common.ElementID("p2"),
148		PackageDownloadLocation:   "NOASSERTION",
149		FilesAnalyzed:             true,
150		IsFilesAnalyzedTagPresent: true,
151		// fake the verification code for present purposes
152		PackageVerificationCode: common.PackageVerificationCode{Value: "def456def456"},
153		PackageLicenseConcluded: "NOASSERTION",
154		PackageLicenseInfoFromFiles: []string{
155			"NOASSERTION",
156		},
157		PackageLicenseDeclared: "NOASSERTION",
158		PackageCopyrightText:   "NOASSERTION",
159		Files: []*v2_1.File{
160			f1,
161			f3,
162			f4_2,
163			f5_2,
164			f6_2,
165		},
166	}
167
168	// run the diff between the two packages
169	diffMap, err := MakePairs2_1(p1, p2)
170	if err != nil {
171		t.Fatalf("Expected nil error, got %v", err)
172	}
173
174	// check that the diff results are what we expect
175	// there should be 6 entries, one for each unique filename
176	if len(diffMap) != 6 {
177		t.Fatalf("Expected %d, got %d", 6, len(diffMap))
178	}
179
180	// check each filename is present, and check its pair
181	// pair 1 -- same in both
182	pair1, ok := diffMap["/project/file1.txt"]
183	if !ok {
184		t.Fatalf("Couldn't get pair1")
185	}
186	if pair1.First != f1.LicenseConcluded {
187		t.Errorf("Expected %s, got %s", f1.LicenseConcluded, pair1.First)
188	}
189	if pair1.Second != f1.LicenseConcluded {
190		t.Errorf("Expected %s, got %s", f2.LicenseConcluded, pair1.Second)
191	}
192
193	// pair 2 -- only in first
194	pair2, ok := diffMap["/project/file2.txt"]
195	if !ok {
196		t.Fatalf("Couldn't get pair2")
197	}
198	if pair2.First != f2.LicenseConcluded {
199		t.Errorf("Expected %s, got %s", f2.LicenseConcluded, pair2.First)
200	}
201	if pair2.Second != "" {
202		t.Errorf("Expected %s, got %s", "", pair2.Second)
203	}
204
205	// pair 3 -- only in second
206	pair3, ok := diffMap["/project/file3.txt"]
207	if !ok {
208		t.Fatalf("Couldn't get pair3")
209	}
210	if pair3.First != "" {
211		t.Errorf("Expected %s, got %s", "", pair3.First)
212	}
213	if pair3.Second != f3.LicenseConcluded {
214		t.Errorf("Expected %s, got %s", f3.LicenseConcluded, pair3.Second)
215	}
216
217	// pair 4 -- in both but different license
218	pair4, ok := diffMap["/project/file4.txt"]
219	if !ok {
220		t.Fatalf("Couldn't get pair4")
221	}
222	if pair4.First != f4_1.LicenseConcluded {
223		t.Errorf("Expected %s, got %s", f4_1.LicenseConcluded, pair4.First)
224	}
225	if pair4.Second != f4_2.LicenseConcluded {
226		t.Errorf("Expected %s, got %s", f4_2.LicenseConcluded, pair4.Second)
227	}
228
229	// pair 5 -- in both but different hash, same license
230	pair5, ok := diffMap["/project/file5.txt"]
231	if !ok {
232		t.Fatalf("Couldn't get pair5")
233	}
234	if pair5.First != f5_1.LicenseConcluded {
235		t.Errorf("Expected %s, got %s", f5_1.LicenseConcluded, pair5.First)
236	}
237	if pair5.Second != f5_2.LicenseConcluded {
238		t.Errorf("Expected %s, got %s", f5_2.LicenseConcluded, pair5.Second)
239	}
240
241	// pair 6 -- in both but different hash, different license
242	pair6, ok := diffMap["/project/file6.txt"]
243	if !ok {
244		t.Fatalf("Couldn't get pair6")
245	}
246	if pair6.First != f6_1.LicenseConcluded {
247		t.Errorf("Expected %s, got %s", f6_1.LicenseConcluded, pair6.First)
248	}
249	if pair6.Second != f6_2.LicenseConcluded {
250		t.Errorf("Expected %s, got %s", f6_2.LicenseConcluded, pair6.Second)
251	}
252}
253
254func Test2_1DifferCanCreateDiffStructuredResults(t *testing.T) {
255	// create files to be used in diff
256	// f1 will be identical in both
257	f1 := &v2_1.File{
258		FileName:           "/project/file1.txt",
259		FileSPDXIdentifier: common.ElementID("File561"),
260		Checksums:          []common.Checksum{{Value: "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3", Algorithm: common.SHA1}},
261		LicenseConcluded:   "Apache-2.0",
262		LicenseInfoInFiles: []string{
263			"LicenseRef-We-will-ignore-LicenseInfoInFiles",
264		},
265		FileCopyrightText: "We'll ignore copyright values",
266	}
267
268	// f2 will only appear in the first Package
269	f2 := &v2_1.File{
270		FileName:           "/project/file2.txt",
271		FileSPDXIdentifier: common.ElementID("File562"),
272		Checksums:          []common.Checksum{{Value: "066c5139bd9a43d15812ec1a1755b08ccf199824", Algorithm: common.SHA1}},
273		LicenseConcluded:   "GPL-2.0-or-later",
274		LicenseInfoInFiles: []string{
275			"NOASSERTION",
276		},
277		FileCopyrightText: "NOASSERTION",
278	}
279
280	// f3 will only appear in the second Package
281	f3 := &v2_1.File{
282		FileName:           "/project/file3.txt",
283		FileSPDXIdentifier: common.ElementID("File563"),
284		Checksums:          []common.Checksum{{Value: "bd0f4863b15fad2b79b35303af54fcb5baaf7c68", Algorithm: common.SHA1}},
285		LicenseConcluded:   "MPL-2.0",
286		LicenseInfoInFiles: []string{
287			"NOASSERTION",
288		},
289		FileCopyrightText: "NOASSERTION",
290	}
291
292	// f4_1 and f4_2 will appear in first and second,
293	// with same name, same hash and different license
294	f4_1 := &v2_1.File{
295		FileName:           "/project/file4.txt",
296		FileSPDXIdentifier: common.ElementID("File564"),
297		Checksums:          []common.Checksum{{Value: "bc417a575ceae93435bcb7bfd382ac28cbdaa8b5", Algorithm: common.SHA1}},
298		LicenseConcluded:   "MIT",
299		LicenseInfoInFiles: []string{
300			"NOASSERTION",
301		},
302		FileCopyrightText: "NOASSERTION",
303	}
304	f4_2 := &v2_1.File{
305		FileName:           "/project/file4.txt",
306		FileSPDXIdentifier: common.ElementID("File564"),
307		Checksums:          []common.Checksum{{Value: "bc417a575ceae93435bcb7bfd382ac28cbdaa8b5", Algorithm: common.SHA1}},
308		LicenseConcluded:   "Apache-2.0 AND MIT",
309		LicenseInfoInFiles: []string{
310			"NOASSERTION",
311		},
312		FileCopyrightText: "NOASSERTION",
313	}
314
315	// f5_1 and f5_2 will appear in first and second,
316	// with same name, different hash and same license
317	f5_1 := &v2_1.File{
318		FileName:           "/project/file5.txt",
319		FileSPDXIdentifier: common.ElementID("File565"),
320		Checksums:          []common.Checksum{{Value: "ba226db943bbbf455da77afab6f16dbab156d000", Algorithm: common.SHA1}},
321		LicenseConcluded:   "BSD-3-Clause",
322		LicenseInfoInFiles: []string{
323			"NOASSERTION",
324		},
325		FileCopyrightText: "NOASSERTION",
326	}
327	f5_2 := &v2_1.File{
328		FileName:           "/project/file5.txt",
329		FileSPDXIdentifier: common.ElementID("File565"),
330		Checksums:          []common.Checksum{{Value: "b6e0ec7d085c5699b46f6f8d425413702652874d", Algorithm: common.SHA1}},
331		LicenseConcluded:   "BSD-3-Clause",
332		LicenseInfoInFiles: []string{
333			"NOASSERTION",
334		},
335		FileCopyrightText: "NOASSERTION",
336	}
337
338	// f6_1 and f6_2 will appear in first and second,
339	// with same name, different hash and different license
340	f6_1 := &v2_1.File{
341		FileName:           "/project/file6.txt",
342		FileSPDXIdentifier: common.ElementID("File566"),
343		Checksums:          []common.Checksum{{Value: "ba226db943bbbf455da77afab6f16dbab156d000", Algorithm: common.SHA1}},
344		LicenseConcluded:   "CC0-1.0",
345		LicenseInfoInFiles: []string{
346			"NOASSERTION",
347		},
348		FileCopyrightText: "NOASSERTION",
349	}
350	f6_2 := &v2_1.File{
351		FileName:           "/project/file6.txt",
352		FileSPDXIdentifier: common.ElementID("File566"),
353		Checksums:          []common.Checksum{{Value: "b6e0ec7d085c5699b46f6f8d425413702652874d", Algorithm: common.SHA1}},
354		LicenseConcluded:   "Unlicense",
355		LicenseInfoInFiles: []string{
356			"NOASSERTION",
357		},
358		FileCopyrightText: "NOASSERTION",
359	}
360
361	// create Packages
362	p1 := &v2_1.Package{
363		PackageName:               "p1",
364		PackageSPDXIdentifier:     common.ElementID("p1"),
365		PackageDownloadLocation:   "NOASSERTION",
366		FilesAnalyzed:             true,
367		IsFilesAnalyzedTagPresent: true,
368		// fake the verification code for present purposes
369		PackageVerificationCode: common.PackageVerificationCode{Value: "abc123abc123"},
370		PackageLicenseConcluded: "NOASSERTION",
371		PackageLicenseInfoFromFiles: []string{
372			"NOASSERTION",
373		},
374		PackageLicenseDeclared: "NOASSERTION",
375		PackageCopyrightText:   "NOASSERTION",
376		Files: []*v2_1.File{
377			f1,
378			f2,
379			f4_1,
380			f5_1,
381			f6_1,
382		},
383	}
384	p2 := &v2_1.Package{
385		PackageName:               "p2",
386		PackageSPDXIdentifier:     common.ElementID("p2"),
387		PackageDownloadLocation:   "NOASSERTION",
388		FilesAnalyzed:             true,
389		IsFilesAnalyzedTagPresent: true,
390		// fake the verification code for present purposes
391		PackageVerificationCode: common.PackageVerificationCode{Value: "def456def456"},
392		PackageLicenseConcluded: "NOASSERTION",
393		PackageLicenseInfoFromFiles: []string{
394			"NOASSERTION",
395		},
396		PackageLicenseDeclared: "NOASSERTION",
397		PackageCopyrightText:   "NOASSERTION",
398		Files: []*v2_1.File{
399			f1,
400			f3,
401			f4_2,
402			f5_2,
403			f6_2,
404		},
405	}
406
407	// run the diff between the two packages
408	diffMap, err := MakePairs2_1(p1, p2)
409	if err != nil {
410		t.Fatalf("Expected nil error, got %v", err)
411	}
412
413	// now, create the LicenseDiff structured results from the pairs
414	diffResults, err := MakeResults(diffMap)
415	if err != nil {
416		t.Fatalf("Expected nil error, got %v", err)
417	}
418
419	// check that the diff results are the expected lengths
420	if len(diffResults.InBothChanged) != 2 {
421		t.Fatalf("Expected %d, got %d", 2, len(diffResults.InBothChanged))
422	}
423	if len(diffResults.InBothSame) != 2 {
424		t.Fatalf("Expected %d, got %d", 2, len(diffResults.InBothSame))
425	}
426	if len(diffResults.InFirstOnly) != 1 {
427		t.Fatalf("Expected %d, got %d", 1, len(diffResults.InFirstOnly))
428	}
429	if len(diffResults.InSecondOnly) != 1 {
430		t.Fatalf("Expected %d, got %d", 1, len(diffResults.InSecondOnly))
431	}
432
433	// check each filename is present where it belongs, and check license(s)
434
435	// in both and different license: f4 and f6
436	// filename will map to a LicensePair
437	check4, ok := diffResults.InBothChanged["/project/file4.txt"]
438	if !ok {
439		t.Fatalf("Couldn't get check4")
440	}
441	if check4.First != f4_1.LicenseConcluded {
442		t.Errorf("Expected %s, got %s", f4_1.LicenseConcluded, check4.First)
443	}
444	if check4.Second != f4_2.LicenseConcluded {
445		t.Errorf("Expected %s, got %s", f4_2.LicenseConcluded, check4.Second)
446	}
447	check6, ok := diffResults.InBothChanged["/project/file6.txt"]
448	if !ok {
449		t.Fatalf("Couldn't get check6")
450	}
451	if check6.First != f6_1.LicenseConcluded {
452		t.Errorf("Expected %s, got %s", f6_1.LicenseConcluded, check6.First)
453	}
454	if check6.Second != f6_2.LicenseConcluded {
455		t.Errorf("Expected %s, got %s", f6_2.LicenseConcluded, check6.Second)
456	}
457
458	// in both and same license: f1 and f5
459	// filename will map to a string
460	check1, ok := diffResults.InBothSame["/project/file1.txt"]
461	if !ok {
462		t.Fatalf("Couldn't get check1")
463	}
464	if check1 != f1.LicenseConcluded {
465		t.Errorf("Expected %s, got %s", f1.LicenseConcluded, check1)
466	}
467	check5, ok := diffResults.InBothSame["/project/file5.txt"]
468	if !ok {
469		t.Fatalf("Couldn't get check5")
470	}
471	if check5 != f5_1.LicenseConcluded {
472		t.Errorf("Expected %s, got %s", f5_1.LicenseConcluded, check5)
473	}
474	if check5 != f5_2.LicenseConcluded {
475		t.Errorf("Expected %s, got %s", f5_2.LicenseConcluded, check5)
476	}
477
478	// in first only: f2
479	// filename will map to a string
480	check2, ok := diffResults.InFirstOnly["/project/file2.txt"]
481	if !ok {
482		t.Fatalf("Couldn't get check2")
483	}
484	if check2 != f2.LicenseConcluded {
485		t.Errorf("Expected %s, got %s", f2.LicenseConcluded, check2)
486	}
487
488	// in second only: f3
489	// filename will map to a string
490	check3, ok := diffResults.InSecondOnly["/project/file3.txt"]
491	if !ok {
492		t.Fatalf("Couldn't get check3")
493	}
494	if check3 != f3.LicenseConcluded {
495		t.Errorf("Expected %s, got %s", f3.LicenseConcluded, check2)
496	}
497
498}
499
500// ===== 2.2 License diff top-level function tests =====
501func Test2_2DifferCanCreateDiffPairs(t *testing.T) {
502	// create files to be used in diff
503	// f1 will be identical in both
504	f1 := &v2_2.File{
505		FileName:           "/project/file1.txt",
506		FileSPDXIdentifier: common.ElementID("File561"),
507		Checksums: []common.Checksum{{
508			Algorithm: common.SHA1,
509			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
510		},
511		},
512		LicenseConcluded: "Apache-2.0",
513		LicenseInfoInFiles: []string{
514			"LicenseRef-We-will-ignore-LicenseInfoInFiles",
515		},
516		FileCopyrightText: "We'll ignore copyright values",
517	}
518
519	// f2 will only appear in the first Package
520	f2 := &v2_2.File{
521		FileName:           "/project/file2.txt",
522		FileSPDXIdentifier: common.ElementID("File562"),
523		Checksums: []common.Checksum{{
524			Algorithm: common.SHA1,
525			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
526		},
527		},
528		LicenseConcluded: "GPL-2.0-or-later",
529		LicenseInfoInFiles: []string{
530			"NOASSERTION",
531		},
532		FileCopyrightText: "NOASSERTION",
533	}
534
535	// f3 will only appear in the second Package
536	f3 := &v2_2.File{
537		FileName:           "/project/file3.txt",
538		FileSPDXIdentifier: common.ElementID("File563"),
539		Checksums: []common.Checksum{{
540			Algorithm: common.SHA1,
541			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
542		},
543		},
544		LicenseConcluded: "MPL-2.0",
545		LicenseInfoInFiles: []string{
546			"NOASSERTION",
547		},
548		FileCopyrightText: "NOASSERTION",
549	}
550
551	// f4_1 and f4_2 will appear in first and second,
552	// with same name, same hash and different license
553	f4_1 := &v2_2.File{
554		FileName:           "/project/file4.txt",
555		FileSPDXIdentifier: common.ElementID("File564"),
556		Checksums: []common.Checksum{{
557			Algorithm: common.SHA1,
558			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
559		},
560		},
561		LicenseConcluded: "MIT",
562		LicenseInfoInFiles: []string{
563			"NOASSERTION",
564		},
565		FileCopyrightText: "NOASSERTION",
566	}
567	f4_2 := &v2_2.File{
568		FileName:           "/project/file4.txt",
569		FileSPDXIdentifier: common.ElementID("File564"),
570		Checksums: []common.Checksum{{
571			Algorithm: common.SHA1,
572			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
573		},
574		},
575		LicenseConcluded: "Apache-2.0 AND MIT",
576		LicenseInfoInFiles: []string{
577			"NOASSERTION",
578		},
579		FileCopyrightText: "NOASSERTION",
580	}
581
582	// f5_1 and f5_2 will appear in first and second,
583	// with same name, different hash and same license
584	f5_1 := &v2_2.File{
585		FileName:           "/project/file5.txt",
586		FileSPDXIdentifier: common.ElementID("File565"),
587		Checksums: []common.Checksum{{
588			Algorithm: common.SHA1,
589			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
590		},
591		},
592		LicenseConcluded: "BSD-3-Clause",
593		LicenseInfoInFiles: []string{
594			"NOASSERTION",
595		},
596		FileCopyrightText: "NOASSERTION",
597	}
598	f5_2 := &v2_2.File{
599		FileName:           "/project/file5.txt",
600		FileSPDXIdentifier: common.ElementID("File565"),
601		Checksums: []common.Checksum{{
602			Algorithm: common.SHA1,
603			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
604		},
605		},
606		LicenseConcluded: "BSD-3-Clause",
607		LicenseInfoInFiles: []string{
608			"NOASSERTION",
609		},
610		FileCopyrightText: "NOASSERTION",
611	}
612
613	// f6_1 and f6_2 will appear in first and second,
614	// with same name, different hash and different license
615	f6_1 := &v2_2.File{
616		FileName:           "/project/file6.txt",
617		FileSPDXIdentifier: common.ElementID("File566"),
618		Checksums: []common.Checksum{{
619			Algorithm: common.SHA1,
620			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
621		},
622		},
623		LicenseConcluded: "CC0-1.0",
624		LicenseInfoInFiles: []string{
625			"NOASSERTION",
626		},
627		FileCopyrightText: "NOASSERTION",
628	}
629	f6_2 := &v2_2.File{
630		FileName:           "/project/file6.txt",
631		FileSPDXIdentifier: common.ElementID("File566"),
632		Checksums: []common.Checksum{{
633			Algorithm: common.SHA1,
634			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
635		},
636		},
637		LicenseConcluded: "Unlicense",
638		LicenseInfoInFiles: []string{
639			"NOASSERTION",
640		},
641		FileCopyrightText: "NOASSERTION",
642	}
643
644	// create Packages
645	p1 := &v2_2.Package{
646		PackageName:               "p1",
647		PackageSPDXIdentifier:     common.ElementID("p1"),
648		PackageDownloadLocation:   "NOASSERTION",
649		FilesAnalyzed:             true,
650		IsFilesAnalyzedTagPresent: true,
651		// fake the verification code for present purposes
652		PackageVerificationCode: common.PackageVerificationCode{Value: "abc123abc123"},
653		PackageLicenseConcluded: "NOASSERTION",
654		PackageLicenseInfoFromFiles: []string{
655			"NOASSERTION",
656		},
657		PackageLicenseDeclared: "NOASSERTION",
658		PackageCopyrightText:   "NOASSERTION",
659		Files: []*v2_2.File{
660			f1,
661			f2,
662			f4_1,
663			f5_1,
664			f6_1,
665		},
666	}
667	p2 := &v2_2.Package{
668		PackageName:               "p2",
669		PackageSPDXIdentifier:     common.ElementID("p2"),
670		PackageDownloadLocation:   "NOASSERTION",
671		FilesAnalyzed:             true,
672		IsFilesAnalyzedTagPresent: true,
673		// fake the verification code for present purposes
674		PackageVerificationCode: common.PackageVerificationCode{Value: "def456def456"},
675		PackageLicenseConcluded: "NOASSERTION",
676		PackageLicenseInfoFromFiles: []string{
677			"NOASSERTION",
678		},
679		PackageLicenseDeclared: "NOASSERTION",
680		PackageCopyrightText:   "NOASSERTION",
681		Files: []*v2_2.File{
682			f1,
683			f3,
684			f4_2,
685			f5_2,
686			f6_2,
687		},
688	}
689
690	// run the diff between the two packages
691	diffMap, err := MakePairs2_2(p1, p2)
692	if err != nil {
693		t.Fatalf("Expected nil error, got %v", err)
694	}
695
696	// check that the diff results are what we expect
697	// there should be 6 entries, one for each unique filename
698	if len(diffMap) != 6 {
699		t.Fatalf("Expected %d, got %d", 6, len(diffMap))
700	}
701
702	// check each filename is present, and check its pair
703	// pair 1 -- same in both
704	pair1, ok := diffMap["/project/file1.txt"]
705	if !ok {
706		t.Fatalf("Couldn't get pair1")
707	}
708	if pair1.First != f1.LicenseConcluded {
709		t.Errorf("Expected %s, got %s", f1.LicenseConcluded, pair1.First)
710	}
711	if pair1.Second != f1.LicenseConcluded {
712		t.Errorf("Expected %s, got %s", f2.LicenseConcluded, pair1.Second)
713	}
714
715	// pair 2 -- only in first
716	pair2, ok := diffMap["/project/file2.txt"]
717	if !ok {
718		t.Fatalf("Couldn't get pair2")
719	}
720	if pair2.First != f2.LicenseConcluded {
721		t.Errorf("Expected %s, got %s", f2.LicenseConcluded, pair2.First)
722	}
723	if pair2.Second != "" {
724		t.Errorf("Expected %s, got %s", "", pair2.Second)
725	}
726
727	// pair 3 -- only in second
728	pair3, ok := diffMap["/project/file3.txt"]
729	if !ok {
730		t.Fatalf("Couldn't get pair3")
731	}
732	if pair3.First != "" {
733		t.Errorf("Expected %s, got %s", "", pair3.First)
734	}
735	if pair3.Second != f3.LicenseConcluded {
736		t.Errorf("Expected %s, got %s", f3.LicenseConcluded, pair3.Second)
737	}
738
739	// pair 4 -- in both but different license
740	pair4, ok := diffMap["/project/file4.txt"]
741	if !ok {
742		t.Fatalf("Couldn't get pair4")
743	}
744	if pair4.First != f4_1.LicenseConcluded {
745		t.Errorf("Expected %s, got %s", f4_1.LicenseConcluded, pair4.First)
746	}
747	if pair4.Second != f4_2.LicenseConcluded {
748		t.Errorf("Expected %s, got %s", f4_2.LicenseConcluded, pair4.Second)
749	}
750
751	// pair 5 -- in both but different hash, same license
752	pair5, ok := diffMap["/project/file5.txt"]
753	if !ok {
754		t.Fatalf("Couldn't get pair5")
755	}
756	if pair5.First != f5_1.LicenseConcluded {
757		t.Errorf("Expected %s, got %s", f5_1.LicenseConcluded, pair5.First)
758	}
759	if pair5.Second != f5_2.LicenseConcluded {
760		t.Errorf("Expected %s, got %s", f5_2.LicenseConcluded, pair5.Second)
761	}
762
763	// pair 6 -- in both but different hash, different license
764	pair6, ok := diffMap["/project/file6.txt"]
765	if !ok {
766		t.Fatalf("Couldn't get pair6")
767	}
768	if pair6.First != f6_1.LicenseConcluded {
769		t.Errorf("Expected %s, got %s", f6_1.LicenseConcluded, pair6.First)
770	}
771	if pair6.Second != f6_2.LicenseConcluded {
772		t.Errorf("Expected %s, got %s", f6_2.LicenseConcluded, pair6.Second)
773	}
774}
775
776func Test2_2DifferCanCreateDiffStructuredResults(t *testing.T) {
777	// create files to be used in diff
778	// f1 will be identical in both
779	f1 := &v2_2.File{
780		FileName:           "/project/file1.txt",
781		FileSPDXIdentifier: common.ElementID("File561"),
782		Checksums: []common.Checksum{{
783			Algorithm: common.SHA1,
784			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
785		},
786		},
787		LicenseConcluded: "Apache-2.0",
788		LicenseInfoInFiles: []string{
789			"LicenseRef-We-will-ignore-LicenseInfoInFiles",
790		},
791		FileCopyrightText: "We'll ignore copyright values",
792	}
793
794	// f2 will only appear in the first Package
795	f2 := &v2_2.File{
796		FileName:           "/project/file2.txt",
797		FileSPDXIdentifier: common.ElementID("File562"),
798		Checksums: []common.Checksum{{
799			Algorithm: common.SHA1,
800			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
801		},
802		},
803		LicenseConcluded: "GPL-2.0-or-later",
804		LicenseInfoInFiles: []string{
805			"NOASSERTION",
806		},
807		FileCopyrightText: "NOASSERTION",
808	}
809
810	// f3 will only appear in the second Package
811	f3 := &v2_2.File{
812		FileName:           "/project/file3.txt",
813		FileSPDXIdentifier: common.ElementID("File563"),
814		Checksums: []common.Checksum{{
815			Algorithm: common.SHA1,
816			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
817		},
818		},
819		LicenseConcluded: "MPL-2.0",
820		LicenseInfoInFiles: []string{
821			"NOASSERTION",
822		},
823		FileCopyrightText: "NOASSERTION",
824	}
825
826	// f4_1 and f4_2 will appear in first and second,
827	// with same name, same hash and different license
828	f4_1 := &v2_2.File{
829		FileName:           "/project/file4.txt",
830		FileSPDXIdentifier: common.ElementID("File564"),
831		Checksums: []common.Checksum{{
832			Algorithm: common.SHA1,
833			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
834		},
835		},
836		LicenseConcluded: "MIT",
837		LicenseInfoInFiles: []string{
838			"NOASSERTION",
839		},
840		FileCopyrightText: "NOASSERTION",
841	}
842	f4_2 := &v2_2.File{
843		FileName:           "/project/file4.txt",
844		FileSPDXIdentifier: common.ElementID("File564"),
845		Checksums: []common.Checksum{{
846			Algorithm: common.SHA1,
847			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
848		},
849		},
850		LicenseConcluded: "Apache-2.0 AND MIT",
851		LicenseInfoInFiles: []string{
852			"NOASSERTION",
853		},
854		FileCopyrightText: "NOASSERTION",
855	}
856
857	// f5_1 and f5_2 will appear in first and second,
858	// with same name, different hash and same license
859	f5_1 := &v2_2.File{
860		FileName:           "/project/file5.txt",
861		FileSPDXIdentifier: common.ElementID("File565"),
862		LicenseConcluded:   "BSD-3-Clause",
863		LicenseInfoInFiles: []string{
864			"NOASSERTION",
865		},
866		FileCopyrightText: "NOASSERTION",
867	}
868	f5_2 := &v2_2.File{
869		FileName:           "/project/file5.txt",
870		FileSPDXIdentifier: common.ElementID("File565"),
871		Checksums: []common.Checksum{{
872			Algorithm: common.SHA1,
873			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
874		},
875		},
876
877		LicenseConcluded: "BSD-3-Clause",
878		LicenseInfoInFiles: []string{
879			"NOASSERTION",
880		},
881		FileCopyrightText: "NOASSERTION",
882	}
883
884	// f6_1 and f6_2 will appear in first and second,
885	// with same name, different hash and different license
886	f6_1 := &v2_2.File{
887		FileName:           "/project/file6.txt",
888		FileSPDXIdentifier: common.ElementID("File566"),
889		Checksums: []common.Checksum{{
890			Algorithm: common.SHA1,
891			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
892		},
893		},
894		LicenseConcluded: "CC0-1.0",
895		LicenseInfoInFiles: []string{
896			"NOASSERTION",
897		},
898		FileCopyrightText: "NOASSERTION",
899	}
900	f6_2 := &v2_2.File{
901		FileName:           "/project/file6.txt",
902		FileSPDXIdentifier: common.ElementID("File566"),
903		Checksums: []common.Checksum{{
904			Algorithm: common.SHA1,
905			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
906		},
907		},
908		LicenseConcluded: "Unlicense",
909		LicenseInfoInFiles: []string{
910			"NOASSERTION",
911		},
912		FileCopyrightText: "NOASSERTION",
913	}
914
915	// create Packages
916	p1 := &v2_2.Package{
917		PackageName:               "p1",
918		PackageSPDXIdentifier:     common.ElementID("p1"),
919		PackageDownloadLocation:   "NOASSERTION",
920		FilesAnalyzed:             true,
921		IsFilesAnalyzedTagPresent: true,
922		// fake the verification code for present purposes
923		PackageVerificationCode: common.PackageVerificationCode{Value: "abc123abc123"},
924		PackageLicenseConcluded: "NOASSERTION",
925		PackageLicenseInfoFromFiles: []string{
926			"NOASSERTION",
927		},
928		PackageLicenseDeclared: "NOASSERTION",
929		PackageCopyrightText:   "NOASSERTION",
930		Files: []*v2_2.File{
931			f1,
932			f2,
933			f4_1,
934			f5_1,
935			f6_1,
936		},
937	}
938	p2 := &v2_2.Package{
939		PackageName:               "p2",
940		PackageSPDXIdentifier:     common.ElementID("p2"),
941		PackageDownloadLocation:   "NOASSERTION",
942		FilesAnalyzed:             true,
943		IsFilesAnalyzedTagPresent: true,
944		// fake the verification code for present purposes
945		PackageVerificationCode: common.PackageVerificationCode{Value: "def456def456"},
946		PackageLicenseConcluded: "NOASSERTION",
947		PackageLicenseInfoFromFiles: []string{
948			"NOASSERTION",
949		},
950		PackageLicenseDeclared: "NOASSERTION",
951		PackageCopyrightText:   "NOASSERTION",
952		Files: []*v2_2.File{
953			f1,
954			f3,
955			f4_2,
956			f5_2,
957			f6_2,
958		},
959	}
960
961	// run the diff between the two packages
962	diffMap, err := MakePairs2_2(p1, p2)
963	if err != nil {
964		t.Fatalf("Expected nil error, got %v", err)
965	}
966
967	// now, create the LicenseDiff structured results from the pairs
968	diffResults, err := MakeResults(diffMap)
969	if err != nil {
970		t.Fatalf("Expected nil error, got %v", err)
971	}
972
973	// check that the diff results are the expected lengths
974	if len(diffResults.InBothChanged) != 2 {
975		t.Fatalf("Expected %d, got %d", 2, len(diffResults.InBothChanged))
976	}
977	if len(diffResults.InBothSame) != 2 {
978		t.Fatalf("Expected %d, got %d", 2, len(diffResults.InBothSame))
979	}
980	if len(diffResults.InFirstOnly) != 1 {
981		t.Fatalf("Expected %d, got %d", 1, len(diffResults.InFirstOnly))
982	}
983	if len(diffResults.InSecondOnly) != 1 {
984		t.Fatalf("Expected %d, got %d", 1, len(diffResults.InSecondOnly))
985	}
986
987	// check each filename is present where it belongs, and check license(s)
988
989	// in both and different license: f4 and f6
990	// filename will map to a LicensePair
991	check4, ok := diffResults.InBothChanged["/project/file4.txt"]
992	if !ok {
993		t.Fatalf("Couldn't get check4")
994	}
995	if check4.First != f4_1.LicenseConcluded {
996		t.Errorf("Expected %s, got %s", f4_1.LicenseConcluded, check4.First)
997	}
998	if check4.Second != f4_2.LicenseConcluded {
999		t.Errorf("Expected %s, got %s", f4_2.LicenseConcluded, check4.Second)
1000	}
1001	check6, ok := diffResults.InBothChanged["/project/file6.txt"]
1002	if !ok {
1003		t.Fatalf("Couldn't get check6")
1004	}
1005	if check6.First != f6_1.LicenseConcluded {
1006		t.Errorf("Expected %s, got %s", f6_1.LicenseConcluded, check6.First)
1007	}
1008	if check6.Second != f6_2.LicenseConcluded {
1009		t.Errorf("Expected %s, got %s", f6_2.LicenseConcluded, check6.Second)
1010	}
1011
1012	// in both and same license: f1 and f5
1013	// filename will map to a string
1014	check1, ok := diffResults.InBothSame["/project/file1.txt"]
1015	if !ok {
1016		t.Fatalf("Couldn't get check1")
1017	}
1018	if check1 != f1.LicenseConcluded {
1019		t.Errorf("Expected %s, got %s", f1.LicenseConcluded, check1)
1020	}
1021	check5, ok := diffResults.InBothSame["/project/file5.txt"]
1022	if !ok {
1023		t.Fatalf("Couldn't get check5")
1024	}
1025	if check5 != f5_1.LicenseConcluded {
1026		t.Errorf("Expected %s, got %s", f5_1.LicenseConcluded, check5)
1027	}
1028	if check5 != f5_2.LicenseConcluded {
1029		t.Errorf("Expected %s, got %s", f5_2.LicenseConcluded, check5)
1030	}
1031
1032	// in first only: f2
1033	// filename will map to a string
1034	check2, ok := diffResults.InFirstOnly["/project/file2.txt"]
1035	if !ok {
1036		t.Fatalf("Couldn't get check2")
1037	}
1038	if check2 != f2.LicenseConcluded {
1039		t.Errorf("Expected %s, got %s", f2.LicenseConcluded, check2)
1040	}
1041
1042	// in second only: f3
1043	// filename will map to a string
1044	check3, ok := diffResults.InSecondOnly["/project/file3.txt"]
1045	if !ok {
1046		t.Fatalf("Couldn't get check3")
1047	}
1048	if check3 != f3.LicenseConcluded {
1049		t.Errorf("Expected %s, got %s", f3.LicenseConcluded, check2)
1050	}
1051
1052}
1053
1054// ===== 2.3 License diff top-level function tests =====
1055func Test2_3DifferCanCreateDiffPairs(t *testing.T) {
1056	// create files to be used in diff
1057	// f1 will be identical in both
1058	f1 := &v2_3.File{
1059		FileName:           "/project/file1.txt",
1060		FileSPDXIdentifier: common.ElementID("File561"),
1061		Checksums: []common.Checksum{{
1062			Algorithm: common.SHA1,
1063			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1064		},
1065		},
1066		LicenseConcluded: "Apache-2.0",
1067		LicenseInfoInFiles: []string{
1068			"LicenseRef-We-will-ignore-LicenseInfoInFiles",
1069		},
1070		FileCopyrightText: "We'll ignore copyright values",
1071	}
1072
1073	// f2 will only appear in the first Package
1074	f2 := &v2_3.File{
1075		FileName:           "/project/file2.txt",
1076		FileSPDXIdentifier: common.ElementID("File562"),
1077		Checksums: []common.Checksum{{
1078			Algorithm: common.SHA1,
1079			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1080		},
1081		},
1082		LicenseConcluded: "GPL-2.0-or-later",
1083		LicenseInfoInFiles: []string{
1084			"NOASSERTION",
1085		},
1086		FileCopyrightText: "NOASSERTION",
1087	}
1088
1089	// f3 will only appear in the second Package
1090	f3 := &v2_3.File{
1091		FileName:           "/project/file3.txt",
1092		FileSPDXIdentifier: common.ElementID("File563"),
1093		Checksums: []common.Checksum{{
1094			Algorithm: common.SHA1,
1095			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1096		},
1097		},
1098		LicenseConcluded: "MPL-2.0",
1099		LicenseInfoInFiles: []string{
1100			"NOASSERTION",
1101		},
1102		FileCopyrightText: "NOASSERTION",
1103	}
1104
1105	// f4_1 and f4_2 will appear in first and second,
1106	// with same name, same hash and different license
1107	f4_1 := &v2_3.File{
1108		FileName:           "/project/file4.txt",
1109		FileSPDXIdentifier: common.ElementID("File564"),
1110		Checksums: []common.Checksum{{
1111			Algorithm: common.SHA1,
1112			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1113		},
1114		},
1115		LicenseConcluded: "MIT",
1116		LicenseInfoInFiles: []string{
1117			"NOASSERTION",
1118		},
1119		FileCopyrightText: "NOASSERTION",
1120	}
1121	f4_2 := &v2_3.File{
1122		FileName:           "/project/file4.txt",
1123		FileSPDXIdentifier: common.ElementID("File564"),
1124		Checksums: []common.Checksum{{
1125			Algorithm: common.SHA1,
1126			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1127		},
1128		},
1129		LicenseConcluded: "Apache-2.0 AND MIT",
1130		LicenseInfoInFiles: []string{
1131			"NOASSERTION",
1132		},
1133		FileCopyrightText: "NOASSERTION",
1134	}
1135
1136	// f5_1 and f5_2 will appear in first and second,
1137	// with same name, different hash and same license
1138	f5_1 := &v2_3.File{
1139		FileName:           "/project/file5.txt",
1140		FileSPDXIdentifier: common.ElementID("File565"),
1141		Checksums: []common.Checksum{{
1142			Algorithm: common.SHA1,
1143			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1144		},
1145		},
1146		LicenseConcluded: "BSD-3-Clause",
1147		LicenseInfoInFiles: []string{
1148			"NOASSERTION",
1149		},
1150		FileCopyrightText: "NOASSERTION",
1151	}
1152	f5_2 := &v2_3.File{
1153		FileName:           "/project/file5.txt",
1154		FileSPDXIdentifier: common.ElementID("File565"),
1155		Checksums: []common.Checksum{{
1156			Algorithm: common.SHA1,
1157			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1158		},
1159		},
1160		LicenseConcluded: "BSD-3-Clause",
1161		LicenseInfoInFiles: []string{
1162			"NOASSERTION",
1163		},
1164		FileCopyrightText: "NOASSERTION",
1165	}
1166
1167	// f6_1 and f6_2 will appear in first and second,
1168	// with same name, different hash and different license
1169	f6_1 := &v2_3.File{
1170		FileName:           "/project/file6.txt",
1171		FileSPDXIdentifier: common.ElementID("File566"),
1172		Checksums: []common.Checksum{{
1173			Algorithm: common.SHA1,
1174			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1175		},
1176		},
1177		LicenseConcluded: "CC0-1.0",
1178		LicenseInfoInFiles: []string{
1179			"NOASSERTION",
1180		},
1181		FileCopyrightText: "NOASSERTION",
1182	}
1183	f6_2 := &v2_3.File{
1184		FileName:           "/project/file6.txt",
1185		FileSPDXIdentifier: common.ElementID("File566"),
1186		Checksums: []common.Checksum{{
1187			Algorithm: common.SHA1,
1188			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1189		},
1190		},
1191		LicenseConcluded: "Unlicense",
1192		LicenseInfoInFiles: []string{
1193			"NOASSERTION",
1194		},
1195		FileCopyrightText: "NOASSERTION",
1196	}
1197
1198	// create Packages
1199	p1 := &v2_3.Package{
1200		PackageName:               "p1",
1201		PackageSPDXIdentifier:     common.ElementID("p1"),
1202		PackageDownloadLocation:   "NOASSERTION",
1203		FilesAnalyzed:             true,
1204		IsFilesAnalyzedTagPresent: true,
1205		// fake the verification code for present purposes
1206		PackageVerificationCode: &common.PackageVerificationCode{Value: "abc123abc123"},
1207		PackageLicenseConcluded: "NOASSERTION",
1208		PackageLicenseInfoFromFiles: []string{
1209			"NOASSERTION",
1210		},
1211		PackageLicenseDeclared: "NOASSERTION",
1212		PackageCopyrightText:   "NOASSERTION",
1213		Files: []*v2_3.File{
1214			f1,
1215			f2,
1216			f4_1,
1217			f5_1,
1218			f6_1,
1219		},
1220	}
1221	p2 := &v2_3.Package{
1222		PackageName:               "p2",
1223		PackageSPDXIdentifier:     common.ElementID("p2"),
1224		PackageDownloadLocation:   "NOASSERTION",
1225		FilesAnalyzed:             true,
1226		IsFilesAnalyzedTagPresent: true,
1227		// fake the verification code for present purposes
1228		PackageVerificationCode: &common.PackageVerificationCode{Value: "def456def456"},
1229		PackageLicenseConcluded: "NOASSERTION",
1230		PackageLicenseInfoFromFiles: []string{
1231			"NOASSERTION",
1232		},
1233		PackageLicenseDeclared: "NOASSERTION",
1234		PackageCopyrightText:   "NOASSERTION",
1235		Files: []*v2_3.File{
1236			f1,
1237			f3,
1238			f4_2,
1239			f5_2,
1240			f6_2,
1241		},
1242	}
1243
1244	// run the diff between the two packages
1245	diffMap, err := MakePairs2_3(p1, p2)
1246	if err != nil {
1247		t.Fatalf("Expected nil error, got %v", err)
1248	}
1249
1250	// check that the diff results are what we expect
1251	// there should be 6 entries, one for each unique filename
1252	if len(diffMap) != 6 {
1253		t.Fatalf("Expected %d, got %d", 6, len(diffMap))
1254	}
1255
1256	// check each filename is present, and check its pair
1257	// pair 1 -- same in both
1258	pair1, ok := diffMap["/project/file1.txt"]
1259	if !ok {
1260		t.Fatalf("Couldn't get pair1")
1261	}
1262	if pair1.First != f1.LicenseConcluded {
1263		t.Errorf("Expected %s, got %s", f1.LicenseConcluded, pair1.First)
1264	}
1265	if pair1.Second != f1.LicenseConcluded {
1266		t.Errorf("Expected %s, got %s", f2.LicenseConcluded, pair1.Second)
1267	}
1268
1269	// pair 2 -- only in first
1270	pair2, ok := diffMap["/project/file2.txt"]
1271	if !ok {
1272		t.Fatalf("Couldn't get pair2")
1273	}
1274	if pair2.First != f2.LicenseConcluded {
1275		t.Errorf("Expected %s, got %s", f2.LicenseConcluded, pair2.First)
1276	}
1277	if pair2.Second != "" {
1278		t.Errorf("Expected %s, got %s", "", pair2.Second)
1279	}
1280
1281	// pair 3 -- only in second
1282	pair3, ok := diffMap["/project/file3.txt"]
1283	if !ok {
1284		t.Fatalf("Couldn't get pair3")
1285	}
1286	if pair3.First != "" {
1287		t.Errorf("Expected %s, got %s", "", pair3.First)
1288	}
1289	if pair3.Second != f3.LicenseConcluded {
1290		t.Errorf("Expected %s, got %s", f3.LicenseConcluded, pair3.Second)
1291	}
1292
1293	// pair 4 -- in both but different license
1294	pair4, ok := diffMap["/project/file4.txt"]
1295	if !ok {
1296		t.Fatalf("Couldn't get pair4")
1297	}
1298	if pair4.First != f4_1.LicenseConcluded {
1299		t.Errorf("Expected %s, got %s", f4_1.LicenseConcluded, pair4.First)
1300	}
1301	if pair4.Second != f4_2.LicenseConcluded {
1302		t.Errorf("Expected %s, got %s", f4_2.LicenseConcluded, pair4.Second)
1303	}
1304
1305	// pair 5 -- in both but different hash, same license
1306	pair5, ok := diffMap["/project/file5.txt"]
1307	if !ok {
1308		t.Fatalf("Couldn't get pair5")
1309	}
1310	if pair5.First != f5_1.LicenseConcluded {
1311		t.Errorf("Expected %s, got %s", f5_1.LicenseConcluded, pair5.First)
1312	}
1313	if pair5.Second != f5_2.LicenseConcluded {
1314		t.Errorf("Expected %s, got %s", f5_2.LicenseConcluded, pair5.Second)
1315	}
1316
1317	// pair 6 -- in both but different hash, different license
1318	pair6, ok := diffMap["/project/file6.txt"]
1319	if !ok {
1320		t.Fatalf("Couldn't get pair6")
1321	}
1322	if pair6.First != f6_1.LicenseConcluded {
1323		t.Errorf("Expected %s, got %s", f6_1.LicenseConcluded, pair6.First)
1324	}
1325	if pair6.Second != f6_2.LicenseConcluded {
1326		t.Errorf("Expected %s, got %s", f6_2.LicenseConcluded, pair6.Second)
1327	}
1328}
1329
1330func Test2_3DifferCanCreateDiffStructuredResults(t *testing.T) {
1331	// create files to be used in diff
1332	// f1 will be identical in both
1333	f1 := &v2_3.File{
1334		FileName:           "/project/file1.txt",
1335		FileSPDXIdentifier: common.ElementID("File561"),
1336		Checksums: []common.Checksum{{
1337			Algorithm: common.SHA1,
1338			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1339		},
1340		},
1341		LicenseConcluded: "Apache-2.0",
1342		LicenseInfoInFiles: []string{
1343			"LicenseRef-We-will-ignore-LicenseInfoInFiles",
1344		},
1345		FileCopyrightText: "We'll ignore copyright values",
1346	}
1347
1348	// f2 will only appear in the first Package
1349	f2 := &v2_3.File{
1350		FileName:           "/project/file2.txt",
1351		FileSPDXIdentifier: common.ElementID("File562"),
1352		Checksums: []common.Checksum{{
1353			Algorithm: common.SHA1,
1354			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1355		},
1356		},
1357		LicenseConcluded: "GPL-2.0-or-later",
1358		LicenseInfoInFiles: []string{
1359			"NOASSERTION",
1360		},
1361		FileCopyrightText: "NOASSERTION",
1362	}
1363
1364	// f3 will only appear in the second Package
1365	f3 := &v2_3.File{
1366		FileName:           "/project/file3.txt",
1367		FileSPDXIdentifier: common.ElementID("File563"),
1368		Checksums: []common.Checksum{{
1369			Algorithm: common.SHA1,
1370			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1371		},
1372		},
1373		LicenseConcluded: "MPL-2.0",
1374		LicenseInfoInFiles: []string{
1375			"NOASSERTION",
1376		},
1377		FileCopyrightText: "NOASSERTION",
1378	}
1379
1380	// f4_1 and f4_2 will appear in first and second,
1381	// with same name, same hash and different license
1382	f4_1 := &v2_3.File{
1383		FileName:           "/project/file4.txt",
1384		FileSPDXIdentifier: common.ElementID("File564"),
1385		Checksums: []common.Checksum{{
1386			Algorithm: common.SHA1,
1387			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1388		},
1389		},
1390		LicenseConcluded: "MIT",
1391		LicenseInfoInFiles: []string{
1392			"NOASSERTION",
1393		},
1394		FileCopyrightText: "NOASSERTION",
1395	}
1396	f4_2 := &v2_3.File{
1397		FileName:           "/project/file4.txt",
1398		FileSPDXIdentifier: common.ElementID("File564"),
1399		Checksums: []common.Checksum{{
1400			Algorithm: common.SHA1,
1401			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1402		},
1403		},
1404		LicenseConcluded: "Apache-2.0 AND MIT",
1405		LicenseInfoInFiles: []string{
1406			"NOASSERTION",
1407		},
1408		FileCopyrightText: "NOASSERTION",
1409	}
1410
1411	// f5_1 and f5_2 will appear in first and second,
1412	// with same name, different hash and same license
1413	f5_1 := &v2_3.File{
1414		FileName:           "/project/file5.txt",
1415		FileSPDXIdentifier: common.ElementID("File565"),
1416		LicenseConcluded:   "BSD-3-Clause",
1417		LicenseInfoInFiles: []string{
1418			"NOASSERTION",
1419		},
1420		FileCopyrightText: "NOASSERTION",
1421	}
1422	f5_2 := &v2_3.File{
1423		FileName:           "/project/file5.txt",
1424		FileSPDXIdentifier: common.ElementID("File565"),
1425		Checksums: []common.Checksum{{
1426			Algorithm: common.SHA1,
1427			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1428		},
1429		},
1430
1431		LicenseConcluded: "BSD-3-Clause",
1432		LicenseInfoInFiles: []string{
1433			"NOASSERTION",
1434		},
1435		FileCopyrightText: "NOASSERTION",
1436	}
1437
1438	// f6_1 and f6_2 will appear in first and second,
1439	// with same name, different hash and different license
1440	f6_1 := &v2_3.File{
1441		FileName:           "/project/file6.txt",
1442		FileSPDXIdentifier: common.ElementID("File566"),
1443		Checksums: []common.Checksum{{
1444			Algorithm: common.SHA1,
1445			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1446		},
1447		},
1448		LicenseConcluded: "CC0-1.0",
1449		LicenseInfoInFiles: []string{
1450			"NOASSERTION",
1451		},
1452		FileCopyrightText: "NOASSERTION",
1453	}
1454	f6_2 := &v2_3.File{
1455		FileName:           "/project/file6.txt",
1456		FileSPDXIdentifier: common.ElementID("File566"),
1457		Checksums: []common.Checksum{{
1458			Algorithm: common.SHA1,
1459			Value:     "6c92dc8bc462b6889d9b1c0bc16c54d19a2cbdd3",
1460		},
1461		},
1462		LicenseConcluded: "Unlicense",
1463		LicenseInfoInFiles: []string{
1464			"NOASSERTION",
1465		},
1466		FileCopyrightText: "NOASSERTION",
1467	}
1468
1469	// create Packages
1470	p1 := &v2_3.Package{
1471		PackageName:               "p1",
1472		PackageSPDXIdentifier:     common.ElementID("p1"),
1473		PackageDownloadLocation:   "NOASSERTION",
1474		FilesAnalyzed:             true,
1475		IsFilesAnalyzedTagPresent: true,
1476		// fake the verification code for present purposes
1477		PackageVerificationCode: &common.PackageVerificationCode{Value: "abc123abc123"},
1478		PackageLicenseConcluded: "NOASSERTION",
1479		PackageLicenseInfoFromFiles: []string{
1480			"NOASSERTION",
1481		},
1482		PackageLicenseDeclared: "NOASSERTION",
1483		PackageCopyrightText:   "NOASSERTION",
1484		Files: []*v2_3.File{
1485			f1,
1486			f2,
1487			f4_1,
1488			f5_1,
1489			f6_1,
1490		},
1491	}
1492	p2 := &v2_3.Package{
1493		PackageName:               "p2",
1494		PackageSPDXIdentifier:     common.ElementID("p2"),
1495		PackageDownloadLocation:   "NOASSERTION",
1496		FilesAnalyzed:             true,
1497		IsFilesAnalyzedTagPresent: true,
1498		// fake the verification code for present purposes
1499		PackageVerificationCode: &common.PackageVerificationCode{Value: "def456def456"},
1500		PackageLicenseConcluded: "NOASSERTION",
1501		PackageLicenseInfoFromFiles: []string{
1502			"NOASSERTION",
1503		},
1504		PackageLicenseDeclared: "NOASSERTION",
1505		PackageCopyrightText:   "NOASSERTION",
1506		Files: []*v2_3.File{
1507			f1,
1508			f3,
1509			f4_2,
1510			f5_2,
1511			f6_2,
1512		},
1513	}
1514
1515	// run the diff between the two packages
1516	diffMap, err := MakePairs2_3(p1, p2)
1517	if err != nil {
1518		t.Fatalf("Expected nil error, got %v", err)
1519	}
1520
1521	// now, create the LicenseDiff structured results from the pairs
1522	diffResults, err := MakeResults(diffMap)
1523	if err != nil {
1524		t.Fatalf("Expected nil error, got %v", err)
1525	}
1526
1527	// check that the diff results are the expected lengths
1528	if len(diffResults.InBothChanged) != 2 {
1529		t.Fatalf("Expected %d, got %d", 2, len(diffResults.InBothChanged))
1530	}
1531	if len(diffResults.InBothSame) != 2 {
1532		t.Fatalf("Expected %d, got %d", 2, len(diffResults.InBothSame))
1533	}
1534	if len(diffResults.InFirstOnly) != 1 {
1535		t.Fatalf("Expected %d, got %d", 1, len(diffResults.InFirstOnly))
1536	}
1537	if len(diffResults.InSecondOnly) != 1 {
1538		t.Fatalf("Expected %d, got %d", 1, len(diffResults.InSecondOnly))
1539	}
1540
1541	// check each filename is present where it belongs, and check license(s)
1542
1543	// in both and different license: f4 and f6
1544	// filename will map to a LicensePair
1545	check4, ok := diffResults.InBothChanged["/project/file4.txt"]
1546	if !ok {
1547		t.Fatalf("Couldn't get check4")
1548	}
1549	if check4.First != f4_1.LicenseConcluded {
1550		t.Errorf("Expected %s, got %s", f4_1.LicenseConcluded, check4.First)
1551	}
1552	if check4.Second != f4_2.LicenseConcluded {
1553		t.Errorf("Expected %s, got %s", f4_2.LicenseConcluded, check4.Second)
1554	}
1555	check6, ok := diffResults.InBothChanged["/project/file6.txt"]
1556	if !ok {
1557		t.Fatalf("Couldn't get check6")
1558	}
1559	if check6.First != f6_1.LicenseConcluded {
1560		t.Errorf("Expected %s, got %s", f6_1.LicenseConcluded, check6.First)
1561	}
1562	if check6.Second != f6_2.LicenseConcluded {
1563		t.Errorf("Expected %s, got %s", f6_2.LicenseConcluded, check6.Second)
1564	}
1565
1566	// in both and same license: f1 and f5
1567	// filename will map to a string
1568	check1, ok := diffResults.InBothSame["/project/file1.txt"]
1569	if !ok {
1570		t.Fatalf("Couldn't get check1")
1571	}
1572	if check1 != f1.LicenseConcluded {
1573		t.Errorf("Expected %s, got %s", f1.LicenseConcluded, check1)
1574	}
1575	check5, ok := diffResults.InBothSame["/project/file5.txt"]
1576	if !ok {
1577		t.Fatalf("Couldn't get check5")
1578	}
1579	if check5 != f5_1.LicenseConcluded {
1580		t.Errorf("Expected %s, got %s", f5_1.LicenseConcluded, check5)
1581	}
1582	if check5 != f5_2.LicenseConcluded {
1583		t.Errorf("Expected %s, got %s", f5_2.LicenseConcluded, check5)
1584	}
1585
1586	// in first only: f2
1587	// filename will map to a string
1588	check2, ok := diffResults.InFirstOnly["/project/file2.txt"]
1589	if !ok {
1590		t.Fatalf("Couldn't get check2")
1591	}
1592	if check2 != f2.LicenseConcluded {
1593		t.Errorf("Expected %s, got %s", f2.LicenseConcluded, check2)
1594	}
1595
1596	// in second only: f3
1597	// filename will map to a string
1598	check3, ok := diffResults.InSecondOnly["/project/file3.txt"]
1599	if !ok {
1600		t.Fatalf("Couldn't get check3")
1601	}
1602	if check3 != f3.LicenseConcluded {
1603		t.Errorf("Expected %s, got %s", f3.LicenseConcluded, check2)
1604	}
1605
1606}
1607