/ sdks / sandbox / go / testify_compat_test.go
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  }