From f652816522876a038fed37d869039ee38311f253 Mon Sep 17 00:00:00 2001 From: RishabhBhatnagar Date: Thu, 27 Aug 2020 13:02:50 +0530 Subject: Add Tests And Bug Fixes For parse_file.go - noticeText can now assume two states: SPDX_NOASSERTION and string - add tests for parse_file.go file - relationship now returns the MUX error - getRelationshipTypeFromURI fixed - add constant for NS_SPDX+"Checksum" (SPDX_CHECKSUM_CAPITALIZED) - file Dependency set to the file being populated - add extended support for licenseInfoInFile Signed-off-by: RishabhBhatnagar --- rdfloader/parser2v2/constants.go | 1 + rdfloader/parser2v2/parse_file.go | 60 ++- rdfloader/parser2v2/parse_file_test.go | 701 ++++++++++++++++++++++++++++++ rdfloader/parser2v2/parse_relationship.go | 26 +- 4 files changed, 766 insertions(+), 22 deletions(-) create mode 100644 rdfloader/parser2v2/parse_file_test.go diff --git a/rdfloader/parser2v2/constants.go b/rdfloader/parser2v2/constants.go index 27a807c..dea7e68 100644 --- a/rdfloader/parser2v2/constants.go +++ b/rdfloader/parser2v2/constants.go @@ -32,6 +32,7 @@ var ( SPDX_SPDX_DOCUMENT = NS_SPDX + "spdxDocument" SPDX_SPDX_DOCUMENT_CAPITALIZED = NS_SPDX + "SpdxDocument" SPDX_CHECKSUM = NS_SPDX + "checksum" + SPDX_CHECKSUM_CAPITALIZED = NS_SPDX + "Checksum" SPDX_ANNOTATION_TYPE = NS_SPDX + "annotationType" SPDX_ANNOTATION_TYPE_OTHER = NS_SPDX + "annotationType_other" SPDX_ANNOTATION_TYPE_REVIEW = NS_SPDX + "annotationType_review" diff --git a/rdfloader/parser2v2/parse_file.go b/rdfloader/parser2v2/parse_file.go index c91db64..a080808 100644 --- a/rdfloader/parser2v2/parse_file.go +++ b/rdfloader/parser2v2/parse_file.go @@ -13,7 +13,7 @@ import ( func (parser *rdfParser2_2) getFileFromNode(fileNode *gordfParser.Node) (file *spdx.File2_2, err error) { file = &spdx.File2_2{} - err = setFileIdentifier(fileNode.ID, file, parser) // 4.2 + err = setFileIdentifier(fileNode.ID, file) // 4.2 if err != nil { return nil, err } @@ -25,7 +25,7 @@ func (parser *rdfParser2_2) getFileFromNode(fileNode *gordfParser.Node) (file *s file.FileName = subTriple.Object.ID case SPDX_NAME: // cardinality: exactly 1 - // todo: check where it will be set in the golang-tools spdx-data-model + // TODO: check where it will be set in the golang-tools spdx-data-model case RDF_TYPE: // cardinality: exactly 1 case SPDX_FILE_TYPE: // 4.3 @@ -45,16 +45,20 @@ func (parser *rdfParser2_2) getFileFromNode(fileNode *gordfParser.Node) (file *s file.LicenseConcluded = anyLicense.ToLicenseString() case SPDX_LICENSE_INFO_IN_FILE: // 4.6 // cardinality: min 1 - lastPart := getLastPartOfURI(subTriple.Object.ID) - file.LicenseInfoInFile = append(file.LicenseInfoInFile, lastPart) + lic, err := parser.getLicenseInfoInFileFromNode(subTriple.Object) + if err != nil { + return nil, fmt.Errorf("error parsing licenseInfoInFile: %v", err) + } + file.LicenseInfoInFile = append(file.LicenseInfoInFile, lic.ToLicenseString()) case SPDX_LICENSE_COMMENTS: // 4.7 // cardinality: max 1 file.LicenseComments = subTriple.Object.ID + // TODO: allow copyright text to be of type NOASSERTION case SPDX_COPYRIGHT_TEXT: // 4.8 // cardinality: exactly 1 file.FileCopyrightText = subTriple.Object.ID case SPDX_LICENSE_INFO_FROM_FILES: - // todo: implement it. It is not defined in the tools-golang model. + // TODO: implement it. It is not defined in the tools-golang model. // deprecated artifactOf (see sections 4.9, 4.10, 4.11) case SPDX_ARTIFACT_OF: // cardinality: min 0 @@ -66,23 +70,26 @@ func (parser *rdfParser2_2) getFileFromNode(fileNode *gordfParser.Node) (file *s file.FileComment = subTriple.Object.ID case SPDX_NOTICE_TEXT: // 4.13 // cardinality: max 1 - file.FileNotice = subTriple.Object.ID + file.FileNotice = getNoticeTextFromNode(subTriple.Object) case SPDX_FILE_CONTRIBUTOR: // 4.14 // cardinality: min 0 file.FileContributor = append(file.FileContributor, subTriple.Object.ID) case SPDX_FILE_DEPENDENCY: // cardinality: min 0 - file, err := parser.getFileFromNode(subTriple.Object) + newFile, err := parser.getFileFromNode(subTriple.Object) if err != nil { return nil, fmt.Errorf("error setting a file dependency in a file: %v", err) } + file.FileDependencies = append(file.FileDependencies, string(newFile.FileSPDXIdentifier)) parser.files[file.FileSPDXIdentifier] = file case SPDX_ATTRIBUTION_TEXT: // cardinality: min 0 file.FileAttributionTexts = append(file.FileAttributionTexts, subTriple.Object.ID) - case SPDX_ANNOTATION: // unknown section + case SPDX_ANNOTATION: + // cardinality: min 0 err = parser.parseAnnotationFromNode(subTriple.Object) - case SPDX_RELATIONSHIP: // unknown section + case SPDX_RELATIONSHIP: + // cardinality: min 0 err = parser.parseRelationship(subTriple) default: return nil, fmt.Errorf("unknown triple predicate id %s", subTriple.Predicate.ID) @@ -97,7 +104,7 @@ func (parser *rdfParser2_2) getFileFromNode(fileNode *gordfParser.Node) (file *s func (parser *rdfParser2_2) setFileChecksumFromNode(file *spdx.File2_2, checksumNode *gordfParser.Node) error { checksumAlgorithm, checksumValue, err := parser.getChecksumFromNode(checksumNode) if err != nil { - return nil + return fmt.Errorf("error parsing checksumNode of a file: %v", err) } switch checksumAlgorithm { case "MD5": @@ -109,7 +116,7 @@ func (parser *rdfParser2_2) setFileChecksumFromNode(file *spdx.File2_2, checksum case "": return fmt.Errorf("empty checksum algorithm and value") default: - return fmt.Errorf("unknown checksumAlgorithm %s while parsing a file", checksumAlgorithm) + return fmt.Errorf("unknown checksumAlgorithm %s for a file", checksumAlgorithm) } return nil } @@ -135,6 +142,7 @@ func (parser *rdfParser2_2) getArtifactFromNode(node *gordfParser.Node) (*spdx.A return artifactOf, nil } +// TODO: check if the filetype is valid. func (parser *rdfParser2_2) getFileTypeFromUri(uri string) (string, error) { // fileType is given as a uri. for example: http://spdx.org/rdf/terms#fileType_text lastPart := getLastPartOfURI(uri) @@ -155,7 +163,7 @@ func (parser *rdfParser2_2) setUnpackagedFiles() { } } -func setFileIdentifier(idURI string, file *spdx.File2_2, parser *rdfParser2_2) (err error) { +func setFileIdentifier(idURI string, file *spdx.File2_2) (err error) { idURI = strings.TrimSpace(idURI) uriFragment := getLastPartOfURI(idURI) file.FileSPDXIdentifier, err = ExtractElementID(uriFragment) @@ -164,3 +172,31 @@ func setFileIdentifier(idURI string, file *spdx.File2_2, parser *rdfParser2_2) ( } return nil } + +func getNoticeTextFromNode(node *gordfParser.Node) string { + switch node.ID { + case SPDX_NOASSERTION_CAPS, SPDX_NOASSERTION_SMALL: + return "NOASSERTION" + default: + return node.ID + } +} + +func (parser *rdfParser2_2) getLicenseInfoInFileFromNode(node *gordfParser.Node) (AnyLicenseInfo, error) { + // LicenseInfoInFile can either be NONE | NOASSERTION | SimpleLicensingInfo + // return type is kept as AnyLicenseInfo because, we can have + // either SpecialLicense or SimpleLicensingInfo as the output + switch node.ID { + case SPDX_NOASSERTION_CAPS, SPDX_NOASSERTION_SMALL: + return SpecialLicense{ + value: NOASSERTION, + }, nil + case SPDX_NONE_CAPS, SPDX_NONE_SMALL: + return SpecialLicense{ + value: NONE, + }, nil + } + + // the license must be a SimpleLicense + return parser.getSimpleLicensingInfoFromNode(node) +} diff --git a/rdfloader/parser2v2/parse_file_test.go b/rdfloader/parser2v2/parse_file_test.go new file mode 100644 index 0000000..e9fa16c --- /dev/null +++ b/rdfloader/parser2v2/parse_file_test.go @@ -0,0 +1,701 @@ +package parser2v2 + +import ( + "bufio" + gordfParser "github.com/RishabhBhatnagar/gordf/rdfloader/parser" + rdfloader2 "github.com/RishabhBhatnagar/gordf/rdfloader/xmlreader" + gordfWriter "github.com/RishabhBhatnagar/gordf/rdfwriter" + "github.com/spdx/tools-golang/spdx" + "strings" + "testing" +) + +// content is the tags within the rdf:RDF tag +// pads the content with the enclosing rdf:RDF tag +func wrapIntoTemplate(content string) string { + header := `` + footer := `` + return header + content + footer +} + +func parserFromBodyContent(content string) (*rdfParser2_2, error) { + rdfContent := wrapIntoTemplate(content) + xmlreader := rdfloader2.XMLReaderFromFileObject(bufio.NewReader(strings.NewReader(rdfContent))) + rootBlock, err := xmlreader.Read() + if err != nil { + return nil, err + } + parser := gordfParser.New() + err = parser.Parse(rootBlock) + if err != nil { + return nil, err + } + nodeToTriples := gordfWriter.GetNodeToTriples(parser.Triples) + rdfParser := NewParser2_2(parser, nodeToTriples) + return rdfParser, err +} + +func Test_rdfParser2_2_getArtifactFromNode(t *testing.T) { + // TestCase 1: artifactOf without project URI + rdfParser, err := parserFromBodyContent( + ` + + + http://www.openjena.org/ + Jena + + + `) + if err != nil { + t.Errorf("unexpected error while parsing a valid example: %v", err) + } + artifactOfNode := gordfWriter.FilterTriples(rdfParser.gordfParserObj.Triples, nil, &SPDX_ARTIFACT_OF, nil)[0].Object + artifact, err := rdfParser.getArtifactFromNode(artifactOfNode) + if err != nil { + t.Errorf("error parsing a valid artifactOf node: %v", err) + } + if artifact.Name != "Jena" { + t.Errorf("expected name of artifact: %s, found: %s", "Jena", artifact.Name) + } + expectedHomePage := "http://www.openjena.org/" + if artifact.HomePage != expectedHomePage { + t.Errorf("wrong artifact homepage. Expected: %s, found: %s", expectedHomePage, artifact.HomePage) + } + if artifact.URI != "" { + t.Errorf("wrong artifact URI. Expected: %s, found: %s", "", artifact.URI) + } + + // TestCase 2: artifactOf with a Project URI + rdfParser, err = parserFromBodyContent( + ` + + + http://www.openjena.org/ + Jena + + + `) + if err != nil { + t.Errorf("unexpected error while parsing a valid example: %v", err) + } + artifactOfNode = gordfWriter.FilterTriples(rdfParser.gordfParserObj.Triples, nil, &SPDX_ARTIFACT_OF, nil)[0].Object + artifact, err = rdfParser.getArtifactFromNode(artifactOfNode) + if err != nil { + t.Errorf("error parsing a valid artifactOf node: %v", err) + } + expectedURI := "http://subversion.apache.org/doap.rdf" + if artifact.URI != expectedURI { + t.Errorf("wrong artifact URI. Expected: %s, found: %s", expectedURI, artifact.URI) + } + + // TestCase 3: artifactOf with unknown predicate + rdfParser, err = parserFromBodyContent( + ` + + + http://www.openjena.org/ + Jena + + + + `) + if err != nil { + t.Errorf("unexpected error while parsing a valid example: %v", err) + } + artifactOfNode = gordfWriter.FilterTriples(rdfParser.gordfParserObj.Triples, nil, &SPDX_ARTIFACT_OF, nil)[0].Object + _, err = rdfParser.getArtifactFromNode(artifactOfNode) + if err == nil { + t.Errorf("must've raised an error for an invalid predicate") + } +} + +func Test_rdfParser2_2_getFileTypeFromUri(t *testing.T) { + rdfParser, _ := parserFromBodyContent(``) + + // TestCase 1: Valid fileType URI: + fileTypeURI := "http://spdx.org/rdf/terms#fileType_source" + fileType, err := rdfParser.getFileTypeFromUri(fileTypeURI) + if err != nil { + t.Errorf("error in a valid example: %v", err) + } + if fileType != "source" { + t.Errorf("wrong fileType. expected: %s, found: %s", "source", fileType) + } + + // TestCase 2: Invalid fileType URI format. + fileTypeURI = "http://spdx.org/rdf/terms#source" + fileType, err = rdfParser.getFileTypeFromUri(fileTypeURI) + if err == nil { + t.Error("should've raised an error for invalid fileType") + } +} + +func Test_rdfParser2_2_setUnpackagedFiles(t *testing.T) { + // unpackaged files are the files which are not associated with any package + // file associated with a package sets parser.assocWithPackage[fileID] to true. + rdfParser, _ := parserFromBodyContent(``) + file1 := &spdx.File2_2{FileSPDXIdentifier: spdx.ElementID("file1")} + file2 := &spdx.File2_2{FileSPDXIdentifier: spdx.ElementID("file2")} + file3 := &spdx.File2_2{FileSPDXIdentifier: spdx.ElementID("file3")} + + // setting files to the document as if it were to be set when it was parsed using triples. + rdfParser.files[file1.FileSPDXIdentifier] = file1 + rdfParser.files[file2.FileSPDXIdentifier] = file2 + rdfParser.files[file3.FileSPDXIdentifier] = file3 + + // assuming file1 is associated with a package + rdfParser.assocWithPackage[file1.FileSPDXIdentifier] = true + + rdfParser.setUnpackagedFiles() + + // after setting unpackaged files, parser.doc.UnpackagedFiles must've file2 and file3 + if n := len(rdfParser.doc.UnpackagedFiles); n != 2 { + t.Errorf("unpackage files should've had 2 files, found %d files", n) + } + + // checking if the unpackagedFiles contain only file2 & file3. + for fileID, _ := range rdfParser.doc.UnpackagedFiles { + switch string(fileID) { + case "file2", "file3": + continue + default: + t.Errorf("unexpected file with id %s found in unpackaged files", fileID) + } + } +} + +func Test_setFileIdentifier(t *testing.T) { + file := &spdx.File2_2{} + + // TestCase 1: valid example + err := setFileIdentifier("http://spdx.org/documents/spdx-toolsv2.1.7-SNAPSHOT#SPDXRef-129", file) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if file.FileSPDXIdentifier != "129" { + t.Errorf("expected %s, found: %s", "129", file.FileSPDXIdentifier) + } + + // TestCase 2: invalid example + err = setFileIdentifier("http://spdx.org/documents/spdx-toolsv2.1.7-SNAPSHOT#129", file) + if err == nil { + t.Errorf("should've raised an error for an invalid example") + } +} + +func Test_rdfParser2_2_setFileChecksumFromNode(t *testing.T) { + // TestCase 1: md5 checksum + parser, _ := parserFromBodyContent(` + + + d2356e0fe1c0b85285d83c6b2ad51b5f + + `) + checksumNode := gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_CHECKSUM_CAPITALIZED)[0].Subject + file := &spdx.File2_2{} + err := parser.setFileChecksumFromNode(file, checksumNode) + if err != nil { + t.Errorf("error parsing a valid checksum node") + } + checksumValue := "d2356e0fe1c0b85285d83c6b2ad51b5f" + if file.FileChecksumMD5 != checksumValue { + t.Errorf("wrong checksum value for md5. Expected: %s, found: %s", checksumValue, file.FileChecksumMD5) + } + if file.FileChecksumSHA1 != "" { + t.Errorf("incorrectly set sha1, should've been empty") + } + if file.FileChecksumSHA256 != "" { + t.Errorf("incorrectly set sha256, should've been empty") + } + + // TestCase 2: valid sha1 checksum + parser, _ = parserFromBodyContent(` + + + d2356e0fe1c0b85285d83c6b2ad51b5f + + `) + checksumNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_CHECKSUM_CAPITALIZED)[0].Subject + file = &spdx.File2_2{} + err = parser.setFileChecksumFromNode(file, checksumNode) + if err != nil { + t.Errorf("error parsing a valid checksum node") + } + if file.FileChecksumSHA1 != checksumValue { + t.Errorf("wrong checksum value for sha1. Expected: %s, found: %s", checksumValue, file.FileChecksumSHA1) + } + if file.FileChecksumMD5 != "" { + t.Errorf("incorrectly set md5, should've been empty") + } + if file.FileChecksumSHA256 != "" { + t.Errorf("incorrectly set sha256, should've been empty") + } + + // TestCase 3: valid sha256 checksum + parser, _ = parserFromBodyContent(` + + + d2356e0fe1c0b85285d83c6b2ad51b5f + + `) + checksumNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_CHECKSUM_CAPITALIZED)[0].Subject + file = &spdx.File2_2{} + err = parser.setFileChecksumFromNode(file, checksumNode) + if err != nil { + t.Errorf("error parsing a valid checksum node") + } + if file.FileChecksumSHA256 != checksumValue { + t.Errorf("wrong checksum value for sha256. Expected: %s, found: %s", checksumValue, file.FileChecksumSHA256) + } + if file.FileChecksumMD5 != "" { + t.Errorf("incorrectly set md5, should've been empty") + } + if file.FileChecksumSHA1 != "" { + t.Errorf("incorrectly set sha1, should've been empty") + } + + // TestCase 4: checksum node without one of the mandatory attributes + parser, _ = parserFromBodyContent(` + + d2356e0fe1c0b85285d83c6b2ad51b5f + + `) + checksumNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_CHECKSUM_CAPITALIZED)[0].Subject + file = &spdx.File2_2{} + err = parser.setFileChecksumFromNode(file, checksumNode) + if err == nil { + t.Errorf("should've raised an error parsing an invalid checksum node") + } + + // TestCase 5: invalid checksum algorithm + parser, _ = parserFromBodyContent(` + + + d2356e0fe1c0b85285d83c6b2ad51b5f + + `) + checksumNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_CHECKSUM_CAPITALIZED)[0].Subject + file = &spdx.File2_2{} + err = parser.setFileChecksumFromNode(file, checksumNode) + if err == nil { + t.Errorf("should've raised an error parsing an invalid checksum node") + } + + // TestCase 6: valid checksum algorithm which is invalid for file (like md4, md6, sha384, etc.) + parser, _ = parserFromBodyContent(` + + + d2356e0fe1c0b85285d83c6b2ad51b5f + + `) + checksumNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_CHECKSUM_CAPITALIZED)[0].Subject + file = &spdx.File2_2{} + err = parser.setFileChecksumFromNode(file, checksumNode) + if err == nil { + t.Errorf("should've raised an error parsing an invalid checksum algorithm for a file") + } +} + +func Test_rdfParser2_2_getFileFromNode(t *testing.T) { + // TestCase 1: file with invalid id + parser, _ := parserFromBodyContent(` + + `) + fileNode := gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_FILE)[0].Subject + _, err := parser.getFileFromNode(fileNode) + if err == nil { + t.Errorf("should've raised an error stating invalid file ID") + } + + // TestCase 2: invalid fileType + parser, _ = parserFromBodyContent(` + + + + `) + fileNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_FILE)[0].Subject + _, err = parser.getFileFromNode(fileNode) + if err == nil { + t.Errorf("should've raised an error stating invalid fileType") + } + + // TestCase 3: invalid file checksum + parser, _ = parserFromBodyContent(` + + + + + 0a3a0e1ab72b7c132f5021c538a7a3ea6d539bcd + + + + `) + fileNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_FILE)[0].Subject + _, err = parser.getFileFromNode(fileNode) + if err == nil { + t.Errorf("should've raised an error stating invalid checksum") + } + + // TestCase 4: invalid license concluded + parser, _ = parserFromBodyContent(` + + + + `) + fileNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_FILE)[0].Subject + _, err = parser.getFileFromNode(fileNode) + if err == nil { + t.Errorf("should've raised an error stating invalid license Concluded") + } + + // TestCase 5: invalid artifactOf attribute + parser, _ = parserFromBodyContent(` + + + + + Jena + + + + `) + fileNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_FILE)[0].Subject + _, err = parser.getFileFromNode(fileNode) + if err == nil { + t.Errorf("should've raised an error stating invalid artifactOf predicate") + } + + // TestCase 6: invalid file dependency + parser, _ = parserFromBodyContent(` + + + + `) + fileNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_FILE)[0].Subject + _, err = parser.getFileFromNode(fileNode) + if err == nil { + t.Errorf("should've raised an error stating invalid fileDependency") + } + + // TestCase 7: invalid annotation with unknown predicate + parser, _ = parserFromBodyContent(` + + + + + + + + `) + fileNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_FILE)[0].Subject + _, err = parser.getFileFromNode(fileNode) + if err == nil { + t.Errorf("should've raised an error stating invalid annotation predicate") + } + + // TestCase 8: invalid relationship + parser, _ = parserFromBodyContent(` + + + + + + + + `) + fileNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_FILE)[0].Subject + _, err = parser.getFileFromNode(fileNode) + if err == nil { + t.Errorf("should've raised an error stating invalid relationship Type") + } + + // TestCase 8: unknown predicate + parser, _ = parserFromBodyContent(` + + + + `) + fileNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_FILE)[0].Subject + _, err = parser.getFileFromNode(fileNode) + if err == nil { + t.Errorf("should've raised an error stating invalid predicate for a file") + } + + // TestCase 9: all valid attribute and it's values. + parser, _ = parserFromBodyContent(` + + time-1.9/ChangeLog + + + + + + 0a3a0e1ab72b7c132f5021c538a7a3ea6d539bcd + + + + + no comments + from spdx file + + + http://www.openjena.org/ + Jena + + + no comments + + Some Organization + + attribution text + + + 2011-01-29T18:30:22Z + File level annotation copied from a spdx document + Person: File Commenter + + + + + + + + + + + `) + fileNode = gordfWriter.FilterTriples(parser.gordfParserObj.Triples, nil, &RDF_TYPE, &SPDX_FILE)[0].Subject + file, err := parser.getFileFromNode(fileNode) + if err != nil { + t.Errorf("unexpected error parsing a valid file: %v", err) + } + + // checking each and every attribute of the obtained file. + + expectedFileName := "time-1.9/ChangeLog" + if file.FileName != expectedFileName { + t.Errorf("expected %s, found %s", expectedFileName, file.FileName) + } + + if len(file.FileType) != 1 { + t.Errorf("given file should have 1 fileType attribute. found %d", len(file.FileType)) + } + expectedFileType := "source" + if file.FileType[0] != expectedFileType { + t.Errorf("expected %s, found %s", expectedFileType, file.FileType) + } + + expectedChecksum := "0a3a0e1ab72b7c132f5021c538a7a3ea6d539bcd" + if file.FileChecksumSHA1 != expectedChecksum { + t.Errorf("expected %s, found %s", expectedChecksum, file.FileChecksumSHA1) + } + + expectedLicenseConcluded := "NOASSERTION" + if file.LicenseConcluded != expectedLicenseConcluded { + t.Errorf("expected %s, found %s", expectedLicenseConcluded, file.LicenseConcluded) + } + + if len(file.LicenseInfoInFile) != 1 { + t.Errorf("given file should have 1 licenseInfoInFile attribute. found %d", len(file.LicenseInfoInFile)) + } + expectedLicenseInfoInFile := "NOASSERTION" + if file.LicenseInfoInFile[0] != expectedLicenseInfoInFile { + t.Errorf("expected %s, found %s", expectedLicenseInfoInFile, file.LicenseInfoInFile[0]) + } + + expectedLicenseComments := "no comments" + if file.LicenseComments != expectedLicenseComments { + t.Errorf("expected %s, found %s", expectedLicenseComments, file.LicenseComments) + } + + expectedCopyrightText := "from spdx file" + if file.FileCopyrightText != expectedCopyrightText { + t.Errorf("expected %s, found %s", expectedCopyrightText, file.FileCopyrightText) + } + + if n := len(file.ArtifactOfProjects); n != 1 { + t.Errorf("given file should have 1 artifactOfProjects attribute. found %d", n) + } + artifactOf := file.ArtifactOfProjects[0] + expectedHomePage := "http://www.openjena.org/" + if artifactOf.HomePage != expectedHomePage { + t.Errorf("expected %s, found %s", expectedHomePage, artifactOf.HomePage) + } + if artifactOf.Name != "Jena" { + t.Errorf("expected %s, found %s", "Jena", artifactOf.Name) + } + if artifactOf.URI != "" { + t.Errorf("expected artifactOf uri to be empty, found %s", artifactOf.URI) + } + + expectedFileComment := "no comments" + if file.FileComment != expectedFileComment { + t.Errorf("expected %s, found %s", expectedFileName, file.FileComment) + } + + expectedNoticeText := "NOASSERTION" + if file.FileNotice != expectedNoticeText { + t.Errorf("expected %s, found %s", expectedNoticeText, file.FileNotice) + } + + if n := len(file.FileContributor); n != 1 { + t.Errorf("given file should have 1 fileContributor. found %d", n) + } + expectedFileContributor := "Some Organization" + if file.FileContributor[0] != expectedFileContributor { + t.Errorf("expected %s, found %s", expectedFileContributor, file.FileContributor) + } + + if n := len(file.FileDependencies); n != 1 { + t.Errorf("given file should have 1 fileDependencies. found %d", n) + } + expectedFileDependency := "CommonsLangSrc" + if file.FileDependencies[0] != expectedFileDependency { + t.Errorf("expected %s, found %s", expectedFileDependency, file.FileDependencies[0]) + } + + if n := len(file.FileAttributionTexts); n != 1 { + t.Errorf("given file should have 1 attributionText. found %d", n) + } + expectedAttributionText := "attribution text" + if file.FileAttributionTexts[0] != expectedAttributionText { + t.Errorf("expected %s, found %s", expectedAttributionText, file.FileAttributionTexts[0]) + } + + if n := len(parser.doc.Annotations); n != 1 { + t.Errorf("doc should've had 1 annotation. found %d", n) + } + ann := parser.doc.Annotations[0] + expectedAnnDate := "2011-01-29T18:30:22Z" + if ann.AnnotationDate != expectedAnnDate { + t.Errorf("expected %s, found %s", expectedAnnDate, ann.AnnotationDate) + } + expectedAnnComment := "File level annotation copied from a spdx document" + if ann.AnnotationComment != expectedAnnComment { + t.Errorf("expected %s, found %s", expectedAnnComment, ann.AnnotationComment) + } + expectedAnnotationType := "OTHER" + if ann.AnnotationType != expectedAnnotationType { + t.Errorf("expected %s, found %s", expectedAnnotationType, ann.AnnotationType) + } + expectedAnnotator := "File Commenter" + if ann.Annotator != expectedAnnotator { + t.Errorf("expected %s, found %s", expectedAnnotator, ann.Annotator) + } + expectedAnnotatorType := "Person" + if ann.AnnotationType != expectedAnnotationType { + t.Errorf("expected %s, found %s", expectedAnnotatorType, ann.AnnotatorType) + } + + if n := len(parser.doc.Relationships); n != 1 { + t.Errorf("doc should've had 1 relation. found %d", n) + } + reln := parser.doc.Relationships[0] + expectedRefAEID := "item177" + if reln.RefA.DocumentRefID != "" { + t.Errorf("expected refA.DocumentRefID to be empty, found %s", reln.RefA.DocumentRefID) + } + if string(reln.RefA.ElementRefID) != expectedRefAEID { + t.Errorf("expected %s, found %s", expectedRefAEID, reln.RefA.ElementRefID) + } + expectedRefBEID := "Package" + if reln.RefB.DocumentRefID != "" { + t.Errorf("expected refB.DocumentRefID to be empty, found %s", reln.RefB.DocumentRefID) + } + if string(reln.RefB.ElementRefID) != expectedRefBEID { + t.Errorf("expected %s, found %s", expectedRefBEID, reln.RefB.ElementRefID) + } + expectedRelationType := "contains" + if reln.Relationship != expectedRelationType { + t.Errorf("expected %s, found %s", expectedRefBEID, reln.RefB.ElementRefID) + } + if reln.RelationshipComment != "" { + t.Errorf("expected relationship comment to be empty, found %s", reln.RelationshipComment) + } +} + +func Test_getNoticeTextFromNode(t *testing.T) { + // TestCase 1: SPDX_NOASSERTION_SMALL must return NOASSERTION + output := getNoticeTextFromNode(&gordfParser.Node{ + NodeType: gordfParser.IRI, + ID: SPDX_NOASSERTION_SMALL, + }) + if strings.ToUpper(output) != "NOASSERTION" { + t.Errorf("expected NOASSERTION, found %s", strings.ToUpper(output)) + } + + // TestCase 2: SPDX_NOASSERTION_CAPS must return NOASSERTION + output = getNoticeTextFromNode(&gordfParser.Node{ + NodeType: gordfParser.IRI, + ID: SPDX_NOASSERTION_CAPS, + }) + if strings.ToUpper(output) != "NOASSERTION" { + t.Errorf("expected NOASSERTION, found %s", strings.ToUpper(output)) + } + + // TestCase 3: not a NOASSERTION must return the field verbatim + // TestCase 1: SPDX_NOASSERTION_SMALL must return NOASSERTION + output = getNoticeTextFromNode(&gordfParser.Node{ + NodeType: gordfParser.IRI, + ID: "text", + }) + if output != "text" { + t.Errorf("expected text, found %s", output) + } +} + +func Test_rdfParser2_2_getLicenseInfoInFileFromNode(t *testing.T) { + parser, _ := parserFromBodyContent(``) + + // TestCase 1: noassertion License + lic, err := parser.getLicenseInfoInFileFromNode(&gordfParser.Node{ + NodeType: gordfParser.RESOURCELITERAL, + ID: SPDX_NOASSERTION_CAPS, + }) + if err != nil { + t.Errorf("error parsing a valid license") + } + if lic.ToLicenseString() != "NOASSERTION" { + t.Errorf("expected %s, found %s", "NOASSERTION", lic.ToLicenseString()) + } + + // TestCase 2: none License + lic, err = parser.getLicenseInfoInFileFromNode(&gordfParser.Node{ + NodeType: gordfParser.RESOURCELITERAL, + ID: SPDX_NONE_CAPS, + }) + if err != nil { + t.Errorf("error parsing a valid license") + } + if lic.ToLicenseString() != "NONE" { + t.Errorf("expected %s, found %s", "NONE", lic.ToLicenseString()) + } + + // TestCase 3: invalid license + // TestCase 1: noassertion License + node := &gordfParser.Node{ + NodeType: gordfParser.BLANK, + ID: "N0", + } + parser.gordfParserObj.Triples = append(parser.gordfParserObj.Triples, &gordfParser.Triple{ + Subject: node, + Predicate: &gordfParser.Node{ + NodeType: gordfParser.IRI, + ID: NS_SPDX + "invalidAttribute", + }, + Object: &gordfParser.Node{ + NodeType: gordfParser.IRI, + ID: NS_SPDX + "weirdLicense", + }, + }) + lic, err = parser.getLicenseInfoInFileFromNode(node) + if err == nil { + t.Errorf("should've raised an error parsing an invalid license") + } +} diff --git a/rdfloader/parser2v2/parse_relationship.go b/rdfloader/parser2v2/parse_relationship.go index b51105b..b4c4704 100644 --- a/rdfloader/parser2v2/parse_relationship.go +++ b/rdfloader/parser2v2/parse_relationship.go @@ -26,7 +26,7 @@ func (parser *rdfParser2_2) parseRelationship(triple *gordfParser.Triple) (err e switch subTriple.Predicate.ID { case SPDX_RELATIONSHIP_TYPE: // cardinality: exactly 1 - reln.Relationship, err = getRelationshipType(subTriple.Object.ID) + reln.Relationship, err = getRelationshipTypeFromURI(subTriple.Object.ID) case RDF_TYPE: // cardinality: exactly 1 continue @@ -57,6 +57,9 @@ func (parser *rdfParser2_2) parseRelationship(triple *gordfParser.Triple) (err e default: return fmt.Errorf("unexpected predicate id: %s", subTriple.Predicate.ID) } + if err != nil { + return err + } } parser.doc.Relationships = append(parser.doc.Relationships, &reln) return nil @@ -102,6 +105,8 @@ func (parser *rdfParser2_2) parseRelatedElementFromTriple(reln spdx.Relationship return nil } + +// references like RefA and RefB of any relationship func getReferenceFromURI(uri string) (spdx.DocElementID, error) { fragment := getLastPartOfURI(uri) switch strings.ToLower(strings.TrimSpace(fragment)) { @@ -114,18 +119,19 @@ func getReferenceFromURI(uri string) (spdx.DocElementID, error) { return ExtractDocElementID(fragment) } -func getRelationshipType(relnType string) (string, error) { - relnType = strings.TrimSpace(relnType) - if !strings.HasPrefix(relnType, PREFIX_RELATIONSHIP_TYPE) { - return "", fmt.Errorf("relationshipType must start with %s. found %s", PREFIX_RELATIONSHIP_TYPE, relnType) +func getRelationshipTypeFromURI(relnTypeURI string) (string, error) { + relnTypeURI = strings.TrimSpace(relnTypeURI) + lastPart := getLastPartOfURI(relnTypeURI) + if !strings.HasPrefix(lastPart, PREFIX_RELATIONSHIP_TYPE) { + return "", fmt.Errorf("relationshipType must start with %s. found %s", PREFIX_RELATIONSHIP_TYPE, lastPart) } - relnType = strings.TrimPrefix(relnType, PREFIX_RELATIONSHIP_TYPE) + lastPart = strings.TrimPrefix(lastPart, PREFIX_RELATIONSHIP_TYPE) - relnType = strings.TrimSpace(relnType) + lastPart = strings.TrimSpace(lastPart) for _, validRelationshipType := range AllRelationshipTypes() { - if relnType == validRelationshipType { - return relnType, nil + if lastPart == validRelationshipType { + return lastPart, nil } } - return "", fmt.Errorf("unknown relationshipType: %s", relnType) + return "", fmt.Errorf("unknown relationshipType: '%s'", lastPart) } -- cgit v1.2.3