Giter Club home page Giter Club logo

brshamcrest's Introduction

brsHamcrest Build Status

Hamcrest implementation in BrightScript

Usage

brsHamcrest is designed for use standalone or with an existing unit test framework (such as brstest).

Assertions

You can use either assertThat() or that() to assert that a Matcher returns positive:

assertThat(foo, is(aString()))
assertThat(foo, startsWithString("bar"))
assertThat(foo, is(allOf([aNumber(), greaterThan(5), lessThan(10)])))

You may find that using that() fits better with an assertion from an existing test framework:

assertTrue(that(foo, is(aString())))
assertTrue(that(foo, startsWithString("bar")))
assertTrue(that(foo, is(allOf([aNumber(), greaterThan(5.3), lessThan(10)]))))

For more information, see the Assertions wiki page.

Matcher Wrappers

You can wrap a Matcher (or several Matchers) in various wrappers:

' is() doesn't change logic, just improves readability:
assertThat(foo, is(aString()))

' isNot() inverses a Matcher's output:
assertThat(foo, isNot(aString()))

' allOf() / anyOf() / noneOf() checks against several Matchers:
assertThat(foo, is(allOf([aNumber(), lessThan(5)])))
assertThat(foo, is(anyOf([anArray(), anAssociativeArray()])))
assertThat(foo, is(noneOf([startsWithString("bar"), endsWithString("bar")])))

' is() and isNot() can also accept arrays of Matchers to act as shortcuts to allOf() and noneOf() respectively
assertThat(foo, is([anInteger(), lessThan(100)]))
assertThat(foo, isNot([anEmptyCollection(), identicalTo(bar)]))

As you can see in the examples, you can chain up Wrappers to form an easy to read assertion. This can read to some different structures but equal outputs, for example isNot(anyOf()) is equal to is(noneOf()), it's up to you.

For more information, see the Core Matchers wiki page.

Matchers

Included are various Matchers, such as:

' Examples are listed here, this is not a complete list.

' Type Matchers
assertThat(10, is(anInteger()))
assertThat("foo", is(aString()))
assertThat(myFunc, is(aFunction()))

' Numeric Matchers
assertThat(10, is(greaterThan(5)))
assertThat(3.543, is(lessThanOrEqualTo(8.5)))
assertThat(5.5, is(closeTo(5, 0.8)))

' Text Matchers
assertThat("foobar", startsWithString("foo"))
assertThat("foobar", endsWithString("bar"))
assertThat("foobar", containsStringsInOrder(["foo", "bar"]))

' Collection Matchers
assertThat(myArray, is(anEmptyCollection()))
assertThat("foo", is(inCollection(["foo", "bar"])))
assertThat(myAssocArray, containsKeyValuePairs({foo: "bar", someKey: "someValue"}))

' Object Matchers
assertThat(foo, is(sameObjectAs(bar)))
assertThat(foo, is(identicalTo(bar)))

Feel free to create your own Matchers, just extend from BaseMatcher and ensure that the doMatch() function returns a Boolean.

For more information, see the Matcher pages available on the wiki.

Unit Tests

brsHamcrest is fully unit tested. the tests directory contains the unit test source files and testrunner utility (using brstestrunner). To run the unit tests, execute make test from the project directory (where Makefile is located).

brshamcrest's People

Contributors

imbenjamin avatar oneronaut avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

brshamcrest's Issues

AssocArray API methods used to compare objects are sometimes not available

Issue: We parse some data,

rawData = "{items:[item1,item2,item3]}"
data = ParseJson(rawData)

data is an object, but it is now missing parts of its ifAssociativeArray interface โ€“ namely https://sdkdocs.roku.com/display/sdkdoc/ifAssociativeArray#ifAssociativeArray-Items()asObject.

This currently conflicts with BrsHamcrest coreDoMatch() which uses various AssocArray API to traverse the object being matched.

The only way to avoid this is to change our coreDoMatch() method to avoid using dangerously named API members.

So, to avoid clashes the following API members should not be used in this matching;

  • ifAssociativeArray:items
  • ifAssociativeArray:keys

equalTo() matcher to avoid circular references

requirement: Stop the equalTo() matcher from traversing any object it has already traversed during the match.

driver: This will stop it from overflowing the stack when an object being checked contains a circular reference.

add explicit equalTo() matcher

requirement: Sometimes an explicit match is required while using BrsHamcrest. Add the following matchers:

  • equalTo(comparison as dynamic)
  • notEqualTo(comparison as dynamic)

Extend Object matching to support roArray

Requirement: To extend the current objectMatchers to support checking arrays for the same comparison as currently supported for AssociativeArrays. That is;

  1. identicalTo: are not the same array, but is identical to the comparison array in terms of structure and values.
  2. sameObjectAs: the two references to an array are actually references to the same array.

NOTE: They could even cover any "object" that is not intrinsic in value and can be successfully compared in this way.

Reduce number of HamcrestError instance by simply failing the match

Where we can replace HamcrestError instances with just simply return false, minimising the number of code stops and respecting the Boolean return value:

  • brsHamcrest_CollectionMatchers.brs // inCollection()
  • brsHamcrest_CoreMatchers.brs // isNot()
  • brsHamcrest_CoreMatchers.brs // allOf()
  • brsHamcrest_CoreMatchers.brs // anyOf()
  • brsHamcrest_CoreMatchers.brs // noneOf()
  • brsHamcrest_Assert.brs // assertThat()
  • brsHamcrest_Matcher.brs // BaseMatcher()

Perhaps an error should still be logged (and remove the stop from HamcrestError), and continue to execute code, returning the false value.

allow any type to be used as a matcher value

Request: Change all `doMatch(matcherValue) signatures to allow any type to be used as the matcher value. Where an incorrect type is used, the response should be to fail instead of generating an error.

Reason: This would allow better integration into Rokito, where the chance of attempting to perform a match against the wrong type would be impossible to avoid.

allow complex comparisons of values for containsKeyValuePairs matcher

Requirement: Use coreDoMatch() method for comparing values in the containsKeyValuePairs() matcher.

Reason: In containsKeyValuePairs(), matching of the key values is currently done with a simple (a = b) comparison. This works well with intrinsic values, but where the value is a more complex object then a complex matcher is required.

New Matcher: typeOf()

Idea for a new Matcher:
typeOf (componentName as String)

Checks a variable is an instance of a specific BrightScript component. (Essentially opens up type matching to any component)

Eg:

dt = CreateObject("roDateTime")
assertThat(dt, is(typeOf("roDateTime")))      '= True
assertThat(dt, is(typeOf("roDeviceInfo")))    '= False

coreDoMatch does not ignore case differences in key names

Issue: Given the following statement:

obj = {fooKey : "fooValue"}
obj2 = parseJson{"{""fooKey"":""fooValue""}")

Then:

obj.items()[0].key = "fookey"
obj2.items()[0].key = "fooKey"

Note the difference in casing of the string representations of these keys.

So brsHamcrest's coreDoMatch needs to account for this when comparing key names.

add object-matcher that matches structure but not value

Suggestion: Add an object-matcher that will test the structure of an object, but not its values.

For example, the following would be true,

that({foo:"fooValue1", bar:true}, is(identicalStructureTo({foo:"fooValue2", bar:false})))

NOTE: there could end up being a lot of edge cases around this where more complex objects are used. Opening to investigate whether this is possible.

Passing is() or isNot() an array should shortcut to allOf() and noneOf()

Idea: To be able to pass is() or isNot() an array of matchers as a shortcut to using allOf() and noneOf().

Example:
assertThat(42, is(allOf([greaterThan(40), lessThan(50)])))
becomes
assertThat(42, is([greaterThan(40), lessThan(50)]))
Same deal with isNot() and noneOf()

It just offers one less nesting level and more flexibility with syntax.

Create objects upfront rather then populating after instantiating

Currently:

matcher = BaseMatcher()

matcher.doMatch = function (target as Dynamic) as Boolean
...
end function

Should change to:

matcher = BaseMatcher()

matcher.append({
    doMatch: function (target as Dynamic) as Boolean
    ...
    end function
})

To enforce better coding standards, etc

Object matching is no longer applying a lexicographical order to key comparison

Problem: When working on #28 we stopped the object.key comparison from being applied in the same lexicographical order. This means that even if two objects are identical, an identicalTo comparison might still fail if the keys are traversed in a different order.

Solution: Within the coreDoMatch algorithm do a comparison by specific key instead of relying on the order that the object is traversed in a for each item in target statement.

New `collectionWithSize()` Matcher

Looking at the list of established Java Hamcrest matchers, there's an arrayWithSize() or hasSize() Matcher (see this doc page )
The equivalent here would be something collectionWithSize(size as Integer) or hasSize(size as Integer) added to the Collection Matchers. This would check the .length() of a collection and match it against the given size value.

Add isSameMatch to matcher common interface

requirement: Add a new method to the matcher interface to allow it to determine whether it is the same match as another matcher instance.

matcher.isSameMatch(matcher)

This will allow for better integration into Rokito, where matchers themselves, when used to define expected parameter values, need to be compared with each other.

Matcher validation before execution

Instead of checking CLASS_TYPE = "Matcher" when executing doMatch(), a validation method could be written that checks a given object is a valid matcher, perhaps using eval() against the matcher to check the behaviour. This is eliminate the CLASS_TYPE magic string and improve assertion resiliency.

New Matcher: isAnything()

Request: Add an isAnything() matcher that will match anything. This won't have much use in direct matches. But when a matcher is used to define an expected parameter in a mocking framework, it becomes useful when you are defining params where you don't care what the value is. For example:

mock.given("fooFunction").with(["foo", isAnything(), true]).willReturn("bar")

Matching an instance of an object

Is it currently possible to match an instance of an object from two unique references? Something like:

AssertThat(objectRef1, is(objectRef2))

An example of the requirement would be when checking that a particular getter would always return the same instance of an object every time it was called. I've just built this into my unit tests so far with the following test method:

isSame: function (ref1 as Object, ref2 as Object) as Boolean
    ref1.uniqueTestId = "uniqueTestId"
    isSame = (ref1.uniqueTestId = ref2.uniqueTestId)
    ref1.delete("uniqueTestId")
    return isSame
end function

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.