1// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 2package parser2v3 3 4import ( 5 "testing" 6 7 "github.com/spdx/tools-golang/spdx/v2_3" 8) 9 10// ===== Parser creation info state change tests ===== 11func TestParser2_3CIMovesToPackageAfterParsingPackageNameTag(t *testing.T) { 12 parser := tvParser2_3{ 13 doc: &v2_3.Document{}, 14 st: psCreationInfo2_3, 15 } 16 pkgName := "testPkg" 17 err := parser.parsePair2_3("PackageName", pkgName) 18 if err != nil { 19 t.Errorf("got error when calling parsePair2_3: %v", err) 20 } 21 // state should be correct 22 if parser.st != psPackage2_3 { 23 t.Errorf("parser is in state %v, expected %v", parser.st, psPackage2_3) 24 } 25 // and a package should be created 26 if parser.pkg == nil { 27 t.Fatalf("parser didn't create new package") 28 } 29 // and the package name should be as expected 30 if parser.pkg.PackageName != pkgName { 31 t.Errorf("expected package name %s, got %s", pkgName, parser.pkg.PackageName) 32 } 33 // and the package should default to true for FilesAnalyzed 34 if parser.pkg.FilesAnalyzed != true { 35 t.Errorf("expected FilesAnalyzed to default to true, got false") 36 } 37 if parser.pkg.IsFilesAnalyzedTagPresent != false { 38 t.Errorf("expected IsFilesAnalyzedTagPresent to default to false, got true") 39 } 40 // and the package should NOT be in the SPDX Document's map of packages, 41 // because it doesn't have an SPDX identifier yet 42 if len(parser.doc.Packages) != 0 { 43 t.Errorf("expected 0 packages, got %d", len(parser.doc.Packages)) 44 } 45} 46 47func TestParser2_3CIMovesToFileAfterParsingFileNameTagWithNoPackages(t *testing.T) { 48 parser := tvParser2_3{ 49 doc: &v2_3.Document{}, 50 st: psCreationInfo2_3, 51 } 52 err := parser.parsePair2_3("FileName", "testFile") 53 if err != nil { 54 t.Errorf("got error when calling parsePair2_3: %v", err) 55 } 56 // state should be correct 57 if parser.st != psFile2_3 { 58 t.Errorf("parser is in state %v, expected %v", parser.st, psFile2_3) 59 } 60 // and current package should be nil, meaning Files are placed in the 61 // Files map instead of in a Package 62 if parser.pkg != nil { 63 t.Fatalf("expected pkg to be nil, got non-nil pkg") 64 } 65} 66 67func TestParser2_3CIMovesToOtherLicenseAfterParsingLicenseIDTag(t *testing.T) { 68 parser := tvParser2_3{ 69 doc: &v2_3.Document{}, 70 st: psCreationInfo2_3, 71 } 72 err := parser.parsePair2_3("LicenseID", "LicenseRef-TestLic") 73 if err != nil { 74 t.Errorf("got error when calling parsePair2_3: %v", err) 75 } 76 if parser.st != psOtherLicense2_3 { 77 t.Errorf("parser is in state %v, expected %v", parser.st, psOtherLicense2_3) 78 } 79} 80 81func TestParser2_3CIMovesToReviewAfterParsingReviewerTag(t *testing.T) { 82 parser := tvParser2_3{ 83 doc: &v2_3.Document{}, 84 st: psCreationInfo2_3, 85 } 86 err := parser.parsePair2_3("Reviewer", "Person: John Doe") 87 if err != nil { 88 t.Errorf("got error when calling parsePair2_3: %v", err) 89 } 90 if parser.st != psReview2_3 { 91 t.Errorf("parser is in state %v, expected %v", parser.st, psReview2_3) 92 } 93} 94 95func TestParser2_3CIStaysAfterParsingRelationshipTags(t *testing.T) { 96 parser := tvParser2_3{ 97 doc: &v2_3.Document{}, 98 st: psCreationInfo2_3, 99 } 100 101 err := parser.parsePair2_3("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-else") 102 if err != nil { 103 t.Errorf("got error when calling parsePair2_3: %v", err) 104 } 105 if parser.st != psCreationInfo2_3 { 106 t.Errorf("parser is in state %v, expected %v", parser.st, psCreationInfo2_3) 107 } 108 109 err = parser.parsePair2_3("RelationshipComment", "blah") 110 if err != nil { 111 t.Errorf("got error when calling parsePair2_3: %v", err) 112 } 113 if parser.st != psCreationInfo2_3 { 114 t.Errorf("parser is in state %v, expected %v", parser.st, psCreationInfo2_3) 115 } 116} 117 118func TestParser2_3CIStaysAfterParsingAnnotationTags(t *testing.T) { 119 parser := tvParser2_3{ 120 doc: &v2_3.Document{}, 121 st: psCreationInfo2_3, 122 } 123 124 err := parser.parsePair2_3("Annotator", "Person: John Doe ()") 125 if err != nil { 126 t.Errorf("got error when calling parsePair2_3: %v", err) 127 } 128 if parser.st != psCreationInfo2_3 { 129 t.Errorf("parser is in state %v, expected %v", parser.st, psCreationInfo2_3) 130 } 131 132 err = parser.parsePair2_3("AnnotationDate", "2018-09-15T00:36:00Z") 133 if err != nil { 134 t.Errorf("got error when calling parsePair2_3: %v", err) 135 } 136 if parser.st != psCreationInfo2_3 { 137 t.Errorf("parser is in state %v, expected %v", parser.st, psCreationInfo2_3) 138 } 139 140 err = parser.parsePair2_3("AnnotationType", "REVIEW") 141 if err != nil { 142 t.Errorf("got error when calling parsePair2_3: %v", err) 143 } 144 if parser.st != psCreationInfo2_3 { 145 t.Errorf("parser is in state %v, expected %v", parser.st, psCreationInfo2_3) 146 } 147 148 err = parser.parsePair2_3("SPDXREF", "SPDXRef-45") 149 if err != nil { 150 t.Errorf("got error when calling parsePair2_3: %v", err) 151 } 152 if parser.st != psCreationInfo2_3 { 153 t.Errorf("parser is in state %v, expected %v", parser.st, psCreationInfo2_3) 154 } 155 156 err = parser.parsePair2_3("AnnotationComment", "i guess i had something to say about this spdx file") 157 if err != nil { 158 t.Errorf("got error when calling parsePair2_3: %v", err) 159 } 160 if parser.st != psCreationInfo2_3 { 161 t.Errorf("parser is in state %v, expected %v", parser.st, psCreationInfo2_3) 162 } 163} 164 165func TestParser2_3FailsParsingCreationInfoWithInvalidState(t *testing.T) { 166 parser := tvParser2_3{ 167 doc: &v2_3.Document{}, 168 st: psPackage2_3, 169 } 170 err := parser.parsePairFromCreationInfo2_3("SPDXVersion", "SPDX-2.3") 171 if err == nil { 172 t.Errorf("expected non-nil error, got nil") 173 } 174} 175 176// ===== Creation Info section tests ===== 177func TestParser2_3HasCreationInfoAfterCallToParseFirstTag(t *testing.T) { 178 parser := tvParser2_3{ 179 doc: &v2_3.Document{}, 180 st: psCreationInfo2_3, 181 } 182 err := parser.parsePairFromCreationInfo2_3("LicenseListVersion", "3.9") 183 if err != nil { 184 t.Errorf("got error when calling parsePairFromCreationInfo2_3: %v", err) 185 } 186 if parser.doc.CreationInfo == nil { 187 t.Errorf("doc.CreationInfo is still nil after parsing first pair") 188 } 189} 190 191func TestParser2_3CanParseCreationInfoTags(t *testing.T) { 192 parser := tvParser2_3{ 193 doc: &v2_3.Document{}, 194 st: psCreationInfo2_3, 195 } 196 197 // License List Version 198 err := parser.parsePairFromCreationInfo2_3("LicenseListVersion", "2.3") 199 if err != nil { 200 t.Errorf("expected nil error, got %v", err) 201 } 202 if parser.doc.CreationInfo.LicenseListVersion != "2.3" { 203 t.Errorf("got %v for LicenseListVersion", parser.doc.CreationInfo.LicenseListVersion) 204 } 205 206 // Creators: Persons 207 refPersons := []string{ 208 "Person: Person A", 209 "Person: Person B", 210 } 211 err = parser.parsePairFromCreationInfo2_3("Creator", refPersons[0]) 212 if err != nil { 213 t.Errorf("expected nil error, got %v", err) 214 } 215 err = parser.parsePairFromCreationInfo2_3("Creator", refPersons[1]) 216 if err != nil { 217 t.Errorf("expected nil error, got %v", err) 218 } 219 if len(parser.doc.CreationInfo.Creators) != 2 || 220 parser.doc.CreationInfo.Creators[0].Creator != "Person A" || 221 parser.doc.CreationInfo.Creators[1].Creator != "Person B" { 222 t.Errorf("got %v for CreatorPersons", parser.doc.CreationInfo.Creators) 223 } 224 225 // Creators: Organizations 226 refOrgs := []string{ 227 "Organization: Organization A", 228 "Organization: Organization B", 229 } 230 err = parser.parsePairFromCreationInfo2_3("Creator", refOrgs[0]) 231 if err != nil { 232 t.Errorf("expected nil error, got %v", err) 233 } 234 err = parser.parsePairFromCreationInfo2_3("Creator", refOrgs[1]) 235 if err != nil { 236 t.Errorf("expected nil error, got %v", err) 237 } 238 if len(parser.doc.CreationInfo.Creators) != 4 || 239 parser.doc.CreationInfo.Creators[2].Creator != "Organization A" || 240 parser.doc.CreationInfo.Creators[3].Creator != "Organization B" { 241 t.Errorf("got %v for CreatorOrganizations", parser.doc.CreationInfo.Creators) 242 } 243 244 // Creators: Tools 245 refTools := []string{ 246 "Tool: Tool A", 247 "Tool: Tool B", 248 } 249 err = parser.parsePairFromCreationInfo2_3("Creator", refTools[0]) 250 if err != nil { 251 t.Errorf("expected nil error, got %v", err) 252 } 253 err = parser.parsePairFromCreationInfo2_3("Creator", refTools[1]) 254 if err != nil { 255 t.Errorf("expected nil error, got %v", err) 256 } 257 if len(parser.doc.CreationInfo.Creators) != 6 || 258 parser.doc.CreationInfo.Creators[4].Creator != "Tool A" || 259 parser.doc.CreationInfo.Creators[5].Creator != "Tool B" { 260 t.Errorf("got %v for CreatorTools", parser.doc.CreationInfo.Creators) 261 } 262 263 // Created date 264 err = parser.parsePairFromCreationInfo2_3("Created", "2018-09-10T11:46:00Z") 265 if err != nil { 266 t.Errorf("expected nil error, got %v", err) 267 } 268 if parser.doc.CreationInfo.Created != "2018-09-10T11:46:00Z" { 269 t.Errorf("got %v for Created", parser.doc.CreationInfo.Created) 270 } 271 272 // Creator Comment 273 err = parser.parsePairFromCreationInfo2_3("CreatorComment", "Blah whatever") 274 if err != nil { 275 t.Errorf("expected nil error, got %v", err) 276 } 277 if parser.doc.CreationInfo.CreatorComment != "Blah whatever" { 278 t.Errorf("got %v for CreatorComment", parser.doc.CreationInfo.CreatorComment) 279 } 280} 281 282func TestParser2_3InvalidCreatorTagsFail(t *testing.T) { 283 parser := tvParser2_3{ 284 doc: &v2_3.Document{}, 285 st: psCreationInfo2_3, 286 } 287 288 err := parser.parsePairFromCreationInfo2_3("Creator", "blah: somebody") 289 if err == nil { 290 t.Errorf("expected error from parsing invalid Creator format, got nil") 291 } 292 293 err = parser.parsePairFromCreationInfo2_3("Creator", "Tool with no colons") 294 if err == nil { 295 t.Errorf("expected error from parsing invalid Creator format, got nil") 296 } 297} 298 299func TestParser2_3CreatorTagWithMultipleColonsPasses(t *testing.T) { 300 parser := tvParser2_3{ 301 doc: &v2_3.Document{}, 302 st: psCreationInfo2_3, 303 } 304 305 err := parser.parsePairFromCreationInfo2_3("Creator", "Tool: tool1:2:3") 306 if err != nil { 307 t.Errorf("unexpected error from parsing valid Creator format") 308 } 309} 310 311func TestParser2_3CIUnknownTagFails(t *testing.T) { 312 parser := tvParser2_3{ 313 doc: &v2_3.Document{}, 314 st: psCreationInfo2_3, 315 } 316 317 err := parser.parsePairFromCreationInfo2_3("blah", "something") 318 if err == nil { 319 t.Errorf("expected error from parsing unknown tag") 320 } 321} 322 323func TestParser2_3CICreatesRelationship(t *testing.T) { 324 parser := tvParser2_3{ 325 doc: &v2_3.Document{}, 326 st: psCreationInfo2_3, 327 } 328 329 err := parser.parsePair2_3("Relationship", "SPDXRef-blah CONTAINS SPDXRef-blah-whatever") 330 if err != nil { 331 t.Errorf("got error when calling parsePair2_3: %v", err) 332 } 333 if parser.rln == nil { 334 t.Fatalf("parser didn't create and point to Relationship struct") 335 } 336 if parser.rln != parser.doc.Relationships[0] { 337 t.Errorf("pointer to new Relationship doesn't match idx 0 for doc.Relationships[]") 338 } 339} 340 341func TestParser2_3CICreatesAnnotation(t *testing.T) { 342 parser := tvParser2_3{ 343 doc: &v2_3.Document{}, 344 st: psCreationInfo2_3, 345 } 346 347 err := parser.parsePair2_3("Annotator", "Person: John Doe ()") 348 if err != nil { 349 t.Errorf("got error when calling parsePair2_3: %v", err) 350 } 351 if parser.ann == nil { 352 t.Fatalf("parser didn't create and point to Annotation struct") 353 } 354 if parser.ann != parser.doc.Annotations[0] { 355 t.Errorf("pointer to new Annotation doesn't match idx 0 for doc.Annotations[]") 356 } 357} 358 359// ===== Helper function tests ===== 360 361func TestCanExtractExternalDocumentReference(t *testing.T) { 362 refstring := "DocumentRef-spdx-tool-1.2 http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301 SHA1:d6a770ba38583ed4bb4525bd96e50461655d2759" 363 wantDocumentRefID := "spdx-tool-1.2" 364 wantURI := "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301" 365 wantAlg := "SHA1" 366 wantChecksum := "d6a770ba38583ed4bb4525bd96e50461655d2759" 367 368 gotDocumentRefID, gotURI, gotAlg, gotChecksum, err := extractExternalDocumentReference(refstring) 369 if err != nil { 370 t.Errorf("got non-nil error: %v", err) 371 } 372 if wantDocumentRefID != gotDocumentRefID { 373 t.Errorf("wanted document ref ID %s, got %s", wantDocumentRefID, gotDocumentRefID) 374 } 375 if wantURI != gotURI { 376 t.Errorf("wanted URI %s, got %s", wantURI, gotURI) 377 } 378 if wantAlg != gotAlg { 379 t.Errorf("wanted alg %s, got %s", wantAlg, gotAlg) 380 } 381 if wantChecksum != gotChecksum { 382 t.Errorf("wanted checksum %s, got %s", wantChecksum, gotChecksum) 383 } 384} 385 386func TestCanExtractExternalDocumentReferenceWithExtraWhitespace(t *testing.T) { 387 refstring := " DocumentRef-spdx-tool-1.2 \t http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301 \t SHA1: \t d6a770ba38583ed4bb4525bd96e50461655d2759" 388 wantDocumentRefID := "spdx-tool-1.2" 389 wantURI := "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301" 390 wantAlg := "SHA1" 391 wantChecksum := "d6a770ba38583ed4bb4525bd96e50461655d2759" 392 393 gotDocumentRefID, gotURI, gotAlg, gotChecksum, err := extractExternalDocumentReference(refstring) 394 if err != nil { 395 t.Errorf("got non-nil error: %v", err) 396 } 397 if wantDocumentRefID != gotDocumentRefID { 398 t.Errorf("wanted document ref ID %s, got %s", wantDocumentRefID, gotDocumentRefID) 399 } 400 if wantURI != gotURI { 401 t.Errorf("wanted URI %s, got %s", wantURI, gotURI) 402 } 403 if wantAlg != gotAlg { 404 t.Errorf("wanted alg %s, got %s", wantAlg, gotAlg) 405 } 406 if wantChecksum != gotChecksum { 407 t.Errorf("wanted checksum %s, got %s", wantChecksum, gotChecksum) 408 } 409} 410 411func TestFailsExternalDocumentReferenceWithInvalidFormats(t *testing.T) { 412 invalidRefs := []string{ 413 "whoops", 414 "DocumentRef-", 415 "DocumentRef- ", 416 "DocumentRef-spdx-tool-1.2 http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301", 417 "DocumentRef-spdx-tool-1.2 http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301 d6a770ba38583ed4bb4525bd96e50461655d2759", 418 "DocumentRef-spdx-tool-1.2", 419 "spdx-tool-1.2 http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301 SHA1:d6a770ba38583ed4bb4525bd96e50461655d2759", 420 } 421 for _, refstring := range invalidRefs { 422 _, _, _, _, err := extractExternalDocumentReference(refstring) 423 if err == nil { 424 t.Errorf("expected non-nil error for %s, got nil", refstring) 425 } 426 } 427} 428