rwadurian/backend/mpc-system/tests/unit/pkg/utils_test.go

320 lines
8.1 KiB
Go

package pkg_test
import (
"math/big"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/rwadurian/mpc-system/pkg/utils"
)
func TestGenerateID(t *testing.T) {
t.Run("should generate unique IDs", func(t *testing.T) {
id1 := utils.GenerateID()
id2 := utils.GenerateID()
assert.NotEqual(t, id1, id2)
})
}
func TestParseUUID(t *testing.T) {
t.Run("should parse valid UUID", func(t *testing.T) {
id := utils.GenerateID()
parsed, err := utils.ParseUUID(id.String())
require.NoError(t, err)
assert.Equal(t, id, parsed)
})
t.Run("should fail on invalid UUID", func(t *testing.T) {
_, err := utils.ParseUUID("invalid-uuid")
assert.Error(t, err)
})
}
func TestIsValidUUID(t *testing.T) {
t.Run("should return true for valid UUID", func(t *testing.T) {
id := utils.GenerateID()
assert.True(t, utils.IsValidUUID(id.String()))
})
t.Run("should return false for invalid UUID", func(t *testing.T) {
assert.False(t, utils.IsValidUUID("not-a-uuid"))
})
}
func TestJSON(t *testing.T) {
t.Run("should marshal and unmarshal JSON", func(t *testing.T) {
original := map[string]interface{}{
"key": "value",
"count": float64(42),
}
data, err := utils.ToJSON(original)
require.NoError(t, err)
var result map[string]interface{}
err = utils.FromJSON(data, &result)
require.NoError(t, err)
assert.Equal(t, original["key"], result["key"])
assert.Equal(t, original["count"], result["count"])
})
}
func TestNowUTC(t *testing.T) {
t.Run("should return UTC time", func(t *testing.T) {
now := utils.NowUTC()
assert.Equal(t, time.UTC, now.Location())
})
}
func TestTimePtr(t *testing.T) {
t.Run("should return pointer to time", func(t *testing.T) {
now := time.Now()
ptr := utils.TimePtr(now)
require.NotNil(t, ptr)
assert.Equal(t, now, *ptr)
})
}
func TestBigIntBytes(t *testing.T) {
t.Run("should convert big.Int to bytes and back", func(t *testing.T) {
original, _ := new(big.Int).SetString("12345678901234567890", 10)
bytes := utils.BigIntToBytes(original)
assert.Len(t, bytes, 32)
result := utils.BytesToBigInt(bytes)
assert.Equal(t, 0, original.Cmp(result))
})
t.Run("should handle nil big.Int", func(t *testing.T) {
bytes := utils.BigIntToBytes(nil)
assert.Len(t, bytes, 32)
assert.Equal(t, make([]byte, 32), bytes)
})
}
func TestStringSliceContains(t *testing.T) {
t.Run("should find existing value", func(t *testing.T) {
slice := []string{"a", "b", "c"}
assert.True(t, utils.StringSliceContains(slice, "b"))
})
t.Run("should not find missing value", func(t *testing.T) {
slice := []string{"a", "b", "c"}
assert.False(t, utils.StringSliceContains(slice, "d"))
})
t.Run("should handle empty slice", func(t *testing.T) {
assert.False(t, utils.StringSliceContains([]string{}, "a"))
})
}
func TestStringSliceRemove(t *testing.T) {
t.Run("should remove existing value", func(t *testing.T) {
slice := []string{"a", "b", "c"}
result := utils.StringSliceRemove(slice, "b")
assert.Len(t, result, 2)
assert.Contains(t, result, "a")
assert.Contains(t, result, "c")
assert.NotContains(t, result, "b")
})
t.Run("should not modify slice if value not found", func(t *testing.T) {
slice := []string{"a", "b", "c"}
result := utils.StringSliceRemove(slice, "d")
assert.Len(t, result, 3)
})
}
func TestUniqueStrings(t *testing.T) {
t.Run("should return unique strings", func(t *testing.T) {
slice := []string{"a", "b", "a", "c", "b"}
result := utils.UniqueStrings(slice)
assert.Len(t, result, 3)
assert.Contains(t, result, "a")
assert.Contains(t, result, "b")
assert.Contains(t, result, "c")
})
t.Run("should preserve order", func(t *testing.T) {
slice := []string{"c", "a", "b", "a"}
result := utils.UniqueStrings(slice)
assert.Equal(t, []string{"c", "a", "b"}, result)
})
}
func TestTruncateString(t *testing.T) {
t.Run("should truncate long string", func(t *testing.T) {
s := "hello world"
result := utils.TruncateString(s, 5)
assert.Equal(t, "hello", result)
})
t.Run("should not truncate short string", func(t *testing.T) {
s := "hi"
result := utils.TruncateString(s, 5)
assert.Equal(t, "hi", result)
})
}
func TestSafeString(t *testing.T) {
t.Run("should return string value", func(t *testing.T) {
s := "test"
result := utils.SafeString(&s)
assert.Equal(t, "test", result)
})
t.Run("should return empty string for nil", func(t *testing.T) {
result := utils.SafeString(nil)
assert.Equal(t, "", result)
})
}
func TestPointerHelpers(t *testing.T) {
t.Run("StringPtr", func(t *testing.T) {
ptr := utils.StringPtr("test")
require.NotNil(t, ptr)
assert.Equal(t, "test", *ptr)
})
t.Run("IntPtr", func(t *testing.T) {
ptr := utils.IntPtr(42)
require.NotNil(t, ptr)
assert.Equal(t, 42, *ptr)
})
t.Run("BoolPtr", func(t *testing.T) {
ptr := utils.BoolPtr(true)
require.NotNil(t, ptr)
assert.True(t, *ptr)
})
}
func TestCoalesce(t *testing.T) {
t.Run("should return first non-zero value", func(t *testing.T) {
result := utils.Coalesce("", "", "value", "other")
assert.Equal(t, "value", result)
})
t.Run("should return zero if all values are zero", func(t *testing.T) {
result := utils.Coalesce("", "", "")
assert.Equal(t, "", result)
})
t.Run("should work with ints", func(t *testing.T) {
result := utils.Coalesce(0, 0, 42, 100)
assert.Equal(t, 42, result)
})
}
func TestMapKeys(t *testing.T) {
t.Run("should return all keys", func(t *testing.T) {
m := map[string]int{"a": 1, "b": 2, "c": 3}
keys := utils.MapKeys(m)
assert.Len(t, keys, 3)
assert.Contains(t, keys, "a")
assert.Contains(t, keys, "b")
assert.Contains(t, keys, "c")
})
t.Run("should return empty slice for empty map", func(t *testing.T) {
m := map[string]int{}
keys := utils.MapKeys(m)
assert.Empty(t, keys)
})
}
func TestMapValues(t *testing.T) {
t.Run("should return all values", func(t *testing.T) {
m := map[string]int{"a": 1, "b": 2, "c": 3}
values := utils.MapValues(m)
assert.Len(t, values, 3)
assert.Contains(t, values, 1)
assert.Contains(t, values, 2)
assert.Contains(t, values, 3)
})
}
func TestMinMax(t *testing.T) {
t.Run("Min should return smaller value", func(t *testing.T) {
assert.Equal(t, 1, utils.Min(1, 2))
assert.Equal(t, 1, utils.Min(2, 1))
assert.Equal(t, -5, utils.Min(-5, 0))
})
t.Run("Max should return larger value", func(t *testing.T) {
assert.Equal(t, 2, utils.Max(1, 2))
assert.Equal(t, 2, utils.Max(2, 1))
assert.Equal(t, 0, utils.Max(-5, 0))
})
}
func TestClamp(t *testing.T) {
t.Run("should clamp value to range", func(t *testing.T) {
assert.Equal(t, 5, utils.Clamp(5, 0, 10)) // within range
assert.Equal(t, 0, utils.Clamp(-5, 0, 10)) // below min
assert.Equal(t, 10, utils.Clamp(15, 0, 10)) // above max
})
}
func TestMaskString(t *testing.T) {
t.Run("should mask middle of string", func(t *testing.T) {
result := utils.MaskString("1234567890", 2)
assert.Equal(t, "12******90", result)
})
t.Run("should mask short strings completely", func(t *testing.T) {
result := utils.MaskString("1234", 3)
assert.Equal(t, "****", result)
})
}
func TestRetry(t *testing.T) {
t.Run("should succeed on first attempt", func(t *testing.T) {
attempts := 0
err := utils.Retry(3, time.Millisecond, func() error {
attempts++
return nil
})
assert.NoError(t, err)
assert.Equal(t, 1, attempts)
})
t.Run("should retry on failure and eventually succeed", func(t *testing.T) {
attempts := 0
err := utils.Retry(3, time.Millisecond, func() error {
attempts++
if attempts < 3 {
return assert.AnError
}
return nil
})
assert.NoError(t, err)
assert.Equal(t, 3, attempts)
})
t.Run("should fail after max attempts", func(t *testing.T) {
attempts := 0
err := utils.Retry(3, time.Millisecond, func() error {
attempts++
return assert.AnError
})
assert.Error(t, err)
assert.Equal(t, 3, attempts)
})
}