From 2aa900a7787c4cd594dbd936cc022634b56a567d Mon Sep 17 00:00:00 2001 From: vsukharew Date: Tue, 26 Oct 2021 20:58:45 +0300 Subject: [PATCH 1/9] edited publishing script --- library/build.gradle | 2 +- ...maven-central.gradle => publishing.gradle} | 32 ++++++------------- 2 files changed, 10 insertions(+), 24 deletions(-) rename scripts/{publish-maven-central.gradle => publishing.gradle} (78%) diff --git a/library/build.gradle b/library/build.gradle index e560770..f85a459 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply from: '../dependencies.gradle' -apply from: "../scripts/publish-maven-central.gradle" +apply from: "../scripts/publishing.gradle" android { compileSdkVersion build.compileSdkVersion diff --git a/scripts/publish-maven-central.gradle b/scripts/publishing.gradle similarity index 78% rename from scripts/publish-maven-central.gradle rename to scripts/publishing.gradle index a7d5ccb..ada10fe 100644 --- a/scripts/publish-maven-central.gradle +++ b/scripts/publishing.gradle @@ -1,6 +1,6 @@ -task androidSourcesJar(type: Jar) { - classifier = 'sources' - from android.sourceSets.main.java.source +tasks.register("androidSourcesJar", Jar) { + from android.sourceSets.main.java.srcDirs + archiveClassifier.set('sources') } artifacts { @@ -39,16 +39,15 @@ afterEvaluate { publishing { publications { release(MavenPublication) { + from components.release + artifact androidSourcesJar + // The coordinates of the library, being set from variables that // we'll set up in a moment groupId build.library.publishGroupId artifactId build.library.publishArtifactId version build.library.versionName - // Two artifacts, the `aar` and the sources - artifact("$buildDir/outputs/aar/${project.getName()}-release.aar") - artifact androidSourcesJar - // Self-explanatory metadata for the most part pom { name = build.library.publishArtifactId @@ -74,18 +73,6 @@ afterEvaluate { developerConnection = 'scm:git:ssh://github.com/vsukharew/AnyTypeAdapter' url = 'https://github.com/vsukharew/AnyTypeAdapter/tree/master' } - // A slightly hacky fix so that your POM will include any transitive dependencies - // that your library builds upon - withXml { - def dependenciesNode = asNode().appendNode('dependencies') - - project.configurations.implementation.allDependencies.each { - def dependencyNode = dependenciesNode.appendNode('dependency') - dependencyNode.appendNode('groupId', it.group) - dependencyNode.appendNode('artifactId', it.name) - dependencyNode.appendNode('version', it.version) - } - } } } } @@ -111,8 +98,7 @@ afterEvaluate { } } } -} - -signing { - sign publishing.publications + signing { + sign publishing.publications + } } \ No newline at end of file From 37092eba16ba3220a4ab1e6d327f29e8193b1b74 Mon Sep 17 00:00:00 2001 From: vsukharew Date: Tue, 26 Oct 2021 21:07:25 +0300 Subject: [PATCH 2/9] change addition methods arguments (#79) * changed AnyTypeCollection.Builder methods: - addIf now along with items of List type takes delegate typed with instead of , V, H> - addIfNotEmpty now along with items of List type takes delegate typed with instead of , V, H> - another overload of addIfNotEmpty added * syntax refactor --- dependencies.gradle | 4 +- library/build.gradle | 5 ++ .../adapter/AnyTypeCollection.kt | 28 ++++-- .../AnyTypeCollectionBuilderTest.kt | 90 +++++++++++++++++++ .../anytypeadapter/ExampleUnitTest.kt | 17 ---- .../vsukharev/anytypeadapter/MockDelegates.kt | 53 +++++++++++ .../anytypeadapter/domain/Activity.kt | 8 ++ .../vsukharev/anytypeadapter/domain/Track.kt | 8 ++ 8 files changed, 186 insertions(+), 27 deletions(-) create mode 100644 library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt delete mode 100644 library/src/test/java/vsukharev/anytypeadapter/ExampleUnitTest.kt create mode 100644 library/src/test/java/vsukharev/anytypeadapter/MockDelegates.kt create mode 100644 library/src/test/java/vsukharev/anytypeadapter/domain/Activity.kt create mode 100644 library/src/test/java/vsukharev/anytypeadapter/domain/Track.kt diff --git a/dependencies.gradle b/dependencies.gradle index bac45fa..67dde4a 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -41,7 +41,7 @@ ext { moxy : '2.1.2', retrofit : '2.8.1', leakcanary : '2.2', - junit : '4.12' + junit : '5.7.1' ] androidx = [ appCompat : "androidx.appcompat:appcompat:${versions.androidx.appCompat}", @@ -72,5 +72,5 @@ ext { compiler: "com.google.dagger:dagger-compiler:${versions.dagger}", dagger : "com.google.dagger:dagger:${versions.dagger}", ] - junit = "junit:junit:${versions.junit}" + junit = "org.junit.jupiter:junit-jupiter-engine:${versions.junit}" } \ No newline at end of file diff --git a/library/build.gradle b/library/build.gradle index f85a459..c5432c5 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -26,6 +26,11 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + testOptions { + unitTests.all { + useJUnitPlatform() + } + } } dependencies { diff --git a/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt b/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt index 1ac4b56..5829813 100644 --- a/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt +++ b/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt @@ -110,9 +110,9 @@ class AnyTypeCollection private constructor( * Adds [items] and the corresponding [delegate] only if [predicate] is true * @param predicate the condition determining whether the items and delegate should be added */ - fun , V>> addIf( + fun > addIf( items: List, - delegate: AnyTypeDelegate, V, H>, + delegate: AnyTypeDelegate, predicate: () -> Boolean ): Builder { return apply { @@ -137,23 +137,35 @@ class AnyTypeCollection private constructor( } } + /** + * Adds [item] and the corresponding [delegate] only if the item (which must be a collection) is not empty + */ + fun , V : ViewBinding, H : AnyTypeViewHolder> addIfNotEmpty( + item: T, + delegate: AnyTypeDelegate + ): Builder { + return apply { addIf(item, delegate) { item.count() > 0 } } + } + /** * Adds [items] and the corresponding [delegate] only if the list of items is not empty */ - fun , V>> addIfNotEmpty( + fun > addIfNotEmpty( items: List, - delegate: AnyTypeDelegate, V, H> + delegate: AnyTypeDelegate ): Builder { return apply { addIf(items, delegate) { items.isNotEmpty() } } } fun build(): AnyTypeCollection { val positionsRanges = with(itemsMetaData) { - zipWithNext { first, second -> - first.position until second.position - } + when { + when { isEmpty() -> emptyList() - else -> listOf(last().position until items.size) + else -> { + zipWithNext { first, second -> + first.position until second.position + } + listOf(last().position until items.size) + } } } return AnyTypeCollection(items, itemsMetaData, positionsRanges) diff --git a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt b/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt new file mode 100644 index 0000000..65fd04b --- /dev/null +++ b/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt @@ -0,0 +1,90 @@ +package vsukharev.anytypeadapter + +import org.junit.jupiter.api.Test +import vsukharev.anytypeadapter.adapter.AnyTypeCollection +import vsukharev.anytypeadapter.domain.Activity +import vsukharev.anytypeadapter.domain.Track + +class AnyTypeCollectionBuilderTest { + + @Test + fun add_addItemsOfDifferentViewTypes_eachTimeViewTypeIsDifferentNewItemIsAddedToItemsMetaDataCollection() { + var itemsCount = 0 + var itemsMetadataCount = 0 + AnyTypeCollection.Builder() + .apply { + repeat((1..10).count()) { + add(Track(), trackDelegate).also { itemsCount++ } + }.also { itemsMetadataCount++ } + add(headerDelegate).also { itemsCount++; itemsMetadataCount++ } + repeat((1..10).count()) { + add(Activity(), activityDelegate).also { itemsCount++ } + }.also { itemsMetadataCount++ } + } + .build() + .apply { + assert(itemsMetaData.size == itemsMetadataCount && items.size == itemsCount) + } + } + + @Test + fun addIf_predicateIsEitherTrueEitherFalse_itemIsAddedOnlyWhenPredicateIsTrue() { + var itemsCount = 0 + var itemsMetadataCount = 0 + AnyTypeCollection.Builder() + .apply { + repeat((1..10).count()) { + (addIf(Track(), trackDelegate) { it % 2 == 0 }).also { itemsCount++ } + }.also { itemsMetadataCount++ } + } + .build() + .apply { + assert(itemsMetaData.size == itemsMetadataCount && size == itemsCount / 2) + } + } + + @Test + fun addIf_predicateIsEitherTrueEitherFalse_noDataItemIsAddedOnlyWhenPredicateIsTrue() { + var itemsCount = 0 + var itemsMetadataCount = 0 + AnyTypeCollection.Builder() + .addIf(headerDelegate) { true }.also { itemsCount++ ; itemsMetadataCount++ } + .addIf(headerDelegate) { false }.also { itemsCount++} + .build() + .apply { itemsMetaData.size == 1 && size == 1 } + } + + @Test + fun addIf_dataIsListAndPredicateIsEitherTrueEitherFalse_itemIsAddedOnlyWhenPredicateIsTrue() { + var itemsCount = 0 + var itemsMetadataCount = 0 + AnyTypeCollection.Builder() + .apply { + repeat((1..10).count()) { + (addIf(listOf(Track()), trackDelegate) { it % 2 == 0 }).also { itemsCount++ } + }.also { itemsMetadataCount++ } + } + .build() + .apply { + assert(itemsMetaData.size == itemsMetadataCount && items.size == itemsCount / 2) + } + } + + @Test + fun addIfNotEmpty_inputListIsEmpty_dataListShouldNotBeAdded() { + AnyTypeCollection.Builder() + .addIfNotEmpty(listOf(), trackDelegate) + .addIfNotEmpty(listOf(), trackListDelegate) + .build() + .apply { assert(itemsMetaData.isEmpty() && items.isEmpty()) } + } + + @Test + fun addIfNotEmpty_inputListIsNotEmpty_dataListShouldBeAdded() { + AnyTypeCollection.Builder() + .addIfNotEmpty(listOf(Track()), trackDelegate) + .addIfNotEmpty(listOf(Track()), trackListDelegate) + .build() + .apply { assert(itemsMetaData.isNotEmpty() && items.isNotEmpty()) } + } +} \ No newline at end of file diff --git a/library/src/test/java/vsukharev/anytypeadapter/ExampleUnitTest.kt b/library/src/test/java/vsukharev/anytypeadapter/ExampleUnitTest.kt deleted file mode 100644 index 31c14ff..0000000 --- a/library/src/test/java/vsukharev/anytypeadapter/ExampleUnitTest.kt +++ /dev/null @@ -1,17 +0,0 @@ -package vsukharev.anytypeadapter - -import org.junit.Test - -import org.junit.Assert.* - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} diff --git a/library/src/test/java/vsukharev/anytypeadapter/MockDelegates.kt b/library/src/test/java/vsukharev/anytypeadapter/MockDelegates.kt new file mode 100644 index 0000000..66dbb5c --- /dev/null +++ b/library/src/test/java/vsukharev/anytypeadapter/MockDelegates.kt @@ -0,0 +1,53 @@ +package vsukharev.anytypeadapter + +import android.view.View +import androidx.viewbinding.ViewBinding +import vsukharev.anytypeadapter.delegate.AnyTypeDelegate +import vsukharev.anytypeadapter.delegate.NoDataDelegate +import vsukharev.anytypeadapter.domain.Activity +import vsukharev.anytypeadapter.domain.Track +import vsukharev.anytypeadapter.holder.AnyTypeViewHolder +import vsukharev.anytypeadapter.holder.NoDataViewHolder +import java.util.* + +val headerDelegate = + object : NoDataDelegate() { + override fun createViewHolder(itemView: View): NoDataViewHolder { + TODO("Not yet implemented") + } + + override fun getItemViewType(): Int = 0 + } + +val trackDelegate = + object : AnyTypeDelegate>() { + override fun createViewHolder(itemView: View): AnyTypeViewHolder { + TODO("Not yet implemented") + } + + override fun getItemViewType(): Int = 2 + + override fun getItemId(item: Track): String = UUID.randomUUID().toString() + } + +val activityDelegate = + object : AnyTypeDelegate>() { + override fun createViewHolder(itemView: View): AnyTypeViewHolder { + TODO("Not yet implemented") + } + + override fun getItemViewType(): Int = 3 + + override fun getItemId(item: Activity): String = item.toString() + } + +val trackListDelegate = + object : AnyTypeDelegate, ViewBinding, AnyTypeViewHolder, ViewBinding>>() { + override fun createViewHolder(itemView: View): AnyTypeViewHolder, ViewBinding> { + TODO("Not yet implemented") + } + + override fun getItemViewType(): Int = 4 + + override fun getItemId(item: List): String = item.toString() + } \ No newline at end of file diff --git a/library/src/test/java/vsukharev/anytypeadapter/domain/Activity.kt b/library/src/test/java/vsukharev/anytypeadapter/domain/Activity.kt new file mode 100644 index 0000000..f9ab2f3 --- /dev/null +++ b/library/src/test/java/vsukharev/anytypeadapter/domain/Activity.kt @@ -0,0 +1,8 @@ +package vsukharev.anytypeadapter.domain + +import java.util.* + +data class Activity( + val name: String = UUID.randomUUID().toString(), + val id: String = UUID.randomUUID().toString() +) \ No newline at end of file diff --git a/library/src/test/java/vsukharev/anytypeadapter/domain/Track.kt b/library/src/test/java/vsukharev/anytypeadapter/domain/Track.kt new file mode 100644 index 0000000..c535f40 --- /dev/null +++ b/library/src/test/java/vsukharev/anytypeadapter/domain/Track.kt @@ -0,0 +1,8 @@ +package vsukharev.anytypeadapter.domain + +import java.util.* + +data class Track( + val name: String = UUID.randomUUID().toString(), + val id: String = UUID.randomUUID().toString() +) \ No newline at end of file From e0e6a73b5a58b659eb89264e1e5010b7e32093bd Mon Sep 17 00:00:00 2001 From: vsukharew Date: Wed, 27 Oct 2021 22:58:47 +0300 Subject: [PATCH 3/9] Add AnyTypeCollection tests (#80) * added test for 'build' function * - moved findCurrentItemViewTypePosition() from AnyTypeAdapter.kt to AnyTypeCollection.kt - added tests for AnyTypeCollection.kt * added tests for AnyTypeDelegate --- dependencies.gradle | 10 ++-- library/build.gradle | 1 + .../anytypeadapter/adapter/AnyTypeAdapter.kt | 27 +-------- .../adapter/AnyTypeCollection.kt | 39 ++++++++++++- .../AnyTypeCollectionBuilderTest.kt | 14 ++++- .../anytypeadapter/AnyTypeCollectionTest.kt | 56 +++++++++++++++++++ .../delegate/AnyTypeDelegateTest.kt | 21 +++++++ 7 files changed, 134 insertions(+), 34 deletions(-) create mode 100644 library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt create mode 100644 library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt diff --git a/dependencies.gradle b/dependencies.gradle index 67dde4a..984973f 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -4,10 +4,10 @@ ext { buildToolsVersion: "29.0.3", minSdkVersion : 14, library : [ - publishGroupId: 'io.github.vsukharew', + publishGroupId : 'io.github.vsukharew', publishArtifactId: 'anytypeadapter', - versionName: "1.0.11", - versionCode: 1, + versionName : "1.0.11", + versionCode : 1, ], sample : [ versionName: "1.0", @@ -41,7 +41,8 @@ ext { moxy : '2.1.2', retrofit : '2.8.1', leakcanary : '2.2', - junit : '5.7.1' + junit : '5.7.1', + mockito : '3.2.0', ] androidx = [ appCompat : "androidx.appcompat:appcompat:${versions.androidx.appCompat}", @@ -73,4 +74,5 @@ ext { dagger : "com.google.dagger:dagger:${versions.dagger}", ] junit = "org.junit.jupiter:junit-jupiter-engine:${versions.junit}" + mockito = "org.mockito.kotlin:mockito-kotlin:${versions.mockito}" } \ No newline at end of file diff --git a/library/build.gradle b/library/build.gradle index c5432c5..b22a06c 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -42,6 +42,7 @@ dependencies { implementation androidx.constraintLayout implementation androidx.recyclerView testImplementation junit + testImplementation mockito androidTestImplementation androidx.testRunner androidTestImplementation androidx.espresso } \ No newline at end of file diff --git a/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeAdapter.kt b/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeAdapter.kt index 2d8c5f2..1f4ef6f 100644 --- a/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeAdapter.kt +++ b/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeAdapter.kt @@ -41,10 +41,9 @@ open class AnyTypeAdapter : RecyclerView.Adapter, - adapterPosition: Int - ): Int { - return with(positionsRanges) { - binarySearch { - when { - adapterPosition in it -> 0 - adapterPosition < it.first -> 1 - else -> -1 - } - } - } - } - private class DiffUtilCallback( private val oldList: List>, private val newList: List> diff --git a/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt b/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt index 5829813..5a413ac 100644 --- a/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt +++ b/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt @@ -7,6 +7,7 @@ import vsukharev.anytypeadapter.item.AdapterItemMetaData import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding import vsukharev.anytypeadapter.delegate.NoDataDelegate +import java.lang.IllegalStateException /** * Class that wraps items for [AnyTypeAdapter] @@ -23,16 +24,43 @@ class AnyTypeCollection private constructor( /** * Saved position value provided in [RecyclerView.Adapter.getItemViewType] */ - var currentItemViewTypePosition: Int = 0 + internal var currentItemViewTypePosition: Int = NO_POSITION /** * Returns delegate at the given position in the [itemsMetaData] collection */ val currentItemViewTypeDelegate: AnyTypeDelegate> - get() = itemsMetaData[currentItemViewTypePosition].delegate + get() { + return if (itemsMetaData.isNotEmpty()) { + itemsMetaData[currentItemViewTypePosition].delegate + } else { + throw IllegalStateException("Unable to get a delegate in an empty collection") + } + } val size: Int = items.size + /** + * Finds position for the current item view type given current [adapterPosition] + * @see [AnyTypeCollection.itemsMetaData] + */ + fun findCurrentItemViewTypePosition(adapterPosition: Int): Int { + val currentPositionsRange = positionsRanges.getOrNull(currentItemViewTypePosition) + return if (currentPositionsRange?.contains(adapterPosition) == true) { + currentItemViewTypePosition + } else { + with(positionsRanges) { + binarySearch { + when { + adapterPosition in it -> 0 + adapterPosition < it.first -> 1 + else -> -1 + } + } + } + } + } + class Builder { private val items = mutableListOf>() private val itemsMetaData = mutableListOf>() @@ -168,11 +196,16 @@ class AnyTypeCollection private constructor( } } } - return AnyTypeCollection(items, itemsMetaData, positionsRanges) + return AnyTypeCollection(items, itemsMetaData, positionsRanges).apply { + if (items.isNotEmpty()) { + currentItemViewTypePosition = 0 + } + } } } companion object { + const val NO_POSITION = -1 val EMPTY = Builder().build() } } \ No newline at end of file diff --git a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt b/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt index 65fd04b..5555c82 100644 --- a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt +++ b/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt @@ -48,10 +48,10 @@ class AnyTypeCollectionBuilderTest { var itemsCount = 0 var itemsMetadataCount = 0 AnyTypeCollection.Builder() - .addIf(headerDelegate) { true }.also { itemsCount++ ; itemsMetadataCount++ } - .addIf(headerDelegate) { false }.also { itemsCount++} + .addIf(headerDelegate) { true }.also { itemsCount++; itemsMetadataCount++ } + .addIf(headerDelegate) { false }.also { itemsCount++ } .build() - .apply { itemsMetaData.size == 1 && size == 1 } + .apply { assert(itemsMetaData.size == itemsMetadataCount && size != itemsCount && size == 1) } } @Test @@ -87,4 +87,12 @@ class AnyTypeCollectionBuilderTest { .build() .apply { assert(itemsMetaData.isNotEmpty() && items.isNotEmpty()) } } + + @Test + fun build_emptyCollection_shouldGetEmptyCollectionOfRanges() { + val collection = AnyTypeCollection.EMPTY + val expected = emptyList() + val actual = collection.positionsRanges + assert(expected == actual) + } } \ No newline at end of file diff --git a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt b/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt new file mode 100644 index 0000000..4017e7e --- /dev/null +++ b/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt @@ -0,0 +1,56 @@ +package vsukharev.anytypeadapter + +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertDoesNotThrow +import org.junit.jupiter.api.assertThrows +import vsukharev.anytypeadapter.adapter.AnyTypeCollection +import vsukharev.anytypeadapter.domain.Activity +import vsukharev.anytypeadapter.domain.Track +import java.lang.IllegalStateException + +class AnyTypeCollectionTest { + + @Test + fun currentItemViewTypeDelegate_collectionIsEmpty_exceptionShouldBeThrown() { + val collection = AnyTypeCollection.EMPTY + assertThrows { collection.currentItemViewTypeDelegate } + } + + @Test + fun currentItemViewTypeDelegate_collectionIsNotEmpty_exceptionShouldNotBeThrown() { + AnyTypeCollection.Builder() + .add(headerDelegate) + .build() + .apply { + assertDoesNotThrow { currentItemViewTypeDelegate } + assert(currentItemViewTypeDelegate::class == headerDelegate::class) + } + } + + @Test + fun currentItemViewTypePosition_collectionIsEmpty_shouldBeEqualToNoPosition() { + val collection = AnyTypeCollection.EMPTY + assert(collection.currentItemViewTypePosition == AnyTypeCollection.NO_POSITION) + } + + @Test + fun findCurrentItemViewType() { + AnyTypeCollection.Builder() + .add(listOf(Track(), Track(), Track()), trackDelegate) + .add(headerDelegate) + .add(listOf(Activity(), Activity()), activityDelegate) + .build() + .apply { + for (i in 1 until size) { + val position = findCurrentItemViewTypePosition(i) + if (items[i].data::class == items[i - 1].data::class) { + assert(position == currentItemViewTypePosition) + } else { + assert(position != currentItemViewTypePosition) + currentItemViewTypePosition = position + } + } + assert(currentItemViewTypePosition == itemsMetaData.size - 1) + } + } +} \ No newline at end of file diff --git a/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt b/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt new file mode 100644 index 0000000..4312651 --- /dev/null +++ b/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt @@ -0,0 +1,21 @@ +package vsukharev.anytypeadapter.delegate + +import androidx.viewbinding.ViewBinding +import org.junit.jupiter.api.Test +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify +import vsukharev.anytypeadapter.domain.Track +import vsukharev.anytypeadapter.holder.AnyTypeViewHolder +import vsukharev.anytypeadapter.item.AdapterItem +import vsukharev.anytypeadapter.trackDelegate + +class AnyTypeDelegateTest { + private val holder = mock>() + + @Test + fun bind() { + val track = Track() + trackDelegate.bind(AdapterItem("", track), holder) + verify(holder).bind(track) + } +} \ No newline at end of file From 545e24edb480ff04640a8c4e8c53a3fda6849db3 Mon Sep 17 00:00:00 2001 From: vsukharew Date: Sun, 31 Oct 2021 16:05:01 +0300 Subject: [PATCH 4/9] Edit tests using mocks (#81) * fixed returning the same id for each NoDataDelegate * added tests that verify methods calls --- .../anytypeadapter/delegate/NoDataDelegate.kt | 17 ++-- .../AnyTypeCollectionBuilderTest.kt | 85 ++++++++++++++++++- .../anytypeadapter/AnyTypeCollectionTest.kt | 7 +- .../anytypeadapter/MockInitializer.kt | 40 +++++++++ .../delegate/AnyTypeDelegateTest.kt | 17 ++-- 5 files changed, 138 insertions(+), 28 deletions(-) create mode 100644 library/src/test/java/vsukharev/anytypeadapter/MockInitializer.kt diff --git a/library/src/main/java/vsukharev/anytypeadapter/delegate/NoDataDelegate.kt b/library/src/main/java/vsukharev/anytypeadapter/delegate/NoDataDelegate.kt index 2274516..97cb5f7 100644 --- a/library/src/main/java/vsukharev/anytypeadapter/delegate/NoDataDelegate.kt +++ b/library/src/main/java/vsukharev/anytypeadapter/delegate/NoDataDelegate.kt @@ -1,10 +1,8 @@ package vsukharev.anytypeadapter.delegate -import android.view.LayoutInflater -import android.view.View import androidx.viewbinding.ViewBinding -import vsukharev.anytypeadapter.holder.NoDataViewHolder import vsukharev.anytypeadapter.adapter.AnyTypeAdapter +import vsukharev.anytypeadapter.holder.NoDataViewHolder import java.util.* /** @@ -12,13 +10,8 @@ import java.util.* * This delegate can be used when creating list for [AnyTypeAdapter] without specifying data to bind */ abstract class NoDataDelegate : AnyTypeDelegate>() { - - override fun getItemId(item: Unit): String = ITEM_ID - - private companion object { - /** - * This delegate has an "artificial" identifier because there is no data - */ - val ITEM_ID: String = UUID.randomUUID().toString() - } + /** + * This delegate has an artificial identifier because there is no data + */ + override fun getItemId(item: Unit): String = UUID.randomUUID().toString() } \ No newline at end of file diff --git a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt b/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt index 5555c82..08205cc 100644 --- a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt +++ b/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt @@ -1,11 +1,15 @@ package vsukharev.anytypeadapter import org.junit.jupiter.api.Test +import org.mockito.kotlin.any +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.verifyZeroInteractions import vsukharev.anytypeadapter.adapter.AnyTypeCollection import vsukharev.anytypeadapter.domain.Activity import vsukharev.anytypeadapter.domain.Track -class AnyTypeCollectionBuilderTest { +class AnyTypeCollectionBuilderTest : MockInitializer() { @Test fun add_addItemsOfDifferentViewTypes_eachTimeViewTypeIsDifferentNewItemIsAddedToItemsMetaDataCollection() { @@ -27,6 +31,49 @@ class AnyTypeCollectionBuilderTest { } } + @Test + fun add_addItemsOfDifferentViewTypes_verifyGetItemIdCalledEachTimeWhenItemAdded() { + val tracksCount = 10 + val activitiesCount = 10 + AnyTypeCollection.Builder() + .apply { + repeat((1..tracksCount).count()) { + add(Track(), trackDelegate) + } + add(headerDelegate) + repeat((1..activitiesCount).count()) { + add(Activity(), activityDelegate) + } + + verify(trackDelegate, times(tracksCount)).getItemId(any()) + verify(headerDelegate, times(1)).getItemId(any()) + verify(activityDelegate, times(activitiesCount)).getItemId(any()) + } + } + + @Test + fun add_addItemsOfDifferentViewTypes_verifyGetItemViewTypeCalledTwiceEachTimeItemAddedExceptCornerAdditions() { + val tracksCount = 10 + val tracksListsCount = 1 + val activitiesCount = 10 + AnyTypeCollection.Builder() + .apply { + repeat((1..tracksCount).count()) { + add(Track(), trackDelegate) + } //corner addition + add(headerDelegate) + add(listOf(Track(), Track()), trackListDelegate) + repeat((1..activitiesCount).count()) { + add(Activity(), activityDelegate) + } //corner addition + + verify(trackDelegate, times((tracksCount * 2 - 1))).getItemViewType() + verify(headerDelegate, times(2)).getItemViewType() + verify(trackListDelegate, times(tracksListsCount * 2)).getItemViewType() + verify(activityDelegate, times((activitiesCount * 2 - 1))).getItemViewType() + } + } + @Test fun addIf_predicateIsEitherTrueEitherFalse_itemIsAddedOnlyWhenPredicateIsTrue() { var itemsCount = 0 @@ -70,6 +117,20 @@ class AnyTypeCollectionBuilderTest { } } + @Test + fun addIf_predicateIsEitherTrueEitherFalse_verifyGetItemIdCalledOnlyWhenPredicateIsTrue() { + var itemsCount = 0 + var itemsMetadataCount = 0 + AnyTypeCollection.Builder() + .apply { + repeat((1..10).count()) { + (addIf(Track(), trackDelegate) { it % 2 == 0 }).also { itemsCount++ } + }.also { itemsMetadataCount++ } + + verify(trackDelegate, times((itemsCount / 2))).getItemId(any()) + } + } + @Test fun addIfNotEmpty_inputListIsEmpty_dataListShouldNotBeAdded() { AnyTypeCollection.Builder() @@ -79,6 +140,17 @@ class AnyTypeCollectionBuilderTest { .apply { assert(itemsMetaData.isEmpty() && items.isEmpty()) } } + @Test + fun addIfNotEmpty_inputListIsEmpty_noneDelegateMethodsGetCalled() { + AnyTypeCollection.Builder() + .addIfNotEmpty(listOf(), trackDelegate) + .addIfNotEmpty(listOf(), trackListDelegate) + .apply { + verifyZeroInteractions(trackDelegate) + verifyZeroInteractions(trackListDelegate) + } + } + @Test fun addIfNotEmpty_inputListIsNotEmpty_dataListShouldBeAdded() { AnyTypeCollection.Builder() @@ -88,6 +160,17 @@ class AnyTypeCollectionBuilderTest { .apply { assert(itemsMetaData.isNotEmpty() && items.isNotEmpty()) } } + @Test + fun addIfNotEmpty_inputListIsNotEmpty_delegateMethodsGetCalled() { + AnyTypeCollection.Builder() + .addIfNotEmpty(listOf(Track()), trackDelegate) + .addIfNotEmpty(listOf(Track()), trackListDelegate) + .apply { + verify(trackDelegate).getItemId(any()) + verify(trackListDelegate).getItemId(any()) + } + } + @Test fun build_emptyCollection_shouldGetEmptyCollectionOfRanges() { val collection = AnyTypeCollection.EMPTY diff --git a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt b/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt index 4017e7e..63dc6d5 100644 --- a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt +++ b/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt @@ -6,9 +6,8 @@ import org.junit.jupiter.api.assertThrows import vsukharev.anytypeadapter.adapter.AnyTypeCollection import vsukharev.anytypeadapter.domain.Activity import vsukharev.anytypeadapter.domain.Track -import java.lang.IllegalStateException -class AnyTypeCollectionTest { +class AnyTypeCollectionTest : MockInitializer() { @Test fun currentItemViewTypeDelegate_collectionIsEmpty_exceptionShouldBeThrown() { @@ -34,7 +33,7 @@ class AnyTypeCollectionTest { } @Test - fun findCurrentItemViewType() { + fun findCurrentItemViewType_iterateThroughCollection_whileItemsAreOfSameFindCurrentItemViewTypePositionReturnsSavedValue() { AnyTypeCollection.Builder() .add(listOf(Track(), Track(), Track()), trackDelegate) .add(headerDelegate) @@ -47,7 +46,7 @@ class AnyTypeCollectionTest { assert(position == currentItemViewTypePosition) } else { assert(position != currentItemViewTypePosition) - currentItemViewTypePosition = position + currentItemViewTypePosition = position // in real code, this saving takes place in adapter } } assert(currentItemViewTypePosition == itemsMetaData.size - 1) diff --git a/library/src/test/java/vsukharev/anytypeadapter/MockInitializer.kt b/library/src/test/java/vsukharev/anytypeadapter/MockInitializer.kt new file mode 100644 index 0000000..a6956c1 --- /dev/null +++ b/library/src/test/java/vsukharev/anytypeadapter/MockInitializer.kt @@ -0,0 +1,40 @@ +package vsukharev.anytypeadapter + +import androidx.viewbinding.ViewBinding +import org.junit.jupiter.api.BeforeEach +import org.mockito.Mockito +import org.mockito.kotlin.any +import org.mockito.kotlin.mock +import vsukharev.anytypeadapter.delegate.AnyTypeDelegate +import vsukharev.anytypeadapter.delegate.NoDataDelegate +import vsukharev.anytypeadapter.domain.Activity +import vsukharev.anytypeadapter.domain.Track +import vsukharev.anytypeadapter.holder.AnyTypeViewHolder +import java.util.* + +open class MockInitializer { + protected val headerDelegate = mock>() + protected val trackDelegate = + mock>>() + protected val activityDelegate = + mock>>() + protected val trackListDelegate = + mock, ViewBinding, AnyTypeViewHolder, ViewBinding>>>() + protected val trackHolder = mock>() + + @BeforeEach + protected fun initMocks() { + Mockito.`when`(headerDelegate.getItemViewType()).thenReturn(0) + Mockito.`when`(headerDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) + + + Mockito.`when`(trackDelegate.getItemViewType()).thenReturn(1) + Mockito.`when`(trackDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) + + Mockito.`when`(activityDelegate.getItemViewType()).thenReturn(2) + Mockito.`when`(activityDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) + + Mockito.`when`(trackListDelegate.getItemViewType()).thenReturn(3) + Mockito.`when`(trackListDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) + } +} \ No newline at end of file diff --git a/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt b/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt index 4312651..1c3cd4e 100644 --- a/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt +++ b/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt @@ -1,21 +1,16 @@ package vsukharev.anytypeadapter.delegate -import androidx.viewbinding.ViewBinding import org.junit.jupiter.api.Test -import org.mockito.kotlin.mock +import org.mockito.kotlin.any import org.mockito.kotlin.verify -import vsukharev.anytypeadapter.domain.Track -import vsukharev.anytypeadapter.holder.AnyTypeViewHolder +import vsukharev.anytypeadapter.MockInitializer import vsukharev.anytypeadapter.item.AdapterItem -import vsukharev.anytypeadapter.trackDelegate -class AnyTypeDelegateTest { - private val holder = mock>() +class AnyTypeDelegateTest : MockInitializer() { @Test - fun bind() { - val track = Track() - trackDelegate.bind(AdapterItem("", track), holder) - verify(holder).bind(track) + fun bind_callWithAnyData_verifyHolderBindGetCalled() { + trackDelegate.bind(AdapterItem(any(), any()), trackHolder) + verify(trackHolder).bind(any()) } } \ No newline at end of file From 8e978350ca3b4c730a3640592bcdc9256c74bce5 Mon Sep 17 00:00:00 2001 From: vsukharew Date: Tue, 2 Nov 2021 19:46:10 +0300 Subject: [PATCH 5/9] cleanup code (#82) - distributed classes into packages - deleted unused code - imported `when` method --- .../vsukharev/anytypeadapter/MockDelegates.kt | 53 ------------------- .../AnyTypeCollectionBuilderTest.kt | 4 +- .../{ => adapter}/AnyTypeCollectionTest.kt | 4 +- .../{ => common}/MockInitializer.kt | 21 ++++---- .../delegate/AnyTypeDelegateTest.kt | 2 +- 5 files changed, 15 insertions(+), 69 deletions(-) delete mode 100644 library/src/test/java/vsukharev/anytypeadapter/MockDelegates.kt rename library/src/test/java/vsukharev/anytypeadapter/{ => adapter}/AnyTypeCollectionBuilderTest.kt (98%) rename library/src/test/java/vsukharev/anytypeadapter/{ => adapter}/AnyTypeCollectionTest.kt (95%) rename library/src/test/java/vsukharev/anytypeadapter/{ => common}/MockInitializer.kt (58%) diff --git a/library/src/test/java/vsukharev/anytypeadapter/MockDelegates.kt b/library/src/test/java/vsukharev/anytypeadapter/MockDelegates.kt deleted file mode 100644 index 66dbb5c..0000000 --- a/library/src/test/java/vsukharev/anytypeadapter/MockDelegates.kt +++ /dev/null @@ -1,53 +0,0 @@ -package vsukharev.anytypeadapter - -import android.view.View -import androidx.viewbinding.ViewBinding -import vsukharev.anytypeadapter.delegate.AnyTypeDelegate -import vsukharev.anytypeadapter.delegate.NoDataDelegate -import vsukharev.anytypeadapter.domain.Activity -import vsukharev.anytypeadapter.domain.Track -import vsukharev.anytypeadapter.holder.AnyTypeViewHolder -import vsukharev.anytypeadapter.holder.NoDataViewHolder -import java.util.* - -val headerDelegate = - object : NoDataDelegate() { - override fun createViewHolder(itemView: View): NoDataViewHolder { - TODO("Not yet implemented") - } - - override fun getItemViewType(): Int = 0 - } - -val trackDelegate = - object : AnyTypeDelegate>() { - override fun createViewHolder(itemView: View): AnyTypeViewHolder { - TODO("Not yet implemented") - } - - override fun getItemViewType(): Int = 2 - - override fun getItemId(item: Track): String = UUID.randomUUID().toString() - } - -val activityDelegate = - object : AnyTypeDelegate>() { - override fun createViewHolder(itemView: View): AnyTypeViewHolder { - TODO("Not yet implemented") - } - - override fun getItemViewType(): Int = 3 - - override fun getItemId(item: Activity): String = item.toString() - } - -val trackListDelegate = - object : AnyTypeDelegate, ViewBinding, AnyTypeViewHolder, ViewBinding>>() { - override fun createViewHolder(itemView: View): AnyTypeViewHolder, ViewBinding> { - TODO("Not yet implemented") - } - - override fun getItemViewType(): Int = 4 - - override fun getItemId(item: List): String = item.toString() - } \ No newline at end of file diff --git a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt b/library/src/test/java/vsukharev/anytypeadapter/adapter/AnyTypeCollectionBuilderTest.kt similarity index 98% rename from library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt rename to library/src/test/java/vsukharev/anytypeadapter/adapter/AnyTypeCollectionBuilderTest.kt index 08205cc..af39eb7 100644 --- a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionBuilderTest.kt +++ b/library/src/test/java/vsukharev/anytypeadapter/adapter/AnyTypeCollectionBuilderTest.kt @@ -1,11 +1,11 @@ -package vsukharev.anytypeadapter +package vsukharev.anytypeadapter.adapter import org.junit.jupiter.api.Test import org.mockito.kotlin.any import org.mockito.kotlin.times import org.mockito.kotlin.verify import org.mockito.kotlin.verifyZeroInteractions -import vsukharev.anytypeadapter.adapter.AnyTypeCollection +import vsukharev.anytypeadapter.common.MockInitializer import vsukharev.anytypeadapter.domain.Activity import vsukharev.anytypeadapter.domain.Track diff --git a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt b/library/src/test/java/vsukharev/anytypeadapter/adapter/AnyTypeCollectionTest.kt similarity index 95% rename from library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt rename to library/src/test/java/vsukharev/anytypeadapter/adapter/AnyTypeCollectionTest.kt index 63dc6d5..a2bfcf1 100644 --- a/library/src/test/java/vsukharev/anytypeadapter/AnyTypeCollectionTest.kt +++ b/library/src/test/java/vsukharev/anytypeadapter/adapter/AnyTypeCollectionTest.kt @@ -1,9 +1,9 @@ -package vsukharev.anytypeadapter +package vsukharev.anytypeadapter.adapter import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertDoesNotThrow import org.junit.jupiter.api.assertThrows -import vsukharev.anytypeadapter.adapter.AnyTypeCollection +import vsukharev.anytypeadapter.common.MockInitializer import vsukharev.anytypeadapter.domain.Activity import vsukharev.anytypeadapter.domain.Track diff --git a/library/src/test/java/vsukharev/anytypeadapter/MockInitializer.kt b/library/src/test/java/vsukharev/anytypeadapter/common/MockInitializer.kt similarity index 58% rename from library/src/test/java/vsukharev/anytypeadapter/MockInitializer.kt rename to library/src/test/java/vsukharev/anytypeadapter/common/MockInitializer.kt index a6956c1..600f9e9 100644 --- a/library/src/test/java/vsukharev/anytypeadapter/MockInitializer.kt +++ b/library/src/test/java/vsukharev/anytypeadapter/common/MockInitializer.kt @@ -1,8 +1,8 @@ -package vsukharev.anytypeadapter +package vsukharev.anytypeadapter.common import androidx.viewbinding.ViewBinding import org.junit.jupiter.api.BeforeEach -import org.mockito.Mockito +import org.mockito.Mockito.`when` import org.mockito.kotlin.any import org.mockito.kotlin.mock import vsukharev.anytypeadapter.delegate.AnyTypeDelegate @@ -24,17 +24,16 @@ open class MockInitializer { @BeforeEach protected fun initMocks() { - Mockito.`when`(headerDelegate.getItemViewType()).thenReturn(0) - Mockito.`when`(headerDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) + `when`(headerDelegate.getItemViewType()).thenReturn(0) + `when`(headerDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) + `when`(trackDelegate.getItemViewType()).thenReturn(1) + `when`(trackDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) - Mockito.`when`(trackDelegate.getItemViewType()).thenReturn(1) - Mockito.`when`(trackDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) + `when`(activityDelegate.getItemViewType()).thenReturn(2) + `when`(activityDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) - Mockito.`when`(activityDelegate.getItemViewType()).thenReturn(2) - Mockito.`when`(activityDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) - - Mockito.`when`(trackListDelegate.getItemViewType()).thenReturn(3) - Mockito.`when`(trackListDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) + `when`(trackListDelegate.getItemViewType()).thenReturn(3) + `when`(trackListDelegate.getItemId(any())).thenReturn(UUID.randomUUID().toString()) } } \ No newline at end of file diff --git a/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt b/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt index 1c3cd4e..cf2597b 100644 --- a/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt +++ b/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt @@ -3,7 +3,7 @@ package vsukharev.anytypeadapter.delegate import org.junit.jupiter.api.Test import org.mockito.kotlin.any import org.mockito.kotlin.verify -import vsukharev.anytypeadapter.MockInitializer +import vsukharev.anytypeadapter.common.MockInitializer import vsukharev.anytypeadapter.item.AdapterItem class AnyTypeDelegateTest : MockInitializer() { From 62a56bccd8d035c6786593fec7302d69f2d21831 Mon Sep 17 00:00:00 2001 From: vsukharew Date: Tue, 2 Nov 2021 21:41:59 +0300 Subject: [PATCH 6/9] added tests with argument captors usage (#83) --- .../adapter/AnyTypeCollectionBuilderTest.kt | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/library/src/test/java/vsukharev/anytypeadapter/adapter/AnyTypeCollectionBuilderTest.kt b/library/src/test/java/vsukharev/anytypeadapter/adapter/AnyTypeCollectionBuilderTest.kt index af39eb7..38e8627 100644 --- a/library/src/test/java/vsukharev/anytypeadapter/adapter/AnyTypeCollectionBuilderTest.kt +++ b/library/src/test/java/vsukharev/anytypeadapter/adapter/AnyTypeCollectionBuilderTest.kt @@ -1,10 +1,7 @@ package vsukharev.anytypeadapter.adapter import org.junit.jupiter.api.Test -import org.mockito.kotlin.any -import org.mockito.kotlin.times -import org.mockito.kotlin.verify -import org.mockito.kotlin.verifyZeroInteractions +import org.mockito.kotlin.* import vsukharev.anytypeadapter.common.MockInitializer import vsukharev.anytypeadapter.domain.Activity import vsukharev.anytypeadapter.domain.Track @@ -53,27 +50,48 @@ class AnyTypeCollectionBuilderTest : MockInitializer() { @Test fun add_addItemsOfDifferentViewTypes_verifyGetItemViewTypeCalledTwiceEachTimeItemAddedExceptCornerAdditions() { - val tracksCount = 10 - val tracksListsCount = 1 + val tracksList = listOf(Track(), Track()) val activitiesCount = 10 AnyTypeCollection.Builder() .apply { - repeat((1..tracksCount).count()) { - add(Track(), trackDelegate) - } //corner addition + add(tracksList, trackDelegate) //corner addition add(headerDelegate) - add(listOf(Track(), Track()), trackListDelegate) + add(tracksList, trackListDelegate) repeat((1..activitiesCount).count()) { add(Activity(), activityDelegate) } //corner addition - verify(trackDelegate, times((tracksCount * 2 - 1))).getItemViewType() + verify(trackDelegate, times((tracksList.size * 2 - 1))).getItemViewType() verify(headerDelegate, times(2)).getItemViewType() - verify(trackListDelegate, times(tracksListsCount * 2)).getItemViewType() + verify(trackListDelegate, times(tracksList.size)).getItemViewType() verify(activityDelegate, times((activitiesCount * 2 - 1))).getItemViewType() } } + @Test + fun add_addSingleItem_verifyGetItemIdCalledWithAddedItem() { + val track = Track() + val captor = argumentCaptor() + AnyTypeCollection.Builder() + .apply { + add(track, trackDelegate) + verify(trackDelegate).getItemId(captor.capture()) + assert(track == captor.lastValue) + } + } + + @Test + fun add_addList_verifyGetItemIdCalledWithEachListItem() { + val tracksList = listOf(Track(), Track()) + val captor = argumentCaptor() + AnyTypeCollection.Builder() + .apply { + add(tracksList, trackDelegate) + verify(trackDelegate, times(tracksList.size)).getItemId(captor.capture()) + assert(tracksList == captor.allValues) + } + } + @Test fun addIf_predicateIsEitherTrueEitherFalse_itemIsAddedOnlyWhenPredicateIsTrue() { var itemsCount = 0 @@ -134,8 +152,8 @@ class AnyTypeCollectionBuilderTest : MockInitializer() { @Test fun addIfNotEmpty_inputListIsEmpty_dataListShouldNotBeAdded() { AnyTypeCollection.Builder() - .addIfNotEmpty(listOf(), trackDelegate) - .addIfNotEmpty(listOf(), trackListDelegate) + .addIfNotEmpty(emptyList(), trackDelegate) + .addIfNotEmpty(emptyList(), trackListDelegate) .build() .apply { assert(itemsMetaData.isEmpty() && items.isEmpty()) } } @@ -143,8 +161,8 @@ class AnyTypeCollectionBuilderTest : MockInitializer() { @Test fun addIfNotEmpty_inputListIsEmpty_noneDelegateMethodsGetCalled() { AnyTypeCollection.Builder() - .addIfNotEmpty(listOf(), trackDelegate) - .addIfNotEmpty(listOf(), trackListDelegate) + .addIfNotEmpty(emptyList(), trackDelegate) + .addIfNotEmpty(emptyList(), trackListDelegate) .apply { verifyZeroInteractions(trackDelegate) verifyZeroInteractions(trackListDelegate) From 6706a614c26b3a6d1df5c4caf2f870c4defad246 Mon Sep 17 00:00:00 2001 From: vsukharew Date: Tue, 2 Nov 2021 23:03:15 +0300 Subject: [PATCH 7/9] fixed AnyTypeDelegateTest (#84) --- .../anytypeadapter/delegate/AnyTypeDelegateTest.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt b/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt index cf2597b..365d9f4 100644 --- a/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt +++ b/library/src/test/java/vsukharev/anytypeadapter/delegate/AnyTypeDelegateTest.kt @@ -1,16 +1,20 @@ package vsukharev.anytypeadapter.delegate import org.junit.jupiter.api.Test -import org.mockito.kotlin.any +import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.verify import vsukharev.anytypeadapter.common.MockInitializer +import vsukharev.anytypeadapter.domain.Track import vsukharev.anytypeadapter.item.AdapterItem class AnyTypeDelegateTest : MockInitializer() { @Test - fun bind_callWithAnyData_verifyHolderBindGetCalled() { - trackDelegate.bind(AdapterItem(any(), any()), trackHolder) - verify(trackHolder).bind(any()) + fun bind_callWithTrack_verifyHolderBindGetCalledWithTheSameTrack() { + val track = Track() + val captor = argumentCaptor() + trackDelegate.bind(AdapterItem(track.id, track), trackHolder) + verify(trackHolder).bind(captor.capture()) + assert(track == captor.firstValue) } } \ No newline at end of file From 8ba36ab1c89ae9dbe530e25a10b0da10bda17d95 Mon Sep 17 00:00:00 2001 From: vsukharew Date: Tue, 2 Nov 2021 23:08:34 +0300 Subject: [PATCH 8/9] changed visibility modifier (#85) --- .../java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt b/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt index 5a413ac..d414b88 100644 --- a/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt +++ b/library/src/main/java/vsukharev/anytypeadapter/adapter/AnyTypeCollection.kt @@ -205,7 +205,7 @@ class AnyTypeCollection private constructor( } companion object { - const val NO_POSITION = -1 + internal const val NO_POSITION = -1 val EMPTY = Builder().build() } } \ No newline at end of file From a53ba4990b9b2348cf779556a131dcb5951dbce5 Mon Sep 17 00:00:00 2001 From: vsukharew Date: Tue, 2 Nov 2021 23:23:14 +0300 Subject: [PATCH 9/9] changed version to 1.2.0 --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 984973f..280b1d3 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -6,7 +6,7 @@ ext { library : [ publishGroupId : 'io.github.vsukharew', publishArtifactId: 'anytypeadapter', - versionName : "1.0.11", + versionName : "1.2.0", versionCode : 1, ], sample : [