aboutsummaryrefslogtreecommitdiff
path: root/tvloader/parser2v2
diff options
context:
space:
mode:
authorSteve Winslow <steve@swinslow.net>2021-03-20 17:16:31 -0400
committerSteve Winslow <steve@swinslow.net>2021-03-20 17:16:31 -0400
commit6234aa66fed08ee03a2be31ec177152cefeedfd2 (patch)
tree8f62b5948cffe465927cc06a6eb83c815ac39d04 /tvloader/parser2v2
parentad870ed6f31eb4918018af143611a5a2dc6aa798 (diff)
downloadspdx-tools-6234aa66fed08ee03a2be31ec177152cefeedfd2.tar.gz
Fix special IDs for right-side 2.2 Relationships
In SPDX 2.2, the right-hand side of Relationships are not limited to SPDX IDs; they can also include the special values NONE and NOASSERTION. To handle these, since Golang doesn't (to my knowledge) have a concept of union types, and since I don't want to use interface{}, this commit instead adds a new SpecialID field to DocElementID. When SpecialID is non-empty, it should be treated as being a "special" ID value, and DocumentRefID / ElementRefID should be ignored. (Unfortunately, we can't just use ElementRefID == "NONE", etc. for this purpose, because in theory an SPDX document could define the identifier SPDXRef-NONE to mean something. Even though they really, really shouldn't do that.) This commit updates tvloader and tvsaver to appropriately handle the possibility of NONE and NOASSERTION for this field. Signed-off-by: Steve Winslow <steve@swinslow.net>
Diffstat (limited to 'tvloader/parser2v2')
-rw-r--r--tvloader/parser2v2/parse_relationship.go4
-rw-r--r--tvloader/parser2v2/parse_relationship_test.go31
-rw-r--r--tvloader/parser2v2/util.go17
-rw-r--r--tvloader/parser2v2/util_test.go47
4 files changed, 97 insertions, 2 deletions
diff --git a/tvloader/parser2v2/parse_relationship.go b/tvloader/parser2v2/parse_relationship.go
index 28e5b72..092b554 100644
--- a/tvloader/parser2v2/parse_relationship.go
+++ b/tvloader/parser2v2/parse_relationship.go
@@ -35,7 +35,9 @@ func (parser *tvParser2_2) parsePairForRelationship2_2(tag string, value string)
}
parser.rln.RefA = aID
parser.rln.Relationship = strings.TrimSpace(rp[1])
- bID, err := extractDocElementID(strings.TrimSpace(rp[2]))
+ // NONE and NOASSERTION are permitted on right side
+ permittedSpecial := []string{"NONE", "NOASSERTION"}
+ bID, err := extractDocElementSpecial(strings.TrimSpace(rp[2]), permittedSpecial)
if err != nil {
return err
}
diff --git a/tvloader/parser2v2/parse_relationship_test.go b/tvloader/parser2v2/parse_relationship_test.go
index 1312cc5..0e6c013 100644
--- a/tvloader/parser2v2/parse_relationship_test.go
+++ b/tvloader/parser2v2/parse_relationship_test.go
@@ -152,6 +152,37 @@ func TestParser2_2InvalidRelationshipTagsInvalidRefIDs(t *testing.T) {
}
}
+func TestParser2_2SpecialValuesValidForRightSideOfRelationship(t *testing.T) {
+ parser := tvParser2_2{
+ doc: &spdx.Document2_2{},
+ st: psCreationInfo2_2,
+ }
+
+ // NONE in right side of relationship should pass
+ err := parser.parsePair2_2("Relationship", "SPDXRef-a CONTAINS NONE")
+ if err != nil {
+ t.Errorf("expected nil error for CONTAINS NONE, got %v", err)
+ }
+
+ // NOASSERTION in right side of relationship should pass
+ err = parser.parsePair2_2("Relationship", "SPDXRef-a CONTAINS NOASSERTION")
+ if err != nil {
+ t.Errorf("expected nil error for CONTAINS NOASSERTION, got %v", err)
+ }
+
+ // NONE in left side of relationship should fail
+ err = parser.parsePair2_2("Relationship", "NONE CONTAINS SPDXRef-a")
+ if err == nil {
+ t.Errorf("expected non-nil error for NONE CONTAINS, got nil")
+ }
+
+ // NOASSERTION in left side of relationship should fail
+ err = parser.parsePair2_2("Relationship", "NOASSERTION CONTAINS SPDXRef-a")
+ if err == nil {
+ t.Errorf("expected non-nil error for NOASSERTION CONTAINS, got nil")
+ }
+}
+
func TestParser2_2FailsToParseUnknownTagInRelationshipSection(t *testing.T) {
parser := tvParser2_2{
doc: &spdx.Document2_2{},
diff --git a/tvloader/parser2v2/util.go b/tvloader/parser2v2/util.go
index 691fe4e..6676846 100644
--- a/tvloader/parser2v2/util.go
+++ b/tvloader/parser2v2/util.go
@@ -73,6 +73,23 @@ func extractDocElementID(value string) (spdx.DocElementID, error) {
return spdx.DocElementID{DocumentRefID: docRefID, ElementRefID: spdx.ElementID(eltRefID)}, nil
}
+// used to extract SPDXRef values from an SPDX Identifier, OR "special" strings
+// from a specified set of permitted values. The primary use case for this is
+// the right-hand side of Relationships, where beginning in SPDX 2.2 the values
+// "NONE" and "NOASSERTION" are permitted. If the value does not match one of
+// the specified permitted values, it will fall back to the ordinary
+// DocElementID extractor.
+func extractDocElementSpecial(value string, permittedSpecial []string) (spdx.DocElementID, error) {
+ // check value against special set first
+ for _, sp := range permittedSpecial {
+ if sp == value {
+ return spdx.DocElementID{SpecialID: sp}, nil
+ }
+ }
+ // not found, fall back to regular search
+ return extractDocElementID(value)
+}
+
// 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.
diff --git a/tvloader/parser2v2/util_test.go b/tvloader/parser2v2/util_test.go
index 9f63364..e2f75d7 100644
--- a/tvloader/parser2v2/util_test.go
+++ b/tvloader/parser2v2/util_test.go
@@ -67,13 +67,58 @@ func helperForExtractDocElementID(t *testing.T, tst string, wantErr bool, wantDo
}
if deID.ElementRefID != spdx.ElementID(wantElt) {
if wantElt == "" {
- t.Errorf("testing %v: want emptyString for ElementRefID, got %v", tst, deID.ElementRefID)
+ t.Errorf("testing %v: want empty string for ElementRefID, got %v", tst, deID.ElementRefID)
} else {
t.Errorf("testing %v: want %v for ElementRefID, got %v", tst, wantElt, deID.ElementRefID)
}
}
}
+func TestCanExtractSpecialDocumentIDs(t *testing.T) {
+ permittedSpecial := []string{"NONE", "NOASSERTION"}
+ // test with valid special values
+ helperForExtractDocElementSpecial(t, permittedSpecial, "NONE", false, "", "", "NONE")
+ helperForExtractDocElementSpecial(t, permittedSpecial, "NOASSERTION", false, "", "", "NOASSERTION")
+ // test with valid regular IDs
+ helperForExtractDocElementSpecial(t, permittedSpecial, "SPDXRef-file1", false, "", "file1", "")
+ helperForExtractDocElementSpecial(t, permittedSpecial, "DocumentRef-doc2:SPDXRef-file2", false, "doc2", "file2", "")
+ helperForExtractDocElementSpecial(t, permittedSpecial, "a:SPDXRef-file1", true, "", "", "")
+ helperForExtractDocElementSpecial(t, permittedSpecial, "DocumentRef-doc2", true, "", "", "")
+ // test with invalid other words not on permitted list
+ helperForExtractDocElementSpecial(t, permittedSpecial, "FOO", true, "", "", "")
+}
+
+func helperForExtractDocElementSpecial(t *testing.T, permittedSpecial []string, tst string, wantErr bool, wantDoc string, wantElt string, wantSpecial string) {
+ deID, err := extractDocElementSpecial(tst, permittedSpecial)
+ 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 empty string for ElementRefID, got %v", tst, deID.ElementRefID)
+ } else {
+ t.Errorf("testing %v: want %v for ElementRefID, got %v", tst, wantElt, deID.ElementRefID)
+ }
+ }
+ if deID.SpecialID != wantSpecial {
+ if wantSpecial == "" {
+ t.Errorf("testing %v: want empty string for SpecialID, got %v", tst, deID.SpecialID)
+ } else {
+ t.Errorf("testing %v: want %v for SpecialID, got %v", tst, wantSpecial, deID.SpecialID)
+ }
+ }
+}
+
func TestCanExtractElementRefsOnlyFromID(t *testing.T) {
// test with valid ID in this document
helperForExtractElementID(t, "SPDXRef-file1", false, "file1")