diff --git a/docs/jsonloader.md b/docs/jsonloader.md new file mode 100644 index 00000000..047c4b74 --- /dev/null +++ b/docs/jsonloader.md @@ -0,0 +1,24 @@ +SPDX-License-Identifier: CC-BY-4.0 + +## Working + +A UnmarshallJSON function on the spdx.Document2_2 struct is defined so that when the JSON is unmarshalled in it the function is called and we can implement the process in a custom way . Then a new map[string]interface{} is deifined which temporarily holds the unmarshalled json . The map is then parsed into the spdx.Document2_2 using functions defined for it’s different sections . + +JSON → map[string]interface{} → spdx.Document2_2 + +## Some Key Points + +- The packages have a property "hasFiles" defined in the schema which is an array of the SPDX Identifiers of the files of that pacakge . The parses first parses all the files into the Unpackaged files map of the document and then when it parses the packages , it removes the respective files from the unpackaged files map and places it inside the files map of that package . + +- The snippets have a property "snippetFromFile" which has the SPDX identiifer of the file to which the snippet is related . Thus the snippets require the files to be parsed before them . Then the snippets are parsed one by one and inserted into the respective files using this property . + + +The json file loader in `package jsonloader` makes the following assumptions: + + +### Order of appearance of the properties +* The parser does not make any pre-assumptions based on the order in which the properties appear . + + +### Annotations +* The json spdx schema does not define the SPDX Identifier property for the annotation object . The parser assumes the spdx Identifier of the parent property of the currently being parsed annotation array to be the SPDX Identifer for all the annotation objects of that array. \ No newline at end of file diff --git a/docs/jsonsaver.md b/docs/jsonsaver.md new file mode 100644 index 00000000..8531cd3e --- /dev/null +++ b/docs/jsonsaver.md @@ -0,0 +1,28 @@ +SPDX-License-Identifier: CC-BY-4.0 + +## Working + +The spdx document is converted to map[string]interface{} and then the entire map is converted to json using a single json Marshall function call . The saver uses a tempoarary storage to store all the files (Paackaged and Unpackaged) together in a single data structure in order to comply with the json schema defined by spdx . + +spdx.Document2_2 → map[string]interface{} → JSON + +## Some Key Points + +- The packages have a property "hasFiles" defined in the schema which is an array of the SPDX Identifiers of the files of that pacakge . The saver iterates through the files of a package and inserted all the SPDX Identifiers of the files in the "hasFiles" array . In addition it adds the file to a temporary storage map to store all the files of the entire document at a single place . + +- The files require the packages to be saved before them in order to ensure that the packaged files are added to the temporary storage before the files are saved . + +- The snippets are saved after the files and a property "snippetFromFile" identifies the file of the snippets. + +The json file loader in `package jsonsaver` makes the following assumptions: + + +### Order of appearance of the properties +* The saver does not make any pre-assumptions based on the order in which the properties are saved . + + +### Annotations +* The json spdx schema does not define the SPDX Identifier property for the annotation object . The saver inserts the annotation inside the element who spdx identifier mathches the annotation SPDX identifier . + +### Indentation +* The jsonsaver uses the marshall indent function with "" as he prefix and "\t" as the indent character , passed as funtion parameters . \ No newline at end of file diff --git a/examples/10-jsonloader/example_json_loader.go b/examples/10-jsonloader/example_json_loader.go new file mode 100644 index 00000000..96f47fd0 --- /dev/null +++ b/examples/10-jsonloader/example_json_loader.go @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +// Example for: *jsonparser2v2* + +// This example demonstrates loading an SPDX json from disk into memory, +// and then logging out some attributes to the console . + +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/spdx/tools-golang/jsonloader" +) + +func main() { + + // check that we've received the right number of arguments + args := os.Args + if len(args) != 3 { + fmt.Printf("Usage: %v \n", args[0]) + fmt.Printf(" Load SPDX 2.2 tag-value file , and\n") + fmt.Printf(" save it out to .\n") + return + } + + // open the SPDX file + fileIn := args[1] + r, err := os.Open(fileIn) + if err != nil { + fmt.Printf("Error while opening %v for reading: %v", fileIn, err) + return + } + defer r.Close() + + // try to load the SPDX file's contents as a json file, version 2.2 + doc, err := jsonloader.Load2_2(r) + if err != nil { + fmt.Printf("Error while parsing %v: %v", args[1], err) + return + } + + // if we got here, the file is now loaded into memory. + fmt.Printf("Successfully loaded %s\n", args[1]) + + fmt.Println(strings.Repeat("=", 80)) + fmt.Println("Some Attributes of the Document:") + fmt.Printf("Document Name: %s\n", doc.CreationInfo.DocumentName) + fmt.Printf("DataLicense: %s\n", doc.CreationInfo.DataLicense) + fmt.Printf("Document NameSpace: %s\n", doc.CreationInfo.DocumentNamespace) + fmt.Printf("SPDX Document Version: %s\n", doc.CreationInfo.SPDXVersion) + fmt.Println(strings.Repeat("=", 80)) +} diff --git a/examples/8-jsonloader/examplejsontotv.go b/examples/8-jsontotv/examplejsontotv.go similarity index 100% rename from examples/8-jsonloader/examplejsontotv.go rename to examples/8-jsontotv/examplejsontotv.go diff --git a/examples/9-tvtojson/exampletvtojson.go b/examples/9-tvtojson/exampletvtojson.go new file mode 100644 index 00000000..2c6ec7ef --- /dev/null +++ b/examples/9-tvtojson/exampletvtojson.go @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +// Example for: *tvloader*, *jsonsaver* + +// This example demonstrates loading an SPDX tag-value file from disk into memory, +// and re-saving it to a different json file on disk. + +package main + +import ( + "fmt" + "os" + + "github.com/spdx/tools-golang/jsonsaver" + "github.com/spdx/tools-golang/tvloader" +) + +func main() { + + // check that we've received the right number of arguments + args := os.Args + if len(args) != 3 { + fmt.Printf("Usage: %v \n", args[0]) + fmt.Printf(" Load SPDX 2.2 tag-value file , and\n") + fmt.Printf(" save it out to .\n") + return + } + + // open the SPDX file + fileIn := args[1] + r, err := os.Open(fileIn) + if err != nil { + fmt.Printf("Error while opening %v for reading: %v", fileIn, err) + return + } + defer r.Close() + + // try to load the SPDX file's contents as a tag-value file, version 2.2 + doc, err := tvloader.Load2_2(r) + if err != nil { + fmt.Printf("Error while parsing %v: %v", args[1], err) + return + } + + // if we got here, the file is now loaded into memory. + fmt.Printf("Successfully loaded %s\n", args[1]) + + // we can now save it back to disk, using jsonsaver. + + // create a new file for writing + fileOut := args[2] + w, err := os.Create(fileOut) + if err != nil { + fmt.Printf("Error while opening %v for writing: %v", fileOut, err) + return + } + defer w.Close() + + // try to save the document to disk as an SPDX json file, version 2.2 + err = jsonsaver.Save2_2(doc, w) + if err != nil { + fmt.Printf("Error while saving %v: %v", fileOut, err) + return + } + + // it worked + fmt.Printf("Successfully saved %s\n", fileOut) +} diff --git a/examples/README.md b/examples/README.md index 7cd80a06..bd4b3d3e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -64,9 +64,23 @@ the same identifier in both documents. This example demonstrates loading an SPDX rdf file from disk into memory and then printing the corresponding spdx struct for the document. -## 8-jsonloader +## 8-jsontotv *jsonloader*, *tvsaver* This example demonstrates loading an SPDX json from disk into memory and then re-saving it to a different file on disk in tag-value format. + +## 9-tvtojson + +*jsonsaver*, *tvloader* + +This example demonstrates loading an SPDX tag-value from disk into memory +and then re-saving it to a different file on disk in json format. + +## 10-jsonloader + +*jsonloader* + +This example demonstrates loading an SPDX json from disk into memory +and then logging some of the attributes to the console. diff --git a/jsonloader/jsonloader_test.go b/jsonloader/jsonloader_test.go index 2ce87502..e90a6a58 100644 --- a/jsonloader/jsonloader_test.go +++ b/jsonloader/jsonloader_test.go @@ -3,6 +3,7 @@ package jsonloader import ( + "bytes" "fmt" "io" "os" @@ -45,6 +46,14 @@ func TestLoad2_2(t *testing.T) { }, wantErr: false, }, + { + name: "fail - invalidjson ", + args: args{ + content: bytes.NewReader([]byte(`{"Hello":"HI",}`)), + }, + want: nil, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -53,7 +62,7 @@ func TestLoad2_2(t *testing.T) { t.Errorf("Load2_2() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got.CreationInfo, tt.want.CreationInfo) { + if !tt.wantErr && !reflect.DeepEqual(got.CreationInfo, tt.want.CreationInfo) { t.Errorf("Load2_2() = %v, want %v", got.CreationInfo, tt.want.CreationInfo) } }) diff --git a/jsonloader/parser2v2/parse_annotations_test.go b/jsonloader/parser2v2/parse_annotations_test.go index 6ef5693c..014c3dde 100644 --- a/jsonloader/parser2v2/parse_annotations_test.go +++ b/jsonloader/parser2v2/parse_annotations_test.go @@ -31,6 +31,26 @@ func TestJSONSpdxDocument_parseJsonAnnotations2_2(t *testing.T) { } ] } `) + data2 := []byte(`{ + "annotations" : [ { + "annotationDate" : "2010-02-10T00:00:00Z", + "annotationType" : "REVIEW", + "annotator" : "Person: Joe Reviewer", + "comment" : "This is just an example. Some of the non-standard licenses look like they are actually BSD 3 clause licenses", + "Hello":"hellp" + }] +} +`) + data3 := []byte(`{ + "annotations" : [ { + "annotationDate" : "2010-02-10T00:00:00Z", + "annotationType" : "REVIEW", + "annotator" : "Fasle: Joe Reviewer", + "comment" : "This is just an example. Some of the non-standard licenses look like they are actually BSD 3 clause licenses", + "Hello":"hellp" + }] +} +`) annotationstest1 := []*spdx.Annotation2_2{ { @@ -60,7 +80,12 @@ func TestJSONSpdxDocument_parseJsonAnnotations2_2(t *testing.T) { } var specs JSONSpdxDocument + var specs2 JSONSpdxDocument + var specs3 JSONSpdxDocument + json.Unmarshal(data, &specs) + json.Unmarshal(data2, &specs2) + json.Unmarshal(data3, &specs3) type args struct { key string @@ -88,16 +113,41 @@ func TestJSONSpdxDocument_parseJsonAnnotations2_2(t *testing.T) { want: annotationstest1, wantErr: false, }, + { + name: "failure test - invaid creator type", + spec: specs2, + args: args{ + key: "annotations", + value: specs2["annotations"], + doc: &spdxDocument2_2{}, + SPDXElementID: spdx.DocElementID{DocumentRefID: "", ElementRefID: "DOCUMENT"}, + }, + want: nil, + wantErr: true, + }, + { + name: "failure test - invalid tag", + spec: specs3, + args: args{ + key: "annotations", + value: specs3["annotations"], + doc: &spdxDocument2_2{}, + SPDXElementID: spdx.DocElementID{DocumentRefID: "", ElementRefID: "DOCUMENT"}, + }, + want: nil, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if err := tt.spec.parseJsonAnnotations2_2(tt.args.key, tt.args.value, tt.args.doc, tt.args.SPDXElementID); (err != nil) != tt.wantErr { t.Errorf("JSONSpdxDocument.parseJsonAnnotations2_2() error = %v, wantErr %v", err, tt.wantErr) } - - for i := 0; i < len(tt.want); i++ { - if !reflect.DeepEqual(tt.args.doc.Annotations[i], tt.want[i]) { - t.Errorf("Load2_2() = %v, want %v", tt.args.doc.Annotations[i], tt.want[i]) + if !tt.wantErr { + for i := 0; i < len(tt.want); i++ { + if !reflect.DeepEqual(tt.args.doc.Annotations[i], tt.want[i]) { + t.Errorf("Load2_2() = %v, want %v", tt.args.doc.Annotations[i], tt.want[i]) + } } } diff --git a/jsonloader/parser2v2/parse_creation_info.go b/jsonloader/parser2v2/parse_creation_info.go index 074e25e1..9e818e83 100644 --- a/jsonloader/parser2v2/parse_creation_info.go +++ b/jsonloader/parser2v2/parse_creation_info.go @@ -79,9 +79,9 @@ func parseCreators(creators interface{}, ci *spdx.CreationInfo2_2) error { } switch subkey { case "Person": - ci.CreatorPersons = append(ci.CreatorPersons, strings.TrimSuffix(subvalue, " ()")) + ci.CreatorPersons = append(ci.CreatorPersons, subvalue) case "Organization": - ci.CreatorOrganizations = append(ci.CreatorOrganizations, strings.TrimSuffix(subvalue, " ()")) + ci.CreatorOrganizations = append(ci.CreatorOrganizations, subvalue) case "Tool": ci.CreatorTools = append(ci.CreatorTools, subvalue) default: diff --git a/jsonloader/parser2v2/parse_creation_info_test.go b/jsonloader/parser2v2/parse_creation_info_test.go index 525bb505..280775ac 100644 --- a/jsonloader/parser2v2/parse_creation_info_test.go +++ b/jsonloader/parser2v2/parse_creation_info_test.go @@ -115,8 +115,8 @@ func TestJSONSpdxDocument_parseJsonCreationInfo2_2(t *testing.T) { want: &spdx.CreationInfo2_2{ CreatorComment: "This package has been shipped in source and binary form.\nThe binaries were created with gcc 4.5.1 and expect to link to\ncompatible system run time libraries.", Created: "2010-01-29T18:30:22Z", - CreatorPersons: []string{"Jane Doe"}, - CreatorOrganizations: []string{"ExampleCodeInspect"}, + CreatorPersons: []string{"Jane Doe ()"}, + CreatorOrganizations: []string{"ExampleCodeInspect ()"}, CreatorTools: []string{"LicenseFind-1.0"}, LicenseListVersion: "3.8", ExternalDocumentReferences: map[string]spdx.ExternalDocumentRef2_2{}, @@ -153,6 +153,64 @@ func TestJSONSpdxDocument_parseJsonCreationInfo2_2(t *testing.T) { }, wantErr: false, }, + { + name: "failure : Invalid tag ", + spec: specs, + args: args{ + key: "invalid", + value: "This document was created using SPDX 2.0 using licenses from the web site.", + doc: &spdxDocument2_2{}, + }, + want: &spdx.CreationInfo2_2{ExternalDocumentReferences: map[string]spdx.ExternalDocumentRef2_2{}}, + wantErr: true, + }, + { + name: "failure : DocRef missing in ExternalRefs", + spec: specs, + args: args{ + key: "externalDocumentRefs", + value: []map[string]interface{}{ + { + "externalDocumentId": "spdx-tool-1.2", + "spdxDocument": "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301", + "checksum": map[string]interface{}{ + "algorithm": "SHA1", + "checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2759", + }, + }, + }, + doc: &spdxDocument2_2{}, + }, + want: nil, + wantErr: true, + }, + { + name: "failure : invalid SPDXID", + spec: specs, + args: args{ + key: "SPDXID", + value: "DOCUMENT", + doc: &spdxDocument2_2{}, + }, + want: &spdx.CreationInfo2_2{ExternalDocumentReferences: map[string]spdx.ExternalDocumentRef2_2{}}, + wantErr: true, + }, + { + name: "failure - invalid creator type", + spec: specs, + args: args{ + key: "creationInfo", + value: map[string]interface{}{ + "comment": "This package has been shipped in source and binary form.\nThe binaries were created with gcc 4.5.1 and expect to link to\ncompatible system run time libraries.", + "created": "2010-01-29T18:30:22Z", + "creators": []string{"Invalid: LicenseFind-1.0", "Organization: ExampleCodeInspect ()", "Person: Jane Doe ()"}, + "licenseListVersion": "3.8", + }, + doc: &spdxDocument2_2{}, + }, + want: nil, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -160,7 +218,7 @@ func TestJSONSpdxDocument_parseJsonCreationInfo2_2(t *testing.T) { if err := tt.spec.parseJsonCreationInfo2_2(tt.args.key, tt.args.value, tt.args.doc); (err != nil) != tt.wantErr { t.Errorf("JSONSpdxDocument.parseJsonCreationInfo2_2() error = %v, wantErr %v", err, tt.wantErr) } - if !reflect.DeepEqual(tt.args.doc.CreationInfo, tt.want) { + if !tt.wantErr && !reflect.DeepEqual(tt.args.doc.CreationInfo, tt.want) { t.Errorf("Load2_2() = %v, want %v", tt.args.doc.CreationInfo, tt.want) } diff --git a/jsonloader/parser2v2/parse_files_test.go b/jsonloader/parser2v2/parse_files_test.go index 196cb605..4d54fad5 100644 --- a/jsonloader/parser2v2/parse_files_test.go +++ b/jsonloader/parser2v2/parse_files_test.go @@ -27,6 +27,7 @@ func TestJSONSpdxDocument_parseJsonFiles2_2(t *testing.T) { "fileName" : "./src/org/spdx/parser/DOAPProject.java", "fileTypes" : [ "SOURCE" ], "licenseConcluded" : "Apache-2.0", + "attributionTexts":["text1"], "licenseInfoInFiles" : [ "Apache-2.0" ] }, { "SPDXID" : "SPDXRef-CommonsLangSrc", @@ -97,13 +98,14 @@ func TestJSONSpdxDocument_parseJsonFiles2_2(t *testing.T) { Value: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", }, }, - FileCopyrightText: "Copyright 2010, 2011 Source Auditor Inc.", - FileContributor: []string{"Protecode Inc.", "SPDX Technical Team Members", "Open Logic Inc.", "Source Auditor Inc.", "Black Duck Software In.c"}, - FileDependencies: []string{"SPDXRef-JenaLib", "SPDXRef-CommonsLangSrc"}, - FileName: "./src/org/spdx/parser/DOAPProject.java", - FileType: []string{"SOURCE"}, - LicenseConcluded: "Apache-2.0", - LicenseInfoInFile: []string{"Apache-2.0"}, + FileCopyrightText: "Copyright 2010, 2011 Source Auditor Inc.", + FileContributor: []string{"Protecode Inc.", "SPDX Technical Team Members", "Open Logic Inc.", "Source Auditor Inc.", "Black Duck Software In.c"}, + FileDependencies: []string{"SPDXRef-JenaLib", "SPDXRef-CommonsLangSrc"}, + FileName: "./src/org/spdx/parser/DOAPProject.java", + FileType: []string{"SOURCE"}, + LicenseConcluded: "Apache-2.0", + FileAttributionTexts: []string{"text1"}, + LicenseInfoInFile: []string{"Apache-2.0"}, }, "CommonsLangSrc": { FileSPDXIdentifier: "CommonsLangSrc", @@ -195,13 +197,11 @@ func TestJSONSpdxDocument_parseJsonFiles2_2(t *testing.T) { t.Errorf("JSONSpdxDocument.parseJsonFiles2_2() error = %v, wantErr %v", err, tt.wantErr) } - // if !reflect.DeepEqual(tt.args.doc.UnpackagedFiles, tt.want) { - // t.Errorf("Load2_2() = %v, want %v", tt.args.doc.UnpackagedFiles, tt.want) - // } - - for k, v := range tt.want { - if !reflect.DeepEqual(tt.args.doc.UnpackagedFiles[k], v) { - t.Errorf("Load2_2() = %v, want %v", tt.args.doc.UnpackagedFiles[k], v) + if !tt.wantErr { + for k, v := range tt.want { + if !reflect.DeepEqual(tt.args.doc.UnpackagedFiles[k], v) { + t.Errorf("Load2_2() = %v, want %v", tt.args.doc.UnpackagedFiles[k], v) + } } } diff --git a/jsonloader/parser2v2/parse_other_license.go b/jsonloader/parser2v2/parse_other_license.go index de9e8f24..997ad025 100644 --- a/jsonloader/parser2v2/parse_other_license.go +++ b/jsonloader/parser2v2/parse_other_license.go @@ -34,7 +34,7 @@ func (spec JSONSpdxDocument) parseJsonOtherLicenses2_2(key string, value interfa } } default: - return fmt.Errorf("received unknown tag %v in Annotation section", k) + return fmt.Errorf("received unknown tag %v in Licenses section", k) } } doc.OtherLicenses = append(doc.OtherLicenses, &license) diff --git a/jsonloader/parser2v2/parse_other_license_test.go b/jsonloader/parser2v2/parse_other_license_test.go index 0ccee1cc..41d8ede9 100644 --- a/jsonloader/parser2v2/parse_other_license_test.go +++ b/jsonloader/parser2v2/parse_other_license_test.go @@ -45,9 +45,20 @@ func TestJSONSpdxDocument_parseJsonOtherLicenses2_2(t *testing.T) { }, } + otherLicensestest2 := []byte(`{ + "hasExtractedLicensingInfos":[{ + "extractedText" : "\"THE BEER-WARE LICENSE\" (Revision 42):\nphk@FreeBSD.ORG wrote this file. As long as you retain this notice you\ncan do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp unknown tag", + spec: specs2, + args: args{ + key: "hasExtractedLicensingInfos", + value: specs2["hasExtractedLicensingInfos"], + doc: &spdxDocument2_2{}, + }, + want: nil, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -79,12 +101,13 @@ func TestJSONSpdxDocument_parseJsonOtherLicenses2_2(t *testing.T) { t.Errorf("JSONSpdxDocument.parseJsonOtherLicenses2_2() error = %v, wantErr %v", err, tt.wantErr) } - for i := 0; i < len(tt.want); i++ { - if !reflect.DeepEqual(tt.args.doc.OtherLicenses[i], tt.want[i]) { - t.Errorf("Load2_2() = %v, want %v", tt.args.doc.OtherLicenses[i], tt.want[i]) + if !tt.wantErr { + for i := 0; i < len(tt.want); i++ { + if !reflect.DeepEqual(tt.args.doc.OtherLicenses[i], tt.want[i]) { + t.Errorf("Load2_2() = %v, want %v", tt.args.doc.OtherLicenses[i], tt.want[i]) + } } } - }) } } diff --git a/jsonloader/parser2v2/parse_snippets.go b/jsonloader/parser2v2/parse_snippets.go index 68a018a9..a49191d7 100644 --- a/jsonloader/parser2v2/parse_snippets.go +++ b/jsonloader/parser2v2/parse_snippets.go @@ -70,7 +70,7 @@ func (spec JSONSpdxDocument) parseJsonSnippets2_2(key string, value interface{}, } } default: - return fmt.Errorf("received unknown tag %v in files section", k) + return fmt.Errorf("received unknown tag %v in snippet section", k) } } fileID, err2 := extractDocElementID(snippetmap["snippetFromFile"].(string)) diff --git a/jsonloader/parser2v2/parse_snippets_test.go b/jsonloader/parser2v2/parse_snippets_test.go index e72599e4..b25bee55 100644 --- a/jsonloader/parser2v2/parse_snippets_test.go +++ b/jsonloader/parser2v2/parse_snippets_test.go @@ -21,6 +21,7 @@ func TestJSONSpdxDocument_parseJsonSnippets2_2(t *testing.T) { "licenseComments" : "The concluded license was taken from package xyz, from which the snippet was copied into the current file. The concluded license information was found in the COPYING.txt file in package xyz.", "licenseConcluded" : "GPL-2.0-only", "licenseInfoInSnippets" : [ "GPL-2.0-only" ], + "attributionTexts":["text1"], "name" : "from linux kernel", "ranges" : [ { "endPointer" : { @@ -52,6 +53,7 @@ func TestJSONSpdxDocument_parseJsonSnippets2_2(t *testing.T) { Snippets: map[spdx.ElementID]*spdx.Snippet2_2{ "Snippet": { SnippetSPDXIdentifier: "Snippet", + SnippetAttributionTexts: []string{"text1"}, SnippetFromFileSPDXIdentifier: spdx.DocElementID{ElementRefID: "DoapSource"}, SnippetComment: "This snippet was identified as significant and highlighted in this Apache-2.0 file, when a commercial scanner identified it as being derived from file foo.c in package xyz which is licensed under GPL-2.0.", SnippetCopyrightText: "Copyright 2008-2010 John Smith", diff --git a/jsonloader/parser2v2/parser_test.go b/jsonloader/parser2v2/parser_test.go index d80e9d51..051ff99f 100644 --- a/jsonloader/parser2v2/parser_test.go +++ b/jsonloader/parser2v2/parser_test.go @@ -43,8 +43,8 @@ func TestLoad2_2(t *testing.T) { DocumentComment: "This document was created using SPDX 2.0 using licenses from the web site.", LicenseListVersion: "3.8", Created: "2010-01-29T18:30:22Z", - CreatorPersons: []string{"Jane Doe"}, - CreatorOrganizations: []string{"ExampleCodeInspect"}, + CreatorPersons: []string{"Jane Doe ()"}, + CreatorOrganizations: []string{"ExampleCodeInspect ()"}, CreatorTools: []string{"LicenseFind-1.0"}, DocumentName: "SPDX-Tools-v2.0", DocumentNamespace: "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301", diff --git a/jsonsaver/jsonsaver.go b/jsonsaver/jsonsaver.go new file mode 100644 index 00000000..4748e16c --- /dev/null +++ b/jsonsaver/jsonsaver.go @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +package jsonsaver + +import ( + "bytes" + "io" + + "github.com/spdx/tools-golang/jsonsaver/saver2v2" + "github.com/spdx/tools-golang/spdx" +) + +// Save2_2 takes an io.Writer and an SPDX Document (version 2.2), +// and writes it to the writer in json format. It returns error +// if any error is encountered. +func Save2_2(doc *spdx.Document2_2, w io.Writer) error { + var b []byte + buf := bytes.NewBuffer(b) + err := saver2v2.RenderDocument2_2(doc, buf) + if err != nil { + return err + } + w.Write(buf.Bytes()) + return nil +} diff --git a/jsonsaver/jsonsaver_test.go b/jsonsaver/jsonsaver_test.go new file mode 100644 index 00000000..3d5daa93 --- /dev/null +++ b/jsonsaver/jsonsaver_test.go @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later + +package jsonsaver + +import ( + "bytes" + "testing" + + "github.com/spdx/tools-golang/spdx" +) + +func TestSave2_2(t *testing.T) { + type args struct { + doc *spdx.Document2_2 + } + test1 := &spdx.Document2_2{ + CreationInfo: &spdx.CreationInfo2_2{ + DataLicense: "CC0-1.0", + SPDXVersion: "SPDX-2.2", + SPDXIdentifier: "DOCUMENT", + DocumentComment: "This document was created using SPDX 2.0 using licenses from the web site.", + LicenseListVersion: "3.8", + Created: "2010-01-29T18:30:22Z", + CreatorPersons: []string{"Jane Doe ()"}, + CreatorOrganizations: []string{"ExampleCodeInspect ()"}, + CreatorTools: []string{"LicenseFind-1.0"}, + DocumentName: "SPDX-Tools-v2.0", + DocumentNamespace: "http://spdx.org/spdxdocs/spdx-example-444504E0-4F89-41D3-9A0C-0305E82C3301", + CreatorComment: "This package has been shipped in source and binary form.\nThe binaries were created with gcc 4.5.1 and expect to link to\ncompatible system run time libraries.", + ExternalDocumentReferences: map[string]spdx.ExternalDocumentRef2_2{ + "spdx-tool-1.2": { + DocumentRefID: "spdx-tool-1.2", + URI: "http://spdx.org/spdxdocs/spdx-tools-v1.2-3F2504E0-4F89-41D3-9A0C-0305E82C3301", + Alg: "SHA1", + Checksum: "d6a770ba38583ed4bb4525bd96e50461655d2759", + }, + }, + }, + OtherLicenses: []*spdx.OtherLicense2_2{ + { + ExtractedText: "\"THE BEER-WARE LICENSE\" (Revision 42):\nphk@FreeBSD.ORG wrote this file. As long as you retain this notice you\ncan do whatever you want with this stuff. If we meet some day, and you think this stuff is worth it, you can buy me a beer in return Poul-Henning Kamp