Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Dotconfig [![Go Reference](https://pkg.go.dev/badge/github.com/DeanPDX/dotconfig.svg)](https://pkg.go.dev/github.com/DeanPDX/dotconfig) [![Go Report Card](https://goreportcard.com/badge/github.com/DeanPDX/dotconfig)](https://goreportcard.com/report/github.com/DeanPDX/dotconfig) ![Codecov](https://img.shields.io/codecov/c/github/DeanPDX/dotconfig)
# Dotconfig [![Go Reference](https://pkg.go.dev/badge/github.com/DeanPDX/dotconfig.svg)](https://pkg.go.dev/github.com/DeanPDX/dotconfig) [![Go Report Card](https://goreportcard.com/badge/github.com/DeanPDX/dotconfig)](https://goreportcard.com/report/github.com/DeanPDX/dotconfig) [![Codecov](https://img.shields.io/codecov/c/github/DeanPDX/dotconfig)](https://app.codecov.io/gh/DeanPDX/dotconfig/)

This package aims to simplify configuration from environment variables. In local development, we can supply a `.env` file with key/value pairs. When deployed, values come from a secret manager. This is similar to [joho/godotenv](https://github.com/joho/godotenv) but the aim here is to not only read the `.env` file but use reflection to produce a config struct. We also support optional/required fields in the struct and default values.

Expand Down
23 changes: 23 additions & 0 deletions dotconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,26 @@ func TestSingleError(t *testing.T) {
t.Errorf("Expecting exactly 1 error")
}
}

func TestMustBeStruct(t *testing.T) {
_, err := dotconfig.FromFileName[string](".env")
// Just make sure we get exactly 1 error.
errs := dotconfig.Errors(err)
if len(errs) != 1 {
t.Fatalf("Expecting exactly 1 error")
}
if !errors.Is(errs[0], dotconfig.ErrConfigMustBeStruct) {
t.Errorf("Expecting invalid type error. Got: %v", errs[0])
}
}

type empty struct{}

func TestFileIO(t *testing.T) {
// Just to get us to 100% I am doing this to
// hit the deferred file.Close()
_, err := dotconfig.FromFileName[empty]("go.mod")
if err != nil {
t.Fatal(err)
}
}
60 changes: 60 additions & 0 deletions joinerror_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package dotconfig

import (
"errors"
"strings"
"testing"
)

func TestErrorsReturnsErr(t *testing.T) {
// Make sure calling Errors on an error just returns that in collection
err := errors.New("test error")
errs := Errors(err)
if len(errs) != 1 {
t.Fatalf("Expected 1 error. Got %v", len(errs))
}
}

func TestErrorsReturnsNil(t *testing.T) {
// Make sure calling Errors on an error just returns that in collection
errs := Errors(nil)
if errs != nil {
t.Fatal("Expected nil slice")
}
}

type empty struct{}

type required struct {
MyInt int `env:"MY_INT,required"`
}

type doubleRequired struct {
MyInt int `env:"MY_INT,required"`
MySecond int `env:"MY_SECOND, required"`
}

func TestErrorsStringer(t *testing.T) {
// Make sure calling Errors on an error just returns that in collection
_, err := FromReader[empty](strings.NewReader(""))
if err != nil {
t.Fatal("Expected nil slice")
}
// Single error should return in common error format
_, err = FromReader[required](strings.NewReader(""))
want := "key not present in ENV: MY_INT"
if err.Error() != want {
t.Fatalf("Expected %v. Got %v.", want, err.Error())
}
_, err = FromReader[doubleRequired](strings.NewReader(""))
want = `multiple errors:
- key not present in ENV: MY_INT
- key not present in ENV: MY_SECOND`
if err.Error() != want {
t.Fatalf("Expected %v. Got %v.", want, err.Error())
}
errs := joinError{}
if errs.Error() != "" {
t.Fatalf("Expected empty string. Got: %v", errs.Error())
}
}
Loading