646 lines
16 KiB
Go
646 lines
16 KiB
Go
// Copyright © 2022 Roberto Hidalgo <joao@un.rob.mx>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
package cmd_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"os"
|
|
"path"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
|
|
. "git.rob.mx/nidito/joao/cmd"
|
|
opclient "git.rob.mx/nidito/joao/internal/op-client"
|
|
"git.rob.mx/nidito/joao/internal/op-client/mock"
|
|
"github.com/1Password/connect-sdk-go/connect"
|
|
"github.com/1Password/connect-sdk-go/onepassword"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var testConfig = &onepassword.Item{
|
|
Title: "some:test",
|
|
Vault: onepassword.ItemVault{ID: "example"},
|
|
Category: "PASSWORD",
|
|
Sections: []*onepassword.ItemSection{
|
|
{ID: "~annotations", Label: "~annotations"},
|
|
{ID: "nested", Label: "nested"},
|
|
{ID: "list", Label: "list"},
|
|
},
|
|
Fields: []*onepassword.ItemField{
|
|
{
|
|
ID: "password",
|
|
Type: "CONCEALED",
|
|
Purpose: "PASSWORD",
|
|
Label: "password",
|
|
Value: "8b23de7705b79b73d9f75b120651bc162859e45a732b764362feaefc882eab5d",
|
|
},
|
|
{
|
|
ID: "notesPlain",
|
|
Type: "STRING",
|
|
Purpose: "NOTES",
|
|
Label: "notesPlain",
|
|
Value: "flushed by joao",
|
|
},
|
|
{
|
|
ID: "~annotations.int",
|
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
|
Type: "STRING",
|
|
Label: "int",
|
|
Value: "int",
|
|
},
|
|
{
|
|
ID: "int",
|
|
Type: "STRING",
|
|
Label: "int",
|
|
Value: "1",
|
|
},
|
|
{
|
|
ID: "string",
|
|
Type: "STRING",
|
|
Label: "string",
|
|
Value: "pato",
|
|
},
|
|
{
|
|
ID: "~annotations.bool",
|
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
|
Type: "STRING",
|
|
Label: "bool",
|
|
Value: "bool",
|
|
},
|
|
{
|
|
ID: "bool",
|
|
Type: "STRING",
|
|
Label: "bool",
|
|
Value: "false",
|
|
},
|
|
{
|
|
ID: "~annotations.secret",
|
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
|
Type: "STRING",
|
|
Label: "secret",
|
|
Value: "secret",
|
|
},
|
|
{
|
|
ID: "secret",
|
|
Type: "CONCEALED",
|
|
Label: "secret",
|
|
Value: "very secret",
|
|
},
|
|
{
|
|
ID: "~annotations.nested.int",
|
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
|
Type: "STRING",
|
|
Label: "nested.int",
|
|
Value: "int",
|
|
},
|
|
{
|
|
ID: "nested.int",
|
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
|
Type: "STRING",
|
|
Label: "int",
|
|
Value: "1",
|
|
},
|
|
{
|
|
ID: "~annotations.nested.bool",
|
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
|
Type: "STRING",
|
|
Label: "nested.bool",
|
|
Value: "bool",
|
|
},
|
|
{
|
|
ID: "nested.bool",
|
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
|
Type: "STRING",
|
|
Label: "bool",
|
|
Value: "true",
|
|
},
|
|
{
|
|
ID: "~annotations.nested.list.0",
|
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
|
Type: "STRING",
|
|
Label: "nested.list.0",
|
|
Value: "int",
|
|
},
|
|
{
|
|
ID: "nested.list.0",
|
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
|
Type: "STRING",
|
|
Label: "list.0",
|
|
Value: "1",
|
|
},
|
|
{
|
|
ID: "~annotations.nested.list.1",
|
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
|
Type: "STRING",
|
|
Label: "nested.list.1",
|
|
Value: "int",
|
|
},
|
|
{
|
|
ID: "nested.list.1",
|
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
|
Type: "STRING",
|
|
Label: "list.1",
|
|
Value: "2",
|
|
},
|
|
{
|
|
ID: "~annotations.nested.list.2",
|
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
|
Type: "STRING",
|
|
Label: "nested.list.2",
|
|
Value: "int",
|
|
},
|
|
{
|
|
ID: "nested.list.2",
|
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
|
Type: "STRING",
|
|
Label: "list.2",
|
|
Value: "3",
|
|
},
|
|
{
|
|
ID: "~annotations.nested.secret",
|
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
|
Type: "STRING",
|
|
Label: "nested.secret",
|
|
Value: "secret",
|
|
},
|
|
{
|
|
ID: "nested.secret",
|
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
|
Type: "CONCEALED",
|
|
Label: "secret",
|
|
Value: "very secret",
|
|
},
|
|
{
|
|
ID: "~annotations.nested.second_secret",
|
|
Section: &onepassword.ItemSection{ID: "~annotations", Label: "~annotations"},
|
|
Type: "STRING",
|
|
Label: "nested.second_secret",
|
|
Value: "secret",
|
|
},
|
|
{
|
|
ID: "nested.second_secret",
|
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
|
Type: "CONCEALED",
|
|
Label: "second_secret",
|
|
Value: "very secret",
|
|
},
|
|
{
|
|
ID: "nested.string",
|
|
Section: &onepassword.ItemSection{ID: "nested", Label: "nested"},
|
|
Type: "STRING",
|
|
Label: "string",
|
|
Value: "quem",
|
|
},
|
|
{
|
|
ID: "list.0",
|
|
Section: &onepassword.ItemSection{ID: "list", Label: "list"},
|
|
Type: "STRING",
|
|
Label: "0",
|
|
Value: "one",
|
|
},
|
|
{
|
|
ID: "list.1",
|
|
Section: &onepassword.ItemSection{ID: "list", Label: "list"},
|
|
Type: "STRING",
|
|
Label: "1",
|
|
Value: "two",
|
|
},
|
|
{
|
|
ID: "list.2",
|
|
Section: &onepassword.ItemSection{ID: "list", Label: "list"},
|
|
Type: "STRING",
|
|
Label: "2",
|
|
Value: "three",
|
|
},
|
|
},
|
|
}
|
|
|
|
func mockOPConnect(t *testing.T) {
|
|
t.Helper()
|
|
opclient.ConnectClientFactory = func(host, token, userAgent string) connect.Client {
|
|
return &mock.Client{}
|
|
}
|
|
client := opclient.NewConnect("", "")
|
|
opclient.Use(client)
|
|
mock.Add(testConfig)
|
|
}
|
|
|
|
func fromProjectRoot() string {
|
|
_, filename, _, _ := runtime.Caller(0)
|
|
dir := path.Join(path.Dir(filename), "../")
|
|
if err := os.Chdir(dir); err != nil {
|
|
panic(err)
|
|
}
|
|
wd, _ := os.Getwd()
|
|
return wd
|
|
}
|
|
|
|
func TestGetBadYAML(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
Get.SetBindings()
|
|
out := bytes.Buffer{}
|
|
cmd := &cobra.Command{}
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
err := Get.Run(cmd, []string{root + "/bad-test.yaml", "."})
|
|
if err == nil {
|
|
t.Fatalf("Did not throw on bad path: %s", out.String())
|
|
}
|
|
wantedPrefix := "could not parse file"
|
|
wantedSuffix := "/bad-test.yaml as yaml: line 4: mapping values are not allowed in this context"
|
|
if got := err.Error(); !(strings.HasPrefix(got, wantedPrefix) && strings.HasSuffix(got, wantedSuffix)) {
|
|
t.Fatalf("Failed with bad error, wanted %s /some-path%s, got %s", wantedPrefix, wantedSuffix, got)
|
|
}
|
|
}
|
|
|
|
func TestGetBadPath(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
Get.SetBindings()
|
|
out := bytes.Buffer{}
|
|
cmd := &cobra.Command{}
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
err := Get.Run(cmd, []string{root + "/does-not-exist.yaml", "."})
|
|
if err == nil {
|
|
t.Fatalf("Did not throw on bad path: %s", out.String())
|
|
}
|
|
wantedPrefix := "could not read file"
|
|
wantedSuffix := "/does-not-exist.yaml"
|
|
|
|
if got := err.Error(); !(strings.HasPrefix(got, wantedPrefix) && strings.HasSuffix(got, wantedSuffix)) {
|
|
t.Fatalf("Failed with bad error, wanted %s /some-path%s, got %s", wantedPrefix, wantedSuffix, got)
|
|
}
|
|
}
|
|
|
|
func TestGetNormal(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", false, "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
err := Get.Run(cmd, []string{root + "/test.yaml", "."})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected, err := os.ReadFile(root + "/test.yaml")
|
|
if err != nil {
|
|
t.Fatalf("could not read file: %s", err)
|
|
}
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != strings.TrimSpace(string(expected)) {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetRedacted(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", true, "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
os.Args = []string{root + "/test.yaml", ".", "--redacted"}
|
|
err := Get.Run(cmd, []string{root + "/test.yaml", "."})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected, err := os.ReadFile(root + "/test.yaml")
|
|
if err != nil {
|
|
t.Fatalf("could not read file: %s", err)
|
|
}
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != strings.ReplaceAll(strings.TrimSpace(string(expected)), " very secret", "") {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetPath(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", false, "")
|
|
cmd.Flags().StringP("output", "o", "yaml", "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
os.Args = []string{root + "/test.yaml", "nested.secret"}
|
|
err := Get.Run(cmd, os.Args)
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected := "very secret"
|
|
if got := out.String(); strings.TrimSpace(got) != strings.TrimSpace(expected) {
|
|
t.Fatalf("did not get expected scalar output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
|
|
out = bytes.Buffer{}
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
os.Args = []string{root + "/test.yaml", "nested", "--output", "diff-yaml"}
|
|
err = Get.Run(cmd, []string{root + "/test.yaml", "nested"})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected = `bool: true
|
|
int: 1
|
|
list:
|
|
- 1
|
|
- 2
|
|
- 3
|
|
second_secret: very secret
|
|
secret: very secret
|
|
string: quem`
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != strings.TrimSpace(expected) {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetPathCollection(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", false, "")
|
|
cmd.Flags().StringP("output", "o", "yaml", "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
os.Args = []string{root + "/test.yaml", "nested", "--output", "yaml"}
|
|
err := Get.Run(cmd, []string{root + "/test.yaml", "nested"})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected := `bool: true
|
|
int: 1
|
|
list:
|
|
- 1
|
|
- 2
|
|
- 3
|
|
second_secret: very secret
|
|
secret: very secret
|
|
string: quem`
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetDiff(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", false, "")
|
|
cmd.Flags().StringP("output", "o", "diff-yaml", "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
os.Args = []string{root + "/test.yaml", ".", "--output", "diff-yaml"}
|
|
err := Get.Run(cmd, []string{root + "/test.yaml", "."})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected := `_config: !!joao
|
|
name: some:test
|
|
vault: example
|
|
bool: false
|
|
int: 1
|
|
list:
|
|
- one
|
|
- two
|
|
- three
|
|
nested:
|
|
bool: true
|
|
int: 1
|
|
list:
|
|
- 1
|
|
- 2
|
|
- 3
|
|
second_secret: !!secret very secret
|
|
secret: !!secret very secret
|
|
string: quem
|
|
secret: !!secret very secret
|
|
string: pato`
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetJSON(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", false, "")
|
|
cmd.Flags().StringP("output", "o", "json", "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
os.Args = []string{root + "/test.yaml", ".", "--output", "json"}
|
|
err := Get.Run(cmd, []string{root + "/test.yaml", "."})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected := `{"bool":false,"int":1,"list":["one","two","three"],"nested":{"bool":true,"int":1,"list":[1,2,3],"second_secret":"very secret","secret":"very secret","string":"quem"},"secret":"very secret","string":"pato"}`
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetDeepJSON(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", false, "")
|
|
cmd.Flags().StringP("output", "o", "json", "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
os.Args = []string{root + "/deeply-nested.test.yaml", ".", "--output", "json"}
|
|
err := Get.Run(cmd, []string{root + "/deeply-nested.test.yaml", "."})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected := `{"root":{"of":{"deeply":{"nested_list":["10.42.31.42/32"],"nested_map":"asdf"}}}}`
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetJSONPathScalar(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", false, "")
|
|
cmd.Flags().StringP("output", "o", "json", "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
os.Args = []string{root + "/test.yaml", "nested.secret", "--output", "json"}
|
|
err := Get.Run(cmd, []string{root + "/test.yaml", "nested.secret"})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected := `very secret` // nolint: ifshort
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetJSONPathCollection(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", false, "")
|
|
cmd.Flags().StringP("output", "o", "json", "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
os.Args = []string{root + "/test.yaml", "nested", "--output", "json"}
|
|
err := Get.Run(cmd, []string{root + "/test.yaml", "nested"})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected := `{"bool":true,"int":1,"list":[1,2,3],"second_secret":"very secret","secret":"very secret","string":"quem"}`
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetJSONRedacted(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", true, "")
|
|
cmd.Flags().StringP("output", "o", "json", "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
os.Args = []string{root + "/test.yaml", ".", "--output", "json", "--redacted"}
|
|
err := Get.Run(cmd, []string{root + "/test.yaml", "."})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected := `{"bool":false,"int":1,"list":["one","two","three"],"nested":{"bool":true,"int":1,"list":[1,2,3],"second_secret":"","secret":"","string":"quem"},"secret":"","string":"pato"}`
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetJSONOP(t *testing.T) {
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().StringP("output", "o", "op", "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
os.Args = []string{root + "/test.yaml", ".", "--output", "op"}
|
|
err := Get.Run(cmd, []string{root + "/test.yaml", "."})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
id := testConfig.ID
|
|
testConfig.ID = ""
|
|
defer func() { testConfig.ID = id }()
|
|
expected, err := json.Marshal(testConfig)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != strings.TrimSpace(string(expected)) {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|
|
|
|
func TestGetRemote(t *testing.T) {
|
|
mockOPConnect(t)
|
|
root := fromProjectRoot()
|
|
out := bytes.Buffer{}
|
|
Get.SetBindings()
|
|
cmd := &cobra.Command{}
|
|
cmd.Flags().Bool("redacted", false, "")
|
|
cmd.Flags().Bool("remote", true, "")
|
|
cmd.Flags().StringP("output", "o", "diff-yaml", "")
|
|
cmd.SetOut(&out)
|
|
cmd.SetErr(&out)
|
|
Get.Cobra = cmd
|
|
logrus.SetLevel(logrus.DebugLevel)
|
|
os.Args = []string{root + "/test.yaml", "."}
|
|
err := Get.Run(cmd, []string{root + "/test.yaml", "."})
|
|
|
|
if err != nil {
|
|
t.Fatalf("could not get: %s", err)
|
|
}
|
|
|
|
expected := `bool: false
|
|
int: 1
|
|
list:
|
|
- one
|
|
- two
|
|
- three
|
|
nested:
|
|
bool: true
|
|
int: 1
|
|
list:
|
|
- 1
|
|
- 2
|
|
- 3
|
|
second_secret: !!secret very secret
|
|
secret: !!secret very secret
|
|
string: quem
|
|
secret: !!secret very secret
|
|
string: pato`
|
|
|
|
if got := out.String(); strings.TrimSpace(got) != expected {
|
|
t.Fatalf("did not get expected output:\nwanted: %s\ngot: %s", expected, got)
|
|
}
|
|
}
|