Merge pull request #97 from specter25/jsonparser1

[GSoC'21] Pr:7 . JSON saver bug fix
diff --git a/jsonloader/parser2v2/parse_files_test.go b/jsonloader/parser2v2/parse_files_test.go
index 30f1bdc..4d54fad 100644
--- a/jsonloader/parser2v2/parse_files_test.go
+++ b/jsonloader/parser2v2/parse_files_test.go
@@ -197,13 +197,11 @@
 				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 de9e8f2..997ad02 100644
--- a/jsonloader/parser2v2/parse_other_license.go
+++ b/jsonloader/parser2v2/parse_other_license.go
@@ -34,7 +34,7 @@
 						}
 					}
 				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 0ccee1c..41d8ede 100644
--- a/jsonloader/parser2v2/parse_other_license_test.go
+++ b/jsonloader/parser2v2/parse_other_license_test.go
@@ -45,9 +45,20 @@
 		},
 	}
 
+	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  </\nLicenseName: Beer-Ware License (Version 42)\nLicenseCrossReference:  http://people.freebsd.org/~phk/\nLicenseComment: \nThe beerware license has a couple of other standard variants.",
+			"licensd" : "LicenseRef-Beerware-4.2"
+		  }]
+		}
+  	`)
+
 	var specs JSONSpdxDocument
 	json.Unmarshal(jsonData, &specs)
 
+	var specs2 JSONSpdxDocument
+	json.Unmarshal(otherLicensestest2, &specs2)
+
 	type args struct {
 		key   string
 		value interface{}
@@ -72,6 +83,17 @@
 			want:    otherLicensestest1,
 			wantErr: false,
 		},
+		{
+			name: "failure test --> 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 @@
 				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/jsonsaver/saver2v2/save_document_test.go b/jsonsaver/saver2v2/save_document_test.go
index 90d01f1..9651367 100644
--- a/jsonsaver/saver2v2/save_document_test.go
+++ b/jsonsaver/saver2v2/save_document_test.go
@@ -177,14 +177,14 @@
 			"File": {
 				FileSPDXIdentifier: "File",
 				FileChecksums: map[spdx.ChecksumAlgorithm]spdx.Checksum{
+					"MD5": {
+						Algorithm: "MD5",
+						Value:     "624c1abb3664f4b35547e7c73864ad24",
+					},
 					"SHA1": {
 						Algorithm: "SHA1",
 						Value:     "d6a770ba38583ed4bb4525bd96e50461655d2758",
 					},
-					// "MD5": {
-					// 	Algorithm: "MD5",
-					// 	Value:     "624c1abb3664f4b35547e7c73864ad24",
-					// },
 				},
 				FileComment:       "The concluded license was taken from the package level that the file was .\nThis information was found in the COPYING.txt file in the xyz directory.",
 				FileCopyrightText: "Copyright 2008-2010 John Smith",
@@ -318,36 +318,6 @@
 		},
 		"files": []interface{}{
 			map[string]interface{}{
-				"SPDXID": "SPDXRef-File",
-				"annotations": []interface{}{
-					map[string]interface{}{
-						"annotationDate": "2011-01-29T18:30:22Z",
-						"annotationType": "OTHER",
-						"annotator":      "Person: File Commenter",
-						"comment":        "File level annotation",
-					},
-				},
-				"checksums": []interface{}{
-					map[string]interface{}{
-						"algorithm":     "SHA1",
-						"checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2758",
-					},
-					// map[string]interface{}{
-					// 	"algorithm":     "MD5",
-					// 	"checksumValue": "624c1abb3664f4b35547e7c73864ad24",
-					// },
-				},
-				"comment":            "The concluded license was taken from the package level that the file was .\nThis information was found in the COPYING.txt file in the xyz directory.",
-				"copyrightText":      "Copyright 2008-2010 John Smith",
-				"fileContributors":   []string{"The Regents of the University of California", "Modified by Paul Mundt lethal@linux-sh.org", "IBM Corporation"},
-				"fileName":           "./package/foo.c",
-				"fileTypes":          []string{"SOURCE"},
-				"licenseComments":    "The concluded license was taken from the package level that the file was .\nThis information was found in the COPYING.txt file in the xyz directory.",
-				"licenseConcluded":   "(LGPL-2.0-only OR LicenseRef-2)",
-				"licenseInfoInFiles": []string{"GPL-2.0-only", "LicenseRef-2"},
-				"noticeText":         "Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.",
-			},
-			map[string]interface{}{
 				"SPDXID": "SPDXRef-DoapSource",
 				"checksums": []interface{}{
 					map[string]interface{}{
@@ -363,6 +333,37 @@
 				"licenseConcluded":   "Apache-2.0",
 				"licenseInfoInFiles": []string{"Apache-2.0"},
 			},
+			map[string]interface{}{
+				"SPDXID": "SPDXRef-File",
+				"annotations": []interface{}{
+					map[string]interface{}{
+						"annotationDate": "2011-01-29T18:30:22Z",
+						"annotationType": "OTHER",
+						"annotator":      "Person: File Commenter",
+						"comment":        "File level annotation",
+					},
+				},
+				"checksums": []interface{}{
+					map[string]interface{}{
+						"algorithm":     "MD5",
+						"checksumValue": "624c1abb3664f4b35547e7c73864ad24",
+					},
+
+					map[string]interface{}{
+						"algorithm":     "SHA1",
+						"checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2758",
+					},
+				},
+				"comment":            "The concluded license was taken from the package level that the file was .\nThis information was found in the COPYING.txt file in the xyz directory.",
+				"copyrightText":      "Copyright 2008-2010 John Smith",
+				"fileContributors":   []string{"The Regents of the University of California", "Modified by Paul Mundt lethal@linux-sh.org", "IBM Corporation"},
+				"fileName":           "./package/foo.c",
+				"fileTypes":          []string{"SOURCE"},
+				"licenseComments":    "The concluded license was taken from the package level that the file was .\nThis information was found in the COPYING.txt file in the xyz directory.",
+				"licenseConcluded":   "(LGPL-2.0-only OR LicenseRef-2)",
+				"licenseInfoInFiles": []string{"GPL-2.0-only", "LicenseRef-2"},
+				"noticeText":         "Copyright (c) 2001 Aaron Lehmann aaroni@vitelus.",
+			},
 		},
 		"snippets": []interface{}{
 			map[string]interface{}{
diff --git a/jsonsaver/saver2v2/save_files.go b/jsonsaver/saver2v2/save_files.go
index ca6d6b3..d866fd3 100644
--- a/jsonsaver/saver2v2/save_files.go
+++ b/jsonsaver/saver2v2/save_files.go
@@ -3,15 +3,25 @@
 package saver2v2
 
 import (
+	"sort"
+
 	"github.com/spdx/tools-golang/spdx"
 )
 
 func renderFiles2_2(doc *spdx.Document2_2, jsondocument map[string]interface{}) ([]interface{}, error) {
 
+	var keys []string
+	for ke := range doc.UnpackagedFiles {
+		keys = append(keys, string(ke))
+	}
+	sort.Strings(keys)
+
 	var files []interface{}
-	for k, v := range doc.UnpackagedFiles {
+	// for k, v := range doc.UnpackagedFiles {
+	for _, k := range keys {
+		v := doc.UnpackagedFiles[spdx.ElementID(k)]
 		file := make(map[string]interface{})
-		file["SPDXID"] = spdx.RenderElementID(k)
+		file["SPDXID"] = spdx.RenderElementID(spdx.ElementID(k))
 		ann, _ := renderAnnotations2_2(doc.Annotations, spdx.MakeDocElementID("", string(v.FileSPDXIdentifier)))
 		if ann != nil {
 			file["annotations"] = ann
@@ -26,7 +36,16 @@
 		// save package checksums
 		if v.FileChecksums != nil {
 			var checksums []interface{}
-			for _, value := range v.FileChecksums {
+
+			var algos []string
+			for alg := range v.FileChecksums {
+				algos = append(algos, string(alg))
+			}
+			sort.Strings(algos)
+
+			// for _, value := range v.FileChecksums {
+			for _, algo := range algos {
+				value := v.FileChecksums[spdx.ChecksumAlgorithm(algo)]
 				checksum := make(map[string]interface{})
 				checksum["algorithm"] = string(value.Algorithm)
 				checksum["checksumValue"] = value.Value
diff --git a/jsonsaver/saver2v2/save_files_test.go b/jsonsaver/saver2v2/save_files_test.go
index c2e61d8..fbc6ba1 100644
--- a/jsonsaver/saver2v2/save_files_test.go
+++ b/jsonsaver/saver2v2/save_files_test.go
@@ -75,10 +75,10 @@
 									Algorithm: "SHA1",
 									Value:     "d6a770ba38583ed4bb4525bd96e50461655d2758",
 								},
-								// "MD5": {
-								// 	Algorithm: "MD5",
-								// 	Value:     "624c1abb3664f4b35547e7c73864ad24",
-								// },
+								"MD5": {
+									Algorithm: "MD5",
+									Value:     "624c1abb3664f4b35547e7c73864ad24",
+								},
 							},
 							FileComment:          "The concluded license was taken from the package level that the file was .",
 							FileCopyrightText:    "Copyright 2008-2010 John Smith",
@@ -108,13 +108,13 @@
 					},
 					"checksums": []interface{}{
 						map[string]interface{}{
+							"algorithm":     "MD5",
+							"checksumValue": "624c1abb3664f4b35547e7c73864ad24",
+						},
+						map[string]interface{}{
 							"algorithm":     "SHA1",
 							"checksumValue": "d6a770ba38583ed4bb4525bd96e50461655d2758",
 						},
-						// map[string]interface{}{
-						// 	"algorithm":     "MD5",
-						// 	"checksumValue": "624c1abb3664f4b35547e7c73864ad24",
-						// },
 					},
 					"comment":            "The concluded license was taken from the package level that the file was .",
 					"copyrightText":      "Copyright 2008-2010 John Smith",
diff --git a/jsonsaver/saver2v2/save_package.go b/jsonsaver/saver2v2/save_package.go
index a402945..ab96045 100644
--- a/jsonsaver/saver2v2/save_package.go
+++ b/jsonsaver/saver2v2/save_package.go
@@ -4,6 +4,7 @@
 
 import (
 	"fmt"
+	"sort"
 
 	"github.com/spdx/tools-golang/spdx"
 )
@@ -11,9 +12,18 @@
 func renderPackage2_2(doc *spdx.Document2_2, jsondocument map[string]interface{}) ([]interface{}, error) {
 
 	var packages []interface{}
-	for k, v := range doc.Packages {
+
+	var keys []string
+	for ke := range doc.Packages {
+		keys = append(keys, string(ke))
+	}
+	sort.Strings(keys)
+
+	// for k, v := range doc.Packages {
+	for _, k := range keys {
+		v := doc.Packages[spdx.ElementID(k)]
 		pkg := make(map[string]interface{})
-		pkg["SPDXID"] = spdx.RenderElementID(k)
+		pkg["SPDXID"] = spdx.RenderElementID(spdx.ElementID(k))
 		ann, _ := renderAnnotations2_2(doc.Annotations, spdx.MakeDocElementID("", string(v.PackageSPDXIdentifier)))
 		if ann != nil {
 			pkg["annotations"] = ann
@@ -24,7 +34,15 @@
 		// save package checksums
 		if v.PackageChecksums != nil {
 			var checksums []interface{}
-			for _, value := range v.PackageChecksums {
+
+			var algos []string
+			for alg := range v.PackageChecksums {
+				algos = append(algos, string(alg))
+			}
+			sort.Strings(algos)
+
+			for _, algo := range algos {
+				value := v.PackageChecksums[spdx.ChecksumAlgorithm(algo)]
 				checksum := make(map[string]interface{})
 				checksum["algorithm"] = string(value.Algorithm)
 				checksum["checksumValue"] = value.Value