testify_compat_test.go
1 // Copyright 2026 Alibaba Group Holding Ltd. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package opensandbox 16 17 import ( 18 "errors" 19 "fmt" 20 "reflect" 21 "strings" 22 "testing" 23 "time" 24 ) 25 26 type assertCompat struct{} 27 type requireCompat struct{} 28 29 var ( 30 assert = assertCompat{} 31 require = requireCompat{} 32 ) 33 34 func (assertCompat) Fail(t *testing.T, failureMessage string, msgAndArgs ...any) bool { 35 t.Helper() 36 t.Errorf("%s", joinMessage(failureMessage, msgAndArgs...)) 37 return false 38 } 39 40 func (assertCompat) ErrorAs(t *testing.T, err error, target any, msgAndArgs ...any) bool { 41 t.Helper() 42 if errors.As(err, target) { 43 return true 44 } 45 t.Errorf("%s", joinMessage(fmt.Sprintf("expected error %v to match target %T", err, target), msgAndArgs...)) 46 return false 47 } 48 49 func (assertCompat) Contains(t *testing.T, s string, contains string, msgAndArgs ...any) bool { 50 t.Helper() 51 if strings.Contains(s, contains) { 52 return true 53 } 54 t.Errorf("%s", joinMessage(fmt.Sprintf("expected %q to contain %q", s, contains), msgAndArgs...)) 55 return false 56 } 57 58 func (requireCompat) FailNow(t *testing.T, failureMessage string, msgAndArgs ...any) { 59 t.Helper() 60 t.Fatalf("%s", joinMessage(failureMessage, msgAndArgs...)) 61 } 62 63 func (requireCompat) NoError(t *testing.T, err error, msgAndArgs ...any) { 64 t.Helper() 65 if err == nil { 66 return 67 } 68 t.Fatalf("%s", joinMessage(fmt.Sprintf("expected no error, got %v", err), msgAndArgs...)) 69 } 70 71 func (requireCompat) NoErrorf(t *testing.T, err error, msg string, args ...any) { 72 t.Helper() 73 if err == nil { 74 return 75 } 76 t.Fatalf("%s: %v", fmt.Sprintf(msg, args...), err) 77 } 78 79 func (requireCompat) Error(t *testing.T, err error, msgAndArgs ...any) { 80 t.Helper() 81 if err != nil { 82 return 83 } 84 t.Fatalf("%s", joinMessage("expected error, got nil", msgAndArgs...)) 85 } 86 87 func (requireCompat) ErrorAs(t *testing.T, err error, target any, msgAndArgs ...any) { 88 t.Helper() 89 if errors.As(err, target) { 90 return 91 } 92 t.Fatalf("%s", joinMessage(fmt.Sprintf("expected error %v to match target %T", err, target), msgAndArgs...)) 93 } 94 95 func (requireCompat) ErrorIs(t *testing.T, err error, target error, msgAndArgs ...any) { 96 t.Helper() 97 if errors.Is(err, target) { 98 return 99 } 100 t.Fatalf("%s", joinMessage(fmt.Sprintf("expected error %v to match %v", err, target), msgAndArgs...)) 101 } 102 103 func (requireCompat) True(t *testing.T, value bool, msgAndArgs ...any) { 104 t.Helper() 105 if value { 106 return 107 } 108 t.Fatalf("%s", joinMessage("expected true, got false", msgAndArgs...)) 109 } 110 111 func (requireCompat) Len(t *testing.T, object any, length int, msgAndArgs ...any) { 112 t.Helper() 113 v := reflect.ValueOf(object) 114 switch v.Kind() { 115 case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String: 116 if v.Len() == length { 117 return 118 } 119 t.Fatalf("%s", joinMessage(fmt.Sprintf("expected length %d, got %d", length, v.Len()), msgAndArgs...)) 120 default: 121 t.Fatalf("%s", joinMessage(fmt.Sprintf("cannot get length of %T", object), msgAndArgs...)) 122 } 123 } 124 125 func (requireCompat) NotNil(t *testing.T, object any, msgAndArgs ...any) { 126 t.Helper() 127 if !isNil(object) { 128 return 129 } 130 t.Fatalf("%s", joinMessage("expected value not to be nil", msgAndArgs...)) 131 } 132 133 func (requireCompat) Equal(t *testing.T, expected any, actual any, msgAndArgs ...any) { 134 t.Helper() 135 if reflect.DeepEqual(expected, actual) { 136 return 137 } 138 t.Fatalf("%s", joinMessage(fmt.Sprintf("expected %v, got %v", expected, actual), msgAndArgs...)) 139 } 140 141 func (requireCompat) NotEmpty(t *testing.T, object any, msgAndArgs ...any) { 142 t.Helper() 143 if !isEmpty(object) { 144 return 145 } 146 t.Fatalf("%s", joinMessage("expected value not to be empty", msgAndArgs...)) 147 } 148 149 func (requireCompat) LessOrEqual(t *testing.T, a any, b any, msgAndArgs ...any) { 150 t.Helper() 151 switch left := a.(type) { 152 case time.Duration: 153 right, ok := b.(time.Duration) 154 if !ok { 155 t.Fatalf("%s", joinMessage(fmt.Sprintf("cannot compare %T and %T", a, b), msgAndArgs...)) 156 } 157 if left <= right { 158 return 159 } 160 t.Fatalf("%s", joinMessage(fmt.Sprintf("expected %v <= %v", left, right), msgAndArgs...)) 161 default: 162 t.Fatalf("%s", joinMessage(fmt.Sprintf("unsupported LessOrEqual type %T", a), msgAndArgs...)) 163 } 164 } 165 166 func isNil(v any) bool { 167 if v == nil { 168 return true 169 } 170 rv := reflect.ValueOf(v) 171 switch rv.Kind() { 172 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice: 173 return rv.IsNil() 174 default: 175 return false 176 } 177 } 178 179 func isEmpty(v any) bool { 180 if v == nil { 181 return true 182 } 183 rv := reflect.ValueOf(v) 184 switch rv.Kind() { 185 case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String: 186 return rv.Len() == 0 187 default: 188 zero := reflect.Zero(rv.Type()).Interface() 189 return reflect.DeepEqual(v, zero) 190 } 191 } 192 193 func joinMessage(base string, msgAndArgs ...any) string { 194 if len(msgAndArgs) == 0 { 195 return base 196 } 197 if format, ok := msgAndArgs[0].(string); ok { 198 if len(msgAndArgs) == 1 { 199 return fmt.Sprintf("%s: %s", base, format) 200 } 201 return fmt.Sprintf("%s: %s", base, fmt.Sprintf(format, msgAndArgs[1:]...)) 202 } 203 return fmt.Sprintf("%s: %v", base, msgAndArgs) 204 }