Skip to content

Commit

Permalink
Published methods for get configuration through io.Reader (#122)
Browse files Browse the repository at this point in the history
Closes #86
  • Loading branch information
ilyakaznacheev committed Jul 14, 2023
2 parents aea2c89 + 1c4029f commit cb46e5a
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 17 deletions.
18 changes: 9 additions & 9 deletions cleanenv.go
Expand Up @@ -135,11 +135,11 @@ func parseFile(path string, cfg interface{}) error {
// parse the file depending on the file type
switch ext := strings.ToLower(filepath.Ext(path)); ext {
case ".yaml", ".yml":
err = parseYAML(f, cfg)
err = ParseYAML(f, cfg)
case ".json":
err = parseJSON(f, cfg)
err = ParseJSON(f, cfg)
case ".toml":
err = parseTOML(f, cfg)
err = ParseTOML(f, cfg)
case ".edn":
err = parseEDN(f, cfg)
case ".env":
Expand All @@ -153,18 +153,18 @@ func parseFile(path string, cfg interface{}) error {
return nil
}

// parseYAML parses YAML from reader to data structure
func parseYAML(r io.Reader, str interface{}) error {
// ParseYAML parses YAML from reader to data structure
func ParseYAML(r io.Reader, str interface{}) error {
return yaml.NewDecoder(r).Decode(str)
}

// parseJSON parses JSON from reader to data structure
func parseJSON(r io.Reader, str interface{}) error {
// ParseJSON parses JSON from reader to data structure
func ParseJSON(r io.Reader, str interface{}) error {
return json.NewDecoder(r).Decode(str)
}

// parseTOML parses TOML from reader to data structure
func parseTOML(r io.Reader, str interface{}) error {
// ParseTOML parses TOML from reader to data structure
func ParseTOML(r io.Reader, str interface{}) error {
_, err := toml.NewDecoder(r).Decode(str)
return err
}
Expand Down
182 changes: 180 additions & 2 deletions cleanenv_test.go
Expand Up @@ -4,6 +4,7 @@ import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"net/url"
"os"
Expand Down Expand Up @@ -1191,8 +1192,8 @@ func TestTimeLocation(t *testing.T) {
func TestSkipUnexportedField(t *testing.T) {
conf := struct {
Database struct {
Host string `yaml:"host" env:"DB_HOST" env-description:"Database host"`
Port string `yaml:"port" env:"DB_PORT" env-description:"Database port"`
Host string `yaml:"host" env:"DB_HOST" env-description:"Database host"`
Port string `yaml:"port" env:"DB_PORT" env-description:"Database port"`
} `yaml:"database"`
server struct {
Host string `yaml:"host" env:"SRV_HOST,HOST" env-description:"Server host" env-default:"localhost"`
Expand All @@ -1210,3 +1211,180 @@ func TestSkipUnexportedField(t *testing.T) {
t.Fatal("expect value on exported fields")
}
}

func TestParseYAML(t *testing.T) {
type configObject struct {
One int `yaml:"one"`
Two int `yaml:"two"`
}
type config struct {
Number int64 `yaml:"number"`
Float float64 `yaml:"float"`
String string `yaml:"string"`
Boolean bool `yaml:"boolean"`
Object configObject `yaml:"object"`
Array []int `yaml:"array"`
}

wantConfig := config{
Number: 1,
Float: 2.3,
String: "test",
Boolean: true,
Object: configObject{1, 2},
Array: []int{1, 2, 3},
}

tests := []struct {
name string
r io.Reader
want *config
wantErr bool
}{
{
name: "yaml",
r: bytes.NewBufferString(`
number: 1
float: 2.3
string: test
boolean: yes
object:
one: 1
two: 2
array: [1, 2, 3]`),
want: &wantConfig,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var cfg config
var err error
if err = ParseYAML(tt.r, &cfg); (err != nil) != tt.wantErr {
t.Errorf("ParseYAML() error = %v, wantErr %v", err, tt.wantErr)
}
if err == nil && !reflect.DeepEqual(&cfg, tt.want) {
t.Errorf("wrong data %v, want %v", &cfg, tt.want)
}
})
}
}

func TestParseJSON(t *testing.T) {
type configObject struct {
One int `json:"one"`
Two int `json:"two"`
}
type config struct {
Number int64 `json:"number"`
Float float64 `json:"float"`
String string `json:"string"`
Boolean bool `json:"boolean"`
Object configObject `json:"object"`
Array []int `json:"array"`
}

wantConfig := config{
Number: 1,
Float: 2.3,
String: "test",
Boolean: true,
Object: configObject{1, 2},
Array: []int{1, 2, 3},
}

tests := []struct {
name string
r io.Reader
want *config
wantErr bool
}{
{
name: "json",
r: bytes.NewBufferString(`
{
"number": 1,
"float": 2.3,
"string": "test",
"boolean": true,
"object": {
"one": 1,
"two": 2
},
"array": [1, 2, 3]
}`),
want: &wantConfig,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var cfg config
var err error
if err := ParseJSON(tt.r, &cfg); (err != nil) != tt.wantErr {
t.Errorf("ParseJSON() error = %v, wantErr %v", err, tt.wantErr)
}
if err == nil && !reflect.DeepEqual(&cfg, tt.want) {
t.Errorf("wrong data %v, want %v", &cfg, tt.want)
}
})
}
}

func TestParseTOML(t *testing.T) {
type configObject struct {
One int `toml:"one"`
Two int `toml:"two"`
}
type config struct {
Number int64 `toml:"number"`
Float float64 `toml:"float"`
String string `toml:"string"`
Boolean bool `toml:"boolean"`
Object configObject `toml:"object"`
Array []int `toml:"array"`
}

wantConfig := config{
Number: 1,
Float: 2.3,
String: "test",
Boolean: true,
Object: configObject{1, 2},
Array: []int{1, 2, 3},
}

tests := []struct {
name string
r io.Reader
want *config
wantErr bool
}{
{
name: "toml",
r: bytes.NewBufferString(`
number = 1
float = 2.3
string = "test"
boolean = true
array = [1, 2, 3]
[object]
one = 1
two = 2`),
want: &wantConfig,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var cfg config
var err error
if err := ParseTOML(tt.r, &cfg); (err != nil) != tt.wantErr {
t.Errorf("ParseTOML() error = %v, wantErr %v", err, tt.wantErr)
}
if err == nil && !reflect.DeepEqual(&cfg, tt.want) {
t.Errorf("wrong data %v, want %v", &cfg, tt.want)
}
})
}
}
4 changes: 2 additions & 2 deletions go.mod
@@ -1,8 +1,8 @@
module github.com/ilyakaznacheev/cleanenv

require (
github.com/BurntSushi/toml v1.1.0
github.com/joho/godotenv v1.4.0
github.com/BurntSushi/toml v1.2.1
github.com/joho/godotenv v1.5.1
gopkg.in/yaml.v3 v3.0.1
olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3
)
Expand Down
8 changes: 4 additions & 4 deletions go.sum
@@ -1,7 +1,7 @@
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down

0 comments on commit cb46e5a

Please sign in to comment.