...

Source file src/edge-infra.dev/test/framework/config/config_test.go

Documentation: edge-infra.dev/test/framework/config

     1  package config
     2  
     3  import (
     4  	"bytes"
     5  	"flag"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func TestInt(t *testing.T) {
    14  	flags := flag.NewFlagSet("test", 0)
    15  	var context struct {
    16  		Number int `default:"5" usage:"some number"`
    17  	}
    18  	require.NotPanics(t, func() {
    19  		AddOptionsToSet(flags, &context, "")
    20  	})
    21  	require.Equal(t, []simpleFlag{
    22  		{
    23  			name:     "number",
    24  			usage:    "some number",
    25  			defValue: "5",
    26  		}},
    27  		allFlags(flags))
    28  	assert.Equal(t, 5, context.Number)
    29  }
    30  
    31  func TestLower(t *testing.T) {
    32  	flags := flag.NewFlagSet("test", 0)
    33  	var context struct {
    34  		Ahem      string
    35  		MixedCase string
    36  	}
    37  	require.NotPanics(t, func() {
    38  		AddOptionsToSet(flags, &context, "")
    39  	})
    40  	require.Equal(t, []simpleFlag{
    41  		{
    42  			name: "ahem",
    43  		},
    44  		{
    45  			name: "mixedcase",
    46  		},
    47  	},
    48  		allFlags(flags))
    49  }
    50  
    51  func TestPrefix(t *testing.T) {
    52  	flags := flag.NewFlagSet("test", 0)
    53  	var context struct {
    54  		Number int `usage:"some number"`
    55  	}
    56  	require.NotPanics(t, func() {
    57  		AddOptionsToSet(flags, &context, "some.prefix")
    58  	})
    59  	require.Equal(t, []simpleFlag{
    60  		{
    61  			name:     "some.prefix.number",
    62  			usage:    "some number",
    63  			defValue: "0",
    64  		}},
    65  		allFlags(flags))
    66  }
    67  
    68  func TestRecursion(t *testing.T) {
    69  	flags := flag.NewFlagSet("test", 0)
    70  	type Nested struct {
    71  		Number1 int `usage:"embedded number"`
    72  	}
    73  	var context struct {
    74  		Nested
    75  		A struct {
    76  			B struct {
    77  				C struct {
    78  					Number2 int `usage:"some number"`
    79  				}
    80  			}
    81  		}
    82  	}
    83  	require.NotPanics(t, func() {
    84  		AddOptionsToSet(flags, &context, "")
    85  	})
    86  	require.Equal(t, []simpleFlag{
    87  		{
    88  			name:     "a.b.c.number2",
    89  			usage:    "some number",
    90  			defValue: "0",
    91  		},
    92  		{
    93  			name:     "number1",
    94  			usage:    "embedded number",
    95  			defValue: "0",
    96  		},
    97  	},
    98  		allFlags(flags))
    99  }
   100  
   101  func TestPanics(t *testing.T) {
   102  	flags := flag.NewFlagSet("test", 0)
   103  	assert.PanicsWithValue(t, `invalid default "a" for int entry prefix.number: strconv.Atoi: parsing "a": invalid syntax`, func() {
   104  		var context struct {
   105  			Number int `default:"a"`
   106  		}
   107  		AddOptionsToSet(flags, &context, "prefix")
   108  	})
   109  
   110  	assert.PanicsWithValue(t, `invalid default "10000000000000000000" for int entry prefix.number: strconv.Atoi: parsing "10000000000000000000": value out of range`, func() {
   111  		var context struct {
   112  			Number int `default:"10000000000000000000"`
   113  		}
   114  		AddOptionsToSet(flags, &context, "prefix")
   115  	})
   116  
   117  	assert.PanicsWithValue(t, `options parameter without a type - nil?!`, func() {
   118  		AddOptionsToSet(flags, nil, "")
   119  	})
   120  
   121  	assert.PanicsWithValue(t, `need a pointer to a struct, got instead: *int`, func() {
   122  		number := 0
   123  		AddOptionsToSet(flags, &number, "")
   124  	})
   125  
   126  	assert.PanicsWithValue(t, `struct entry "prefix.number" not exported`, func() {
   127  		var context struct {
   128  			number int
   129  		}
   130  		AddOptionsToSet(flags, &context, "prefix")
   131  	})
   132  
   133  	assert.PanicsWithValue(t, `unsupported struct entry type "prefix.somenumber": config.MyInt`, func() {
   134  		type MyInt int
   135  		var context struct {
   136  			SomeNumber MyInt
   137  		}
   138  		AddOptionsToSet(flags, &context, "prefix")
   139  	})
   140  }
   141  
   142  type TypesTestCase struct {
   143  	name      string
   144  	copyFlags bool
   145  }
   146  
   147  func TestTypes(t *testing.T) {
   148  	testcases := []TypesTestCase{
   149  		{name: "directly"},
   150  		{name: "CopyFlags", copyFlags: true},
   151  	}
   152  
   153  	for _, testcase := range testcases {
   154  		testTypes(t, testcase)
   155  	}
   156  }
   157  
   158  func testTypes(t *testing.T, testcase TypesTestCase) {
   159  	flags := flag.NewFlagSet("test", 0)
   160  	type Context struct {
   161  		Bool     bool          `default:"true"`
   162  		Duration time.Duration `default:"1ms"`
   163  		Float64  float64       `default:"1.23456789"`
   164  		String   string        `default:"hello world"`
   165  		Int      int           `default:"-1" usage:"some number"`
   166  		Int64    int64         `default:"-1234567890123456789"`
   167  		Uint     uint          `default:"1"`
   168  		Uint64   uint64        `default:"1234567890123456789"`
   169  	}
   170  	var context Context
   171  	require.NotPanics(t, func() {
   172  		AddOptionsToSet(flags, &context, "")
   173  	})
   174  
   175  	if testcase.copyFlags {
   176  		original := bytes.Buffer{}
   177  		flags.SetOutput(&original)
   178  		flags.PrintDefaults()
   179  
   180  		flags2 := flag.NewFlagSet("test", 0)
   181  		CopyFlags(flags, flags2)
   182  		flags = flags2
   183  
   184  		copier := bytes.Buffer{}
   185  		flags.SetOutput(&copier)
   186  		flags.PrintDefaults()
   187  		assert.Equal(t, original.String(), copier.String(), testcase.name+": help messages equal")
   188  		assert.Contains(t, copier.String(), "some number", testcase.name+": copied help message contains defaults")
   189  	}
   190  
   191  	require.Equal(t, []simpleFlag{
   192  		{
   193  			name:     "bool",
   194  			defValue: "true",
   195  			isBool:   true,
   196  		},
   197  		{
   198  			name:     "duration",
   199  			defValue: "1ms",
   200  		},
   201  		{
   202  			name:     "float64",
   203  			defValue: "1.23456789",
   204  		},
   205  		{
   206  			name:     "int",
   207  			usage:    "some number",
   208  			defValue: "-1",
   209  		},
   210  		{
   211  			name:     "int64",
   212  			defValue: "-1234567890123456789",
   213  		},
   214  		{
   215  			name:     "string",
   216  			defValue: "hello world",
   217  		},
   218  		{
   219  			name:     "uint",
   220  			defValue: "1",
   221  		},
   222  		{
   223  			name:     "uint64",
   224  			defValue: "1234567890123456789",
   225  		},
   226  	},
   227  		allFlags(flags), testcase.name)
   228  	assert.Equal(t,
   229  		Context{true, time.Millisecond, 1.23456789, "hello world",
   230  			-1, -1234567890123456789, 1, 1234567890123456789,
   231  		},
   232  		context,
   233  		"default values must match")
   234  	require.NoError(t, flags.Parse([]string{
   235  		"-int", "-2",
   236  		"-int64", "-9123456789012345678",
   237  		"-uint", "2",
   238  		"-uint64", "9123456789012345678",
   239  		"-string", "pong",
   240  		"-float64", "-1.23456789",
   241  		"-bool=false",
   242  		"-duration=1s",
   243  	}), testcase.name)
   244  	assert.Equal(t,
   245  		Context{false, time.Second, -1.23456789, "pong",
   246  			-2, -9123456789012345678, 2, 9123456789012345678,
   247  		},
   248  		context,
   249  		testcase.name+": parsed values must match")
   250  }
   251  
   252  func allFlags(fs *flag.FlagSet) []simpleFlag {
   253  	var flags []simpleFlag
   254  	fs.VisitAll(func(f *flag.Flag) {
   255  		s := simpleFlag{
   256  			name:     f.Name,
   257  			usage:    f.Usage,
   258  			defValue: f.DefValue,
   259  		}
   260  		type boolFlag interface {
   261  			flag.Value
   262  			IsBoolFlag() bool
   263  		}
   264  		if fv, ok := f.Value.(boolFlag); ok && fv.IsBoolFlag() {
   265  			s.isBool = true
   266  		}
   267  		flags = append(flags, s)
   268  	})
   269  	return flags
   270  }
   271  
   272  type simpleFlag struct {
   273  	name     string
   274  	usage    string
   275  	defValue string
   276  	isBool   bool
   277  }
   278  

View as plain text