-
Notifications
You must be signed in to change notification settings - Fork 274
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
Fix conflict with standard flag package on testing #194
Conversation
Is this something that needs solving? Isn't it just easier to use the bulitin |
"Use the bulit-in Not only that's repetitive (must be done for each project having tests), but also stops us from using our app args/flags during tests: if we call Killing a feature of the Another option is to duplicate our Kingpin flags into the All in all, a lot of us have tests and use tools that require, for example, the Personally, I'm even surprised that it has not been solved yet! 😛 |
Not exactly. It means if you have flags for modifying test behaviour, use the builtin Can you give an example of when this would not work?
It is not, but I'm not convinced this is the right solution. |
Take this main.go file: package main
import "github.com/alecthomas/kingpin"
func main() {
kingpin.Parse()
} Take this main_test.go file: package main
import "testing"
func Test(t *testing.T) {
main()
} Run a test with any valid flag of the
This one is used by every continuous integration service (like Travis CI) or editor plugin. Test fails:
Very simple use case, right? That's why I'm surprised.
Originally, like in this example, I don't even want to mess with the |
I agree, but this is not the best way to achieve that. A more resilient way is to not directly (or indirectly in your example) call Adapting your example, this would be something like this: package main
import (
"os"
"github.com/alecthomas/kingpin"
)
func run(args []string) {
kingpin.CommandLine.Parse(args)
}
func main() {
run(os.Args[1:])
} Test: package main
import "testing"
func Test(t *testing.T) {
run([]string{"--some-flag"})
} This is both safer and more flexible, as you can test your application with any variation of command line arguments you like. I'm not trying to be argumentative for the sake of being difficult. My objection is that this approach is fragile and inflexible, and basically a hack that will likely break under some conditions. |
OK, calling But like that, it's a feature of Kingpin that you kill. So (I know, I will be painful till the end), what if I still need to print usage and exit when a user makes a mistake and, at the same time, be able to just run my tests during dev?
I won't say the contrary. |
That is just an omission in the example. In reality you would check the error return value from
Then you'll need to check the error return value and call func run(args []string) error {
_, err := kingpin.CommandLine.Parse(args)
if err != nil {
return err
}
// more code...
return nil
}
func main() {
err := run(os.Args[1:])
if err != nil {
kingpin.Usage()
os.Exit(1)
}
} Thanks for the PR. I think it might be good for me to update the docs to clarify "best practice" for this approach. |
OK, and how do you differentiate an "unknown flag" error from the others? If you take all parsing errors with the same severity, you're just rewriting the Worst, a part of the problem is not even solved because using the So, to sum up, I understand that your package conflicts with the customs and habits of the language we use… And you just want to delegate the tricky and repetitive code to the users of your package for a normal usage. This is kind of a philosophy. |
You should not be parsing test arguments with kingpin. It's that simple. There are two scenarios:
No, it does not conflict with the language or habits of Go. The approach outlined above is the way you should be doing this with Go. Feel free to post your approach to golang-nuts and see what the response is.
It's 9 extra lines of code. If your argument is that perhaps this code should be included in Kingpin as a |
This fixes #167 and #187.
How it works
If it's a test (binary name ends with
.test
), keep flags that doesn't start with-test.
and remove them fromos.Args
(as we have no control over flag.Parse).Like that, for a command like
go test -timeout 5s -args --flagforkingpin
, we keep-test.timeout=5s
for flag.Parse and--flagforkingpin
for kingpin.Parse.I also tried defusing flag.Parse by replacing flag.CommandLine with a new flag.FlagSet using PanicOnError instead of ExitOnError and recover if panic error is
flag provided but not defined
.But we loose
-test.
flags.