How to use NewT method of td Package

Best Go-testdeep code snippet using td.NewT

example_t_test.go

Source:example_t_test.go Github

copy

Full Screen

...20 "time"21 "github.com/maxatome/go-testdeep/td"22)23func ExampleT_All() {24 t := td.NewT(&testing.T{})25 got := "foo/bar"26 // Checks got string against:27 // "o/b" regexp *AND* "bar" suffix *AND* exact "foo/bar" string28 ok := t.All(got, []any{td.Re("o/b"), td.HasSuffix("bar"), "foo/bar"},29 "checks value %s", got)30 fmt.Println(ok)31 // Checks got string against:32 // "o/b" regexp *AND* "bar" suffix *AND* exact "fooX/Ybar" string33 ok = t.All(got, []any{td.Re("o/b"), td.HasSuffix("bar"), "fooX/Ybar"},34 "checks value %s", got)35 fmt.Println(ok)36 // When some operators or values have to be reused and mixed between37 // several calls, Flatten can be used to avoid boring and38 // inefficient []any copies:39 regOps := td.Flatten([]td.TestDeep{td.Re("o/b"), td.Re(`^fo`), td.Re(`ar$`)})40 ok = t.All(got, []any{td.HasPrefix("foo"), regOps, td.HasSuffix("bar")},41 "checks all operators against value %s", got)42 fmt.Println(ok)43 // Output:44 // true45 // false46 // true47}48func ExampleT_Any() {49 t := td.NewT(&testing.T{})50 got := "foo/bar"51 // Checks got string against:52 // "zip" regexp *OR* "bar" suffix53 ok := t.Any(got, []any{td.Re("zip"), td.HasSuffix("bar")},54 "checks value %s", got)55 fmt.Println(ok)56 // Checks got string against:57 // "zip" regexp *OR* "foo" suffix58 ok = t.Any(got, []any{td.Re("zip"), td.HasSuffix("foo")},59 "checks value %s", got)60 fmt.Println(ok)61 // When some operators or values have to be reused and mixed between62 // several calls, Flatten can be used to avoid boring and63 // inefficient []any copies:64 regOps := td.Flatten([]td.TestDeep{td.Re("a/c"), td.Re(`^xx`), td.Re(`ar$`)})65 ok = t.Any(got, []any{td.HasPrefix("xxx"), regOps, td.HasSuffix("zip")},66 "check at least one operator matches value %s", got)67 fmt.Println(ok)68 // Output:69 // true70 // false71 // true72}73func ExampleT_Array_array() {74 t := td.NewT(&testing.T{})75 got := [3]int{42, 58, 26}76 ok := t.Array(got, [3]int{42}, td.ArrayEntries{1: 58, 2: td.Ignore()},77 "checks array %v", got)78 fmt.Println("Simple array:", ok)79 ok = t.Array(&got, &[3]int{42}, td.ArrayEntries{1: 58, 2: td.Ignore()},80 "checks array %v", got)81 fmt.Println("Array pointer:", ok)82 ok = t.Array(&got, (*[3]int)(nil), td.ArrayEntries{0: 42, 1: 58, 2: td.Ignore()},83 "checks array %v", got)84 fmt.Println("Array pointer, nil model:", ok)85 // Output:86 // Simple array: true87 // Array pointer: true88 // Array pointer, nil model: true89}90func ExampleT_Array_typedArray() {91 t := td.NewT(&testing.T{})92 type MyArray [3]int93 got := MyArray{42, 58, 26}94 ok := t.Array(got, MyArray{42}, td.ArrayEntries{1: 58, 2: td.Ignore()},95 "checks typed array %v", got)96 fmt.Println("Typed array:", ok)97 ok = t.Array(&got, &MyArray{42}, td.ArrayEntries{1: 58, 2: td.Ignore()},98 "checks pointer on typed array %v", got)99 fmt.Println("Pointer on a typed array:", ok)100 ok = t.Array(&got, &MyArray{}, td.ArrayEntries{0: 42, 1: 58, 2: td.Ignore()},101 "checks pointer on typed array %v", got)102 fmt.Println("Pointer on a typed array, empty model:", ok)103 ok = t.Array(&got, (*MyArray)(nil), td.ArrayEntries{0: 42, 1: 58, 2: td.Ignore()},104 "checks pointer on typed array %v", got)105 fmt.Println("Pointer on a typed array, nil model:", ok)106 // Output:107 // Typed array: true108 // Pointer on a typed array: true109 // Pointer on a typed array, empty model: true110 // Pointer on a typed array, nil model: true111}112func ExampleT_ArrayEach_array() {113 t := td.NewT(&testing.T{})114 got := [3]int{42, 58, 26}115 ok := t.ArrayEach(got, td.Between(25, 60),116 "checks each item of array %v is in [25 .. 60]", got)117 fmt.Println(ok)118 // Output:119 // true120}121func ExampleT_ArrayEach_typedArray() {122 t := td.NewT(&testing.T{})123 type MyArray [3]int124 got := MyArray{42, 58, 26}125 ok := t.ArrayEach(got, td.Between(25, 60),126 "checks each item of typed array %v is in [25 .. 60]", got)127 fmt.Println(ok)128 ok = t.ArrayEach(&got, td.Between(25, 60),129 "checks each item of typed array pointer %v is in [25 .. 60]", got)130 fmt.Println(ok)131 // Output:132 // true133 // true134}135func ExampleT_ArrayEach_slice() {136 t := td.NewT(&testing.T{})137 got := []int{42, 58, 26}138 ok := t.ArrayEach(got, td.Between(25, 60),139 "checks each item of slice %v is in [25 .. 60]", got)140 fmt.Println(ok)141 // Output:142 // true143}144func ExampleT_ArrayEach_typedSlice() {145 t := td.NewT(&testing.T{})146 type MySlice []int147 got := MySlice{42, 58, 26}148 ok := t.ArrayEach(got, td.Between(25, 60),149 "checks each item of typed slice %v is in [25 .. 60]", got)150 fmt.Println(ok)151 ok = t.ArrayEach(&got, td.Between(25, 60),152 "checks each item of typed slice pointer %v is in [25 .. 60]", got)153 fmt.Println(ok)154 // Output:155 // true156 // true157}158func ExampleT_Bag() {159 t := td.NewT(&testing.T{})160 got := []int{1, 3, 5, 8, 8, 1, 2}161 // Matches as all items are present162 ok := t.Bag(got, []any{1, 1, 2, 3, 5, 8, 8},163 "checks all items are present, in any order")164 fmt.Println(ok)165 // Does not match as got contains 2 times 1 and 8, and these166 // duplicates are not expected167 ok = t.Bag(got, []any{1, 2, 3, 5, 8},168 "checks all items are present, in any order")169 fmt.Println(ok)170 got = []int{1, 3, 5, 8, 2}171 // Duplicates of 1 and 8 are expected but not present in got172 ok = t.Bag(got, []any{1, 1, 2, 3, 5, 8, 8},173 "checks all items are present, in any order")174 fmt.Println(ok)175 // Matches as all items are present176 ok = t.Bag(got, []any{1, 2, 3, 5, td.Gt(7)},177 "checks all items are present, in any order")178 fmt.Println(ok)179 // When expected is already a non-[]any slice, it cannot be180 // flattened directly using expected... without copying it to a new181 // []any slice, then use td.Flatten!182 expected := []int{1, 2, 3, 5}183 ok = t.Bag(got, []any{td.Flatten(expected), td.Gt(7)},184 "checks all expected items are present, in any order")185 fmt.Println(ok)186 // Output:187 // true188 // false189 // false190 // true191 // true192}193func ExampleT_Between_int() {194 t := td.NewT(&testing.T{})195 got := 156196 ok := t.Between(got, 154, 156, td.BoundsInIn,197 "checks %v is in [154 .. 156]", got)198 fmt.Println(ok)199 // BoundsInIn is implicit200 ok = t.Between(got, 154, 156, td.BoundsInIn,201 "checks %v is in [154 .. 156]", got)202 fmt.Println(ok)203 ok = t.Between(got, 154, 156, td.BoundsInOut,204 "checks %v is in [154 .. 156[", got)205 fmt.Println(ok)206 ok = t.Between(got, 154, 156, td.BoundsOutIn,207 "checks %v is in ]154 .. 156]", got)208 fmt.Println(ok)209 ok = t.Between(got, 154, 156, td.BoundsOutOut,210 "checks %v is in ]154 .. 156[", got)211 fmt.Println(ok)212 // Output:213 // true214 // true215 // false216 // true217 // false218}219func ExampleT_Between_string() {220 t := td.NewT(&testing.T{})221 got := "abc"222 ok := t.Between(got, "aaa", "abc", td.BoundsInIn,223 `checks "%v" is in ["aaa" .. "abc"]`, got)224 fmt.Println(ok)225 // BoundsInIn is implicit226 ok = t.Between(got, "aaa", "abc", td.BoundsInIn,227 `checks "%v" is in ["aaa" .. "abc"]`, got)228 fmt.Println(ok)229 ok = t.Between(got, "aaa", "abc", td.BoundsInOut,230 `checks "%v" is in ["aaa" .. "abc"[`, got)231 fmt.Println(ok)232 ok = t.Between(got, "aaa", "abc", td.BoundsOutIn,233 `checks "%v" is in ]"aaa" .. "abc"]`, got)234 fmt.Println(ok)235 ok = t.Between(got, "aaa", "abc", td.BoundsOutOut,236 `checks "%v" is in ]"aaa" .. "abc"[`, got)237 fmt.Println(ok)238 // Output:239 // true240 // true241 // false242 // true243 // false244}245func ExampleT_Between_time() {246 t := td.NewT(&testing.T{})247 before := time.Now()248 occurredAt := time.Now()249 after := time.Now()250 ok := t.Between(occurredAt, before, after, td.BoundsInIn)251 fmt.Println("It occurred between before and after:", ok)252 type MyTime time.Time253 ok = t.Between(MyTime(occurredAt), MyTime(before), MyTime(after), td.BoundsInIn)254 fmt.Println("Same for convertible MyTime type:", ok)255 ok = t.Between(MyTime(occurredAt), before, after, td.BoundsInIn)256 fmt.Println("MyTime vs time.Time:", ok)257 ok = t.Between(occurredAt, before, 10*time.Second, td.BoundsInIn)258 fmt.Println("Using a time.Duration as TO:", ok)259 ok = t.Between(MyTime(occurredAt), MyTime(before), 10*time.Second, td.BoundsInIn)260 fmt.Println("Using MyTime as FROM and time.Duration as TO:", ok)261 // Output:262 // It occurred between before and after: true263 // Same for convertible MyTime type: true264 // MyTime vs time.Time: false265 // Using a time.Duration as TO: true266 // Using MyTime as FROM and time.Duration as TO: true267}268func ExampleT_Cap() {269 t := td.NewT(&testing.T{})270 got := make([]int, 0, 12)271 ok := t.Cap(got, 12, "checks %v capacity is 12", got)272 fmt.Println(ok)273 ok = t.Cap(got, 0, "checks %v capacity is 0", got)274 fmt.Println(ok)275 got = nil276 ok = t.Cap(got, 0, "checks %v capacity is 0", got)277 fmt.Println(ok)278 // Output:279 // true280 // false281 // true282}283func ExampleT_Cap_operator() {284 t := td.NewT(&testing.T{})285 got := make([]int, 0, 12)286 ok := t.Cap(got, td.Between(10, 12),287 "checks %v capacity is in [10 .. 12]", got)288 fmt.Println(ok)289 ok = t.Cap(got, td.Gt(10),290 "checks %v capacity is in [10 .. 12]", got)291 fmt.Println(ok)292 // Output:293 // true294 // true295}296func ExampleT_Code() {297 t := td.NewT(&testing.T{})298 got := "12"299 ok := t.Code(got, func(num string) bool {300 n, err := strconv.Atoi(num)301 return err == nil && n > 10 && n < 100302 },303 "checks string `%s` contains a number and this number is in ]10 .. 100[",304 got)305 fmt.Println(ok)306 // Same with failure reason307 ok = t.Code(got, func(num string) (bool, string) {308 n, err := strconv.Atoi(num)309 if err != nil {310 return false, "not a number"311 }312 if n > 10 && n < 100 {313 return true, ""314 }315 return false, "not in ]10 .. 100["316 },317 "checks string `%s` contains a number and this number is in ]10 .. 100[",318 got)319 fmt.Println(ok)320 // Same with failure reason thanks to error321 ok = t.Code(got, func(num string) error {322 n, err := strconv.Atoi(num)323 if err != nil {324 return err325 }326 if n > 10 && n < 100 {327 return nil328 }329 return fmt.Errorf("%d not in ]10 .. 100[", n)330 },331 "checks string `%s` contains a number and this number is in ]10 .. 100[",332 got)333 fmt.Println(ok)334 // Output:335 // true336 // true337 // true338}339func ExampleT_Code_custom() {340 t := td.NewT(&testing.T{})341 got := 123342 ok := t.Code(got, func(t *td.T, num int) {343 t.Cmp(num, 123)344 })345 fmt.Println("with one *td.T:", ok)346 ok = t.Code(got, func(assert, require *td.T, num int) {347 assert.Cmp(num, 123)348 require.Cmp(num, 123)349 })350 fmt.Println("with assert & require *td.T:", ok)351 // Output:352 // with one *td.T: true353 // with assert & require *td.T: true354}355func ExampleT_Contains_arraySlice() {356 t := td.NewT(&testing.T{})357 ok := t.Contains([...]int{11, 22, 33, 44}, 22)358 fmt.Println("array contains 22:", ok)359 ok = t.Contains([...]int{11, 22, 33, 44}, td.Between(20, 25))360 fmt.Println("array contains at least one item in [20 .. 25]:", ok)361 ok = t.Contains([]int{11, 22, 33, 44}, 22)362 fmt.Println("slice contains 22:", ok)363 ok = t.Contains([]int{11, 22, 33, 44}, td.Between(20, 25))364 fmt.Println("slice contains at least one item in [20 .. 25]:", ok)365 ok = t.Contains([]int{11, 22, 33, 44}, []int{22, 33})366 fmt.Println("slice contains the sub-slice [22, 33]:", ok)367 // Output:368 // array contains 22: true369 // array contains at least one item in [20 .. 25]: true370 // slice contains 22: true371 // slice contains at least one item in [20 .. 25]: true372 // slice contains the sub-slice [22, 33]: true373}374func ExampleT_Contains_nil() {375 t := td.NewT(&testing.T{})376 num := 123377 got := [...]*int{&num, nil}378 ok := t.Contains(got, nil)379 fmt.Println("array contains untyped nil:", ok)380 ok = t.Contains(got, (*int)(nil))381 fmt.Println("array contains *int nil:", ok)382 ok = t.Contains(got, td.Nil())383 fmt.Println("array contains Nil():", ok)384 ok = t.Contains(got, (*byte)(nil))385 fmt.Println("array contains *byte nil:", ok) // types differ: *byte ≠ *int386 // Output:387 // array contains untyped nil: true388 // array contains *int nil: true389 // array contains Nil(): true390 // array contains *byte nil: false391}392func ExampleT_Contains_map() {393 t := td.NewT(&testing.T{})394 ok := t.Contains(map[string]int{"foo": 11, "bar": 22, "zip": 33}, 22)395 fmt.Println("map contains value 22:", ok)396 ok = t.Contains(map[string]int{"foo": 11, "bar": 22, "zip": 33}, td.Between(20, 25))397 fmt.Println("map contains at least one value in [20 .. 25]:", ok)398 // Output:399 // map contains value 22: true400 // map contains at least one value in [20 .. 25]: true401}402func ExampleT_Contains_string() {403 t := td.NewT(&testing.T{})404 got := "foobar"405 ok := t.Contains(got, "oob", "checks %s", got)406 fmt.Println("contains `oob` string:", ok)407 ok = t.Contains(got, []byte("oob"), "checks %s", got)408 fmt.Println("contains `oob` []byte:", ok)409 ok = t.Contains(got, 'b', "checks %s", got)410 fmt.Println("contains 'b' rune:", ok)411 ok = t.Contains(got, byte('a'), "checks %s", got)412 fmt.Println("contains 'a' byte:", ok)413 ok = t.Contains(got, td.Between('n', 'p'), "checks %s", got)414 fmt.Println("contains at least one character ['n' .. 'p']:", ok)415 // Output:416 // contains `oob` string: true417 // contains `oob` []byte: true418 // contains 'b' rune: true419 // contains 'a' byte: true420 // contains at least one character ['n' .. 'p']: true421}422func ExampleT_Contains_stringer() {423 t := td.NewT(&testing.T{})424 // bytes.Buffer implements fmt.Stringer425 got := bytes.NewBufferString("foobar")426 ok := t.Contains(got, "oob", "checks %s", got)427 fmt.Println("contains `oob` string:", ok)428 ok = t.Contains(got, 'b', "checks %s", got)429 fmt.Println("contains 'b' rune:", ok)430 ok = t.Contains(got, byte('a'), "checks %s", got)431 fmt.Println("contains 'a' byte:", ok)432 ok = t.Contains(got, td.Between('n', 'p'), "checks %s", got)433 fmt.Println("contains at least one character ['n' .. 'p']:", ok)434 // Output:435 // contains `oob` string: true436 // contains 'b' rune: true437 // contains 'a' byte: true438 // contains at least one character ['n' .. 'p']: true439}440func ExampleT_Contains_error() {441 t := td.NewT(&testing.T{})442 got := errors.New("foobar")443 ok := t.Contains(got, "oob", "checks %s", got)444 fmt.Println("contains `oob` string:", ok)445 ok = t.Contains(got, 'b', "checks %s", got)446 fmt.Println("contains 'b' rune:", ok)447 ok = t.Contains(got, byte('a'), "checks %s", got)448 fmt.Println("contains 'a' byte:", ok)449 ok = t.Contains(got, td.Between('n', 'p'), "checks %s", got)450 fmt.Println("contains at least one character ['n' .. 'p']:", ok)451 // Output:452 // contains `oob` string: true453 // contains 'b' rune: true454 // contains 'a' byte: true455 // contains at least one character ['n' .. 'p']: true456}457func ExampleT_ContainsKey() {458 t := td.NewT(&testing.T{})459 ok := t.ContainsKey(map[string]int{"foo": 11, "bar": 22, "zip": 33}, "foo")460 fmt.Println(`map contains key "foo":`, ok)461 ok = t.ContainsKey(map[int]bool{12: true, 24: false, 42: true, 51: false}, td.Between(40, 50))462 fmt.Println("map contains at least a key in [40 .. 50]:", ok)463 ok = t.ContainsKey(map[string]int{"FOO": 11, "bar": 22, "zip": 33}, td.Smuggle(strings.ToLower, "foo"))464 fmt.Println(`map contains key "foo" without taking case into account:`, ok)465 // Output:466 // map contains key "foo": true467 // map contains at least a key in [40 .. 50]: true468 // map contains key "foo" without taking case into account: true469}470func ExampleT_ContainsKey_nil() {471 t := td.NewT(&testing.T{})472 num := 1234473 got := map[*int]bool{&num: false, nil: true}474 ok := t.ContainsKey(got, nil)475 fmt.Println("map contains untyped nil key:", ok)476 ok = t.ContainsKey(got, (*int)(nil))477 fmt.Println("map contains *int nil key:", ok)478 ok = t.ContainsKey(got, td.Nil())479 fmt.Println("map contains Nil() key:", ok)480 ok = t.ContainsKey(got, (*byte)(nil))481 fmt.Println("map contains *byte nil key:", ok) // types differ: *byte ≠ *int482 // Output:483 // map contains untyped nil key: true484 // map contains *int nil key: true485 // map contains Nil() key: true486 // map contains *byte nil key: false487}488func ExampleT_Empty() {489 t := td.NewT(&testing.T{})490 ok := t.Empty(nil) // special case: nil is considered empty491 fmt.Println(ok)492 // fails, typed nil is not empty (expect for channel, map, slice or493 // pointers on array, channel, map slice and strings)494 ok = t.Empty((*int)(nil))495 fmt.Println(ok)496 ok = t.Empty("")497 fmt.Println(ok)498 // Fails as 0 is a number, so not empty. Use Zero() instead499 ok = t.Empty(0)500 fmt.Println(ok)501 ok = t.Empty((map[string]int)(nil))502 fmt.Println(ok)503 ok = t.Empty(map[string]int{})504 fmt.Println(ok)505 ok = t.Empty(([]int)(nil))506 fmt.Println(ok)507 ok = t.Empty([]int{})508 fmt.Println(ok)509 ok = t.Empty([]int{3}) // fails, as not empty510 fmt.Println(ok)511 ok = t.Empty([3]int{}) // fails, Empty() is not Zero()!512 fmt.Println(ok)513 // Output:514 // true515 // false516 // true517 // false518 // true519 // true520 // true521 // true522 // false523 // false524}525func ExampleT_Empty_pointers() {526 t := td.NewT(&testing.T{})527 type MySlice []int528 ok := t.Empty(MySlice{}) // Ptr() not needed529 fmt.Println(ok)530 ok = t.Empty(&MySlice{})531 fmt.Println(ok)532 l1 := &MySlice{}533 l2 := &l1534 l3 := &l2535 ok = t.Empty(&l3)536 fmt.Println(ok)537 // Works the same for array, map, channel and string538 // But not for others types as:539 type MyStruct struct {540 Value int541 }542 ok = t.Empty(&MyStruct{}) // fails, use Zero() instead543 fmt.Println(ok)544 // Output:545 // true546 // true547 // true548 // false549}550func ExampleT_CmpErrorIs() {551 t := td.NewT(&testing.T{})552 err1 := fmt.Errorf("failure1")553 err2 := fmt.Errorf("failure2: %w", err1)554 err3 := fmt.Errorf("failure3: %w", err2)555 err := fmt.Errorf("failure4: %w", err3)556 ok := t.CmpErrorIs(err, err)557 fmt.Println("error is itself:", ok)558 ok = t.CmpErrorIs(err, err1)559 fmt.Println("error is also err1:", ok)560 ok = t.CmpErrorIs(err1, err)561 fmt.Println("err1 is err:", ok)562 // Output:563 // error is itself: true564 // error is also err1: true565 // err1 is err: false566}567func ExampleT_First_classic() {568 t := td.NewT(&testing.T{})569 got := []int{-3, -2, -1, 0, 1, 2, 3}570 ok := t.First(got, td.Gt(0), 1)571 fmt.Println("first positive number is 1:", ok)572 isEven := func(x int) bool { return x%2 == 0 }573 ok = t.First(got, isEven, -2)574 fmt.Println("first even number is -2:", ok)575 ok = t.First(got, isEven, td.Lt(0))576 fmt.Println("first even number is < 0:", ok)577 ok = t.First(got, isEven, td.Code(isEven))578 fmt.Println("first even number is well even:", ok)579 // Output:580 // first positive number is 1: true581 // first even number is -2: true582 // first even number is < 0: true583 // first even number is well even: true584}585func ExampleT_First_empty() {586 t := td.NewT(&testing.T{})587 ok := t.First(([]int)(nil), td.Gt(0), td.Gt(0))588 fmt.Println("first in nil slice:", ok)589 ok = t.First([]int{}, td.Gt(0), td.Gt(0))590 fmt.Println("first in empty slice:", ok)591 ok = t.First(&[]int{}, td.Gt(0), td.Gt(0))592 fmt.Println("first in empty pointed slice:", ok)593 ok = t.First([0]int{}, td.Gt(0), td.Gt(0))594 fmt.Println("first in empty array:", ok)595 // Output:596 // first in nil slice: false597 // first in empty slice: false598 // first in empty pointed slice: false599 // first in empty array: false600}601func ExampleT_First_struct() {602 t := td.NewT(&testing.T{})603 type Person struct {604 Fullname string `json:"fullname"`605 Age int `json:"age"`606 }607 got := []*Person{608 {609 Fullname: "Bob Foobar",610 Age: 42,611 },612 {613 Fullname: "Alice Bingo",614 Age: 37,615 },616 }617 ok := t.First(got, td.Smuggle("Age", td.Gt(30)), td.Smuggle("Fullname", "Bob Foobar"))618 fmt.Println("first person.Age > 30 → Bob:", ok)619 ok = t.First(got, td.JSONPointer("/age", td.Gt(30)), td.SuperJSONOf(`{"fullname":"Bob Foobar"}`))620 fmt.Println("first person.Age > 30 → Bob, using JSON:", ok)621 ok = t.First(got, td.JSONPointer("/age", td.Gt(30)), td.JSONPointer("/fullname", td.HasPrefix("Bob")))622 fmt.Println("first person.Age > 30 → Bob, using JSONPointer:", ok)623 // Output:624 // first person.Age > 30 → Bob: true625 // first person.Age > 30 → Bob, using JSON: true626 // first person.Age > 30 → Bob, using JSONPointer: true627}628func ExampleT_Grep_classic() {629 t := td.NewT(&testing.T{})630 got := []int{-3, -2, -1, 0, 1, 2, 3}631 ok := t.Grep(got, td.Gt(0), []int{1, 2, 3})632 fmt.Println("check positive numbers:", ok)633 isEven := func(x int) bool { return x%2 == 0 }634 ok = t.Grep(got, isEven, []int{-2, 0, 2})635 fmt.Println("even numbers are -2, 0 and 2:", ok)636 ok = t.Grep(got, isEven, td.Set(0, 2, -2))637 fmt.Println("even numbers are also 0, 2 and -2:", ok)638 ok = t.Grep(got, isEven, td.ArrayEach(td.Code(isEven)))639 fmt.Println("even numbers are each even:", ok)640 // Output:641 // check positive numbers: true642 // even numbers are -2, 0 and 2: true643 // even numbers are also 0, 2 and -2: true644 // even numbers are each even: true645}646func ExampleT_Grep_nil() {647 t := td.NewT(&testing.T{})648 var got []int649 ok := t.Grep(got, td.Gt(0), ([]int)(nil))650 fmt.Println("typed []int nil:", ok)651 ok = t.Grep(got, td.Gt(0), ([]string)(nil))652 fmt.Println("typed []string nil:", ok)653 ok = t.Grep(got, td.Gt(0), td.Nil())654 fmt.Println("td.Nil:", ok)655 ok = t.Grep(got, td.Gt(0), []int{})656 fmt.Println("empty non-nil slice:", ok)657 // Output:658 // typed []int nil: true659 // typed []string nil: false660 // td.Nil: true661 // empty non-nil slice: false662}663func ExampleT_Grep_struct() {664 t := td.NewT(&testing.T{})665 type Person struct {666 Fullname string `json:"fullname"`667 Age int `json:"age"`668 }669 got := []*Person{670 {671 Fullname: "Bob Foobar",672 Age: 42,673 },674 {675 Fullname: "Alice Bingo",676 Age: 27,677 },678 }679 ok := t.Grep(got, td.Smuggle("Age", td.Gt(30)), td.All(680 td.Len(1),681 td.ArrayEach(td.Smuggle("Fullname", "Bob Foobar")),682 ))683 fmt.Println("person.Age > 30 → only Bob:", ok)684 ok = t.Grep(got, td.JSONPointer("/age", td.Gt(30)), td.JSON(`[ SuperMapOf({"fullname":"Bob Foobar"}) ]`))685 fmt.Println("person.Age > 30 → only Bob, using JSON:", ok)686 // Output:687 // person.Age > 30 → only Bob: true688 // person.Age > 30 → only Bob, using JSON: true689}690func ExampleT_Gt_int() {691 t := td.NewT(&testing.T{})692 got := 156693 ok := t.Gt(got, 155, "checks %v is > 155", got)694 fmt.Println(ok)695 ok = t.Gt(got, 156, "checks %v is > 156", got)696 fmt.Println(ok)697 // Output:698 // true699 // false700}701func ExampleT_Gt_string() {702 t := td.NewT(&testing.T{})703 got := "abc"704 ok := t.Gt(got, "abb", `checks "%v" is > "abb"`, got)705 fmt.Println(ok)706 ok = t.Gt(got, "abc", `checks "%v" is > "abc"`, got)707 fmt.Println(ok)708 // Output:709 // true710 // false711}712func ExampleT_Gte_int() {713 t := td.NewT(&testing.T{})714 got := 156715 ok := t.Gte(got, 156, "checks %v is ≥ 156", got)716 fmt.Println(ok)717 ok = t.Gte(got, 155, "checks %v is ≥ 155", got)718 fmt.Println(ok)719 ok = t.Gte(got, 157, "checks %v is ≥ 157", got)720 fmt.Println(ok)721 // Output:722 // true723 // true724 // false725}726func ExampleT_Gte_string() {727 t := td.NewT(&testing.T{})728 got := "abc"729 ok := t.Gte(got, "abc", `checks "%v" is ≥ "abc"`, got)730 fmt.Println(ok)731 ok = t.Gte(got, "abb", `checks "%v" is ≥ "abb"`, got)732 fmt.Println(ok)733 ok = t.Gte(got, "abd", `checks "%v" is ≥ "abd"`, got)734 fmt.Println(ok)735 // Output:736 // true737 // true738 // false739}740func ExampleT_HasPrefix() {741 t := td.NewT(&testing.T{})742 got := "foobar"743 ok := t.HasPrefix(got, "foo", "checks %s", got)744 fmt.Println("using string:", ok)745 ok = t.Cmp([]byte(got), td.HasPrefix("foo"), "checks %s", got)746 fmt.Println("using []byte:", ok)747 // Output:748 // using string: true749 // using []byte: true750}751func ExampleT_HasPrefix_stringer() {752 t := td.NewT(&testing.T{})753 // bytes.Buffer implements fmt.Stringer754 got := bytes.NewBufferString("foobar")755 ok := t.HasPrefix(got, "foo", "checks %s", got)756 fmt.Println(ok)757 // Output:758 // true759}760func ExampleT_HasPrefix_error() {761 t := td.NewT(&testing.T{})762 got := errors.New("foobar")763 ok := t.HasPrefix(got, "foo", "checks %s", got)764 fmt.Println(ok)765 // Output:766 // true767}768func ExampleT_HasSuffix() {769 t := td.NewT(&testing.T{})770 got := "foobar"771 ok := t.HasSuffix(got, "bar", "checks %s", got)772 fmt.Println("using string:", ok)773 ok = t.Cmp([]byte(got), td.HasSuffix("bar"), "checks %s", got)774 fmt.Println("using []byte:", ok)775 // Output:776 // using string: true777 // using []byte: true778}779func ExampleT_HasSuffix_stringer() {780 t := td.NewT(&testing.T{})781 // bytes.Buffer implements fmt.Stringer782 got := bytes.NewBufferString("foobar")783 ok := t.HasSuffix(got, "bar", "checks %s", got)784 fmt.Println(ok)785 // Output:786 // true787}788func ExampleT_HasSuffix_error() {789 t := td.NewT(&testing.T{})790 got := errors.New("foobar")791 ok := t.HasSuffix(got, "bar", "checks %s", got)792 fmt.Println(ok)793 // Output:794 // true795}796func ExampleT_Isa() {797 t := td.NewT(&testing.T{})798 type TstStruct struct {799 Field int800 }801 got := TstStruct{Field: 1}802 ok := t.Isa(got, TstStruct{}, "checks got is a TstStruct")803 fmt.Println(ok)804 ok = t.Isa(got, &TstStruct{},805 "checks got is a pointer on a TstStruct")806 fmt.Println(ok)807 ok = t.Isa(&got, &TstStruct{},808 "checks &got is a pointer on a TstStruct")809 fmt.Println(ok)810 // Output:811 // true812 // false813 // true814}815func ExampleT_Isa_interface() {816 t := td.NewT(&testing.T{})817 got := bytes.NewBufferString("foobar")818 ok := t.Isa(got, (*fmt.Stringer)(nil),819 "checks got implements fmt.Stringer interface")820 fmt.Println(ok)821 errGot := fmt.Errorf("An error #%d occurred", 123)822 ok = t.Isa(errGot, (*error)(nil),823 "checks errGot is a *error or implements error interface")824 fmt.Println(ok)825 // As nil, is passed below, it is not an interface but nil… So it826 // does not match827 errGot = nil828 ok = t.Isa(errGot, (*error)(nil),829 "checks errGot is a *error or implements error interface")830 fmt.Println(ok)831 // BUT if its address is passed, now it is OK as the types match832 ok = t.Isa(&errGot, (*error)(nil),833 "checks &errGot is a *error or implements error interface")834 fmt.Println(ok)835 // Output:836 // true837 // true838 // false839 // true840}841func ExampleT_JSON_basic() {842 t := td.NewT(&testing.T{})843 got := &struct {844 Fullname string `json:"fullname"`845 Age int `json:"age"`846 }{847 Fullname: "Bob",848 Age: 42,849 }850 ok := t.JSON(got, `{"age":42,"fullname":"Bob"}`, nil)851 fmt.Println("check got with age then fullname:", ok)852 ok = t.JSON(got, `{"fullname":"Bob","age":42}`, nil)853 fmt.Println("check got with fullname then age:", ok)854 ok = t.JSON(got, `855// This should be the JSON representation of a struct856{857 // A person:858 "fullname": "Bob", // The name of this person859 "age": 42 /* The age of this person:860 - 42 of course861 - to demonstrate a multi-lines comment */862}`, nil)863 fmt.Println("check got with nicely formatted and commented JSON:", ok)864 ok = t.JSON(got, `{"fullname":"Bob","age":42,"gender":"male"}`, nil)865 fmt.Println("check got with gender field:", ok)866 ok = t.JSON(got, `{"fullname":"Bob"}`, nil)867 fmt.Println("check got with fullname only:", ok)868 ok = t.JSON(true, `true`, nil)869 fmt.Println("check boolean got is true:", ok)870 ok = t.JSON(42, `42`, nil)871 fmt.Println("check numeric got is 42:", ok)872 got = nil873 ok = t.JSON(got, `null`, nil)874 fmt.Println("check nil got is null:", ok)875 // Output:876 // check got with age then fullname: true877 // check got with fullname then age: true878 // check got with nicely formatted and commented JSON: true879 // check got with gender field: false880 // check got with fullname only: false881 // check boolean got is true: true882 // check numeric got is 42: true883 // check nil got is null: true884}885func ExampleT_JSON_placeholders() {886 t := td.NewT(&testing.T{})887 type Person struct {888 Fullname string `json:"fullname"`889 Age int `json:"age"`890 Children []*Person `json:"children,omitempty"`891 }892 got := &Person{893 Fullname: "Bob Foobar",894 Age: 42,895 }896 ok := t.JSON(got, `{"age": $1, "fullname": $2}`, []any{42, "Bob Foobar"})897 fmt.Println("check got with numeric placeholders without operators:", ok)898 ok = t.JSON(got, `{"age": $1, "fullname": $2}`, []any{td.Between(40, 45), td.HasSuffix("Foobar")})899 fmt.Println("check got with numeric placeholders:", ok)900 ok = t.JSON(got, `{"age": "$1", "fullname": "$2"}`, []any{td.Between(40, 45), td.HasSuffix("Foobar")})901 fmt.Println("check got with double-quoted numeric placeholders:", ok)902 ok = t.JSON(got, `{"age": $age, "fullname": $name}`, []any{td.Tag("age", td.Between(40, 45)), td.Tag("name", td.HasSuffix("Foobar"))})903 fmt.Println("check got with named placeholders:", ok)904 got.Children = []*Person{905 {Fullname: "Alice", Age: 28},906 {Fullname: "Brian", Age: 22},907 }908 ok = t.JSON(got, `{"age": $age, "fullname": $name, "children": $children}`, []any{td.Tag("age", td.Between(40, 45)), td.Tag("name", td.HasSuffix("Foobar")), td.Tag("children", td.Bag(909 &Person{Fullname: "Brian", Age: 22},910 &Person{Fullname: "Alice", Age: 28},911 ))})912 fmt.Println("check got w/named placeholders, and children w/go structs:", ok)913 ok = t.JSON(got, `{"age": Between($1, $2), "fullname": HasSuffix($suffix), "children": Len(2)}`, []any{40, 45, td.Tag("suffix", "Foobar")})914 fmt.Println("check got w/num & named placeholders:", ok)915 // Output:916 // check got with numeric placeholders without operators: true917 // check got with numeric placeholders: true918 // check got with double-quoted numeric placeholders: true919 // check got with named placeholders: true920 // check got w/named placeholders, and children w/go structs: true921 // check got w/num & named placeholders: true922}923func ExampleT_JSON_embedding() {924 t := td.NewT(&testing.T{})925 got := &struct {926 Fullname string `json:"fullname"`927 Age int `json:"age"`928 }{929 Fullname: "Bob Foobar",930 Age: 42,931 }932 ok := t.JSON(got, `{"age": NotZero(), "fullname": NotEmpty()}`, nil)933 fmt.Println("check got with simple operators:", ok)934 ok = t.JSON(got, `{"age": $^NotZero, "fullname": $^NotEmpty}`, nil)935 fmt.Println("check got with operator shortcuts:", ok)936 ok = t.JSON(got, `937{938 "age": Between(40, 42, "]]"), // in ]40; 42]939 "fullname": All(940 HasPrefix("Bob"),941 HasSuffix("bar") // ← comma is optional here942 )943}`, nil)944 fmt.Println("check got with complex operators:", ok)945 ok = t.JSON(got, `946{947 "age": Between(40, 42, "]["), // in ]40; 42[ → 42 excluded948 "fullname": All(949 HasPrefix("Bob"),950 HasSuffix("bar"),951 )952}`, nil)953 fmt.Println("check got with complex operators:", ok)954 ok = t.JSON(got, `955{956 "age": Between($1, $2, $3), // in ]40; 42]957 "fullname": All(958 HasPrefix($4),959 HasSuffix("bar") // ← comma is optional here960 )961}`, []any{40, 42, td.BoundsOutIn, "Bob"})962 fmt.Println("check got with complex operators, w/placeholder args:", ok)963 // Output:964 // check got with simple operators: true965 // check got with operator shortcuts: true966 // check got with complex operators: true967 // check got with complex operators: false968 // check got with complex operators, w/placeholder args: true969}970func ExampleT_JSON_rawStrings() {971 t := td.NewT(&testing.T{})972 type details struct {973 Address string `json:"address"`974 Car string `json:"car"`975 }976 got := &struct {977 Fullname string `json:"fullname"`978 Age int `json:"age"`979 Details details `json:"details"`980 }{981 Fullname: "Foo Bar",982 Age: 42,983 Details: details{984 Address: "something",985 Car: "Peugeot",986 },987 }988 ok := t.JSON(got, `989{990 "fullname": HasPrefix("Foo"),991 "age": Between(41, 43),992 "details": SuperMapOf({993 "address": NotEmpty, // () are optional when no parameters994 "car": Any("Peugeot", "Tesla", "Jeep") // any of these995 })996}`, nil)997 fmt.Println("Original:", ok)998 ok = t.JSON(got, `999{1000 "fullname": "$^HasPrefix(\"Foo\")",1001 "age": "$^Between(41, 43)",1002 "details": "$^SuperMapOf({\n\"address\": NotEmpty,\n\"car\": Any(\"Peugeot\", \"Tesla\", \"Jeep\")\n})"1003}`, nil)1004 fmt.Println("JSON compliant:", ok)1005 ok = t.JSON(got, `1006{1007 "fullname": "$^HasPrefix(\"Foo\")",1008 "age": "$^Between(41, 43)",1009 "details": "$^SuperMapOf({1010 \"address\": NotEmpty, // () are optional when no parameters1011 \"car\": Any(\"Peugeot\", \"Tesla\", \"Jeep\") // any of these1012 })"1013}`, nil)1014 fmt.Println("JSON multilines strings:", ok)1015 ok = t.JSON(got, `1016{1017 "fullname": "$^HasPrefix(r<Foo>)",1018 "age": "$^Between(41, 43)",1019 "details": "$^SuperMapOf({1020 r<address>: NotEmpty, // () are optional when no parameters1021 r<car>: Any(r<Peugeot>, r<Tesla>, r<Jeep>) // any of these1022 })"1023}`, nil)1024 fmt.Println("Raw strings:", ok)1025 // Output:1026 // Original: true1027 // JSON compliant: true1028 // JSON multilines strings: true1029 // Raw strings: true1030}1031func ExampleT_JSON_file() {1032 t := td.NewT(&testing.T{})1033 got := &struct {1034 Fullname string `json:"fullname"`1035 Age int `json:"age"`1036 Gender string `json:"gender"`1037 }{1038 Fullname: "Bob Foobar",1039 Age: 42,1040 Gender: "male",1041 }1042 tmpDir, err := os.MkdirTemp("", "")1043 if err != nil {1044 t.Fatal(err)1045 }1046 defer os.RemoveAll(tmpDir) // clean up1047 filename := tmpDir + "/test.json"1048 if err = os.WriteFile(filename, []byte(`1049{1050 "fullname": "$name",1051 "age": "$age",1052 "gender": "$gender"1053}`), 0644); err != nil {1054 t.Fatal(err)1055 }1056 // OK let's test with this file1057 ok := t.JSON(got, filename, []any{td.Tag("name", td.HasPrefix("Bob")), td.Tag("age", td.Between(40, 45)), td.Tag("gender", td.Re(`^(male|female)\z`))})1058 fmt.Println("Full match from file name:", ok)1059 // When the file is already open1060 file, err := os.Open(filename)1061 if err != nil {1062 t.Fatal(err)1063 }1064 ok = t.JSON(got, file, []any{td.Tag("name", td.HasPrefix("Bob")), td.Tag("age", td.Between(40, 45)), td.Tag("gender", td.Re(`^(male|female)\z`))})1065 fmt.Println("Full match from io.Reader:", ok)1066 // Output:1067 // Full match from file name: true1068 // Full match from io.Reader: true1069}1070func ExampleT_JSONPointer_rfc6901() {1071 t := td.NewT(&testing.T{})1072 got := json.RawMessage(`1073{1074 "foo": ["bar", "baz"],1075 "": 0,1076 "a/b": 1,1077 "c%d": 2,1078 "e^f": 3,1079 "g|h": 4,1080 "i\\j": 5,1081 "k\"l": 6,1082 " ": 7,1083 "m~n": 81084}`)1085 expected := map[string]any{1086 "foo": []any{"bar", "baz"},1087 "": 0,1088 "a/b": 1,1089 "c%d": 2,1090 "e^f": 3,1091 "g|h": 4,1092 `i\j`: 5,1093 `k"l`: 6,1094 " ": 7,1095 "m~n": 8,1096 }1097 ok := t.JSONPointer(got, "", expected)1098 fmt.Println("Empty JSON pointer means all:", ok)1099 ok = t.JSONPointer(got, `/foo`, []any{"bar", "baz"})1100 fmt.Println("Extract `foo` key:", ok)1101 ok = t.JSONPointer(got, `/foo/0`, "bar")1102 fmt.Println("First item of `foo` key slice:", ok)1103 ok = t.JSONPointer(got, `/`, 0)1104 fmt.Println("Empty key:", ok)1105 ok = t.JSONPointer(got, `/a~1b`, 1)1106 fmt.Println("Slash has to be escaped using `~1`:", ok)1107 ok = t.JSONPointer(got, `/c%d`, 2)1108 fmt.Println("% in key:", ok)1109 ok = t.JSONPointer(got, `/e^f`, 3)1110 fmt.Println("^ in key:", ok)1111 ok = t.JSONPointer(got, `/g|h`, 4)1112 fmt.Println("| in key:", ok)1113 ok = t.JSONPointer(got, `/i\j`, 5)1114 fmt.Println("Backslash in key:", ok)1115 ok = t.JSONPointer(got, `/k"l`, 6)1116 fmt.Println("Double-quote in key:", ok)1117 ok = t.JSONPointer(got, `/ `, 7)1118 fmt.Println("Space key:", ok)1119 ok = t.JSONPointer(got, `/m~0n`, 8)1120 fmt.Println("Tilde has to be escaped using `~0`:", ok)1121 // Output:1122 // Empty JSON pointer means all: true1123 // Extract `foo` key: true1124 // First item of `foo` key slice: true1125 // Empty key: true1126 // Slash has to be escaped using `~1`: true1127 // % in key: true1128 // ^ in key: true1129 // | in key: true1130 // Backslash in key: true1131 // Double-quote in key: true1132 // Space key: true1133 // Tilde has to be escaped using `~0`: true1134}1135func ExampleT_JSONPointer_struct() {1136 t := td.NewT(&testing.T{})1137 // Without json tags, encoding/json uses public fields name1138 type Item struct {1139 Name string1140 Value int641141 Next *Item1142 }1143 got := Item{1144 Name: "first",1145 Value: 1,1146 Next: &Item{1147 Name: "second",1148 Value: 2,1149 Next: &Item{1150 Name: "third",1151 Value: 3,1152 },1153 },1154 }1155 ok := t.JSONPointer(got, "/Next/Next/Name", "third")1156 fmt.Println("3rd item name is `third`:", ok)1157 ok = t.JSONPointer(got, "/Next/Next/Value", td.Gte(int64(3)))1158 fmt.Println("3rd item value is greater or equal than 3:", ok)1159 ok = t.JSONPointer(got, "/Next", td.JSONPointer("/Next",1160 td.JSONPointer("/Value", td.Gte(int64(3)))))1161 fmt.Println("3rd item value is still greater or equal than 3:", ok)1162 ok = t.JSONPointer(got, "/Next/Next/Next/Name", td.Ignore())1163 fmt.Println("4th item exists and has a name:", ok)1164 // Struct comparison work with or without pointer: &Item{…} works too1165 ok = t.JSONPointer(got, "/Next/Next", Item{1166 Name: "third",1167 Value: 3,1168 })1169 fmt.Println("3rd item full comparison:", ok)1170 // Output:1171 // 3rd item name is `third`: true1172 // 3rd item value is greater or equal than 3: true1173 // 3rd item value is still greater or equal than 3: true1174 // 4th item exists and has a name: false1175 // 3rd item full comparison: true1176}1177func ExampleT_JSONPointer_has_hasnt() {1178 t := td.NewT(&testing.T{})1179 got := json.RawMessage(`1180{1181 "name": "Bob",1182 "age": 42,1183 "children": [1184 {1185 "name": "Alice",1186 "age": 161187 },1188 {1189 "name": "Britt",1190 "age": 21,1191 "children": [1192 {1193 "name": "John",1194 "age": 11195 }1196 ]1197 }1198 ]1199}`)1200 // Has Bob some children?1201 ok := t.JSONPointer(got, "/children", td.Len(td.Gt(0)))1202 fmt.Println("Bob has at least one child:", ok)1203 // But checking "children" exists is enough here1204 ok = t.JSONPointer(got, "/children/0/children", td.Ignore())1205 fmt.Println("Alice has children:", ok)1206 ok = t.JSONPointer(got, "/children/1/children", td.Ignore())1207 fmt.Println("Britt has children:", ok)1208 // The reverse can be checked too1209 ok = t.Cmp(got, td.Not(td.JSONPointer("/children/0/children", td.Ignore())))1210 fmt.Println("Alice hasn't children:", ok)1211 ok = t.Cmp(got, td.Not(td.JSONPointer("/children/1/children", td.Ignore())))1212 fmt.Println("Britt hasn't children:", ok)1213 // Output:1214 // Bob has at least one child: true1215 // Alice has children: false1216 // Britt has children: true1217 // Alice hasn't children: true1218 // Britt hasn't children: false1219}1220func ExampleT_Keys() {1221 t := td.NewT(&testing.T{})1222 got := map[string]int{"foo": 1, "bar": 2, "zip": 3}1223 // Keys tests keys in an ordered manner1224 ok := t.Keys(got, []string{"bar", "foo", "zip"})1225 fmt.Println("All sorted keys are found:", ok)1226 // If the expected keys are not ordered, it fails1227 ok = t.Keys(got, []string{"zip", "bar", "foo"})1228 fmt.Println("All unsorted keys are found:", ok)1229 // To circumvent that, one can use Bag operator1230 ok = t.Keys(got, td.Bag("zip", "bar", "foo"))1231 fmt.Println("All unsorted keys are found, with the help of Bag operator:", ok)1232 // Check that each key is 3 bytes long1233 ok = t.Keys(got, td.ArrayEach(td.Len(3)))1234 fmt.Println("Each key is 3 bytes long:", ok)1235 // Output:1236 // All sorted keys are found: true1237 // All unsorted keys are found: false1238 // All unsorted keys are found, with the help of Bag operator: true1239 // Each key is 3 bytes long: true1240}1241func ExampleT_Last_classic() {1242 t := td.NewT(&testing.T{})1243 got := []int{-3, -2, -1, 0, 1, 2, 3}1244 ok := t.Last(got, td.Lt(0), -1)1245 fmt.Println("last negative number is -1:", ok)1246 isEven := func(x int) bool { return x%2 == 0 }1247 ok = t.Last(got, isEven, 2)1248 fmt.Println("last even number is 2:", ok)1249 ok = t.Last(got, isEven, td.Gt(0))1250 fmt.Println("last even number is > 0:", ok)1251 ok = t.Last(got, isEven, td.Code(isEven))1252 fmt.Println("last even number is well even:", ok)1253 // Output:1254 // last negative number is -1: true1255 // last even number is 2: true1256 // last even number is > 0: true1257 // last even number is well even: true1258}1259func ExampleT_Last_empty() {1260 t := td.NewT(&testing.T{})1261 ok := t.Last(([]int)(nil), td.Gt(0), td.Gt(0))1262 fmt.Println("last in nil slice:", ok)1263 ok = t.Last([]int{}, td.Gt(0), td.Gt(0))1264 fmt.Println("last in empty slice:", ok)1265 ok = t.Last(&[]int{}, td.Gt(0), td.Gt(0))1266 fmt.Println("last in empty pointed slice:", ok)1267 ok = t.Last([0]int{}, td.Gt(0), td.Gt(0))1268 fmt.Println("last in empty array:", ok)1269 // Output:1270 // last in nil slice: false1271 // last in empty slice: false1272 // last in empty pointed slice: false1273 // last in empty array: false1274}1275func ExampleT_Last_struct() {1276 t := td.NewT(&testing.T{})1277 type Person struct {1278 Fullname string `json:"fullname"`1279 Age int `json:"age"`1280 }1281 got := []*Person{1282 {1283 Fullname: "Bob Foobar",1284 Age: 42,1285 },1286 {1287 Fullname: "Alice Bingo",1288 Age: 37,1289 },1290 }1291 ok := t.Last(got, td.Smuggle("Age", td.Gt(30)), td.Smuggle("Fullname", "Alice Bingo"))1292 fmt.Println("last person.Age > 30 → Alice:", ok)1293 ok = t.Last(got, td.JSONPointer("/age", td.Gt(30)), td.SuperJSONOf(`{"fullname":"Alice Bingo"}`))1294 fmt.Println("last person.Age > 30 → Alice, using JSON:", ok)1295 ok = t.Last(got, td.JSONPointer("/age", td.Gt(30)), td.JSONPointer("/fullname", td.HasPrefix("Alice")))1296 fmt.Println("first person.Age > 30 → Alice, using JSONPointer:", ok)1297 // Output:1298 // last person.Age > 30 → Alice: true1299 // last person.Age > 30 → Alice, using JSON: true1300 // first person.Age > 30 → Alice, using JSONPointer: true1301}1302func ExampleT_CmpLax() {1303 t := td.NewT(&testing.T{})1304 gotInt64 := int64(1234)1305 gotInt32 := int32(1235)1306 type myInt uint161307 gotMyInt := myInt(1236)1308 expected := td.Between(1230, 1240) // int type here1309 ok := t.CmpLax(gotInt64, expected)1310 fmt.Println("int64 got between ints [1230 .. 1240]:", ok)1311 ok = t.CmpLax(gotInt32, expected)1312 fmt.Println("int32 got between ints [1230 .. 1240]:", ok)1313 ok = t.CmpLax(gotMyInt, expected)1314 fmt.Println("myInt got between ints [1230 .. 1240]:", ok)1315 // Output:1316 // int64 got between ints [1230 .. 1240]: true1317 // int32 got between ints [1230 .. 1240]: true1318 // myInt got between ints [1230 .. 1240]: true1319}1320func ExampleT_Len_slice() {1321 t := td.NewT(&testing.T{})1322 got := []int{11, 22, 33}1323 ok := t.Len(got, 3, "checks %v len is 3", got)1324 fmt.Println(ok)1325 ok = t.Len(got, 0, "checks %v len is 0", got)1326 fmt.Println(ok)1327 got = nil1328 ok = t.Len(got, 0, "checks %v len is 0", got)1329 fmt.Println(ok)1330 // Output:1331 // true1332 // false1333 // true1334}1335func ExampleT_Len_map() {1336 t := td.NewT(&testing.T{})1337 got := map[int]bool{11: true, 22: false, 33: false}1338 ok := t.Len(got, 3, "checks %v len is 3", got)1339 fmt.Println(ok)1340 ok = t.Len(got, 0, "checks %v len is 0", got)1341 fmt.Println(ok)1342 got = nil1343 ok = t.Len(got, 0, "checks %v len is 0", got)1344 fmt.Println(ok)1345 // Output:1346 // true1347 // false1348 // true1349}1350func ExampleT_Len_operatorSlice() {1351 t := td.NewT(&testing.T{})1352 got := []int{11, 22, 33}1353 ok := t.Len(got, td.Between(3, 8),1354 "checks %v len is in [3 .. 8]", got)1355 fmt.Println(ok)1356 ok = t.Len(got, td.Lt(5), "checks %v len is < 5", got)1357 fmt.Println(ok)1358 // Output:1359 // true1360 // true1361}1362func ExampleT_Len_operatorMap() {1363 t := td.NewT(&testing.T{})1364 got := map[int]bool{11: true, 22: false, 33: false}1365 ok := t.Len(got, td.Between(3, 8),1366 "checks %v len is in [3 .. 8]", got)1367 fmt.Println(ok)1368 ok = t.Len(got, td.Gte(3), "checks %v len is ≥ 3", got)1369 fmt.Println(ok)1370 // Output:1371 // true1372 // true1373}1374func ExampleT_Lt_int() {1375 t := td.NewT(&testing.T{})1376 got := 1561377 ok := t.Lt(got, 157, "checks %v is < 157", got)1378 fmt.Println(ok)1379 ok = t.Lt(got, 156, "checks %v is < 156", got)1380 fmt.Println(ok)1381 // Output:1382 // true1383 // false1384}1385func ExampleT_Lt_string() {1386 t := td.NewT(&testing.T{})1387 got := "abc"1388 ok := t.Lt(got, "abd", `checks "%v" is < "abd"`, got)1389 fmt.Println(ok)1390 ok = t.Lt(got, "abc", `checks "%v" is < "abc"`, got)1391 fmt.Println(ok)1392 // Output:1393 // true1394 // false1395}1396func ExampleT_Lte_int() {1397 t := td.NewT(&testing.T{})1398 got := 1561399 ok := t.Lte(got, 156, "checks %v is ≤ 156", got)1400 fmt.Println(ok)1401 ok = t.Lte(got, 157, "checks %v is ≤ 157", got)1402 fmt.Println(ok)1403 ok = t.Lte(got, 155, "checks %v is ≤ 155", got)1404 fmt.Println(ok)1405 // Output:1406 // true1407 // true1408 // false1409}1410func ExampleT_Lte_string() {1411 t := td.NewT(&testing.T{})1412 got := "abc"1413 ok := t.Lte(got, "abc", `checks "%v" is ≤ "abc"`, got)1414 fmt.Println(ok)1415 ok = t.Lte(got, "abd", `checks "%v" is ≤ "abd"`, got)1416 fmt.Println(ok)1417 ok = t.Lte(got, "abb", `checks "%v" is ≤ "abb"`, got)1418 fmt.Println(ok)1419 // Output:1420 // true1421 // true1422 // false1423}1424func ExampleT_Map_map() {1425 t := td.NewT(&testing.T{})1426 got := map[string]int{"foo": 12, "bar": 42, "zip": 89}1427 ok := t.Map(got, map[string]int{"bar": 42}, td.MapEntries{"foo": td.Lt(15), "zip": td.Ignore()},1428 "checks map %v", got)1429 fmt.Println(ok)1430 ok = t.Map(got, map[string]int{}, td.MapEntries{"bar": 42, "foo": td.Lt(15), "zip": td.Ignore()},1431 "checks map %v", got)1432 fmt.Println(ok)1433 ok = t.Map(got, (map[string]int)(nil), td.MapEntries{"bar": 42, "foo": td.Lt(15), "zip": td.Ignore()},1434 "checks map %v", got)1435 fmt.Println(ok)1436 // Output:1437 // true1438 // true1439 // true1440}1441func ExampleT_Map_typedMap() {1442 t := td.NewT(&testing.T{})1443 type MyMap map[string]int1444 got := MyMap{"foo": 12, "bar": 42, "zip": 89}1445 ok := t.Map(got, MyMap{"bar": 42}, td.MapEntries{"foo": td.Lt(15), "zip": td.Ignore()},1446 "checks typed map %v", got)1447 fmt.Println(ok)1448 ok = t.Map(&got, &MyMap{"bar": 42}, td.MapEntries{"foo": td.Lt(15), "zip": td.Ignore()},1449 "checks pointer on typed map %v", got)1450 fmt.Println(ok)1451 ok = t.Map(&got, &MyMap{}, td.MapEntries{"bar": 42, "foo": td.Lt(15), "zip": td.Ignore()},1452 "checks pointer on typed map %v", got)1453 fmt.Println(ok)1454 ok = t.Map(&got, (*MyMap)(nil), td.MapEntries{"bar": 42, "foo": td.Lt(15), "zip": td.Ignore()},1455 "checks pointer on typed map %v", got)1456 fmt.Println(ok)1457 // Output:1458 // true1459 // true1460 // true1461 // true1462}1463func ExampleT_MapEach_map() {1464 t := td.NewT(&testing.T{})1465 got := map[string]int{"foo": 12, "bar": 42, "zip": 89}1466 ok := t.MapEach(got, td.Between(10, 90),1467 "checks each value of map %v is in [10 .. 90]", got)1468 fmt.Println(ok)1469 // Output:1470 // true1471}1472func ExampleT_MapEach_typedMap() {1473 t := td.NewT(&testing.T{})1474 type MyMap map[string]int1475 got := MyMap{"foo": 12, "bar": 42, "zip": 89}1476 ok := t.MapEach(got, td.Between(10, 90),1477 "checks each value of typed map %v is in [10 .. 90]", got)1478 fmt.Println(ok)1479 ok = t.MapEach(&got, td.Between(10, 90),1480 "checks each value of typed map pointer %v is in [10 .. 90]", got)1481 fmt.Println(ok)1482 // Output:1483 // true1484 // true1485}1486func ExampleT_N() {1487 t := td.NewT(&testing.T{})1488 got := 1.123451489 ok := t.N(got, 1.1234, 0.00006,1490 "checks %v = 1.1234 ± 0.00006", got)1491 fmt.Println(ok)1492 // Output:1493 // true1494}1495func ExampleT_NaN_float32() {1496 t := td.NewT(&testing.T{})1497 got := float32(math.NaN())1498 ok := t.NaN(got,1499 "checks %v is not-a-number", got)1500 fmt.Println("float32(math.NaN()) is float32 not-a-number:", ok)1501 got = 121502 ok = t.NaN(got,1503 "checks %v is not-a-number", got)1504 fmt.Println("float32(12) is float32 not-a-number:", ok)1505 // Output:1506 // float32(math.NaN()) is float32 not-a-number: true1507 // float32(12) is float32 not-a-number: false1508}1509func ExampleT_NaN_float64() {1510 t := td.NewT(&testing.T{})1511 got := math.NaN()1512 ok := t.NaN(got,1513 "checks %v is not-a-number", got)1514 fmt.Println("math.NaN() is not-a-number:", ok)1515 got = 121516 ok = t.NaN(got,1517 "checks %v is not-a-number", got)1518 fmt.Println("float64(12) is not-a-number:", ok)1519 // math.NaN() is not-a-number: true1520 // float64(12) is not-a-number: false1521}1522func ExampleT_Nil() {1523 t := td.NewT(&testing.T{})1524 var got fmt.Stringer // interface1525 // nil value can be compared directly with nil, no need of Nil() here1526 ok := t.Cmp(got, nil)1527 fmt.Println(ok)1528 // But it works with Nil() anyway1529 ok = t.Nil(got)1530 fmt.Println(ok)1531 got = (*bytes.Buffer)(nil)1532 // In the case of an interface containing a nil pointer, comparing1533 // with nil fails, as the interface is not nil1534 ok = t.Cmp(got, nil)1535 fmt.Println(ok)1536 // In this case Nil() succeed1537 ok = t.Nil(got)1538 fmt.Println(ok)1539 // Output:1540 // true1541 // true1542 // false1543 // true1544}1545func ExampleT_None() {1546 t := td.NewT(&testing.T{})1547 got := 181548 ok := t.None(got, []any{0, 10, 20, 30, td.Between(100, 199)},1549 "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)1550 fmt.Println(ok)1551 got = 201552 ok = t.None(got, []any{0, 10, 20, 30, td.Between(100, 199)},1553 "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)1554 fmt.Println(ok)1555 got = 1421556 ok = t.None(got, []any{0, 10, 20, 30, td.Between(100, 199)},1557 "checks %v is non-null, and ≠ 10, 20 & 30, and not in [100-199]", got)1558 fmt.Println(ok)1559 prime := td.Flatten([]int{1, 2, 3, 5, 7, 11, 13})1560 even := td.Flatten([]int{2, 4, 6, 8, 10, 12, 14})1561 for _, got := range [...]int{9, 3, 8, 15} {1562 ok = t.None(got, []any{prime, even, td.Gt(14)},1563 "checks %v is not prime number, nor an even number and not > 14")1564 fmt.Printf("%d → %t\n", got, ok)1565 }1566 // Output:1567 // true1568 // false1569 // false1570 // 9 → true1571 // 3 → false1572 // 8 → false1573 // 15 → false1574}1575func ExampleT_Not() {1576 t := td.NewT(&testing.T{})1577 got := 421578 ok := t.Not(got, 0, "checks %v is non-null", got)1579 fmt.Println(ok)1580 ok = t.Not(got, td.Between(10, 30),1581 "checks %v is not in [10 .. 30]", got)1582 fmt.Println(ok)1583 got = 01584 ok = t.Not(got, 0, "checks %v is non-null", got)1585 fmt.Println(ok)1586 // Output:1587 // true1588 // true1589 // false1590}1591func ExampleT_NotAny() {1592 t := td.NewT(&testing.T{})1593 got := []int{4, 5, 9, 42}1594 ok := t.NotAny(got, []any{3, 6, 8, 41, 43},1595 "checks %v contains no item listed in NotAny()", got)1596 fmt.Println(ok)1597 ok = t.NotAny(got, []any{3, 6, 8, 42, 43},1598 "checks %v contains no item listed in NotAny()", got)1599 fmt.Println(ok)1600 // When expected is already a non-[]any slice, it cannot be1601 // flattened directly using notExpected... without copying it to a new1602 // []any slice, then use td.Flatten!1603 notExpected := []int{3, 6, 8, 41, 43}1604 ok = t.NotAny(got, []any{td.Flatten(notExpected)},1605 "checks %v contains no item listed in notExpected", got)1606 fmt.Println(ok)1607 // Output:1608 // true1609 // false1610 // true1611}1612func ExampleT_NotEmpty() {1613 t := td.NewT(&testing.T{})1614 ok := t.NotEmpty(nil) // fails, as nil is considered empty1615 fmt.Println(ok)1616 ok = t.NotEmpty("foobar")1617 fmt.Println(ok)1618 // Fails as 0 is a number, so not empty. Use NotZero() instead1619 ok = t.NotEmpty(0)1620 fmt.Println(ok)1621 ok = t.NotEmpty(map[string]int{"foobar": 42})1622 fmt.Println(ok)1623 ok = t.NotEmpty([]int{1})1624 fmt.Println(ok)1625 ok = t.NotEmpty([3]int{}) // succeeds, NotEmpty() is not NotZero()!1626 fmt.Println(ok)1627 // Output:1628 // false1629 // true1630 // false1631 // true1632 // true1633 // true1634}1635func ExampleT_NotEmpty_pointers() {1636 t := td.NewT(&testing.T{})1637 type MySlice []int1638 ok := t.NotEmpty(MySlice{12})1639 fmt.Println(ok)1640 ok = t.NotEmpty(&MySlice{12}) // Ptr() not needed1641 fmt.Println(ok)1642 l1 := &MySlice{12}1643 l2 := &l11644 l3 := &l21645 ok = t.NotEmpty(&l3)1646 fmt.Println(ok)1647 // Works the same for array, map, channel and string1648 // But not for others types as:1649 type MyStruct struct {1650 Value int1651 }1652 ok = t.NotEmpty(&MyStruct{}) // fails, use NotZero() instead1653 fmt.Println(ok)1654 // Output:1655 // true1656 // true1657 // true1658 // false1659}1660func ExampleT_NotNaN_float32() {1661 t := td.NewT(&testing.T{})1662 got := float32(math.NaN())1663 ok := t.NotNaN(got,1664 "checks %v is not-a-number", got)1665 fmt.Println("float32(math.NaN()) is NOT float32 not-a-number:", ok)1666 got = 121667 ok = t.NotNaN(got,1668 "checks %v is not-a-number", got)1669 fmt.Println("float32(12) is NOT float32 not-a-number:", ok)1670 // Output:1671 // float32(math.NaN()) is NOT float32 not-a-number: false1672 // float32(12) is NOT float32 not-a-number: true1673}1674func ExampleT_NotNaN_float64() {1675 t := td.NewT(&testing.T{})1676 got := math.NaN()1677 ok := t.NotNaN(got,1678 "checks %v is not-a-number", got)1679 fmt.Println("math.NaN() is not-a-number:", ok)1680 got = 121681 ok = t.NotNaN(got,1682 "checks %v is not-a-number", got)1683 fmt.Println("float64(12) is not-a-number:", ok)1684 // math.NaN() is NOT not-a-number: false1685 // float64(12) is NOT not-a-number: true1686}1687func ExampleT_NotNil() {1688 t := td.NewT(&testing.T{})1689 var got fmt.Stringer = &bytes.Buffer{}1690 // nil value can be compared directly with Not(nil), no need of NotNil() here1691 ok := t.Cmp(got, td.Not(nil))1692 fmt.Println(ok)1693 // But it works with NotNil() anyway1694 ok = t.NotNil(got)1695 fmt.Println(ok)1696 got = (*bytes.Buffer)(nil)1697 // In the case of an interface containing a nil pointer, comparing1698 // with Not(nil) succeeds, as the interface is not nil1699 ok = t.Cmp(got, td.Not(nil))1700 fmt.Println(ok)1701 // In this case NotNil() fails1702 ok = t.NotNil(got)1703 fmt.Println(ok)1704 // Output:1705 // true1706 // true1707 // true1708 // false1709}1710func ExampleT_NotZero() {1711 t := td.NewT(&testing.T{})1712 ok := t.NotZero(0) // fails1713 fmt.Println(ok)1714 ok = t.NotZero(float64(0)) // fails1715 fmt.Println(ok)1716 ok = t.NotZero(12)1717 fmt.Println(ok)1718 ok = t.NotZero((map[string]int)(nil)) // fails, as nil1719 fmt.Println(ok)1720 ok = t.NotZero(map[string]int{}) // succeeds, as not nil1721 fmt.Println(ok)1722 ok = t.NotZero(([]int)(nil)) // fails, as nil1723 fmt.Println(ok)1724 ok = t.NotZero([]int{}) // succeeds, as not nil1725 fmt.Println(ok)1726 ok = t.NotZero([3]int{}) // fails1727 fmt.Println(ok)1728 ok = t.NotZero([3]int{0, 1}) // succeeds, DATA[1] is not 01729 fmt.Println(ok)1730 ok = t.NotZero(bytes.Buffer{}) // fails1731 fmt.Println(ok)1732 ok = t.NotZero(&bytes.Buffer{}) // succeeds, as pointer not nil1733 fmt.Println(ok)1734 ok = t.Cmp(&bytes.Buffer{}, td.Ptr(td.NotZero())) // fails as deref by Ptr()1735 fmt.Println(ok)1736 // Output:1737 // false1738 // false1739 // true1740 // false1741 // true1742 // false1743 // true1744 // false1745 // true1746 // false1747 // true1748 // false1749}1750func ExampleT_PPtr() {1751 t := td.NewT(&testing.T{})1752 num := 121753 got := &num1754 ok := t.PPtr(&got, 12)1755 fmt.Println(ok)1756 ok = t.PPtr(&got, td.Between(4, 15))1757 fmt.Println(ok)1758 // Output:1759 // true1760 // true1761}1762func ExampleT_Ptr() {1763 t := td.NewT(&testing.T{})1764 got := 121765 ok := t.Ptr(&got, 12)1766 fmt.Println(ok)1767 ok = t.Ptr(&got, td.Between(4, 15))1768 fmt.Println(ok)1769 // Output:1770 // true1771 // true1772}1773func ExampleT_Re() {1774 t := td.NewT(&testing.T{})1775 got := "foo bar"1776 ok := t.Re(got, "(zip|bar)$", nil, "checks value %s", got)1777 fmt.Println(ok)1778 got = "bar foo"1779 ok = t.Re(got, "(zip|bar)$", nil, "checks value %s", got)1780 fmt.Println(ok)1781 // Output:1782 // true1783 // false1784}1785func ExampleT_Re_stringer() {1786 t := td.NewT(&testing.T{})1787 // bytes.Buffer implements fmt.Stringer1788 got := bytes.NewBufferString("foo bar")1789 ok := t.Re(got, "(zip|bar)$", nil, "checks value %s", got)1790 fmt.Println(ok)1791 // Output:1792 // true1793}1794func ExampleT_Re_error() {1795 t := td.NewT(&testing.T{})1796 got := errors.New("foo bar")1797 ok := t.Re(got, "(zip|bar)$", nil, "checks value %s", got)1798 fmt.Println(ok)1799 // Output:1800 // true1801}1802func ExampleT_Re_capture() {1803 t := td.NewT(&testing.T{})1804 got := "foo bar biz"1805 ok := t.Re(got, `^(\w+) (\w+) (\w+)$`, td.Set("biz", "foo", "bar"),1806 "checks value %s", got)1807 fmt.Println(ok)1808 got = "foo bar! biz"1809 ok = t.Re(got, `^(\w+) (\w+) (\w+)$`, td.Set("biz", "foo", "bar"),1810 "checks value %s", got)1811 fmt.Println(ok)1812 // Output:1813 // true1814 // false1815}1816func ExampleT_Re_compiled() {1817 t := td.NewT(&testing.T{})1818 expected := regexp.MustCompile("(zip|bar)$")1819 got := "foo bar"1820 ok := t.Re(got, expected, nil, "checks value %s", got)1821 fmt.Println(ok)1822 got = "bar foo"1823 ok = t.Re(got, expected, nil, "checks value %s", got)1824 fmt.Println(ok)1825 // Output:1826 // true1827 // false1828}1829func ExampleT_Re_compiledStringer() {1830 t := td.NewT(&testing.T{})1831 expected := regexp.MustCompile("(zip|bar)$")1832 // bytes.Buffer implements fmt.Stringer1833 got := bytes.NewBufferString("foo bar")1834 ok := t.Re(got, expected, nil, "checks value %s", got)1835 fmt.Println(ok)1836 // Output:1837 // true1838}1839func ExampleT_Re_compiledError() {1840 t := td.NewT(&testing.T{})1841 expected := regexp.MustCompile("(zip|bar)$")1842 got := errors.New("foo bar")1843 ok := t.Re(got, expected, nil, "checks value %s", got)1844 fmt.Println(ok)1845 // Output:1846 // true1847}1848func ExampleT_Re_compiledCapture() {1849 t := td.NewT(&testing.T{})1850 expected := regexp.MustCompile(`^(\w+) (\w+) (\w+)$`)1851 got := "foo bar biz"1852 ok := t.Re(got, expected, td.Set("biz", "foo", "bar"),1853 "checks value %s", got)1854 fmt.Println(ok)1855 got = "foo bar! biz"1856 ok = t.Re(got, expected, td.Set("biz", "foo", "bar"),1857 "checks value %s", got)1858 fmt.Println(ok)1859 // Output:1860 // true1861 // false1862}1863func ExampleT_ReAll_capture() {1864 t := td.NewT(&testing.T{})1865 got := "foo bar biz"1866 ok := t.ReAll(got, `(\w+)`, td.Set("biz", "foo", "bar"),1867 "checks value %s", got)1868 fmt.Println(ok)1869 // Matches, but all catured groups do not match Set1870 got = "foo BAR biz"1871 ok = t.ReAll(got, `(\w+)`, td.Set("biz", "foo", "bar"),1872 "checks value %s", got)1873 fmt.Println(ok)1874 // Output:1875 // true1876 // false1877}1878func ExampleT_ReAll_captureComplex() {1879 t := td.NewT(&testing.T{})1880 got := "11 45 23 56 85 96"1881 ok := t.ReAll(got, `(\d+)`, td.ArrayEach(td.Code(func(num string) bool {1882 n, err := strconv.Atoi(num)1883 return err == nil && n > 10 && n < 1001884 })),1885 "checks value %s", got)1886 fmt.Println(ok)1887 // Matches, but 11 is not greater than 201888 ok = t.ReAll(got, `(\d+)`, td.ArrayEach(td.Code(func(num string) bool {1889 n, err := strconv.Atoi(num)1890 return err == nil && n > 20 && n < 1001891 })),1892 "checks value %s", got)1893 fmt.Println(ok)1894 // Output:1895 // true1896 // false1897}1898func ExampleT_ReAll_compiledCapture() {1899 t := td.NewT(&testing.T{})1900 expected := regexp.MustCompile(`(\w+)`)1901 got := "foo bar biz"1902 ok := t.ReAll(got, expected, td.Set("biz", "foo", "bar"),1903 "checks value %s", got)1904 fmt.Println(ok)1905 // Matches, but all catured groups do not match Set1906 got = "foo BAR biz"1907 ok = t.ReAll(got, expected, td.Set("biz", "foo", "bar"),1908 "checks value %s", got)1909 fmt.Println(ok)1910 // Output:1911 // true1912 // false1913}1914func ExampleT_ReAll_compiledCaptureComplex() {1915 t := td.NewT(&testing.T{})1916 expected := regexp.MustCompile(`(\d+)`)1917 got := "11 45 23 56 85 96"1918 ok := t.ReAll(got, expected, td.ArrayEach(td.Code(func(num string) bool {1919 n, err := strconv.Atoi(num)1920 return err == nil && n > 10 && n < 1001921 })),1922 "checks value %s", got)1923 fmt.Println(ok)1924 // Matches, but 11 is not greater than 201925 ok = t.ReAll(got, expected, td.ArrayEach(td.Code(func(num string) bool {1926 n, err := strconv.Atoi(num)1927 return err == nil && n > 20 && n < 1001928 })),1929 "checks value %s", got)1930 fmt.Println(ok)1931 // Output:1932 // true1933 // false1934}1935func ExampleT_Recv_basic() {1936 t := td.NewT(&testing.T{})1937 got := make(chan int, 3)1938 ok := t.Recv(got, td.RecvNothing, 0)1939 fmt.Println("nothing to receive:", ok)1940 got <- 11941 got <- 21942 got <- 31943 close(got)1944 ok = t.Recv(got, 1, 0)1945 fmt.Println("1st receive is 1:", ok)1946 ok = t.Cmp(got, td.All(1947 td.Recv(2),1948 td.Recv(td.Between(3, 4)),1949 td.Recv(td.RecvClosed),1950 ))1951 fmt.Println("next receives are 2, 3 then closed:", ok)1952 ok = t.Recv(got, td.RecvNothing, 0)1953 fmt.Println("nothing to receive:", ok)1954 // Output:1955 // nothing to receive: true1956 // 1st receive is 1: true1957 // next receives are 2, 3 then closed: true1958 // nothing to receive: false1959}1960func ExampleT_Recv_channelPointer() {1961 t := td.NewT(&testing.T{})1962 got := make(chan int, 3)1963 ok := t.Recv(got, td.RecvNothing, 0)1964 fmt.Println("nothing to receive:", ok)1965 got <- 11966 got <- 21967 got <- 31968 close(got)1969 ok = t.Recv(&got, 1, 0)1970 fmt.Println("1st receive is 1:", ok)1971 ok = t.Cmp(&got, td.All(1972 td.Recv(2),1973 td.Recv(td.Between(3, 4)),1974 td.Recv(td.RecvClosed),1975 ))1976 fmt.Println("next receives are 2, 3 then closed:", ok)1977 ok = t.Recv(got, td.RecvNothing, 0)1978 fmt.Println("nothing to receive:", ok)1979 // Output:1980 // nothing to receive: true1981 // 1st receive is 1: true1982 // next receives are 2, 3 then closed: true1983 // nothing to receive: false1984}1985func ExampleT_Recv_withTimeout() {1986 t := td.NewT(&testing.T{})1987 got := make(chan int, 1)1988 tick := make(chan struct{})1989 go func() {1990 // ①1991 <-tick1992 time.Sleep(100 * time.Millisecond)1993 got <- 01994 // ②1995 <-tick1996 time.Sleep(100 * time.Millisecond)1997 got <- 11998 // ③1999 <-tick2000 time.Sleep(100 * time.Millisecond)2001 close(got)2002 }()2003 t.Recv(got, td.RecvNothing, 0)2004 // ①2005 tick <- struct{}{}2006 ok := t.Recv(got, td.RecvNothing, 0)2007 fmt.Println("① RecvNothing:", ok)2008 ok = t.Recv(got, 0, 150*time.Millisecond)2009 fmt.Println("① receive 0 w/150ms timeout:", ok)2010 ok = t.Recv(got, td.RecvNothing, 0)2011 fmt.Println("① RecvNothing:", ok)2012 // ②2013 tick <- struct{}{}2014 ok = t.Recv(got, td.RecvNothing, 0)2015 fmt.Println("② RecvNothing:", ok)2016 ok = t.Recv(got, 1, 150*time.Millisecond)2017 fmt.Println("② receive 1 w/150ms timeout:", ok)2018 ok = t.Recv(got, td.RecvNothing, 0)2019 fmt.Println("② RecvNothing:", ok)2020 // ③2021 tick <- struct{}{}2022 ok = t.Recv(got, td.RecvNothing, 0)2023 fmt.Println("③ RecvNothing:", ok)2024 ok = t.Recv(got, td.RecvClosed, 150*time.Millisecond)2025 fmt.Println("③ check closed w/150ms timeout:", ok)2026 // Output:2027 // ① RecvNothing: true2028 // ① receive 0 w/150ms timeout: true2029 // ① RecvNothing: true2030 // ② RecvNothing: true2031 // ② receive 1 w/150ms timeout: true2032 // ② RecvNothing: true2033 // ③ RecvNothing: true2034 // ③ check closed w/150ms timeout: true2035}2036func ExampleT_Recv_nilChannel() {2037 t := td.NewT(&testing.T{})2038 var ch chan int2039 ok := t.Recv(ch, td.RecvNothing, 0)2040 fmt.Println("nothing to receive from nil channel:", ok)2041 ok = t.Recv(ch, 42, 0)2042 fmt.Println("something to receive from nil channel:", ok)2043 ok = t.Recv(ch, td.RecvClosed, 0)2044 fmt.Println("is a nil channel closed:", ok)2045 // Output:2046 // nothing to receive from nil channel: true2047 // something to receive from nil channel: false2048 // is a nil channel closed: false2049}2050func ExampleT_Set() {2051 t := td.NewT(&testing.T{})2052 got := []int{1, 3, 5, 8, 8, 1, 2}2053 // Matches as all items are present, ignoring duplicates2054 ok := t.Set(got, []any{1, 2, 3, 5, 8},2055 "checks all items are present, in any order")2056 fmt.Println(ok)2057 // Duplicates are ignored in a Set2058 ok = t.Set(got, []any{1, 2, 2, 2, 2, 2, 3, 5, 8},2059 "checks all items are present, in any order")2060 fmt.Println(ok)2061 // Tries its best to not raise an error when a value can be matched2062 // by several Set entries2063 ok = t.Set(got, []any{td.Between(1, 4), 3, td.Between(2, 10)},2064 "checks all items are present, in any order")2065 fmt.Println(ok)2066 // When expected is already a non-[]any slice, it cannot be2067 // flattened directly using expected... without copying it to a new2068 // []any slice, then use td.Flatten!2069 expected := []int{1, 2, 3, 5, 8}2070 ok = t.Set(got, []any{td.Flatten(expected)},2071 "checks all expected items are present, in any order")2072 fmt.Println(ok)2073 // Output:2074 // true2075 // true2076 // true2077 // true2078}2079func ExampleT_Shallow() {2080 t := td.NewT(&testing.T{})2081 type MyStruct struct {2082 Value int2083 }2084 data := MyStruct{Value: 12}2085 got := &data2086 ok := t.Shallow(got, &data,2087 "checks pointers only, not contents")2088 fmt.Println(ok)2089 // Same contents, but not same pointer2090 ok = t.Shallow(got, &MyStruct{Value: 12},2091 "checks pointers only, not contents")2092 fmt.Println(ok)2093 // Output:2094 // true2095 // false2096}2097func ExampleT_Shallow_slice() {2098 t := td.NewT(&testing.T{})2099 back := []int{1, 2, 3, 1, 2, 3}2100 a := back[:3]2101 b := back[3:]2102 ok := t.Shallow(a, back)2103 fmt.Println("are ≠ but share the same area:", ok)2104 ok = t.Shallow(b, back)2105 fmt.Println("are = but do not point to same area:", ok)2106 // Output:2107 // are ≠ but share the same area: true2108 // are = but do not point to same area: false2109}2110func ExampleT_Shallow_string() {2111 t := td.NewT(&testing.T{})2112 back := "foobarfoobar"2113 a := back[:6]2114 b := back[6:]2115 ok := t.Shallow(a, back)2116 fmt.Println("are ≠ but share the same area:", ok)2117 ok = t.Shallow(b, a)2118 fmt.Println("are = but do not point to same area:", ok)2119 // Output:2120 // are ≠ but share the same area: true2121 // are = but do not point to same area: false2122}2123func ExampleT_Slice_slice() {2124 t := td.NewT(&testing.T{})2125 got := []int{42, 58, 26}2126 ok := t.Slice(got, []int{42}, td.ArrayEntries{1: 58, 2: td.Ignore()},2127 "checks slice %v", got)2128 fmt.Println(ok)2129 ok = t.Slice(got, []int{}, td.ArrayEntries{0: 42, 1: 58, 2: td.Ignore()},2130 "checks slice %v", got)2131 fmt.Println(ok)2132 ok = t.Slice(got, ([]int)(nil), td.ArrayEntries{0: 42, 1: 58, 2: td.Ignore()},2133 "checks slice %v", got)2134 fmt.Println(ok)2135 // Output:2136 // true2137 // true2138 // true2139}2140func ExampleT_Slice_typedSlice() {2141 t := td.NewT(&testing.T{})2142 type MySlice []int2143 got := MySlice{42, 58, 26}2144 ok := t.Slice(got, MySlice{42}, td.ArrayEntries{1: 58, 2: td.Ignore()},2145 "checks typed slice %v", got)2146 fmt.Println(ok)2147 ok = t.Slice(&got, &MySlice{42}, td.ArrayEntries{1: 58, 2: td.Ignore()},2148 "checks pointer on typed slice %v", got)2149 fmt.Println(ok)2150 ok = t.Slice(&got, &MySlice{}, td.ArrayEntries{0: 42, 1: 58, 2: td.Ignore()},2151 "checks pointer on typed slice %v", got)2152 fmt.Println(ok)2153 ok = t.Slice(&got, (*MySlice)(nil), td.ArrayEntries{0: 42, 1: 58, 2: td.Ignore()},2154 "checks pointer on typed slice %v", got)2155 fmt.Println(ok)2156 // Output:2157 // true2158 // true2159 // true2160 // true2161}2162func ExampleT_Smuggle_convert() {2163 t := td.NewT(&testing.T{})2164 got := int64(123)2165 ok := t.Smuggle(got, func(n int64) int { return int(n) }, 123,2166 "checks int64 got against an int value")2167 fmt.Println(ok)2168 ok = t.Smuggle("123", func(numStr string) (int, bool) {2169 n, err := strconv.Atoi(numStr)2170 return n, err == nil2171 }, td.Between(120, 130),2172 "checks that number in %#v is in [120 .. 130]")2173 fmt.Println(ok)2174 ok = t.Smuggle("123", func(numStr string) (int, bool, string) {2175 n, err := strconv.Atoi(numStr)2176 if err != nil {2177 return 0, false, "string must contain a number"2178 }2179 return n, true, ""2180 }, td.Between(120, 130),2181 "checks that number in %#v is in [120 .. 130]")2182 fmt.Println(ok)2183 ok = t.Smuggle("123", func(numStr string) (int, error) { //nolint: gocritic2184 return strconv.Atoi(numStr)2185 }, td.Between(120, 130),2186 "checks that number in %#v is in [120 .. 130]")2187 fmt.Println(ok)2188 // Short version :)2189 ok = t.Smuggle("123", strconv.Atoi, td.Between(120, 130),2190 "checks that number in %#v is in [120 .. 130]")2191 fmt.Println(ok)2192 // Output:2193 // true2194 // true2195 // true2196 // true2197 // true2198}2199func ExampleT_Smuggle_lax() {2200 t := td.NewT(&testing.T{})2201 // got is an int16 and Smuggle func input is an int64: it is OK2202 got := int(123)2203 ok := t.Smuggle(got, func(n int64) uint32 { return uint32(n) }, uint32(123))2204 fmt.Println("got int16(123) → smuggle via int64 → uint32(123):", ok)2205 // Output:2206 // got int16(123) → smuggle via int64 → uint32(123): true2207}2208func ExampleT_Smuggle_auto_unmarshal() {2209 t := td.NewT(&testing.T{})2210 // Automatically json.Unmarshal to compare2211 got := []byte(`{"a":1,"b":2}`)2212 ok := t.Smuggle(got, func(b json.RawMessage) (r map[string]int, err error) {2213 err = json.Unmarshal(b, &r)2214 return2215 }, map[string]int{2216 "a": 1,2217 "b": 2,2218 })2219 fmt.Println("JSON contents is OK:", ok)2220 // Output:2221 // JSON contents is OK: true2222}2223func ExampleT_Smuggle_cast() {2224 t := td.NewT(&testing.T{})2225 // A string containing JSON2226 got := `{ "foo": 123 }`2227 // Automatically cast a string to a json.RawMessage so td.JSON can operate2228 ok := t.Smuggle(got, json.RawMessage{}, td.JSON(`{"foo":123}`))2229 fmt.Println("JSON contents in string is OK:", ok)2230 // Automatically read from io.Reader to a json.RawMessage2231 ok = t.Smuggle(bytes.NewReader([]byte(got)), json.RawMessage{}, td.JSON(`{"foo":123}`))2232 fmt.Println("JSON contents just read is OK:", ok)2233 // Output:2234 // JSON contents in string is OK: true2235 // JSON contents just read is OK: true2236}2237func ExampleT_Smuggle_complex() {2238 t := td.NewT(&testing.T{})2239 // No end date but a start date and a duration2240 type StartDuration struct {2241 StartDate time.Time2242 Duration time.Duration2243 }2244 // Checks that end date is between 17th and 19th February both at 0h2245 // for each of these durations in hours2246 for _, duration := range []time.Duration{48 * time.Hour, 72 * time.Hour, 96 * time.Hour} {2247 got := StartDuration{2248 StartDate: time.Date(2018, time.February, 14, 12, 13, 14, 0, time.UTC),2249 Duration: duration,2250 }2251 // Simplest way, but in case of Between() failure, error will be bound2252 // to DATA<smuggled>, not very clear...2253 ok := t.Smuggle(got, func(sd StartDuration) time.Time {2254 return sd.StartDate.Add(sd.Duration)2255 }, td.Between(2256 time.Date(2018, time.February, 17, 0, 0, 0, 0, time.UTC),2257 time.Date(2018, time.February, 19, 0, 0, 0, 0, time.UTC)))2258 fmt.Println(ok)2259 // Name the computed value "ComputedEndDate" to render a Between() failure2260 // more understandable, so error will be bound to DATA.ComputedEndDate2261 ok = t.Smuggle(got, func(sd StartDuration) td.SmuggledGot {2262 return td.SmuggledGot{2263 Name: "ComputedEndDate",2264 Got: sd.StartDate.Add(sd.Duration),2265 }2266 }, td.Between(2267 time.Date(2018, time.February, 17, 0, 0, 0, 0, time.UTC),2268 time.Date(2018, time.February, 19, 0, 0, 0, 0, time.UTC)))2269 fmt.Println(ok)2270 }2271 // Output:2272 // false2273 // false2274 // true2275 // true2276 // true2277 // true2278}2279func ExampleT_Smuggle_interface() {2280 t := td.NewT(&testing.T{})2281 gotTime, err := time.Parse(time.RFC3339, "2018-05-23T12:13:14Z")2282 if err != nil {2283 t.Fatal(err)2284 }2285 // Do not check the struct itself, but its stringified form2286 ok := t.Smuggle(gotTime, func(s fmt.Stringer) string {2287 return s.String()2288 }, "2018-05-23 12:13:14 +0000 UTC")2289 fmt.Println("stringified time.Time OK:", ok)2290 // If got does not implement the fmt.Stringer interface, it fails2291 // without calling the Smuggle func2292 type MyTime time.Time2293 ok = t.Smuggle(MyTime(gotTime), func(s fmt.Stringer) string {2294 fmt.Println("Smuggle func called!")2295 return s.String()2296 }, "2018-05-23 12:13:14 +0000 UTC")2297 fmt.Println("stringified MyTime OK:", ok)2298 // Output:2299 // stringified time.Time OK: true2300 // stringified MyTime OK: false2301}2302func ExampleT_Smuggle_field_path() {2303 t := td.NewT(&testing.T{})2304 type Body struct {2305 Name string2306 Value any2307 }2308 type Request struct {2309 Body *Body2310 }2311 type Transaction struct {2312 Request2313 }2314 type ValueNum struct {2315 Num int2316 }2317 got := &Transaction{2318 Request: Request{2319 Body: &Body{2320 Name: "test",2321 Value: &ValueNum{Num: 123},2322 },2323 },2324 }2325 // Want to check whether Num is between 100 and 200?2326 ok := t.Smuggle(got, func(t *Transaction) (int, error) {2327 if t.Request.Body == nil ||2328 t.Request.Body.Value == nil {2329 return 0, errors.New("Request.Body or Request.Body.Value is nil")2330 }2331 if v, ok := t.Request.Body.Value.(*ValueNum); ok && v != nil {2332 return v.Num, nil2333 }2334 return 0, errors.New("Request.Body.Value isn't *ValueNum or nil")2335 }, td.Between(100, 200))2336 fmt.Println("check Num by hand:", ok)2337 // Same, but automagically generated...2338 ok = t.Smuggle(got, "Request.Body.Value.Num", td.Between(100, 200))2339 fmt.Println("check Num using a fields-path:", ok)2340 // And as Request is an anonymous field, can be simplified further2341 // as it can be omitted2342 ok = t.Smuggle(got, "Body.Value.Num", td.Between(100, 200))2343 fmt.Println("check Num using an other fields-path:", ok)2344 // Note that maps and array/slices are supported2345 got.Request.Body.Value = map[string]any{2346 "foo": []any{2347 3: map[int]string{666: "bar"},2348 },2349 }2350 ok = t.Smuggle(got, "Body.Value[foo][3][666]", "bar")2351 fmt.Println("check fields-path including maps/slices:", ok)2352 // Output:2353 // check Num by hand: true2354 // check Num using a fields-path: true2355 // check Num using an other fields-path: true2356 // check fields-path including maps/slices: true2357}2358func ExampleT_SStruct() {2359 t := td.NewT(&testing.T{})2360 type Person struct {2361 Name string2362 Age int2363 NumChildren int2364 }2365 got := Person{2366 Name: "Foobar",2367 Age: 42,2368 NumChildren: 0,2369 }2370 // NumChildren is not listed in expected fields so it must be zero2371 ok := t.SStruct(got, Person{Name: "Foobar"}, td.StructFields{2372 "Age": td.Between(40, 50),2373 },2374 "checks %v is the right Person")2375 fmt.Println("Foobar is between 40 & 50:", ok)2376 // Model can be empty2377 got.NumChildren = 32378 ok = t.SStruct(got, Person{}, td.StructFields{2379 "Name": "Foobar",2380 "Age": td.Between(40, 50),2381 "NumChildren": td.Not(0),2382 },2383 "checks %v is the right Person")2384 fmt.Println("Foobar has some children:", ok)2385 // Works with pointers too2386 ok = t.SStruct(&got, &Person{}, td.StructFields{2387 "Name": "Foobar",2388 "Age": td.Between(40, 50),2389 "NumChildren": td.Not(0),2390 },2391 "checks %v is the right Person")2392 fmt.Println("Foobar has some children (using pointer):", ok)2393 // Model does not need to be instanciated2394 ok = t.SStruct(&got, (*Person)(nil), td.StructFields{2395 "Name": "Foobar",2396 "Age": td.Between(40, 50),2397 "NumChildren": td.Not(0),2398 },2399 "checks %v is the right Person")2400 fmt.Println("Foobar has some children (using nil model):", ok)2401 // Output:2402 // Foobar is between 40 & 50: true2403 // Foobar has some children: true2404 // Foobar has some children (using pointer): true2405 // Foobar has some children (using nil model): true2406}2407func ExampleT_SStruct_overwrite_model() {2408 t := td.NewT(&testing.T{})2409 type Person struct {2410 Name string2411 Age int2412 NumChildren int2413 }2414 got := Person{2415 Name: "Foobar",2416 Age: 42,2417 NumChildren: 3,2418 }2419 ok := t.SStruct(got, Person{2420 Name: "Foobar",2421 Age: 53,2422 }, td.StructFields{2423 ">Age": td.Between(40, 50), // ">" to overwrite Age:53 in model2424 "NumChildren": td.Gt(2),2425 },2426 "checks %v is the right Person")2427 fmt.Println("Foobar is between 40 & 50:", ok)2428 ok = t.SStruct(got, Person{2429 Name: "Foobar",2430 Age: 53,2431 }, td.StructFields{2432 "> Age": td.Between(40, 50), // same, ">" can be followed by spaces2433 "NumChildren": td.Gt(2),2434 },2435 "checks %v is the right Person")2436 fmt.Println("Foobar is between 40 & 50:", ok)2437 // Output:2438 // Foobar is between 40 & 50: true2439 // Foobar is between 40 & 50: true2440}2441func ExampleT_SStruct_patterns() {2442 t := td.NewT(&testing.T{})2443 type Person struct {2444 Firstname string2445 Lastname string2446 Surname string2447 Nickname string2448 CreatedAt time.Time2449 UpdatedAt time.Time2450 DeletedAt *time.Time2451 id int642452 secret string2453 }2454 now := time.Now()2455 got := Person{2456 Firstname: "Maxime",2457 Lastname: "Foo",2458 Surname: "Max",2459 Nickname: "max",2460 CreatedAt: now,2461 UpdatedAt: now,2462 DeletedAt: nil, // not deleted yet2463 id: 2345,2464 secret: "5ecr3T",2465 }2466 ok := t.SStruct(got, Person{Lastname: "Foo"}, td.StructFields{2467 `DeletedAt`: nil,2468 `= *name`: td.Re(`^(?i)max`), // shell pattern, matches all names except Lastname as in model2469 `=~ At\z`: td.Lte(time.Now()), // regexp, matches CreatedAt & UpdatedAt2470 `! [A-Z]*`: td.Ignore(), // private fields2471 },2472 "mix shell & regexp patterns")2473 fmt.Println("Patterns match only remaining fields:", ok)2474 ok = t.SStruct(got, Person{Lastname: "Foo"}, td.StructFields{2475 `DeletedAt`: nil,2476 `1 = *name`: td.Re(`^(?i)max`), // shell pattern, matches all names except Lastname as in model2477 `2 =~ At\z`: td.Lte(time.Now()), // regexp, matches CreatedAt & UpdatedAt2478 `3 !~ ^[A-Z]`: td.Ignore(), // private fields2479 },2480 "ordered patterns")2481 fmt.Println("Ordered patterns match only remaining fields:", ok)2482 // Output:2483 // Patterns match only remaining fields: true2484 // Ordered patterns match only remaining fields: true2485}2486func ExampleT_String() {2487 t := td.NewT(&testing.T{})2488 got := "foobar"2489 ok := t.String(got, "foobar", "checks %s", got)2490 fmt.Println("using string:", ok)2491 ok = t.Cmp([]byte(got), td.String("foobar"), "checks %s", got)2492 fmt.Println("using []byte:", ok)2493 // Output:2494 // using string: true2495 // using []byte: true2496}2497func ExampleT_String_stringer() {2498 t := td.NewT(&testing.T{})2499 // bytes.Buffer implements fmt.Stringer2500 got := bytes.NewBufferString("foobar")2501 ok := t.String(got, "foobar", "checks %s", got)2502 fmt.Println(ok)2503 // Output:2504 // true2505}2506func ExampleT_String_error() {2507 t := td.NewT(&testing.T{})2508 got := errors.New("foobar")2509 ok := t.String(got, "foobar", "checks %s", got)2510 fmt.Println(ok)2511 // Output:2512 // true2513}2514func ExampleT_Struct() {2515 t := td.NewT(&testing.T{})2516 type Person struct {2517 Name string2518 Age int2519 NumChildren int2520 }2521 got := Person{2522 Name: "Foobar",2523 Age: 42,2524 NumChildren: 3,2525 }2526 // As NumChildren is zero in Struct() call, it is not checked2527 ok := t.Struct(got, Person{Name: "Foobar"}, td.StructFields{2528 "Age": td.Between(40, 50),2529 },2530 "checks %v is the right Person")2531 fmt.Println("Foobar is between 40 & 50:", ok)2532 // Model can be empty2533 ok = t.Struct(got, Person{}, td.StructFields{2534 "Name": "Foobar",2535 "Age": td.Between(40, 50),2536 "NumChildren": td.Not(0),2537 },2538 "checks %v is the right Person")2539 fmt.Println("Foobar has some children:", ok)2540 // Works with pointers too2541 ok = t.Struct(&got, &Person{}, td.StructFields{2542 "Name": "Foobar",2543 "Age": td.Between(40, 50),2544 "NumChildren": td.Not(0),2545 },2546 "checks %v is the right Person")2547 fmt.Println("Foobar has some children (using pointer):", ok)2548 // Model does not need to be instanciated2549 ok = t.Struct(&got, (*Person)(nil), td.StructFields{2550 "Name": "Foobar",2551 "Age": td.Between(40, 50),2552 "NumChildren": td.Not(0),2553 },2554 "checks %v is the right Person")2555 fmt.Println("Foobar has some children (using nil model):", ok)2556 // Output:2557 // Foobar is between 40 & 50: true2558 // Foobar has some children: true2559 // Foobar has some children (using pointer): true2560 // Foobar has some children (using nil model): true2561}2562func ExampleT_Struct_overwrite_model() {2563 t := td.NewT(&testing.T{})2564 type Person struct {2565 Name string2566 Age int2567 NumChildren int2568 }2569 got := Person{2570 Name: "Foobar",2571 Age: 42,2572 NumChildren: 3,2573 }2574 ok := t.Struct(got, Person{2575 Name: "Foobar",2576 Age: 53,2577 }, td.StructFields{2578 ">Age": td.Between(40, 50), // ">" to overwrite Age:53 in model2579 "NumChildren": td.Gt(2),2580 },2581 "checks %v is the right Person")2582 fmt.Println("Foobar is between 40 & 50:", ok)2583 ok = t.Struct(got, Person{2584 Name: "Foobar",2585 Age: 53,2586 }, td.StructFields{2587 "> Age": td.Between(40, 50), // same, ">" can be followed by spaces2588 "NumChildren": td.Gt(2),2589 },2590 "checks %v is the right Person")2591 fmt.Println("Foobar is between 40 & 50:", ok)2592 // Output:2593 // Foobar is between 40 & 50: true2594 // Foobar is between 40 & 50: true2595}2596func ExampleT_Struct_patterns() {2597 t := td.NewT(&testing.T{})2598 type Person struct {2599 Firstname string2600 Lastname string2601 Surname string2602 Nickname string2603 CreatedAt time.Time2604 UpdatedAt time.Time2605 DeletedAt *time.Time2606 }2607 now := time.Now()2608 got := Person{2609 Firstname: "Maxime",2610 Lastname: "Foo",2611 Surname: "Max",2612 Nickname: "max",2613 CreatedAt: now,2614 UpdatedAt: now,2615 DeletedAt: nil, // not deleted yet2616 }2617 ok := t.Struct(got, Person{Lastname: "Foo"}, td.StructFields{2618 `DeletedAt`: nil,2619 `= *name`: td.Re(`^(?i)max`), // shell pattern, matches all names except Lastname as in model2620 `=~ At\z`: td.Lte(time.Now()), // regexp, matches CreatedAt & UpdatedAt2621 },2622 "mix shell & regexp patterns")2623 fmt.Println("Patterns match only remaining fields:", ok)2624 ok = t.Struct(got, Person{Lastname: "Foo"}, td.StructFields{2625 `DeletedAt`: nil,2626 `1 = *name`: td.Re(`^(?i)max`), // shell pattern, matches all names except Lastname as in model2627 `2 =~ At\z`: td.Lte(time.Now()), // regexp, matches CreatedAt & UpdatedAt2628 },2629 "ordered patterns")2630 fmt.Println("Ordered patterns match only remaining fields:", ok)2631 // Output:2632 // Patterns match only remaining fields: true2633 // Ordered patterns match only remaining fields: true2634}2635func ExampleT_SubBagOf() {2636 t := td.NewT(&testing.T{})2637 got := []int{1, 3, 5, 8, 8, 1, 2}2638 ok := t.SubBagOf(got, []any{0, 0, 1, 1, 2, 2, 3, 3, 5, 5, 8, 8, 9, 9},2639 "checks at least all items are present, in any order")2640 fmt.Println(ok)2641 // got contains one 8 too many2642 ok = t.SubBagOf(got, []any{0, 0, 1, 1, 2, 2, 3, 3, 5, 5, 8, 9, 9},2643 "checks at least all items are present, in any order")2644 fmt.Println(ok)2645 got = []int{1, 3, 5, 2}2646 ok = t.SubBagOf(got, []any{td.Between(0, 3), td.Between(0, 3), td.Between(0, 3), td.Between(0, 3), td.Gt(4), td.Gt(4)},2647 "checks at least all items match, in any order with TestDeep operators")2648 fmt.Println(ok)2649 // When expected is already a non-[]any slice, it cannot be2650 // flattened directly using expected... without copying it to a new2651 // []any slice, then use td.Flatten!2652 expected := []int{1, 2, 3, 5, 9, 8}2653 ok = t.SubBagOf(got, []any{td.Flatten(expected)},2654 "checks at least all expected items are present, in any order")2655 fmt.Println(ok)2656 // Output:2657 // true2658 // false2659 // true2660 // true2661}2662func ExampleT_SubJSONOf_basic() {2663 t := td.NewT(&testing.T{})2664 got := &struct {2665 Fullname string `json:"fullname"`2666 Age int `json:"age"`2667 }{2668 Fullname: "Bob",2669 Age: 42,2670 }2671 ok := t.SubJSONOf(got, `{"age":42,"fullname":"Bob","gender":"male"}`, nil)2672 fmt.Println("check got with age then fullname:", ok)2673 ok = t.SubJSONOf(got, `{"fullname":"Bob","age":42,"gender":"male"}`, nil)2674 fmt.Println("check got with fullname then age:", ok)2675 ok = t.SubJSONOf(got, `2676// This should be the JSON representation of a struct2677{2678 // A person:2679 "fullname": "Bob", // The name of this person2680 "age": 42, /* The age of this person:2681 - 42 of course2682 - to demonstrate a multi-lines comment */2683 "gender": "male" // This field is ignored as SubJSONOf2684}`, nil)2685 fmt.Println("check got with nicely formatted and commented JSON:", ok)2686 ok = t.SubJSONOf(got, `{"fullname":"Bob","gender":"male"}`, nil)2687 fmt.Println("check got without age field:", ok)2688 // Output:2689 // check got with age then fullname: true2690 // check got with fullname then age: true2691 // check got with nicely formatted and commented JSON: true2692 // check got without age field: false2693}2694func ExampleT_SubJSONOf_placeholders() {2695 t := td.NewT(&testing.T{})2696 got := &struct {2697 Fullname string `json:"fullname"`2698 Age int `json:"age"`2699 }{2700 Fullname: "Bob Foobar",2701 Age: 42,2702 }2703 ok := t.SubJSONOf(got, `{"age": $1, "fullname": $2, "gender": $3}`, []any{42, "Bob Foobar", "male"})2704 fmt.Println("check got with numeric placeholders without operators:", ok)2705 ok = t.SubJSONOf(got, `{"age": $1, "fullname": $2, "gender": $3}`, []any{td.Between(40, 45), td.HasSuffix("Foobar"), td.NotEmpty()})2706 fmt.Println("check got with numeric placeholders:", ok)2707 ok = t.SubJSONOf(got, `{"age": "$1", "fullname": "$2", "gender": "$3"}`, []any{td.Between(40, 45), td.HasSuffix("Foobar"), td.NotEmpty()})2708 fmt.Println("check got with double-quoted numeric placeholders:", ok)2709 ok = t.SubJSONOf(got, `{"age": $age, "fullname": $name, "gender": $gender}`, []any{td.Tag("age", td.Between(40, 45)), td.Tag("name", td.HasSuffix("Foobar")), td.Tag("gender", td.NotEmpty())})2710 fmt.Println("check got with named placeholders:", ok)2711 ok = t.SubJSONOf(got, `{"age": $^NotZero, "fullname": $^NotEmpty, "gender": $^NotEmpty}`, nil)2712 fmt.Println("check got with operator shortcuts:", ok)2713 // Output:2714 // check got with numeric placeholders without operators: true2715 // check got with numeric placeholders: true2716 // check got with double-quoted numeric placeholders: true2717 // check got with named placeholders: true2718 // check got with operator shortcuts: true2719}2720func ExampleT_SubJSONOf_file() {2721 t := td.NewT(&testing.T{})2722 got := &struct {2723 Fullname string `json:"fullname"`2724 Age int `json:"age"`2725 Gender string `json:"gender"`2726 }{2727 Fullname: "Bob Foobar",2728 Age: 42,2729 Gender: "male",2730 }2731 tmpDir, err := os.MkdirTemp("", "")2732 if err != nil {2733 t.Fatal(err)2734 }2735 defer os.RemoveAll(tmpDir) // clean up2736 filename := tmpDir + "/test.json"2737 if err = os.WriteFile(filename, []byte(`2738{2739 "fullname": "$name",2740 "age": "$age",2741 "gender": "$gender",2742 "details": {2743 "city": "TestCity",2744 "zip": 6662745 }2746}`), 0644); err != nil {2747 t.Fatal(err)2748 }2749 // OK let's test with this file2750 ok := t.SubJSONOf(got, filename, []any{td.Tag("name", td.HasPrefix("Bob")), td.Tag("age", td.Between(40, 45)), td.Tag("gender", td.Re(`^(male|female)\z`))})2751 fmt.Println("Full match from file name:", ok)2752 // When the file is already open2753 file, err := os.Open(filename)2754 if err != nil {2755 t.Fatal(err)2756 }2757 ok = t.SubJSONOf(got, file, []any{td.Tag("name", td.HasPrefix("Bob")), td.Tag("age", td.Between(40, 45)), td.Tag("gender", td.Re(`^(male|female)\z`))})2758 fmt.Println("Full match from io.Reader:", ok)2759 // Output:2760 // Full match from file name: true2761 // Full match from io.Reader: true2762}2763func ExampleT_SubMapOf_map() {2764 t := td.NewT(&testing.T{})2765 got := map[string]int{"foo": 12, "bar": 42}2766 ok := t.SubMapOf(got, map[string]int{"bar": 42}, td.MapEntries{"foo": td.Lt(15), "zip": 666},2767 "checks map %v is included in expected keys/values", got)2768 fmt.Println(ok)2769 // Output:2770 // true2771}2772func ExampleT_SubMapOf_typedMap() {2773 t := td.NewT(&testing.T{})2774 type MyMap map[string]int2775 got := MyMap{"foo": 12, "bar": 42}2776 ok := t.SubMapOf(got, MyMap{"bar": 42}, td.MapEntries{"foo": td.Lt(15), "zip": 666},2777 "checks typed map %v is included in expected keys/values", got)2778 fmt.Println(ok)2779 ok = t.SubMapOf(&got, &MyMap{"bar": 42}, td.MapEntries{"foo": td.Lt(15), "zip": 666},2780 "checks pointed typed map %v is included in expected keys/values", got)2781 fmt.Println(ok)2782 // Output:2783 // true2784 // true2785}2786func ExampleT_SubSetOf() {2787 t := td.NewT(&testing.T{})2788 got := []int{1, 3, 5, 8, 8, 1, 2}2789 // Matches as all items are expected, ignoring duplicates2790 ok := t.SubSetOf(got, []any{1, 2, 3, 4, 5, 6, 7, 8},2791 "checks at least all items are present, in any order, ignoring duplicates")2792 fmt.Println(ok)2793 // Tries its best to not raise an error when a value can be matched2794 // by several SubSetOf entries2795 ok = t.SubSetOf(got, []any{td.Between(1, 4), 3, td.Between(2, 10), td.Gt(100)},2796 "checks at least all items are present, in any order, ignoring duplicates")2797 fmt.Println(ok)2798 // When expected is already a non-[]any slice, it cannot be2799 // flattened directly using expected... without copying it to a new2800 // []any slice, then use td.Flatten!2801 expected := []int{1, 2, 3, 4, 5, 6, 7, 8}2802 ok = t.SubSetOf(got, []any{td.Flatten(expected)},2803 "checks at least all expected items are present, in any order, ignoring duplicates")2804 fmt.Println(ok)2805 // Output:2806 // true2807 // true2808 // true2809}2810func ExampleT_SuperBagOf() {2811 t := td.NewT(&testing.T{})2812 got := []int{1, 3, 5, 8, 8, 1, 2}2813 ok := t.SuperBagOf(got, []any{8, 5, 8},2814 "checks the items are present, in any order")2815 fmt.Println(ok)2816 ok = t.SuperBagOf(got, []any{td.Gt(5), td.Lte(2)},2817 "checks at least 2 items of %v match", got)2818 fmt.Println(ok)2819 // When expected is already a non-[]any slice, it cannot be2820 // flattened directly using expected... without copying it to a new2821 // []any slice, then use td.Flatten!2822 expected := []int{8, 5, 8}2823 ok = t.SuperBagOf(got, []any{td.Flatten(expected)},2824 "checks the expected items are present, in any order")2825 fmt.Println(ok)2826 // Output:2827 // true2828 // true2829 // true2830}2831func ExampleT_SuperJSONOf_basic() {2832 t := td.NewT(&testing.T{})2833 got := &struct {2834 Fullname string `json:"fullname"`2835 Age int `json:"age"`2836 Gender string `json:"gender"`2837 City string `json:"city"`2838 Zip int `json:"zip"`2839 }{2840 Fullname: "Bob",2841 Age: 42,2842 Gender: "male",2843 City: "TestCity",2844 Zip: 666,2845 }2846 ok := t.SuperJSONOf(got, `{"age":42,"fullname":"Bob","gender":"male"}`, nil)2847 fmt.Println("check got with age then fullname:", ok)2848 ok = t.SuperJSONOf(got, `{"fullname":"Bob","age":42,"gender":"male"}`, nil)2849 fmt.Println("check got with fullname then age:", ok)2850 ok = t.SuperJSONOf(got, `2851// This should be the JSON representation of a struct2852{2853 // A person:2854 "fullname": "Bob", // The name of this person2855 "age": 42, /* The age of this person:2856 - 42 of course2857 - to demonstrate a multi-lines comment */2858 "gender": "male" // The gender!2859}`, nil)2860 fmt.Println("check got with nicely formatted and commented JSON:", ok)2861 ok = t.SuperJSONOf(got, `{"fullname":"Bob","gender":"male","details":{}}`, nil)2862 fmt.Println("check got with details field:", ok)2863 // Output:2864 // check got with age then fullname: true2865 // check got with fullname then age: true2866 // check got with nicely formatted and commented JSON: true2867 // check got with details field: false2868}2869func ExampleT_SuperJSONOf_placeholders() {2870 t := td.NewT(&testing.T{})2871 got := &struct {2872 Fullname string `json:"fullname"`2873 Age int `json:"age"`2874 Gender string `json:"gender"`2875 City string `json:"city"`2876 Zip int `json:"zip"`2877 }{2878 Fullname: "Bob Foobar",2879 Age: 42,2880 Gender: "male",2881 City: "TestCity",2882 Zip: 666,2883 }2884 ok := t.SuperJSONOf(got, `{"age": $1, "fullname": $2, "gender": $3}`, []any{42, "Bob Foobar", "male"})2885 fmt.Println("check got with numeric placeholders without operators:", ok)2886 ok = t.SuperJSONOf(got, `{"age": $1, "fullname": $2, "gender": $3}`, []any{td.Between(40, 45), td.HasSuffix("Foobar"), td.NotEmpty()})2887 fmt.Println("check got with numeric placeholders:", ok)2888 ok = t.SuperJSONOf(got, `{"age": "$1", "fullname": "$2", "gender": "$3"}`, []any{td.Between(40, 45), td.HasSuffix("Foobar"), td.NotEmpty()})2889 fmt.Println("check got with double-quoted numeric placeholders:", ok)2890 ok = t.SuperJSONOf(got, `{"age": $age, "fullname": $name, "gender": $gender}`, []any{td.Tag("age", td.Between(40, 45)), td.Tag("name", td.HasSuffix("Foobar")), td.Tag("gender", td.NotEmpty())})2891 fmt.Println("check got with named placeholders:", ok)2892 ok = t.SuperJSONOf(got, `{"age": $^NotZero, "fullname": $^NotEmpty, "gender": $^NotEmpty}`, nil)2893 fmt.Println("check got with operator shortcuts:", ok)2894 // Output:2895 // check got with numeric placeholders without operators: true2896 // check got with numeric placeholders: true2897 // check got with double-quoted numeric placeholders: true2898 // check got with named placeholders: true2899 // check got with operator shortcuts: true2900}2901func ExampleT_SuperJSONOf_file() {2902 t := td.NewT(&testing.T{})2903 got := &struct {2904 Fullname string `json:"fullname"`2905 Age int `json:"age"`2906 Gender string `json:"gender"`2907 City string `json:"city"`2908 Zip int `json:"zip"`2909 }{2910 Fullname: "Bob Foobar",2911 Age: 42,2912 Gender: "male",2913 City: "TestCity",2914 Zip: 666,2915 }2916 tmpDir, err := os.MkdirTemp("", "")2917 if err != nil {2918 t.Fatal(err)2919 }2920 defer os.RemoveAll(tmpDir) // clean up2921 filename := tmpDir + "/test.json"2922 if err = os.WriteFile(filename, []byte(`2923{2924 "fullname": "$name",2925 "age": "$age",2926 "gender": "$gender"2927}`), 0644); err != nil {2928 t.Fatal(err)2929 }2930 // OK let's test with this file2931 ok := t.SuperJSONOf(got, filename, []any{td.Tag("name", td.HasPrefix("Bob")), td.Tag("age", td.Between(40, 45)), td.Tag("gender", td.Re(`^(male|female)\z`))})2932 fmt.Println("Full match from file name:", ok)2933 // When the file is already open2934 file, err := os.Open(filename)2935 if err != nil {2936 t.Fatal(err)2937 }2938 ok = t.SuperJSONOf(got, file, []any{td.Tag("name", td.HasPrefix("Bob")), td.Tag("age", td.Between(40, 45)), td.Tag("gender", td.Re(`^(male|female)\z`))})2939 fmt.Println("Full match from io.Reader:", ok)2940 // Output:2941 // Full match from file name: true2942 // Full match from io.Reader: true2943}2944func ExampleT_SuperMapOf_map() {2945 t := td.NewT(&testing.T{})2946 got := map[string]int{"foo": 12, "bar": 42, "zip": 89}2947 ok := t.SuperMapOf(got, map[string]int{"bar": 42}, td.MapEntries{"foo": td.Lt(15)},2948 "checks map %v contains at leat all expected keys/values", got)2949 fmt.Println(ok)2950 // Output:2951 // true2952}2953func ExampleT_SuperMapOf_typedMap() {2954 t := td.NewT(&testing.T{})2955 type MyMap map[string]int2956 got := MyMap{"foo": 12, "bar": 42, "zip": 89}2957 ok := t.SuperMapOf(got, MyMap{"bar": 42}, td.MapEntries{"foo": td.Lt(15)},2958 "checks typed map %v contains at leat all expected keys/values", got)2959 fmt.Println(ok)2960 ok = t.SuperMapOf(&got, &MyMap{"bar": 42}, td.MapEntries{"foo": td.Lt(15)},2961 "checks pointed typed map %v contains at leat all expected keys/values",2962 got)2963 fmt.Println(ok)2964 // Output:2965 // true2966 // true2967}2968func ExampleT_SuperSetOf() {2969 t := td.NewT(&testing.T{})2970 got := []int{1, 3, 5, 8, 8, 1, 2}2971 ok := t.SuperSetOf(got, []any{1, 2, 3},2972 "checks the items are present, in any order and ignoring duplicates")2973 fmt.Println(ok)2974 ok = t.SuperSetOf(got, []any{td.Gt(5), td.Lte(2)},2975 "checks at least 2 items of %v match ignoring duplicates", got)2976 fmt.Println(ok)2977 // When expected is already a non-[]any slice, it cannot be2978 // flattened directly using expected... without copying it to a new2979 // []any slice, then use td.Flatten!2980 expected := []int{1, 2, 3}2981 ok = t.SuperSetOf(got, []any{td.Flatten(expected)},2982 "checks the expected items are present, in any order and ignoring duplicates")2983 fmt.Println(ok)2984 // Output:2985 // true2986 // true2987 // true2988}2989func ExampleT_SuperSliceOf_array() {2990 t := td.NewT(&testing.T{})2991 got := [4]int{42, 58, 26, 666}2992 ok := t.SuperSliceOf(got, [4]int{1: 58}, td.ArrayEntries{3: td.Gt(660)},2993 "checks array %v", got)2994 fmt.Println("Only check items #1 & #3:", ok)2995 ok = t.SuperSliceOf(got, [4]int{}, td.ArrayEntries{0: 42, 3: td.Between(660, 670)},2996 "checks array %v", got)2997 fmt.Println("Only check items #0 & #3:", ok)2998 ok = t.SuperSliceOf(&got, &[4]int{}, td.ArrayEntries{0: 42, 3: td.Between(660, 670)},2999 "checks array %v", got)3000 fmt.Println("Only check items #0 & #3 of an array pointer:", ok)3001 ok = t.SuperSliceOf(&got, (*[4]int)(nil), td.ArrayEntries{0: 42, 3: td.Between(660, 670)},3002 "checks array %v", got)3003 fmt.Println("Only check items #0 & #3 of an array pointer, using nil model:", ok)3004 // Output:3005 // Only check items #1 & #3: true3006 // Only check items #0 & #3: true3007 // Only check items #0 & #3 of an array pointer: true3008 // Only check items #0 & #3 of an array pointer, using nil model: true3009}3010func ExampleT_SuperSliceOf_typedArray() {3011 t := td.NewT(&testing.T{})3012 type MyArray [4]int3013 got := MyArray{42, 58, 26, 666}3014 ok := t.SuperSliceOf(got, MyArray{1: 58}, td.ArrayEntries{3: td.Gt(660)},3015 "checks typed array %v", got)3016 fmt.Println("Only check items #1 & #3:", ok)3017 ok = t.SuperSliceOf(got, MyArray{}, td.ArrayEntries{0: 42, 3: td.Between(660, 670)},3018 "checks array %v", got)3019 fmt.Println("Only check items #0 & #3:", ok)3020 ok = t.SuperSliceOf(&got, &MyArray{}, td.ArrayEntries{0: 42, 3: td.Between(660, 670)},3021 "checks array %v", got)3022 fmt.Println("Only check items #0 & #3 of an array pointer:", ok)3023 ok = t.SuperSliceOf(&got, (*MyArray)(nil), td.ArrayEntries{0: 42, 3: td.Between(660, 670)},3024 "checks array %v", got)3025 fmt.Println("Only check items #0 & #3 of an array pointer, using nil model:", ok)3026 // Output:3027 // Only check items #1 & #3: true3028 // Only check items #0 & #3: true3029 // Only check items #0 & #3 of an array pointer: true3030 // Only check items #0 & #3 of an array pointer, using nil model: true3031}3032func ExampleT_SuperSliceOf_slice() {3033 t := td.NewT(&testing.T{})3034 got := []int{42, 58, 26, 666}3035 ok := t.SuperSliceOf(got, []int{1: 58}, td.ArrayEntries{3: td.Gt(660)},3036 "checks array %v", got)3037 fmt.Println("Only check items #1 & #3:", ok)3038 ok = t.SuperSliceOf(got, []int{}, td.ArrayEntries{0: 42, 3: td.Between(660, 670)},3039 "checks array %v", got)3040 fmt.Println("Only check items #0 & #3:", ok)3041 ok = t.SuperSliceOf(&got, &[]int{}, td.ArrayEntries{0: 42, 3: td.Between(660, 670)},3042 "checks array %v", got)3043 fmt.Println("Only check items #0 & #3 of a slice pointer:", ok)3044 ok = t.SuperSliceOf(&got, (*[]int)(nil), td.ArrayEntries{0: 42, 3: td.Between(660, 670)},3045 "checks array %v", got)3046 fmt.Println("Only check items #0 & #3 of a slice pointer, using nil model:", ok)3047 // Output:3048 // Only check items #1 & #3: true3049 // Only check items #0 & #3: true3050 // Only check items #0 & #3 of a slice pointer: true3051 // Only check items #0 & #3 of a slice pointer, using nil model: true3052}3053func ExampleT_SuperSliceOf_typedSlice() {3054 t := td.NewT(&testing.T{})3055 type MySlice []int3056 got := MySlice{42, 58, 26, 666}3057 ok := t.SuperSliceOf(got, MySlice{1: 58}, td.ArrayEntries{3: td.Gt(660)},3058 "checks typed array %v", got)3059 fmt.Println("Only check items #1 & #3:", ok)3060 ok = t.SuperSliceOf(got, MySlice{}, td.ArrayEntries{0: 42, 3: td.Between(660, 670)},3061 "checks array %v", got)3062 fmt.Println("Only check items #0 & #3:", ok)3063 ok = t.SuperSliceOf(&got, &MySlice{}, td.ArrayEntries{0: 42, 3: td.Between(660, 670)},3064 "checks array %v", got)3065 fmt.Println("Only check items #0 & #3 of a slice pointer:", ok)3066 ok = t.SuperSliceOf(&got, (*MySlice)(nil), td.ArrayEntries{0: 42, 3: td.Between(660, 670)},3067 "checks array %v", got)3068 fmt.Println("Only check items #0 & #3 of a slice pointer, using nil model:", ok)3069 // Output:3070 // Only check items #1 & #3: true3071 // Only check items #0 & #3: true3072 // Only check items #0 & #3 of a slice pointer: true3073 // Only check items #0 & #3 of a slice pointer, using nil model: true3074}3075func ExampleT_TruncTime() {3076 t := td.NewT(&testing.T{})3077 dateToTime := func(str string) time.Time {3078 t, err := time.Parse(time.RFC3339Nano, str)3079 if err != nil {3080 panic(err)3081 }3082 return t3083 }3084 got := dateToTime("2018-05-01T12:45:53.123456789Z")3085 // Compare dates ignoring nanoseconds and monotonic parts3086 expected := dateToTime("2018-05-01T12:45:53Z")3087 ok := t.TruncTime(got, expected, time.Second,3088 "checks date %v, truncated to the second", got)3089 fmt.Println(ok)3090 // Compare dates ignoring time and so monotonic parts3091 expected = dateToTime("2018-05-01T11:22:33.444444444Z")3092 ok = t.TruncTime(got, expected, 24*time.Hour,3093 "checks date %v, truncated to the day", got)3094 fmt.Println(ok)3095 // Compare dates exactly but ignoring monotonic part3096 expected = dateToTime("2018-05-01T12:45:53.123456789Z")3097 ok = t.TruncTime(got, expected, 0,3098 "checks date %v ignoring monotonic part", got)3099 fmt.Println(ok)3100 // Output:3101 // true3102 // true3103 // true3104}3105func ExampleT_Values() {3106 t := td.NewT(&testing.T{})3107 got := map[string]int{"foo": 1, "bar": 2, "zip": 3}3108 // Values tests values in an ordered manner3109 ok := t.Values(got, []int{1, 2, 3})3110 fmt.Println("All sorted values are found:", ok)3111 // If the expected values are not ordered, it fails3112 ok = t.Values(got, []int{3, 1, 2})3113 fmt.Println("All unsorted values are found:", ok)3114 // To circumvent that, one can use Bag operator3115 ok = t.Values(got, td.Bag(3, 1, 2))3116 fmt.Println("All unsorted values are found, with the help of Bag operator:", ok)3117 // Check that each value is between 1 and 33118 ok = t.Values(got, td.ArrayEach(td.Between(1, 3)))3119 fmt.Println("Each value is between 1 and 3:", ok)3120 // Output:3121 // All sorted values are found: true3122 // All unsorted values are found: false3123 // All unsorted values are found, with the help of Bag operator: true3124 // Each value is between 1 and 3: true3125}3126func ExampleT_Zero() {3127 t := td.NewT(&testing.T{})3128 ok := t.Zero(0)3129 fmt.Println(ok)3130 ok = t.Zero(float64(0))3131 fmt.Println(ok)3132 ok = t.Zero(12) // fails, as 12 is not 0 :)3133 fmt.Println(ok)3134 ok = t.Zero((map[string]int)(nil))3135 fmt.Println(ok)3136 ok = t.Zero(map[string]int{}) // fails, as not nil3137 fmt.Println(ok)3138 ok = t.Zero(([]int)(nil))3139 fmt.Println(ok)3140 ok = t.Zero([]int{}) // fails, as not nil3141 fmt.Println(ok)...

Full Screen

Full Screen

test_api_test.go

Source:test_api_test.go Github

copy

Full Screen

...112 w.Header().Set("X-TestDeep-Foo", "bar")113 })114 return mux115}116func TestNewTestAPI(t *testing.T) {117 mux := server()118 containsKey := td.ContainsKey("X-Testdeep-Method")119 t.Run("No error", func(t *testing.T) {120 mockT := tdutil.NewT("test")121 td.CmpFalse(t,122 tdhttp.NewTestAPI(mockT, mux).123 Head("/any").124 CmpStatus(200).125 CmpHeader(containsKey).126 CmpHeader(td.SuperMapOf(http.Header{}, td.MapEntries{127 "X-Testdeep-Method": td.Bag(td.Re(`(?i)^head\z`)),128 })).129 NoBody().130 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {131 assert.Cmp(resp.StatusCode, 200)132 assert.Cmp(resp.Header, containsKey)133 assert.Smuggle(resp.Body, io.ReadAll, td.Empty())134 })).135 Failed())136 td.CmpEmpty(t, mockT.LogBuf())137 mockT = tdutil.NewT("test")138 td.CmpFalse(t,139 tdhttp.NewTestAPI(mockT, mux).140 Head("/any").141 CmpStatus(200).142 CmpHeader(containsKey).143 CmpBody(td.Empty()).144 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {145 assert.Cmp(resp.StatusCode, 200)146 assert.Cmp(resp.Header, containsKey)147 assert.Smuggle(resp.Body, io.ReadAll, td.Empty())148 })).149 Failed())150 td.CmpEmpty(t, mockT.LogBuf())151 mockT = tdutil.NewT("test")152 td.CmpFalse(t,153 tdhttp.NewTestAPI(mockT, mux).154 Get("/any").155 CmpStatus(200).156 CmpHeader(containsKey).157 CmpBody("GET!").158 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {159 assert.Cmp(resp.StatusCode, 200)160 assert.Cmp(resp.Header, containsKey)161 assert.Smuggle(resp.Body, io.ReadAll, td.String("GET!"))162 })).163 Failed())164 td.CmpEmpty(t, mockT.LogBuf())165 mockT = tdutil.NewT("test")166 td.CmpFalse(t,167 tdhttp.NewTestAPI(mockT, mux).168 Get("/any").169 CmpStatus(200).170 CmpHeader(containsKey).171 CmpBody(td.Contains("GET")).172 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {173 assert.Cmp(resp.StatusCode, 200)174 assert.Cmp(resp.Header, containsKey)175 assert.Smuggle(resp.Body, io.ReadAll, td.Contains("GET"))176 })).177 Failed())178 td.CmpEmpty(t, mockT.LogBuf())179 mockT = tdutil.NewT("test")180 td.CmpFalse(t,181 tdhttp.NewTestAPI(mockT, mux).182 Options("/any", strings.NewReader("OPTIONS body")).183 CmpStatus(200).184 CmpHeader(containsKey).185 CmpBody("OPTIONS!\n---\nOPTIONS body").186 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {187 assert.Cmp(resp.StatusCode, 200)188 assert.Cmp(resp.Header, containsKey)189 assert.Smuggle(resp.Body, io.ReadAll, td.String("OPTIONS!\n---\nOPTIONS body"))190 })).191 Failed())192 td.CmpEmpty(t, mockT.LogBuf())193 mockT = tdutil.NewT("test")194 td.CmpFalse(t,195 tdhttp.NewTestAPI(mockT, mux).196 Post("/any", strings.NewReader("POST body")).197 CmpStatus(200).198 CmpHeader(containsKey).199 CmpBody("POST!\n---\nPOST body").200 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {201 assert.Cmp(resp.StatusCode, 200)202 assert.Cmp(resp.Header, containsKey)203 assert.Smuggle(resp.Body, io.ReadAll, td.String("POST!\n---\nPOST body"))204 })).205 Failed())206 td.CmpEmpty(t, mockT.LogBuf())207 mockT = tdutil.NewT("test")208 td.CmpFalse(t,209 tdhttp.NewTestAPI(mockT, mux).210 PostForm("/any", url.Values{"p1": []string{"v1"}, "p2": []string{"v2"}}).211 CmpStatus(200).212 CmpHeader(containsKey).213 CmpBody("POST!\n---\np1=v1&p2=v2").214 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {215 assert.Cmp(resp.StatusCode, 200)216 assert.Cmp(resp.Header, containsKey)217 assert.Smuggle(resp.Body, io.ReadAll, td.String("POST!\n---\np1=v1&p2=v2"))218 })).219 Failed())220 td.CmpEmpty(t, mockT.LogBuf())221 mockT = tdutil.NewT("test")222 td.CmpFalse(t,223 tdhttp.NewTestAPI(mockT, mux).224 PostForm("/any", tdhttp.Q{"p1": "v1", "p2": "v2"}).225 CmpStatus(200).226 CmpHeader(containsKey).227 CmpBody("POST!\n---\np1=v1&p2=v2").228 CmpResponse(td.Code(func(assert *td.T, resp *http.Response) {229 assert.Cmp(resp.StatusCode, 200)230 assert.Cmp(resp.Header, containsKey)231 assert.Smuggle(resp.Body, io.ReadAll, td.String("POST!\n---\np1=v1&p2=v2"))232 })).233 Failed())234 td.CmpEmpty(t, mockT.LogBuf())235 mockT = tdutil.NewT("test")236 td.CmpFalse(t,237 tdhttp.NewTestAPI(mockT, mux).238 PostMultipartFormData("/any", &tdhttp.MultipartBody{239 Boundary: "BoUnDaRy",240 Parts: []*tdhttp.MultipartPart{241 tdhttp.NewMultipartPartString("pipo", "bingo"),242 },243 }).244 CmpStatus(200).245 CmpHeader(containsKey).246 CmpBody(strings.ReplaceAll(247 `POST!248---249--BoUnDaRy%CR250Content-Disposition: form-data; name="pipo"%CR251Content-Type: text/plain; charset=utf-8%CR252%CR253bingo%CR254--BoUnDaRy--%CR255`,256 "%CR", "\r")).257 Failed())258 td.CmpEmpty(t, mockT.LogBuf())259 mockT = tdutil.NewT("test")260 td.CmpFalse(t,261 tdhttp.NewTestAPI(mockT, mux).262 Put("/any", strings.NewReader("PUT body")).263 CmpStatus(200).264 CmpHeader(containsKey).265 CmpBody("PUT!\n---\nPUT body").266 Failed())267 td.CmpEmpty(t, mockT.LogBuf())268 mockT = tdutil.NewT("test")269 td.CmpFalse(t,270 tdhttp.NewTestAPI(mockT, mux).271 Patch("/any", strings.NewReader("PATCH body")).272 CmpStatus(200).273 CmpHeader(containsKey).274 CmpBody("PATCH!\n---\nPATCH body").275 Failed())276 td.CmpEmpty(t, mockT.LogBuf())277 mockT = tdutil.NewT("test")278 td.CmpFalse(t,279 tdhttp.NewTestAPI(mockT, mux).280 Delete("/any", strings.NewReader("DELETE body")).281 CmpStatus(200).282 CmpHeader(containsKey).283 CmpBody("DELETE!\n---\nDELETE body").284 Failed())285 td.CmpEmpty(t, mockT.LogBuf())286 })287 t.Run("No JSON error", func(t *testing.T) {288 requestBody := map[string]any{"hey": 123}289 expectedBody := func(m string) td.TestDeep {290 return td.JSON(`{"method": $1, "body": {"hey": 123}}`, m)291 }292 mockT := tdutil.NewT("test")293 td.CmpFalse(t,294 tdhttp.NewTestAPI(mockT, mux).295 NewJSONRequest("GET", "/mirror/json", json.RawMessage(`null`)).296 CmpStatus(200).297 CmpHeader(containsKey).298 CmpJSONBody(nil).299 Failed())300 td.CmpEmpty(t, mockT.LogBuf())301 mockT = tdutil.NewT("test")302 td.CmpFalse(t,303 tdhttp.NewTestAPI(mockT, mux).304 NewJSONRequest("ZIP", "/any/json", requestBody).305 CmpStatus(200).306 CmpHeader(containsKey).307 CmpJSONBody(expectedBody("ZIP")).308 Failed())309 td.CmpEmpty(t, mockT.LogBuf())310 mockT = tdutil.NewT("test")311 td.CmpFalse(t,312 tdhttp.NewTestAPI(mockT, mux).313 NewJSONRequest("ZIP", "/any/json", requestBody).314 CmpStatus(200).315 CmpHeader(containsKey).316 CmpJSONBody(td.JSONPointer("/body/hey", 123)).317 Failed())318 td.CmpEmpty(t, mockT.LogBuf())319 mockT = tdutil.NewT("test")320 td.CmpFalse(t,321 tdhttp.NewTestAPI(mockT, mux).322 PostJSON("/any/json", requestBody).323 CmpStatus(200).324 CmpHeader(containsKey).325 CmpJSONBody(expectedBody("POST")).326 Failed())327 td.CmpEmpty(t, mockT.LogBuf())328 mockT = tdutil.NewT("test")329 td.CmpFalse(t,330 tdhttp.NewTestAPI(mockT, mux).331 PutJSON("/any/json", requestBody).332 CmpStatus(200).333 CmpHeader(containsKey).334 CmpJSONBody(expectedBody("PUT")).335 Failed())336 td.CmpEmpty(t, mockT.LogBuf())337 mockT = tdutil.NewT("test")338 td.CmpFalse(t,339 tdhttp.NewTestAPI(mockT, mux).340 PatchJSON("/any/json", requestBody).341 CmpStatus(200).342 CmpHeader(containsKey).343 CmpJSONBody(expectedBody("PATCH")).344 Failed())345 td.CmpEmpty(t, mockT.LogBuf())346 mockT = tdutil.NewT("test")347 td.CmpFalse(t,348 tdhttp.NewTestAPI(mockT, mux).349 DeleteJSON("/any/json", requestBody).350 CmpStatus(200).351 CmpHeader(containsKey).352 CmpJSONBody(expectedBody("DELETE")).353 Failed())354 td.CmpEmpty(t, mockT.LogBuf())355 // With anchors356 type ReqBody struct {357 Hey int `json:"hey"`358 }359 type Resp struct {360 Method string `json:"method"`361 ReqBody ReqBody `json:"body"`362 }363 mockT = tdutil.NewT("test")364 tt := td.NewT(mockT)365 td.CmpFalse(t,366 tdhttp.NewTestAPI(mockT, mux).367 DeleteJSON("/any/json", requestBody).368 CmpStatus(200).369 CmpHeader(containsKey).370 CmpJSONBody(Resp{371 Method: tt.A(td.Re(`^(?i)delete\z`), "").(string),372 ReqBody: ReqBody{373 Hey: tt.A(td.Between(120, 130)).(int),374 },375 }).376 Failed())377 td.CmpEmpty(t, mockT.LogBuf())378 // JSON and root operator (here SuperMapOf)379 mockT = tdutil.NewT("test")380 td.CmpFalse(t,381 tdhttp.NewTestAPI(mockT, mux).382 PostJSON("/any/json", true).383 CmpStatus(200).384 CmpJSONBody(td.JSON(`SuperMapOf({"body":Ignore()})`)).385 Failed())386 td.CmpEmpty(t, mockT.LogBuf())387 // td.Bag+td.JSON388 mockT = tdutil.NewT("test")389 td.CmpFalse(t,390 tdhttp.NewTestAPI(mockT, mux).391 PostJSON("/mirror/json",392 json.RawMessage(`[{"name":"Bob"},{"name":"Alice"}]`)).393 CmpStatus(200).394 CmpJSONBody(td.Bag(395 td.JSON(`{"name":"Alice"}`),396 td.JSON(`{"name":"Bob"}`),397 )).398 Failed())399 td.CmpEmpty(t, mockT.LogBuf())400 // td.Bag+literal401 type People struct {402 Name string `json:"name"`403 }404 mockT = tdutil.NewT("test")405 td.CmpFalse(t,406 tdhttp.NewTestAPI(mockT, mux).407 PostJSON("/mirror/json",408 json.RawMessage(`[{"name":"Bob"},{"name":"Alice"}]`)).409 CmpStatus(200).410 CmpJSONBody(td.Bag(People{"Alice"}, People{"Bob"})).411 Failed())412 td.CmpEmpty(t, mockT.LogBuf())413 })414 t.Run("No XML error", func(t *testing.T) {415 type XBody struct {416 Hey int `xml:"hey"`417 }418 type XResp struct {419 Method string `xml:"method"`420 ReqBody *XBody `xml:"XBody"`421 }422 requestBody := XBody{Hey: 123}423 expectedBody := func(m string) XResp {424 return XResp{425 Method: m,426 ReqBody: &requestBody,427 }428 }429 mockT := tdutil.NewT("test")430 td.CmpFalse(t,431 tdhttp.NewTestAPI(mockT, mux).432 NewXMLRequest("ZIP", "/any/xml", requestBody).433 CmpStatus(200).434 CmpHeader(containsKey).435 CmpXMLBody(expectedBody("ZIP")).436 Failed())437 td.CmpEmpty(t, mockT.LogBuf())438 mockT = tdutil.NewT("test")439 td.CmpFalse(t,440 tdhttp.NewTestAPI(mockT, mux).441 PostXML("/any/xml", requestBody).442 CmpStatus(200).443 CmpHeader(containsKey).444 CmpXMLBody(expectedBody("POST")).445 Failed())446 td.CmpEmpty(t, mockT.LogBuf())447 mockT = tdutil.NewT("test")448 td.CmpFalse(t,449 tdhttp.NewTestAPI(mockT, mux).450 PutXML("/any/xml", requestBody).451 CmpStatus(200).452 CmpHeader(containsKey).453 CmpXMLBody(expectedBody("PUT")).454 Failed())455 td.CmpEmpty(t, mockT.LogBuf())456 mockT = tdutil.NewT("test")457 td.CmpFalse(t,458 tdhttp.NewTestAPI(mockT, mux).459 PatchXML("/any/xml", requestBody).460 CmpStatus(200).461 CmpHeader(containsKey).462 CmpXMLBody(expectedBody("PATCH")).463 Failed())464 td.CmpEmpty(t, mockT.LogBuf())465 mockT = tdutil.NewT("test")466 td.CmpFalse(t,467 tdhttp.NewTestAPI(mockT, mux).468 DeleteXML("/any/xml", requestBody).469 CmpStatus(200).470 CmpHeader(containsKey).471 CmpXMLBody(expectedBody("DELETE")).472 Failed())473 td.CmpEmpty(t, mockT.LogBuf())474 // With anchors475 mockT = tdutil.NewT("test")476 tt := td.NewT(mockT)477 td.CmpFalse(tt,478 tdhttp.NewTestAPI(mockT, mux).479 DeleteXML("/any/xml", requestBody).480 CmpStatus(200).481 CmpHeader(containsKey).482 CmpXMLBody(XResp{483 Method: tt.A(td.Re(`^(?i)delete\z`), "").(string),484 ReqBody: &XBody{485 Hey: tt.A(td.Between(120, 130)).(int),486 },487 }).488 Failed())489 td.CmpEmpty(t, mockT.LogBuf())490 })491 t.Run("Cookies", func(t *testing.T) {492 mockT := tdutil.NewT("test")493 td.CmpFalse(t,494 tdhttp.NewTestAPI(mockT, mux).495 Get("/any/cookies").496 CmpCookies([]*http.Cookie{497 {498 Name: "first",499 Value: "cookie1",500 MaxAge: 123456,501 Expires: time.Date(2021, time.August, 12, 11, 22, 33, 0, time.UTC),502 },503 {504 Name: "second",505 Value: "cookie2",506 MaxAge: 654321,507 },508 }).509 Failed())510 td.CmpEmpty(t, mockT.LogBuf())511 mockT = tdutil.NewT("test")512 td.CmpTrue(t,513 tdhttp.NewTestAPI(mockT, mux).514 Get("/any/cookies").515 CmpCookies([]*http.Cookie{516 {517 Name: "first",518 Value: "cookie1",519 MaxAge: 123456,520 Expires: time.Date(2021, time.August, 12, 11, 22, 33, 0, time.UTC),521 },522 }).523 Failed())524 td.CmpContains(t, mockT.LogBuf(),525 "Failed test 'cookies should match'")526 td.CmpContains(t, mockT.LogBuf(),527 "Response.Cookie: comparing slices, from index #1")528 // 2 cookies are here whatever their order is using Bag529 mockT = tdutil.NewT("test")530 td.CmpFalse(t,531 tdhttp.NewTestAPI(mockT, mux).532 Get("/any/cookies").533 CmpCookies(td.Bag(534 td.Smuggle("Name", "second"),535 td.Smuggle("Name", "first"),536 )).537 Failed())538 td.CmpEmpty(t, mockT.LogBuf())539 // Testing only Name & Value whatever their order is using Bag540 mockT = tdutil.NewT("test")541 td.CmpFalse(t,542 tdhttp.NewTestAPI(mockT, mux).543 Get("/any/cookies").544 CmpCookies(td.Bag(545 td.Struct(&http.Cookie{Name: "first", Value: "cookie1"}, nil),546 td.Struct(&http.Cookie{Name: "second", Value: "cookie2"}, nil),547 )).548 Failed())549 td.CmpEmpty(t, mockT.LogBuf())550 // Testing the presence of only one using SuperBagOf551 mockT = tdutil.NewT("test")552 td.CmpFalse(t,553 tdhttp.NewTestAPI(mockT, mux).554 Get("/any/cookies").555 CmpCookies(td.SuperBagOf(556 td.Struct(&http.Cookie{Name: "first", Value: "cookie1"}, nil),557 )).558 Failed())559 td.CmpEmpty(t, mockT.LogBuf())560 // Testing only the number of cookies561 mockT = tdutil.NewT("test")562 td.CmpFalse(t,563 tdhttp.NewTestAPI(mockT, mux).564 Get("/any/cookies").565 CmpCookies(td.Len(2)).566 Failed())567 td.CmpEmpty(t, mockT.LogBuf())568 // Error followed by a success: Failed() should return true anyway569 mockT = tdutil.NewT("test")570 td.CmpTrue(t,571 tdhttp.NewTestAPI(mockT, mux).572 Get("/any").573 CmpCookies(td.Len(100)). // fails574 CmpCookies(td.Len(2)). // succeeds575 Failed())576 td.CmpContains(t, mockT.LogBuf(),577 "Failed test 'cookies should match'")578 // AutoDumpResponse579 mockT = tdutil.NewT("test")580 td.CmpTrue(t,581 tdhttp.NewTestAPI(mockT, mux).582 AutoDumpResponse().583 Get("/any/cookies").584 Name("my test").585 CmpCookies(td.Len(100)).586 Failed())587 td.CmpContains(t, mockT.LogBuf(),588 "Failed test 'my test: cookies should match'")589 td.CmpContains(t, mockT.LogBuf(), "Response.Cookie: bad length")590 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))591 // Request not sent592 mockT = tdutil.NewT("test")593 ta := tdhttp.NewTestAPI(mockT, mux).594 Name("my test").595 CmpCookies(td.Len(2))596 td.CmpTrue(t, ta.Failed())597 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")598 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")599 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")600 td.CmpNot(t, mockT.LogBuf(), td.Contains("No response received yet\n"))601 })602 t.Run("Trailer", func(t *testing.T) {603 mockT := tdutil.NewT("test")604 td.CmpFalse(t,605 tdhttp.NewTestAPI(mockT, mux).606 Get("/any").607 CmpStatus(200).608 CmpTrailer(nil). // No trailer at all609 Failed())610 mockT = tdutil.NewT("test")611 td.CmpFalse(t,612 tdhttp.NewTestAPI(mockT, mux).613 Get("/any/trailer").614 CmpStatus(200).615 CmpTrailer(containsKey).616 Failed())617 mockT = tdutil.NewT("test")618 td.CmpFalse(t,619 tdhttp.NewTestAPI(mockT, mux).620 Get("/any/trailer").621 CmpStatus(200).622 CmpTrailer(http.Header{623 "X-Testdeep-Method": {"GET"},624 "X-Testdeep-Foo": {"bar"},625 }).626 Failed())627 // AutoDumpResponse628 mockT = tdutil.NewT("test")629 td.CmpTrue(t,630 tdhttp.NewTestAPI(mockT, mux).631 AutoDumpResponse().632 Get("/any/trailer").633 Name("my test").634 CmpTrailer(http.Header{}).635 Failed())636 td.CmpContains(t, mockT.LogBuf(),637 "Failed test 'my test: trailer should match'")638 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))639 // OrDumpResponse640 mockT = tdutil.NewT("test")641 td.CmpTrue(t,642 tdhttp.NewTestAPI(mockT, mux).643 Get("/any/trailer").644 Name("my test").645 CmpTrailer(http.Header{}).646 OrDumpResponse().647 OrDumpResponse(). // only one log648 Failed())649 td.CmpContains(t, mockT.LogBuf(),650 "Failed test 'my test: trailer should match'")651 logPos := strings.Index(mockT.LogBuf(), "Received response:\n")652 if td.Cmp(t, logPos, td.Gte(0)) {653 // Only one occurrence654 td.Cmp(t,655 strings.Index(mockT.LogBuf()[logPos+1:], "Received response:\n"),656 -1)657 }658 mockT = tdutil.NewT("test")659 ta := tdhttp.NewTestAPI(mockT, mux).660 Name("my test").661 CmpTrailer(http.Header{})662 td.CmpTrue(t, ta.Failed())663 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")664 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")665 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")666 td.CmpNot(t, mockT.LogBuf(), td.Contains("No response received yet\n"))667 end := len(mockT.LogBuf())668 ta.OrDumpResponse()669 td.CmpContains(t, mockT.LogBuf()[end:], "No response received yet\n")670 })671 t.Run("Status error", func(t *testing.T) {672 mockT := tdutil.NewT("test")673 td.CmpTrue(t,674 tdhttp.NewTestAPI(mockT, mux).675 Get("/any").676 CmpStatus(400).677 Failed())678 td.CmpContains(t, mockT.LogBuf(),679 "Failed test 'status code should match'")680 // Error followed by a success: Failed() should return true anyway681 mockT = tdutil.NewT("test")682 td.CmpTrue(t,683 tdhttp.NewTestAPI(mockT, mux).684 Get("/any").685 CmpStatus(400). // fails686 CmpStatus(200). // succeeds687 Failed())688 td.CmpContains(t, mockT.LogBuf(),689 "Failed test 'status code should match'")690 mockT = tdutil.NewT("test")691 td.CmpTrue(t,692 tdhttp.NewTestAPI(mockT, mux).693 Get("/any").694 Name("my test").695 CmpStatus(400).696 Failed())697 td.CmpContains(t, mockT.LogBuf(),698 "Failed test 'my test: status code should match'")699 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))700 // AutoDumpResponse701 mockT = tdutil.NewT("test")702 td.CmpTrue(t,703 tdhttp.NewTestAPI(mockT, mux).704 AutoDumpResponse().705 Get("/any").706 Name("my test").707 CmpStatus(400).708 Failed())709 td.CmpContains(t, mockT.LogBuf(),710 "Failed test 'my test: status code should match'")711 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))712 // OrDumpResponse713 mockT = tdutil.NewT("test")714 td.CmpTrue(t,715 tdhttp.NewTestAPI(mockT, mux).716 Get("/any").717 Name("my test").718 CmpStatus(400).719 OrDumpResponse().720 OrDumpResponse(). // only one log721 Failed())722 td.CmpContains(t, mockT.LogBuf(),723 "Failed test 'my test: status code should match'")724 logPos := strings.Index(mockT.LogBuf(), "Received response:\n")725 if td.Cmp(t, logPos, td.Gte(0)) {726 // Only one occurrence727 td.Cmp(t,728 strings.Index(mockT.LogBuf()[logPos+1:], "Received response:\n"),729 -1)730 }731 mockT = tdutil.NewT("test")732 ta := tdhttp.NewTestAPI(mockT, mux).733 Name("my test").734 CmpStatus(400)735 td.CmpTrue(t, ta.Failed())736 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")737 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")738 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")739 td.CmpNot(t, mockT.LogBuf(), td.Contains("No response received yet\n"))740 end := len(mockT.LogBuf())741 ta.OrDumpResponse()742 td.CmpContains(t, mockT.LogBuf()[end:], "No response received yet\n")743 })744 t.Run("Header error", func(t *testing.T) {745 mockT := tdutil.NewT("test")746 td.CmpTrue(t,747 tdhttp.NewTestAPI(mockT, mux).748 Get("/any").749 CmpHeader(td.Not(containsKey)).750 Failed())751 td.CmpContains(t, mockT.LogBuf(),752 "Failed test 'header should match'")753 // Error followed by a success: Failed() should return true anyway754 mockT = tdutil.NewT("test")755 td.CmpTrue(t,756 tdhttp.NewTestAPI(mockT, mux).757 Get("/any").758 CmpHeader(td.Not(containsKey)). // fails759 CmpHeader(td.Ignore()). // succeeds760 Failed())761 td.CmpContains(t, mockT.LogBuf(),762 "Failed test 'header should match'")763 mockT = tdutil.NewT("test")764 td.CmpTrue(t,765 tdhttp.NewTestAPI(mockT, mux).766 Get("/any").767 Name("my test").768 CmpHeader(td.Not(containsKey)).769 Failed())770 td.CmpContains(t, mockT.LogBuf(),771 "Failed test 'my test: header should match'")772 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))773 // AutoDumpResponse774 mockT = tdutil.NewT("test")775 td.CmpTrue(t,776 tdhttp.NewTestAPI(mockT, mux).777 AutoDumpResponse().778 Get("/any").779 Name("my test").780 CmpHeader(td.Not(containsKey)).781 Failed())782 td.CmpContains(t, mockT.LogBuf(),783 "Failed test 'my test: header should match'")784 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))785 mockT = tdutil.NewT("test")786 td.CmpTrue(t,787 tdhttp.NewTestAPI(mockT, mux).788 Name("my test").789 CmpHeader(td.Not(containsKey)).790 Failed())791 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")792 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")793 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")794 })795 t.Run("Body error", func(t *testing.T) {796 mockT := tdutil.NewT("test")797 td.CmpTrue(t,798 tdhttp.NewTestAPI(mockT, mux).799 Get("/any").800 CmpBody("xxx").801 Failed())802 td.CmpContains(t, mockT.LogBuf(), "Failed test 'body contents is OK'")803 td.CmpContains(t, mockT.LogBuf(), "Response.Body: values differ\n")804 td.CmpContains(t, mockT.LogBuf(), `expected: "xxx"`)805 td.CmpContains(t, mockT.LogBuf(), `got: "GET!"`)806 // Error followed by a success: Failed() should return true anyway807 mockT = tdutil.NewT("test")808 td.CmpTrue(t,809 tdhttp.NewTestAPI(mockT, mux).810 Get("/any").811 CmpBody("xxx"). // fails812 CmpBody(td.Ignore()). // succeeds813 Failed())814 // Without AutoDumpResponse815 mockT = tdutil.NewT("test")816 td.CmpTrue(t,817 tdhttp.NewTestAPI(mockT, mux).818 Get("/any").819 Name("my test").820 CmpBody("xxx").821 Failed())822 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: body contents is OK'")823 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))824 // AutoDumpResponse825 mockT = tdutil.NewT("test")826 td.CmpTrue(t,827 tdhttp.NewTestAPI(mockT, mux).828 AutoDumpResponse().829 Get("/any").830 Name("my test").831 CmpBody("xxx").832 Failed())833 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: body contents is OK'")834 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))835 mockT = tdutil.NewT("test")836 td.CmpTrue(t,837 tdhttp.NewTestAPI(mockT, mux).838 Name("my test").839 CmpBody("xxx").840 Failed())841 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")842 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")843 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")844 // NoBody845 mockT = tdutil.NewT("test")846 td.CmpTrue(t,847 tdhttp.NewTestAPI(mockT, mux).848 Name("my test").849 NoBody().850 Failed())851 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")852 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")853 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")854 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))855 // Error followed by a success: Failed() should return true anyway856 mockT = tdutil.NewT("test")857 td.CmpTrue(t,858 tdhttp.NewTestAPI(mockT, mux).859 Name("my test").860 Head("/any").861 CmpBody("fail"). // fails862 NoBody(). // succeeds863 Failed())864 // No JSON body865 mockT = tdutil.NewT("test")866 td.CmpTrue(t,867 tdhttp.NewTestAPI(mockT, mux).868 Head("/any").869 CmpStatus(200).870 CmpHeader(containsKey).871 CmpJSONBody(json.RawMessage(`{}`)).872 Failed())873 td.CmpContains(t, mockT.LogBuf(), "Failed test 'body should not be empty'")874 td.CmpContains(t, mockT.LogBuf(), "Response body is empty!")875 td.CmpContains(t, mockT.LogBuf(), "Body cannot be empty when using CmpJSONBody")876 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))877 // Error followed by a success: Failed() should return true anyway878 mockT = tdutil.NewT("test")879 td.CmpTrue(t,880 tdhttp.NewTestAPI(mockT, mux).881 Get("/any/json").882 CmpStatus(200).883 CmpHeader(containsKey).884 CmpJSONBody(json.RawMessage(`{}`)). // fails885 CmpJSONBody(td.Ignore()). // succeeds886 Failed())887 // No JSON body + AutoDumpResponse888 mockT = tdutil.NewT("test")889 td.CmpTrue(t,890 tdhttp.NewTestAPI(mockT, mux).891 AutoDumpResponse().892 Head("/any").893 CmpStatus(200).894 CmpHeader(containsKey).895 CmpJSONBody(json.RawMessage(`{}`)).896 Failed())897 td.CmpContains(t, mockT.LogBuf(), "Failed test 'body should not be empty'")898 td.CmpContains(t, mockT.LogBuf(), "Response body is empty!")899 td.CmpContains(t, mockT.LogBuf(), "Body cannot be empty when using CmpJSONBody")900 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))901 // No XML body902 mockT = tdutil.NewT("test")903 td.CmpTrue(t,904 tdhttp.NewTestAPI(mockT, mux).905 Head("/any").906 CmpStatus(200).907 CmpHeader(containsKey).908 CmpXMLBody(struct{ Test string }{}).909 Failed())910 td.CmpContains(t, mockT.LogBuf(), "Failed test 'body should not be empty'")911 td.CmpContains(t, mockT.LogBuf(), "Response body is empty!")912 td.CmpContains(t, mockT.LogBuf(), "Body cannot be empty when using CmpXMLBody")913 })914 t.Run("Response error", func(t *testing.T) {915 mockT := tdutil.NewT("test")916 td.CmpTrue(t,917 tdhttp.NewTestAPI(mockT, mux).918 Get("/any").919 CmpResponse(nil).920 Failed())921 td.CmpContains(t, mockT.LogBuf(), "Failed test 'full response should match'")922 td.CmpContains(t, mockT.LogBuf(), "Response: values differ")923 td.CmpContains(t, mockT.LogBuf(), "got: (*http.Response)(")924 td.CmpContains(t, mockT.LogBuf(), "expected: nil")925 // Error followed by a success: Failed() should return true anyway926 mockT = tdutil.NewT("test")927 td.CmpTrue(t,928 tdhttp.NewTestAPI(mockT, mux).929 Get("/any").930 CmpResponse(nil). // fails931 CmpResponse(td.Ignore()). // succeeds932 Failed())933 // Without AutoDumpResponse934 mockT = tdutil.NewT("test")935 td.CmpTrue(t,936 tdhttp.NewTestAPI(mockT, mux).937 Get("/any").938 Name("my test").939 CmpResponse(nil).940 Failed())941 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: full response should match'")942 td.CmpNot(t, mockT.LogBuf(), td.Contains("Received response:\n"))943 // AutoDumpResponse944 mockT = tdutil.NewT("test")945 td.CmpTrue(t,946 tdhttp.NewTestAPI(mockT, mux).947 AutoDumpResponse().948 Get("/any").949 Name("my test").950 CmpResponse(nil).951 Failed())952 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: full response should match'")953 td.Cmp(t, mockT.LogBuf(), td.Contains("Received response:\n"))954 mockT = tdutil.NewT("test")955 td.CmpTrue(t,956 tdhttp.NewTestAPI(mockT, mux).957 Name("my test").958 CmpResponse(nil).959 Failed())960 td.CmpContains(t, mockT.LogBuf(), "Failed test 'my test: request is sent'\n")961 td.CmpContains(t, mockT.LogBuf(), "Request not sent!\n")962 td.CmpContains(t, mockT.LogBuf(), "A request must be sent before testing status, header, body or full response\n")963 })964 t.Run("Request error", func(t *testing.T) {965 var ta *tdhttp.TestAPI966 checkFatal := func(fn func()) {967 mockT := tdutil.NewT("test")968 td.CmpTrue(t, mockT.CatchFailNow(func() {969 ta = tdhttp.NewTestAPI(mockT, mux)970 fn()971 }))972 td.Cmp(t,973 mockT.LogBuf(),974 td.Contains("headersQueryParams... can only contains string, http.Header, http.Cookie, url.Values and tdhttp.Q, not bool"),975 )976 }977 empty := strings.NewReader("")978 checkFatal(func() { ta.Get("/path", true) })979 checkFatal(func() { ta.Head("/path", true) })980 checkFatal(func() { ta.Options("/path", empty, true) })981 checkFatal(func() { ta.Post("/path", empty, true) })982 checkFatal(func() { ta.PostForm("/path", nil, true) })983 checkFatal(func() { ta.PostMultipartFormData("/path", &tdhttp.MultipartBody{}, true) })984 checkFatal(func() { ta.Put("/path", empty, true) })985 checkFatal(func() { ta.Patch("/path", empty, true) })986 checkFatal(func() { ta.Delete("/path", empty, true) })987 checkFatal(func() { ta.NewJSONRequest("ZIP", "/path", nil, true) })988 checkFatal(func() { ta.PostJSON("/path", nil, true) })989 checkFatal(func() { ta.PutJSON("/path", nil, true) })990 checkFatal(func() { ta.PatchJSON("/path", nil, true) })991 checkFatal(func() { ta.DeleteJSON("/path", nil, true) })992 checkFatal(func() { ta.NewXMLRequest("ZIP", "/path", nil, true) })993 checkFatal(func() { ta.PostXML("/path", nil, true) })994 checkFatal(func() { ta.PutXML("/path", nil, true) })995 checkFatal(func() { ta.PatchXML("/path", nil, true) })996 checkFatal(func() { ta.DeleteXML("/path", nil, true) })997 })998}999func TestWith(t *testing.T) {1000 mux := server()1001 ta := tdhttp.NewTestAPI(tdutil.NewT("test1"), mux)1002 td.CmpFalse(t, ta.Head("/any").CmpStatus(200).Failed())1003 nt := tdutil.NewT("test2")1004 nta := ta.With(nt)1005 td.Cmp(t, nta.T(), td.Not(td.Shallow(ta.T())))1006 td.CmpTrue(t, nta.CmpStatus(200).Failed()) // as no request sent yet1007 td.CmpContains(t, nt.LogBuf(),1008 "A request must be sent before testing status, header, body or full response")1009 td.CmpFalse(t, ta.CmpStatus(200).Failed()) // request already sent, so OK1010 nt = tdutil.NewT("test3")1011 nta = ta.With(nt)1012 td.CmpTrue(t, nta.Head("/any").1013 CmpStatus(400).1014 OrDumpResponse().1015 Failed())1016 td.CmpContains(t, nt.LogBuf(), "Response.Status: values differ")1017 td.CmpContains(t, nt.LogBuf(), "X-Testdeep-Method: HEAD") // Header dumped1018}1019func TestOr(t *testing.T) {1020 mux := server()1021 t.Run("Success", func(t *testing.T) {1022 var orCalled bool1023 for i, fn := range []any{1024 func(body string) { orCalled = true },1025 func(t *td.T, body string) { orCalled = true },1026 func(body []byte) { orCalled = true },1027 func(t *td.T, body []byte) { orCalled = true },1028 func(t *td.T, r *httptest.ResponseRecorder) { orCalled = true },1029 } {1030 orCalled = false1031 // As CmpStatus succeeds, Or function is not called1032 td.CmpFalse(t,1033 tdhttp.NewTestAPI(tdutil.NewT("test"), mux).1034 Head("/any").1035 CmpStatus(200).1036 Or(fn).1037 Failed(),1038 "Not failed #%d", i)1039 td.CmpFalse(t, orCalled, "called #%d", i)1040 }1041 })1042 t.Run("No request sent", func(t *testing.T) {1043 var ok, orCalled bool1044 for i, fn := range []any{1045 func(body string) { orCalled = true; ok = body == "" },1046 func(t *td.T, body string) { orCalled = true; ok = t != nil && body == "" },1047 func(body []byte) { orCalled = true; ok = body == nil },1048 func(t *td.T, body []byte) { orCalled = true; ok = t != nil && body == nil },1049 func(t *td.T, r *httptest.ResponseRecorder) { orCalled = true; ok = t != nil && r == nil },1050 } {1051 orCalled, ok = false, false1052 // Check status without sending a request → fail1053 td.CmpTrue(t,1054 tdhttp.NewTestAPI(tdutil.NewT("test"), mux).1055 CmpStatus(123).1056 Or(fn).1057 Failed(),1058 "Failed #%d", i)1059 td.CmpTrue(t, orCalled, "called #%d", i)1060 td.CmpTrue(t, ok, "OK #%d", i)1061 }1062 })1063 t.Run("Empty bodies", func(t *testing.T) {1064 var ok, orCalled bool1065 for i, fn := range []any{1066 func(body string) { orCalled = true; ok = body == "" },1067 func(t *td.T, body string) { orCalled = true; ok = t != nil && body == "" },1068 func(body []byte) { orCalled = true; ok = body == nil },1069 func(t *td.T, body []byte) { orCalled = true; ok = t != nil && body == nil },1070 func(t *td.T, r *httptest.ResponseRecorder) {1071 orCalled = true1072 ok = t != nil && r != nil && r.Body.Len() == 01073 },1074 } {1075 orCalled, ok = false, false1076 // HEAD /any = no body + CmpStatus fails1077 td.CmpTrue(t,1078 tdhttp.NewTestAPI(tdutil.NewT("test"), mux).1079 Head("/any").1080 CmpStatus(123).1081 Or(fn).1082 Failed(),1083 "Failed #%d", i)1084 td.CmpTrue(t, orCalled, "called #%d", i)1085 td.CmpTrue(t, ok, "OK #%d", i)1086 }1087 })1088 t.Run("Body", func(t *testing.T) {1089 var ok, orCalled bool1090 for i, fn := range []any{1091 func(body string) { orCalled = true; ok = body == "GET!" },1092 func(t *td.T, body string) { orCalled = true; ok = t != nil && body == "GET!" },1093 func(body []byte) { orCalled = true; ok = string(body) == "GET!" },1094 func(t *td.T, body []byte) { orCalled = true; ok = t != nil && string(body) == "GET!" },1095 func(t *td.T, r *httptest.ResponseRecorder) {1096 orCalled = true1097 ok = t != nil && r != nil && r.Body.String() == "GET!"1098 },1099 } {1100 orCalled, ok = false, false1101 // GET /any = "GET!" body + CmpStatus fails1102 td.CmpTrue(t,1103 tdhttp.NewTestAPI(tdutil.NewT("test"), mux).1104 Get("/any").1105 CmpStatus(123).1106 Or(fn).1107 Failed(),1108 "Failed #%d", i)1109 td.CmpTrue(t, orCalled, "called #%d", i)1110 td.CmpTrue(t, ok, "OK #%d", i)1111 }1112 })1113 tt := tdutil.NewT("test")1114 ta := tdhttp.NewTestAPI(tt, mux)1115 if td.CmpTrue(t, tt.CatchFailNow(func() { ta.Or(123) })) {1116 td.CmpContains(t, tt.LogBuf(),1117 "usage: Or(func([*td.T,]string) | func([*td.T,][]byte) | func(*td.T,*httptest.ResponseRecorder)), but received int as 1st parameter")1118 }1119}1120func TestRun(t *testing.T) {1121 mux := server()1122 ta := tdhttp.NewTestAPI(tdutil.NewT("test"), mux)1123 ok := ta.Run("Test", func(ta *tdhttp.TestAPI) {1124 td.CmpFalse(t, ta.Get("/any").CmpStatus(200).Failed())1125 })1126 td.CmpTrue(t, ok)1127 ok = ta.Run("Test", func(ta *tdhttp.TestAPI) {1128 td.CmpTrue(t, ta.Get("/any").CmpStatus(123).Failed())1129 })1130 td.CmpFalse(t, ok)1131}...

Full Screen

Full Screen

t_struct_test.go

Source:t_struct_test.go Github

copy

Full Screen

...25 }),26 )27 }28 tt.Run("without config", func(tt *testing.T) {29 t := td.NewT(tt)30 cmp(tt, t.Config, td.DefaultContextConfig)31 tDup := td.NewT(t)32 cmp(tt, tDup.Config, td.DefaultContextConfig)33 })34 tt.Run("explicit default config", func(tt *testing.T) {35 t := td.NewT(tt, td.ContextConfig{})36 cmp(tt, t.Config, td.DefaultContextConfig)37 tDup := td.NewT(t)38 cmp(tt, tDup.Config, td.DefaultContextConfig)39 })40 tt.Run("specific config", func(tt *testing.T) {41 conf := td.ContextConfig{42 RootName: "TEST",43 MaxErrors: 33,44 }45 t := td.NewT(tt, conf)46 cmp(tt, t.Config, conf)47 tDup := td.NewT(t)48 cmp(tt, tDup.Config, conf)49 newConf := conf50 newConf.MaxErrors = 3451 tDup = td.NewT(t, newConf)52 cmp(tt, tDup.Config, newConf)53 t2 := t.RootName("T2")54 cmp(tt, t.Config, conf)55 cmp(tt, t2.Config, td.ContextConfig{56 RootName: "T2",57 MaxErrors: 33,58 })59 t3 := t.RootName("")60 cmp(tt, t3.Config, td.ContextConfig{61 RootName: "DATA",62 MaxErrors: 33,63 })64 })65 //66 // Bad usages67 ttb := test.NewTestingTB("usage params")68 ttb.CatchFatal(func() {69 td.NewT(ttb, td.ContextConfig{}, td.ContextConfig{})70 })71 test.IsTrue(tt, ttb.IsFatal)72 test.IsTrue(tt, strings.Contains(ttb.Messages[0], "usage: NewT("))73 test.CheckPanic(tt, func() { td.NewT(nil) }, "usage: NewT")74}75func TestTCmp(tt *testing.T) {76 ttt := test.NewTestingTB(tt.Name())77 t := td.NewT(ttt)78 test.IsTrue(tt, t.Cmp(1, 1))79 test.IsFalse(tt, ttt.Failed())80 ttt = test.NewTestingTB(tt.Name())81 t = td.NewT(ttt)82 test.IsFalse(tt, t.Cmp(1, 2))83 test.IsTrue(tt, ttt.Failed())84}85func TestTCmpDeeply(tt *testing.T) {86 ttt := test.NewTestingTB(tt.Name())87 t := td.NewT(ttt)88 test.IsTrue(tt, t.CmpDeeply(1, 1))89 test.IsFalse(tt, ttt.Failed())90 ttt = test.NewTestingTB(tt.Name())91 t = td.NewT(ttt)92 test.IsFalse(tt, t.CmpDeeply(1, 2))93 test.IsTrue(tt, ttt.Failed())94}95func TestParallel(t *testing.T) {96 t.Run("without Parallel", func(tt *testing.T) {97 ttt := test.NewTestingTB(tt.Name())98 t := td.NewT(ttt)99 t.Parallel()100 // has no effect101 })102 t.Run("with Parallel", func(tt *testing.T) {103 ttt := test.NewParallelTestingTB(tt.Name())104 t := td.NewT(ttt)105 t.Parallel()106 test.IsTrue(tt, ttt.IsParallel)107 })108 t.Run("Run with Parallel", func(tt *testing.T) {109 // This test verifies that subtests with t.Parallel() are run110 // in parallel. We use a WaitGroup to make both subtests block111 // until they're both ready. This test will block forever if112 // the tests are not run together.113 var ready sync.WaitGroup114 ready.Add(2)115 t := td.NewT(tt)116 t.Run("level 1", func(t *td.T) {117 t.Parallel()118 ready.Done() // I'm ready.119 ready.Wait() // Are you?120 })121 t.Run("level 2", func(t *td.T) {122 t.Parallel()123 ready.Done() // I'm ready.124 ready.Wait() // Are you?125 })126 })127}128func TestRun(t *testing.T) {129 t.Run("test.TB with Run", func(tt *testing.T) {130 t := td.NewT(tt)131 runPassed := false132 nestedFailureIsFatal := false133 ok := t.Run("Test level1",134 func(t *td.T) {135 ok := t.FailureIsFatal().Run("Test level2",136 func(t *td.T) {137 runPassed = t.True(true) // test succeeds!138 // Check we inherit config from caller139 nestedFailureIsFatal = t.Config.FailureIsFatal140 })141 t.True(ok)142 })143 test.IsTrue(tt, ok)144 test.IsTrue(tt, runPassed)145 test.IsTrue(tt, nestedFailureIsFatal)146 })147 t.Run("test.TB without Run", func(tt *testing.T) {148 t := td.NewT(test.NewTestingTB("gg"))149 runPassed := false150 ok := t.Run("Test level1",151 func(t *td.T) {152 ok := t.Run("Test level2",153 func(t *td.T) {154 runPassed = t.True(true) // test succeeds!155 })156 t.True(ok)157 })158 t.True(ok)159 t.True(runPassed)160 })161}162func TestRunAssertRequire(t *testing.T) {163 t.Run("test.TB with Run", func(tt *testing.T) {164 t := td.NewT(tt)165 runPassed := false166 assertIsFatal := true167 requireIsFatal := false168 ok := t.RunAssertRequire("Test level1",169 func(assert, require *td.T) {170 assertIsFatal = assert.Config.FailureIsFatal171 requireIsFatal = require.Config.FailureIsFatal172 ok := assert.RunAssertRequire("Test level2",173 func(assert, require *td.T) {174 runPassed = assert.True(true) // test succeeds!175 runPassed = runPassed && require.True(true) // test succeeds!176 assertIsFatal = assertIsFatal || assert.Config.FailureIsFatal177 requireIsFatal = requireIsFatal && require.Config.FailureIsFatal178 })179 assert.True(ok)180 require.True(ok)181 ok = require.RunAssertRequire("Test level2",182 func(assert, require *td.T) {183 runPassed = runPassed && assert.True(true) // test succeeds!184 runPassed = runPassed && require.True(true) // test succeeds!185 assertIsFatal = assertIsFatal || assert.Config.FailureIsFatal186 requireIsFatal = requireIsFatal && require.Config.FailureIsFatal187 })188 assert.True(ok)189 require.True(ok)190 })191 test.IsTrue(tt, ok)192 test.IsTrue(tt, runPassed)193 test.IsFalse(tt, assertIsFatal)194 test.IsTrue(tt, requireIsFatal)195 })196 t.Run("test.TB without Run", func(tt *testing.T) {197 t := td.NewT(test.NewTestingTB("gg"))198 runPassed := false199 assertIsFatal := true200 requireIsFatal := false201 ok := t.RunAssertRequire("Test level1",202 func(assert, require *td.T) {203 assertIsFatal = assert.Config.FailureIsFatal204 requireIsFatal = require.Config.FailureIsFatal205 ok := assert.RunAssertRequire("Test level2",206 func(assert, require *td.T) {207 runPassed = assert.True(true) // test succeeds!208 runPassed = runPassed && require.True(true) // test succeeds!209 assertIsFatal = assertIsFatal || assert.Config.FailureIsFatal210 requireIsFatal = requireIsFatal && require.Config.FailureIsFatal211 })212 assert.True(ok)213 require.True(ok)214 ok = require.RunAssertRequire("Test level2",215 func(assert, require *td.T) {216 runPassed = runPassed && assert.True(true) // test succeeds!217 runPassed = runPassed && require.True(true) // test succeeds!218 assertIsFatal = assertIsFatal || assert.Config.FailureIsFatal219 requireIsFatal = requireIsFatal && require.Config.FailureIsFatal220 })221 assert.True(ok)222 require.True(ok)223 })224 test.IsTrue(tt, ok)225 test.IsTrue(tt, runPassed)226 test.IsFalse(tt, assertIsFatal)227 test.IsTrue(tt, requireIsFatal)228 })229}230// Deprecated RunT.231func TestRunT(t *testing.T) {232 t.Run("test.TB with Run", func(tt *testing.T) {233 t := td.NewT(tt)234 runPassed := false235 ok := t.RunT("Test level1", //nolint: staticcheck236 func(t *td.T) {237 ok := t.RunT("Test level2", //nolint: staticcheck238 func(t *td.T) {239 runPassed = t.True(true) // test succeeds!240 })241 t.True(ok)242 })243 test.IsTrue(tt, ok)244 test.IsTrue(tt, runPassed)245 })246 t.Run("test.TB without Run", func(tt *testing.T) {247 t := td.NewT(test.NewTestingTB("gg"))248 runPassed := false249 ok := t.RunT("Test level1", //nolint: staticcheck250 func(t *td.T) {251 ok := t.RunT("Test level2", //nolint: staticcheck252 func(t *td.T) {253 runPassed = t.True(true) // test succeeds!254 })255 t.True(ok)256 })257 test.IsTrue(tt, ok)258 test.IsTrue(tt, runPassed)259 })260}261func TestFailureIsFatal(tt *testing.T) {262 // All t.True(false) tests of course fail263 // Using default config264 ttt := test.NewTestingTB(tt.Name())265 t := td.NewT(ttt)266 t.True(false) // failure267 test.IsTrue(tt, ttt.LastMessage() != "")268 test.IsFalse(tt, ttt.IsFatal, "by default it is not fatal")269 // Using specific config270 ttt = test.NewTestingTB(tt.Name())271 t = td.NewT(ttt, td.ContextConfig{FailureIsFatal: true})272 ttt.CatchFatal(func() { t.True(false) }) // failure273 test.IsTrue(tt, ttt.LastMessage() != "")274 test.IsTrue(tt, ttt.IsFatal, "it must be fatal")275 // Using FailureIsFatal()276 ttt = test.NewTestingTB(tt.Name())277 t = td.NewT(ttt).FailureIsFatal()278 ttt.CatchFatal(func() { t.True(false) }) // failure279 test.IsTrue(tt, ttt.LastMessage() != "")280 test.IsTrue(tt, ttt.IsFatal, "it must be fatal")281 // Using FailureIsFatal(true)282 ttt = test.NewTestingTB(tt.Name())283 t = td.NewT(ttt).FailureIsFatal(true)284 ttt.CatchFatal(func() { t.True(false) }) // failure285 test.IsTrue(tt, ttt.LastMessage() != "")286 test.IsTrue(tt, ttt.IsFatal, "it must be fatal")287 // Using T.Assert()288 ttt = test.NewTestingTB(tt.Name())289 t = td.NewT(ttt, td.ContextConfig{FailureIsFatal: true}).Assert()290 t.True(false) // failure291 test.IsTrue(tt, ttt.LastMessage() != "")292 test.IsFalse(tt, ttt.IsFatal, "by default it is not fatal")293 // Using T.Require()294 ttt = test.NewTestingTB(tt.Name())295 t = td.NewT(ttt).Require()296 ttt.CatchFatal(func() { t.True(false) }) // failure297 test.IsTrue(tt, ttt.LastMessage() != "")298 test.IsTrue(tt, ttt.IsFatal, "it must be fatal")299 // Using Require()300 ttt = test.NewTestingTB(tt.Name())301 t = td.Require(ttt)302 ttt.CatchFatal(func() { t.True(false) }) // failure303 test.IsTrue(tt, ttt.LastMessage() != "")304 test.IsTrue(tt, ttt.IsFatal, "it must be fatal")305 // Using Require() with specific config (cannot override FailureIsFatal)306 ttt = test.NewTestingTB(tt.Name())307 t = td.Require(ttt, td.ContextConfig{FailureIsFatal: false})308 ttt.CatchFatal(func() { t.True(false) }) // failure309 test.IsTrue(tt, ttt.LastMessage() != "")310 test.IsTrue(tt, ttt.IsFatal, "it must be fatal")311 // Canceling specific config312 ttt = test.NewTestingTB(tt.Name())313 t = td.NewT(ttt, td.ContextConfig{FailureIsFatal: false}).314 FailureIsFatal(false)315 t.True(false) // failure316 test.IsTrue(tt, ttt.LastMessage() != "")317 test.IsFalse(tt, ttt.IsFatal, "it must be not fatal")318 // Using Assert()319 ttt = test.NewTestingTB(tt.Name())320 t = td.Assert(ttt)321 t.True(false) // failure322 test.IsTrue(tt, ttt.LastMessage() != "")323 test.IsFalse(tt, ttt.IsFatal, "it must be not fatal")324 // Using Assert() with specific config (cannot override FailureIsFatal)325 ttt = test.NewTestingTB(tt.Name())326 t = td.Assert(ttt, td.ContextConfig{FailureIsFatal: true})327 t.True(false) // failure328 test.IsTrue(tt, ttt.LastMessage() != "")329 test.IsFalse(tt, ttt.IsFatal, "it must be not fatal")330 // AssertRequire() / assert331 ttt = test.NewTestingTB(tt.Name())332 t, _ = td.AssertRequire(ttt)333 t.True(false) // failure334 test.IsTrue(tt, ttt.LastMessage() != "")335 test.IsFalse(tt, ttt.IsFatal, "it must be not fatal")336 // Using AssertRequire() / assert with specific config (cannot337 // override FailureIsFatal)338 ttt = test.NewTestingTB(tt.Name())339 t, _ = td.AssertRequire(ttt, td.ContextConfig{FailureIsFatal: true})340 t.True(false) // failure341 test.IsTrue(tt, ttt.LastMessage() != "")342 test.IsFalse(tt, ttt.IsFatal, "it must be not fatal")343 // AssertRequire() / require344 ttt = test.NewTestingTB(tt.Name())345 _, t = td.AssertRequire(ttt)346 ttt.CatchFatal(func() { t.True(false) }) // failure347 test.IsTrue(tt, ttt.LastMessage() != "")348 test.IsTrue(tt, ttt.IsFatal, "it must be fatal")349 // Using AssertRequire() / require with specific config (cannot350 // override FailureIsFatal)351 ttt = test.NewTestingTB(tt.Name())352 _, t = td.AssertRequire(ttt, td.ContextConfig{FailureIsFatal: true})353 ttt.CatchFatal(func() { t.True(false) }) // failure354 test.IsTrue(tt, ttt.LastMessage() != "")355 test.IsTrue(tt, ttt.IsFatal, "it must be fatal")356}357func TestUseEqual(tt *testing.T) {358 ttt := test.NewTestingTB(tt.Name())359 var time1, time2 time.Time360 for {361 time1 = time.Now()362 time2 = time1.Truncate(0)363 if !time1.Equal(time2) {364 tt.Fatal("time.Equal() does not work as expected")365 }366 if time1 != time2 { // to avoid the bad luck case where time1.wall=0367 break368 }369 }370 // Using default config371 t := td.NewT(ttt)372 test.IsFalse(tt, t.Cmp(time1, time2))373 // UseEqual374 t = td.NewT(ttt).UseEqual() // enable globally375 test.IsTrue(tt, t.Cmp(time1, time2))376 t = td.NewT(ttt).UseEqual(true) // enable globally377 test.IsTrue(tt, t.Cmp(time1, time2))378 t = td.NewT(ttt).UseEqual(false) // disable globally379 test.IsFalse(tt, t.Cmp(time1, time2))380 t = td.NewT(ttt).UseEqual(time.Time{}) // enable only for time.Time381 test.IsTrue(tt, t.Cmp(time1, time2))382 t = t.UseEqual().UseEqual(false) // enable then disable globally383 test.IsTrue(tt, t.Cmp(time1, time2)) // Equal() still used384 test.EqualStr(tt,385 ttt.CatchFatal(func() { td.NewT(ttt).UseEqual(42) }),386 "UseEqual expects type int owns an Equal method (@0)")387}388func TestBeLax(tt *testing.T) {389 ttt := test.NewTestingTB(tt.Name())390 // Using default config391 t := td.NewT(ttt)392 test.IsFalse(tt, t.Cmp(int64(123), 123))393 // BeLax394 t = td.NewT(ttt).BeLax()395 test.IsTrue(tt, t.Cmp(int64(123), 123))396 t = td.NewT(ttt).BeLax(true)397 test.IsTrue(tt, t.Cmp(int64(123), 123))398 t = td.NewT(ttt).BeLax(false)399 test.IsFalse(tt, t.Cmp(int64(123), 123))400}401func TestIgnoreUnexported(tt *testing.T) {402 ttt := test.NewTestingTB(tt.Name())403 type SType1 struct {404 Public int405 private string406 }407 a1, b1 := SType1{Public: 42, private: "test"}, SType1{Public: 42}408 type SType2 struct {409 Public int410 private string411 }412 a2, b2 := SType2{Public: 42, private: "test"}, SType2{Public: 42}413 // Using default config414 t := td.NewT(ttt)415 test.IsFalse(tt, t.Cmp(a1, b1))416 // IgnoreUnexported417 t = td.NewT(ttt).IgnoreUnexported() // ignore unexported globally418 test.IsTrue(tt, t.Cmp(a1, b1))419 test.IsTrue(tt, t.Cmp(a2, b2))420 t = td.NewT(ttt).IgnoreUnexported(true) // ignore unexported globally421 test.IsTrue(tt, t.Cmp(a1, b1))422 test.IsTrue(tt, t.Cmp(a2, b2))423 t = td.NewT(ttt).IgnoreUnexported(false) // handle unexported globally424 test.IsFalse(tt, t.Cmp(a1, b1))425 test.IsFalse(tt, t.Cmp(a2, b2))426 t = td.NewT(ttt).IgnoreUnexported(SType1{}) // ignore only for SType1427 test.IsTrue(tt, t.Cmp(a1, b1))428 test.IsFalse(tt, t.Cmp(a2, b2))429 t = t.UseEqual().UseEqual(false) // enable then disable globally430 test.IsTrue(tt, t.Cmp(a1, b1))431 test.IsFalse(tt, t.Cmp(a2, b2))432 t = td.NewT(ttt).IgnoreUnexported(SType1{}, SType2{}) // enable for both433 test.IsTrue(tt, t.Cmp(a1, b1))434 test.IsTrue(tt, t.Cmp(a2, b2))435 test.EqualStr(tt,436 ttt.CatchFatal(func() { td.NewT(ttt).IgnoreUnexported(42) }),437 "IgnoreUnexported expects type int be a struct, not a int (@0)")438}439func TestLogTrace(tt *testing.T) {440 ttt := test.NewTestingTB(tt.Name())441 t := td.NewT(ttt)442//line /t_struct_test.go:100443 t.LogTrace()444 test.EqualStr(tt, ttt.LastMessage(), `Stack trace:445 TestLogTrace() /t_struct_test.go:100`)446 test.IsFalse(tt, ttt.HasFailed)447 test.IsFalse(tt, ttt.IsFatal)448 ttt.ResetMessages()449//line /t_struct_test.go:110450 t.LogTrace("This is the %s:", "stack")451 test.EqualStr(tt, ttt.LastMessage(), `This is the stack:452 TestLogTrace() /t_struct_test.go:110`)453 ttt.ResetMessages()454//line /t_struct_test.go:120455 t.LogTrace("This is the %s:\n", "stack")456 test.EqualStr(tt, ttt.LastMessage(), `This is the stack:457 TestLogTrace() /t_struct_test.go:120`)458 ttt.ResetMessages()459//line /t_struct_test.go:130460 t.LogTrace("This is the ", "stack")461 test.EqualStr(tt, ttt.LastMessage(), `This is the stack462 TestLogTrace() /t_struct_test.go:130`)463 ttt.ResetMessages()464 trace.IgnorePackage()465 defer trace.UnignorePackage()466//line /t_struct_test.go:140467 t.LogTrace("Stack:\n")468 test.EqualStr(tt, ttt.LastMessage(), `Stack:469 Empty stack trace`)470}471func TestErrorTrace(tt *testing.T) {472 ttt := test.NewTestingTB(tt.Name())473 t := td.NewT(ttt)474//line /t_struct_test.go:200475 t.ErrorTrace()476 test.EqualStr(tt, ttt.LastMessage(), `Stack trace:477 TestErrorTrace() /t_struct_test.go:200`)478 test.IsTrue(tt, ttt.HasFailed)479 test.IsFalse(tt, ttt.IsFatal)480 ttt.ResetMessages()481//line /t_struct_test.go:210482 t.ErrorTrace("This is the %s:", "stack")483 test.EqualStr(tt, ttt.LastMessage(), `This is the stack:484 TestErrorTrace() /t_struct_test.go:210`)485 ttt.ResetMessages()486//line /t_struct_test.go:220487 t.ErrorTrace("This is the %s:\n", "stack")488 test.EqualStr(tt, ttt.LastMessage(), `This is the stack:489 TestErrorTrace() /t_struct_test.go:220`)490 ttt.ResetMessages()491//line /t_struct_test.go:230492 t.ErrorTrace("This is the ", "stack")493 test.EqualStr(tt, ttt.LastMessage(), `This is the stack494 TestErrorTrace() /t_struct_test.go:230`)495 ttt.ResetMessages()496 trace.IgnorePackage()497 defer trace.UnignorePackage()498//line /t_struct_test.go:240499 t.ErrorTrace("Stack:\n")500 test.EqualStr(tt, ttt.LastMessage(), `Stack:501 Empty stack trace`)502}503func TestFatalTrace(tt *testing.T) {504 ttt := test.NewTestingTB(tt.Name())505 t := td.NewT(ttt)506 match := func(got, expectedRe string) {507 tt.Helper()508 re := regexp.MustCompile(expectedRe)509 if !re.MatchString(got) {510 test.EqualErrorMessage(tt, got, expectedRe)511 }512 }513//line /t_struct_test.go:300514 match(ttt.CatchFatal(func() { t.FatalTrace() }), `Stack trace:515 TestFatalTrace\.func\d\(\) /t_struct_test\.go:300516 \(\*TestingT\)\.CatchFatal\(\) internal/test/types\.go:\d+517 TestFatalTrace\(\) /t_struct_test\.go:300`)518 test.IsTrue(tt, ttt.HasFailed)519 test.IsTrue(tt, ttt.IsFatal)...

Full Screen

Full Screen

NewT

Using AI Code Generation

copy

Full Screen

1import (2type td struct {3}4func main() {5 t := td.NewT(10, 20)6 fmt.Println(t)7}8{10 20}9import (10func (f MyFloat) Abs() float64 {11 if f < 0 {12 return float64(-f)13 }14 return float64(f)15}16func main() {17 f := MyFloat(-math.Sqrt2)18 fmt.Println(f.Abs())19}20For the statement v.Scale(5), even though v is

Full Screen

Full Screen

NewT

Using AI Code Generation

copy

Full Screen

1func main() {2 t := td.NewT()3 t.Print()4}5type T struct {6}7func NewT() *T {8 return &T{Name: "Hello"}9}10func (t *T) Print() {11 fmt.Println(t.Name)12}13import (14func main() {15 t := td.NewT()16 t.Print()17}18type T struct {19}20func NewT() *T {21 return &T{Name: "Hello"}22}23func (t *T) Print() {24 fmt.Println(t.Name)25}26import (27func main() {28 t := td.NewT()29 t.Print()30}31type T struct {32}33func NewT() *T {34 return &T{Name: "Hello"}35}36func (t *T) Print() {37 fmt.Println(t.Name)38}39import (40func main()

Full Screen

Full Screen

NewT

Using AI Code Generation

copy

Full Screen

1import (2func main() {3 t.NewT(1, 2)4 fmt.Println(t.x)5 fmt.Println(t.y)6}7import (8func main() {9 t.NewT(1, 2)10 fmt.Println(t.x)11 fmt.Println(t.y)12}13import (14func main() {15 t.NewT(1, 2)16 fmt.Println(t.x)17 fmt.Println(t.y)18}19import (20func main() {21 t.NewT(1, 2)22 fmt.Println(t.x)23 fmt.Println(t.y)24}25import (26func main() {27 t.NewT(1, 2)28 fmt.Println(t.x)29 fmt.Println(t.y)30}31import (32func main() {33 t.NewT(1, 2)34 fmt.Println(t.x)35 fmt.Println(t.y)36}37import (38func main() {39 t.NewT(1, 2)40 fmt.Println(t.x)41 fmt.Println(t.y)42}43import (44func main() {45 t.NewT(1, 2)46 fmt.Println(t.x)47 fmt.Println(t.y)48}49import (50func main() {51 t.NewT(1, 2)52 fmt.Println(t.x)53 fmt.Println(t.y)54}

Full Screen

Full Screen

NewT

Using AI Code Generation

copy

Full Screen

1func main() {2 t := td.NewT()3 t.Print()4}5type T struct {6}7func NewT() *T {8 return &T{"hello"}9}10func (t *T) Print() {11 fmt.Println(t.s)12}13The code is a little bit more complex than I would like, but it is a good example of how to use the go tool. The go tool is a simple tool to build and test Go code. It is a single binary that can be distributed as is. It is a command line tool that takes a number of commands, the most important of which are:14The go tool is a very important tool to learn. It is the only tool that is required to build Go code. It is very useful for building and testing Go code. It is very useful for managing Go code. It is very useful for installing Go code. It is very useful for getting Go code. It is very useful for running Go code. It is very useful for cleaning Go code. It is very useful for fixing Go code. It is very useful

Full Screen

Full Screen

NewT

Using AI Code Generation

copy

Full Screen

1import "fmt"2import "github.com/GoLangTutorials/td"3func main() {4 t := td.NewT(5, 6)5 fmt.Println("t.a = ", t.a)6 fmt.Println("t.b = ", t.b)7}

Full Screen

Full Screen

NewT

Using AI Code Generation

copy

Full Screen

1t := td.NewT()2fmt.Printf("t: %v3fmt.Printf("t.Method(): %v4", t.Method())5t := td.NewT()6fmt.Printf("t: %v7fmt.Printf("t.Method(): %v8", t.Method())9t := td.NewT()10fmt.Printf("t: %v11fmt.Printf("t.Method(): %v12", t.Method())13t := td.NewT()14fmt.Printf("t: %v15fmt.Printf("t.Method(): %v16", t.Method())17t := td.NewT()18fmt.Printf("t: %v19fmt.Printf("t.Method(): %v20", t.Method())21t := td.NewT()22fmt.Printf("t: %v23fmt.Printf("t.Method(): %v24", t.Method())25t := td.NewT()26fmt.Printf("t: %v27fmt.Printf("t.Method(): %v28", t.Method())

Full Screen

Full Screen

NewT

Using AI Code Generation

copy

Full Screen

1import "fmt"2func main() {3 td := new(td)4 td.NewT(10)5 fmt.Println(td.i)6}7import "fmt"8type xyz struct {9}10func main() {11 xyz := &xyz{10}12 fmt.Println(xyz.i)13}14import "fmt"15type xyz struct {16}17func main() {18 xyz := &xyz{10}19 fmt.Println(xyz.i)20}21import "fmt"22type xyz struct {23}24func main() {25 xyz := &xyz{10}26 fmt.Println(xyz.i)27}28import "fmt"29type xyz struct {30}31func main() {32 xyz := &xyz{10}33 fmt.Println(xyz.i)34}35import "fmt"36type xyz struct {37}38func main() {39 xyz := &xyz{10}40 fmt.Println(xyz.i)41}

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Go-testdeep automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Most used method in

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful