xref: /aosp_15_r20/external/spdx-tools/tvloader/parser2v3/parse_file_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 file section state change tests =====
13func TestParser2_3FileStartsNewFileAfterParsingFileNameTag(t *testing.T) {
14	// create the first file
15	fileOldName := "f1.txt"
16
17	parser := tvParser2_3{
18		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
19		st:   psFile2_3,
20		pkg:  &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
21		file: &v2_3.File{FileName: fileOldName, FileSPDXIdentifier: "f1"},
22	}
23	fileOld := parser.file
24	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
25	parser.pkg.Files = append(parser.pkg.Files, fileOld)
26	// the Package's Files should have this one only
27	if len(parser.pkg.Files) != 1 {
28		t.Fatalf("expected 1 file, got %d", len(parser.pkg.Files))
29	}
30	if parser.pkg.Files[0] != fileOld {
31		t.Errorf("expected file %v in Files[f1], got %v", fileOld, parser.pkg.Files[0])
32	}
33	if parser.pkg.Files[0].FileName != fileOldName {
34		t.Errorf("expected file name %s in Files[f1], got %s", fileOldName, parser.pkg.Files[0].FileName)
35	}
36
37	// now add a new file
38	fileName := "f2.txt"
39	err := parser.parsePair2_3("FileName", fileName)
40	if err != nil {
41		t.Errorf("got error when calling parsePair2_3: %v", err)
42	}
43	// state should be correct
44	if parser.st != psFile2_3 {
45		t.Errorf("expected state to be %v, got %v", psFile2_3, parser.st)
46	}
47	// and a file should be created
48	if parser.file == nil {
49		t.Fatalf("parser didn't create new file")
50	}
51	// and the file name should be as expected
52	if parser.file.FileName != fileName {
53		t.Errorf("expected file name %s, got %s", fileName, parser.file.FileName)
54	}
55	// and the Package's Files should still be of size 1 and not have this new
56	// one yet, since it hasn't seen an SPDX identifier
57	if len(parser.pkg.Files) != 1 {
58		t.Fatalf("expected 1 file, got %d", len(parser.pkg.Files))
59	}
60	if parser.pkg.Files[0] != fileOld {
61		t.Errorf("expected file %v in Files[f1], got %v", fileOld, parser.pkg.Files[0])
62	}
63	if parser.pkg.Files[0].FileName != fileOldName {
64		t.Errorf("expected file name %s in Files[f1], got %s", fileOldName, parser.pkg.Files[0].FileName)
65	}
66
67	// now parse an SPDX identifier tag
68	err = parser.parsePair2_3("SPDXID", "SPDXRef-f2ID")
69	if err != nil {
70		t.Errorf("got error when calling parsePair2_3: %v", err)
71	}
72	// and the Package's Files should now be of size 2 and have this new one
73	if len(parser.pkg.Files) != 2 {
74		t.Fatalf("expected 2 files, got %d", len(parser.pkg.Files))
75	}
76	if parser.pkg.Files[0] != fileOld {
77		t.Errorf("expected file %v in Files[f1], got %v", fileOld, parser.pkg.Files[0])
78	}
79	if parser.pkg.Files[0].FileName != fileOldName {
80		t.Errorf("expected file name %s in Files[f1], got %s", fileOldName, parser.pkg.Files[0].FileName)
81	}
82	if parser.pkg.Files[1] != parser.file {
83		t.Errorf("expected file %v in Files[f2ID], got %v", parser.file, parser.pkg.Files[1])
84	}
85	if parser.pkg.Files[1].FileName != fileName {
86		t.Errorf("expected file name %s in Files[f2ID], got %s", fileName, parser.pkg.Files[1].FileName)
87	}
88}
89
90func TestParser2_3FileAddsToPackageOrUnpackagedFiles(t *testing.T) {
91	// start with no packages
92	parser := tvParser2_3{
93		doc: &v2_3.Document{},
94		st:  psCreationInfo2_3,
95	}
96
97	// add a file and SPDX identifier
98	fileName := "f2.txt"
99	err := parser.parsePair2_3("FileName", fileName)
100	if err != nil {
101		t.Errorf("got error when calling parsePair2_3: %v", err)
102	}
103	err = parser.parsePair2_3("SPDXID", "SPDXRef-f2ID")
104	if err != nil {
105		t.Errorf("got error when calling parsePair2_3: %v", err)
106	}
107	fileOld := parser.file
108	// should have been added to Files
109	if len(parser.doc.Files) != 1 {
110		t.Fatalf("expected 1 file in Files, got %d", len(parser.doc.Files))
111	}
112	if parser.doc.Files[0] != fileOld {
113		t.Errorf("expected file %v in Files[f2ID], got %v", fileOld, parser.doc.Files[0])
114	}
115	// now create a package and a new file
116	err = parser.parsePair2_3("PackageName", "package1")
117	if err != nil {
118		t.Errorf("got error when calling parsePair2_3: %v", err)
119	}
120	err = parser.parsePair2_3("SPDXID", "SPDXRef-pkg1")
121	if err != nil {
122		t.Errorf("got error when calling parsePair2_3: %v", err)
123	}
124	err = parser.parsePair2_3("FileName", "f3.txt")
125	if err != nil {
126		t.Errorf("got error when calling parsePair2_3: %v", err)
127	}
128	err = parser.parsePair2_3("SPDXID", "SPDXRef-f3ID")
129	if err != nil {
130		t.Errorf("got error when calling parsePair2_3: %v", err)
131	}
132	// Files should still be size 1 and have old file only
133	if len(parser.doc.Files) != 1 {
134		t.Fatalf("expected 1 file in Files, got %d", len(parser.doc.Files))
135	}
136	if parser.doc.Files[0] != fileOld {
137		t.Errorf("expected file %v in Files[f2ID], got %v", fileOld, parser.doc.Files[0])
138	}
139	// and new package should have gotten the new file
140	if len(parser.pkg.Files) != 1 {
141		t.Fatalf("expected 1 file in Files, got %d", len(parser.pkg.Files))
142	}
143	if parser.pkg.Files[0] != parser.file {
144		t.Errorf("expected file %v in Files[f3ID], got %v", parser.file, parser.pkg.Files[0])
145	}
146}
147
148func TestParser2_3FileStartsNewPackageAfterParsingPackageNameTag(t *testing.T) {
149	// create the first file and package
150	p1Name := "package1"
151	f1Name := "f1.txt"
152
153	parser := tvParser2_3{
154		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
155		st:   psFile2_3,
156		pkg:  &v2_3.Package{PackageName: p1Name, PackageSPDXIdentifier: "package1", Files: []*v2_3.File{}},
157		file: &v2_3.File{FileName: f1Name, FileSPDXIdentifier: "f1"},
158	}
159	p1 := parser.pkg
160	f1 := parser.file
161	parser.doc.Packages = append(parser.doc.Packages, p1)
162	parser.pkg.Files = append(parser.pkg.Files, f1)
163
164	// now add a new package
165	p2Name := "package2"
166	err := parser.parsePair2_3("PackageName", p2Name)
167	if err != nil {
168		t.Errorf("got error when calling parsePair2_3: %v", err)
169	}
170	// state should go back to Package
171	if parser.st != psPackage2_3 {
172		t.Errorf("expected state to be %v, got %v", psPackage2_3, parser.st)
173	}
174	// and a package should be created
175	if parser.pkg == nil {
176		t.Fatalf("parser didn't create new pkg")
177	}
178	// and the package name should be as expected
179	if parser.pkg.PackageName != p2Name {
180		t.Errorf("expected package name %s, got %s", p2Name, parser.pkg.PackageName)
181	}
182	// and the package should default to true for FilesAnalyzed
183	if parser.pkg.FilesAnalyzed != true {
184		t.Errorf("expected FilesAnalyzed to default to true, got false")
185	}
186	if parser.pkg.IsFilesAnalyzedTagPresent != false {
187		t.Errorf("expected IsFilesAnalyzedTagPresent to default to false, got true")
188	}
189	// and the new Package should have no files
190	if len(parser.pkg.Files) != 0 {
191		t.Errorf("Expected no files in pkg.Files, got %d", len(parser.pkg.Files))
192	}
193	// and the Document's Packages should still be of size 1 and not have this
194	// new one, because no SPDX identifier has been seen yet
195	if len(parser.doc.Packages) != 1 {
196		t.Fatalf("expected 1 package, got %d", len(parser.doc.Packages))
197	}
198	if parser.doc.Packages[0] != p1 {
199		t.Errorf("Expected package %v in Packages[package1], got %v", p1, parser.doc.Packages[0])
200	}
201	if parser.doc.Packages[0].PackageName != p1Name {
202		t.Errorf("expected package name %s in Packages[package1], got %s", p1Name, parser.doc.Packages[0].PackageName)
203	}
204	// and the first Package's Files should be of size 1 and have f1 only
205	if len(parser.doc.Packages[0].Files) != 1 {
206		t.Errorf("Expected 1 file in Packages[package1].Files, got %d", len(parser.doc.Packages[0].Files))
207	}
208	if parser.doc.Packages[0].Files[0] != f1 {
209		t.Errorf("Expected file %v in Files[f1], got %v", f1, parser.doc.Packages[0].Files[0])
210	}
211	if parser.doc.Packages[0].Files[0].FileName != f1Name {
212		t.Errorf("expected file name %s in Files[f1], got %s", f1Name, parser.doc.Packages[0].Files[0].FileName)
213	}
214	// and the current file should be nil
215	if parser.file != nil {
216		t.Errorf("Expected nil for parser.file, got %v", parser.file)
217	}
218}
219
220func TestParser2_3FileMovesToSnippetAfterParsingSnippetSPDXIDTag(t *testing.T) {
221	parser := tvParser2_3{
222		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
223		st:   psFile2_3,
224		pkg:  &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
225		file: &v2_3.File{FileName: "f1.txt", FileSPDXIdentifier: "f1"},
226	}
227	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
228	parser.pkg.Files = append(parser.pkg.Files, parser.file)
229	fileCurrent := parser.file
230
231	err := parser.parsePair2_3("SnippetSPDXID", "SPDXRef-Test1")
232	if err != nil {
233		t.Errorf("got error when calling parsePair2_3: %v", err)
234	}
235	// state should be correct
236	if parser.st != psSnippet2_3 {
237		t.Errorf("expected state to be %v, got %v", psSnippet2_3, parser.st)
238	}
239	// and current file should remain what it was
240	if parser.file != fileCurrent {
241		t.Fatalf("expected file to remain %v, got %v", fileCurrent, parser.file)
242	}
243}
244
245func TestParser2_3FileMovesToOtherLicenseAfterParsingLicenseIDTag(t *testing.T) {
246	parser := tvParser2_3{
247		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
248		st:   psFile2_3,
249		pkg:  &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
250		file: &v2_3.File{FileName: "f1.txt", FileSPDXIdentifier: "f1"},
251	}
252	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
253	parser.pkg.Files = append(parser.pkg.Files, parser.file)
254
255	err := parser.parsePair2_3("LicenseID", "LicenseRef-TestLic")
256	if err != nil {
257		t.Errorf("got error when calling parsePair2_3: %v", err)
258	}
259	if parser.st != psOtherLicense2_3 {
260		t.Errorf("expected state to be %v, got %v", psOtherLicense2_3, parser.st)
261	}
262}
263
264func TestParser2_3FileMovesToReviewAfterParsingReviewerTag(t *testing.T) {
265	parser := tvParser2_3{
266		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
267		st:   psFile2_3,
268		pkg:  &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
269		file: &v2_3.File{FileName: "f1.txt", FileSPDXIdentifier: "f1"},
270	}
271	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
272	parser.pkg.Files = append(parser.pkg.Files, parser.file)
273
274	err := parser.parsePair2_3("Reviewer", "Person: John Doe")
275	if err != nil {
276		t.Errorf("got error when calling parsePair2_3: %v", err)
277	}
278	if parser.st != psReview2_3 {
279		t.Errorf("expected state to be %v, got %v", psReview2_3, parser.st)
280	}
281}
282
283func TestParser2_3FileStaysAfterParsingRelationshipTags(t *testing.T) {
284	parser := tvParser2_3{
285		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
286		st:   psFile2_3,
287		pkg:  &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
288		file: &v2_3.File{FileName: "f1.txt", FileSPDXIdentifier: "f1"},
289	}
290	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
291	parser.pkg.Files = append(parser.pkg.Files, parser.file)
292
293	err := parser.parsePair2_3("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-else")
294	if err != nil {
295		t.Errorf("got error when calling parsePair2_3: %v", err)
296	}
297	// state should remain unchanged
298	if parser.st != psFile2_3 {
299		t.Errorf("expected state to be %v, got %v", psFile2_3, parser.st)
300	}
301
302	err = parser.parsePair2_3("RelationshipComment", "blah")
303	if err != nil {
304		t.Errorf("got error when calling parsePair2_3: %v", err)
305	}
306	// state should still remain unchanged
307	if parser.st != psFile2_3 {
308		t.Errorf("expected state to be %v, got %v", psFile2_3, parser.st)
309	}
310}
311
312func TestParser2_3FileStaysAfterParsingAnnotationTags(t *testing.T) {
313	parser := tvParser2_3{
314		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
315		st:   psFile2_3,
316		pkg:  &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
317		file: &v2_3.File{FileName: "f1.txt", FileSPDXIdentifier: "f1"},
318	}
319	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
320	parser.pkg.Files = append(parser.pkg.Files, parser.file)
321
322	err := parser.parsePair2_3("Annotator", "Person: John Doe ()")
323	if err != nil {
324		t.Errorf("got error when calling parsePair2_3: %v", err)
325	}
326	if parser.st != psFile2_3 {
327		t.Errorf("parser is in state %v, expected %v", parser.st, psFile2_3)
328	}
329
330	err = parser.parsePair2_3("AnnotationDate", "2018-09-15T00:36:00Z")
331	if err != nil {
332		t.Errorf("got error when calling parsePair2_3: %v", err)
333	}
334	if parser.st != psFile2_3 {
335		t.Errorf("parser is in state %v, expected %v", parser.st, psFile2_3)
336	}
337
338	err = parser.parsePair2_3("AnnotationType", "REVIEW")
339	if err != nil {
340		t.Errorf("got error when calling parsePair2_3: %v", err)
341	}
342	if parser.st != psFile2_3 {
343		t.Errorf("parser is in state %v, expected %v", parser.st, psFile2_3)
344	}
345
346	err = parser.parsePair2_3("SPDXREF", "SPDXRef-45")
347	if err != nil {
348		t.Errorf("got error when calling parsePair2_3: %v", err)
349	}
350	if parser.st != psFile2_3 {
351		t.Errorf("parser is in state %v, expected %v", parser.st, psFile2_3)
352	}
353
354	err = parser.parsePair2_3("AnnotationComment", "i guess i had something to say about this particular file")
355	if err != nil {
356		t.Errorf("got error when calling parsePair2_3: %v", err)
357	}
358	if parser.st != psFile2_3 {
359		t.Errorf("parser is in state %v, expected %v", parser.st, psFile2_3)
360	}
361}
362
363// ===== File data section tests =====
364func TestParser2_3CanParseFileTags(t *testing.T) {
365	parser := tvParser2_3{
366		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
367		st:  psFile2_3,
368		pkg: &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
369	}
370	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
371
372	// File Name
373	err := parser.parsePairFromFile2_3("FileName", "f1.txt")
374	if err != nil {
375		t.Errorf("expected nil error, got %v", err)
376	}
377	if parser.file.FileName != "f1.txt" {
378		t.Errorf("got %v for FileName", parser.file.FileName)
379	}
380	// should not yet be added to the Packages file list, because we haven't
381	// seen an SPDX identifier yet
382	if len(parser.pkg.Files) != 0 {
383		t.Errorf("expected 0 files, got %d", len(parser.pkg.Files))
384	}
385
386	// File SPDX Identifier
387	err = parser.parsePairFromFile2_3("SPDXID", "SPDXRef-f1")
388	if err != nil {
389		t.Errorf("expected nil error, got %v", err)
390	}
391	if parser.file.FileSPDXIdentifier != "f1" {
392		t.Errorf("got %v for FileSPDXIdentifier", parser.file.FileSPDXIdentifier)
393	}
394	// should now be added to the Packages file list
395	if len(parser.pkg.Files) != 1 {
396		t.Errorf("expected 1 file, got %d", len(parser.pkg.Files))
397	}
398	if parser.pkg.Files[0] != parser.file {
399		t.Errorf("expected Files[f1] to be %v, got %v", parser.file, parser.pkg.Files[0])
400	}
401
402	// File Type
403	fileTypes := []string{
404		"TEXT",
405		"DOCUMENTATION",
406	}
407	for _, ty := range fileTypes {
408		err = parser.parsePairFromFile2_3("FileType", ty)
409		if err != nil {
410			t.Errorf("expected nil error, got %v", err)
411		}
412	}
413	for _, typeWant := range fileTypes {
414		flagFound := false
415		for _, typeCheck := range parser.file.FileTypes {
416			if typeWant == typeCheck {
417				flagFound = true
418			}
419		}
420		if flagFound == false {
421			t.Errorf("didn't find %s in FileTypes", typeWant)
422		}
423	}
424	if len(fileTypes) != len(parser.file.FileTypes) {
425		t.Errorf("expected %d types in FileTypes, got %d", len(fileTypes),
426			len(parser.file.FileTypes))
427	}
428
429	testChecksums := map[common.ChecksumAlgorithm]string{
430		"MD5":    "624c1abb3664f4b35547e7c73864ad24",
431		"SHA1":   "85ed0817af83a24ad8da68c2b5094de69833983c",
432		"SHA256": "11b6d3ee554eedf79299905a98f9b9a04e498210b59f15094c916c91d150efcd",
433		"SHA512": "4ced3267f5ed38df65ceebc43e97aa6c2948cc7ef3288c2e5074e7df7fab544cc93339604513ea5f65616f9ed1c48581465043c8a9b693ef20fd4fddaf25e1b9",
434		"BLAKE3": "981d32ed7aad9e408c5c36f6346c915ba11c2bd8b3e7d44902a11d7a141abdd9",
435	}
436
437	for algo, tc := range testChecksums {
438		if err := parser.parsePairFromFile2_3(
439			"FileChecksum", fmt.Sprintf("%s: %s", algo, tc)); err != nil {
440			t.Errorf("expected error, got %v", err)
441		}
442	}
443
444	for _, checksum := range parser.file.Checksums {
445		if checksum.Value != testChecksums[checksum.Algorithm] {
446			t.Errorf(
447				"expected %s for FileChecksum%s, got %s",
448				testChecksums[checksum.Algorithm], checksum.Algorithm, checksum.Value,
449			)
450		}
451	}
452
453	// Concluded License
454	err = parser.parsePairFromFile2_3("LicenseConcluded", "Apache-2.0 OR GPL-2.0-or-later")
455	if err != nil {
456		t.Errorf("expected nil error, got %v", err)
457	}
458	if parser.file.LicenseConcluded != "Apache-2.0 OR GPL-2.0-or-later" {
459		t.Errorf("got %v for LicenseConcluded", parser.file.LicenseConcluded)
460	}
461
462	// License Information in File
463	lics := []string{
464		"Apache-2.0",
465		"GPL-2.0-or-later",
466		"CC0-1.0",
467	}
468	for _, lic := range lics {
469		err = parser.parsePairFromFile2_3("LicenseInfoInFile", lic)
470		if err != nil {
471			t.Errorf("expected nil error, got %v", err)
472		}
473	}
474	for _, licWant := range lics {
475		flagFound := false
476		for _, licCheck := range parser.file.LicenseInfoInFiles {
477			if licWant == licCheck {
478				flagFound = true
479			}
480		}
481		if flagFound == false {
482			t.Errorf("didn't find %s in LicenseInfoInFiles", licWant)
483		}
484	}
485	if len(lics) != len(parser.file.LicenseInfoInFiles) {
486		t.Errorf("expected %d licenses in LicenseInfoInFiles, got %d", len(lics),
487			len(parser.file.LicenseInfoInFiles))
488	}
489
490	// Comments on License
491	err = parser.parsePairFromFile2_3("LicenseComments", "this is a comment")
492	if err != nil {
493		t.Errorf("expected nil error, got %v", err)
494	}
495	if parser.file.LicenseComments != "this is a comment" {
496		t.Errorf("got %v for LicenseComments", parser.file.LicenseComments)
497	}
498
499	// Copyright Text
500	err = parser.parsePairFromFile2_3("FileCopyrightText", "copyright (c) me")
501	if err != nil {
502		t.Errorf("expected nil error, got %v", err)
503	}
504	if parser.file.FileCopyrightText != "copyright (c) me" {
505		t.Errorf("got %v for FileCopyrightText", parser.file.FileCopyrightText)
506	}
507
508	// Artifact of Projects: Name, HomePage and URI
509	// Artifact set 1
510	err = parser.parsePairFromFile2_3("ArtifactOfProjectName", "project1")
511	if err != nil {
512		t.Errorf("expected nil error, got %v", err)
513	}
514	err = parser.parsePairFromFile2_3("ArtifactOfProjectHomePage", "http://example.com/1/")
515	if err != nil {
516		t.Errorf("expected nil error, got %v", err)
517	}
518	err = parser.parsePairFromFile2_3("ArtifactOfProjectURI", "http://example.com/1/uri.whatever")
519	if err != nil {
520		t.Errorf("expected nil error, got %v", err)
521	}
522	// Artifact set 2 -- just name
523	err = parser.parsePairFromFile2_3("ArtifactOfProjectName", "project2")
524	if err != nil {
525		t.Errorf("expected nil error, got %v", err)
526	}
527	// Artifact set 3 -- just name and home page
528	err = parser.parsePairFromFile2_3("ArtifactOfProjectName", "project3")
529	if err != nil {
530		t.Errorf("expected nil error, got %v", err)
531	}
532	err = parser.parsePairFromFile2_3("ArtifactOfProjectHomePage", "http://example.com/3/")
533	if err != nil {
534		t.Errorf("expected nil error, got %v", err)
535	}
536	// Artifact set 4 -- just name and URI
537	err = parser.parsePairFromFile2_3("ArtifactOfProjectName", "project4")
538	if err != nil {
539		t.Errorf("expected nil error, got %v", err)
540	}
541	err = parser.parsePairFromFile2_3("ArtifactOfProjectURI", "http://example.com/4/uri.whatever")
542	if err != nil {
543		t.Errorf("expected nil error, got %v", err)
544	}
545
546	if len(parser.file.ArtifactOfProjects) != 4 {
547		t.Fatalf("expected len %d, got %d", 4, len(parser.file.ArtifactOfProjects))
548	}
549
550	aop := parser.file.ArtifactOfProjects[0]
551	if aop.Name != "project1" {
552		t.Errorf("expected %v, got %v", "project1", aop.Name)
553	}
554	if aop.HomePage != "http://example.com/1/" {
555		t.Errorf("expected %v, got %v", "http://example.com/1/", aop.HomePage)
556	}
557	if aop.URI != "http://example.com/1/uri.whatever" {
558		t.Errorf("expected %v, got %v", "http://example.com/1/uri.whatever", aop.URI)
559	}
560
561	aop = parser.file.ArtifactOfProjects[1]
562	if aop.Name != "project2" {
563		t.Errorf("expected %v, got %v", "project2", aop.Name)
564	}
565	if aop.HomePage != "" {
566		t.Errorf("expected %v, got %v", "", aop.HomePage)
567	}
568	if aop.URI != "" {
569		t.Errorf("expected %v, got %v", "", aop.URI)
570	}
571
572	aop = parser.file.ArtifactOfProjects[2]
573	if aop.Name != "project3" {
574		t.Errorf("expected %v, got %v", "project3", aop.Name)
575	}
576	if aop.HomePage != "http://example.com/3/" {
577		t.Errorf("expected %v, got %v", "http://example.com/3/", aop.HomePage)
578	}
579	if aop.URI != "" {
580		t.Errorf("expected %v, got %v", "", aop.URI)
581	}
582
583	aop = parser.file.ArtifactOfProjects[3]
584	if aop.Name != "project4" {
585		t.Errorf("expected %v, got %v", "project4", aop.Name)
586	}
587	if aop.HomePage != "" {
588		t.Errorf("expected %v, got %v", "", aop.HomePage)
589	}
590	if aop.URI != "http://example.com/4/uri.whatever" {
591		t.Errorf("expected %v, got %v", "http://example.com/4/uri.whatever", aop.URI)
592	}
593
594	// File Comment
595	err = parser.parsePairFromFile2_3("FileComment", "this is a comment")
596	if err != nil {
597		t.Errorf("expected nil error, got %v", err)
598	}
599	if parser.file.FileComment != "this is a comment" {
600		t.Errorf("got %v for FileComment", parser.file.FileComment)
601	}
602
603	// File Notice
604	err = parser.parsePairFromFile2_3("FileNotice", "this is a Notice")
605	if err != nil {
606		t.Errorf("expected nil error, got %v", err)
607	}
608	if parser.file.FileNotice != "this is a Notice" {
609		t.Errorf("got %v for FileNotice", parser.file.FileNotice)
610	}
611
612	// File Contributor
613	contribs := []string{
614		"John Doe [email protected]",
615		"EvilCorp",
616	}
617	for _, contrib := range contribs {
618		err = parser.parsePairFromFile2_3("FileContributor", contrib)
619		if err != nil {
620			t.Errorf("expected nil error, got %v", err)
621		}
622	}
623	for _, contribWant := range contribs {
624		flagFound := false
625		for _, contribCheck := range parser.file.FileContributors {
626			if contribWant == contribCheck {
627				flagFound = true
628			}
629		}
630		if flagFound == false {
631			t.Errorf("didn't find %s in FileContributors", contribWant)
632		}
633	}
634	if len(contribs) != len(parser.file.FileContributors) {
635		t.Errorf("expected %d contribenses in FileContributors, got %d", len(contribs),
636			len(parser.file.FileContributors))
637	}
638
639	// File Dependencies
640	deps := []string{
641		"f-1.txt",
642		"g.txt",
643	}
644	for _, dep := range deps {
645		err = parser.parsePairFromFile2_3("FileDependency", dep)
646		if err != nil {
647			t.Errorf("expected nil error, got %v", err)
648		}
649	}
650	for _, depWant := range deps {
651		flagFound := false
652		for _, depCheck := range parser.file.FileDependencies {
653			if depWant == depCheck {
654				flagFound = true
655			}
656		}
657		if flagFound == false {
658			t.Errorf("didn't find %s in FileDependency", depWant)
659		}
660	}
661	if len(deps) != len(parser.file.FileDependencies) {
662		t.Errorf("expected %d depenses in FileDependency, got %d", len(deps),
663			len(parser.file.FileDependencies))
664	}
665
666	// File Attribution Texts
667	attrs := []string{
668		"Include this notice in all advertising materials",
669		"This is a \nmulti-line string",
670	}
671	for _, attr := range attrs {
672		err = parser.parsePairFromFile2_3("FileAttributionText", attr)
673		if err != nil {
674			t.Errorf("expected nil error, got %v", err)
675		}
676	}
677	for _, attrWant := range attrs {
678		flagFound := false
679		for _, attrCheck := range parser.file.FileAttributionTexts {
680			if attrWant == attrCheck {
681				flagFound = true
682			}
683		}
684		if flagFound == false {
685			t.Errorf("didn't find %s in FileAttributionText", attrWant)
686		}
687	}
688	if len(attrs) != len(parser.file.FileAttributionTexts) {
689		t.Errorf("expected %d attribution texts in FileAttributionTexts, got %d", len(attrs),
690			len(parser.file.FileAttributionTexts))
691	}
692
693}
694
695func TestParser2_3FileCreatesRelationshipInDocument(t *testing.T) {
696	parser := tvParser2_3{
697		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
698		st:   psFile2_3,
699		pkg:  &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
700		file: &v2_3.File{FileName: "f1.txt", FileSPDXIdentifier: "f1"},
701	}
702	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
703	parser.pkg.Files = append(parser.pkg.Files, parser.file)
704
705	err := parser.parsePair2_3("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-whatever")
706	if err != nil {
707		t.Errorf("got error when calling parsePair2_3: %v", err)
708	}
709	if parser.rln == nil {
710		t.Fatalf("parser didn't create and point to Relationship struct")
711	}
712	if parser.rln != parser.doc.Relationships[0] {
713		t.Errorf("pointer to new Relationship doesn't match idx 0 for doc.Relationships[]")
714	}
715}
716
717func TestParser2_3FileCreatesAnnotationInDocument(t *testing.T) {
718	parser := tvParser2_3{
719		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
720		st:   psFile2_3,
721		pkg:  &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
722		file: &v2_3.File{FileName: "f1.txt", FileSPDXIdentifier: "f1"},
723	}
724	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
725	parser.pkg.Files = append(parser.pkg.Files, parser.file)
726
727	err := parser.parsePair2_3("Annotator", "Person: John Doe ()")
728	if err != nil {
729		t.Errorf("got error when calling parsePair2_3: %v", err)
730	}
731	if parser.ann == nil {
732		t.Fatalf("parser didn't create and point to Annotation struct")
733	}
734	if parser.ann != parser.doc.Annotations[0] {
735		t.Errorf("pointer to new Annotation doesn't match idx 0 for doc.Annotations[]")
736	}
737}
738
739func TestParser2_3FileUnknownTagFails(t *testing.T) {
740	parser := tvParser2_3{
741		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
742		st:   psFile2_3,
743		pkg:  &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
744		file: &v2_3.File{FileName: "f1.txt", FileSPDXIdentifier: "f1"},
745	}
746	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
747	parser.pkg.Files = append(parser.pkg.Files, parser.file)
748
749	err := parser.parsePairFromFile2_3("blah", "something")
750	if err == nil {
751		t.Errorf("expected error from parsing unknown tag")
752	}
753}
754
755func TestFileAOPPointerChangesAfterTags(t *testing.T) {
756	parser := tvParser2_3{
757		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
758		st:   psFile2_3,
759		pkg:  &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
760		file: &v2_3.File{FileName: "f1.txt", FileSPDXIdentifier: "f1"},
761	}
762	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
763	parser.pkg.Files = append(parser.pkg.Files, parser.file)
764
765	err := parser.parsePairFromFile2_3("ArtifactOfProjectName", "project1")
766	if err != nil {
767		t.Errorf("expected nil error, got %v", err)
768	}
769	if parser.fileAOP == nil {
770		t.Errorf("expected non-nil AOP pointer, got nil")
771	}
772	curPtr := parser.fileAOP
773
774	// now, a home page; pointer should stay
775	err = parser.parsePairFromFile2_3("ArtifactOfProjectHomePage", "http://example.com/1/")
776	if err != nil {
777		t.Errorf("expected nil error, got %v", err)
778	}
779	if parser.fileAOP != curPtr {
780		t.Errorf("expected no change in AOP pointer, was %v, got %v", curPtr, parser.fileAOP)
781	}
782
783	// a URI; pointer should stay
784	err = parser.parsePairFromFile2_3("ArtifactOfProjectURI", "http://example.com/1/uri.whatever")
785	if err != nil {
786		t.Errorf("expected nil error, got %v", err)
787	}
788	if parser.fileAOP != curPtr {
789		t.Errorf("expected no change in AOP pointer, was %v, got %v", curPtr, parser.fileAOP)
790	}
791
792	// now, another artifact name; pointer should change but be non-nil
793	// now, a home page; pointer should stay
794	err = parser.parsePairFromFile2_3("ArtifactOfProjectName", "project2")
795	if err != nil {
796		t.Errorf("expected nil error, got %v", err)
797	}
798	if parser.fileAOP == curPtr {
799		t.Errorf("expected change in AOP pointer, got no change")
800	}
801
802	// finally, an unrelated tag; pointer should go away
803	err = parser.parsePairFromFile2_3("FileComment", "whatever")
804	if err != nil {
805		t.Errorf("expected nil error, got %v", err)
806	}
807	if parser.fileAOP != nil {
808		t.Errorf("expected nil AOP pointer, got %v", parser.fileAOP)
809	}
810}
811
812func TestParser2_3FailsIfInvalidSPDXIDInFileSection(t *testing.T) {
813	parser := tvParser2_3{
814		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
815		st:  psFile2_3,
816		pkg: &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
817	}
818	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
819
820	// start with File Name
821	err := parser.parsePairFromFile2_3("FileName", "f1.txt")
822	if err != nil {
823		t.Errorf("expected nil error, got %v", err)
824	}
825	// invalid SPDX Identifier
826	err = parser.parsePairFromFile2_3("SPDXID", "whoops")
827	if err == nil {
828		t.Errorf("expected non-nil error, got nil")
829	}
830}
831
832func TestParser2_3FailsIfInvalidChecksumFormatInFileSection(t *testing.T) {
833	parser := tvParser2_3{
834		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
835		st:  psFile2_3,
836		pkg: &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
837	}
838	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
839
840	// start with File Name
841	err := parser.parsePairFromFile2_3("FileName", "f1.txt")
842	if err != nil {
843		t.Errorf("expected nil error, got %v", err)
844	}
845	// invalid format for checksum line, missing colon
846	err = parser.parsePairFromFile2_3("FileChecksum", "SHA1 85ed0817af83a24ad8da68c2b5094de69833983c")
847	if err == nil {
848		t.Errorf("expected non-nil error, got nil")
849	}
850}
851
852func TestParser2_1FailsIfUnknownChecksumTypeInFileSection(t *testing.T) {
853	parser := tvParser2_3{
854		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
855		st:  psFile2_3,
856		pkg: &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
857	}
858	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
859
860	// start with File Name
861	err := parser.parsePairFromFile2_3("FileName", "f1.txt")
862	if err != nil {
863		t.Errorf("expected nil error, got %v", err)
864	}
865	// unknown checksum type
866	err = parser.parsePairFromFile2_3("FileChecksum", "Special: 85ed0817af83a24ad8da68c2b5094de69833983c")
867	if err == nil {
868		t.Errorf("expected non-nil error, got nil")
869	}
870}
871
872func TestParser2_3FailsIfArtifactHomePageBeforeArtifactName(t *testing.T) {
873	parser := tvParser2_3{
874		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
875		st:  psFile2_3,
876		pkg: &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
877	}
878	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
879
880	// start with File Name
881	err := parser.parsePairFromFile2_3("FileName", "f1.txt")
882	if err != nil {
883		t.Errorf("expected nil error, got %v", err)
884	}
885	// artifact home page appears before artifact name
886	err = parser.parsePairFromFile2_3("ArtifactOfProjectHomePage", "https://example.com")
887	if err == nil {
888		t.Errorf("expected non-nil error, got nil")
889	}
890}
891
892func TestParser2_3FailsIfArtifactURIBeforeArtifactName(t *testing.T) {
893	parser := tvParser2_3{
894		doc: &v2_3.Document{Packages: []*v2_3.Package{}},
895		st:  psFile2_3,
896		pkg: &v2_3.Package{PackageName: "test", PackageSPDXIdentifier: "test", Files: []*v2_3.File{}},
897	}
898	parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
899
900	// start with File Name
901	err := parser.parsePairFromFile2_3("FileName", "f1.txt")
902	if err != nil {
903		t.Errorf("expected nil error, got %v", err)
904	}
905	// artifact home page appears before artifact name
906	err = parser.parsePairFromFile2_3("ArtifactOfProjectURI", "https://example.com")
907	if err == nil {
908		t.Errorf("expected non-nil error, got nil")
909	}
910}
911
912func TestParser2_3FilesWithoutSpdxIdThrowError(t *testing.T) {
913	// case 1: The previous file (packaged or unpackaged) does not contain spdx ID
914	parser1 := tvParser2_3{
915		doc:  &v2_3.Document{Packages: []*v2_3.Package{}},
916		st:   psFile2_3,
917		file: &v2_3.File{FileName: "FileName"},
918	}
919
920	err := parser1.parsePair2_3("FileName", "f2")
921	if err == nil {
922		t.Errorf("file without SPDX Identifier getting accepted")
923	}
924
925	// case 2: Invalid file with snippet
926	// Last unpackaged file before the snippet start
927	fileName := "f2.txt"
928	sid1 := common.ElementID("s1")
929	parser2 := tvParser2_3{
930		doc:  &v2_3.Document{},
931		st:   psCreationInfo2_3,
932		file: &v2_3.File{FileName: fileName},
933	}
934	err = parser2.parsePair2_3("SnippetSPDXID", string(sid1))
935	if err == nil {
936		t.Errorf("file without SPDX Identifier getting accepted")
937	}
938
939	// case 3: Invalid File without snippets
940	// Last unpackaged file before the package starts
941	// Last file of a package and New package starts
942	parser3 := tvParser2_3{
943		doc: &v2_3.Document{},
944		st:  psCreationInfo2_3,
945	}
946	fileName = "f3.txt"
947	err = parser3.parsePair2_3("FileName", fileName)
948	if err != nil {
949		t.Errorf("%s", err)
950	}
951	err = parser3.parsePair2_3("PackageName", "p2")
952	if err == nil {
953		t.Errorf("file without SPDX Identifier getting accepted")
954	}
955}
956