Skip to content

Commit

Permalink
more tests for float32 fields (#19)
Browse files Browse the repository at this point in the history
* more tests for float32 fields

* doc improvements

* parses float64 fields

* parses complex fields

* tests for parsing invalid byte field

* fixes markdown

* raises coverage of complex type testing

* raises coverage for bool type

* adds more OS to run tests

* fixes indent

* raises code coverage

* adds byte type to readme
  • Loading branch information
taciogt authored Dec 29, 2022
1 parent 0a25499 commit bcf88dd
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 90 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@ jobs:
strategy:
matrix:
go-version: [ '1.18', '1.19' ]
runs-on: ubuntu-latest
os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ]
runs-on: ${{ matrix.os }}

steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Setup Go Environment
uses: actions/setup-go@v3
with:
go-version: ${{matrix.go-version}}
go-version: ${{ matrix.go-version }}
check-latest: true
- name: Prints Go version
run: go version
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ $(COVERAGE_OUT): *.go
coverage-report: $(COVERAGE_OUT)
$(GOTOOL) cover -html=coverage.out

doc:
doc: setup
godoc -http=:6060
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/6904ddba8e6747559c7b4141b0f91e71)](https://www.codacy.com/gh/taciogt/envtags/dashboard?utm_source=github.com&utm_medium=referral&utm_content=taciogt/envtags&utm_campaign=Badge_Grade)
[![Codacy Badge](https://app.codacy.com/project/badge/Coverage/6904ddba8e6747559c7b4141b0f91e71)](https://www.codacy.com/gh/taciogt/envtags/dashboard?utm_source=github.com&utm_medium=referral&utm_content=taciogt/envtags&utm_campaign=Badge_Coverage)

_envtags_ is a package to use struct tags to automatically load environment variables on them. It is more about studying Go reflection approach than to create something better than what already exists.
_envtags_ is a package to use struct tags to automatically load environment variables on them. It is more about studying Go reflection approach than to create something better than what already exists, but an useful package with a [complete documentation](https://pkg.go.dev/github.com/taciogt/envtags) may come out of this.

## Requirements

Expand Down Expand Up @@ -44,7 +44,9 @@ If the field type is not supported, an `envtags.ErrParserNotAvailable` is return
- `string`
- `int`, `int64`, `int32`, `int16`, `int8`
- `uint`, `uint64`, `uint32`, `uint16`, `uint8`
- `float32`
- `float32`, `float64`
- `complex64`, `complex128`
- `byte`

## Refs

Expand Down
5 changes: 5 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,10 @@ Package envtags provides easy to use methods for setting struct fields from envi
type Config struct {
Foo int `env:"BAR"`
}
var cfg Config
Set(&cfg)
Currently, it supports the most common types in the root of the struct and parses the environment variables using the package strconv. For details on how the environment variable can be set, check [strconv.ParseBool], [strconv.ParseInt], [strconv.ParseUint], [strconv.ParseFloat]
*/
package envtags
73 changes: 42 additions & 31 deletions env.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package envtags
import (
"errors"
"fmt"
"math"
"os"
"reflect"
"strconv"
Expand All @@ -19,25 +18,20 @@ var (
ErrParserNotAvailable = errors.New("parser not available") // the field to be set has no parser for its reflect.Kind
)

func getIntParser(minSize int, maxSize int) func(envVarValue string, v reflect.Value) error {
func getIntParser(bitSize int) func(envVarValue string, v reflect.Value) error {
return func(envVarValue string, v reflect.Value) error {
intValue, err := strconv.Atoi(envVarValue)
intValue, err := strconv.ParseInt(envVarValue, 0, bitSize)
if err != nil {
return getError(ErrInvalidTypeConversion, err)
}
if intValue > maxSize {
return getError(ErrInvalidTypeConversion, errors.New("value greater than max available"))
} else if intValue < minSize {
return getError(ErrInvalidTypeConversion, errors.New("value less than min available"))
}
v.SetInt(int64(intValue))
v.SetInt(intValue)
return nil
}
}

func getUIntParser(bitSize int) func(envVarValue string, v reflect.Value) error {
return func(envVarValue string, v reflect.Value) error {
uintValue, err := strconv.ParseUint(envVarValue, 10, bitSize)
uintValue, err := strconv.ParseUint(envVarValue, 0, bitSize)
if err != nil {
return getError(ErrInvalidTypeConversion, err)
}
Expand All @@ -46,8 +40,29 @@ func getUIntParser(bitSize int) func(envVarValue string, v reflect.Value) error
}
}

var parserByKindMap = map[reflect.Kind]func(envVarValue string, v reflect.Value) error{
func getFloatParser(bitSize int) func(envVarValue string, v reflect.Value) error {
return func(envVarValue string, v reflect.Value) error {
floatValue, err := strconv.ParseFloat(envVarValue, bitSize)
if err != nil {
return getError(ErrInvalidTypeConversion, err)
}
v.SetFloat(floatValue)
return nil
}
}

func getComplexParser(bitSize int) func(envVarValue string, v reflect.Value) error {
return func(envVarValue string, v reflect.Value) error {
complexValue, err := strconv.ParseComplex(envVarValue, bitSize)
if err != nil {
return getError(ErrInvalidTypeConversion, err)
}
v.SetComplex(complexValue)
return nil
}
}

var parserByKindMap = map[reflect.Kind]func(envVarValue string, v reflect.Value) error{
reflect.Bool: func(envVarValue string, v reflect.Value) error {
if envVarValue == "" {
v.SetBool(false)
Expand All @@ -64,28 +79,24 @@ var parserByKindMap = map[reflect.Kind]func(envVarValue string, v reflect.Value)
v.SetString(envVarValue)
return nil
},
reflect.Int: getIntParser(math.MinInt, math.MaxInt),
reflect.Int8: getIntParser(math.MinInt8, math.MaxInt8),
reflect.Int16: getIntParser(math.MinInt16, math.MaxInt16),
reflect.Int32: getIntParser(math.MinInt32, math.MaxInt32),
reflect.Int64: getIntParser(math.MinInt64, math.MaxInt64),
reflect.Uint: getUIntParser(64),
reflect.Uint8: getUIntParser(8),
reflect.Uint16: getUIntParser(16),
reflect.Uint32: getUIntParser(32),
reflect.Uint64: getUIntParser(32),
reflect.Float32: func(envVarValue string, v reflect.Value) error {
floatValue, err := strconv.ParseFloat(envVarValue, 32)
if err != nil {
return getError(ErrInvalidTypeConversion, err)
}
v.SetFloat(floatValue)
return nil
},
reflect.Int: getIntParser(64),
reflect.Int8: getIntParser(8),
reflect.Int16: getIntParser(16),
reflect.Int32: getIntParser(32),
reflect.Int64: getIntParser(64),
reflect.Uint: getUIntParser(64),
reflect.Uint8: getUIntParser(8),
reflect.Uint16: getUIntParser(16),
reflect.Uint32: getUIntParser(32),
reflect.Uint64: getUIntParser(32),
reflect.Float32: getFloatParser(32),
reflect.Float64: getFloatParser(64),
reflect.Complex64: getComplexParser(64),
reflect.Complex128: getComplexParser(128),
}

/*
Set receives a struct pointer and sets its fields using the parameters defined on
Set receives a struct pointer and sets its fields using the value from environment variables defined in the struct tag "env".
*/
func Set(s interface{}) error {
value := reflect.ValueOf(s)
Expand All @@ -103,7 +114,7 @@ func Set(s interface{}) error {
return getError(ErrParserNotAvailable, fmt.Errorf("parser for %s not found", fType.Type.Kind()))
}
if err := parser(envVarValue, f); err != nil {
return err
return fmt.Errorf("failed to parse value for field %s: %w", elem.Type().Field(i).Name, err)
}
}

Expand Down
Loading

0 comments on commit bcf88dd

Please sign in to comment.