Skip to content

Commit

Permalink
Fix override with zero value for readers source
Browse files Browse the repository at this point in the history
  • Loading branch information
brumhard committed Mar 30, 2021
1 parent a8285a1 commit cd62786
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 13 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ For sources that only support setting values as strings (like for example enviro
slice containing the string and it will automatically be converted to the target type if possible. Any other type is
used directly leading to an error on type mismatch.

> You should not return structs directly since this could lead to errors if some struct properties are set and others
> are not. This would then overwrite the target with the zero value, which is not intended.
The received fields match directly to the fields in the config. So for example for a config struct like the following:

```Go
Expand Down
14 changes: 6 additions & 8 deletions alligotor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -280,36 +280,34 @@ var _ = Describe("config", func() {
})
Context("file is set", func() {
BeforeEach(func() {
jsonBytes := []byte(`{"sleep": "2s","api": {"port": 2, "logLevel": "file"}, "db": {"logLevel": "file"}}`)
jsonBytes := []byte(`{"sleep": "2s","api": {"port": 2}, "db": {"logLevel": "file"}}`)
Expect(os.WriteFile(path.Join(tempDir, fileBaseName+".json"), jsonBytes, 0600)).To(Succeed())
})
It("overrides defaults", func() {
It("overrides defaults only if set", func() {
Expect(c.Get(&testingStruct)).To(Succeed())
Expect(testingStruct.Sleep).To(Equal(2 * time.Second))
Expect(testingStruct.API.Port).To(Equal(2))
Expect(testingStruct.API.LogLevel).To(Equal("file"))
Expect(testingStruct.API.LogLevel).To(Equal("info"))
Expect(testingStruct.DB.LogLevel).To(Equal("file"))
})
Context("env is set", func() {
BeforeEach(func() {
Expect(os.Setenv("SLEEP", "3s")).To(Succeed())
Expect(os.Setenv("API_PORT", "3")).To(Succeed())
Expect(os.Setenv("API_LOGLEVEL", "env")).To(Succeed())
Expect(os.Setenv("DB_LOGLEVEL", "env")).To(Succeed())
})
It("overrides file", func() {
It("overrides file, keeps defaults if not set", func() {
Expect(c.Get(&testingStruct)).To(Succeed())
Expect(testingStruct.Sleep).To(Equal(3 * time.Second))
Expect(testingStruct.API.Port).To(Equal(3))
Expect(testingStruct.API.LogLevel).To(Equal("env"))
Expect(testingStruct.API.LogLevel).To(Equal("info"))
Expect(testingStruct.DB.LogLevel).To(Equal("env"))
})
Context("flags are set", func() {
BeforeEach(func() {
os.Args = []string{"commandName",
"--sleep", "4s",
"--api.port", "4",
"--api.loglevel", "flag",
"--db.loglevel", "flag",
}
})
Expand All @@ -318,7 +316,7 @@ var _ = Describe("config", func() {
Expect(testingStruct.Enabled).To(Equal(true))
Expect(testingStruct.Sleep).To(Equal(4 * time.Second))
Expect(testingStruct.API.Port).To(Equal(4))
Expect(testingStruct.API.LogLevel).To(Equal("flag"))
Expect(testingStruct.API.LogLevel).To(Equal("info"))
Expect(testingStruct.DB.LogLevel).To(Equal("flag"))
})
})
Expand Down
14 changes: 9 additions & 5 deletions readers.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,19 @@ func readFileMap(f *Field, m *ciMap) (interface{}, error) {

fieldTypeNew := reflect.New(f.Type())

if err := mapstructure.Decode(valueForField, fieldTypeNew.Interface()); err != nil {
// if theres a type mismatch check if value is a string so maybe it can be parsed
if f.Type().Kind() == reflect.Struct {
// if it's a struct, it could be assigned with TextUnmarshaler, otherwise return nil
if valueString, ok := valueForField.(string); ok {
return []byte(valueString), nil
}

// if it's a struct, maybe one of the properties can be assigned nevertheless
if f.Type().Kind() == reflect.Struct {
return nil, nil
return nil, nil
}

if err := mapstructure.Decode(valueForField, fieldTypeNew.Interface()); err != nil {
// if theres a type mismatch check if value is a string so maybe it can be parsed
if valueString, ok := valueForField.(string); ok {
return []byte(valueString), nil
}

return nil, err
Expand Down

0 comments on commit cd62786

Please sign in to comment.