Extremely flexible golang deep comparison, extends the go testing package, tests HTTP APIs and provides tests suite

Overview

go-testdeep

Build Status Coverage Status Go Report Card GoDoc Version Mentioned in Awesome Go

go-testdeep

Extremely flexible golang deep comparison, extends the go testing package.

Latest news

Synopsis

Make golang tests easy, from simplest usage:

import (
  "testing"

  "github.com/maxatome/go-testdeep/td"
)

func TestMyFunc(t *testing.T) {
  td.Cmp(t, MyFunc(), &Info{Name: "Alice", Age: 42})
}

To a bit more complex one, allowing flexible comparisons using TestDeep operators:

import (
  "testing"

  "github.com/maxatome/go-testdeep/td"
)

func TestMyFunc(t *testing.T) {
  td.Cmp(t, MyFunc(), td.Struct(
    &Info{Name: "Alice"},
    td.StructFields{
      "Age": td.Between(40, 45),
    },
  ))
}

Or anchoring operators directly in literals, as in:

import (
  "testing"

  "github.com/maxatome/go-testdeep/td"
)

func TestMyFunc(tt *testing.T) {
  t := td.NewT(tt)

  t.Cmp(MyFunc(), &Info{
    Name: "Alice",
    Age:  t.Anchor(td.Between(40, 45)).(int),
  })
}

To most complex one, allowing to easily test HTTP API routes, using flexible operators:

import (
  "testing"
  "time"

  "github.com/maxatome/go-testdeep/helpers/tdhttp"
  "github.com/maxatome/go-testdeep/td"
)

type Person struct {
  ID        uint64    `json:"id"`
  Name      string    `json:"name"`
  Age       int       `json:"age"`
  CreatedAt time.Time `json:"created_at"`
}

func TestMyApi(t *testing.T) {
  var id uint64
  var createdAt time.Time

  testAPI := tdhttp.NewTestAPI(t, myAPI) // ← ①

  testAPI.PostJSON("/person", Person{Name: "Bob", Age: 42}). // ← ②
    Name("Create a new Person").
    CmpStatus(http.StatusCreated). // ← ③
    CmpJSONBody(td.JSON(`
// Note that comments are allowed
{
  "id":         $id,             // set by the API/DB
  "name":       "Alice",
  "age":        Between(40, 45), // ← ④
  "created_at": "$createdAt",    // set by the API/DB
}`,
      td.Tag("id", td.Catch(&id, td.NotZero())),        // ← ⑤
      td.Tag("created_at", td.All(                      // ← ⑥
        td.HasSuffix("Z"),                              // ← ⑦
        td.Smuggle(func(s string) (time.Time, error) {  // ← ⑧
          return time.Parse(time.RFC3339Nano, s)
        }, td.Catch(&createdAt, td.Between(testAPI.SentAt(), time.Now()))), // ← ⑨
      )),
    ))
  if !testAPI.Failed() {
    t.Logf("The new Person ID is %d and was created at %s", id, createdAt)
  }
}
  1. the API handler ready to be tested;
  2. the POST request with automatic JSON marshalling;
  3. the expected response HTTP status should be http.StatusCreated and the line just below, the body should match the JSON operator;
  4. some operators can be embedded, like Between here;
  5. for the $id placeholder, Catch its value: put it in id variable and check it is NotZero;
  6. for the $createdAt placeholder, use the All operator. It combines several operators like a AND;
  7. check that $createdAt date ends with "Z" using HasSuffix. As we expect a RFC3339 date, we require it in UTC time zone;
  8. convert $createdAt date into a time.Time using a custom function thanks to the Smuggle operator;
  9. then Catch the resulting value: put it in createdAt variable and check it is greater or equal than testAPI.SentAt() (the time just before the request is handled) and lesser or equal than time.Now().

See tdhttp helper or the FAQ for details about HTTP API testing.

Example of produced error in case of mismatch:

error output

Description

go-testdeep is historically a go rewrite and adaptation of wonderful Test::Deep perl.

In golang, comparing data structure is usually done using reflect.DeepEqual or using a package that uses this function behind the scene.

This function works very well, but it is not flexible. Both compared structures must match exactly and when a difference is returned, it is up to the caller to display it. Not easy when comparing big data structures.

The purpose of go-testdeep, via the td package and its helpers, is to do its best to introduce this missing flexibility using "operators", when the expected value (or one of its component) cannot be matched exactly, mixed with some useful comparison functions.

See go-testdeep.zetta.rocks for details.

Installation

$ go get -u github.com/maxatome/go-testdeep

Helpers

The goal of helpers is to make use of go-testdeep even more powerful by providing common features using TestDeep operators behind the scene.

tdhttp or HTTP API testing helper

The package github.com/maxatome/go-testdeep/helpers/tdhttp provides some functions to easily test HTTP handlers.

See tdhttp documentation for details or FAQ for an example of use.

tdsuite or testing suite helper

The package github.com/maxatome/go-testdeep/helpers/tdsuite adds tests suite feature to go-testdeep in a non-intrusive way, but easily and powerfully.

A tests suite is a set of tests run sequentially that share some data.

Some hooks can be set to be automatically called before the suite is run, before, after and/or between each test, and at the end of the suite.

See tdsuite documentation for details.

tdutil aka the helper of helpers

The package github.com/maxatome/go-testdeep/helpers/tdutil allows to write unit tests for go-testdeep helpers and so provides some helpful functions.

See tdutil for details.

See also

  • testify: a toolkit with common assertions and mocks that plays nicely with the standard library
  • go-cmp: package for comparing Go values in tests

License

go-testdeep is released under the BSD-style license found in the LICENSE file in the root directory of this source tree.

Internal function deepValueEqual is based on deepValueEqual from reflect golang package licensed under the BSD-style license found in the LICENSE file in the golang repository.

Uses two files (bypass.go & bypasssafe.go) from Go-spew which is licensed under the copyfree ISC License.

Public Domain Gopher provided by Egon Elbre. The Go gopher was designed by Renee French.

FAQ

See FAQ.

Comments
  • Ignore unexported struct fields?

    Ignore unexported struct fields?

    I want to compare all fields in two large structs, except the unexported fields. Is there any way to achieve that without manually specifying each field in a SStruct? I might be missing an operator/helper function, but the best solution that comes to my mind is to compare the JSON representation of the two structs.

    Example for clarification:

    type X struct {
      Field1      int
      Field2      int
      Field3      int
      Field4      int
      Field5      int
      fieldIgnore int // <--- want to ignore this when doing a t.Cmp(x1, x2)
    }
    
    opened by siadat 13
  • Comparison of reflect.Value types

    Comparison of reflect.Value types

    Here to annoy you again :P

    I'm aiming to support the encoding of reflect.Type and reflect.Value in my encoding library. go-testdeep has been amazing for tests, but test cases where I compare a reflect.Value values, go-testdeep compares them like a typical struct, and doesn't compare the underlying value inside reflect.Value.

    This means a reflect.Value of a value is only equal if the underlying value is at the same pointer address, and the reflect.Value was created in the same way due to how reflect uses the flag field in reflect.Value.

    In any case, I don't think the semantics of how reflect.Value works is important. For my use case, I'm looking to compare the value inside reflect.Value, and I don't care so much about the reflect.Value itself, e.g if both are addressable or if only one is, although an argument could be made for this. I believe something like

    if got.Type() == reflect.TypeOf(reflect.Value{}) {
        return deepValueEqual(ctx, got.Interface().(reflect.Value), expected.Interface().(reflect.Value))
    }
    

    in deepValueEqual could work, but I'm unsure how this might work with the rest of the codebase. I also know that the ptr field of reflect.Value could introduce an infinite recursion, an extreme case being a reflect.Value that is the value of itself, but less contrived examples do exist.

    I'd be happy to experiment implementing this and submit a PR. Is this something you'd want to support?

    opened by stewi1014 8
  • Recursive SubMap/SuperMap?

    Recursive SubMap/SuperMap?

    Is there a way to compare submaps/supermaps recursively (make sure that partial compare is propagated to nested maps)? Based on what I see, the default behavior is that only the parent map is compared partially, while all nested maps are expected to have exact match.

    question 
    opened by artem-nefedov 4
  • remove Run method from TF interface

    remove Run method from TF interface

    The TestingFT interface includes the Run method, which uses the *testing.T parameter directly, which means that go-testdeep cannot be used with *testing.B or alongside other testing helper packages such as quicktest.

    If you embed testing.TB inside T instead of defining your own testingFT interface, this problem goes away, and additionally you can take advantage of new features added to testing.TB (Cleanup for example) automatically and without breaking your API by adding methods to an interface type.

    opened by rogpeppe 4
  • feat(tdhttp): add CmpCookies

    feat(tdhttp): add CmpCookies

    [email protected]:~/git/go-testdeep$ go test ./... -cover
    ok      github.com/maxatome/go-testdeep 0.038s  coverage: [no statements]
    ok      github.com/maxatome/go-testdeep/helpers/nocolor 0.047s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/helpers/tdhttp  0.075s  coverage: 99.4% of statements
    ok      github.com/maxatome/go-testdeep/helpers/tdhttp/internal 0.017s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/helpers/tdsuite 0.019s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/helpers/tdutil  0.004s  coverage: 99.4% of statements
    ok      github.com/maxatome/go-testdeep/internal/anchors        0.022s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/color  0.011s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/ctxerr 0.007s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/dark   0.003s  coverage: 95.6% of statements
    ok      github.com/maxatome/go-testdeep/internal/flat   0.011s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/hooks  0.009s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/json   0.006s  coverage: 91.6% of statements
    ?       github.com/maxatome/go-testdeep/internal/location       [no test files]
    ?       github.com/maxatome/go-testdeep/internal/test   [no test files]
    ok      github.com/maxatome/go-testdeep/internal/trace  0.005s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/types  0.008s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/util   0.016s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/internal/visited        0.007s  coverage: 100.0% of statements
    ok      github.com/maxatome/go-testdeep/td      0.209s  coverage: 99.8% of statements
    
    opened by Julien2313 3
  • Difficult to call t.Parallel with td.T

    Difficult to call t.Parallel with td.T

    testdeep encourages wrapping the *testing.T into a *td.T. This unfortunately makes it difficult to call t.Parallel() on the *testing.T once hidden behind the *td.T.

    func TestFoo(tt *testing.T) {
        t := td.NewT(tt)
        
        t.Run("foo", func(t *td.T) {
            // t.Parallel() <<< errors because Parallel() does not exist
            //                  on the testing.TB interface.
            
            t.Cmp(...)
        })
        
        t.Run("bar", func(t *td.T) {
            // t.Parallel()
            
            t.Cmp(...)
        })
    }
    

    It's possible to call t.Parallel() on the *testing.T with some upcasting on the wrapped testing.TB.

    func Parallel(t *td.T) {
    	tp, ok := t.TB.(interface{ Parallel() })
    	if ok {
    		tp.Parallel()
    	}
    }
    

    If you're open to addressing this within testdeep, there are two straightforward options:

    • Add a top-level func Parallel(*td.T) that does the same as above. Usage would then be,

      t.Run("foo", func(t *td.T) {
          td.Parallel(t)
      
          t.Cmp(...)
      })
      
    • Add a Parallel() method on td.T. Usage:

      t.Run("foo", func(t *td.T) {
          t.Parallel()
      
          t.Cmp(...)
      })
      

    The latter is closest to what people already do with *testing.T so it might be preferable.


    Separately, either choice opens room for a setting in testdeep to always call t.Parallel() for subtests invoked with a specific *td.T.Run. For example,

    func TestFoo(tt *testing.T) {
        t := td.NewT(tt).AlwaysParallel(true)
        
        t.Run("foo", func(t *td.T) {
            // already parallel
            t.Cmp(...)
        })
        
        t.Run("bar", func(t *td.T) {
            // already parallel
            t.Cmp(...)
        })
    }
    

    But that can be a separate discussion.

    opened by abhinav 3
  • deepValueEqual infinite recursion with recursive map types

    deepValueEqual infinite recursion with recursive map types

    I've found an infinite recursion case with go-testdeep. It's a bit contrived I know; I was actually trying to break things. I'm currently developing an encoding library and trying to break it with test cases galore. Interestingly enough encoding/gob, reflect.DeepEqual (fixed in go1.15), and every 3rd party library I've found suffers from this same issue.

    If given a map containing a struct that contains the same map, deepValueEqual recuses infinitely.

    This test case reproduces the issue

    func TestEqualRecursMap(t *testing.T) {
    	gen := func() interface{} {
    		type S struct {
    			Map map[int]S
    		}
    
    		m := make(map[int]S)
    		m[1] = S{
    			Map: m,
    		}
    
    		return m
    	}
    
    	checkOK(t, gen(), gen())
    }
    

    Thanks so much for your work. Let me know if I can help.

    opened by stewi1014 3
  • feat(Code): Code can now officially delegate its comparison

    feat(Code): Code can now officially delegate its comparison

    Using two new kinds of function:

    • func(t *td.T, arg)
    • func(assert, require *td.T, arg)

    this way the usage of *td.T methods is secure. Note that these functions do not return anything.

    At the same time, using a *td.T instance as Cmp* first parameter allows to inherit its configuration.

    td.Cmp(td.Require(t), got, 42)
    

    is the same as:

    td.Require(t).Cmp(got, 42)
    
    opened by maxatome 2
  • fix(tdsuite): detect wrongly defined hooks

    fix(tdsuite): detect wrongly defined hooks

    Given the 5 hooks:

    • Setup
    • PreTest
    • PostTest
    • BetweenTests
    • Destroy raise an error when a method is defined on a tdsuite with one of these names but without matching the proper interface.
    opened by deathiop 2
  • anchors not working with table driven tests / multiple t.Cmp calls

    anchors not working with table driven tests / multiple t.Cmp calls

    I'm building some Stripe tests with large, deeply nested structs, where using anchors is very helpful. They work great when I have a single test, but if I'm calling t.Cmp multiple times or have table driven tests, anchors are being compared against the wrong values. Since the anchors have to be set outside the inner test run loop, I'm not sure how td knows when to iterate between them. Am I doing something incorrectly?

    Table driven test

    func Test_payInvoiceWithStripe(stdT *testing.T) {
    	tdt := td.NewT(stdT)
    
    	tests := []struct {
    		name                  string
    		stripeCustomerID      string
    		stripePaymentMethodID string
    		wantPaymentIntent     *stripe.PaymentIntent
    		wantErr               error
    	}{
    		// lots of tdt.A
    	}
    
    	stripeClient := client.New(apiKey, nil)
    	invoice := &billingpb.Invoice{
    		InvoiceId:            111,
    		AccountId:            22222,
    	}
    
    	for i, tt := range tests {
    		tdt.Run(tt.name, func(t *td.T) {
    			gotPaymentIntent, err := chargeCustomer(context.Background(), stripeClient, tt.stripeCustomerID, tt.stripePaymentMethodID, invoice, int64(i))
    			if tt.wantErr == nil {
    				t.CmpNoError(err)
    			} else {
    				t.Cmp(e.Cause(err).(*stripe.Error), e.Cause(tt.wantErr).(*stripe.Error))
    			}
    			t.Cmp(gotPaymentIntent, tt.wantPaymentIntent)
    		})
    	}
    

    Output

            DATA.ChargeID: values differ
            	     got: "ch_3KH0DO4HQ2O7mN7V1o3cxNfi"
            	expected: "<[email protected]#12>"
    

    Thanks for a great library!

    opened by derekperkins 2
  • feat(fatalizer): operators do not panic anymore

    feat(fatalizer): operators do not panic anymore

    Get rid of fatalizer, if an operator can not be built, it raises an error during the next Match() attempt.

    This way, we don't need to panic anymore, and so the user is not disappointed by a sometimes hard-to-read stack trace, erroneously thinking the fault comes from go-testdeep.

    opened by maxatome 2
  • Add support for quotation marks in JSON operators

    Add support for quotation marks in JSON operators

    Problem: We use different operators in JSONs which are then used for comparison. If we add regular operators to json string, e.g. Len, HasPrefix, etc, the JSON becomes invalid and formatters, validators cannot parse the string.

    Proposal: Add support for quotation marks for operators in JSON strings, similarly to currently it is being used for shortcut operators "$^NotEmpty". Ideally it could look similar "$^Len(10)"

    enhancement 
    opened by r6q 3
  • Add comparison to github.com/go-test/deep

    Add comparison to github.com/go-test/deep

    It would be helpful to have a comparison table or something in the readme to help people understand the difference between this package and https://github.com/go-test/deep. That has more stars and shows up better in search, while this library seems much more active.

    documentation 
    opened by derekperkins 3
  • Expose some internal types, so custom operators can be built

    Expose some internal types, so custom operators can be built

    The request in a nutshell: can enough internal details be exposed to allow building custom operators externally? Ideally in a stable way.

    I very much realize this is not a simple request, but someone has to make it :) Maybe it can serve as a placeholder for planning / discussion. Some context / broader reasoning is below.


    TestDeep looks super interesting! From a quick glance it looks like there are a lot of good, flexible, well-thought-out features, especially around good error messages (that's so rare, thank you!).

    While there are quite a few built-in operators, there are always some edge cases that benefit from custom ones. The JSON operators serve as a nice example of this: it's just a string, but there's a lot of structure that can imply much-better error reporting and a simpler API, so it has a custom operator to improve things.
    Unfortunately, though td/types.go exposes the TestDeep interface, the base type is not exposed, and location.GetLocationer deals with the (afaict) internal-only Location type, so custom operators cannot be built outside this library. There may be other causes as well, this one was just one I saw while reading.

    This is... probably a very reasonable choice for API stability, but somewhat crippling for less-common needs. I assume you don't want to collect every ill-advised and poorly-implemented operator that every user/company/etc dreams up, so being able to build things from the outside would be great. It could also enable "enriching" libraries that enhance TestDeep.

    Is there a way this can be done?

    opened by Groxx 1
Releases(v1.12.0)
  • v1.12.0(Aug 7, 2022)

    New features

    • Struct & SStruct can override model fields in expectedFields, as in:
        td.Cmp(t, got, td.Struct(
          Person{
            Name:     "John Doe",
            Age:      23,
            Children: 4,
          },
          td.StructFields{
            "> Age":     td.Between(40, 45),
            ">Children": 0, // spaces after ">" are optional
          }),
        )
      
    • Struct & SStruct expectedFields is now optional or multiple. If multiple, all maps are merged from left to right;
    • try to detect wrongly defined hooks in tdsuite @deathiop Given the 5 hooks:
    • try to detect possible tdsuite.Run() misuse, warn the user when it is called with a non-pointer suite, and some key methods are only available via a pointer suite;
    • add tdhttp.Options function & tdhttp.TestAPI.Options method;
    • Code can now officially delegate its comparison, using two new kinds of function:
      • func(t *td.T, arg)
      • func(assert, require *td.T, arg) this way the usage of *td.T methods is secure. Note that these functions do not return anything;
    • using a *td.T instance as Cmp* first parameter now allows to inherit its configuration.
      td.Cmp(td.Require(t), got, 42)
      

      is the same as:

      td.Require(t).Cmp(got, 42)
      

    Fixes

    Miscellaneous

    • enhance & refactor doc comments with new go 1.19 features;
    • documentation now uses any instead of interface{};
    • fix typos.

    As usual: enjoy! :)

    Source code(tar.gz)
    Source code(zip)
  • v1.11.0(Jan 5, 2022)

    New features

    • JSON, SubJSONOf and SuperJSONOf operators:
      • Now:
        td.JSON(`{"foo": $1}`, td.Between(12, 34))
        td.JSON(`{"foo": Between($1, $2)}`, 12, 34)
        

        act the same way. Since v1.10.1 rework, the second was not working as expected.
        At the same time:

        td.JSON(`{"foo": Between(12, 34, $1)}`, td.BoundsOutIn)
        

        now works as expected. It was rejected before,

      • int_lit & float_lit numbers, as defined in go specification, are now accepted in JSON, allowing, for example, to embed hexadecimal numbers in expected JSON;
    • Between operator accepts time.Duration as TO when FROM is a time.Time;
    • Between, Gt, Gte, Lt and Lte operators:
      • now handle values implementing Compare or Less methods:
        Compare and/or Less methods signatures follow:
        func (a T) Less(b T) bool   // returns true if a < b
        func (a T) Compare(b T) int // returns -1 if a < b, 1 if a > b, 0 if a == b
        

        for example, the new go1.18 net/netip.Addr implements both,

      • failure reports display numbers as elsewhere,
      • some docs have been fixed;
    • Smuggle can now cast values, allowing such things:
      // A string containing JSON
      got := `{ "foo": 123 }`
      td.Cmp(t, got, td.Smuggle(json.RawMessage{}, td.JSON(`{"foo":123}`))
      // or
      td.Cmp(t, got, td.Smuggle((json.RawMessage)(nil), td.JSON(`{"foo":123}`))
      
    • in report failures, the stack trace was displayed if it contained at least 2 levels. Now it is also displayed if it contains one level BUT the source file path contains a directory. It helps to localize quickly the errors in large repositories;
    • td.T gains 3 new methods to log with a stack trace: LogTrace, ErrorTrace and FatalTrace;
    • handle go1.17 []T*[n]T convertibility edge case;
    • in failure reports (float64) type is now omitted (like (int) and (bool) already were), but the value always contains a "." (except if ±Inf, NaN or with exponent) to distinguish them from int.

    Fixes

    • Contains: slice in slice search didn't work at end of slice;
    • JSON, SubJSONOf and SuperJSONOf operators panicked when using All+JSON-operator+embeddedOp+$1;
    • anchoring 2 slices at the same time didn't work.

    Miscellaneous

    And happy new year!

    Source code(tar.gz)
    Source code(zip)
  • v1.10.1(Sep 27, 2021)

    Fixes:

    • Len and Cap could not be embedded in JSON, SubJSONOf and SuperJSONOf. Fixed;
    • Bag and Set didn't implement TypeBehind() method. Fixed;
    • JSONPointer expectedValue and JSON placeholders didn't have the same behavior. Now the pointed data is JSON-unmarshaled into a value using the same type of expectedValue (for JSONPointer) or any placeholder (for JSON) before comparison;
    • Catch TypeBehind() method didn't use the type of target when the type behind expectedValue could not be determined. Fixed;
    • (*tdhttp.TestApi).CmpJSONBody(nil) panicked. Fixed;
    • and some typos fixed.

    Enjoy!

    Source code(tar.gz)
    Source code(zip)
  • v1.10.0(Aug 31, 2021)

    New features:

    Fixes:

    • multi-lines colored text → color-off \n color-on for each line (@siadat);
    • JSON TypeBehind() method is now delegated when an operator is at the root of the JSON;
    • tdhttp package:
      • chaining of Cmp* methods can lead to skew Failed() result.

    Enjoy!

    Source code(tar.gz)
    Source code(zip)
  • v1.9.2(Mar 18, 2021)

  • v1.9.1(Mar 16, 2021)

    Fixes:

    • traces displayed when a Cmp failure occurs, are now properly stripped to ignore testing, td, tdhttp and tdsuite internal calls;
    • JSON unmarshal bug when \uxxxx is first escaping sequence in a string.
    Source code(tar.gz)
    Source code(zip)
  • v1.9.0(Mar 9, 2021)

    New features:

    • introducing new tdsuite helper, allowing to easily create testing suites, fully integrated with go-testdeep;
    • JSON, SubJSONOf and SuperJSONOf now accept almost all operators embedded directly in JSON thanks to our new custom JSON decoder:
      td.Cmp(t,
        got,
        td.JSON(`{"name": HasPrefix("Bob"), "age": Between(20, 25)}`),
      )
      
    • Re and ReAll capture parameter can now be a []interface{} (only []string until now);
    • Flatten is now able to flatten maps, can be useful when creating request using tdhttp package;
    • when a Cmp failure occurs outside the root of a test function, a trace of all successive function calls is displayed to help the user to understand/locate the error;
    • in tdhttp helper (aka the ultimate HTTP API tester), tdhttp.TestAPI gains several methods:
      • AutoDumpResponse allows to dump the HTTP response when the first error is encountered after a request,
      • OrDumpResponse dumps the response if at least one previous test failed,
      • Run runs a subtest,
      • T returns the internal instance of *td.T,
      • With creates a new *TestAPI instance.

    Fixes:

    • reflect.Interface containing nil could produce wrong comparisons.

    Enjoy!

    Source code(tar.gz)
    Source code(zip)
  • v1.8.0(Dec 17, 2020)

    New features:

    • add new JSONPointer operator following RFC 6901;
    • when 2 types differ but have the same short name, use full pkg name in error report;
    • add Cmp and Smuggle hooks feature;
    • new td.Tuple type added and its td.TupleFrom() builder. Useful to quickly test functions returning several values as in:
      price := func(p float64) (float64, string, error) {
        if p < 0 {
          return 0, "", errors.New("negative price not supported")
        }
        return p * 1.2, "€", nil
      }
      
      td.Cmp(t,
        td.TupleFrom(price(10)),
        td.TupleFrom(float64(12), "€", nil),
      )
      
      td.Cmp(t,
        td.TupleFrom(price(-10)),
        td.TupleFrom(float64(0), "", td.Not(nil)),
      )
      
    • when calling tdhttp.NewRequest() (and all other request builder methods) headers can be flattened with td.Flatten().

    Fixes:

    Enjoy!

    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(Jul 19, 2020)

    New features:

    • new (*td.T).RunAssertRequire function. Useful to avoid boilerplate code:
      t.RunAssertRequire("GetAge", func (assert *td.T, require *td.T) {
        age, err := GetAge("Bob")
        require.CmpNoError(err)
        assert.Cmp(age, 42)
      })
      
    • new tdhttp.TestAPI method Or(), useful to debug a test failure:
      ta.Get("/person/42", "Accept", "application/json").
        CmpJSONBody(td.JSON(`{"id": $1, "name": "Bob"}`, td.NotZero())).
        Or(func (body string) { t.Logf("received unexpected body: <%s>", body) })
      

      see the Or() documentation as the passed function can have a much more complex signature. It is inspired by Test::Mojo or() method and allows to easily inspect the response of the requested API when the checks fail.

    Fixes:

    • #101 → some data recursion cases were not correctly handled (reported and tested by @stewi1014);
    • some panics due to the user misbehavior were not properly red-colored;
    • (*td.T).Run: t.Config is now copied instead of shared before using it in sub-func;
    • typos in doc.

    Enjoy!

    Source code(tar.gz)
    Source code(zip)
  • v1.6.0(May 31, 2020)

    Changes:

    • td.TestingFT interface is deprecated (but still usable) and superseded by testing.TB standard one: it allows to work with *testing.B instances as well (or any other type implementing testing.TB);
    • (*td.T).RunT() is deprecated (but still usable) and superseded by (*td.T).Run() which now delegates to td.T.TB if it implements a Run() method with the following signature:
      (X) Run(string, func(X)) bool
      

    Breaking changes:

    • as td.TestingFT interface is now an alias on testing.TB, it does not contain Run(string, func (*testing.T)) bool anymore;
    • it is quite unlikely that (*td.T).Run(string, func (*testing.T)) method is used, but if it is, all calls have to be replaced by (*td.T).Run(string, func (*td.T)) like in:
      tt.Run("my_test", func (tt *td.T) {
          t := tt.TB.(testing.T)
          ...
      })
      

      note that even though (*td.T).RunT() is deprecated, it still works as expected.

    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(May 17, 2020)

    New features:

    • new Flatten function: useful to flatten non interface{} slices in Set, Bag arguments (but not only, read the doc);
    • panic messages due to user misuse of go-testdeep functions/methods are now red colored to help her/him to focus on her/his mistake and not think go-testdeep failed shamefully;
    • delay colors initialization to the first use. So colors can now be disabled in golang playgroung. See the corresponding FAQ point;
    • optimize some type retrievals.

    Fix:

    • forbid Isa(nil) because it is a nonsense and so avoid a deep panic.

    New FAQ entries:

    Enjoy and do not forget to star!

    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(Apr 11, 2020)

  • v1.3.0(Feb 29, 2020)

    Package github.com/maxatome/go-testdeep is deprecated, it is recommended to use github.com/maxatome/go-testdeep/td in new code.

    github.com/maxatome/go-testdeep is still usable so the compatibility is preserved.

    The only breaking change is the disappearance of testdeep.DefaultContextConfig. It should be replaced by td.DefaultContextConfig and so the go-testdeep import line should be changed (at least "github.com/maxatome/go-testdeep/td" should be added).

    To summarize: migration to github.com/maxatome/go-testdeep/td is not needed, only recommended, except if testdeep.DefaultContextConfig is used.

    To migrate:

    import "github.com/maxatome/go-testdeep"
    …
    testdeep.DefaultContextConfig = testdeep.ContextConfig{…}
    testdeep.Cmp(…)
    

    or with "td" package alias:

    import td "github.com/maxatome/go-testdeep"
    …
    td.DefaultContextConfig = td.ContextConfig{…}
    td.Cmp(…)
    

    simply do (see import line changes):

    import "github.com/maxatome/go-testdeep/td"
    …
    td.DefaultContextConfig = td.ContextConfig{…}
    td.Cmp(…)
    

    See the FAQ point for details about this migration.

    And still, do not forget to visit https://go-testdeep.zetta.rocks/ and open an issue if something seems to be missing or not clear.

    Happy testing!

    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Feb 13, 2020)

  • v1.1.2(Nov 18, 2019)

    New features:

    Synopsis revisited!

    Enjoy powerful API testing!

    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Nov 3, 2019)

  • v1.1.0(Jul 7, 2019)

    New features:

    Breaking changes:

    Bugs fixes:

    • Fix a bug when compared slices have the same backend array.

    Misc:

    Source code(tar.gz)
    Source code(zip)
  • v1.0.8(Jan 14, 2019)

  • v1.0.7(Dec 10, 2018)

  • v1.0.6(Dec 7, 2018)

  • v1.0.5(Nov 2, 2018)

  • v1.0.3(Aug 19, 2018)

    • internal structures not accessible anymore
    • works around golang https://github.com/golang/go/issues/26995 issue (impact go test -race usages)
    • unit tests pass when "unsafe" package is not available
    • test coverage increased
    Source code(tar.gz)
    Source code(zip)
  • v1.0.2(Jul 20, 2018)

  • v1.0.1(Jul 15, 2018)

  • v1.0.0(Jun 24, 2018)

Package truthy provides truthy condition testing with Go generics

Truthy Truthy is a package which uses generics (Go 1.18+) to create useful boolean tests and helper functions. Examples // truthy.Value returns the tr

Carl Johnson 31 Aug 28, 2022
golden provides utilities for golden file tests.

golden provides utilities for golden file tests.

Takuya Ueda 13 Jul 29, 2022
Magma: Gives network operators an open, flexible and extendable mobile core network solution

Connecting the Next Billion People Magma is an open-source software platform tha

nikhilc 0 Dec 24, 2021
gofu aims to provide a flexible toolkit for creating custom scripting languages in Go.

gofu a scripting language toolkit in Go intro gofu aims to provide a flexible toolkit for creating custom scripting languages in Go. functions Functio

Andreas Nilsson 9 Aug 2, 2021
Golang library to act on structure fields at runtime. Similar to Python getattr(), setattr(), hasattr() APIs.

go-attr Golang library to act on structure fields at runtime. Similar to Python getattr(), setattr(), hasattr() APIs. This package provides user frien

Shyamsunder Rathi 27 Jul 5, 2022
Go-path - A helper package that provides utilities for parsing and using ipfs paths

go-path is a helper package that provides utilities for parsing and using ipfs paths

y 0 Jan 18, 2022
keeper is package for Go that provides a mechanism for waiting a result of execution function until context cancel.

keeper is package for Go that provides a mechanism for waiting a result of execution function until context cancel.

Gunosy 5 Apr 18, 2022
Utility package that provides the ability to more conveniently work with URL parameters.

Utility package that provides the ability to more conveniently work with URL parameters.

Radik Khisamutdinov 1 Feb 8, 2022
A Go utility to convert Go example tests into jupyter notebooks.

go2colab Scientists (my main project's users) love jupyter notebook tutorials pkg.dev.go's runnable playground doesn't support file IO but I love exam

Tim 1 Jul 10, 2022
Flock is a project which provides a Go solution for system level file locks for all platforms Golang supports.

Flock is a project which provides a Go solution for system level file locks for all platforms Golang supports.

Ken Sipe 0 Feb 8, 2022
A package for running subprocesses in Go, similar to Python's subprocesses package.

A package for running subprocesses in Go, similar to Python's subprocesses package.

Esteban Garcia 5 Jul 28, 2022
Utility to restrict which package is allowed to import another package.

go-import-rules Utility to restrict which package is allowed to import another package. This tool will read import-rules.yaml or import-rules.yml in t

PAYFAZZ 0 Jan 7, 2022
Small utility to allow simpler, quicker testing of parsing files in crowdsec

cs_parser_test Small utility to allow simpler, quicker testing of parsing files in crowdsec Usage $ sudo cs_parser_test -t syslog /var/log/mail.log N

david reid 3 Jul 13, 2021
This project provides some working examples using Go and Hotwire Turbo.

hotwire-golang-website This project provides some working examples using Go the hotwire/turbo library published by basecamp.

Mark Wolfe 149 Sep 16, 2022
Go library that provides fuzzy string matching optimized for filenames and code symbols in the style of Sublime Text, VSCode, IntelliJ IDEA et al.

Go library that provides fuzzy string matching optimized for filenames and code symbols in the style of Sublime Text, VSCode, IntelliJ IDEA et al. This library is external dependency-free. It only depends on the Go standard library.

Sahil Muthoo 1.2k Sep 22, 2022
Slice - provides generic Map, Reduce and Filter functions for Go.

slice slice is a simple Go package to provide generic versions of Map, Reduce and Filter on slices. I mainly wrote it as an exercise to get more famil

Andreas Krennmair 23 Sep 19, 2022
An API that provides a small but well-thought service converting Euro to US Dollar and vice-versa

Currency Converter ###Problem An API that provides a small but well-thought service converting Euro to US Dollar and vice-versa. That API should only

Akshay Nambiar 0 Jan 30, 2022
rxscan provides functionality to scan text to variables using regular expression capture group.

rxscan rxscan provides functionality to scan text to variables using regular expression capture group. This library is still experimental, use at your

Ahmy Yulrizka 14 Dec 21, 2020
Hotswap provides a solution for reloading your go code without restarting your server, interrupting or blocking any ongoing procedure.

Hotswap provides a solution for reloading your go code without restarting your server, interrupting or blocking any ongoing procedure. Hotswap is built upon the plugin mechanism.

Edwin 115 Sep 21, 2022