massert: make most assertions handle the case of a reference type, like a map, being changed before Assert is called
This commit is contained in:
parent
bc8f323514
commit
23045168cf
@ -290,6 +290,10 @@ func toStr(i interface{}) string {
|
|||||||
|
|
||||||
// Equal asserts that the two values are exactly equal, and uses the
|
// Equal asserts that the two values are exactly equal, and uses the
|
||||||
// reflect.DeepEqual function to determine if they are.
|
// reflect.DeepEqual function to determine if they are.
|
||||||
|
//
|
||||||
|
// TODO this does not currently handle the case of creating the Assertion using
|
||||||
|
// a reference type (like a map), changing one of the map's keys, and then
|
||||||
|
// calling Assert.
|
||||||
func Equal(a, b interface{}) Assertion {
|
func Equal(a, b interface{}) Assertion {
|
||||||
return newAssertion(func() error {
|
return newAssertion(func() error {
|
||||||
if !reflect.DeepEqual(a, b) {
|
if !reflect.DeepEqual(a, b) {
|
||||||
@ -320,6 +324,10 @@ func Nil(i interface{}) Assertion {
|
|||||||
}, toStr(i)+" is nil", 0)
|
}, toStr(i)+" is nil", 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type setKV struct {
|
||||||
|
k, v interface{}
|
||||||
|
}
|
||||||
|
|
||||||
func toSet(i interface{}, keyedMap bool) ([]interface{}, error) {
|
func toSet(i interface{}, keyedMap bool) ([]interface{}, error) {
|
||||||
v := reflect.ValueOf(i)
|
v := reflect.ValueOf(i)
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
@ -334,7 +342,7 @@ func toSet(i interface{}, keyedMap bool) ([]interface{}, error) {
|
|||||||
vv := make([]interface{}, len(keys))
|
vv := make([]interface{}, len(keys))
|
||||||
for i := range keys {
|
for i := range keys {
|
||||||
if keyedMap {
|
if keyedMap {
|
||||||
vv[i] = struct{ k, v interface{} }{
|
vv[i] = setKV{
|
||||||
k: keys[i].Interface(),
|
k: keys[i].Interface(),
|
||||||
v: v.MapIndex(keys[i]).Interface(),
|
v: v.MapIndex(keys[i]).Interface(),
|
||||||
}
|
}
|
||||||
@ -351,20 +359,19 @@ func toSet(i interface{}, keyedMap bool) ([]interface{}, error) {
|
|||||||
// Subset asserts that the given subset is a subset of the given set. Both must
|
// Subset asserts that the given subset is a subset of the given set. Both must
|
||||||
// be of the same type and may be arrays, slices, or maps.
|
// be of the same type and may be arrays, slices, or maps.
|
||||||
func Subset(set, subset interface{}) Assertion {
|
func Subset(set, subset interface{}) Assertion {
|
||||||
|
if reflect.TypeOf(set) != reflect.TypeOf(subset) {
|
||||||
|
panic(errors.New("set and subset aren't of same type"))
|
||||||
|
}
|
||||||
|
|
||||||
|
setVV, err := toSet(set, true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
subsetVV, err := toSet(subset, true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
return newAssertion(func() error {
|
return newAssertion(func() error {
|
||||||
if reflect.TypeOf(set) != reflect.TypeOf(subset) {
|
|
||||||
return errors.New("set and subset aren't of same type")
|
|
||||||
}
|
|
||||||
|
|
||||||
setVV, err := toSet(set, true)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
subsetVV, err := toSet(subset, true)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// this is obviously not the most efficient way to do this
|
// this is obviously not the most efficient way to do this
|
||||||
outer:
|
outer:
|
||||||
for i := range subsetVV {
|
for i := range subsetVV {
|
||||||
@ -383,12 +390,12 @@ func Subset(set, subset interface{}) Assertion {
|
|||||||
// set may be an array, a slice, or a map, and if it's a map then the elem will
|
// set may be an array, a slice, or a map, and if it's a map then the elem will
|
||||||
// need to be a value in it.
|
// need to be a value in it.
|
||||||
func Has(set, elem interface{}) Assertion {
|
func Has(set, elem interface{}) Assertion {
|
||||||
return newAssertion(func() error {
|
setVV, err := toSet(set, false)
|
||||||
setVV, err := toSet(set, false)
|
if err != nil {
|
||||||
if err != nil {
|
panic(err)
|
||||||
return err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
return newAssertion(func() error {
|
||||||
for i := range setVV {
|
for i := range setVV {
|
||||||
if reflect.DeepEqual(setVV[i], elem) {
|
if reflect.DeepEqual(setVV[i], elem) {
|
||||||
return nil
|
return nil
|
||||||
@ -401,14 +408,16 @@ func Has(set, elem interface{}) Assertion {
|
|||||||
// HasKey asserts that the given set (which must be a map type) has the given
|
// HasKey asserts that the given set (which must be a map type) has the given
|
||||||
// element as a key in it.
|
// element as a key in it.
|
||||||
func HasKey(set, elem interface{}) Assertion {
|
func HasKey(set, elem interface{}) Assertion {
|
||||||
|
if v := reflect.ValueOf(set); v.Kind() != reflect.Map {
|
||||||
|
panic(fmt.Errorf("type %s is not a map", v.Type()))
|
||||||
|
}
|
||||||
|
setVV, err := toSet(set, true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
return newAssertion(func() error {
|
return newAssertion(func() error {
|
||||||
v := reflect.ValueOf(set)
|
for _, kv := range setVV {
|
||||||
if v.Kind() != reflect.Map {
|
if reflect.DeepEqual(kv.(setKV).k, elem) {
|
||||||
return fmt.Errorf("type %s is not a map", v.Type())
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, key := range v.MapKeys() {
|
|
||||||
if reflect.DeepEqual(key.Interface(), elem) {
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,11 +429,13 @@ func HasKey(set, elem interface{}) Assertion {
|
|||||||
// set may be an array, a slice, or a map. A nil value'd set is considered to be
|
// set may be an array, a slice, or a map. A nil value'd set is considered to be
|
||||||
// a length of zero.
|
// a length of zero.
|
||||||
func Len(set interface{}, length int) Assertion {
|
func Len(set interface{}, length int) Assertion {
|
||||||
|
setVV, err := toSet(set, false)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
return newAssertion(func() error {
|
return newAssertion(func() error {
|
||||||
setVV, err := toSet(set, false)
|
if len(setVV) != length {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if len(setVV) != length {
|
|
||||||
return fmt.Errorf("set not correct length, is %d", len(setVV))
|
return fmt.Errorf("set not correct length, is %d", len(setVV))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -145,15 +145,19 @@ func TestSubset(t *T) {
|
|||||||
))
|
))
|
||||||
|
|
||||||
Fatal(t, None(
|
Fatal(t, None(
|
||||||
Subset([]int64{1, 2, 3}, []int{1}),
|
|
||||||
Subset([]int{}, []int{1, 2, 3}),
|
Subset([]int{}, []int{1, 2, 3}),
|
||||||
Subset([]int{1, 2, 3}, []int{4}),
|
Subset([]int{1, 2, 3}, []int{4}),
|
||||||
Subset([]int{1, 2, 3}, []int{1, 3, 2, 4}),
|
Subset([]int{1, 2, 3}, []int{1, 3, 2, 4}),
|
||||||
|
|
||||||
Subset(map[int]int{1: 1, 2: 2}, map[int]int64{1: 1}),
|
|
||||||
Subset(map[int]int{1: 1, 2: 2}, map[int]int{1: 2}),
|
Subset(map[int]int{1: 1, 2: 2}, map[int]int{1: 2}),
|
||||||
Subset(map[int]int{1: 1, 2: 2}, map[int]int{1: 1, 3: 3}),
|
Subset(map[int]int{1: 1, 2: 2}, map[int]int{1: 1, 3: 3}),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
// make sure changes don't retroactively fail the assertion
|
||||||
|
m := map[int]int{1: 1, 2: 2}
|
||||||
|
a := Subset(m, map[int]int{1: 1})
|
||||||
|
m[1] = 2
|
||||||
|
Fatal(t, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHas(t *T) {
|
func TestHas(t *T) {
|
||||||
@ -176,6 +180,12 @@ func TestHas(t *T) {
|
|||||||
Has(map[int]int{1: 2}, 1),
|
Has(map[int]int{1: 2}, 1),
|
||||||
Has(map[int]int{1: 2, 2: 1}, 3),
|
Has(map[int]int{1: 2, 2: 1}, 3),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
// make sure changes don't retroactively fail the assertion
|
||||||
|
m := map[int]int{1: 1}
|
||||||
|
a := Has(m, 1)
|
||||||
|
m[1] = 2
|
||||||
|
Fatal(t, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHasKey(t *T) {
|
func TestHasKey(t *T) {
|
||||||
@ -186,11 +196,16 @@ func TestHasKey(t *T) {
|
|||||||
))
|
))
|
||||||
|
|
||||||
Fatal(t, None(
|
Fatal(t, None(
|
||||||
HasKey([]int{}, 1),
|
|
||||||
HasKey([]int{1}, 1),
|
|
||||||
HasKey(map[int]int{}, 1),
|
HasKey(map[int]int{}, 1),
|
||||||
HasKey(map[int]int{2: 2}, 1),
|
HasKey(map[int]int{2: 2}, 1),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
// make sure changes don't retroactively fail the assertion
|
||||||
|
m := map[int]int{1: 1}
|
||||||
|
a := HasKey(m, 1)
|
||||||
|
delete(m, 1)
|
||||||
|
Fatal(t, a)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLen(t *T) {
|
func TestLen(t *T) {
|
||||||
@ -215,4 +230,10 @@ func TestLen(t *T) {
|
|||||||
Len(map[int]int(nil), 1),
|
Len(map[int]int(nil), 1),
|
||||||
Len(map[int]int{}, 1),
|
Len(map[int]int{}, 1),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
// make sure changes don't retroactively fail the assertion
|
||||||
|
m := map[int]int{1: 1}
|
||||||
|
a := Len(m, 1)
|
||||||
|
m[2] = 2
|
||||||
|
Fatal(t, a)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user