diff --git a/env/env.go b/env/env.go index 6d6481d..70eba50 100644 --- a/env/env.go +++ b/env/env.go @@ -10,6 +10,7 @@ import "os" // Reader defines an interface for environment variable access type Reader interface { Getenv(key string) string + LookupEnv(key string) (string, bool) } // OSReader implements Reader using the standard os package @@ -19,3 +20,8 @@ type OSReader struct{} func (*OSReader) Getenv(key string) string { return os.Getenv(key) } + +// LookupEnv returns the value of the environment variable named by the key +func (*OSReader) LookupEnv(key string) (string, bool) { + return os.LookupEnv(key) +} diff --git a/env/env_test.go b/env/env_test.go index ce21916..c2cf0bb 100644 --- a/env/env_test.go +++ b/env/env_test.go @@ -59,6 +59,65 @@ func TestOSReader_Getenv(t *testing.T) { //nolint:paralleltest // Modifies envir } } +func TestOSReader_LookupEnv(t *testing.T) { //nolint:paralleltest // Modifies environment variables + testKey := "TEST_LOOKUP_ENV_VARIABLE_FOR_TESTING" + testValue := "lookup_test_value_123" + + originalValue, wasSet := os.LookupEnv(testKey) + t.Cleanup(func() { + if wasSet { + os.Setenv(testKey, originalValue) + } else { + os.Unsetenv(testKey) + } + }) + + reader := &OSReader{} + + tests := []struct { + name string + setup func() + key string + wantVal string + wantFound bool + }{ + { + name: "existing variable returns value and true", + setup: func() { os.Setenv(testKey, testValue) }, + key: testKey, + wantVal: testValue, + wantFound: true, + }, + { + name: "variable set to empty string returns empty and true", + setup: func() { os.Setenv(testKey, "") }, + key: testKey, + wantVal: "", + wantFound: true, + }, + { + name: "absent variable returns empty and false", + setup: func() { os.Unsetenv(testKey) }, + key: testKey, + wantVal: "", + wantFound: false, + }, + } + + for _, tt := range tests { //nolint:paralleltest // Test modifies environment variables + t.Run(tt.name, func(t *testing.T) { + tt.setup() + gotVal, gotFound := reader.LookupEnv(tt.key) + if gotVal != tt.wantVal { + t.Errorf("OSReader.LookupEnv() val = %q, want %q", gotVal, tt.wantVal) + } + if gotFound != tt.wantFound { + t.Errorf("OSReader.LookupEnv() found = %v, want %v", gotFound, tt.wantFound) + } + }) + } +} + // TestReader_InterfaceCompliance ensures OSReader implements the Reader interface func TestReader_InterfaceCompliance(t *testing.T) { t.Parallel() diff --git a/env/mocks/mock_reader.go b/env/mocks/mock_reader.go index 17358bb..3bc8c50 100644 --- a/env/mocks/mock_reader.go +++ b/env/mocks/mock_reader.go @@ -56,3 +56,18 @@ func (mr *MockReaderMockRecorder) Getenv(key any) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Getenv", reflect.TypeOf((*MockReader)(nil).Getenv), key) } + +// LookupEnv mocks base method. +func (m *MockReader) LookupEnv(key string) (string, bool) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LookupEnv", key) + ret0, _ := ret[0].(string) + ret1, _ := ret[1].(bool) + return ret0, ret1 +} + +// LookupEnv indicates an expected call of LookupEnv. +func (mr *MockReaderMockRecorder) LookupEnv(key any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LookupEnv", reflect.TypeOf((*MockReader)(nil).LookupEnv), key) +}