// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package watch import ( "errors" "testing" "github.com/stretchr/testify/require" ) func TestMap(t *testing.T) { m := NewMap[string, testVal]() // Set without init is a no-op { m.Set("hello", "world") require.Equal(t, 0, m.Len()) } // Getting from empty map { got, ok := m.Get("hello") require.False(t, ok) require.Empty(t, got) } var called bool cancelMock := func() { called = true } // InitWatch successful { m.InitWatch("hello", cancelMock) require.Equal(t, 1, m.Len()) } // Get still returns false { got, ok := m.Get("hello") require.False(t, ok) require.Empty(t, got) } // Set successful { require.True(t, m.Set("hello", "world")) require.Equal(t, 1, m.Len()) } // Get successful { got, ok := m.Get("hello") require.True(t, ok) require.Equal(t, "world", string(got)) } // CancelWatch successful { m.CancelWatch("hello") require.Equal(t, 0, m.Len()) require.True(t, called) } // Get no-op { got, ok := m.Get("hello") require.False(t, ok) require.Empty(t, got) } // Set no-op { require.False(t, m.Set("hello", "world")) require.Equal(t, 0, m.Len()) } } func TestMap_ForEach(t *testing.T) { m := NewMap[string, testVal]() inputs := map[string]testVal{ "hello": "world", "foo": "bar", "baz": "bat", } for k, v := range inputs { m.InitWatch(k, nil) m.Set(k, v) } require.Equal(t, 3, m.Len()) // returning true continues iteration { var count int m.ForEachKey(func(k string) bool { count++ return true }) require.Equal(t, 3, count) } // returning false exits loop { var count int m.ForEachKey(func(k string) bool { count++ return false }) require.Equal(t, 1, count) } } func TestMap_ForEachE(t *testing.T) { m := NewMap[string, testVal]() inputs := map[string]testVal{ "hello": "world", "foo": "bar", "baz": "bat", } for k, v := range inputs { m.InitWatch(k, nil) m.Set(k, v) } require.Equal(t, 3, m.Len()) // returning nil error continues iteration { var count int err := m.ForEachKeyE(func(k string) error { count++ return nil }) require.Equal(t, 3, count) require.Nil(t, err) } // returning an error should exit immediately { var count int err := m.ForEachKeyE(func(k string) error { count++ return errors.New("boooo") }) require.Equal(t, 1, count) require.Errorf(t, err, "boo") } } func TestMap_DeepCopy(t *testing.T) { orig := NewMap[string, testVal]() inputs := map[string]testVal{ "hello": "world", "foo": "bar", "baz": "bat", } for k, v := range inputs { orig.InitWatch(k, nil) orig.Set(k, v) } require.Equal(t, 3, orig.Len()) clone := orig.DeepCopy() require.Equal(t, 3, clone.Len()) orig.CancelWatch("hello") require.NotEqual(t, orig.Len(), clone.Len()) } type testVal string func (tv testVal) DeepCopy() testVal { return tv }