diff --git a/pkg/namespace/namespace.go b/pkg/namespace/namespace.go index 5da38bc398..b6ab358d04 100644 --- a/pkg/namespace/namespace.go +++ b/pkg/namespace/namespace.go @@ -148,7 +148,7 @@ func (n Namespace) IsPayForBlob() bool { func (n Namespace) Repeat(times int) []Namespace { ns := make([]Namespace, times) for i := 0; i < times; i++ { - ns[i] = n + ns[i] = n.deepCopy() } return ns } @@ -180,3 +180,18 @@ func leftPad(b []byte, size int) []byte { pad := make([]byte, size-len(b)) return append(pad, b...) } + +// deepCopy returns a deep copy of the Namespace object. +func (n Namespace) deepCopy() Namespace { + // Create a deep copy of the ID slice + copyID := make([]byte, len(n.ID)) + copy(copyID, n.ID) + + // Create a new Namespace object with the copied fields + copyNamespace := Namespace{ + Version: n.Version, + ID: copyID, + } + + return copyNamespace +} diff --git a/pkg/namespace/namespace_test.go b/pkg/namespace/namespace_test.go index f7b97487dc..199a5d0a79 100644 --- a/pkg/namespace/namespace_test.go +++ b/pkg/namespace/namespace_test.go @@ -73,6 +73,19 @@ func TestNew(t *testing.T) { } } +// TestRepeatNonMutability ensures that the output of Repeat method is not mutated when the original namespace is mutated. +func TestRepeatNonMutability(t *testing.T) { + n := 10 + namespace := Namespace{Version: NamespaceVersionMax, ID: []byte{1, 2, 3, 4}} + repeated := namespace.Repeat(n) + // mutate the original namespace + namespace.ID[0] = 5 + // ensure the repeated namespaces are not mutated + for i := 0; i < n; i++ { + assert.NotEqual(t, repeated[i], namespace) + } +} + func TestNewV0(t *testing.T) { type testCase struct { name string