Compare commits

...

2 commits

Author SHA1 Message Date
e72c317bbb
feat: add support for toml in addition to json
All checks were successful
/ linting (push) Successful in 3m44s
/ tests (push) Successful in 27s
2024-05-06 11:19:26 +02:00
c3d51b1cc2
chore: update changelog 2024-05-04 22:18:57 +02:00
22 changed files with 458 additions and 291 deletions

View file

@ -577,6 +577,7 @@ linters-settings:
# List of allowed modules. # List of allowed modules.
# Default: [] # Default: []
modules: # List of allowed modules modules: # List of allowed modules
- github.com/pelletier/go-toml/v2
- github.com/stretchr/testify - github.com/stretchr/testify
# - gopkg.in/yaml.v2 # - gopkg.in/yaml.v2
# List of allowed module domains. # List of allowed module domains.

View file

@ -2,6 +2,10 @@
## Unreleased ## Unreleased
- Add support for TOML configuration files
- Use stdlib for tests instead of convey
- Update golangci-lint config
## v0.2.0 (2021-12-19) ## v0.2.0 (2021-12-19)
- Added License - Added License
@ -9,5 +13,5 @@
- Added a Loadfiles function to load at once several config files - Added a Loadfiles function to load at once several config files
## v0.1.0 (2020-03-17) ## v0.1.0 (2020-03-17)
- Initial varsion
- Initial varsion with support for JSON files

86
adapters.go Normal file
View file

@ -0,0 +1,86 @@
package conf
import (
"encoding/json"
"fmt"
"strings"
"github.com/pelletier/go-toml/v2"
)
type filetype int
const (
typeInvalid filetype = iota
typeJSON
typeTOML
)
func getType(filename string) filetype {
switch {
case strings.HasSuffix(filename, ".json"):
return typeJSON
case strings.HasSuffix(filename, ".toml"):
return typeTOML
default:
return typeInvalid
}
}
func unmarshal(ft filetype, data []byte, v interface{}) error {
switch ft {
case typeJSON:
return unmarshalJSON(data, v)
case typeTOML:
return unmarshalTOML(data, v)
default:
return ErrUnsupportedFileType
}
}
func marshal(ft filetype, v interface{}) ([]byte, error) {
switch ft {
case typeJSON:
return marshalJSON(v)
case typeTOML:
return marshalTOML(v)
default:
return nil, ErrUnsupportedFileType
}
}
func unmarshalJSON(data []byte, v interface{}) error {
err := json.Unmarshal(data, v)
if err != nil {
return fmt.Errorf("cannot parse config file: %w", err)
}
return nil
}
func marshalJSON(v interface{}) ([]byte, error) {
data, err := json.MarshalIndent(v, "", " ")
if err != nil {
return nil, fmt.Errorf("cannot generate config content: %w", err)
}
return data, nil
}
func unmarshalTOML(data []byte, v interface{}) error {
err := toml.Unmarshal(data, v)
if err != nil {
return fmt.Errorf("cannot parse config file: %w", err)
}
return nil
}
func marshalTOML(v interface{}) ([]byte, error) {
data, err := toml.Marshal(v)
if err != nil {
return nil, fmt.Errorf("cannot generate config content: %w", err)
}
return data, nil
}

View file

@ -1,15 +1,25 @@
// Package conf defines utils to simplify configuration // Package conf defines utils to simplify configuration management.
// management. //
// It provides functions to load and save config files.
//
// Several formats are supported. The encoders/decoders are selected according
// to the extension of the paths passed to functions:
//
// - JSON: ".json"
// - TOML: ".toml"
package conf package conf
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
) )
// ErrUnsupportedFileType is returned when the type of the config file is not
// supported.
var ErrUnsupportedFileType = errors.New("unsupported config type")
// LoadFile reads the file at path, parses its json content and fills the struct // LoadFile reads the file at path, parses its json content and fills the struct
// with the content of the file. // with the content of the file.
func LoadFile(path string, data interface{}) error { func LoadFile(path string, data interface{}) error {
@ -21,7 +31,7 @@ func LoadFile(path string, data interface{}) error {
// If a path does not exist, it is ignored. // If a path does not exist, it is ignored.
// //
// It returns an error only if the content of a file is invalid, i.e. it // It returns an error only if the content of a file is invalid, i.e. it
// cannot be unmarshaled by json. // cannot be unmarshaled to the struct.
func LoadFiles(data interface{}, paths ...string) error { func LoadFiles(data interface{}, paths ...string) error {
for _, p := range paths { for _, p := range paths {
err := read(p, data) err := read(p, data)
@ -78,18 +88,13 @@ func read(path string, data interface{}) error {
return fmt.Errorf("cannot read config file: %w", err) return fmt.Errorf("cannot read config file: %w", err)
} }
err = json.Unmarshal(content, &data) return unmarshal(getType(path), content, data)
if err != nil {
return fmt.Errorf("cannot parse config file: %w", err)
}
return nil
} }
func write(path string, data interface{}) error { func write(path string, data interface{}) error {
content, err := json.MarshalIndent(data, "", " ") content, err := marshal(getType(path), data)
if err != nil { if err != nil {
return fmt.Errorf("cannot generate config content: %w", err) return err
} }
err = os.WriteFile(path, content, 0o600) err = os.WriteFile(path, content, 0o600)

View file

@ -11,6 +11,68 @@ import (
"code.bcarlin.xyz/go/conf" "code.bcarlin.xyz/go/conf"
) )
func TestJSONFiles(t *testing.T) {
t.Parallel()
runTestSuite(t, "json")
}
func TestTOMLFiles(t *testing.T) {
t.Parallel()
runTestSuite(t, "toml")
}
func TestUnknownFiles(t *testing.T) {
t.Parallel()
t.Run("LoadFile", func(t *testing.T) {
t.Parallel()
s := struct{}{}
err := conf.LoadFile("test_data/valid.unknown", &s)
if assert.Error(t, err) {
assert.ErrorIs(t, err, conf.ErrUnsupportedFileType)
}
})
t.Run("SaveFile", func(t *testing.T) {
t.Parallel()
s := struct{}{}
err := conf.SaveFile("test.unknown", &s)
if assert.Error(t, err) {
assert.ErrorIs(t, err, conf.ErrUnsupportedFileType)
}
assert.NoFileExists(t, "test.unknown")
})
t.Run("LoadAndUpdateFile", func(t *testing.T) {
t.Parallel()
s := struct{}{}
err := conf.LoadAndUpdateFile("test.unknown", &s)
if assert.Error(t, err) {
assert.ErrorIs(t, err, conf.ErrUnsupportedFileType)
}
assert.NoFileExists(t, "test.unknown")
})
}
func runTestSuite(t *testing.T, ext string) {
t.Helper()
testLoadFile(t, ext)
testLoadFiles(t, ext)
testSaveFile(t, ext)
testLoadAndUpdateFile(t, ext)
}
type testconf struct { type testconf struct {
inUpdate func() inUpdate func()
String string String string
@ -24,374 +86,352 @@ func (t testconf) Update() {
} }
} }
func TestLoadFile(t *testing.T) { func testLoadFile(t *testing.T, ext string) {
t.Parallel() t.Helper()
t.Run("with a valid file", func(t *testing.T) { t.Run("LoadFile", func(t *testing.T) {
t.Parallel() t.Parallel()
c := testconf{ t.Run("with a valid file", func(t *testing.T) {
String: "default string", t.Parallel()
Int: 1,
Invariant: "should not change",
}
file := "test_data/valid.json" c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
}
err := conf.LoadFile(file, &c) file := "test_data/valid." + ext
require.NoError(t, err)
assert.Equal(t, "config string", c.String) err := conf.LoadFile(file, &c)
assert.Equal(t, 42, c.Int) require.NoError(t, err)
assert.Equal(t, "should not change", c.Invariant)
})
t.Run("with an invalid file", func(t *testing.T) { assert.Equal(t, "config string", c.String)
t.Parallel() assert.Equal(t, 42, c.Int)
assert.Equal(t, "should not change", c.Invariant)
})
c := testconf{ t.Run("with an invalid file", func(t *testing.T) {
String: "default string", t.Parallel()
Int: 1,
Invariant: "should not change",
}
file := "test_data/invalid.json" c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
}
err := conf.LoadFile(file, &c) file := "test_data/invalid." + ext
require.Error(t, err)
assert.Equal(t, "default string", c.String) err := conf.LoadFile(file, &c)
assert.Equal(t, 1, c.Int) require.Error(t, err)
assert.Equal(t, "should not change", c.Invariant)
})
t.Run("with a non existent file", func(t *testing.T) { assert.Equal(t, "default string", c.String)
t.Parallel() assert.Equal(t, 1, c.Int)
assert.Equal(t, "should not change", c.Invariant)
})
c := testconf{ t.Run("with a non existent file", func(t *testing.T) {
String: "default string", t.Parallel()
Int: 1,
Invariant: "should not change",
}
file := "does-not-exist.conf" c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
}
err := conf.LoadFile(file, &c) file := "does-not-exist." + ext
require.Error(t, err)
assert.Equal(t, "default string", c.String) err := conf.LoadFile(file, &c)
assert.Equal(t, 1, c.Int) require.Error(t, err)
assert.Equal(t, "should not change", c.Invariant)
assert.Equal(t, "default string", c.String)
assert.Equal(t, 1, c.Int)
assert.Equal(t, "should not change", c.Invariant)
})
}) })
} }
func TestLoadFiles(t *testing.T) { func testLoadFiles(t *testing.T, ext string) {
t.Parallel() t.Helper()
t.Run("with two valid files with different options", func(t *testing.T) { t.Run("LoadFiles", func(t *testing.T) {
t.Parallel() t.Parallel()
c := testconf{} t.Run("with two valid files with different options", func(t *testing.T) {
tmpDir := t.TempDir() t.Parallel()
content1 := []byte(`{"String": "foo"}`) c := testconf{}
content2 := []byte(`{"Int": 42}`) err := conf.LoadFiles(&c, "test_data/part1."+ext, "test_data/part2."+ext)
paths := []string{ require.NoError(t, err)
filepath.Join(tmpDir, "file1.json"),
filepath.Join(tmpDir, "file2.json"),
}
err := os.WriteFile(paths[0], content1, 0o600) assert.Equal(t, "foo", c.String)
require.NoError(t, err) assert.Equal(t, 42, c.Int)
err = os.WriteFile(paths[1], content2, 0o600) })
require.NoError(t, err)
err = conf.LoadFiles(&c, paths...) t.Run("with two valid files with the same option", func(t *testing.T) {
require.NoError(t, err) t.Parallel()
assert.Equal(t, "foo", c.String) c := testconf{}
assert.Equal(t, 42, c.Int)
})
t.Run("with two valid files with the same option", func(t *testing.T) { err := conf.LoadFiles(&c, "test_data/same1."+ext, "test_data/same2."+ext)
t.Parallel() require.NoError(t, err)
c := testconf{} assert.Equal(t, "bar", c.String)
tmpDir := t.TempDir() })
content1 := []byte(`{"String": "foo"}`) t.Run("with one non-existing and one existing file", func(t *testing.T) {
content2 := []byte(`{"String": "bar"}`) t.Parallel()
paths := []string{
filepath.Join(tmpDir, "file1.json"),
filepath.Join(tmpDir, "file2.json"),
}
err := os.WriteFile(paths[0], content1, 0o600) c := testconf{}
require.NoError(t, err)
err = os.WriteFile(paths[1], content2, 0o600)
require.NoError(t, err)
err = conf.LoadFiles(&c, paths...) err := conf.LoadFiles(&c, "does-not-exist."+ext, "test_data/valid."+ext)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "bar", c.String) assert.Equal(t, "config string", c.String)
}) })
t.Run("with one non-existing and one existing file", func(t *testing.T) { t.Run("with one invalid and one valid file", func(t *testing.T) {
t.Parallel() t.Parallel()
c := testconf{} c := testconf{}
tmpDir := t.TempDir()
content2 := []byte(`{"String": "bar"}`) err := conf.LoadFiles(&c, "test_data/invalid."+ext, "test_data/valid."+ext)
paths := []string{ require.Error(t, err)
"does-not-exist.json",
filepath.Join(tmpDir, "file2.json"),
}
err := os.WriteFile(paths[1], content2, 0o600) assert.Equal(t, "", c.String)
require.NoError(t, err) })
err = conf.LoadFiles(&c, paths...)
require.NoError(t, err)
assert.Equal(t, "bar", c.String)
})
t.Run("with one valid and one invalid file", func(t *testing.T) {
t.Parallel()
c := testconf{}
tmpDir := t.TempDir()
content1 := []byte(`{"`)
content2 := []byte(`{"String": "bar"}`)
paths := []string{
filepath.Join(tmpDir, "file1.json"),
filepath.Join(tmpDir, "file2.json"),
}
err := os.WriteFile(paths[0], content1, 0o600)
require.NoError(t, err)
err = os.WriteFile(paths[1], content2, 0o600)
require.NoError(t, err)
err = conf.LoadFiles(&c, paths...)
require.Error(t, err)
assert.Equal(t, "", c.String)
}) })
} }
func TestSaveFile(t *testing.T) { func testSaveFile(t *testing.T, ext string) {
t.Parallel() t.Helper()
t.Run("with a valid path", func(t *testing.T) { t.Run("SaveFile", func(t *testing.T) {
t.Parallel() t.Parallel()
c := testconf{ t.Run("with a valid path", func(t *testing.T) {
String: "default string", t.Parallel()
Invariant: "should not change",
Int: 1,
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
err := conf.SaveFile(file, &c) c := testconf{
require.NoError(t, err) String: "default string",
Invariant: "should not change",
Int: 1,
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test."+ext)
assert.FileExists(t, file) err := conf.SaveFile(file, &c)
require.NoError(t, err)
expected := "{\n \"String\": \"default string\",\n \"Invariant\": \"should not change\",\n \"Int\": 1\n}" require.FileExists(t, file)
got, err := os.ReadFile(file)
require.NoError(t, err)
assert.Equal(t, expected, string(got))
})
t.Run("with a valid path and invalid data", func(t *testing.T) { expected, err := os.ReadFile("test_data/full." + ext)
t.Parallel() require.NoError(t, err)
got, err := os.ReadFile(file)
require.NoError(t, err)
tmpDir := t.TempDir() assert.Equal(t, string(expected), string(got))
file := filepath.Join(tmpDir, "test.conf") })
err := conf.SaveFile(file, func() error { return nil }) t.Run("with a valid path and invalid data", func(t *testing.T) {
require.Error(t, err) t.Parallel()
assert.NoFileExists(t, file) tmpDir := t.TempDir()
}) file := filepath.Join(tmpDir, "test."+ext)
t.Run("with an invalid path", func(t *testing.T) { err := conf.SaveFile(file, func() error { return nil })
t.Parallel() require.Error(t, err)
c := testconf{ assert.NoFileExists(t, file)
String: "default string", })
Invariant: "should not change",
Int: 1,
}
file := "cannot/write/here.conf"
err := conf.SaveFile(file, &c) t.Run("with an invalid path", func(t *testing.T) {
require.Error(t, err) t.Parallel()
assert.NoFileExists(t, file) c := testconf{
String: "default string",
Invariant: "should not change",
Int: 1,
}
file := "cannot/write/here." + ext
err := conf.SaveFile(file, &c)
require.Error(t, err)
assert.NoFileExists(t, file)
})
}) })
} }
func TestLoadAndUpdateFile(t *testing.T) { func testLoadAndUpdateFile(t *testing.T, ext string) {
t.Parallel() t.Helper()
t.Run("when the target file does not exist", func(t *testing.T) { t.Run("LoadAndUpdateFile", func(t *testing.T) {
t.Parallel() t.Parallel()
updated := false t.Run("when the target file does not exist", func(t *testing.T) {
c := testconf{ t.Parallel()
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
err := conf.LoadAndUpdateFile(file, &c) updated := false
require.NoError(t, err) c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "does-not-exist."+ext)
var c2 testconf err := conf.LoadAndUpdateFile(file, &c)
err = conf.LoadFile(file, &c2) require.NoError(t, err)
require.NoError(t, err)
assert.Equal(t, c.String, c2.String)
assert.Equal(t, c.Int, c2.Int)
assert.Equal(t, c.Invariant, c2.Invariant)
assert.False(t, updated) require.FileExists(t, file)
})
t.Run("when the path cannot be written", func(t *testing.T) { var c2 testconf
t.Parallel() err = conf.LoadFile(file, &c2)
require.NoError(t, err)
assert.Equal(t, c.String, c2.String)
assert.Equal(t, c.Int, c2.Int)
assert.Equal(t, c.Invariant, c2.Invariant)
updated := false assert.False(t, updated)
c := testconf{ })
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "does-not-exist", "test.conf")
err := conf.LoadAndUpdateFile(file, &c) t.Run("when the path cannot be written", func(t *testing.T) {
require.Error(t, err) t.Parallel()
assert.NoFileExists(t, file) updated := false
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "does-not-exist", "test."+ext)
assert.False(t, updated) err := conf.LoadAndUpdateFile(file, &c)
}) require.Error(t, err)
t.Run("when the config file is invalid", func(t *testing.T) { assert.NoFileExists(t, file)
t.Parallel()
updated := false assert.False(t, updated)
c := testconf{ })
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
content := []byte(`String: not json`) t.Run("when the config file is invalid", func(t *testing.T) {
err := os.WriteFile(file, content, 0o644) t.Parallel()
require.NoError(t, err)
err = conf.LoadAndUpdateFile(file, &c) updated := false
require.Error(t, err) c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test."+ext)
assert.False(t, updated) content, err := os.ReadFile("test_data/invalid." + ext)
}) require.NoError(t, err)
t.Run("when the config file is valid", func(t *testing.T) { err = os.WriteFile(file, content, 0o600)
t.Parallel() require.NoError(t, err)
updated := false err = conf.LoadAndUpdateFile("test_data/invalid."+ext, &c)
c := testconf{ require.Error(t, err)
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
content := []byte(`{"String": "config string", "Int": 42}`) assert.False(t, updated)
err := os.WriteFile(file, content, 0o644) })
require.NoError(t, err)
err = conf.LoadAndUpdateFile(file, &c) t.Run("when the config file is valid", func(t *testing.T) {
require.NoError(t, err) t.Parallel()
var c2 testconf updated := false
err = conf.LoadFile(file, &c2) c := testconf{
require.NoError(t, err) String: "default string",
assert.Equal(t, "config string", c2.String) Int: 1,
assert.Equal(t, 42, c2.Int) Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test."+ext)
assert.True(t, updated) content, err := os.ReadFile("test_data/valid." + ext)
}) require.NoError(t, err)
t.Run("when the config file is missing options", func(t *testing.T) { err = os.WriteFile(file, content, 0o600)
t.Parallel() require.NoError(t, err)
updated := false err = conf.LoadAndUpdateFile(file, &c)
c := testconf{ require.NoError(t, err)
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
content := []byte(`{"String": "config string"}`) var c2 testconf
err := os.WriteFile(file, content, 0o644) err = conf.LoadFile(file, &c2)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "config string", c2.String)
assert.Equal(t, 42, c2.Int)
assert.Equal(t, "should not change", c2.Invariant)
err = conf.LoadAndUpdateFile(file, &c) assert.True(t, updated)
require.NoError(t, err) })
newContent, err := os.ReadFile(file) t.Run("when the config file is missing options", func(t *testing.T) {
require.NoError(t, err) t.Parallel()
assert.Contains(t, string(newContent), "Int") //nolint:usestdlibvars // not the constant here updated := false
assert.Contains(t, string(newContent), "Invariant") c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test."+ext)
assert.True(t, updated) content, err := os.ReadFile("test_data/valid." + ext)
}) require.NoError(t, err)
t.Run("when the config contains unknown options", func(t *testing.T) { err = os.WriteFile(file, content, 0o600)
t.Parallel() require.NoError(t, err)
updated := false err = conf.LoadAndUpdateFile(file, &c)
c := testconf{ require.NoError(t, err)
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test.conf")
content := []byte(`{"String": "config string", "Foo": "blah"}`) newContent, err := os.ReadFile(file)
err := os.WriteFile(file, content, 0o644) require.NoError(t, err)
require.NoError(t, err)
err = conf.LoadAndUpdateFile(file, &c) assert.Contains(t, string(newContent), "Invariant")
require.NoError(t, err)
newContent, err := os.ReadFile(file) assert.True(t, updated)
require.NoError(t, err) })
assert.NotContains(t, string(newContent), "Foo")
assert.True(t, updated) t.Run("when the config contains unknown options", func(t *testing.T) {
t.Parallel()
updated := false
c := testconf{
String: "default string",
Int: 1,
Invariant: "should not change",
inUpdate: func() { updated = true },
}
tmpDir := t.TempDir()
file := filepath.Join(tmpDir, "test."+ext)
content, err := os.ReadFile("test_data/unknown." + ext)
require.NoError(t, err)
err = os.WriteFile(file, content, 0o600)
require.NoError(t, err)
err = conf.LoadAndUpdateFile(file, &c)
require.NoError(t, err)
newContent, err := os.ReadFile(file)
require.NoError(t, err)
assert.NotContains(t, string(newContent), "Unknown")
assert.True(t, updated)
})
}) })
} }

1
go.mod
View file

@ -6,6 +6,7 @@ require github.com/stretchr/testify v1.9.0
require ( require (
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

2
go.sum
View file

@ -1,6 +1,8 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

5
test_data/full.json Normal file
View file

@ -0,0 +1,5 @@
{
"String": "default string",
"Invariant": "should not change",
"Int": 1
}

3
test_data/full.toml Normal file
View file

@ -0,0 +1,3 @@
String = 'default string'
Invariant = 'should not change'
Int = 1

1
test_data/invalid.toml Normal file
View file

@ -0,0 +1 @@
String: not toml

1
test_data/part1.json Normal file
View file

@ -0,0 +1 @@
{"String": "foo"}

1
test_data/part1.toml Normal file
View file

@ -0,0 +1 @@
String = "foo"

1
test_data/part2.json Normal file
View file

@ -0,0 +1 @@
{"Int": 42}

1
test_data/part2.toml Normal file
View file

@ -0,0 +1 @@
Int = 42

1
test_data/same1.json Normal file
View file

@ -0,0 +1 @@
{"String": "foo"}

1
test_data/same1.toml Normal file
View file

@ -0,0 +1 @@
String = "foo"

1
test_data/same2.json Normal file
View file

@ -0,0 +1 @@
{"String": "bar"}

1
test_data/same2.toml Normal file
View file

@ -0,0 +1 @@
String = "bar"

5
test_data/unknown.json Normal file
View file

@ -0,0 +1,5 @@
{
"String": "config string",
"Int": 42,
"Unknown": "foo"
}

3
test_data/unknown.toml Normal file
View file

@ -0,0 +1,3 @@
String = "config string"
Int = 42
Unknown = "foo"

2
test_data/valid.toml Normal file
View file

@ -0,0 +1,2 @@
string = "config string"
int = 42

1
test_data/valid.unknown Normal file
View file

@ -0,0 +1 @@
String: not json