Linting, CI, some small logic fixes.
This commit is contained in:
		
							
								
								
									
										10
									
								
								.gitlab-ci.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								.gitlab-ci.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| stages: | ||||
|   - test | ||||
|  | ||||
| lint: | ||||
|   stage: test | ||||
|   tags: | ||||
|     - docker | ||||
|   image: golangci/golangci-lint:v1.32.2 | ||||
|   script: | ||||
|     - golangci-lint run | ||||
							
								
								
									
										20
									
								
								.golangci.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								.golangci.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| run: | ||||
|   deadline: 5m | ||||
| linters: | ||||
|   enable-all: true | ||||
|   disable: | ||||
|     - dupl | ||||
|     - gochecknoglobals | ||||
|     - exhaustive | ||||
|     - testpackage | ||||
| linters-settings: | ||||
|   lll: | ||||
|     line-length: 120 | ||||
|   gocyclo: | ||||
|     min-complexity: 80 | ||||
|   gocognit: | ||||
|     min-complexity: 100 | ||||
|   funlen: | ||||
|     lines: 200 | ||||
|     statements: 100 | ||||
|  | ||||
							
								
								
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @@ -2,5 +2,6 @@ | ||||
|     "go.testFlags": [ | ||||
|         "-test.v", | ||||
|         "-cover" | ||||
|     ] | ||||
|     ], | ||||
|     "go.inferGopath": false | ||||
| } | ||||
| @@ -1,7 +1,6 @@ | ||||
| package sec | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| ) | ||||
| @@ -30,17 +29,26 @@ func composeTree(value reflect.Value, prefix string) { | ||||
| 	} | ||||
|  | ||||
| 	if value.Kind() != reflect.Struct { | ||||
| 		f := &field{ | ||||
| 			Name:    typeOf.Name(), | ||||
| 			EnvVar:  curPrefix + strings.ToUpper(typeOf.Name()), | ||||
| 			Pointer: value, | ||||
| 			Kind:    value.Kind(), | ||||
| 		if value.Kind() == reflect.Map { | ||||
| 			newElementPrefix := curPrefix | ||||
|  | ||||
| 			mapIter := value.MapRange() | ||||
| 			for mapIter.Next() { | ||||
| 				composeTree(mapIter.Value().Elem(), newElementPrefix+"_"+strings.ToUpper(mapIter.Key().String())) | ||||
| 			} | ||||
| 		} else { | ||||
| 			f := &field{ | ||||
| 				Name:    typeOf.Name(), | ||||
| 				EnvVar:  curPrefix + strings.ToUpper(typeOf.Name()), | ||||
| 				Pointer: value, | ||||
| 				Kind:    value.Kind(), | ||||
| 			} | ||||
|  | ||||
| 			parsedTree = append(parsedTree, f) | ||||
|  | ||||
| 			printDebug("Field data constructed (start): %+v", f) | ||||
| 		} | ||||
|  | ||||
| 		parsedTree = append(parsedTree, f) | ||||
|  | ||||
| 		printDebug("Field data constructed: %+v", f) | ||||
|  | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -72,25 +80,35 @@ func composeTree(value reflect.Value, prefix string) { | ||||
| 					fieldToProcess.Set(reflect.New(fieldToProcess.Type().Elem())) | ||||
| 				} else { | ||||
| 					printDebug("Field '%s' is unexported and will be ignored", fieldToProcessType.Name) | ||||
|  | ||||
| 					continue | ||||
| 				} | ||||
|  | ||||
| 				fieldToProcess = fieldToProcess.Elem() | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		printDebug("Field: '%s', type: %s (anonymous or embedded: %t)", fieldToProcessType.Name, fieldToProcess.Type().Kind().String(), fieldToProcessType.Anonymous) | ||||
| 		printDebug("Field: '%s', type: %s (anonymous or embedded: %t)", | ||||
| 			fieldToProcessType.Name, | ||||
| 			fieldToProcess.Type().Kind().String(), | ||||
| 			fieldToProcessType.Anonymous, | ||||
| 		) | ||||
|  | ||||
| 		// Dealing with embedded things. | ||||
| 		if fieldToProcessType.Anonymous { | ||||
| 			// We should not allow anything other than struct. | ||||
| 			if fieldToProcess.Kind() != reflect.Struct { | ||||
| 				printDebug("Field is embedded, but not a struct (%s), which cannot be used", fieldToProcess.Kind().String()) | ||||
|  | ||||
| 				continue | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if fieldToProcess.Kind() != reflect.Struct && !fieldToProcess.CanSet() { | ||||
| 			printDebug("Field '%s' of type '%s' can't be set, skipping", fieldToProcessType.Name, fieldToProcess.Type().Kind().String()) | ||||
| 			printDebug("Field '%s' of type '%s' can't be set, skipping", | ||||
| 				fieldToProcessType.Name, | ||||
| 				fieldToProcess.Type().Kind().String()) | ||||
|  | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| @@ -98,13 +116,15 @@ func composeTree(value reflect.Value, prefix string) { | ||||
|  | ||||
| 		// Hello, I'm recursion and I'm here to make you happy. | ||||
| 		// I'll be launched only for structures to get their fields. | ||||
| 		if fieldToProcess.Kind() == reflect.Struct { | ||||
| 		switch fieldToProcess.Kind() { | ||||
| 		case reflect.Struct: | ||||
| 			newElementPrefix := curPrefix | ||||
| 			if !fieldToProcessType.Anonymous { | ||||
| 				newElementPrefix = strings.ToUpper(newElementPrefix + typeOf.Field(i).Name) | ||||
| 			} | ||||
|  | ||||
| 			composeTree(fieldToProcess, newElementPrefix) | ||||
| 		} else if fieldToProcess.Kind() == reflect.Map { | ||||
| 		case reflect.Map: | ||||
| 			newElementPrefix := curPrefix | ||||
| 			if !fieldToProcessType.Anonymous { | ||||
| 				newElementPrefix = strings.ToUpper(newElementPrefix + typeOf.Field(i).Name) | ||||
| @@ -114,7 +134,7 @@ func composeTree(value reflect.Value, prefix string) { | ||||
| 			for mapIter.Next() { | ||||
| 				composeTree(mapIter.Value().Elem(), newElementPrefix+"_"+strings.ToUpper(mapIter.Key().String())) | ||||
| 			} | ||||
| 		} else { | ||||
| 		default: | ||||
| 			f := &field{ | ||||
| 				Name:    typeOf.Field(i).Name, | ||||
| 				EnvVar:  curPrefix + strings.ToUpper(typeOf.Field(i).Name), | ||||
| @@ -124,7 +144,7 @@ func composeTree(value reflect.Value, prefix string) { | ||||
|  | ||||
| 			parsedTree = append(parsedTree, f) | ||||
|  | ||||
| 			printDebug("Field data constructed: %+v", f) | ||||
| 			printDebug("Field data constructed (end): %+v", f) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										3
									
								
								field.go
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								field.go
									
									
									
									
									
								
							| @@ -1,7 +1,6 @@ | ||||
| package sec | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"reflect" | ||||
| ) | ||||
|  | ||||
| @@ -18,5 +17,5 @@ type field struct { | ||||
| 	Kind reflect.Kind | ||||
|  | ||||
| 	// Next variables are tag-related. | ||||
| 	optional bool | ||||
| 	// optional bool | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| package sec | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"errors" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| @@ -15,10 +14,12 @@ func fillValue(element *field, data string) error { | ||||
| 		val, err := strconv.ParseBool(data) | ||||
| 		if err != nil { | ||||
| 			printDebug("Error occurred while parsing boolean: %s", err.Error()) | ||||
|  | ||||
| 			if options.ErrorsAreCritical { | ||||
| 				return errNotBool | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		element.Pointer.SetBool(val) | ||||
| 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 		// Bitsize 64 here specified for a reason - actual ints | ||||
| @@ -27,10 +28,12 @@ func fillValue(element *field, data string) error { | ||||
| 		val, err := strconv.ParseInt(data, 10, 64) | ||||
| 		if err != nil { | ||||
| 			printDebug("Error occurred while parsing int: %s", err.Error()) | ||||
|  | ||||
| 			if options.ErrorsAreCritical { | ||||
| 				return errNotInt | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		switch element.Kind { | ||||
| 		case reflect.Int8: | ||||
| 			// int8 is an integer in [-128...127] range. | ||||
| @@ -75,14 +78,16 @@ func fillValue(element *field, data string) error { | ||||
| 		val, err := strconv.ParseUint(data, 10, 64) | ||||
| 		if err != nil { | ||||
| 			printDebug("Error occurred while parsing unsigned integer: %s", err.Error()) | ||||
|  | ||||
| 			if options.ErrorsAreCritical { | ||||
| 				return errNotUint | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		switch element.Kind { | ||||
| 		case reflect.Uint8: | ||||
| 			// uint8 is an integer in [0...255] range. | ||||
| 			if val <= 255 { | ||||
| 			if val <= uint64(^uint8(0)) { | ||||
| 				element.Pointer.SetUint(val) | ||||
| 			} else { | ||||
| 				printDebug("Data in environment variable '%s' isn't uint8", element.EnvVar) | ||||
| @@ -93,7 +98,7 @@ func fillValue(element *field, data string) error { | ||||
| 			} | ||||
| 		case reflect.Uint16: | ||||
| 			// uint16 is an integer in [0...65535] range. | ||||
| 			if val <= 65535 { | ||||
| 			if val <= uint64(^uint16(0)) { | ||||
| 				element.Pointer.SetUint(val) | ||||
| 			} else { | ||||
| 				printDebug("Data in environment variable '%s' isn't uint16", element.EnvVar) | ||||
| @@ -104,7 +109,7 @@ func fillValue(element *field, data string) error { | ||||
| 			} | ||||
| 		case reflect.Uint32: | ||||
| 			// uint32 is an integer in [0...4294967295] range. | ||||
| 			if val <= 4294967295 { | ||||
| 			if val <= uint64(^uint32(0)) { | ||||
| 				element.Pointer.SetUint(val) | ||||
| 			} else { | ||||
| 				printDebug("Data in environment variable '%s' isn't uint32", element.EnvVar) | ||||
| @@ -123,19 +128,25 @@ func fillValue(element *field, data string) error { | ||||
| 		val, err := strconv.ParseFloat(data, 64) | ||||
| 		if err != nil { | ||||
| 			printDebug("Error occurred while parsing float: %s", err.Error()) | ||||
|  | ||||
| 			if options.ErrorsAreCritical { | ||||
| 				return errNotFloat | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		element.Pointer.SetFloat(val) | ||||
| 	case reflect.Interface: | ||||
| 		// We should not attempt to work with data in interface{} | ||||
| 		// unless it is a pointer to value. | ||||
| 		if element.Pointer.Elem().Kind() != reflect.Ptr { | ||||
| 			printDebug("Element for environment variable '%s' isn't a pointer and put into interface{}. Nothing will be done with this element.", element.EnvVar) | ||||
| 			printDebug("Element for environment variable '%s' isn't a pointer and put "+ | ||||
| 				"into interface{}. Nothing will be done with this element.", | ||||
| 				element.EnvVar) | ||||
|  | ||||
| 			if options.ErrorsAreCritical { | ||||
| 				return errors.New("element for environment variable '" + element.EnvVar + "' isn't a pointer and put into interface") | ||||
| 			} | ||||
|  | ||||
| 			return nil | ||||
| 		} | ||||
|  | ||||
| @@ -143,7 +154,9 @@ func fillValue(element *field, data string) error { | ||||
| 		// It goes interface{} -> ptr -> real element. | ||||
| 		element.Pointer = element.Pointer.Elem().Elem() | ||||
| 		element.Kind = element.Pointer.Kind() | ||||
|  | ||||
| 		return fillValue(element, data) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -11,8 +11,6 @@ type Options struct { | ||||
| 	ErrorsAreCritical bool | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	defaultOptions = &Options{ | ||||
| 		ErrorsAreCritical: false, | ||||
| 	} | ||||
| ) | ||||
| var defaultOptions = &Options{ | ||||
| 	ErrorsAreCritical: false, | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| package sec | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"errors" | ||||
| 	"os" | ||||
| ) | ||||
| @@ -32,9 +31,11 @@ func parseEnv() error { | ||||
|  | ||||
| 	for _, element := range parsedTree { | ||||
| 		printDebug("Processing element '%s'", element.EnvVar) | ||||
|  | ||||
| 		data, found := os.LookupEnv(element.EnvVar) | ||||
| 		if !found { | ||||
| 			printDebug("Value for '%s' environment variable wasn't found", element.EnvVar) | ||||
|  | ||||
| 			continue | ||||
| 		} else { | ||||
| 			printDebug("Value for '%s' will be: %s", element.EnvVar, data) | ||||
|   | ||||
| @@ -1,12 +1,10 @@ | ||||
| package sec | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"testing" | ||||
|  | ||||
| 	// other | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
|  | ||||
| @@ -18,10 +16,12 @@ func TestParseString(t *testing.T) { | ||||
| 	os.Setenv("STRINGDATA", "test") | ||||
|  | ||||
| 	s := &testStruct{} | ||||
|  | ||||
| 	err := Parse(s, nil) | ||||
| 	if err != nil { | ||||
| 		t.Log(err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	require.Nil(t, err) | ||||
| } | ||||
|  | ||||
| @@ -56,10 +56,12 @@ func TestParseBoolean(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.BoolData) | ||||
|  | ||||
| @@ -69,6 +71,7 @@ func TestParseBoolean(t *testing.T) { | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotBoolError bool | ||||
|  | ||||
| 		_, err2 := strconv.ParseBool(testCase.TestData) | ||||
| 		if err2 != nil { | ||||
| 			checkNotBoolError = true | ||||
| @@ -78,6 +81,7 @@ func TestParseBoolean(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
| 			require.Equal(t, errNotBool, err1) | ||||
| 		} | ||||
| @@ -112,10 +116,12 @@ func TestParseInt8(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.IntData) | ||||
|  | ||||
| @@ -124,12 +130,16 @@ func TestParseInt8(t *testing.T) { | ||||
| 		s1 := &testStruct{} | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotIntError bool | ||||
| 		var checkRangeError bool | ||||
| 		var ( | ||||
| 			checkNotIntError bool | ||||
| 			checkRangeError  bool | ||||
| 		) | ||||
|  | ||||
| 		passedData, err2 := strconv.ParseInt(testCase.TestData, 10, 64) | ||||
| 		if err2 != nil { | ||||
| 			checkNotIntError = true | ||||
| 		} | ||||
|  | ||||
| 		if passedData != int64(testCase.ValidData) { | ||||
| 			checkRangeError = true | ||||
| 		} | ||||
| @@ -138,11 +148,13 @@ func TestParseInt8(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
|  | ||||
| 			if checkNotIntError { | ||||
| 				require.Equal(t, errNotInt, err1) | ||||
| 			} | ||||
|  | ||||
| 			if checkRangeError { | ||||
| 				require.Equal(t, errNotInt8, err1) | ||||
| 			} | ||||
| @@ -178,10 +190,12 @@ func TestParseInt16(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.IntData) | ||||
|  | ||||
| @@ -190,12 +204,16 @@ func TestParseInt16(t *testing.T) { | ||||
| 		s1 := &testStruct{} | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotIntError bool | ||||
| 		var checkRangeError bool | ||||
| 		var ( | ||||
| 			checkNotIntError bool | ||||
| 			checkRangeError  bool | ||||
| 		) | ||||
|  | ||||
| 		passedData, err2 := strconv.ParseInt(testCase.TestData, 10, 64) | ||||
| 		if err2 != nil { | ||||
| 			checkNotIntError = true | ||||
| 		} | ||||
|  | ||||
| 		if passedData != int64(testCase.ValidData) { | ||||
| 			checkRangeError = true | ||||
| 		} | ||||
| @@ -204,11 +222,13 @@ func TestParseInt16(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
|  | ||||
| 			if checkNotIntError { | ||||
| 				require.Equal(t, errNotInt, err1) | ||||
| 			} | ||||
|  | ||||
| 			if checkRangeError { | ||||
| 				require.Equal(t, errNotInt16, err1) | ||||
| 			} | ||||
| @@ -244,10 +264,12 @@ func TestParseInt32(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.IntData) | ||||
|  | ||||
| @@ -256,12 +278,16 @@ func TestParseInt32(t *testing.T) { | ||||
| 		s1 := &testStruct{} | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotIntError bool | ||||
| 		var checkRangeError bool | ||||
| 		var ( | ||||
| 			checkNotIntError bool | ||||
| 			checkRangeError  bool | ||||
| 		) | ||||
|  | ||||
| 		passedData, err2 := strconv.ParseInt(testCase.TestData, 10, 64) | ||||
| 		if err2 != nil { | ||||
| 			checkNotIntError = true | ||||
| 		} | ||||
|  | ||||
| 		if passedData != int64(testCase.ValidData) { | ||||
| 			checkRangeError = true | ||||
| 		} | ||||
| @@ -270,11 +296,13 @@ func TestParseInt32(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
|  | ||||
| 			if checkNotIntError { | ||||
| 				require.Equal(t, errNotInt, err1) | ||||
| 			} | ||||
|  | ||||
| 			if checkRangeError { | ||||
| 				require.Equal(t, errNotInt32, err1) | ||||
| 			} | ||||
| @@ -310,10 +338,12 @@ func TestParseInt64(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.IntData) | ||||
|  | ||||
| @@ -322,12 +352,16 @@ func TestParseInt64(t *testing.T) { | ||||
| 		s1 := &testStruct{} | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotIntError bool | ||||
| 		var checkRangeError bool | ||||
| 		var ( | ||||
| 			checkNotIntError bool | ||||
| 			checkRangeError  bool | ||||
| 		) | ||||
|  | ||||
| 		passedData, err2 := strconv.ParseInt(testCase.TestData, 10, 64) | ||||
| 		if err2 != nil { | ||||
| 			checkNotIntError = true | ||||
| 		} | ||||
|  | ||||
| 		if passedData != testCase.ValidData { | ||||
| 			checkRangeError = true | ||||
| 		} | ||||
| @@ -336,11 +370,13 @@ func TestParseInt64(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
|  | ||||
| 			if checkNotIntError { | ||||
| 				require.Equal(t, errNotInt, err1) | ||||
| 			} | ||||
|  | ||||
| 			if checkRangeError { | ||||
| 				require.Equal(t, errNotInt64, err1) | ||||
| 			} | ||||
| @@ -375,10 +411,12 @@ func TestParseUint8(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.UintData) | ||||
|  | ||||
| @@ -387,12 +425,16 @@ func TestParseUint8(t *testing.T) { | ||||
| 		s1 := &testStruct{} | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotIntError bool | ||||
| 		var checkRangeError bool | ||||
| 		var ( | ||||
| 			checkNotIntError bool | ||||
| 			checkRangeError  bool | ||||
| 		) | ||||
|  | ||||
| 		passedData, err2 := strconv.ParseUint(testCase.TestData, 10, 64) | ||||
| 		if err2 != nil { | ||||
| 			checkNotIntError = true | ||||
| 		} | ||||
|  | ||||
| 		if passedData != uint64(testCase.ValidData) { | ||||
| 			checkRangeError = true | ||||
| 		} | ||||
| @@ -401,11 +443,13 @@ func TestParseUint8(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
|  | ||||
| 			if checkNotIntError { | ||||
| 				require.Equal(t, errNotUint, err1) | ||||
| 			} | ||||
|  | ||||
| 			if checkRangeError { | ||||
| 				require.Equal(t, errNotUint8, err1) | ||||
| 			} | ||||
| @@ -440,10 +484,12 @@ func TestParseUint16(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.UintData) | ||||
|  | ||||
| @@ -452,12 +498,16 @@ func TestParseUint16(t *testing.T) { | ||||
| 		s1 := &testStruct{} | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotIntError bool | ||||
| 		var checkRangeError bool | ||||
| 		var ( | ||||
| 			checkNotIntError bool | ||||
| 			checkRangeError  bool | ||||
| 		) | ||||
|  | ||||
| 		passedData, err2 := strconv.ParseUint(testCase.TestData, 10, 64) | ||||
| 		if err2 != nil { | ||||
| 			checkNotIntError = true | ||||
| 		} | ||||
|  | ||||
| 		if passedData != uint64(testCase.ValidData) { | ||||
| 			checkRangeError = true | ||||
| 		} | ||||
| @@ -466,11 +516,13 @@ func TestParseUint16(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
|  | ||||
| 			if checkNotIntError { | ||||
| 				require.Equal(t, errNotUint, err1) | ||||
| 			} | ||||
|  | ||||
| 			if checkRangeError { | ||||
| 				require.Equal(t, errNotUint16, err1) | ||||
| 			} | ||||
| @@ -505,10 +557,12 @@ func TestParseUint32(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.UintData) | ||||
|  | ||||
| @@ -517,12 +571,16 @@ func TestParseUint32(t *testing.T) { | ||||
| 		s1 := &testStruct{} | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotIntError bool | ||||
| 		var checkRangeError bool | ||||
| 		var ( | ||||
| 			checkNotIntError bool | ||||
| 			checkRangeError  bool | ||||
| 		) | ||||
|  | ||||
| 		passedData, err2 := strconv.ParseUint(testCase.TestData, 10, 64) | ||||
| 		if err2 != nil { | ||||
| 			checkNotIntError = true | ||||
| 		} | ||||
|  | ||||
| 		if passedData != uint64(testCase.ValidData) { | ||||
| 			checkRangeError = true | ||||
| 		} | ||||
| @@ -531,11 +589,13 @@ func TestParseUint32(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
|  | ||||
| 			if checkNotIntError { | ||||
| 				require.Equal(t, errNotUint, err1) | ||||
| 			} | ||||
|  | ||||
| 			if checkRangeError { | ||||
| 				require.Equal(t, errNotUint32, err1) | ||||
| 			} | ||||
| @@ -570,10 +630,12 @@ func TestParseUint64(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.UintData) | ||||
|  | ||||
| @@ -582,12 +644,16 @@ func TestParseUint64(t *testing.T) { | ||||
| 		s1 := &testStruct{} | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotIntError bool | ||||
| 		var checkRangeError bool | ||||
| 		var ( | ||||
| 			checkNotIntError bool | ||||
| 			checkRangeError  bool | ||||
| 		) | ||||
|  | ||||
| 		passedData, err2 := strconv.ParseUint(testCase.TestData, 10, 64) | ||||
| 		if err2 != nil { | ||||
| 			checkNotIntError = true | ||||
| 		} | ||||
|  | ||||
| 		if passedData != testCase.ValidData { | ||||
| 			checkRangeError = true | ||||
| 		} | ||||
| @@ -596,11 +662,13 @@ func TestParseUint64(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
|  | ||||
| 			if checkNotIntError { | ||||
| 				require.Equal(t, errNotUint, err1) | ||||
| 			} | ||||
|  | ||||
| 			if checkRangeError { | ||||
| 				require.Equal(t, errNotUint64, err1) | ||||
| 			} | ||||
| @@ -634,10 +702,12 @@ func TestParseFloat32(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.FloatData) | ||||
|  | ||||
| @@ -646,12 +716,16 @@ func TestParseFloat32(t *testing.T) { | ||||
| 		s1 := &testStruct{} | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotIntError bool | ||||
| 		var checkRangeError bool | ||||
| 		var ( | ||||
| 			checkNotIntError bool | ||||
| 			checkRangeError  bool | ||||
| 		) | ||||
|  | ||||
| 		passedData, err2 := strconv.ParseFloat(testCase.TestData, 64) | ||||
| 		if err2 != nil { | ||||
| 			checkNotIntError = true | ||||
| 		} | ||||
|  | ||||
| 		if passedData != float64(testCase.ValidData) { | ||||
| 			checkRangeError = true | ||||
| 		} | ||||
| @@ -660,11 +734,13 @@ func TestParseFloat32(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
|  | ||||
| 			if checkNotIntError { | ||||
| 				require.Equal(t, errNotFloat, err1) | ||||
| 			} | ||||
|  | ||||
| 			if checkRangeError { | ||||
| 				require.Equal(t, errNotFloat32, err1) | ||||
| 			} | ||||
| @@ -697,10 +773,12 @@ func TestParseFloat64(t *testing.T) { | ||||
| 		// If ErrorsAreCritical == false, then we should check only | ||||
| 		// equality of parsed data and valid data. | ||||
| 		s := &testStruct{} | ||||
|  | ||||
| 		err := Parse(s, nil) | ||||
| 		if err != nil { | ||||
| 			t.Log(err.Error()) | ||||
| 		} | ||||
|  | ||||
| 		require.Nil(t, err) | ||||
| 		require.Equal(t, testCase.ValidData, s.FloatData) | ||||
|  | ||||
| @@ -709,12 +787,16 @@ func TestParseFloat64(t *testing.T) { | ||||
| 		s1 := &testStruct{} | ||||
| 		err1 := Parse(s1, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 		var checkNotIntError bool | ||||
| 		var checkRangeError bool | ||||
| 		var ( | ||||
| 			checkNotIntError bool | ||||
| 			checkRangeError  bool | ||||
| 		) | ||||
|  | ||||
| 		passedData, err2 := strconv.ParseFloat(testCase.TestData, 64) | ||||
| 		if err2 != nil { | ||||
| 			checkNotIntError = true | ||||
| 		} | ||||
|  | ||||
| 		if passedData != testCase.ValidData { | ||||
| 			checkRangeError = true | ||||
| 		} | ||||
| @@ -723,11 +805,13 @@ func TestParseFloat64(t *testing.T) { | ||||
| 			if err1 == nil { | ||||
| 				t.Log("No error returned!") | ||||
| 			} | ||||
|  | ||||
| 			require.NotNil(t, err1) | ||||
|  | ||||
| 			if checkNotIntError { | ||||
| 				require.Equal(t, errNotFloat, err1) | ||||
| 			} | ||||
|  | ||||
| 			if checkRangeError { | ||||
| 				require.Equal(t, errNotFloat64, err1) | ||||
| 			} | ||||
| @@ -772,6 +856,7 @@ func TestParseStructWitStructAsInterface(t *testing.T) { | ||||
| 		Data interface{} | ||||
| 		Int  int | ||||
| 	} | ||||
|  | ||||
| 	type testUnderlyingStruct struct { | ||||
| 		Data string | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										5
									
								
								sec.go
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								sec.go
									
									
									
									
									
								
							| @@ -1,7 +1,6 @@ | ||||
| package sec | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"errors" | ||||
| 	"log" | ||||
| 	"os" | ||||
| @@ -38,9 +37,11 @@ func Parse(structure interface{}, config *Options) error { | ||||
| 	debugFlagRaw, found := os.LookupEnv(debugFlagEnvName) | ||||
| 	if found { | ||||
| 		var err error | ||||
|  | ||||
| 		debug, err = strconv.ParseBool(debugFlagRaw) | ||||
| 		if err != nil { | ||||
| 			log.Println("Invalid '" + debugFlagEnvName + "' environment variable data: '" + debugFlagRaw + "'. Error: " + err.Error()) | ||||
| 			log.Printf("Invalid '%s' environment variable data: '%s'. Error: %s", debugFlagEnvName, debugFlagRaw, err.Error()) | ||||
|  | ||||
| 			if options.ErrorsAreCritical { | ||||
| 				return err | ||||
| 			} | ||||
|   | ||||
							
								
								
									
										87
									
								
								sec_test.go
									
									
									
									
									
								
							
							
						
						
									
										87
									
								
								sec_test.go
									
									
									
									
									
								
							| @@ -1,12 +1,10 @@ | ||||
| package sec | ||||
|  | ||||
| import ( | ||||
| 	// stdlib | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"testing" | ||||
|  | ||||
| 	// other | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
|  | ||||
| @@ -26,18 +24,23 @@ var ( | ||||
| ) | ||||
|  | ||||
| type testDatas struct { | ||||
| 	TestString  string | ||||
| 	TestInt8    int8 | ||||
| 	TestInt16   int16 | ||||
| 	TestInt32   int32 | ||||
| 	TestInt64   int64 | ||||
| 	TestUint8   uint8 | ||||
| 	TestUint16  uint16 | ||||
| 	TestUint32  uint32 | ||||
| 	TestUint64  uint64 | ||||
| 	TestFloat32 float32 | ||||
| 	TestFloat64 float64 | ||||
| 	TestBool    bool | ||||
| 	TestUint64  uint64 | ||||
| 	TestInt64   int64 | ||||
|  | ||||
| 	TestFloat32 float32 | ||||
| 	TestUint32  uint32 | ||||
| 	TestInt32   int32 | ||||
|  | ||||
| 	TestUint16 uint16 | ||||
| 	TestInt16  int16 | ||||
|  | ||||
| 	TestUint8 uint8 | ||||
| 	TestInt8  int8 | ||||
|  | ||||
| 	TestBool bool | ||||
|  | ||||
| 	TestString string | ||||
| } | ||||
|  | ||||
| type testStringType string | ||||
| @@ -46,32 +49,42 @@ type testStruct1 struct { | ||||
| 	testDatas | ||||
| 	testStringType | ||||
| 	TestNestAnonymous struct { | ||||
| 		TestString  string | ||||
| 		TestInt8    int8 | ||||
| 		TestInt16   int16 | ||||
| 		TestInt32   int32 | ||||
| 		TestInt64   int64 | ||||
| 		TestUint8   uint8 | ||||
| 		TestUint16  uint16 | ||||
| 		TestUint32  uint32 | ||||
| 		TestUint64  uint64 | ||||
| 		TestFloat32 float32 | ||||
| 		TestFloat64 float64 | ||||
| 		TestBool    bool | ||||
| 		TestUint64  uint64 | ||||
| 		TestInt64   int64 | ||||
|  | ||||
| 		TestFloat32 float32 | ||||
| 		TestUint32  uint32 | ||||
| 		TestInt32   int32 | ||||
|  | ||||
| 		TestUint16 uint16 | ||||
| 		TestInt16  int16 | ||||
|  | ||||
| 		TestUint8 uint8 | ||||
| 		TestInt8  int8 | ||||
|  | ||||
| 		TestBool bool | ||||
|  | ||||
| 		TestString string | ||||
| 	} | ||||
| 	TestNestAnonymousPointer *struct { | ||||
| 		TestString  string | ||||
| 		TestInt8    int8 | ||||
| 		TestInt16   int16 | ||||
| 		TestInt32   int32 | ||||
| 		TestInt64   int64 | ||||
| 		TestUint8   uint8 | ||||
| 		TestUint16  uint16 | ||||
| 		TestUint32  uint32 | ||||
| 		TestUint64  uint64 | ||||
| 		TestFloat32 float32 | ||||
| 		TestFloat64 float64 | ||||
| 		TestBool    bool | ||||
| 		TestUint64  uint64 | ||||
| 		TestInt64   int64 | ||||
|  | ||||
| 		TestFloat32 float32 | ||||
| 		TestUint32  uint32 | ||||
| 		TestInt32   int32 | ||||
|  | ||||
| 		TestUint16 uint16 | ||||
| 		TestInt16  int16 | ||||
|  | ||||
| 		TestUint8 uint8 | ||||
| 		TestInt8  int8 | ||||
|  | ||||
| 		TestBool bool | ||||
|  | ||||
| 		TestString string | ||||
| 	} | ||||
| 	TestNestPointer          *testDatas | ||||
| 	TestNest                 testDatas | ||||
| @@ -90,7 +103,7 @@ func setenv(prefix string) { | ||||
| 	os.Setenv(prefix+"TESTINT8", strconv.FormatInt(int64(testInt8), 10)) | ||||
| 	os.Setenv(prefix+"TESTINT16", strconv.FormatInt(int64(testInt16), 10)) | ||||
| 	os.Setenv(prefix+"TESTINT32", strconv.FormatInt(int64(testInt32), 10)) | ||||
| 	os.Setenv(prefix+"TESTINT64", strconv.FormatInt(int64(testInt64), 10)) | ||||
| 	os.Setenv(prefix+"TESTINT64", strconv.FormatInt(testInt64, 10)) | ||||
| 	os.Setenv(prefix+"TESTUINT8", strconv.FormatInt(int64(testUint8), 10)) | ||||
| 	os.Setenv(prefix+"TESTUINT16", strconv.FormatInt(int64(testUint16), 10)) | ||||
| 	os.Setenv(prefix+"TESTUINT32", strconv.FormatInt(int64(testUint32), 10)) | ||||
| @@ -209,8 +222,8 @@ func TestInvalidDebugFlagValue(t *testing.T) { | ||||
| func TestInvalidDebugFlagValueWithErrorsAreCritical(t *testing.T) { | ||||
| 	_ = os.Setenv(debugFlagEnvName, "INVALID") | ||||
| 	c := &testStruct1{} | ||||
| 	err := Parse(c, &Options{ErrorsAreCritical: true}) | ||||
|  | ||||
| 	err := Parse(c, &Options{ErrorsAreCritical: true}) | ||||
| 	if err != nil { | ||||
| 		t.Log(err.Error()) | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user