elvish/pkg/eval/vals/tester.go

198 lines
4.6 KiB
Go

package vals
import (
"reflect"
"testing"
)
// Tester is a helper for testing properties of a value.
type Tester struct {
t *testing.T
v any
}
// TestValue returns a ValueTester.
func TestValue(t *testing.T, v any) Tester {
// Hack to get test coverage on the marker method IsStructMap, which is
// never invoked.
if m, ok := v.(StructMap); ok {
m.IsStructMap()
}
return Tester{t, v}
}
// Kind tests the Kind of the value.
func (vt Tester) Kind(wantKind string) Tester {
vt.t.Helper()
kind := Kind(vt.v)
if kind != wantKind {
vt.t.Errorf("Kind(v) = %s, want %s", kind, wantKind)
}
return vt
}
// Bool tests the Boool of the value.
func (vt Tester) Bool(wantBool bool) Tester {
vt.t.Helper()
b := Bool(vt.v)
if b != wantBool {
vt.t.Errorf("Bool(v) = %v, want %v", b, wantBool)
}
return vt
}
// Hash tests the Hash of the value.
func (vt Tester) Hash(wantHash uint32) Tester {
vt.t.Helper()
hash := Hash(vt.v)
if hash != wantHash {
vt.t.Errorf("Hash(v) = %v, want %v", hash, wantHash)
}
return vt
}
// Len tests the Len of the value.
func (vt Tester) Len(wantLen int) Tester {
vt.t.Helper()
kind := Len(vt.v)
if kind != wantLen {
vt.t.Errorf("Len(v) = %v, want %v", kind, wantLen)
}
return vt
}
// Repr tests the Repr of the value.
func (vt Tester) Repr(wantRepr string) Tester {
vt.t.Helper()
kind := ReprPlain(vt.v)
if kind != wantRepr {
vt.t.Errorf("Repr(v) = %s, want %s", kind, wantRepr)
}
return vt
}
// Equal tests that the value is Equal to every of the given values.
func (vt Tester) Equal(others ...any) Tester {
vt.t.Helper()
for _, other := range others {
eq := Equal(vt.v, other)
if !eq {
vt.t.Errorf("Equal(v, %v) = false, want true", other)
}
}
return vt
}
// NotEqual tests that the value is not Equal to any of the given values.
func (vt Tester) NotEqual(others ...any) Tester {
vt.t.Helper()
for _, other := range others {
eq := Equal(vt.v, other)
if eq {
vt.t.Errorf("Equal(v, %v) = true, want false", other)
}
}
return vt
}
// HasKey tests that the value has each of the given keys.
func (vt Tester) HasKey(keys ...any) Tester {
vt.t.Helper()
for _, key := range keys {
has := HasKey(vt.v, key)
if !has {
vt.t.Errorf("HasKey(v, %v) = false, want true", key)
}
}
return vt
}
// HasNoKey tests that the value does not have any of the given keys.
func (vt Tester) HasNoKey(keys ...any) Tester {
vt.t.Helper()
for _, key := range keys {
has := HasKey(vt.v, key)
if has {
vt.t.Errorf("HasKey(v, %v) = true, want false", key)
}
}
return vt
}
// AllKeys tests that the given keys match what the result of IterateKeys on the
// value.
//
// NOTE: This now checks equality using reflect.DeepEqual, since all the builtin
// types have string keys. This can be changed in future to use Equal is the
// need arises.
func (vt Tester) AllKeys(wantKeys ...any) Tester {
vt.t.Helper()
keys, err := collectKeys(vt.v)
if err != nil {
vt.t.Errorf("IterateKeys(v, f) -> err %v, want nil", err)
}
if !reflect.DeepEqual(keys, wantKeys) {
vt.t.Errorf("IterateKeys(v, f) calls f with %v, want %v", keys, wantKeys)
}
return vt
}
func collectKeys(v any) ([]any, error) {
var keys []any
err := IterateKeys(v, func(k any) bool {
keys = append(keys, k)
return true
})
return keys, err
}
// Index tests that Index'ing the value with the given key returns the wanted value
// and no error.
func (vt Tester) Index(key, wantVal any) Tester {
vt.t.Helper()
got, err := Index(vt.v, key)
if err != nil {
vt.t.Errorf("Index(v, %v) -> err %v, want nil", key, err)
}
if !Equal(got, wantVal) {
vt.t.Errorf("Index(v, %v) -> %v, want %v", key, got, wantVal)
}
return vt
}
// IndexError tests that Index'ing the value with the given key returns the given
// error.
func (vt Tester) IndexError(key any, wantErr error) Tester {
vt.t.Helper()
_, err := Index(vt.v, key)
if !reflect.DeepEqual(err, wantErr) {
vt.t.Errorf("Index(v, %v) -> err %v, want %v", key, err, wantErr)
}
return vt
}
// Assoc tests that Assoc'ing the value with the given key-value pair returns
// the wanted new value and no error.
func (vt Tester) Assoc(key, val, wantNew any) Tester {
vt.t.Helper()
got, err := Assoc(vt.v, key, val)
if err != nil {
vt.t.Errorf("Assoc(v, %v) -> err %v, want nil", key, err)
}
if !Equal(got, wantNew) {
vt.t.Errorf("Assoc(v, %v) -> %v, want %v", key, got, wantNew)
}
return vt
}
// AssocError tests that Assoc'ing the value with the given key-value pair
// returns the given error.
func (vt Tester) AssocError(key, val any, wantErr error) Tester {
vt.t.Helper()
_, err := Assoc(vt.v, key, val)
if !reflect.DeepEqual(err, wantErr) {
vt.t.Errorf("Assoc(v, %v) -> err %v, want %v", key, err, wantErr)
}
return vt
}