Coder Social home page Coder Social logo

gocrest's Introduction

gocrest

A hamcrest-like assertion library for Go. GoCrest matchers are composable, self-describing and can be strung together in a more readable form to create flexible assertions.

Inspired by Hamcrest.

Build Go Report Card GoDoc Coverage Status

Package import

import (
  "github.com/corbym/gocrest/by"
  "github.com/corbym/gocrest/then"
  "github.com/corbym/gocrest/is"
  "github.com/corbym/gocrest/has"
)

Example:

then.AssertThat(testing, "hi", is.EqualTo("bye").Reason("we are going"))

output:

we are going
Expected: value equal to <bye>
     but: <hi>

Composed with AllOf:

then.AssertThat(t, "abcdef", is.AllOf(is.StringContaining("abc"), is.LessThan("ghi")))

Asynchronous Matching (v1.0.8 onwards):

//Reader
then.WithinFiveSeconds(t, func(eventually gocrest.TestingT) {
	then.AssertThat(eventually, by.Reading(slowReader, 1024), is.EqualTo([]byte("abcdefghijklmnopqrstuv")))
})
//channels
then.Eventually(t, time.Second*5, time.Second, func(eventually gocrest.TestingT) {
	then.AssertThat(eventually, by.Channelling(channel), is.EqualTo(3).Reason("should not fail"))
})
// multiple assertions
then.WithinTenSeconds(t, func(eventually gocrest.TestingT) {
	then.AssertThat(eventually, by.Channelling(channel), is.EqualTo(3).Reason("should not fail"))
	then.AssertThat(eventually, by.Channelling(channelTwo), is.EqualTo("11").Reason("This is unreachable"))
})

v.1.1.0 - generics

Changes all the matchers to use generics instead of reflection. Some still use a bit of reflection, e.g. TypeName etc.

Other major changes:

  • ValueContaining has been split into StringContaining, MapContaining, MapContainingValues, MapMatchingValues, ArrayContaining and ArrayMatching.

  • No longer panics with unknown types, as types will fail at compile time. Some idiosyncrasies with the generic types do exist, but this is language specific;

  • Map matchers generally need to know the type of the map key values explicitly or the compiler will complain, e.g.

then.AssertThat(testing, map[string]bool{"hi": true, "bye": true}, has.AllKeys[string, bool]("hi", "bye"))
  • has.Length() is likewise pernickety about types being explicit, mainly because it works on both strings and arrays. It needs to know both the type of the array and the array/string type. Confused? me too.
  • is.LessThan() and is.GreaterThan() (and by extension is.GreaterThanOrEqualTo and is.LessThanOrEqualTo) no longer work on complex types. This is because the complex types do not support the comparison operators (yet, somehow, they could be compared by reflection ๐Ÿคท )

See the matcher_test.go file for full usage.

Matchers so far..

  • is.EqualTo(x)
  • is.EqualToIgnoringWhitespace(string) - compares two strings without comparing their whitespace characters.
  • is.Nil() - value must be nil
  • is.StringContaining(expected) -- acts like containsAll
  • is.MapContaining(expected) -- acts like containsAll
  • is.MapContainingValues(expected) -- acts like containsAll
  • is.MapMatchingValues(expected) -- acts like containsAll
  • is.ArrayContaining(expected) -- acts like containsAll
  • is.ArrayMatching(expected) -- acts like containsAll
  • is.Not(m *Matcher) -- logical not of matcher's result
  • is.MatchForPattern(regex string) -- a string regex expression
  • has.FunctionNamed(string x) - checks if an interface has a function (method)
  • has.FieldNamed(string x) - checks if a struct has a field named x
  • is.AllOf(... *Matcher) - returns true if all matchers match
  • is.AnyOf(... *Matcher) - return true if any matcher matches
  • is.GreaterThan(expected) - checks if actual > expected
  • is.LessThan(expected)
  • is.Empty() - matches if the actual is "", nil or len(actual)==0
  • is.LessThan(x)
  • is.LessThanOrEqualTo(x)
  • is.GreaterThan(x)
  • is.GreaterThanOrEqualTo(x)
  • has.Length(x) - matcher if given value (int or matcher) matches the len of the given
  • has.Prefix(x) - string starts with x
  • has.Suffix(x) - string ends with x
  • has.Key(x) - map has key x
  • has.AllKeys(T x, T y) (or has.AllKeys([]T{x,y})) - finds key of type T in map
  • has.EveryElement(x1...xn) - checks if actual[i] matches corresponding expectation (x[i])
  • has.StructWithValues(map[string]*gocrest.Matcher) - checks if actual[key] matches corresponding expectation (x[key])

For more comprehensive documentation see godoc.

gocrest's People

Contributors

corbym avatar jpolack avatar mattcorbyeaglen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

gocrest's Issues

matcher for nil interface value

Existing matchers can do nil assertions on interface values because they match on T or *T but not a T that can be an interface(ie ptr)

type Blah interface{
   DoSomething()
}

func TestShouldHaveANilBlah(t *testing.T){
var myBlah Blah

then.AssertThat(t, myBlah, is.NilPtr[Blah])

}

wont compile - as the signature for NilPtr is assuming a struct T and returns a [*T] matcher...

does a NoError() matcher make sense?

Hi,

since foo, err := bar() is a typical go style, I wonder, if a NoError() matcher would make sense to add?

Example

foo, err := bar()
then.assertThat(t, err, is.NoError())

What do you think?
I would be open to create a PR ... but would like to get your view first :)

Implement Testify custom matchers via mock.MatchedBy

Hi, I saw the recent gomock discussion and would love documentation on how to Implement Testify's custom matchers via mock.MatchedBy using this library.

// Anything and AnythingOfType matchers
mockDoer.
    On("Do", mock.Anything, mock.AnythingOfType("string"))

// Custom matcher
mockDoer.
    On("Do", 1, mock.MatchedBy(func(x string) bool {
        return strings.HasPrefix(x, "abc")
    })

more boilerplate for has.Length() and is.Nil() after upgrade 1.1.0 release

Hi,

thank you for your continuous effort to maintain this great lib.

With the new 1.1.0 release, I read you implemented generics support.
I have to admit, without looking into the release notes, I did accept the PR from dependabot and was surprised, my pet project did not compile anymore.
May I share some feedback?
Introducing generics is good, but this breaking change should have been mentioned in the Release Notes.
Also, I don't like the extra boilerplate code, I have to write, just to make the compiler happy.
Is there a chance of introducing generics, with keeping the existing test code intact? And maybe omit the boilerplate code?

before (it works with gocrest 1.0.x
// from type inference, settings is of type []PoePortSetting
settings, err := findPortSettingsInHtml(strings.NewReader(getPoePortConfigCgiHtml))

then.AssertThat(t, err, is.Nil())
then.AssertThat(t, settings, has.Length(4))
after (to make it work with gocrest 1.1.x
// from type inference, settings is of type []PoePortSetting
settings, err := findPortSettingsInHtml(strings.NewReader(getPoePortConfigCgiHtml))

then.AssertThat(t, err, is.Nil[error]())
then.AssertThat(t, settings, has.Length[PoePortSetting, []PoePortSetting](4))

PS: the source, I'm talking about https://github.com/nitram509/ntgrrc/blob/main/poe_settings_test.go

Looking forward to hear your thoughts.

Describe only failed matchers in AllOf

AllOf reports all matcher's descriptions when it fails.

Given a number of matchers, when less than all of them fail, we should only report the description of the failing matchers.

Implement the gomock.Matcher interface

I was using gomock and wanted to use our matchers.
Sadly it didn't work out because our matchers don't implement the gomock.Matcher interface:

type Matcher interface {
  // Matches returns whether x is a match.
  Matches(x interface{}) bool

  // String describes what the matcher matches.
  String() string
}

To implement the gomock.Matcher interface we would have to:

  1. implement a .Matches method as a struct method, not only as a field
  2. implement the Stringer interface

The Stringer interface should be fairly easy. But the Matches method would cause trouble, because Matcher already has a field called Matches of type func(actual interface{}) bool.

At this point I see two options:

1. add a mapping method from gocrest.Matcher to gomock.Matcher:

A quick win, but kind of dirty because it doesn't really take advantage of go's interface system. Additionally it kind of breaks gomocks syntax:

m.
  EXPECT().
  Bar(is.Equalto(99).toGomockMatcher()).
  Return(101)

2. rename the Matches method on the Matcher struct:

Seems like the cleaner way to me, but would cause a breaking change in how matchers are written.
Would result in the following gomock syntax:

m.
  EXPECT().
  Bar(is.Equalto(99)).
  Return(101)

I would love to discuss this and find a way that suites us best!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.