diff options
author | Steve Winslow <steve@swinslow.net> | 2020-05-09 18:24:20 -0400 |
---|---|---|
committer | Steve Winslow <steve@swinslow.net> | 2020-05-09 18:24:20 -0400 |
commit | 1500a6e983917e450f8da95b86418d8db3af926f (patch) | |
tree | d10dd12102f2f11e115b726865fda86ea27982e0 | |
parent | 4a8bcf1883c3547f2efb6af5a2f002293117c45b (diff) | |
download | spdx-tools-1500a6e983917e450f8da95b86418d8db3af926f.tar.gz |
Refactor parser to handle element ID maps
Signed-off-by: Steve Winslow <steve@swinslow.net>
27 files changed, 864 insertions, 663 deletions
diff --git a/builder/build_test.go b/builder/build_test.go index 48e5047..d7d47b7 100644 --- a/builder/build_test.go +++ b/builder/build_test.go @@ -73,9 +73,6 @@ func TestBuild2_1CreatesDocument(t *testing.T) { t.Fatalf("expected %d, got %d", 1, len(doc.Packages)) } pkg := doc.Packages[0] - if pkg.IsUnpackaged { - t.Errorf("expected %v, got %v", false, pkg.IsUnpackaged) - } if pkg.PackageName != "project1" { t.Errorf("expected %v, got %v", "project1", pkg.PackageName) } diff --git a/builder/builder2v1/build_package.go b/builder/builder2v1/build_package.go index d2f0ec9..3cefe5c 100644 --- a/builder/builder2v1/build_package.go +++ b/builder/builder2v1/build_package.go @@ -41,7 +41,6 @@ func BuildPackageSection2_1(packageName string, dirRoot string, pathsIgnore []st // now build the package section pkg := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: packageName, PackageSPDXIdentifier: fmt.Sprintf("SPDXRef-Package-%s", packageName), PackageDownloadLocation: "NOASSERTION", diff --git a/builder/builder2v1/build_package_test.go b/builder/builder2v1/build_package_test.go index 68aa5b5..42e4e47 100644 --- a/builder/builder2v1/build_package_test.go +++ b/builder/builder2v1/build_package_test.go @@ -21,9 +21,6 @@ func TestBuilder2_1CanBuildPackageSection(t *testing.T) { if pkg == nil { t.Fatalf("expected non-nil Package, got nil") } - if pkg.IsUnpackaged { - t.Errorf("expected %v, got %v", false, pkg.IsUnpackaged) - } if pkg.PackageName != "project1" { t.Errorf("expected %v, got %v", "project1", pkg.PackageName) } diff --git a/licensediff/licensediff_test.go b/licensediff/licensediff_test.go index 4dedc58..33f65f7 100644 --- a/licensediff/licensediff_test.go +++ b/licensediff/licensediff_test.go @@ -118,7 +118,6 @@ func TestDifferCanCreateDiffPairs(t *testing.T) { // create Packages p1 := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: "p1", PackageSPDXIdentifier: "SPDXRef-p1", PackageDownloadLocation: "NOASSERTION", @@ -141,7 +140,6 @@ func TestDifferCanCreateDiffPairs(t *testing.T) { }, } p2 := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: "p2", PackageSPDXIdentifier: "SPDXRef-p2", PackageDownloadLocation: "NOASSERTION", @@ -359,7 +357,6 @@ func TestDifferCanCreateDiffStructuredResults(t *testing.T) { // create Packages p1 := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: "p1", PackageSPDXIdentifier: "SPDXRef-p1", PackageDownloadLocation: "NOASSERTION", @@ -382,7 +379,6 @@ func TestDifferCanCreateDiffStructuredResults(t *testing.T) { }, } p2 := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: "p2", PackageSPDXIdentifier: "SPDXRef-p2", PackageDownloadLocation: "NOASSERTION", diff --git a/spdx/document.go b/spdx/document.go index d2e9e13..2541ec4 100644 --- a/spdx/document.go +++ b/spdx/document.go @@ -6,11 +6,12 @@ package spdx // Document2_1 is an SPDX Document for version 2.1 of the spec. // See https://spdx.org/sites/cpstandard/files/pages/files/spdxversion2.1.pdf type Document2_1 struct { - CreationInfo *CreationInfo2_1 - Packages map[ElementID]*Package2_1 - OtherLicenses []*OtherLicense2_1 - Relationships []*Relationship2_1 - Annotations []*Annotation2_1 + CreationInfo *CreationInfo2_1 + Packages map[ElementID]*Package2_1 + UnpackagedFiles map[ElementID]*File2_1 + OtherLicenses []*OtherLicense2_1 + Relationships []*Relationship2_1 + Annotations []*Annotation2_1 // DEPRECATED in version 2.0 of spec Reviews []*Review2_1 diff --git a/spdx/file.go b/spdx/file.go index 91e40d1..f7c1b42 100644 --- a/spdx/file.go +++ b/spdx/file.go @@ -62,8 +62,10 @@ type File2_1 struct { FileDependencies []string // Snippets contained in this File - // Note that Snippets could be defined in a different Document! - Snippets map[DocElementID]*Snippet2_1 + // Note that Snippets could be defined in a different Document! However, + // the only ones that _THIS_ document can contain are this ones that are + // defined here -- so this should just be an ElementID. + Snippets map[ElementID]*Snippet2_1 } // ArtifactOfProject2_1 is a DEPRECATED collection of data regarding diff --git a/spdx/package.go b/spdx/package.go index 989e2de..40d0c3c 100644 --- a/spdx/package.go +++ b/spdx/package.go @@ -5,11 +5,6 @@ package spdx // Package2_1 is a Package section of an SPDX Document for version 2.1 of the spec. type Package2_1 struct { - // NOT PART OF SPEC - // flag: does this "package" contain files that were in fact "unpackaged", - // e.g. included directly in the Document without being in a Package? - IsUnpackaged bool - // 3.1: Package Name // Cardinality: mandatory, one PackageName string diff --git a/tvloader/parser2v1/parse_annotation.go b/tvloader/parser2v1/parse_annotation.go index f83d5bb..65680d9 100644 --- a/tvloader/parser2v1/parse_annotation.go +++ b/tvloader/parser2v1/parse_annotation.go @@ -28,7 +28,11 @@ func (parser *tvParser2_1) parsePairForAnnotation2_1(tag string, value string) e case "AnnotationType": parser.ann.AnnotationType = value case "SPDXREF": - parser.ann.AnnotationSPDXIdentifier = value + deID, err := extractDocElementID(value) + if err != nil { + return err + } + parser.ann.AnnotationSPDXIdentifier = deID case "AnnotationComment": parser.ann.AnnotationComment = value default: diff --git a/tvloader/parser2v1/parse_annotation_test.go b/tvloader/parser2v1/parse_annotation_test.go index 9e53b2d..b66026f 100644 --- a/tvloader/parser2v1/parse_annotation_test.go +++ b/tvloader/parser2v1/parse_annotation_test.go @@ -86,8 +86,9 @@ func TestParser2_1CanParseAnnotationTags(t *testing.T) { if err != nil { t.Errorf("expected nil error, got %v", err) } - if parser.ann.AnnotationSPDXIdentifier != ref { - t.Errorf("got %v for SPDXREF, expected %v", parser.ann.AnnotationSPDXIdentifier, ref) + deID := parser.ann.AnnotationSPDXIdentifier + if deID.DocumentRefID != "" || deID.ElementRefID != "30" { + t.Errorf("got %v for SPDXREF, expected %v", parser.ann.AnnotationSPDXIdentifier, "30") } // Annotation Comment diff --git a/tvloader/parser2v1/parse_creation_info.go b/tvloader/parser2v1/parse_creation_info.go index f29fe12..b02b5c0 100644 --- a/tvloader/parser2v1/parse_creation_info.go +++ b/tvloader/parser2v1/parse_creation_info.go @@ -26,7 +26,7 @@ func (parser *tvParser2_1) parsePairFromCreationInfo2_1(tag string, value string case "DataLicense": ci.DataLicense = value case "SPDXID": - ci.SPDXIdentifier = value + ci.SPDXIdentifier = spdx.ElementID(value) case "DocumentName": ci.DocumentName = value case "DocumentNamespace": @@ -61,22 +61,15 @@ func (parser *tvParser2_1) parsePairFromCreationInfo2_1(tag string, value string case "PackageName": parser.st = psPackage2_1 parser.pkg = &spdx.Package2_1{ - IsUnpackaged: false, FilesAnalyzed: true, IsFilesAnalyzedTagPresent: false, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) return parser.parsePairFromPackage2_1(tag, value) // tag for going on to _unpackaged_ file section case "FileName": - // create an "unpackaged" Package structure + // leave pkg as nil, so that packages will be placed in UnpackagedFiles parser.st = psFile2_1 - parser.pkg = &spdx.Package2_1{ - IsUnpackaged: true, - FilesAnalyzed: true, - IsFilesAnalyzedTagPresent: false, - } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.pkg = nil return parser.parsePairFromFile2_1(tag, value) // tag for going on to other license section case "LicenseID": diff --git a/tvloader/parser2v1/parse_creation_info_test.go b/tvloader/parser2v1/parse_creation_info_test.go index ea63dbc..64eae0b 100644 --- a/tvloader/parser2v1/parse_creation_info_test.go +++ b/tvloader/parser2v1/parse_creation_info_test.go @@ -30,10 +30,6 @@ func TestParser2_1CIMovesToPackageAfterParsingPackageNameTag(t *testing.T) { if parser.pkg.PackageName != pkgName { t.Errorf("expected package name %s, got %s", pkgName, parser.pkg.PackageName) } - // and the package should _not_ be an "unpackaged" placeholder - if parser.pkg.IsUnpackaged == true { - t.Errorf("package incorrectly has IsUnpackaged flag set") - } // and the package should default to true for FilesAnalyzed if parser.pkg.FilesAnalyzed != true { t.Errorf("expected FilesAnalyzed to default to true, got false") @@ -41,19 +37,14 @@ func TestParser2_1CIMovesToPackageAfterParsingPackageNameTag(t *testing.T) { if parser.pkg.IsFilesAnalyzedTagPresent != false { t.Errorf("expected IsFilesAnalyzedTagPresent to default to false, got true") } - // and the package should be in the SPDX Document's slice of packages - flagFound := false - for _, p := range parser.doc.Packages { - if p == parser.pkg { - flagFound = true - } - } - if flagFound == false { - t.Errorf("package isn't in the SPDX Document's slice of packages") + // and the package should NOT be in the SPDX Document's map of packages, + // because it doesn't have an SPDX identifier yet + if len(parser.doc.Packages) != 0 { + t.Errorf("expected 0 packages, got %d", len(parser.doc.Packages)) } } -func TestParser2_1CIMovesToFileAfterParsingFileNameTag(t *testing.T) { +func TestParser2_1CIMovesToFileAfterParsingFileNameTagWithNoPackages(t *testing.T) { parser := tvParser2_1{ doc: &spdx.Document2_1{}, st: psCreationInfo2_1, @@ -66,29 +57,10 @@ func TestParser2_1CIMovesToFileAfterParsingFileNameTag(t *testing.T) { if parser.st != psFile2_1 { t.Errorf("parser is in state %v, expected %v", parser.st, psFile2_1) } - // and current package should be an "unpackaged" placeholder - if parser.pkg == nil { - t.Fatalf("parser didn't create placeholder package") - } - if !parser.pkg.IsUnpackaged { - t.Errorf("placeholder package is not set as unpackaged") - } - // and the package should default to true for FilesAnalyzed - if parser.pkg.FilesAnalyzed != true { - t.Errorf("expected FilesAnalyzed to default to true, got false") - } - if parser.pkg.IsFilesAnalyzedTagPresent != false { - t.Errorf("expected IsFilesAnalyzedTagPresent to default to false, got true") - } - // and the package should be in the SPDX Document's slice of packages - flagFound := false - for _, p := range parser.doc.Packages { - if p == parser.pkg { - flagFound = true - } - } - if flagFound == false { - t.Errorf("package isn't in the SPDX Document's slice of packages") + // and current package should be nil, meaning Files are placed in the + // UnpackagedFiles map instead of in a Package + if parser.pkg != nil { + t.Fatalf("expected pkg to be nil, got non-nil pkg") } } @@ -126,7 +98,7 @@ func TestParser2_1CIStaysAfterParsingRelationshipTags(t *testing.T) { st: psCreationInfo2_1, } - err := parser.parsePair2_1("Relationship", "blah CONTAINS blah-else") + err := parser.parsePair2_1("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-else") if err != nil { t.Errorf("got error when calling parsePair2_1: %v", err) } @@ -417,7 +389,7 @@ func TestParser2_1CICreatesRelationship(t *testing.T) { st: psCreationInfo2_1, } - err := parser.parsePair2_1("Relationship", "blah CONTAINS blah-whatever") + err := parser.parsePair2_1("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-whatever") if err != nil { t.Errorf("got error when calling parsePair2_1: %v", err) } diff --git a/tvloader/parser2v1/parse_file.go b/tvloader/parser2v1/parse_file.go index 449b4ae..efe31d9 100644 --- a/tvloader/parser2v1/parse_file.go +++ b/tvloader/parser2v1/parse_file.go @@ -19,7 +19,6 @@ func (parser *tvParser2_1) parsePairFromFile2_1(tag string, value string) error // tag for creating new file section case "FileName": parser.file = &spdx.File2_1{} - parser.pkg.Files = append(parser.pkg.Files, parser.file) parser.file.FileName = value // tag for creating new package section and going back to parsing Package case "PackageName": @@ -36,7 +35,22 @@ func (parser *tvParser2_1) parsePairFromFile2_1(tag string, value string) error return parser.parsePairFromOtherLicense2_1(tag, value) // tags for file data case "SPDXID": - parser.file.FileSPDXIdentifier = value + eID, err := extractElementID(value) + if err != nil { + return err + } + parser.file.FileSPDXIdentifier = eID + if parser.pkg == nil { + if parser.doc.UnpackagedFiles == nil { + parser.doc.UnpackagedFiles = map[spdx.ElementID]*spdx.File2_1{} + } + parser.doc.UnpackagedFiles[eID] = parser.file + } else { + if parser.pkg.Files == nil { + parser.pkg.Files = map[spdx.ElementID]*spdx.File2_1{} + } + parser.pkg.Files[eID] = parser.file + } case "FileType": parser.file.FileType = append(parser.file.FileType, value) case "FileChecksum": diff --git a/tvloader/parser2v1/parse_file_test.go b/tvloader/parser2v1/parse_file_test.go index 9aef1ea..8b48cec 100644 --- a/tvloader/parser2v1/parse_file_test.go +++ b/tvloader/parser2v1/parse_file_test.go @@ -13,20 +13,23 @@ func TestParser2_1FileStartsNewFileAfterParsingFileNameTag(t *testing.T) { fileOldName := "f1.txt" parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: fileOldName}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: fileOldName, FileSPDXIdentifier: "f1"}, } fileOld := parser.file - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, fileOld) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = fileOld // the Package's Files should have this one only - if parser.pkg.Files[0] != fileOld { - t.Errorf("Expected file %v in Files[0], got %v", fileOld, parser.pkg.Files[0]) + if len(parser.pkg.Files) != 1 { + t.Fatalf("expected 1 file, got %d", len(parser.pkg.Files)) } - if parser.pkg.Files[0].FileName != fileOldName { - t.Errorf("expected file name %s in Files[0], got %s", fileOldName, parser.pkg.Files[0].FileName) + if parser.pkg.Files["f1"] != fileOld { + t.Errorf("expected file %v in Files[f1], got %v", fileOld, parser.pkg.Files["f1"]) + } + if parser.pkg.Files["f1"].FileName != fileOldName { + t.Errorf("expected file name %s in Files[f1], got %s", fileOldName, parser.pkg.Files["f1"].FileName) } // now add a new file @@ -47,18 +50,96 @@ func TestParser2_1FileStartsNewFileAfterParsingFileNameTag(t *testing.T) { if parser.file.FileName != fileName { t.Errorf("expected file name %s, got %s", fileName, parser.file.FileName) } - // and the Package's Files should be of size 2 and have these two - if parser.pkg.Files[0] != fileOld { - t.Errorf("Expected file %v in Files[0], got %v", fileOld, parser.pkg.Files[0]) + // and the Package's Files should still be of size 1 and not have this new + // one yet, since it hasn't seen an SPDX identifier + if len(parser.pkg.Files) != 1 { + t.Fatalf("expected 1 file, got %d", len(parser.pkg.Files)) + } + if parser.pkg.Files["f1"] != fileOld { + t.Errorf("expected file %v in Files[f1], got %v", fileOld, parser.pkg.Files["f1"]) + } + if parser.pkg.Files["f1"].FileName != fileOldName { + t.Errorf("expected file name %s in Files[f1], got %s", fileOldName, parser.pkg.Files["f1"].FileName) + } + + // now parse an SPDX identifier tag + err = parser.parsePair2_1("SPDXID", "SPDXRef-f2ID") + if err != nil { + t.Errorf("got error when calling parsePair2_1: %v", err) + } + // and the Package's Files should now be of size 2 and have this new one + if len(parser.pkg.Files) != 2 { + t.Fatalf("expected 2 files, got %d", len(parser.pkg.Files)) + } + if parser.pkg.Files["f1"] != fileOld { + t.Errorf("expected file %v in Files[f1], got %v", fileOld, parser.pkg.Files["f1"]) + } + if parser.pkg.Files["f1"].FileName != fileOldName { + t.Errorf("expected file name %s in Files[f1], got %s", fileOldName, parser.pkg.Files["f1"].FileName) + } + if parser.pkg.Files["f2ID"] != parser.file { + t.Errorf("expected file %v in Files[f2ID], got %v", parser.file, parser.pkg.Files["f2ID"]) + } + if parser.pkg.Files["f2ID"].FileName != fileName { + t.Errorf("expected file name %s in Files[f2ID], got %s", fileName, parser.pkg.Files["f2ID"].FileName) + } +} + +func TestParser2_1FileAddsToPackageOrUnpackagedFiles(t *testing.T) { + // start with no packages + parser := tvParser2_1{ + doc: &spdx.Document2_1{}, + st: psCreationInfo2_1, + } + + // add a file and SPDX identifier + fileName := "f2.txt" + err := parser.parsePair2_1("FileName", fileName) + if err != nil { + t.Errorf("got error when calling parsePair2_1: %v", err) + } + err = parser.parsePair2_1("SPDXID", "SPDXRef-f2ID") + if err != nil { + t.Errorf("got error when calling parsePair2_1: %v", err) + } + fileOld := parser.file + // should have been added to UnpackagedFiles + if len(parser.doc.UnpackagedFiles) != 1 { + t.Fatalf("expected 1 file in UnpackagedFiles, got %d", len(parser.doc.UnpackagedFiles)) + } + if parser.doc.UnpackagedFiles["f2ID"] != fileOld { + t.Errorf("expected file %v in UnpackagedFiles[f2ID], got %v", fileOld, parser.doc.UnpackagedFiles["f2ID"]) + } + // now create a package and a new file + err = parser.parsePair2_1("PackageName", "package1") + if err != nil { + t.Errorf("got error when calling parsePair2_1: %v", err) + } + err = parser.parsePair2_1("SPDXID", "SPDXRef-pkg1") + if err != nil { + t.Errorf("got error when calling parsePair2_1: %v", err) + } + err = parser.parsePair2_1("FileName", "f3.txt") + if err != nil { + t.Errorf("got error when calling parsePair2_1: %v", err) + } + err = parser.parsePair2_1("SPDXID", "SPDXRef-f3ID") + if err != nil { + t.Errorf("got error when calling parsePair2_1: %v", err) + } + // UnpackagedFiles should still be size 1 and have old file only + if len(parser.doc.UnpackagedFiles) != 1 { + t.Fatalf("expected 1 file in UnpackagedFiles, got %d", len(parser.doc.UnpackagedFiles)) } - if parser.pkg.Files[0].FileName != fileOldName { - t.Errorf("expected file name %s in Files[0], got %s", fileOldName, parser.pkg.Files[0].FileName) + if parser.doc.UnpackagedFiles["f2ID"] != fileOld { + t.Errorf("expected file %v in UnpackagedFiles[f2ID], got %v", fileOld, parser.doc.UnpackagedFiles["f2ID"]) } - if parser.pkg.Files[1] != parser.file { - t.Errorf("Expected file %v in Files[1], got %v", parser.file, parser.pkg.Files[1]) + // and new package should have gotten the new file + if len(parser.pkg.Files) != 1 { + t.Fatalf("expected 1 file in Files, got %d", len(parser.pkg.Files)) } - if parser.pkg.Files[1].FileName != fileName { - t.Errorf("expected file name %s in Files[1], got %s", fileName, parser.pkg.Files[1].FileName) + if parser.pkg.Files["f3ID"] != parser.file { + t.Errorf("expected file %v in Files[f3ID], got %v", parser.file, parser.pkg.Files["f3ID"]) } } @@ -68,15 +149,15 @@ func TestParser2_1FileStartsNewPackageAfterParsingPackageNameTag(t *testing.T) { f1Name := "f1.txt" parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: p1Name}, - file: &spdx.File2_1{FileName: f1Name}, + pkg: &spdx.Package2_1{PackageName: p1Name, PackageSPDXIdentifier: "package1", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: f1Name, FileSPDXIdentifier: "f1"}, } p1 := parser.pkg f1 := parser.file - parser.doc.Packages = append(parser.doc.Packages, p1) - parser.pkg.Files = append(parser.pkg.Files, f1) + parser.doc.Packages["package1"] = p1 + parser.pkg.Files["f1"] = f1 // now add a new package p2Name := "package2" @@ -103,36 +184,30 @@ func TestParser2_1FileStartsNewPackageAfterParsingPackageNameTag(t *testing.T) { if parser.pkg.IsFilesAnalyzedTagPresent != false { t.Errorf("expected IsFilesAnalyzedTagPresent to default to false, got true") } - // and the package should _not_ be an "unpackaged" placeholder - if parser.pkg.IsUnpackaged == true { - t.Errorf("package incorrectly has IsUnpackaged flag set") + // and the new Package should have no files + if len(parser.pkg.Files) != 0 { + t.Errorf("Expected no files in pkg.Files, got %d", len(parser.pkg.Files)) } - // and the Document's Packages should be of size 2 and have these two - if parser.doc.Packages[0] != p1 { - t.Errorf("Expected package %v in Packages[0], got %v", p1, parser.doc.Packages[0]) + // and the Document's Packages should still be of size 1 and not have this + // new one, because no SPDX identifier has been seen yet + if len(parser.doc.Packages) != 1 { + t.Fatalf("expected 1 package, got %d", len(parser.doc.Packages)) } - if parser.doc.Packages[0].PackageName != p1Name { - t.Errorf("expected package name %s in Packages[0], got %s", p1Name, parser.doc.Packages[0].PackageName) + if parser.doc.Packages["package1"] != p1 { + t.Errorf("Expected package %v in Packages[package1], got %v", p1, parser.doc.Packages["package1"]) } - if parser.doc.Packages[1] != parser.pkg { - t.Errorf("Expected package %v in Packages[1], got %v", parser.pkg, parser.doc.Packages[1]) - } - if parser.doc.Packages[1].PackageName != p2Name { - t.Errorf("expected package name %s in Packages[1], got %s", p2Name, parser.doc.Packages[1].PackageName) + if parser.doc.Packages["package1"].PackageName != p1Name { + t.Errorf("expected package name %s in Packages[package1], got %s", p1Name, parser.doc.Packages["package1"].PackageName) } // and the first Package's Files should be of size 1 and have f1 only - if len(parser.doc.Packages[0].Files) != 1 { - t.Errorf("Expected 1 file in Packages[0].Files, got %d", len(parser.doc.Packages[0].Files)) - } - if parser.doc.Packages[0].Files[0] != f1 { - t.Errorf("Expected file %v in Files[0], got %v", f1, parser.doc.Packages[0].Files[0]) + if len(parser.doc.Packages["package1"].Files) != 1 { + t.Errorf("Expected 1 file in Packages[package1].Files, got %d", len(parser.doc.Packages["package1"].Files)) } - if parser.doc.Packages[0].Files[0].FileName != f1Name { - t.Errorf("expected file name %s in Files[0], got %s", f1Name, parser.doc.Packages[0].Files[0].FileName) + if parser.doc.Packages["package1"].Files["f1"] != f1 { + t.Errorf("Expected file %v in Files[f1], got %v", f1, parser.doc.Packages["package1"].Files["f1"]) } - // and the second Package should have no files - if len(parser.doc.Packages[1].Files) != 0 { - t.Errorf("Expected no files in Packages[1].Files, got %d", len(parser.doc.Packages[1].Files)) + if parser.doc.Packages["package1"].Files["f1"].FileName != f1Name { + t.Errorf("expected file name %s in Files[f1], got %s", f1Name, parser.doc.Packages["package1"].Files["f1"].FileName) } // and the current file should be nil if parser.file != nil { @@ -142,13 +217,13 @@ func TestParser2_1FileStartsNewPackageAfterParsingPackageNameTag(t *testing.T) { func TestParser2_1FileMovesToSnippetAfterParsingSnippetSPDXIDTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file fileCurrent := parser.file err := parser.parsePair2_1("SnippetSPDXID", "SPDXRef-Test1") @@ -167,13 +242,13 @@ func TestParser2_1FileMovesToSnippetAfterParsingSnippetSPDXIDTag(t *testing.T) { func TestParser2_1FileMovesToOtherLicenseAfterParsingLicenseIDTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file err := parser.parsePair2_1("LicenseID", "LicenseRef-TestLic") if err != nil { @@ -186,13 +261,13 @@ func TestParser2_1FileMovesToOtherLicenseAfterParsingLicenseIDTag(t *testing.T) func TestParser2_1FileMovesToReviewAfterParsingReviewerTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file err := parser.parsePair2_1("Reviewer", "Person: John Doe") if err != nil { @@ -205,15 +280,15 @@ func TestParser2_1FileMovesToReviewAfterParsingReviewerTag(t *testing.T) { func TestParser2_1FileStaysAfterParsingRelationshipTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file - err := parser.parsePair2_1("Relationship", "blah CONTAINS blah-else") + err := parser.parsePair2_1("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-else") if err != nil { t.Errorf("got error when calling parsePair2_1: %v", err) } @@ -234,13 +309,13 @@ func TestParser2_1FileStaysAfterParsingRelationshipTags(t *testing.T) { func TestParser2_1FileStaysAfterParsingAnnotationTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file err := parser.parsePair2_1("Annotator", "Person: John Doe ()") if err != nil { @@ -286,12 +361,11 @@ func TestParser2_1FileStaysAfterParsingAnnotationTags(t *testing.T) { // ===== File data section tests ===== func TestParser2_1CanParseFileTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg // File Name err := parser.parsePairFromFile2_1("FileName", "f1.txt") @@ -301,15 +375,27 @@ func TestParser2_1CanParseFileTags(t *testing.T) { if parser.file.FileName != "f1.txt" { t.Errorf("got %v for FileName", parser.file.FileName) } + // should not yet be added to the Packages file list, because we haven't + // seen an SPDX identifier yet + if len(parser.pkg.Files) != 0 { + t.Errorf("expected 0 files, got %d", len(parser.pkg.Files)) + } // File SPDX Identifier err = parser.parsePairFromFile2_1("SPDXID", "SPDXRef-f1") if err != nil { t.Errorf("expected nil error, got %v", err) } - if parser.file.FileSPDXIdentifier != "SPDXRef-f1" { + if parser.file.FileSPDXIdentifier != "f1" { t.Errorf("got %v for FileSPDXIdentifier", parser.file.FileSPDXIdentifier) } + // should now be added to the Packages file list + if len(parser.pkg.Files) != 1 { + t.Errorf("expected 1 file, got %d", len(parser.pkg.Files)) + } + if parser.pkg.Files["f1"] != parser.file { + t.Errorf("expected Files[f1] to be %v, got %v", parser.file, parser.pkg.Files["f1"]) + } // File Type fileTypes := []string{ @@ -584,15 +670,15 @@ func TestParser2_1CanParseFileTags(t *testing.T) { func TestParser2_1FileCreatesRelationshipInDocument(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file - err := parser.parsePair2_1("Relationship", "blah CONTAINS blah-whatever") + err := parser.parsePair2_1("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-whatever") if err != nil { t.Errorf("got error when calling parsePair2_1: %v", err) } @@ -606,13 +692,13 @@ func TestParser2_1FileCreatesRelationshipInDocument(t *testing.T) { func TestParser2_1FileCreatesAnnotationInDocument(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file err := parser.parsePair2_1("Annotator", "Person: John Doe ()") if err != nil { @@ -628,13 +714,13 @@ func TestParser2_1FileCreatesAnnotationInDocument(t *testing.T) { func TestParser2_1FileUnknownTagFails(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file err := parser.parsePairFromFile2_1("blah", "something") if err == nil { @@ -644,13 +730,13 @@ func TestParser2_1FileUnknownTagFails(t *testing.T) { func TestFileAOPPointerChangesAfterTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file err := parser.parsePairFromFile2_1("ArtifactOfProjectName", "project1") if err != nil { diff --git a/tvloader/parser2v1/parse_other_license_test.go b/tvloader/parser2v1/parse_other_license_test.go index 7d004de..d97eb1c 100644 --- a/tvloader/parser2v1/parse_other_license_test.go +++ b/tvloader/parser2v1/parse_other_license_test.go @@ -14,18 +14,18 @@ func TestParser2_1OLStartsNewOtherLicenseAfterParsingLicenseIDTag(t *testing.T) olname1 := "License 11" parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psOtherLicense2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: olid1, LicenseName: olname1, }, } olic1 := parser.otherLic - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) // the Document's OtherLicenses should have this one only @@ -90,13 +90,13 @@ func TestParser2_1OLStartsNewOtherLicenseAfterParsingLicenseIDTag(t *testing.T) func TestParser2_1OLMovesToReviewAfterParsingReviewerTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psOtherLicense2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) err := parser.parsePair2_1("Reviewer", "Person: John Doe") @@ -110,20 +110,20 @@ func TestParser2_1OLMovesToReviewAfterParsingReviewerTag(t *testing.T) { func TestParser2_1OtherLicenseStaysAfterParsingRelationshipTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psOtherLicense2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-whatever", LicenseName: "the whatever license", }, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) - err := parser.parsePair2_1("Relationship", "blah CONTAINS blah-else") + err := parser.parsePair2_1("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-else") if err != nil { t.Errorf("got error when calling parsePair2_1: %v", err) } @@ -135,7 +135,8 @@ func TestParser2_1OtherLicenseStaysAfterParsingRelationshipTags(t *testing.T) { if len(parser.doc.Relationships) != 1 { t.Fatalf("expected doc.Relationships to have len 1, got %d", len(parser.doc.Relationships)) } - if parser.doc.Relationships[0].RefA != "blah" { + deID := parser.doc.Relationships[0].RefA + if deID.DocumentRefID != "" || deID.ElementRefID != "blah" { t.Errorf("expected RefA to be %s, got %s", "blah", parser.doc.Relationships[0].RefA) } @@ -151,17 +152,17 @@ func TestParser2_1OtherLicenseStaysAfterParsingRelationshipTags(t *testing.T) { func TestParser2_1OtherLicenseStaysAfterParsingAnnotationTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psOtherLicense2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-whatever", LicenseName: "the whatever license", }, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) err := parser.parsePair2_1("Annotator", "Person: John Doe ()") @@ -215,17 +216,17 @@ func TestParser2_1OtherLicenseStaysAfterParsingAnnotationTags(t *testing.T) { func TestParser2_1OLFailsAfterParsingOtherSectionTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psOtherLicense2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-Lic11", LicenseName: "License 11", }, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) // can't go back to old sections @@ -246,13 +247,13 @@ func TestParser2_1OLFailsAfterParsingOtherSectionTags(t *testing.T) { // ===== Other License data section tests ===== func TestParser2_1CanParseOtherLicenseTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psOtherLicense2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) // License Identifier @@ -322,13 +323,13 @@ func TestParser2_1CanParseOtherLicenseTags(t *testing.T) { func TestParser2_1OLUnknownTagFails(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psOtherLicense2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) err := parser.parsePairFromOtherLicense2_1("blah", "something") diff --git a/tvloader/parser2v1/parse_package.go b/tvloader/parser2v1/parse_package.go index 1d04861..4c908be 100644 --- a/tvloader/parser2v1/parse_package.go +++ b/tvloader/parser2v1/parse_package.go @@ -19,13 +19,11 @@ func (parser *tvParser2_1) parsePairFromPackage2_1(tag string, value string) err switch tag { case "PackageName": // if package already has a name, create and go on to a new package - if parser.pkg.PackageName != "" || parser.pkg.IsUnpackaged == true { + if parser.pkg == nil || parser.pkg.PackageName != "" { parser.pkg = &spdx.Package2_1{ - IsUnpackaged: false, FilesAnalyzed: true, IsFilesAnalyzedTagPresent: false, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) } parser.pkg.PackageName = value // tag for going on to file section @@ -37,7 +35,15 @@ func (parser *tvParser2_1) parsePairFromPackage2_1(tag string, value string) err parser.st = psOtherLicense2_1 return parser.parsePairFromOtherLicense2_1(tag, value) case "SPDXID": - parser.pkg.PackageSPDXIdentifier = value + eID, err := extractElementID(value) + if err != nil { + return err + } + parser.pkg.PackageSPDXIdentifier = eID + if parser.doc.Packages == nil { + parser.doc.Packages = map[spdx.ElementID]*spdx.Package2_1{} + } + parser.doc.Packages[eID] = parser.pkg case "PackageVersion": parser.pkg.PackageVersion = value case "PackageFileName": diff --git a/tvloader/parser2v1/parse_package_test.go b/tvloader/parser2v1/parse_package_test.go index bba6070..b4b37f6 100644 --- a/tvloader/parser2v1/parse_package_test.go +++ b/tvloader/parser2v1/parse_package_test.go @@ -13,18 +13,18 @@ func TestParser2_1PackageStartsNewPackageAfterParsingPackageNameTag(t *testing.T pkgOldName := "p1" parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: pkgOldName}, + pkg: &spdx.Package2_1{PackageName: pkgOldName, PackageSPDXIdentifier: "p1"}, } pkgOld := parser.pkg - parser.doc.Packages = append(parser.doc.Packages, pkgOld) + parser.doc.Packages["p1"] = pkgOld // the Document's Packages should have this one only - if parser.doc.Packages[0] != pkgOld { - t.Errorf("Expected package %v in Packages[0], got %v", pkgOld, parser.doc.Packages[0]) + if parser.doc.Packages["p1"] != pkgOld { + t.Errorf("expected package %v, got %v", pkgOld, parser.doc.Packages["p1"]) } - if parser.doc.Packages[0].PackageName != pkgOldName { - t.Errorf("expected package name %s in Packages[0], got %s", pkgOldName, parser.doc.Packages[0].PackageName) + if len(parser.doc.Packages) != 1 { + t.Errorf("expected 1 package, got %d", len(parser.doc.Packages)) } // now add a new package @@ -41,6 +41,10 @@ func TestParser2_1PackageStartsNewPackageAfterParsingPackageNameTag(t *testing.T if parser.pkg == nil { t.Fatalf("parser didn't create new package") } + // and it should not be pkgOld + if parser.pkg == pkgOld { + t.Errorf("expected new package, got pkgOld") + } // and the package name should be as expected if parser.pkg.PackageName != pkgName { t.Errorf("expected package name %s, got %s", pkgName, parser.pkg.PackageName) @@ -52,41 +56,26 @@ func TestParser2_1PackageStartsNewPackageAfterParsingPackageNameTag(t *testing.T if parser.pkg.IsFilesAnalyzedTagPresent != false { t.Errorf("expected IsFilesAnalyzedTagPresent to default to false, got true") } - // and the package should _not_ be an "unpackaged" placeholder - if parser.pkg.IsUnpackaged == true { - t.Errorf("package incorrectly has IsUnpackaged flag set") - } - // and the Document's Packages should be of size 2 and have these two - if parser.doc.Packages[0] != pkgOld { - t.Errorf("Expected package %v in Packages[0], got %v", pkgOld, parser.doc.Packages[0]) - } - if parser.doc.Packages[0].PackageName != pkgOldName { - t.Errorf("expected package name %s in Packages[0], got %s", pkgOldName, parser.doc.Packages[0].PackageName) + // and the Document's Packages should still be of size 1 and have pkgOld only + if parser.doc.Packages["p1"] != pkgOld { + t.Errorf("Expected package %v, got %v", pkgOld, parser.doc.Packages["p1"]) } - if parser.doc.Packages[1] != parser.pkg { - t.Errorf("Expected package %v in Packages[1], got %v", parser.pkg, parser.doc.Packages[1]) - } - if parser.doc.Packages[1].PackageName != pkgName { - t.Errorf("expected package name %s in Packages[1], got %s", pkgName, parser.doc.Packages[1].PackageName) + if len(parser.doc.Packages) != 1 { + t.Errorf("expected 1 package, got %d", len(parser.doc.Packages)) } } func TestParser2_1PackageStartsNewPackageAfterParsingPackageNameTagWhileInUnpackaged(t *testing.T) { - // create the first package, which is an "unpackaged" Package structure - // (for Files appearing before the first PackageName tag) + // pkg is nil, so that Files appearing before the first PackageName tag + // are added to UnpackagedFiles instead of Packages parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psFile2_1, - pkg: &spdx.Package2_1{IsUnpackaged: true}, + pkg: nil, } - pkgOld := parser.pkg - parser.doc.Packages = append(parser.doc.Packages, pkgOld) - // the Document's Packages should have this one only - if parser.doc.Packages[0] != pkgOld { - t.Errorf("Expected package %v in Packages[0], got %v", pkgOld, parser.doc.Packages[0]) - } - if parser.doc.Packages[0].IsUnpackaged != true { - t.Errorf("expected unpackaged 'Package' in Packages[0], got IsUnpackaged == false") + // the Document's Packages should be empty + if len(parser.doc.Packages) != 0 { + t.Errorf("Expected zero packages, got %d", len(parser.doc.Packages)) } // now add a new package @@ -114,35 +103,20 @@ func TestParser2_1PackageStartsNewPackageAfterParsingPackageNameTagWhileInUnpack if parser.pkg.IsFilesAnalyzedTagPresent != false { t.Errorf("expected IsFilesAnalyzedTagPresent to default to false, got true") } - // and the package should _not_ be an "unpackaged" placeholder - if parser.pkg.IsUnpackaged == true { - t.Errorf("package incorrectly has IsUnpackaged flag set") - } - // and the Document's Packages should be of size 2 and have these two - if len(parser.doc.Packages) != 2 { - t.Errorf("Expected %v packages in doc, got %v", 2, len(parser.doc.Packages)) - } - if parser.doc.Packages[0] != pkgOld { - t.Errorf("Expected package %v in Packages[0], got %v", pkgOld, parser.doc.Packages[0]) - } - if parser.doc.Packages[0].IsUnpackaged != true { - t.Errorf("expected unpackaged 'Package' in Packages[0], got IsUnpackaged == false") - } - if parser.doc.Packages[1] != parser.pkg { - t.Errorf("Expected package %v in Packages[1], got %v", parser.pkg, parser.doc.Packages[1]) - } - if parser.doc.Packages[1].PackageName != pkgName { - t.Errorf("expected package name %s in Packages[1], got %s", pkgName, parser.doc.Packages[1].PackageName) + // and the Document's Packages should be of size 0, because the prior was + // unpackaged files and this one won't be added until an SPDXID is seen + if len(parser.doc.Packages) != 0 { + t.Errorf("Expected %v packages in doc, got %v", 0, len(parser.doc.Packages)) } } func TestParser2_1PackageMovesToFileAfterParsingFileNameTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg pkgCurrent := parser.pkg err := parser.parsePair2_1("FileName", "testFile") @@ -157,18 +131,15 @@ func TestParser2_1PackageMovesToFileAfterParsingFileNameTag(t *testing.T) { if parser.pkg != pkgCurrent { t.Fatalf("expected package to remain %v, got %v", pkgCurrent, parser.pkg) } - if parser.pkg.IsUnpackaged { - t.Errorf("expected IsUnpackaged to be false, got true") - } } func TestParser2_1PackageMovesToOtherLicenseAfterParsingLicenseIDTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg err := parser.parsePair2_1("LicenseID", "LicenseRef-TestLic") if err != nil { @@ -181,11 +152,11 @@ func TestParser2_1PackageMovesToOtherLicenseAfterParsingLicenseIDTag(t *testing. func TestParser2_1PackageMovesToReviewAfterParsingReviewerTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg err := parser.parsePair2_1("Reviewer", "Person: John Doe") if err != nil { @@ -198,13 +169,13 @@ func TestParser2_1PackageMovesToReviewAfterParsingReviewerTag(t *testing.T) { func TestParser2_1PackageStaysAfterParsingRelationshipTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg - err := parser.parsePair2_1("Relationship", "blah CONTAINS blah-else") + err := parser.parsePair2_1("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-else") if err != nil { t.Errorf("got error when calling parsePair2_1: %v", err) } @@ -225,11 +196,11 @@ func TestParser2_1PackageStaysAfterParsingRelationshipTags(t *testing.T) { func TestParser2_1PackageStaysAfterParsingAnnotationTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg err := parser.parsePair2_1("Annotator", "Person: John Doe ()") if err != nil { @@ -275,11 +246,15 @@ func TestParser2_1PackageStaysAfterParsingAnnotationTags(t *testing.T) { // ===== Package data section tests ===== func TestParser2_1CanParsePackageTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{IsUnpackaged: false}, + pkg: &spdx.Package2_1{}, + } + + // should not yet be in Packages map, b/c no SPDX identifier + if len(parser.doc.Packages) != 0 { + t.Errorf("expected 0 packages, got %d", len(parser.doc.Packages)) } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) // Package Name err := parser.parsePairFromPackage2_1("PackageName", "p1") @@ -289,15 +264,27 @@ func TestParser2_1CanParsePackageTags(t *testing.T) { if parser.pkg.PackageName != "p1" { t.Errorf("got %v for PackageName", parser.pkg.PackageName) } + // still should not yet be in Packages map, b/c no SPDX identifier + if len(parser.doc.Packages) != 0 { + t.Errorf("expected 0 packages, got %d", len(parser.doc.Packages)) + } // Package SPDX Identifier err = parser.parsePairFromPackage2_1("SPDXID", "SPDXRef-p1") if err != nil { t.Errorf("expected nil error, got %v", err) } - if parser.pkg.PackageSPDXIdentifier != "SPDXRef-p1" { + // "SPDXRef-" prefix should be removed from the item + if parser.pkg.PackageSPDXIdentifier != "p1" { t.Errorf("got %v for PackageSPDXIdentifier", parser.pkg.PackageSPDXIdentifier) } + // and it should now be added to the Packages map + if len(parser.doc.Packages) != 1 { + t.Errorf("expected 1 package, got %d", len(parser.doc.Packages)) + } + if parser.doc.Packages["p1"] != parser.pkg { + t.Errorf("expected to point to parser.pkg, got %v", parser.doc.Packages["p1"]) + } // Package Version err = parser.parsePairFromPackage2_1("PackageVersion", "2.1.1") @@ -568,11 +555,11 @@ func TestParser2_1CanParsePackageTags(t *testing.T) { func TestParser2_1CanParsePackageSupplierPersonTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg // Package Supplier: Person err := parser.parsePairFromPackage2_1("PackageSupplier", "Person: John Doe") @@ -586,11 +573,11 @@ func TestParser2_1CanParsePackageSupplierPersonTag(t *testing.T) { func TestParser2_1CanParsePackageSupplierOrganizationTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg // Package Supplier: Organization err := parser.parsePairFromPackage2_1("PackageSupplier", "Organization: John Doe, Inc.") @@ -604,11 +591,11 @@ func TestParser2_1CanParsePackageSupplierOrganizationTag(t *testing.T) { func TestParser2_1CanParsePackageSupplierNOASSERTIONTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg // Package Supplier: NOASSERTION err := parser.parsePairFromPackage2_1("PackageSupplier", "NOASSERTION") @@ -622,11 +609,11 @@ func TestParser2_1CanParsePackageSupplierNOASSERTIONTag(t *testing.T) { func TestParser2_1CanParsePackageOriginatorPersonTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg // Package Originator: Person err := parser.parsePairFromPackage2_1("PackageOriginator", "Person: John Doe") @@ -640,11 +627,11 @@ func TestParser2_1CanParsePackageOriginatorPersonTag(t *testing.T) { func TestParser2_1CanParsePackageOriginatorOrganizationTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg // Package Originator: Organization err := parser.parsePairFromPackage2_1("PackageOriginator", "Organization: John Doe, Inc.") @@ -658,11 +645,11 @@ func TestParser2_1CanParsePackageOriginatorOrganizationTag(t *testing.T) { func TestParser2_1CanParsePackageOriginatorNOASSERTIONTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg // Package Originator: NOASSERTION err := parser.parsePairFromPackage2_1("PackageOriginator", "NOASSERTION") @@ -676,11 +663,11 @@ func TestParser2_1CanParsePackageOriginatorNOASSERTIONTag(t *testing.T) { func TestParser2_1CanParsePackageVerificationCodeTagWithExcludes(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg // Package Verification Code with excludes parenthetical code := "d6a770ba38583ed4bb4525bd96e50461655d2758" @@ -701,11 +688,11 @@ func TestParser2_1CanParsePackageVerificationCodeTagWithExcludes(t *testing.T) { func TestParser2_1CanParsePackageVerificationCodeTagWithoutExcludes(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg // Package Verification Code without excludes parenthetical code := "d6a770ba38583ed4bb4525bd96e50461655d2758" @@ -724,11 +711,11 @@ func TestParser2_1CanParsePackageVerificationCodeTagWithoutExcludes(t *testing.T func TestPackageExternalRefPointerChangesAfterTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg ref1 := "SECURITY cpe23Type cpe:2.3:a:pivotal_software:spring_framework:4.1.0:*:*:*:*:*:*:*" err := parser.parsePairFromPackage2_1("ExternalRef", ref1) @@ -769,13 +756,13 @@ func TestPackageExternalRefPointerChangesAfterTags(t *testing.T) { func TestParser2_1PackageCreatesRelationshipInDocument(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg - err := parser.parsePair2_1("Relationship", "blah CONTAINS blah-whatever") + err := parser.parsePair2_1("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-whatever") if err != nil { t.Errorf("got error when calling parsePair2_1: %v", err) } @@ -789,11 +776,11 @@ func TestParser2_1PackageCreatesRelationshipInDocument(t *testing.T) { func TestParser2_1PackageCreatesAnnotationInDocument(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg err := parser.parsePair2_1("Annotator", "Person: John Doe ()") if err != nil { @@ -809,11 +796,11 @@ func TestParser2_1PackageCreatesAnnotationInDocument(t *testing.T) { func TestParser2_1PackageUnknownTagFails(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psPackage2_1, - pkg: &spdx.Package2_1{PackageName: "p1", IsUnpackaged: false}, + pkg: &spdx.Package2_1{PackageName: "p1", PackageSPDXIdentifier: "p1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) + parser.doc.Packages["p1"] = parser.pkg err := parser.parsePairFromPackage2_1("blah", "something") if err == nil { diff --git a/tvloader/parser2v1/parse_relationship.go b/tvloader/parser2v1/parse_relationship.go index 8b72285..2b9b8cc 100644 --- a/tvloader/parser2v1/parse_relationship.go +++ b/tvloader/parser2v1/parse_relationship.go @@ -29,9 +29,17 @@ func (parser *tvParser2_1) parsePairForRelationship2_1(tag string, value string) return fmt.Errorf("invalid relationship format for %s", value) } - parser.rln.RefA = strings.TrimSpace(rp[0]) + aID, err := extractDocElementID(strings.TrimSpace(rp[0])) + if err != nil { + return err + } + parser.rln.RefA = aID parser.rln.Relationship = strings.TrimSpace(rp[1]) - parser.rln.RefB = strings.TrimSpace(rp[2]) + bID, err := extractDocElementID(strings.TrimSpace(rp[2])) + if err != nil { + return err + } + parser.rln.RefB = bID return nil } diff --git a/tvloader/parser2v1/parse_relationship_test.go b/tvloader/parser2v1/parse_relationship_test.go index 17964fc..ad1dd52 100644 --- a/tvloader/parser2v1/parse_relationship_test.go +++ b/tvloader/parser2v1/parse_relationship_test.go @@ -13,7 +13,7 @@ func TestParser2_1FailsIfRelationshipNotSet(t *testing.T) { doc: &spdx.Document2_1{}, st: psCreationInfo2_1, } - err := parser.parsePairForRelationship2_1("Relationship", "something DESCRIBES something-else") + err := parser.parsePairForRelationship2_1("Relationship", "SPDXRef-A CONTAINS SPDXRef-B") if err == nil { t.Errorf("expected error when calling parsePairFromRelationship2_1 without setting rln pointer") } @@ -37,18 +37,18 @@ func TestParser2_1CanParseRelationshipTags(t *testing.T) { } // Relationship - err := parser.parsePair2_1("Relationship", "something DESCRIBES something-else") + err := parser.parsePair2_1("Relationship", "SPDXRef-something CONTAINS DocumentRef-otherdoc:SPDXRef-something-else") if err != nil { t.Errorf("expected nil error, got %v", err) } - if parser.rln.RefA != "something" { + if parser.rln.RefA.DocumentRefID != "" || parser.rln.RefA.ElementRefID != "something" { t.Errorf("got %v for first part of Relationship, expected something", parser.rln.RefA) } - if parser.rln.RefB != "something-else" { - t.Errorf("got %v for second part of Relationship, expected something-else", parser.rln.RefB) + if parser.rln.RefB.DocumentRefID != "otherdoc" || parser.rln.RefB.ElementRefID != "something-else" { + t.Errorf("got %v for second part of Relationship, expected otherdoc:something-else", parser.rln.RefB) } - if parser.rln.Relationship != "DESCRIBES" { - t.Errorf("got %v for Relationship type, expected DESCRIBES", parser.rln.Relationship) + if parser.rln.Relationship != "CONTAINS" { + t.Errorf("got %v for Relationship type, expected CONTAINS", parser.rln.Relationship) } // Relationship Comment @@ -112,7 +112,7 @@ func TestParser2_1InvalidRelationshipTagsThreeValuesSucceed(t *testing.T) { // three items but with interspersed additional whitespace parser.rln = nil - err := parser.parsePair2_1("Relationship", " SPDXRef-DOCUMENT \t DESCRIBES something-else ") + err := parser.parsePair2_1("Relationship", " SPDXRef-DOCUMENT \t DESCRIBES SPDXRef-something-else ") if err != nil { t.Errorf("expected pass for three items in relationship w/ extra whitespace, got: %v", err) } @@ -126,8 +126,28 @@ func TestParser2_1InvalidRelationshipTagsFourValuesFail(t *testing.T) { // four items parser.rln = nil - err := parser.parsePair2_1("Relationship", "a DESCRIBES b c") + err := parser.parsePair2_1("Relationship", "SPDXRef-a DESCRIBES SPDXRef-b SPDXRef-c") if err == nil { t.Errorf("expected error for more than three items in relationship, got nil") } } + +func TestParser2_1InvalidRelationshipTagsInvalidRefIDs(t *testing.T) { + parser := tvParser2_1{ + doc: &spdx.Document2_1{}, + st: psCreationInfo2_1, + } + + // four items + parser.rln = nil + err := parser.parsePair2_1("Relationship", "SPDXRef-a DESCRIBES b") + if err == nil { + t.Errorf("expected error for missing SPDXRef- prefix, got nil") + } + + parser.rln = nil + err = parser.parsePair2_1("Relationship", "a DESCRIBES SPDXRef-b") + if err == nil { + t.Errorf("expected error for missing SPDXRef- prefix, got nil") + } +} diff --git a/tvloader/parser2v1/parse_review_test.go b/tvloader/parser2v1/parse_review_test.go index 56a0fa8..6f44ed9 100644 --- a/tvloader/parser2v1/parse_review_test.go +++ b/tvloader/parser2v1/parse_review_test.go @@ -12,10 +12,10 @@ func TestParser2_1ReviewStartsNewReviewAfterParsingReviewerTag(t *testing.T) { // create the first review rev1 := "John Doe" parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psReview2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-Lic11", LicenseName: "License 11", @@ -25,8 +25,8 @@ func TestParser2_1ReviewStartsNewReviewAfterParsingReviewerTag(t *testing.T) { ReviewerType: "Person", }, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) parser.doc.Reviews = append(parser.doc.Reviews, parser.rev) r1 := parser.rev @@ -82,10 +82,10 @@ func TestParser2_1ReviewStartsNewReviewAfterParsingReviewerTag(t *testing.T) { func TestParser2_1ReviewStaysAfterParsingRelationshipTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psReview2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-Lic11", LicenseName: "License 11", @@ -95,12 +95,12 @@ func TestParser2_1ReviewStaysAfterParsingRelationshipTags(t *testing.T) { ReviewerType: "Person", }, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) parser.doc.Reviews = append(parser.doc.Reviews, parser.rev) - err := parser.parsePair2_1("Relationship", "blah CONTAINS blah-else") + err := parser.parsePair2_1("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-else") if err != nil { t.Errorf("got error when calling parsePair2_1: %v", err) } @@ -112,7 +112,8 @@ func TestParser2_1ReviewStaysAfterParsingRelationshipTags(t *testing.T) { if len(parser.doc.Relationships) != 1 { t.Fatalf("expected doc.Relationships to have len 1, got %d", len(parser.doc.Relationships)) } - if parser.doc.Relationships[0].RefA != "blah" { + deID := parser.doc.Relationships[0].RefA + if deID.DocumentRefID != "" || deID.ElementRefID != "blah" { t.Errorf("expected RefA to be %s, got %s", "blah", parser.doc.Relationships[0].RefA) } @@ -128,10 +129,10 @@ func TestParser2_1ReviewStaysAfterParsingRelationshipTags(t *testing.T) { func TestParser2_1ReviewStaysAfterParsingAnnotationTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psReview2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-Lic11", LicenseName: "License 11", @@ -141,8 +142,8 @@ func TestParser2_1ReviewStaysAfterParsingAnnotationTags(t *testing.T) { ReviewerType: "Person", }, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) parser.doc.Reviews = append(parser.doc.Reviews, parser.rev) @@ -197,18 +198,18 @@ func TestParser2_1ReviewStaysAfterParsingAnnotationTags(t *testing.T) { func TestParser2_1ReviewFailsAfterParsingOtherSectionTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psReview2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-Lic11", LicenseName: "License 11", }, rev: &spdx.Review2_1{}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) parser.doc.Reviews = append(parser.doc.Reviews, parser.rev) @@ -234,18 +235,18 @@ func TestParser2_1ReviewFailsAfterParsingOtherSectionTags(t *testing.T) { // ===== Review data section tests ===== func TestParser2_1CanParseReviewTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psReview2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-Lic11", LicenseName: "License 11", }, rev: &spdx.Review2_1{}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) parser.doc.Reviews = append(parser.doc.Reviews, parser.rev) @@ -273,18 +274,18 @@ func TestParser2_1CanParseReviewTags(t *testing.T) { func TestParser2_1CanParseReviewerPersonTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psReview2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-Lic11", LicenseName: "License 11", }, rev: &spdx.Review2_1{}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) parser.doc.Reviews = append(parser.doc.Reviews, parser.rev) @@ -303,18 +304,18 @@ func TestParser2_1CanParseReviewerPersonTag(t *testing.T) { func TestParser2_1CanParseReviewerOrganizationTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psReview2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-Lic11", LicenseName: "License 11", }, rev: &spdx.Review2_1{}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) parser.doc.Reviews = append(parser.doc.Reviews, parser.rev) @@ -333,18 +334,18 @@ func TestParser2_1CanParseReviewerOrganizationTag(t *testing.T) { func TestParser2_1CanParseReviewerToolTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psReview2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-Lic11", LicenseName: "License 11", }, rev: &spdx.Review2_1{}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) parser.doc.Reviews = append(parser.doc.Reviews, parser.rev) @@ -363,18 +364,18 @@ func TestParser2_1CanParseReviewerToolTag(t *testing.T) { func TestParser2_1ReviewUnknownTagFails(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psReview2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1"}, otherLic: &spdx.OtherLicense2_1{ LicenseIdentifier: "LicenseRef-Lic11", LicenseName: "License 11", }, rev: &spdx.Review2_1{}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file parser.doc.OtherLicenses = append(parser.doc.OtherLicenses, parser.otherLic) parser.doc.Reviews = append(parser.doc.Reviews, parser.rev) diff --git a/tvloader/parser2v1/parse_snippet.go b/tvloader/parser2v1/parse_snippet.go index b9abbaf..f7085a7 100644 --- a/tvloader/parser2v1/parse_snippet.go +++ b/tvloader/parser2v1/parse_snippet.go @@ -14,8 +14,18 @@ func (parser *tvParser2_1) parsePairFromSnippet2_1(tag string, value string) err // tag for creating new snippet section case "SnippetSPDXID": parser.snippet = &spdx.Snippet2_1{} - parser.file.Snippets = append(parser.file.Snippets, parser.snippet) - parser.snippet.SnippetSPDXIdentifier = value + eID, err := extractElementID(value) + if err != nil { + return err + } + // FIXME: how should we handle where not associated with current file? + if parser.file != nil { + if parser.file.Snippets == nil { + parser.file.Snippets = map[spdx.ElementID]*spdx.Snippet2_1{} + } + parser.file.Snippets[eID] = parser.snippet + } + parser.snippet.SnippetSPDXIdentifier = eID // tag for creating new file section and going back to parsing File case "FileName": parser.st = psFile2_1 @@ -33,7 +43,11 @@ func (parser *tvParser2_1) parsePairFromSnippet2_1(tag string, value string) err return parser.parsePairFromOtherLicense2_1(tag, value) // tags for snippet data case "SnippetFromFileSPDXID": - parser.snippet.SnippetFromFileSPDXIdentifier = value + deID, err := extractDocElementID(value) + if err != nil { + return err + } + parser.snippet.SnippetFromFileSPDXIdentifier = deID case "SnippetByteRange": byteStart, byteEnd, err := extractSubs(value) if err != nil { diff --git a/tvloader/parser2v1/parse_snippet_test.go b/tvloader/parser2v1/parse_snippet_test.go index 41b2f9e..5201a28 100644 --- a/tvloader/parser2v1/parse_snippet_test.go +++ b/tvloader/parser2v1/parse_snippet_test.go @@ -10,34 +10,32 @@ import ( // ===== Parser snippet section state change tests ===== func TestParser2_1SnippetStartsNewSnippetAfterParsingSnippetSPDXIDTag(t *testing.T) { // create the first snippet - sid1 := "SPDXRef-s1" - + sid1 := spdx.ElementID("s1") parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psSnippet2_1, - pkg: &spdx.Package2_1{PackageName: "test"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "test", PackageSPDXIdentifier: "test", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1", Snippets: map[spdx.ElementID]*spdx.Snippet2_1{}}, snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: sid1}, } s1 := parser.snippet - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) - parser.file.Snippets = append(parser.file.Snippets, parser.snippet) + parser.doc.Packages["test"] = parser.pkg + parser.pkg.Files["f1"] = parser.file + parser.file.Snippets[sid1] = parser.snippet // the File's Snippets should have this one only if len(parser.file.Snippets) != 1 { t.Errorf("Expected len(Snippets) to be 1, got %d", len(parser.file.Snippets)) } - if parser.file.Snippets[0] != s1 { - t.Errorf("Expected snippet %v in Snippets[0], got %v", s1, parser.file.Snippets[0]) + if parser.file.Snippets["s1"] != s1 { + t.Errorf("Expected snippet %v in Snippets[s1], got %v", s1, parser.file.Snippets["s1"]) } - if parser.file.Snippets[0].SnippetSPDXIdentifier != sid1 { - t.Errorf("expected snippet ID %s in Snippets[0], got %s", sid1, parser.file.Snippets[0].SnippetSPDXIdentifier) + if parser.file.Snippets["s1"].SnippetSPDXIdentifier != sid1 { + t.Errorf("expected snippet ID %s in Snippets[s1], got %s", sid1, parser.file.Snippets["s1"].SnippetSPDXIdentifier) } // now add a new snippet - sid2 := "SPDXRef-s2" - err := parser.parsePair2_1("SnippetSPDXID", sid2) + err := parser.parsePair2_1("SnippetSPDXID", "SPDXRef-s2") if err != nil { t.Errorf("got error when calling parsePair2_1: %v", err) } @@ -50,43 +48,40 @@ func TestParser2_1SnippetStartsNewSnippetAfterParsingSnippetSPDXIDTag(t *testing t.Fatalf("parser didn't create new snippet") } // and the snippet ID should be as expected - if parser.snippet.SnippetSPDXIdentifier != sid2 { - t.Errorf("expected snippet ID %s, got %s", sid2, parser.snippet.SnippetSPDXIdentifier) + if parser.snippet.SnippetSPDXIdentifier != "s2" { + t.Errorf("expected snippet ID %s, got %s", "s2", parser.snippet.SnippetSPDXIdentifier) } // and the File's Snippets should be of size 2 and have these two if len(parser.file.Snippets) != 2 { t.Errorf("Expected len(Snippets) to be 2, got %d", len(parser.file.Snippets)) } - if parser.file.Snippets[0] != s1 { - t.Errorf("Expected snippet %v in Snippets[0], got %v", s1, parser.file.Snippets[0]) + if parser.file.Snippets["s1"] != s1 { + t.Errorf("Expected snippet %v in Snippets[s1], got %v", s1, parser.file.Snippets["s1"]) } - if parser.file.Snippets[0].SnippetSPDXIdentifier != sid1 { - t.Errorf("expected snippet ID %s in Snippets[0], got %s", sid1, parser.file.Snippets[0].SnippetSPDXIdentifier) + if parser.file.Snippets["s1"].SnippetSPDXIdentifier != sid1 { + t.Errorf("expected snippet ID %s in Snippets[s1], got %s", sid1, parser.file.Snippets["s1"].SnippetSPDXIdentifier) } - if parser.file.Snippets[1] != parser.snippet { - t.Errorf("Expected snippet %v in Snippets[1], got %v", parser.snippet, parser.file.Snippets[1]) + if parser.file.Snippets["s2"] != parser.snippet { + t.Errorf("Expected snippet %v in Snippets[s2], got %v", parser.snippet, parser.file.Snippets["s2"]) } - if parser.file.Snippets[1].SnippetSPDXIdentifier != sid2 { - t.Errorf("expected snippet ID %s in Snippets[1], got %s", sid2, parser.file.Snippets[1].SnippetSPDXIdentifier) + if parser.file.Snippets["s2"].SnippetSPDXIdentifier != "s2" { + t.Errorf("expected snippet ID %s in Snippets[s2], got %s", "s2", parser.file.Snippets["s2"].SnippetSPDXIdentifier) } } func TestParser2_1SnippetStartsNewPackageAfterParsingPackageNameTag(t *testing.T) { - p1Name := "package1" - f1Name := "f1.txt" - s1Name := "SPDXRef-s1" parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psSnippet2_1, - pkg: &spdx.Package2_1{PackageName: p1Name}, - file: &spdx.File2_1{FileName: f1Name}, - snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: s1Name}, + pkg: &spdx.Package2_1{PackageName: "package1", PackageSPDXIdentifier: "package1", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1", Snippets: map[spdx.ElementID]*spdx.Snippet2_1{}}, + snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "s1"}, } p1 := parser.pkg f1 := parser.file - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) - parser.file.Snippets = append(parser.file.Snippets, parser.snippet) + parser.doc.Packages["package1"] = parser.pkg + parser.pkg.Files["f1"] = parser.file + parser.file.Snippets["s1"] = parser.snippet // now add a new package p2Name := "package2" @@ -113,39 +108,30 @@ func TestParser2_1SnippetStartsNewPackageAfterParsingPackageNameTag(t *testing.T if parser.pkg.IsFilesAnalyzedTagPresent != false { t.Errorf("expected IsFilesAnalyzedTagPresent to default to false, got true") } - // and the package should _not_ be an "unpackaged" placeholder - if parser.pkg.IsUnpackaged == true { - t.Errorf("package incorrectly has IsUnpackaged flag set") - } - // and the Document's Packages should be of size 2 and have these two - if len(parser.doc.Packages) != 2 { - t.Errorf("Expected len(Packages) to be 2, got %d", len(parser.doc.Packages)) + // and the Document's Packages should still be of size 1 b/c no SPDX + // identifier has been seen yet + if len(parser.doc.Packages) != 1 { + t.Errorf("Expected len(Packages) to be 1, got %d", len(parser.doc.Packages)) } - if parser.doc.Packages[0] != p1 { - t.Errorf("Expected package %v in Packages[0], got %v", p1, parser.doc.Packages[0]) + if parser.doc.Packages["package1"] != p1 { + t.Errorf("Expected package %v in Packages[package1], got %v", p1, parser.doc.Packages["package1"]) } - if parser.doc.Packages[0].PackageName != p1Name { - t.Errorf("expected package name %s in Packages[0], got %s", p1Name, parser.doc.Packages[0].PackageName) - } - if parser.doc.Packages[1] != parser.pkg { - t.Errorf("Expected package %v in Packages[1], got %v", parser.pkg, parser.doc.Packages[1]) - } - if parser.doc.Packages[1].PackageName != p2Name { - t.Errorf("expected package name %s in Packages[1], got %s", p2Name, parser.doc.Packages[1].PackageName) + if parser.doc.Packages["package1"].PackageName != "package1" { + t.Errorf("expected package name %s in Packages[package1], got %s", "package1", parser.doc.Packages["package1"].PackageName) } // and the first Package's Files should be of size 1 and have f1 only - if len(parser.doc.Packages[0].Files) != 1 { - t.Errorf("Expected 1 file in Packages[0].Files, got %d", len(parser.doc.Packages[0].Files)) + if len(parser.doc.Packages["package1"].Files) != 1 { + t.Errorf("Expected 1 file in Packages[package1].Files, got %d", len(parser.doc.Packages["package1"].Files)) } - if parser.doc.Packages[0].Files[0] != f1 { - t.Errorf("Expected file %v in Files[0], got %v", f1, parser.doc.Packages[0].Files[0]) + if parser.doc.Packages["package1"].Files["f1"] != f1 { + t.Errorf("Expected file %v in Files[f1], got %v", f1, parser.doc.Packages["package1"].Files["f1"]) } - if parser.doc.Packages[0].Files[0].FileName != f1Name { - t.Errorf("expected file name %s in Files[0], got %s", f1Name, parser.doc.Packages[0].Files[0].FileName) + if parser.doc.Packages["package1"].Files["f1"].FileName != "f1.txt" { + t.Errorf("expected file name %s in Files[f1], got %s", "f1.txt", parser.doc.Packages["package1"].Files["f1"].FileName) } - // and the second Package should have no files - if len(parser.doc.Packages[1].Files) != 0 { - t.Errorf("Expected no files in Packages[1].Files, got %d", len(parser.doc.Packages[1].Files)) + // and the new Package should have no files + if len(parser.pkg.Files) != 0 { + t.Errorf("Expected no files in Packages[1].Files, got %d", len(parser.pkg.Files)) } // and the current file should be nil if parser.file != nil { @@ -158,21 +144,19 @@ func TestParser2_1SnippetStartsNewPackageAfterParsingPackageNameTag(t *testing.T } func TestParser2_1SnippetMovesToFileAfterParsingFileNameTag(t *testing.T) { - p1Name := "package1" f1Name := "f1.txt" - s1Name := "SPDXRef-s1" parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psSnippet2_1, - pkg: &spdx.Package2_1{PackageName: p1Name}, - file: &spdx.File2_1{FileName: f1Name}, - snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: s1Name}, + pkg: &spdx.Package2_1{PackageName: "package1", PackageSPDXIdentifier: "package1", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1", Snippets: map[spdx.ElementID]*spdx.Snippet2_1{}}, + snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "s1"}, } p1 := parser.pkg f1 := parser.file - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) - parser.file.Snippets = append(parser.file.Snippets, parser.snippet) + parser.doc.Packages["package1"] = parser.pkg + parser.pkg.Files["f1"] = parser.file + parser.file.Snippets["s1"] = parser.snippet f2Name := "f2.txt" err := parser.parsePair2_1("FileName", f2Name) @@ -195,18 +179,16 @@ func TestParser2_1SnippetMovesToFileAfterParsingFileNameTag(t *testing.T) { if parser.file.FileName != f2Name { t.Errorf("expected file name %s, got %s", f2Name, parser.file.FileName) } - // and the Package's Files should be of size 2 and have these two - if parser.pkg.Files[0] != f1 { - t.Errorf("Expected file %v in Files[0], got %v", f1, parser.pkg.Files[0]) - } - if parser.pkg.Files[0].FileName != f1Name { - t.Errorf("expected file name %s in Files[0], got %s", f1Name, parser.pkg.Files[0].FileName) + // and the Package's Files should still be of size 1 since we haven't seen + // an SPDX identifier yet for this new file + if len(parser.pkg.Files) != 1 { + t.Errorf("Expected len(Files) to be 1, got %d", len(parser.pkg.Files)) } - if parser.pkg.Files[1] != parser.file { - t.Errorf("Expected file %v in Files[1], got %v", parser.file, parser.pkg.Files[1]) + if parser.pkg.Files["f1"] != f1 { + t.Errorf("Expected file %v in Files[f1], got %v", f1, parser.pkg.Files["f1"]) } - if parser.pkg.Files[1].FileName != f2Name { - t.Errorf("expected file name %s in Files[1], got %s", f2Name, parser.pkg.Files[1].FileName) + if parser.pkg.Files["f1"].FileName != f1Name { + t.Errorf("expected file name %s in Files[f1], got %s", f1Name, parser.pkg.Files["f1"].FileName) } // and the current snippet should be nil if parser.snippet != nil { @@ -216,15 +198,15 @@ func TestParser2_1SnippetMovesToFileAfterParsingFileNameTag(t *testing.T) { func TestParser2_1SnippetMovesToOtherLicenseAfterParsingLicenseIDTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psSnippet2_1, - pkg: &spdx.Package2_1{PackageName: "package1"}, - file: &spdx.File2_1{FileName: "f1.txt"}, - snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "SPDXRef-s1"}, + pkg: &spdx.Package2_1{PackageName: "package1", PackageSPDXIdentifier: "package1", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1", Snippets: map[spdx.ElementID]*spdx.Snippet2_1{}}, + snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "s1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) - parser.file.Snippets = append(parser.file.Snippets, parser.snippet) + parser.doc.Packages["package1"] = parser.pkg + parser.pkg.Files["f1"] = parser.file + parser.file.Snippets["s1"] = parser.snippet err := parser.parsePair2_1("LicenseID", "LicenseRef-TestLic") if err != nil { @@ -237,15 +219,15 @@ func TestParser2_1SnippetMovesToOtherLicenseAfterParsingLicenseIDTag(t *testing. func TestParser2_1SnippetMovesToReviewAfterParsingReviewerTag(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psSnippet2_1, - pkg: &spdx.Package2_1{PackageName: "package1"}, - file: &spdx.File2_1{FileName: "f1.txt"}, - snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "SPDXRef-s1"}, + pkg: &spdx.Package2_1{PackageName: "package1", PackageSPDXIdentifier: "package1", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1", Snippets: map[spdx.ElementID]*spdx.Snippet2_1{}}, + snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "s1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) - parser.file.Snippets = append(parser.file.Snippets, parser.snippet) + parser.doc.Packages["package1"] = parser.pkg + parser.pkg.Files["f1"] = parser.file + parser.file.Snippets["s1"] = parser.snippet err := parser.parsePair2_1("Reviewer", "Person: John Doe") if err != nil { @@ -258,17 +240,17 @@ func TestParser2_1SnippetMovesToReviewAfterParsingReviewerTag(t *testing.T) { func TestParser2_1SnippetStaysAfterParsingRelationshipTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psSnippet2_1, - pkg: &spdx.Package2_1{PackageName: "package1"}, - file: &spdx.File2_1{FileName: "f1.txt"}, - snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "SPDXRef-s1"}, + pkg: &spdx.Package2_1{PackageName: "package1", PackageSPDXIdentifier: "package1", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1", Snippets: map[spdx.ElementID]*spdx.Snippet2_1{}}, + snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "s1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) - parser.file.Snippets = append(parser.file.Snippets, parser.snippet) + parser.doc.Packages["package1"] = parser.pkg + parser.pkg.Files["f1"] = parser.file + parser.file.Snippets["s1"] = parser.snippet - err := parser.parsePair2_1("Relationship", "blah CONTAINS blah-else") + err := parser.parsePair2_1("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-else") if err != nil { t.Errorf("got error when calling parsePair2_1: %v", err) } @@ -280,7 +262,8 @@ func TestParser2_1SnippetStaysAfterParsingRelationshipTags(t *testing.T) { if len(parser.doc.Relationships) != 1 { t.Fatalf("expected doc.Relationships to have len 1, got %d", len(parser.doc.Relationships)) } - if parser.doc.Relationships[0].RefA != "blah" { + deID := parser.doc.Relationships[0].RefA + if deID.DocumentRefID != "" || deID.ElementRefID != "blah" { t.Errorf("expected RefA to be %s, got %s", "blah", parser.doc.Relationships[0].RefA) } @@ -296,15 +279,15 @@ func TestParser2_1SnippetStaysAfterParsingRelationshipTags(t *testing.T) { func TestParser2_1SnippetStaysAfterParsingAnnotationTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psSnippet2_1, - pkg: &spdx.Package2_1{PackageName: "package1"}, - file: &spdx.File2_1{FileName: "f1.txt"}, - snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "SPDXRef-s1"}, + pkg: &spdx.Package2_1{PackageName: "package1", PackageSPDXIdentifier: "package1", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1", Snippets: map[spdx.ElementID]*spdx.Snippet2_1{}}, + snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "s1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) - parser.file.Snippets = append(parser.file.Snippets, parser.snippet) + parser.doc.Packages["package1"] = parser.pkg + parser.pkg.Files["f1"] = parser.file + parser.file.Snippets["s1"] = parser.snippet err := parser.parsePair2_1("Annotator", "Person: John Doe ()") if err != nil { @@ -358,22 +341,21 @@ func TestParser2_1SnippetStaysAfterParsingAnnotationTags(t *testing.T) { // ===== Snippet data section tests ===== func TestParser2_1CanParseSnippetTags(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psSnippet2_1, - pkg: &spdx.Package2_1{PackageName: "package1"}, - file: &spdx.File2_1{FileName: "f1.txt"}, + pkg: &spdx.Package2_1{PackageName: "package1", PackageSPDXIdentifier: "package1", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1", Snippets: map[spdx.ElementID]*spdx.Snippet2_1{}}, snippet: &spdx.Snippet2_1{}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) - parser.file.Snippets = append(parser.file.Snippets, parser.snippet) + parser.doc.Packages["package1"] = parser.pkg + parser.pkg.Files["f1"] = parser.file // Snippet SPDX Identifier err := parser.parsePairFromSnippet2_1("SnippetSPDXID", "SPDXRef-s1") if err != nil { t.Errorf("expected nil error, got %v", err) } - if parser.snippet.SnippetSPDXIdentifier != "SPDXRef-s1" { + if parser.snippet.SnippetSPDXIdentifier != "s1" { t.Errorf("got %v for SnippetSPDXIdentifier", parser.snippet.SnippetSPDXIdentifier) } @@ -382,7 +364,8 @@ func TestParser2_1CanParseSnippetTags(t *testing.T) { if err != nil { t.Errorf("expected nil error, got %v", err) } - if parser.snippet.SnippetFromFileSPDXIdentifier != "SPDXRef-f1" { + wantDeID := spdx.DocElementID{DocumentRefID: "", ElementRefID: spdx.ElementID("f1")} + if parser.snippet.SnippetFromFileSPDXIdentifier != wantDeID { t.Errorf("got %v for SnippetFromFileSPDXIdentifier", parser.snippet.SnippetFromFileSPDXIdentifier) } @@ -486,15 +469,14 @@ func TestParser2_1CanParseSnippetTags(t *testing.T) { func TestParser2_1SnippetUnknownTagFails(t *testing.T) { parser := tvParser2_1{ - doc: &spdx.Document2_1{}, + doc: &spdx.Document2_1{Packages: map[spdx.ElementID]*spdx.Package2_1{}}, st: psSnippet2_1, - pkg: &spdx.Package2_1{PackageName: "package1"}, - file: &spdx.File2_1{FileName: "f1.txt"}, - snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "SPDXRef-s1"}, + pkg: &spdx.Package2_1{PackageName: "package1", PackageSPDXIdentifier: "package1", Files: map[spdx.ElementID]*spdx.File2_1{}}, + file: &spdx.File2_1{FileName: "f1.txt", FileSPDXIdentifier: "f1", Snippets: map[spdx.ElementID]*spdx.Snippet2_1{}}, + snippet: &spdx.Snippet2_1{SnippetSPDXIdentifier: "s1"}, } - parser.doc.Packages = append(parser.doc.Packages, parser.pkg) - parser.pkg.Files = append(parser.pkg.Files, parser.file) - parser.file.Snippets = append(parser.file.Snippets, parser.snippet) + parser.doc.Packages["package1"] = parser.pkg + parser.pkg.Files["f1"] = parser.file err := parser.parsePairFromSnippet2_1("blah", "something") if err == nil { diff --git a/tvloader/parser2v1/util.go b/tvloader/parser2v1/util.go index ed99063..d2df57b 100644 --- a/tvloader/parser2v1/util.go +++ b/tvloader/parser2v1/util.go @@ -5,6 +5,8 @@ package parser2v1 import ( "fmt" "strings" + + "github.com/spdx/tools-golang/spdx" ) // used to extract key / value from embedded substrings @@ -21,3 +23,76 @@ func extractSubs(value string) (string, string, error) { return subkey, subvalue, nil } + +// used to extract DocumentRef and SPDXRef values from an SPDX Identifier +// which can point either to this document or to a different one +func extractDocElementID(value string) (spdx.DocElementID, error) { + docRefID := "" + idStr := value + + // check prefix to see if it's a DocumentRef ID + if strings.HasPrefix(idStr, "DocumentRef-") { + // extract the part that comes between "DocumentRef-" and ":" + strs := strings.Split(idStr, ":") + // should be exactly two, part before and part after + if len(strs) < 2 { + return spdx.DocElementID{}, fmt.Errorf("no colon found although DocumentRef- prefix present") + } + if len(strs) > 2 { + return spdx.DocElementID{}, fmt.Errorf("more than one colon found") + } + + // trim the prefix and confirm non-empty + docRefID = strings.TrimPrefix(strs[0], "DocumentRef-") + if docRefID == "" { + return spdx.DocElementID{}, fmt.Errorf("document identifier has nothing after prefix") + } + // and use remainder for element ID parsing + idStr = strs[1] + } + + // check prefix to confirm it's got the right prefix for element IDs + if !strings.HasPrefix(idStr, "SPDXRef-") { + return spdx.DocElementID{}, fmt.Errorf("missing SPDXRef- prefix for element identifier") + } + + // make sure no colons are present + if strings.Contains(idStr, ":") { + // we know this means there was no DocumentRef- prefix, because + // we would have handled multiple colons above if it was + return spdx.DocElementID{}, fmt.Errorf("invalid colon in element identifier") + } + + // trim the prefix and confirm non-empty + eltRefID := strings.TrimPrefix(idStr, "SPDXRef-") + if eltRefID == "" { + return spdx.DocElementID{}, fmt.Errorf("element identifier has nothing after prefix") + } + + // we're good + return spdx.DocElementID{DocumentRefID: docRefID, ElementRefID: spdx.ElementID(eltRefID)}, nil +} + +// used to extract SPDXRef values only from an SPDX Identifier which can point +// to this document only. Use extractDocElementID for parsing IDs that can +// refer either to this document or a different one. +func extractElementID(value string) (spdx.ElementID, error) { + // check prefix to confirm it's got the right prefix for element IDs + if !strings.HasPrefix(value, "SPDXRef-") { + return spdx.ElementID(""), fmt.Errorf("missing SPDXRef- prefix for element identifier") + } + + // make sure no colons are present + if strings.Contains(value, ":") { + return spdx.ElementID(""), fmt.Errorf("invalid colon in element identifier") + } + + // trim the prefix and confirm non-empty + eltRefID := strings.TrimPrefix(value, "SPDXRef-") + if eltRefID == "" { + return spdx.ElementID(""), fmt.Errorf("element identifier has nothing after prefix") + } + + // we're good + return spdx.ElementID(eltRefID), nil +} diff --git a/tvloader/parser2v1/util_test.go b/tvloader/parser2v1/util_test.go index c544001..b6a2fb2 100644 --- a/tvloader/parser2v1/util_test.go +++ b/tvloader/parser2v1/util_test.go @@ -3,6 +3,8 @@ package parser2v1 import ( "testing" + + "github.com/spdx/tools-golang/spdx" ) // ===== Helper function tests ===== @@ -26,3 +28,80 @@ func TestReturnsErrorForInvalidSubvalueFormat(t *testing.T) { t.Errorf("expected error when calling extractSubs for invalid format (0 colons), got nil") } } + +func TestCanExtractDocumentAndElementRefsFromID(t *testing.T) { + // test with valid ID in this document + helperForExtractDocElementID(t, "SPDXRef-file1", false, "", "file1") + // test with valid ID in another document + helperForExtractDocElementID(t, "DocumentRef-doc2:SPDXRef-file2", false, "doc2", "file2") + // test with invalid ID in this document + helperForExtractDocElementID(t, "a:SPDXRef-file1", true, "", "") + helperForExtractDocElementID(t, "file1", true, "", "") + helperForExtractDocElementID(t, "SPDXRef-", true, "", "") + // test with invalid ID in another document + helperForExtractDocElementID(t, "DocumentRef-doc2", true, "", "") + helperForExtractDocElementID(t, "DocumentRef-doc2:", true, "", "") + helperForExtractDocElementID(t, "DocumentRef-doc2:SPDXRef-", true, "", "") + helperForExtractDocElementID(t, "DocumentRef-doc2:a", true, "", "") + helperForExtractDocElementID(t, "DocumentRef-:", true, "", "") + helperForExtractDocElementID(t, "DocumentRef-:SPDXRef-file1", true, "", "") +} + +func helperForExtractDocElementID(t *testing.T, tst string, wantErr bool, wantDoc string, wantElt string) { + deID, err := extractDocElementID(tst) + if err != nil && wantErr == false { + t.Errorf("testing %v: expected nil error, got %v", tst, err) + } + if err == nil && wantErr == true { + t.Errorf("testing %v: expected non-nil error, got nil", tst) + } + if deID.DocumentRefID != wantDoc { + if wantDoc == "" { + t.Errorf("testing %v: want empty string for DocumentRefID, got %v", tst, deID.DocumentRefID) + } else { + t.Errorf("testing %v: want %v for DocumentRefID, got %v", tst, wantDoc, deID.DocumentRefID) + } + } + if deID.ElementRefID != spdx.ElementID(wantElt) { + if wantElt == "" { + t.Errorf("testing %v: want emptyString for ElementRefID, got %v", tst, deID.ElementRefID) + } else { + t.Errorf("testing %v: want %v for ElementRefID, got %v", tst, wantElt, deID.ElementRefID) + } + } +} + +func TestCanExtractElementRefsOnlyFromID(t *testing.T) { + // test with valid ID in this document + helperForExtractElementID(t, "SPDXRef-file1", false, "file1") + // test with valid ID in another document + helperForExtractElementID(t, "DocumentRef-doc2:SPDXRef-file2", true, "") + // test with invalid ID in this document + helperForExtractElementID(t, "a:SPDXRef-file1", true, "") + helperForExtractElementID(t, "file1", true, "") + helperForExtractElementID(t, "SPDXRef-", true, "") + // test with invalid ID in another document + helperForExtractElementID(t, "DocumentRef-doc2", true, "") + helperForExtractElementID(t, "DocumentRef-doc2:", true, "") + helperForExtractElementID(t, "DocumentRef-doc2:SPDXRef-", true, "") + helperForExtractElementID(t, "DocumentRef-doc2:a", true, "") + helperForExtractElementID(t, "DocumentRef-:", true, "") + helperForExtractElementID(t, "DocumentRef-:SPDXRef-file1", true, "") +} + +func helperForExtractElementID(t *testing.T, tst string, wantErr bool, wantElt string) { + eID, err := extractElementID(tst) + if err != nil && wantErr == false { + t.Errorf("testing %v: expected nil error, got %v", tst, err) + } + if err == nil && wantErr == true { + t.Errorf("testing %v: expected non-nil error, got nil", tst) + } + if eID != spdx.ElementID(wantElt) { + if wantElt == "" { + t.Errorf("testing %v: want emptyString for ElementRefID, got %v", tst, eID) + } else { + t.Errorf("testing %v: want %v for ElementRefID, got %v", tst, wantElt, eID) + } + } +} diff --git a/tvsaver/saver2v1/save_document.go b/tvsaver/saver2v1/save_document.go index 97891f5..e573ad3 100644 --- a/tvsaver/saver2v1/save_document.go +++ b/tvsaver/saver2v1/save_document.go @@ -22,12 +22,15 @@ func RenderDocument2_1(doc *spdx.Document2_1, w io.Writer) error { renderCreationInfo2_1(doc.CreationInfo, w) - for _, pkg := range doc.Packages { - if pkg.IsUnpackaged == true { - fmt.Fprintf(w, "##### Unpackaged files\n\n") - } else { - fmt.Fprintf(w, "##### Package: %s\n\n", pkg.PackageName) + if len(doc.UnpackagedFiles) > 0 { + fmt.Fprintf(w, "##### Unpackaged files\n\n") + for _, fi := range doc.UnpackagedFiles { + renderFile2_1(fi, w) } + } + + for _, pkg := range doc.Packages { + fmt.Fprintf(w, "##### Package: %s\n\n", pkg.PackageName) renderPackage2_1(pkg, w) } diff --git a/tvsaver/saver2v1/save_document_test.go b/tvsaver/saver2v1/save_document_test.go index fd47b9c..f75093d 100644 --- a/tvsaver/saver2v1/save_document_test.go +++ b/tvsaver/saver2v1/save_document_test.go @@ -25,7 +25,7 @@ func TestSaver2_1DocumentSavesText(t *testing.T) { Created: "2018-10-10T06:20:00Z", } - // Package 1: unpackaged files + // unpackaged files f1 := &spdx.File2_1{ FileName: "/tmp/whatever1.txt", FileSPDXIdentifier: "SPDXRef-File1231", @@ -44,15 +44,12 @@ func TestSaver2_1DocumentSavesText(t *testing.T) { FileCopyrightText: "Copyright (c) John Doe", } - pkgUn := &spdx.Package2_1{ - IsUnpackaged: true, - Files: []*spdx.File2_1{ - f1, - f2, - }, + unFiles := map[spdx.ElementID]*spdx.File2_1{ + "File1231": f1, + "File1232": f2, } - // Package 2: packaged files with snippets + // Package 1: packaged files with snippets sn1 := &spdx.Snippet2_1{ SnippetSPDXIdentifier: "SPDXRef-Snippet19", SnippetFromFileSPDXIdentifier: "SPDXRef-FileHasSnippets", @@ -82,9 +79,9 @@ func TestSaver2_1DocumentSavesText(t *testing.T) { "WTFPL", }, FileCopyrightText: "Copyright (c) Jane Doe", - Snippets: []*spdx.Snippet2_1{ - sn1, - sn2, + Snippets: map[spdx.ElementID]*spdx.Snippet2_1{ + "Snippet19": sn1, + "Snippet20": sn2, }, } @@ -98,7 +95,6 @@ func TestSaver2_1DocumentSavesText(t *testing.T) { } pkgWith := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: "p1", PackageSPDXIdentifier: "SPDXRef-p1", PackageDownloadLocation: "http://example.com/p1/p1-0.1.0-master.tar.gz", @@ -114,9 +110,9 @@ func TestSaver2_1DocumentSavesText(t *testing.T) { }, PackageLicenseDeclared: "Apache-2.0 OR GPL-2.0-or-later", PackageCopyrightText: "Copyright (c) John Doe, Inc.", - Files: []*spdx.File2_1{ - f3, - f4, + Files: map[spdx.ElementID]*spdx.File2_1{ + "FileHasSnippets": f3, + "FileAnother": f4, }, } @@ -189,10 +185,10 @@ blah blah blah blah`, // now, build the document doc := &spdx.Document2_1{ CreationInfo: ci, - Packages: []*spdx.Package2_1{ - pkgUn, + Packages: map[spdx.ElementID]*spdx.Package2_1{ pkgWith, }, + UnpackagedFiles: unFiles, OtherLicenses: []*spdx.OtherLicense2_1{ ol1, ol2, diff --git a/tvsaver/saver2v1/save_package.go b/tvsaver/saver2v1/save_package.go index 3c83547..080c362 100644 --- a/tvsaver/saver2v1/save_package.go +++ b/tvsaver/saver2v1/save_package.go @@ -10,106 +10,104 @@ import ( ) func renderPackage2_1(pkg *spdx.Package2_1, w io.Writer) error { - if pkg.IsUnpackaged == false { - if pkg.PackageName != "" { - fmt.Fprintf(w, "PackageName: %s\n", pkg.PackageName) - } - if pkg.PackageSPDXIdentifier != "" { - fmt.Fprintf(w, "SPDXID: %s\n", pkg.PackageSPDXIdentifier) - } - if pkg.PackageVersion != "" { - fmt.Fprintf(w, "PackageVersion: %s\n", pkg.PackageVersion) - } - if pkg.PackageFileName != "" { - fmt.Fprintf(w, "PackageFileName: %s\n", pkg.PackageFileName) - } - if pkg.PackageSupplierPerson != "" { - fmt.Fprintf(w, "PackageSupplier: Person: %s\n", pkg.PackageSupplierPerson) - } - if pkg.PackageSupplierOrganization != "" { - fmt.Fprintf(w, "PackageSupplier: Organization: %s\n", pkg.PackageSupplierOrganization) - } - if pkg.PackageSupplierNOASSERTION == true { - fmt.Fprintf(w, "PackageSupplier: NOASSERTION\n") - } - if pkg.PackageOriginatorPerson != "" { - fmt.Fprintf(w, "PackageOriginator: Person: %s\n", pkg.PackageOriginatorPerson) - } - if pkg.PackageOriginatorOrganization != "" { - fmt.Fprintf(w, "PackageOriginator: Organization: %s\n", pkg.PackageOriginatorOrganization) - } - if pkg.PackageOriginatorNOASSERTION == true { - fmt.Fprintf(w, "PackageOriginator: NOASSERTION\n") - } - if pkg.PackageDownloadLocation != "" { - fmt.Fprintf(w, "PackageDownloadLocation: %s\n", pkg.PackageDownloadLocation) + if pkg.PackageName != "" { + fmt.Fprintf(w, "PackageName: %s\n", pkg.PackageName) + } + if pkg.PackageSPDXIdentifier != "" { + fmt.Fprintf(w, "SPDXID: %s\n", pkg.PackageSPDXIdentifier) + } + if pkg.PackageVersion != "" { + fmt.Fprintf(w, "PackageVersion: %s\n", pkg.PackageVersion) + } + if pkg.PackageFileName != "" { + fmt.Fprintf(w, "PackageFileName: %s\n", pkg.PackageFileName) + } + if pkg.PackageSupplierPerson != "" { + fmt.Fprintf(w, "PackageSupplier: Person: %s\n", pkg.PackageSupplierPerson) + } + if pkg.PackageSupplierOrganization != "" { + fmt.Fprintf(w, "PackageSupplier: Organization: %s\n", pkg.PackageSupplierOrganization) + } + if pkg.PackageSupplierNOASSERTION == true { + fmt.Fprintf(w, "PackageSupplier: NOASSERTION\n") + } + if pkg.PackageOriginatorPerson != "" { + fmt.Fprintf(w, "PackageOriginator: Person: %s\n", pkg.PackageOriginatorPerson) + } + if pkg.PackageOriginatorOrganization != "" { + fmt.Fprintf(w, "PackageOriginator: Organization: %s\n", pkg.PackageOriginatorOrganization) + } + if pkg.PackageOriginatorNOASSERTION == true { + fmt.Fprintf(w, "PackageOriginator: NOASSERTION\n") + } + if pkg.PackageDownloadLocation != "" { + fmt.Fprintf(w, "PackageDownloadLocation: %s\n", pkg.PackageDownloadLocation) + } + if pkg.FilesAnalyzed == true { + if pkg.IsFilesAnalyzedTagPresent == true { + fmt.Fprintf(w, "FilesAnalyzed: true\n") } - if pkg.FilesAnalyzed == true { - if pkg.IsFilesAnalyzedTagPresent == true { - fmt.Fprintf(w, "FilesAnalyzed: true\n") - } + } else { + fmt.Fprintf(w, "FilesAnalyzed: false\n") + } + if pkg.PackageVerificationCode != "" && pkg.FilesAnalyzed == true { + if pkg.PackageVerificationCodeExcludedFile == "" { + fmt.Fprintf(w, "PackageVerificationCode: %s\n", pkg.PackageVerificationCode) } else { - fmt.Fprintf(w, "FilesAnalyzed: false\n") - } - if pkg.PackageVerificationCode != "" && pkg.FilesAnalyzed == true { - if pkg.PackageVerificationCodeExcludedFile == "" { - fmt.Fprintf(w, "PackageVerificationCode: %s\n", pkg.PackageVerificationCode) - } else { - fmt.Fprintf(w, "PackageVerificationCode: %s (excludes %s)\n", pkg.PackageVerificationCode, pkg.PackageVerificationCodeExcludedFile) - } - } - if pkg.PackageChecksumSHA1 != "" { - fmt.Fprintf(w, "PackageChecksum: SHA1: %s\n", pkg.PackageChecksumSHA1) - } - if pkg.PackageChecksumSHA256 != "" { - fmt.Fprintf(w, "PackageChecksum: SHA256: %s\n", pkg.PackageChecksumSHA256) - } - if pkg.PackageChecksumMD5 != "" { - fmt.Fprintf(w, "PackageChecksum: MD5: %s\n", pkg.PackageChecksumMD5) + fmt.Fprintf(w, "PackageVerificationCode: %s (excludes %s)\n", pkg.PackageVerificationCode, pkg.PackageVerificationCodeExcludedFile) } - if pkg.PackageHomePage != "" { - fmt.Fprintf(w, "PackageHomePage: %s\n", pkg.PackageHomePage) - } - if pkg.PackageSourceInfo != "" { - fmt.Fprintf(w, "PackageSourceInfo: %s\n", textify(pkg.PackageSourceInfo)) - } - if pkg.PackageLicenseConcluded != "" { - fmt.Fprintf(w, "PackageLicenseConcluded: %s\n", pkg.PackageLicenseConcluded) - } - if pkg.FilesAnalyzed == true { - for _, s := range pkg.PackageLicenseInfoFromFiles { - fmt.Fprintf(w, "PackageLicenseInfoFromFiles: %s\n", s) - } - } - if pkg.PackageLicenseDeclared != "" { - fmt.Fprintf(w, "PackageLicenseDeclared: %s\n", pkg.PackageLicenseDeclared) - } - if pkg.PackageLicenseComments != "" { - fmt.Fprintf(w, "PackageLicenseComments: %s\n", textify(pkg.PackageLicenseComments)) - } - if pkg.PackageCopyrightText != "" { - fmt.Fprintf(w, "PackageCopyrightText: %s\n", pkg.PackageCopyrightText) - } - if pkg.PackageSummary != "" { - fmt.Fprintf(w, "PackageSummary: %s\n", textify(pkg.PackageSummary)) - } - if pkg.PackageDescription != "" { - fmt.Fprintf(w, "PackageDescription: %s\n", textify(pkg.PackageDescription)) - } - if pkg.PackageComment != "" { - fmt.Fprintf(w, "PackageComment: %s\n", textify(pkg.PackageComment)) + } + if pkg.PackageChecksumSHA1 != "" { + fmt.Fprintf(w, "PackageChecksum: SHA1: %s\n", pkg.PackageChecksumSHA1) + } + if pkg.PackageChecksumSHA256 != "" { + fmt.Fprintf(w, "PackageChecksum: SHA256: %s\n", pkg.PackageChecksumSHA256) + } + if pkg.PackageChecksumMD5 != "" { + fmt.Fprintf(w, "PackageChecksum: MD5: %s\n", pkg.PackageChecksumMD5) + } + if pkg.PackageHomePage != "" { + fmt.Fprintf(w, "PackageHomePage: %s\n", pkg.PackageHomePage) + } + if pkg.PackageSourceInfo != "" { + fmt.Fprintf(w, "PackageSourceInfo: %s\n", textify(pkg.PackageSourceInfo)) + } + if pkg.PackageLicenseConcluded != "" { + fmt.Fprintf(w, "PackageLicenseConcluded: %s\n", pkg.PackageLicenseConcluded) + } + if pkg.FilesAnalyzed == true { + for _, s := range pkg.PackageLicenseInfoFromFiles { + fmt.Fprintf(w, "PackageLicenseInfoFromFiles: %s\n", s) } - for _, s := range pkg.PackageExternalReferences { - fmt.Fprintf(w, "ExternalRef: %s %s %s\n", s.Category, s.RefType, s.Locator) - if s.ExternalRefComment != "" { - fmt.Fprintf(w, "ExternalRefComment: %s\n", s.ExternalRefComment) - } + } + if pkg.PackageLicenseDeclared != "" { + fmt.Fprintf(w, "PackageLicenseDeclared: %s\n", pkg.PackageLicenseDeclared) + } + if pkg.PackageLicenseComments != "" { + fmt.Fprintf(w, "PackageLicenseComments: %s\n", textify(pkg.PackageLicenseComments)) + } + if pkg.PackageCopyrightText != "" { + fmt.Fprintf(w, "PackageCopyrightText: %s\n", pkg.PackageCopyrightText) + } + if pkg.PackageSummary != "" { + fmt.Fprintf(w, "PackageSummary: %s\n", textify(pkg.PackageSummary)) + } + if pkg.PackageDescription != "" { + fmt.Fprintf(w, "PackageDescription: %s\n", textify(pkg.PackageDescription)) + } + if pkg.PackageComment != "" { + fmt.Fprintf(w, "PackageComment: %s\n", textify(pkg.PackageComment)) + } + for _, s := range pkg.PackageExternalReferences { + fmt.Fprintf(w, "ExternalRef: %s %s %s\n", s.Category, s.RefType, s.Locator) + if s.ExternalRefComment != "" { + fmt.Fprintf(w, "ExternalRefComment: %s\n", s.ExternalRefComment) } - - fmt.Fprintf(w, "\n") } - // also render any files for this package, even if unpackaged + fmt.Fprintf(w, "\n") + + // also render any files for this package for _, f := range pkg.Files { renderFile2_1(f, w) } diff --git a/tvsaver/saver2v1/save_package_test.go b/tvsaver/saver2v1/save_package_test.go index deb80a8..3dbd985 100644 --- a/tvsaver/saver2v1/save_package_test.go +++ b/tvsaver/saver2v1/save_package_test.go @@ -40,7 +40,6 @@ func TestSaver2_1PackageSavesTextCombo1(t *testing.T) { } pkg := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: "p1", PackageSPDXIdentifier: "SPDXRef-p1", PackageVersion: "0.1.0", @@ -129,7 +128,6 @@ func TestSaver2_1PackageSavesTextCombo2(t *testing.T) { // PackageVerificationCodeExcludedFile is empty pkg := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: "p1", PackageSPDXIdentifier: "SPDXRef-p1", PackageVersion: "0.1.0", @@ -207,7 +205,6 @@ func TestSaver2_1PackageSavesTextCombo3(t *testing.T) { // PackageVerificationCodeExcludedFile is empty pkg := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: "p1", PackageSPDXIdentifier: "SPDXRef-p1", PackageVersion: "0.1.0", @@ -281,7 +278,6 @@ PackageComment: this is a comment comment func TestSaver2_1PackageSaveOmitsOptionalFieldsIfEmpty(t *testing.T) { pkg := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: "p1", PackageSPDXIdentifier: "SPDXRef-p1", PackageDownloadLocation: "http://example.com/p1/p1-0.1.0-master.tar.gz", @@ -346,7 +342,6 @@ func TestSaver2_1PackageSavesFilesIfPresent(t *testing.T) { } pkg := &spdx.Package2_1{ - IsUnpackaged: false, PackageName: "p1", PackageSPDXIdentifier: "SPDXRef-p1", PackageDownloadLocation: "http://example.com/p1/p1-0.1.0-master.tar.gz", @@ -428,12 +423,9 @@ func TestSaver2_1PackageSavesUnpackagedFilesIfPresent(t *testing.T) { FileCopyrightText: "Copyright (c) John Doe", } - pkg := &spdx.Package2_1{ - IsUnpackaged: true, - Files: []*spdx.File2_1{ - f1, - f2, - }, + unFiles := map[spdx.ElementID]*spdx.File2_1{ + "File1231": f1, + "File1232": f2, } // what we want to get, as a buffer of bytes @@ -455,29 +447,11 @@ FileCopyrightText: Copyright (c) John Doe // render as buffer of bytes var got bytes.Buffer - err := renderPackage2_1(pkg, &got) - if err != nil { - t.Errorf("Expected nil error, got %v", err) - } - - // check that they match - c := bytes.Compare(want.Bytes(), got.Bytes()) - if c != 0 { - t.Errorf("Expected %v, got %v", want.String(), got.String()) - } -} - -func TestSaver2_1PackageSavesNothingIfUnpackagedAndNoFilesPresent(t *testing.T) { - pkg := &spdx.Package2_1{IsUnpackaged: true} - - // what we want to get, as a buffer of bytes - want := bytes.NewBufferString("") - - // render as buffer of bytes - var got bytes.Buffer - err := renderPackage2_1(pkg, &got) - if err != nil { - t.Errorf("Expected nil error, got %v", err) + for fi := unFiles { + err := renderFile2_1(fi, &got) + if err != nil { + t.Errorf("Expected nil error, got %v", err) + } } // check that they match |