robstoll / atrium Goto Github PK
View Code? Open in Web Editor NEWA multiplatform expectation library for Kotlin
Home Page: https://docs.atriumlib.org
License: European Union Public License 1.2
A multiplatform expectation library for Kotlin
Home Page: https://docs.atriumlib.org
License: European Union Public License 1.2
The original idea was to: deprecate ...Nullable overloads if subject is non-nullable
I changed the idea to deprecate it always.
For instance:
assert(listOf(1, 2)).containsNullableValue(null)
Affected Version: 0.6.0
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.
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..)
asEntries
)Platform (JVM and/or JS): JVM/JS
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.
Platform (JVM, JS and/or Android): jall
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
domain
cause
to ThrowableAssertions (see Fun0Assertions.isThrowing)api
Expect<TSub>
(see fun0Assertions.toThrow)assertionCreator
-lambda and returns Expect<TSub>
(see fun0Assertions.toThrow as well)@since 0.9.0
to both functionsother
TODO #31
and simplify the code with the shortcut funI'll work on this
if you would like to take this issue over.Any plans to support other platforms (JS, etc ...)?
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
Platform (JVM and/or JS): all
I think we should use simpler names for the bundles:
-robstoll
from the name. It suffices to mention that the standard implementation uses core-robstoll and domain-robstoll.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
shortcut for
assert("Atrium - assertion library for Kotlin").returnValueOf(CharSequence::isNotBlank).toBe(true)
It is enough if you add it to
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 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):
Platform (JVM and/or JS): JVM
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.
Platform (JVM and/or JS): JVM and JS
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.
Affected Version: 0.7.0
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 ofAssert
.
Moreover:
- make sure KDoc only mentions
Assert
and notAssertionPlant
in addition (probably also confusing > for the most)- revise README, it states somewhere that
Assert
is a type alias ofAssertionPlant
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)
Affected Version: 0.6.0
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.
Affected Version: 0.6.0
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
Affected Version: 0.6.0
Consider the following code snippet
assert("this dummy text").contains("")
We should throw an IllegalArgumentException
for an empty string
Affected Version: 0.7.0
Platform (JVM or JS): JVM (Android/Art/Dalvik)
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)
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.
The project should be compiled (assembled) at least.
Affected Version: 0.6.0
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
....
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:
Platform (JVM and/or JS): JVM/JS
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.
Platform (JVM and/or JS): JVM/JS
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
Platform (JVM and/or JS): all
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):
Platform (JVM and/or JS): all
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
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!
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..)
asValues
)Platform (JVM and/or JS): JVM/JS
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:
assert: false to be true
but wouldn't know which one failed.
assert(someComplexMethodAndIamNotAwareOfReturnValueOf()).toBe(true)
assert(anotherMethod()).toBe(true)
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:
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).
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:
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
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:
Last but not least it would be interesting to use it combined with a feature assertion (maybe for a later version)
Platform (JVM and/or JS): JMV/JS
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
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
Platform (JVM and/or JS): JVM/JS
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
Platform (JVM and/or JS): JVM/JS
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.
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:
value(e: E)
and values(e: E, vararg otherE: E)
for Expect<T: Set<E>>
toContain(E)
for Expect<T: Set<E>>
Affected Version: 0.6.0
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
.
Platform (JVM and/or JS): all
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<...>>
Affected Version: 0.6.0
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
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:
iterableAssertions.kt
in atrium-api-cc-en_UK and paste it as arrayAssertions.kt
Iterable<T>
with Array<out T>
Platform (JVM and/or JS): all
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) })
Platform (JVM and/or JS): JVM (only jdk8)
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
api
I'll work on this
if you would like to take this issue over.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)
Have a look at 08ddbb6 to get an idea.
A few notes as it is only for JVM and not for JS:
Affected Version: <= 0.7.0
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:
containsStrictly
to the JVM platform after renaming it; deprecate it with a ReplaceWith to containsExactlyAffected Version: 0.6.0
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 for
assert(mapOf(1 to "hello")).returnValueOf(Map<Int, String>::get, 2)...
It is enough if you add it to
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..)
I think for better adoption, just create an atrium
channel in kotlinlang.slack.com
.
Platform (JVM and/or JS): all
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
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)
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:
iterableAssertions.kt
in atrium-api-cc-en_UK and paste it as sequenceAssertions.kt
Iterable<T>
with Sequence<T>
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.