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) }) }