The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/3235
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) === This is a proof of concept of some unit-testable code that I'd like to later use for making cmdInit testable (as per #2834). It's small so should it be easy to review and because I wish to have some feedback on the approach before moving forward. I hope that the branch gives a feel of what further branches would look like. As a general note, I feel it'd be important to improve coverage of the parts that can be unit tested easily (so basically most higher-level application logic except for system-level interactions). I think this can be done incrementally without too much disruption, if we agree. Signed-off-by: Free Ekanayaka <[email protected]>
From c2745ac8116012dc2a8d115dde51fbb2b8f80af9 Mon Sep 17 00:00:00 2001 From: Free Ekanayaka <[email protected]> Date: Thu, 27 Apr 2017 15:04:46 +0200 Subject: [PATCH] Add a new shared/cmd package with initial command I/O logic This is a proof of concept of some unit-testable code that I'd like to later use for making cmdInit testable (as per #2834). It's small so should it be easy to review and because I wish to have some feedback on the approach before moving forward. I hope that the branch gives a feel of what further branches would look like. As a general note, I feel it'd be important to improve coverage of the parts that can be unit tested easily (so basically most higher-level application logic except for system-level interactions). I think this can be done incrementally without too much disruption, if we agree. Signed-off-by: Free Ekanayaka <[email protected]> --- shared/cmd/context.go | 50 +++++++++++++++++++++++++++++ shared/cmd/context_test.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++ shared/cmd/doc.go | 11 +++++++ 3 files changed, 141 insertions(+) create mode 100644 shared/cmd/context.go create mode 100644 shared/cmd/context_test.go create mode 100644 shared/cmd/doc.go diff --git a/shared/cmd/context.go b/shared/cmd/context.go new file mode 100644 index 0000000..2b7384f --- /dev/null +++ b/shared/cmd/context.go @@ -0,0 +1,50 @@ +package cmd + +import ( + "bufio" + "fmt" + "io" + "strings" + + "github.com/lxc/lxd/shared" +) + +// Context captures the environment the sub-command is being run in, +// such as in/out/err streams and command line arguments. +type Context struct { + stdin io.Reader + stdout io.Writer +} + +// NewContext creates a new command context with the given parameters. +func NewContext(stdin io.Reader, stdout io.Writer) *Context { + return &Context{ + stdin: stdin, + stdout: stdout, + } +} + +// AskBool asks a question an expect a yes/no answer. +func (c *Context) AskBool(question string, defaultAnswer string) bool { + + reader := bufio.NewReader(c.stdin) + + for { + fmt.Fprintf(c.stdout, question) + + answer, _ := reader.ReadString('\n') + answer = strings.TrimSuffix(answer, "\n") + + if answer == "" { + answer = defaultAnswer + } + + if shared.StringInSlice(strings.ToLower(answer), []string{"yes", "y"}) { + return true + } else if shared.StringInSlice(strings.ToLower(answer), []string{"no", "n"}) { + return false + } + + fmt.Fprintf(c.stdout, "Invalid input, try again.\n\n") + } +} diff --git a/shared/cmd/context_test.go b/shared/cmd/context_test.go new file mode 100644 index 0000000..162320f --- /dev/null +++ b/shared/cmd/context_test.go @@ -0,0 +1,80 @@ +package cmd_test + +import ( + "bytes" + "strings" + "testing" + + "github.com/lxc/lxd/shared/cmd" +) + +// The given question is printed on standard output. +func TestAskBoolPrintQuestion(t *testing.T) { + stdin := strings.NewReader("\n") + stdout := new(bytes.Buffer) + context := cmd.NewContext(stdin, stdout) + context.AskBool("Do you like me?", "yes") + + expected := "Do you like me?" + if output := stdout.String(); output != expected { + t.Errorf("Expected '%s' got '%s'", expected, output) + } +} + +// If no input is given (e.g. the user just presses "enter"), the default +// answer will be returned. +func TestAskBoolDefault(t *testing.T) { + stdin := strings.NewReader("\n") + stdout := new(bytes.Buffer) + context := cmd.NewContext(stdin, stdout) + + answer := context.AskBool("Do you like me?", "yes") + + if answer != true { + t.Errorf("Expected 'true' answer") + } +} + +// If "yes" is given, AskBool returns true. +func TestAskBoolYes(t *testing.T) { + stdin := strings.NewReader("yes\n") + stdout := new(bytes.Buffer) + context := cmd.NewContext(stdin, stdout) + + answer := context.AskBool("Do you like me?", "yes") + + if answer != true { + t.Errorf("Expected 'true' answer") + } +} + +// If "no" is given, AskBool returns false. +func TestAskBoolNo(t *testing.T) { + stdin := strings.NewReader("no\n") + stdout := new(bytes.Buffer) + context := cmd.NewContext(stdin, stdout) + + answer := context.AskBool("Do you like me?", "yes") + + if answer != false { + t.Errorf("Expected 'false' answer") + } +} + +// If an invalid answer is given, the question gets repeated until +// it succeeds. +func TestAskBoolInvalid(t *testing.T) { + stdin := strings.NewReader("foo\nyes\n") + stdout := new(bytes.Buffer) + context := cmd.NewContext(stdin, stdout) + answer := context.AskBool("Do you like me?", "yes") + + expected := "Do you like me?Invalid input, try again.\n\nDo you like me?" + if output := stdout.String(); output != expected { + t.Errorf("Expected '%s?' got '%s'", expected, output) + } + + if answer != true { + t.Errorf("Expected 'true' answer") + } +} diff --git a/shared/cmd/doc.go b/shared/cmd/doc.go new file mode 100644 index 0000000..02dab72 --- /dev/null +++ b/shared/cmd/doc.go @@ -0,0 +1,11 @@ +/* + +The package cmd implements a simple abstraction around a "sub-command" for +a main executable (e.g. "lxd init", where "init" is the sub-command). + +It is designed to make unit-testing easier, since OS-specific parts like +standard in/out can be set in tests. + +*/ + +package cmd
_______________________________________________ lxc-devel mailing list [email protected] http://lists.linuxcontainers.org/listinfo/lxc-devel
