code.cestus.io/tools/fabricator@v0.4.3/pkg/ff/fftest/vars.go (about) 1 package fftest 2 3 import ( 4 "errors" 5 "flag" 6 "fmt" 7 "reflect" 8 "strings" 9 "time" 10 ) 11 12 // Pair returns a predefined flag set, and a predefined set of variables that 13 // have been registered into it. Tests can call parse on the flag set with a 14 // variety of flags, config files, and env vars, and check the resulting effect 15 // on the vars. 16 func Pair() (*flag.FlagSet, *Vars) { 17 fs := flag.NewFlagSet("fftest", flag.ContinueOnError) 18 19 var v Vars 20 fs.StringVar(&v.S, "s", "", "string") 21 fs.IntVar(&v.I, "i", 0, "int") 22 fs.Float64Var(&v.F, "f", 0., "float64") 23 fs.BoolVar(&v.B, "b", false, "bool") 24 fs.DurationVar(&v.D, "d", 0*time.Second, "time.Duration") 25 fs.Var(&v.X, "x", "collection of strings (repeatable)") 26 27 return fs, &v 28 } 29 30 // Vars are a common set of variables used for testing. 31 type Vars struct { 32 S string 33 I int 34 F float64 35 B bool 36 D time.Duration 37 X StringSlice 38 39 // ParseError should be assigned as the result of Parse in tests. 40 ParseError error 41 42 // If a test case expects an input to generate a parse error, 43 // it can specify that error here. The Compare helper will 44 // look for it using errors.Is. 45 WantParseErrorIs error 46 47 // If a test case expects an input to generate a parse error, 48 // it can specify part of that error string here. The Compare 49 // helper will look for it using strings.Contains. 50 WantParseErrorString string 51 } 52 53 // Compare one set of vars with another 54 // and return an error on any difference. 55 func Compare(want, have *Vars) error { 56 if want.WantParseErrorIs != nil || want.WantParseErrorString != "" { 57 if want.WantParseErrorIs != nil && have.ParseError == nil { 58 return fmt.Errorf("want error (%v), have none", want.WantParseErrorIs) 59 } 60 61 if want.WantParseErrorString != "" && have.ParseError == nil { 62 return fmt.Errorf("want error (%q), have none", want.WantParseErrorString) 63 } 64 65 if want.WantParseErrorIs == nil && want.WantParseErrorString == "" && have.ParseError != nil { 66 return fmt.Errorf("want clean parse, have error (%v)", have.ParseError) 67 } 68 69 if want.WantParseErrorIs != nil && have.ParseError != nil && !errors.Is(have.ParseError, want.WantParseErrorIs) { 70 return fmt.Errorf("want wrapped error (%#+v), have error (%#+v)", want.WantParseErrorIs, have.ParseError) 71 } 72 73 if want.WantParseErrorString != "" && have.ParseError != nil && !strings.Contains(have.ParseError.Error(), want.WantParseErrorString) { 74 return fmt.Errorf("want error string (%q), have error (%v)", want.WantParseErrorString, have.ParseError) 75 } 76 77 return nil 78 } 79 80 if want.S != have.S { 81 return fmt.Errorf("var S: want %q, have %q", want.S, have.S) 82 } 83 if want.I != have.I { 84 return fmt.Errorf("var I: want %d, have %d", want.I, have.I) 85 } 86 if want.F != have.F { 87 return fmt.Errorf("var F: want %f, have %f", want.F, have.F) 88 } 89 if want.B != have.B { 90 return fmt.Errorf("var B: want %v, have %v", want.B, have.B) 91 } 92 if want.D != have.D { 93 return fmt.Errorf("var D: want %s, have %s", want.D, have.D) 94 } 95 if !reflect.DeepEqual(want.X, have.X) { 96 return fmt.Errorf("var X: want %v, have %v", want.X, have.X) 97 } 98 99 return nil 100 } 101 102 // StringSlice is a flag.Value that collects each Set string 103 // into a slice, allowing for repeated flags. 104 type StringSlice []string 105 106 // Set implements flag.Value and appends the string to the slice. 107 func (ss *StringSlice) Set(s string) error { 108 (*ss) = append(*ss, s) 109 return nil 110 } 111 112 // String implements flag.Value and returns the list of 113 // strings, or "..." if no strings have been added. 114 func (ss *StringSlice) String() string { 115 if len(*ss) <= 0 { 116 return "..." 117 } 118 return strings.Join(*ss, ", ") 119 }