Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport JSON InputSource to v1 #598

Merged
merged 3 commits into from
Feb 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -701,9 +701,9 @@ the yaml input source for any flags that are defined on that command. As a note
the "load" flag used would also have to be defined on the command flags in order
for this code snipped to work.

Currently only the aboved specified formats are supported but developers can
add support for other input sources by implementing the
altsrc.InputSourceContext for their given sources.
Currently only YAML and JSON files are supported but developers can add support
for other input sources by implementing the altsrc.InputSourceContext for their
given sources.

Here is a more complete sample of a command using YAML support:

Expand Down
324 changes: 324 additions & 0 deletions altsrc/json_command_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,324 @@
package altsrc

import (
"flag"
"io/ioutil"
"os"
"testing"

"gopkg.in/urfave/cli.v1"
)

const (
fileName = "current.json"
simpleJSON = `{"test": 15}`
nestedJSON = `{"top": {"test": 15}}`
)

func TestCommandJSONFileTest(t *testing.T) {
cleanup := writeTempFile(t, fileName, simpleJSON)
defer cleanup()

app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"test-cmd", "--load", fileName}
set.Parse(test)

c := cli.NewContext(app, set, nil)

command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("test")
expect(t, val, 15)
return nil
},
Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test"}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
err := command.Run(c)

expect(t, err, nil)
}

func TestCommandJSONFileTestGlobalEnvVarWins(t *testing.T) {
cleanup := writeTempFile(t, fileName, simpleJSON)
defer cleanup()

app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
os.Setenv("THE_TEST", "10")
defer os.Setenv("THE_TEST", "")

test := []string{"test-cmd", "--load", fileName}
set.Parse(test)

c := cli.NewContext(app, set, nil)

command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("test")
expect(t, val, 10)
return nil
},
Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "THE_TEST"}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))

err := command.Run(c)

expect(t, err, nil)
}

func TestCommandJSONFileTestGlobalEnvVarWinsNested(t *testing.T) {
cleanup := writeTempFile(t, fileName, nestedJSON)
defer cleanup()

app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
os.Setenv("THE_TEST", "10")
defer os.Setenv("THE_TEST", "")

test := []string{"test-cmd", "--load", fileName}
set.Parse(test)

c := cli.NewContext(app, set, nil)

command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("top.test")
expect(t, val, 10)
return nil
},
Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "top.test", EnvVar: "THE_TEST"}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))

err := command.Run(c)

expect(t, err, nil)
}

func TestCommandJSONFileTestSpecifiedFlagWins(t *testing.T) {
cleanup := writeTempFile(t, fileName, simpleJSON)
defer cleanup()

app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"test-cmd", "--load", fileName, "--test", "7"}
set.Parse(test)

c := cli.NewContext(app, set, nil)

command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("test")
expect(t, val, 7)
return nil
},
Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test"}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))

err := command.Run(c)

expect(t, err, nil)
}

func TestCommandJSONFileTestSpecifiedFlagWinsNested(t *testing.T) {
cleanup := writeTempFile(t, fileName, nestedJSON)
defer cleanup()

app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"test-cmd", "--load", fileName, "--top.test", "7"}
set.Parse(test)

c := cli.NewContext(app, set, nil)

command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("top.test")
expect(t, val, 7)
return nil
},
Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "top.test"}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))

err := command.Run(c)

expect(t, err, nil)
}

func TestCommandJSONFileTestDefaultValueFileWins(t *testing.T) {
cleanup := writeTempFile(t, fileName, simpleJSON)
defer cleanup()

app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"test-cmd", "--load", fileName}
set.Parse(test)

c := cli.NewContext(app, set, nil)

command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("test")
expect(t, val, 15)
return nil
},
Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test", Value: 7}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))

err := command.Run(c)

expect(t, err, nil)
}

func TestCommandJSONFileTestDefaultValueFileWinsNested(t *testing.T) {
cleanup := writeTempFile(t, fileName, nestedJSON)
defer cleanup()

app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
test := []string{"test-cmd", "--load", fileName}
set.Parse(test)

c := cli.NewContext(app, set, nil)

command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("top.test")
expect(t, val, 15)
return nil
},
Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "top.test", Value: 7}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))

err := command.Run(c)

expect(t, err, nil)
}

func TestCommandJSONFileFlagHasDefaultGlobalEnvJSONSetGlobalEnvWins(t *testing.T) {
cleanup := writeTempFile(t, fileName, simpleJSON)
defer cleanup()

app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
os.Setenv("THE_TEST", "11")
defer os.Setenv("THE_TEST", "")

test := []string{"test-cmd", "--load", fileName}
set.Parse(test)

c := cli.NewContext(app, set, nil)

command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("test")
expect(t, val, 11)
return nil
},
Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "test", Value: 7, EnvVar: "THE_TEST"}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
err := command.Run(c)

expect(t, err, nil)
}

func TestCommandJSONFileFlagHasDefaultGlobalEnvJSONSetGlobalEnvWinsNested(t *testing.T) {
cleanup := writeTempFile(t, fileName, nestedJSON)
defer cleanup()

app := cli.NewApp()
set := flag.NewFlagSet("test", 0)
os.Setenv("THE_TEST", "11")
defer os.Setenv("THE_TEST", "")

test := []string{"test-cmd", "--load", fileName}
set.Parse(test)

c := cli.NewContext(app, set, nil)

command := &cli.Command{
Name: "test-cmd",
Aliases: []string{"tc"},
Usage: "this is for testing",
Description: "testing",
Action: func(c *cli.Context) error {
val := c.Int("top.test")
expect(t, val, 11)
return nil
},
Flags: []cli.Flag{
NewIntFlag(cli.IntFlag{Name: "top.test", Value: 7, EnvVar: "THE_TEST"}),
&cli.StringFlag{Name: "load"}},
}
command.Before = InitInputSourceWithContext(command.Flags, NewJSONSourceFromFlagFunc("load"))
err := command.Run(c)

expect(t, err, nil)
}

func writeTempFile(t *testing.T, name string, content string) func() {
if err := ioutil.WriteFile(name, []byte(content), 0666); err != nil {
t.Fatalf("cannot write %q: %v", name, err)
}
return func() {
if err := os.Remove(name); err != nil {
t.Errorf("cannot remove %q: %v", name, err)
}
}
}