diff --git a/.golangci.yml b/.golangci.yml index 42c7640..204c5c6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -577,6 +577,7 @@ linters-settings: # List of allowed modules. # Default: [] modules: # List of allowed modules + - github.com/pelletier/go-toml/v2 - github.com/stretchr/testify # - gopkg.in/yaml.v2 # List of allowed module domains. diff --git a/CHANGELOG.md b/CHANGELOG.md index c4f3833..2c17dd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- Add support for TOML configuration files - Use stdlib for tests instead of convey - Update golangci-lint config @@ -12,5 +13,5 @@ - Added a Loadfiles function to load at once several config files ## v0.1.0 (2020-03-17) -- Initial varsion +- Initial varsion with support for JSON files diff --git a/adapters.go b/adapters.go new file mode 100644 index 0000000..363c1bd --- /dev/null +++ b/adapters.go @@ -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 +} diff --git a/config.go b/config.go index 5aa8e1e..0a4fbbe 100644 --- a/config.go +++ b/config.go @@ -1,15 +1,25 @@ -// Package conf defines utils to simplify configuration -// management. +// Package conf defines utils to simplify configuration 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 import ( - "encoding/json" "errors" "fmt" "os" "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 // with the content of the file. 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. // // 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 { for _, p := range paths { err := read(p, data) @@ -78,18 +88,13 @@ func read(path string, data interface{}) error { return fmt.Errorf("cannot read config file: %w", err) } - err = json.Unmarshal(content, &data) - if err != nil { - return fmt.Errorf("cannot parse config file: %w", err) - } - - return nil + return unmarshal(getType(path), content, data) } func write(path string, data interface{}) error { - content, err := json.MarshalIndent(data, "", " ") + content, err := marshal(getType(path), data) if err != nil { - return fmt.Errorf("cannot generate config content: %w", err) + return err } err = os.WriteFile(path, content, 0o600) diff --git a/config_test.go b/config_test.go index 4c4c131..6ea067a 100644 --- a/config_test.go +++ b/config_test.go @@ -11,6 +11,68 @@ import ( "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 { inUpdate func() String string @@ -24,374 +86,352 @@ func (t testconf) Update() { } } -func TestLoadFile(t *testing.T) { - t.Parallel() +func testLoadFile(t *testing.T, ext string) { + t.Helper() - t.Run("with a valid file", func(t *testing.T) { + t.Run("LoadFile", func(t *testing.T) { t.Parallel() - c := testconf{ - String: "default string", - Int: 1, - Invariant: "should not change", - } + t.Run("with a valid file", func(t *testing.T) { + t.Parallel() - file := "test_data/valid.json" + c := testconf{ + String: "default string", + Int: 1, + Invariant: "should not change", + } - err := conf.LoadFile(file, &c) - require.NoError(t, err) + file := "test_data/valid." + ext - assert.Equal(t, "config string", c.String) - assert.Equal(t, 42, c.Int) - assert.Equal(t, "should not change", c.Invariant) - }) + err := conf.LoadFile(file, &c) + require.NoError(t, err) - t.Run("with an invalid file", func(t *testing.T) { - t.Parallel() + assert.Equal(t, "config string", c.String) + assert.Equal(t, 42, c.Int) + assert.Equal(t, "should not change", c.Invariant) + }) - c := testconf{ - String: "default string", - Int: 1, - Invariant: "should not change", - } + t.Run("with an invalid file", func(t *testing.T) { + t.Parallel() - file := "test_data/invalid.json" + c := testconf{ + String: "default string", + Int: 1, + Invariant: "should not change", + } - err := conf.LoadFile(file, &c) - require.Error(t, err) + file := "test_data/invalid." + ext - assert.Equal(t, "default string", c.String) - assert.Equal(t, 1, c.Int) - assert.Equal(t, "should not change", c.Invariant) - }) + err := conf.LoadFile(file, &c) + require.Error(t, err) - t.Run("with a non existent file", func(t *testing.T) { - t.Parallel() + assert.Equal(t, "default string", c.String) + assert.Equal(t, 1, c.Int) + assert.Equal(t, "should not change", c.Invariant) + }) - c := testconf{ - String: "default string", - Int: 1, - Invariant: "should not change", - } + t.Run("with a non existent file", func(t *testing.T) { + t.Parallel() - file := "does-not-exist.conf" + c := testconf{ + String: "default string", + Int: 1, + Invariant: "should not change", + } - err := conf.LoadFile(file, &c) - require.Error(t, err) + file := "does-not-exist." + ext - assert.Equal(t, "default string", c.String) - assert.Equal(t, 1, c.Int) - assert.Equal(t, "should not change", c.Invariant) + err := conf.LoadFile(file, &c) + require.Error(t, err) + + 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) { - t.Parallel() +func testLoadFiles(t *testing.T, ext string) { + t.Helper() - t.Run("with two valid files with different options", func(t *testing.T) { + t.Run("LoadFiles", func(t *testing.T) { t.Parallel() - c := testconf{} - tmpDir := t.TempDir() + t.Run("with two valid files with different options", func(t *testing.T) { + t.Parallel() - content1 := []byte(`{"String": "foo"}`) - content2 := []byte(`{"Int": 42}`) - paths := []string{ - filepath.Join(tmpDir, "file1.json"), - filepath.Join(tmpDir, "file2.json"), - } + c := testconf{} + err := conf.LoadFiles(&c, "test_data/part1."+ext, "test_data/part2."+ext) + require.NoError(t, err) - err := os.WriteFile(paths[0], content1, 0o600) - require.NoError(t, err) - err = os.WriteFile(paths[1], content2, 0o600) - require.NoError(t, err) + assert.Equal(t, "foo", c.String) + assert.Equal(t, 42, c.Int) + }) - err = conf.LoadFiles(&c, paths...) - require.NoError(t, err) + t.Run("with two valid files with the same option", func(t *testing.T) { + t.Parallel() - assert.Equal(t, "foo", c.String) - assert.Equal(t, 42, c.Int) - }) + c := testconf{} - t.Run("with two valid files with the same option", func(t *testing.T) { - t.Parallel() + err := conf.LoadFiles(&c, "test_data/same1."+ext, "test_data/same2."+ext) + require.NoError(t, err) - c := testconf{} - tmpDir := t.TempDir() + assert.Equal(t, "bar", c.String) + }) - content1 := []byte(`{"String": "foo"}`) - content2 := []byte(`{"String": "bar"}`) - paths := []string{ - filepath.Join(tmpDir, "file1.json"), - filepath.Join(tmpDir, "file2.json"), - } + t.Run("with one non-existing and one existing file", func(t *testing.T) { + t.Parallel() - err := os.WriteFile(paths[0], content1, 0o600) - require.NoError(t, err) - err = os.WriteFile(paths[1], content2, 0o600) - require.NoError(t, err) + c := testconf{} - err = conf.LoadFiles(&c, paths...) - require.NoError(t, err) + err := conf.LoadFiles(&c, "does-not-exist."+ext, "test_data/valid."+ext) + 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.Parallel() + t.Run("with one invalid and one valid file", func(t *testing.T) { + t.Parallel() - c := testconf{} - tmpDir := t.TempDir() + c := testconf{} - content2 := []byte(`{"String": "bar"}`) - paths := []string{ - "does-not-exist.json", - filepath.Join(tmpDir, "file2.json"), - } + err := conf.LoadFiles(&c, "test_data/invalid."+ext, "test_data/valid."+ext) + require.Error(t, err) - err := os.WriteFile(paths[1], content2, 0o600) - 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) + assert.Equal(t, "", c.String) + }) }) } -func TestSaveFile(t *testing.T) { - t.Parallel() +func testSaveFile(t *testing.T, ext string) { + t.Helper() - t.Run("with a valid path", func(t *testing.T) { + t.Run("SaveFile", func(t *testing.T) { t.Parallel() - c := testconf{ - String: "default string", - Invariant: "should not change", - Int: 1, - } - tmpDir := t.TempDir() - file := filepath.Join(tmpDir, "test.conf") + t.Run("with a valid path", func(t *testing.T) { + t.Parallel() - err := conf.SaveFile(file, &c) - require.NoError(t, err) + c := testconf{ + 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}" - got, err := os.ReadFile(file) - require.NoError(t, err) - assert.Equal(t, expected, string(got)) - }) + require.FileExists(t, file) - t.Run("with a valid path and invalid data", func(t *testing.T) { - t.Parallel() + expected, err := os.ReadFile("test_data/full." + ext) + require.NoError(t, err) + got, err := os.ReadFile(file) + require.NoError(t, err) - tmpDir := t.TempDir() - file := filepath.Join(tmpDir, "test.conf") + assert.Equal(t, string(expected), string(got)) + }) - err := conf.SaveFile(file, func() error { return nil }) - require.Error(t, err) + t.Run("with a valid path and invalid data", func(t *testing.T) { + 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) { - t.Parallel() + err := conf.SaveFile(file, func() error { return nil }) + require.Error(t, err) - c := testconf{ - String: "default string", - Invariant: "should not change", - Int: 1, - } - file := "cannot/write/here.conf" + assert.NoFileExists(t, file) + }) - err := conf.SaveFile(file, &c) - require.Error(t, err) + t.Run("with an invalid path", func(t *testing.T) { + 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) { - t.Parallel() +func testLoadAndUpdateFile(t *testing.T, ext string) { + t.Helper() - t.Run("when the target file does not exist", func(t *testing.T) { + t.Run("LoadAndUpdateFile", 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.conf") + t.Run("when the target file does not exist", func(t *testing.T) { + t.Parallel() - err := conf.LoadAndUpdateFile(file, &c) - require.NoError(t, err) + 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."+ext) - var c2 testconf - 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) + err := conf.LoadAndUpdateFile(file, &c) + require.NoError(t, err) - assert.False(t, updated) - }) + require.FileExists(t, file) - t.Run("when the path cannot be written", func(t *testing.T) { - t.Parallel() + var c2 testconf + 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 - 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") + assert.False(t, updated) + }) - err := conf.LoadAndUpdateFile(file, &c) - require.Error(t, err) + t.Run("when the path cannot be written", func(t *testing.T) { + 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) { - 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, "test.conf") + assert.False(t, updated) + }) - content := []byte(`String: not json`) - err := os.WriteFile(file, content, 0o644) - require.NoError(t, err) + t.Run("when the config file is invalid", func(t *testing.T) { + t.Parallel() - err = conf.LoadAndUpdateFile(file, &c) - require.Error(t, err) + 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) - 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) { - t.Parallel() + err = os.WriteFile(file, content, 0o600) + require.NoError(t, err) - 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.conf") + err = conf.LoadAndUpdateFile("test_data/invalid."+ext, &c) + require.Error(t, err) - content := []byte(`{"String": "config string", "Int": 42}`) - err := os.WriteFile(file, content, 0o644) - require.NoError(t, err) + assert.False(t, updated) + }) - err = conf.LoadAndUpdateFile(file, &c) - require.NoError(t, err) + t.Run("when the config file is valid", func(t *testing.T) { + t.Parallel() - var c2 testconf - err = conf.LoadFile(file, &c2) - require.NoError(t, err) - assert.Equal(t, "config string", c2.String) - assert.Equal(t, 42, c2.Int) + 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) - 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) { - t.Parallel() + err = os.WriteFile(file, content, 0o600) + require.NoError(t, err) - 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.conf") + err = conf.LoadAndUpdateFile(file, &c) + require.NoError(t, err) - content := []byte(`{"String": "config string"}`) - err := os.WriteFile(file, content, 0o644) - require.NoError(t, err) + var c2 testconf + err = conf.LoadFile(file, &c2) + 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) - require.NoError(t, err) + assert.True(t, updated) + }) - newContent, err := os.ReadFile(file) - require.NoError(t, err) + t.Run("when the config file is missing options", func(t *testing.T) { + t.Parallel() - assert.Contains(t, string(newContent), "Int") //nolint:usestdlibvars // not the constant here - assert.Contains(t, string(newContent), "Invariant") + 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) - 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) { - t.Parallel() + err = os.WriteFile(file, content, 0o600) + require.NoError(t, err) - 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.conf") + err = conf.LoadAndUpdateFile(file, &c) + require.NoError(t, err) - content := []byte(`{"String": "config string", "Foo": "blah"}`) - err := os.WriteFile(file, content, 0o644) - require.NoError(t, err) + newContent, err := os.ReadFile(file) + require.NoError(t, err) - err = conf.LoadAndUpdateFile(file, &c) - require.NoError(t, err) + assert.Contains(t, string(newContent), "Invariant") - newContent, err := os.ReadFile(file) - require.NoError(t, err) - assert.NotContains(t, string(newContent), "Foo") + assert.True(t, updated) + }) - 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) + }) }) } diff --git a/go.mod b/go.mod index 776efb5..737e6fe 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require github.com/stretchr/testify v1.9.0 require ( 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 gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 8f0c6a1..d049134 100644 --- a/go.sum +++ b/go.sum @@ -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.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/test_data/full.json b/test_data/full.json new file mode 100644 index 0000000..6dfe37a --- /dev/null +++ b/test_data/full.json @@ -0,0 +1,5 @@ +{ + "String": "default string", + "Invariant": "should not change", + "Int": 1 +} \ No newline at end of file diff --git a/test_data/full.toml b/test_data/full.toml new file mode 100644 index 0000000..837bd97 --- /dev/null +++ b/test_data/full.toml @@ -0,0 +1,3 @@ +String = 'default string' +Invariant = 'should not change' +Int = 1 diff --git a/test_data/invalid.toml b/test_data/invalid.toml new file mode 100644 index 0000000..df4615f --- /dev/null +++ b/test_data/invalid.toml @@ -0,0 +1 @@ +String: not toml diff --git a/test_data/part1.json b/test_data/part1.json new file mode 100644 index 0000000..e1c09a4 --- /dev/null +++ b/test_data/part1.json @@ -0,0 +1 @@ +{"String": "foo"} diff --git a/test_data/part1.toml b/test_data/part1.toml new file mode 100644 index 0000000..acec3a1 --- /dev/null +++ b/test_data/part1.toml @@ -0,0 +1 @@ +String = "foo" diff --git a/test_data/part2.json b/test_data/part2.json new file mode 100644 index 0000000..da2d7a5 --- /dev/null +++ b/test_data/part2.json @@ -0,0 +1 @@ +{"Int": 42} diff --git a/test_data/part2.toml b/test_data/part2.toml new file mode 100644 index 0000000..a002354 --- /dev/null +++ b/test_data/part2.toml @@ -0,0 +1 @@ +Int = 42 diff --git a/test_data/same1.json b/test_data/same1.json new file mode 100644 index 0000000..e1c09a4 --- /dev/null +++ b/test_data/same1.json @@ -0,0 +1 @@ +{"String": "foo"} diff --git a/test_data/same1.toml b/test_data/same1.toml new file mode 100644 index 0000000..acec3a1 --- /dev/null +++ b/test_data/same1.toml @@ -0,0 +1 @@ +String = "foo" diff --git a/test_data/same2.json b/test_data/same2.json new file mode 100644 index 0000000..17c710a --- /dev/null +++ b/test_data/same2.json @@ -0,0 +1 @@ +{"String": "bar"} diff --git a/test_data/same2.toml b/test_data/same2.toml new file mode 100644 index 0000000..570e876 --- /dev/null +++ b/test_data/same2.toml @@ -0,0 +1 @@ +String = "bar" diff --git a/test_data/unknown.json b/test_data/unknown.json new file mode 100644 index 0000000..32ecd40 --- /dev/null +++ b/test_data/unknown.json @@ -0,0 +1,5 @@ +{ + "String": "config string", + "Int": 42, + "Unknown": "foo" +} diff --git a/test_data/unknown.toml b/test_data/unknown.toml new file mode 100644 index 0000000..cbc6ca3 --- /dev/null +++ b/test_data/unknown.toml @@ -0,0 +1,3 @@ +String = "config string" +Int = 42 +Unknown = "foo" diff --git a/test_data/valid.toml b/test_data/valid.toml new file mode 100644 index 0000000..6028b6e --- /dev/null +++ b/test_data/valid.toml @@ -0,0 +1,2 @@ +string = "config string" +int = 42 diff --git a/test_data/valid.unknown b/test_data/valid.unknown new file mode 100644 index 0000000..db650bf --- /dev/null +++ b/test_data/valid.unknown @@ -0,0 +1 @@ +String: not json