src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/eval/vals/tester.go (about) 1 package vals 2 3 import ( 4 "reflect" 5 "testing" 6 ) 7 8 // Tester is a helper for testing properties of a value. 9 type Tester struct { 10 t *testing.T 11 v any 12 } 13 14 // TestValue returns a ValueTester. 15 func TestValue(t *testing.T, v any) Tester { 16 // Hack to get test coverage on the marker method IsStructMap, which is 17 // never invoked. 18 if m, ok := v.(StructMap); ok { 19 m.IsStructMap() 20 } 21 return Tester{t, v} 22 } 23 24 // Kind tests the Kind of the value. 25 func (vt Tester) Kind(wantKind string) Tester { 26 vt.t.Helper() 27 kind := Kind(vt.v) 28 if kind != wantKind { 29 vt.t.Errorf("Kind(v) = %s, want %s", kind, wantKind) 30 } 31 return vt 32 } 33 34 // Bool tests the Boool of the value. 35 func (vt Tester) Bool(wantBool bool) Tester { 36 vt.t.Helper() 37 b := Bool(vt.v) 38 if b != wantBool { 39 vt.t.Errorf("Bool(v) = %v, want %v", b, wantBool) 40 } 41 return vt 42 } 43 44 // Hash tests the Hash of the value. 45 func (vt Tester) Hash(wantHash uint32) Tester { 46 vt.t.Helper() 47 hash := Hash(vt.v) 48 if hash != wantHash { 49 vt.t.Errorf("Hash(v) = %v, want %v", hash, wantHash) 50 } 51 return vt 52 } 53 54 // Len tests the Len of the value. 55 func (vt Tester) Len(wantLen int) Tester { 56 vt.t.Helper() 57 kind := Len(vt.v) 58 if kind != wantLen { 59 vt.t.Errorf("Len(v) = %v, want %v", kind, wantLen) 60 } 61 return vt 62 } 63 64 // Repr tests the Repr of the value. 65 func (vt Tester) Repr(wantRepr string) Tester { 66 vt.t.Helper() 67 kind := ReprPlain(vt.v) 68 if kind != wantRepr { 69 vt.t.Errorf("Repr(v) = %s, want %s", kind, wantRepr) 70 } 71 return vt 72 } 73 74 // Equal tests that the value is Equal to every of the given values. 75 func (vt Tester) Equal(others ...any) Tester { 76 vt.t.Helper() 77 for _, other := range others { 78 eq := Equal(vt.v, other) 79 if !eq { 80 vt.t.Errorf("Equal(v, %v) = false, want true", other) 81 } 82 } 83 return vt 84 } 85 86 // NotEqual tests that the value is not Equal to any of the given values. 87 func (vt Tester) NotEqual(others ...any) Tester { 88 vt.t.Helper() 89 for _, other := range others { 90 eq := Equal(vt.v, other) 91 if eq { 92 vt.t.Errorf("Equal(v, %v) = true, want false", other) 93 } 94 } 95 return vt 96 } 97 98 // HasKey tests that the value has each of the given keys. 99 func (vt Tester) HasKey(keys ...any) Tester { 100 vt.t.Helper() 101 for _, key := range keys { 102 has := HasKey(vt.v, key) 103 if !has { 104 vt.t.Errorf("HasKey(v, %v) = false, want true", key) 105 } 106 } 107 return vt 108 } 109 110 // HasNoKey tests that the value does not have any of the given keys. 111 func (vt Tester) HasNoKey(keys ...any) Tester { 112 vt.t.Helper() 113 for _, key := range keys { 114 has := HasKey(vt.v, key) 115 if has { 116 vt.t.Errorf("HasKey(v, %v) = true, want false", key) 117 } 118 } 119 return vt 120 } 121 122 // AllKeys tests that the given keys match what the result of IterateKeys on the 123 // value. 124 // 125 // NOTE: This now checks equality using reflect.DeepEqual, since all the builtin 126 // types have string keys. This can be changed in future to use Equal is the 127 // need arises. 128 func (vt Tester) AllKeys(wantKeys ...any) Tester { 129 vt.t.Helper() 130 keys, err := collectKeys(vt.v) 131 if err != nil { 132 vt.t.Errorf("IterateKeys(v, f) -> err %v, want nil", err) 133 } 134 if !reflect.DeepEqual(keys, wantKeys) { 135 vt.t.Errorf("IterateKeys(v, f) calls f with %v, want %v", keys, wantKeys) 136 } 137 return vt 138 } 139 140 func collectKeys(v any) ([]any, error) { 141 var keys []any 142 err := IterateKeys(v, func(k any) bool { 143 keys = append(keys, k) 144 return true 145 }) 146 return keys, err 147 } 148 149 // Index tests that Index'ing the value with the given key returns the wanted value 150 // and no error. 151 func (vt Tester) Index(key, wantVal any) Tester { 152 vt.t.Helper() 153 got, err := Index(vt.v, key) 154 if err != nil { 155 vt.t.Errorf("Index(v, %v) -> err %v, want nil", key, err) 156 } 157 if !Equal(got, wantVal) { 158 vt.t.Errorf("Index(v, %v) -> %v, want %v", key, got, wantVal) 159 } 160 return vt 161 } 162 163 // IndexError tests that Index'ing the value with the given key returns the given 164 // error. 165 func (vt Tester) IndexError(key any, wantErr error) Tester { 166 vt.t.Helper() 167 _, err := Index(vt.v, key) 168 if !reflect.DeepEqual(err, wantErr) { 169 vt.t.Errorf("Index(v, %v) -> err %v, want %v", key, err, wantErr) 170 } 171 return vt 172 } 173 174 // Assoc tests that Assoc'ing the value with the given key-value pair returns 175 // the wanted new value and no error. 176 func (vt Tester) Assoc(key, val, wantNew any) Tester { 177 vt.t.Helper() 178 got, err := Assoc(vt.v, key, val) 179 if err != nil { 180 vt.t.Errorf("Assoc(v, %v) -> err %v, want nil", key, err) 181 } 182 if !Equal(got, wantNew) { 183 vt.t.Errorf("Assoc(v, %v) -> %v, want %v", key, got, wantNew) 184 } 185 return vt 186 } 187 188 // AssocError tests that Assoc'ing the value with the given key-value pair 189 // returns the given error. 190 func (vt Tester) AssocError(key, val any, wantErr error) Tester { 191 vt.t.Helper() 192 _, err := Assoc(vt.v, key, val) 193 if !reflect.DeepEqual(err, wantErr) { 194 vt.t.Errorf("Assoc(v, %v) -> err %v, want %v", key, err, wantErr) 195 } 196 return vt 197 }