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  }