From 4b3e2cacb7c2c413801d7edad272052c27cc4c38 Mon Sep 17 00:00:00 2001 From: Eric Fritz Date: Wed, 30 Sep 2020 21:37:09 -0500 Subject: [PATCH] Migrate tests to testify (#5) --- LICENSE | 2 +- config.go | 92 +++++---- config_mock_test.go | 18 +- config_test.go | 336 ++++++++++++++++++--------------- default_tag_setter.go | 2 + default_tag_setter_test.go | 61 +++--- directory_sourcer_options.go | 12 +- directory_sourcer_test.go | 71 ++++--- display_tag_setter.go | 2 + display_tag_setter_test.go | 57 +++--- env_sourcer_test.go | 31 ++- env_tag_prefixer.go | 2 + env_tag_prefixer_test.go | 39 ++-- file_sourcer.go | 20 +- file_sourcer_options.go | 12 +- file_sourcer_test.go | 95 +++++----- file_tag_prefixer.go | 2 + file_tag_prefixer_test.go | 39 ++-- file_tag_setter.go | 2 + file_tag_setter_test.go | 57 +++--- flag_sourcer_options.go | 14 +- flag_sourcer_test.go | 31 ++- flag_tag_prefixer.go | 2 + flag_tag_prefixer_test.go | 39 ++-- flag_tag_setter.go | 2 + flag_tag_setter_test.go | 57 +++--- fs.go | 46 ++--- fs_mock_test.go | 18 +- gen.go | 6 + glob_sourcer_options.go | 12 +- glob_sourcer_test.go | 54 +++--- go.mod | 14 +- go.sum | 115 +++++------ helpers_test.go | 69 +++++++ json_test.go | 31 ++- logger_mock_test.go | 10 +- logging_config.go | 34 ++-- logging_config_test.go | 115 +++++------ main_test.go | 103 +--------- mocks/config.go | 18 +- mocks/{generator.go => gen.go} | 0 mocks/logger.go | 10 +- mocks/sourcer.go | 18 +- mocks/tag_modifier.go | 10 +- multi_sourcer_test.go | 69 +++---- reflect.go | 6 +- sourcer.go | 58 +++--- sourcer_mock_test.go | 18 +- tag_modifier.go | 8 +- test_env_sourcer_test.go | 32 ++-- test_fixtures.go | 122 ------------ 51 files changed, 959 insertions(+), 1134 deletions(-) create mode 100644 gen.go create mode 100644 helpers_test.go rename mocks/{generator.go => gen.go} (100%) delete mode 100644 test_fixtures.go diff --git a/LICENSE b/LICENSE index a324c94..6623d93 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Eric Fritz +Copyright (c) 2020 Eric Fritz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/config.go b/config.go index e644481..af35312 100644 --- a/config.go +++ b/config.go @@ -7,47 +7,47 @@ import ( "strings" ) -type ( - // Config is a structure that can populate the exported fields of a - // struct based on the value of the field `env` tags. - Config interface { - // Init prepares state required by the registered sourcer. This - // method should be called before calling any other method. - Init() error - - // Load populates a configuration object. The given tag modifiers - // are applied to the configuration object pre-load. If the target - // value conforms to the PostLoadConfig interface, the PostLoad - // function may be called multiple times. - Load(interface{}, ...TagModifier) error - - // MustInject calls Injects and panics on error. - MustLoad(interface{}, ...TagModifier) - - // Assets returns a list of names of assets that compose the - // underlying sourcer. This can be a list of matched files that are - // read, or a token that denotes a fixed source. - Assets() []string - - // Dump returns the full content of the underlying sourcer. This - // is used by the logging package to show the content of the - // environment and config files when a value is missing or otherwise - // illegal. - Dump() map[string]string - } - - // PostLoadConfig is a marker interface for configuration objects - // which should do some post-processing after being loaded. This - // can perform additional casting (e.g. ints to time.Duration) and - // more sophisticated validation (e.g. enum or exclusive values). - PostLoadConfig interface { - PostLoad() error - } - - config struct { - sourcer Sourcer - } -) +// Config is a structure that can populate the exported fields of a +// struct based on the value of the field `env` tags. +type Config interface { + // Init prepares state required by the registered sourcer. This + // method should be called before calling any other method. + Init() error + + // Load populates a configuration object. The given tag modifiers + // are applied to the configuration object pre-load. If the target + // value conforms to the PostLoadConfig interface, the PostLoad + // function may be called multiple times. + Load(interface{}, ...TagModifier) error + + // MustInject calls Injects and panics on error. + MustLoad(interface{}, ...TagModifier) + + // Assets returns a list of names of assets that compose the + // underlying sourcer. This can be a list of matched files that are + // read, or a token that denotes a fixed source. + Assets() []string + + // Dump returns the full content of the underlying sourcer. This + // is used by the logging package to show the content of the + // environment and config files when a value is missing or otherwise + // illegal. + Dump() map[string]string +} + +// PostLoadConfig is a marker interface for configuration objects +// which should do some post-processing after being loaded. This +// can perform additional casting (e.g. ints to time.Duration) and +// more sophisticated validation (e.g. enum or exclusive values). +type PostLoadConfig interface { + PostLoad() error +} + +type config struct { + sourcer Sourcer +} + +var _ Config = &config{} // NewConfig creates a config loader with the given sourcer. func NewConfig(sourcer Sourcer) Config { @@ -119,12 +119,10 @@ func (c *config) loadStruct(objValue reflect.Value, objType reflect.Type) []erro errors := []error{} for i := 0; i < objType.NumField(); i++ { - var ( - field = objValue.Field(i) - fieldType = objType.Field(i) - defaultTagValue = fieldType.Tag.Get(DefaultTag) - requiredTagValue = fieldType.Tag.Get(RequiredTag) - ) + field := objValue.Field(i) + fieldType := objType.Field(i) + defaultTagValue := fieldType.Tag.Get(DefaultTag) + requiredTagValue := fieldType.Tag.Get(RequiredTag) if fieldType.Anonymous { errors = append(errors, c.loadStruct(field, fieldType.Type)...) diff --git a/config_mock_test.go b/config_mock_test.go index 293ad52..5b826eb 100644 --- a/config_mock_test.go +++ b/config_mock_test.go @@ -1,14 +1,10 @@ -// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. -// This file was generated by robots at -// 2020-04-01T15:32:13-05:00 -// using the command -// $ go-mockgen -f github.com/go-nacelle/config -i Config -o config_mock_test.go +// Code generated by go-mockgen 0.1.0; DO NOT EDIT. package config import "sync" -// MockConfig is a mock impelementation of the Config interface (from the +// MockConfig is a mock implementation of the Config interface (from the // package github.com/go-nacelle/config) used for unit testing. type MockConfig struct { // AssetsFunc is an instance of a mock function object controlling the @@ -106,7 +102,7 @@ func (f *ConfigAssetsFunc) SetDefaultHook(hook func() []string) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Assets method of the parent MockConfig instance inovkes the hook at the +// Assets method of the parent MockConfig instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *ConfigAssetsFunc) PushHook(hook func() []string) { @@ -205,7 +201,7 @@ func (f *ConfigDumpFunc) SetDefaultHook(hook func() map[string]string) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Dump method of the parent MockConfig instance inovkes the hook at the +// Dump method of the parent MockConfig instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *ConfigDumpFunc) PushHook(hook func() map[string]string) { @@ -304,7 +300,7 @@ func (f *ConfigInitFunc) SetDefaultHook(hook func() error) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Init method of the parent MockConfig instance inovkes the hook at the +// Init method of the parent MockConfig instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *ConfigInitFunc) PushHook(hook func() error) { @@ -403,7 +399,7 @@ func (f *ConfigLoadFunc) SetDefaultHook(hook func(interface{}, ...TagModifier) e } // PushHook adds a function to the end of hook queue. Each invocation of the -// Load method of the parent MockConfig instance inovkes the hook at the +// Load method of the parent MockConfig instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *ConfigLoadFunc) PushHook(hook func(interface{}, ...TagModifier) error) { @@ -515,7 +511,7 @@ func (f *ConfigMustLoadFunc) SetDefaultHook(hook func(interface{}, ...TagModifie } // PushHook adds a function to the end of hook queue. Each invocation of the -// MustLoad method of the parent MockConfig instance inovkes the hook at the +// MustLoad method of the parent MockConfig instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *ConfigMustLoadFunc) PushHook(hook func(interface{}, ...TagModifier)) { diff --git a/config_test.go b/config_test.go index 977ab23..36c9e7b 100644 --- a/config_test.go +++ b/config_test.go @@ -2,212 +2,236 @@ package config import ( "fmt" - "os" "strings" + "testing" "time" - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -type ConfigSuite struct{} +func TestConfigSimpleConfig(t *testing.T) { + type C struct { + X string `env:"x"` + Y int `env:"y"` + Z []string `env:"w" display:"Q"` + } -func (s *ConfigSuite) SetUpTest(t sweet.T) { - os.Clearenv() -} - -func (s *ConfigSuite) TestSimpleConfig(t sweet.T) { config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_X": "foo", "APP_Y": "123", "APP_W": `["bar", "baz", "bonk"]`, })) - chunk := &TestSimpleConfig{} - Expect(config.Load(chunk)).To(BeNil()) - Expect(chunk.X).To(Equal("foo")) - Expect(chunk.Y).To(Equal(123)) - Expect(chunk.Z).To(Equal([]string{"bar", "baz", "bonk"})) + chunk := &C{} + require.Nil(t, config.Load(chunk)) + assert.Equal(t, "foo", chunk.X) + assert.Equal(t, 123, chunk.Y) + assert.Equal(t, []string{"bar", "baz", "bonk"}, chunk.Z) } -func (s *ConfigSuite) TestNestedJSONDeserialization(t sweet.T) { +func TestConfigNestedJSONDeserialization(t *testing.T) { + type P struct { + V1 int `json:"v_int"` + V2 float64 `json:"v_float"` + V3 bool `json:"v_bool"` + } + type C struct { + P1 *P `env:"p1"` + P2 *P `env:"p2"` + } + config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_P1": `{"v_int": 3, "v_float": 3.14, "v_bool": true}`, "APP_P2": `{"v_int": 5, "v_float": 6.28, "v_bool": false}`, })) - chunk := &TestEmbeddedJSONConfig{} - Expect(config.Load(chunk)).To(BeNil()) - Expect(chunk.P1).To(Equal(&TestJSONPayload{V1: 3, V2: 3.14, V3: true})) - Expect(chunk.P2).To(Equal(&TestJSONPayload{V1: 5, V2: 6.28, V3: false})) + chunk := &C{} + require.Nil(t, config.Load(chunk)) + assert.Equal(t, &P{V1: 3, V2: 3.14, V3: true}, chunk.P1) + assert.Equal(t, &P{V1: 5, V2: 6.28, V3: false}, chunk.P2) } -func (s *ConfigSuite) TestRequired(t sweet.T) { +func TestConfigRequired(t *testing.T) { + type C struct { + X string `env:"x" required:"true"` + } + config := NewConfig(NewFakeSourcer("app", nil)) - chunk := &TestRequiredConfig{} - - Expect(config.Load(chunk)).To(MatchError("" + - "failed to load config" + - " (" + - "no value supplied for field 'X'" + - ")", - )) + chunk := &C{} + assert.EqualError(t, config.Load(chunk), "failed to load config (no value supplied for field 'X')") } -func (s *ConfigSuite) TestRequiredBadTag(t sweet.T) { +func TestConfigRequiredBadTag(t *testing.T) { + type C struct { + X string `env:"x" required:"yup"` + } + config := NewConfig(NewFakeSourcer("app", nil)) - chunk := &TestBadRequiredConfig{} - - Expect(config.Load(chunk)).To(MatchError("" + - "failed to load config" + - " (" + - "field 'X' has an invalid required tag" + - ")", - )) + chunk := &C{} + assert.EqualError(t, config.Load(chunk), "failed to load config (field 'X' has an invalid required tag)") } -func (s *ConfigSuite) TestDefault(t sweet.T) { +func TestConfigDefault(t *testing.T) { + type C struct { + X string `env:"x" default:"foo"` + Y []string `env:"y" default:"[\"bar\", \"baz\", \"bonk\"]"` + } + config := NewConfig(NewFakeSourcer("app", nil)) - chunk := &TestDefaultConfig{} + chunk := &C{} - Expect(config.Load(chunk)).To(BeNil()) - Expect(chunk.X).To(Equal("foo")) - Expect(chunk.Y).To(Equal([]string{"bar", "baz", "bonk"})) + require.Nil(t, config.Load(chunk)) + assert.Equal(t, "foo", chunk.X) + assert.Equal(t, []string{"bar", "baz", "bonk"}, chunk.Y) } -func (s *ConfigSuite) TestBadType(t sweet.T) { +func TestConfigBadType(t *testing.T) { + type C struct { + X string `env:"x"` + Y int `env:"y"` + Z []string `env:"w" display:"Q"` + } + config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_X": "123", // silently converted to string "APP_Y": "foo", "APP_W": `bar`, })) - chunk := &TestSimpleConfig{} - - Expect(config.Load(chunk)).To(MatchError("" + - "failed to load config" + - " (" + - "value supplied for field 'Y' cannot be coerced into the expected type" + - ", " + - "value supplied for field 'Z' cannot be coerced into the expected type" + - ")", - )) + chunk := &C{} + assert.EqualError(t, config.Load(chunk), fmt.Sprintf("failed to load config (%s)", strings.Join([]string{ + "value supplied for field 'Y' cannot be coerced into the expected type", + "value supplied for field 'Z' cannot be coerced into the expected type", + }, ", "))) } -func (s *ConfigSuite) TestBadDefaultType(t sweet.T) { +func TestConfigBadDefaultType(t *testing.T) { + type C struct { + X int `env:"x" default:"foo"` + } + config := NewConfig(NewFakeSourcer("app", nil)) - chunk := &TestBadDefaultConfig{} - - Expect(config.Load(chunk)).To(MatchError("" + - "failed to load config" + - " (" + - "default value for field 'X' cannot be coerced into the expected type" + - ")", - )) + chunk := &C{} + assert.EqualError(t, config.Load(chunk), "failed to load config (default value for field 'X' cannot be coerced into the expected type)") } -func (s *ConfigSuite) TestPostLoadConfig(t sweet.T) { +func TestConfigPostLoadConfig(t *testing.T) { config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_X": "3", })) - chunk := &TestPostLoadConfig{} - Expect(config.Load(chunk)).To(BeNil()) + chunk := &testPostLoadConfig{} + require.Nil(t, config.Load(chunk)) config = NewConfig(NewFakeSourcer("app", map[string]string{ "APP_X": "-4", })) - Expect(config.Load(chunk)).To(MatchError("" + - "failed to load config" + - " (" + - "X must be positive" + - ")", - )) + assert.EqualError(t, config.Load(chunk), "failed to load config (X must be positive)") +} + +type testPostLoadConfig struct { + X int `env:"X"` } -func (s *ConfigSuite) TestUnsettableFields(t sweet.T) { +func (c *testPostLoadConfig) PostLoad() error { + if c.X < 0 { + return fmt.Errorf("X must be positive") + } + + return nil +} + +func TestConfigUnsettableFields(t *testing.T) { + type C struct { + x int `env:"s"` + } + config := NewConfig(NewFakeSourcer("app", nil)) - chunk := &TestUnsettableConfig{} - - Expect(config.Load(chunk)).To(MatchError("" + - "failed to load config" + - " (" + - "field 'x' can not be set" + - ")", - )) + chunk := &C{} + assert.EqualError(t, config.Load(chunk), "failed to load config (field 'x' can not be set)") } -func (s *ConfigSuite) TestLoad(t sweet.T) { +func TestConfigLoad(t *testing.T) { + type C struct { + X string `env:"x"` + Y int `env:"y"` + Z []string `env:"w" display:"Q"` + } + config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_X": "foo", "APP_Y": "123", "APP_W": `["bar", "baz", "bonk"]`, })) - chunk := &TestSimpleConfig{} + chunk := &C{} - Expect(config.Load(chunk)).To(BeNil()) - Expect(chunk.X).To(Equal("foo")) - Expect(chunk.Y).To(Equal(123)) - Expect(chunk.Z).To(Equal([]string{"bar", "baz", "bonk"})) + require.Nil(t, config.Load(chunk)) + assert.Equal(t, "foo", chunk.X) + assert.Equal(t, 123, chunk.Y) + assert.Equal(t, []string{"bar", "baz", "bonk"}, chunk.Z) } -func (s *ConfigSuite) TestLoadIsomorphicType(t sweet.T) { +func TestConfigLoadIsomorphicType(t *testing.T) { + type C struct { + X string `env:"x"` + Y int `env:"y"` + Z []string `env:"w" display:"Q"` + } + config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_X": "foo", "APP_Y": "123", "APP_W": `["bar", "baz", "bonk"]`, })) - chunk := &TestSimpleConfig{} + chunk := &C{} - Expect(config.Load(chunk)).To(BeNil()) - Expect(chunk.X).To(Equal("foo")) - Expect(chunk.Y).To(Equal(123)) - Expect(chunk.Z).To(Equal([]string{"bar", "baz", "bonk"})) + require.Nil(t, config.Load(chunk)) + assert.Equal(t, "foo", chunk.X) + assert.Equal(t, 123, chunk.Y) + assert.Equal(t, []string{"bar", "baz", "bonk"}, chunk.Z) } -func (s *ConfigSuite) TestLoadPostLoadWithConversion(t sweet.T) { +func TestConfigLoadPostLoadWithConversion(t *testing.T) { config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_DURATION": "3", })) - chunk := &TestPostLoadConversion{} - - Expect(config.Load(chunk)).To(BeNil()) - Expect(chunk.Duration).To(Equal(time.Second * 3)) + chunk := &testPostLoadConversion{} + require.Nil(t, config.Load(chunk)) + assert.Equal(t, time.Second*3, chunk.Duration) } -func (s *ConfigSuite) TestLoadPostLoadWithTags(t sweet.T) { +func TestConfigLoadPostLoadWithTags(t *testing.T) { config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_FOO_DURATION": "3", })) - chunk := &TestPostLoadConversion{} + chunk := &testPostLoadConversion{} + require.Nil(t, config.Load(chunk, NewEnvTagPrefixer("foo"))) + assert.Equal(t, time.Second*3, chunk.Duration) +} + +type testPostLoadConversion struct { + RawDuration int `env:"duration"` + Duration time.Duration +} - Expect(config.Load(chunk, NewEnvTagPrefixer("foo"))).To(BeNil()) - Expect(chunk.Duration).To(Equal(time.Second * 3)) +func (c *testPostLoadConversion) PostLoad() error { + c.Duration = time.Duration(c.RawDuration) * time.Second + return nil } -func (s *ConfigSuite) TestBadConfigObjectTypes(t sweet.T) { - Expect(NewConfig(NewFakeSourcer("app", nil)).Load(nil)).To(MatchError("" + - "failed to load config" + - " (" + - "configuration target is not a pointer to struct" + - ")", - )) - - Expect(NewConfig(NewFakeSourcer("app", nil)).Load("foo")).To(MatchError("" + - "failed to load config" + - " (" + - "configuration target is not a pointer to struct" + - ")", - )) +func TestConfigBadConfigObjectTypes(t *testing.T) { + assert.EqualError(t, NewConfig(NewFakeSourcer("app", nil)).Load(nil), "failed to load config (configuration target is not a pointer to struct)") + assert.EqualError(t, NewConfig(NewFakeSourcer("app", nil)).Load("foo"), "failed to load config (configuration target is not a pointer to struct)") } -func (s *ConfigSuite) TestEmbeddedConfig(t sweet.T) { +func TestConfigEmbeddedConfig(t *testing.T) { config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_A": "1", "APP_B": "2", @@ -216,17 +240,16 @@ func (s *ConfigSuite) TestEmbeddedConfig(t sweet.T) { "APP_Y": "5", })) - chunk := &TestParentConfig{} - - Expect(config.Load(chunk)).To(BeNil()) - Expect(chunk.X).To(Equal(4)) - Expect(chunk.Y).To(Equal(5)) - Expect(chunk.A).To(Equal(1)) - Expect(chunk.B).To(Equal(2)) - Expect(chunk.C).To(Equal(3)) + chunk := &testParentConfig{} + require.Nil(t, config.Load(chunk)) + assert.Equal(t, 4, chunk.X) + assert.Equal(t, 5, chunk.Y) + assert.Equal(t, 1, chunk.A) + assert.Equal(t, 2, chunk.B) + assert.Equal(t, 3, chunk.C) } -func (s *ConfigSuite) TestEmbeddedConfigWithTags(t sweet.T) { +func TestConfigEmbeddedConfigWithTags(t *testing.T) { config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_FOO_A": "1", "APP_FOO_B": "2", @@ -235,17 +258,16 @@ func (s *ConfigSuite) TestEmbeddedConfigWithTags(t sweet.T) { "APP_FOO_Y": "5", })) - chunk := &TestParentConfig{} - - Expect(config.Load(chunk, NewEnvTagPrefixer("foo"))).To(BeNil()) - Expect(chunk.X).To(Equal(4)) - Expect(chunk.Y).To(Equal(5)) - Expect(chunk.A).To(Equal(1)) - Expect(chunk.B).To(Equal(2)) - Expect(chunk.C).To(Equal(3)) + chunk := &testParentConfig{} + require.Nil(t, config.Load(chunk, NewEnvTagPrefixer("foo"))) + assert.Equal(t, 4, chunk.X) + assert.Equal(t, 5, chunk.Y) + assert.Equal(t, 1, chunk.A) + assert.Equal(t, 2, chunk.B) + assert.Equal(t, 3, chunk.C) } -func (s *ConfigSuite) TestEmbeddedConfigPostLoad(t sweet.T) { +func TestConfigEmbeddedConfigPostLoad(t *testing.T) { config := NewConfig(NewFakeSourcer("app", map[string]string{ "APP_A": "1", "APP_B": "3", @@ -254,26 +276,40 @@ func (s *ConfigSuite) TestEmbeddedConfigPostLoad(t sweet.T) { "APP_Y": "5", })) - chunk := &TestParentConfig{} + chunk := &testParentConfig{} + assert.EqualError(t, config.Load(chunk), "failed to load config (fields must be increasing)") +} + +type testParentConfig struct { + TestChildConfig + X int `env:"x"` + Y int `env:"y"` +} - Expect(config.Load(chunk)).To(MatchError("" + - "failed to load config" + - " (" + - "fields must be increasing" + - ")", - )) +type TestChildConfig struct { + A int `env:"a"` + B int `env:"b"` + C int `env:"c"` } -func (s *ConfigSuite) TestBadEmbeddedObjectType(t sweet.T) { +func (c *TestChildConfig) PostLoad() error { + if c.A >= c.B || c.B >= c.C { + return fmt.Errorf("fields must be increasing") + } + + return nil +} + +func TestConfigBadEmbeddedObjectType(t *testing.T) { + type C struct { + *TestChildConfig + X int `env:"x"` + Y int `env:"y"` + } + config := NewConfig(NewFakeSourcer("app", nil)) - chunk := &TestBadParentConfig{} - - Expect(config.Load(chunk)).To(MatchError("" + - "failed to load config" + - " (" + - "invalid embedded type in configuration struct" + - ")", - )) + chunk := &C{} + assert.EqualError(t, config.Load(chunk), "failed to load config (invalid embedded type in configuration struct)") } // diff --git a/default_tag_setter.go b/default_tag_setter.go index 75a1e2b..523bbad 100644 --- a/default_tag_setter.go +++ b/default_tag_setter.go @@ -11,6 +11,8 @@ type defaultTagSetter struct { defaultValue string } +var _ TagModifier = &defaultTagSetter{} + // NewDefaultTagSetter creates a new TagModifier which sets the value of // the default tag for a particular field. This is used to change the default // values provided by third party libraries (for which a source change would diff --git a/default_tag_setter_test.go b/default_tag_setter_test.go index eb33e7d..ad50b04 100644 --- a/default_tag_setter_test.go +++ b/default_tag_setter_test.go @@ -1,46 +1,33 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" -) - -type DefaultTagSetterSuite struct{} + "testing" -func (s *DefaultTagSetterSuite) TestDefaultTagSetter(t sweet.T) { - obj, err := ApplyTagModifiers( - &BasicConfig{}, - NewDefaultTagSetter("X", "r"), - NewDefaultTagSetter("Y", "null"), - ) - - Expect(err).To(BeNil()) + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "a", - "default": "r", - })) +func TestDefaultTagSetter(t *testing.T) { + type C struct { + X string `env:"a" default:"q"` + Y string + } - Expect(gatherTags(obj, "Y")).To(Equal(map[string]string{ - "default": "null", - })) + obj, err := ApplyTagModifiers(&C{}, NewDefaultTagSetter("X", "r"), NewDefaultTagSetter("Y", "null")) + require.Nil(t, err) + assert.Equal(t, map[string]string{"env": "a", "default": "r"}, gatherTags(obj, "X")) + assert.Equal(t, map[string]string{"default": "null"}, gatherTags(obj, "Y")) } -func (s *DefaultTagSetterSuite) TestDefaultTagSetterEmbedded(t sweet.T) { - obj, err := ApplyTagModifiers( - &ParentConfig{}, - NewDefaultTagSetter("X", "r"), - NewDefaultTagSetter("Y", "null"), - ) - - Expect(err).To(BeNil()) - - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "a", - "default": "r", - })) - - Expect(gatherTags(obj, "Y")).To(Equal(map[string]string{ - "default": "null", - })) +func TestDefaultTagSetterEmbedded(t *testing.T) { + type C1 struct { + X string `env:"a" default:"q"` + Y string + } + type C2 struct{ C1 } + + obj, err := ApplyTagModifiers(&C2{}, NewDefaultTagSetter("X", "r"), NewDefaultTagSetter("Y", "null")) + require.Nil(t, err) + assert.Equal(t, map[string]string{"env": "a", "default": "r"}, gatherTags(obj, "X")) + assert.Equal(t, map[string]string{"default": "null"}, gatherTags(obj, "Y")) } diff --git a/directory_sourcer_options.go b/directory_sourcer_options.go index 6bf6bef..cb4ff0f 100644 --- a/directory_sourcer_options.go +++ b/directory_sourcer_options.go @@ -1,12 +1,12 @@ package config -type ( - directorySourcerOptions struct{ fs FileSystem } +type directorySourcerOptions struct { + fs FileSystem +} - // DirectorySourcerConfigFunc is a function used to configure instances of - // directory sourcers. - DirectorySourcerConfigFunc func(*directorySourcerOptions) -) +// DirectorySourcerConfigFunc is a function used to configure instances of +// directory sourcers. +type DirectorySourcerConfigFunc func(*directorySourcerOptions) // WithDirectorySourcerFS sets the FileSystem instance. func WithDirectorySourcerFS(fs FileSystem) DirectorySourcerConfigFunc { diff --git a/directory_sourcer_test.go b/directory_sourcer_test.go index 636f9c9..a8a25a4 100644 --- a/directory_sourcer_test.go +++ b/directory_sourcer_test.go @@ -1,28 +1,27 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/efritz/go-mockgen/matchers" - . "github.com/onsi/gomega" -) + "testing" -type DirectorySourcerSuite struct{} + mockassert "github.com/derision-test/go-mockgen/testutil/assert" + "github.com/stretchr/testify/require" +) -func (s *DirectorySourcerSuite) TestLoadJSON(t sweet.T) { +func TestDirectorySourcerLoadJSON(t *testing.T) { sourcer := NewDirectorySourcer("test-files/dir", nil) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) - ensureEquals(sourcer, []string{"a"}, "1") - ensureEquals(sourcer, []string{"b"}, "10") - ensureEquals(sourcer, []string{"c"}, "100") - ensureEquals(sourcer, []string{"d"}, "200") - ensureEquals(sourcer, []string{"e"}, "300") - ensureEquals(sourcer, []string{"x"}, "7") - ensureEquals(sourcer, []string{"y"}, "8") - ensureEquals(sourcer, []string{"z"}, "9") + ensureEquals(t, sourcer, []string{"a"}, "1") + ensureEquals(t, sourcer, []string{"b"}, "10") + ensureEquals(t, sourcer, []string{"c"}, "100") + ensureEquals(t, sourcer, []string{"d"}, "200") + ensureEquals(t, sourcer, []string{"e"}, "300") + ensureEquals(t, sourcer, []string{"x"}, "7") + ensureEquals(t, sourcer, []string{"y"}, "8") + ensureEquals(t, sourcer, []string{"z"}, "9") } -func (s *DirectorySourcerSuite) TestLoadJSONWithFakeFS(t sweet.T) { +func TestDirectorySourcerLoadJSONWithFakeFS(t *testing.T) { fs := NewMockFileSystem() fs.ListFilesFunc.SetDefaultReturn([]string{"a.json", "b.json", "c.json"}, nil) @@ -48,36 +47,36 @@ func (s *DirectorySourcerSuite) TestLoadJSONWithFakeFS(t sweet.T) { }`), nil) sourcer := NewDirectorySourcer("test-files/dir", nil, WithDirectorySourcerFS((fs))) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) - ensureEquals(sourcer, []string{"a"}, "1") - ensureEquals(sourcer, []string{"b"}, "10") - ensureEquals(sourcer, []string{"c"}, "100") - ensureEquals(sourcer, []string{"d"}, "200") - ensureEquals(sourcer, []string{"e"}, "300") - ensureEquals(sourcer, []string{"x"}, "7") - ensureEquals(sourcer, []string{"y"}, "8") - ensureEquals(sourcer, []string{"z"}, "9") + ensureEquals(t, sourcer, []string{"a"}, "1") + ensureEquals(t, sourcer, []string{"b"}, "10") + ensureEquals(t, sourcer, []string{"c"}, "100") + ensureEquals(t, sourcer, []string{"d"}, "200") + ensureEquals(t, sourcer, []string{"e"}, "300") + ensureEquals(t, sourcer, []string{"x"}, "7") + ensureEquals(t, sourcer, []string{"y"}, "8") + ensureEquals(t, sourcer, []string{"z"}, "9") - Expect(fs.ListFilesFunc).To(BeCalledOnceWith("test-files/dir")) - Expect(fs.ReadFileFunc).To(BeCalledOnceWith("test-files/dir/a.json")) - Expect(fs.ReadFileFunc).To(BeCalledOnceWith("test-files/dir/b.json")) - Expect(fs.ReadFileFunc).To(BeCalledOnceWith("test-files/dir/c.json")) + mockassert.CalledOnceWith(t, fs.ListFilesFunc, mockassert.Values("test-files/dir")) + mockassert.CalledOnceWith(t, fs.ReadFileFunc, mockassert.Values("test-files/dir/a.json")) + mockassert.CalledOnceWith(t, fs.ReadFileFunc, mockassert.Values("test-files/dir/b.json")) + mockassert.CalledOnceWith(t, fs.ReadFileFunc, mockassert.Values("test-files/dir/c.json")) } -func (s *DirectorySourcerSuite) TestOptionalDirectorySourcer(t sweet.T) { +func TestOptionalDirectorySourcer(t *testing.T) { sourcer := NewOptionalDirectorySourcer("test-files/no-such-directory", nil) - Expect(sourcer.Init()).To(BeNil()) - ensureMissing(sourcer, []string{"foo"}) + require.Nil(t, sourcer.Init()) + ensureMissing(t, sourcer, []string{"foo"}) } -func (s *DirectorySourcerSuite) TestOptionalDirectorySourcerWithFakeFS(t sweet.T) { +func TestOptionalDirectorySourcerWithFakeFS(t *testing.T) { fs := NewMockFileSystem() fs.ExistsFunc.SetDefaultReturn(false, nil) sourcer := NewOptionalDirectorySourcer("test-files/no-such-directory", nil, WithDirectorySourcerFS(fs)) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) - ensureMissing(sourcer, []string{"foo"}) - Expect(fs.ExistsFunc).To(BeCalledOnceWith("test-files/no-such-directory")) + ensureMissing(t, sourcer, []string{"foo"}) + mockassert.CalledOnceWith(t, fs.ExistsFunc, mockassert.Values("test-files/no-such-directory")) } diff --git a/display_tag_setter.go b/display_tag_setter.go index 05616d8..c74c020 100644 --- a/display_tag_setter.go +++ b/display_tag_setter.go @@ -8,6 +8,8 @@ import ( type displayTagSetter struct{} +var _ TagModifier = &displayTagSetter{} + // NewDisplayTagSetter creates a new TagModifier which sets the value // of the display tag to be the same as the env tag. func NewDisplayTagSetter() TagModifier { diff --git a/display_tag_setter_test.go b/display_tag_setter_test.go index 976dd33..1b8373a 100644 --- a/display_tag_setter_test.go +++ b/display_tag_setter_test.go @@ -1,42 +1,33 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" -) - -type DisplayTagSetterSuite struct{} + "testing" -func (s *DisplayTagSetterSuite) TestDisplayTagSetter(t sweet.T) { - obj, err := ApplyTagModifiers( - &BasicConfig{}, - NewDisplayTagSetter(), - ) - - Expect(err).To(BeNil()) + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "a", - "display": "a", - "default": "q", - })) +func TestDisplayTagSetter(t *testing.T) { + type C struct { + X string `env:"a" default:"q"` + Y string + } - Expect(gatherTags(obj, "Y")).To(Equal(map[string]string{})) + obj, err := ApplyTagModifiers(&C{}, NewDisplayTagSetter()) + require.Nil(t, err) + assert.Equal(t, map[string]string{"env": "a", "display": "a", "default": "q"}, gatherTags(obj, "X")) + assert.Equal(t, map[string]string{}, gatherTags(obj, "Y")) } -func (s *DisplayTagSetterSuite) TestDisplayTagSetterEmbedded(t sweet.T) { - obj, err := ApplyTagModifiers( - &ParentConfig{}, - NewDisplayTagSetter(), - ) - - Expect(err).To(BeNil()) - - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "a", - "display": "a", - "default": "q", - })) - - Expect(gatherTags(obj, "Y")).To(Equal(map[string]string{})) +func TestDisplayTagSetterEmbedded(t *testing.T) { + type C1 struct { + X string `env:"a" default:"q"` + Y string + } + type C2 struct{ C1 } + + obj, err := ApplyTagModifiers(&C2{}, NewDisplayTagSetter()) + require.Nil(t, err) + assert.Equal(t, map[string]string{"env": "a", "display": "a", "default": "q"}, gatherTags(obj, "X")) + assert.Equal(t, map[string]string{}, gatherTags(obj, "Y")) } diff --git a/env_sourcer_test.go b/env_sourcer_test.go index 6984da2..b38fd8e 100644 --- a/env_sourcer_test.go +++ b/env_sourcer_test.go @@ -2,45 +2,44 @@ package config import ( "os" + "testing" - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -type EnvSourcerSuite struct{} - -func (s *EnvSourcerSuite) TestUnprefixed(t sweet.T) { +func TestEnvSourcerUnprefixed(t *testing.T) { os.Setenv("X", "foo") os.Setenv("Y", "123") os.Setenv("APP_Y", "456") sourcer := NewEnvSourcer("app") - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) val1, _, _ := sourcer.Get([]string{"X"}) val2, _, _ := sourcer.Get([]string{"Y"}) - Expect(val1).To(Equal("foo")) - Expect(val2).To(Equal("456")) + assert.Equal(t, "foo", val1) + assert.Equal(t, "456", val2) } -func (s *EnvSourcerSuite) TestNormalizedPrefix(t sweet.T) { +func TestEnvSourcerNormalizedPrefix(t *testing.T) { os.Setenv("FOO_BAR_X", "foo") os.Setenv("FOO_BAR_Y", "123") sourcer := NewEnvSourcer("$foo-^-bar@") - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) val1, _, _ := sourcer.Get([]string{"X"}) val2, _, _ := sourcer.Get([]string{"Y"}) - Expect(val1).To(Equal("foo")) - Expect(val2).To(Equal("123")) + assert.Equal(t, "foo", val1) + assert.Equal(t, "123", val2) } -func (s *EnvSourcerSuite) TestDump(t sweet.T) { +func TestEnvSourcerDump(t *testing.T) { os.Setenv("X", "foo") os.Setenv("Y", "123") sourcer := NewEnvSourcer("app") - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) dump := sourcer.Dump() - Expect(dump["X"]).To(Equal("foo")) - Expect(dump["Y"]).To(Equal("123")) + assert.Equal(t, "foo", dump["X"]) + assert.Equal(t, "123", dump["Y"]) } diff --git a/env_tag_prefixer.go b/env_tag_prefixer.go index b39cc60..75b3352 100644 --- a/env_tag_prefixer.go +++ b/env_tag_prefixer.go @@ -11,6 +11,8 @@ type envTagPrefixer struct { prefix string } +var _ TagModifier = &envTagPrefixer{} + // NewEnvTagPrefixer creates a new TagModifier which adds a prefix to the // values of `env` tags. This can be used to register one config multiple // times and have their initialization be read from different environment diff --git a/env_tag_prefixer_test.go b/env_tag_prefixer_test.go index 01fe3e3..2caf73a 100644 --- a/env_tag_prefixer_test.go +++ b/env_tag_prefixer_test.go @@ -1,28 +1,31 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" -) + "testing" -type EnvTagPrefixerSuite struct{} + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) -func (s *EnvTagPrefixerSuite) TestEnvTagPrefixer(t sweet.T) { - obj, err := ApplyTagModifiers(&BasicConfig{}, NewEnvTagPrefixer("foo")) - Expect(err).To(BeNil()) +func TestEnvTagPrefixer(t *testing.T) { + type C struct { + X string `env:"a" default:"q"` + Y string + } - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "foo_a", - "default": "q", - })) + obj, err := ApplyTagModifiers(&C{}, NewEnvTagPrefixer("foo")) + require.Nil(t, err) + assert.Equal(t, map[string]string{"env": "foo_a", "default": "q"}, gatherTags(obj, "X")) } -func (s *EnvTagPrefixerSuite) TestEnvTagPrefixerEmbedded(t sweet.T) { - obj, err := ApplyTagModifiers(&ParentConfig{}, NewEnvTagPrefixer("foo")) - Expect(err).To(BeNil()) +func TestEnvTagPrefixerEmbedded(t *testing.T) { + type C1 struct { + X string `env:"a" default:"q"` + Y string + } + type C2 struct{ C1 } - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "foo_a", - "default": "q", - })) + obj, err := ApplyTagModifiers(&C2{}, NewEnvTagPrefixer("foo")) + require.Nil(t, err) + assert.Equal(t, map[string]string{"env": "foo_a", "default": "q"}, gatherTags(obj, "X")) } diff --git a/file_sourcer.go b/file_sourcer.go index 6678b14..70a8480 100644 --- a/file_sourcer.go +++ b/file_sourcer.go @@ -10,20 +10,18 @@ import ( "github.com/ghodss/yaml" ) -type ( - fileSourcer struct { - filename string - parser FileParser - fs FileSystem - optional bool - values map[string]string - } - - FileParser func(content []byte) (map[string]interface{}, error) -) +type fileSourcer struct { + filename string + parser FileParser + fs FileSystem + optional bool + values map[string]string +} var _ Sourcer = &fileSourcer{} +type FileParser func(content []byte) (map[string]interface{}, error) + var parserMap = map[string]FileParser{ ".yaml": ParseYAML, ".yml": ParseYAML, diff --git a/file_sourcer_options.go b/file_sourcer_options.go index fbbfaaf..815a167 100644 --- a/file_sourcer_options.go +++ b/file_sourcer_options.go @@ -1,12 +1,12 @@ package config -type ( - fileSourcerOptions struct{ fs FileSystem } +type fileSourcerOptions struct { + fs FileSystem +} - // FileSourcerConfigFunc is a function used to configure instances of - // file sourcers. - FileSourcerConfigFunc func(*fileSourcerOptions) -) +// FileSourcerConfigFunc is a function used to configure instances of +// file sourcers. +type FileSourcerConfigFunc func(*fileSourcerOptions) // WithFileSourcerFS sets the FileSystem instance. func WithFileSourcerFS(fs FileSystem) FileSourcerConfigFunc { diff --git a/file_sourcer_test.go b/file_sourcer_test.go index 6676ae9..45373f5 100644 --- a/file_sourcer_test.go +++ b/file_sourcer_test.go @@ -1,49 +1,49 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/efritz/go-mockgen/matchers" - . "github.com/onsi/gomega" -) + "testing" -type FileSourcerSuite struct{} + mockassert "github.com/derision-test/go-mockgen/testutil/assert" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) -func (s *FileSourcerSuite) TestLoadJSON(t sweet.T) { +func TestFileSourcerLoadJSON(t *testing.T) { sourcer := NewFileSourcer("test-files/values.json", ParseYAML) - Expect(sourcer.Init()).To(BeNil()) - testFileSourcer(sourcer) + require.Nil(t, sourcer.Init()) + testFileSourcer(t, sourcer) } -func (s *FileSourcerSuite) TestLoadJSONNoParser(t sweet.T) { +func TestFileSourcerLoadJSONNoParser(t *testing.T) { sourcer := NewFileSourcer("test-files/values.json", nil) - Expect(sourcer.Init()).To(BeNil()) - testFileSourcer(sourcer) + require.Nil(t, sourcer.Init()) + testFileSourcer(t, sourcer) } -func (s *FileSourcerSuite) TestLoadYAML(t sweet.T) { +func TestFileSourcerLoadYAML(t *testing.T) { sourcer := NewFileSourcer("test-files/values.yaml", ParseYAML) - Expect(sourcer.Init()).To(BeNil()) - testFileSourcer(sourcer) + require.Nil(t, sourcer.Init()) + testFileSourcer(t, sourcer) } -func (s *FileSourcerSuite) TestLoadYAMLNoParser(t sweet.T) { +func TestFileSourcerLoadYAMLNoParser(t *testing.T) { sourcer := NewFileSourcer("test-files/values.yaml", nil) - Expect(sourcer.Init()).To(BeNil()) - testFileSourcer(sourcer) + require.Nil(t, sourcer.Init()) + testFileSourcer(t, sourcer) } -func (s *FileSourcerSuite) TestLoadTOML(t sweet.T) { +func TestFileSourcerLoadTOML(t *testing.T) { sourcer := NewFileSourcer("test-files/values.toml", ParseTOML) - Expect(sourcer.Init()).To(BeNil()) - testFileSourcer(sourcer) + require.Nil(t, sourcer.Init()) + testFileSourcer(t, sourcer) } -func (s *FileSourcerSuite) TestLoadTOMLNoParser(t sweet.T) { +func TestFileSourcerLoadTOMLNoParser(t *testing.T) { sourcer := NewFileSourcer("test-files/values.toml", nil) - Expect(sourcer.Init()).To(BeNil()) - testFileSourcer(sourcer) + require.Nil(t, sourcer.Init()) + testFileSourcer(t, sourcer) } -func (s *FileSourcerSuite) TestLoadJSONWithFakeFS(t sweet.T) { +func TestFileSourcerLoadJSONWithFakeFS(t *testing.T) { fs := NewMockFileSystem() fs.ReadFileFunc.SetDefaultReturn([]byte(`{ "foo": "bar", @@ -63,48 +63,49 @@ func (s *FileSourcerSuite) TestLoadJSONWithFakeFS(t sweet.T) { }`), nil) sourcer := NewFileSourcer("test-files/values.json", ParseYAML, WithFileSourcerFS(fs)) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) - testFileSourcer(sourcer) - Expect(fs.ReadFileFunc).To(BeCalledOnceWith("test-files/values.json")) + testFileSourcer(t, sourcer) + mockassert.CalledOnceWith(t, fs.ReadFileFunc, mockassert.Values("test-files/values.json")) } -func (s *FileSourcerSuite) TestOptionalFileSourcer(t sweet.T) { +func TestOptionalFileSourcer(t *testing.T) { sourcer := NewOptionalFileSourcer("test-files/no-such-file.json", nil) - Expect(sourcer.Init()).To(BeNil()) - ensureMissing(sourcer, []string{"foo"}) + require.Nil(t, sourcer.Init()) + ensureMissing(t, sourcer, []string{"foo"}) } -func (s *FileSourcerSuite) TestOptionalFileSourcerWithFakeFS(t sweet.T) { +func TestOptionalFileSourcerWithFakeFS(t *testing.T) { fs := NewMockFileSystem() fs.ExistsFunc.SetDefaultReturn(false, nil) sourcer := NewOptionalFileSourcer("test-files/no-such-file.json", nil, WithFileSourcerFS(fs)) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) - ensureMissing(sourcer, []string{"foo"}) - Expect(fs.ExistsFunc).To(BeCalledOnceWith("test-files/no-such-file.json")) + ensureMissing(t, sourcer, []string{"foo"}) + mockassert.CalledOnceWith(t, fs.ExistsFunc, mockassert.Values("test-files/no-such-file.json")) } -func (s *FileSourcerSuite) TestDump(t sweet.T) { +func TestFileSourcerDump(t *testing.T) { sourcer := NewOptionalFileSourcer("test-files/values.json", ParseYAML) - Expect(sourcer.Init()).To(BeNil()) - - Expect(sourcer.Dump()).To(Equal(map[string]string{ + expected := map[string]string{ "foo": `bar`, "bar": `[1,2,3]`, "baz": `null`, "bonk": `{"x":1,"y":2,"z":3}`, "encoded": `{"w": 4}`, "deeply": `{"nested":{"struct":[1,2,3]}}`, - })) + } + + require.Nil(t, sourcer.Init()) + assert.Equal(t, expected, sourcer.Dump()) } -func testFileSourcer(sourcer Sourcer) { - ensureEquals(sourcer, []string{"foo"}, "bar") - ensureMatches(sourcer, []string{"bar"}, "[1, 2, 3]") - ensureMatches(sourcer, []string{"bonk"}, `{"x": 1, "y": 2, "z": 3}`) - ensureMatches(sourcer, []string{"encoded"}, `{"w": 4}`) - ensureMatches(sourcer, []string{"bonk.x"}, `1`) - ensureMatches(sourcer, []string{"encoded.w"}, `4`) - ensureMatches(sourcer, []string{"deeply.nested.struct"}, `[1, 2, 3]`) +func testFileSourcer(t *testing.T, sourcer Sourcer) { + ensureEquals(t, sourcer, []string{"foo"}, "bar") + ensureMatches(t, sourcer, []string{"bar"}, "[1, 2, 3]") + ensureMatches(t, sourcer, []string{"bonk"}, `{"x": 1, "y": 2, "z": 3}`) + ensureMatches(t, sourcer, []string{"encoded"}, `{"w": 4}`) + ensureMatches(t, sourcer, []string{"bonk.x"}, `1`) + ensureMatches(t, sourcer, []string{"encoded.w"}, `4`) + ensureMatches(t, sourcer, []string{"deeply.nested.struct"}, `[1, 2, 3]`) } diff --git a/file_tag_prefixer.go b/file_tag_prefixer.go index f42d217..67cd24e 100644 --- a/file_tag_prefixer.go +++ b/file_tag_prefixer.go @@ -11,6 +11,8 @@ type fileTagPrefixer struct { prefix string } +var _ TagModifier = &fileTagPrefixer{} + // NewFileTagPrefixer creates a new TagModifier which adds a prefix to the // values of `file` tags. This can be used to register one config multiple // times and have their initialization be read from different keys in a diff --git a/file_tag_prefixer_test.go b/file_tag_prefixer_test.go index 1b070bd..0e8640e 100644 --- a/file_tag_prefixer_test.go +++ b/file_tag_prefixer_test.go @@ -1,28 +1,31 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" -) + "testing" -type FileTagPrefixerSuite struct{} + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) -func (s *FileTagPrefixerSuite) TestEnvTagPrefixer(t sweet.T) { - obj, err := ApplyTagModifiers(&BasicConfig{}, NewEnvTagPrefixer("foo")) - Expect(err).To(BeNil()) +func TestFileTagPrefixer(t *testing.T) { + type C struct { + X string `file:"a" default:"q"` + Y string + } - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "foo_a", - "default": "q", - })) + obj, err := ApplyTagModifiers(&C{}, NewFileTagPrefixer("foo")) + require.Nil(t, err) + assert.Equal(t, map[string]string{"file": "foo_a", "default": "q"}, gatherTags(obj, "X")) } -func (s *FileTagPrefixerSuite) TestEnvTagPrefixerEmbedded(t sweet.T) { - obj, err := ApplyTagModifiers(&ParentConfig{}, NewEnvTagPrefixer("foo")) - Expect(err).To(BeNil()) +func TestFileTagPrefixerEmbedded(t *testing.T) { + type C1 struct { + X string `file:"a" default:"q"` + Y string + } + type C2 struct{ C1 } - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "foo_a", - "default": "q", - })) + obj, err := ApplyTagModifiers(&C2{}, NewFileTagPrefixer("foo")) + require.Nil(t, err) + assert.Equal(t, map[string]string{"file": "foo_a", "default": "q"}, gatherTags(obj, "X")) } diff --git a/file_tag_setter.go b/file_tag_setter.go index dc12116..11276f7 100644 --- a/file_tag_setter.go +++ b/file_tag_setter.go @@ -8,6 +8,8 @@ import ( type fileTagSetter struct{} +var _ TagModifier = &fileTagSetter{} + // NewFileTagSetter creates a new TagModifier which sets the value // of the file tag to be the same as the env tag. func NewFileTagSetter() TagModifier { diff --git a/file_tag_setter_test.go b/file_tag_setter_test.go index fb3397b..c174d1f 100644 --- a/file_tag_setter_test.go +++ b/file_tag_setter_test.go @@ -1,42 +1,33 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" -) - -type FileTagSetterSuite struct{} + "testing" -func (s *FileTagSetterSuite) TestFileTagSetter(t sweet.T) { - obj, err := ApplyTagModifiers( - &BasicConfig{}, - NewFileTagSetter(), - ) - - Expect(err).To(BeNil()) + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "a", - "file": "a", - "default": "q", - })) +func TestFileTagSetter(t *testing.T) { + type C struct { + X string `env:"a" default:"q"` + Y string + } - Expect(gatherTags(obj, "Y")).To(Equal(map[string]string{})) + obj, err := ApplyTagModifiers(&C{}, NewFileTagSetter()) + require.Nil(t, err) + assert.Equal(t, map[string]string{"env": "a", "file": "a", "default": "q"}, gatherTags(obj, "X")) + assert.Equal(t, map[string]string{}, gatherTags(obj, "Y")) } -func (s *FileTagSetterSuite) TestFileTagSetterEmbedded(t sweet.T) { - obj, err := ApplyTagModifiers( - &ParentConfig{}, - NewFileTagSetter(), - ) - - Expect(err).To(BeNil()) - - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "a", - "file": "a", - "default": "q", - })) - - Expect(gatherTags(obj, "Y")).To(Equal(map[string]string{})) +func TestFileTagSetterEmbedded(t *testing.T) { + type C1 struct { + X string `env:"a" default:"q"` + Y string + } + type C2 struct{ C1 } + + obj, err := ApplyTagModifiers(&C2{}, NewFileTagSetter()) + require.Nil(t, err) + assert.Equal(t, map[string]string{"env": "a", "file": "a", "default": "q"}, gatherTags(obj, "X")) + assert.Equal(t, map[string]string{}, gatherTags(obj, "Y")) } diff --git a/flag_sourcer_options.go b/flag_sourcer_options.go index ead57b8..e23c20d 100644 --- a/flag_sourcer_options.go +++ b/flag_sourcer_options.go @@ -2,15 +2,13 @@ package config import "os" -type ( - flagSourcerOptions struct { - args []string - } +type flagSourcerOptions struct { + args []string +} - // FlagSourcerConfigFunc is a function used to configure instances of - // flag sourcers. - FlagSourcerConfigFunc func(*flagSourcerOptions) -) +// FlagSourcerConfigFunc is a function used to configure instances of +// flag sourcers. +type FlagSourcerConfigFunc func(*flagSourcerOptions) // WithFlagSourcerArgs sets raw command line arguments. func WithFlagSourcerArgs(args []string) FlagSourcerConfigFunc { diff --git a/flag_sourcer_test.go b/flag_sourcer_test.go index b3899cc..111c9b5 100644 --- a/flag_sourcer_test.go +++ b/flag_sourcer_test.go @@ -2,40 +2,39 @@ package config import ( "fmt" + "testing" - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -type FlagSourcerSuite struct{} - -func (s *FlagSourcerSuite) TestGet(t sweet.T) { +func TestFlagSourcerGet(t *testing.T) { sourcer := NewFlagSourcer(WithFlagSourcerArgs([]string{"-X=foo", "--Y", "123"})) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) val1, _, _ := sourcer.Get([]string{"X"}) val2, _, _ := sourcer.Get([]string{"Y"}) - Expect(val1).To(Equal("foo")) - Expect(val2).To(Equal("123")) + assert.Equal(t, "foo", val1) + assert.Equal(t, "123", val2) } -func (s *FlagSourcerSuite) TestIllegalFlag(t sweet.T) { +func TestFlagSourcerIllegalFlag(t *testing.T) { for _, badFlag := range []string{"X", "---X", "-=", "--="} { sourcer := NewFlagSourcer(WithFlagSourcerArgs([]string{badFlag})) - Expect(sourcer.Init()).To(MatchError(fmt.Sprintf("illegal flag: %s", badFlag))) + assert.EqualError(t, sourcer.Init(), fmt.Sprintf("illegal flag: %s", badFlag)) } } -func (s *FlagSourcerSuite) TestMissingArgument(t sweet.T) { +func TestFlagSourcerMissingArgument(t *testing.T) { sourcer := NewFlagSourcer(WithFlagSourcerArgs([]string{"--X"})) - Expect(sourcer.Init()).To(MatchError(fmt.Sprintf("flag needs an argument: -X"))) + assert.EqualError(t, sourcer.Init(), fmt.Sprintf("flag needs an argument: -X")) } -func (s *FlagSourcerSuite) TestDump(t sweet.T) { +func TestFlagSourcerDump(t *testing.T) { sourcer := NewFlagSourcer(WithFlagSourcerArgs([]string{"-X=foo", "--Y", "123"})) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) dump := sourcer.Dump() - Expect(dump["X"]).To(Equal("foo")) - Expect(dump["Y"]).To(Equal("123")) + assert.Equal(t, "foo", dump["X"]) + assert.Equal(t, "123", dump["Y"]) } diff --git a/flag_tag_prefixer.go b/flag_tag_prefixer.go index 13ed4c0..ce9a51b 100644 --- a/flag_tag_prefixer.go +++ b/flag_tag_prefixer.go @@ -11,6 +11,8 @@ type flagTagPrefixer struct { prefix string } +var _ TagModifier = &flagTagPrefixer{} + // NewFlagTagPrefixer creates a new TagModifier which adds a prefix to the // values of `flag` tags. func NewFlagTagPrefixer(prefix string) TagModifier { diff --git a/flag_tag_prefixer_test.go b/flag_tag_prefixer_test.go index 3e47d17..806550e 100644 --- a/flag_tag_prefixer_test.go +++ b/flag_tag_prefixer_test.go @@ -1,28 +1,31 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" -) + "testing" -type FlagTagPrefixerSuite struct{} + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) -func (s *FlagTagPrefixerSuite) TestEnvTagPrefixer(t sweet.T) { - obj, err := ApplyTagModifiers(&BasicConfig{}, NewEnvTagPrefixer("foo")) - Expect(err).To(BeNil()) +func TestFlagTagPrefixer(t *testing.T) { + type C1 struct { + X string `flag:"a" default:"q"` + Y string + } - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "foo_a", - "default": "q", - })) + obj, err := ApplyTagModifiers(&C1{}, NewFlagTagPrefixer("foo")) + require.Nil(t, err) + assert.Equal(t, map[string]string{"flag": "foo_a", "default": "q"}, gatherTags(obj, "X")) } -func (s *FlagTagPrefixerSuite) TestEnvTagPrefixerEmbedded(t sweet.T) { - obj, err := ApplyTagModifiers(&ParentConfig{}, NewEnvTagPrefixer("foo")) - Expect(err).To(BeNil()) +func TestFlagTagPrefixerEmbedded(t *testing.T) { + type C1 struct { + X string `flag:"a" default:"q"` + Y string + } + type C2 struct{ C1 } - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "foo_a", - "default": "q", - })) + obj, err := ApplyTagModifiers(&C2{}, NewFlagTagPrefixer("foo")) + require.Nil(t, err) + assert.Equal(t, map[string]string{"flag": "foo_a", "default": "q"}, gatherTags(obj, "X")) } diff --git a/flag_tag_setter.go b/flag_tag_setter.go index f60ddea..ac64194 100644 --- a/flag_tag_setter.go +++ b/flag_tag_setter.go @@ -8,6 +8,8 @@ import ( type flagTagSetter struct{} +var _ TagModifier = &flagTagSetter{} + // NewFlagTagSetter creates a new TagModifier which sets the value // of the flag tag to be the same as the env tag. func NewFlagTagSetter() TagModifier { diff --git a/flag_tag_setter_test.go b/flag_tag_setter_test.go index dcd97ea..afab514 100644 --- a/flag_tag_setter_test.go +++ b/flag_tag_setter_test.go @@ -1,42 +1,33 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" -) - -type FlagTagSetterSuite struct{} + "testing" -func (s *FlagTagSetterSuite) TestFlagTagSetter(t sweet.T) { - obj, err := ApplyTagModifiers( - &BasicConfig{}, - NewFlagTagSetter(), - ) - - Expect(err).To(BeNil()) + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "a", - "flag": "a", - "default": "q", - })) +func TestFlagTagSetter(t *testing.T) { + type C struct { + X string `env:"a" default:"q"` + Y string + } - Expect(gatherTags(obj, "Y")).To(Equal(map[string]string{})) + obj, err := ApplyTagModifiers(&C{}, NewFlagTagSetter()) + require.Nil(t, err) + assert.Equal(t, map[string]string{"env": "a", "flag": "a", "default": "q"}, gatherTags(obj, "X")) + assert.Equal(t, map[string]string{}, gatherTags(obj, "Y")) } -func (s *FlagTagSetterSuite) TestFlagTagSetterEmbedded(t sweet.T) { - obj, err := ApplyTagModifiers( - &ParentConfig{}, - NewFlagTagSetter(), - ) - - Expect(err).To(BeNil()) - - Expect(gatherTags(obj, "X")).To(Equal(map[string]string{ - "env": "a", - "flag": "a", - "default": "q", - })) - - Expect(gatherTags(obj, "Y")).To(Equal(map[string]string{})) +func TestFlagTagSetterEmbedded(t *testing.T) { + type C1 struct { + X string `env:"a" default:"q"` + Y string + } + type C2 struct{ C1 } + + obj, err := ApplyTagModifiers(&C2{}, NewFlagTagSetter()) + require.Nil(t, err) + assert.Equal(t, map[string]string{"env": "a", "flag": "a", "default": "q"}, gatherTags(obj, "X")) + assert.Equal(t, map[string]string{}, gatherTags(obj, "Y")) } diff --git a/fs.go b/fs.go index 926e809..e04d4af 100644 --- a/fs.go +++ b/fs.go @@ -7,30 +7,30 @@ import ( "github.com/mattn/go-zglob" ) -type ( - // FileSystem is an interface wrapping filesystem operations for - // sourcers that read information from disk. This is necessary in - // order to allow remote and in-memory filesystems that may be - // present in some application deployments. Third-party libraries - // such as spf13/afero that provide FS-like functionality can be - // shimmed into this interface. - FileSystem interface { - // Exists determines if the given path exists. - Exists(path string) (bool, error) - - // ListFiles returns the names of the files that are a direct - // child of the directory at the given path. - ListFiles(path string) ([]string, error) - - // Glob returns the paths that the given pattern matches. - Glob(pattern string) ([]string, error) - - // ReadFile returns the content of the file at the given path. - ReadFile(path string) ([]byte, error) - } +// FileSystem is an interface wrapping filesystem operations for +// sourcers that read information from disk. This is necessary in +// order to allow remote and in-memory filesystems that may be +// present in some application deployments. Third-party libraries +// such as spf13/afero that provide FS-like functionality can be +// shimmed into this interface. +type FileSystem interface { + // Exists determines if the given path exists. + Exists(path string) (bool, error) + + // ListFiles returns the names of the files that are a direct + // child of the directory at the given path. + ListFiles(path string) ([]string, error) + + // Glob returns the paths that the given pattern matches. + Glob(pattern string) ([]string, error) + + // ReadFile returns the content of the file at the given path. + ReadFile(path string) ([]byte, error) +} - realFileSystem struct{} -) +type realFileSystem struct{} + +var _ FileSystem = &realFileSystem{} func (fs *realFileSystem) Exists(path string) (bool, error) { if _, err := os.Stat(path); err != nil { diff --git a/fs_mock_test.go b/fs_mock_test.go index 3cd25db..96be48d 100644 --- a/fs_mock_test.go +++ b/fs_mock_test.go @@ -1,15 +1,11 @@ -// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. -// This file was generated by robots at -// 2020-04-01T15:32:17-05:00 -// using the command -// $ go-mockgen -f github.com/go-nacelle/config -i FileSystem -o fs_mock_test.go +// Code generated by go-mockgen 0.1.0; DO NOT EDIT. package config import "sync" -// MockFileSystem is a mock impelementation of the FileSystem interface -// (from the package github.com/go-nacelle/config) used for unit testing. +// MockFileSystem is a mock implementation of the FileSystem interface (from +// the package github.com/go-nacelle/config) used for unit testing. type MockFileSystem struct { // ExistsFunc is an instance of a mock function object controlling the // behavior of the method Exists. @@ -95,7 +91,7 @@ func (f *FileSystemExistsFunc) SetDefaultHook(hook func(string) (bool, error)) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Exists method of the parent MockFileSystem instance inovkes the hook at +// Exists method of the parent MockFileSystem instance invokes the hook at // the front of the queue and discards it. After the queue is empty, the // default hook function is invoked for any future action. func (f *FileSystemExistsFunc) PushHook(hook func(string) (bool, error)) { @@ -200,7 +196,7 @@ func (f *FileSystemGlobFunc) SetDefaultHook(hook func(string) ([]string, error)) } // PushHook adds a function to the end of hook queue. Each invocation of the -// Glob method of the parent MockFileSystem instance inovkes the hook at the +// Glob method of the parent MockFileSystem instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *FileSystemGlobFunc) PushHook(hook func(string) ([]string, error)) { @@ -306,7 +302,7 @@ func (f *FileSystemListFilesFunc) SetDefaultHook(hook func(string) ([]string, er } // PushHook adds a function to the end of hook queue. Each invocation of the -// ListFiles method of the parent MockFileSystem instance inovkes the hook +// ListFiles method of the parent MockFileSystem instance invokes the hook // at the front of the queue and discards it. After the queue is empty, the // default hook function is invoked for any future action. func (f *FileSystemListFilesFunc) PushHook(hook func(string) ([]string, error)) { @@ -412,7 +408,7 @@ func (f *FileSystemReadFileFunc) SetDefaultHook(hook func(string) ([]byte, error } // PushHook adds a function to the end of hook queue. Each invocation of the -// ReadFile method of the parent MockFileSystem instance inovkes the hook at +// ReadFile method of the parent MockFileSystem instance invokes the hook at // the front of the queue and discards it. After the queue is empty, the // default hook function is invoked for any future action. func (f *FileSystemReadFileFunc) PushHook(hook func(string) ([]byte, error)) { diff --git a/gen.go b/gen.go new file mode 100644 index 0000000..e529f4c --- /dev/null +++ b/gen.go @@ -0,0 +1,6 @@ +package config + +//go:generate go-mockgen -f github.com/go-nacelle/config -i Config -o config_mock_test.go +//go:generate go-mockgen -f github.com/go-nacelle/config -i Logger -o logger_mock_test.go +//go:generate go-mockgen -f github.com/go-nacelle/config -i Sourcer -o sourcer_mock_test.go +//go:generate go-mockgen -f github.com/go-nacelle/config -i FileSystem -o fs_mock_test.go diff --git a/glob_sourcer_options.go b/glob_sourcer_options.go index ce11030..5dab3bb 100644 --- a/glob_sourcer_options.go +++ b/glob_sourcer_options.go @@ -1,12 +1,12 @@ package config -type ( - globSourcerOptions struct{ fs FileSystem } +type globSourcerOptions struct { + fs FileSystem +} - // GlobSourcerConfigFunc is a function used to configure instances of - // glob sourcers. - GlobSourcerConfigFunc func(*globSourcerOptions) -) +// GlobSourcerConfigFunc is a function used to configure instances of +// glob sourcers. +type GlobSourcerConfigFunc func(*globSourcerOptions) // WithGlobSourcerFS sets the FileSystem instance. func WithGlobSourcerFS(fs FileSystem) GlobSourcerConfigFunc { diff --git a/glob_sourcer_test.go b/glob_sourcer_test.go index b9c9d85..53a58c6 100644 --- a/glob_sourcer_test.go +++ b/glob_sourcer_test.go @@ -1,24 +1,24 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/efritz/go-mockgen/matchers" - . "github.com/onsi/gomega" -) + "testing" -type GlobSourcerSuite struct{} + mockassert "github.com/derision-test/go-mockgen/testutil/assert" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) -func (s *GlobSourcerSuite) TestLoadJSON(t sweet.T) { +func TestGlobSourcerLoadJSON(t *testing.T) { sourcer := NewGlobSourcer("test-files/**/*.json", nil) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) - ensureEquals(sourcer, []string{"nested-x"}, "1") - ensureEquals(sourcer, []string{"nested-y"}, "2") - ensureEquals(sourcer, []string{"nested-z"}, "3") - ensureEquals(sourcer, []string{"nested-w"}, "4") + ensureEquals(t, sourcer, []string{"nested-x"}, "1") + ensureEquals(t, sourcer, []string{"nested-y"}, "2") + ensureEquals(t, sourcer, []string{"nested-z"}, "3") + ensureEquals(t, sourcer, []string{"nested-w"}, "4") } -func (s *GlobSourcerSuite) TestLoadJSONWithFakeFS(t sweet.T) { +func TestGlobSourcerLoadJSONWithFakeFS(t *testing.T) { fs := NewMockFileSystem() fs.GlobFunc.SetDefaultReturn([]string{ "test-files/dir/nested-a/x.json", @@ -33,22 +33,22 @@ func (s *GlobSourcerSuite) TestLoadJSONWithFakeFS(t sweet.T) { fs.ReadFileFunc.PushReturn([]byte(`{"nested-w": 4}`), nil) sourcer := NewGlobSourcer("test-files/**/*.json", nil, WithGlobSourcerFS(fs)) - Expect(sourcer.Init()).To(BeNil()) - - Expect(fs.GlobFunc).To(BeCalledOnceWith("test-files/**/*.json")) - Expect(fs.ReadFileFunc).To(BeCalledOnceWith("test-files/dir/nested-a/x.json")) - Expect(fs.ReadFileFunc).To(BeCalledOnceWith("test-files/dir/nested-b/y.json")) - Expect(fs.ReadFileFunc).To(BeCalledOnceWith("test-files/dir/nested-b/z.json")) - Expect(fs.ReadFileFunc).To(BeCalledOnceWith("test-files/dir/nested-b/nested-c/w.json")) - - ensureEquals(sourcer, []string{"nested-x"}, "1") - ensureEquals(sourcer, []string{"nested-y"}, "2") - ensureEquals(sourcer, []string{"nested-z"}, "3") - ensureEquals(sourcer, []string{"nested-w"}, "4") + require.Nil(t, sourcer.Init()) + + mockassert.CalledOnceWith(t, fs.GlobFunc, mockassert.Values("test-files/**/*.json")) + mockassert.CalledOnceWith(t, fs.ReadFileFunc, mockassert.Values("test-files/dir/nested-a/x.json")) + mockassert.CalledOnceWith(t, fs.ReadFileFunc, mockassert.Values("test-files/dir/nested-b/y.json")) + mockassert.CalledOnceWith(t, fs.ReadFileFunc, mockassert.Values("test-files/dir/nested-b/z.json")) + mockassert.CalledOnceWith(t, fs.ReadFileFunc, mockassert.Values("test-files/dir/nested-b/nested-c/w.json")) + + ensureEquals(t, sourcer, []string{"nested-x"}, "1") + ensureEquals(t, sourcer, []string{"nested-y"}, "2") + ensureEquals(t, sourcer, []string{"nested-z"}, "3") + ensureEquals(t, sourcer, []string{"nested-w"}, "4") } -func (s *GlobSourcerSuite) TestNoMatches(t sweet.T) { +func TestGlobSourcerNoMatches(t *testing.T) { sourcer := NewGlobSourcer("test-files/notexist/*.yaml", nil) - Expect(sourcer.Init()).To(BeNil()) - Expect(sourcer.Tags()).To(BeEmpty()) + require.Nil(t, sourcer.Init()) + assert.Empty(t, sourcer.Tags()) } diff --git a/go.mod b/go.mod index 0e49067..7f24536 100644 --- a/go.mod +++ b/go.mod @@ -1,17 +1,13 @@ module github.com/go-nacelle/config +go 1.15 + require ( github.com/BurntSushi/toml v0.3.1 - github.com/aphistic/sweet v0.2.0 - github.com/aphistic/sweet-junit v0.0.0-20190314030539-8d7e248096c2 - github.com/efritz/go-mockgen v0.0.0-20190613153341-3425cf558834 + github.com/derision-test/go-mockgen v0.0.0-20201001011750-eb2233de6342 github.com/fatih/structtag v1.0.0 github.com/ghodss/yaml v1.0.0 - github.com/golang/protobuf v1.3.2 // indirect - github.com/mattn/go-colorable v0.1.2 // indirect + github.com/kr/pretty v0.2.1 // indirect github.com/mattn/go-zglob v0.0.1 - github.com/onsi/gomega v1.5.0 - golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 // indirect - golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect - golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e // indirect + github.com/stretchr/testify v1.6.1 ) diff --git a/go.sum b/go.sum index cad1297..371a619 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,15 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/aphistic/sweet v0.0.0-20180618201346-68e18ab55a67 h1:enhUz4F+39zbOQsM0rVTfqdg+p8HCeNWpr+5bk4RTvY= -github.com/aphistic/sweet v0.0.0-20180618201346-68e18ab55a67/go.mod h1:iggGz3Cujwru5rGKuOi4u1rfI+38suzhVVJj8Ey7Q3M= -github.com/aphistic/sweet v0.2.0 h1:I4z+fAUqvKfvZV/CHi5dV0QuwbmIvYYFDjG0Ss5QpAs= -github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= -github.com/aphistic/sweet-junit v0.0.0-20190314030539-8d7e248096c2 h1:qDCG/a4+mCcRqj+QHTc1RNncar6rpg0oGz9ynH4IRME= -github.com/aphistic/sweet-junit v0.0.0-20190314030539-8d7e248096c2/go.mod h1:+eL69RqmiKF2Jm3poefxF/ZyVNGXFdSsPq3ScBFtX9s= -github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= -github.com/dave/jennifer v1.3.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/dave/jennifer v1.4.1/go.mod h1:7jEdnm+qBcxl8PC0zyp7vxcpSRnzXSt9r39tpTVGlwA= 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/derision-test/go-mockgen v0.0.0-20201001011750-eb2233de6342 h1:EyNcBkaw2jkJxYuCN+Aa1fTOohkjTRK9Ltapi1SWcFk= +github.com/derision-test/go-mockgen v0.0.0-20201001011750-eb2233de6342/go.mod h1:FGP9Qq+gWtYK9ine/2Bzeww8SXS7mD1wypNl1Q3AKN0= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/efritz/go-genlib v0.0.0-20190429143346-e1e478a98211/go.mod h1:zUniQY7pV7ciqIjXY8TyDHXaqHZJa3NQIiiYDycogYk= -github.com/efritz/go-mockgen v0.0.0-20190613153341-3425cf558834 h1:37JFXKsLttHkcvFFr4t68C21uInpCNAIvPeE7IYRXKA= -github.com/efritz/go-mockgen v0.0.0-20190613153341-3425cf558834/go.mod h1:2Ia+C4l9Ns2t8XwO8JVbJ6GUEL/Bwm4u1DAj7ApQdqE= github.com/fatih/structtag v1.0.0 h1:pTHj65+u3RKWYPSGaU290FpI/dXxTaHdVwVwbcPKmEc= github.com/fatih/structtag v1.0.0/go.mod h1:IKitwq45uXL/yqi5mYghiD3w9H6eTOvI9vnk8tXMphA= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= @@ -26,73 +18,83 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-zglob v0.0.1 h1:xsEx/XUoVlI6yXjqBK062zYhRTZltCNmYPx6v+8DNaY= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= +github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= 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/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190424112056-4829fb13d2c6/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e h1:o3PsSEY8E4eXWkXrIP9YJALUkVZqzHJT5DOasTyn8Vs= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190429094411-2cc0cad0ac78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e h1:D5TXcfTk7xF7hvieo4QErS3qqCB4teTffacDWr7CI+0= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190128232029-0a99049195af/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190428024724-550556f78a90/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200916225323-c537a342ddf6/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -100,7 +102,10 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helpers_test.go b/helpers_test.go new file mode 100644 index 0000000..4ca438b --- /dev/null +++ b/helpers_test.go @@ -0,0 +1,69 @@ +package config + +import ( + "reflect" + "testing" + + "github.com/fatih/structtag" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func ensureEquals(t *testing.T, sourcer Sourcer, values []string, expected string) { + val, flag, err := sourcer.Get(values) + require.Nil(t, err) + assert.Equal(t, FlagFound, flag) + assert.Equal(t, expected, val) +} + +func ensureMatches(t *testing.T, sourcer Sourcer, values []string, expected string) { + val, flag, err := sourcer.Get(values) + require.Nil(t, err) + assert.Equal(t, FlagFound, flag) + assert.JSONEq(t, expected, val) +} + +func ensureMissing(t *testing.T, sourcer Sourcer, values []string) { + _, flag, err := sourcer.Get(values) + require.Nil(t, err) + assert.Equal(t, FlagMissing, flag) +} + +func gatherTags(obj interface{}, name string) map[string]string { + objValue := reflect.Indirect(reflect.ValueOf(obj)) + objType := objValue.Type() + + return gatherTagsStruct(objValue, objType, name) +} + +func gatherTagsStruct(objValue reflect.Value, objType reflect.Type, name string) map[string]string { + for i := 0; i < objType.NumField(); i++ { + field := objValue.Field(i) + fieldType := objType.Field(i) + + if fieldType.Anonymous { + if tags := gatherTagsStruct(field, fieldType.Type, name); tags != nil { + return tags + } + } + + if fieldType.Name == name { + if tags, ok := getTags(fieldType); ok { + return decomposeTags(tags) + } + } + } + + return nil +} + +func decomposeTags(tags *structtag.Tags) map[string]string { + fieldTags := map[string]string{} + + for _, name := range tags.Keys() { + tag, _ := tags.Get(name) + fieldTags[name] = tag.Name + } + + return fieldTags +} diff --git a/json_test.go b/json_test.go index 3fa3047..c8c7e5f 100644 --- a/json_test.go +++ b/json_test.go @@ -1,37 +1,34 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" -) + "testing" -type JSONSuite struct{} + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) -func (s *JSONSuite) TestToJSONString(t sweet.T) { +func TestToJSONString(t *testing.T) { var val string - ok := toJSON([]byte("foobar"), &val) - Expect(ok).To(BeTrue()) - Expect(val).To(Equal("foobar")) + require.True(t, toJSON([]byte("foobar"), &val)) + assert.Equal(t, "foobar", val) } -func (s *JSONSuite) TestToJSONNonString(t sweet.T) { +func TestToJSONNonString(t *testing.T) { var val []int - ok := toJSON([]byte("[1, 2, 3, 4, 5]"), &val) - Expect(ok).To(BeTrue()) - Expect(val).To(Equal([]int{1, 2, 3, 4, 5})) + require.True(t, toJSON([]byte("[1, 2, 3, 4, 5]"), &val)) + assert.Equal(t, []int{1, 2, 3, 4, 5}, val) } -func (s *JSONSuite) TestToJSONBadType(t sweet.T) { +func TestToJSONBadType(t *testing.T) { var val []int - ok := toJSON([]byte(`[1, 2, "3", 4, 5]`), &val) - Expect(ok).To(BeFalse()) + assert.False(t, toJSON([]byte(`[1, 2, "3", 4, 5]`), &val)) } -func (s *JSONSuite) TestQuoteJSON(t sweet.T) { +func TestQuoteJSON(t *testing.T) { json := quoteJSON([]byte(` foo bar baz`)) - Expect(json).To(MatchJSON(`"\n\tfoo\n\tbar\n\tbaz"`)) + assert.JSONEq(t, `"\n\tfoo\n\tbar\n\tbaz"`, string(json)) } diff --git a/logger_mock_test.go b/logger_mock_test.go index 1fe7139..870b425 100644 --- a/logger_mock_test.go +++ b/logger_mock_test.go @@ -1,14 +1,10 @@ -// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. -// This file was generated by robots at -// 2020-04-01T15:32:14-05:00 -// using the command -// $ go-mockgen -f github.com/go-nacelle/config -i Logger -o logger_mock_test.go +// Code generated by go-mockgen 0.1.0; DO NOT EDIT. package config import "sync" -// MockLogger is a mock impelementation of the Logger interface (from the +// MockLogger is a mock implementation of the Logger interface (from the // package github.com/go-nacelle/config) used for unit testing. type MockLogger struct { // PrintfFunc is an instance of a mock function object controlling the @@ -62,7 +58,7 @@ func (f *LoggerPrintfFunc) SetDefaultHook(hook func(string, ...interface{})) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Printf method of the parent MockLogger instance inovkes the hook at the +// Printf method of the parent MockLogger instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *LoggerPrintfFunc) PushHook(hook func(string, ...interface{})) { diff --git a/logging_config.go b/logging_config.go index 65f3539..cc0e069 100644 --- a/logging_config.go +++ b/logging_config.go @@ -9,19 +9,17 @@ import ( "strings" ) -type ( - loggingConfig struct { - Config - logger Logger - maskedKeys []string - } +// Logger is an interface to the logger where config values are printed. +type Logger interface { + // Printf logs a message. Arguments should be handled in the manner of fmt.Printf. + Printf(format string, args ...interface{}) +} - // Logger is an interface to the logger where config values are printed. - Logger interface { - // Printf logs a message. Arguments should be handled in the manner of fmt.Printf. - Printf(format string, args ...interface{}) - } -) +type loggingConfig struct { + Config + logger Logger + maskedKeys []string +} // NewLoggingConfig wraps a config object with logging. After each successful load, // the populated configuration object is serialized as fields and output at the info @@ -88,13 +86,11 @@ func dumpChunk(obj interface{}) (map[string]interface{}, error) { m := map[string]interface{}{} for i := 0; i < objType.NumField(); i++ { - var ( - fieldType = objType.Field(i) - fieldValue = objValue.Field(i) - maskTagValue = fieldType.Tag.Get(MaskTag) - displayTagValue = fieldType.Tag.Get(DisplayTag) - displayName = fieldType.Name - ) + fieldType := objType.Field(i) + fieldValue := objValue.Field(i) + maskTagValue := fieldType.Tag.Get(MaskTag) + displayTagValue := fieldType.Tag.Get(DisplayTag) + displayName := fieldType.Name if displayTagValue != "" { displayName = displayTagValue diff --git a/logging_config_test.go b/logging_config_test.go index c5f13fa..b58ddf2 100644 --- a/logging_config_test.go +++ b/logging_config_test.go @@ -1,81 +1,84 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/efritz/go-mockgen/matchers" - . "github.com/onsi/gomega" + "testing" + + mockassert "github.com/derision-test/go-mockgen/testutil/assert" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) -type LoggingConfigSuite struct{} +func TestLoggingConfigLoadLogs(t *testing.T) { + type C struct { + X string `env:"x"` + Y int `env:"y"` + Z []string `env:"w" display:"Q"` + } -func (s *LoggingConfigSuite) TestLoadLogs(t sweet.T) { - var ( - config = NewMockConfig() - logger = NewMockLogger() - lc = NewLoggingConfig(config, logger, nil) - chunk = &TestSimpleConfig{} - ) + config := NewMockConfig() + logger := NewMockLogger() + lc := NewLoggingConfig(config, logger, nil) + chunk := &C{} config.LoadFunc.SetDefaultHook(func(target interface{}, modifiers ...TagModifier) error { - target.(*TestSimpleConfig).X = "foo" - target.(*TestSimpleConfig).Y = 123 - target.(*TestSimpleConfig).Z = []string{"bar", "baz", "bonk"} + target.(*C).X = "foo" + target.(*C).Y = 123 + target.(*C).Z = []string{"bar", "baz", "bonk"} return nil }) - Expect(lc.Load(chunk)).To(BeNil()) - Expect(logger.PrintfFunc).To(BeCalledOnceWith( - "Config loaded: %s", - "\nQ=[\"bar\",\"baz\",\"bonk\"]\nX=foo\nY=123", - )) + require.Nil(t, lc.Load(chunk)) + mockassert.CalledOnceWith(t, logger.PrintfFunc, mockassert.Values("Config loaded: %s", "\nQ=[\"bar\",\"baz\",\"bonk\"]\nX=foo\nY=123")) } -func (s *LoggingConfigSuite) TestMask(t sweet.T) { - var ( - config = NewMockConfig() - logger = NewMockLogger() - lc = NewLoggingConfig(config, logger, nil) - chunk = &TestMaskConfig{} - ) +func TestLoggingConfigMask(t *testing.T) { + type C struct { + X string `env:"x"` + Y int `env:"y" mask:"true"` + Z []string `env:"w" mask:"true"` + } + + config := NewMockConfig() + logger := NewMockLogger() + lc := NewLoggingConfig(config, logger, nil) + chunk := &C{} config.LoadFunc.SetDefaultHook(func(target interface{}, modifiers ...TagModifier) error { - target.(*TestMaskConfig).X = "foo" - target.(*TestMaskConfig).Y = 123 - target.(*TestMaskConfig).Z = []string{"bar", "baz", "bonk"} + target.(*C).X = "foo" + target.(*C).Y = 123 + target.(*C).Z = []string{"bar", "baz", "bonk"} return nil }) - Expect(lc.Load(chunk)).To(BeNil()) - Expect(logger.PrintfFunc).To(BeCalledOnceWith( - "Config loaded: %s", - "\nX=foo", - )) + require.Nil(t, lc.Load(chunk)) + mockassert.CalledOnceWith(t, logger.PrintfFunc, mockassert.Values("Config loaded: %s", "\nX=foo")) } -func (s *LoggingConfigSuite) TestBadMaskTag(t sweet.T) { - var ( - config = NewMockConfig() - logger = NewMockLogger() - lc = NewLoggingConfig(config, logger, nil) - chunk = &TestBadMaskTagConfig{} - ) - - Expect(lc.Load(chunk)).To(MatchError("" + - "failed to serialize config" + - " (" + - "field 'X' has an invalid mask tag" + - ")", - )) +func TestLoggingConfigBadMaskTag(t *testing.T) { + type C struct { + X string `env:"x" mask:"34"` + } + + config := NewMockConfig() + logger := NewMockLogger() + lc := NewLoggingConfig(config, logger, nil) + chunk := &C{} + + assert.EqualError(t, lc.Load(chunk), "failed to serialize config (field 'X' has an invalid mask tag)") } -func (s *LoggingConfigSuite) TestMustLoadLogs(t sweet.T) { - var ( - config = NewMockConfig() - logger = NewMockLogger() - lc = NewLoggingConfig(config, logger, nil) - chunk = &TestSimpleConfig{} - ) +func TestLoggingConfigMustLoadLogs(t *testing.T) { + type C struct { + X string `env:"x"` + Y int `env:"y"` + Z []string `env:"w" display:"Q"` + } + + config := NewMockConfig() + logger := NewMockLogger() + lc := NewLoggingConfig(config, logger, nil) + chunk := &C{} lc.MustLoad(chunk) - Expect(logger.PrintfFunc).To(BeCalledOnce()) + mockassert.CalledOnce(t, logger.PrintfFunc) } diff --git a/main_test.go b/main_test.go index 5e0fa31..bd061c9 100644 --- a/main_test.go +++ b/main_test.go @@ -1,108 +1,11 @@ package config -//go:generate go-mockgen -f github.com/go-nacelle/config -i Config -o config_mock_test.go -//go:generate go-mockgen -f github.com/go-nacelle/config -i Logger -o logger_mock_test.go -//go:generate go-mockgen -f github.com/go-nacelle/config -i Sourcer -o sourcer_mock_test.go -//go:generate go-mockgen -f github.com/go-nacelle/config -i FileSystem -o fs_mock_test.go - import ( - "reflect" + "os" "testing" - - "github.com/aphistic/sweet" - junit "github.com/aphistic/sweet-junit" - "github.com/fatih/structtag" - . "github.com/onsi/gomega" ) func TestMain(m *testing.M) { - RegisterFailHandler(sweet.GomegaFail) - - sweet.Run(m, func(s *sweet.S) { - s.RegisterPlugin(junit.NewPlugin()) - - s.AddSuite(&ConfigSuite{}) - s.AddSuite(&DefaultTagSetterSuite{}) - s.AddSuite(&DirectorySourcerSuite{}) - s.AddSuite(&DisplayTagSetterSuite{}) - s.AddSuite(&EnvSourcerSuite{}) - s.AddSuite(&EnvTagPrefixerSuite{}) - s.AddSuite(&FlagSourcerSuite{}) - s.AddSuite(&FlagTagPrefixerSuite{}) - s.AddSuite(&FlagTagSetterSuite{}) - s.AddSuite(&FileSourcerSuite{}) - s.AddSuite(&FileTagPrefixerSuite{}) - s.AddSuite(&FileTagSetterSuite{}) - s.AddSuite(&GlobSourcerSuite{}) - s.AddSuite(&JSONSuite{}) - s.AddSuite(&LoggingConfigSuite{}) - s.AddSuite(&MultiSourcerSuite{}) - s.AddSuite(&TestEnvSourcerSuite{}) - }) -} - -// -// - -func ensureEquals(sourcer Sourcer, values []string, expected string) { - val, flag, err := sourcer.Get(values) - Expect(err).To(BeNil()) - Expect(flag).To(Equal(FlagFound)) - Expect(val).To(Equal(expected)) -} - -func ensureMatches(sourcer Sourcer, values []string, expected string) { - val, flag, err := sourcer.Get(values) - Expect(err).To(BeNil()) - Expect(flag).To(Equal(FlagFound)) - Expect(val).To(MatchJSON(expected)) -} - -func ensureMissing(sourcer Sourcer, values []string) { - _, flag, err := sourcer.Get(values) - Expect(err).To(BeNil()) - Expect(flag).To(Equal(FlagMissing)) -} - -func gatherTags(obj interface{}, name string) map[string]string { - var ( - objValue = reflect.Indirect(reflect.ValueOf(obj)) - objType = objValue.Type() - ) - - return gatherTagsStruct(objValue, objType, name) -} - -func gatherTagsStruct(objValue reflect.Value, objType reflect.Type, name string) map[string]string { - for i := 0; i < objType.NumField(); i++ { - var ( - field = objValue.Field(i) - fieldType = objType.Field(i) - ) - - if fieldType.Anonymous { - if tags := gatherTagsStruct(field, fieldType.Type, name); tags != nil { - return tags - } - } - - if fieldType.Name == name { - if tags, ok := getTags(fieldType); ok { - return decomposeTags(tags) - } - } - } - - return nil -} - -func decomposeTags(tags *structtag.Tags) map[string]string { - fieldTags := map[string]string{} - - for _, name := range tags.Keys() { - tag, _ := tags.Get(name) - fieldTags[name] = tag.Name - } - - return fieldTags + os.Clearenv() + os.Exit(m.Run()) } diff --git a/mocks/config.go b/mocks/config.go index 8002bd7..a7a972e 100644 --- a/mocks/config.go +++ b/mocks/config.go @@ -1,8 +1,4 @@ -// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. -// This file was generated by robots at -// 2020-04-01T15:32:18-05:00 -// using the command -// $ go-mockgen -f github.com/go-nacelle/config -i Config -o config.go +// Code generated by go-mockgen 0.1.0; DO NOT EDIT. package mocks @@ -11,7 +7,7 @@ import ( "sync" ) -// MockConfig is a mock impelementation of the Config interface (from the +// MockConfig is a mock implementation of the Config interface (from the // package github.com/go-nacelle/config) used for unit testing. type MockConfig struct { // AssetsFunc is an instance of a mock function object controlling the @@ -109,7 +105,7 @@ func (f *ConfigAssetsFunc) SetDefaultHook(hook func() []string) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Assets method of the parent MockConfig instance inovkes the hook at the +// Assets method of the parent MockConfig instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *ConfigAssetsFunc) PushHook(hook func() []string) { @@ -208,7 +204,7 @@ func (f *ConfigDumpFunc) SetDefaultHook(hook func() map[string]string) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Dump method of the parent MockConfig instance inovkes the hook at the +// Dump method of the parent MockConfig instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *ConfigDumpFunc) PushHook(hook func() map[string]string) { @@ -307,7 +303,7 @@ func (f *ConfigInitFunc) SetDefaultHook(hook func() error) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Init method of the parent MockConfig instance inovkes the hook at the +// Init method of the parent MockConfig instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *ConfigInitFunc) PushHook(hook func() error) { @@ -406,7 +402,7 @@ func (f *ConfigLoadFunc) SetDefaultHook(hook func(interface{}, ...config.TagModi } // PushHook adds a function to the end of hook queue. Each invocation of the -// Load method of the parent MockConfig instance inovkes the hook at the +// Load method of the parent MockConfig instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *ConfigLoadFunc) PushHook(hook func(interface{}, ...config.TagModifier) error) { @@ -518,7 +514,7 @@ func (f *ConfigMustLoadFunc) SetDefaultHook(hook func(interface{}, ...config.Tag } // PushHook adds a function to the end of hook queue. Each invocation of the -// MustLoad method of the parent MockConfig instance inovkes the hook at the +// MustLoad method of the parent MockConfig instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *ConfigMustLoadFunc) PushHook(hook func(interface{}, ...config.TagModifier)) { diff --git a/mocks/generator.go b/mocks/gen.go similarity index 100% rename from mocks/generator.go rename to mocks/gen.go diff --git a/mocks/logger.go b/mocks/logger.go index 442b7a2..d9fed5d 100644 --- a/mocks/logger.go +++ b/mocks/logger.go @@ -1,8 +1,4 @@ -// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. -// This file was generated by robots at -// 2020-04-01T15:32:19-05:00 -// using the command -// $ go-mockgen -f github.com/go-nacelle/config -i Logger -o logger.go +// Code generated by go-mockgen 0.1.0; DO NOT EDIT. package mocks @@ -11,7 +7,7 @@ import ( "sync" ) -// MockLogger is a mock impelementation of the Logger interface (from the +// MockLogger is a mock implementation of the Logger interface (from the // package github.com/go-nacelle/config) used for unit testing. type MockLogger struct { // PrintfFunc is an instance of a mock function object controlling the @@ -65,7 +61,7 @@ func (f *LoggerPrintfFunc) SetDefaultHook(hook func(string, ...interface{})) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Printf method of the parent MockLogger instance inovkes the hook at the +// Printf method of the parent MockLogger instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *LoggerPrintfFunc) PushHook(hook func(string, ...interface{})) { diff --git a/mocks/sourcer.go b/mocks/sourcer.go index 4b20b92..6908e10 100644 --- a/mocks/sourcer.go +++ b/mocks/sourcer.go @@ -1,8 +1,4 @@ -// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. -// This file was generated by robots at -// 2020-04-01T15:32:20-05:00 -// using the command -// $ go-mockgen -f github.com/go-nacelle/config -i Sourcer -o sourcer.go +// Code generated by go-mockgen 0.1.0; DO NOT EDIT. package mocks @@ -11,7 +7,7 @@ import ( "sync" ) -// MockSourcer is a mock impelementation of the Sourcer interface (from the +// MockSourcer is a mock implementation of the Sourcer interface (from the // package github.com/go-nacelle/config) used for unit testing. type MockSourcer struct { // AssetsFunc is an instance of a mock function object controlling the @@ -109,7 +105,7 @@ func (f *SourcerAssetsFunc) SetDefaultHook(hook func() []string) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Assets method of the parent MockSourcer instance inovkes the hook at the +// Assets method of the parent MockSourcer instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *SourcerAssetsFunc) PushHook(hook func() []string) { @@ -208,7 +204,7 @@ func (f *SourcerDumpFunc) SetDefaultHook(hook func() map[string]string) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Dump method of the parent MockSourcer instance inovkes the hook at the +// Dump method of the parent MockSourcer instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *SourcerDumpFunc) PushHook(hook func() map[string]string) { @@ -307,7 +303,7 @@ func (f *SourcerGetFunc) SetDefaultHook(hook func([]string) (string, config.Sour } // PushHook adds a function to the end of hook queue. Each invocation of the -// Get method of the parent MockSourcer instance inovkes the hook at the +// Get method of the parent MockSourcer instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *SourcerGetFunc) PushHook(hook func([]string) (string, config.SourcerFlag, error)) { @@ -415,7 +411,7 @@ func (f *SourcerInitFunc) SetDefaultHook(hook func() error) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Init method of the parent MockSourcer instance inovkes the hook at the +// Init method of the parent MockSourcer instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *SourcerInitFunc) PushHook(hook func() error) { @@ -514,7 +510,7 @@ func (f *SourcerTagsFunc) SetDefaultHook(hook func() []string) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Tags method of the parent MockSourcer instance inovkes the hook at the +// Tags method of the parent MockSourcer instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *SourcerTagsFunc) PushHook(hook func() []string) { diff --git a/mocks/tag_modifier.go b/mocks/tag_modifier.go index 79e543d..c00c1c7 100644 --- a/mocks/tag_modifier.go +++ b/mocks/tag_modifier.go @@ -1,8 +1,4 @@ -// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. -// This file was generated by robots at -// 2020-04-01T15:32:21-05:00 -// using the command -// $ go-mockgen -f github.com/go-nacelle/config -i TagModifier -o tag_modifier.go +// Code generated by go-mockgen 0.1.0; DO NOT EDIT. package mocks @@ -13,7 +9,7 @@ import ( "sync" ) -// MockTagModifier is a mock impelementation of the TagModifier interface +// MockTagModifier is a mock implementation of the TagModifier interface // (from the package github.com/go-nacelle/config) used for unit testing. type MockTagModifier struct { // AlterFieldTagFunc is an instance of a mock function object @@ -69,7 +65,7 @@ func (f *TagModifierAlterFieldTagFunc) SetDefaultHook(hook func(reflect.StructFi } // PushHook adds a function to the end of hook queue. Each invocation of the -// AlterFieldTag method of the parent MockTagModifier instance inovkes the +// AlterFieldTag method of the parent MockTagModifier instance invokes the // hook at the front of the queue and discards it. After the queue is empty, // the default hook function is invoked for any future action. func (f *TagModifierAlterFieldTagFunc) PushHook(hook func(reflect.StructField, *structtag.Tags) error) { diff --git a/multi_sourcer_test.go b/multi_sourcer_test.go index f7dcd5f..16a92a9 100644 --- a/multi_sourcer_test.go +++ b/multi_sourcer_test.go @@ -1,14 +1,15 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/efritz/go-mockgen/matchers" - . "github.com/onsi/gomega" -) + "sort" + "testing" -type MultiSourcerSuite struct{} + mockassert "github.com/derision-test/go-mockgen/testutil/assert" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) -func (s *MultiSourcerSuite) TestMultiSourcerBasic(t sweet.T) { +func TestMultiSourcerBasic(t *testing.T) { s1 := NewMockSourcer() s2 := NewMockSourcer() s1.TagsFunc.SetDefaultReturn([]string{"env"}) @@ -31,14 +32,14 @@ func (s *MultiSourcerSuite) TestMultiSourcerBasic(t sweet.T) { }) sourcer := NewMultiSourcer(s2, s1) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) - ensureEquals(sourcer, []string{"foo"}, "bar") - ensureEquals(sourcer, []string{"bar"}, "baz") - ensureMissing(sourcer, []string{"baz"}) + ensureEquals(t, sourcer, []string{"foo"}, "bar") + ensureEquals(t, sourcer, []string{"bar"}, "baz") + ensureMissing(t, sourcer, []string{"baz"}) } -func (s *MultiSourcerSuite) TestMultiSourcerPriority(t sweet.T) { +func TestMultiSourcerPriority(t *testing.T) { s1 := NewMockSourcer() s2 := NewMockSourcer() s1.TagsFunc.SetDefaultReturn([]string{"env"}) @@ -47,11 +48,11 @@ func (s *MultiSourcerSuite) TestMultiSourcerPriority(t sweet.T) { s2.GetFunc.SetDefaultReturn("baz", FlagFound, nil) sourcer := NewMultiSourcer(s2, s1) - Expect(sourcer.Init()).To(BeNil()) - ensureEquals(sourcer, []string{"foo"}, "bar") + require.Nil(t, sourcer.Init()) + ensureEquals(t, sourcer, []string{"foo"}, "bar") } -func (s *MultiSourcerSuite) TestMultiSourcerTags(t sweet.T) { +func TestMultiSourcerTags(t *testing.T) { s1 := NewMockSourcer() s2 := NewMockSourcer() s3 := NewMockSourcer() @@ -64,14 +65,14 @@ func (s *MultiSourcerSuite) TestMultiSourcerTags(t sweet.T) { s5.TagsFunc.SetDefaultReturn([]string{"e"}) sourcer := NewMultiSourcer(s5, s4, s3, s2, s1) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) tags := sourcer.Tags() - Expect(tags).To(HaveLen(5)) - Expect(tags).To(ConsistOf("a", "b", "c", "d", "e")) + sort.Strings(tags) + assert.Equal(t, []string{"a", "b", "c", "d", "e"}, tags) } -func (s *MultiSourcerSuite) TestMultiSourcerDifferentTags(t sweet.T) { +func TestMultiSourcerDifferentTags(t *testing.T) { s1 := NewMockSourcer() s2 := NewMockSourcer() s3 := NewMockSourcer() @@ -83,17 +84,18 @@ func (s *MultiSourcerSuite) TestMultiSourcerDifferentTags(t sweet.T) { s3.GetFunc.SetDefaultReturn("", FlagMissing, nil) sourcer := NewMultiSourcer(s3, s2, s1) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) _, flag, err := sourcer.Get([]string{"foo", "bar"}) - Expect(err).To(BeNil()) - Expect(flag).To(Equal(FlagMissing)) - Expect(s1.GetFunc).To(BeCalledOnceWith([]string{"foo"})) - Expect(s2.GetFunc).To(BeCalledOnceWith([]string{"bar"})) - Expect(s3.GetFunc).To(BeCalledOnceWith([]string{"foo"})) + require.Nil(t, err) + assert.Equal(t, FlagMissing, flag) + + mockassert.CalledOnceWith(t, s1.GetFunc, mockassert.Values([]string{"foo"})) + mockassert.CalledOnceWith(t, s2.GetFunc, mockassert.Values([]string{"bar"})) + mockassert.CalledOnceWith(t, s3.GetFunc, mockassert.Values([]string{"foo"})) } -func (s *MultiSourcerSuite) TestMultiSourceSkip(t sweet.T) { +func TestMultiSourcerSkip(t *testing.T) { s1 := NewMockSourcer() s2 := NewMockSourcer() s3 := NewMockSourcer() @@ -106,14 +108,14 @@ func (s *MultiSourcerSuite) TestMultiSourceSkip(t sweet.T) { s3.GetFunc.SetDefaultReturn("", FlagSkip, nil) sourcer := NewMultiSourcer(s3, s2, s1) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) _, flag, err := sourcer.Get([]string{"", ""}) - Expect(err).To(BeNil()) - Expect(flag).To(Equal(FlagSkip)) + require.Nil(t, err) + assert.Equal(t, FlagSkip, flag) } -func (s *MultiSourcerSuite) TestDump(t sweet.T) { +func TestMultiSourcerDump(t *testing.T) { s1 := NewMockSourcer() s2 := NewMockSourcer() s3 := NewMockSourcer() @@ -122,11 +124,12 @@ func (s *MultiSourcerSuite) TestDump(t sweet.T) { s3.DumpFunc.SetDefaultReturn(map[string]string{"c": "baz"}) sourcer := NewMultiSourcer(s3, s2, s1) - Expect(sourcer.Init()).To(BeNil()) - - Expect(sourcer.Dump()).To(Equal(map[string]string{ + expected := map[string]string{ "a": "bonk", "b": "bar", "c": "baz", - })) + } + + require.Nil(t, sourcer.Init()) + assert.Equal(t, expected, sourcer.Dump()) } diff --git a/reflect.go b/reflect.go index 42513ae..3c50c44 100644 --- a/reflect.go +++ b/reflect.go @@ -28,10 +28,8 @@ func getExportedFieldsStruct(objValue reflect.Value, objType reflect.Type) ([]*R fields := []*ReflectField{} for i := 0; i < objType.NumField(); i++ { - var ( - field = objValue.Field(i) - fieldType = objType.Field(i) - ) + field := objValue.Field(i) + fieldType := objType.Field(i) if fieldType.Anonymous { embeddedFields, err := getExportedFieldsStruct(field, fieldType.Type) diff --git a/sourcer.go b/sourcer.go index 48804be..4602f93 100644 --- a/sourcer.go +++ b/sourcer.go @@ -1,40 +1,38 @@ package config -type ( - // Sourcer pulls requested names from a variable source. This can be the - // environment, a file, a remote server, etc. This can be done on-demand - // per variable, or a cache of variables can be built on startup and then - // pulled from a cached mapping as requested. - Sourcer interface { - // Init is a hook for certain classes of sourcers to read and normalize - // the source data. This gives a canonical place where external errors - // can occur that are not directly related to validation. - Init() error +// Sourcer pulls requested names from a variable source. This can be the +// environment, a file, a remote server, etc. This can be done on-demand +// per variable, or a cache of variables can be built on startup and then +// pulled from a cached mapping as requested. +type Sourcer interface { + // Init is a hook for certain classes of sourcers to read and normalize + // the source data. This gives a canonical place where external errors + // can occur that are not directly related to validation. + Init() error - // Tags returns a list of tags which are required to get a value from - // the source. Order matters. - Tags() []string + // Tags returns a list of tags which are required to get a value from + // the source. Order matters. + Tags() []string - // Get will retrieve a value from the source with the given tag values. - // The tag values passed to this method will be in the same order as - // returned from the Tags method. The flag return value directs config - // population whether or not this value should be treated as missing or - // skippable. - Get(values []string) (string, SourcerFlag, error) + // Get will retrieve a value from the source with the given tag values. + // The tag values passed to this method will be in the same order as + // returned from the Tags method. The flag return value directs config + // population whether or not this value should be treated as missing or + // skippable. + Get(values []string) (string, SourcerFlag, error) - // Assets returns a list of names of assets that compose the sourcer. - // This can be a list of matched files that are read, or a token that - // denotes a fixed source. - Assets() []string + // Assets returns a list of names of assets that compose the sourcer. + // This can be a list of matched files that are read, or a token that + // denotes a fixed source. + Assets() []string - // Dump returns the full content of the sourcer. This is used by the - // logging package to show the content of the environment and config - // files when a value is missing or otherwise illegal. - Dump() map[string]string - } + // Dump returns the full content of the sourcer. This is used by the + // logging package to show the content of the environment and config + // files when a value is missing or otherwise illegal. + Dump() map[string]string +} - SourcerFlag int -) +type SourcerFlag int const ( FlagUnknown SourcerFlag = iota diff --git a/sourcer_mock_test.go b/sourcer_mock_test.go index 93c1564..b9ca817 100644 --- a/sourcer_mock_test.go +++ b/sourcer_mock_test.go @@ -1,14 +1,10 @@ -// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. -// This file was generated by robots at -// 2020-04-01T15:32:15-05:00 -// using the command -// $ go-mockgen -f github.com/go-nacelle/config -i Sourcer -o sourcer_mock_test.go +// Code generated by go-mockgen 0.1.0; DO NOT EDIT. package config import "sync" -// MockSourcer is a mock impelementation of the Sourcer interface (from the +// MockSourcer is a mock implementation of the Sourcer interface (from the // package github.com/go-nacelle/config) used for unit testing. type MockSourcer struct { // AssetsFunc is an instance of a mock function object controlling the @@ -106,7 +102,7 @@ func (f *SourcerAssetsFunc) SetDefaultHook(hook func() []string) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Assets method of the parent MockSourcer instance inovkes the hook at the +// Assets method of the parent MockSourcer instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *SourcerAssetsFunc) PushHook(hook func() []string) { @@ -205,7 +201,7 @@ func (f *SourcerDumpFunc) SetDefaultHook(hook func() map[string]string) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Dump method of the parent MockSourcer instance inovkes the hook at the +// Dump method of the parent MockSourcer instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *SourcerDumpFunc) PushHook(hook func() map[string]string) { @@ -304,7 +300,7 @@ func (f *SourcerGetFunc) SetDefaultHook(hook func([]string) (string, SourcerFlag } // PushHook adds a function to the end of hook queue. Each invocation of the -// Get method of the parent MockSourcer instance inovkes the hook at the +// Get method of the parent MockSourcer instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *SourcerGetFunc) PushHook(hook func([]string) (string, SourcerFlag, error)) { @@ -412,7 +408,7 @@ func (f *SourcerInitFunc) SetDefaultHook(hook func() error) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Init method of the parent MockSourcer instance inovkes the hook at the +// Init method of the parent MockSourcer instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *SourcerInitFunc) PushHook(hook func() error) { @@ -511,7 +507,7 @@ func (f *SourcerTagsFunc) SetDefaultHook(hook func() []string) { } // PushHook adds a function to the end of hook queue. Each invocation of the -// Tags method of the parent MockSourcer instance inovkes the hook at the +// Tags method of the parent MockSourcer instance invokes the hook at the // front of the queue and discards it. After the queue is empty, the default // hook function is invoked for any future action. func (f *SourcerTagsFunc) PushHook(hook func() []string) { diff --git a/tag_modifier.go b/tag_modifier.go index 11a470f..aff7e1d 100644 --- a/tag_modifier.go +++ b/tag_modifier.go @@ -21,13 +21,7 @@ type TagModifier interface { // ApplyTagModifiers returns a new struct with a dynamic type whose fields // are equivalent to the given object but whose field tags are run through // each tag modifier in sequence. -func ApplyTagModifiers( - obj interface{}, - modifiers ...TagModifier, -) ( - modified interface{}, - err error, -) { +func ApplyTagModifiers(obj interface{}, modifiers ...TagModifier) (modified interface{}, err error) { modified = obj for _, modifier := range modifiers { modified, err = apply(modified, modifier) diff --git a/test_env_sourcer_test.go b/test_env_sourcer_test.go index 2a98991..a756253 100644 --- a/test_env_sourcer_test.go +++ b/test_env_sourcer_test.go @@ -1,52 +1,52 @@ package config import ( - "github.com/aphistic/sweet" - . "github.com/onsi/gomega" -) + "testing" -type TestEnvSourcerSuite struct{} + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) -func (s *TestEnvSourcerSuite) TestUnprefixed(t sweet.T) { +func TestTestEnvSourcerUnprefixed(t *testing.T) { values := map[string]string{ "X": "foo", "Y": "123", } sourcer := NewTestEnvSourcer(values) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) val1, _, _ := sourcer.Get([]string{"X"}) val2, _, _ := sourcer.Get([]string{"Y"}) - Expect(val1).To(Equal("foo")) - Expect(val2).To(Equal("123")) + assert.Equal(t, "foo", val1) + assert.Equal(t, "123", val2) } -func (s *TestEnvSourcerSuite) TestNormalizedCasing(t sweet.T) { +func TestTestEnvSourcerNormalizedCasing(t *testing.T) { values := map[string]string{ "x": "foo", "y": "123", } sourcer := NewTestEnvSourcer(values) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) val1, _, _ := sourcer.Get([]string{"X"}) val2, _, _ := sourcer.Get([]string{"y"}) - Expect(val1).To(Equal("foo")) - Expect(val2).To(Equal("123")) + assert.Equal(t, "foo", val1) + assert.Equal(t, "123", val2) } -func (s *TestEnvSourcerSuite) TestDump(t sweet.T) { +func TestTestEnvSourcerDump(t *testing.T) { values := map[string]string{ "X": "foo", "Y": "123", } sourcer := NewTestEnvSourcer(values) - Expect(sourcer.Init()).To(BeNil()) + require.Nil(t, sourcer.Init()) dump := sourcer.Dump() - Expect(dump["X"]).To(Equal("foo")) - Expect(dump["Y"]).To(Equal("123")) + assert.Equal(t, "foo", dump["X"]) + assert.Equal(t, "123", dump["Y"]) } diff --git a/test_fixtures.go b/test_fixtures.go deleted file mode 100644 index 2d49b4d..0000000 --- a/test_fixtures.go +++ /dev/null @@ -1,122 +0,0 @@ -package config - -import ( - "fmt" - "time" -) - -type ( - TestSimpleConfig struct { - X string `env:"x"` - Y int `env:"y"` - Z []string `env:"w" display:"Q"` - } - - TestEmbeddedJSONConfig struct { - P1 *TestJSONPayload `env:"p1"` - P2 *TestJSONPayload `env:"p2"` - } - - TestJSONPayload struct { - V1 int `json:"v_int"` - V2 float64 `json:"v_float"` - V3 bool `json:"v_bool"` - } - - TestRequiredConfig struct { - X string `env:"x" required:"true"` - } - - TestBadRequiredConfig struct { - X string `env:"x" required:"yup"` - } - - TestDefaultConfig struct { - X string `env:"x" default:"foo"` - Y []string `env:"y" default:"[\"bar\", \"baz\", \"bonk\"]"` - } - - TestBadDefaultConfig struct { - X int `env:"x" default:"foo"` - } - - TestUnsettableConfig struct { - x int `env:"s"` - } - - TestPostLoadConfig struct { - X int `env:"X"` - } - - TestPostLoadConversion struct { - RawDuration int `env:"duration"` - Duration time.Duration - } - - TestMaskConfig struct { - X string `env:"x"` - Y int `env:"y" mask:"true"` - Z []string `env:"w" mask:"true"` - } - - TestBadMaskTagConfig struct { - X string `env:"x" mask:"34"` - } - - TestParentConfig struct { - ChildConfig - X int `env:"x"` - Y int `env:"y"` - } - - ChildConfig struct { - A int `env:"a"` - B int `env:"b"` - C int `env:"c"` - } - - TestBadParentConfig struct { - *ChildConfig - X int `env:"x"` - Y int `env:"y"` - } - - BasicConfig struct { - X string `env:"a" default:"q"` - Y string - } - - ParentConfig struct { - BasicConfig - } -) - -func (c *TestPostLoadConfig) PostLoad() error { - if c.X < 0 { - return fmt.Errorf("X must be positive") - } - - return nil -} - -func (c *TestPostLoadConversion) PostLoad() error { - c.Duration = time.Duration(c.RawDuration) * time.Second - return nil -} - -func (c *ChildConfig) PostLoad() error { - if c.A >= c.B || c.B >= c.C { - return fmt.Errorf("fields must be increasing") - } - - return nil -} - -// -// Helpers - -type TestStringer struct{} - -func (TestStringer) String() string { - return "bar" -}