How to use extracting class of io.kotest.assertions package

Best Kotest code snippet using io.kotest.assertions.extracting

SubscriptionManagerTest.kt

Source:SubscriptionManagerTest.kt Github

copy

Full Screen

...26import fr.nihilus.music.core.os.PermissionDeniedException27import fr.nihilus.music.core.test.coroutines.CoroutineTestRule28import fr.nihilus.music.core.test.failAssumption29import fr.nihilus.music.service.browser.PaginationOptions30import io.kotest.assertions.extracting31import io.kotest.assertions.throwables.shouldNotThrow32import io.kotest.assertions.throwables.shouldThrow33import io.kotest.matchers.collections.*34import io.kotest.matchers.nulls.shouldNotBeNull35import io.kotest.matchers.shouldBe36import io.kotest.matchers.types.shouldBeSameInstanceAs37import io.kotest.matchers.types.shouldNotBeSameInstanceAs38import kotlinx.coroutines.CoroutineScope39import kotlinx.coroutines.delay40import kotlinx.coroutines.yield41import org.junit.Rule42import org.junit.runner.RunWith43import kotlin.test.BeforeTest44import kotlin.test.Test45@RunWith(AndroidJUnit4::class)46class SubscriptionManagerTest {47 @get:Rule48 val test = CoroutineTestRule()49 private lateinit var dispatchers: AppDispatchers50 @BeforeTest51 fun initDispatchers() {52 dispatchers = AppDispatchers(test.dispatcher)53 }54 @Test55 fun `When loading children, then subscribe to their parent in the tree`() =56 test.runWithin { scope ->57 val manager = CachingSubscriptionManager(scope, TestBrowserTree, dispatchers)58 val children = manager.loadChildren(MediaId(TYPE_TRACKS, CATEGORY_ALL), null)59 extracting(children, MediaContent::id).shouldContainExactly(60 MediaId(TYPE_TRACKS, CATEGORY_ALL, 161),61 MediaId(TYPE_TRACKS, CATEGORY_ALL, 309),62 MediaId(TYPE_TRACKS, CATEGORY_ALL, 481),63 MediaId(TYPE_TRACKS, CATEGORY_ALL, 48),64 MediaId(TYPE_TRACKS, CATEGORY_ALL, 125),65 MediaId(TYPE_TRACKS, CATEGORY_ALL, 294),66 MediaId(TYPE_TRACKS, CATEGORY_ALL, 219),67 MediaId(TYPE_TRACKS, CATEGORY_ALL, 75),68 MediaId(TYPE_TRACKS, CATEGORY_ALL, 464),69 MediaId(TYPE_TRACKS, CATEGORY_ALL, 477)70 )71 }72 @Test73 fun `Given active subscription, when reloading then return cached children`() =74 test.runWithin { scope ->75 val manager = CachingSubscriptionManager(scope, TestBrowserTree, dispatchers)76 val parentId = MediaId(TYPE_TRACKS, CATEGORY_ALL)77 // Trigger initial subscription78 val children = manager.loadChildren(parentId, null)79 // Reload children, and check that those are the same80 val reloadedChildren = manager.loadChildren(parentId, null)81 reloadedChildren shouldBeSameInstanceAs children82 }83 @Test84 fun `When loading children of invalid parent, then fail with NoSuchElementException`() =85 test.runWithin { scope ->86 val manager = CachingSubscriptionManager(scope, TestBrowserTree, dispatchers)87 shouldThrow<NoSuchElementException> {88 val invalidMediaId = MediaId(TYPE_PLAYLISTS, "unknown")89 manager.loadChildren(invalidMediaId, null)90 }91 }92 @Test93 fun `Given denied permission, when loading children then fail with PermissionDeniedException`() =94 test.runWithin { scope ->95 val deniedTree = PermissionBrowserTree(granted = false)96 val manager = CachingSubscriptionManager(scope, deniedTree, dispatchers)97 val permissionFailure = shouldThrow<PermissionDeniedException> {98 val parentId = MediaId(TYPE_TRACKS, CATEGORY_ALL)99 manager.loadChildren(parentId, null)100 }101 permissionFailure.permission shouldBe Manifest.permission.READ_EXTERNAL_STORAGE102 }103 @Test104 fun `After permission grant, when loading children then proceed without error`() =105 test.runWithin { scope ->106 val permissionTree = PermissionBrowserTree(granted = false)107 val manager = CachingSubscriptionManager(scope, permissionTree, dispatchers)108 val parentId = MediaId(TYPE_TRACKS, CATEGORY_ALL)109 shouldThrow<PermissionDeniedException> {110 manager.loadChildren(parentId, null)111 }112 permissionTree.granted = true113 shouldNotThrow<PermissionDeniedException> {114 manager.loadChildren(parentId, null)115 }116 }117 @Test118 fun `After permission denial, when loading children then recover`() = test.runWithin { scope ->119 val permissionTree = PermissionBrowserTree(granted = true)120 val manager = CachingSubscriptionManager(scope, permissionTree, dispatchers)121 // Start initial subscription.122 val parentId = MediaId(TYPE_TRACKS, CATEGORY_ALL)123 shouldNotThrow<PermissionDeniedException> {124 manager.loadChildren(parentId, null)125 }126 // Then the permission is denied. When trying to update children, it should fail.127 permissionTree.granted = false128 delay(1001)129 shouldThrow<PermissionDeniedException> {130 manager.loadChildren(parentId, null)131 }132 // It should create a new subscription and succeed.133 permissionTree.granted = true134 shouldNotThrow<PermissionDeniedException> {135 manager.loadChildren(parentId, null)136 }137 }138 @Test139 fun `Given max subscriptions, when loading children then dispose oldest subscriptions`() =140 test.runWithin { scope ->141 val manager = CachingSubscriptionManager(scope, TestBrowserTree, dispatchers)142 // Trigger subscription of albums 0 to MAX included.143 val childrenPerAlbumId = (0..MAX_ACTIVE_SUBSCRIPTIONS).map { albumId ->144 val parentId = MediaId(TYPE_ALBUMS, albumId.toString())145 manager.loadChildren(parentId, null)146 }147 // Subscription to album 0 should have been disposed when subscribing to album MAX.148 // Its children should not be loaded from cache.149 val albumZeroChildren = manager.loadChildren(MediaId(TYPE_ALBUMS, "0"), null)150 albumZeroChildren shouldNotBeSameInstanceAs childrenPerAlbumId[0]151 // Previous re-subscription to album 0 should clear subscription to album 1,152 // and therefore it should not load its children from cache.153 val albumOneChildren = manager.loadChildren(MediaId(TYPE_ALBUMS, "1"), null)154 albumOneChildren shouldNotBeSameInstanceAs childrenPerAlbumId[1]155 // Subscription to album MAX should still be active,156 // hence children are loaded from cache.157 val lastAlbumId = MediaId(TYPE_ALBUMS, MAX_ACTIVE_SUBSCRIPTIONS.toString())158 val albumMaxChildren = manager.loadChildren(lastAlbumId, null)159 albumMaxChildren shouldBeSameInstanceAs childrenPerAlbumId[MAX_ACTIVE_SUBSCRIPTIONS]160 }161 @Test162 fun `Given max subscriptions, when reloading children then keep its subscription longer`() =163 test.runWithin { scope ->164 val manager = CachingSubscriptionManager(scope, TestBrowserTree, dispatchers)165 // Trigger subscriptions to reach the max allowed count.166 val childrenPerAlbumId = (0 until MAX_ACTIVE_SUBSCRIPTIONS).map { albumId ->167 val parentId = MediaId(TYPE_ALBUMS, albumId.toString())168 manager.loadChildren(parentId, null)169 }170 // Reload children of album 0, then create a new subscription.171 manager.loadChildren(MediaId(TYPE_ALBUMS, "0"), null)172 manager.loadChildren(MediaId(TYPE_ALBUMS, MAX_ACTIVE_SUBSCRIPTIONS.toString()), null)173 // If album 0 had not been reloaded, its subscription should have been disposed.174 // The oldest subscription now being that of album 1, it has been disposed instead.175 val albumZeroChildren = manager.loadChildren(MediaId(TYPE_ALBUMS, "0"), null)176 val albumOneChildren = manager.loadChildren(MediaId(TYPE_ALBUMS, "1"), null)177 albumZeroChildren shouldBeSameInstanceAs childrenPerAlbumId[0]178 albumOneChildren shouldNotBeSameInstanceAs childrenPerAlbumId[1]179 }180 @Test181 fun `Given pages of size N, when loading children then return the N first items`() =182 test.runWithin { scope ->183 val manager = CachingSubscriptionManager(scope, TestBrowserTree, dispatchers)184 val paginatedChildren = manager.loadChildren(185 MediaId(TYPE_TRACKS, CATEGORY_ALL),186 PaginationOptions(0, 3)187 )188 extracting(paginatedChildren, MediaContent::id).shouldContainExactly(189 MediaId(TYPE_TRACKS, CATEGORY_ALL, 161),190 MediaId(TYPE_TRACKS, CATEGORY_ALL, 309),191 MediaId(TYPE_TRACKS, CATEGORY_ALL, 481)192 )193 }194 @Test195 fun `Given the page X of size N, when loading children then return N items from position NX`() =196 test.runWithin { scope ->197 val manager = CachingSubscriptionManager(scope, TestBrowserTree, dispatchers)198 val paginatedChildren = manager.loadChildren(199 MediaId(TYPE_TRACKS, CATEGORY_ALL),200 PaginationOptions(3, 2)201 )202 extracting(paginatedChildren, MediaContent::id).shouldContainExactly(203 MediaId(TYPE_TRACKS, CATEGORY_ALL, 219),204 MediaId(TYPE_TRACKS, CATEGORY_ALL, 75)205 )206 }207 @Test208 fun `Given a page after the last page, when loading children then return no children`() =209 test.runWithin { scope ->210 val manager = CachingSubscriptionManager(scope, TestBrowserTree, dispatchers)211 val pagePastChildren = manager.loadChildren(212 MediaId(TYPE_TRACKS, CATEGORY_ALL),213 PaginationOptions(2, 5)214 )215 pagePastChildren.shouldBeEmpty()216 }...

Full Screen

Full Screen

BrowserTreeSearchTest.kt

Source:BrowserTreeSearchTest.kt Github

copy

Full Screen

...26import fr.nihilus.music.media.provider.MediaDao27import fr.nihilus.music.media.provider.Track28import fr.nihilus.music.media.usage.UsageManager29import fr.nihilus.music.service.MediaContent30import io.kotest.assertions.extracting31import io.kotest.matchers.collections.shouldBeEmpty32import io.kotest.matchers.collections.shouldContainAll33import io.kotest.matchers.collections.shouldContainExactly34import kotlinx.coroutines.test.runTest35import org.junit.runner.RunWith36import kotlin.test.Test37@RunWith(AndroidJUnit4::class)38internal class BrowserTreeSearchTest {39 private val context: Context40 get() = ApplicationProvider.getApplicationContext()41 @Test42 fun `When searching with an empty query then return no results`() = runTest {43 val tree = givenRealisticBrowserTree()44 val results = tree.search(SearchQuery.Empty)45 results.shouldBeEmpty()46 }47 @Test48 fun `Given artist focus, when searching an artist then return that artist`() = runTest {49 val browserTree = givenRealisticBrowserTree()50 val results = browserTree.search(SearchQuery.Artist("Foo Fighters"))51 extracting(results, MediaContent::id).shouldContainExactly(52 MediaId(TYPE_ARTISTS, "13")53 )54 }55 @Test56 fun `Given album focus, when searching an album then return that album`() = runTest {57 val tree = givenRealisticBrowserTree()58 val results = tree.search(SearchQuery.Album("Foo Fighters", "Wasting Light"))59 extracting(results, MediaContent::id).shouldContainExactly(60 MediaId(TYPE_ALBUMS, "26")61 )62 }63 @Test64 fun `Given track focused query, when searching songs then return that song`() = runTest {65 val tree = givenRealisticBrowserTree()66 val results = tree.search(67 SearchQuery.Song(68 artist = "Foo Fighters",69 album = "Concrete and Gold",70 title = "Dirty Water"71 )72 )73 extracting(results, MediaContent::id).shouldContainExactly(74 MediaId(TYPE_TRACKS, CATEGORY_ALL, 481)75 )76 }77 @Test78 fun `Given exact artist name, when searching unfocused then return that artist`() = runTest {79 val tree = givenRealisticBrowserTree()80 val results = tree.search(SearchQuery.Unspecified("foo fighters"))81 extracting(results, MediaContent::id).shouldContainExactly(82 MediaId(TYPE_ARTISTS, "13")83 )84 }85 @Test86 fun `Given exact album title, when searching unfocused then return that album`() = runTest {87 val tree = givenRealisticBrowserTree()88 val results = tree.search(SearchQuery.Unspecified("concrete and gold"))89 extracting(results, MediaContent::id).shouldContainExactly(90 MediaId(TYPE_ALBUMS, "102")91 )92 }93 @Test94 fun `Given exact song title, when searching unfocused then return that song`() = runTest {95 val tree = givenRealisticBrowserTree()96 val results = tree.search(SearchQuery.Unspecified("dirty water"))97 extracting(results, MediaContent::id).shouldContainExactly(98 MediaId(TYPE_TRACKS, CATEGORY_ALL, 481)99 )100 }101 @Test102 fun `Given query matching both album and song, when searching albums then return only that album`() =103 runTest {104 val tree = givenRealisticBrowserTree()105 val results = tree.search(SearchQuery.Album("Avenged Sevenfold", "Nightmare"))106 extracting(results, MediaContent::id).shouldContainExactly(107 MediaId(TYPE_ALBUMS, "6")108 )109 }110 @Test111 fun `Given query matching both album and song, when searching unfocused then return both`() =112 runTest {113 val tree = givenRealisticBrowserTree()114 // Both the album "Nightmare" and its eponymous track are listed in search results.115 // Note that the album should be listed first.116 val results = tree.search(SearchQuery.Unspecified("nightmare"))117 extracting(results, MediaContent::id).shouldContainExactly(118 MediaId(TYPE_ALBUMS, "6"),119 MediaId(TYPE_TRACKS, CATEGORY_ALL, 75)120 )121 }122 @Test123 fun `Given uppercase query, when searching unfocused then return results`() = runTest {124 val tree = givenRealisticBrowserTree()125 val results = tree.search(SearchQuery.Unspecified("Nightmare"))126 extracting(results, MediaContent::id).shouldContainAll(127 MediaId(TYPE_ALBUMS, "6"),128 MediaId(TYPE_TRACKS, CATEGORY_ALL, 75)129 )130 }131 @Test132 fun `Given pattern query, when searching then return items containing that pattern`() =133 runTest {134 val tracks = listOf(135 Track(136 23,137 "Another Brick In The Wall",138 "Pink Floyd",139 "The Wall",140 0,141 1,142 5,143 "",144 null,145 0,146 2,147 2,148 0149 ),150 Track(151 34,152 "Another One Bites the Dust",153 "Queen",154 "The Game",155 0,156 1,157 3,158 "",159 null,160 0,161 3,162 3,163 0164 ),165 Track(166 56,167 "Nothing Else Matters",168 "Metallica",169 "Metallica",170 0L,171 1,172 8,173 "",174 null,175 0,176 4,177 4,178 0179 ),180 Track(181 12,182 "Otherside",183 "Red Hot Chili Peppers",184 "Californication",185 0,186 1,187 6,188 "",189 null,190 0,191 1,192 1,193 0194 ),195 Track(196 98,197 "You've Got Another Thing Comin",198 "Judas Priest",199 "Screaming for Vengeance",200 0,201 1,202 8,203 "",204 null,205 0,206 7,207 7,208 0209 )210 )211 val tree = BrowserTree(TestMediaDao(emptyList(), emptyList(), tracks))212 // "OTHERside" is listed first (it starts with the pattern),213 // then "AnOTHER Brick In the Wall" (same pattern at same position),214 // then "AnOTHER One Bites the Dust" (one word contains the pattern but slightly longer),215 // then "You've Got AnOTHER Thing Comin" (pattern matches farther)216 val results = tree.search(SearchQuery.Unspecified("other"))217 extracting(results, MediaContent::id).shouldContainExactly(218 MediaId(TYPE_TRACKS, CATEGORY_ALL, 12),219 MediaId(TYPE_TRACKS, CATEGORY_ALL, 23),220 MediaId(TYPE_TRACKS, CATEGORY_ALL, 34),221 MediaId(TYPE_TRACKS, CATEGORY_ALL, 98)222 )223 }224 @Test225 fun `Given pattern query that matches multiple items equally, when searching then return shortest first`() =226 runTest {227 val tracks = listOf(228 Track(229 10,230 "Are You Ready",231 "AC/DC",232 "The Razor's Edge",233 0,234 1,235 7,236 "",237 null,238 0,239 32,240 18,241 0242 ),243 Track(244 42,245 "Are You Gonna Be My Girl",246 "Jet",247 "Get Born",248 0,249 1,250 2,251 "",252 null,253 0,254 78,255 90,256 0257 ),258 Track(259 63,260 "Are You Gonna Go My Way",261 "Lenny Kravitz",262 "Are You Gonna Go My Way",263 0,264 1,265 1,266 "",267 null,268 0,269 57,270 23,271 0272 )273 )274 val tree = BrowserTree(TestMediaDao(emptyList(), emptyList(), tracks))275 // When the pattern matches multiple items equally,276 // shorter items should be displayed first.277 val results = tree.search(SearchQuery.Unspecified("are"))278 extracting(results, MediaContent::id).shouldContainExactly(279 MediaId(TYPE_TRACKS, CATEGORY_ALL, 10),280 MediaId(TYPE_TRACKS, CATEGORY_ALL, 63),281 MediaId(TYPE_TRACKS, CATEGORY_ALL, 42)282 )283 }284 @Test285 fun `When search pattern matches multiple items, then first return results that matches the start of a word`() =286 runTest {287 val tracks = listOf(288 Track(90, "Avalanche", "Ghost", "Prequelle", 0, 1, 12, "", null, 0, 56, 97, 0),289 Track(290 91,291 "No Grave But The Sea",292 "Alestorm",293 "No Grave But The Sea",294 0,295 1,296 1,297 "",298 null,299 0,300 456,301 856,302 0303 ),304 Track(305 356,306 "Gravity",307 "Bullet For My Valentine",308 "Gravity",309 0,310 1,311 8,312 "",313 null,314 0,315 45,316 99,317 0318 )319 )320 val artist = listOf(321 Artist(65, "Avatar", 0, 0, null),322 Artist(98, "Avenged Sevenfold", 0, 0, null)323 )324 val tree = BrowserTree(TestMediaDao(artist, emptyList(), tracks))325 val results = tree.search(SearchQuery.Unspecified("av"))326 extracting(results, MediaContent::id).shouldContainExactly(327 MediaId(TYPE_ARTISTS, "65"), // AVatar328 MediaId(TYPE_TRACKS, CATEGORY_ALL, 90), // AValanche329 MediaId(TYPE_ARTISTS, "98"), // AVenged Sevenfold330 MediaId(TYPE_TRACKS, CATEGORY_ALL, 356), // GrAVity331 MediaId(TYPE_TRACKS, CATEGORY_ALL, 91) // No GrAVe But the Sea332 )333 }334 private fun BrowserTree(335 mediaDao: MediaDao,336 usageManager: UsageManager = StubUsageManager337 ): BrowserTree = BrowserTreeImpl(context, mediaDao, StubPlaylistDao, usageManager, StubSpotifyManager)338 private fun givenRealisticBrowserTree(): BrowserTreeImpl =339 BrowserTreeImpl(context, TestMediaDao(), TestPlaylistDao(), TestUsageManager(), StubSpotifyManager)340}...

Full Screen

Full Screen

DockerClientImagePullSpec.kt

Source:DockerClientImagePullSpec.kt Github

copy

Full Screen

1/*2 Copyright 2017-2022 Charles Korn.3 Licensed under the Apache License, Version 2.0 (the "License");4 you may not use this file except in compliance with the License.5 You may obtain a copy of the License at6 https://www.apache.org/licenses/LICENSE-2.07 Unless required by applicable law or agreed to in writing, software8 distributed under the License is distributed on an "AS IS" BASIS,9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.10 See the License for the specific language governing permissions and11 limitations under the License.12*/13package batect.dockerclient14import io.kotest.assertions.throwables.shouldThrow15import io.kotest.core.spec.style.ShouldSpec16import io.kotest.inspectors.forAtLeastOne17import io.kotest.matchers.collections.shouldBeIn18import io.kotest.matchers.collections.shouldContain19import io.kotest.matchers.collections.shouldContainAnyOf20import io.kotest.matchers.collections.shouldEndWith21import io.kotest.matchers.collections.shouldStartWith22import io.kotest.matchers.shouldBe23import io.kotest.matchers.shouldNotBe24class DockerClientImagePullSpec : ShouldSpec({25 val client = closeAfterTest(DockerClient.Builder().build())26 val defaultLinuxTestImage = "gcr.io/distroless/static@sha256:aadea1b1f16af043a34491eec481d0132479382096ea34f608087b4bef3634be"27 val defaultWindowsTestImage = "mcr.microsoft.com/windows/nanoserver@sha256:4f06e1d8263b934d2e88dc1c6ff402f5b499c4d19ad6d0e2a5b9ee945f782928" // This is nanoserver:180928 val testImages = when (testEnvironmentContainerOperatingSystem) {29 ContainerOperatingSystem.Linux -> mapOf(30 "with a digest and no tag" to defaultLinuxTestImage,31 "with a digest and tag" to "gcr.io/distroless/static:063a079c1a87bad3369cb9daf05e371e925c0c91@sha256:aadea1b1f16af043a34491eec481d0132479382096ea34f608087b4bef3634be",32 "with a tag and no digest" to "gcr.io/distroless/static:063a079c1a87bad3369cb9daf05e371e925c0c91",33 "with neither a digest nor a tag" to "gcr.io/distroless/static",34 // To recreate this image:35 // docker pull gcr.io/distroless/static@sha256:aadea1b1f16af043a34491eec481d0132479382096ea34f608087b4bef3634be36 // docker tag gcr.io/distroless/static@sha256:aadea1b1f16af043a34491eec481d0132479382096ea34f608087b4bef3634be ghcr.io/batect/docker-client:sample-authenticated-image37 // docker push ghcr.io/batect/docker-client:sample-authenticated-image38 //39 // If you need to configure credentials locally: https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#authenticating-to-the-container-registry40 "that requires authentication to pull" to "ghcr.io/batect/docker-client:sample-authenticated-image"41 )42 ContainerOperatingSystem.Windows -> mapOf(43 "with a tag" to defaultWindowsTestImage44 )45 }46 val imageThatDoesNotExist = "batect/this-image-does-not-exist:abc123"47 beforeEach {48 testImages.values.forEach { image -> client.deleteImageIfPresent(image) }49 }50 testImages.forEach { (description, image) ->51 should("be able to pull, get and delete an image $description").onlyIfDockerDaemonPresent {52 val imageReferenceFromPull = client.pullImage(image)53 val imageReferenceFromGet = client.getImage(image)54 imageReferenceFromPull shouldBe imageReferenceFromGet55 client.deleteImage(imageReferenceFromPull, force = true)56 val imageReferenceAfterDelete = client.getImage(image)57 imageReferenceAfterDelete shouldBe null58 }59 }60 context("pulling an image that does not exist on the local machine") {61 // Recreate this image with 'resources/base-images/recreate.sh'.62 val image = "ghcr.io/batect/docker-client:image-pull-progress@sha256:ed32e6eb4f059d2ac57e47413855d737db00c21f39edb0a5845c3a30a18a7263"63 val imageWithoutTag = "ghcr.io/batect/docker-client@sha256:ed32e6eb4f059d2ac57e47413855d737db00c21f39edb0a5845c3a30a18a7263"64 beforeAny {65 client.deleteImageIfPresent(image)66 client.deleteImageIfPresent(imageWithoutTag)67 }68 should("report progress information while pulling an image").onlyIfDockerDaemonSupportsLinuxContainers {69 val progressUpdatesReceived = mutableListOf<ImagePullProgressUpdate>()70 client.pullImage(image) { update ->71 progressUpdatesReceived.add(update)72 }73 val layerId = "0f17b32804d3"74 val layerSize = 127L75 progressUpdatesReceived.forAtLeastOne {76 it.message shouldBe "Pulling from batect/docker-client"77 it.detail shouldBe null78 it.id shouldBeIn setOf(imageWithoutTag, imageWithoutTag.substringAfter('@')) // Older versions of Docker only return the digest here79 }80 progressUpdatesReceived shouldContain ImagePullProgressUpdate("Pulling fs layer", ImagePullProgressDetail(0, 0), layerId)81 // Docker does some rate limiting of progress updates, so to make this test more resilient to this non-determinism, we82 // consider the test passing if at least one of these updates is posted.83 progressUpdatesReceived shouldContainAnyOf setOf(84 ImagePullProgressUpdate("Downloading", ImagePullProgressDetail(0, layerSize), layerId),85 ImagePullProgressUpdate("Downloading", ImagePullProgressDetail(layerSize, layerSize), layerId),86 ImagePullProgressUpdate("Download complete", ImagePullProgressDetail(0, 0), layerId)87 )88 progressUpdatesReceived.forAtLeastOne {89 it.message shouldBe "Extracting"90 it.detail shouldNotBe null91 it.detail!!.total shouldBe layerSize92 it.id shouldBe layerId93 }94 progressUpdatesReceived shouldEndWith listOf(95 ImagePullProgressUpdate("Pull complete", ImagePullProgressDetail(0, 0), layerId),96 ImagePullProgressUpdate("Digest: sha256:ed32e6eb4f059d2ac57e47413855d737db00c21f39edb0a5845c3a30a18a7263", null, ""),97 ImagePullProgressUpdate("Status: Downloaded newer image for $imageWithoutTag", null, "")98 )99 }100 }101 should("gracefully handle a progress callback that throws an exception while pulling an image").onlyIfDockerDaemonSupportsLinuxContainers {102 val exceptionThrownByCallbackHandler = RuntimeException("This is an exception from the callback handler")103 val exceptionThrownByPullMethod = shouldThrow<ImagePullFailedException> {104 client.pullImage(defaultLinuxTestImage) {105 throw exceptionThrownByCallbackHandler106 }107 }108 exceptionThrownByPullMethod.message shouldBe "Image pull progress receiver threw an exception: $exceptionThrownByCallbackHandler"109 exceptionThrownByPullMethod.cause shouldBe exceptionThrownByCallbackHandler110 }111 should("report progress information while pulling a Windows image").onlyIfDockerDaemonSupportsWindowsContainers {112 val image = defaultWindowsTestImage113 val progressUpdatesReceived = mutableListOf<ImagePullProgressUpdate>()114 client.pullImage(image) { update ->115 progressUpdatesReceived.add(update)116 }117 val layerId = "934e212983f2"118 val layerSize = 102661372119 progressUpdatesReceived shouldStartWith listOf(120 ImagePullProgressUpdate("Pulling from windows/nanoserver", null, image),121 ImagePullProgressUpdate("Pulling fs layer", ImagePullProgressDetail(0, 0), layerId),122 )123 progressUpdatesReceived.forAtLeastOne {124 it.message shouldBe "Downloading"125 it.detail shouldNotBe null126 it.detail!!.total shouldBe layerSize127 it.id shouldBe layerId128 }129 progressUpdatesReceived shouldContain ImagePullProgressUpdate("Download complete", ImagePullProgressDetail(0, 0), layerId)130 progressUpdatesReceived.forAtLeastOne {131 it.message shouldBe "Extracting"132 it.detail shouldNotBe null133 it.detail!!.total shouldBe layerSize134 it.id shouldBe layerId135 }136 progressUpdatesReceived shouldEndWith listOf(137 ImagePullProgressUpdate("Pull complete", ImagePullProgressDetail(0, 0), layerId),138 ImagePullProgressUpdate("Digest: sha256:4f06e1d8263b934d2e88dc1c6ff402f5b499c4d19ad6d0e2a5b9ee945f782928", null, ""),139 ImagePullProgressUpdate("Status: Downloaded newer image for $image", null, "")140 )141 }142 should("fail when pulling a non-existent image").onlyIfDockerDaemonPresent {143 val exception = shouldThrow<ImagePullFailedException> {144 client.pullImage(imageThatDoesNotExist)145 }146 // Docker returns a different error message depending on whether or not the user is logged in to the source registry147 exception.message shouldBeIn setOf(148 // User is logged in149 "Error response from daemon: manifest for batect/this-image-does-not-exist:abc123 not found: manifest unknown: manifest unknown",150 // User is not logged in151 "Error response from daemon: pull access denied for batect/this-image-does-not-exist, repository does not exist or may require 'docker login': denied: requested access to the resource is denied"152 )153 }154 should("fail when pulling an image for another platform").onlyIfDockerDaemonPresent {155 val imageForOtherPlatform = when (testEnvironmentContainerOperatingSystem) {156 ContainerOperatingSystem.Linux -> "mcr.microsoft.com/windows/nanoserver:ltsc2022"157 ContainerOperatingSystem.Windows -> "gcr.io/distroless/static:063a079c1a87bad3369cb9daf05e371e925c0c91@sha256:aadea1b1f16af043a34491eec481d0132479382096ea34f608087b4bef3634be"158 }159 val exception = shouldThrow<ImagePullFailedException> {160 client.pullImage(imageForOtherPlatform)161 }162 val expectedMessages = when (testEnvironmentContainerOperatingSystem) {163 ContainerOperatingSystem.Linux -> setOf(164 "no matching manifest for linux/amd64 in the manifest list entries",165 "no matching manifest for linux/arm64/v8 in the manifest list entries",166 "image operating system \"windows\" cannot be used on this platform"167 )168 ContainerOperatingSystem.Windows -> setOf(169 "no matching manifest for windows/amd64 in the manifest list entries",170 "image operating system \"linux\" cannot be used on this platform"171 )172 }173 exception.message shouldBeIn expectedMessages174 }175 should("return null when getting a non-existent image").onlyIfDockerDaemonPresent {176 val imageReference = client.getImage(imageThatDoesNotExist)177 imageReference shouldBe null178 }179 should("fail when deleting a non-existent image").onlyIfDockerDaemonPresent {180 val exception = shouldThrow<ImageDeletionFailedException> {181 client.deleteImage(ImageReference("this-image-does-not-exist"))182 }183 exception.message shouldBe "No such image: this-image-does-not-exist"184 }185})186internal fun DockerClient.deleteImageIfPresent(name: String) {187 val image = getImage(name)188 if (image != null) {189 deleteImage(image, force = true)190 }191}...

Full Screen

Full Screen

ManagePlaylistActionTest.kt

Source:ManagePlaylistActionTest.kt Github

copy

Full Screen

...28import fr.nihilus.music.core.media.MediaId.Builder.TYPE_TRACKS29import fr.nihilus.music.core.test.coroutines.CoroutineTestRule30import fr.nihilus.music.core.test.os.TestClock31import io.kotest.assertions.assertSoftly32import io.kotest.assertions.extracting33import io.kotest.assertions.throwables.shouldThrow34import io.kotest.inspectors.forAll35import io.kotest.inspectors.forNone36import io.kotest.matchers.collections.shouldBeEmpty37import io.kotest.matchers.collections.shouldContainExactlyInAnyOrder38import io.kotest.matchers.collections.shouldHaveSize39import io.kotest.matchers.collections.shouldNotContain40import io.kotest.matchers.file.shouldBeAFile41import io.kotest.matchers.file.shouldContainFile42import io.kotest.matchers.file.shouldNotBeEmpty43import io.kotest.matchers.file.shouldNotExist44import io.kotest.matchers.shouldBe45import kotlinx.coroutines.test.runTest46import org.junit.Rule47import org.junit.rules.RuleChain48import org.junit.rules.TemporaryFolder49import org.junit.runner.RunWith50import java.io.File51import kotlin.test.Test52private const val TEST_TIME = 1585662510L53private const val NEW_PLAYLIST_NAME = "My favorites"54private const val BASE_ICON_URI = "content://fr.nihilus.music.test.provider/icons"55private val SAMPLE_PLAYLIST = Playlist(56 id = 1L,57 title = "Zen",58 created = 0L,59 iconUri = "content://fr.nihilus.music.test.provider/icons/zen.png".toUri()60)61@RunWith(AndroidJUnit4::class)62internal class ManagePlaylistActionTest {63 private val test = CoroutineTestRule()64 private val iconDir = TemporaryFolder()65 @get:Rule66 val rules: RuleChain = RuleChain67 .outerRule(test)68 .around(iconDir)69 private val clock = TestClock(TEST_TIME)70 private val dispatchers = AppDispatchers(test.dispatcher)71 @Test72 fun `When creating a playlist without tracks then record it to PlaylistDao`() = test {73 val dao = InMemoryPlaylistDao()74 val action = ManagePlaylistAction(dao)75 action.createPlaylist(NEW_PLAYLIST_NAME, emptyList())76 val playlists = dao.savedPlaylists77 playlists shouldHaveSize 178 assertSoftly(playlists[0]) {79 title shouldBe NEW_PLAYLIST_NAME80 created shouldBe TEST_TIME81 iconUri shouldBe "content://fr.nihilus.music.test.provider/icons/My_favorites.png".toUri()82 }83 dao.savedTracks.shouldBeEmpty()84 }85 @Test86 fun `When creating a playlist then generate and save its icon`() = test {87 val action = ManagePlaylistAction(InMemoryPlaylistDao())88 action.createPlaylist(NEW_PLAYLIST_NAME, emptyList())89 iconDir.root shouldContainFile "My_favorites.png"90 val iconFile = File(iconDir.root, "My_favorites.png")91 iconFile.shouldBeAFile()92 iconFile.shouldNotBeEmpty()93 }94 @Test95 fun `Given blank name, when creating a playlist then fail with IAE`() = test {96 val action = ManagePlaylistAction(InMemoryPlaylistDao())97 shouldThrow<IllegalArgumentException> {98 action.createPlaylist("", emptyList())99 }100 shouldThrow<IllegalArgumentException> {101 action.createPlaylist(" \t\n\r", emptyList())102 }103 }104 @Test105 fun `When creating a playlist with tracks then record them to PlaylistDao`() = test {106 val dao = InMemoryPlaylistDao()107 val action = ManagePlaylistAction(dao)108 action.createPlaylist(109 name = NEW_PLAYLIST_NAME,110 members = listOf(111 MediaId(TYPE_TRACKS, CATEGORY_ALL, 16L),112 MediaId(TYPE_TRACKS, CATEGORY_ALL, 42L)113 )114 )115 val playlists = dao.savedPlaylists116 playlists shouldHaveSize 1117 val newPlaylist = playlists[0]118 newPlaylist.title shouldBe NEW_PLAYLIST_NAME119 newPlaylist.created shouldBe TEST_TIME120 val tracks = dao.savedTracks121 tracks shouldHaveSize 2122 tracks.forAll { it.playlistId shouldBe newPlaylist.id }123 extracting(tracks) { trackId }.shouldContainExactlyInAnyOrder(16L, 42L)124 }125 @Test126 fun `When creating a playlist with non-track members them fail with IAE`() = test {127 val action = ManagePlaylistAction(InMemoryPlaylistDao())128 for (mediaId in invalidTrackIds()) {129 shouldThrow<IllegalArgumentException> {130 action.createPlaylist(131 name = NEW_PLAYLIST_NAME,132 members = listOf(mediaId)133 )134 }135 }136 }137 @Test138 fun `When appending members then add tracks to that playlist`() = test {139 val dao = InMemoryPlaylistDao(initialPlaylists = listOf(SAMPLE_PLAYLIST))140 val action = ManagePlaylistAction(dao)141 action.appendMembers(142 targetPlaylist = MediaId(TYPE_PLAYLISTS, SAMPLE_PLAYLIST.id.toString()),143 members = listOf(144 MediaId(TYPE_TRACKS, CATEGORY_ALL, 16L),145 MediaId(TYPE_TRACKS, CATEGORY_ALL, 42L)146 )147 )148 val tracks = dao.savedTracks149 tracks shouldHaveSize 2150 tracks.forAll { it.playlistId shouldBe SAMPLE_PLAYLIST.id }151 extracting(tracks) { trackId }.shouldContainExactlyInAnyOrder(16L, 42L)152 }153 @Test154 fun `Given invalid target media id, when appending members then fail with IAE`() = test {155 val dao = InMemoryPlaylistDao(initialPlaylists = listOf(SAMPLE_PLAYLIST))156 val action = ManagePlaylistAction(dao)157 val newMemberIds = listOf(158 MediaId(TYPE_TRACKS, CATEGORY_ALL, 16L),159 MediaId(TYPE_TRACKS, CATEGORY_ALL, 42L)160 )161 for (mediaId in invalidPlaylistIds()) {162 shouldThrow<IllegalArgumentException> {163 action.appendMembers(164 targetPlaylist = mediaId,165 members = newMemberIds...

Full Screen

Full Screen

DeleteTracksActionTest.kt

Source:DeleteTracksActionTest.kt Github

copy

Full Screen

...22import fr.nihilus.music.core.media.MediaId.Builder.TYPE_PLAYLISTS23import fr.nihilus.music.core.media.MediaId.Builder.TYPE_TRACKS24import fr.nihilus.music.media.provider.DeleteTracksResult25import fr.nihilus.music.media.provider.Track26import io.kotest.assertions.extracting27import io.kotest.assertions.throwables.shouldThrow28import io.kotest.matchers.collections.shouldNotContain29import io.kotest.matchers.shouldBe30import io.kotest.matchers.types.shouldBeInstanceOf31import kotlinx.coroutines.flow.first32import kotlinx.coroutines.test.runTest33import kotlin.test.Test34private val SAMPLE_TRACKS = listOf(35 Track(36 161,37 "1741 (The Battle of Cartagena)",38 "Alestorm",39 "Sunset on the Golden Age",40 437603,41 1,42 4,43 "",44 null,45 1466283480,46 26,47 65,48 17_506_48149 ),50 Track(51 309,52 "The 2nd Law: Isolated System",53 "Muse",54 "The 2nd Law",55 300042,56 1,57 13,58 "",59 null,60 1439653800,61 18,62 40,63 12_075_96764 ),65 Track(66 481,67 "Dirty Water",68 "Foo Fighters",69 "Concrete and Gold",70 320914,71 1,72 6,73 "",74 null,75 1506374520,76 13,77 102,78 12_912_28279 ),80 Track(81 48,82 "Give It Up",83 "AC/DC",84 "Greatest Hits 30 Anniversary Edition",85 233592,86 1,87 19,88 "",89 null,90 1455310080,91 5,92 7,93 5_716_57894 ),95 Track(96 125,97 "Jailbreak",98 "AC/DC",99 "Greatest Hits 30 Anniversary Edition",100 276668,101 2,102 14,103 "",104 null,105 1455310140,106 5,107 7,108 6_750_404109 ),110 Track(111 294,112 "Knights of Cydonia",113 "Muse",114 "Black Holes and Revelations",115 366946,116 1,117 11,118 "",119 null,120 1414880700,121 18,122 38,123 11_746_572124 ),125 Track(126 219,127 "A Matter of Time",128 "Foo Fighters",129 "Wasting Light",130 276140,131 1,132 8,133 "",134 null,135 1360677660,136 13,137 26,138 11_149_678139 ),140 Track(141 75,142 "Nightmare",143 "Avenged Sevenfold",144 "Nightmare",145 374648,146 1,147 1,148 "",149 null,150 1439590380,151 4,152 6,153 10_828_662154 ),155 Track(156 464,157 "The Pretenders",158 "Foo Fighters",159 "Echoes, Silence, Patience & Grace",160 266509,161 1,162 1,163 "",164 null,165 1439653740,166 13,167 95,168 4_296_041169 ),170 Track(171 477,172 "Run",173 "Foo Fighters",174 "Concrete and Gold",175 323424,176 1,177 2,178 "",179 null,180 1506374520,181 13,182 102,183 13_012_576184 )185)186/**187 * Verify behavior of [DeleteTracksAction].188 */189internal class DeleteTracksActionTest {190 @Test191 fun `Given invalid track media ids, when deleting then fail with IAE`() = runTest {192 val dao = InMemoryTrackDao()193 val action = DeleteTracksAction(dao)194 val invalidTrackIds = listOf(195 MediaId(TYPE_TRACKS, CATEGORY_ALL),196 MediaId(TYPE_ALBUMS, "13"),197 MediaId(TYPE_ARTISTS, "78"),198 MediaId(TYPE_PLAYLISTS, "9")199 )200 for (mediaId in invalidTrackIds) {201 shouldThrow<IllegalArgumentException> {202 action.delete(listOf(mediaId))203 }204 }205 }206 @Test207 fun `When deleting tracks then remove records from dao`() = runTest {208 val dao = InMemoryTrackDao(initial = SAMPLE_TRACKS)209 val action = DeleteTracksAction(dao)210 val deleteResult = action.delete(211 mediaIds = listOf(212 MediaId(TYPE_TRACKS, CATEGORY_ALL, 161),213 MediaId(TYPE_TRACKS, CATEGORY_ALL, 48),214 MediaId(TYPE_TRACKS, CATEGORY_ALL, 75)215 )216 )217 deleteResult.shouldBeInstanceOf<DeleteTracksResult.Deleted>()218 deleteResult.count shouldBe 3219 val savedTracks = dao.tracks.first()220 savedTracks.size shouldBe 7221 extracting(savedTracks) { id }.also {222 it shouldNotContain 161223 it shouldNotContain 48224 it shouldNotContain 75225 }226 }227 @Test228 fun `Given denied permission, when deleting tracks then return RequiresPermission`() = runTest {229 val deniedDao = InMemoryTrackDao(permissionGranted = false)230 val action = DeleteTracksAction(deniedDao)231 val targetTrackIds = listOf(232 MediaId(TYPE_TRACKS, CATEGORY_ALL, 161),233 MediaId(TYPE_TRACKS, CATEGORY_ALL, 464)234 )235 val result = action.delete(targetTrackIds)...

Full Screen

Full Screen

UserHashedAuthenticationPasswordSpec.kt

Source:UserHashedAuthenticationPasswordSpec.kt Github

copy

Full Screen

...6import stasis.client_android.lib.encryption.secrets.UserHashedAuthenticationPassword7import java.util.UUID8class UserHashedAuthenticationPasswordSpec : WordSpec({9 "A UserHashedAuthenticationPassword" should {10 "allow extracting the hashed password" {11 val originalPassword = "test-password"12 val expectedPassword = "dGVzdC1wYXNzd29yZA"13 val actualPassword = UserHashedAuthenticationPassword(14 user = UUID.randomUUID(),15 hashedPassword = originalPassword.encodeUtf8()16 )17 actualPassword.extract() shouldBe (expectedPassword)18 }19 "fail if the password is extracted more than once" {20 val originalPassword = "test-password"21 val expectedPassword = "dGVzdC1wYXNzd29yZA"22 val actualPassword = UserHashedAuthenticationPassword(23 user = UUID.randomUUID(),24 hashedPassword = originalPassword.encodeUtf8()...

Full Screen

Full Screen

ExtractTest.kt

Source:ExtractTest.kt Github

copy

Full Screen

1package com.sksamuel.kotest2import io.kotest.assertions.extracting3import io.kotest.assertions.throwables.shouldThrowAny4import io.kotest.core.spec.style.WordSpec5import io.kotest.matchers.collections.shouldContainAll6import io.kotest.matchers.shouldBe7class ExtractTest : WordSpec() {8 init {9 data class Person(val name: String, val age: Int, val friends: List<Person>)10 val p1 = Person("John Doe", 20, emptyList())11 val p2 = Person("Samantha Rose", 19, listOf(p1))12 val persons = listOf(p1, p2)13 "extracting" should {14 "extract simple properties"{15 extracting(persons) { name }16 .shouldContainAll("John Doe", "Samantha Rose")17 }18 "extract complex properties"{19 extracting(persons) { Pair(name, age) }20 .shouldContainAll(21 Pair("John Doe", 20),22 Pair("Samantha Rose", 19)23 )24 }25 "fail if the matcher fails"{26 shouldThrowAny {27 extracting(persons) { name }28 .shouldContainAll("<Some name that is wrong>")29 }.message shouldBe """Collection should contain all of ["<Some name that is wrong>"] but was missing ["<Some name that is wrong>"]"""30 }31 }32 }33}

Full Screen

Full Screen

extracting.kt

Source:extracting.kt Github

copy

Full Screen

1package io.kotest.assertions2/**3 * `extracting` pulls property values out of a list of objects for _typed_ bulk assertions on properties.4 *5 * The **simple example** shows how `extracting` helps with disjunct collection assertions:6 * ```7 * extracting(persons){ name }8 * .shouldContainAll("John Doe", "Samantha Roes")9 * ```10 *11 * This is similar to using multiple [forOne] however allows for a more concise notation.12 * ```13 * forOne(persons){ it.name shouldBe "John Doe" }14 * forOne(persons){ it.name shouldBe "Samantha Rose" }15 * ```16 *17 * `extracting` also allows to define complex return types shown in this **elaborate example**:18 * ```19 * extracting(persons){ Pair(name, age) }20 * .shouldContainAll(21 * Pair("John Doe", 20),22 * Pair("Samantha Roes", 19)23 * )24 * ```25 * @param col the collection of objects from which to extract the properties26 * @param extractor the extractor that defines _which_ properties are returned27 * @author Hannes Thaller28 */29fun <K, T> extracting(col: Collection<K>, extractor: K.() -> T): List<T> {30 return col.map(extractor)31}...

Full Screen

Full Screen

extracting

Using AI Code Generation

copy

Full Screen

1 import io.kotest.assertions.extracting2 import io.kotest.matchers.shouldNotBe3 import io.kotest.matchers.comparables.extract4 class ExtractingTest {5 fun `extracting`() {6 data class Person(val name: String, val age: Int)7 val person = Person("John", 30)8 person.extracting(Person::name, Person::age) shouldBe listOf("John", 30)9 person.extracting(Person::name, Person::age) shouldNotBe listOf("John", 20)10 person.extracting(Person::name, Person::age) shouldBe listOf(extract { it shouldNotBe "John" }, 30)11 }12 }

Full Screen

Full Screen

extracting

Using AI Code Generation

copy

Full Screen

1import io.kotest.assertions.Extractor2val extractor = Extractor<Int, String> { it.toString() }3val result = extractor.extract(1)4import io.kotest.assertions.Extractor5val extractor = Extractor { it.toString() }6val result = extractor.extract(1)7import io.kotest.assertions.Extractor8val extractor = Extractor<Int, String> { it.toString() }9val result = extractor.extract(1)10import io.kotest.assertions.Extractor11val extractor = Extractor { it.toString() }12val result = extractor.extract(1)13import io.kotest.assertions.Extractor14val extractor = Extractor<Int, String> { it.toString() }15val result = extractor.extract(1)16import io.kotest.assertions.Extractor17val extractor = Extractor { it.toString() }18val result = extractor.extract(1)19import io.kotest.assertions.Extractor20val extractor = Extractor<Int, String> { it.toString() }21val result = extractor.extract(1)22import io.kotest.assertions.Extractor23val extractor = Extractor { it.toString() }24val result = extractor.extract(1)25import io.kotest.assertions.Extractor26val extractor = Extractor<Int, String> { it.toString() }27val result = extractor.extract(1)28import io.kotest.assertions.Extractor29val extractor = Extractor { it.toString() }30val result = extractor.extract(1)31import io.kotest.assertions.Extractor32val extractor = Extractor<Int, String> { it.toString() }33val result = extractor.extract(1)34import

Full Screen

Full Screen

extracting

Using AI Code Generation

copy

Full Screen

1result.shouldBeFailure()2result.exceptionOrNull() shouldHaveType ArithmeticException::class3result.exceptionOrNull() shouldHaveMessage "/ by zero"4result.exceptionOrNull() shouldHaveCause IllegalArgumentException::class5result.exceptionOrNull() shouldHaveCauseMessage "some message"6result.shouldBeFailure()7result.exceptionOrNull() shouldHaveType ArithmeticException::class8result.exceptionOrNull() shouldHaveMessage "/ by zero"9result.exceptionOrNull() shouldHaveCause IllegalArgumentException::class10result.exceptionOrNull() shouldHaveCauseMessage "some message"11result.shouldBeFailure()12result.exceptionOrNull() shouldHaveType ArithmeticException::class13result.exceptionOrNull() shouldHaveMessage "/ by zero"14result.exceptionOrNull() shouldHaveCause IllegalArgumentException::class15result.exceptionOrNull() shouldHaveCauseMessage "some message"16result.shouldBeFailure()17result.exceptionOrNull() shouldHaveType ArithmeticException::class18result.exceptionOrNull() shouldHaveMessage "/ by zero"19result.exceptionOrNull() shouldHaveCause IllegalArgumentException::class20result.exceptionOrNull() shouldHaveCauseMessage "some message"21result.shouldBeFailure()22result.exceptionOrNull() shouldHaveType ArithmeticException::class23result.exceptionOrNull() shouldHaveMessage "/ by zero"24result.exceptionOrNull() shouldHaveCause IllegalArgumentException::class25result.exceptionOrNull() shouldHaveCauseMessage "some message"26result.shouldBeFailure()27result.exceptionOrNull() shouldHaveType ArithmeticException::class28result.exceptionOrNull() shouldHaveMessage "/ by zero"29result.exceptionOrNull() shouldHaveCause IllegalArgumentException::class30result.exceptionOrNull() shouldHaveCauseMessage "some message"31result.shouldBeFailure()32result.exceptionOrNull() shouldHaveType ArithmeticException::class

Full Screen

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run Kotest automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Most used methods in extracting

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful