summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorantichris <[email protected]>2021-04-06 06:46:20 +0300
committerGitHub <[email protected]>2021-04-06 06:46:20 +0300
commit4a17a04514e754aded1594d4125264e1e1976c6b (patch)
tree98777cffc723aa203a5311cb329830ec30a7508e
parent002575c9d5d6c6e162302512c5b899920e839e56 (diff)
complete: enable complete.Complete() output capturing (#138)
* complete: test capturing Complete() output Implement an Example test to demonstrate capturing the output of Complete(), which is crucial for integration tests. * complete: do not hard-code the I/O streams at the package initialization Instead of defining the input/output streams as unexported global vars that only get their values assigned to once, at the very initialization of the package, use the values that `os.Stdin` and `os.Stdout` have at the particular moment on every `complete.Complete()` call. Fix #137 * complete: capture and discard output in TestComplete Restore earlier behavior using proper stream redirection this time. * complete: output capturing example: define things in the package scope Define the `stringLookup` func type and `promptEnv` func in the package scope instead of the `ExampleComplete_outputCapturing` test. * complete: rename the `stringLookup` func type to `getEnvFn`
-rw-r--r--complete.go10
-rw-r--r--complete_test.go48
2 files changed, 52 insertions, 6 deletions
diff --git a/complete.go b/complete.go
index 2a4c905..0641c39 100644
--- a/complete.go
+++ b/complete.go
@@ -49,10 +49,8 @@ func (p PredictFunc) Predict(prefix string) []string {
}
var (
- getEnv = os.Getenv
- exit = os.Exit
- out io.Writer = os.Stdout
- in io.Reader = os.Stdin
+ getEnv = os.Getenv
+ exit = os.Exit
)
// Complete the command line arguments for the given command in the case that the program
@@ -66,6 +64,10 @@ func Complete(name string, cmd Completer) {
doUninstall = getEnv("COMP_UNINSTALL") == "1"
yes = getEnv("COMP_YES") == "1"
)
+ var (
+ out io.Writer = os.Stdout
+ in io.Reader = os.Stdin
+ )
if doInstall || doUninstall {
install.Run(name, doUninstall, yes, out, in)
exit(0)
diff --git a/complete_test.go b/complete_test.go
index 3a0809f..9870910 100644
--- a/complete_test.go
+++ b/complete_test.go
@@ -1,8 +1,10 @@
package complete
import (
+ "io"
"io/ioutil"
"os"
+ "strconv"
"testing"
"github.com/posener/complete/v2/internal/arg"
@@ -159,9 +161,17 @@ func TestComplete(t *testing.T) {
defer func() {
getEnv = os.Getenv
exit = os.Exit
- out = os.Stdout
}()
+ in, out, err := os.Pipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer func(o *os.File) { os.Stdout = o }(os.Stdout)
+ defer out.Close()
+ os.Stdout = out
+ go io.Copy(ioutil.Discard, in)
+
tests := []struct {
line, point string
shouldExit bool
@@ -203,7 +213,6 @@ func TestComplete(t *testing.T) {
exit = func(int) {
isExit = true
}
- out = ioutil.Discard
if tt.shouldPanic {
assert.Panics(t, func() { testCmd.Complete("") })
} else {
@@ -214,6 +223,24 @@ func TestComplete(t *testing.T) {
}
}
+// ExampleComplete_outputCapturing demonstrates the ability to capture
+// the output of Complete() invocations, crucial for integration tests.
+func ExampleComplete_outputCapturing() {
+ defer func(f func(int)) { exit = f }(exit)
+ defer func(f getEnvFn) { getEnv = f }(getEnv)
+ exit = func(int) {}
+
+ // This is where the actual example starts:
+
+ cmd := &Command{Sub: map[string]*Command{"bar": {}}}
+ getEnv = promptEnv("foo b")
+
+ Complete("foo", cmd)
+
+ // Output:
+ // bar
+}
+
type set []string
func (s set) Predict(_ string) []string {
@@ -245,3 +272,20 @@ func TestHasPrefix(t *testing.T) {
})
}
}
+
+// getEnvFn emulates os.GetEnv by mapping one string to another.
+type getEnvFn = func(string) string
+
+// promptEnv returns getEnvFn that emulates the environment variables
+// a shell would set when its prompt has the given contents.
+var promptEnv = func(contents string) getEnvFn {
+ return func(key string) string {
+ switch key {
+ case "COMP_LINE":
+ return contents
+ case "COMP_POINT":
+ return strconv.Itoa(len(contents))
+ }
+ return ""
+ }
+}