Skip to content

Commit d1e9d85

Browse files
Make detection for test-binary more universal (#2173)
When running tests in verbose mode (or other options), tests involving Cobra may fail if the test does not explicitly set Command.args to an empty slice; in this case, Cobra defaults to using `os.Args`, which will contain arguments passed to the test (such as `-v` (verbose)). Commits e576205 and 1ef0913 implemented a workaround for this when running (unit) tests for Cobra itself, but this check is specifig to Cobra (checking for `cobra.test`), and don't work on Windows (which will have a `.exe` extension), This patch implements a more universal check, so that users of Cobra as a module also benefit from this workaround. go1.21 and up provides a `testing.Testing()` utility ([1]); as the Cobra module still supports Go1.16 and up, an alternative implementation was added for older versions, based on golang.org/x/mod/lazyregexp [2]. Before this patch: go test -c -o foo.test ./foo.test -test.run TestNoArgs --- FAIL: TestNoArgs (0.00s) args_test.go:37: Unexpected output: Error: unknown command "TestNoArgs" for "c" Usage: c [flags] Flags: -h, --help help for c args_test.go:40: Unexpected error: unknown command "TestNoArgs" for "c" FAIL After this patch: go test -c -o foo.test ./foo.test -test.run TestNoArgs PASS [1]: https://pkg.go.dev/testing#Testing [2]: https://cs.opensource.google/go/x/mod/+/refs/tags/v0.19.0:internal/lazyregexp/lazyre.go;l=66-78 Signed-off-by: Sebastiaan van Stijn <[email protected]> Signed-off-by: Marc Khouzam <[email protected]> Co-authored-by: Marc Khouzam <[email protected]>
1 parent 9f90567 commit d1e9d85

File tree

4 files changed

+76
-3
lines changed

4 files changed

+76
-3
lines changed

command.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"fmt"
2424
"io"
2525
"os"
26-
"path/filepath"
2726
"sort"
2827
"strings"
2928

@@ -1078,8 +1077,11 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
10781077

10791078
args := c.args
10801079

1081-
// Workaround FAIL with "go test -v" or "cobra.test -test.v", see #155
1082-
if c.args == nil && filepath.Base(os.Args[0]) != "cobra.test" {
1080+
// If running unit tests, we don't want to take the os.Args, see #155 and #2173.
1081+
// For example, the following would fail:
1082+
// go test -c -o foo.test
1083+
// ./foo.test -test.run TestNoArgs
1084+
if c.args == nil && !isTesting() {
10831085
args = os.Args[1:]
10841086
}
10851087

command_go120.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2013-2024 The Cobra Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//go:build !go1.21
16+
// +build !go1.21
17+
18+
package cobra
19+
20+
import (
21+
"os"
22+
"strings"
23+
)
24+
25+
// based on golang.org/x/mod/internal/lazyregexp: https://cs.opensource.google/go/x/mod/+/refs/tags/v0.19.0:internal/lazyregexp/lazyre.go;l=66
26+
// For a non-go-test program which still has a name ending with ".test[.exe]", it will need to either:
27+
// 1- Use go >= 1.21, or
28+
// 2- call "rootCmd.SetArgs(os.Args[1:])" before calling "rootCmd.Execute()"
29+
var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test")
30+
31+
func isTesting() bool {
32+
return inTest
33+
}

command_go121.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2013-2024 The Cobra Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//go:build go1.21
16+
// +build go1.21
17+
18+
package cobra
19+
20+
import "testing"
21+
22+
func isTesting() bool {
23+
// Only available starting with go 1.21
24+
return testing.Testing()
25+
}

command_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2839,3 +2839,16 @@ func TestUnknownFlagShouldReturnSameErrorRegardlessOfArgPosition(t *testing.T) {
28392839
})
28402840
}
28412841
}
2842+
2843+
// This tests verifies that when running unit tests, os.Args are not used.
2844+
// This is because we don't want to process any arguments that are provided
2845+
// by "go test"; instead, unit tests must set the arguments they need using
2846+
// rootCmd.SetArgs().
2847+
func TestNoOSArgsWhenTesting(t *testing.T) {
2848+
root := &Command{Use: "root", Run: emptyRun}
2849+
os.Args = append(os.Args, "--unknown")
2850+
2851+
if _, err := root.ExecuteC(); err != nil {
2852+
t.Errorf("error: %v", err)
2853+
}
2854+
}

0 commit comments

Comments
 (0)