Files
go-jdenticon/internal/util/hash_test.go
Kevin McIntyre d9e84812ff Initial release: Go Jdenticon library v0.1.0
- Core library with SVG and PNG generation
- CLI tool with generate and batch commands
- Cross-platform path handling for Windows compatibility
- Comprehensive test suite with integration tests
2026-01-03 23:41:48 -05:00

361 lines
7.8 KiB
Go

package util
import (
"math"
"strconv"
"testing"
)
func TestContainsInt(t *testing.T) {
tests := []struct {
name string
slice []int
value int
expected bool
}{
{
name: "value exists in slice",
slice: []int{1, 2, 3, 4, 5},
value: 3,
expected: true,
},
{
name: "value does not exist in slice",
slice: []int{1, 2, 3, 4, 5},
value: 6,
expected: false,
},
{
name: "empty slice",
slice: []int{},
value: 1,
expected: false,
},
{
name: "single element slice - match",
slice: []int{42},
value: 42,
expected: true,
},
{
name: "single element slice - no match",
slice: []int{42},
value: 43,
expected: false,
},
{
name: "duplicate values in slice",
slice: []int{1, 2, 2, 3, 2},
value: 2,
expected: true,
},
{
name: "negative values",
slice: []int{-5, -3, -1, 0, 1},
value: -3,
expected: true,
},
{
name: "zero value",
slice: []int{-1, 0, 1},
value: 0,
expected: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := ContainsInt(tt.slice, tt.value)
if result != tt.expected {
t.Errorf("ContainsInt(%v, %d) = %v, expected %v",
tt.slice, tt.value, result, tt.expected)
}
})
}
}
func TestParseHex(t *testing.T) {
tests := []struct {
name string
hash string
startPosition int
octets int
expected int
expectError bool
errorType string
}{
// Valid cases
{
name: "simple hex parsing",
hash: "abc123def456",
startPosition: 0,
octets: 2,
expected: 0xab,
expectError: false,
},
{
name: "parse single character",
hash: "a1b2c3d4e5f6",
startPosition: 1,
octets: 1,
expected: 0x1,
expectError: false,
},
{
name: "parse from middle",
hash: "123456789abc",
startPosition: 6,
octets: 3,
expected: 0x789,
expectError: false,
},
{
name: "negative position (from end)",
hash: "abcdef123456",
startPosition: -2,
octets: 2,
expected: 0x56,
expectError: false,
},
{
name: "octets 0 reads to end",
hash: "abc123",
startPosition: 3,
octets: 0,
expected: 0x123,
expectError: false,
},
// Error cases
{
name: "position out of bounds",
hash: "abc123",
startPosition: 10,
octets: 1,
expectError: true,
errorType: "position out of bounds",
},
{
name: "negative position too large",
hash: "abc123",
startPosition: -10,
octets: 1,
expectError: true,
errorType: "position out of bounds",
},
{
name: "invalid hex character",
hash: "abcghi",
startPosition: 3,
octets: 3,
expectError: true,
errorType: "invalid hex format",
},
// Platform-specific overflow tests
{
name: "value at 32-bit int boundary (safe)",
hash: "7fffffff",
startPosition: 0,
octets: 8,
expected: math.MaxInt32,
expectError: false,
},
}
// Add platform-specific overflow test that should fail on 32-bit systems
if strconv.IntSize == 32 {
tests = append(tests, struct {
name string
hash string
startPosition int
octets int
expected int
expectError bool
errorType string
}{
name: "overflow on 32-bit systems",
hash: "80000000", // This exceeds math.MaxInt32
startPosition: 0,
octets: 8,
expectError: true,
errorType: "value out of range",
})
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := ParseHex(tt.hash, tt.startPosition, tt.octets)
if tt.expectError {
if err == nil {
t.Errorf("ParseHex(%q, %d, %d) expected error but got none",
tt.hash, tt.startPosition, tt.octets)
return
}
if tt.errorType != "" && !containsString(err.Error(), tt.errorType) {
t.Errorf("ParseHex(%q, %d, %d) error %q does not contain expected type %q",
tt.hash, tt.startPosition, tt.octets, err.Error(), tt.errorType)
}
return
}
if err != nil {
t.Errorf("ParseHex(%q, %d, %d) unexpected error: %v",
tt.hash, tt.startPosition, tt.octets, err)
return
}
if result != tt.expected {
t.Errorf("ParseHex(%q, %d, %d) = %d, expected %d",
tt.hash, tt.startPosition, tt.octets, result, tt.expected)
}
})
}
}
func TestValidateHash(t *testing.T) {
tests := []struct {
name string
hash string
expectError bool
errorType string
}{
{
name: "valid hash",
hash: "abc123def456789",
expectError: false,
},
{
name: "minimum valid length",
hash: "abc123def45", // exactly 11 chars
expectError: false,
},
{
name: "hash too short",
hash: "abc123def4", // 10 chars
expectError: true,
errorType: "insufficient length",
},
{
name: "invalid character",
hash: "abc123gef456789",
expectError: true,
errorType: "invalid character",
},
{
name: "uppercase hex is valid",
hash: "ABC123DEF456789",
expectError: false,
},
{
name: "mixed case is valid",
hash: "AbC123dEf456789",
expectError: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateHash(tt.hash)
if tt.expectError {
if err == nil {
t.Errorf("ValidateHash(%q) expected error but got none", tt.hash)
return
}
if tt.errorType != "" && !containsString(err.Error(), tt.errorType) {
t.Errorf("ValidateHash(%q) error %q does not contain expected type %q",
tt.hash, err.Error(), tt.errorType)
}
return
}
if err != nil {
t.Errorf("ValidateHash(%q) unexpected error: %v", tt.hash, err)
}
})
}
}
func TestIsValidHash(t *testing.T) {
tests := []struct {
name string
hash string
expected bool
}{
{
name: "valid hash returns true",
hash: "abc123def456789",
expected: true,
},
{
name: "invalid hash returns false",
hash: "abc123g", // too short and invalid char
expected: false,
},
{
name: "empty hash returns false",
hash: "",
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IsValidHash(tt.hash)
if result != tt.expected {
t.Errorf("IsValidHash(%q) = %v, expected %v", tt.hash, result, tt.expected)
}
})
}
}
// TestParseHexDeterministic verifies that ParseHex produces consistent results
func TestParseHexDeterministic(t *testing.T) {
testCases := []struct {
hash string
pos int
oct int
}{
{"abc123def456", 0, 2},
{"fedcba987654", 3, 4},
{"123456789abc", 6, 3},
}
for _, tc := range testCases {
t.Run("deterministic_"+tc.hash, func(t *testing.T) {
// Parse the same input multiple times
results := make([]int, 10)
for i := 0; i < 10; i++ {
result, err := ParseHex(tc.hash, tc.pos, tc.oct)
if err != nil {
t.Fatalf("ParseHex failed on iteration %d: %v", i, err)
}
results[i] = result
}
// Verify all results are identical
first := results[0]
for i, result := range results[1:] {
if result != first {
t.Errorf("ParseHex result not deterministic: iteration %d gave %d, expected %d",
i+1, result, first)
}
}
})
}
}
// Helper function to check if a string contains a substring
func containsString(s, substr string) bool {
return len(s) >= len(substr) &&
(len(substr) == 0 ||
func() bool {
for i := 0; i <= len(s)-len(substr); i++ {
if s[i:i+len(substr)] == substr {
return true
}
}
return false
}())
}