Giter VIP home page Giter VIP logo

hamkrest's Introduction

HamKrest - Hamcrest for Kotlin

A reimplementation of Hamcrest to take advantage of Kotlin language features.

Kotlin Build Status Maven Central

Note: as of version 1.4.0.0, you must add kotlin-reflect to the classpath to use HamKrest's reflective features.

When working in Kotlin, Hamkrest provides these benefits over using the Java Hamcrest library:

  • Kotlin's type system means that developers don't have to worry about getting the variance of generic signatures right. Variance is defined on the abstract Matcher type and Kotlin makes sure composition and subtyping work together the way you expect.

  • Syntactic sugar. You can negate a matcher with the ! operator and compose matchers with infix and and or functions:

    import com.natpryce.hamkrest.assertion.assert
          
    ...
          
    assertThat("xyzzy", startsWith("x") and endsWith("y") and !containsSubstring("a"))
  • Easier to extend. You can convert named unary predicates into matchers.

    val isBlank = Matcher(String::isBlank)
    
    assertThat(input, isBlank)

    As a shortcut, you can pass named functions to the assertThat, and, or and many other functions that take a matcher.

    assertThat(input, String::isBlank)

    You can also convert a named binary predicate and the second argument to a matcher for first argument, which works well for extension methods.

    fun String.hasLength(n: Int): Boolean = this.length == n
    
    val isTheRightLength = Matcher(String::hasLength, 8)
    
    assertThat(secretCode, isTheRightLength)

    You can use function and property references to match features of a value:

    val isLongEnough = has(String::length, greaterThan(8))
    
    assertThat(password, isLongEnough)

    All of these shortcuts produce good, human-readable diagnostics.

    You can customise how diagnostics are generated by creating a project-specific assert object.

More documentation

More detailed documentation of specific library features is in the docs/ directory.

hamkrest's People

Contributors

andreasvolkmann avatar benusher avatar cbeust avatar dhobbs avatar dmcg avatar gypsydave5 avatar lmirabal avatar npryce avatar s4nchez 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hamkrest's Issues

But why is it not Hamcrest compatible?

Right now there're tons of libs relying on Hamcrest matchers, such as rest-assured, which is also has Kotlin support.

When I saw your library first time I was pretty surprised. It was until I realised that Hamkrest is not compatible with Hamcrest interfaces. That's really disappointing, as all of your syntactic sugar renders useless for me. The only question is why?

Maybe is it possible to make your awesome lib compatible with Hamcrest?

If not, don't you know any alternatives?

Adding hamkrest as test dependency to multiplatform module

Is it possible to add hamkrest as test dependency in multiplatform package?

I am trying to do this
commonTest { dependencies { implementation kotlin('test-common') implementation kotlin('test-annotations-common') implementation 'com.natpryce:hamkrest:1.7.0.0' } }

but that doesn't work. I can see the lib in Intellij but classes are not accessible in tests

Next release to Maven?

I'm looking to use some newer features in HamKrest, like allOf. These were added since the last tagged/released 1.4.2.2 version. Is there any ETA when these will be published to Maven Central as a new version?

Rik

hasSize overload for just taking an integer

Something that would just make writing test simpler:

/**
 * Matches a collection with a size that is equal to [size].
 */
fun hasSize(size: Int) = has(Collection<Any>::size, equalTo(size))

Make compatible with Hamcrest

I appreciate that with Kotlin you could make the API much nicer, but the fact that your Matcher does not implement Hamcrest's Matcher interface is a very bad idea. Hamcrest is pretty much a standard, it is supported by JUnit itself and other libraries like Mockito. Hamkrest should augment Hamcrest not be a incompatible replacement for it.

Add assertThat overload with the reason argument as Function0<String>

Sometimes it is useful not to evaluate the reason expression until the assertion failed. Example:

val userJson = JsonPath.parse(userResponseBody)
assertThat(
    userJson.read("$.error_description"), 
    userResponse.status, 
    equalTo(Response.Status.OK.statusCode)
)

Possible solution would be

fun <T> assertThat(actual: T, matcher: Matcher<in T>, reason: () -> String) {
    if (!matcher.matches(actual)) {
        val description = StringDescription()
        description.appendText(reason.invoke())
                .appendText("\nExpected: ")
                .appendDescriptionOf(matcher)
                .appendText("\n     but: ")
        matcher.describeMismatch(actual, description)

        throw AssertionError(description.toString())
    }
}

fun <T> assertThat(reason: String, actual: T, matcher: Matcher<in T>) = 
    assertThat(actual, matcher) { reason } 

Upgrade to Kotlin 1.1

Kotlin 1.1 has moved reflection classes into a new package, and deprecated the ones in the kotlin.reflect package

How about a shouldEqual infix method

So you can say

value shouldEqual 42

instead of

value shouldMatch equalTo(42)

Or perhaps it is just another version of shouldMatch and you say

value shouldMatch 42

Failing equalsTo assertion with java.nio.file.Path results in StackOverflowError

If you have an assertion like this:

assertThat(somePath, equalTo(fileSystem.getPath("some.file")))

and the assertion fails (ie. somePath != fileSystem.getPath("some.file")), instead of failing with an assertion failed message, a StackOverflowError is thrown.

The stack trace is:

java.lang.StackOverflowError
        at sun.nio.fs.UnixPath.initOffsets(UnixPath.java:206)
        at sun.nio.fs.UnixPath.getName(UnixPath.java:319)
        at sun.nio.fs.UnixPath.getName(UnixPath.java:43)
        at sun.nio.fs.AbstractPath$1.next(AbstractPath.java:80)
        at sun.nio.fs.AbstractPath$1.next(AbstractPath.java:71)
        at com.natpryce.hamkrest.Describe.describe(describe.kt:43)
        at com.natpryce.hamkrest.Describe.describe(describe.kt:19)
        at com.natpryce.hamkrest.Describe.describe(describe.kt:19)
        at com.natpryce.hamkrest.Describe.describe(describe.kt:19)
        ...

It looks like the issue is that Path implements Iterable<Path>, and each of those returned Paths are themselves Iterable<Path>s, and so describe just keeps recursing. Path probably shouldn't be treated as an Iterable anyway, given that the standard string representation would be much easier to understand.

Support Intellij IDEA's automatic diff calculation

IDEA can format test errors as diffs between expected and actual, which is helpful for large string/object graph comparisons. It appears that all you would need to do is remove the newline between expected: and but was:.

Details here: link

Modern reference to the location in IDEA source: link

Add on library for Guava?

Guava has a bunch of it's own collection types. It would be really cool if there was a hamkrest-guava library that added matchers for these types.

Some of the matchers that I've written up for my own use case are these:

fun <K, V> hasKey(element: K): Matcher<Multimap<K, V>> = object : Matcher.Primitive<Multimap<K, V>>() {
    override fun invoke(actual: Multimap<K, V>): MatchResult =
        if (actual.containsKey(element)) {
            MatchResult.Match
        } else {
            MatchResult.Mismatch("was ${describe(actual)}")
        }

    override val description: String get() = "contains key ${describe(element)}"
    override val negatedDescription: String get() = "does not contain key ${describe(element)}"
}

fun <K, V> hasValue(element: V): Matcher<Multimap<K, V>> = object : Matcher.Primitive<Multimap<K, V>>() {
    override fun invoke(actual: Multimap<K, V>): MatchResult =
        if (actual.containsValue(element)) {
            MatchResult.Match
        } else {
            MatchResult.Mismatch("was ${describe(actual)}")
        }

    override val description: String get() = "contains value ${describe(element)}"
    override val negatedDescription: String get() = "does not contain value ${describe(element)}"
}

fun <K, V> contains(key: K, value: V): Matcher<Multimap<K, V>> = object : Matcher.Primitive<Multimap<K, V>>() {
    override fun invoke(actual: Multimap<K, V>): MatchResult =
        if (actual.containsEntry(key, value)) {
            MatchResult.Match
        } else {
            MatchResult.Mismatch("was ${describe(actual)}")
        }

    override val description: String
        get() =
            "contains key ${describe(key)} with value ${describe(value)}"
    override val negatedDescription: String
        get() =
            "does not contain key ${describe(key)} with value ${describe(value)}"
}

Infix asserts?

Since this is for Kotlin and we have infix functions seems natural that instead of saying something like:

assertThat(myValue, eq(5))

that it would be much nicer to have infix versions (which I am renaming to assertThatIt for a more natural wording):

myValue assertThatIt eq(5)

isNullOr* Can't Be Used With Nullable CharSequence

val isNullOrBlank = Matcher(CharSequence::isNullOrBlank)
val isNullOrEmptyString = Matcher(CharSequence::isNullOrEmpty)

should be:

val isNullOrBlank = Matcher(CharSequence?::isNullOrBlank)
val isNullOrEmptyString = Matcher(CharSequence?::isNullOrEmpty)

assertThat should take vararg criteria

While doing some checks on the same item that requires checking multiple things it occurred to me that this function:

fun <T> assertThat(actual: T, criteria: Matcher<T>) {
    _assertThat(null, actual, criteria)
}

could be more convenient as:

fun <T> assertThat(actual: T, vararg criteria: Matcher<T>) {
    criteria.foreach {_assertThat(null, actual, it) }
}

Test DelimitingValuesInStrings::file_paths fails on Windows

On Windows 10, the test DelimitingValuesInStrings::file_paths fails (and I assume it does not fail on non-Windows platforms). The error is:

java.lang.AssertionError: expected: a value that is equal to "/foo/bar/baz"
but was: "\\foo\\bar\\baz"
Expected :a value that is equal to "/foo/bar/baz"

Actual   :"\\foo\\bar\\baz"

It looks like this is a Windows-specific issue given that the failure occurs because the platform's separator is different.

What is the status of Hamkrest?

Hi,

I stumbled across Hamkrest only recently, as I'd been incorrectly assuming that these were the only implementations of Hamcrest matchers. And I also see that Hamkrest has existed now for almost 3 years, which would seem to suggest that there are no plans to move it under the Hamcrest umbrella either.

Can you tell me what Hamkrest's roadmap is please? I can't help but think of the Yammer/CodaHale/DropWizard metrics library here and wonder if the Hamkrest artifacts could ever mutate in such a way.

Thanks,
Chris

You haven't specified a license

Trying to do my due diligence and document and credit all libraries I am using including noting the license, but I notice that you haven't actually declared a license in GitHub

Change the description of assertion errors so that IntelliJ shows the "show difference" option in the console output.

Hello,

Love using hamkrest! but I have one gripe with it. IntelliJ doesn't show the "show difference" option when an assertion fails. This is quite handy when you're asserting the contents of data classes.

A quick google shows that IntelliJ offers this functionality simply by checking a regular expression. Would it be possible to change the description strings so that IntelliJ shows the "show difference" option when using hamkrest?

Kind regards,

Ewout.

IntelliJ doesn't always show source

In IntelliJ, opening the 'External Libraries' view and finding Hamkrest, some of the 'files' are listed with a .class extension (CollectionMatchers.class) and some are not (CaseSensitity). The source for the latter is shown, the former just shows a decompiled version.

It applies Maven and Gradle projects imported into IntelliJ, and certainly hampers my ability to work out how to use the library.

Add assertAll?

This might be outside of the scope of this assertion library but a kotlin friendly way of declaring multiple assertions in a single test would be nice to add.

I'm opening this issue due to the discussion in the Junit5:

junit-team/junit5#924

Is this outside the scope of this project? If not, this method should probably throw the org.opentest4j.MultipleFailuresError which would require creating a dependency on opentest4j

Failing collection type inference

For example:

    @Test fun `collection type inference`() {
        assertThat(listOf(1) as Collection<Int>, equalTo(listOf(1)))
    }

doesn't compile with error:

Error: Kotlin: None of the following functions can be called with the arguments supplied: 
public fun <T> assertThat(actual: ???, criteria: Matcher<???>): Unit defined in com.natpryce.hamkrest.assertion
public fun <T> assertThat(actual: Collection<Int>, criteria: KFunction1<Collection<Int>, Boolean>): Unit defined in com.natpryce.hamkrest.assertion

If I remove assertThat overloaded with KFunction1 compilation fails with:

Error: Kotlin: Type inference failed: Cannot infer type parameter T in fun <T> assertThat(actual: T, criteria: Matcher<T>): Unit
None of the following substitutions
(Collection<Int>,Matcher<Collection<Int>>)
(List<Int>?,Matcher<List<Int>?>)
can be applied to
(Collection<Int>,Matcher<List<Int>?>)

Similar code works in Java version:

    @Test public void collection_type_inference() {
        assertThat(((Collection<Integer>) asList(1)), equalTo(asList(1)));
    }

Why does anything matcher not accept nullable types

I was pretty surprised that the anything matcher doesn't allow things like this:

val value: Int? = null
value shouldMatch anything

Is there any reason for the anything Matcher to be of type Matcher<Any and not Matcher<Any?>?
If not I would be happy to work on a (very small) pull request to fix this issue.
If there is a reason I'm interested in hearing it.

Question: have I missed something fundamental?

I struggled to write an assertion without creating custom matchers to assert on a nullable boolean, this is what i ended up with but
I don't think it reads very well;

assertThat(capturedValue, false::equals)

Do you have any advice?

Available via Gradle?

Hi, I'm trying to install by adding to my app's build.gradle:

testCompile 'com.natpryce.hamkrest:1.4.2.0'

but wasn't in your README, and it fails to resolve, and I found that this plugin is missing on plugins.gradle.org. I haven't authored a plugin myself but I believe this just requires publishing to plugins.gradle.org. That would make this library infinitely more useful. Thanks!

Add more sugar

What about adding more syntactic sugar to have assertions that reads even better like :

"banana" should starts with "bana"

Kotlintest has something similar so I know it's doable :)
I'll be happy to PR this if interested.

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.