xref: /aosp_15_r20/external/spdx-tools/tvloader/parser2v2/parse_package_test.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2package parser2v2
3
4import (
5	"fmt"
6	"testing"
7
8	"github.com/spdx/tools-golang/spdx/common"
9	"github.com/spdx/tools-golang/spdx/v2_2"
10)
11
12// ===== Parser package section state change tests =====
13func TestParser2_2PackageStartsNewPackageAfterParsingPackageNameTag(t *testing.T) {
14	// create the first package
15	pkgOldName := "p1"
16
17	parser := tvParser2_2{
18		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
19		st:  psPackage2_2,
20		pkg: &v2_2.Package{PackageName: pkgOldName, PackageSPDXIdentifier: "p1"},
21	}
22	pkgOld := parser.pkg
23	parser.doc.Packages = append(parser.doc.Packages, pkgOld)
24	// the Document's Packages should have this one only
25	if parser.doc.Packages[0] != pkgOld {
26		t.Errorf("expected package %v, got %v", pkgOld, parser.doc.Packages[0])
27	}
28	if len(parser.doc.Packages) != 1 {
29		t.Errorf("expected 1 package, got %d", len(parser.doc.Packages))
30	}
31
32	// now add a new package
33	pkgName := "p2"
34	err := parser.parsePair2_2("PackageName", pkgName)
35	if err != nil {
36		t.Errorf("got error when calling parsePair2_2: %v", err)
37	}
38	// state should be correct
39	if parser.st != psPackage2_2 {
40		t.Errorf("expected state to be %v, got %v", psPackage2_2, parser.st)
41	}
42	// and a package should be created
43	if parser.pkg == nil {
44		t.Fatalf("parser didn't create new package")
45	}
46	// and it should not be pkgOld
47	if parser.pkg == pkgOld {
48		t.Errorf("expected new package, got pkgOld")
49	}
50	// and the package name should be as expected
51	if parser.pkg.PackageName != pkgName {
52		t.Errorf("expected package name %s, got %s", pkgName, parser.pkg.PackageName)
53	}
54	// and the package should default to true for FilesAnalyzed
55	if parser.pkg.FilesAnalyzed != true {
56		t.Errorf("expected FilesAnalyzed to default to true, got false")
57	}
58	if parser.pkg.IsFilesAnalyzedTagPresent != false {
59		t.Errorf("expected IsFilesAnalyzedTagPresent to default to false, got true")
60	}
61	// and the Document's Packages should still be of size 1 and have pkgOld only
62	if parser.doc.Packages[0] != pkgOld {
63		t.Errorf("Expected package %v, got %v", pkgOld, parser.doc.Packages[0])
64	}
65	if len(parser.doc.Packages) != 1 {
66		t.Errorf("expected 1 package, got %d", len(parser.doc.Packages))
67	}
68}
69
70func TestParser2_2PackageStartsNewPackageAfterParsingPackageNameTagWhileInUnpackaged(t *testing.T) {
71	// pkg is nil, so that Files appearing before the first PackageName tag
72	// are added to Files instead of Packages
73	parser := tvParser2_2{
74		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
75		st:  psFile2_2,
76		pkg: nil,
77	}
78	// the Document's Packages should be empty
79	if len(parser.doc.Packages) != 0 {
80		t.Errorf("Expected zero packages, got %d", len(parser.doc.Packages))
81	}
82
83	// now add a new package
84	pkgName := "p2"
85	err := parser.parsePair2_2("PackageName", pkgName)
86	if err != nil {
87		t.Errorf("got error when calling parsePair2_2: %v", err)
88	}
89	// state should be correct
90	if parser.st != psPackage2_2 {
91		t.Errorf("expected state to be %v, got %v", psPackage2_2, parser.st)
92	}
93	// and a package should be created
94	if parser.pkg == nil {
95		t.Fatalf("parser didn't create new package")
96	}
97	// and the package name should be as expected
98	if parser.pkg.PackageName != pkgName {
99		t.Errorf("expected package name %s, got %s", pkgName, parser.pkg.PackageName)
100	}
101	// and the package should default to true for FilesAnalyzed
102	if parser.pkg.FilesAnalyzed != true {
103		t.Errorf("expected FilesAnalyzed to default to true, got false")
104	}
105	if parser.pkg.IsFilesAnalyzedTagPresent != false {
106		t.Errorf("expected IsFilesAnalyzedTagPresent to default to false, got true")
107	}
108	// and the Document's Packages should be of size 0, because the prior was
109	// unpackaged files and this one won't be added until an SPDXID is seen
110	if len(parser.doc.Packages) != 0 {
111		t.Errorf("Expected %v packages in doc, got %v", 0, len(parser.doc.Packages))
112	}
113}
114
115func TestParser2_2PackageMovesToFileAfterParsingFileNameTag(t *testing.T) {
116	parser := tvParser2_2{
117		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
118		st:  psPackage2_2,
119		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
120	}
121	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
122	pkgCurrent := parser.pkg
123
124	err := parser.parsePair2_2("FileName", "testFile")
125	if err != nil {
126		t.Errorf("got error when calling parsePair2_2: %v", err)
127	}
128	// state should be correct
129	if parser.st != psFile2_2 {
130		t.Errorf("expected state to be %v, got %v", psFile2_2, parser.st)
131	}
132	// and current package should remain what it was
133	if parser.pkg != pkgCurrent {
134		t.Fatalf("expected package to remain %v, got %v", pkgCurrent, parser.pkg)
135	}
136}
137
138func TestParser2_2PackageMovesToOtherLicenseAfterParsingLicenseIDTag(t *testing.T) {
139	parser := tvParser2_2{
140		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
141		st:  psPackage2_2,
142		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
143	}
144	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
145
146	err := parser.parsePair2_2("LicenseID", "LicenseRef-TestLic")
147	if err != nil {
148		t.Errorf("got error when calling parsePair2_2: %v", err)
149	}
150	if parser.st != psOtherLicense2_2 {
151		t.Errorf("expected state to be %v, got %v", psOtherLicense2_2, parser.st)
152	}
153}
154
155func TestParser2_2PackageMovesToReviewAfterParsingReviewerTag(t *testing.T) {
156	parser := tvParser2_2{
157		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
158		st:  psPackage2_2,
159		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
160	}
161	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
162
163	err := parser.parsePair2_2("Reviewer", "Person: John Doe")
164	if err != nil {
165		t.Errorf("got error when calling parsePair2_2: %v", err)
166	}
167	if parser.st != psReview2_2 {
168		t.Errorf("expected state to be %v, got %v", psReview2_2, parser.st)
169	}
170}
171
172func TestParser2_2PackageStaysAfterParsingRelationshipTags(t *testing.T) {
173	parser := tvParser2_2{
174		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
175		st:  psPackage2_2,
176		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
177	}
178	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
179
180	err := parser.parsePair2_2("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-else")
181	if err != nil {
182		t.Errorf("got error when calling parsePair2_2: %v", err)
183	}
184	// state should remain unchanged
185	if parser.st != psPackage2_2 {
186		t.Errorf("expected state to be %v, got %v", psPackage2_2, parser.st)
187	}
188
189	err = parser.parsePair2_2("RelationshipComment", "blah")
190	if err != nil {
191		t.Errorf("got error when calling parsePair2_2: %v", err)
192	}
193	// state should still remain unchanged
194	if parser.st != psPackage2_2 {
195		t.Errorf("expected state to be %v, got %v", psPackage2_2, parser.st)
196	}
197}
198
199func TestParser2_2PackageStaysAfterParsingAnnotationTags(t *testing.T) {
200	parser := tvParser2_2{
201		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
202		st:  psPackage2_2,
203		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
204	}
205	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
206
207	err := parser.parsePair2_2("Annotator", "Person: John Doe ()")
208	if err != nil {
209		t.Errorf("got error when calling parsePair2_2: %v", err)
210	}
211	if parser.st != psPackage2_2 {
212		t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_2)
213	}
214
215	err = parser.parsePair2_2("AnnotationDate", "2018-09-15T00:36:00Z")
216	if err != nil {
217		t.Errorf("got error when calling parsePair2_2: %v", err)
218	}
219	if parser.st != psPackage2_2 {
220		t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_2)
221	}
222
223	err = parser.parsePair2_2("AnnotationType", "REVIEW")
224	if err != nil {
225		t.Errorf("got error when calling parsePair2_2: %v", err)
226	}
227	if parser.st != psPackage2_2 {
228		t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_2)
229	}
230
231	err = parser.parsePair2_2("SPDXREF", "SPDXRef-45")
232	if err != nil {
233		t.Errorf("got error when calling parsePair2_2: %v", err)
234	}
235	if parser.st != psPackage2_2 {
236		t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_2)
237	}
238
239	err = parser.parsePair2_2("AnnotationComment", "i guess i had something to say about this package")
240	if err != nil {
241		t.Errorf("got error when calling parsePair2_2: %v", err)
242	}
243	if parser.st != psPackage2_2 {
244		t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_2)
245	}
246}
247
248// ===== Package data section tests =====
249func TestParser2_2CanParsePackageTags(t *testing.T) {
250	parser := tvParser2_2{
251		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
252		st:  psPackage2_2,
253		pkg: &v2_2.Package{},
254	}
255
256	// should not yet be in Packages map, b/c no SPDX identifier
257	if len(parser.doc.Packages) != 0 {
258		t.Errorf("expected 0 packages, got %d", len(parser.doc.Packages))
259	}
260
261	// Package Name
262	err := parser.parsePairFromPackage2_2("PackageName", "p1")
263	if err != nil {
264		t.Errorf("expected nil error, got %v", err)
265	}
266	if parser.pkg.PackageName != "p1" {
267		t.Errorf("got %v for PackageName", parser.pkg.PackageName)
268	}
269	// still should not yet be in Packages map, b/c no SPDX identifier
270	if len(parser.doc.Packages) != 0 {
271		t.Errorf("expected 0 packages, got %d", len(parser.doc.Packages))
272	}
273
274	// Package SPDX Identifier
275	err = parser.parsePairFromPackage2_2("SPDXID", "SPDXRef-p1")
276	if err != nil {
277		t.Errorf("expected nil error, got %v", err)
278	}
279	// "SPDXRef-" prefix should be removed from the item
280	if parser.pkg.PackageSPDXIdentifier != "p1" {
281		t.Errorf("got %v for PackageSPDXIdentifier", parser.pkg.PackageSPDXIdentifier)
282	}
283	// and it should now be added to the Packages map
284	if len(parser.doc.Packages) != 1 {
285		t.Errorf("expected 1 package, got %d", len(parser.doc.Packages))
286	}
287	if parser.doc.Packages[0] != parser.pkg {
288		t.Errorf("expected to point to parser.pkg, got %v", parser.doc.Packages[0])
289	}
290
291	// Package Version
292	err = parser.parsePairFromPackage2_2("PackageVersion", "2.1.1")
293	if err != nil {
294		t.Errorf("expected nil error, got %v", err)
295	}
296	if parser.pkg.PackageVersion != "2.1.1" {
297		t.Errorf("got %v for PackageVersion", parser.pkg.PackageVersion)
298	}
299
300	// Package File Name
301	err = parser.parsePairFromPackage2_2("PackageFileName", "p1-2.1.1.tar.gz")
302	if err != nil {
303		t.Errorf("expected nil error, got %v", err)
304	}
305	if parser.pkg.PackageFileName != "p1-2.1.1.tar.gz" {
306		t.Errorf("got %v for PackageFileName", parser.pkg.PackageFileName)
307	}
308
309	// Package Supplier
310	// SKIP -- separate tests for subvalues below
311
312	// Package Originator
313	// SKIP -- separate tests for subvalues below
314
315	// Package Download Location
316	err = parser.parsePairFromPackage2_2("PackageDownloadLocation", "https://example.com/whatever")
317	if err != nil {
318		t.Errorf("expected nil error, got %v", err)
319	}
320	if parser.pkg.PackageDownloadLocation != "https://example.com/whatever" {
321		t.Errorf("got %v for PackageDownloadLocation", parser.pkg.PackageDownloadLocation)
322	}
323
324	// Files Analyzed
325	err = parser.parsePairFromPackage2_2("FilesAnalyzed", "false")
326	if err != nil {
327		t.Errorf("expected nil error, got %v", err)
328	}
329	if parser.pkg.FilesAnalyzed != false {
330		t.Errorf("got %v for FilesAnalyzed", parser.pkg.FilesAnalyzed)
331	}
332	if parser.pkg.IsFilesAnalyzedTagPresent != true {
333		t.Errorf("got %v for IsFilesAnalyzedTagPresent", parser.pkg.IsFilesAnalyzedTagPresent)
334	}
335
336	// Package Verification Code
337	// SKIP -- separate tests for "excludes", or not, below
338
339	testChecksums := map[common.ChecksumAlgorithm]string{
340		"MD5":    "624c1abb3664f4b35547e7c73864ad24",
341		"SHA1":   "85ed0817af83a24ad8da68c2b5094de69833983c",
342		"SHA256": "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd",
343		"SHA512": "4ced3267f5ed38df65ceebc43e97aa6c2948cc7ef3288c2e5074e7df7fab544cc93339604513ea5f65616f9ed1c48581465043c8a9b693ef20fd4fddaf25e1b9",
344	}
345
346	for algo, tc := range testChecksums {
347		if err := parser.parsePairFromPackage2_2(
348			"PackageChecksum", fmt.Sprintf("%s: %s", algo, tc)); err != nil {
349			t.Errorf("expected error, got %v", err)
350		}
351	}
352
353	for _, checksum := range parser.pkg.PackageChecksums {
354		if checksum.Value != testChecksums[checksum.Algorithm] {
355			t.Errorf(
356				"expected %s for PackageChecksum%s, got %s",
357				testChecksums[checksum.Algorithm], checksum.Algorithm, checksum.Value,
358			)
359		}
360	}
361
362	// Package Home Page
363	err = parser.parsePairFromPackage2_2("PackageHomePage", "https://example.com/whatever2")
364	if err != nil {
365		t.Errorf("expected nil error, got %v", err)
366	}
367	if parser.pkg.PackageHomePage != "https://example.com/whatever2" {
368		t.Errorf("got %v for PackageHomePage", parser.pkg.PackageHomePage)
369	}
370
371	// Package Source Info
372	err = parser.parsePairFromPackage2_2("PackageSourceInfo", "random comment")
373	if err != nil {
374		t.Errorf("expected nil error, got %v", err)
375	}
376	if parser.pkg.PackageSourceInfo != "random comment" {
377		t.Errorf("got %v for PackageSourceInfo", parser.pkg.PackageSourceInfo)
378	}
379
380	// Package License Concluded
381	err = parser.parsePairFromPackage2_2("PackageLicenseConcluded", "Apache-2.0 OR GPL-2.0-or-later")
382	if err != nil {
383		t.Errorf("expected nil error, got %v", err)
384	}
385	if parser.pkg.PackageLicenseConcluded != "Apache-2.0 OR GPL-2.0-or-later" {
386		t.Errorf("got %v for PackageLicenseConcluded", parser.pkg.PackageLicenseConcluded)
387	}
388
389	// All Licenses Info From Files
390	lics := []string{
391		"Apache-2.0",
392		"GPL-2.0-or-later",
393		"CC0-1.0",
394	}
395	for _, lic := range lics {
396		err = parser.parsePairFromPackage2_2("PackageLicenseInfoFromFiles", lic)
397		if err != nil {
398			t.Errorf("expected nil error, got %v", err)
399		}
400	}
401	for _, licWant := range lics {
402		flagFound := false
403		for _, licCheck := range parser.pkg.PackageLicenseInfoFromFiles {
404			if licWant == licCheck {
405				flagFound = true
406			}
407		}
408		if flagFound == false {
409			t.Errorf("didn't find %s in PackageLicenseInfoFromFiles", licWant)
410		}
411	}
412	if len(lics) != len(parser.pkg.PackageLicenseInfoFromFiles) {
413		t.Errorf("expected %d licenses in PackageLicenseInfoFromFiles, got %d", len(lics),
414			len(parser.pkg.PackageLicenseInfoFromFiles))
415	}
416
417	// Package License Declared
418	err = parser.parsePairFromPackage2_2("PackageLicenseDeclared", "Apache-2.0 OR GPL-2.0-or-later")
419	if err != nil {
420		t.Errorf("expected nil error, got %v", err)
421	}
422	if parser.pkg.PackageLicenseDeclared != "Apache-2.0 OR GPL-2.0-or-later" {
423		t.Errorf("got %v for PackageLicenseDeclared", parser.pkg.PackageLicenseDeclared)
424	}
425
426	// Package License Comments
427	err = parser.parsePairFromPackage2_2("PackageLicenseComments", "this is a license comment")
428	if err != nil {
429		t.Errorf("expected nil error, got %v", err)
430	}
431	if parser.pkg.PackageLicenseComments != "this is a license comment" {
432		t.Errorf("got %v for PackageLicenseComments", parser.pkg.PackageLicenseComments)
433	}
434
435	// Package Copyright Text
436	err = parser.parsePairFromPackage2_2("PackageCopyrightText", "Copyright (c) me myself and i")
437	if err != nil {
438		t.Errorf("expected nil error, got %v", err)
439	}
440	if parser.pkg.PackageCopyrightText != "Copyright (c) me myself and i" {
441		t.Errorf("got %v for PackageCopyrightText", parser.pkg.PackageCopyrightText)
442	}
443
444	// Package Summary
445	err = parser.parsePairFromPackage2_2("PackageSummary", "i wrote this package")
446	if err != nil {
447		t.Errorf("expected nil error, got %v", err)
448	}
449	if parser.pkg.PackageSummary != "i wrote this package" {
450		t.Errorf("got %v for PackageSummary", parser.pkg.PackageSummary)
451	}
452
453	// Package Description
454	err = parser.parsePairFromPackage2_2("PackageDescription", "i wrote this package a lot")
455	if err != nil {
456		t.Errorf("expected nil error, got %v", err)
457	}
458	if parser.pkg.PackageDescription != "i wrote this package a lot" {
459		t.Errorf("got %v for PackageDescription", parser.pkg.PackageDescription)
460	}
461
462	// Package Comment
463	err = parser.parsePairFromPackage2_2("PackageComment", "i scanned this package")
464	if err != nil {
465		t.Errorf("expected nil error, got %v", err)
466	}
467	if parser.pkg.PackageComment != "i scanned this package" {
468		t.Errorf("got %v for PackageComment", parser.pkg.PackageComment)
469	}
470
471	// Package Attribution Text
472	attrs := []string{
473		"Include this notice in all advertising materials",
474		"This is a \nmulti-line string",
475	}
476	for _, attr := range attrs {
477		err = parser.parsePairFromPackage2_2("PackageAttributionText", attr)
478		if err != nil {
479			t.Errorf("expected nil error, got %v", err)
480		}
481	}
482	for _, attrWant := range attrs {
483		flagFound := false
484		for _, attrCheck := range parser.pkg.PackageAttributionTexts {
485			if attrWant == attrCheck {
486				flagFound = true
487			}
488		}
489		if flagFound == false {
490			t.Errorf("didn't find %s in PackageAttributionText", attrWant)
491		}
492	}
493	if len(attrs) != len(parser.pkg.PackageAttributionTexts) {
494		t.Errorf("expected %d attribution texts in PackageAttributionTexts, got %d", len(attrs),
495			len(parser.pkg.PackageAttributionTexts))
496	}
497
498	// Package External References and Comments
499	ref1 := "SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
500	ref1Category := "SECURITY"
501	ref1Type := "cpe23Type"
502	ref1Locator := "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
503	ref1Comment := "this is comment #1"
504	ref2 := "OTHER LocationRef-acmeforge acmecorp/acmenator/4.1.3alpha"
505	ref2Category := "OTHER"
506	ref2Type := "LocationRef-acmeforge"
507	ref2Locator := "acmecorp/acmenator/4.1.3alpha"
508	ref2Comment := "this is comment #2"
509	err = parser.parsePairFromPackage2_2("ExternalRef", ref1)
510	if err != nil {
511		t.Errorf("expected nil error, got %v", err)
512	}
513	if len(parser.pkg.PackageExternalReferences) != 1 {
514		t.Errorf("expected 1 external reference, got %d", len(parser.pkg.PackageExternalReferences))
515	}
516	if parser.pkgExtRef == nil {
517		t.Errorf("expected non-nil pkgExtRef, got nil")
518	}
519	if parser.pkg.PackageExternalReferences[0] == nil {
520		t.Errorf("expected non-nil PackageExternalReferences[0], got nil")
521	}
522	if parser.pkgExtRef != parser.pkg.PackageExternalReferences[0] {
523		t.Errorf("expected pkgExtRef to match PackageExternalReferences[0], got no match")
524	}
525	err = parser.parsePairFromPackage2_2("ExternalRefComment", ref1Comment)
526	if err != nil {
527		t.Errorf("expected nil error, got %v", err)
528	}
529	err = parser.parsePairFromPackage2_2("ExternalRef", ref2)
530	if err != nil {
531		t.Errorf("expected nil error, got %v", err)
532	}
533	if len(parser.pkg.PackageExternalReferences) != 2 {
534		t.Errorf("expected 2 external references, got %d", len(parser.pkg.PackageExternalReferences))
535	}
536	if parser.pkgExtRef == nil {
537		t.Errorf("expected non-nil pkgExtRef, got nil")
538	}
539	if parser.pkg.PackageExternalReferences[1] == nil {
540		t.Errorf("expected non-nil PackageExternalReferences[1], got nil")
541	}
542	if parser.pkgExtRef != parser.pkg.PackageExternalReferences[1] {
543		t.Errorf("expected pkgExtRef to match PackageExternalReferences[1], got no match")
544	}
545	err = parser.parsePairFromPackage2_2("ExternalRefComment", ref2Comment)
546	if err != nil {
547		t.Errorf("expected nil error, got %v", err)
548	}
549	// finally, check these values
550	gotRef1 := parser.pkg.PackageExternalReferences[0]
551	if gotRef1.Category != ref1Category {
552		t.Errorf("expected ref1 category to be %s, got %s", gotRef1.Category, ref1Category)
553	}
554	if gotRef1.RefType != ref1Type {
555		t.Errorf("expected ref1 type to be %s, got %s", gotRef1.RefType, ref1Type)
556	}
557	if gotRef1.Locator != ref1Locator {
558		t.Errorf("expected ref1 locator to be %s, got %s", gotRef1.Locator, ref1Locator)
559	}
560	if gotRef1.ExternalRefComment != ref1Comment {
561		t.Errorf("expected ref1 comment to be %s, got %s", gotRef1.ExternalRefComment, ref1Comment)
562	}
563	gotRef2 := parser.pkg.PackageExternalReferences[1]
564	if gotRef2.Category != ref2Category {
565		t.Errorf("expected ref2 category to be %s, got %s", gotRef2.Category, ref2Category)
566	}
567	if gotRef2.RefType != ref2Type {
568		t.Errorf("expected ref2 type to be %s, got %s", gotRef2.RefType, ref2Type)
569	}
570	if gotRef2.Locator != ref2Locator {
571		t.Errorf("expected ref2 locator to be %s, got %s", gotRef2.Locator, ref2Locator)
572	}
573	if gotRef2.ExternalRefComment != ref2Comment {
574		t.Errorf("expected ref2 comment to be %s, got %s", gotRef2.ExternalRefComment, ref2Comment)
575	}
576
577}
578
579func TestParser2_2CanParsePackageSupplierPersonTag(t *testing.T) {
580	parser := tvParser2_2{
581		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
582		st:  psPackage2_2,
583		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
584	}
585	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
586
587	// Package Supplier: Person
588	err := parser.parsePairFromPackage2_2("PackageSupplier", "Person: John Doe")
589	if err != nil {
590		t.Errorf("expected nil error, got %v", err)
591	}
592	if parser.pkg.PackageSupplier.Supplier != "John Doe" {
593		t.Errorf("got %v for PackageSupplierPerson", parser.pkg.PackageSupplier.Supplier)
594	}
595}
596
597func TestParser2_2CanParsePackageSupplierOrganizationTag(t *testing.T) {
598	parser := tvParser2_2{
599		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
600		st:  psPackage2_2,
601		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
602	}
603	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
604
605	// Package Supplier: Organization
606	err := parser.parsePairFromPackage2_2("PackageSupplier", "Organization: John Doe, Inc.")
607	if err != nil {
608		t.Errorf("expected nil error, got %v", err)
609	}
610	if parser.pkg.PackageSupplier.Supplier != "John Doe, Inc." {
611		t.Errorf("got %v for PackageSupplierOrganization", parser.pkg.PackageSupplier.Supplier)
612	}
613}
614
615func TestParser2_2CanParsePackageSupplierNOASSERTIONTag(t *testing.T) {
616	parser := tvParser2_2{
617		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
618		st:  psPackage2_2,
619		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
620	}
621	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
622
623	// Package Supplier: NOASSERTION
624	err := parser.parsePairFromPackage2_2("PackageSupplier", "NOASSERTION")
625	if err != nil {
626		t.Errorf("expected nil error, got %v", err)
627	}
628	if parser.pkg.PackageSupplier.Supplier != "NOASSERTION" {
629		t.Errorf("got value for Supplier, expected NOASSERTION")
630	}
631}
632
633func TestParser2_2CanParsePackageOriginatorPersonTag(t *testing.T) {
634	parser := tvParser2_2{
635		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
636		st:  psPackage2_2,
637		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
638	}
639	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
640
641	// Package Originator: Person
642	err := parser.parsePairFromPackage2_2("PackageOriginator", "Person: John Doe")
643	if err != nil {
644		t.Errorf("expected nil error, got %v", err)
645	}
646	if parser.pkg.PackageOriginator.Originator != "John Doe" {
647		t.Errorf("got %v for PackageOriginator", parser.pkg.PackageOriginator.Originator)
648	}
649}
650
651func TestParser2_2CanParsePackageOriginatorOrganizationTag(t *testing.T) {
652	parser := tvParser2_2{
653		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
654		st:  psPackage2_2,
655		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
656	}
657	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
658
659	// Package Originator: Organization
660	err := parser.parsePairFromPackage2_2("PackageOriginator", "Organization: John Doe, Inc.")
661	if err != nil {
662		t.Errorf("expected nil error, got %v", err)
663	}
664	if parser.pkg.PackageOriginator.Originator != "John Doe, Inc." {
665		t.Errorf("got %v for PackageOriginator", parser.pkg.PackageOriginator.Originator)
666	}
667}
668
669func TestParser2_2CanParsePackageOriginatorNOASSERTIONTag(t *testing.T) {
670	parser := tvParser2_2{
671		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
672		st:  psPackage2_2,
673		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
674	}
675	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
676
677	// Package Originator: NOASSERTION
678	err := parser.parsePairFromPackage2_2("PackageOriginator", "NOASSERTION")
679	if err != nil {
680		t.Errorf("expected nil error, got %v", err)
681	}
682	if parser.pkg.PackageOriginator.Originator != "NOASSERTION" {
683		t.Errorf("got false for PackageOriginatorNOASSERTION")
684	}
685}
686
687func TestParser2_2CanParsePackageVerificationCodeTagWithExcludes(t *testing.T) {
688	parser := tvParser2_2{
689		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
690		st:  psPackage2_2,
691		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
692	}
693	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
694
695	// Package Verification Code with excludes parenthetical
696	code := "d6a770ba38583ed4bb4525bd96e50461655d2758"
697	fileName := "./package.spdx"
698	fullCodeValue := "d6a770ba38583ed4bb4525bd96e50461655d2758 (excludes: ./package.spdx)"
699	err := parser.parsePairFromPackage2_2("PackageVerificationCode", fullCodeValue)
700	if err != nil {
701		t.Errorf("expected nil error, got %v", err)
702	}
703	if parser.pkg.PackageVerificationCode.Value != code {
704		t.Errorf("got %v for PackageVerificationCode", parser.pkg.PackageVerificationCode)
705	}
706	if len(parser.pkg.PackageVerificationCode.ExcludedFiles) != 1 || parser.pkg.PackageVerificationCode.ExcludedFiles[0] != fileName {
707		t.Errorf("got %v for PackageVerificationCodeExcludedFile", parser.pkg.PackageVerificationCode.ExcludedFiles)
708	}
709
710}
711
712func TestParser2_2CanParsePackageVerificationCodeTagWithoutExcludes(t *testing.T) {
713	parser := tvParser2_2{
714		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
715		st:  psPackage2_2,
716		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
717	}
718	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
719
720	// Package Verification Code without excludes parenthetical
721	code := "d6a770ba38583ed4bb4525bd96e50461655d2758"
722	err := parser.parsePairFromPackage2_2("PackageVerificationCode", code)
723	if err != nil {
724		t.Errorf("expected nil error, got %v", err)
725	}
726	if parser.pkg.PackageVerificationCode.Value != code {
727		t.Errorf("got %v for PackageVerificationCode", parser.pkg.PackageVerificationCode)
728	}
729	if len(parser.pkg.PackageVerificationCode.ExcludedFiles) != 0 {
730		t.Errorf("got %v for PackageVerificationCodeExcludedFile", parser.pkg.PackageVerificationCode.ExcludedFiles)
731	}
732
733}
734
735func TestParser2_2PackageExternalRefPointerChangesAfterTags(t *testing.T) {
736	parser := tvParser2_2{
737		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
738		st:  psPackage2_2,
739		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
740	}
741	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
742
743	ref1 := "SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
744	err := parser.parsePairFromPackage2_2("ExternalRef", ref1)
745	if err != nil {
746		t.Errorf("expected nil error, got %v", err)
747	}
748	if parser.pkgExtRef == nil {
749		t.Errorf("expected non-nil external reference pointer, got nil")
750	}
751
752	// now, a comment; pointer should go away
753	err = parser.parsePairFromPackage2_2("ExternalRefComment", "whatever")
754	if err != nil {
755		t.Errorf("expected nil error, got %v", err)
756	}
757	if parser.pkgExtRef != nil {
758		t.Errorf("expected nil external reference pointer, got non-nil")
759	}
760
761	ref2 := "Other LocationRef-something https://example.com/whatever"
762	err = parser.parsePairFromPackage2_2("ExternalRef", ref2)
763	if err != nil {
764		t.Errorf("expected nil error, got %v", err)
765	}
766	if parser.pkgExtRef == nil {
767		t.Errorf("expected non-nil external reference pointer, got nil")
768	}
769
770	// and some other random tag makes the pointer go away too
771	err = parser.parsePairFromPackage2_2("PackageSummary", "whatever")
772	if err != nil {
773		t.Errorf("expected nil error, got %v", err)
774	}
775	if parser.pkgExtRef != nil {
776		t.Errorf("expected nil external reference pointer, got non-nil")
777	}
778}
779
780func TestParser2_2PackageCreatesRelationshipInDocument(t *testing.T) {
781	parser := tvParser2_2{
782		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
783		st:  psPackage2_2,
784		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
785	}
786	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
787
788	err := parser.parsePair2_2("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-whatever")
789	if err != nil {
790		t.Errorf("got error when calling parsePair2_2: %v", err)
791	}
792	if parser.rln == nil {
793		t.Fatalf("parser didn't create and point to Relationship struct")
794	}
795	if parser.rln != parser.doc.Relationships[0] {
796		t.Errorf("pointer to new Relationship doesn't match idx 0 for doc.Relationships[]")
797	}
798}
799
800func TestParser2_2PackageCreatesAnnotationInDocument(t *testing.T) {
801	parser := tvParser2_2{
802		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
803		st:  psPackage2_2,
804		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
805	}
806	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
807
808	err := parser.parsePair2_2("Annotator", "Person: John Doe ()")
809	if err != nil {
810		t.Errorf("got error when calling parsePair2_2: %v", err)
811	}
812	if parser.ann == nil {
813		t.Fatalf("parser didn't create and point to Annotation struct")
814	}
815	if parser.ann != parser.doc.Annotations[0] {
816		t.Errorf("pointer to new Annotation doesn't match idx 0 for doc.Annotations[]")
817	}
818}
819
820func TestParser2_2PackageUnknownTagFails(t *testing.T) {
821	parser := tvParser2_2{
822		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
823		st:  psPackage2_2,
824		pkg: &v2_2.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
825	}
826	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
827
828	err := parser.parsePairFromPackage2_2("blah", "something")
829	if err == nil {
830		t.Errorf("expected error from parsing unknown tag")
831	}
832}
833
834func TestParser2_2FailsIfInvalidSPDXIDInPackageSection(t *testing.T) {
835	parser := tvParser2_2{
836		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
837		st:  psPackage2_2,
838		pkg: &v2_2.Package{},
839	}
840
841	// start with Package Name
842	err := parser.parsePairFromPackage2_2("PackageName", "p1")
843	if err != nil {
844		t.Errorf("expected nil error, got %v", err)
845	}
846	// invalid ID format
847	err = parser.parsePairFromPackage2_2("SPDXID", "whoops")
848	if err == nil {
849		t.Errorf("expected non-nil error, got nil")
850	}
851}
852
853func TestParser2_2FailsIfInvalidPackageSupplierFormat(t *testing.T) {
854	parser := tvParser2_2{
855		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
856		st:  psPackage2_2,
857		pkg: &v2_2.Package{},
858	}
859
860	// start with Package Name
861	err := parser.parsePairFromPackage2_2("PackageName", "p1")
862	if err != nil {
863		t.Errorf("expected nil error, got %v", err)
864	}
865	// invalid supplier format
866	err = parser.parsePairFromPackage2_2("PackageSupplier", "whoops")
867	if err == nil {
868		t.Errorf("expected non-nil error, got nil")
869	}
870}
871
872func TestParser2_2FailsIfUnknownPackageSupplierType(t *testing.T) {
873	parser := tvParser2_2{
874		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
875		st:  psPackage2_2,
876		pkg: &v2_2.Package{},
877	}
878
879	// start with Package Name
880	err := parser.parsePairFromPackage2_2("PackageName", "p1")
881	if err != nil {
882		t.Errorf("expected nil error, got %v", err)
883	}
884	// invalid supplier type
885	err = parser.parsePairFromPackage2_2("PackageSupplier", "whoops: John Doe")
886	if err == nil {
887		t.Errorf("expected non-nil error, got nil")
888	}
889}
890
891func TestParser2_2FailsIfInvalidPackageOriginatorFormat(t *testing.T) {
892	parser := tvParser2_2{
893		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
894		st:  psPackage2_2,
895		pkg: &v2_2.Package{},
896	}
897
898	// start with Package Name
899	err := parser.parsePairFromPackage2_2("PackageName", "p1")
900	if err != nil {
901		t.Errorf("expected nil error, got %v", err)
902	}
903	// invalid originator format
904	err = parser.parsePairFromPackage2_2("PackageOriginator", "whoops")
905	if err == nil {
906		t.Errorf("expected non-nil error, got nil")
907	}
908}
909
910func TestParser2_2FailsIfUnknownPackageOriginatorType(t *testing.T) {
911	parser := tvParser2_2{
912		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
913		st:  psPackage2_2,
914		pkg: &v2_2.Package{},
915	}
916
917	// start with Package Name
918	err := parser.parsePairFromPackage2_2("PackageName", "p1")
919	if err != nil {
920		t.Errorf("expected nil error, got %v", err)
921	}
922	// invalid originator type
923	err = parser.parsePairFromPackage2_2("PackageOriginator", "whoops: John Doe")
924	if err == nil {
925		t.Errorf("expected non-nil error, got nil")
926	}
927}
928
929func TestParser2_2SetsFilesAnalyzedTagsCorrectly(t *testing.T) {
930	parser := tvParser2_2{
931		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
932		st:  psPackage2_2,
933		pkg: &v2_2.Package{},
934	}
935
936	// start with Package Name
937	err := parser.parsePairFromPackage2_2("PackageName", "p1")
938	if err != nil {
939		t.Errorf("expected nil error, got %v", err)
940	}
941	// set tag
942	err = parser.parsePairFromPackage2_2("FilesAnalyzed", "true")
943	if err != nil {
944		t.Errorf("expected nil error, got %v", err)
945	}
946	if parser.pkg.FilesAnalyzed != true {
947		t.Errorf("expected %v, got %v", true, parser.pkg.FilesAnalyzed)
948	}
949	if parser.pkg.IsFilesAnalyzedTagPresent != true {
950		t.Errorf("expected %v, got %v", true, parser.pkg.IsFilesAnalyzedTagPresent)
951	}
952}
953
954func TestParser2_2FailsIfInvalidPackageChecksumFormat(t *testing.T) {
955	parser := tvParser2_2{
956		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
957		st:  psPackage2_2,
958		pkg: &v2_2.Package{},
959	}
960
961	// start with Package Name
962	err := parser.parsePairFromPackage2_2("PackageName", "p1")
963	if err != nil {
964		t.Errorf("expected nil error, got %v", err)
965	}
966	// invalid checksum format
967	err = parser.parsePairFromPackage2_2("PackageChecksum", "whoops")
968	if err == nil {
969		t.Errorf("expected non-nil error, got nil")
970	}
971}
972
973func TestParser2_2FailsIfInvalidPackageChecksumType(t *testing.T) {
974	parser := tvParser2_2{
975		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
976		st:  psPackage2_2,
977		pkg: &v2_2.Package{},
978	}
979
980	// start with Package Name
981	err := parser.parsePairFromPackage2_2("PackageName", "p1")
982	if err != nil {
983		t.Errorf("expected nil error, got %v", err)
984	}
985	// invalid checksum type
986	err = parser.parsePairFromPackage2_2("PackageChecksum", "whoops: blah")
987	if err == nil {
988		t.Errorf("expected non-nil error, got nil")
989	}
990}
991
992func TestParser2_2FailsIfInvalidExternalRefFormat(t *testing.T) {
993	parser := tvParser2_2{
994		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
995		st:  psPackage2_2,
996		pkg: &v2_2.Package{},
997	}
998
999	// start with Package Name
1000	err := parser.parsePairFromPackage2_2("PackageName", "p1")
1001	if err != nil {
1002		t.Errorf("expected nil error, got %v", err)
1003	}
1004	// invalid external ref format
1005	err = parser.parsePairFromPackage2_2("ExternalRef", "whoops")
1006	if err == nil {
1007		t.Errorf("expected non-nil error, got nil")
1008	}
1009}
1010
1011func TestParser2_2FailsIfExternalRefCommentBeforeExternalRef(t *testing.T) {
1012	parser := tvParser2_2{
1013		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
1014		st:  psPackage2_2,
1015		pkg: &v2_2.Package{},
1016	}
1017
1018	// start with Package Name
1019	err := parser.parsePairFromPackage2_2("PackageName", "p1")
1020	if err != nil {
1021		t.Errorf("expected nil error, got %v", err)
1022	}
1023	// external ref comment before external ref
1024	err = parser.parsePairFromPackage2_2("ExternalRefComment", "whoops")
1025	if err == nil {
1026		t.Errorf("expected non-nil error, got nil")
1027	}
1028}
1029
1030// ===== Helper function tests =====
1031
1032func TestCanCheckAndExtractExcludesFilenameAndCode(t *testing.T) {
1033	code := "d6a770ba38583ed4bb4525bd96e50461655d2758"
1034	fileName := "./package.spdx"
1035	fullCodeValue := "d6a770ba38583ed4bb4525bd96e50461655d2758 (excludes: ./package.spdx)"
1036
1037	gotCode := extractCodeAndExcludes(fullCodeValue)
1038	if gotCode.Value != code {
1039		t.Errorf("got %v for gotCode", gotCode)
1040	}
1041	if len(gotCode.ExcludedFiles) != 1 || gotCode.ExcludedFiles[0] != fileName {
1042		t.Errorf("got %v for gotFileName", gotCode.ExcludedFiles)
1043	}
1044}
1045
1046func TestCanExtractPackageExternalReference(t *testing.T) {
1047	ref1 := "SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
1048	category := "SECURITY"
1049	refType := "cpe23Type"
1050	location := "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
1051
1052	gotCategory, gotRefType, gotLocation, err := extractPackageExternalReference(ref1)
1053	if err != nil {
1054		t.Errorf("got non-nil error: %v", err)
1055	}
1056	if gotCategory != category {
1057		t.Errorf("expected category %s, got %s", category, gotCategory)
1058	}
1059	if gotRefType != refType {
1060		t.Errorf("expected refType %s, got %s", refType, gotRefType)
1061	}
1062	if gotLocation != location {
1063		t.Errorf("expected location %s, got %s", location, gotLocation)
1064	}
1065}
1066
1067func TestCanExtractPackageExternalReferenceWithExtraWhitespace(t *testing.T) {
1068	ref1 := "  SECURITY    \t cpe23Type   cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:* \t "
1069	category := "SECURITY"
1070	refType := "cpe23Type"
1071	location := "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
1072
1073	gotCategory, gotRefType, gotLocation, err := extractPackageExternalReference(ref1)
1074	if err != nil {
1075		t.Errorf("got non-nil error: %v", err)
1076	}
1077	if gotCategory != category {
1078		t.Errorf("expected category %s, got %s", category, gotCategory)
1079	}
1080	if gotRefType != refType {
1081		t.Errorf("expected refType %s, got %s", refType, gotRefType)
1082	}
1083	if gotLocation != location {
1084		t.Errorf("expected location %s, got %s", location, gotLocation)
1085	}
1086}
1087
1088func TestFailsPackageExternalRefWithInvalidFormat(t *testing.T) {
1089	_, _, _, err := extractPackageExternalReference("whoops")
1090	if err == nil {
1091		t.Errorf("expected non-nil error, got nil")
1092	}
1093}
1094
1095func TestParser2_2PackageWithoutSpdxIdentifierThrowsError(t *testing.T) {
1096	// More than one package, the previous package doesn't contain an SPDX ID
1097	pkgOldName := "p1"
1098	parser := tvParser2_2{
1099		doc: &v2_2.Document{Packages: []*v2_2.Package{}},
1100		st:  psPackage2_2,
1101		pkg: &v2_2.Package{PackageName: pkgOldName},
1102	}
1103	pkgOld := parser.pkg
1104	parser.doc.Packages = append(parser.doc.Packages, pkgOld)
1105	// the Document's Packages should have this one only
1106	if parser.doc.Packages[0] != pkgOld {
1107		t.Errorf("expected package %v, got %v", pkgOld, parser.doc.Packages[0])
1108	}
1109	if len(parser.doc.Packages) != 1 {
1110		t.Errorf("expected 1 package, got %d", len(parser.doc.Packages))
1111	}
1112
1113	pkgName := "p2"
1114	err := parser.parsePair2_2("PackageName", pkgName)
1115	if err == nil {
1116		t.Errorf("package without SPDX Identifier getting accepted")
1117	}
1118}
1119