Coder Social home page Coder Social logo

robstoll / atrium Goto Github PK

View Code? Open in Web Editor NEW
540.0 540.0 207.0 69.91 MB

A multiplatform expectation library for Kotlin

Home Page: https://docs.atriumlib.org

License: European Union Public License 1.2

Kotlin 99.45% Java 0.16% Scala 0.38% Shell 0.01%
assert assertion-framework assertion-library assertions hacktoberfest kotlin kotlin-multiplatform kotlin-testing

atrium's People

Contributors

assaflei avatar azrytkech17 avatar binkley avatar chadmarchand avatar constantine-zubrylin avatar danherrera avatar dark-knight11 avatar dependabot-preview[bot] avatar dependabot[bot] avatar isfedorov avatar ivanmiklec avatar jakubriegel avatar jdornieden avatar jgleitz avatar jordanllharper avatar miftahunajat avatar nikos-tsiougranas avatar ratkayandras avatar renovate[bot] avatar rhushikesh avatar robstoll avatar sanatik avatar shytnik-igor avatar szatyinadam avatar tarczynskitomek avatar tfesenko avatar uaarsen avatar vlsi avatar wordhou avatar z13z 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

atrium's Issues

deprecate ...Nullable overloads

The original idea was to: deprecate ...Nullable overloads if subject is non-nullable
I changed the idea to deprecate it always.


*Platform* (JVM and/or JS): all

Code related feature

For instance:

assert(listOf(1, 2)).containsNullableValue(null)

Include actual size for hasSize

Affected Version: 0.6.0

How to reproduce the problem

Consider the following code snippet

assert(0..100).hasSize(40)

It is very cumbersome if we do not see what the actual size is but have to count it by ourself.

asEntries for Map

@arjank is working on this one

function which switches the subject of the assertion (similar to the existing asIterable for Sequence or Array)
Simplification of:

assert(mapOf(1 to "hello")) {
  AssertImpl.changeSubject(this) { subject.entries }
}

It is enough if you add it to the following (do not add it to en_UK..)

  • api-cc-en_GB-common
  • api-infix-cc-en_GB-common
  • api-cc-de_CH-common (name it also asEntries)

Turn deprecated overloads which throw PleaseReplace into error

Platform (JVM and/or JS): JVM/JS

Code related feature

assert(BigDecimal("1.0")).toBe(BigDecimal.TEN)

toBe is deprecated and if one keeps the method then it throws a PleaseReplaceException. I was not aware of that one can turn deprecation also into an error with the help of level = DeprecationLevel.ERROR in the @Deprecated annotation.

shortcut fun `cause` for Throwable::getCause

Platform (JVM, JS and/or Android): jall

Code related feature

expect(expection).cause<NumberFormatException>().messageContains(...)

// instead of
expect(exception).feature(Throwable::cause) {
  isA<NumberFormatException>().messageContains(...)
}

// and
expect(expection).cause<NumberFormatException>() { 
  messageContains(...)
  cause.toBe(null)
}

// instead of

expect(exception).feature(Throwable::cause) {
    isA<NumberFormatException>() {
        messageContains(...)
        feature(Throwable::cause).toBe(null)
    }
}

Following the things you need to do:

lib

  • implement _cause in throwableAssertions (similar to _isThrowing in fun0Assertions.kt)

domain

  • add cause to ThrowableAssertions (see Fun0Assertions.isThrowing)
  • modify ThrowableAssertionsBuilder, delegate to throwableAssertions (see ListAssertionsBuilder as a guideline)
  • delegate implementation to robstoll-lib in ThrowableAssertionsImpl (see ListAssertionsImpl as a guideline)

api

  • provide a fun without argument and returns Expect<TSub> (see fun0Assertions.toThrow)
  • provide a fun which expects an assertionCreator-lambda and returns Expect<TSub> (see fun0Assertions.toThrow as well)
  • add @since 0.9.0 to both functions
  • extends ThrowableFeatureAssertionsSpec in specs-common

other

  • search for TODO #31 and simplify the code with the shortcut fun

Your first contribution?

  • Write a comment I'll work on this if you would like to take this issue over.
    This way we get the chance to revise the description in case things have changed in the meantime,
    we might give you additional hints and we can assign the task to you, so that others do not start as well.
  • See Your first code contribution for guidelines.
  • Do not hesitate to ask questions here or to contact us via Atrium's slack channel if you need help
    (Invite yourself in case you do not have an account yet).

Mocking framework

Hi,

hope find you well with this cold call.

I am an author of mocking framework for Kotlin

I see you are using mockito-kotlin.

I just want you to be aware that there is solution that fully supports Kotlin and ask to try it in your new/current projects.

I can help you if you answer to this issue.

Thanks and please star it

rename api and bundles, exchange cc and remove -robstoll

Platform (JVM and/or JS): all

I think we should use simpler names for the bundles:

  1. I guess we can remove -robstoll from the name. It suffices to mention that the standard implementation uses core-robstoll and domain-robstoll.
  2. Maybe we should get rid of cc which is rather cryptic and exchange it with fluent in case of cc-en_GB and remove it entirely for infix. This way we get atrium-fluent-en_GB and atrium-infix-en_GB
  3. We could consider to remove en_GB from the bundle name. However, I think i18n is a feature which one is not aware of and en_GB gives a nice hint.

isNotBlank for CharSequence

pt2121 is working on this one

shortcut for

assert("Atrium - assertion library for Kotlin").returnValueOf(CharSequence::isNotBlank).toBe(true)

It is enough if you add it to

  • api-cc-en_GB-common
  • api-infix-cc-en_GB-common
  • api-cc-de_CH-common

Build Script references java 7 and java 9

I saw a comment by you in stack overflow, not enough reputation to comment..

I noticed your build script references java 7 and java 9. If it isn't a bug, could you write a comment explaining why?

shortcut fun `get` for List

shortcut for

assert(listOf(1, 2)).returnValueOf(List<Int>::get, 2)...

It is enough if you add it to the following APIs (create a new file called listAssertions):

  • api-cc-en_GB-common
  • api-infix-cc-en_GB-common
  • api-cc-de_CH-common

deprecate `notToBeNullBut` for BigDecimal

Platform (JVM and/or JS): JVM

Code related feature

val a: BigDecimal? = BigDecimal("10.0")
assert(a).notToBeNullBut(BigDecimal.TEN)

we overloaded toBe for BigDecimal but not notToBeNullBut we should do it as well to prevent failures.

make atLeast(1) optional/default for CharSequence.contains

Platform (JVM and/or JS): JVM and JS

Code related feature

assert("hello WORLD").contains.ignoringCase.value("world")

Currently one has to specify the option concerning the number of occurrences always, so as follows:

assert("hello WORLD").contains.ignoringCase.atLeast(1).value("world")

leaving it out implies atLeast(1) IMO and thus we could make it optional.

Make AssertionPlant an alias of Assert => introduce Expect

Affected Version: 0.7.0

How to reproduce the problem

assert(listOf(1,2).contains( // <- invoke code completion here

Since Assert is currently a type alias of AssertionPlant we always see /* AssertionPlant */ in the signature where Assert<T>.() -> Unit is expected. That's quite annoying and also confusing for new users.

obsolete (here for traceability)

Therefore we should change it and make AssertionPlant a type alias of Assert.
Moreover:

  • make sure KDoc only mentions Assert and not AssertionPlant in addition (probably also confusing > for the most)
  • revise README, it states somewhere that Assert is a type alias of AssertionPlant

I decided to introduce a replacement for Assert and AssertionPlant named Expect. It will be an own type + invariant T + no upper bound (means it works also for nullable types)

Message of Exception not shown if different type than the expected one

Affected Version: 0.6.0

How to reproduce the problem

Consider the following code snippet

expect {
  throw new RuntimeException("an important detail which helps to understand a failing test")
}.toThrow<IllegalArgumentException> {
   message { contains("Bla bla...") }
}

We will only see that the actual thrown Throwable was of type RuntimeException and not IllegalArgumentException as expected. In such cases it would be good to see the message of the exception because we cannot make the sub-assertion about message since the down-cast to IllegalArgumentException fails beforehand.

CharSequence contains.regex should mention regex in reporting

Affected Version: 0.6.0

How to reproduce the problem

Consider the following code snippet

assert("hello").containsRegex("^[A-Z][a-z]+[A-Z]$")

The output is:

assert: "hello"        <2010366935>
◆ contains: "^[A-Z][a-z]+[A-Z]$"

We can assume that one searched with the help of a regex but we cannot be sure. It would be better if the output states something like contains value matching regex

Atrium v0.7.0 java 7 and java 9 compile issue with module-info.java for Android Instrumentation Tests

Affected Version: 0.7.0
Platform (JVM or JS): JVM (Android/Art/Dalvik)

How to reproduce the problem

try to run ./gradlew :app:assembleDebugAndroidTest
There is compile issue.

error processing /Users/myuser/.gradle/caches/modules-2/files-2.1/ch.tutteli.atrium/atrium-cc-en_GB-robstoll/0.7.0/f01425b9648391ee682607d945e55b377607ea6f/atrium-cc-en_GB-robstoll-0.7.0.jar
java.lang.RuntimeException
	at org.objectweb.asm.ClassVisitor.visitModule(ClassVisitor.java:148)
	at org.objectweb.asm.ClassReader.readModule(ClassReader.java:731)
	at org.objectweb.asm.ClassReader.accept(ClassReader.java:632)
	at org.objectweb.asm.ClassReader.accept(ClassReader.java:500)
	at com.android.builder.desugaring.DesugaringClassAnalyzer.analyze(DesugaringClassAnalyzer.java:144)
	at com.android.builder.desugaring.DesugaringClassAnalyzer.analyzeJar(DesugaringClassAnalyzer.java:92)
	at com.android.builder.desugaring.DesugaringClassAnalyzer.analyze(DesugaringClassAnalyzer.java:63)
	at com.android.build.gradle.internal.transforms.DesugarIncrementalTransformHelper.lambda$getInitalGraphData$4(DesugarIncrementalTransformHelper.java:150)
	at java.util.concurrent.ForkJoinTask$AdaptedCallable.exec(ForkJoinTask.java:1424)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)

Describe the bug

When I updated Atrium version to 0.7.0 it doesn't work anymore for Android specific (Instrumentation) Tests which runs on the device or emulator. I think the issue with D8 (https://developer.android.com/studio/command-line/d8) compiler of Java bytecode to dex format. When I try to run the same version of Atrium on the JVM it works well.

Expected behaviour

The project should be compiled (assembled) at least.

Iterable contains in any order values create multiple assertions instead of sub-assertions

Affected Version: 0.6.0

How to reproduce the problem

Consider the following code snippet

assert(list(1, 2)).contains("a","b")

Results in:

assert: ...
* contains, in any order: 1
   ...
* contains, in any order: 2
   ...

Whereas it should result in the following (the user has defined both in the same assertion):

assert: ...
* contains, in any order: 
   - 1
      ...
   - 2
     ....

add Assert<Map>.isEmpty()

So far Atrium does not support any assertion functions for Map it would be nice to have at least the basic function isEmpty.
I think it is a good starting point to see how Atrium supports multiple APIs.
The tasks of this issue are:

  • add the function to atrium-assertion (as impl-function, see README)
    • add the DescriptionMapAssertions.kt to atrium-translations-en_UK
  • use the function in atrium-api-cc-en_UK
  • write (or rather copy and modify an existing) Spec
  • repeat the same for atrium-api-cc-de_CH
  • repeat the same for atrium-api-cc-infix-en_UK

assertion functions for Json

Platform (JVM and/or JS): JVM/JS

Code related feature

Yet to be defined how it should look like and how it should behave.
Following a suggestion:

assert("{val: "value", obj: {prop: \"value\"}}").isJson {  
  property("obj").isObject {
    property("prop").toBe("value")
  }
}

Where it normally should not matter in which order the properties appear. However, I am not sure how we should treat data which we did not expect (val in the above example).
Sometimes even order matters, for such cases we could introduce something like inOrder:

assert("{val: \"value\", obj: {prop1: \"val1\", prop2: \"val2\"}}").isJson.inOrder{  
  property("obj").isObject {
    property("prop").toBe("val2") // does not fail, inOrder is per object
    property("prop").toBe("val1")
  }
  property("val").toBe("value") // fails because not in order  
}

Ideas and feedback are welcome.

keys and values for Map

Platform (JVM and/or JS): JVM/JS

Code related feature

assert(mapOf(1 to "a", 2 to "b")) {
  keys....
  values...
}

We already have asKey and asValues but I came to the conclusion that they don't make sense (only asEntries make sense). Or at least it is confusing in error reporting if you see something like:

assert: Map(1 to "a")
* contains 1

containsNotKey for Map

@uaArsen is working on this one

Platform (JVM and/or JS): all

Code related feature

Similar to #28 (see #58) but this time we want the opposite, check if a key is not contained in the Map:

It is enough if you add it to (don't add to UK):

  • api-cc-en_GB-common
  • api-infix-cc-en_GB-common
  • api-cc-de_CH-common -- name it enthaeltNichtKey
    => de_CH DescriptionMapAssertions.CONTAINS_NOT_KEY("enthält nicht den Key")

Expect<T>.toBe, contains etc. should only accept T and not Any

Platform (JVM and/or JS): all

Code related feature

assert(listOf(1, 2)).contains("apple", "banana")
val l: List<Int> = listOf(1,2)
assert(l).contains("apple", "banana")
val a: Assert<List<Int>> = assert(l)
a.contains("apple", "banana")

IMO this should result in three compile errors. Yet, it does not because the compiler falls back to type the left hand side of contains as Assert<Iterable<Any>>. Maybe we could improve the situation by using @OnlyInputTypes. This would require some trickery because it is not officially supported and might cause problems in the future (if it is removed by Jetbrains) but might be worth while nonetheless.
https://youtrack.jetbrains.com/issue/KT-13198

Artifact name in Bintray's jCenter repository

Can you please fix the artifact names on your Bintray?

Affected Version: 0.4.0 and newer

It was "atrium-api" before. But today I had to spent some time to figure
out why Gradle cannot find 'ch.tutteli:atrium-api:0.6.0' dependency

Best regards!

Thanks for the lib!

asValues for Map

@arjank is working on this one

function which switches the subject of the assertion (similar to the existing asIterable for Sequence or Array)
Simplification of:

assert(mapOf(1 to "hello"){
  AssertImpl.changeSubject(this) { subject.values() }
}

It is enough if you add it to the following (do not add it to en_UK..)

  • api-cc-en_GB-common
  • api-infix-cc-en_GB-common
  • api-cc-de_CH-common (name it also asValues)

Filter stack trace in reporting

Platform (JVM and/or JS): JVM/JS

Code related feature

Most of the times, I am not interested in the full stack trace if a test fails. We could omit the stack trace all together but that would be too much, because:

  • I want to see the stack trace if an unexpected exception occurred.
  • If one defines more than one assertion per test (which is not recommended but I guess people do it) and depending on what kind of assertions one makes it might be handy to know on which line it failed. E.g. in the following I would only see; assert: false to be true but wouldn't know which one failed.
    assert(someComplexMethodAndIamNotAwareOfReturnValueOf()).toBe(true)
    assert(anotherMethod()).toBe(true)
    
  • Having a file + line number in the output is handy since I am able to jump to the test within IntelliJ

Thus for the following

assert(1).toBe(2)

I would like to see something like the following:

assert: 1        (kotlin.Int <1165303897>)
◆ to be: 2        (kotlin.Int <887750041>)

at DummySpec$1$1.invoke(DummySpec.kt:14)

Yet, sometimes we might use own assertion functions and in such a case it is not enough to show the first stack frame which is not atrium specific. Therefore:

  • filter out atrium specific frames
  • filter out spek/junit specific frames (optional)

Currently it shows up in reporting (using Spek intelliJ Plugin) as follows:

assert: 1        (kotlin.Int <1165303897>)
◆ to be: 2        (kotlin.Int <887750041>)
java.lang.AssertionError: assert: 1        (kotlin.Int <1165303897>)
◆ to be: 2        (kotlin.Int <887750041>)
	at ch.tutteli.atrium.core.robstoll.lib.checking.ThrowingAssertionChecker.check(ThrowingAssertionChecker.kt:42)
	at ch.tutteli.atrium.creating.AssertionPlantWithCommonFields$CommonFields.check(AssertionPlantWithCommonFields.kt:71)
	at ch.tutteli.atrium.core.robstoll.lib.creating.MutableListBasedReportingAssertionPlant.checkAssertions(MutableListBasedReportingAssertionPlant.kt:21)
	at ch.tutteli.atrium.core.robstoll.lib.creating.MutableListBasedReportingAssertionPlant.addAssertion(MutableListBasedReportingAssertionPlant.kt:15)
	at ch.tutteli.atrium.api.cc.infix.en_GB.AnyAssertionsKt.toBe(anyAssertions.kt:19)
	at ThrowableStackTest$1$2.invoke(ThrowableStackTest.kt:18)
	at ThrowableStackTest$1$2.invoke(ThrowableStackTest.kt:8)
	at org.jetbrains.spek.engine.Scope$Test.execute(Scope.kt:102)
	at org.jetbrains.spek.engine.Scope$Test.execute(Scope.kt:80)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:105)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:71)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:110)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:71)
	at java.util.ArrayList.forEach(ArrayList.java:1249)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:110)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:72)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:71)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
	at org.jetbrains.spek.tooling.runner.junit.JUnitPlatformSpekRunner.run(JUnitPlatformSpekRunner.kt:107)
	at org.jetbrains.spek.tooling.MainKt.main(Main.kt:58)

In such a case I am not really interested in the stack trace. I know that I just run the test. The output should be reduced to

assert: 1        (kotlin.Int <1165303897>)
◆ to be: 2        (kotlin.Int <887750041>)

at ThrowableStackTest$1$2.invoke(ThrowableStackTest.kt:18)
at ThrowableStackTest$1$2.invoke(ThrowableStackTest.kt:8)

Running the same from gradle (also using Spek) results in:

Spek:DummySpec:it will fail on purpose
    => java.lang.AssertionError: assert: 1        (kotlin.Int <1986901753>)
◆ to be: 2        (kotlin.Int <1871689990>)
       ch.tutteli.atrium.core.robstoll.lib.checking.ThrowingAssertionChecker.check(ThrowingAssertionChecker.kt:
42)
       ch.tutteli.atrium.creating.AssertionPlantWithCommonFields$CommonFields.check(AssertionPlantWithCommonFie
lds.kt:71)
       ch.tutteli.atrium.core.robstoll.lib.creating.MutableListBasedReportingAssertionPlant.checkAssertions(Mut
ableListBasedReportingAssertionPlant.kt:21)
       ch.tutteli.atrium.core.robstoll.lib.creating.MutableListBasedReportingAssertionPlant.addAssertion(Mutabl
eListBasedReportingAssertionPlant.kt:15)
       ch.tutteli.atrium.api.cc.infix.en_GB.AnyAssertionsKt.toBe(anyAssertions.kt:19)
       DummySpec$1$2.invoke(DummySpec.kt:19)
       DummySpec$1$2.invoke(DummySpec.kt:9)
       org.jetbrains.spek.engine.Scope$Test.execute(Scope.kt:102)
       org.jetbrains.spek.engine.Scope$Test.execute(Scope.kt:80)
       org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.jav
a:105)

Also here, I don't need the stack since I have enough information from Spek (that depends on the used junit reporter I reckon but that's not Atrium's concern).

Running the test using Mocha (JS Platform)

1) ch.tutteli.atrium.core.polyfills
       DummySpec
         itWillFailOnPurpose:
     assert: 1        (Int <1>)
◆ to be: 2        (Int <2>)
      at ThrowingAssertionChecker.check_i2wsmx$ (build\node_modules\atrium-core-robstoll-lib-js.js:148:25)
      at AssertionPlantWithCommonFields$CommonFields.check_tgi7xs$ (build\node_modules\atrium-core-api-js.js:13
47:27)
      at ReportingAssertionPlantImpl.MutableListBasedReportingAssertionPlant.checkAssertions_8qzvkp$_0 (build\n
ode_modules\atrium-core-robstoll-lib-js.js:277:25)
      at ReportingAssertionPlantImpl.MutableListBasedReportingAssertionPlant.addAssertion_94orq3$ (build\node_m
odules\atrium-core-robstoll-lib-js.js:272:10)
      at toBe (build\node_modules\atrium-api-cc-infix-en_GB-js.js:95:22)
      at DummySpec.itWillFailOnPurpose (build\classes\kotlin\test\atrium-core-api-js_test.js:308:5)
      at Context.<anonymous> (build\classes\kotlin\test\atrium-core-api-js_test.js:838:34)

Same, the stack trace is not necessary (depends on the chosen reporter).

Hint if `Iterable.contains in any order only` fails due to first win

contains in any order only applies a first win strategy regarding the given identification lambdas.
A user which is not aware of this fact might struggle for a moment. The corresponding functions contain a hint in KDoc but not everybody reads KDoc (and sometimes IntelliJ has problems). Thus it would be great if the user gets an extra hint instead or rather in addition if the assertion would have hold in case the first win strategy were not applied.

This task is surely a bit more sophisticated but gives a good inside how you can write assertions which give extra hints on failing. Some hints for the implementation:

  • have a look at bigDecimalAssertions (we give hints there as well)

extend TranslatorIntSpec with Locale using a Variant

The TranslatorIntSpec does not cover the use case where a Locale has a Variant specified (for instance:
en_UK_LINUX).

I guess it is a good starting point to get a bit familiar with the i18n topic in Atrium

notToThrow

I think it makes sense to provide such a functionality in order that one can make it explicit. Moreover we can report more than usual. For instance:

  • we can report suppressed exceptions. (they are actually already included in the stacktrace which gets printed)
  • JS does not include the cause in a stacktrace (at least not the one mocha produces)

Last but not least it would be interesting to use it combined with a feature assertion (maybe for a later version)

improve infix API workaround `this` limitation in lambdas

Platform (JVM and/or JS): JMV/JS

Code related feature

Currently we can do

assert("hello robert") {
   this startsWith "hello"
   this endsWith "robert"
}

It is a bit ugly and it does not really read nicely. I think we could enhance on this one by adding a property with name o:

inline val <T: Any> Assert<T>.o get() : Assert<T> = this

And then it reads as follows:

assert("hello robert") {
   o startsWith "hello"
   o endsWith "robert"
}

which looks more like bullet points IMO

keyValue to match Map.Entry

Provide a shortcut function which matches key and value of a Map.Entry.
Make sure both (key and value) are reported if there is a mismatch

asIterable with assertionCreator block

Platform (JVM and/or JS): JVM/JS

Code related feature

assert(sequenceOf(1, 2)).asIterable {
   ...
}

Currently we can only do

assert(sequenceOf(1, 2)).asIterable().and {
   ...
}

Hence, add an overload which expects: assertionCreator: Assert<Iterable<T>>.() -> Unit

replace `property` and returnValueOf with `feature` or similar

Platform (JVM and/or JS): JVM/JS

Code related feature

setup

data class Person(val firstName: String, val lastName: String) {
    fun fullName() = "$firstName $lastName"
    fun nickname(includeLastName: Boolean) = when(includeLastName){
        false -> "Mr. $firstName"
        true -> "$firstName aka. $lastName"
    }
}
val person = Person("Robert", "Stoll")

feature as such

assert(person) {
    feature(Person::fullName).contains("treboR", "llotS")
    feature(Person::nickname, false).toBe("Robert aka. Stoll")
}

We could furthermore consider to add featureRef as alternative where one can use a bounded reference:

assert(person).featureRef { subject::firstName }.toBe("robert")
assert(person).featureRef({ subjectPerson::nickname }, false).toBe("Robert aka. Stoll")

Yet, considering the problems we still encounter due to Kotlins problems with overloads involving KFunction types, I am not sure if it is really a good idea to allow bounded reference.

Alternatively we could also go with a Pair<String, T>:

assert(person)
  .feature{ "name" to name }

But that involves quite a bit of boilerplate. On the other hand it would allow mapping over multiple levels:

assert(person)
  .feature{ "name.first()" to name.first() }

We could reduce the boilerplate for JS by using eval but eval is evil and we would loose type safety so probably not a good idea.

The good thing about map` would be that we hide the implementation detail whether firstName is actually a property or a getter. I stumble over this problematic from time to time when I deal with Java Code where Kotlin provides property syntax even for getters. But that's not the case for function references. So the following is the result which is... not so nice:

val person = Person("hello")
person.name //calling the getter via property syntax
assert(person).property(Person::name).toBe(...) //fails because it is not really a property but the method `getName`
assert(person).property(Person::getName).toBe(...) // fails as well, because it is a method not a property
assert(person).returnValueOf(Person::getName).toBe(...) // that's ok

We cannot get rid of the confusion that Person does not have a name property, but we can at least lower the confusion by providing one single method.

assert(person).feature(Person::getName)

Care has to be taken due to current bugs concerning overloading in Kotlin.

overloaded `toContain` for Set

We currently share the logic for all Iterable when it comes to toContain. However, we could provide a faster implementation for contains values because there will never be more than 1 value in a Set and thus it does not make sense to list how many occurrences we found.
The same does not apply to the overload expecting one or multiple assertionCreator (Expect<E>.() -> Unit).
Hence:

  • overload value(e: E) and values(e: E, vararg otherE: E) for Expect<T: Set<E>>
  • overload toContain(E) for Expect<T: Set<E>>

Nested feature-assertion, forbid usage of outer subject

Affected Version: 0.6.0

How to reproduce the problem

Consider the following code snippet

class Person(val firstName: String)
assert(Person("robert")) {
    property(subject::firstName) {
        property(subject::length){
            startsWith("ro")
        }
    }
}

One should not be able to call startsWith within the second property block because length is of type int whereas startsWith refers to the outer subject.

Map.contains by passing Pairs

Platform (JVM and/or JS): all

Code related feature

assert(mapOf("a to 1, "b" to 2 "c" to 3)).contains("a" to 1, "b" to 2)

Motivation see #25. I have created a different issue because I decided that keyVale should only be for Assert<Map.Entry<...>> and not directly available on Assert<Map<...>>

expect `Iterable<T: Any>` to contain `null`

Affected Version: 0.6.0

How to reproduce the problem

Consider the following code snippet

assert(listOf(1, 2)).contains.inAny.order.values(null, null)

One should not even be able to assert that a list ofInt contains null. The same problem applies to other contains assertion for Iterable

contains fun and builders for Array

So far one has to use asIterable when it comes to Array.
Add corresponding extension functions for Array<out T> which delegate to the Iterable<T> by using asIterable internally.
I think it is an easy starting point to see how Atrium supports multiple APIs.
The tasks of this issue are:

  • copy iterableAssertions.kt in atrium-api-cc-en_UK and paste it as arrayAssertions.kt
    • replace Iterable<T> with Array<out T>
    • adjust KDoc if necessary
  • repeat the same for atrium-api-cc-de_CH
  • repeat the same for atrium-api-cc-infix-en_UK

Map.contains with value assertions

Platform (JVM and/or JS): all

Code related feature

assert(mapOf("a" to 1, "b" to 2)).contains("a" to { isLessThan(2) }, "b" to { isGreaterThan(1) })

Ideally we could use Pair but that won't be possible as intended above due to this bug:
https://youtrack.jetbrains.com/issue/KT-29129

Hence, use a helper object something like KeyValue (as current workaround, we could go back to Pair later on). This would look like the following:

assert(mapOf("a" to 1, "b" to 2)).contains(KeyValue("a") { isLessThan(2) }, KeyValue("b") { isGreaterThan(1) })

shortcut for Optional.isEmpty

Platform (JVM and/or JS): JVM (only jdk8)

Code related feature

expect(Optional.empty<Int>()).isEmpty()
//instead of
expect(Optional.of(1)).feature(Optional::isEmpty()) { toBe(true) }

However in reporting we want to see

expect: Optional[1]
* is: empty

and not

expect: Optional[1]
* => isEmpty: false
    * to be: true

Following the things you need to do:

domain
-:heavy_check_mark: everything is already setup for you (see OptionalAssertions, OptionalAssertionsBuilder and OptionalAssertionsImpl)

lib

  • implement _isEmpty

api

  • ✔️ isEmpty is already added
  • add OptionalAssertionsSpec to specs-common (see PathAssertionsSpec as guideline) and extend the spec in api-fluent-en_GB-common

Your first contribution?

  • Write a comment I'll work on this if you would like to take this issue over.
    This way we get the chance to revise the description in case things have changed in the meantime,
    we might give you additional hints and we can assign the task to you, so that others do not start as well.
  • See Your first code contribution for guidelines.
  • Do not hesitate to ask questions here or to contact us via Atrium's slack channel if you need help
    (Invite yourself in case you do not have an account yet).

shortcut fun `suppressed` for Throwable::getSuppressed

Platform (JVM, JS, Android): only JVM/Android (JS does not have getSuppressed)

shortcut for

assert {
   throw IllegalArgumentException("no", NullPointerException())
}.toThrow<IllegalArgumentException> {
  returnValueOf(Throwable::getSuppressed)... // here we'd like to use `suppressed`
}

We want two versions, a val which returns Assert<Array<out Throwable>> and a fun which takes an assertionCreator lambda as argument and allows users to define sub-assertions.

It is enough if you add it to the following APIs (create a new file with name throwableJvmAssertions.kt)

  • api-cc-en_GB-jvm
  • api-infix-cc-en_GB-jvm
  • api-cc-de_CH-jvm

Have a look at 08ddbb6 to get an idea.

A few notes as it is only for JVM and not for JS:

  • you need to combine throwableJvmAssertions with throwableAssertions.kt from common (see floatingPointJvmAssertions.kt)

rename containsStrictly to containsExactly

@msmoljan is working on this one

Affected Version: <= 0.7.0

How to reproduce the problem

Consider the following code snippet

assert(listOf(1, 2)).containsStrictly(1, 2, 3)

The name containsStrictly does not really tell something. One might have a very vague guess but I think almost everyone will read the docs to know what containsStrictly does. That's suboptimal in the sense that a method which tells what it does is better. Due to a false assumption within my recollection I named it this way because I figured containsExactly in AssertJ is actually contains.inAnyOrder.only. Due to this I decided that it is better if we do not use containsExactly to lower confusion.

However, as indicated it was a false assumption. containsExactly is also contains.inOrder.only as one would expect it. Thus we can rename it without problems to containsExactly

Notice:

  • renaming has to be done in api-cc-en_GB, api-infix-cc-en_GB and api-cc-de_CH (rename enthaeltStrikt to enthaeltExakt)
  • we need to re-add containsStrictly to the JVM platform after renaming it; deprecate it with a ReplaceWith to containsExactly

PlantHasNoSubjectException in case of missing exception message

Affected Version: 0.6.0

How to reproduce the problem

Consider the following code snippet

expect {
   throw new IllegalArgumentException()
}.toThrow<IllegalArgumentException> {
   message { contains("oh no...") }
}

The problem is that creating assertions is sometimes done lazily (so that it isn't done if a previous assertion assertion fails, improves performance). However, if we collect assertions, then we have to provoke the computation otherwise we get the PlantHasNoSubjectException at a later stage which does not catch it and shows a nice error message instead.

shortcut fun `get` for Map

shortcut for

assert(mapOf(1 to "hello")).returnValueOf(Map<Int, String>::get, 2)...

It is enough if you add it to

  • api-cc-en_GB-common
  • api-infix-cc-en_GB-common
  • api-cc-de_CH-common

asKeys for Map

@arjank is working on this one

function which switches the subject of the assertion (similar to the existing asIterable for Sequence or Array)
Simplification of:

assert(mapOf(1 to "hello")) {
  AssertImpl.changeSubject(this) { subject.keySet() }
}

It is enough if you add it to the following (do not add it to en_UK..)

  • api-cc-en_GB-common
  • api-infix-cc-en_GB-common
  • api-cc-de_CH-common

infix: deprecate toBe if one passes keywords

Platform (JVM and/or JS): all

Code related feature

val collection = returnsNotACollection()
assert(collection) toBe Empty

One might not be aware of that the call of returnsNotACollectoin() does not return a collection.
The code compiles because toBe currently allows that one can compare any objects with each other.
It would be nicer if the user gets already a hint during compile time and not only at runtime.

same for notToBe Empty

containsKey for Map

@uaArsen is working on this one

shortcut for

assert(mapOf(1 to "hello")).returnValueOf(Map<Int, *>::get, 2).toBe(true)

It is enough if you add it to (don't add to UK)

  • api-cc-en_GB-common
  • api-infix-cc-en_GB-common
  • api-cc-de_CH-common -- name it enthaeltKey

contains fun and builders for Sequence

So far one has to use asIterable when it comes to Sequence.
Add corresponding extension functions for Sequence<T> which delegate to the implementation of Iterable<T> by using asIterable internally.
I think it is an easy starting point to see how Atrium supports multiple APIs.
The tasks of this issue are:

  • copy iterableAssertions.kt in atrium-api-cc-en_UK and paste it as sequenceAssertions.kt
    • replace Iterable<T> with Sequence<T>
    • adjust KDoc if necessary
  • repeat the same for atrium-api-cc-de_CH
  • repeat the same for atrium-api-cc-infix-en_UK

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.