package flag import ( "encoding/json" "testing" "time" ) const ( success = "\u2713" failed = "\u2717" ) // TestProcessNoArgs validates when no arguments are passed to the Process API. func TestProcessNoArgs(t *testing.T) { var cfg struct { Web struct { APIHost string `default:"0.0.0.0:3000" flag:"a" flagdesc:"The ip:port for the api endpoint."` BatchSize int `default:"1000" flagdesc:"Represets number of items to move."` ReadTimeout time.Duration `default:"5s"` } DialTimeout time.Duration `default:"5s"` Host string `default:"mongo:27017/gotraining" flag:"h"` } t.Log("Given the need to validate was handle no arguments.") { t.Log("\tWhen there are no OS arguments.") { if err := Process(&cfg); err != nil { t.Fatalf("\t%s\tShould be able to call Process with no arguments : %s.", failed, err) } t.Logf("\t%s\tShould be able to call Process with no arguments.", success) } } } // TestParse validates the ability to reflect and parse out the argument // metadata from the provided struct value. func TestParse(t *testing.T) { var cfg struct { Web struct { APIHost string `default:"0.0.0.0:3000" flag:"a" flagdesc:"The ip:port for the api endpoint."` BatchSize int `default:"1000" flagdesc:"Represets number of items to move."` ReadTimeout time.Duration `default:"5s"` } DialTimeout time.Duration `default:"5s"` Host string `default:"mongo:27017/gotraining" flag:"h"` Insecure bool `flag:"i"` } parseOutput := `[{"Short":"a","Long":"web_apihost","Default":"0.0.0.0:3000","Type":"string","Desc":"The ip:port for the api endpoint."},{"Short":"","Long":"web_batchsize","Default":"1000","Type":"int","Desc":"Represets number of items to move."},{"Short":"","Long":"web_readtimeout","Default":"5s","Type":"Duration","Desc":""},{"Short":"","Long":"dialtimeout","Default":"5s","Type":"Duration","Desc":""},{"Short":"h","Long":"host","Default":"mongo:27017/gotraining","Type":"string","Desc":""},{"Short":"i","Long":"insecure","Default":"","Type":"bool","Desc":""}]` t.Log("Given the need to validate we can parse a struct value.") { t.Log("\tWhen parsing the test config.") { args, err := parse("", &cfg) if err != nil { t.Fatalf("\t%s\tShould be able to parse arguments without error : %s.", failed, err) } t.Logf("\t%s\tShould be able to parse arguments without error.", success) d, _ := json.Marshal(args) if string(d) != parseOutput { t.Log("\t\tGot :", string(d)) t.Log("\t\tWant:", parseOutput) t.Fatalf("\t%s\tShould get back the expected arguments.", failed) } t.Logf("\t%s\tShould get back the expected arguments.", success) } } } // TestApply validates the ability to apply overrides to a struct value // based on provided flag arguments. func TestApply(t *testing.T) { var cfg struct { Web struct { APIHost string `default:"0.0.0.0:3000" flag:"a" flagdesc:"The ip:port for the api endpoint."` BatchSize int `default:"1000" flagdesc:"Represets number of items to move."` ReadTimeout time.Duration `default:"5s"` } DialTimeout time.Duration `default:"5s"` Host string `default:"mongo:27017/gotraining" flag:"h"` Insecure bool `flag:"i"` } osArgs := []string{"./web-api", "-i", "-a", "0.0.1.1:5000", "--web_batchsize", "300", "--dialtimeout", "10s"} expected := `{"Web":{"APIHost":"0.0.1.1:5000","BatchSize":300,"ReadTimeout":0},"DialTimeout":10000000000,"Host":"","Insecure":true}` t.Log("Given the need to validate we can apply overrides a struct value.") { t.Log("\tWhen parsing the test config.") { args, err := parse("", &cfg) if err != nil { t.Fatalf("\t%s\tShould be able to parse arguments without error : %s.", failed, err) } t.Logf("\t%s\tShould be able to parse arguments without error.", success) if err := apply(osArgs, args); err != nil { t.Fatalf("\t%s\tShould be able to apply arguments without error : %s.", failed, err) } t.Logf("\t%s\tShould be able to apply arguments without error.", success) d, _ := json.Marshal(&cfg) if string(d) != expected { t.Log("\t\tGot :", string(d)) t.Log("\t\tWant:", expected) t.Fatalf("\t%s\tShould get back the expected struct value.", failed) } t.Logf("\t%s\tShould get back the expected struct value.", success) } } } // TestApplyBad validates the ability to handle bad arguments on the command line. func TestApplyBad(t *testing.T) { var cfg struct { Web struct { APIHost string `default:"0.0.0.0:3000" flag:"a" flagdesc:"The ip:port for the api endpoint."` BatchSize int `default:"1000" flagdesc:"Represets number of items to move."` ReadTimeout time.Duration `default:"5s"` } DialTimeout time.Duration `default:"5s"` Host string `default:"mongo:27017/gotraining" flag:"h"` Insecure bool } tests := []struct { osArg []string }{ {[]string{"testapp", "-help"}}, {[]string{"testapp", "-bad", "value"}}, {[]string{"testapp", "-insecure", "value"}}, } t.Log("Given the need to validate we can parse a struct value with bad OS arguments.") { for i, tt := range tests { t.Logf("\tTest: %d\tWhen checking %v", i, tt.osArg) { args, err := parse("", &cfg) if err != nil { t.Fatalf("\t%s\tShould be able to parse arguments without error : %s.", failed, err) } t.Logf("\t%s\tShould be able to parse arguments without error.", success) if err := apply(tt.osArg, args); err != nil { t.Logf("\t%s\tShould not be able to apply arguments.", success) } else { t.Errorf("\t%s\tShould not be able to apply arguments.", failed) } } } } } // TestDisplay provides a test for displaying the command line arguments. func TestDisplay(t *testing.T) { var cfg struct { Web struct { APIHost string `default:"0.0.0.0:3000" flag:"a" flagdesc:"The ip:port for the api endpoint."` BatchSize int `default:"1000" flagdesc:"Represets number of items to move."` ReadTimeout time.Duration `default:"5s"` } DialTimeout time.Duration `default:"5s"` Host string `default:"mongo:27017/gotraining" flag:"h"` Insecure bool `flag:"i"` } want := ` Usage of TestApp -a --web_apihost string <0.0.0.0:3000> : The ip:port for the api endpoint. --web_batchsize int <1000> : Represets number of items to move. --web_readtimeout Duration <5s> --dialtimeout Duration <5s> -h --host string -i --insecure bool ` got := display("TestApp", &cfg) if got != want { t.Log("\t\tGot :", []byte(got)) t.Log("\t\tWant:", []byte(want)) t.Fatalf("\t%s\tShould get back the expected help output.", failed) } t.Logf("\t%s\tShould get back the expected help output.", success) }