Releases: LemonAppDev/konsist
v0.17.3
v0.17.2
v0.17.1
This release is focused on bug fixes and minor improvements.
Konsist 0.17.0
has accidentally changed layer dependency behaviour from "may depend on" to "has to depend on".
We have reverted this change and added a strict
parameter to dependsOn
method:
strict = false
(default) - may depend on layerstrict = true
- have to depend on layer
// Optional dependency - Feature layer may depend on Domain layer
featureLayer.dependsOn(domainLayer) // strict = false by default
// Required dependency - Feature layer must depend on Domain layer
featureLayer.dependsOn(domainLayer, strict = true)
Complete List Of Changes
🐛 API Bug Fixes
- KON-699 Restore Layer Package Validation by @igorwojda in #1600
- KON-698 Restore Depends On Behaviour by @igorwojda in #1599
- KON-697 hasValidKDocParamTags not distinguish non-KDoc tags by @nataliapeterwas in #1598
- KON-692 Fix "StackOverflowError" Exception when trying to find indirect parents by @nataliapeterwas in #1583
💡 API Improvements
- KON-696 Add missing deprecation for KoTypeDeclaration for extensions from KoDeclarationCastProviderListExt by @nataliapeterwas in #1597
- KON-693 Add ASCII tree to missing methods like assertNotEmpty by @nataliapeterwas in #1586
🏗️ Maintenance
- Block Kotlin updates prior to version 2.1.0 (no Kotlin-related changes in this release) by @igorwojda
- Revert "Update kotlin monorepo to v2.1.0" by @igorwojda in #1592
- Disable Kotlin updates by @igorwojda in #1594
- Update allowed Kotlin version in renovate to "allowedVersions": "<2.1.0" by @igorwojda in #1591
v0.17.0
First of all we have an exciting news - Konsist is the winner of the Kotlin Foundation Grants Program 2024 🎉.
We have been hearing you feedback, so this update bring many important improvements requested by the community.
This release bring bugs fixes and many API improvements as well as some groundwork for upcoming 1.0.0-Beta1
release.
Overall Kosnist API is quite stable now , so we don’t expect any more major API changes.
Big thanks goes to @chrisbanes for the contributions.
Key changes
Improvement for Parent References (⚠️ Breaking Change)
We enhanced parent references in the API to now support both examining the parent type declaration (enabling Konsist checks for annotations, modifiers, and other declaration properties) and analyzing actual parent usage details (such as inspecting generic type arguments) through separate access methods.
This is best demonstrated with the example:
Konsist
.classes
.withName("StringContainer")
.assertTrue {
it.parent.sourceDeclaration.hasModifier(KoModifier.PUBLIC) // previously it.parent.hasModifier
}
This change allows to verify parent generic type arguments (parent use site).
Konsist
.classes
.withName("StringContainer")
.assertTrue {
it.typeArguments.flattern().contains { it.name == "String" }
}
Added Support for Generic Type Arguments
This release bring top requested feature - support for generic types. Generic type parameters and type arguments can be now verified with Konsist.
Check Verifying Generics documentation page.
Source Declaration (⚠️ Breaking Change)
API around source declarations has been unified. From property declaration, function declaration, function return type, parent
declaration, etc. it's possible to can access sourceDeclaration
(declaration site) to get the actual type and verify it.
In this example we are checking if type of current
property is a class declaration with internal
modifier:
// Snippet
internal class Engine
val current: Engine? = null // testing this in below test
// Konsist test
Konsist
.scopeFromProject()
.properties
.assertTrue {
it.type?.sourceDeclaration?.asClassDeclaration()?.hasInnerModifier // true
}
Note that explicit casting (
asXDeclaration
) has to be used to access specific properties of the declaration.
Due to updated API, some methods have been deprecated. For example, asClassDeclaration
has been "moved to sourceDeclaration`:
Konsist
.scopeFromProject()
.functions()
.returnTypes
.assertTrue {
it.asClassDeclaration() // Deprecated
?.hasPrivateModifier
}
Konsist
.scopeFromProject()
.functions()
.returnTypes
.assertTrue {
it.sourceDeclaration()
?.asClassDeclaration()
?.hasPrivateModifier
}
Improved Kotlin Backwards Compatibility
Konsist has been updated to ensure backward compatibility with Kotlin 1.8. This enhancement enables developers to integrate Konsist
into projects that haven't yet upgraded to the latest Kotlin version. By supporting Kotlin 1.8, Konsist can now be utilized in a wider
range of codebases, including those maintaining older Kotlin versions for various reasons. From now on Konsist should be compatible with
at least 3 most recent releases of Kotlin (does not take path
releases into consideration). We will also slow down with updating minor
version of Kotlin to boost compatibility even more.
Language Reference Link
The Konsist Language reference was added.
API Improvements
Added isExtension
:
// Snippet
fun String.sampleFunction() {}
// Konsist test
Konsist
.scopeFromProject()
.functions()
.assertTrue {
it.isExtension shouldBeEqualTo true // true
}
... and more.
Updated Architecture Assertions
- Reimplemented assertArchitecture to fix few bugs.
- Error handling has been improved to cover more edge cases for invalid architecture check configurations.
- We have added new methods and improved validation and messaging around errors:
'Domain' layer does not depends on 'Presentation' layer failed. Files that depend on 'Presentation' layer:
└──file /Users/igorwojda/domain/MyUseCase.kt
├── import presentation.MyView.kt
└── import presentation.MyUiState.kt
A new include()
method was added to include layers in architecture verification, without defining a dependency.
private val domain = Layer("Domain", "com.domain..")
private val presentation = Layer("Presentation", "com..presentation..")
Konsist
.scopeFromProject()
scope.assertArchitecture {
presentation.include() // Include layer without defining a dependency
domain.doesOnNothing()
}
}
What's Next
We will now focus on adding baseline and processing community feedback.
Complete List Of Changes
⚠️ Breaking API Changes
- KON-624 KoParameterDeclaration should not have a fullyQualifiedName property by @nataliapeterwas #1234
- KON-608 Rename KoInitializerProvider to KoIsInitializedProvider by @nataliapeterwas in #1281
🐛 API Bug Fixes
- KON-620 Fix crash while parsing generated Kotlin by @chrisbanes in #1334
- KON-637 Types are not retrieved when placed on the same package by @nataliapeterwas in #1353
- KON-638 Wrong type returned when using import alias by @nataliapeterwas in #1354
- KON-659 IsKotlinCollectinType IsKotlinBaseType IsKotlinType For Generic Types Return Wrong Value by @igorwojda in #1437
- KON-675 Add Number Type Basic Kotlin Types by @igorwojda in #1490
💡 API Improvements
- KON-626 Allow to retrieve class generic type argument by @nataliapeterwas in #1363
- KON-642 KoGenericTypeDeclaration API by @nataliapeterwas in #1387
- KON-646 Add extension functions for properties defined in KoFunctionTypeDeclaration and KoGenericTypeDeclaration by @nataliapeterwas in #1389
- KON-636 Add isMutableType by @nataliapeterwas in #1391
- Update Layer Documentation And Exception Messages by @igorwojda in #1430
- KON-654 Add type projection to generic type by @nataliapeterwas in #1439
- KON-657 Deprecate isValModifier/isVarModifier and add isVal/isVar by @nataliapeterwas in #1458
- KON-665 Add Is Extension by @igorwojda in #1455
- KON-663 Add IsSortedByName And IsSortedBy Extensions by @igorwojda in #1449
- KON-649 Add sourceDeclaration to KoImportDeclaration and KoImportAliasDeclaration by @nataliapeterwas in #1392
- KON-671 Dont Allow Blank Arguments In Layer by @igorwojda in #1469
- KON-669 Add universal providers directly to KoTypeDeclaration and change type structure by @nataliapeterwas in #1468
- Rename Layer definedBy To rootPackage by @igorwojda in #1483
- KON-673 Merge KoTypeDeclarationProvider and KoTypeProvider into one KoDeclarationCastProvider by @nataliapeterwas in #1478
- KON-655 Update parent references by @nataliapeterwas in #1486
- KON-656 Add KoTypeParameterDeclaration by @nataliapeterwas in #1445
- KON-650 Change KoGenericTypeDeclaration API by @nataliapeterwas in #1410
- Update Architecture Assertions by @nataliapeterwas in #1505
- KON-678 Add Layer Include by @igorwojda in #1506
- KON-679 Allow To Call Layer Dependency Method On Collections by @igorwojda in #1507
- KON-680 Rename isGenericType to isGeneric by @nataliapeterwas in #1508
- KON-681 Add isGeneric for declarations in declaration site by @nataliapeterwas in #1510
- KON-683 KoSourceAndAliasTypeProvider deprecate isAlias by @nataliapeterwas in #1519
- KON-685 Add missing declaration in KoDeclarationCastProvider for combined types by @nataliapeterwas in #1547
- KON-686 Update API so that properties from KoDeclarationCastProvider are not directly available in the source declaration by @nataliapeterwas in #1551
- KON-685 Add missing declaration in KoDeclarationCastProvider for combined types by @nataliapeterwas in #1551
- KON-688 Update KoSourceDeclaration and KoStarProjectionDeclaration API by @nataliapeterwas in #1567
💡 Improvements
- KON-648 Improve Kotlin Backwards Compatibility by @igorwojda in https://github.com/LemonAppDev/kons...
v0.16.1
v0.16.0
What's Changed
This release contains new improvement and API updates. Two new features are providers for all common combinations of interface, object and class and doesNotDependOn
method for architecture checks.
Thanks you for your feedback 🙏
1. Add providers for all common combinations of interface, object and class
Adding suport for writing tests for classes, interfaces and objects in one test.
Konsist now provides a set of methods such as:
classesAndInterfacesAndObjects()
classesAndInterfaces()
classesAndObjects()
interfacesAndObjects()
These methods can be used in two ways:
- Case 1: After creating the initial scope.
- Case 2: When filtering chosen declarations from other declarations.
For example:
// Case 1
scope
.classesAndInterfacesAndObjects(includeNested = true, includeLocal = false)
.assertTrue { it.hasNameEndingWith("Suffix") }
scope
.classesAndObjects()
.assertTrue { it.hasDataModifier }
// Case 2
scope
.classes()
.classesAndInterfaces(includeNested = true, includeLocal = false)
.assertTrue { it.hasNameEndingWith("Suffix") }
scope
.classes()
.classesAndObjects()
.assertTrue { it.hasDataModifier }
In addition to these methods, Konsist offers various other functions that allow you to count all selected declarations, check whether they meet a specific predicate, or determine if any declarations match the selected criteria. Examples include:
numClassesAndInterfacesAndObjects()
countClassesAndInterfacesAndObjects { it.hasNameEndingWith("Suffix") }
hasClassesOrInterfacesOrObjects()
hasClassOrInterfaceOrObject { it.hasNameEndingWith("Suffix") }
The examples above demonstrate methods for classes, interfaces, and objects, but Konsist provides similar methods for all combinations of classes, interfaces, and objects (either individually, in pairs, or all together).
Additionally, Konsist includes a set of withX/withoutX
extension functions, enabling you to write tests like:
scope
.classes()
.withClassOrInterfaceOrObjectNamed("SampleName")
.assertTrue { ... }
2. doesNotDependOn
method
Added doesNotDependOn
method to architectural checks.
Eg. It is possible to write such tests for this architecture
private val scope = Konsist.scopeFromProject()
private val adapter = Layer("Adapter", "com.samplepackage.adapter..")
private val common = Layer("Common", "com.samplepackage.common..")
private val domain = Layer("Domain", "com.samplepackage.domain..")
private val port = Layer("Port", "com.samplepackage.port..")
@Test
fun `Domain layer not depend on Adapter and Port layers and Adapter layer not depend on Domain layer`() {
scope.assertArchitecture {
domain.doesNotDependOn(adapter, port)
adapter.doesNotDependOn(domain)
}
}
Complete list of changes
⚠️ Breaking API Changes
- KON-624 KoParameterDeclaration should not have a fullyQualifiedName property @nataliapeterwas #1234
- KON-608 Rename KoInitializerProvider to KoIsInitializedProvider by @nataliapeterwas in #1281
🐛 API Bug Fixes
- KON-620
KoTypeDeclarationProvider.declaration
throws an exception whentypeAliases
extension is called by @nataliapeterwas in #1089 - KON-627 Fix bug: During
hasOperatorModifier()
filtrationKoInternalException
was shown with message:Modifier not found: with
by @nataliapeterwas in #1167 - KON-630
KoDefaultValueProviderCore
does not handle default values that are objects by @nataliapeterwas in #1282 - KON-628 Bug with fully qualified names of inner class declarations by @nataliapeterwas in #1241
💡 API Improvements
- KON-618 Remove Deprecated Items by @nataliapeterwas in #1012
- KON-622 Add KoAnnotationProvider for type declarations by @nataliapeterwas in #1095
- KON-263 Add
withText
extensions by @nataliapeterwas in #1118 - KON-623 Add
doesNotDependOn
to layer verification by @nataliapeterwas in #1233 - KON-605 KoImportDeclaration add represents type by @nataliapeterwas in #1258
- Add file information to getKtFile IllegalArgumentException by @nataliapeterwas in #1296
- KON-629 Add providers for all common combinations of interface, object and class by @nataliapeterwas in #1260
📕 Documentation
- Clean Up Readme by @igorwojda in #982
- KON-612 Sample projects are using deprecated code by @nataliapeterwas in #1013
- KON-581 Remove konsist-starter- directory prefix in smaple projects by @jibidus in #1031
- Upd docs by @igorwojda in #1177
- Add Snippet by @igorwojda in #1194
🏗️ Maintanance
- Fix CI jobs on macos-latest after github actions image migration by @jibidus in #1032
- KON-607 Update script and release snippets to kotlin documentation repo by @nataliapeterwas in #1014
- KON-266 Add Konsist test to check that none method has name containing "Some" by @nataliapeterwas in #1115
- KON-625 Create script to verify that all snippets with extension
.ktdoc
have valid Kotlin code by @nataliapeterwas in #1122 - KON-231 Add tests for KoParameterDeclaration using function parameters by @nataliapeterwas in #1238
Full Changelog: v0.15.1...v0.16.0
v0.15.1
v0.15.0
What's Changed
1. Use Kotlin compiler kotlin-compiler-embeddable
dependency
This release updates Kotlin compiler dependency to kotlin-compiler-embeddable
reducing dependency conflicts and simplifying dependency management.
2. All all APIs accepting varargs
now accept Kotlin collections (List
and Set
, etc.):
// Existing API
Konsist
.scopeFromFiles(path1, path2, path3)
...
// Improved API (old API stil works)
val paths = setOf(path1, path2, path3) // listOf()
Konsist
.scopeFromFiles(paths)
...
💡 Improvements
- KON-614 Update Kotlin Compiler Dependency
kotlin-compiler
tokotlin-compiler-embeddable
by @igorwojda in #954 - KON-598 Add ability to pass list and set to withX functions by @nataliapeterwas in #943
- KON-616 Add ability to pass collections to functions in providers by @nataliapeterwas in #974
Full Changelog: v0.14.0...v0.15.0
v0.14.0
What's Changed
1.0.0
, but this will be a big change, so instead we decided to follow more granular deprecation strategy to facilitate future upgrades. API with deprecation target for 1.0.0
has beed updated to 0.16.0
(#902). From now on deprecated methods will be available for 2 minor versions (until 1.0.0 release). After 1.0.0 release Konsist will follow semantic versioning scheme meaning breaking changes will be introduced only when major version of the Konsist changes. Deprecated methods (with initial removal targeted for 1.0.0
) will be removed in next release (deprecation target has bee updated). Please update your by removing Deprecated
Konsist API to facilitate future migration.
Thanks you for your feedback 🙏
New Contributors
- @guiguegon made their first contribution in #720
- @TheMaxCoder made their first contribution in #827
- @pkubowicz made their first contribution in #831
- @kollstrom made their first contribution in #780
- @jibidus made their first contribution in #830
- @ablx made their first contribution in #830
1. Added declaration references
Konsist understands the code's structure better. This new feature, highly requested by the community, provides link between declarations, giving you more control over code quality checks. Konsist now works with declarations directly, allowing you to precisely verify type properties, inheritance relationships, and more e.g.
All parent interfaces have actual
modifier:
Konsist
.scopeFromProject()
.classes()
.parentInterfaces()
.assertTrue {
it.hasActualModifier() // Can access other properties of the interface
}
All function parameters are interfaces:
Konsist
.scopeFromPackage("com.app.worker..")
.functions()
.parameters
.types
.assertTrue {
it.isInterface // Can
}
All classes have test classes with Test
annotation and a name containing its name:
Konsist
.scopeFromProject()
.classes()
.assertTrue {
it.testClasses().all { testClass ->
testClass.hasAnnotationOf<Test>() && testClass.hasNameContaining(it.name)
}
}
All interfaces have children (child classes and child interfaces) resided in ..somepackage..
package:
Konsist
.scopeFromProject()
.interfaces()
.assertTrue {
it.hasAllChildren(indirectChildren = true) { child ->
child.resideInPackage("..somepackage..")
}
}
See Declaration References docs.
2. Retrieve indirect parents
The indirectParents
parameter has been added to parent retrieval methods (parents()
, hasParentClass()
, hasAllParentInterfacesOf
etc.). This parameter specifies whether or not to include parents such as parent of the parent. By default, indirectParents
is false
e.g.
// Class hierarchy
ClassA
↓
ClassB
↓
ClassC
For above inheritance hierarchy is possible to retrieve direct parents of ClassC
(ClassB
) as well as all parents present in the codebase (ClassB
and ClassC
).
Konsist
.scopeFromProject()
.classes()
.first { it.name == "ClassC" }
.parents() // returns direct parents listOf(ClassB)
Konsist
.scopeFromProject()
.classes()
.first { it.name == "SampleClass" }
.parents(indirectParents = true) // returns listOf(ClassB, ClassA)
3. Improved assertArchitecture
methods
Following other assert
methods, we added the testName
and additionalMessage
arguments to the assertArchitecture
methods.
You can now manually set the test name that will be displayed in the test failure message and used to suppress tests. This is useful for Kotest
and dynamic tests.
scope
.assertArchitecture(
testName = "sample name",
additionalMessage = "sample message"
) {
// some dependencies
}
4. Added support for variables
Now Konsist will allow to access and verify variables located inside functions, init blocks, getters, setters and enum constants.
Konsist
.scopeFromProject()
.functions()
.assertTrue {
it.hasVariable { variable ->
variable.name == "sampleVariable"
}
}
5. Ability to check tacit
type
Now Konsist can check whether the properties or variables have a tacit type. Tacit type means that the declaration has an explicitly or implicitly specified type.
val sut: Foo = someCollection.first() // hasTacitTypeOf(SampleClass::class) == true
val sut = Foo("some text") // hasTacitTypeOf(SampleClass::class) == true
val sut = someCollection.first() // hasTacitTypeOf(SampleClass::class) == false
One scenario where tacit type
is useful is verification of sut
(system under test / class under test) existence:
Konsist
.scopeFromTest()
.classes()
.assertTrue {
// Get type name from test class e.g. FooTest -> Foo
val type = it.name.removeSuffix("Test")
val sut = it
.properties()
.firstOrNull { property -> property.name == "sut" }
sut != null && sut.hasTacitType(type)
}
6. Ability to check sourceType
and bareSourceType
Now Konsist provides sourceType
and bareSourceType
properties for better type analysis:
val car: MyClass // sourceType == "MyClass".
val car: MyClass<String> // sourceType == "MyClass<String>"
val car: MyClass // bareSourceType == "MyClass".
val car: MyClass? // bareSourceType == "MyClass".
val car: MyClass<String> // bareSourceType == "MyClass"
val car: MyClass<String?>? // bareSourceType == "MyClass"
val car: com.app.MyClass // bareSourceType == "MyClass"
One scenario where bareSourceType
is useful is naming verification of property with List
type:
Konsist
.scopeFromProject()
.properties()
.types
.withBareSourceTypeOf(List::class)
.assertTrue {
it.hasNameEndingWith("s") || it.hasNameEndingWith("es")
}
7. Ability to check whether a property is read-only
Now Konsist provides isReadOnly
property that checks whether a property is specified with a val
modifier:
val foo = Foo("some text") // isReadOnly == true
var foo = Foo("some text") // isReadOnly == false
Complete list of changes
⚠️ Breaking API Changes
- KON-369 Add Parent Declaration References by @nataliapeterwas in #709
- KON-541 Add KoVariableDeclaration by @nataliapeterwas in #717
- KON-368 Add Tests Declaration References by @nataliapeterwas in #784
- KON-547 Add Type Declarations by @nataliapeterwas in #868
🐛 Bug Fixes
- Replace REGEX to allow using .. as wildcard again by @guiguegon in #720
- Fix wrong detection of Git root project dir by @pkubowicz in #831
- Fix git dir resolver uses the wrong paths by @kollstrom in #780
- KON-578 Fix fully qualified name by @jibidus in #830
- KON-560 Methods With KClass Parameter Fails When Name Of The Class Defined In The File Is The Same As Imported Class by @nataliapeterwas in #775
- KON-577 Layer doesn't allow string that uses a package wildcard twice by @nataliapeterwas in #892
- KON-593 KoPackageMatchingPathProviderCore.hasMatchingPath fails on windows by @nataliapeterwas in #893
💡 Improvements
- Update Kotest Snippets by @nataliapeterwas in #701
- KON-538 Add
testName
ToassertArchitecture
by @nataliapeterwas in #712 - KON-553: Allow
null
values in representsType() by @yonatankarp in #719 - KON-369 Add Parent Declaration References by @nataliapeterwas in #709
- KON-205 Add Konsist Test Which Check That All Core Declarations Override
toString
by @nataliapeterwas in #735 - KON-541 Add KoVariableDeclaration by @nataliapeterwas in #717
- KON-564 Extract if statements to variable by @ablx in #730
- KON-571 Fix
isKotlinType
Property Where Generic Types Where Treated As Kotlin Collections by @igorwojda in #754 - KON-570 Add
KoSourceAndAliasTypeProviderCore.baseSourceType
by @igorwojda in #753 - KON-572 Fix for
sourcetype
stripping?
by @igorwojda in #756 - KON-574 Add
isKotlinBasicType
AndisKotlinCollectionType
by @igorwojda in #757 - KON-570 Rename
baseSourceType
TobareSourcetype
by @igorwojda in #758 - KON-570 Remove Package From
bareType
by @igorwojda in #759 - Update Gitignore by @igorwojda in #762
- Update
check_kttxt_snippets
by @igorwojda in #764 - KON-365 Add
indirectParents=false
Parameter by @nataliapeterwas in #726 - KON-366 Change Return Type Of
containingDeclaration
by @nataliapeterwas in #715 - KON-367 Add Child Declaration References by @nataliapeterwas in #736
- Add Tests by @igorwojda in #842
- Remove Scope Violation Suppress by @igorwojda in #855
- KON-432 Add Konsist Tests Which Check That All Declarations And Providers Implement Correct Parents by @nataliapeterwas in #772
- KON-368 Add Tests Declaration References by @nataliapeterwas in #784
- KON-264 add lists scope from directory by @JonathanSarco in #778
- KON-579 Create
konsist-declaration-tester
by @nataliapeterwas in #858 - KON-583 Add possibility to create scope passing sets of items by @nataliapeterwas in #861
- KON-525 Add isReadOnly property to the KoPropertyDeclaration by @jibidus in #867
- KON-543 Add
hasTacitType
by @nataliapeterwas in #773 - KON-371 Initialize ...
v0.13.0
What's Changed
This release focuses on improving KoTest support and improve assertions (Konsist docs).

From this point, Konsit will have a first-class KoTest support meaning that every following release will be developed with KoTest support in mind. At the moment we have addressed known issues and improved the API. If you think something is still missing just let us know on Slack. We would like to add more KoTest snippets to our documentation, but first, we want to see how you are using Konsist with KoTest (let us know).
On top of that, we have introduced, new assertions, multiple improvements and bug fixes (thanks to your feedback🙏).
Some of our efforts happen in the background. For instance, we improve documentation are enhance the CI setup and release process to facilitate a more frequent release schedule. Additionally, we aim to make the Konsist backlog and roadmap public to boost transparency and community involvement.
Big claps go towards @JonathanSarco for his open-source contributions to the Konsist codebase 👏.
1. Improved Assertions
Konsist
.scopeFromProject()
.classes()
.assertTrue { ... } // previously assert { ... }
Konsist
.scopeFromProject()
.classes()
.assertFalse { ... } // previously assertNot { ... }
We have relaxed the empty list behavior. Konsist test will pass on an empty list to match the behavior of methods in Kotlin collection processing:
Konsist
.scopeFromProject()
.classes()
.filter { it.name == "non existing class name" }
.assertTrue { ... } // no crash
We have also added a strict
parameter to restore old behavior:
Konsist
.scopeFromProject()
.classes()
.filter { it.name == "non existing class name" }
.assertTrue(strict = true) { ... } // crash
The assertTrue
and assertFalse
can be called on a single declaration:
Konsist
.scopeFromProject()
.classes()
.first()
.assertTrue { ... }
Konsist
.scopeFromProject()
.classes()
.first()
.assertFalse { ... }
We have added new assertions. Now you can verify if certain queries result in empty or non-empty lists with assertEmpty()
and assertNotEmpty()
:
Konsist
.scopeFromPackage("..data..")
.classes()
.assertEmpty()
Konsist
.scopeFromPackage("..data..")
.classes()
.assertNotEmpty()
You can now check whether a specific query is invoked on a null or non-null declaration.
Konsist
.scopeFromProject()
.classes()
.first()
.assertNull()
Konsist
.scopeFromProject()
.classes()
.first()
.assertNotNull()
The assertArchitecture
assertion on the list of files (previously it worked only on KoScope
):
// Works as before
Konsist
.scopeFromProject()
.assertArchitecture { ... }
// Now files can be further processed before asserting architecture
Konsist
.scopeFromProject()
.files
.filter { ... }
.assertArchitecture { ... }
The additionalMessage param allows to provision of additional messages that will be displayed with the failing test. This may be a more detailed description of the problem or a hint on how to fix the issue:
Konist
.scopeFromProject()
.classes()
.assertFalse(additionalMessage = "Do X to fix the issue") { ... }
2. Improved KoTest Support
We've allowed assertions for individual declaration (previously list of declarations was required).
Konsist
.scopeFromProject()
.classes()
.first()
.assertTrue { } // now possible
Due to Kotlin/JVM limitation, the test name has to be passed manually for each KoTest
test. We have added a dedicated testName
argument (assertTrue
and assertFalse
methods). The test name is used in two ways - as a test name displayed in the failing test crash and as a suppressName
used for suppressing tests. While this solution may not be perfect (unlike JUnit tests which don't require this), it's still effective and works well. We are open to making it better, but ATM we are stuck. The upcoming The K2 Compiler may provide a more convenient alternative.
With the new testName
parameter the KoTest test can be now suppressed:
Konsist
.scopeFromProject()
.classes()
.assert(testName = "custom suppress name") { ... }
// Suppression by custom name passed as an argument
@Suppress("custom supress name")
class Car {
}
// Suppression by custom name passed as argument also works with `konsist.` prefix
// This prefix does not have to be explicitly specified for the `testName` argument
@Suppress("konsist.custom supress name")
class Car {
}
We have added multiple KoTest starter projects. Each project has Konsist
and KoTest
preconfigured configured and a single KoTest
test:
- konsist-starter-android-gradle-groovy-kotest
- konsist-starter-android-gradle-kotlin-kotest
- konsist-starter-kmp-gradle-kotlin-kotest
- konsist-starter-spring-gradle-groovy-kotest
- konsist-starter-spring-gradle-kotlin-kotest
We have also updated snippets to include a few KoTest examples (help us with adding a few more). The entire Konsist documentation was updated to take KoTest into consideration.
3. Added support for getters & setters
Now Konsist will allow to access and verify setters and getters. For example, now it is possible to verify if a given property has a getter
(or setter
):
Konsist
.scopeFromProject()
.properties()
.assertTrue { it.hasGetter && it.hasSetter}
Konsist
.scopeFromProject()
.properties()
.getters
.assertTrue { it.hasBlockBody }
4. Ability to check block body and expression body
With declarations such as functions, getters, and setters you can now they the type of the body (block
or expression
):
Konsist
.scopeFromProject()
.functions()
.assertTrue { it.hasExpressionBody}
Konsist
.scopeFromProject()
.properties()
.getters
.assertTrue { it.hasBlockBody }
5. Ability to check return value
You can check if functions have a return value:
Konsist
.scopeFromProject()
.functions()
.assertTrue { it.hasReturnValue }
You can inspect return value further
Konsist
.scopeFromProject()
.functions()
.assertTrue { it.returnType?.text == "Unit" || it.returnType?.text == null}
6. Ability to inspect property value
You can check if properties have a value:
Konsist
.scopeFromProject()
.properties()
.assertTrue { it.hasValue() }
Assert if property has a given value:
Konsist
.scopeFromProject()
.properties()
.assertTrue { it.value.startsWith("prefix") }
Filter properties with given value:
Konsist
.scopeFromProject()
.properties()
.withValue { it.startsWith(“prefix”) }
.assertTrue { ... }
7. Added withName/withoutName
with predicate parameter
Now it is possible to call withName
and withoutName
with the specified predicate:
Konsist
.scopeFromProject()
.properties()
.withName { it.startsWith(“prefix”) || it.endsWith(“suffix”) }
.assertTrue { ... }
8. Improved hasX
methods
We have deprecated all containsX
methods and instead added some methods with has
prefixes (like hasX
, hasAllX
etc.):
Konsist
.scopeFromProject()
.interfaces()
.assertTrue { it.hasClasses() }
Konsist
.scopeFromProject()
.classes()
.assertTrue { it.hasProperty { prop -> prop.hasValue() } }
Konsist
.scopeFromProject()
.classes()
.assertTrue { it.hasAllProperties { prop -> prop.hasValue() } }
9. Improved Scope Creation
We are continuing our exploration of JGit and other APIs to enhance various development workflows e.g. a way to run Konsist Tests only on files modified in a given PR. We have added a new way of creating the scope:
// Create scope from paths
Konsist.scopeFromFiles("Repository.kt", "path\UseCase.kt")
// Create scope from set of paths
val paths = setOf("Repository.kt", "path\UseCase.kt")
Konsist.scopeFromFiles(paths)
What’s Next?
We are hearing the community feedback. The top 1 requested feature is the declaration references
. We want to enable a way to retrieve parents (of a given class/interface/companion object) as Konsist declarations, rather than string names. You will be able to verify the properties of the parent in the Konsist test. This API is not finalized yet, but we are aiming to expose parents
property containing a list of Konsist declarations:
Konsist
.scopeFromProject()
.classes()
.assertTrue { it.parents.any { parent -> parent.hasAnnotationOf<Repository> }
We also want to take a look at architecture assertions. Exact changes are quite a vague ATM, but we have a few community-driven threads to process and rethink our approach. We will consider adding “optional/empty layers” and add a few other tweaks to the Konsist API.
Thank you for your engagement using Konsist 🙏 (if you got here you must be really engaged Konsist community member congratulations 🥳). If you are missing something let us know.