Skip to content

Commit

Permalink
Equal is more of a util function then a template specific function
Browse files Browse the repository at this point in the history
  • Loading branch information
nolman committed Apr 2, 2013
1 parent d0091d3 commit ccf1f84
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 106 deletions.
40 changes: 0 additions & 40 deletions template.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,43 +363,3 @@ func ReverseUrl(args ...interface{}) string {

return MainRouter.Reverse(args[0].(string), argsByName).Url
}

// Equal is a helper for comparing value equality, following these rules:
// - Values with equivalent types are compared with reflect.DeepEqual
// - int, uint, and float values are compared without regard to the type width.
// for example, Equal(int32(5), int64(5)) == true
// - strings and byte slices are converted to strings before comparison.
// - else, return false.
func Equal(a, b interface{}) bool {
if reflect.TypeOf(a) == reflect.TypeOf(b) {
return reflect.DeepEqual(a, b)
}
switch a.(type) {
case int, int8, int16, int32, int64:
switch b.(type) {
case int, int8, int16, int32, int64:
return reflect.ValueOf(a).Int() == reflect.ValueOf(b).Int()
}
case uint, uint8, uint16, uint32, uint64:
switch b.(type) {
case uint, uint8, uint16, uint32, uint64:
return reflect.ValueOf(a).Uint() == reflect.ValueOf(b).Uint()
}
case float32, float64:
switch b.(type) {
case float32, float64:
return reflect.ValueOf(a).Float() == reflect.ValueOf(b).Float()
}
case string:
switch b.(type) {
case []byte:
return a.(string) == string(b.([]byte))
}
case []byte:
switch b.(type) {
case string:
return b.(string) == string(a.([]byte))
}
}
return false
}
66 changes: 0 additions & 66 deletions template_test.go
Original file line number Diff line number Diff line change
@@ -1,67 +1 @@
package revel

import (
"reflect"
"testing"
)

func TestEqual(t *testing.T) {
type testStruct struct{}
type testStruct2 struct{}
i, i2 := 8, 9
s, s2 := "@朕µ\n\tüöäß", "@朕µ\n\tüöäss"
slice, slice2 := []int{1, 2, 3, 4, 5}, []int{1, 2, 3, 4, 5}
slice3, slice4 := []int{5, 4, 3, 2, 1}, []int{5, 4, 3, 2, 1}

tm := map[string][]interface{}{
"slices": {slice, slice2},
"slices2": {slice3, slice4},
"types": {new(testStruct), new(testStruct)},
"types2": {new(testStruct2), new(testStruct2)},
"ints": {int(i), int8(i), int16(i), int32(i), int64(i)},
"ints2": {int(i2), int8(i2), int16(i2), int32(i2), int64(i2)},
"uints": {uint(i), uint8(i), uint16(i), uint32(i), uint64(i)},
"uints2": {uint(i2), uint8(i2), uint16(i2), uint32(i2), uint64(i2)},
"floats": {float32(i), float64(i)},
"floats2": {float32(i2), float64(i2)},
"strings": {[]byte(s), s},
"strings2": {[]byte(s2), s2},
}

testRow := func(row, row2 string, expected bool) {
for _, a := range tm[row] {
for _, b := range tm[row2] {
ok := Equal(a, b)
if ok != expected {
ak := reflect.TypeOf(a).Kind()
bk := reflect.TypeOf(b).Kind()
t.Errorf("eq(%s=%v,%s=%v) want %t got %t", ak, a, bk, b, expected, ok)
}
}
}
}

testRow("slices", "slices", true)
testRow("slices", "slices2", false)
testRow("slices2", "slices", false)

testRow("types", "types", true)
testRow("types2", "types", false)
testRow("types", "types2", false)

testRow("ints", "ints", true)
testRow("ints", "ints2", false)
testRow("ints2", "ints", false)

testRow("uints", "uints", true)
testRow("uints2", "uints", false)
testRow("uints", "uints2", false)

testRow("floats", "floats", true)
testRow("floats2", "floats", false)
testRow("floats", "floats2", false)

testRow("strings", "strings", true)
testRow("strings2", "strings", false)
testRow("strings", "strings2", false)
}
40 changes: 40 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,43 @@ func FirstNonEmpty(strs ...string) string {
}
return ""
}

// Equal is a helper for comparing value equality, following these rules:
// - Values with equivalent types are compared with reflect.DeepEqual
// - int, uint, and float values are compared without regard to the type width.
// for example, Equal(int32(5), int64(5)) == true
// - strings and byte slices are converted to strings before comparison.
// - else, return false.
func Equal(a, b interface{}) bool {
if reflect.TypeOf(a) == reflect.TypeOf(b) {
return reflect.DeepEqual(a, b)
}
switch a.(type) {
case int, int8, int16, int32, int64:
switch b.(type) {
case int, int8, int16, int32, int64:
return reflect.ValueOf(a).Int() == reflect.ValueOf(b).Int()
}
case uint, uint8, uint16, uint32, uint64:
switch b.(type) {
case uint, uint8, uint16, uint32, uint64:
return reflect.ValueOf(a).Uint() == reflect.ValueOf(b).Uint()
}
case float32, float64:
switch b.(type) {
case float32, float64:
return reflect.ValueOf(a).Float() == reflect.ValueOf(b).Float()
}
case string:
switch b.(type) {
case []byte:
return a.(string) == string(b.([]byte))
}
case []byte:
switch b.(type) {
case string:
return b.(string) == string(a.([]byte))
}
}
return false
}
62 changes: 62 additions & 0 deletions util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"path"
"path/filepath"
"testing"
"reflect"
)

func TestContentTypeByFilename(t *testing.T) {
Expand All @@ -28,3 +29,64 @@ func TestContentTypeByFilename(t *testing.T) {
}
}
}

func TestEqual(t *testing.T) {
type testStruct struct{}
type testStruct2 struct{}
i, i2 := 8, 9
s, s2 := "@朕µ\n\tüöäß", "@朕µ\n\tüöäss"
slice, slice2 := []int{1, 2, 3, 4, 5}, []int{1, 2, 3, 4, 5}
slice3, slice4 := []int{5, 4, 3, 2, 1}, []int{5, 4, 3, 2, 1}

tm := map[string][]interface{}{
"slices": {slice, slice2},
"slices2": {slice3, slice4},
"types": {new(testStruct), new(testStruct)},
"types2": {new(testStruct2), new(testStruct2)},
"ints": {int(i), int8(i), int16(i), int32(i), int64(i)},
"ints2": {int(i2), int8(i2), int16(i2), int32(i2), int64(i2)},
"uints": {uint(i), uint8(i), uint16(i), uint32(i), uint64(i)},
"uints2": {uint(i2), uint8(i2), uint16(i2), uint32(i2), uint64(i2)},
"floats": {float32(i), float64(i)},
"floats2": {float32(i2), float64(i2)},
"strings": {[]byte(s), s},
"strings2": {[]byte(s2), s2},
}

testRow := func(row, row2 string, expected bool) {
for _, a := range tm[row] {
for _, b := range tm[row2] {
ok := Equal(a, b)
if ok != expected {
ak := reflect.TypeOf(a).Kind()
bk := reflect.TypeOf(b).Kind()
t.Errorf("eq(%s=%v,%s=%v) want %t got %t", ak, a, bk, b, expected, ok)
}
}
}
}

testRow("slices", "slices", true)
testRow("slices", "slices2", false)
testRow("slices2", "slices", false)

testRow("types", "types", true)
testRow("types2", "types", false)
testRow("types", "types2", false)

testRow("ints", "ints", true)
testRow("ints", "ints2", false)
testRow("ints2", "ints", false)

testRow("uints", "uints", true)
testRow("uints2", "uints", false)
testRow("uints", "uints2", false)

testRow("floats", "floats", true)
testRow("floats2", "floats", false)
testRow("floats", "floats2", false)

testRow("strings", "strings", true)
testRow("strings2", "strings", false)
testRow("strings", "strings2", false)
}

0 comments on commit ccf1f84

Please sign in to comment.