Changelog History
Page 1
-
v0.14.0 Changes
November 14, 2020Table of Content
- New Features
- π Fixes
- Improvements
- Breaking Changes
- π Deprecation
- π Migrating deprecated functionality
- Sponsors
π New Features
All APIs
- #461 Sequence.asList => thanks to @Valefant for the implementation
- #462 Iterable.asList => thanks to @Valefant for the implementation
- #172 Iterable.containsNoDuplicates => thanks to @frikit for the implementation
- #480 accept date as string in ISO 8601 format for ChronoLocalDate => thanks to @Valefant for implementation
- #482 accept date and time as string in ISO 8601 for ChronoZonedDateTime => thanks to @Valefant for implementation
- #591 Path.isExecutable => thanks to @jGleitz for the implementation
- #629 Path.isAbsolute => thanks to @jakubriegel for the implementation
- #630 Path.isRelative => thanks to @jakubriegel for the implementation
- #590 Path.hasDirectoryEntry => thanks to @jgrgt for the first implementation (api-fluent) and @jGleitz for the completion (generalise to logic and add to infix)
api-fluent-en_GB
- no fluent only additions this time
api-infx-en_GB
- no infix only additions this time
Domain / Core
- π we transition away from atrium-domain-... to atrium-logic, getting rid of ServiceLoader and other changes. Some parts of domain were already deprecated (see below)
π Fixes
- #631 Atrium stops working for JS with Kotlin 1.4 => thanks to @chadmarchand for the fix
π Improvements
- #628 Report Evaluation Result After notToThrow(), catch exceptions in feature extraction
- #329 fuse FeatureAssertionSpec with AssertionSpec => thanks to @tarczynskitomek for the first few adjustments
- β‘οΈ #349 configure dependabot to update samples => thanks to @uzilan for the implementation
- π #400 check if Js isIntance bug is really fixed in Kotlin => thanks to @Valefant for the time and simplification
- #409 limit representation to 10'000 chars => thanks to @Valefant for the implementation
- #600 make generateLogic more readable with named matches => thanks to @jgrgt for the suggestion and implementation
- β‘οΈ #637 update gradle wrapper => thanks to @fejd
- β‘οΈ #473 update js samples to use the new org.jetbrains.kotlin.js gradle plugin => thanks to @chadmarchand for most of the work
- #643 add samples for anyAssertions => thanks to @jdornieden
- #644 add samples for arrayAssertions => thanks to @jdornieden
- #646 add samples for collectionAssertions => thanks to @Gosunet
- #647 add samples for comparableAssertions => thanks to @Gosunet
- #649 add samples for floatingPointAssertions => thanks to @BimuratMukhtar
- #652 add samples for iteratorAssertions => thanks to @Gosunet
- #653 add samples for listAssertions => thanks to @BimuratMukhtar
- #656 add samples for pairAssertions => thanks to @BimuratMukhtar
π₯ Breaking Changes
Planned (previously deprecated or announced)
- π we are no longer using the builders defined in the API for CharSequence/Iterable.contains but the new ones from atrium-logic. This constitutes a binary backward compatibility break. Please re-compile, it is still source compatible.
Unplanned
- π we are no longer using the builders defined in atrium-domain-builders for a subject change and feature extraction but the once from atrium-logic. This constitutes a binary backward compatibility break. Please re-compile, it is still source compatible.
π Deprecation
- π± the helper function
asExpect
to turn anAssert<T>
into anExpect<T>
=> time to move on π - π most of the module atrium-domain-builders -> use atrium-logic instead, see migration hints further down below. Inter alia:
- SubjectChanger and SubjectChangerBuilder
- FeatureExtractor and FeatureExtractorBuilder
- toVarArg, iterableLikeToIterable
- nullable, nullableContainer, nullableKeyMap etc.
- mapArguments
π₯ Breaking Changes with 0.15.0
- π might be we have to break compatibility when we deprecate core-robstoll and core-robstoll-lib
- π might also be, that we have to break compatibility when we move ExpectBuilder and ExpectOptions from domain-builders to atrium-logic
- π we will break binary compatibility when we move Group from atrium-domain-builders to atrium-logic (or to the individual APIs)
- π we will break binary compatibility when we move VarArgHelper from atrium-domain-builders to atrium-logic
π₯ Breaking Changes with 1.0.0
π See atrium-roadmap -> Milestone 1.0.0
π Migrating deprecated functionality
We don't provide
ReplaceWith
to transition from atrium-domain-robstoll/-robstoll-lib to atrium-logic in all cases. We don't expect that there are enough users using types of those modules directly. Let us know if you do and have troubles migrating.In case you should use:
- π
mapArguments
, then search forimport ch.tutteli.atrium.domain.builders.utils.mapArguments
and replace it withimport ch.tutteli.atrium.logic.utils.mapArguments
- π
nullable
, then search forimport ch.tutteli.atrium.domain.builders.utils.nullable
and replace withimport ch.tutteli.atrium.logic.utils.nullable
- π
subExpect
, then search forsubExpect
and replace withexpectLambda
and search forimport ch.tutteli.atrium.domain.builders.utils.subExpect
and replace withimport ch.tutteli.atrium.logic.utils.expectLambda
Some further search&replace patterns for assertion writers, in case you use:
CharSequenceOrNumberOrChar
orCharSequenceOrNumberOrChar
, search forimport ch.tutteli.atrium.domain.creating.typeutils
and replace withimport ch.tutteli.atrium.logic.creating.typeutils
In case you already started using the experimental atrium-logic module, then you might run into the problem that:
getExpectOfFeature()
does not exist => replace with transform()addToInitial
does not exist => replace withcollectAndAppend
- π we removed
genericSubjectBasedFeature
andgenericFeature
from FeatureAssertions -> use either manualFeature or FeatureExtractor/FeatureExtractorBuilder instead
π Please have a look at the older release-notes in case you don't migrate from 0.12.0 or 0.13.0
Sponsors
π We would like to thank Tegonal GmbH for sponsoring Support and PR-Review time.
Are you are using Atrium at work?
π Please consider to support the project as well by:
- sponsoring robstoll (Author and main contributor)
- share your assertion functions with others
- report bugs
- provide feedback in case you miss a feature
-
v0.14.0.RC1
October 30, 2020 -
v0.13.0
August 26, 2020 -
v0.12.0 Changes
May 26, 2020API 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 and experimental features. 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
- π Fixes
- Improvments
- Breaking Changes
- π Deprecation
- π Migrating deprecated functionality
π New Features
api-fluent-en_GB
π new api-infix-en_GB
Thanks to the following contributors to support the migration from cc-infix-en_GB to infix-en_GB:
- #227 collectionAssertions => thanks to @ratkayandras
- #231 pairAssertions => thanks to @dexpota
- #228 listAssertions => thanks to @sanatik
- #232 sequenceAssertions => thanks to @ivanmiklec
- #229 mapAssertions => thanks to @jlundhol
- #230 mapEntryAssertions => thanks to @johnGachihi
- #226 arrayAssertions => thanks to @isfedorov
- #233 bigDecimalAssertions => thanks to @isfedorov
- #236 create bundles for the new infix API => thanks to @isfedorov
- #316 fileAssertions => thanks to @jGleitz
- #317 localDateAssertions => thanks to @jGleitz
- #318 localDateTimeAssertions => thanks to @jGleitz
- #319 zonedDateTimeAssertions=> thanks to @tfesenko
- #313 chronoLocalDateAssertions => thanks to @ivanmiklec
- #314 chronoLocalDateTimeAssertions => thanks to @isfedorov
- #315 chronoZonedDateTimeAssertions => thanks to @tfesenko
- #388 optionalAssertions => thanks to @isfedorov
kotlin 1.3 extensions
- #389 resultAssertions => thanks to @ivanmiklec
Domain / Core
- none this time
π Fixes
- none this time
π Improvements
- π #235 setup code coverage for windows=> thanks to @ivanmiklec
- π #245 Build samples as composite build => thanks to @assaflei
#/167 compile android class files into dex bytecode => thanks to @assaflei - π #493 merge jdk8 extension into jvm module => thanks to @assaflei
- #470 create maven sample project => thanks to @binkley
- #466 fail if a TranslatableWithArgs has not exact arguments => thanks to @tkech17
- #495 cache gradle and dependencies in github actions => thanks to @assaflei
- π #506 remove android jars -> they are no longer required => thanks to @ultraon for checking if the module-info.class bug was really resolved in d8
π₯ Breaking Changes
Planned (previously deprecated or announced)
- none this time (yet we no longer publish a dedicated
-android
jar you can use the regular jvm artifact instead)
Unplanned
- none this time
π Deprecation
π The following was deprecated and will be removed with 1.0.0:
- API cc-infix-en_GB => use infix-en_GB, fluent-en_GB respectively => a big thank you to @Miftahunajat for the many ReplaceWith he placed all over api-cc-infix to ease the migration π
- the jdk8 extension was merged into the normal module => search
import ch.tutteli.atrium.api.fluent.en_GB.jdk8
replace withimport ch.tutteli.atrium.api.fluent.en_GB
π₯ Breaking Changes with 1.0.0
π See atrium-roadmap -> Milestone 1.0.0
π Migrating deprecated functionality
API fluent
β‘οΈ There aren't any deprecations in api-fluent-en_GB in this version and thus also no migration required if you update from 0.9.x, 0.10.0 or 0.11.0
π In case you used the jdk8 extension: it was merged into the main artifact:
- perform a search for
import ch.tutteli.atrium.api.fluent.en_GB.jdk8
and replace withimport ch.tutteli.atrium.api.fluent.en_GB
- β remove the corresponding dependency
API infix
You should migrate from api-cc-infix-en_GB to the new api-infix-en_GB (api-cc-infix-en_GB will be removed with 1.0.0)
π In case you migrate from a version < 0.7.0 to this version, then please have a look at the migration guide given in the Release notes of v0.7.0 and v0.8.0 first.Otherwise you can use the suggested replacements (ALT + Enter -> Replace with ...) or the search/replace patterns shown below (recommended, since faster).
Notice, that you don't have to migrate everything at once where
asExpect
andasAssert
allow to switch between the oldAssert
and the newExpect
world.
Ping us in the Atrium slack channel if you need help.The following command is carrying out the points 1 to 14 as described below. The script for 15a or 15b follows afterwards (don't forget to do the manual points 16, 17, ...), run it from the root of your project, no guarantees that your system is capable of carrying it out. If not, you can use the manual steps described below.
find ./ -path "*/test/*" -name "*.kt" | xargs perl -0777 -i \ -pe 's/AssertImpl([\n\r\s]*)\.changeSubject\(([^\)\n]+)\)[\n\r\s]*\{[\n\r\s]*subject/ExpectImpl$1.changeSubject\($2\)$1.unreported \{ it/g;' \ -pe 's/AssertImpl([\n\r\s]*)\.changeSubject\(([^\)]+)\)/ExpectImpl$1.changeSubject\($2\).unreported/g;' \ -pe 's/AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.createDescriptive\(([^,\n]+,[^\)]+\)[\n\r\s]*\{[\n\r\s]*)plant.subject/AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.createDescriptive\(([^,\n]+,[^\)]+\)[\n\r\s]*\{[\n\r\s]*)plant.subject/g;' \ -pe 's/AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.descriptive([\n\r\s]*).withTest(\(?[\n\r\s]*)\{([\n\r\s]*)plant.subject/AssertImpl$1.builder$2.descriptive$3.withTest\(plant\)$4\{$5it/g;' \ -pe 's/AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.descriptive([\n\r\s]*).withTest(\(?[\n\r\s]*)\{([\n\r\s]*)subject/AssertImpl$1.builder$2.descriptive$3.withTest\(this\)$4\{$5it/g;' \ -pe 's/(\.| )((?:toThrow|isA)<.*>)\s*\{\s*\}/$1$2()/g;' \ -pe 's/notToBeNull\s*\{\s*\}/notToBe null/g;' \ -pe 's/fun <T\s*:\s*Any> ([^\(]+)\(subject:\s*T\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlant\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[\n\r\s]*reporter\)/fun <T> $1\(subject: T\): Expect<T> = \n ExpectBuilder.forSubject\(subject\)\n .withVerb\($2\)\n .withoutOptions\(\)\n .build\(\)/g;' \ -pe 's/fun <T\s*:\s*Any> ([^\(]+)\(subject:\s*T\s*,[\n\r\s]*assertionCreator: Assert<T>.\(\)\s*->\s*Unit\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlantAndAddAssertionsCreatedBy\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[\n\r\s]*reporter,[\n\r\s]*assertionCreator\)/fun <T> $1\(subject: T, assertionCreator: Expect<T>.\(\) -> Unit\): Expect<T> = \n $1(subject).addAssertionsCreatedBy(assertionCreator)/g;' \ -pe 's/(?:internal )?fun <T(?:\s*:\s*Any\?)?> ([^\(]+)\(subject:\s*T\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlantNullable\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[^\)]+\)//g;' \ -pe 's/import ch.tutteli.atrium.verbs\.(expect|assert|assertThat)/import ch.tutteli.atrium.api.verbs.$1/g;' \ -pe 's/AssertImpl/ExpectImpl/g;' \ -pe 's/fun Assert(?:ionPlant(?:Nullable)?)?<(.*)>\./fun <T: $1> Expect<T>\./g;' \ -pe 's/Assert(ionPlant(Nullable)?)?</Expect</g;' \ -pe 's/import ch\.tutteli\.atrium\.creating\.Assert(ionPlant(Nullable)?)?/import ch.tutteli.atrium.creating.Expect/g;' \ -pe 's/import ch.tutteli\.atrium\.api\.cc\.infix\.en_GB/import ch.tutteli.atrium.api.infix.en_GB/g;' \ -pe 's/is(Less|Greater)OrEquals/is$1ThanOrEqual/g;' \ -pe 's/\.asIterable\(\)/ asList o/g;' \ -pe 's/asIterable(\s*\{)/asList$1/g;' \ -pe 's/\.asEntries\(\)/ asEntries o/g;' \ -pe 's/ o / it /g;' \ -pe 's/get\s*Index\(([^\)]+)\)\s*assertIt\s*\{([^\}]+)\}/get index($1) {$2}/g;' \ -pe 's/import ch.tutteli.atrium.api.infix.en_GB.Index/import ch.tutteli.atrium.api.infix.en_GB.index/g;' \ -pe 's/getExisting\s*Key\(([^\)]+)\)\s*assertIt\s*\{([^\}]+)\}/getExisting key($1) {$2}/g;' \ -pe 's/import ch.tutteli.atrium.api.infix.en_GB.Key/import ch.tutteli.atrium.api.infix.en_GB.key/g;'
In case you use Kotlin 1.4 or have enabled the new type inference, then you can use the following script to carry out point 13a:
find ./ -path "*/test/*" -name "*.kt" | xargs perl -0777 -i \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)/$1its feature of(\{ f(it::$2) \})$3/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)/feature of(\{ f(it::$1) \})$2/g;' \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)/$1its feature \{ f(it::$2) \}/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)/feature \{ f(it::$1) \}/g;' \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)(\s*\{)/$1its feature of($2::$3)$4/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)(\s*\{)/feature of($1::$2)$3/g;' \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\),]+)\)/$1 its feature($2::$3)/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\),]+)\)/feature($1::$2)/g;' \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)/$1its feature of($2::$3)/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)/feature of($1::$2)/g;' \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([^:]+)::([^\)]+)\)/$1its feature of("$2.$3") { $2.$3 }/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\(([^:]+)::([^\)]+)\)/feature("$1.$2", { $1.$2 })/g;' \ -pe 's/(import ch\.tutteli\.atrium\.api\.cc\.(?:\.infix)?(?:en_GB|de_CH))\.(property|returnValueOf)/$1.feature/g;' \
Otherwise you need to carry out the point 13b which can be done with the following script`
find ./ -path "*/test/*" -name "*.kt" | xargs perl -0777 -i \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)/$1its feature \{ f(it::$2) \} it$3/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)/feature \{ f(it::$1) \} it$2/g;' \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)/$1its feature \{ f(it::$2) \}/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)/feature \{ f(it::$1) \}/g;' \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)(\s*\{)/$1its feature of($2::$3)$4/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)(\s*\{)/feature of($1::$2)$3/g;' \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\),]+)\)/$1 its feature($2::$3)/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\),]+)\)/feature($1::$2)/g;' \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)/$1its feature of($2::$3)/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)/feature of($1::$2)/g;' \ -pe 's/((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([^:]+)::([^\)]+)\)/$1its feature of("$2.$3") { $2.$3 }/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\(([^:]+)::([^\)]+)\)/feature("$1.$2", { $1.$2 })/g;' \ -pe 's/(import ch\.tutteli\.atrium\.api\.cc\.(?:\.infix)?(?:en_GB|de_CH))\.(property|returnValueOf)/$1.feature/g;'
βͺ But you still need to add manually
import ch.tutteli.atrium.api.infix.en_GB.workaround.it
whereit
is not known
In case you cannot carry out the commands above, then read on to perform the manual steps:
The following list helps you to migrate faster by using a few regex search replace commands (in Intellij). Make sure you have checked
Regex
as well asMatch Case
in the search options. Notice, that the code will certainly not compile after a single replace, you need to carry out all search&replace commands.
It is not perfect, maybe you need to do a few adjustments in addition, let us now and we improve the search/replace commands here.Switch to ExpectImpl.changeSubject instead of using AssertImpl.changeSubject:
Search:AssertImpl([\n\r\s]*)\.changeSubject\(([^\)\n]+)\)[\n\r\s]*\{[\n\r\s]*subject
Replace:ExpectImpl$1.changeSubject\($2\)$1.unreported { it
Search:
AssertImpl([\n\r\s]*)\.changeSubject\(([^\)]+)\)
Replace:ExpectImpl$1.changeSubject\($2\).unreported
π builder.descriptive, safe withTest
π Search:
AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.createDescriptive\(([^,\n]+,[^\)]+\)[\n\r\s]*\{[\n\r\s]*)plant.subject
π Replace:AssertImpl$1.builder$2.createDescriptive\(plant, $3it
π Search:
AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.descriptive([\n\r\s]*).withTest(\(?[\n\r\s]*)\{([\n\r\s]*)plant.subject
π Replace:AssertImpl$1.builder$2.descriptive$3.withTest\(plant\)$4{$5it
π Search:
AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.descriptive([\n\r\s]*).withTest(\(?[\n\r\s]*)\{([\n\r\s]*)subject
π Replace:AssertImpl$1.builder$2.descriptive$3.withTest\(this\)$4{$5it
toThrow and isA with empty assertionCreator lambda
Search:(\.| )((?:toThrow|wirft|isA|istEin)<.*>)\s*\{\s*\}
Replace$1$2()
notToBeNull with empty assertionCreator lambda
Search:notToBeNull\s*\{\s*\}
Replace:notToBe null
migrate custom assertion verbs:
Search:
fun <T\s*:\s*Any> ([^\(]+)\(subject:\s*T\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlant\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[\n\r\s]*reporter\)
Replace:
πfun <T> $1\(subject: T\): Expect<T> = \n ExpectBuilder.forSubject\(subject\)\n .withVerb\($2\)\n .withoutOptions\(\)\n .build\(\)
Search:
fun <T\s*:\s*Any> ([^\(]+)\(subject:\s*T\s*,[\n\r\s]*assertionCreator: Assert<T>.\(\)\s*->\s*Unit\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlantAndAddAssertionsCreatedBy\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[\n\r\s]*reporter,[\n\r\s]*assertionCreator\)
Replace:
fun <T> $1\(subject: T, assertionCreator: Expect<T>.\(\) -> Unit\): Expect<T> = \n $1(subject).addAssertionsCreatedBy(assertionCreator)
Search:
(?:internal )?fun <T(?:\s*:\s*Any\?)?> ([^\(]+)\(subject:\s*T\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlantNullable\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[^\)]+\)
Replace:(empty string)
In case the above search&replace did not find anything (because your code is different):
π¨ Switch fromAssertImpl.coreFactory.newReportingPlant
toExpectBuilder
π => see atriumVerbs.kt for an example of how own assertion verbs are defined now; or use the suggested replacements but please addimport ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
first as it will not work correctly otherwise due to an Intellij bug
=> Note that you don't need a verb for nullable types any more. Thus:- remove the upper bound
T: Any
- remove the verb which uses `newReportingPlantNullable
- remove the verb which expected
act: () -> Unit
Switch to new built-in assertion verbs which use Expect
Search: import ch.tutteli.atrium.verbs.(expect|assert|assertThat)
Replace: import ch.tutteli.atrium.api.verbs.$1Switch from AssertImpl to ExpectImpl
Search:
AssertImpl
Replace:ExpectImpl
Switch all your assertion functions to use Expect and no longer Assert:
Search:
import ch\.tutteli\.atrium\.creating\.Assert(ionPlant(Nullable)?)?
Replace:import ch.tutteli.atrium.creating.Expect
Search:
fun Assert(?:ionPlant(?:Nullable)?)?<(.*)>\.
Replace:fun <T: $1> Expect<T>\.
Search:
Assert(ionPlant(Nullable)?)?<
Replace:Expect<
Switch the API
Search:
import ch.tutteli\.atrium\.api\.cc\.infix\.en_GB Replace:
import ch.tutteli.atrium.api.infix`isLessOr/isGreaterOrEquals
Search:
is(Less|Greater)OrEquals
Replace:is$1ThanOrEqual
11 use asList instead of asIterable and replace
asEntries()
Search:
\.asIterable\(\)
Replace:asList o
Search:
asIterable(\s*\{)
Replace:asList$1
Search:
asEntries\(\)
Replace:asEntries o
12 List get Index assertIt
This one has to be done with care as there could be nested assertion group blocksSearch:
get\s*Index\(([^\)]+)\)\s*assertIt\s*\{([^\}]+)\}
Replace:get index($1) {$2}
Search:
import ch.tutteli.atrium.api.infix.en_GB.Index
Replace:import ch.tutteli.atrium.api.infix.en_GB.index
13 Map getExisting Key assertIt
This one has to be done with care as there could be nested assertion group blocksSearch:
getExisting\s*Key\(([^\)]+)\)\s*assertIt\s*\{([^\}]+)\}
Replace:getExisting key($1) {$2}
Search:
import ch.tutteli.atrium.api.infix.en_GB.Key
Replace:import ch.tutteli.atrium.api.infix.en_GB.key
14 use
it
instead ofo
inside assertion groups:
Search:o
Replace:it
(you can also replace byits
)15a. use new feature mechanism - replacements for Kotlin 1.4 or the new inference (skip to 13b in case you use Kotlin < 1.4)
This one needs extra care as arguments could be function calls. Verify the replacements
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)
Replace:$1its feature of(\{ f(it::$2) \})$3
Search:
(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)
Replace:feature of(\{ f(it::$1) \})$2
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)
Replace:$1its feature \{ f(it::$2) \}
Search:
(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)
Replace:feature \{ f(it::$1) \}
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)(\s*\{)
Replace:$1its feature of($2::$3)$4
Search:
(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)(\s*\{)
Replace:feature of($1::$2)$3
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\),]+)\)
Replace:$1 its feature($2::$3)
Search:
(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\),]+)\)
Replace:feature($1::$2)
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)
Replace:$1its feature of($2::$3)
Search:
(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)
Replace:feature of($1::$2)
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([^:]+)::([^\)]+)\)
Replace:$1its feature of("$2.$3") { $2.$3 }
Search:
(?:property|returnValueOf|rueckgabewertVon)\(([^:]+)::([^\)]+)\)
Replace:feature("$1.$2", { $1.$2 })
Search:
(import ch\.tutteli\.atrium\.api\.cc\.(?:\.infix)?(?:en_GB|de_CH))\.(property|returnValueOf)
Replace:$1.feature
15b use new feature mechanism - replacements for Kotlin < 1.4 (skip if you already applied 11a)
This one needs extra care as arguments could be function calls. Verify the replacements
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)
β addimport ch.tutteli.atrium.api.infix.en_GB.workaround.it
to those filesSearch again for:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)
Replace:$1its feature \{ f(it::$2) \} it$3
Search:
(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)
Replace:feature \{ f(it::$1) \} it$2
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)
Replace:$1its feature \{ f(it::$2) \}
Search:
(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)
Replace:feature \{ f(it::$1) \}
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)(\s*\{)
Replace:$1its feature of($2::$3)$4
Search:
(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)(\s*\{)
Replace:feature of($1::$2)$3
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\),]+)\)
Replace:$1 its feature($2::$3)
Search:
(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\),]+)\)
Replace:feature($1::$2)
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)
Replace:$1its feature of($2::$3)
Search:
(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)
Replace:feature of($1::$2)
Search:
((?:[\n\r]+|\{)\s*)(?:property|returnValueOf|rueckgabewertVon)\(([^:]+)::([^\)]+)\)
Replace:$1its feature of("$2.$3") { $2.$3 }
Search:
(?:property|returnValueOf|rueckgabewertVon)\(([^:]+)::([^\)]+)\)
Replace:feature("$1.$2", { $1.$2 })
Search:
(import ch\.tutteli\.atrium\.api\.cc\.(?:\.infix)?(?:en_GB|de_CH))\.(property|returnValueOf)
Replace:$1.feature
βͺ But you still need to add manually
import ch.tutteli.atrium.api.infix.en_GB.workaround.it
whereit
is not known16 In case you have custom assertion verbs
Dealing with thrown exceptions is now handled byExpect
as well.
π» However, in case you have named the assertion verb differently for expecting an Exception then you have to decide:- π use the same name => rename the corresponding function which expects
act: () -> Unit
to the same name and remove it afterwards - π use a different name => delegate the function which expects
act: () -> Unit
to the other verb
π Check if you need to add
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
Try to reduce duplicated Expect imports
Repeat until you don't have duplicate imports any more
Search:import ch\.tutteli\.atrium\.creating\.Expect\n\s*import ch\.tutteli\.atrium\.creating\.Expect
Replace:import ch.tutteli.atrium.creating.Expect
β Try to compile your project and watch out for the following warnings:
'MyClass' is a final type, and thus a value of the type parameter is predetermined
=> you can suppress this warning by adding@file:Suppress("FINAL_UPPER_BOUND")
to your file, this is actually a Kotlin bug (https://youtrack.jetbrains.com/issue/KT-34257)
-
v0.11.1 Changes
April 30, 2020π See #485 for more details. All other features introduce in v0.11.0 are shown in release notes of v0.11.0
-
v0.11.0 Changes
April 19, 2020API 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 and experimental features. But we want to progress as well and deprecate functionality in each version (e.g quite a lot with 0.7.0 and with 0.9.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
- π Fixes
- Improvements
- Breaking Changes
- π Deprecation
- π Migrating deprecated functionality
π New Features
API fluent-en_GB
- #131 shortcut Iterable.containsExactlyElementsOf => thanks to @tkech17
- #425 shortcut Iterable.containsElementsOf => thanks to @tkech17
- #422 add elementsOf to contains.ignoreCase => thanks to @Miftahunajat
Domain / Core
- none this time
π Fixes
- none this time
π Improvements
- #339 Avoid Duplicated Messages
- #116 Migrate Spek1 specs to Spek2 => thanks to @assaflei
- π #416 move non-jvm specific specs to common => thanks to @assaflei
π₯ Breaking Changes
Planned (previously deprecated or announced)
- none this time
Unplanned
- none this time
π Deprecation
- none this time
π₯ Breaking Changes with 1.0.0
π See atrium-roadmap -> Milestone 1.0.0
π Migrating deprecated functionality
β‘οΈ There aren't any deprecations in this version and thus also no migration required if you update from 0.9.x or 0.10.0.
π In case you migrate from 0.8.0 to this version, have a look at the migration guide given in the release notes of v0.9.0
-
v0.10.0 Changes
March 12, 2020API 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 and experimental features. 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
- π Fixes
- Improvements
- Breaking Changes
- π Deprecation
- π Migrating deprecated functionality
π New Features
API fluent-en_GB
jdk8 extensions
Domain / Core
- none this time
π Fixes
- none this time
π Improvements
- component diagram by @tfesenko in CONTRIBUTING.md
π₯ Breaking Changes
Planned (previously deprecated or announced)
- none this time
Unplanned
- none this time
π Deprecation
- none this time
π₯ Breaking Changes with 1.0.0
π See atrium-roadmap -> Milestone 1.0.0
π Migrating deprecated functionality
β‘οΈ There aren't any deprecations in this version and thus also no migration required if you update from 0.9.0.
π In case you migrate from 0.8.0 to this version, have a look at the migration guide given in the release notes of v0.9.0
-
v0.9.2 Changes
February 08, 2020π Fixes
π it was planned that
withOptions
ships with 0.9.0 (see #153). However, this was done only for the assertion verb which is used internally in Atrium but was not revealed for the predefined assertion verbs, hence this patch-version (thanks to @matejdro for the report - #362)Most users won't use
withOptions
and thus we are going to present onlywithRepresentation
for now (introduced in 0.9.2 #365).
ββNote though thatwithOptions
andwithRepresentation
are both experimental and might be changed in a future version without previous notice nor migration path.withRepresentation
can be used as follows :expect(listOf(1,2,2,3 /* imagine a lot more numbers */)) .withRepresentation("xy numbers") .all { isLessThan(10) }
The error report looks then as follows in case of a failure:
expected that subject: xy numbers ββall entries: Β» is less than: 10 (kotlin.Int <1234789>) ββ following entries were mismatched: β¬ index 101: 12 (kotlin.Int <8933389>) β¬ index 223: 10 (kotlin.Int <4523459>)
π To use it, you have to add the following annotation to your test method/class
@UseExperimental(ExperimentalWithOptions::class)
Further Improvements
π all other features as well a migration guide is given in the release notes of v0.9.0
-
v0.9.1 Changes
February 04, 2020π all other features as well a migration guide is given in the release notes of v0.9.0
-
v0.9.0 Changes
February 02, 2020API 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 and experimental features. 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
- π Fixes
- Improvments
- Breaking Changes
- π Deprecation
- π Migrating deprecated functionality
π New Features
π new API fluent-en_GB
- #26 Introduced
Expect<T>
as replacement forAssert<out T>
=> things likeexpect(1).toBe("not an int")
result now in a compile error - #66 allow to pass single Char to starts(Not)With/ends(Not)With => thanks to @kssc0112 for the implementation
- #128 Iterable.contains.inOrder.only.elementsOf => thanks to @npswedberg for the implementation
- #129 Iterable.contains.inAnyOrder.elementsOf => thanks to @sanatik for the implementation
- #127 Iterable.contains.inAnyOrder.only.elementsOf => thanks to @johnGachihi for the implementation
- #158 Iterable.hasNext/hasNotNext => thanks to @sanatik for the implementation
- #163 shortcut for Iterable.min() => thanks to @piyushmor for the implementation
- #163 shortcut for Iterable.min() => thanks to @Megamiun for the implementation
- #130 CharSequence.contains.elementsOf => thanks to @mattyway for the implementation
- #165 CharSequence.matches => thanks to @mikemolenda for the implementation
- #165 CharSequence.mismatches => thanks to @shardulsonar for the implementation
- #183 Array.asList => thanks to @piraces for the implementaiton
jdk8 extensions
- #108 Path.exists and Path.existsNot with excellent failure hints => big thanks to @jGleitz for the implementation
- #111 shortcut for Paht.isDirectory and Paht.isRegularFile => thanks to @jGleitz for the implementation
- #112 shortcut for Paht.isReadable and Paht.isWritable => thanks to @jGleitz for the implementation
- #187 Path.startsWith => thanks to @arjank for the implementation
- #189 Path.startsNotWith => thanks to @arjank for the implementation
- #188 Path.endsWith => thanks to @gaconkzk for the implementation
- #190 Path.endsNotWith => thanks to @segunfamisa for the implementation
- #109 shortcut for Path.fileName => thanks to @Tregz for the implementation
- #110 shortcut for Path.getParent => thanks to @lpicanco for the implementation
- #169 shortcut for Path.extension => thanks to @lelloman for the implementation
- #170 shortcut for Path.fileNameWithoutExtension => thanks to @aljacinto for the implementation
- #166 File.asPath => thanks to @lelloman for the implementation
- #261 LocalDate(Time) and ZonedDatetime.isBefore => thanks to @sandjelkovic for the start and @name213 for the finishing
- #261 LocalDate(Time) and ZonedDatetime.isBeforeOrEqual => thanks to @name213 for the implementation
- #175 LocalDate(Time) and ZonedDatetime.isAfter => thanks to @name213 for the implementation
- #262 LocalDate(Time) and ZonedDatetime.isAfterOrEqual => thanks to @lukebiddell for the implementation
- #290 LocalDate(Time) and ZonedDatetime.isEqual => thanks to @name213 for the implementation
- #174 shortcut for LocalDate(Time) and ZonedDatetime.year => thanks to @lpicanco for the implementation
- #175 shortcut for LocalDate(Time) and ZonedDatetime.month => thanks to @ShradhaSangtani for the implementation
- #176 shortcut for LocalDate(Time) and ZonedDatetime.day => thanks to @ShradhaSangtani for the implementation
- #175 shortcut for LocalDate(Time) and ZonedDatetime.dayOfWeek => thanks to @sanatik for the implementation
- #47 Optional.isEmpty => thanks to @arjank for the implementation
- #113 shortcut for Optional.get named isPresent => thanks to @slalu for the implementation
kotlin 1.3 extensions
- #203 Result.isSuccess => thanks to @shardulsonar
- #204 Result.isFailure => thanks to @johnGachihi
Domain / Core
π Features for assertion-function-writers:
- introduced ExtractedFeaturePostStep and ChangedSubjectPostStep in order to have only one function on the domain level which covers both, narrowing features and features which expect an
assertionCreator
-lambda ExpectImpl.feature.extractor
- π
ExpectImpl.builder.representationOnly
=> assertion without description but only a representation
Others
- #80 sample project for Atrium + junit5 => thanks to @bsemexan for the implementation
- #207 sample project for Atrium + jasmine => thanks to @bsemexan for the implementation
π Fixes
- #143 domain-api-js was not included in bundle => thanks go to Darren Bell for reporting the issue
π Improvements
- #160 CharSequence.containsRegex accepts now also a Regex => thanks to @neelkamath for the implementation
- π #85 switch to
implement
instead ofcompile
in build.gradle where possible => thanks to @kssc0112 for the implementation
due to this cc-en_GB should no longer show up in cc-infix-en_GB - β‘οΈ #193 update to spek 2.0.8 and use Spek's include => thanks to @Anubhav007 for the implementation
- #202 use spek-js instead of dummy impl => thanks to @wudmer for the implementation
- #239 spec for elementsOf empty iterable => thanks to @Megamiun for the implementation
- β‘οΈ #218 update tutteli-spek-extensions to 1.0.1 => thanks to @ShradhaSangtani for the implementation
- #86 switch to native emoij => thanks to @Frandall
- #156 improve specs for iterable, use one time consumable iterables => thanks to @aljacinto for the analysis and implementation
- π #296 git guide for newcomers as well as other fixes in CONTRIBUTING.md => thanks to @johnGachihi for the implementation
- #285 do not report value type for map contains values
- #297 rename ...OrEquals to ...OrEqual
- π #298 remove isA check in toBe for nullable types
- #300 show only java's qualified name if different from kotlin => thanks to @Hubisco for the implementation
- βͺ #303 workaround KT-35882, set cause of AtriumError explicit to null
- #306 reword
number of occurrences
=> thanks to @Jak-Sidious for the implementation - #307 change assertion verb in reporting => thanks to @Jak-Sidious for the implementation
- #308 change toBe in reporting to
equals
=> thanks to @Hubisco for the implementation
π₯ Breaking Changes
Planned (previously deprecated or announced)
- none this time
Unplanned
- none this time
π Deprecation
π The following was deprecated and will be removed with 1.0.0:
- API cc-en_GB => use fluent-en_GB, infix-en_GB respectively
- API cc-de_CH => there won't be a replacement, vote for #137 if you used it, we recommend you switch to fluent-en_GB
- everything involving
Assert/AssertionPlant
and the like => switch toExpect
and the like - π Assert.subject, which means Expect.subject is deprecated as well. Subject is passed as argument to lambdas which have to deal with it.
For instance, instead of writingcreateAndAddAssertion(TO_BE, expected) { subject == expected }
one has to writecreateAndAddAssertion(TO_BE, expected) { it == expected }
- ThrowableBuider including the assertion verb which dealt with exceptions (accepted a lambda) => can now be done with the regular expect function
- π SubjectProvider and AssertionHolder, both introduced in this version and it might well be we remove it with 1.0.0
π The following deprecations are planned for a future version
- this release does not yet include the new infix API. However, we are going to deprecate cc-infix-en_GB in favour of the new infix API infix-en_GB which is based on
Expect
as soon as the new infix API is ready. - π AssertImpl will be deprecated in favour of ExpectImpl
π₯ Breaking Changes with 1.0.0
π See atrium-roadmap -> Milestone 1.0.0
π Migrating deprecated functionality
π In case you migrate from a version < 0.7.0 then please have a look at the migration guide given in the Release Notes of 0.7.0 and 0.8.0.
Otherwise you can use the suggested replacements (ALT + Enter -> Replace with ...) or the search/replace patterns shown below.Notice, that you don't have to migrate everything at once where
asExpect
andasAssert
allow to switch between the oldAssert
and the newExpect
world.
Ping us in the Atrium slack channel if you need help.The following command is carrying out the points 1 to 11 described below (don't forget the points 12, 13, ...), run it from the root of your project, no guarantees that your system is capable of carrying it out. If not, you can use the manual steps described below.
find ./ -name "*.kt" | xargs perl -0777 -i \ -pe 's/AssertImpl([\n\r\s]*)\.changeSubject\(([^\)\n]+)\)[\n\r\s]*\{[\n\r\s]*subject/ExpectImpl$1.changeSubject\($2\)$1.unreported \{ it/g;' \ -pe 's/AssertImpl([\n\r\s]*)\.changeSubject\(([^\)]+)\)/ExpectImpl$1.changeSubject\($2\).unreported/g;' \ -pe 's/AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.createDescriptive\(([^,\n]+,[^\)]+\)[\n\r\s]*\{[\n\r\s]*)plant.subject/AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.createDescriptive\(([^,\n]+,[^\)]+\)[\n\r\s]*\{[\n\r\s]*)plant.subject/g;' \ -pe 's/AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.descriptive([\n\r\s]*).withTest(\(?[\n\r\s]*)\{([\n\r\s]*)plant.subject/AssertImpl$1.builder$2.descriptive$3.withTest\(plant\)$4\{$5it/g;' \ -pe 's/AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.descriptive([\n\r\s]*).withTest(\(?[\n\r\s]*)\{([\n\r\s]*)subject/AssertImpl$1.builder$2.descriptive$3.withTest\(this\)$4\{$5it/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)/feature(\{ f(it::$1) \})$2/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)/feature \{ f(it::$1) \}/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)`/feature(\{ f(it::$1) \})$2/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)/feature($1::$2)/g;' \ -pe 's/(?:property|returnValueOf|rueckgabewertVon)\(([^:]+)::([^\)]+)\)/feature("$1.$2", { $1.$2 })/g;' \ -pe 's/(import ch\.tutteli\.atrium\.api\.cc\.(?:\.infix)?(?:en_GB|de_CH))\.(property|returnValueOf)/$1.feature/g;' \ -pe 's/(\.| )((?:toThrow|wirft|isA|istEin)<.*>)\s*\{\s*\}/$1$2()/g;' \ -pe 's/notToBeNull\s*\{\s*\}/notToBe(null)/g;' \ -pe 's/fun <T\s*:\s*Any> ([^\(]+)\(subject:\s*T\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlant\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[\n\r\s]*reporter\)/fun <T> $1\(subject: T\): Expect<T> = \n ExpectBuilder.forSubject\(subject\)\n .withVerb\($2\)\n .withoutOptions\(\)\n .build\(\)/g;' \ -pe 's/fun <T\s*:\s*Any> ([^\(]+)\(subject:\s*T\s*,[\n\r\s]*assertionCreator: Assert<T>.\(\)\s*->\s*Unit\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlantAndAddAssertionsCreatedBy\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[\n\r\s]*reporter,[\n\r\s]*assertionCreator\)/fun <T> $1\(subject: T, assertionCreator: Expect<T>.\(\) -> Unit\): Expect<T> = \n $1(subject).addAssertionsCreatedBy(assertionCreator)/g;' \ -pe 's/(?:internal )?fun <T(?:\s*:\s*Any\?)?> ([^\(]+)\(subject:\s*T\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlantNullable\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[^\)]+\)//g;' \ -pe 's/import ch.tutteli.atrium.verbs\.(expect|assert|assertThat)/import ch.tutteli.atrium.api.verbs.$1/g;' \ -pe 's/AssertImpl/ExpectImpl/g;' \ -pe 's/fun Assert(?:ionPlant(?:Nullable)?)?<(.*)>\./fun <T: $1> Expect<T>\./g;' \ -pe 's/Assert(ionPlant(Nullable)?)?</Expect</g;' \ -pe 's/import ch\.tutteli\.atrium\.creating\.Assert(ionPlant(Nullable)?)?/import ch.tutteli.atrium.creating.Expect/g;' \ -pe 's/import ch.tutteli\.atrium\.api\.cc\.(en_GB|de_CH)/import ch.tutteli.atrium.api.fluent.$1/g;' \ -pe 's/is(Less|Greater)OrEquals/is$1ThanOrEqual/g;'
The following list helps you to migrate faster by using a few regex search replace commands (in Intellij). Make sure you have checked
Regex
as well asMatch Case
in the search options. Notice, that the good will certainly not compile after a single replace, you need to carry out all search&replace commands.
It is not perfect, maybe you need to do a few adjustments in addition, let us now and we improve the search/replace commands here.Switch to ExpectImpl.changeSubject instead of using AssertImpl.changeSubject:
Search:AssertImpl([\n\r\s]*)\.changeSubject\(([^\)\n]+)\)[\n\r\s]*\{[\n\r\s]*subject
Replace:ExpectImpl$1.changeSubject\($2\)$1.unreported { it
Search:
AssertImpl([\n\r\s]*)\.changeSubject\(([^\)]+)\)
Replace:ExpectImpl$1.changeSubject\($2\).unreported
π builder.descriptive, safe withTest
π Search:
AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.createDescriptive\(([^,\n]+,[^\)]+\)[\n\r\s]*\{[\n\r\s]*)plant.subject
π Replace:AssertImpl$1.builder$2.createDescriptive\(plant, $3it
π Search:
AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.descriptive([\n\r\s]*).withTest(\(?[\n\r\s]*)\{([\n\r\s]*)plant.subject
π Replace:AssertImpl$1.builder$2.descriptive$3.withTest\(plant\)$4{$5it
π Search:
AssertImpl([\n\r\s]*)\.builder([\n\r\s]*)\.descriptive([\n\r\s]*).withTest(\(?[\n\r\s]*)\{([\n\r\s]*)subject
π Replace:AssertImpl$1.builder$2.descriptive$3.withTest\(this\)$4{$5it
π use new feature mechanism
This one needs extra care as arguments could be function calls. Verify the replacements
Search:
(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)(\s*\{)
Replace:feature(\{ f(it::$1) \})$2
Search:
(?:property|returnValueOf|rueckgabewertVon)\((?:[\n\r\s]*)subject::([^\)]+)\)
Replace:feature \{ f(it::$1) \}
Search:
(?:property|returnValueOf|rueckgabewertVon)\(([A-Z][^:]+)::([^\)]+)\)
Replace:feature($1::$2)
Search:
(?:property|returnValueOf|rueckgabewertVon)\(([^:]+)::([^\)]+)\)
Replace:feature("$1.$2", { $1.$2 })
Search:
(import ch\.tutteli\.atrium\.api\.cc\.(?:\.infix)?(?:en_GB|de_CH))\.(property|returnValueOf)
Replace:$1.feature
toThrow and isA with empty assertionCreator lambda
Search:(\.| )((?:toThrow|wirft|isA|istEin)<.*>)\s*\{\s*\}
Replace$1$2()
notToBeNull with empty assertionCreator lambda
Search:notToBeNull\s*\{\s*\}
Replace:notToBe(null)
migrate custom assertion verbs:
Search:
fun <T\s*:\s*Any> ([^\(]+)\(subject:\s*T\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlant\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[\n\r\s]*reporter\)
Replace:
πfun <T> $1\(subject: T\): Expect<T> = \n ExpectBuilder.forSubject\(subject\)\n .withVerb\($2\)\n .withoutOptions\(\)\n .build\(\)
Search:
fun <T\s*:\s*Any> ([^\(]+)\(subject:\s*T\s*,[\n\r\s]*assertionCreator: Assert<T>.\(\)\s*->\s*Unit\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlantAndAddAssertionsCreatedBy\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[\n\r\s]*reporter,[\n\r\s]*assertionCreator\)
Replace:
fun <T> $1\(subject: T, assertionCreator: Expect<T>.\(\) -> Unit\): Expect<T> = \n $1(subject).addAssertionsCreatedBy(assertionCreator)
Search:
(?:internal )?fun <T(?:\s*:\s*Any\?)?> ([^\(]+)\(subject:\s*T\)[\n\r\s]*=[\n\r\s]*AssertImpl[\n\r\s]*\.coreFactory[\n\r\s]*\.newReportingPlantNullable\(([^,]+),[\n\r\s]*\{\s*subject\s*\}[\n\r\s]*,[^\)]+\)
Replace:(empty string)
In case the above search&replace did not find anything (because your code is different):
π¨ Switch fromAssertImpl.coreFactory.newReportingPlant
toExpectBuilder
π => see atriumVerbs.kt for an example of how own assertion verbs are defined now; or use the suggested replacements but please addimport ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
first as it will not work correctly otherwise due to an Intellij bug
=> Note that you don't need a verb for nullable types any more. Thus:- remove the upper bound
T: Any
- remove the verb which uses `newReportingPlantNullable
- remove the verb which expected
act: () -> Unit
Switch to new built-in assertion verbs which use Expect
Search: import ch.tutteli.atrium.verbs.(expect|assert|assertThat)
Replace: import ch.tutteli.atrium.api.verbs.$1Switch from AssertImpl to ExpectImpl
Search:
AssertImpl
Replace:ExpectImpl
Switch all your assertion functions to use Expect and no longer Assert:
Search:
import ch\.tutteli\.atrium\.creating\.Assert(ionPlant(Nullable)?)?
Replace:import ch.tutteli.atrium.creating.Expect
Search:
fun Assert(?:ionPlant(?:Nullable)?)?<(.*)>\.
Replace:fun <T: $1> Expect<T>\.
Search:
Assert(ionPlant(Nullable)?)?<
Replace:Expect<
Switch the API
Search:
import ch.tutteli\.atrium\.api\.cc\.(en_GB|de_CH)
Replace:import ch.tutteli.atrium.api.fluent.$1
isLessOr/isGreaterOrEquals
Search:
is(Less|Greater)OrEquals
Replace:is$1ThanOrEqual
In case you have custom assertion verbs
Dealing with thrown exceptions is now handled byExpect
as well.
π» However, in case you have named the assertion verb differently for expecting an Exception then you have to decide:- π use the same name => rename the corresponding function which expects
act: () -> Unit
to the same name and remove it afterwards - π use a different name => delegate the function which expects
act: () -> Unit
to the other verb
π Check if you need to add
import ch.tutteli.atrium.domain.builders.reporting.ExpectBuilder
Try to reduce duplicated Expect imports
Repeat until you don't have duplicate imports anymore
Search:import ch\.tutteli\.atrium\.creating\.Expect\n\s*import ch\.tutteli\.atrium\.creating\.Expect
Replace:import ch.tutteli.atrium.creating.Expect
β Try to compile your project and watch out for the following warnings:
'MyClass' is a final type, and thus a value of the type parameter is predetermined
=> you can suppress this warning by adding@file:Suppress("FINAL_UPPER_BOUND")
to your file, this is actually a Kotlin bug (https://youtrack.jetbrains.com/issue/KT-34257)