cmd/govulncheck: add test for JSON output

The challenge here involved filenames of Go source files, which might
contain the full path to the working directory or the Go module cache.
These paths differ across systems, so tests that might work on a
developer machine would fail on a CI system.

This CL solves that problem by filtering the JSON, replacing path
directories with "..." while preserving the base filenames.

Change-Id: I938a96a2d6ed23648106293bfe3fa9d3a540586d
Reviewed-on: https://go-review.googlesource.com/c/vuln/+/399119
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Zvonimir Pavlinovic <zpavlinovic@google.com>
diff --git a/cmd/govulncheck/main_test.go b/cmd/govulncheck/main_test.go
index fb42539..f7a0996 100644
--- a/cmd/govulncheck/main_test.go
+++ b/cmd/govulncheck/main_test.go
@@ -10,9 +10,11 @@
 import (
 	"errors"
 	"flag"
+	"fmt"
 	"os"
 	"os/exec"
 	"path/filepath"
+	"regexp"
 	"strings"
 	"testing"
 
@@ -54,11 +56,30 @@
 			return nil, errors.New("input redirection makes no sense")
 		}
 		cmd.Env = append(os.Environ(), "GOVULNDB=file://"+testDir+"/testdata/vulndb")
-		return cmd.CombinedOutput()
+		out, err := cmd.CombinedOutput()
+		for _, arg := range args {
+			if arg == "-json" {
+				out = filterJSON(out)
+				break
+			}
+		}
+		return out, err
 	}
 	ts.Run(t, *update)
 }
 
+var goFileRegexp = regexp.MustCompile(`"[^"]*\.go"`)
+
+// filterJSON  modifies paths to Go files by replacing their directory with "...".
+// For example, "/a/b/c.go" becomes ".../c.go".
+// This makes it possible to compare govulncheck JSON  output across systems, because
+// Go filenames in JSON output include setup-specific paths.
+func filterJSON(data []byte) []byte {
+	return goFileRegexp.ReplaceAllFunc(data, func(b []byte) []byte {
+		return []byte(fmt.Sprintf(`".../%s"`, filepath.Base(string(b)[1:len(b)-1])))
+	})
+}
+
 func TestLatestFixed(t *testing.T) {
 	for _, test := range []struct {
 		name string
diff --git a/cmd/govulncheck/testdata/json.ct b/cmd/govulncheck/testdata/json.ct
new file mode 100644
index 0000000..90d856f
--- /dev/null
+++ b/cmd/govulncheck/testdata/json.ct
@@ -0,0 +1,354 @@
+# Test of the -json flag.
+
+$ cdmodule novuln
+$ govulncheck -json .
+{
+	"Calls": {
+		"Functions": {},
+		"Entries": null
+	},
+	"Imports": {
+		"Packages": {},
+		"Entries": null
+	},
+	"Requires": {
+		"Modules": {},
+		"Entries": null
+	},
+	"Vulns": null
+}
+
+$ cdmodule vuln
+$ govulncheck -json . --> FAIL 3
+{
+	"Calls": {
+		"Functions": {
+			"1": {
+				"ID": 1,
+				"Name": "Parse",
+				"RecvType": "",
+				"PkgPath": "golang.org/x/text/language",
+				"Pos": {
+					"Filename": ".../parse.go",
+					"Offset": 5808,
+					"Line": 228,
+					"Column": 6
+				},
+				"CallSites": [
+					{
+						"Parent": 2,
+						"Name": "Parse",
+						"RecvType": "",
+						"Pos": {
+							"Filename": ".../vuln.go",
+							"Offset": 115,
+							"Line": 11,
+							"Column": 16
+						},
+						"Resolved": true
+					}
+				]
+			},
+			"2": {
+				"ID": 2,
+				"Name": "main",
+				"RecvType": "",
+				"PkgPath": "vuln",
+				"Pos": {
+					"Filename": ".../vuln.go",
+					"Offset": 69,
+					"Line": 9,
+					"Column": 6
+				},
+				"CallSites": null
+			}
+		},
+		"Entries": [
+			2
+		]
+	},
+	"Imports": {
+		"Packages": {
+			"1": {
+				"ID": 1,
+				"Name": "language",
+				"Path": "golang.org/x/text/language",
+				"Module": 1,
+				"ImportedBy": [
+					2
+				]
+			},
+			"2": {
+				"ID": 2,
+				"Name": "main",
+				"Path": "vuln",
+				"Module": 2,
+				"ImportedBy": null
+			}
+		},
+		"Entries": [
+			2
+		]
+	},
+	"Requires": {
+		"Modules": {
+			"1": {
+				"ID": 1,
+				"Path": "golang.org/x/text",
+				"Version": "v0.3.0",
+				"Replace": 0,
+				"RequiredBy": [
+					2
+				]
+			},
+			"2": {
+				"ID": 2,
+				"Path": "vuln",
+				"Version": "",
+				"Replace": 0,
+				"RequiredBy": null
+			}
+		},
+		"Entries": [
+			2
+		]
+	},
+	"Vulns": [
+		{
+			"OSV": {
+				"id": "GO-2021-0113",
+				"published": "2021-10-06T17:51:21Z",
+				"modified": "2021-10-06T17:51:21Z",
+				"aliases": [
+					"CVE-2021-38561"
+				],
+				"details": "Due to improper index calculation, an incorrectly formatted language tag can cause Parse\nto panic via an out of bounds read. If Parse is used to process untrusted user inputs,\nthis may be used as a vector for a denial of service attack.\n",
+				"affected": [
+					{
+						"package": {
+							"name": "golang.org/x/text/language",
+							"ecosystem": "Go"
+						},
+						"ranges": [
+							{
+								"type": "SEMVER",
+								"events": [
+									{
+										"introduced": "0"
+									},
+									{
+										"fixed": "0.3.7"
+									}
+								]
+							}
+						],
+						"database_specific": {
+							"url": "https://pkg.go.dev/vuln/GO-2021-0113"
+						},
+						"ecosystem_specific": {
+							"symbols": [
+								"Parse",
+								"MatchStrings",
+								"MustParse",
+								"ParseAcceptLanguage"
+							]
+						}
+					}
+				],
+				"references": [
+					{
+						"type": "FIX",
+						"url": "https://go-review.googlesource.com/c/text/+/340830"
+					},
+					{
+						"type": "FIX",
+						"url": "https://go.googlesource.com/text/+/383b2e75a7a4198c42f8f87833eefb772868a56f"
+					}
+				]
+			},
+			"Symbol": "Parse",
+			"PkgPath": "golang.org/x/text/language",
+			"ModPath": "golang.org/x/text",
+			"CallSink": 1,
+			"ImportSink": 1,
+			"RequireSink": 1
+		},
+		{
+			"OSV": {
+				"id": "GO-2021-0113",
+				"published": "2021-10-06T17:51:21Z",
+				"modified": "2021-10-06T17:51:21Z",
+				"aliases": [
+					"CVE-2021-38561"
+				],
+				"details": "Due to improper index calculation, an incorrectly formatted language tag can cause Parse\nto panic via an out of bounds read. If Parse is used to process untrusted user inputs,\nthis may be used as a vector for a denial of service attack.\n",
+				"affected": [
+					{
+						"package": {
+							"name": "golang.org/x/text/language",
+							"ecosystem": "Go"
+						},
+						"ranges": [
+							{
+								"type": "SEMVER",
+								"events": [
+									{
+										"introduced": "0"
+									},
+									{
+										"fixed": "0.3.7"
+									}
+								]
+							}
+						],
+						"database_specific": {
+							"url": "https://pkg.go.dev/vuln/GO-2021-0113"
+						},
+						"ecosystem_specific": {
+							"symbols": [
+								"Parse",
+								"MatchStrings",
+								"MustParse",
+								"ParseAcceptLanguage"
+							]
+						}
+					}
+				],
+				"references": [
+					{
+						"type": "FIX",
+						"url": "https://go-review.googlesource.com/c/text/+/340830"
+					},
+					{
+						"type": "FIX",
+						"url": "https://go.googlesource.com/text/+/383b2e75a7a4198c42f8f87833eefb772868a56f"
+					}
+				]
+			},
+			"Symbol": "MatchStrings",
+			"PkgPath": "golang.org/x/text/language",
+			"ModPath": "golang.org/x/text",
+			"CallSink": 0,
+			"ImportSink": 1,
+			"RequireSink": 1
+		},
+		{
+			"OSV": {
+				"id": "GO-2021-0113",
+				"published": "2021-10-06T17:51:21Z",
+				"modified": "2021-10-06T17:51:21Z",
+				"aliases": [
+					"CVE-2021-38561"
+				],
+				"details": "Due to improper index calculation, an incorrectly formatted language tag can cause Parse\nto panic via an out of bounds read. If Parse is used to process untrusted user inputs,\nthis may be used as a vector for a denial of service attack.\n",
+				"affected": [
+					{
+						"package": {
+							"name": "golang.org/x/text/language",
+							"ecosystem": "Go"
+						},
+						"ranges": [
+							{
+								"type": "SEMVER",
+								"events": [
+									{
+										"introduced": "0"
+									},
+									{
+										"fixed": "0.3.7"
+									}
+								]
+							}
+						],
+						"database_specific": {
+							"url": "https://pkg.go.dev/vuln/GO-2021-0113"
+						},
+						"ecosystem_specific": {
+							"symbols": [
+								"Parse",
+								"MatchStrings",
+								"MustParse",
+								"ParseAcceptLanguage"
+							]
+						}
+					}
+				],
+				"references": [
+					{
+						"type": "FIX",
+						"url": "https://go-review.googlesource.com/c/text/+/340830"
+					},
+					{
+						"type": "FIX",
+						"url": "https://go.googlesource.com/text/+/383b2e75a7a4198c42f8f87833eefb772868a56f"
+					}
+				]
+			},
+			"Symbol": "MustParse",
+			"PkgPath": "golang.org/x/text/language",
+			"ModPath": "golang.org/x/text",
+			"CallSink": 0,
+			"ImportSink": 1,
+			"RequireSink": 1
+		},
+		{
+			"OSV": {
+				"id": "GO-2021-0113",
+				"published": "2021-10-06T17:51:21Z",
+				"modified": "2021-10-06T17:51:21Z",
+				"aliases": [
+					"CVE-2021-38561"
+				],
+				"details": "Due to improper index calculation, an incorrectly formatted language tag can cause Parse\nto panic via an out of bounds read. If Parse is used to process untrusted user inputs,\nthis may be used as a vector for a denial of service attack.\n",
+				"affected": [
+					{
+						"package": {
+							"name": "golang.org/x/text/language",
+							"ecosystem": "Go"
+						},
+						"ranges": [
+							{
+								"type": "SEMVER",
+								"events": [
+									{
+										"introduced": "0"
+									},
+									{
+										"fixed": "0.3.7"
+									}
+								]
+							}
+						],
+						"database_specific": {
+							"url": "https://pkg.go.dev/vuln/GO-2021-0113"
+						},
+						"ecosystem_specific": {
+							"symbols": [
+								"Parse",
+								"MatchStrings",
+								"MustParse",
+								"ParseAcceptLanguage"
+							]
+						}
+					}
+				],
+				"references": [
+					{
+						"type": "FIX",
+						"url": "https://go-review.googlesource.com/c/text/+/340830"
+					},
+					{
+						"type": "FIX",
+						"url": "https://go.googlesource.com/text/+/383b2e75a7a4198c42f8f87833eefb772868a56f"
+					}
+				]
+			},
+			"Symbol": "ParseAcceptLanguage",
+			"PkgPath": "golang.org/x/text/language",
+			"ModPath": "golang.org/x/text",
+			"CallSink": 0,
+			"ImportSink": 1,
+			"RequireSink": 1
+		}
+	]
+}