diff --git a/.github/workflows/codetests.yml b/.github/workflows/codetests.yml index 95215f2..9dfa0a5 100644 --- a/.github/workflows/codetests.yml +++ b/.github/workflows/codetests.yml @@ -36,7 +36,7 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: 'v1.53' + version: 'v1.55' # Runs golangci-lint on linux against linux and windows. golangci-linux: strategy: @@ -54,4 +54,4 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: 'v1.53' \ No newline at end of file + version: 'v1.55' \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml index c51423a..821f22a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -22,10 +22,9 @@ linters: - structcheck - deadcode - ifshort - - rowserrcheck - - sqlclosecheck - - wastedassign - exhaustive + - depguard + - tagalign run: timeout: 3m \ No newline at end of file diff --git a/LICENSE b/LICENSE index 4cd9795..82e52b3 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ MIT LICENSE. -Copyright (c) 2019-2023 Go Lift - Building Strong Go Tools +Copyright (c) 2019-2024 Go Lift - Building Strong Go Tools Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/config_test.go b/config_test.go index 2adccc5..f909829 100644 --- a/config_test.go +++ b/config_test.go @@ -8,6 +8,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golift.io/cnfg" ) @@ -71,7 +72,7 @@ func TestUnmarshalText(t *testing.T) { d := cnfg.Duration{Duration: time.Minute + time.Second} b, err := d.MarshalText() - assert.Nil(t, err, "this method must not return an error") + require.NoError(t, err, "this method must not return an error") assert.Equal(t, []byte("1m1s"), b) } @@ -81,7 +82,7 @@ func TestUnmarshalJSON(t *testing.T) { d := cnfg.Duration{Duration: time.Minute + time.Hour} b, err := d.MarshalJSON() - assert.Nil(t, err, "this method must not return an error") + require.NoError(t, err, "this method must not return an error") assert.Equal(t, []byte(`"1h1m0s"`), b) } diff --git a/env.go b/env.go index 7a7f364..bb7751c 100644 --- a/env.go +++ b/env.go @@ -46,7 +46,7 @@ func MarshalENV(i interface{}, prefix string) (Pairs, error) { return (&ENV{Pfx: prefix, Tag: ENVTag}).Marshal(i) } -// Marshal converts deconstructs a data structure into environment variable pairs. +// Marshal deconstructs a data structure into environment variable pairs. func (e *ENV) Marshal(i interface{}) (Pairs, error) { value := reflect.ValueOf(i) if value.Kind() != reflect.Ptr || value.Elem().Kind() != reflect.Struct { diff --git a/env_test.go b/env_test.go index efdff8a..1053f45 100644 --- a/env_test.go +++ b/env_test.go @@ -9,6 +9,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golift.io/cnfg" ) @@ -32,46 +33,48 @@ type testSubConfig struct { } // A few tests hit this. -func testUnmarshalFileValues(assert *assert.Assertions, config *testStruct, err error, from string) { +func testUnmarshalFileValues(t *testing.T, assert *assert.Assertions, config *testStruct, err error, from string) { + t.Helper() + from += " " - assert.Nil(err, "there should not be an error reading the test file") + require.NoError(t, err, "there should not be an error reading the test file") // PointerSlice - assert.Equal(1, len(config.PointerSlice), from+"pointerslice is too short") + assert.Len(config.PointerSlice, 1, from+"pointerslice is too short") assert.EqualValues(true, config.PointerSlice[0].Bool, from+"the boolean was true") assert.EqualValues(123.4567, *config.PointerSlice[0].FloatP, from+"the float64 was set to 123.4567") assert.EqualValues(0, config.PointerSlice[0].Int, from+"int was not set so should be zero") assert.Nil(config.PointerSlice[0].StringP, from+"the string pointer was not set so should remain nil") // StructSlice - assert.Equal(1, len(config.StructSlice), from+"pointerslice is too short") + assert.Len(config.StructSlice, 1, from+"pointerslice is too short") assert.EqualValues(false, config.StructSlice[0].Bool, from+"the boolean was missing and should be false") - assert.Nil(config.StructSlice[0].FloatP, from+"the float64 was missing and should be nil") + assert.Nil(config.StructSlice[0].FloatP, from+"the float64 was missing and should be nil 1") assert.EqualValues(123, config.StructSlice[0].Int, from+"int was set to 123") assert.EqualValues("foo", *config.StructSlice[0].StringP, from+"the string was set to foo") // Struct assert.EqualValues(false, config.Struct.Bool, from+"the boolean was false and should be false") - assert.Nil(config.Struct.FloatP, from+"the float64 was missing and should be nil") + assert.Nil(config.Struct.FloatP, from+"the float64 was missing and should be nil 2") assert.EqualValues(0, config.Struct.Int, from+"int was not set and must be 0") assert.Nil(config.Struct.StringP, from+"the string was missing and should be nil") // PointerStruct assert.NotNil(config.PointerStruct, from+"the pointer struct has values and must not be nil") assert.EqualValues(false, config.PointerStruct.Bool, from+"the boolean was missing and should be false") - assert.Nil(config.PointerStruct.FloatP, from+"the float64 was missing and should be nil") + assert.Nil(config.PointerStruct.FloatP, from+"the float64 was missing and should be nil 3") assert.EqualValues(0, config.PointerStruct.Int, from+"int was not set and must be 0") assert.EqualValues("foo2", *config.PointerStruct.StringP, from+"the string was set to foo2") // PointerSlice2 - assert.Equal(0, len(config.PointerSlice2), from+"pointerslice2 is too long") + assert.Empty(config.PointerSlice2, from+"pointerslice2 is too long") // StructSlice2 - assert.Equal(0, len(config.StructSlice2), from+"structslice2 is too long") + assert.Empty(config.StructSlice2, from+"structslice2 is too long") // Struct2 - assert.EqualValues(false, config.Struct2.Bool, from+"this must be zero value") - assert.Nil(config.Struct2.FloatP, from+"this must be zero value") - assert.EqualValues(0, config.Struct2.Int, from+"this must be zero value") - assert.Nil(config.Struct2.StringP, from+"this must be zero value") + assert.EqualValues(false, config.Struct2.Bool, from+"this must be zero value 1") + assert.Nil(config.Struct2.FloatP, from+"this must be zero value 2") + assert.EqualValues(0, config.Struct2.Int, from+"this must be zero value 3") + assert.Nil(config.Struct2.StringP, from+"this must be zero value 4") // PointerStruct2 assert.Nil(config.PointerStruct2, from+"pointer struct 2 must be nil") } @@ -96,19 +99,19 @@ func TestBrokenENV(t *testing.T) { //nolint:paralleltest // cannot parallel env c := &testBroken{} worked, err := cnfg.UnmarshalENV(c, "TEST") - assert.NotNil(err, "an error must be returned for an unsupported type") + require.Error(t, err, "an error must be returned for an unsupported type") assert.False(worked) config := &testBroken2{} worked, err = cnfg.UnmarshalENV(config, "TEST") - assert.NotNil(err, "an error must be returned for an unsupported map type") + require.Error(t, err, "an error must be returned for an unsupported map type") assert.False(worked) config2 := &testBroken3{} worked, err = cnfg.UnmarshalENV(config2, "TEST") - assert.NotNil(err, "an error must be returned for an unsupported map type") + require.Error(t, err, "an error must be returned for an unsupported map type") assert.False(worked) } @@ -133,7 +136,7 @@ func TestUnmarshalENVerrors(t *testing.T) { //nolint:paralleltest // cannot para config := tester{} worked, err := cnfg.UnmarshalENV(&config, "YO") - assert.Nil(err, "maps are supported and must not produce an error") + require.NoError(t, err, "maps are supported and must not produce an error") assert.Empty(os.Getenv("YO_WORKS_foo2string"), "delenv must delete the environment variable") assert.Empty(os.Getenv("YO_WORKS_foostring"), "delenv must delete the environment variable") assert.True(worked) @@ -161,7 +164,7 @@ func TestUnmarshalENVerrors(t *testing.T) { //nolint:paralleltest // cannot para config2 := tester2{HasStuff: []map[string]string{{"freesoda": "at-pops"}, {"a": "v"}}} worked, err = cnfg.UnmarshalENV(&config2, "MORE") - assert.Nil(err, "map slices are supported and must not produce an error") + require.NoError(t, err, "map slices are supported and must not produce an error") assert.True(worked) f := *config2.NotBroken2[0] @@ -179,7 +182,7 @@ func TestUnmarshalENV(t *testing.T) { //nolint:paralleltest // cannot parallel e c := &testStruct{} ok, err := cnfg.UnmarshalENV(c, "PRE") - assert.Nil(err, "there must not be an error when parsing no variables") + require.NoError(t, err, "there must not be an error when parsing no variables") assert.False(ok, "there are no environment variables set, so ok should be false") testThingENV(t, assert) testOscureENV(t, assert) @@ -188,7 +191,7 @@ func TestUnmarshalENV(t *testing.T) { //nolint:paralleltest // cannot parallel e f := true g := &f _, err = cnfg.UnmarshalENV(g, "OOO") - assert.NotNil(err, "unmarshaling a non-struct pointer must produce an error") + require.Error(t, err, "unmarshaling a non-struct pointer must produce an error") } func testThingENV(t *testing.T, assert *assert.Assertions) { @@ -207,11 +210,11 @@ func testThingENV(t *testing.T, assert *assert.Assertions) { ok, err := cnfg.UnmarshalENV(config, "PRE") assert.True(ok, "ok must be true since things must be parsed") - testUnmarshalFileValues(assert, config, err, "testThingENV") + testUnmarshalFileValues(t, assert, config, err, "testThingENV") // do it again, and we should get the same result ok, err = cnfg.UnmarshalENV(config, "PRE") assert.True(ok, "ok must be true since things must be parsed") - testUnmarshalFileValues(assert, config, err, "testThingENV") + testUnmarshalFileValues(t, assert, config, err, "testThingENV") } func testOscureENV(t *testing.T, assert *assert.Assertions) { @@ -238,13 +241,13 @@ func testOscureENV(t *testing.T, assert *assert.Assertions) { testit := func() { ok, err := cnfg.UnmarshalENV(config, "OB") assert.True(ok, "ok must be true since things must be parsed") - assert.Nil(err) + require.NoError(t, err) - assert.EqualValues(2, len(config.FloatSlice)) + assert.Len(config.FloatSlice, 2) assert.EqualValues(-5, config.FloatSlice[0]) assert.EqualValues(8, config.FloatSlice[1]) - assert.EqualValues(2, len(config.UintSliceP)) + assert.Len(config.UintSliceP, 2) assert.EqualValues(12, *config.UintSliceP[0]) assert.EqualValues(22, *config.UintSliceP[1]) @@ -254,9 +257,9 @@ func testOscureENV(t *testing.T, assert *assert.Assertions) { weirdo := *config.Weirdo wut := *config.Wut - assert.EqualValues(1, len(weirdo)) + assert.Len(weirdo, 1) assert.EqualValues(-1, weirdo[0]) - assert.EqualValues(1, len(wut)) + assert.Len(wut, 1) assert.True(wut[0].Bool) } @@ -289,7 +292,7 @@ func testSpecialENV(t *testing.T, assert *assert.Assertions) { worked, err := (&cnfg.ENV{Pfx: "TEST"}).Unmarshal(config) assert.True(worked, "ok must be true since things must be parsed") - assert.Nil(err) + require.NoError(t, err) assert.Equal(time.Minute, config.Dur) assert.Equal(time.Second, config.CDur.Duration) assert.Equal("golift.io", config.Sub.URL.Host, "the url wasn't parsed properly") @@ -302,5 +305,5 @@ func testSpecialENV(t *testing.T, assert *assert.Assertions) { worked, err = (&cnfg.ENV{Pfx: "TEST"}).Unmarshal(config) assert.False(worked, "cannot parse an invalid time") - assert.NotNil(err, "cannot parse an invalid time") + require.Error(t, err, "cannot parse an invalid time") } diff --git a/map_test.go b/map_test.go index 2f3a42a..ecf4b37 100644 --- a/map_test.go +++ b/map_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golift.io/cnfg" ) @@ -26,18 +27,18 @@ func TestUnmarshalMap(t *testing.T) { config := mapTester{} worked, err := cnfg.UnmarshalMap(pairs, &config) - assert.Nil(err) + require.NoError(t, err) assert.True(worked) assert.EqualValues("bar", config.Foo) worked, err = cnfg.UnmarshalMap(pairs, config) assert.False(worked) - assert.NotNil(err, "must have an error when attempting unmarshal to non-pointer") + require.Error(t, err, "must have an error when attempting unmarshal to non-pointer") worked, err = (&cnfg.ENV{}).UnmarshalMap(pairs, &config) assert.True(worked) - assert.Nil(err) + require.NoError(t, err) } func ExampleUnmarshalMap() { diff --git a/parse_test.go b/parse_test.go index a51fa55..1b523bd 100644 --- a/parse_test.go +++ b/parse_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestParseInt(t *testing.T) { @@ -13,11 +14,11 @@ func TestParseInt(t *testing.T) { assert := assert.New(t) - for _, t := range []interface{}{int(0), int8(8), int16(16), int32(32), int64(64)} { - i, err := parseInt(t, fmt.Sprintf("%d", t)) + for _, val := range []interface{}{int(0), int8(8), int16(16), int32(32), int64(64)} { + i, err := parseInt(val, fmt.Sprintf("%d", val)) - assert.EqualValues(t, i) - assert.NoError(err) + require.NoError(t, err) + assert.EqualValues(val, i) } } @@ -34,7 +35,7 @@ func TestParseByteSlice(t *testing.T) { //nolint:paralleltest ok, err := UnmarshalENV(testStruct, "D") assert.True(ok) - assert.NoError(err) + require.NoError(t, err) assert.Equal("byte slice incoming", string(testStruct.F)) } @@ -50,11 +51,10 @@ func TestParseUint(t *testing.T) { embeddedInt := &test{} theField := reflect.ValueOf(embeddedInt).Elem().Field(0) - for _, t := range []interface{}{uint(0), uint16(16), uint32(32), uint64(64)} { - err := parseUint(theField, t, "1") - + for _, val := range []interface{}{uint(0), uint16(16), uint32(32), uint64(64)} { + err := parseUint(theField, val, "1") + require.NoError(t, err) assert.EqualValues(1, embeddedInt.F) - assert.NoError(err) } type test2 struct { @@ -65,14 +65,14 @@ func TestParseUint(t *testing.T) { theField = reflect.ValueOf(testStruct).Elem().Field(0) err := parseUint(theField, uint8(0), "11") - assert.NotNil(err, "must return an error when more than one byte is provided") + require.Error(t, err, "must return an error when more than one byte is provided") err = parseUint(theField, uint8(0), "f") - assert.Nil(err, "must not return an error when only one byte is provided") + require.NoError(t, err, "must not return an error when only one byte is provided") assert.Equal(byte('f'), testStruct.F) err = parseUint(theField, uint8(0), "") - assert.Nil(err, "must not return an error when only no bytes are provided") + require.NoError(t, err, "must not return an error when only no bytes are provided") assert.Equal(uint8(0), testStruct.F) } @@ -85,6 +85,6 @@ func TestParseInterfaceError(t *testing.T) { type F uint64 ok, err := (&parser{}).Interface(reflect.ValueOf(F(0)), "", "", false) + require.NoError(t, err, "unaddressable value must return nil") assert.False(ok, "unaddressable value must return false") - assert.Nil(err, "unaddressable value must return nil") } diff --git a/unparse_test.go b/unparse_test.go index f6e83b6..8899c4c 100644 --- a/unparse_test.go +++ b/unparse_test.go @@ -3,14 +3,18 @@ package cnfg_test import ( "fmt" "net" + "strconv" "strings" "testing" "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "golift.io/cnfg" ) +const base10 = 10 + type MarshalTest struct { Name string `xml:"name,omitempty"` Pass string `xml:"pass,omitempty"` @@ -87,7 +91,7 @@ func TestDeconStruct(t *testing.T) { data, count := marshalTestData() pairs, err := cnfg.MarshalENV(data, "PFX") - assert.Nil(err) + require.NoError(t, err) assert.Equal(data.Name, pairs["PFX_NAME"]) assert.Equal(data.Pass, pairs["PFX_PASS"]) assert.Equal(data.IP.String(), pairs["PFX_IP"]) @@ -100,16 +104,16 @@ func TestDeconStruct(t *testing.T) { assert.Equal(data.List[0], pairs["PFX_LIST_0"]) assert.Equal(data.List[1], pairs["PFX_LIST_1"]) assert.Equal(string(data.Byte), pairs["PFX_BYTE"]) - assert.Equal(fmt.Sprintf("%d", data.Uint), pairs["PFX_UINT"]) - assert.Equal(fmt.Sprintf("%d", data.Un16), pairs["PFX_UN16"]) - assert.Equal(fmt.Sprintf("%d", data.Un32), pairs["PFX_UN32"]) - assert.Equal(fmt.Sprintf("%d", data.Un64), pairs["PFX_UN64"]) + assert.Equal(strconv.FormatUint(uint64(data.Uint), base10), pairs["PFX_UINT"]) + assert.Equal(strconv.FormatUint(uint64(data.Un16), base10), pairs["PFX_UN16"]) + assert.Equal(strconv.FormatUint(uint64(data.Un32), base10), pairs["PFX_UN32"]) + assert.Equal(strconv.FormatUint(data.Un64, base10), pairs["PFX_UN64"]) assert.Equal(data.Dur.String(), pairs["PFX_DUR"]) - assert.Equal(fmt.Sprintf("%d", data.Int), pairs["PFX_INT"]) - assert.Equal(fmt.Sprintf("%d", data.In8), pairs["PFX_IN8"]) - assert.Equal(fmt.Sprintf("%d", data.In16), pairs["PFX_IN16"]) - assert.Equal(fmt.Sprintf("%d", data.In32), pairs["PFX_IN32"]) - assert.Equal(fmt.Sprintf("%d", data.In64), pairs["PFX_IN64"]) + assert.Equal(strconv.FormatInt(int64(data.Int), base10), pairs["PFX_INT"]) + assert.Equal(strconv.FormatInt(int64(data.In8), base10), pairs["PFX_IN8"]) + assert.Equal(strconv.FormatInt(int64(data.In16), base10), pairs["PFX_IN16"]) + assert.Equal(strconv.FormatInt(int64(data.In32), base10), pairs["PFX_IN32"]) + assert.Equal(strconv.FormatInt(data.In64, base10), pairs["PFX_IN64"]) assert.Equal("true", pairs["PFX_BOOL"]) assert.Equal(data.Test2.MarshalTest.Name, pairs["PFX_TEST2_NAME"]) assert.Equal(data.Test2.Name, pairs["PFX_TEST2_NAME"]) @@ -117,7 +121,7 @@ func TestDeconStruct(t *testing.T) { assert.Equal("64.64", pairs["PFX_FL64"]) assert.Equal(data.Test.Name, pairs["PFX_TEST_NAME"]) assert.Equal(data.Test.Err.Error(), pairs["PFX_TEST_ERR"]) - assert.Equal(count, len(pairs), + assert.Len(pairs, count, fmt.Sprintf("%d variables are created in marshalTestData, update as more tests are added.", count)) for _, v := range pairs.Quoted() {