src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/tt/tt_test.go (about) 1 package tt 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 ) 8 9 // Simple functions to test. 10 11 func add(x, y int) int { 12 return x + y 13 } 14 15 func addsub(x int, y int) (int, int) { 16 return x + y, x - y 17 } 18 19 func TestTest(t *testing.T) { 20 Test(t, test, 21 It("reports no errors for passing tests"). 22 Args(add, Args(1, 1).Rets(2)). 23 Rets([]testResult{{"", nil}}), 24 It("supports multiple tests"). 25 Args(add, Args(1, 1).Rets(2), Args(1, 2).Rets(3)), 26 It("supports for multiple return values"). 27 Args(addsub, Args(1, 2).Rets(3, -1)). 28 Rets([]testResult{{"", nil}}), 29 It("supports named tests"). 30 Args(add, It("can add 1 and 1").Args(1, 1).Rets(2)). 31 Rets([]testResult{{"can add 1 and 1", nil}}), 32 33 It("reports error for failed test"). 34 Args(Fn(add).Named("add"), Args(2, 2).Rets(5)). 35 Rets(testResultsMatcher{ 36 {"", []string{"add(2, 2) returns (-want +got):\n"}}, 37 }), 38 It("respects custom argument format strings when reporting errors"). 39 Args(Fn(add).Named("add").ArgsFmt("x = %d, y = %d"), Args(1, 2).Rets(5)). 40 Rets(testResultsMatcher{ 41 {"", []string{"add(x = 1, y = 2) returns (-want +got):\n"}}, 42 }), 43 ) 44 } 45 46 // An alternative to the exported [Test] that uses a mock test runner that 47 // collects results from all the subtests. 48 func test(fn any, tests ...*Case) []testResult { 49 var tr mockTestRunner 50 testInner[*mockSubtestRunner](&tr, fn, tests...) 51 return tr 52 } 53 54 // Mock implementations of testRunner and subtestRunner. 55 56 type testResult struct { 57 Name string 58 Errors []string 59 } 60 61 type mockTestRunner []testResult 62 63 func (tr *mockTestRunner) Helper() {} 64 65 func (tr *mockTestRunner) Run(name string, f func(*mockSubtestRunner)) bool { 66 sr := mockSubtestRunner{name, nil} 67 f(&sr) 68 *tr = append(*tr, testResult(sr)) 69 return len(sr.Errors) == 0 70 } 71 72 type mockSubtestRunner testResult 73 74 func (sr *mockSubtestRunner) Errorf(format string, args ...any) { 75 sr.Errors = append(sr.Errors, fmt.Sprintf(format, args...)) 76 } 77 78 // Matches []testResult, but doesn't check the exact content of the error 79 // messages, only that they contain a substring. 80 type testResultsMatcher []testResult 81 82 func (m testResultsMatcher) Match(ret RetValue) bool { 83 results, ok := ret.([]testResult) 84 if !ok { 85 return false 86 } 87 if len(results) != len(m) { 88 return false 89 } 90 for i, result := range results { 91 if result.Name != m[i].Name || len(result.Errors) != len(m[i].Errors) { 92 return false 93 } 94 for i, s := range result.Errors { 95 if !strings.Contains(s, m[i].Errors[i]) { 96 return false 97 } 98 } 99 } 100 return true 101 }