xref: /aosp_15_r20/external/spdx-tools/tvloader/parser2v3/parse_package_test.go (revision ba677afa8f67bb56cbc794f4d0e378e0da058e16)
1// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2package parser2v3
3
4import (
5	"fmt"
6	"testing"
7
8	"github.com/spdx/tools-golang/spdx/common"
9	"github.com/spdx/tools-golang/spdx/v2_3"
10)
11
12// ===== Parser package section state change tests =====
13func TestParser2_3PackageStartsNewPackageAfterParsingPackageNameTag(t *testing.T) {
14	// create the first package
15	pkgOldName := "p1"
16
17	parser := tvParser2_3{
18		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
19		st:  psPackage2_3,
20		pkg: &v2_3.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_3("PackageName", pkgName)
35	if err != nil {
36		t.Errorf("got error when calling parsePair2_3: %v", err)
37	}
38	// state should be correct
39	if parser.st != psPackage2_3 {
40		t.Errorf("expected state to be %v, got %v", psPackage2_3, 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_3PackageStartsNewPackageAfterParsingPackageNameTagWhileInUnpackaged(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_3{
74		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
75		st:  psFile2_3,
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_3("PackageName", pkgName)
86	if err != nil {
87		t.Errorf("got error when calling parsePair2_3: %v", err)
88	}
89	// state should be correct
90	if parser.st != psPackage2_3 {
91		t.Errorf("expected state to be %v, got %v", psPackage2_3, 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_3PackageMovesToFileAfterParsingFileNameTag(t *testing.T) {
116	parser := tvParser2_3{
117		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
118		st:  psPackage2_3,
119		pkg: &v2_3.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_3("FileName", "testFile")
125	if err != nil {
126		t.Errorf("got error when calling parsePair2_3: %v", err)
127	}
128	// state should be correct
129	if parser.st != psFile2_3 {
130		t.Errorf("expected state to be %v, got %v", psFile2_3, 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_3PackageMovesToOtherLicenseAfterParsingLicenseIDTag(t *testing.T) {
139	parser := tvParser2_3{
140		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
141		st:  psPackage2_3,
142		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
143	}
144	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
145
146	err := parser.parsePair2_3("LicenseID", "LicenseRef-TestLic")
147	if err != nil {
148		t.Errorf("got error when calling parsePair2_3: %v", err)
149	}
150	if parser.st != psOtherLicense2_3 {
151		t.Errorf("expected state to be %v, got %v", psOtherLicense2_3, parser.st)
152	}
153}
154
155func TestParser2_3PackageMovesToReviewAfterParsingReviewerTag(t *testing.T) {
156	parser := tvParser2_3{
157		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
158		st:  psPackage2_3,
159		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
160	}
161	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
162
163	err := parser.parsePair2_3("Reviewer", "Person: John Doe")
164	if err != nil {
165		t.Errorf("got error when calling parsePair2_3: %v", err)
166	}
167	if parser.st != psReview2_3 {
168		t.Errorf("expected state to be %v, got %v", psReview2_3, parser.st)
169	}
170}
171
172func TestParser2_3PackageStaysAfterParsingRelationshipTags(t *testing.T) {
173	parser := tvParser2_3{
174		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
175		st:  psPackage2_3,
176		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
177	}
178	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
179
180	err := parser.parsePair2_3("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-else")
181	if err != nil {
182		t.Errorf("got error when calling parsePair2_3: %v", err)
183	}
184	// state should remain unchanged
185	if parser.st != psPackage2_3 {
186		t.Errorf("expected state to be %v, got %v", psPackage2_3, parser.st)
187	}
188
189	err = parser.parsePair2_3("RelationshipComment", "blah")
190	if err != nil {
191		t.Errorf("got error when calling parsePair2_3: %v", err)
192	}
193	// state should still remain unchanged
194	if parser.st != psPackage2_3 {
195		t.Errorf("expected state to be %v, got %v", psPackage2_3, parser.st)
196	}
197}
198
199func TestParser2_3PackageStaysAfterParsingAnnotationTags(t *testing.T) {
200	parser := tvParser2_3{
201		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
202		st:  psPackage2_3,
203		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
204	}
205	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
206
207	err := parser.parsePair2_3("Annotator", "Person: John Doe ()")
208	if err != nil {
209		t.Errorf("got error when calling parsePair2_3: %v", err)
210	}
211	if parser.st != psPackage2_3 {
212		t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_3)
213	}
214
215	err = parser.parsePair2_3("AnnotationDate", "2018-09-15T00:36:00Z")
216	if err != nil {
217		t.Errorf("got error when calling parsePair2_3: %v", err)
218	}
219	if parser.st != psPackage2_3 {
220		t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_3)
221	}
222
223	err = parser.parsePair2_3("AnnotationType", "REVIEW")
224	if err != nil {
225		t.Errorf("got error when calling parsePair2_3: %v", err)
226	}
227	if parser.st != psPackage2_3 {
228		t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_3)
229	}
230
231	err = parser.parsePair2_3("SPDXREF", "SPDXRef-45")
232	if err != nil {
233		t.Errorf("got error when calling parsePair2_3: %v", err)
234	}
235	if parser.st != psPackage2_3 {
236		t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_3)
237	}
238
239	err = parser.parsePair2_3("AnnotationComment", "i guess i had something to say about this package")
240	if err != nil {
241		t.Errorf("got error when calling parsePair2_3: %v", err)
242	}
243	if parser.st != psPackage2_3 {
244		t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_3)
245	}
246}
247
248// ===== Package data section tests =====
249func TestParser2_3CanParsePackageTags(t *testing.T) {
250	parser := tvParser2_3{
251		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
252		st:  psPackage2_3,
253		pkg: &v2_3.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_3("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_3("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_3("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_3("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_3("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_3("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		"BLAKE3": "981d32ed7aad9e408c5c36f6346c915ba11c2bd8b3e7d44902a11d7a141abdd9",
345	}
346
347	for algo, tc := range testChecksums {
348		if err := parser.parsePairFromPackage2_3(
349			"PackageChecksum", fmt.Sprintf("%s: %s", algo, tc)); err != nil {
350			t.Errorf("expected error, got %v", err)
351		}
352	}
353
354	for _, checksum := range parser.pkg.PackageChecksums {
355		if checksum.Value != testChecksums[checksum.Algorithm] {
356			t.Errorf(
357				"expected %s for PackageChecksum%s, got %s",
358				testChecksums[checksum.Algorithm], checksum.Algorithm, checksum.Value,
359			)
360		}
361	}
362
363	// Package Home Page
364	err = parser.parsePairFromPackage2_3("PackageHomePage", "https://example.com/whatever2")
365	if err != nil {
366		t.Errorf("expected nil error, got %v", err)
367	}
368	if parser.pkg.PackageHomePage != "https://example.com/whatever2" {
369		t.Errorf("got %v for PackageHomePage", parser.pkg.PackageHomePage)
370	}
371
372	// Package Source Info
373	err = parser.parsePairFromPackage2_3("PackageSourceInfo", "random comment")
374	if err != nil {
375		t.Errorf("expected nil error, got %v", err)
376	}
377	if parser.pkg.PackageSourceInfo != "random comment" {
378		t.Errorf("got %v for PackageSourceInfo", parser.pkg.PackageSourceInfo)
379	}
380
381	// Package License Concluded
382	err = parser.parsePairFromPackage2_3("PackageLicenseConcluded", "Apache-2.0 OR GPL-2.0-or-later")
383	if err != nil {
384		t.Errorf("expected nil error, got %v", err)
385	}
386	if parser.pkg.PackageLicenseConcluded != "Apache-2.0 OR GPL-2.0-or-later" {
387		t.Errorf("got %v for PackageLicenseConcluded", parser.pkg.PackageLicenseConcluded)
388	}
389
390	// All Licenses Info From Files
391	lics := []string{
392		"Apache-2.0",
393		"GPL-2.0-or-later",
394		"CC0-1.0",
395	}
396	for _, lic := range lics {
397		err = parser.parsePairFromPackage2_3("PackageLicenseInfoFromFiles", lic)
398		if err != nil {
399			t.Errorf("expected nil error, got %v", err)
400		}
401	}
402	for _, licWant := range lics {
403		flagFound := false
404		for _, licCheck := range parser.pkg.PackageLicenseInfoFromFiles {
405			if licWant == licCheck {
406				flagFound = true
407			}
408		}
409		if flagFound == false {
410			t.Errorf("didn't find %s in PackageLicenseInfoFromFiles", licWant)
411		}
412	}
413	if len(lics) != len(parser.pkg.PackageLicenseInfoFromFiles) {
414		t.Errorf("expected %d licenses in PackageLicenseInfoFromFiles, got %d", len(lics),
415			len(parser.pkg.PackageLicenseInfoFromFiles))
416	}
417
418	// Package License Declared
419	err = parser.parsePairFromPackage2_3("PackageLicenseDeclared", "Apache-2.0 OR GPL-2.0-or-later")
420	if err != nil {
421		t.Errorf("expected nil error, got %v", err)
422	}
423	if parser.pkg.PackageLicenseDeclared != "Apache-2.0 OR GPL-2.0-or-later" {
424		t.Errorf("got %v for PackageLicenseDeclared", parser.pkg.PackageLicenseDeclared)
425	}
426
427	// Package License Comments
428	err = parser.parsePairFromPackage2_3("PackageLicenseComments", "this is a license comment")
429	if err != nil {
430		t.Errorf("expected nil error, got %v", err)
431	}
432	if parser.pkg.PackageLicenseComments != "this is a license comment" {
433		t.Errorf("got %v for PackageLicenseComments", parser.pkg.PackageLicenseComments)
434	}
435
436	// Package Copyright Text
437	err = parser.parsePairFromPackage2_3("PackageCopyrightText", "Copyright (c) me myself and i")
438	if err != nil {
439		t.Errorf("expected nil error, got %v", err)
440	}
441	if parser.pkg.PackageCopyrightText != "Copyright (c) me myself and i" {
442		t.Errorf("got %v for PackageCopyrightText", parser.pkg.PackageCopyrightText)
443	}
444
445	// Package Summary
446	err = parser.parsePairFromPackage2_3("PackageSummary", "i wrote this package")
447	if err != nil {
448		t.Errorf("expected nil error, got %v", err)
449	}
450	if parser.pkg.PackageSummary != "i wrote this package" {
451		t.Errorf("got %v for PackageSummary", parser.pkg.PackageSummary)
452	}
453
454	// Package Description
455	err = parser.parsePairFromPackage2_3("PackageDescription", "i wrote this package a lot")
456	if err != nil {
457		t.Errorf("expected nil error, got %v", err)
458	}
459	if parser.pkg.PackageDescription != "i wrote this package a lot" {
460		t.Errorf("got %v for PackageDescription", parser.pkg.PackageDescription)
461	}
462
463	// Package Comment
464	err = parser.parsePairFromPackage2_3("PackageComment", "i scanned this package")
465	if err != nil {
466		t.Errorf("expected nil error, got %v", err)
467	}
468	if parser.pkg.PackageComment != "i scanned this package" {
469		t.Errorf("got %v for PackageComment", parser.pkg.PackageComment)
470	}
471
472	// Package Attribution Text
473	attrs := []string{
474		"Include this notice in all advertising materials",
475		"This is a \nmulti-line string",
476	}
477	for _, attr := range attrs {
478		err = parser.parsePairFromPackage2_3("PackageAttributionText", attr)
479		if err != nil {
480			t.Errorf("expected nil error, got %v", err)
481		}
482	}
483	for _, attrWant := range attrs {
484		flagFound := false
485		for _, attrCheck := range parser.pkg.PackageAttributionTexts {
486			if attrWant == attrCheck {
487				flagFound = true
488			}
489		}
490		if flagFound == false {
491			t.Errorf("didn't find %s in PackageAttributionText", attrWant)
492		}
493	}
494	if len(attrs) != len(parser.pkg.PackageAttributionTexts) {
495		t.Errorf("expected %d attribution texts in PackageAttributionTexts, got %d", len(attrs),
496			len(parser.pkg.PackageAttributionTexts))
497	}
498
499	// Package External References and Comments
500	ref1 := "SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
501	ref1Category := "SECURITY"
502	ref1Type := "cpe23Type"
503	ref1Locator := "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
504	ref1Comment := "this is comment #1"
505	ref2 := "OTHER LocationRef-acmeforge acmecorp/acmenator/4.1.3alpha"
506	ref2Category := "OTHER"
507	ref2Type := "LocationRef-acmeforge"
508	ref2Locator := "acmecorp/acmenator/4.1.3alpha"
509	ref2Comment := "this is comment #2"
510	err = parser.parsePairFromPackage2_3("ExternalRef", ref1)
511	if err != nil {
512		t.Errorf("expected nil error, got %v", err)
513	}
514	if len(parser.pkg.PackageExternalReferences) != 1 {
515		t.Errorf("expected 1 external reference, got %d", len(parser.pkg.PackageExternalReferences))
516	}
517	if parser.pkgExtRef == nil {
518		t.Errorf("expected non-nil pkgExtRef, got nil")
519	}
520	if parser.pkg.PackageExternalReferences[0] == nil {
521		t.Errorf("expected non-nil PackageExternalReferences[0], got nil")
522	}
523	if parser.pkgExtRef != parser.pkg.PackageExternalReferences[0] {
524		t.Errorf("expected pkgExtRef to match PackageExternalReferences[0], got no match")
525	}
526	err = parser.parsePairFromPackage2_3("ExternalRefComment", ref1Comment)
527	if err != nil {
528		t.Errorf("expected nil error, got %v", err)
529	}
530	err = parser.parsePairFromPackage2_3("ExternalRef", ref2)
531	if err != nil {
532		t.Errorf("expected nil error, got %v", err)
533	}
534	if len(parser.pkg.PackageExternalReferences) != 2 {
535		t.Errorf("expected 2 external references, got %d", len(parser.pkg.PackageExternalReferences))
536	}
537	if parser.pkgExtRef == nil {
538		t.Errorf("expected non-nil pkgExtRef, got nil")
539	}
540	if parser.pkg.PackageExternalReferences[1] == nil {
541		t.Errorf("expected non-nil PackageExternalReferences[1], got nil")
542	}
543	if parser.pkgExtRef != parser.pkg.PackageExternalReferences[1] {
544		t.Errorf("expected pkgExtRef to match PackageExternalReferences[1], got no match")
545	}
546	err = parser.parsePairFromPackage2_3("ExternalRefComment", ref2Comment)
547	if err != nil {
548		t.Errorf("expected nil error, got %v", err)
549	}
550	// finally, check these values
551	gotRef1 := parser.pkg.PackageExternalReferences[0]
552	if gotRef1.Category != ref1Category {
553		t.Errorf("expected ref1 category to be %s, got %s", gotRef1.Category, ref1Category)
554	}
555	if gotRef1.RefType != ref1Type {
556		t.Errorf("expected ref1 type to be %s, got %s", gotRef1.RefType, ref1Type)
557	}
558	if gotRef1.Locator != ref1Locator {
559		t.Errorf("expected ref1 locator to be %s, got %s", gotRef1.Locator, ref1Locator)
560	}
561	if gotRef1.ExternalRefComment != ref1Comment {
562		t.Errorf("expected ref1 comment to be %s, got %s", gotRef1.ExternalRefComment, ref1Comment)
563	}
564	gotRef2 := parser.pkg.PackageExternalReferences[1]
565	if gotRef2.Category != ref2Category {
566		t.Errorf("expected ref2 category to be %s, got %s", gotRef2.Category, ref2Category)
567	}
568	if gotRef2.RefType != ref2Type {
569		t.Errorf("expected ref2 type to be %s, got %s", gotRef2.RefType, ref2Type)
570	}
571	if gotRef2.Locator != ref2Locator {
572		t.Errorf("expected ref2 locator to be %s, got %s", gotRef2.Locator, ref2Locator)
573	}
574	if gotRef2.ExternalRefComment != ref2Comment {
575		t.Errorf("expected ref2 comment to be %s, got %s", gotRef2.ExternalRefComment, ref2Comment)
576	}
577
578}
579
580func TestParser2_3CanParsePackageSupplierPersonTag(t *testing.T) {
581	parser := tvParser2_3{
582		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
583		st:  psPackage2_3,
584		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
585	}
586	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
587
588	// Package Supplier: Person
589	err := parser.parsePairFromPackage2_3("PackageSupplier", "Person: John Doe")
590	if err != nil {
591		t.Errorf("expected nil error, got %v", err)
592	}
593	if parser.pkg.PackageSupplier.Supplier != "John Doe" {
594		t.Errorf("got %v for PackageSupplierPerson", parser.pkg.PackageSupplier.Supplier)
595	}
596}
597
598func TestParser2_3CanParsePackageSupplierOrganizationTag(t *testing.T) {
599	parser := tvParser2_3{
600		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
601		st:  psPackage2_3,
602		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
603	}
604	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
605
606	// Package Supplier: Organization
607	err := parser.parsePairFromPackage2_3("PackageSupplier", "Organization: John Doe, Inc.")
608	if err != nil {
609		t.Errorf("expected nil error, got %v", err)
610	}
611	if parser.pkg.PackageSupplier.Supplier != "John Doe, Inc." {
612		t.Errorf("got %v for PackageSupplierOrganization", parser.pkg.PackageSupplier.Supplier)
613	}
614}
615
616func TestParser2_3CanParsePackageSupplierNOASSERTIONTag(t *testing.T) {
617	parser := tvParser2_3{
618		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
619		st:  psPackage2_3,
620		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
621	}
622	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
623
624	// Package Supplier: NOASSERTION
625	err := parser.parsePairFromPackage2_3("PackageSupplier", "NOASSERTION")
626	if err != nil {
627		t.Errorf("expected nil error, got %v", err)
628	}
629	if parser.pkg.PackageSupplier.Supplier != "NOASSERTION" {
630		t.Errorf("got value for Supplier, expected NOASSERTION")
631	}
632}
633
634func TestParser2_3CanParsePackageOriginatorPersonTag(t *testing.T) {
635	parser := tvParser2_3{
636		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
637		st:  psPackage2_3,
638		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
639	}
640	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
641
642	// Package Originator: Person
643	err := parser.parsePairFromPackage2_3("PackageOriginator", "Person: John Doe")
644	if err != nil {
645		t.Errorf("expected nil error, got %v", err)
646	}
647	if parser.pkg.PackageOriginator.Originator != "John Doe" {
648		t.Errorf("got %v for PackageOriginator", parser.pkg.PackageOriginator.Originator)
649	}
650}
651
652func TestParser2_3CanParsePackageOriginatorOrganizationTag(t *testing.T) {
653	parser := tvParser2_3{
654		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
655		st:  psPackage2_3,
656		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
657	}
658	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
659
660	// Package Originator: Organization
661	err := parser.parsePairFromPackage2_3("PackageOriginator", "Organization: John Doe, Inc.")
662	if err != nil {
663		t.Errorf("expected nil error, got %v", err)
664	}
665	if parser.pkg.PackageOriginator.Originator != "John Doe, Inc." {
666		t.Errorf("got %v for PackageOriginator", parser.pkg.PackageOriginator.Originator)
667	}
668}
669
670func TestParser2_3CanParsePackageOriginatorNOASSERTIONTag(t *testing.T) {
671	parser := tvParser2_3{
672		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
673		st:  psPackage2_3,
674		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
675	}
676	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
677
678	// Package Originator: NOASSERTION
679	err := parser.parsePairFromPackage2_3("PackageOriginator", "NOASSERTION")
680	if err != nil {
681		t.Errorf("expected nil error, got %v", err)
682	}
683	if parser.pkg.PackageOriginator.Originator != "NOASSERTION" {
684		t.Errorf("got false for PackageOriginatorNOASSERTION")
685	}
686}
687
688func TestParser2_3CanParsePackageVerificationCodeTagWithExcludes(t *testing.T) {
689	parser := tvParser2_3{
690		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
691		st:  psPackage2_3,
692		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
693	}
694	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
695
696	// Package Verification Code with excludes parenthetical
697	code := "d6a770ba38583ed4bb4525bd96e50461655d2758"
698	fileName := "./package.spdx"
699	fullCodeValue := "d6a770ba38583ed4bb4525bd96e50461655d2758 (excludes: ./package.spdx)"
700	err := parser.parsePairFromPackage2_3("PackageVerificationCode", fullCodeValue)
701	if err != nil {
702		t.Errorf("expected nil error, got %v", err)
703	}
704	if parser.pkg.PackageVerificationCode.Value != code {
705		t.Errorf("got %v for PackageVerificationCode", parser.pkg.PackageVerificationCode)
706	}
707	if len(parser.pkg.PackageVerificationCode.ExcludedFiles) != 1 || parser.pkg.PackageVerificationCode.ExcludedFiles[0] != fileName {
708		t.Errorf("got %v for PackageVerificationCodeExcludedFile", parser.pkg.PackageVerificationCode.ExcludedFiles)
709	}
710
711}
712
713func TestParser2_3CanParsePackageVerificationCodeTagWithoutExcludes(t *testing.T) {
714	parser := tvParser2_3{
715		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
716		st:  psPackage2_3,
717		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
718	}
719	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
720
721	// Package Verification Code without excludes parenthetical
722	code := "d6a770ba38583ed4bb4525bd96e50461655d2758"
723	err := parser.parsePairFromPackage2_3("PackageVerificationCode", code)
724	if err != nil {
725		t.Errorf("expected nil error, got %v", err)
726	}
727	if parser.pkg.PackageVerificationCode.Value != code {
728		t.Errorf("got %v for PackageVerificationCode", parser.pkg.PackageVerificationCode)
729	}
730	if len(parser.pkg.PackageVerificationCode.ExcludedFiles) != 0 {
731		t.Errorf("got %v for PackageVerificationCodeExcludedFile", parser.pkg.PackageVerificationCode.ExcludedFiles)
732	}
733
734}
735
736func TestParser2_3PackageExternalRefPointerChangesAfterTags(t *testing.T) {
737	parser := tvParser2_3{
738		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
739		st:  psPackage2_3,
740		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
741	}
742	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
743
744	ref1 := "SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
745	err := parser.parsePairFromPackage2_3("ExternalRef", ref1)
746	if err != nil {
747		t.Errorf("expected nil error, got %v", err)
748	}
749	if parser.pkgExtRef == nil {
750		t.Errorf("expected non-nil external reference pointer, got nil")
751	}
752
753	// now, a comment; pointer should go away
754	err = parser.parsePairFromPackage2_3("ExternalRefComment", "whatever")
755	if err != nil {
756		t.Errorf("expected nil error, got %v", err)
757	}
758	if parser.pkgExtRef != nil {
759		t.Errorf("expected nil external reference pointer, got non-nil")
760	}
761
762	ref2 := "Other LocationRef-something https://example.com/whatever"
763	err = parser.parsePairFromPackage2_3("ExternalRef", ref2)
764	if err != nil {
765		t.Errorf("expected nil error, got %v", err)
766	}
767	if parser.pkgExtRef == nil {
768		t.Errorf("expected non-nil external reference pointer, got nil")
769	}
770
771	// and some other random tag makes the pointer go away too
772	err = parser.parsePairFromPackage2_3("PackageSummary", "whatever")
773	if err != nil {
774		t.Errorf("expected nil error, got %v", err)
775	}
776	if parser.pkgExtRef != nil {
777		t.Errorf("expected nil external reference pointer, got non-nil")
778	}
779}
780
781func TestParser2_3PackageCreatesRelationshipInDocument(t *testing.T) {
782	parser := tvParser2_3{
783		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
784		st:  psPackage2_3,
785		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
786	}
787	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
788
789	err := parser.parsePair2_3("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-whatever")
790	if err != nil {
791		t.Errorf("got error when calling parsePair2_3: %v", err)
792	}
793	if parser.rln == nil {
794		t.Fatalf("parser didn't create and point to Relationship struct")
795	}
796	if parser.rln != parser.doc.Relationships[0] {
797		t.Errorf("pointer to new Relationship doesn't match idx 0 for doc.Relationships[]")
798	}
799}
800
801func TestParser2_3PackageCreatesAnnotationInDocument(t *testing.T) {
802	parser := tvParser2_3{
803		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
804		st:  psPackage2_3,
805		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
806	}
807	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
808
809	err := parser.parsePair2_3("Annotator", "Person: John Doe ()")
810	if err != nil {
811		t.Errorf("got error when calling parsePair2_3: %v", err)
812	}
813	if parser.ann == nil {
814		t.Fatalf("parser didn't create and point to Annotation struct")
815	}
816	if parser.ann != parser.doc.Annotations[0] {
817		t.Errorf("pointer to new Annotation doesn't match idx 0 for doc.Annotations[]")
818	}
819}
820
821func TestParser2_3PackageUnknownTagFails(t *testing.T) {
822	parser := tvParser2_3{
823		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
824		st:  psPackage2_3,
825		pkg: &v2_3.Package{PackageName: "p1", PackageSPDXIdentifier: "p1"},
826	}
827	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
828
829	err := parser.parsePairFromPackage2_3("blah", "something")
830	if err == nil {
831		t.Errorf("expected error from parsing unknown tag")
832	}
833}
834
835func TestParser2_3FailsIfInvalidSPDXIDInPackageSection(t *testing.T) {
836	parser := tvParser2_3{
837		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
838		st:  psPackage2_3,
839		pkg: &v2_3.Package{},
840	}
841
842	// start with Package Name
843	err := parser.parsePairFromPackage2_3("PackageName", "p1")
844	if err != nil {
845		t.Errorf("expected nil error, got %v", err)
846	}
847	// invalid ID format
848	err = parser.parsePairFromPackage2_3("SPDXID", "whoops")
849	if err == nil {
850		t.Errorf("expected non-nil error, got nil")
851	}
852}
853
854func TestParser2_3FailsIfInvalidPackageSupplierFormat(t *testing.T) {
855	parser := tvParser2_3{
856		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
857		st:  psPackage2_3,
858		pkg: &v2_3.Package{},
859	}
860
861	// start with Package Name
862	err := parser.parsePairFromPackage2_3("PackageName", "p1")
863	if err != nil {
864		t.Errorf("expected nil error, got %v", err)
865	}
866	// invalid supplier format
867	err = parser.parsePairFromPackage2_3("PackageSupplier", "whoops")
868	if err == nil {
869		t.Errorf("expected non-nil error, got nil")
870	}
871}
872
873func TestParser2_3FailsIfUnknownPackageSupplierType(t *testing.T) {
874	parser := tvParser2_3{
875		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
876		st:  psPackage2_3,
877		pkg: &v2_3.Package{},
878	}
879
880	// start with Package Name
881	err := parser.parsePairFromPackage2_3("PackageName", "p1")
882	if err != nil {
883		t.Errorf("expected nil error, got %v", err)
884	}
885	// invalid supplier type
886	err = parser.parsePairFromPackage2_3("PackageSupplier", "whoops: John Doe")
887	if err == nil {
888		t.Errorf("expected non-nil error, got nil")
889	}
890}
891
892func TestParser2_3FailsIfInvalidPackageOriginatorFormat(t *testing.T) {
893	parser := tvParser2_3{
894		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
895		st:  psPackage2_3,
896		pkg: &v2_3.Package{},
897	}
898
899	// start with Package Name
900	err := parser.parsePairFromPackage2_3("PackageName", "p1")
901	if err != nil {
902		t.Errorf("expected nil error, got %v", err)
903	}
904	// invalid originator format
905	err = parser.parsePairFromPackage2_3("PackageOriginator", "whoops")
906	if err == nil {
907		t.Errorf("expected non-nil error, got nil")
908	}
909}
910
911func TestParser2_3FailsIfUnknownPackageOriginatorType(t *testing.T) {
912	parser := tvParser2_3{
913		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
914		st:  psPackage2_3,
915		pkg: &v2_3.Package{},
916	}
917
918	// start with Package Name
919	err := parser.parsePairFromPackage2_3("PackageName", "p1")
920	if err != nil {
921		t.Errorf("expected nil error, got %v", err)
922	}
923	// invalid originator type
924	err = parser.parsePairFromPackage2_3("PackageOriginator", "whoops: John Doe")
925	if err == nil {
926		t.Errorf("expected non-nil error, got nil")
927	}
928}
929
930func TestParser2_3SetsFilesAnalyzedTagsCorrectly(t *testing.T) {
931	parser := tvParser2_3{
932		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
933		st:  psPackage2_3,
934		pkg: &v2_3.Package{},
935	}
936
937	// start with Package Name
938	err := parser.parsePairFromPackage2_3("PackageName", "p1")
939	if err != nil {
940		t.Errorf("expected nil error, got %v", err)
941	}
942	// set tag
943	err = parser.parsePairFromPackage2_3("FilesAnalyzed", "true")
944	if err != nil {
945		t.Errorf("expected nil error, got %v", err)
946	}
947	if parser.pkg.FilesAnalyzed != true {
948		t.Errorf("expected %v, got %v", true, parser.pkg.FilesAnalyzed)
949	}
950	if parser.pkg.IsFilesAnalyzedTagPresent != true {
951		t.Errorf("expected %v, got %v", true, parser.pkg.IsFilesAnalyzedTagPresent)
952	}
953}
954
955func TestParser2_3FailsIfInvalidPackageChecksumFormat(t *testing.T) {
956	parser := tvParser2_3{
957		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
958		st:  psPackage2_3,
959		pkg: &v2_3.Package{},
960	}
961
962	// start with Package Name
963	err := parser.parsePairFromPackage2_3("PackageName", "p1")
964	if err != nil {
965		t.Errorf("expected nil error, got %v", err)
966	}
967	// invalid checksum format
968	err = parser.parsePairFromPackage2_3("PackageChecksum", "whoops")
969	if err == nil {
970		t.Errorf("expected non-nil error, got nil")
971	}
972}
973
974func TestParser2_3FailsIfInvalidPackageChecksumType(t *testing.T) {
975	parser := tvParser2_3{
976		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
977		st:  psPackage2_3,
978		pkg: &v2_3.Package{},
979	}
980
981	// start with Package Name
982	err := parser.parsePairFromPackage2_3("PackageName", "p1")
983	if err != nil {
984		t.Errorf("expected nil error, got %v", err)
985	}
986	// invalid checksum type
987	err = parser.parsePairFromPackage2_3("PackageChecksum", "whoops: blah")
988	if err == nil {
989		t.Errorf("expected non-nil error, got nil")
990	}
991}
992
993func TestParser2_3FailsIfInvalidExternalRefFormat(t *testing.T) {
994	parser := tvParser2_3{
995		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
996		st:  psPackage2_3,
997		pkg: &v2_3.Package{},
998	}
999
1000	// start with Package Name
1001	err := parser.parsePairFromPackage2_3("PackageName", "p1")
1002	if err != nil {
1003		t.Errorf("expected nil error, got %v", err)
1004	}
1005	// invalid external ref format
1006	err = parser.parsePairFromPackage2_3("ExternalRef", "whoops")
1007	if err == nil {
1008		t.Errorf("expected non-nil error, got nil")
1009	}
1010}
1011
1012func TestParser2_3FailsIfExternalRefCommentBeforeExternalRef(t *testing.T) {
1013	parser := tvParser2_3{
1014		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
1015		st:  psPackage2_3,
1016		pkg: &v2_3.Package{},
1017	}
1018
1019	// start with Package Name
1020	err := parser.parsePairFromPackage2_3("PackageName", "p1")
1021	if err != nil {
1022		t.Errorf("expected nil error, got %v", err)
1023	}
1024	// external ref comment before external ref
1025	err = parser.parsePairFromPackage2_3("ExternalRefComment", "whoops")
1026	if err == nil {
1027		t.Errorf("expected non-nil error, got nil")
1028	}
1029}
1030
1031// ===== Helper function tests =====
1032
1033func TestCanCheckAndExtractExcludesFilenameAndCode(t *testing.T) {
1034	code := "d6a770ba38583ed4bb4525bd96e50461655d2758"
1035	fileName := "./package.spdx"
1036	fullCodeValue := "d6a770ba38583ed4bb4525bd96e50461655d2758 (excludes: ./package.spdx)"
1037
1038	gotCode := extractCodeAndExcludes(fullCodeValue)
1039	if gotCode.Value != code {
1040		t.Errorf("got %v for gotCode", gotCode)
1041	}
1042	if len(gotCode.ExcludedFiles) != 1 || gotCode.ExcludedFiles[0] != fileName {
1043		t.Errorf("got %v for gotFileName", gotCode.ExcludedFiles)
1044	}
1045}
1046
1047func TestCanExtractPackageExternalReference(t *testing.T) {
1048	ref1 := "SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
1049	category := "SECURITY"
1050	refType := "cpe23Type"
1051	location := "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
1052
1053	gotCategory, gotRefType, gotLocation, err := extractPackageExternalReference(ref1)
1054	if err != nil {
1055		t.Errorf("got non-nil error: %v", err)
1056	}
1057	if gotCategory != category {
1058		t.Errorf("expected category %s, got %s", category, gotCategory)
1059	}
1060	if gotRefType != refType {
1061		t.Errorf("expected refType %s, got %s", refType, gotRefType)
1062	}
1063	if gotLocation != location {
1064		t.Errorf("expected location %s, got %s", location, gotLocation)
1065	}
1066}
1067
1068func TestCanExtractPackageExternalReferenceWithExtraWhitespace(t *testing.T) {
1069	ref1 := "  SECURITY    \t cpe23Type   cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:* \t "
1070	category := "SECURITY"
1071	refType := "cpe23Type"
1072	location := "cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*"
1073
1074	gotCategory, gotRefType, gotLocation, err := extractPackageExternalReference(ref1)
1075	if err != nil {
1076		t.Errorf("got non-nil error: %v", err)
1077	}
1078	if gotCategory != category {
1079		t.Errorf("expected category %s, got %s", category, gotCategory)
1080	}
1081	if gotRefType != refType {
1082		t.Errorf("expected refType %s, got %s", refType, gotRefType)
1083	}
1084	if gotLocation != location {
1085		t.Errorf("expected location %s, got %s", location, gotLocation)
1086	}
1087}
1088
1089func TestFailsPackageExternalRefWithInvalidFormat(t *testing.T) {
1090	_, _, _, err := extractPackageExternalReference("whoops")
1091	if err == nil {
1092		t.Errorf("expected non-nil error, got nil")
1093	}
1094}
1095
1096func TestParser2_3PackageWithoutSpdxIdentifierThrowsError(t *testing.T) {
1097	// More than one package, the previous package doesn't contain an SPDX ID
1098	pkgOldName := "p1"
1099	parser := tvParser2_3{
1100		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
1101		st:  psPackage2_3,
1102		pkg: &v2_3.Package{PackageName: pkgOldName},
1103	}
1104	pkgOld := parser.pkg
1105	parser.doc.Packages = append(parser.doc.Packages, pkgOld)
1106	// the Document's Packages should have this one only
1107	if parser.doc.Packages[0] != pkgOld {
1108		t.Errorf("expected package %v, got %v", pkgOld, parser.doc.Packages[0])
1109	}
1110	if len(parser.doc.Packages) != 1 {
1111		t.Errorf("expected 1 package, got %d", len(parser.doc.Packages))
1112	}
1113
1114	pkgName := "p2"
1115	err := parser.parsePair2_3("PackageName", pkgName)
1116	if err == nil {
1117		t.Errorf("package without SPDX Identifier getting accepted")
1118	}
1119}
1120