From 1fb32b9b2f1196f02fdd0aba8f55e18684e9e932 Mon Sep 17 00:00:00 2001
From: Valentin Rothberg <rothberg@redhat.com>
Date: Fri, 10 Jul 2020 15:22:39 +0200
Subject: version/info: format: allow more json variants

Allow more variants to yield json output for `podman version` and
`podman info`.  Instead of comparing strings, use a regex and add
unit and e2e tests.

Fixes: #6927
Signed-off-by: Valentin Rothberg <rothberg@redhat.com>
---
 cmd/podman/parse/json.go      |  9 +++++++++
 cmd/podman/parse/json_test.go | 30 ++++++++++++++++++++++++++++++
 cmd/podman/system/info.go     |  3 ++-
 cmd/podman/system/version.go  |  3 ++-
 test/e2e/info_test.go         | 30 +++++++++++++++++++++++++-----
 test/e2e/version_test.go      | 34 +++++++++++++++++++++++-----------
 6 files changed, 91 insertions(+), 18 deletions(-)
 create mode 100644 cmd/podman/parse/json.go
 create mode 100644 cmd/podman/parse/json_test.go

diff --git a/cmd/podman/parse/json.go b/cmd/podman/parse/json.go
new file mode 100644
index 000000000..95a6633b8
--- /dev/null
+++ b/cmd/podman/parse/json.go
@@ -0,0 +1,9 @@
+package parse
+
+import "regexp"
+
+var jsonFormatRegex = regexp.MustCompile(`^(\s*json\s*|\s*{{\s*json\s*\.\s*}}\s*)$`)
+
+func MatchesJSONFormat(s string) bool {
+	return jsonFormatRegex.Match([]byte(s))
+}
diff --git a/cmd/podman/parse/json_test.go b/cmd/podman/parse/json_test.go
new file mode 100644
index 000000000..5cad185fd
--- /dev/null
+++ b/cmd/podman/parse/json_test.go
@@ -0,0 +1,30 @@
+package parse
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestMatchesJSONFormat(t *testing.T) {
+	tests := []struct {
+		input    string
+		expected bool
+	}{
+		{"json", true},
+		{" json", true},
+		{"json ", true},
+		{"  json   ", true},
+		{"{{json .}}", true},
+		{"{{ json .}}", true},
+		{"{{json .   }}", true},
+		{"  {{  json .    }}   ", true},
+		{"{{json }}", false},
+		{"{{json .", false},
+		{"json . }}", false},
+	}
+
+	for _, tt := range tests {
+		assert.Equal(t, tt.expected, MatchesJSONFormat(tt.input))
+	}
+}
diff --git a/cmd/podman/system/info.go b/cmd/podman/system/info.go
index 699f7b55c..410b3455a 100644
--- a/cmd/podman/system/info.go
+++ b/cmd/podman/system/info.go
@@ -5,6 +5,7 @@ import (
 	"os"
 	"text/template"
 
+	"github.com/containers/libpod/v2/cmd/podman/parse"
 	"github.com/containers/libpod/v2/cmd/podman/registry"
 	"github.com/containers/libpod/v2/cmd/podman/validate"
 	"github.com/containers/libpod/v2/pkg/domain/entities"
@@ -68,7 +69,7 @@ func info(cmd *cobra.Command, args []string) error {
 		return err
 	}
 
-	if inFormat == "json" {
+	if parse.MatchesJSONFormat(inFormat) {
 		b, err := json.MarshalIndent(info, "", "  ")
 		if err != nil {
 			return err
diff --git a/cmd/podman/system/version.go b/cmd/podman/system/version.go
index 5aac34699..9b70bc9f4 100644
--- a/cmd/podman/system/version.go
+++ b/cmd/podman/system/version.go
@@ -8,6 +8,7 @@ import (
 	"text/tabwriter"
 
 	"github.com/containers/buildah/pkg/formats"
+	"github.com/containers/libpod/v2/cmd/podman/parse"
 	"github.com/containers/libpod/v2/cmd/podman/registry"
 	"github.com/containers/libpod/v2/cmd/podman/validate"
 	"github.com/containers/libpod/v2/libpod/define"
@@ -41,7 +42,7 @@ func version(cmd *cobra.Command, args []string) error {
 	}
 
 	switch {
-	case versionFormat == "json", versionFormat == "{{ json .}}":
+	case parse.MatchesJSONFormat(versionFormat):
 		s, err := json.MarshalToString(versions)
 		if err != nil {
 			return err
diff --git a/test/e2e/info_test.go b/test/e2e/info_test.go
index e38ace53f..8aa9712fd 100644
--- a/test/e2e/info_test.go
+++ b/test/e2e/info_test.go
@@ -11,6 +11,7 @@ import (
 	. "github.com/containers/libpod/v2/test/utils"
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
+	. "github.com/onsi/gomega/gexec"
 )
 
 var _ = Describe("Podman Info", func() {
@@ -35,11 +36,30 @@ var _ = Describe("Podman Info", func() {
 		processTestResult(f)
 	})
 
-	It("podman info json output", func() {
-		session := podmanTest.Podman([]string{"info", "--format=json"})
-		session.WaitWithDefaultTimeout()
-		Expect(session.ExitCode()).To(Equal(0))
-
+	It("podman info --format json", func() {
+		tests := []struct {
+			input    string
+			success  bool
+			exitCode int
+		}{
+			{"json", true, 0},
+			{" json", true, 0},
+			{"json ", true, 0},
+			{"  json   ", true, 0},
+			{"{{json .}}", true, 0},
+			{"{{ json .}}", true, 0},
+			{"{{json .   }}", true, 0},
+			{"  {{  json .    }}   ", true, 0},
+			{"{{json }}", false, 125},
+			{"{{json .", false, 125},
+			{"json . }}", false, 0}, // Note: this does NOT fail but produces garbage
+		}
+		for _, tt := range tests {
+			session := podmanTest.Podman([]string{"info", "--format", tt.input})
+			session.WaitWithDefaultTimeout()
+			Expect(session).Should(Exit(tt.exitCode))
+			Expect(session.IsJSONOutputValid()).To(Equal(tt.success))
+		}
 	})
 
 	It("podman info --format GO template", func() {
diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go
index 775be6511..eb1d1b733 100644
--- a/test/e2e/version_test.go
+++ b/test/e2e/version_test.go
@@ -55,17 +55,29 @@ var _ = Describe("Podman version", func() {
 	})
 
 	It("podman version --format json", func() {
-		session := podmanTest.Podman([]string{"version", "--format", "json"})
-		session.WaitWithDefaultTimeout()
-		Expect(session).Should(Exit(0))
-		Expect(session.IsJSONOutputValid()).To(BeTrue())
-	})
-
-	It("podman version --format json", func() {
-		session := podmanTest.Podman([]string{"version", "--format", "{{ json .}}"})
-		session.WaitWithDefaultTimeout()
-		Expect(session).Should(Exit(0))
-		Expect(session.IsJSONOutputValid()).To(BeTrue())
+		tests := []struct {
+			input    string
+			success  bool
+			exitCode int
+		}{
+			{"json", true, 0},
+			{" json", true, 0},
+			{"json ", true, 0},
+			{"  json   ", true, 0},
+			{"{{json .}}", true, 0},
+			{"{{ json .}}", true, 0},
+			{"{{json .   }}", true, 0},
+			{"  {{  json .    }}   ", true, 0},
+			{"{{json }}", false, 125},
+			{"{{json .", false, 125},
+			{"json . }}", false, 0}, // Note: this does NOT fail but produces garbage
+		}
+		for _, tt := range tests {
+			session := podmanTest.Podman([]string{"version", "--format", tt.input})
+			session.WaitWithDefaultTimeout()
+			Expect(session).Should(Exit(tt.exitCode))
+			Expect(session.IsJSONOutputValid()).To(Equal(tt.success))
+		}
 	})
 
 	It("podman version --format GO template", func() {
-- 
cgit v1.2.3-54-g00ecf