# What is Konsist?

![](/files/5VWIP7oA8Hzrckd62fHW)

Konsist is a structural linter (static code analyzer) designed for [Kotlin](https://kotlinlang.org/) language. Verifying codebase with Konsist enables development teams to enforce architectural rules and class structures through automated testing.&#x20;

Konsist offers comprehensive verification capabilities that enable developers to enforce architectural rules and maintain code consistency, thereby improving the readability and maintainability of the code. It's like [ArchUnit](https://www.archunit.org/), but for Kotlin language. Whether you're working on [Android](https://www.android.com/), [Spring](https://spring.io/), or [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html) projects, Konsist has got you covered.&#x20;

The Konsist API provides developers with the capability to create custom checks through unit tests, customized to align with the project's unique requirements. Additionally, it offers smooth integration with leading testing frameworks, including [JUnit4](https://junit.org/junit4/), [JUnit5](https://junit.org/junit5/), and [Kotest](https://kotest.io/), further streamlining the development process.

{% hint style="info" %}
Konsist is approaching its 1.0 release, marking a significant milestone in its development journey. See the [Project Status](/other/project-status).
{% endhint %}

Konsist offers two types of checks, namely [#declaration-checks](#declaration-checks "mention") and [#architecturalchecks](#architecturalchecks "mention"), to thoroughly evaluate the codebase.

## Declaration Checks

The first type involves declaration checks, where custom tests are created to identify common issues and violations at the declaration level (classes, functions, properties, etc.). These cover various aspects such as class naming, package structure, visibility modifiers, presence of annotations, etc. Here are a few ideas of things to check:

* Every child class extending `ViewModel` must have `ViewModel` suffix
* Classes with the `@Repository` annotation should reside in `..repository..` package
* Every class constructor has alphabetically ordered parameters
* Every constructor parameter has a name derived from the class name
* Field injection and `m` prefix is forbidden
* Every public member in `api` package must be documented with KDoc
* and more...

Here is a sample test that verifies if every use case class resides in `domain.usecase` package:

{% tabs %}
{% tab title="JUnit" %}

```kotlin
class UseCaseKonsistTest {
    @Test
    fun `every use case reside in use case package`() {
        Konsist
            .scopeFromProject() // Define the scope containing all Kotlin files present in the project
            .classes() // Get all class declarations
            .withNameEndingWith("UseCase") // Filter classes heaving name ending with 'UseCase'
            .assertTrue { it.resideInPackage("..domain.usecase..") } // Assert that each class resides in 'any domain.usecase any' package
    }
}

```

{% endtab %}

{% tab title="Kotest" %}

```kotlin
class UseCaseKonsistTest : FreeSpec({
    "every use case reside in use case package" {
        Konsist
        .scopeFromProject() // Define the scope containing all Kotlin files present in the project
        .classes() // Get all class declarations
        .withNameEndingWith("UseCase") // Filter classes heaving name ending with 'UseCase'
        .assertTrue (
                testName = this.testCase.name.testName
         ){ 
              it.resideInPackage("..domain.usecase..") 
         } // Assert that each class resides in 'any domain.usecase any' package
    }
})
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
For more Konsist test samples see the [Snippets](/inspiration/snippets)section.
{% endhint %}

## ArchitecturalChecks

The second type of [Konsist checks](https://github.com/LemonAppDev/konsist) revolves around architecture boundaries - they are intended to maintain the separation of concerns between layers.

Consider this simple 3 layer of [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html):

* The `domain` layer is independent
* The `data` layer depends on `domain` layer
* The `presentation` layer depends on `domain` layer
* etc.

Here is a Konsist test that verifies if Clean Architecture dependency requirements are valid:

{% tabs %}
{% tab title="JUnit" %}

<pre class="language-kotlin"><code class="lang-kotlin">class ArchitectureTest {
<strong>    @Test
</strong>    fun `clean architecture layers have correct dependencies`() {
        Konsist
            .scopeFromProject() // Define the scope containing all Kotlin files present in project
            .assertArchitecture { // Assert architecture
                // Define layers
                val domain = Layer("Domain", "com.myapp.domain..")
                val presentation = Layer("Presentation", "com.myapp.presentation..")
                val data = Layer("Data", "com.myapp.data..")
    
                // Define architecture assertions
                domain.dependsOnNothing()
                presentation.dependsOn(domain)
                data.dependsOn(domain)
            }
    } 
}
</code></pre>

{% endtab %}

{% tab title="Kotest" %}

```kotlin
class ArchitectureTest : FreeSpec({
    "every use case reside in use case package" {
        Konsist
            .scopeFromProject() // Define the scope containing all Kotlin files present in project
            .assertArchitecture { // Assert architecture
                // Define layers
                val domain = Layer("Domain", "com.myapp.domain..")
                val presentation = Layer("Presentation", "com.myapp.presentation..")
                val data = Layer("Data", "com.myapp.data..")
    
                // Define architecture assertions
                domain.dependsOnNothing()
                presentation.dependsOn(domain)
                data.dependsOn(domain)
            }
    }
})
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
These types of checks are useful when the architecture layer is defined by the package, rather than a module where dependencies can be enforced by the build system.
{% endhint %}

## Summary

By utilizing Konsist, teams can be confident that their Kotlin codebase remains standardized and aligned with best practices, making code reviews more efficient and code maintenance smoother.


# Getting Started

The following example provides the minimum setup for defining and running a single Konsist test.

{% hint style="info" %}
Check the [starter projects](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects) containing Konsist tests or review the [Konsist API reference](https://reference.konsist.lemonappdev.com).
{% endhint %}

At a high-level Konsist check is a Unit test following multiple implicit steps.

3 steps are required for a *declaration check* and 4 steps are required for an *architecture check*:

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TB
Step1\["1. Create The Scope"]-->StepD2
Step1\["1. Create The Scope"]-->StepA2
StepD2\["2. Query and Filter The Declarations"]-->StepD3
StepD3\["3. Assert"]
StepA2\["2. Assert Architecture"]-->StepA3
StepA3\["2a. Define Layers"]-->StepA4
StepA4\["2b. Define Architecture Assertions"]
style Step1 fill:#52B523,stroke:#666,stroke-width:2px,color:#fff" %}

{% hint style="info" %}
The declaration represents Kotlin declaration eg. Kotlin class is represented by `KoClassDeclaration` allowing to access class name (`koClassDeclaration.name`), methods (`koClassDeclaration.functions()`), etc. See [Declaration](/features/declaration).
{% endhint %}


# Add Konsist Dependency

### Add Maven Central Repository

Add `mavenCentral` repository:

```
repositories {
    mavenCentral()
}
```

### Add Konsist Dependency

To use Konsist, include the Konsist dependency from Maven Central:

{% tabs %}
{% tab title="Gradle (Kotlin)" %}
Add the following dependency to the `module\build.gradle.kts` file:

```kotlin
dependencies {
    testImplementation("com.lemonappdev:konsist:0.17.3")
}
```

{% endtab %}

{% tab title="Gradle (Groovy)" %}
Add the following dependency to the `module\build.gradle` file:

```groovy
dependencies {
    testImplementation "com.lemonappdev:konsist:0.17.3"
}
```

{% endtab %}

{% tab title="Maven" %}
Add the following dependency to the `module\pom.xml` file:

```xml
<dependency>
    <groupId>com.lemonappdev</groupId>
    <artifactId>konsist</artifactId>
    <version>0.17.3</version>
    <scope>test</scope>
</dependency>
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
See [Compatibility](/help/compatibility)to learn how Konsist integrates with Kotlin ecosystem.
{% endhint %}

{% hint style="info" %}
To achieve better test separation Konsist can be configured inside a custom`konsistTest` source set or a dedicated `konsistTest` module. See [Isolate Konsist Tests](/advanced/isolate-konsist-tests) for guidelines on how to store Konsist test in project codebase and how to run them using cmd.
{% endhint %}


# Create First Konsist Test - Declaration Check

Konsist `Declaration Checks` provide a powerful mechanism for validating the structural elements of the Kotlin codebase. These checks allow developers to enforce structural rules and coding conventions by verifying classes, interfaces, functions, properties, and other code declarations. Here few things that can be verified with Konsist:

* All Use cases should reside in `usecase` specific package
* Repository classes must implement Repository interface
* All repository classes should have name ending with `Repository`
* `data` classes should have only val properties
* Test classes should have test subject named `sut`
* ...

{% hint style="info" %}
See [Snippets](/inspiration/snippets)section for more examples.
{% endhint %}

## Write First Declaration Check

Let's write a simple test to verify that all classes (all class declarations) residing in resides in `controller` package are annotated with the `RestController` annotation .

### Overview

On a high level writing Konsist `declaration check` requires 4 steps:

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TB
Step1\["1. Create The Scope"]-->Step2
Step2\["2. Retrieve Declarations"]-->Step3
Step3\["3. Filter Declarations"]-->Step4
Step4\["4. Define Assertion"]" %}

Let's take a closer look at each of these steps.

### 1. Create The Scope

The first step is to get a list of Kotlin files to be verified.

The `Konsist` object is an entry point to the Konsist library.

```kotlin
Konsist
```

The `scopeFromX` methods obtains the instance of the scope containing Kotlin project files. To get all Kotlin project files present in the project use the `scopeFromProject` method:

```kotlin
 // Define the scope containing all Kotlin files present in the project
Konsist.scopeFromProject() //Returns KoScope
```

{% hint style="info" %}
To define more granular scopes such as scope from production code or scope from single module see the [Create The Scope](/writing-tests/koscope) page.
{% endhint %}

### 2. Retrieve Declarations

Each file in the scope contains set of declarations like classes, properties functions etc. (see [Declaration](/features/declaration)). To write this declaration check for all classes present in the scope query classes using `classes` method :

```kotlin
Konsist.scopeFromProject()
    // Get scope classes
    .classes() 

```

### 3. Filter Declarations

In this project controllers are defined as classes annotated with `RestController` annotation. Use `withAllAnnotationsOf` method to filter classes with with `RestController` annotation:

```kotlin
Konsist.scopeFromProject()
    .classes()
    // Filter classes annotated with 'RestController'
    .withAllAnnotationsOf(RestController::class) 
```

{% hint style="info" %}
To perform more granular querying and filtering see the [Declaration Filtering](/writing-tests/declaration-query-and-filter)page.
{% endhint %}

### 4. Define Assertion

To performa assertion use the `assertTrue` method:

```kotlin
Konsist.scopeFromProject()
    .classes()
    .withAllAnnotationsOf(RestController::class)
    .assertTrue { 
        // Define the assertion
    } 
```

To verify that classes are located in the `controller` package, use the `resideInPackage` method inside `assertTrue` block:

```kotlin
Konsist.scopeFromProject()
    .classes()
    .withAllAnnotationsOf(RestController::class)
    .assertTrue { 
       // Check if classes are located in the controller package
        it.resideInPackage("..controller") 
    } 
```

This verification applies to the entire collection of previously filtered classes, rather than examining just one class in isolation.

{% hint style="info" %}
To learn more about assertions see [Declaration Assertion](/writing-tests/declaration-assert) page.
{% endhint %}

{% hint style="info" %}
The double dot syntax (`..)` means zero or more packages - controller package preceded by any number of packages (see[Package Wildcard](/features/packageselector) syntax).
{% endhint %}

## Wrap Konsist Code In Test

The declaration validation logic should be protected through automated testing. By wrapping Konsist checks within standard testing frameworks such as [JUnit](https://junit.org) or [KoTest](https://kotest.io/), you can verify these rules with each [Pull Request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests):

{% tabs %}
{% tab title="JUnit" %}

```kotlin
class ControllerClassKonsistTest {
    @Test
    fun `classes annotated with 'RestController' annotation reside in 'controller' package`() {
      // 1. Create a scope representing the whole project (all Kotlin files in project)
            Konsist.scopeFromProject()
            // 2. Retrieve class declarations
            .classes()
            // 3. Filter classes annotated with 'RestController'
            .withAllAnnotationsOf(RestController::class)
            // 4. Define the assertion
            .assertTrue { it.resideInPackage("..controller..") }
    }
}
```

{% hint style="info" %}
The [JUnit](https://junit.org) testing framework project dependency should be added to the project. See [starter projects](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects) to get a complete sample project.
{% endhint %}
{% endtab %}

{% tab title="Kotest" %}

```kotlin
class ControllerClassKonsistTest : FreeSpec({
    "classes annotated with 'RestController' annotation reside in 'controller' package" {
         Konsist
            // 1. Create a scope representing the whole project (all Kotlin files in project)
            .scopeFromProject()
            // 2. Retrieve class declarations
            .classes() // 2. Get scope classes
            // 3. Filter classes annotated with 'RestController'
            .withAllAnnotationsOf(RestController::class)
            // 4. Define the assertion
            .assertTrue (testName = this.testCase.name.testName) { 
                it.resideInPackage("..controller..") 
            }
    }
})
```

{% hint style="info" %}
For Kotest to function correctly the Kotest test name has to be explicitly passed. See the[Kotest Support](/features/kotest-support) page.
{% endhint %}

{% hint style="info" %}
The [Kotest](https://kotest.io/) testing framework project dependency should be added to the project. See [starter projects](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects) to get a complete sample project.
{% endhint %}
{% endtab %}
{% endtabs %}

Note that test class has a `KonsistTest` suffix. This is the recommended approach to name classes containing Konsist tests.

## Summary

This section described the basic way of writing Konsist declaration test. To get a better understanding of how Konsist API works see [https://github.com/LemonAppDev/konsist-documentation/blob/main/getting-started/getting-started/broken-reference/README.md](https://github.com/LemonAppDev/konsist-documentation/blob/main/getting-started/getting-started/broken-reference/README.md "mention") and [Debug Konsist Test](/features/debug-konsist-test) sections.

The above test will execute multiple assertions per test (all controllers will be verified in a single test). If you prefer better isolation each assertion can be executed as a separate test. See the [Dynamic Konsist Tests](/advanced/dynamic-konsist-tests) page.


# Create Secound Konsist Test - Architectural Check

Konsist's `Architectural Checks` serve as a robust tool for maintaining layer isolation, enabling development teams to enforce strict boundaries between different architectural layers. Here few things that can be verified with Konsist:

* `domain` layer is independant
* `data` layer depends on domain layer
* ...

{% hint style="info" %}
See [Architecture Snippets](/inspiration/snippets/architecture-snippets)section for more examples.
{% endhint %}

## Write First Architectural Check

Let's write a simple test to verify that application architecture rules are preserved. In this scenario, the application follows a simple 3-layer architecture, where `Presentation` and `Data` layers depend on `Domain` layer and `Domain` layer is independant (from these layers):

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TD
Presentation\["Presentation Layer"]-->Domain
Data\["Domain Layer"]-->Domain" %}

### Overview

On a high level writing Konsist `architectural check` requires 3 steps:

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TB
Step1\["1. Define Layers"]-->Step2
Step2\["2. Create The Scope"]-->Step3
Step3\["3. Assert Architecture"]" %}

Let's take a closer look at each of these steps.

### 1. Define Layers

Create layers instances to represent project layers. Each `Layer` instance accepts the `name` (used for presenting architecture violation errors) and `package` used to define layers.

```kotlin
// Define layers
private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
private val domainLayer = Layer("Domain", "com.myapp.domain..")
private val dataLayer = Layer("Data", "com.myapp.data..")
```

{% hint style="info" %}
The double dot syntax (`..)` means zero or more packages - layer is represented by the package and all of it's sub packages (see[Package Wildcard](/features/packageselector) syntax).
{% endhint %}

### 2. Create The Scope

The `Konsist` object is an entry point to the `Konsist` library.

```kotlin
Konsist
```

The `scopeFromX` methods obtains the instance of the scope containing Kotlin project files. To get all Kotlin project files present in the project use the `scopeFromProject` method:

```kotlin
// Define layers
private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
private val domainLayer = Layer("Domain", "com.myapp.domain..")
private val dataLayer = Layer("Data", "com.myapp.data..")
 
// Define the scope containing all Kotlin files present in the project
Konsist.scopeFromProject() //Returns KoScope
```

{% hint style="info" %}
To define more granular scopes such as scope from production code or scope from single module see the [Create The Scope](/writing-tests/koscope) page.
{% endhint %}

### 3. Assert Architecture

To performa assertion use the `assertArchiteture` method:

<pre class="language-kotlin"><code class="lang-kotlin">// Define layers
private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
private val domainLayer = Layer("Domain", "com.myapp.domain..")
private val dataLayer = Layer("Data", "com.myapp.data..")

Konsist
    .scopeFromProject()
     // Assert architecture
    .assertArchitecture {
<strong>        // Define architectural rules
</strong>    }
</code></pre>

Utilize `dependsX` methods to validate that your project's layers adhere to the defined architectural dependencies:

```kotlin
Konsist
    .scopeFromProject()
    .assertArchitecture {
        private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
        private val domainLayer = Layer("Domain", "com.myapp.business..")
        private val dataLayer = Layer("Data", "com.myapp.data..")

        // Define layer dependnecies
        presentationLayer.dependsOn(domainLayer)
        dataLayer.dependsOn(domainLayer)
        domainLayer.dependsOnNothing()
    }
```

Wrap Konsist Code In Test

The declaration validation logic should be protected through automated testing. By wrapping Konsist checks within standard testing frameworks such as [JUnit](https://junit.org) or [KoTest](https://kotest.io/), you can verify these rules with each [Pull Request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests):

{% tabs %}
{% tab title="JUnit" %}

```kotlin
class ArchitectureKonsistTest {
    @Test
    fun `architecture layers have dependencies correct`() {
        Konsist
            .scopeFromProject()
            .assertArchitecture {
                private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
                private val domainLayer = Layer("Domain", "com.myapp.business..")
                private val dataLayer = Layer("Data", "com.myapp.data..")
        
                // Define layer dependnecies
                presentationLayer.dependsOn(domainLayer)
                dataLayer.dependsOn(domainLayer)
                domainLayer.dependsOnNothing()
            }
    }
}
```

{% hint style="info" %}
The [JUnit](https://junit.org/) testing framework project dependency should be added to the project. See [starter projects](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects) to get a complete sample project.
{% endhint %}
{% endtab %}

{% tab title="Kotest" %}

```kotlin
class ArchitectureKonsistTest {
    class UseCaseTest : FreeSpec({
        "architecture layers have dependencies correct" {
            Konsist
                .scopeFromProject()
                .assertArchitecture {
                    private val presentationLayer = Layer("Presentation", "com.myapp.presentation..")
                    private val domainLayer = Layer("Domain", "com.myapp.business..")
                    private val dataLayer = Layer("Data", "com.myapp.data..")
            
                    // Define layer dependnecies
                    presentationLayer.dependsOn(domainLayer)
                    dataLayer.dependsOn(domainLayer)
                    domainLayer.dependsOnNothing()
                }
        }
    })
}
```

{% hint style="info" %}
For Kotest to function correctly the Kotest test name has to be explicitly passed. See the[Kotest Support](/features/kotest-support) page.
{% endhint %}

{% hint style="info" %}
The [Kotest](https://kotest.io/) testing framework project dependency should be added to the project. See [starter projects](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects) to get a complete sample project.
{% endhint %}
{% endtab %}
{% endtabs %}

Note that test class has a `KonsistTest` suffix. This is the recommended approach to name classes containing Konsist tests.

## Summary

This section described the basic way of writing Konsist architectural test. To get a better understanding of how Konsist API works see [Debug Konsist Test](/features/debug-konsist-test).


# Articles & Videos

## Videos

1. [Maintain consistency in your Kotlin Codebase with Konsist!](https://www.youtube.com/watch?v=WrGuZ9fgWBg)
2. [Harmonizing Kotlin codebase with Konsist (KotlinConf 2024)](https://www.youtube.com/watch?v=3qbKYSI1u1k)
3. [Stop Debating in Code Reviews. Start Enforcing with Lint Rules (Droidcon Berlin 2024)](https://www.droidcon.com/2024/08/30/stop-debating-in-code-reviews-start-enforcing-with-lint-rules-3/)&#x20;
4. [A Tour Through Konsist](https://youtu.be/AlYTvzwZOc4)
5. [Standardisez votre codebase avec Konsist](https://www.youtube.com/watch?v=_bn77FkZkUM) (FR)&#x20;

## Articles

1. [Introducing Konsist: A Cutting-Edge Kotlin Linter](https://blog.kotlin-academy.com/introducing-konsist-a-cutting-edge-kotlin-linter-d3ab916a5461)
2. [Stop Debating in Code Reviews. Start Enforcing with Lint Rules](https://proandroiddev.com/stop-debating-in-code-reviews-start-enforcing-with-lint-rules-6632c907ea94)
3. [Konsist is more than you might think](https://medium.com/@kacper.wojciechowski/konsist-is-more-than-you-might-think-3a2bdc498425)
4. [Konsist adoption with a custom Baseline definition](https://medium.com/@chethan.n/we-randomly-stumbled-upon-konsist-and-were-excited-about-the-possibilities-it-offered-bd4e0db51090)
5. [Konsist: First experience with the new linter for Kotlin](https://proandroiddev.com/konsist-first-experience-with-the-new-linter-for-kotlin-9153b0e7e2c3)
6. [Refactoring Multi-Module Kotlin Project With Konsist](https://medium.com/p/f0de0de59a3d)
7. [ArchUnit vs. Konsist. Why Did We Need Another Kotlin Linter?](https://proandroiddev.com/archunit-vs-konsist-why-did-we-need-another-linter-972c4ff2622d)
8. [Protect Kotlin Project Architecture Using Konsist](https://proandroiddev.com/protect-kotlin-project-architecture-using-konsist-3bfbe1ad0eea)
9. [Konsist: Protect Kotlin Multiplatform projects from architecture guidelines violations](https://medium.com/@lahirujay/konsist-protect-kotlin-multiplatform-projects-from-architecture-guidelines-violations-d88db0614cbd)
10. [Konsist and Conquer: Embracing the World of Kotlin Dynamic Testing](https://proandroiddev.com/konsist-and-conquer-embracing-the-world-of-dynamic-testing-07bf2fefcee1)
11. [Adding Konsist and Ktlint to a GitHub Actions Continuous Integration](https://akjaw.com/konsist-and-ktlint-in-github-actions-continous-integration/)
12. [Kotlin “Lint” Testing With Konsist](https://blog.stackademic.com/kotlin-lint-testing-with-konsist-63756e80cf5a)
13. [Konsist: Protect Kotlin Multiplatform projects from architecture guidelines violations](https://medium.com/@lahirujay/konsist-protect-kotlin-multiplatform-projects-from-architecture-guidelines-violations-d88db0614cbd)
14. [Konsist: First experience with the new linter for Kotlin](https://www.droidcon.com/2023/10/17/konsist-first-experience-with-the-new-linter-for-kotlin/)
15. [Your codebase agreements are broken. You just don’t know it yet](https://medium.com/@yassine.sayah/your-codebase-agreements-are-broken-you-just-dont-know-it-yet-b62826dee074)


# Create The Scope

Access the Kotlin files using Konsist API

Scope represents a set of Kotlin files to be further queried, filtered ([Declaration Filtering](/writing-tests/declaration-query-and-filter)), and verified ([Declaration Assertion](/writing-tests/declaration-assert)).

{% hint style="info" %}
Scopes are an alternative for `baseline` file. Subsets of the codebase can be refactored to be aligned with Konsist tests e.g. code in the single module.
{% endhint %}

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TB
Step1\["1. Create The Scope"] --> StepD2
Step1\["1. Create The Scope"]-->StepA2
StepD2\["2. Filter Declarations"] --> StepD3
StepD3\["3. Define Assertion"]
StepA2\["2. Assert Architecture"] --> StepA3
StepA3\["2a. Define Layers"] --> StepA4
StepA4\["2b. Define Assertion"]
style Step1 fill:#52B523,stroke:#666,stroke-width:2px,color:#fff
" %}

Every scope contains a set of `KoFile` instances. Every `KoFile` instance contains the declarations (see [Declaration](/features/declaration)) representing code entities present in the file e.g.:

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TD
KoScope
KoScope---KoFile
KoFile---KoClass
KoFile---KoInterface
KoFile---KoObject
KoFile---Other\["..."]
KoClass---KoProperty
KoClass---KoFunction
KoClass---Other2\["..."]" %}

{% hint style="info" %}
Konsist is built on top of [Kotlin Compiler Psi](https://github.com/JetBrains/kotlin/tree/master/compiler/psi/src/org/jetbrains/kotlin/psi). It wraps the Kotlin compiler parser and provides a simple API to access Kotlin code base declarations. Konsist [Declaration](/features/declaration) tree mimics the Kotlin code structure:
{% endhint %}

The scope can be created for an entire project, module, package, and Kotlin file.

The scope is dynamically built based on the Kotlin files present in the project, enabling it to adapt seamlessly as the project evolves. For instance, when the scope is set to encapsulate a specific module, any additional file introduced to that module will be automatically incorporated into the scope. This ensures that the scope consistently offers thorough and current coverage.

{% hint style="warning" %}
To execute Konsist tests, the Konsist dependency must be integrated into a module. Yet, by integrating Konsist into a single module (e.g. `app` module), Konsist can still access the entire project. The specific files evaluated are determined by the evolving scope that's been defined.
{% endhint %}

## Scope Creation

Various methods can be used to obtain instances of the scope. This allows the definition of more granular Konsist tests e.g. tests covering only certain modules, source sets, packages, or folders.

{% hint style="info" %}
See [Add Konsist Existing To Project (Baseline)](/features/add-konsist-existing-project).
{% endhint %}

### Project Scope

The widest scope is the scope containing all Kotlin files present inside the project:

```kotlin
Konsist.scopeFromProject() // All Kotlin files present in the project
```

To print a list of files within `koScope` use the `koScope.print()` method:

```kotlin
Konsist
    .scopeFromProject()
    .print()
```

{% hint style="info" %}
To review the scope content in more detail see [Debug Konsist Test](/features/debug-konsist-test).
{% endhint %}

### Production Codebase

The `scopeFromProduction` method allows the creation of a scope containing only a production code (equivalent to `Konsist.scopeFromProject() - Konsist.scopeFromTest()`):

```kotlin
Konsist.scopeFromProduction()
```

Contains:

```
project/
├─ app/
│  ├─ main/   <--- scope contains all production code files
│  │  ├─ App.kt
│  ├─ test/
│  │  ├─ AppTest.kt
├─ core/
│  ├─ main/   <--- scope contains all production code files
│  │  ├─ Core.kt
│  ├─ test/
│  │  ├─ CoreTest.kt
```

### Test Codebase

The `scopeFromTest` method allows the creation of a scope containing only a test code:

```kotlin
Konsist.scopeFromTest()
```

Contains:

```
project/
├─ app/
│  ├─ main/
│  │  ├─ App.kt
│  ├─ test/   <--- scope contains all test code files
│  │  ├─ AppTest.kt
├─ core/
│  ├─ main/
│  │  ├─ Core.kt
│  ├─ test/   <--- scope contains all test code files
│  │  ├─ CoreTest.kt
```

### Module Scope

The `scopeFromModule` method allows the creation of more granular scopes based on the module name e.g. creating a scope containing all Kotlin files present in the `app` module:

```kotlin
Konsist.scopeFromModule("app")
```

Contains:

```
project/
├─ app/   <--- scope contains all files from the 'app' module
│  ├─ main/
│  │  ├─ App.kt
│  ├─ test/
│  │  ├─ AppTest.kt
├─ core/
│  ├─ main/
│  │  ├─ Core.kt
│  ├─ test/
│  │  ├─ CoreTest.kt
```

This approach may be helpful when refactoring existing project modules by module.

```
val refactoredModule1Scope = Konsist.scopeFromModule("refactoredModule1")
val refactoredModule1Scope = Konsist.scopeFromModule("refactoredModule2")

val scope = refactoredModule1Scope + refactoredModule1Scop2

scope
   .classes()
   ...
   .assertTrue { /*..*/ }
```

### Nested Module Scope

A nested module is a module that exists within another module.

{% hint style="warning" %}
The `nested modules` the feature is not complete. The community is reporting that this feature works, however, we still have to take a closer look, review expectations, and add tests. Consider this feature as experimental for now.
{% endhint %}

Consider this `feature` module existing inside `app` module:

```
project/
├─ app/   <--- scope contains all files from the 'app' module
│  ├─ feature/
│  │  ├─ Feature.kt
```

To narrow the scope to `feature` module use:

```kotlin
Konsist.scopeFromModule("app/feature")
```

### Source Set Scope

The `scopeFromSourceSet` method argument allows the creation of more granular scopes based on the source set name e.g. create a scope containing all Kotlin files present in the `test` source set:

```kotlin
Konsist.scopeFromSourceSet("test")
```

Contains:

```
project/
├─ app/
│  ├─ main/
│  │  ├─ App.kt
│  ├─ test/   <--- scope contains all files the 'test' directory
│  │  ├─ AppTest.kt
├─ core/
│  ├─ main/
│  │  ├─ Core.kt
│  ├─ test/   <--- scope contains all files the 'test' directory
│  │  ├─ CoreTest.kt
```

### Module and Source Set Scope

To retrieve scope by using both module and source set use the `scopeFromProject` method with `moduleName` and `sourceSetName` arguments:

```
Konsist.scopeFromProject(moduleName = "app", sourceSetName = "test)
```

Contains:

```

project/
├─ app/
│  ├─ main/
│  │  ├─ App.kt
│  ├─ test/   <--- scope contains all files the 'test' directory
│  │  ├─ AppTest.kt
├─ core/
│  ├─ main/
│  │  ├─ Core.kt
│  ├─ test/
│  │  ├─ CoreTest.kt
```

### Package Scope

The `sourceFromPackage` method allows the creation of a scope containing code present in a given package e.g. `com.usecase` package:

```kotlin
Konsist.sourceFromPackage("com.usecase..")
```

Contains:

```
project/
├─ app/
│  ├─ main/
│  │  ├─ com/
│  │  │  ├─ usecase/
│  │  │  │  ├─ UseCase.kt <--- scope contains files present from 'com.usecase' package kon
│  ├─ test/
│  │  ├─ com/
│  │  │  ├─ usecase/
│  │  │  │  ├─ UseCaseTest.kt <--- scope contains files present from 'com.usecase' package
```

{% hint style="info" %}
The double dots (`..`) syntax means zero or more packages. Check the [Package Wildcard](/features/packageselector) page.
{% endhint %}

### Directory Scope

The `scopeFromDirectory` method allows the creation of a scope containing code present in a given project folder e.g. `domain` directory:

```kotlin
val myScope = Konsist.scopeFromDirectory("app/domain")
```

Contains:

```
project/
├─ app/
│  ├─ main/
│  │  ├─ com/
│  │  │  ├─ domain/  <--- scope contains files present in 'domain' folder
```

## File Scope

It is also possible to create scope from one or more file paths:

```kotlin
val myScope = Konsist.scopeFromFile("app/main/domain/UseCase.kt")
```

We have added a new way of creating the scope from a list of files. This can help with certain development workflows e.g. runing Konsist Tests only on files modified in a given PR:

```kotlin
val filePaths = listOf("/domain/UseCase1.kt", "/domain/UseCase2.kt")
val myScope = Konsist.scopeFromFile(filePaths)
```

## Scope Slice

For even more granular control you can use the `KoScope.slice` method to retrieve a scope containing a subset of files from the given scope:

```kotlin
// scope containing all files in the 'test' folder
koScope.slice { it.relativePath.contains("/test/") }

// scope containing all files in 'com.domain.usecase' package
koScope.slice { it.hasImport("com.domain.usecase") }

// scope containing all files in 'usecase' package and its sub-packages
koScope.slice { it.hasImport("usecase..") }
```

The `KoScope` can be printed to display a list of all files present in the scope. Here is an example:

## Scope Reuse

### Reuse Scope In Test Class

To reuse scope across the test class define the scope in the companion object and access it from multiple tests:

<pre class="language-kotlin"><code class="lang-kotlin">// Test.kt
class DataTest {
<strong>    @Test
</strong>    fun `test 1`() {
        classesScope
            .assertTrue { // .. } 
    }

    fun `test 2`() {
        classesScope
            .assertTrue { // .. } 
    }
    
    companion object {
        // Create a new KoScope once for all tests
        private val classesScope = Konsist
            .scopeFromProject()
            .classes()
    }
}
</code></pre>

### Reuse Scope In Test Source Set

To reuse scope across the multiple test classes define the scope in the file and access it from multiple test classes:

```kotlin
// Scope.kt is "test" source set
val projectScope = Konsist.scopeFromProject() // Create a new KoScope

// AppTest.kt
class AppKonsistTest {
    @Test
    fun `test 1`() {
        projectScope
            .objects()
            .assertTrue { // .. }
    }
}

// DataTest.kt
class CoreKonsistTest {
    @Test
    fun `test 1`() {
        projectScope
            .classes()
            .assertTrue { // .. }
    }

    fun `test 2`() {
        projectScope
            .interfaces()
            .assertTrue { // .. }
    }
}
```

Here is the file structure representing the above snippet:

```
project/
├─ app/
│  ├─ test/
│  │  ├─ app
│  │     ├─ AppKonsistTest.kt
│  │  ├─ core
│  │     ├─ CoreKonsistTest.kt
│  │  ├─ Scope.kt   <--- Instance of the KoScope used in both DataTest and AppTest classes.
```

## Scope Composition

Konsist scope supports [Kotlin Operator overloading](https://kotlinlang.org/docs/operator-overloading.html), so scopes can be further combined together to create the desired scope, tailored to project needs. In this example scopes from `myFeature1` module and `myFeature2` module are combined together:

```kotlin
val featureModule1Scope = Konsist.scopeFromModule("myFeature1")
val featureModule2Scope = Konsist.scopeFromModule("myFeature2")

val refactoredModules = featureModule1Scope + featureModule2Scope

refactoredModules
    .classes()
    ...
    .assertTrue { ... }
```

## Scope Subtraction

Scope subtraction is also supported, so it is possible for example to exclude a part of a given module. Here scope is created from `myFeature` module and then the `..data..` package is excluded:

```kotlin
val moduleScope = Konsist.scopeFromModule("myFeature")
val dataLayerScope = Konsist.scopeFromPackage("..data..")

val moduleSubsetScope = moduleScope - dataLayerScope

moduleSubsetScope
    .classes()
    ...
    .assertTrue { ... }
```

## Print Scope

To print all files within the scope use the `print()` method:

```kotlin
koScope.print()
```

{% hint style="info" %}
See [Debug Konsist Test](/features/debug-konsist-test).
{% endhint %}

## Access Specific Declarations

To access specific declaration types such as interfaces, classes, constructors, functions, etc. utilize the [Declaration Filtering](/writing-tests/declaration-query-and-filter).


# Declaration Filtering

Query and filter declarations using Konsist API

## Declaration Filtering

Declaration querying allows to retrieval of declarations of a given type. It is the middle step of the Konsist config preceded by scope retrieval ([Create The Scope](/writing-tests/koscope)) and followed by the verification ([Declaration Assertion](/writing-tests/declaration-assert)) step.

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TB
Step1\["1. Create The Scope"]-->Step2
Step2\["2. Filter Declarations"]-->Step3
Step3\["3. Define Assertion"]
style Step2 fill:#52B523,stroke:#666,stroke-width:2px,color:#fff" %}

Typically, verification has performed a collection of declarations such as methods marked with particular annotations or classes located within a single package.

Every [Create The Scope](/writing-tests/koscope) contains a set of declarations ([Declaration](/features/declaration)) such as classes (`KoClass`), properties (`KoProperty`), functions (`KoFunction`), etc. The `KoScope` class provides a set of properties and methods to access Kotlin declarations. Each of them returns a list representing a declaration subset:

|                  |                                               |
| ---------------- | --------------------------------------------- |
| Method           | Description                                   |
| `files`          | returns all files present in the scope        |
| `packages`       | returns all packages present in the scope     |
| `imports`        | returns all imports present in the scope      |
| `classes()`      | returns all classes present in the scope      |
| `interfaces()`   | returns all interfaces present in the scope   |
| `objects()`      | returns all objects present in the scope      |
| `functions()`    | returns all functions present in the scope    |
| `properties()`   | returns all properties present in the scope   |
| `typeAliases`    | returns all type aliases present in the scope |
| `declarations()` | returns all declarations present in the scope |

To get all classes from the given scope use `KoScope.classes()` method:

```kotlin
koScope
    .classes()
```

Here is an example of querying all properties defined inside classes:

```kotlin
    koScope
        .classes()
        .properties()
        .assertTrue { 
            //...
        }
```

## Filter Declarations

More granular filtering can be applied to additionally filter classes annotated with certain attributes like classes annotated with `UseCase` annotation.

Konsist is compatible with [Kotlin Collection processing](https://kotlinlang.org/docs/collections-overview.html#list) API, so the `filter` method can be used to filter the content of the `List<KoClass>`: Here filter return classes annotated with `UseCase` annotation:

```kotlin
koScope
    .classes()
    .filter { it.hasAnnotationOf<UseCase>() }
    .assertTrue { 
        //... 
    }
```

Konsist provides a set of `with...` extensions to simplify the filtering syntax. The above snippet can be improved:

```kotlin
koScope
    .classes()
    .withAllAnnotationsOf(UseCase::class)
    .assertTrue { 
        //...
    }
```

{% hint style="info" %}
The`.`**`withAllAnnotationsOf`**`(Annotation1::class, Annotation2::class)` filter classes having all annotations present (`Annotation1` **and** `Annotation2`).

The`.`**`withSomeAnnotationsOf`**`(Annotation1::class, Annotation2::class)` filter classes having at least one annotation (`Annotation1` **or** `Annotation2`)`.`
{% endhint %}

Multiple conditions can be chained to perform more specific filtering. The below snippet filters classes with the `BaseUseCase` parent class that resides in the `usecase` package:

```kotlin
koScope
    .classes()
    .withAllAnnotationsOf(UseCase::class)
    .withPackage("..usecase")
    .assertTrue { 
        //...
    }
```

It is also possible to filter declarations by using certain aspects e.g. visibility modifiers. Usage of `providers` allows verifying the visibility of different declaration types such as classes, functions, properties, etc:

```kotlin
koScope
    .declarationsOf<KoVisibilityModifierProvider>()
    .assertTrue { it.hasInternalModifier }
```

## Query And Filter Declaration

Querying and filtering stages can be mixed to perform more specific checks. The below snippet filters classes reside in the `controller` package retrieves all properties, and filters properties with `Inject` annotation:

```kotlin
koScope
    .classes() // query all classes
    .withPackage("..controller") // filter classes in 'controller' package
    .properties()  // query all properties
    .withAnnotationOf(Inject::class) // filter classes in 'controller' package
    .assertTrue { 
        //...
    }
```

## Print Declarations

To print all declarations within use the `print()` method:

```kotlin
koScope
    .classes()
    .properties()
    .print()
```


# Declaration Assertion

Verify codebase using Konsist API

Assertions are used to perform code base verification. This is the final step of Konsist verification preceded by scope creation ([Create The Scope](/writing-tests/koscope)) and [Declaration Filtering](/writing-tests/declaration-query-and-filter) steps:

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TB
Step1\["1. Create The Scope"]-->Step2
Step2\["2. Filter Declarations"]-->Step3
Step3\["3. Define Assertion"]
style Step3 fill:#52B523,stroke:#666,stroke-width:2px,color:#fff" %}

## Assertion Methods

Konsist offers a variety of assertion methods. These can be applied to a list of KoDeclarations as well as a single declaration.

### Assert True

In the below snippet, the assertion (performed on the list of interfaces) verifies if every interface has a `public` visibility modifier.

```kotlin
koScope
    .interfaces()
    .assertTrue { it.hasPublicModifier() }
```

The `it` parameter inside the `assertTrue` method represents a single declaration (single interface in this case). However, the assertion itself will be performed on every available interface. The last line in the `assertTrue` block will be evaluated as `true` or `false` providing the result for a given asset.

{% hint style="info" %}
Each `KoDeclaration` comes with an API, comprising methods and properties, for verifying the declaration. Additionally, the Konsist API offers a `text` property for exceptional cases where the standard API falls short. This should be used as a last resort, and any issues encountered should be reported [Getting Help](/help/getting-help).
{% endhint %}

### Assert False

The `assertFalse` is a negation of the `assertTrue` method. In the below snippet, the assertion (performed on the list of properties) verifies if none of the properties has the `Inject` annotation:

```kotlin
Konist
    .scopeFromProject()
    .properties()
    .assertFalse { 
        it.hasAnnotationOf(Inject::class)
    }
```

This assertion verifies that the class does not contain any properties with `public` (an explicit `public` modifier) or default (implicit `public` modifier) modifiers:

```kotlin
Konist
    .scopeFromProject()
    .properties()
    .assertFalse { 
        it.hasPublicOrDefaultModifier
    }
```

### Assert Empty

This assertion helps to verify if the given list of declarations is empty.

```kotlin
Konist
    .scopeFromProject()
    .classes()
    .assertEmpty()
```

### Assert Not Empty

This assertion helps to verify if the given list of declarations is not empty.

```kotlin
Konist
    .scopeFromProject()
    .classes()
    .assertNotEmpty()
```

## Assertion Parameters

### Test Name

Assertions offer a set of parameters allowing to tweak the assertion behavior. You can adjust several settings, such as setting `testName` that helps with suppression (see [Suppress Konsist Test](/writing-tests/suppressing-konsist-test)).

### Strict

You can also enable enhanced verification by setting `strict` argument to `true`:

```kotlin
Konist
    .scopeFromProject() 
    .classes()
    .assertFalse(strict = true) { ... }
```

### Additional Message

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.

```kotlin
Konist
    .scopeFromProject() 
    .classes()
    .assertFalse(additionalMessage = "Do X to fix the issue") { ... }
```


# Architecture Assertion

Verify codebase using Konsist API

Architecture assertions are used to perform architecture verification. It is the final step of Konsist verification preceded by scope creation ([Create The Scope](/writing-tests/koscope)):

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TB
StepA2\["2. Assert Architecture"]-->StepA3
StepA3\["2a. Define Layers"]-->StepA4
StepA4\["2b. Define Assertion"]
style StepA2 fill:#52B523,stroke:#666,stroke-width:2px,color:#fff
style StepA3 fill:#52B523,stroke:#666,stroke-width:2px,color:#fff
style StepA4 fill:#52B523,stroke:#666,stroke-width:2px,color:#fff" %}

## Assert Architecture

As an example, this simple 2-layer architecture will be used:

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart LR
Presentation\["Presentation Layer"]-->Data
Data\["Data Layer"]" %}

The `assertArchitecture` block defines architecture layer rules and verifies that the layer requirements are met.

```kotlin
Konsist
    .scopeFromProject()
    .assertArchitecture { 
        // Assert architecture 
    }
```

## Define Layers

Create [Layer](https://lemonappdev.github.io/konsist/-konsist%200.17.0/com.lemonappdev.konsist.api.architecture/-layer/index.html?query=data%20class%20Layer\(name:%20String,%20rootPackage:%20String\)) class instance to represent project layers. Each `Layer` instance accepts the `name` (used for presenting architecture violation errors) and `package` used to define architectural layer:

```kotlin
Konsist
    .scopeFromProject()
    .assertArchitecture {
        // Define layers
        val presentation = Layer("Presentation", "com.myapp.presentation..")
        val data = Layer("Data", "com.myapp.data..")
    }
```

{% hint style="info" %}
The inclusion of two trailing dots indicates that the layer is denoted by the `com.myapp.business` package together with all of its sub-packages.
{% endhint %}

## Define Architecture Assertions

The final step is to define the dependencies (relations) between each layer using one of these methods:

* `dependsOn`
* `dependsOnNothing`
* `doesNotDependOn`

{% hint style="info" %}
See the [language reference](https://lemonappdev.github.io/konsist/-konsist%200.17.0/com.lemonappdev.konsist.api.architecture/-layer-dependencies/index.html) for above methods.
{% endhint %}

The above methods follow up the layer definitions inside `assertArchitecture` block:

```kotlin
Konsist
    .scopeFromProject()
    .assertArchitecture {
        val presentation = Layer("Presentation", "com.myapp.presentation..")
        val data = Layer("Data", "com.myapp.data..")

        // Define dependencies 
        presentation.dependsOn(data)
        data.dependsOnNothing()
    }
```

## Strict DependsOn

By default `dependsOn` method works like does not perform strict layer validation (`strict = false`). However this behaviour is controlled b y`strict` parameter:

* `strict = false` (default) - may depend on layer
* `strict = true` - have to depend on layer

e.g.

```kotlin
// 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)
```

## Excluding Files

Architecture verification can be performed on `KoScope` (as seen above) and a list containing `KoFiles`. For example, you can remove a few files from the scope before performing an architectural check:

```kotlin
Konsist
    .scopeFromProject()
    .files
    .withNameStartingWith("Repository")
    .assertArchitecture {
        val presentation = Layer("Presentation", "com.myapp.presentation..")
        val data = Layer("Data", "com.myapp.data..")

        presentation.dependsOn(data)
        data.dependsOnNothing()
    }
```

This approach provides more flexibility when working with complex projects, however, The desired approach is to create a dedicated scope. See [Create The Scope](/writing-tests/koscope).

## Include Layer Without Defining Dependency

The [include](https://lemonappdev.github.io/konsist/-konsist%200.17.0/com.lemonappdev.konsist.api.architecture/-layer-dependencies/include.html) method allows to include layer in architecture verification, without defining a dependency for this layer:

```kotlin
private val domain = Layer("Domain",  "com.domain..")
private val presentation = Layer("Presentation", "com..presentation..")

Konsist
    .scopeFromProject()
    scope.assertArchitecture {
        // Include presentation for architectural check without defining a dependency
        presentation.include()
        
        // Include domain layer or architectural check and define no dependency (independent)
        domain.doesOnNothing()
    }
}
```

## Architecture As A Variable

Architecture configuration can be defined beforehand and stored in a variable to facilitate checks for multiple scopes:

```kotlin
// Define architecture
val architecture = architecture {
        val presentation = Layer("Presentation", "com.myapp.presentation..")
        val data = Layer("Data", "com.myapp.data..")

        presentation.dependsOn(data)
        data.dependsOnNothing()
}

// Assert Architecture of two modules using common architecture rules
moduleFeature1Scope.assertArchitecture(architecture)
moduleFeature2Scope.assertArchitecture(architecture)
```

This approach may be helpful when refactoring existing applications. To facilitate readability the above checks should be expressed as two unit tests:

```kotlin
class ArchitectureTest {
    private val architecture = architecture {
        val presentation = Layer("Presentation", "com.myapp.presentation..")
        val data = Layer("Data", "com.myapp.data..")

        presentation.dependsOn(data)
        data.dependsOnNothing()
    }

    @Test
    fun `architecture layers of feature1 module have dependencies correct`() {
        moduleFeature1Scope.assertArchitecture(architecture)
    }
    
    @Test
    fun `architecture layers of feature2 module have dependencies correct`() {
        moduleFeature2Scope.assertArchitecture(architecture)
    }
}
```


# Suppress Konsist Test

The [@Suppress](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-suppress/) annotation serves as a powerful tool to control lines and static analysis tools. When writing the Konsist test, there might be instances where the specific guard is not applicable due to certain project-specific reasons. The `@Suppress` annotation can be used to ignore those particular issues, ensuring that the codebase still adheres to the overall linting standards

In Konsist the `@Suppress` annotation parameter name is derived from the name of the test to be suppressed. For example - this test verifies if every API declaration has KDoc:

```
fun `every api declaration has KDoc`() {
    // ...
}
```

The name of the test is `every api declaration has KDoc`, so we can suppress this test by using one of these arguments:

* The name of the actual Konsist test -`@Suppress("every api declaration has KDoc")`
* The name of the actual Konsist test was prefixed by `konsist` - `@Suppress("konsist.every api declaration has KDoc")`. This is helpful if you have multiple lines in the project and want to know which linters own a given check (check that needs to be suppressed)

In the below example, `@Suppress` annotation is applied to `author` property:

```kotlin
package com.myapp.api

/**
 * Represents a simple `Book` entity.
 */
interface Book {
    
    /**
     * The title of the book.
     */
    val title: String
    
    @Suppress("konsist.every api declaration has KDoc")
    val author: String
}
```

{% hint style="info" %}
Suppression without `konsist.`prefix also works (`@Suppress("every api declaration has KDoc")`). However, using the `konsist.prefix` is advised as it links the `Suppress` annotation to a specific tool. This ensures clarity on whether a particular suppression relates to a Konsist test.
{% endhint %}

When using `@Suppress` annotation, it's advisable to apply it to the smallest possible scope to ensure that only the intended warnings are suppressed, so other potential issues aren't inadvertently overlooked. In the above example, the `@Suppress` annotation was applied to the property.

If broader suppression is necessary, you can then escalate to the interface level:

```kotlin
package com.myapp.api

/**
 * Represents a simple `Book` entity.
 */
@Suppress("konsist.every api declaration has KDoc")
interface Book {
    
    /**
     * The title of the book.
     */
    val title: String
    
    val author: String
}
```

As a last resort, if multiple elements in a file need the same suppression, the `@Suppress` annotation can be applied to the entire file:

```kotlin
@file:Suppress("konsist.every api declaration has KDoc")
package com.myapp.api

/**
 * Represents a simple `Book` entity.
 */
interface Book {
    
    /**
     * The title of the book.
     */
    val title: String
    
    @Suppress("konsist.every api declaration has KDoc")
    val author: String
}
```

### Suppressing Kotest Test

Konsist has no way of retrieving the name of the current [Kotest](https://kotest.io/) test (unlike JUnit).

{% hint style="info" %}
See the [Kotest Support](/features/kotest-support) page.
{% endhint %}

To allow suppression (and correct test names) it is recommended to utilize the name derived from the Kotest context using the `testName` argument:

```kotlin
package com.api.test

class UseCaseTest : FreeSpec({
    "useCase test" {
        Konsist
            .scopeFromProject()
            .classes()
            .assertTrue (testName = this.testCase.name.testName) {  }
    }
})
```

To suppress such tests use the test name prefixed with `konsist.`:

```kotlin
package com.api.controller

@Suppress("konsist.useCase test")
class MyUseCase {
    ... // code
}
```

{% hint style="info" %}
See [Kotest Support](/features/kotest-support#kotestname-extension) to simplify the syntax for Kotest test name.
{% endhint %}


# Verify Classes

Konsist enables development teams to enforce structural rules for class ensuring code consistency across projects.

To verify classes start by querying all classes present in the project:

```kotlin
Konsist
.scopeFromProject()
.classes()
...
```

{% hint style="info" %}
The above code selects all classes present in the project codebase. While this demonstrates Konsist's API capabilities, in practical scenarios you'll typically want to verify a specific subset of classes - such as those with a particular name suffix or classes within a given package. See [Create The Scope](/writing-tests/koscope) and [Declaration Filtering](/writing-tests/declaration-query-and-filter).&#x20;
{% endhint %}

Konsist allows you to verify multiple aspects of a class. For a complete understanding of the available APIs, refer to the language reference documentation for [KoClassDeclaration](https://lemonappdev.github.io/konsist/-konsist%200.17.0/com.lemonappdev.konsist.api.declaration/-ko-class-declaration/index.html).

Let's look at few examples.

## Verify Name

Class names can be validated to ensure they follow project naming conventions and patterns.

Check if class name ends with `Repository`:

```kotlin
...
.assertTrue {
   it.hasNameEndingWith("Repository")
}
```

## Verify Modifiers

Class modifiers can be validated to ensure proper encapsulation and access control.

Check if class has `internal` modifier:

```kotlin
...
.assertTrue {
   it.hasInternalModifier
}
```

## Verify Annotations

Class-level and member annotations can be verified for presence, correct usage, and required attribute values.

Check if class is annotated with `Service` annotation:

```kotlin
...
.assertTrue {
   it.hasAnnotationOf(Service::class)
}
```

## Verify Package

Package declarations can be validated to ensure classes are located in the correct package structure according to architectural guidelines.

Check if class has `model` package or sub-packages (`..` means include sub-packages):

```kotlin
...
.assertTrue {
   it.resideInPackage("com.lemonappdev.model..")
}
```

## Verify Methods

Methods can be validated for their signatures, modifiers, annotations, naming patterns, return types, and parameter structures.

Check if methods (functions defined inside class) have no annotations:

```kotlin
...
.functions()
.assertTrue {
   it.annotations.isEmpty()
}
```

See [Broken mention](broken://pages/jgKJIDKGqg3dksBBo5Nl).

## Verify Properties

Properties can be checked for proper access modifiers, type declarations, and initialization patterns.

Check if all properties (defined inside class) has `val` modifiers:

```kotlin
...
.properties()
.assertTrue {
   it.isVal
}
```

See [#verify-properties](#verify-properties "mention").

## Verify Constructors

Primary and secondary constructors can be validated for parameter count, types, and proper initialization.

Check if class has explicit primary constructor:

```kotlin
...
.assertTrue {
   it.hasPrimaryConstructor
}
```

Check if primary constructor is annotated with `Inject` annotation:

```kotlin
...
.primaryConstructors
.assertTrue {
    it.hasAnnotation(Inject::class)
}
```

## Verify Generic Type Parameters

Generic type parameters and constraints can be checked for correct usage and bounds declarations.

Check if class has not type parameters:

<pre class="language-kotlin"><code class="lang-kotlin">...
.assertFalse {
<strong>    it.hasTypeParameters()
</strong>}
</code></pre>

## Verify Generic Type Arguments

Generic type arguments can be checked for correct usage.

Check if parent has no type arguments:

```kotlin
...
.parents()
.assertFalse {
    it.hasTypeArguments()
}
```

## Verify Parents

Inheritance hierarchies, interfaces implementations, and superclass relationships can be validated.

Check if class extends `CrudRepository`:

```kotlin
...
.assertTrue {
   it.hasParentOf(CrudRepository::class)
}
```

## Verify Companion Objects

Companion object declarations, their contents, and usage patterns can be verified for compliance.

Check if class has companion object:

```kotlin
...
.assertTrue { declaration ->
    declaration.hasObject { it.hasCompanionModifier }
}
```

## Verify Members Order

The sequential arrangement of class members can be enforced according to defined organizational rules.

Check if class properties are defined before functions:

```kotlin
...
.assertTrue {
    val lastKoPropertyDeclarationIndex = it
        .declarations(includeNested = false, includeLocal = false)
        .indexOfLastInstance<KoPropertyDeclaration>()
    
    val firstKoFunctionDeclarationIndex = it
        .declarations(includeNested = false, includeLocal = false)
        .indexOfFirstInstance<KoFunctionDeclaration>()
    
    if (lastKoPropertyDeclarationIndex != -1 && firstKoFunctionDeclarationIndex != -1) {
        lastKoPropertyDeclarationIndex < firstKoFunctionDeclarationIndex
    } else {
        true
    }
}
```


# Verify Interfaces

Konsist enables development teams to enforce structural rules for interfaces ensuring code consistency across projects.

To verify interfaces start by querying all interface present in the project:

```kotlin
Konsist
.scopeFromProject()
.interfaces()
...
```

{% hint style="info" %}
The above code selects all interfaces present in the project codebase. While this demonstrates Konsist's API capabilities, in practical scenarios you'll typically want to verify a specific subset of interface - such as those with a particular name suffix or interfaces within a given package. See [Create The Scope](/writing-tests/koscope) and [Declaration Filtering](/writing-tests/declaration-query-and-filter).&#x20;
{% endhint %}

Konsist allows you to verify multiple aspects of a interfaces. For a complete understanding of the available APIs, refer to the language reference documentation for [KoInterfaceDeclaration](https://lemonappdev.github.io/konsist/-konsist%200.17.0/com.lemonappdev.konsist.api.declaration/-ko-interface-declaration/index.html).

Let's look at few examples.

## Verify Name

Interface names can be validated to ensure they follow project naming conventions and patterns.

Check if interface name ends with `Repository`:

```kotlin
..
.assertTrue {
   it.hasNameEndingWith("Repository")
}
```

## Verify Modifiers

Interface modifiers can be validated to ensure proper encapsulation and access control.

Check if interface has `internal` modifier:

```kotlin
..
.assertTrue {
   it.hasInternalModifier
}
```

## Verify Annotations

Interface-level and member annotations can be verified for presence, correct usage, and required attribute values.

Check if interface is annotated with `Service` annotation:

```kotlin
...
.assertTrue {
   it.hasAnnotationOf(Service::class)
}
```

## Verify Package

Package declarations can be validated to ensure classes are located in the correct package structure according to architectural guidelines.

Check if interface has `model` package or sub-packages (`..` means include sub-packages):

```kotlin
...
.assertTrue {
   it.resideInPackage("com.lemonappdev.model..")
}
```

## Verify Methods

Methods can be validated for their signatures, modifiers, annotations, naming patterns, return types, and parameter structures.

Check if methods (functions defined inside interface) have name starting with `Local`:

```kotlin
...
.functions()
.assertTrue {
    it.hasNameStartingWith("Local")
}
```

See [Broken mention](broken://pages/jgKJIDKGqg3dksBBo5Nl).

## Verify Properties

Properties can be checked for proper access modifiers, type declarations, and initialization patterns.

Check if all properties (defined inside interface) has `val` modifiers:

```kotlin
...
.properties()
.assertTrue {
   it.isVal
}
```

See [#verify-properties](#verify-properties "mention").

## Verify Generic Type Parameters

Generic type parameters and constraints can be checked for correct usage and bounds declarations.

Check if interface has not type parameters:

<pre class="language-kotlin"><code class="lang-kotlin">...
.assertFalse {
<strong>    it.hasTypeParameters()
</strong>}
</code></pre>

## Verify Generic Type Arguments

Generic type arguments can be checked for correct usage.

Check if parent has no type arguments:

```kotlin
...
.parents()
.assertFalse {
    it.hasTypeArguments()
}
```

## Verify Parents

Inheritance hierarchies, interfaces implementations, and superclass relationships can be validated.

Check if interface extends `CrudRepository`:

```kotlin
...
.assertTrue {
   it.hasParentOf(CrudRepository::class)
}
```

## Verify Companion Objects

Companion object declarations, their contents, and usage patterns can be verified for compliance.

Check if interface has `companion object`:

```kotlin
...
.assertTrue {
   it.hasObject { objectt -> objectt.hasCompanionModifier }
}
```

## Verify Members Order

The sequential arrangement of interface members can be enforced according to defined organizational rules.

Check if interface properties are defined before functions:

```kotlin
...
.assertTrue {
    val lastKoPropertyDeclarationIndex = it
        .declarations(includeNested = false, includeLocal = false)
        .indexOfLastInstance<KoPropertyDeclaration>()
    
    val firstKoFunctionDeclarationIndex = it
        .declarations(includeNested = false, includeLocal = false)
        .indexOfFirstInstance<KoFunctionDeclaration>()
    
    if (lastKoPropertyDeclarationIndex != -1 && firstKoFunctionDeclarationIndex != -1) {
        lastKoPropertyDeclarationIndex < firstKoFunctionDeclarationIndex
    } else {
        true
    }
}
```


# Verify Functions

Functions can be validated for their signatures, modifiers, naming patterns, return types, and parameter structures.

To verify functions start by querying all functions present in the project:

```kotlin
Konsist
.scopeFromProject()
.functions()
...
```

In practical scenarios you'll typically want to verify a specific subset of functions - such as those defined inside classes:

```kotlin
Konsist
.scopeFromProject()
.classes()
.functions()
...
```

Konsist API allows to query `local` functions:

```kotlin
Konsist
.scopeFromProject()
.classes()
.functions(includeLocal = true)
...
```

Konsist allows you to verify multiple aspects of a functions. For a complete understanding of the available APIs, refer to the language reference documentation for [KoFunctionDeclaration](https://lemonappdev.github.io/konsist/-konsist%200.17.0/com.lemonappdev.konsist.api.declaration/-ko-function-declaration/index.html).

Let's look at few examples.

## Verify Name

Function names can be validated to ensure they follow project naming conventions and patterns.

Check if function name starts with `get` :

```kotlin
...
.assertTrue {
   it.hasNameStartingWith("get")
}
```

## Verify Modifiers

Function modifiers can be validated to ensure proper encapsulation and access control.

Check if function has `public` or default (also `public`) modifier:

```kotlin
..
.assertTrue {
   it.hasPublicOrDefaultModifier
}
```

## Verify Annotations

Function-level and member annotations can be verified for presence, correct usage, and required attribute values.

Check if function is annotated with `Binding` annotation:

```kotlin
...
.assertTrue {
   it.hasAnnotationOf(Binding::class)
}
```

## **Verify Body Type**

Functions with block bodies (using curly braces) can be validated to ensure compliance with code structure requirements:

<pre class="language-kotlin"><code class="lang-kotlin">...
<strong>.assertTrue { 
</strong>    it.hasBlockBody 
}
</code></pre>

Expression body functions (using single-expression syntax) can be verified to maintain consistent style across the codebase:

```kotlin
...
.assertTrue { 
    it.hasExpressionBody 
}
```

## **Verify Parameters**

Function parameters can be validated for their types, names, modifiers, and annotations to ensure consistent parameter usage.

Check if function has parameter of type `String`:

```kotlin
...
.assertTrue { 
    it.hasParameter { parameter  -> parameter.hasTypeOf(String::class) }
}
```

## **Verify Return Type**

Return types can be checked to ensure functions follow expected return type patterns and contracts.

Check if function has Kotlin collection type:

```kotlin
...
.assertTrue { 
    it.returnType?.sourceDeclaration?.isKotlinCollectionType
}
```

## **Verify Generic Parameters**

Generic type parameters can be validated to ensure proper generic type usage and constraints.

Check if function has type parameters:

```kotlin
...
.assertTrue { 
    it.hasTypeParameters()
}
```

## Verify Generic Type Arguments

Generic type arguments can be checked for correct usage.

Check if return type has no type arguments:

```kotlin
...
.assertFalse {
    it.returnType?.hasTypeArguments()
}
```

## **Verify Top Level**

Top-level functions (functions not declared inside a class) can be specifically queried and validated:

```kotlin
...
.assertTrue { 
    it.isTopLevel
}
```

This helps ensure top-level functions follow project conventions, such as limiting their usage or enforcing specific naming patterns.

##


# Verify Properties

Properties can be checked for proper access modifiers, type declarations, and initialization patterns.

To verify properties start by querying all properties present in the project:

```kotlin
Konsist
.scopeFromProject()
.properties()
...
```

In practical scenarios you'll typically want to verify a specific subset of properties - such as those defined inside classes:

```kotlin
Konsist
.scopeFromProject()
.classes()
.properties()
...
```

Konsist allows you to verify multiple aspects of a properties. For a complete understanding of the available APIs, refer to the language reference documentation for KoPropertyDeclaration[^1].

Let's look at few examples.

## **Verify Name**&#x20;

Property names can be validated to ensure they follow project naming conventions and patterns.

Check if `Boolean` property has name starting with `is`:

```kotlin
...
.assertTrue { 
    it.type?.name == "Boolean" && it.hasNameStartingWith("is")
}
```

## **Verify Type**&#x20;

Property types can be validated to ensure type safety and conventions:

```kotlin
...
.assertTrue { 
    it.type?.name == "LocalDateTime"
}
```

## **Verify Modifiers**&#x20;

Property modifiers can be validated to ensure proper encapsulation:

```kotlin
...
.assertTrue { 
    it.hasLateinitModifier
}
```

## **Verify Annotations**&#x20;

Property annotations can be verified for presence and correct usage:

```kotlin
...
.assertTrue { 
    it.hasAnnotationOf(JsonProperty::class)
}
```

## **Verify Accessors**&#x20;

Getter and setter presence and implementation can be validated:

Check if property has `getter`:

```kotlin
...
.assertTrue { 
    it.hasGetter
}
```

Check if property has `setter`:

```kotlin
...
.assertTrue { 
    it.hasSetter
}
```

## **Verify Initialization**&#x20;

Property initialization can be verified:

```kotlin
...
.assertTrue { 
    it.isInitialized
}
```

## **Verify Delegates**

Property delegates can be verified:

Check if property has `lazy` delegate:

```
...
.assertTrue { 
    it.hasDelegate("lazy") 
}
```

## **Verify Visibility**&#x20;

Property visibility scope can be validated:

Check if property has `internal` modifier:

```kotlin
...
.assertTrue { 
    it.isInternal
}
```

## **Verify Mutability**&#x20;

Property mutability can be checked.

Check if property is immutable:

```kotlin
...
.assertTrue { 
    it.isVal
}
```

Check if property is mutable:

```kotlin
...
.assertTrue { 
    it.isVar
}
```

[^1]:


# Verify Generics

Type parameter vs type argument

To undersigned Konsist API let's look at the difference between `generic type parameters` and `generic type arguments`:

1. **Type Parameter** is the placeholder (like `T`) you write when *creating* a class or function (declaration site)
2. **Type Argument** is the actual type (like `String` or `Int`) you provide when *using* that class or function (use site)

Simple Examples:

```kotlin
// Example 1: Class
// Here 'T' is a TYPE PARAMETER
class Box<T>(val item: T)

// Here 'String' is a TYPE ARGUMENT
val stringBox = Box<String>("Hello")


// Example 2: Function
// Here 'T' is a TYPE PARAMETER
fun <T> printWithType(item: T) {
    println("Type is: ${item::class.simpleName}")
}

// Here 'String' and 'Int' are TYPE ARGUMENTS
printWithType<String>("Hello")  // prints: Type is: String
```

## Verify Type Parameters

Type parameters can be defined, for example, inside class or function.

### Check whether a class's generic type parameter has the name `UiState`:

```kotlin
// Code Snippet 
class View<UiState>(val state: UiState) // UiState is typeParamener 

// Konsist
Konsist
    .scopeFromProject()
    .classes()
    .typeParameters // access type parameters
    .assertTrue {
        it.name == "UiState" // true
    }
```

### Check whether function `type parameters` has `out` modifier:

<pre class="language-kotlin"><code class="lang-kotlin">//Code Snippet 
<strong>fun &#x3C;out T> setState(item: T?) {
</strong>    // ...
}

// Konsist
Konsist
    .scopeFromProject()
    .functions()
    .typeParameters // access type parameters
    .assertTrue {
        it.hasOutModifier // true
    }
</code></pre>

## Verify Type Arguments

### Check whether a property generic type argument has the name `Service`:

```kotlin
//Code Snippet 
val services: List<Service> = emptyList()

// Konsist
Konsist
    .scopeFromProject()
    .properties()
    .assertTrue { property ->
        property
            .type
            ?.typeArguments
            ?.flatten()
            ?.any { typeArgument -> typeArgument.name == "Service" }
    }
```

The `flatten()` extension method allows to flatten type parameters structure:

* For a type argument like `String`, it returns `listOf()`.
* For a type argument like `List<String>`, it returns `listOf(String)`.
* For a type argument like `Map<List<String>, Int>`, it returns `listOf("List, String, Int)`.

### Check if all functions parameters are have generic type argument ending with `UIState`:

```kotlin
// Snippet 
fun setState(uiState: View<WelcomeUIState>)

// Konsist Test
Konsist
    .scopeFromProject()
    .properties()
    .parameters
    .types
    .typeArguments
    .assertTrue { 
        it.hasNameEndingWith("UIState")  // true
    }
```

### Check all parents have \`String\` type argument:

```kotlin
// Snippet 
open class Container<T>(private val item: T) { }
class StringContainer(text: String) : Container<String>(text) { }

// Konsist Test
Konsist
    .scopeFromProject()
    .classes()
    .parents()
    .typeArguments
    .flatten()
    .assertTrue { 
        it.name == "String"  // true
    }
```


# Verify Source Declarations

The source declaration (`sourceDeclaration` property) holds the reference to actual type declaration such as class or interface.

Konsist API allows for verify properties of such type e.g.:

* Check if property type implements certain interface
* Check if function return type name ends with `Repository`
* Check if parent class is annotated with given annotation

Every declaration that is using another type such as property, function, parent exposes `sourceDeclaration` property.

Let's look at few examples:

## Verify Property Source Declaration

Check if type of `current` property is has a type which is a class declaration heaving `internal` modifier:

```kotlin
// Code Snippet
internal class Engine
val current: Engine? = null

// Konsist test
Konsist
   .scopeFromProject()
   .properties()
   .assertTrue {
      it
      .type
      ?.sourceDeclaration
      ?.asClassDeclaration()
      ?.hasInternalModifier // true
   }

```

{% hint style="info" %}
Note that explicit casting (`asXDeclaration`) has to be used to access specific properties of the declaration.
{% endhint %}

## Verify Function Return Type Source Declaration

Check if function return type is a basic Kotlin type:

```kotlin
// Code Snippet
internal class Engine {
   fun start(): Boolean
}

// Konsist test
Konsist
   .scopeFromProject()
   .classes()
   .functions()
   .assertTrue {
      it.returnType?
      .sourceDeclaration
      ?.isKotlinBasicType
   }
```

## Verify Class Has Interface Source Declaration

```kotlin
// Code Snippet
internal class Engine {
   fun start(): Boolean
}

// Konsist test
Konsist
   .scopeFromProject()
   .classes()
   .parents()
   .assertTrue {
      it
      .sourceDeclaration
      ?.isInterface
   }
```


# Add Konsist Existing To Project (Baseline)

Retrofitting Konsist into a project that hasn't followed strict structural guidelines can pose initial challenges, necessitating a thoughtful approach to smoothly transition without disrupting ongoing development. Unlike most linters, which provide a [baseline file](https://developer.android.com/studio/write/lint#snapshot), Konsist follows a different methodology (for now).

{% hint style="success" %}
The baseline file will be added in the future.
{% endhint %}

There are two approaches that can be employed when retrofitting Konsist into an existing project[#create-more-granular-scopes](#create-more-granular-scopes "mention") and [#suppress-annotation](#suppress-annotation "mention").

## Create Granular Scopes

Scope represents a set of Kotlin files. The scope allows to verification of all Kotlin files in the project or only a subset of the project code base.

{% hint style="info" %}
See [Create The Scope](/writing-tests/koscope).
{% endhint %}

When refactoring an existing application, you can either choose to first refactor a module and then add a Konsist test or initially add the Konsist test to identify errors, followed by the necessary refactor. Both strategies aim to ensure modules align with Konsist's structural guidelines.

Consider this The `MyDiet` application with feature 3 modules:

<figure><img src="/files/yoZLAhfzv6EEsq2zUzSX" alt=""><figcaption></figcaption></figure>

At first, the Konsist test can be applied to a single module:

```kotlin
Konsist
    .scopeFromModule("featureCaloryCalculator")
    .classes()
    .assertTrue { it.hasTestClasses() }
```

{% hint style="info" %}
To review the content of a given scope see [Debug Konsist Test](/features/debug-konsist-test).
{% endhint %}

As refactoring proceeds and code gets aligned, the Konsist scope can be extended to another feature module (`featureGroceryListGenerator`):

```kotlin
Konsist
    .scopeFromModule("featureCaloryCalculator", "featureGroceryListGenerator")
    .classes()
    .assertTrue { it.hasTest() }
```

When entire code base (all modules) are aligned with the Konsist tests, the scope can be retrieved from the entire project:

```kotlin
Konsist
    .scopeFromProject()
    .classes()
    .assertTrue { it.hasTest() }
```

Usage of project scope (`scopeFromProject` ) is a recommended approach because it helps to guard future modules without modifying the existing Konsist test.

Konsist provides a flexible API to create scopes from modules, source sets, packages, files, etc., and combine these scopes together. See [Create The Scope](/writing-tests/koscope).

## Suppress Annotation

The second approach, Suppress Annotation, may be helpful when to Konsist swiftly without making substantial alterations to the existing kotlin files. See [#suppress](#suppress "mention").


# Debug Konsist Test

Understand whats going on

To gain insight into the inner workings of the Konsist test, examine the data provided by the Konsist API.

Two primary tools can help you comprehend the inner workings of the Konsist API are [#evaluate-expression](#evaluate-expression "mention") and [#print-to-console](#print-to-console "mention").

## Evaluate Expression Debugger Window

The [IntelliJ IDEA](https://www.jetbrains.com/idea/) / [Android Studio](https://developer.android.com/studio) provides a handy feature called [Evaluate Expressions](https://www.jetbrains.com/help/rider/Evaluating_Expressions.html#eval-expression-dialog) which is an excellent tool for debugging Konsist tests.

Create a simple test class and click on the line number to add the [breakpoint](https://www.jetbrains.com/help/idea/using-breakpoints.html):

<figure><img src="/files/VPJ5kqrRlPTPYkhGGPSm" alt=""><figcaption></figcaption></figure>

Debug the test:

<figure><img src="/files/L5NVggyS4JiiEfuDLBuF" alt=""><figcaption></figcaption></figure>

When the program stops at the breakpoint (blue line background) run `Evaluate Expression...` action...

<figure><img src="/files/HYmWNQCThBxTGALUgUj2" alt=""><figcaption></figcaption></figure>

...or press `Evaluate Expression...` button:

<figure><img src="/files/L6VjWawfyPGeHcQ3cxjW" alt=""><figcaption></figcaption></figure>

In the `Evaluate` window enter the code and click the `Evaluate` the button. For example, you can list all of the classes present in the scope to get the class names:

<figure><img src="/files/AiIlqt1VqU2J8eNqB55H" alt=""><figcaption></figcaption></figure>

You can also display a single-class declaration to view its `name`:

```kotlin
koScope
    .classes()
    .first()
    .name
```

## Print To Console

Konsist provides a flexible API that allows to output of the specified data as console logs. Scopes, lists of declarations, and single declarations can all be printed.

Print a list of files from `KoScope`:

```kotlin
koScope // KoScope
    .print()
```

Print multiple declarations:

```kotlin
koScope
    .classes() // List<KoClassDeclaration>
    .print()
```

Print a given attribute for each declaration:

```kotlin
koScope
    .classes() // List<KoClassDeclaration>
    .print { it.fullyQualifiedName }
```

Print single declaration:

```kotlin
koScope
    .classes() // List<KoClassDeclaration>
    .first() // KoClassDeclaration
    .print()
```

Print list of queried declarations before and after query:

```kotlin
koScope
    .classes() // List<KoClassDeclaration>
    .print(prefix = "Before") // or .print(prefix = "Before") { it.name }
    .withSomeAnnotations("Logger")
    .print(prefix = "After") // or .print(prefix = "After") { it.name }
```

Print nested declarations:

```kotlin
koScope
    .classes() // List<KoClassDeclaration>
    .constructors // List<KoConstructorDeclaration>
    .parameters //  List<KoParameterDeclaration>
    .print()
```


# Declaration

What is declaration?

The declaration (`KoDeclaration`) represents a code entity, a piece of Kotlin code. Every parsed Kotlin File (`KoFileDeclaration`) contains one or more declarations. The declaration can be a package (`KoPackageDeclaration`), property (`KoPropertyDeclaration`), annotation (`KoAnnotationDeclaration`), class (`KoClassDeclaration`), etc.

Consider this Kotlin code snippet file:

```kotlin
private const val logLevel = "debug"

@Entity
open class Logger(val level: String) {
   fun log(message: String) {
   
   } 
}
```

The above snippet is represented by the `KoFileDeclaration`class. It contains two declarations - property declaration (`KoPropertyDeclaration`) and class declaration (`KoClassDeclaration`). The `Logger` class declaration contains a single function declaration (`KoFunctionDeclaration` ):

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TD
KoFile
KoFile---KoProperty
KoFile---KoClass
KoClass---KoFunction" %}

Declarations mimic the Kotlin file structure. Konsts API provides a way to retrieve every element. To get all functions in all classes inside the file using `.classes().functions()` :

```kotlin
koFile // List<KoFile>
    .classes()  // List<KoClassDeclaration>
    .functions() // List<KoFunctionDeclaration>
```

{% hint style="info" %}
To print declaration content use `koDeclaration.print()` method.
{% endhint %}

## Declaration Properties

Each declaration contains a set of properties to facilitate filtering and verification eg. `KoClass` declaration has `name`, `modifiers` , `annotations` , `declarations` (containing `KoFunction`) etc. Here is how the `name` of the function can be retrieved.

```kotlin
val name = koFile // List<KoFileDeclaration>
    .classes()  // List<KoClassDeclaration>
    .functions() // List<KoFunctionDeclaration>
    .first() // KoFunctionDeclaration
    .name // String
    
println(name) // prints: log
```

Although it is possible to retrieve a property of a single declaration usually verification is performed on a collection of declarations matching certain criteria eg. methods annotated with specific annotations or classes residing within a single package. See the [Declaration Filtering](/writing-tests/declaration-query-and-filter) page.

## Debugging Declaration Properties

Each declaration exposes a few additional properties to help with debugging:

* `text` - provides declaration text eg. `val property role = "Developer"`
* `location` - provides file path with file name, line, and column e.g. `~\Dev\IdeaProject\SampleApp\src\kotlin\com\sample\Logger:10:5`
* `locationWithText` - provides `location` together with the declaration `text`


# Declaration Vs Property

Some code constructs can be represented as declarations (declaration-site) and as properties (use-site).

## Declaration Site

Consider this annotation class:

```kotlin
annotation class CustomLogger
```

The above code represents the declaration of the `CustomLogger` annotation class, the place in the code where this annotation is declared (declaration-site). This declaration can be retrieved by filtering `KoScope` declarations...

```kotlin
koScope
    .classes()
    .withAnnotationModifier()
```

For example, such declaration can be used to check if annotations reside in a desired package:

```kotlin
// Every annotation class must reside in the "annotation" package

koScope
    .classes()
    .withAnnotationModifier()
    .assertTrue { it.resideInPackage("..annotation..") }
```

## Use Site

Now consider this function:

```kotlin
@CustomLogger
fun logHello() {
    println("Hello")
}
```

The above code also contains `CustomLogger` annotation. However, this time code represents the place in the code where the annotation is used (use-site). Such annotations can be accessed using the `annotations` property:

<pre class="language-kotlin"><code class="lang-kotlin">koScope
    .functions()
<strong>    .annotations
</strong></code></pre>

Such properties can be used to check if the function annotated with `CustomLogger` annotation has the correct name prefix:

```kotlin
// Every function with a name starting with "log" is annotated with CustomLogger

koScope
    .functions()
    .withAllAnnotations("CustomLogger")
    .assertTrue {
        it.hasNameStartingWith("log")
    }
```


# Compiler Type Inference

The primary focus of Konsist API is to reflect the state of the Kotlin source code (that will be verified), not the state of the running program. The Kotlin compiler has a deeper understanding of the Kotlin code base than Konsist, because the compiler can infer more information. Let's take a look at a few examples.

### Class Example

Consider this class:&#x20;

```kotlin
class Logger
```

Is `Logger` class `public`? Yes obviously it is `public`, however, the `hasPublicModifier` method returns the `false` value:

```kotlin
koClass.hasPublicModifier() // false
```

Why is that? The `public` visibility modifier is the default visibility modifier in Kotlin. Meaning that class will be `public` even if it does not have the explicit `public` modifier. Since the class has no `public` modifier the `hasPublicModifier` method returns false. To distinguish between class being `public` and class having explicit`public` modifier Konsist API provides another method to retrieve declaration visibility:

```kotlin
koClass.isPublicOrDefault() // true
```

### Property Example

Let's look at the `name` property:

```
private val name = String
```

The `name` property is obviously of the `String` type. However `String` type is inferred, so Konsist has no way of Knowing the actual type (in this exact case this is achievable, but with more complex expressions containing delegates, setters, getters, or methods this approach would not work).

{% hint style="info" %}
The [K2 Compiler plugin](https://www.youtube.com/watch?v=Pl-89n9wDqo) may enable this feature for Konsist.
{% endhint %}

### Primary Constructor Example

Let's look at the primary constructor for the same class:

```kotlin
class Logger
```

The `Logger` the class has a primary constructor because the Kotlin compiler will generate a parameterless constructor under the hood. However, the Konsist API will return a `null` value  because the primary constructor is not present in the Kotlin source code:

```kotlin
koClass.primaryConstructor // null
```

### Function Return Type Example

Consider this function:

```kotlin
fun getName() = "Konsist"
```

Kotlin will infer `String` as the return type of the `getName` function. Since the source code does not contain this explicit return type Konsist lacks information about the return type.  In this scenario, `hasReturnType` the method will return the `false` value:

```kotlin
koFunction.hasReturnType() // false
```

Unlike the previous example, Konsist has no way to determine the actual function return type.


# Package Wildcard

Select packages

Package wildcard syntax is used to provide a more flexible way of querying packages.

The two dots (`..`) means any zero or more packages eg. all classes reside in a package starting with `com.app`:

```kotlin
    Konsist
        .scopeFromProject()
        .classes()
        .assertTrue { it.resideInPackages("com.app..") }
        
// com.app.data - valid  
// com.app.data.repository - valid  
// com.data - invalid
// com - invalid
        
```

Package wildcard syntax can be used multiple times inside the string argument. Here all interfaces reside in a package `logger` prefixed and suffixed by any number of packages:

```kotlin
    Konsist
        .scopeFromProject()
        .interfaces()
        .assertTrue { it.resideInPackages("..logger..") }

// logger - valid  
// com.logger - valid  
// com.logger.tree - valid
// com - invalid
```


# Declaration References

Declaration reference represents a link between codebase declarations. Konsist allows to precisely verify properties of linked type. This type can be used in function or property declaration or child/parent class or interface. For example

1\. Verify if all types of function parameters are interfaces:

```kotlin
Konsist
    .scopeFromProject()
    .functions()
    .parameters
    .types
    .assertTrue {
        it.isInterface
    }
```

2\. Access properties of parents (parent classes and child interfaces). Below snippet checks if parent class has `internal` modifier:

```kotlin
fun `all parrent interfaces are internal`() {
    Konsist
        .scopeFromProject()
        .classes()
        .parentInterfaces()
        .assertTrue {
            it.hasInternalModifier()
        }
}
```

3\. Access properties of children (child classes and child interfaces). Below snippet checks if all interfaces have children that resided in `..somepackage..` package:

```kotlin
Konsist
    .scopeFromProject()
    .interfaces()
    .assertTrue {
        it.hasAllChildren(indirectChildren = true) { child -> 
            child.resideInPackage("..somepackage..") 
        }
    }
```

## Type Representation

Kotlin types can defined in multiple ways. Consider `foo` property with `Foo` type:

```
val foo: Foo
```

The `Foo` type can be defined by:

* class
* interface
* object
* type alias
* import alias
* kotlin types (Kotlin basic type or Kotlin collections type)
* function type
* external library (type defined outside project codebase) represents declaration which is not defined in the project

The `Foo`  type can be represented by one of `KoXDeclaration` classes:

<table><thead><tr><th width="464">Sorce</th><th width="282">Declaration</th></tr></thead><tbody><tr><td><a data-mention href="#type-represented-by-class">#type-represented-by-class</a></td><td><code>KoClassDeclaration</code></td></tr><tr><td><a data-mention href="#type-represented-by-interface">#type-represented-by-interface</a></td><td><code>KoInterfaceDeclaration</code></td></tr><tr><td><a data-mention href="#type-represented-by-object">#type-represented-by-object</a></td><td><code>KoObjectDeclaration</code></td></tr><tr><td><a data-mention href="#type-represented-by-type-apias">#type-represented-by-type-apias</a></td><td><code>KoTypeAliasDeclaration</code></td></tr><tr><td><a data-mention href="#type-represented-by-import-alias">#type-represented-by-import-alias</a></td><td><code>KoImportAliasDeclaration</code></td></tr><tr><td><a data-mention href="#type-represented-by-kotlin-type">#type-represented-by-kotlin-type</a></td><td><code>KoKotlinTypeDeclaration</code></td></tr><tr><td><a data-mention href="#type-represented-function-type">#type-represented-function-type</a></td><td><code>KoFunctionDeclaration</code></td></tr><tr><td><a data-mention href="#type-represented-by-external-type">#type-represented-by-external-type</a></td><td><code>KoExternalDeclaration</code></td></tr></tbody></table>

Each of these types possesses a largely distinct set of characteristics; for instance, classes and interfaces can include annotations, whereas import aliases cannot.

To access properties the specific declaration type, the declaration cast to more specific type is required (from generic `KoTypeDeclaration`). Example below assumes that `Foo` is represented by the `Foo` class:

```kotlin
Konsist
    .scopeFromProject()
    .properties()    
    .types
    .assertTrue { koTypeDeclaration ->
        val koClass = koTypeDeclaration as KoClassDeclaration

        koClass.hasAllAnnotations {
            it.representsTypeOf<String>()
        }
    }
```

To facilitate testing Konsist API provides set of dedicated casting extensions. The above code can be simplified:

```kotlin
Konsist
    .scopeFromProject()
    .properties()
    .types
    .assertTrue { koTypeDeclaration ->
        koTypeDeclaration
        .asClassDeclaration
        ?.hasAllAnnotations {
            it.representsTypeOf<String>()
        }
    }
```

Here is the list of all casting extensions:

<table data-full-width="true"><thead><tr><th>Sorce</th><th width="273">Declaration</th><th>Cast Extension</th><th>Type Check Extension</th></tr></thead><tbody><tr><td><a data-mention href="#type-represented-by-class">#type-represented-by-class</a></td><td><code>KoClassDeclaration</code></td><td><code>asClassDeclaration</code></td><td><code>isClass</code></td></tr><tr><td><a data-mention href="#type-represented-by-interface">#type-represented-by-interface</a></td><td><code>KoInterfaceDeclaration</code></td><td><code>asObjectDeclaration</code></td><td><code>isObject</code></td></tr><tr><td><a data-mention href="#type-represented-by-object">#type-represented-by-object</a></td><td><code>KoObjectDeclaration</code></td><td><code>asInterfaceDeclaration</code></td><td><code>isInterface</code></td></tr><tr><td><a data-mention href="#type-represented-by-type-apias">#type-represented-by-type-apias</a></td><td><code>KoTypeAliasDeclaration</code></td><td><code>asTypeAliasDeclaration</code></td><td><code>isTypeAlias</code></td></tr><tr><td><a data-mention href="#type-represented-by-kotlin-type">#type-represented-by-kotlin-type</a></td><td><code>KoImportAliasDeclaration</code></td><td><code>asImportAliasDeclaration</code></td><td><code>isImportAlias</code></td></tr><tr><td><a data-mention href="#type-represented-function-type">#type-represented-function-type</a></td><td><code>KoKotlinTypeDeclaration</code></td><td><code>asKotlinTypeDeclaration</code></td><td><code>isKotlinType</code></td></tr><tr><td><a data-mention href="#type-represented-by-external-type">#type-represented-by-external-type</a></td><td><code>KoFunctionDeclaration</code></td><td><code>asFunctionTypeDeclaration</code></td><td><code>isFunctionType</code></td></tr><tr><td><a data-mention href="#external-types">#external-types</a></td><td><code>KoExternalDeclaration</code></td><td><code>asExternalTypeDeclaration</code></td><td><code>isExternalType</code></td></tr></tbody></table>

### Type Represented By Class

Source code:

```kotlin
internal class Foo
```

Usage:

```kotlin
val foo: Foo? = null
```

Konsist test:

```kotlin
scope
    .properties()
    .types
    .assertTrue {
        it.asClassDeclaration?.hasInternalModifier
    }
```

### Type Represented By Interface

Source code:

```kotlin
internal interface Foo
```

Usage:

```kotlin
val foo: Foo? = null
```

Konsist test:

```kotlin
scope
    .properties()
    .types
    .assertTrue {
        it.asInterfaceDeclaration?.hasInternalModifier
    }
```

### Type Represented By Object

This scenario is uncommon, but still possible.

Source code:

```kotlin
internal object Foo
```

Usage:

```kotlin
val foo: Foo? = null
```

Konsist test:

```kotlin
scope
    .properties()
    .types
    .assertTrue {
        it.asObjectDeclaration?.hasInternalModifier
    }
```

### Type Represented By Type Alias

Source code:

```kotlin
internal object Foo
```

Usage:

```kotlin
typealias MyFoo = Foo
val foo: MyFoo? = null
```

Konsist test:

<pre class="language-kotlin"><code class="lang-kotlin">scope
    .properties()
    .types
    .assertTrue {
<strong>        it
</strong><strong>            .sourceTypeAlias
</strong><strong>            .type
</strong><strong>            .sourceInterface
</strong><strong>            .hasInternalModifier
</strong>    }
</code></pre>

### Type Represented By Import Alias

Source code:

```kotlin
internal object Foo
```

Usage:

```kotlin
import com.app.Foo as MyFoo

val foo: MyFoo? = null
```

Konsist test:

<pre class="language-kotlin"><code class="lang-kotlin">scope
    .properties()
    .types
    .assertTrue {
<strong>        it
</strong><strong>            .asTypeAliasDeclaration
</strong><strong>            .type
</strong><strong>            .asInterfaceDeclaration
</strong><strong>            .hasInternalModifier
</strong>    }
</code></pre>

### Type Represented By Kotlin Type

Source code:

```kotlin
// Kotlin internal source code for String
```

Usage:

```kotlin
val foo: String? = null
```

Konsist test:

<pre class="language-kotlin"><code class="lang-kotlin">scope
    .properties()
    .types
    .assertTrue {
<strong>        it.asKotlinTypeDeclaration.name == "String"
</strong>    }
</code></pre>

### Type Represented Function Type

Source code:

```kotlin
// Kotlin internal source code
```

Usage:

```kotlin
val foo: () -> Unit? = null
```

Konsist test:

<pre class="language-kotlin"><code class="lang-kotlin">scope
    .properties()
    .types
    .assertTrue {
<strong>        it
</strong><strong>            .sourceFunctionType
</strong>            .parameterTypes
            .isEmpty()
    }
</code></pre>

### Type Represented By External Type

External type represents the type defined outside of the project codebase, usually by external library. Konsist is not able to parse this type, so type  information is limited (Konsist is not able to parse the compiled file).

For Example:

```
class MyViewModel: ViewModel
```

The Android `ViewModel` class is provided by `androidx.lifecycle:lifecycle-viewmodel-ktx` dependency, so Konsist has limited information.&#x20;


# Indirect Parents

The `indirectParents` parameter  (`parents()`, `hasParentClass()`, `hasAllParentInterfacesOf` methods etc.). specifies whether or not to retrieve parent of the parent (indirect parents). By default, `indirectParents` is `false` e.g.

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart TB
ClassA-->ClassB-->ClassC
style ClassC fill:#52B523,stroke:#666,stroke-width:2px,color:#fff" %}

For above inheritance hierarchy is possible to retrieve:

1. Direct parents of `ClassC` (`ClassB`):

```kotlin
Konsist
	.scopeFromProject()
	.classes()
	.first { it.name == "ClassC" }
	.parents() // ClassB
```

2. All parents present in the codebase hierarchy (`ClassB` and `ClassC`):

```
Konsist
	.scopeFromProject()
	.classes()
	.first { it.name == "SampleClass" }
	.parents(indirectParents = true) // ClassB, ClassA
```

Notice that only parents existing in the project code base are returned.


# Kotest Support

Konsist + Kotest

Konsist has first-class support for [Kotest](https://kotest.io/) meaning that every following release will be developed with Kotest compatibility in mind. API has been improved to support Kotest flows. However, Konsist cannot automatically retrieve Kotest test names, meaning the test name won't appear in error logs upon test failure. To fully utilize Konsist with Kotest, you must explicitly provide the test name.

## Setting The Test Name

Konsist can't obtain the test name from all dynamic tests (including [Kotest](https://kotest.io/) tests).

It's recommended to provide the test name using the `testName` parameter. Supplying a test name provides additional benefits:

* The appropriate test names will appear in the log if the test fails.
* Test suppression will be facilitated (See [Suppress Konsist Test](/writing-tests/suppressing-konsist-test))

{% hint style="info" %}
See [Explicit Test Names](/advanced/dynamic-konsist-tests/explicit-test-names) for more details.
{% endhint %}

Kotest enables fetching the test name from the context to populate the `testName` argument, ensuring consistent naming of tests:

```kotlin
class UseCaseTest : FreeSpec({
    "useCase test" {
        Konsist
            .scopeFromProject()
            .classes()
            .assertTrue (testName = this.testCase.name.testName) {  }
    }
})
```

{% hint style="info" %}
This example is used [FreeSpec](https://kotest.io/docs/framework/testing-styles.html#free-spec) however Kotest provides [multiple testing styles](https://kotest.io/docs/framework/testing-styles.html).
{% endhint %}

## KoTestName Extension

To facilitate test name retrieval you can add a custom `koTestName` extension:

```kotlin
val TestScope.koTestName: String
    get() = this.testCase.name.testName
```

This extension enables more concise syntax for providing Kotest test name:

```kotlin
class UseCaseTest : FreeSpec({
    "useCase test" {
        Konsist
            .scopeFromProject()
            .classes()
            .assertTrue (testName = koTestName) {  } // extension used
    }
})
```

{% hint style="info" %}
The above test will execute multiple assertions per test (all use cases will be verified in a single test). If you prefer better isolation and more visibility you can execute every assertion as a separate test. See the[Dynamic Konsist Tests](/advanced/dynamic-konsist-tests) page.
{% endhint %}


# Starter Projects

Konsist provides preconfigured sample projects. Each project contains a complete build script config and a simple Konsist test. Projects are available in the [starter-projects](https://github.com/LemonAppDev/konsist/tree/develop/samples/starter-projects) directory. Each [JUnit5](https://junit.org/junit5/) and [Kotest](https://kotest.io/) project has an additional dynamic test ([Dynamic Konsist Tests](/advanced/dynamic-konsist-tests))(dynamic tests are currently available at the [develop branch](https://github.com/LemonAppDev/konsist/tree/develop/samples/starter-projects)).

<table><thead><tr><th width="225"></th><th width="148">JUnit 4</th><th>JUnit 5</th><th>Kotest</th></tr></thead><tbody><tr><td>Android</td><td>Static</td><td>Static + Dynamic</td><td>Static + Dynamic</td></tr><tr><td>Spring</td><td>Static</td><td>Static + Dynamic</td><td>Static + Dynamic</td></tr><tr><td>Kotlin Multiplatform</td><td>Static</td><td>Static + Dynamic</td><td>Static + Dynamic</td></tr></tbody></table>

## Projects:

### Android

* JUnit 4
  * [android-gradle-groovy-junit-4](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/android-gradle-groovy-junit-4)
  * [android-gradle-kotlin-junit-4](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/android-gradle-kotlin-junit-4)
* JUnit 5
  * [android-gradle-groovy-junit-5](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/android-gradle-groovy-junit-5)
  * [android-gradle-kotlin-junit-5](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/android-gradle-kotlin-junit-5)
* Kotest
  * [android-gradle-groovy-kotest](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/android-gradle-groovy-kotest)
  * [android-gradle-kotlin-kotest](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/android-gradle-kotlin-kotest)

### Spring

* JUnit 5
  * [spring-gradle-groovy-junit-5](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/spring-gradle-groovy-junit-5)
  * [spring-gradle-kotlin-junit-5](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/spring-gradle-kotlin-junit-5)
  * [spring-maven-junit5](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/spring-maven-junit5)
* Kotest
  * [spring-gradle-kotlin-kotest](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/spring-gradle-kotlin-kotest)
  * [spring-gradle-groovy-kotest](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/spring-gradle-groovy-kotest)
  * [spring-maven-kotest](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/spring-maven-kotest)

### KMP

* JUnit5
  * [konsist-starter-kmp-gradle-kotlin-junit5](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/kmp-gradle-kotlin-junit5)
* Kotest
  * [konsist-starter-kmp-gradle-kotlin-kotest](https://github.com/LemonAppDev/konsist/tree/main/samples/starter-projects/kmp-gradle-kotlin-kotest)


# Snippets

In Konsist all checks are tailored for a given project.&#x20;

As the project grows additional checks can be defined to enforce various checks eg. layer boundaries, package structure, class naming, and more. The following sections contain a set of sample checks to give an idea of what is achievable with Konsist.

Most of the snippets are wrapped as [JUnit](https://junit.org/) tests, however, these snippets can be easily wrapped in the [kotest](https://kotest.io/) tests.


# General Snippets

## 1. Files In `ext` Package Must Have Name Ending With `Ext`

```kotlin
@Test
fun `files in 'ext' package must have name ending with 'Ext'`() {
    Konsist
        .scopeFromProject()
        .files
        .withPackage("..ext..")
        .assertTrue { it.hasNameEndingWith("Ext") }
}
```

## 2. All Data Class Properties Are Defined In Constructor

```kotlin
@Test
fun `all data class properties are defined in constructor`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withModifier(KoModifier.DATA)
        .properties()
        .assertTrue { it.isConstructorDefined }
}
```

## 3. Every Class Has Test

```kotlin
@Test
fun `every class has test`() {
    Konsist
        .scopeFromProduction()
        .classes()
        .assertTrue { it.hasTestClasses() }
}
```

## 4. Every Class - Except Data And Value Class - Has Test

```kotlin
@Test
fun `every class - except data and value class - has test`() {
    Konsist
        .scopeFromProduction()
        .classes()
        .withoutModifier(KoModifier.DATA, KoModifier.VALUE)
        .assertTrue { it.hasTestClasses() }
}
```

## 5. Properties Are Declared Before Functions

```kotlin
@Test
fun `properties are declared before functions`() {
    Konsist
        .scopeFromProject()
        .classes()
        .assertTrue {
            val lastKoPropertyDeclarationIndex = it
                .declarations(includeNested = false, includeLocal = false)
                .indexOfLastInstance<KoPropertyDeclaration>()

            val firstKoFunctionDeclarationIndex = it
                .declarations(includeNested = false, includeLocal = false)
                .indexOfFirstInstance<KoFunctionDeclaration>()

            if (lastKoPropertyDeclarationIndex != -1 && firstKoFunctionDeclarationIndex != -1) {
                lastKoPropertyDeclarationIndex < firstKoFunctionDeclarationIndex
            } else {
                true
            }
        }
}
```

## 6. Every Constructor Parameter Has Name Derived From Parameter Type

```kotlin
@Test
fun `every constructor parameter has name derived from parameter type`() {
    Konsist
        .scopeFromProject()
        .classes()
        .constructors
        .parameters
        .assertTrue {
            val nameTitleCase = it.name.replaceFirstChar { char -> char.titlecase(Locale.getDefault()) }
            nameTitleCase == it.type.sourceType
        }
}
```

## 7. Every Class Constructor Has Alphabetically Ordered Parameters

```kotlin
@Test
fun `every class constructor has alphabetically ordered parameters`() {
    Konsist
        .scopeFromProject()
        .classes()
        .constructors
        .assertTrue { it.parameters.isSortedByName() }
}
```

## 8. Enums Has Alphabetically Ordered Consts

```kotlin
@Test
fun `enums has alphabetically ordered consts`() {
    Konsist
        .scopeFromProduction()
        .classes()
        .withAllModifiers(KoModifier.ENUM)
        .assertTrue { it.enumConstants.isSortedByName() }
}
```

## 9. Companion Object Is Last Declaration In The Class

```kotlin
@Test
fun `companion object is last declaration in the class`() {
    Konsist
        .scopeFromProject()
        .classes()
        .assertTrue {
            val companionObject = it.objects(includeNested = false).lastOrNull { obj ->
                obj.hasModifier(KoModifier.COMPANION)
            }

            if (companionObject != null) {
                it.declarations(includeNested = false, includeLocal = false).last() == companionObject
            } else {
                true
            }
        }
}
```

## 10. Every Value Class Has Parameter Named `value`

```kotlin
@Test
fun `every value class has parameter named 'value'`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withValueModifier()
        .primaryConstructors
        .assertTrue { it.hasParameterWithName("value") }
}
```

## 11. No Empty Files Allowed

```kotlin
@Test
fun `no empty files allowed`() {
    Konsist
        .scopeFromProject()
        .files
        .assertFalse { it.text.isEmpty() }
}
```

## 12. No Field Should Have `m` Prefix

```kotlin
@Test
fun `no field should have 'm' prefix`() {
    Konsist
        .scopeFromProject()
        .classes()
        .properties()
        .assertFalse {
            val secondCharacterIsUppercase = it.name.getOrNull(1)?.isUpperCase() ?: false
            it.name.startsWith('m') && secondCharacterIsUppercase
        }
}
```

## 13. No Class Should Use Field Injection

```kotlin
@Test
fun `no class should use field injection`() {
    Konsist
        .scopeFromProject()
        .classes()
        .properties()
        .assertFalse { it.hasAnnotationOf<Inject>() }
}
```

## 14. No Class Should Use Java Util Logging

```kotlin
@Test
fun `no class should use Java util logging`() {
    Konsist
        .scopeFromProject()
        .files
        .assertFalse { it.hasImport { import -> import.name == "java.util.logging.." } }
}
```

## 15. Package Name Must Match File Path

```kotlin
@Test
fun `package name must match file path`() {
    Konsist
        .scopeFromProject()
        .packages
        .assertTrue { it.hasMatchingPath }
}
```

## 16. No Wildcard Imports Allowed

```kotlin
@Test
fun `no wildcard imports allowed`() {
    Konsist
        .scopeFromProject()
        .imports
        .assertFalse { it.isWildcard }
}
```

## 17. Forbid The Usage Of `forbiddenString` In File

```kotlin
@Test
fun `forbid the usage of 'forbiddenString' in file`() {
    Konsist
        .scopeFromProject()
        .files
        .assertFalse { it.hasTextContaining("forbiddenString") }
}
```

## 18. All Function Parameters Are Interfaces

```kotlin
@Test
fun `all function parameters are interfaces`() {
    Konsist
        .scopeFromProject()
        .functions()
        .parameters
        .types
        .assertTrue { it.sourceDeclaration?.isInterface }
}
```

## 19. All Parent Interfaces Are Public

```kotlin
@Test
fun `all parent interfaces are public`() {
    Konsist
        .scopeFromProject()
        .classes()
        .parentInterfaces()
        .sourceDeclarations()
        .interfaceDeclarations()
        .assertTrue { it.hasPublicModifier }
}
```

## 20. Return Type Of All Functions Are Immutable

```kotlin
@Test
fun `return type of all functions are immutable`() {
    Konsist
        .scopeFromProject()
        .functions()
        .returnTypes
        .assertFalse { it.isMutableType }
}
```


# Android Snippets

Konsist can be used to guard the consistency of the [Android](https://www.android.com/) project.

{% hint style="info" %}
The [android-showcase](https://github.com/igorwojda/android-showcase) project contains set of Konsist tests.
{% endhint %}

## 1. Classes Extending `ViewModel` Should Have `ViewModel` Suffix

```kotlin
@Test
fun `classes extending 'ViewModel' should have 'ViewModel' suffix`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withParentClassOf(ViewModel::class)
        .assertTrue { it.name.endsWith("ViewModel") }
}
```

## 2. Every `ViewModel` Public Property Has `Flow` Type

```kotlin
@Test
fun `Every 'ViewModel' public property has 'Flow' type`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withParentClassOf(ViewModel::class)
        .properties()
        .assertTrue {
            it.hasPublicOrDefaultModifier && it.hasType { type -> type.name == "kotlinx.coroutines.flow.Flow" }
        }
}
```

## 3. `Repository` Classes Should Reside In `repository` Package

```kotlin
@Test
fun `'Repository' classes should reside in 'repository' package`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("Repository")
        .assertTrue { it.resideInPackage("..repository..") }
}
```

## 4. No Class Should Use Android Util Logging

```kotlin
@Test
fun `no class should use Android util logging`() {
    Konsist
        .scopeFromProject()
        .files
        .assertFalse { it.hasImport { import -> import.name == "android.util.Log" } }
}
```

## 5. All JetPack Compose Previews Contain `Preview` In Method Name

```kotlin
@Test
fun `All JetPack Compose previews contain 'Preview' in method name`() {
    Konsist
        .scopeFromProject()
        .functions()
        .withAnnotationOf(Preview::class)
        .assertTrue {
            it.hasNameContaining("Preview")
        }
}
```

## 6. Every Class With Serializable Must Have Its Properties Serializable

```kotlin
@Test
fun `every class with Serializable must have its properties Serializable`() {
    val message =
        """In Android, every serializable class must implement the Serializable interface 
    |or be a simple non-enum type because this is how the Java and Android serialization 
    |mechanisms identify which objects can be safely converted to a byte stream for 
    |storage or transmission, ensuring that complex objects can be properly reconstructed 
    |when deserialized.""".trimMargin()

    Konsist
        .scopeFromProduction()
        .classes()
        .withParentNamed("Serializable")
        .properties()
        .types
        .sourceDeclarations()
        .withoutKotlinBasicTypeDeclaration()
        .withoutClassDeclaration { it.hasEnumModifier }
        .assertTrue(additionalMessage = message) {
            it.asClassDeclaration()?.hasParentWithName("Serializable")
        }
}
```


# Spring Snippets

Konsist can be used to guard the consistency of the [Spring](https://spring.io/) project.

## 1. Interfaces With `Repository` Annotation Should Have `Repository` Suffix

```kotlin
@Test
fun `interfaces with 'Repository' annotation should have 'Repository' suffix`() {
    Konsist
        .scopeFromProject()
        .interfaces()
        .withAnnotationOf(Repository::class)
        .assertTrue { it.hasNameEndingWith("Repository") }
}
```

## 2. Classes With `RestController` Annotation Should Have `Controller` Suffix

```kotlin
@Test
fun `classes with 'RestController' annotation should have 'Controller' suffix`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withAnnotationOf(RestController::class)
        .assertTrue { it.hasNameEndingWith("Controller") }
}
```

## 3. Controllers Never Returns Collection Types

```kotlin
@Test
fun `controllers never returns collection types`() {
    /*
    Avoid returning collection types directly. Structuring the response as
    an object that contains a collection field is preferred. This approach
    allows for future expansion (e.g., adding more properties like "totalPages")
    without disrupting the existing API contract, which would happen if a JSON
    array were returned directly.
    */
    Konsist
        .scopeFromPackage("story.controller..")
        .classes()
        .withAnnotationOf(RestController::class)
        .functions()
        .assertFalse { function ->
            function.hasReturnType { it.isKotlinCollectionType }
        }
}
```

## 4. Classes With `RestController` Annotation Should Reside In `controller` Package

```kotlin
@Test
fun `classes with 'RestController' annotation should reside in 'controller' package`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withAnnotationOf(RestController::class)
        .assertTrue { it.resideInPackage("..controller..") }
}
```

## 5. Classes With `RestController` Annotation Should Never Return Collection

```kotlin
@Test
fun `classes with 'RestController' annotation should never return collection`() {
    Konsist
        .scopeFromPackage("story.controller..")
        .classes()
        .withAnnotationOf(RestController::class)
        .functions()
        .assertFalse { function ->
            function.hasReturnType { it.hasNameStartingWith("List") }
        }
}
```

## 6. Service Classes Should Be Annotated With Service Annotation

```kotlin
@Test
fun `Service classes should be annotated with Service annotation`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("Service")
        .assertTrue { it.hasAnnotationOf(Service::class) }
}
```

## 7. Entity Classes Should Have An Id Field

```kotlin
@Test
fun `Entity classes should have an Id field`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withAnnotationOf(Entity::class)
        .assertTrue { clazz ->
            clazz.properties().any { property ->
                property.hasAnnotationOf(Id::class)
            }
        }
}
```

## 8. DTO Classes Should Be Data Classes

```kotlin
@Test
fun `DTO classes should be data classes`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("DTO")
        .assertTrue { it.hasModifier(KoModifier.DATA) }
}
```

## 9. RestControllers Should Not Have State Fields

```kotlin
@Test
fun `RestControllers should not have state fields`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withAnnotationOf(RestController::class)
        .objects()
        .withModifier(KoModifier.COMPANION)
        .assertTrue {
            it.properties().isEmpty()
        }
}
```

## 10. Files With Domain Package Do Not Have Spring References

```kotlin
@Test
fun `files with domain package do not have Spring references`() {
    Konsist.scopeFromProduction()
        .files
        .withPackage("..domain..")
        .assertFalse {
            it
                .imports
                .any { import ->
                    import.name.startsWith("org.springframework")
                }
        }
}
```

## 11. Transactional Annotation Should Only Be Used On Default Or Public Methods That Are Not Part Of An Interface

```kotlin
@Test
fun `Transactional annotation should only be used on default or public methods that are not part of an interface`() {
    Konsist.scopeFromProject()
        .functions()
        .withAnnotationOf(Transactional::class)
        .assertTrue {
            it.hasPublicOrDefaultModifier && it.containingDeclaration !is KoInterfaceDeclaration
        }
}
```

## 12. Every API Method In RestController With `Admin` Suffix Should Have PreAuthorize Annotation With ROLE\_ADMIN

```kotlin
@Test
fun `every API method in RestController with 'Admin' suffix should have PreAuthorize annotation with ROLE_ADMIN`() {
    Konsist.scopeFromProject()
        .classes()
        .withAnnotationOf(RestController::class)
        .withNameEndingWith("Admin")
        .functions()
        .assertTrue {
            it.hasAnnotationOf(PreAuthorize::class) && it.text.contains("hasRole('ROLE_ADMIN')")
        }
}
```

## 13. Every Non-public Controller Should Have @PreAuthorize On Class Or On Each Endpoint Method

```kotlin
@Test
fun `every non-public Controller should have @PreAuthorize on class or on each endpoint method`() {
    Konsist.scopeFromProject()
        .classes()
        .withAnnotationOf(RestController::class)
        .filterNot { it.hasPublicModifier }
        .assertTrue { controller ->
            controller.hasAnnotationOf(PreAuthorize::class) ||
                    controller.functions()
                        .all { it.hasAnnotationOf(PreAuthorize::class) }
        }
}
```


# Test Snippets

## 1. Every Class Has Test

```kotlin
@Test
fun `every class has test`() {
    Konsist
        .scopeFromProduction()
        .classes()
        .assertTrue { it.hasTestClass() }
}
```

## 2. Every Class - Except Data And Value Class - Has Test

```kotlin
@Test
fun `every class - except data and value class - has test`() {
    Konsist
        .scopeFromProduction()
        .classes()
        .withoutModifier(KoModifier.DATA, KoModifier.VALUE)
        .assertTrue { it.hasTestClass() }
}
```

## 3. Test Classes Should Have Test Subject Named Sut

```kotlin
@Test
fun `test classes should have test subject named sut`() {
    Konsist
        .scopeFromTest()
        .classes()
        .assertTrue {
            val type = it.name.removeSuffix("Test")
            val sut = it
                .properties()
                .firstOrNull { property -> property.name == "sut" }

            sut != null && (sut.type?.name == type || sut.text.contains("$type("))
        }
}
```

## 4. Test Classes Should Have All Members Private Besides Tests

```kotlin
@Test
fun `test classes should have all members private besides tests`() {
    Konsist
        .scopeFromTest()
        .classes()
        .declarations()
        .filterIsInstance<KoAnnotationProvider>()
        .withoutAnnotationOf(Test::class, ParameterizedTest::class, RepeatedTest::class)
        .filterIsInstance<KoVisibilityModifierProvider>()
        .assertTrue { it.hasPrivateModifier }
}
```


# JUnit Snippets

Code snippets employed to ensure the uniformity of tests written with [JUnit](https://junit.org/junit5/) library.

## 1. Classes With `Test` Annotation Should Have `Test` Suffix

```kotlin
@Test
fun `classes with 'Test' Annotation should have 'Test' suffix`() {
    Konsist
        .scopeFromSourceSet("test")
        .classes()
        .filter {
            it.functions().any { func -> func.hasAnnotationOf(Test::class) }
        }
        .assertTrue { it.hasNameEndingWith("Tests") }
}
```

## 2. Test Classes Should Have Test Subject Named Sut

```kotlin
@Test
fun `test classes should have test subject named sut`() {
    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)
        }
}
```

## 3. Test Classes Should Have All Members Private Besides Tests

```kotlin
@Test
fun `test classes should have all members private besides tests`() {
    Konsist
        .scopeFromTest()
        .classes()
        .declarations()
        .filterIsInstance<KoAnnotationProvider>()
        .withoutAnnotationOf(Test::class, ParameterizedTest::class, RepeatedTest::class)
        .filterIsInstance<KoVisibilityModifierProvider>()
        .assertTrue { it.hasPrivateModifier }
}
```

## 4. No Class Should Use JUnit4 Test Annotation

```kotlin
@Test
fun `no class should use JUnit4 Test annotation`() {
    Konsist
        .scopeFromProject()
        .classes()
        .functions()
        .assertFalse {
            it.annotations.any { annotation ->
                annotation.fullyQualifiedName == "org.junit.Test"
            }
        }
}
```


# Kotest Snippets

Sample tests writen using [Kotest](https://kotest.io/) library.

## 1. Use Case Test

```kotlin
class UseCaseTest : FreeSpec({
    "UseCase has test class" {
        Konsist
            .scopeFromProject()
            .classes()
            .withNameEndingWith("UseCase")
            .assertTrue(testName = this.testCase.name.testName) { it.hasTestClasses() }
    }
})
```

## 2. Use Case Tests

```kotlin
class UseCaseTests : FreeSpec({
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .forEach { useCase ->
            "${useCase.name} should have test" {
                useCase.assertTrue(testName = this.testCase.name.testName) { it.hasTestClasses() }
            }
            "${useCase.name} should reside in ..domain..usecase.. package" {
                useCase.assertTrue(testName = this.testCase.name.testName) { it.resideInPackage("..domain..usecase..") }
            }
            "${useCase.name} should ..." {
                // another Konsist assert
            }
        }
})
```


# Architecture Snippets

Snippets used to guard application architecture.

## 1. 2 Layer Architecture Has Correct Dependencies

```kotlin
@Test
fun `2 layer architecture has correct dependencies`() {
    Konsist
        .scopeFromProject()
        .assertArchitecture {
            val presentation = Layer("Presentation", "com.myapp.presentation..")
            val business = Layer("Business", "com.myapp.business..")
            val persistence = Layer("Persistence", "com.myapp.persistence..")
            val database = Layer("Database", "com.myapp.database..")

            presentation.dependsOn(business)
            business.dependsOn(presentation)
            business.dependsOn(persistence)
            persistence.dependsOn(business)
            business.dependsOn(database)
            database.dependsOn(business)
        }
}
```

## 2. Every File In Module Reside In Module Specific Package

```kotlin
@Test
fun `every file in module reside in module specific package`() {
    Konsist
        .scopeFromProject()
        .files
        .assertTrue { it.packagee?.name?.startsWith(it.moduleName) }
}
```

## 3. Files Reside In Package That Is Derived From Module Name

```kotlin
@Test
fun `files reside in package that is derived from module name`() {
    Konsist.scopeFromProduction()
        .files
        .assertTrue {
            /*
            module -> package name:
            feature_meal_planner -> mealplanner
            feature_caloric_calculator -> caloriccalculator
            */
            val featurePackageName = it
                .moduleName
                .removePrefix("feature_")
                .replace("_", "")

            it.hasPackage("com.myapp.$featurePackageName..")
        }
}
```


# Clean Architecture Snippets

Snippets used to guard clean architecture dependencies.

## 1. Clean Architecture Layers Have Correct Dependencies

```kotlin
@Test
fun `clean architecture layers have correct dependencies`() {
    Konsist
        .scopeFromProduction()
        .assertArchitecture {
            // Define layers
            val domain = Layer("Domain", "com.myapp.domain..")
            val presentation = Layer("Presentation", "com.myapp.presentation..")
            val data = Layer("Data", "com.myapp.data..")

            // Define architecture assertions
            domain.dependsOnNothing()
            presentation.dependsOn(domain)
            data.dependsOn(domain)
        }
}
```

## 2. Classes With `UseCase` Suffix Should Reside In `domain` And `usecase` Package

```kotlin
@Test
fun `classes with 'UseCase' suffix should reside in 'domain' and 'usecase' package`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .assertTrue { it.resideInPackage("..domain..usecase..") }
}
```

## 3. Classes With `UseCase` Suffix Should Have Single `public Operator` Method Named `invoke`

```kotlin
@Test
fun `classes with 'UseCase' suffix should have single 'public operator' method named 'invoke'`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .assertTrue {
            val hasSingleInvokeOperatorMethod = it.hasFunction { function ->
                function.name == "invoke" && function.hasPublicOrDefaultModifier && function.hasOperatorModifier
            }

            hasSingleInvokeOperatorMethod && it.countFunctions { item -> item.hasPublicOrDefaultModifier } == 1
        }
}
```

## 4. Classes With `UseCase` Suffix And Parents Should Have Single `public Operator` Method Named `invoke`

```kotlin
@Test
fun `classes with 'UseCase' suffix and parents should have single 'public operator' method named 'invoke'`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .assertTrue {
            // Class and it's parent
            val declarations = listOf(it) + it.parents(true)

            // Functions from all parents without overrides
            val uniqueFunctions = declarations
                .mapNotNull { koParentDeclaration -> koParentDeclaration as? KoFunctionProvider }
                .flatMap { koFunctionProvider ->
                    koFunctionProvider.functions(
                        includeNested = false,
                        includeLocal = false
                    )
                }
                .filterNot { koFunctionDeclaration -> koFunctionDeclaration.hasOverrideModifier }

            val hasInvokeOperatorMethod = uniqueFunctions.any { functionDeclaration ->
                functionDeclaration.name == "invoke" && functionDeclaration.hasPublicOrDefaultModifier && functionDeclaration.hasOperatorModifier
            }

            val numParentPublicFunctions = uniqueFunctions.count { functionDeclaration ->
                functionDeclaration.hasPublicOrDefaultModifier
            }

            hasInvokeOperatorMethod && numParentPublicFunctions == 1
        }
}
```

## 5. Interfaces With `Repository` Annotation Should Reside In `data` Package

```kotlin
@Test
fun `interfaces with 'Repository' annotation should reside in 'data' package`() {
    Konsist
        .scopeFromProject()
        .interfaces()
        .withAnnotationOf(Repository::class)
        .assertTrue { it.resideInPackage("..data..") }
}
```

## 6. Every UseCase Class Has Test

```kotlin
@Test
fun `every UseCase class has test`() {
    Konsist
        .scopeFromProduction()
        .classes()
        .withNameEndingWith("UseCase")
        .assertTrue { it.hasTestClasses() }
}
```


# Kotlin Serialization Snippets

Konsist can be used to guard the consistency of classes related to the \[Kotlin Serialization]\(<https://kotlinlang>. org/docs/serialization.html) library.

## 1. Classes Annotated With `Serializable` Have All Properties Annotated With `SerialName`

```kotlin
@Test
fun `classes annotated with 'Serializable' have all properties annotated with 'SerialName'`() {
    Konsist
        .scopeFromProject()
        .classes()
        .withAnnotationOf(Serializable::class)
        .properties()
        .assertTrue {
            it.hasAnnotationOf(SerialName::class)
        }
}
```

## 2. Enum Classes Annotated With `Serializable` Have All Enum Constants Annotated With `SerialName`

```kotlin
@Test
fun `enum classes annotated with 'Serializable' have all enum constants annotated with 'SerialName'`() {
    Konsist.scopeFromProject()
        .classes()
        .withEnumModifier()
        .withAnnotationOf(Serializable::class)
        .enumConstants
        .assertTrue { it.hasAnnotationOf(SerialName::class) }
}
```

## 3. All Models Are Serializable

```kotlin
@Test
fun `all models are serializable`() {
    Konsist
        .scopeFromPackage("com.myapp.model..")
        .classes()
        .assertTrue {
            it.hasAnnotationOf(Serializable::class)
        }
}
```


# Library Snippets

Snippets to library authors.

## 1. Every Api Declaration Has KDoc

```kotlin
@Test
fun `every api declaration has KDoc`() {
    Konsist
        .scopeFromPackage("..api..")
        .declarationsOf<KoKDocProvider>()
        .assertTrue { it.hasKDoc }
}
```

## 2. Every Function With Parameters Has A Param Tags

```kotlin
@Test
fun `every function with parameters has a param tags`() {
    Konsist.scopeFromPackage("..api..")
        .functions()
        .assertTrue { it.hasValidKDocParamTags() }
}
```

## 3. Every Function With Return Value Has A Return Tag

```kotlin
@Test
fun `every function with return value has a return tag`() {
    Konsist.scopeFromPackage("..api..")
        .functions()
        .assertTrue { it.hasValidKDocReturnTag() }
}
```

## 4. Every Extension Has A Receiver Tag

```kotlin
@Test
fun `every extension has a receiver tag`() {
    Konsist.scopeFromPackage("..api..")
        .declarationsOf<KoReceiverTypeProvider>()
        .assertTrue { it.hasValidKDocReceiverTag() }
}
```

## 5. Every Public Function In Api Package Must Have Explicit Return Type

```kotlin
@Test
fun `every public function in api package must have explicit return type`() {
    Konsist
        .scopeFromPackage("..api..")
        .functions()
        .assertTrue { it.hasReturnType() }
}
```

## 6. Every Public Property In Api Package Must Have Specify Type Explicitly

```kotlin
@Test
fun `every public property in api package must have specify type explicitly`() {
    Konsist
        .scopeFromPackage("..api..")
        .properties()
        .assertTrue { it.hasType() }
}
```


# Generic Types Snippets

## 1. All Generic Return Types Contain X In Their Name

```kotlin
@Test
fun `all generic return types contain X in their name`() {
    Konsist
        .scopeFromProduction()
        .functions()
        .returnTypes
        .withGeneric()
        .assertTrue { it.hasNameContaining("X") }
}
```

## 2. Property Generic Type Does Not Contains Star Projection

```kotlin
@Test
fun `property generic type does not contains star projection`() {
    Konsist
        .scopeFromProduction()
        .properties()
        .types
        .assertFalse { type ->
            type
                .typeArguments
                ?.flatten()
                ?.any { it.isStarProjection }
        }
}
```

## 3. All Generic Return Types Contain Kotlin Collection Type Argument

```kotlin
@Test
fun `all generic return types contain Kotlin collection type argument`() {
    Konsist
        .scopeFromProduction()
        .functions()
        .returnTypes
        .withGeneric()
        .typeArguments
        .assertTrue { it.sourceDeclaration?.isKotlinCollectionType }
}
```

## 4. Function Parameter Has Generic Type Argument With Name Ending With `Repository`

```kotlin
@Test
fun `function parameter has generic type argument with name ending with 'Repository'`() {
    Konsist
        .scopeFromProduction()
        .functions()
        .parameters
        .types
        .withGeneric()
        .sourceDeclarations()
        .assertFalse { it.hasNameEndingWith("Repository") }
}
```


# Isolate Konsist Tests

Aim for better test separation.

Typically, it's advisable to consolidate all Konsist tests in a unified location. This approach is preferred because these tests are often designed to validate the structure of the entire project's codebase. There are three potential options for storing Konsist tests in project codebase:

<table><thead><tr><th width="205"></th><th>Android</th><th>Spring</th><th>KMP</th><th>Pure Kotlin</th></tr></thead><tbody><tr><td><a data-mention href="#existing-test-source-set">#existing-test-source-set</a></td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td><a data-mention href="#dedicated-konsist-test-source-set">#dedicated-konsist-test-source-set</a></td><td>❌</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td><a data-mention href="#dedicated-module">#dedicated-module</a></td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr></tbody></table>

Recommended approach is to use [#dedicated-konsisttest-source-set](#dedicated-konsisttest-source-set "mention") or a [#dedicated-module](#dedicated-module "mention"). These approaches allows to easily isolate Konsist tests from other types of tests e.g. separate `unit tests` from `Konsist tests`.

## Existing Test Source Set

The Konsist library can be added to the project by adding the dependency on the existing `test` source set .

![test sorce directory](/files/poFcMSChx6PYR3cOyScw)

To execute tests run `./gradlew test` command.

The downside of this approach is that various types of tests are mixed in `test` source set e.g. `unit tests` and `Konsist tests`.

## Dedicated konsistTest Source Set

This section demonstrates how to add the `konsistTest` test source directory inside the `app` module. This configuration is mostly useful for Spring and Kotlin projects.

{% hint style="info" %}
This page describes the test located in the `app` module with the build config file located in `app` a folder. If the project does not contain any module then configuration should be applied in the root build config file.
{% endhint %}

This test directory will have a `kotlin` folder containing Kotlin code.

{% tabs %}
{% tab title="Gradle (Kotlin)" %}
Use the Gradle built-in [JVM Test Suite Plugin](https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html) to define the `konsistTest` source set. Add a `testing` block to the project configuration:

```kotlin
// build.gradle.kts (root)

plugins {
    `jvm-test-suite`
}

testing {
    suites {
        register("konsistTest", JvmTestSuite::class) {
            dependencies {
                // Add 'main' source set dependency
                implementation(project())
                
                // Add Konsist dependency
                implementation("com.lemonappdev:konsist:0.13.0") 
            }
        }
    }
}

// Optional : Remove Konsist tests from the 'check' task if it exists
tasks.matching { it.name == "check" }.configureEach {
  setDependsOn(dependsOn.filter { it.toString() != "konsistTest" })
}
```

{% endtab %}

{% tab title="Gradle (Groovy)" %}
Use the Gradle built-in [JVM Test Suite Plugin](https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html) to define the `konsistTest` source set. Add a `testing` block to the project configuration:

```kotlin
// build.gradle (root)

plugins {
    id 'jvm-test-suite'
}

testing {
    suites { 
        test { 
            useJUnitJupiter() 
        }

        konsistTest(JvmTestSuite) { 
            dependencies {
                // Add 'main' source set dependency
                implementation project() 
                
                // Add Konsist dependency
                implementation "com.lemonappdev:konsist:0.13.0"
            }

            targets { 
                all {
                    testTask.configure {
                        shouldRunAfter(test)
                    }
                }
            }
        }
    }
}

// Optional: Remove Konsist tests from the 'check' task if it exists
tasks.matching { it.name == "check" }.configureEach { task ->
    task.setDependsOn(task.getDependsOn().findAll { it.toString() != "konsistTest" })
}
```

{% endtab %}

{% tab title="Maven" %}
Use the [Maven Build Helper Plugin](https://www.mojohaus.org/build-helper-maven-plugin/) to define the `konsistTest` test source directory. Add plugin config to the project configuration:

```xml
# app/pom.xml

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <version>3.3.0</version>
    <executions>
        <execution>
            <id>add-konsist-test-source</id>
            <phase>generate-test-sources</phase>
            <goals>
                <goal>add-test-source</goal>
            </goals>
            <configuration>
                <sources>
                    <source>${project.basedir}/src/konsistTest/kotlin</source>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>
```

{% endtab %}
{% endtabs %}

Create `app/src/konsistTest/kotlin` folder and reload the project. The IDE will present a new `konsistTest` source set in the `app` module.

<figure><img src="/files/4WfmkS0TOwRidoBDHHvD" alt=""><figcaption><p>konsistTest sorce directory</p></figcaption></figure>

The `konsistTest` test source folder works exactly like the build-in `test` source folder, so Kosist tests can be defined and executed in a similar way:

{% tabs %}
{% tab title="Gradle" %}

```
./gradlew app:konsistTest
```

{% endtab %}

{% tab title="Maven" %}

```yaml
mvn test
```

{% endtab %}
{% endtabs %}

## Dedicated Gradle Module

This section demonstrates how to add the `konsistTest` module to the project. This configuration is primarily helpful for Android projects and Kotlin Multiplatform (KMP) projects, however, this approach will also work with Spring and pure Kotlin projects.

{% hint style="info" %}
The [Android Gradle Plugin](https://developer.android.com/build/releases/gradle-plugin) is used to build Android apps. The Android Gradle Plugin is not compatible with the [JVM Test Suite Plugin](https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html) and it does not allow adding new source sets. To fully isolate tests a new module is required.

The [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html) project contains modules with code for different platforms. To decouple Konsist tests from a single platform dedicated module containing Konsist test should be added.
{% endhint %}

### Add Gradle `konsistTest` Module:

{% tabs %}
{% tab title="Gradle (Kotlin)" %}
Create `konsistTest/src/test/kotlin` directory in the project root:

<figure><img src="/files/Cgb6S1HynbztgMQoTgJV" alt="" width="374"><figcaption></figcaption></figure>

Add module include inside `settings.gradle.kts` file:

```kotlin
// settings.gradle.kts
include(":konsistTest")
```

{% endtab %}

{% tab title="Gradle (Groovy)" %}
Create `konsistTest/src/test/kotlin` directory in the project root:

<figure><img src="/files/pILhWRGg24abF9YGsJBc" alt="" width="374"><figcaption></figcaption></figure>

Add module include inside `settings.gradle.kts` file:

```kotlin
// settings.gradle
include ':konsistTest'
```

For Android projects add `com.android.library` plugin in the `konsistTest/scr/test/kotlin/build.gradle` file.

Refresh/Sync the Gradle Project in IDE.
{% endtab %}
{% endtabs %}

### Running Konsist Tests Stored In A Dedicated Gradle Module

Gradle's default behavior assumes that a module's code is up-to-date if the module itself hasn't been modified. This can lead to issues when Konsist tests are placed in a separate module. In such cases, Gradle may skip these tests, believing they're unnecessary.

However, this approach doesn't align well with Konsist's functionality. Konsist analyzes the entire codebase, not just individual modules. As a result, when Gradle skips Konsist tests based on its module-level change detection, it fails to account for potential changes in other modules that Konsist would typically examine.&#x20;

There are few solutions to this problem.

#### Solution 1: Module Is Always Out of Date

An alternative solution for this problem is to define `konsistTest` module as always being out of date:

{% tabs %}
{% tab title="Gradle Kotlin" %}

```kotlin
// konsistTest/build.gradle.kts

tasks.withType<Test> {
    outputs.upToDateWhen { false }
}
```

{% endtab %}

{% tab title="Gradle Grovy" %}

```groovy
// konsistTest/build.gradle

tasks.withType(Test) {
    outputs.upToDateWhen { false }
}
```

{% endtab %}
{% endtabs %}

#### Solution 2: Flag --rerun-tasks

{% hint style="info" %}
To execute all unit tests besides tests in the `konsistTest` module run:

`./gradlew test -x konsistTest:test`
{% endhint %}

To avoid manually passing `--rerun-tasks` flag each time a custom `konsistCheck` task can be added to the root build config file:

{% tabs %}
{% tab title="Gradle Kotlin" %}
Add to root `build.gradle.kts`:

```kotlin
tasks.register("konsistCheck") {
    group = "verification"
    description = "Runs Konsist static code analysis"

    doLast {
        val output = ByteArrayOutputStream()
        val result = project.exec {
            commandLine("./gradlew", "konsistTest:test", "--rerun-tasks")
            standardOutput = output
            errorOutput = output
            isIgnoreExitValue = true
        }

        println(output.toString())

        if (result.exitValue != 0) {
            throw GradleException("Konsist tests failed")
        }
    }
}
```

{% endtab %}

{% tab title="Gradle Groovy" %}
Add to root `build.gradle`:

```groovy
tasks.register("konsistCheck") {
    group = "verification"
    description = "Runs Konsist static code analysis"

    doLast {
        def output = new ByteArrayOutputStream()
        def result = project . exec {
            commandLine './gradlew', 'konsistTest:test', '--rerun-tasks'
            standardOutput = output
            errorOutput = output
            ignoreExitValue = true
        }

        println output . toString ()

        if (result.exitValue != 0) {
            throw new GradleException ("Konsist tests failed")
        }
    }
}
```

{% endtab %}
{% endtabs %}

After adding `konsistCheck` task run `./gradlew konsistCheck` to execute all Konsist tests.


# Enable Full Command Line Logging

Boost command line output

When running using non- [Dynamic Konsist Tests](/advanced/dynamic-konsist-tests)the default command line output contains only the test name:

```
> Task :konsistTest:test

UseCaseKonsistTest > every use case has single public operator function named 'invoke' FAILED
    com.lemonappdev.konsist.core.exception.KoAssertionFailedException at UseCaseKonsistTest.kt:26

2 tests completed, 1 failed

> Task :konsistTest:testDebugUnitTest FAILED

FAILURE: Build failed with an exception.


```

To be able to see full exception log containing invalid declaration `file path` and `line number` enable `exceptionFormat` in Gradle `testLogging`:

{% tabs %}
{% tab title="Gradle Kotlin" %}

```kotlin
tasks.withType<Test> {
  testLogging {
    events(TestLogEvent.FAILED)
    exceptionFormat = TestExceptionFormat.FULL
  }
}
```

{% endtab %}

{% tab title="Gradle Groovy" %}

```groovy
tasks.test { 
    testLogging { 
        events(TestLogEvent.FAILED)
        exceptionFormat = TestExceptionFormat.FULL 
    } 
}
```

{% endtab %}
{% endtabs %}

Now log output provides all informations relevant to pin point the invalid declaration:

```
> Task :konsistTest:test

UseCaseKonsistTest > every use case has single public operator function named 'invoke' FAILED
    com.lemonappdev.konsist.core.exception.KoAssertionFailedException: Assert 'every use case has single public operator function named 'invoke'' was violated (25 times). Invalid declarations:
    /myproject/usecase/LoginUserUseCase.kt:6:1 (LoginUserUseCase ClassDeclaration)
    /myproject/usecase/GetLocationUseCase.kt:8:1 (GetLocationUseCase ClassDeclaration)
    
2 tests completed, 1 failed

> Task :konsistTest:testDebugUnitTest FAILED

FAILURE: Build failed with an exception.

```


# Dynamic Konsist Tests

From static to dynamic

On this page, we explore the domain of static tests and then progress to the flexible world of dynamic tests. As a starting point, let's dive into the traditional approach of static Konsist tests.

## Why Use Dynamic Tests?

With static tests, the failure is represented by a single test:

<figure><img src="/files/TAIkywybKvwygPVpUya4" alt=""><figcaption></figcaption></figure>

From this failure, a developer discerns the breached rule and needs to dive into the test logs to determine the cause of the violation (to pinpoint the use case breaking the given rule).

In contrast, dynamic tests immediately highlight the root issue since every use case is represented by its own distinct test:

<figure><img src="/files/Bb20LvY2UW0oWh1OPjTj" alt=""><figcaption></figcaption></figure>

Utilizing dynamic tests over static ones makes it simpler to pinpoint failures. Consequently, it reduces the time and effort spent on parsing long error logs, offering a more efficient testing experience.&#x20;

{% hint style="info" %}
Take a look at [sample projects](https://github.com/LemonAppDev/konsist/tree/develop/samples/starter-projects). Every [JUnit5](https://junit.org/junit5/) and [Kotest](https://kotest.io/) project has an additional dynamic test (`SampleDynamicKonsistTest`) preconfigured. Check out the project and run the test.
{% endhint %}

Let's begin by creating a static test and then delve into the steps to transition towards dynamic tests.

## Static Tests

Static tests are defined at compile-time. This means the structure and number of these tests are fixed when the code is compiled. When navigating the universe of Konsist tests, the standard approach is to execute several validations all bundled within a single test.&#x20;

To paint a clearer picture: imagine you have a rule (let's represent it with the tool icon 🛠️) ensuring that all use cases should be placed in a specific package. One static test (represented by the check icon ✅) can guard this rule, making sure that everything is in the right place:

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart LR
S1\["🛠️ RULE use case package"]-->S3
S3\["✅ TEST Verify use case package (All use cases)"]" %}

In most projects, the intricacy arises from a multitude of classes/interfaces, each with distinct duties. However, to simplify our understanding, let's use a straightforward and simplified example of a project with just three use cases:

<figure><img src="/files/1p0GTh6vumbKekiVkHs6" alt=""><figcaption></figcaption></figure>

The goal is to verify if every use case follows these two rules:

* verify if every use case has a test
* verify if every use case is in `domain.usecase` package

A typical approach would be to write two Konsist tests:

{% tabs %}
{% tab title="JUnit" %}

```kotlin
class UseCaseKonsistTest {
    @Test
    fun `use case should have test`() {
        Konsist
            .scopeFromProject()
            .classes()
            .withNameEndingWith("UseCase")
            .assertTrue { it.hasTestClass() }
    }

    @Test
    fun `use case reside in domain dor usecase package`() {
        Konsist
            .scopeFromProject()
            .classes()
            .withNameEndingWith("UseCase")
            .assertTrue { it.resideInPackage("..domain..usecase..") }
    }
}
```

{% endtab %}

{% tab title="Kotest" %}

```kotlin
class UseCaseKonsistTest : FreeSpec({
    val useCases = Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")

    "use case should have test" {
        useCases.assertTrue(testName = this.testCase.name.testName) { it.hasTestClass() }
    }

    "use case should reside in ..domain.usecase.. package" {
        useCases.assertTrue(testName = this.testCase.name.testName) { it.resideInPackage("..domain.usecase..") }
    }
})
```

{% endtab %}
{% endtabs %}

Each rule is represented as a separate test verifying all of the use cases:

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart LR
S1\["🛠️ RULE use case package"]-->S3
S2\["🛠️ RULE Verify use case has test"]-->S4
S3\["✅ TEST Verify use case package (All use cases)"]
S4\["✅ TEST Verify use case has test (All use cases)"]" %}

Executing these tests will generate output in the IDE:

<figure><img src="/files/AJv1eqovvCiOOX6JaHTu" alt=""><figcaption></figcaption></figure>

While the current setup using static, predefined tests is functional, dynamic tests offer an avenue for improved development experience and flexibility.

## Dynamic Tests

Dynamic tests are generated at runtime based on conditions and input data. In this scenario, the dynamic input data is the list of use cases that grows over the project life cycle.

The objective is to generate dynamic tests for each combination of rule and use case (KoClass declaration) verified by Konsist. With three use cases and two rules for each, this will yield a total of six separate tests:

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart LR
D1\["🛠️ RULE Verify use case package"]
D1 --> D1T1
D1 --> D2T1
D1 --> D3T1

```
D2["🛠️ RULE Verify use case has test"]
D2 --> D1T2
D2 --> D2T2
D2 --> D3T2

D1T1["✅ TEST Verify use case package (CategorizeGroceryItemsUseCase)"]
D1T2["✅ TEST Verify use case has test (CategorizeGroceryItemsUseCase)"]

D2T1["✅ TEST Verify use case package (AdjustCaloricGoalUseCase)"]
D2T2["✅ TEST Verify use case has test (AdjustCaloricGoalUseCase)"]

D3T1["✅ TEST Verify use case package (CalculateDailyIntakeUseCase)"]
D3T2["✅ TEST Verify use case has test (CalculateDailyIntakeUseCase)"]
```

" %}

Let's convert this idea into a dynamic test:

{% tabs %}
{% tab title="JUnit 5" %}
JUnit provides built-in support for dynamic tests through its core framework. This ensures that developers can seamlessly employ dynamic testing capabilities.&#x20;

{% hint style="info" %}
The`org.junit.jupiter:junit-jupiter-params:x.v.z` dependency is required to enable JUnit 5 dynamic tests.
{% endhint %}

```kotlin
class UseCaseKonsistTest {
    @TestFactory
    fun `use case test`(): Stream<DynamicTest> = Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .stream()
        .flatMap { useCase ->
            Stream.of(
                dynamicTest("${useCase.name} should have test") {
                    useCase.assertTrue(testName = "${useCase.name} should have test") {
                        it.hasTestClass()
                    }
                },
                dynamicTest("${useCase.name} should reside in ..domain.usecase.. package") {
                    useCase.assertTrue(testName = "${useCase.name} should reside in ..domain.usecase.. package") {
                        it.resideInPackage("..domain.usecase..")
                    }
                },
            )
        }
}
```

The IDE will display the tests as follows:

<figure><img src="/files/8RMsPj0fACFSXy1mayGt" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
For dynamic tests such as JUnit 5, it is recommended that the test name is explicitly provided using `testName` argument (see [Explicit Test Names](/advanced/dynamic-konsist-tests/explicit-test-names)). At the moment test names are duplicated. This aspect has to be further investigated.
{% endhint %}
{% endtab %}

{% tab title="Kotest" %}
Kotest offers native support for JUnit's dynamic tests. Developers can effortlessly integrate and utilize dynamic testing features without needing additional configurations or plugins.

```kotlin
class UseCaseKonsistTest : FreeSpec({
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .forEach { useCase ->
            "${useCase.name} should have test" {
                useCase.assertTrue(testName = this.testCase.name.testName) { it.hasTestClass() }
            }
            "${useCase.name} should reside in ..domain.usecase.. package" {
                useCase.assertTrue(testName = this.testCase.name.testName) { it.resideInPackage("..domain..usecase..") }
            }
        }
})
```

The IDE will display the tests as follows:

<figure><img src="/files/0sFyqUZB9eOmEwspj2wS" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
For dynamic tests such as Kotest, it is recommended that the test name is explicitly provided using `testName` argument (see [Explicit Test Names](/advanced/dynamic-konsist-tests/explicit-test-names)).
{% endhint %}
{% endtab %}

{% tab title="JUnit 4" %}
In JUnit 4, the concept of dynamic tests (like JUnit 5's `@TestFactory`) does not exist natively thus dynamic tests are not supported.
{% endtab %}
{% endtabs %}


# Explicit Test Names

For dynamic tests, Konsist can't obtain the current test's name. Test name may be correctly displayed in the IDE, however, the `testName` argument should be provided to enable:

* Correct test names are displayed in the log when the test is failing
* Test suppression (See [Suppress Konsist Test](/writing-tests/suppressing-konsist-test))

{% hint style="info" %}
See [Dynamic Konsist Tests](/advanced/dynamic-konsist-tests).
{% endhint %}

The `testName` argument should be passed to `assertX` methods such as `assertTrue` , `assertFalse` etc. Let's look at the code:

```kotlin
Konsist.scopeFromProject()
    .classes()
    .assertTrue(testName = "My test name") { ... } //passed test name
```

Here is the summary of test frameworks:

| Testing Framework | Determination | Pass testName? |
| ----------------- | ------------- | -------------- |
| JUnit4            | static        | Not required   |
| JUnit5            | static        | Not required   |
| JUnit5            | dynamic       | Recommended    |
| Kotest            | dynamic       | Recommended    |

Here is a concrete implementation passing he `testName` argument for each test Framework:

{% tabs %}
{% tab title="JUnit 5 (static test)" %}
[JUnit 5](https://junit.org/junit5/) introduced native support for dynamic tests, however, it also supports static tests. For static test `testName` does not have to be passed as it can be internally retrieved by Konsist.

```kotlin
@Test
fun myTest() {
    Konsist.scopeFromProject()
        .classes()
        .assertTrue { ... }
}
```

{% endtab %}

{% tab title="Junit 5 (dynamic test)" %}
[JUnit 5](https://junit.org/junit5/) introduced native support for dynamic tests, allowing tests to be generated at runtime through the `@TestFactory` annotation.

```kotlin
class SampleDynamicKonsistTest {
    @TestFactory
    fun `use case test`(): Stream<DynamicTest> = Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .stream()
        .flatMap { useCase ->
            Stream.of(
                dynamicTest("${useCase.name} should have test") {
                   useCase.assertTrue(testName = "${useCase.name} should have test") {
                        it.hasTestClass()
                    }
                },
                dynamicTest("${useCase.name} should reside in ..domain.usecase.. package") {
                    useCase.assertTrue(testName = "${useCase.name} should reside in ..domain.usecase.. package") {
                        it.resideInPackage("..domain.usecase..")
                    }
                },
            )
        }
}
```

{% endtab %}

{% tab title="Kotest" %}
[Kotest](https://kotest.io/) provides robust support for dynamic tests, allowing developers to define test cases programmatically at runtime, making it a flexible alternative to traditional JUnit testing. It is recommended to utilize the name derived from the Kotest (`this.testCase.name.testName`) context as the value for the `testName` argument:

```kotlin
class SampleDynamicKonsistTest : FreeSpec({
    Konsist
        .scopeFromProject()
        .classes()
        .withNameEndingWith("UseCase")
        .forEach { useCase ->
            "${useCase.name} should have test" {
                useCase.assertTrue(testName = this.testCase.name.testName) { it.hasTestClass() }
            }
            "${useCase.name} should reside in ..domain.usecase.. package" {
                useCase.assertTrue(testName = this.testCase.name.testName) { it.resideInPackage("..domain.usecase..") }
            }
        }
})
```

To facilitate test name retrieval you can add this custom `koTestName` extension:

```kotlin
val TestScope.koTestName: String
    get() = this.testCase.name.testName
```

{% endtab %}

{% tab title="JUnit 4" %}
[JUnit 4](https://junit.org/junit4/) does not natively support dynamic tests; tests in this framework are typically static and determined at compile-time, so there is no need to pass `testName` argument.

```kotlin
@Test
fun myTest() {
    Konsist.scopeFromProject()
        .classes()
        .assertTrue { ... }
}
```

{% endtab %}
{% endtabs %}


# When Konsist API Is Not Enough


# Additional JUnit5 Setup

By default, JUnit tests are run sequentially in a single thread. To speed up tests parallel execution can be enabled.&#x20;

Create `junit-platform.properties` a file containing:&#x20;

```properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.strategy=dynamic
junit.jupiter.execution.parallel.config.dynamic.factor=0.95
```

Place this file in the `resources`  directory of the test source set e.g:

```
src/test/resource/junit-platform.properties

or

src/konsistTest/resource/junit-platform.properties
```

Read more in the official [JUnit5 documentation](https://junit.org/junit5/docs/5.3.0-M1/user-guide/index.html#writing-tests-parallel-execution).


# Why There Are No Pre-defined Rules?

Many linters including [Detekt](https://github.com/detekt/detekt) and [ktlint](https://github.com/pinterest/ktlint) have a predefined set of rules. These rules are derived and aligned with guidelines or common practices for writing high-quality code and industry coding conventions ([Kotlin coding conventions](https://kotlinlang.org/docs/coding-conventions.html), [Android Kotlin style guide](https://developer.android.com/kotlin/style-guide), etc.).

However, there are no industry standards when comes to application architecture. Every code base is different - different class names, different package structures, different application layers, etc. As the project grows code base evolves as well - it tends to have more layers, more modules, and a more complex code structure. These "rules" are hard to capture by generic linter, because they are often specific to the given project.&#x20;

Let's consider a use case - a concept defined by the [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html). At a high level the use case definition is quite simple - "use case holds a business logic". How the use case is represented in the code base? Well... In one project this may be a class that has a name ending with `UseCase`, in another, it may be a class extending `BaseUseCase` and in another class annotated with `@UseCase` annotation. The logic for filtering "all project use cases" will vary from project to project.

Now let's consider the actual structure of the use case class:&#x20;

* should every use case have `UseCase` a suffix in the class name?
* can the use case be extended or include another use case?
* should every use case reside in `usecase` the package?
* should the use case have a single method?
* how this method should be named?
* can this method have overloads or should it be defined as `invoke` an operator?
* should this method have a `suspended` modifier?
* …

Answers will vary from project to project. That is why Konsist favors a more flexible approach - it allows filtering members and defining custom code base assertions (tests). On top of that Konsist is utilizing Kotlin collection processing API to provide more control over filtering and asserting declarations ([Declaration](/features/declaration)).

{% hint style="success" %}
Some things can be standardized across different projects e.g. constructor parameter names being derived from the property name, or alphabetic order of the parameter. For now, custom tests will be a core part of Konsist, however, we are considering the addition of a small set of predefined rules in the future.
{% endhint %}


# Konsist Snapshots

Konsist occasionally releases snapshot versions to a dedicated [snapshot repository](https://s01.oss.sonatype.org/content/repositories/snapshots/com/lemonappdev/konsist/). These snapshots provide early access to new features and bug fixes.

{% hint style="warning" %}
Snapshot versions are development builds and may contain unstable features.
{% endhint %}

## Snapshot Release Process

Currently, snapshots are released manually. At some point this process will be automated - new snapshot will be released each time code is merged to `develop` branch

## How to Use Snapshots

### Add Snapshot Repository

First, you need to include the snapshot repository in your project configuration. Here's how to do it for different build systems:

{% tabs %}
{% tab title="Gradle (Kotlin)" %}

```kotlin
repositories {
    // Konsist snapshot repository
    maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")

    // More repositorues
}
```

{% endtab %}

{% tab title="Gradle (Groovy)" %}

```groovy
repositories {
    // Konsist snapshot repository
    maven {
        url 'https://s01.oss.sonatype.org/content/repositories/snapshots/'
    }
    
    // More repositories
}
```

{% endtab %}

{% tab title="Maven" %}
Add the following dependency to the `module\pom.xml` file:

```xml
<repositories>
    <!-- Konsist snapshot repository -->
    <repository>
        <id>konsist-snapshots</id>
        <url>https://s01.oss.sonatype.org/content/repositories/snapshots/</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>

    <!-- More repositories -->
</repositories>
```

{% endtab %}
{% endtabs %}

### Add Konsist Dependency

To use Konsist SNAPSHOT dependency changing version to `X.Y.Z-SNAPSHOT` (versions can be found in [snapshot repository](https://s01.oss.sonatype.org/content/repositories/snapshots/com/lemonappdev/konsist/)):

{% tabs %}
{% tab title="Gradle (Kotlin)" %}
Add the following dependency to the `module\build.gradle.kts` file:

```kotlin
dependencies {
    testImplementation("com.lemonappdev:konsist:X.Y.Z-SNAPSHOT")
}
```

{% endtab %}

{% tab title="Gradle (Groovy)" %}
Add the following dependency to the `module\build.gradle` file:

```groovy
dependencies {
    testImplementation "com.lemonappdev:konsist:X.Y.Z-SNAPSHOT"
}
```

{% endtab %}

{% tab title="Maven" %}
Add the following dependency to the `module\pom.xml` file:

```xml
<dependency>
    <groupId>com.lemonappdev</groupId>
    <artifactId>konsist</artifactId>
    <version>X.Y.Z-SNAPSHOT</version>
    <scope>test</scope>
</dependency>
```

{% endtab %}
{% endtabs %}


# Getting Help

📢 Let us know about issues you face and improvements you would like to see. Your feedback is crucial in shaping the future of Konsist. Whether it's a suggestion for improvement, a bug report, or a question about usage, we're here to listen and help.

Share your thoughts on the [#konsist channel ](https://kotlinlang.slack.com/archives/C05QG9FD6KS) to get help or start a new [GitHub discussion](https://github.com/LemonAppDev/konsist/discussions) 💬 for bug reports, issues, and feature requests.


# Known Issues


# java.lang.OutOfMemoryError: Java heap space

For large projects with many classes to parse, the default JVM heap size might not suffice. If you encounter `java.lang.OutOfMemoryError: Java heap space` error consider increasing the `maxHeapSize` for the `test` source set:

{% tabs %}
{% tab title="Gradle (Kotlin)" %}
Add the following argument to the`build.gradle.kts` file:

```kotlin
tasks.withType<Test> {
    maxHeapSize = "1g"
}
```

{% endtab %}

{% tab title="Gradle (Groovy)" %}
Add the following argument to the `build.gradle` file:

```groovy
tasks.withType(Test).configureEach { 
    maxHeapSize = "1g" 
}
```

{% endtab %}

{% tab title="Maven" %}
Add the following argument to the `pom.xml` file:

```xml
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0</version>
    <configuration>
        <argLine>-Xmx1g</argLine>
    </configuration>
</plugin>
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
You may need to set larger value than 1 gigabyte.
{% endhint %}


# Compatibility

Konsist ecosystem compatibility

Konsist is compatible with all types of Kotlin projects including [Android](https://www.android.com/), [Spring](https://spring.io/), and [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html) projects.

Konsist works with popular testing frameworks executing Kotlin code. Konsist has first-class support for [JUni4](https://junit.org/junit4/), [JUnit5](https://junit.org/junit5/), and [Kotest](https://kotest.io/).

Konsist is compatible with popular build systems such as [Gradle](https://gradle.org/) and [Maven](https://maven.apache.org/).

The `Java 8` is a minimum [Java](https://www.java.com/en) version required to run Konsist.

Konsist is backwards compatible with Kotlin `1.8.x` ( since Konsist `0.17.0` ).

## Dependencies

Konsist depends on:

* `org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4` (minimal coroutine usage make Konsist compatible with newer coroutines versions)
* `org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.20`&#x20;


# Changelog

Stay up to date

The full change log is available in the [Konsist repository](https://github.com/LemonAppDev/konsist/releases).


# Project Status

Where are we now?

The Konsist linter has undergone extensive field testing across a variety of projects, including  [Spring](https://spring.io/), [Android](https://www.android.com/), and [Kotlin Multiplatform](https://kotlinlang.org/docs/multiplatform.html), and is compatible with both [Gradle](https://gradle.org/) and [Maven](https://maven.apache.org/) build systems. Additionally, Konsist features a comprehensive test suite with around 5,000 tests, running on various operating systems including MacOS, Windows, and Ubuntu, to minimize the risk of regressions.

Konsist is safe for use because it is not bundled with the production code (only included in the test source sets).

## Konsist Roadmap

Over the next few months, we will fix bugs, improve existing APIs, and implement missing features (in this order). Here is a high-level roadmap:

* ✅ Milestone 1 (Q1-Q2-Q3 2023)
  * ✅ Setup GitHub project
  * ✅ Setup CI pipeline
  * ✅ Core Library development
  * ✅ Publish artifact to Maven Central
  * ✅ Create documentation
  * ✅ Internal closed testing Android
  * ✅ Internal closed testing Spring
* ✅ Milestone 2 (Q4 2023 Alpha)
  * ✅ Community-driven testing
  * ✅ Improve existing APIs
  * ✅ Fix Bugs
  * ✅ Polish documentation and samples
  * ✅ Implement new features
* ✅  Milestone 3 (Q1 2024)
  * ✅  Stabilize APIs (minimal breaking changes)
  * ✅ Fix Bugs
  * ✅ Polish documentation and samples
  * ✅ Implement new features
* 🚀 Milestone 4 (Q2 2024)
  * ✅  Declaration references
* 🚀 Milestone 5 (Q3 2024)
  * 🚀 Architecture checks improvements
  * 🚀 Bug fixes
  * 🚀 API improvements
* 🚀 Milestone 6 (Q4 2024 Beta)
  * 🚀 Bug fixes
  * 🚀 API improvements
  * 🚀 Release 1.0
* 🕝 Milestone 5 (H1 2025)
  * 🕝 Further maintenance and improvements


# Contributing

Let's Improve Konsist Together

## General

So you want to help? That's great!

{% hint style="info" %}
To chat with Konsist developers and the Konsist community please check the [#konsist channel](https://kotlinlang.slack.com/archives/C05QG9FD6KS) at `kotlinlang` Slack workspace (preferred), or start a new [GitHub discussion](https://github.com/LemonAppDev/konsist/discussions).
{% endhint %}

The Konsist project is now at a critical stage where community input is essential to polish and mature it.

There are a variety of ways to contribute to the Konsit project:

* **Coding:** This is the most common way to contribute. You can fix bugs or add new features.
* **Testing:** You can help to improve the quality by testing the code and reporting bugs. This is a great way to get involved and help out maturing the project.
* **Documentation:** You can help to improve the documentation by writing or editing documentation. This is a great way to help people understand how to use Konsist.
* **Community:** You can answer questions or participate in discussions ([GitHub](https://github.com/LemonAppDev/konsist/discussions), [Slack](https://kotlinlang.slack.com/archives/C05QG9FD6KS)). This is a great way to connect with other programmers.
* **Spread the word:** You can help to spread the word about the Konsist by talking about it with fellow developers. You can also write a short post or a full-fledged article. Make sure to let us know at [#konsist](https://kotlinlang.slack.com/archives/C05QG9FD6KS) channel if you do so.

No matter how you choose to contribute, you will be making a valuable contribution to the open-source community.

## Contributing

Our [contributor backlog is public](https://lemonappdev.atlassian.net/issues/?jql=labels%20%3D%20ContributeOpportunity%20and%20status%20in%20%28Open%2C%20%22Board%20Backlog%22%2C%20Backlog%29%20ORDER%20BY%20created%20DESC) in JIRA.

The best way to interact with the Konsist team is the dedicated [#konsist-dev](https://kotlinlang.slack.com/archives/C0628CK7TEV) channel ([kotlinlang Slack workspace](https://kotlinlang.slack.com/)). If you want to help or need guidelines just say hello at [#konsist-dev](https://kotlinlang.slack.com/archives/C0628CK7TEV) Slack channel.

Tickets that can be grabbed by the community have a [ContributeOpportunity](https://lemonappdev.atlassian.net/issues/?jql=labels%20%3D%20ContributeOpportunity%20and%20status%20in%20\(Open%2C%20%22Board%20Backlog%22%2C%20Backlog\)%20ORDER%20BY%20created%20DESC) label. You can also work on another improvement or bug-fix, but this may require more alignment, for example, certain features and planned ahead, so the ticket should be completed within a given time period.

### Start Contributing - Konsist

1. Get contributor JIRA access - send your email in DM to [#igorwojda](https://kotlinlang.slack.com/archives/D2T3KL43X) at [kotlinlang Slack workspace](https://kotlinlang.slack.com/).
2. Pick the ticket in JIRA
3. Assign it to yourself, and update the ticket status to `In Progress`
4. Fork [Konsist ](https://github.com/LemonAppDev/konsist)repository (uncheck "Copy the main branch only")

<figure><img src="/files/Z706ccQShuO2HtW3UX3g" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/vAhZQsCevv1GlzDQR5Gj" alt=""><figcaption></figcaption></figure>

5. Branch of [develop](https://github.com/LemonAppDev/konsist/tree/develop) branch
6. Implement the changes
7. Add tests (look around in codebase for similar code being tested)
8. Open draft[ Pull Request](https://github.com/LemonAppDev/konsist/compare) with [develop](https://github.com/LemonAppDev/konsist/tree/develop) branch as target ([develop](https://github.com/LemonAppDev/konsist/tree/develop) branch will be merged into the [main](https://github.com/LemonAppDev/konsist/tree/main) branch after the release)
   1. Make sure all checks are passing before marking PR as `Ready for review`.

### Start Contributing - Konsist Docs

The [konsist-documentation](https://github.com/LemonAppDev/konsist-documentation) - repository contains Konsist documentation (this webpage).

1. Fork [Konsist-documentation](https://github.com/LemonAppDev/konsist) repository
2. Branch of [main](https://github.com/LemonAppDev/konsist-documentation/tree/main) branch
3. Make changes
4. Open [new Pull Request](https://github.com/LemonAppDev/konsist-documentation/compare) with [main](https://github.com/LemonAppDev/konsist-documentation/tree/main) branch as a target

## Checks

During the PR review, several types of checks are executed using [GitHub Actions](https://github.com/features/actions) ([.github/workflow](https://github.com/LemonAppDev/konsist/tree/main/.github/workflows)). These checks can also be executed locally using the following commands:

* [Spotless](https://github.com/diffplug/spotless) (runs [ktlint](https://github.com/pinterest/ktlint))
  * `./gradlew spotlessCheck` - check the code using Spotless
  * `./gradlew spotlessApply` - check and fix code using Spotless (if possible)
* [Detekt](https://github.com/detekt/detekt)
  * `./gradlew detektCheck` - check the code using Detekt
  * `./gradlew detektApply` - check and fix code using Detekt (if possible)
* Tests
  * `./gradlew lib:test` - run JUnit tests
  * `./gradlew lib:apiTest` - run API tests
  * `./gradlew lib:integrationTest` - run integrations tests
  * `./gradlew lib:konsistTest` - run Konsist tests to test Konsist codebase 🤯😉

{% hint style="info" %}
Konsist adheres to stringent testing standards. Each Provider undergoes testing against every type of declaration, leading to an extensive set of tests. This thorough testing ensures two main objectives:

1. Guaranteeing future compatibility with Kotlin 2.0.
2. Due to reliance on an external library for parsing, it's imperative to have comprehensive tests to ensure the Konsist API functions as anticipated.
   {% endhint %}

## IntelliJ IDEA Plugins

Some of the project README files contain [Mermaid](https://mermaid.js.org/) diagrams. For a diagram preview, it is recommended to install the [Mermaid plugin](https://plugins.jetbrains.com/plugin/20146-mermaid/reviews).

## Testing Changes Locally

#### Publish Konsist Artifact To Local Maven Repository

To test the changes locally you can publish a `SNAPSHOT` artifact of the Konsist to the local maven repository:

```bash
./gradlew publishToMavenLocal -Pkonsist.releaseTarget=local
```

After publishing a new artifact `x.y.z-SNAPSHOT` with the version number will appear in the local Maven repository:

```
Mac: /Users/<user_name>/.m2/repository/com/lemonappdev/konsist
Windows: C:\Users\<User_Name>\.m2\repository\com\lemonappdev\konsist
Linux: /home/<User_Name>/.m2/repository/com/lemonappdev/konsist
```

The actual Konsist version is defined in the [gradle.properties](https://github.com/LemonAppDev/konsist/blob/main/gradle.properties) file. The `SNAPSHOT` suffix will be added automatically to the published artifact.

To use this artifact you have to add a local Maven repository to your project.

#### Use Published Artifact From Local Maven Repository

Every project contains a list of the repositories used to retrieve the dependencies. A local Maven repository has to be manually added to the project.

{% tabs %}
{% tab title="Gradle" %}
Add the following block to the `build.gradle` / `build.gradle.kts` file:

```kotlin
repositories {
    mavenLocal()
}
```

{% endtab %}

{% tab title="Maven" %}
By default, the Maven project uses a local repository. If not add the following block to the `module\pom.xml` file:

```xml
<repositories>
    <repository>
        <id>local</id>
        <url>file://${user.home}/.m2/repository</url>
    </repository>
</repositories>
```

{% endtab %}

{% tab title="More" %}
Dependency can be added to other build systems as well. Check the [snippets](https://central.sonatype.com/artifact/com.lemonappdev/konsist) section in the sonatype repository.
{% endtab %}
{% endtabs %}

Now build scripts will use the local repository to resolve dependencies, however, the version of Konsist has to be updated to the `SNAPSHOT` version of the newly published artifact e.g.

`com.lemonappdev:konsist:0.12.0-SNAPSHOT`

Now build scripts will be able to resolve this newly published Konsist artifact.

#### Verify Used Konsist Artifact Version

IntelliJ IDEA UI provides a convenient way to check which version of Konsist is used by the project. Open the `External Libraries` section of `Project view` and search for Konsist dependency:

![](/files/Ev2ImV2RZ7LkLAaF9ZRQ)

## No Matching Toolchains Found Error

If during a build you encounter an error regarding `No matching toolchains found` then open `Module Settings` / `Project Structure` windows and set Java SDK to version e.g. `19`.

<figure><img src="/files/1qyCuKT13AvdeoaI7sMK" alt=""><figcaption></figcaption></figure>

You can install missing JDKs directly from IntelliJ IDEA - click on the `Module SDK` combo box and select `+Add SDK`.

If during the build you encounter an error regarding `Could not determine the dependencies of null.` then open `File` / `Settings` / `Build, Execute, Deployment` / `Build Tools` / `Gradle` window and set Java SDK to version `19`.

<figure><img src="/files/sWrFCj1sWQ66C5KJS8Om" alt=""><figcaption></figcaption></figure>

## Architecture

### Source Sets

Konsist contains multiple custom source sets (defined by the [JVM Test Suite Plugin](https://docs.gradle.org/current/userguide/jvm_test_suite_plugin.html)) to provide better isolation between various types of tests:

* `test` - tests related to generic Konsist API (everything except the `architectureAssert`)
* `apiTest` - tests related to `architectureAssert`
* `integrationTest` - test classes using custom Kotlin snippets (`.kttxt`) to test the Konsist API
* `konsistTest` - tests Konsist codebase consistency using `konsist` library
* `snippets` - contains Kotlin code snippets, written as methods (tests without `@Test` annotation), so the tests are not executed. These snippets are used to generate documentation. The update-snippets.py script generates PR to update the [snippets](https://docs.konsist.lemonappdev.com/inspiration/snippets) page

We aim to test the majority of aspects within these source sets. However, certain kinds of checks require a dedicated test project. These projects are available in the [test-project](https://github.com/LemonAppDev/konsist/tree/main/test-projects) directory on the Konsist repository.

### Layers

The high-level view of Konsist architecture:

{% @mermaid/diagram content="%%{init: {'theme':'forest'}}%%
flowchart LR
subgraph Konsist
direction TB
direction LR
Api --> Core
end
Client --> Konsist" %}

### Make a Change In The Konsist Documentation Repository

The [konsist-documentation](https://github.com/LemonAppDev/konsist-documentation) repository contains this website. Create a fork of the repository, make changes using any text editor (e.g. [Visual Studio Code](https://code.visualstudio.com/)), and open the Pull Request targeting the `main` branch.

#### Updating Snippets

The [Snippets](/inspiration/snippets) section requires a different approach. To ensure the snippets remain valid and aligned with Konsist API, we store them within the [snippet source set](https://github.com/LemonAppDev/konsist/tree/main/lib/src/snippet/kotlin) of the [konsist](https://github.com/LemonAppDev/konsist) repository. With every release, new snippet pages are generated from the [snippet source set](https://github.com/LemonAppDev/konsist/tree/main/lib/src/snippet/kotlin) and placed in the GitBook documentation ([konsist-documentation](https://github.com/LemonAppDev/konsist-documentation) repository).

Some snippets depend on classes/interfaces/annotations from external frameworks such as Spring `Repository` annotation or Android `ViewModel` class. To avoid coupling Konsist with these frameworks and allow snippet compilation, we store placeholder classes mimicking the full names of the external framework in [this directory](https://github.com/LemonAppDev/konsist/tree/main/lib/src/snippet/kotlin). class e.g. [Inject.kt](https://github.com/LemonAppDev/konsist/blob/main/lib/src/snippet/kotlin/javax/inject/Inject.kt).


# Contributors

Browse the [current list of contributors](https://github.com/LemonAppDev/konsist/graphs/contributors) directly on GitHub.


# Assets And Logos

The Konsist logo can be found in the [misc folder](https://github.com/LemonAppDev/konsist/tree/main/misc/konsist-logo) of the main repository.

Our [contributor backlog is public](https://lemonappdev.atlassian.net/issues/?jql=labels%20%3D%20ContributeOpportunity%20and%20status%20in%20%28Open%2C%20%22Board%20Backlog%22%2C%20Backlog%29%20ORDER%20BY%20created%20DESC) in JIRA. If you want to join say hello at  [#konsist-dev](https://kotlinlang.slack.com/archives/C0628CK7TEV) Slack channel. If you are working on a ticket make sure to get the JIRA access, assign it to yourself, and update the ticket status to In Progress).


# Open Source Licenses

## Konsist

The Konsist project is licensed under [Apache License-2.0](https://github.com/LemonAppDev/konsist/blob/main/LICENSE).

## Dependencies

Third-party libraries, plugins, and tools that Konsist project uses:

<table><thead><tr><th>Name</th><th width="256.3333333333333">Licence</th><th>Page</th></tr></thead><tbody><tr><td>Kotlin</td><td>Apache-2.0 License</td><td><a href="https://github.com/JetBrains/kotlin">https://github.com/JetBrains/kotlin</a></td></tr><tr><td>Kotlin-compiler</td><td>Apache-2.0 License</td><td><a href="https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-compiler">https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-compiler</a></td></tr><tr><td>Mockk</td><td>Apache-2.0 License</td><td><a href="https://mockk.io/">https://mockk.io/</a></td></tr><tr><td>Spotless</td><td>Apache-2.0 License</td><td><a href="https://github.com/diffplug/spotless">https://github.com/diffplug/spotless</a></td></tr><tr><td>Gradle Test Logger Plugin</td><td>Apache-2.0 License</td><td><a href="https://github.com/radarsh/gradle-test-logger-plugin">https://github.com/radarsh/gradle-test-logger-plugin</a></td></tr><tr><td>JUnit</td><td>Eclipse Public License - v 2.0</td><td><a href="https://junit.org/junit5/">https://junit.org/junit5/</a></td></tr><tr><td>Kotest</td><td>Apache-2.0 License</td><td><a href="https://kotest.io/">https://kotest.io/</a></td></tr><tr><td>Gradle</td><td>Apache-2.0 License</td><td><a href="https://gradle.org/">https://gradle.org/</a></td></tr><tr><td>Ktlint</td><td>MIT License</td><td><a href="https://pinterest.github.io/ktlint/latest/">https://pinterest.github.io/ktlint/latest/</a></td></tr><tr><td>Detekt</td><td>Apache-2.0 License</td><td><a href="https://github.com/detekt/detekt">https://github.com/detekt/detekt</a></td></tr><tr><td>Dokka</td><td>Apache-2.0 License</td><td><a href="https://github.com/Kotlin/dokka">https://github.com/Kotlin/dokka</a></td></tr></tbody></table>

See [libs.versions.toml](https://github.com/LemonAppDev/konsist/blob/main/gradle/libs.versions.toml) file for more details.


# Sponsor Konsist

We appreciate your interest in Konsist. If you find our project valuable, please consider supporting Konsist through [OpenCollective](https://opencollective.com/konsist). Every contribution, no matter how small, adds up to make a significant impact.

## **Personal Support**

Your personal sponsorship helps us continue our work and improve the tool for the entire community.

## **Corporate Backing**

If your organization has open source funding initiatives, we'd be grateful if you could recommend Konsist or connect us with the appropriate team. Corporate backing can significantly boost our ability to enhance and sustain the project, benefiting the entire user community. For corporate sponsorship inquiries, please contact us at <igor.wojda@gmail.com>.


