Releases: robstoll/atrium
multiplatform project and map assertions
Jar's can be found here: https://bintray.com/robstoll/tutteli-jars/atrium/0.8.0
API Maturity: Stable
Implementation Maturity: Almost Stable
There won't be any breaking changes in the API (assertion functions/builders) until v1.0.0 besides parameter name renaming. But we want to progress as well and deprecate functionality in each version (e.g quite a lot with 0.7.0; please replace deprecated functionality until v1.0.0 where we will remove it.
However, we do not provide yet a stable API for the domain and core modules of Atrium -- it is almost stable, but there might be slight breaking changes which we want to introduce before v1.0.0. That is also the reason why we do not have yet established backward compatibility tests for domain/core. This might affect you if you write your own assertion functions. And it also affects you if you provide your own implementation for parts of Atrium.
Table of Content
New Features
API
- #27 containsExactly as replacement for containsStrictly, thanks to @msmoljan for the implementation and thanks to @christophsturm for the idea
- #33 isNotBlank for CharSequence, thanks to @pt2121 for the implementation
- #39 make atLeast optional for CharSequence.contains, thanks to @christophsturm for the idea
- #51 keys and values for Map to postulate assertions about the keys or values of a Map
- #37 asEntries for Map, thanks to @arjank for the implementation
- #29/#75 getExisting for Map to postulate assertions about the value of a corresponding key
- #28 containskey, #59 containsNotKey for Map, thanks to @uaArsen for the implementation
- #61/#62 contains for Map
- #30/#76 get for List
- #53 notToThrow as counterpart of toThrow - thanks to @charleskorn for the idea
- #65 shortcut property/fun for Pair.first and Pair.second
- #25 isKeyValue as well as shortcut property/fun key/value for Map.Entry
- #69 toBe was opened up for nullable subjects (accepts now
Any?
), thanks to @dave08 for the discussion - #70 toBeNullIfNullElse for nullable subjects, thanks to @dave08 for the idea
- #71 shortcut property/fun Collection.size
- #78 containsExactly with single assertion creator
- #48 asIterable with assertionCreator block
- #46
o
as alternative tothis
in sub-assertions for the infix API
Domain / Core
Features for assertion-function-writers:
- #67 AssertImpl.mapArguments -> to map a variable length argument lists of the form
first: T, vararg rest: T
(inside a functionT, Array<out T>
) toR, Array<out R>
- #72 changeSubject to a nullable type
- AssertImpl.feature.extractor -> in case you want to make an assertion about a feature which is not always safe to extract (e.g. List.get expects a suitable index)
- AssertImpl.collector.collectOrExplain => collects assertions for later usage but only if it is safe to collect them, otherwise it wraps them into an explanatory assertion so that it can be used to enhance reporting
- AssertImpl.collector.collectNullable which allows to collect assertions for a nullable subject (for AssertionPlantNullable instead of AssertionPlant)
Others
- turned Atrium into an multi-platform project; all dependencies are also available for:
- the JS platform => use the
-js
suffix; you will have to migrate to bundle en_GB if you still use en_UK, see Migrating deprecated functionality below. - the Android platform => use the
-android
suffix => Thansk to @ultraon for reporting #52 regarding issues with module-info.class
- the JS platform => use the
- #41 deprecated notToBeNullBut for BigDecimal
- #55 infix API - deprecated calls to
toBe
if a keyword is passed inadvertently - stacktraces in error reporting should no longer contain stack frames of Atrium or test runners
Fixes
- none this time
Improvements
- DetailedObjectFormatter shows now Kotlin types instead of Java types (e.g.
kotlin.Int
instead ofjava.lang.Integer
). - an AtriumError is now thrown instead of an AssertionError (AtriumError is a subtype of AssertionError)
Breaking Changes
Planned (previously deprecated or announced)
- none this time
Unplaned
- Made
Group
,GroupWithoutNullableEntries
andGroupWithNullableEntries
invariant. I doubt this will be a problem for someone, otherwise let me know - Made
Value
,Values
,Entry
,Entries
invariant; in case you get problems, try to use user-site variance and specifyout
there
The following breaking changes only bother you if you implemented an own core. Most have been necessary to turn Atrium into a multi-platform project: - core uses now an own implementation of
Locale
and no longer java.util.Locale - core uses now
KClass
instead ofClass
- TranslatableWithArgs takes a List instead of an Array as parameter
- Reporter needs to provide an AtriumErrorAdjuster in addition
- removed duplicate anyAssertions in package ch.tutteli.atrium.domain.creating.any.typetransformation.creators (use the one from package ch.tutteli.atrium.domain.creating)
tl;dr the following is only of interest if you rely on binary compatibility
I changed the JvmName of contains?
in cc-en_UK
and cc-infix-en_UK
to containsDeprecated
and enthaelt?
in cc-de_CH
to enthaeltDeprecated
due to the DEX compiler for android which cannot handle ?
in identifiers. This is a binary backward compatibility break for a method which I introduced in 0.7.0 to retain source backward compatibility. In case you use still use cc-en_UK or cc-infix-en_UK and rely on binary compatibility you will have to recompile when updating to 0.8.0.
Deprecation
The following was deprecated and will be removed with 1.0.0:
Assert<Iterable>.containsStrictly
usecontainsExactly
instead.- ReporterBuilder::withoutTranslations using java.util.Locale => use Atrium's Locale
- TranslatorOption::withDefaultTranslator using java.util.Locale => use Atrium's Locale
- TextAssertionFormatterOption::withDefaultTextCapabilities => use withTextCapabilities which uses KClass instead of Class
- AtriumErrorAdjusterOption::withOnlyFailureReporter and withCustomReporter => new step in configuration, use either withDefaultAtriumErrorAdjusters or choose one of the other options
- all functions containing
nullable
in their name => their counterpart withoutnullable
in their name where opened up to accept also nullable types (see #60 for details)
Possible Breaking Changes with 0.9.0
- I will prepare the transition to
Assert<T>
instead ofAssert<out T>
. I will turnAssert
into an own type (currently only a type alias) - you should not notice something but it means that the binary code will change when you compile against 0.9.0 - I might reuse opentest4j exceptions to improve error reporting in IDEs. For this to work I might have to make modifications to Assertion/AssertionGroup (would only affect core implementors).
- An exception will be thrown where one has to define an assertionCreator -- shall prevent kind of dead code/incomplete assertions; for instance
assert(mapOf("a" to 1)).keys {}
- same for
addAssertionsCreatedBy
/and {}
; they will throw an exception if no sub-assertion is defined
- same for
- toBe, contains etc. which expect
T
where<T: Any>
might be restricted to input types, so that comparing apple with oranges is no longer possible without explicitly stating the type. E.g.assert(1).toBe("hello")
would be a compile error
Possible Breaking Changes with 1.0.0
Please open an issue if you are not happy with one of the changes and state why or contact me via the Atrium slack channel.
-
Assert<Throwable>.message{}
will returnAssert<Throwable>
instead ofUnit
-
Assert<T>.isA{}
will returnAssert<T>
instead ofUnit
-
All property and returnValueOf taking an assertionCreator will return the same type as the current subject.
-
I will remove
out
ofAssert<out T>
in order that things likeasssert(1).toBe("hello")
is no longer possible, overloads can be simplified etc. -
returnValueOf functions might be renamed to returnValueOfX where X denotes the number of arguments. Too often it occurs that Kotlin is not able to infer the correct overload, the user does not get the appropriate help in code completion or the error message is too big. This should help.
-
feature assertion functions might require a lambda in the future. This way error reporting does not blow up in the middle of the way because
subject
is not available. However, there is a bug concerning nullable-features in Kotlin which prevents me from doing it at the moment: https://youtrack.jetbrains.com/issue/KT-23768, please up-vote it. -
A type parameter might be added to
AssertionGroup
to restrict theAssertionGroupType
. -
BulletPointIdentifier
together with subtypes (AssertionGroupType
s) might be moved to another package:ch.tutteli.atrium.reporting.assertions
-
AssertionPlant/Assert will switch roles => AssertionPlant will be the typealias of Assert, see #26; should only break binary compatibility
-
I will introduce interface groups for RepoterBuilder as I did in other cases (e.g. see Descriptive); should only break binary compatibility
Migrating deprecated functionality
In case you migrate from a ve...
v0.8.0-RC1
v0.8.0-RC1
v0.8.0-beta
v0.8.0-beta
v0.8.0-alpha
release 0.8.0-alpha
0.7.0 but without module-info, intended for Android
See https://github.com/robstoll/atrium/releases/tag/v0.7.0 for full information. This is a patch-fix-version for Android because the DEX compiler cannot handle ?
in identifiers and treats module-info.class as normal classes instead of ignoring it.
v0.8.0
of Atrium will support JS as additional platform and will most probably provide a specific artifact for Android as well. Simplified this means, we won't ship an atrium.jar
with 0.8.0-android
as version but atrium-android.jar
with version 0.8.0
.
Stabilisation, Deprecation.
Jar's can be found here: https://bintray.com/robstoll/tutteli-jars/atrium/0.7.0
API Maturity: Stable
Implementation Maturity: Almost Stable
There won't be any breaking changes in the API (assertion functions/builders) until v1.0.0 besides parameter name renaming. Yet, I deprecated quite a lot of with this release; please replace deprecated functionality until v1.0.0 where I will remove it.
However, I do not provide yet a stable API for the core of Atrium -- it is almost stable, but there might be slight breaking changes which I want to introduce before v1.0.0. That is also the reason why I have not yet established backward compatibility tests for the core. This might affect you if you write your own assertion functions. It also affects you if you provide your own implementation for parts of Atrium.
New Features
API
-
isEmpty
,isNotEmpty
andhasSize
forMap
-
messageContains
as shortcut function formessage { contains(...) }
. You can still usemessage { ... }
for more sophisticated assertions. For instance, if a certain string should only be contained once in the message then you can usemessage { contains.exactly(1).values(...) }
. Or in case you want to be sure that something is not contained in the messagemessage { contains(..); containsNot(...) }
. -
toBe(null)
as replacement forisNull
(isNull will be removed with 1.0.0) -
notToBeNull
as replacement forisNotNull
(isNotNull will be removed with 1.0.0) -
notToBeNullBut
as shortuct function fornotToBeNull { toBe(...) }
-
asIterable
forSequence
andArray
-
added
contains.inOrder.only.grouped.within.inAnyOrder
to the sophisticatedcontains
assertion builder forIterable
-
added overloads to
property
andreturnValueOf
which allows to use a class reference rather than a bounded reference with the advantage that it is more robust when it comes to error reporting (since it does not need to access the reference to retrieve its name => see https://youtrack.jetbrains.com/issue/KT-23777 for more information)
=> personally I still usesubject::...
when I write assertions as such (in tests) but useClass::...
inside assertion functions -
added helper functions for people dealing with Java Code. Per default platform types are turned into a non-nullable version if possible. If you want to turn it into a nullable-version nonetheless, then you have to cast and restate the type. Depending on the type this might be cumbersome. Thus I introduced the following functions which give some extra hint to the compiler without actually adding code (they are all inline functions):
nullable
turns a type into a nullable type or a function reference into a function reference with a nullable return type.nullableContainer
turns anIterable
into an iterable with nullable entry type, likewise it does the same forArray
.nullableValueMap
turns aMap
into a map with a nullable value type.
Domain / Core
Features for assertion-function-writers:
-
added function
subAssert
which is basically an identity function and shall help to circumvent different bugs in Kotlin concerning overload resolution
=> for instance, FeatureAssertionsClassReferenceSpec makes use of it. -
introduced AssertImpl as entry point for assertion-function-writers. It guides you to existing assertion function implementations as well as to the AssertionBuilder (see next point). For instance, you need a type transformation assertion, use
AssertImpl.any.typeTransformation.transform
(see TypeTransformationAssertionCreatorSpec) -
introduced AssertionBuilder which shall simplify the creation of assertions and thus the creation of assertion functions. For instance, add a failure hint with
AssertImpl.builder.descriptive.withTest(...).withFailureHint(...).create(...)
(see bigDecimalAssertions.kt) -
introduced AssertionCollector which ease to compose feature assertion functions. As example, have a look at collectionAssertions.kt
-
added AssertImpl.changeSubject which allows to transform an
Assert<T>
into anAssert<Y>
without effects on reporting.
Other
-
further stabilised the API of atrium-core
-
introduced APIs
cc-en_GB
andcc-infix-en_GB
in favour ofcc-en_UK
andcc-infix-en_UK
=> see below for migration guidelines -
introduced atrium-domain modules in favour of atrium-assertion to provide a more stable API concerning impl-functions and sophisticated assertion builders
-
turned most modules into jdk9 modules (deprecated code was placed in separate modules ending with
-deprecated
)- new modules are using ServiceLoader now instead of api-late-binding (due to JDK9 split package problematic, ServiceLoader is a bit slower but on the other hand more commonly used)
-
introduced the module
atrium-bc-test
which ensures that, specs of 0.6.0:- are binary compatible with 0.7.0 (without re-compilation) and
- can still be compiled against 0.7.0 and run successfully
=> This does not test every bits and pieces of Atrium, that is, it is only backward compatible to the extend of the tests.
=> 1.0.0 will contain major BC breaks, see below
=> Please contact me via slack if you would like to have your tests included in the bc-test (the more the merrier I suppose).
Fixed
- #21 Charsequence contains empty string ends in endless loop
Improvements
- #14
message
of a thrownException
as well as the beginning of the stack trace is now shown in case it is of a different type than the expected one (gives you some extra hint). - #15
Assert
is now annotated with a DslMarker which assures that you do not call an assertion function of an outer subject inadvertently. - #16 PlantHasNoSubjectException popped up in some cases, is fixed.
- #17 include actual size for hasSize
- #20
Iterable<T: Any>
contain assertion functions do no longer allow to passnull
. Moreover, we added overloads for nullable where missing and renamed them to ...Nullable... (e.g. nullableValue or containsStrictlyNullableValues) - #22 Iterable contains in any order values create multiple assertions instead of sub-assertions
- #23 CharSequence contains.regex should mention regex in reporting
- predefined assertion verbs are now part of the bundle, newcomers will start off easier using Atrium (Readme was revised as well).
- documented type assertions (
isA
) in Readme - documented handling of assertions for
Sequence
andArray
in FAQ of Readme - the groupId of the artifacts was changed to
ch.tutteli.atrium
=> adjust it next to the version
Breaking Changes
Planned (previously deprecated or announced)
- Was planned but I did not do it:
ReporterBuilder::withSameLineTextAssertionFormatter
was announced to be removed with 0.7.0 but will remain in the deprecatedReporterBuilder
in the deprecated module atrium-assertions and will remain there until 1.0.0. The newReporterBuilder
in module atrium-domain-builders does not include this method.
Unplaned
containsNot
checks in addition that theIterable
returns at least one element (or in other words, it fails ifIterable
returns nothing).DefaultInvisibleAssertionGroupType
was removed, useInvisibleAssertionGroupType
instead, useAssertImpl.builder.invisibleGroup
respectively.- the default implementation for
subject
was removed from interfaceBaseReportingAssertionPlant
andReportingAssertionPlantNullable
- I renamed a few parameter names so that they better reflect what an assertion function expects -> only concerns you if you used named parameters. I assume that no one uses named parameters in this context but let me know if you did because I might introduce more such breaking changes in the future.
The following changes only bother you if you do not use a bundle module but specify the dependencies manually:
- removed impl from the module names atrium-core-impl-robstoll and atrium-core-impl-robstoll-lib; => Adjust the names in such a case. E.g. depend on
atrium-core-robstoll
instead of `atrium-cor...
v0.7.0-RC2
v0.7.0-RC2
v0.7.0-RC1
v0.7.0-RC1
Floating Point Number Assertions
Jar's can be found here: https://bintray.com/robstoll/tutteli-jars/atrium/0.6.0
API Maturity: Almost Stable
Implementation Maturity: Development
I provide more or less a stable API for users of Atrium. Only the ReporterBuilder, which you use to build your own assertion verb might slightly change its API (so migrating will be just a few lines in one file).
There are most likely not any breaking changes in the API of the assertion functions/builders.
However, I do not provide yet a stable API for the core of Atrium -- this might affect you as well if you write your own assertion functions. It also affects you if you provide your own implementation of the core of Atrium.
New Features:
isNumericallyEqualTo
andisNotNumericallyEqualTo
forBigDecimal
isEqualIncludingScale
andisNotEqualIncludingScale
forBigDecimal
=> gives a hint in case of a failure where the assertion would have hold withisNumericallyEqualTo
/isNotNumericallyEqualTo
- overload of
toBe
forBigDecimal
which is deprecated, throws anUnsupportedOperationException
and points the user to the above functions - same same but different for the overload of
notToBe
forBigDecimal
toBeWithErrorTolerance
for floating point numbers (Float
,Double
,BigDecimal
)isLessThan
,isLessThanOrEquals
etc. is now available forComparable<T>
and no longer only forNumber
containsRegex(...)
as shortcut forcontains.atLeast(1).regex(...)
- integrated
contains not
into the sophisticatedcontains
assertion builder (forCharSequence
andIterable
)
=> so that you see how many times it was contained when the assertion fails - identification lambdas for
Iterable
with nullable types. For instance,listOf(null, 1).contains { toBe(1) }
was not possible so far (onlyList<Int>
was supported)- see API differences.md for examples.
- made
AssertionPairFormatter
configurable, one can now chose for instance a multi-line formatter instead of same-line (see README#your-first-assertion for an example) - workaround for a Bug in Kotlin (please upvote it) which causes that
returnValueOf
cannot be used for methods with overloads. - I generalised the
DownCaster
to aTypeTransformer
which you can reuse by using the impl-function_typeTransformation
. You find an example forEither
in TypeTransformerSpec. - I added a few issues with label help wanted so that you get an easy start to contribute to Atrium.
Breaking Changes:
- removed deprecated
ReporterBuilder::withDetailedObjectFormatter
Deprecation:
ReporterBuilder::withSameLineTextAssertionFormatter
-> use the suggested replacement
Not included in this release yet
- sophisticated assertion builder for
toBe
with error tolerance for floating point numbers - failure hint for
toBe
in conjuction with Float or Double - simplify the creation of failure hints, make it reusable for users
Infix API
Jar's can be found here: https://bintray.com/robstoll/tutteli-jars/atrium/0.5.0
API Maturity: Almost Stable
Implementation Maturity: Development
I provide more or less a stable API for users of Atrium. Only the ReporterBuilder, which you use to build your own assertion verb might slightly change its API (so migrating will be just a few lines in one file).
There are most likely not any breaking changes in the API of the assertion functions/builders.
However, I do not provide yet a stable API for the core of Atrium -- this might affect you if you write your own assertion functions. It also affects you if you provide your own implementation of the core of Atrium.
New Features:
- added an infix API including a corresponding bundle module:
atrium-cc-infix-en_UK-robstoll - one can use
Assert<T>
as entry point for assertion functions instead ofAssertionPlant<T>
. containsDefaultTranslationOf
is now also available in the sophisticated assertion builder forcontains
assertions forCharSequence
Breaking Changes:
-
it
as alias forsubject
was removed, due to legitimate confusion (see #7). In case you already use it, then
you can re-add it yourself, paste the following into your assertionVerb.kt:val <T : Any> IAssertionPlant<T>.it get() : T = subject
However, I recommend you rename it tox
or something similar to avoid the confusion thatit
is actually not an implicit lambda parameter. -
The assertion function
contains
forCharSequence
checks now that onlyCharSequence
,Number
andChar
are passed (at runtime).
I consider it as too risky (prone to bugs) if one can passAny
thing -- well compile time still requires onlyAny
; that's because Kotlin does not (yet) support union types.
IMO it is not possible to define more restrictive types (e.g. with multiple overloads) which does not hinder usability and maintanability. That's the reason why it still expectsAny
.
If someone misses the functionality that one can pass in any object, then please open a feature request. -
atrium-api-code-completion-en_UK was renamed to atrium-api-cc-en_UK, same for atrium-api-code-completion-de_CH. In case you have not used the bunde module atrium-cc-en_UK-robstoll but the API directly, then you need to modify your build.gradle
-
Interfaces are no longer prefixed with
I
with the exception ofIAtriumFactory
-
Simplified the implementation for
LocaleOrderDecider
-> special cases Norwegian and Chinese.- no_NO_NY, no_NO etc. are no longer supported (not the recommended way anyway) -> use nb_... or nn_... instead
- Locale zh_Hant without specifying the country is no longer supported (not the recommended way anyway)
- fixed problems loading properties files for Locale with script (e.g. zh_Hant_TW)
- made
ResourceBundleBasedTranslator
internal1 -- if you are usingReporterBuilder.withoutTranslation()
orReporterBuilder.withDefaultTranslator(...)
respectively, then you don't have to do anything. In case you usedResourceBundleBasedTranslator
, then use the mentioned methods instead.
1 ResourceBundleBasedTranslator
is just a reference implementation to assure that TranslationSupplierBasedTranslator
is compatibel with ResourceBundle. Since it was compatible so far, one could have used ResourceBundleBasedTranslator
instead of TranslationSupplierBasedTranslator
as well. However, because I detected that there are bugs in the implementation of ResourceBundle in JDK8 I decided that ResourceBundleBasedTranslator
should no longe be visible to users (bugs are only concerning the special cases Norwegian and Chinese but maybe there are more).
Deprecation:
ReporterBuilder::withDetailedObjectFormatter
will be removed in 0.6.0
Not included in this release yet
- overload for
Iterable<T>
contains assertions which support identification lambdas for nullable types.