Code

func Code(fn any) TestDeep

Code operator allows to check data using a custom function. So fn is a function that must take one parameter whose type must be the same as the type of the compared value.

fn can return a single bool kind value, telling that yes or no the custom test is successful:

td.Cmp(t, gotTime,
  td.Code(func(date time.Time) bool {
    return date.Year() == 2018
  }))

or two values (bool, string) kinds. The bool value has the same meaning as above, and the string value is used to describe the test when it fails:

td.Cmp(t, gotTime,
  td.Code(func(date time.Time) (bool, string) {
    if date.Year() == 2018 {
      return true, ""
    }
    return false, "year must be 2018"
  }))

or a single error value. If the returned error is nil, the test succeeded, else the error contains the reason of failure:

td.Cmp(t, gotJsonRawMesg,
  td.Code(func(b json.RawMessage) error {
    var c map[string]int
    err := json.Unmarshal(b, &c)
    if err != nil {
      return err
    }
    if c["test"] != 42 {
      return fmt.Errorf(`key "test" does not match 42`)
    }
    return nil
  }))

This operator allows to handle any specific comparison not handled by standard operators.

It is not recommended to call Cmp (or any other Cmp* functions or *T methods) inside the body of fn, because of confusion produced by output in case of failure. When the data needs to be transformed before being compared again, Smuggle operator should be used instead.

But in some cases it can be better to handle yourself the comparison than to chain TestDeep operators. In this case, fn can be a function receiving one or two *T as first parameters and returning no values.

When fn expects one *T parameter, it is directly derived from the testing.TB instance passed originally to Cmp (or its derivatives) using NewT:

td.Cmp(t, httpRequest, td.Code(func(t *td.T, r *http.Request) {
  token, err := DecodeToken(r.Header.Get("X-Token-1"))
  if t.CmpNoError(err) {
    t.True(token.OK())
  }
}))

When fn expects two *T parameters, they are directly derived from the testing.TB instance passed originally to Cmp (or its derivatives) using AssertRequire:

td.Cmp(t, httpRequest, td.Code(func(assert, require *td.T, r *http.Request) {
  token, err := DecodeToken(r.Header.Get("X-Token-1"))
  require.CmpNoError(err)
  assert.True(token.OK())
}))

Note that these forms do not work when there is no initial testing.TB instance, like when using EqDeeplyError or EqDeeply functions, or when the Code operator is called behind the following operators, as they just check if a match occurs without raising an error: Any, Bag, Contains, ContainsKey, None, Not, NotAny, Set, SubBagOf, SubSetOf, SuperBagOf and SuperSetOf.

RootName is inherited but not the current path, but it can be recovered if needed:

got := map[string]int{"foo": 123}
td.NewT(t).
  RootName("PIPO").
  Cmp(got, td.Map(map[string]int{}, td.MapEntries{
    "foo": td.Code(func(t *td.T, n int) {
      t.Cmp(n, 124)                                   // inherit only RootName
      t.RootName(t.Config.OriginalPath()).Cmp(n, 125) // recover current path
      t.RootName("").Cmp(n, 126)                      // undo RootName inheritance
    }),
  }))

produces the following errors:

--- FAIL: TestCodeCustom (0.00s)
    td_code_test.go:339: Failed test
        PIPO: values differ             ← inherit only RootName
               got: 123
          expected: 124
    td_code_test.go:338: Failed test
        PIPO["foo"]: values differ      ← recover current path
               got: 123
          expected: 125
    td_code_test.go:342: Failed test
        DATA: values differ             ← undo RootName inheritance
               got: 123
          expected: 126

TypeBehind method returns the reflect.Type of last parameter of fn.

See also Code godoc.

Examples

Base example
Custom example

CmpCode shortcut

func CmpCode(t TestingT, got, fn any, args ...any) bool

CmpCode is a shortcut for:

td.Cmp(t, got, td.Code(fn), args...)

See above for details.

Returns true if the test is OK, false if it fails.

If t is a *T then its Config field is inherited.

args… are optional and allow to name the test. This name is used in case of failure to qualify the test. If len(args) > 1 and the first item of args is a string and contains a ‘%’ rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint. Do not forget it is the name of the test, not the reason of a potential failure.

See also CmpCode godoc.

Examples

Base example
Custom example

T.Code shortcut

func (t *T) Code(got, fn any, args ...any) bool

Code is a shortcut for:

t.Cmp(got, td.Code(fn), args...)

See above for details.

Returns true if the test is OK, false if it fails.

args… are optional and allow to name the test. This name is used in case of failure to qualify the test. If len(args) > 1 and the first item of args is a string and contains a ‘%’ rune then fmt.Fprintf is used to compose the name, else args are passed to fmt.Fprint. Do not forget it is the name of the test, not the reason of a potential failure.

See also T.Code godoc.

Examples

Base example
Custom example