How to use List.shouldMatchInOrder method of io.kotest.matchers.collections.matchers class

Best Kotest code snippet using io.kotest.matchers.collections.matchers.List.shouldMatchInOrder

BitrateControllerNewTest.kt

Source:BitrateControllerNewTest.kt Github

copy

Full Screen

1/*2 * Copyright @ 2018 - present 8x8, Inc.3 * Copyright @ 2021 - Vowel, Inc.4 *5 * Licensed under the Apache License, Version 2.0 (the "License");6 * you may not use this file except in compliance with the License.7 * You may obtain a copy of the License at8 *9 * http://www.apache.org/licenses/LICENSE-2.010 *11 * Unless required by applicable law or agreed to in writing, software12 * distributed under the License is distributed on an "AS IS" BASIS,13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.14 * See the License for the specific language governing permissions and15 * limitations under the License.16 */17package org.jitsi.videobridge.cc.allocation18import io.kotest.core.spec.IsolationMode19import io.kotest.core.spec.Spec20import io.kotest.core.spec.style.ShouldSpec21import io.kotest.matchers.collections.shouldContainInOrder22import io.kotest.matchers.shouldBe23import org.jitsi.config.setNewConfig24import org.jitsi.nlj.MediaSourceDesc25import org.jitsi.nlj.PacketInfo26import org.jitsi.nlj.RtpEncodingDesc27import org.jitsi.nlj.VideoType28import org.jitsi.nlj.format.RtxPayloadType29import org.jitsi.nlj.rtp.VideoRtpPacket30import org.jitsi.nlj.util.bps31import org.jitsi.nlj.util.kbps32import org.jitsi.nlj.util.mbps33import org.jitsi.test.time.FakeClock34import org.jitsi.utils.logging.DiagnosticContext35import org.jitsi.utils.logging2.createLogger36import org.jitsi.utils.ms37import org.jitsi.utils.secs38import org.jitsi.videobridge.configWithMultiStreamEnabled39import org.jitsi.videobridge.message.ReceiverVideoConstraintsMessage40import java.util.function.Supplier41class BitrateControllerNewTest : ShouldSpec() {42 override fun isolationMode() = IsolationMode.InstancePerLeaf43 private val logger = createLogger()44 private val clock = FakeClock()45 private val bc = BitrateControllerWrapper2(createEndpoints2("A", "B", "C", "D"), clock = clock)46 private val A = bc.endpoints.find { it.id == "A" }!! as TestEndpoint247 private val B = bc.endpoints.find { it.id == "B" }!! as TestEndpoint248 private val C = bc.endpoints.find { it.id == "C" }!! as TestEndpoint249 private val D = bc.endpoints.find { it.id == "D" }!! as TestEndpoint250 override fun beforeSpec(spec: Spec) = super.beforeSpec(spec).also {51 // We disable the threshold, causing [BandwidthAllocator] to make a new decision every time BWE changes. This is52 // because these tests are designed to test the decisions themselves and not necessarily when they are made.53 setNewConfig(54 "videobridge.cc.bwe-change-threshold=0" +55 "\n" + configWithMultiStreamEnabled, // Also enable multi stream support56 true57 )58 }59 override fun afterSpec(spec: Spec) = super.afterSpec(spec).also {60 setNewConfig("", true)61 }62 init {63 context("Prioritization") {64 context("Without selection") {65 val sources = createSources("s6", "s5", "s4", "s3", "s2", "s1")66 val ordered = prioritize2(sources)67 ordered.map { it.sourceName } shouldBe listOf("s6", "s5", "s4", "s3", "s2", "s1")68 }69 context("With one selected") {70 val sources = createSources("s6", "s5", "s4", "s3", "s2", "s1")71 val ordered = prioritize2(sources, listOf("s2"))72 ordered.map { it.sourceName } shouldBe listOf("s2", "s6", "s5", "s4", "s3", "s1")73 }74 context("With multiple selected") {75 val sources = createSources("s6", "s5", "s4", "s3", "s2", "s1")76 val ordered = prioritize2(sources, listOf("s2", "s1", "s5"))77 ordered.map { it.sourceName } shouldBe listOf("s2", "s1", "s5", "s6", "s4", "s3")78 }79 }80 context("Allocation") {81 context("Stage view") {82 context("When LastN is not set") {83 context("and the dominant speaker is on stage") {84 listOf(true, false).forEach { screensharing ->85 context("With ${if (screensharing) "screensharing" else "camera"}") {86 if (screensharing) {87 A.mediaSources[0].videoType = VideoType.DESKTOP88 }89 bc.setEndpointOrdering(A, B, C, D)90 bc.setStageView("A-v0")91 bc.bc.allocationSettings.lastN shouldBe -192 bc.bc.allocationSettings.selectedSources shouldBe emptyList()93 bc.bc.allocationSettings.onStageSources shouldBe listOf("A-v0")94 runBweLoop()95 verifyStageView(screensharing)96 }97 }98 }99 context("and a non-dominant speaker is on stage") {100 bc.setEndpointOrdering(B, A, C, D)101 bc.setStageView("A-v0")102 bc.bc.allocationSettings.lastN shouldBe -1103 bc.bc.allocationSettings.selectedSources shouldBe emptyList()104 bc.bc.allocationSettings.onStageSources shouldBe listOf("A-v0")105 runBweLoop()106 verifyStageView()107 }108 }109 context("When LastN=0") {110 // LastN=0 is used when the client goes in "audio-only" mode.111 bc.setEndpointOrdering(A, B, C, D)112 bc.setStageView("A", lastN = 0)113 bc.bc.allocationSettings.lastN shouldBe 0114 bc.bc.allocationSettings.selectedSources shouldBe emptyList()115 bc.bc.allocationSettings.onStageSources shouldBe listOf("A")116 runBweLoop()117 verifyLastN0()118 }119 context("When LastN=1") {120 // LastN=1 is used when the client goes in "audio-only" mode, but someone starts a screenshare.121 context("and the dominant speaker is on-stage") {122 bc.setEndpointOrdering(A, B, C, D)123 bc.setStageView("A-v0", lastN = 1)124 bc.bc.allocationSettings.lastN shouldBe 1125 bc.bc.allocationSettings.selectedSources shouldBe emptyList()126 bc.bc.allocationSettings.onStageSources shouldBe listOf("A-v0")127 runBweLoop()128 verifyStageViewLastN1()129 }130 context("and a non-dominant speaker is on stage") {131 bc.setEndpointOrdering(B, A, C, D)132 bc.setStageView("A-v0", lastN = 1)133 bc.bc.allocationSettings.lastN shouldBe 1134 bc.bc.allocationSettings.selectedSources shouldBe emptyList()135 bc.bc.allocationSettings.onStageSources shouldBe listOf("A-v0")136 runBweLoop()137 verifyStageViewLastN1()138 }139 }140 }141 context("Tile view") {142 bc.setEndpointOrdering(A, B, C, D)143 bc.setTileView("A-v0", "B-v0", "C-v0", "D-v0")144 bc.bc.allocationSettings.lastN shouldBe -1145 bc.bc.allocationSettings.selectedSources shouldBe146 listOf("A-v0", "B-v0", "C-v0", "D-v0")147 context("When LastN is not set") {148 runBweLoop()149 verifyTileView()150 }151 context("When LastN=0") {152 bc.setTileView("A-v0", "B-v0", "C-v0", "D-v0", lastN = 0)153 runBweLoop()154 verifyLastN0()155 }156 context("When LastN=1") {157 bc.setTileView("A-v0", "B-v0", "C-v0", "D-v0", lastN = 1)158 runBweLoop()159 verifyTileViewLastN1()160 }161 }162 context("Tile view 360p") {163 bc.setEndpointOrdering(A, B, C, D)164 bc.setTileView("A-v0", "B-v0", "C-v0", "D-v0", maxFrameHeight = 360)165 bc.bc.allocationSettings.lastN shouldBe -1166 // The legacy API (currently used by jitsi-meet) uses "selected count > 0" to infer TileView,167 // and in tile view we do not use selected endpoints.168 bc.bc.allocationSettings.selectedSources shouldBe169 listOf("A-v0", "B-v0", "C-v0", "D-v0")170 context("When LastN is not set") {171 runBweLoop()172 verifyTileView360p()173 }174 context("When LastN=0") {175 bc.setTileView("A-v0", "B-v0", "C-v0", "D-v0", lastN = 0, maxFrameHeight = 360)176 runBweLoop()177 verifyLastN0()178 }179 context("When LastN=1") {180 bc.setTileView("A-v0", "B-v0", "C-v0", "D-v0", lastN = 1, maxFrameHeight = 360)181 runBweLoop()182 verifyTileViewLastN1(360)183 }184 }185 context("Selected sources should override the dominant speaker (with new signaling)") {186 // A is dominant speaker, A and B are selected. With LastN=2 we should always forward the selected187 // sources regardless of who is speaking.188 // The exact flow of this scenario was taken from a (non-jitsi-meet) client.189 bc.setEndpointOrdering(A, B, C, D)190 bc.bc.setBandwidthAllocationSettings(191 ReceiverVideoConstraintsMessage(192 selectedSources = listOf("A-v0", "B-v0"),193 constraints = mapOf("A-v0" to VideoConstraints(720), "B-v0" to VideoConstraints(720))194 )195 )196 bc.effectiveConstraintsHistory.last().event shouldBe mapOf(197 "A-v0" to VideoConstraints(720),198 "B-v0" to VideoConstraints(720),199 "C-v0" to VideoConstraints(180),200 "D-v0" to VideoConstraints(180)201 )202 bc.bc.setBandwidthAllocationSettings(ReceiverVideoConstraintsMessage(lastN = 2))203 bc.effectiveConstraintsHistory.last().event shouldBe mapOf(204 "A-v0" to VideoConstraints(720),205 "B-v0" to VideoConstraints(720),206 "C-v0" to VideoConstraints(0),207 "D-v0" to VideoConstraints(0)208 )209 bc.bc.allocationSettings.lastN shouldBe 2210 bc.bc.allocationSettings.selectedSources shouldBe listOf("A-v0", "B-v0")211 clock.elapse(20.secs)212 bc.bwe = 10.mbps213 bc.forwardedSourcesHistory.last().event.shouldBe(setOf("A-v0", "B-v0"))214 clock.elapse(2.secs)215 // B becomes dominant speaker.216 bc.setEndpointOrdering(B, A, C, D)217 bc.forwardedSourcesHistory.last().event.shouldBe(setOf("A-v0", "B-v0"))218 clock.elapse(2.secs)219 bc.bc.setBandwidthAllocationSettings(220 ReceiverVideoConstraintsMessage(221 constraints = mapOf("A-v0" to VideoConstraints(360), "B-v0" to VideoConstraints(360))222 )223 )224 bc.effectiveConstraintsHistory.last().event shouldBe mapOf(225 "A-v0" to VideoConstraints(360),226 "B-v0" to VideoConstraints(360),227 "C-v0" to VideoConstraints(0),228 "D-v0" to VideoConstraints(0)229 )230 clock.elapse(2.secs)231 // This should change nothing, the selection didn't change.232 bc.bc.setBandwidthAllocationSettings(233 ReceiverVideoConstraintsMessage(selectedSources = listOf("A-v0", "B-v0"))234 )235 bc.forwardedSourcesHistory.last().event.shouldBe(setOf("A-v0", "B-v0"))236 clock.elapse(2.secs)237 bc.bc.setBandwidthAllocationSettings(ReceiverVideoConstraintsMessage(lastN = -1))238 bc.effectiveConstraintsHistory.last().event shouldBe mapOf(239 "A-v0" to VideoConstraints(360),240 "B-v0" to VideoConstraints(360),241 "C-v0" to VideoConstraints(180),242 "D-v0" to VideoConstraints(180)243 )244 bc.forwardedSourcesHistory.last().event.shouldBe(setOf("A-v0", "B-v0", "C-v0", "D-v0"))245 bc.bc.setBandwidthAllocationSettings(ReceiverVideoConstraintsMessage(lastN = 2))246 bc.effectiveConstraintsHistory.last().event shouldBe mapOf(247 "A-v0" to VideoConstraints(360),248 "B-v0" to VideoConstraints(360),249 "C-v0" to VideoConstraints(0),250 "D-v0" to VideoConstraints(0)251 )252 clock.elapse(2.secs)253 bc.forwardedSourcesHistory.last().event.shouldBe(setOf("A-v0", "B-v0"))254 clock.elapse(2.secs)255 // D is now dominant speaker, but it should not override the selected endpoints.256 bc.setEndpointOrdering(D, B, A, C)257 bc.forwardedSourcesHistory.last().event.shouldBe(setOf("A-v0", "B-v0"))258 bc.bwe = 10.mbps259 bc.forwardedSourcesHistory.last().event.shouldBe(setOf("A-v0", "B-v0"))260 clock.elapse(2.secs)261 bc.bwe = 0.mbps262 clock.elapse(2.secs)263 bc.bwe = 10.mbps264 bc.forwardedSourcesHistory.last().event.shouldBe(setOf("A-v0", "B-v0"))265 clock.elapse(2.secs)266 // C is now dominant speaker, but it should not override the selected endpoints.267 bc.setEndpointOrdering(C, D, A, B)268 bc.forwardedSourcesHistory.last().event.shouldBe(setOf("A-v0", "B-v0"))269 }270 }271 }272 private fun runBweLoop() {273 for (bwe in 0..5_000_000 step 10_000) {274 bc.bwe = bwe.bps275 clock.elapse(100.ms)276 }277 logger.info("Forwarded sources history: ${bc.forwardedSourcesHistory}")278 logger.info("Effective constraints history: ${bc.effectiveConstraintsHistory}")279 logger.info("Allocation history: ${bc.allocationHistory}")280 }281 private fun verifyStageViewScreensharing() {282 // At this stage the purpose of this is just to document current behavior.283 // TODO: The results with bwe==-1 are wrong.284 bc.forwardedSourcesHistory.map { it.event }.shouldContainInOrder(285 setOf("A-v0"),286 setOf("A-v0", "B-v0"),287 setOf("A-v0", "B-v0", "C-v0"),288 setOf("A-v0", "B-v0", "C-v0", "D-v0")289 )290 bc.effectiveConstraintsHistory.last().event shouldBe mapOf(291 "A-v0" to VideoConstraints(720),292 "B-v0" to VideoConstraints(180),293 "C-v0" to VideoConstraints(180),294 "D-v0" to VideoConstraints(180)295 )296 // At this stage the purpose of this is just to document current behavior.297 // TODO: the allocations for bwe=-1 are wrong.298 bc.allocationHistory.removeIf { it.bwe < 0.bps }299 bc.allocationHistory.shouldMatchInOrder(300 // We expect to be oversending when screensharing is used.301 Event(302 0.kbps,303 BandwidthAllocation(304 setOf(305 SingleAllocation(A, targetLayer = sd30),306 SingleAllocation(B, targetLayer = noVideo),307 SingleAllocation(C, targetLayer = noVideo),308 SingleAllocation(D, targetLayer = noVideo)309 ),310 oversending = true311 )312 ),313 Event(314 160.kbps,315 BandwidthAllocation(316 setOf(317 SingleAllocation(A, targetLayer = hd7_5),318 SingleAllocation(B, targetLayer = noVideo),319 SingleAllocation(C, targetLayer = noVideo),320 SingleAllocation(D, targetLayer = noVideo)321 ),322 oversending = true323 )324 ),325 Event(326 660.kbps,327 BandwidthAllocation(328 setOf(329 SingleAllocation(A, targetLayer = hd7_5),330 SingleAllocation(B, targetLayer = noVideo),331 SingleAllocation(C, targetLayer = noVideo),332 SingleAllocation(D, targetLayer = noVideo)333 ),334 oversending = false335 )336 ),337 Event(338 1320.kbps,339 BandwidthAllocation(340 setOf(341 SingleAllocation(A, targetLayer = hd15),342 SingleAllocation(B, targetLayer = noVideo),343 SingleAllocation(C, targetLayer = noVideo),344 SingleAllocation(D, targetLayer = noVideo)345 )346 )347 ),348 Event(349 2000.kbps,350 BandwidthAllocation(351 setOf(352 SingleAllocation(A, targetLayer = hd30),353 SingleAllocation(B, targetLayer = noVideo),354 SingleAllocation(C, targetLayer = noVideo),355 SingleAllocation(D, targetLayer = noVideo)356 )357 )358 ),359 Event(360 2050.kbps,361 BandwidthAllocation(362 setOf(363 SingleAllocation(A, targetLayer = hd30),364 SingleAllocation(B, targetLayer = ld7_5),365 SingleAllocation(C, targetLayer = noVideo),366 SingleAllocation(D, targetLayer = noVideo)367 )368 )369 ),370 Event(371 2100.kbps,372 BandwidthAllocation(373 setOf(374 SingleAllocation(A, targetLayer = hd30),375 SingleAllocation(B, targetLayer = ld7_5),376 SingleAllocation(C, targetLayer = ld7_5),377 SingleAllocation(D, targetLayer = noVideo)378 )379 )380 ),381 Event(382 2150.kbps,383 BandwidthAllocation(384 setOf(385 SingleAllocation(A, targetLayer = hd30),386 SingleAllocation(B, targetLayer = ld7_5),387 SingleAllocation(C, targetLayer = ld7_5),388 SingleAllocation(D, targetLayer = ld7_5)389 )390 )391 ),392 Event(393 2200.kbps,394 BandwidthAllocation(395 setOf(396 SingleAllocation(A, targetLayer = hd30),397 SingleAllocation(B, targetLayer = ld15),398 SingleAllocation(C, targetLayer = ld7_5),399 SingleAllocation(D, targetLayer = ld7_5)400 )401 )402 ),403 Event(404 2250.kbps,405 BandwidthAllocation(406 setOf(407 SingleAllocation(A, targetLayer = hd30),408 SingleAllocation(B, targetLayer = ld15),409 SingleAllocation(C, targetLayer = ld15),410 SingleAllocation(D, targetLayer = ld7_5)411 )412 )413 ),414 Event(415 2300.kbps,416 BandwidthAllocation(417 setOf(418 SingleAllocation(A, targetLayer = hd30),419 SingleAllocation(B, targetLayer = ld15),420 SingleAllocation(C, targetLayer = ld15),421 SingleAllocation(D, targetLayer = ld15)422 )423 )424 ),425 Event(426 2350.kbps,427 BandwidthAllocation(428 setOf(429 SingleAllocation(A, targetLayer = hd30),430 SingleAllocation(B, targetLayer = ld30),431 SingleAllocation(C, targetLayer = ld15),432 SingleAllocation(D, targetLayer = ld15)433 )434 )435 ),436 Event(437 2400.kbps,438 BandwidthAllocation(439 setOf(440 SingleAllocation(A, targetLayer = hd30),441 SingleAllocation(B, targetLayer = ld30),442 SingleAllocation(C, targetLayer = ld30),443 SingleAllocation(D, targetLayer = ld15)444 )445 )446 ),447 Event(448 2460.kbps,449 BandwidthAllocation(450 setOf(451 SingleAllocation(A, targetLayer = hd30),452 SingleAllocation(B, targetLayer = ld30),453 SingleAllocation(C, targetLayer = ld30),454 SingleAllocation(D, targetLayer = ld30)455 )456 )457 )458 )459 }460 private fun verifyStageView(screensharing: Boolean = false) {461 when (screensharing) {462 true -> verifyStageViewScreensharing()463 false -> verifyStageViewCamera()464 }465 }466 private fun verifyStageViewCamera() {467 // At this stage the purpose of this is just to document current behavior.468 // TODO: The results with bwe==-1 are wrong.469 bc.forwardedSourcesHistory.removeIf { it.bwe < 0.bps }470 bc.forwardedSourcesHistory.map { it.event }.shouldContainInOrder(471 setOf("A-v0"),472 setOf("A-v0", "B-v0"),473 setOf("A-v0", "B-v0", "C-v0"),474 setOf("A-v0", "B-v0", "C-v0", "D-v0")475 )476 // TODO add forwarded sources history here477 bc.effectiveConstraintsHistory.last().event shouldBe mapOf(478 "A-v0" to VideoConstraints(720),479 "B-v0" to VideoConstraints(180),480 "C-v0" to VideoConstraints(180),481 "D-v0" to VideoConstraints(180)482 )483 // At this stage the purpose of this is just to document current behavior.484 // TODO: the allocations for bwe=-1 are wrong.485 bc.allocationHistory.removeIf { it.bwe < 0.bps }486 bc.allocationHistory.shouldMatchInOrder(487 Event(488 50.kbps,489 BandwidthAllocation(490 setOf(491 SingleAllocation(A, targetLayer = ld7_5),492 SingleAllocation(B, targetLayer = noVideo),493 SingleAllocation(C, targetLayer = noVideo),494 SingleAllocation(D, targetLayer = noVideo)495 ),496 oversending = false497 )498 ),499 Event(500 100.kbps,501 BandwidthAllocation(502 setOf(503 SingleAllocation(A, targetLayer = ld15),504 SingleAllocation(B, targetLayer = noVideo),505 SingleAllocation(C, targetLayer = noVideo),506 SingleAllocation(D, targetLayer = noVideo)507 )508 )509 ),510 Event(511 150.kbps,512 BandwidthAllocation(513 setOf(514 SingleAllocation(A, targetLayer = ld30),515 SingleAllocation(B, targetLayer = noVideo),516 SingleAllocation(C, targetLayer = noVideo),517 SingleAllocation(D, targetLayer = noVideo)518 )519 )520 ),521 Event(522 500.kbps,523 BandwidthAllocation(524 setOf(525 SingleAllocation(A, targetLayer = sd30),526 SingleAllocation(B, targetLayer = noVideo),527 SingleAllocation(C, targetLayer = noVideo),528 SingleAllocation(D, targetLayer = noVideo)529 )530 )531 ),532 Event(533 550.kbps,534 BandwidthAllocation(535 setOf(536 SingleAllocation(A, targetLayer = sd30),537 SingleAllocation(B, targetLayer = ld7_5),538 SingleAllocation(C, targetLayer = noVideo),539 SingleAllocation(D, targetLayer = noVideo)540 )541 )542 ),543 Event(544 600.kbps,545 BandwidthAllocation(546 setOf(547 SingleAllocation(A, targetLayer = sd30),548 SingleAllocation(B, targetLayer = ld7_5),549 SingleAllocation(C, targetLayer = ld7_5),550 SingleAllocation(D, targetLayer = noVideo)551 )552 )553 ),554 Event(555 650.kbps,556 BandwidthAllocation(557 setOf(558 SingleAllocation(A, targetLayer = sd30),559 SingleAllocation(B, targetLayer = ld7_5),560 SingleAllocation(C, targetLayer = ld7_5),561 SingleAllocation(D, targetLayer = ld7_5)562 )563 )564 ),565 Event(566 700.kbps,567 BandwidthAllocation(568 setOf(569 SingleAllocation(A, targetLayer = sd30),570 SingleAllocation(B, targetLayer = ld15),571 SingleAllocation(C, targetLayer = ld7_5),572 SingleAllocation(D, targetLayer = ld7_5)573 )574 )575 ),576 Event(577 750.kbps,578 BandwidthAllocation(579 setOf(580 SingleAllocation(A, targetLayer = sd30),581 SingleAllocation(B, targetLayer = ld15),582 SingleAllocation(C, targetLayer = ld15),583 SingleAllocation(D, targetLayer = ld7_5)584 )585 )586 ),587 Event(588 800.kbps,589 BandwidthAllocation(590 setOf(591 SingleAllocation(A, targetLayer = sd30),592 SingleAllocation(B, targetLayer = ld15),593 SingleAllocation(C, targetLayer = ld15),594 SingleAllocation(D, targetLayer = ld15)595 )596 )597 ),598 Event(599 850.kbps,600 BandwidthAllocation(601 setOf(602 SingleAllocation(A, targetLayer = sd30),603 SingleAllocation(B, targetLayer = ld30),604 SingleAllocation(C, targetLayer = ld15),605 SingleAllocation(D, targetLayer = ld15)606 )607 )608 ),609 Event(610 900.kbps,611 BandwidthAllocation(612 setOf(613 SingleAllocation(A, targetLayer = sd30),614 SingleAllocation(B, targetLayer = ld30),615 SingleAllocation(C, targetLayer = ld30),616 SingleAllocation(D, targetLayer = ld15)617 )618 )619 ),620 Event(621 960.kbps,622 BandwidthAllocation(623 setOf(624 SingleAllocation(A, targetLayer = sd30),625 SingleAllocation(B, targetLayer = ld30),626 SingleAllocation(C, targetLayer = ld30),627 SingleAllocation(D, targetLayer = ld30)628 )629 )630 ),631 Event(632 2150.kbps,633 BandwidthAllocation(634 setOf(635 SingleAllocation(A, targetLayer = hd30),636 SingleAllocation(B, targetLayer = ld7_5),637 SingleAllocation(C, targetLayer = ld7_5),638 SingleAllocation(D, targetLayer = ld7_5)639 )640 )641 ),642 Event(643 2200.kbps,644 BandwidthAllocation(645 setOf(646 SingleAllocation(A, targetLayer = hd30),647 SingleAllocation(B, targetLayer = ld15),648 SingleAllocation(C, targetLayer = ld7_5),649 SingleAllocation(D, targetLayer = ld7_5)650 )651 )652 ),653 Event(654 2250.kbps,655 BandwidthAllocation(656 setOf(657 SingleAllocation(A, targetLayer = hd30),658 SingleAllocation(B, targetLayer = ld15),659 SingleAllocation(C, targetLayer = ld15),660 SingleAllocation(D, targetLayer = ld7_5)661 )662 )663 ),664 Event(665 2300.kbps,666 BandwidthAllocation(667 setOf(668 SingleAllocation(A, targetLayer = hd30),669 SingleAllocation(B, targetLayer = ld15),670 SingleAllocation(C, targetLayer = ld15),671 SingleAllocation(D, targetLayer = ld15)672 )673 )674 ),675 Event(676 2350.kbps,677 BandwidthAllocation(678 setOf(679 SingleAllocation(A, targetLayer = hd30),680 SingleAllocation(B, targetLayer = ld30),681 SingleAllocation(C, targetLayer = ld15),682 SingleAllocation(D, targetLayer = ld15)683 )684 )685 ),686 Event(687 2400.kbps,688 BandwidthAllocation(689 setOf(690 SingleAllocation(A, targetLayer = hd30),691 SingleAllocation(B, targetLayer = ld30),692 SingleAllocation(C, targetLayer = ld30),693 SingleAllocation(D, targetLayer = ld15)694 )695 )696 ),697 Event(698 2460.kbps,699 BandwidthAllocation(700 setOf(701 SingleAllocation(A, targetLayer = hd30),702 SingleAllocation(B, targetLayer = ld30),703 SingleAllocation(C, targetLayer = ld30),704 SingleAllocation(D, targetLayer = ld30)705 )706 )707 )708 )709 }710 private fun verifyLastN0() {711 // No video forwarded even with high BWE.712 bc.forwardedSourcesHistory.size shouldBe 0713 bc.effectiveConstraintsHistory.last().event shouldBe mapOf(714 "A-v0" to VideoConstraints(0),715 "B-v0" to VideoConstraints(0),716 "C-v0" to VideoConstraints(0),717 "D-v0" to VideoConstraints(0)718 )719 // TODO: The history contains 3 identical elements, which is probably a bug.720 bc.allocationHistory.last().event.shouldMatch(721 BandwidthAllocation(722 setOf(723 SingleAllocation(A, targetLayer = noVideo),724 SingleAllocation(B, targetLayer = noVideo),725 SingleAllocation(C, targetLayer = noVideo),726 SingleAllocation(D, targetLayer = noVideo)727 )728 )729 )730 }731 private fun verifyStageViewLastN1() {732 // At this stage the purpose of this is just to document current behavior.733 // TODO: The results with bwe==-1 are wrong.734 bc.forwardedSourcesHistory.removeIf { it.bwe < 0.bps }735 bc.forwardedSourcesHistory.map { it.event }.shouldContainInOrder(736 setOf("A-v0")737 )738 bc.effectiveConstraintsHistory.last().event shouldBe mapOf(739 "A-v0" to VideoConstraints(720),740 "B-v0" to VideoConstraints(0),741 "C-v0" to VideoConstraints(0),742 "D-v0" to VideoConstraints(0)743 )744 // At this stage the purpose of this is just to document current behavior.745 // TODO: the allocations for bwe=-1 are wrong.746 bc.allocationHistory.removeIf { it.bwe < 0.bps }747 bc.allocationHistory.shouldMatchInOrder(748 Event(749 50.kbps,750 BandwidthAllocation(751 setOf(752 SingleAllocation(A, targetLayer = ld7_5),753 SingleAllocation(B, targetLayer = noVideo),754 SingleAllocation(C, targetLayer = noVideo),755 SingleAllocation(D, targetLayer = noVideo)756 )757 )758 ),759 Event(760 100.kbps,761 BandwidthAllocation(762 setOf(763 SingleAllocation(A, targetLayer = ld15),764 SingleAllocation(B, targetLayer = noVideo),765 SingleAllocation(C, targetLayer = noVideo),766 SingleAllocation(D, targetLayer = noVideo)767 )768 )769 ),770 Event(771 150.kbps,772 BandwidthAllocation(773 setOf(774 SingleAllocation(A, targetLayer = ld30),775 SingleAllocation(B, targetLayer = noVideo),776 SingleAllocation(C, targetLayer = noVideo),777 SingleAllocation(D, targetLayer = noVideo)778 )779 )780 ),781 Event(782 500.kbps,783 BandwidthAllocation(784 setOf(785 SingleAllocation(A, targetLayer = sd30),786 SingleAllocation(B, targetLayer = noVideo),787 SingleAllocation(C, targetLayer = noVideo),788 SingleAllocation(D, targetLayer = noVideo)789 )790 )791 ),792 Event(793 2010.kbps,794 BandwidthAllocation(795 setOf(796 SingleAllocation(A, targetLayer = hd30),797 SingleAllocation(B, targetLayer = noVideo),798 SingleAllocation(C, targetLayer = noVideo),799 SingleAllocation(D, targetLayer = noVideo)800 )801 )802 )803 )804 }805 private fun verifyTileView() {806 // At this stage the purpose of this is just to document current behavior.807 // TODO: The results with bwe==-1 are wrong.808 bc.forwardedSourcesHistory.removeIf { it.bwe < 0.bps }809 bc.forwardedSourcesHistory.map { it.event }.shouldContainInOrder(810 setOf("A-v0"),811 setOf("A-v0", "B-v0"),812 setOf("A-v0", "B-v0", "C-v0"),813 setOf("A-v0", "B-v0", "C-v0", "D-v0")814 )815 bc.allocationHistory.shouldMatchInOrder(816 Event(817 (-1).bps,818 BandwidthAllocation(819 setOf(820 SingleAllocation(A, targetLayer = noVideo),821 SingleAllocation(B, targetLayer = noVideo),822 SingleAllocation(C, targetLayer = noVideo),823 SingleAllocation(D, targetLayer = noVideo)824 )825 )826 ),827 Event(828 50.kbps,829 BandwidthAllocation(830 setOf(831 SingleAllocation(A, targetLayer = ld7_5),832 SingleAllocation(B, targetLayer = noVideo),833 SingleAllocation(C, targetLayer = noVideo),834 SingleAllocation(D, targetLayer = noVideo)835 )836 )837 ),838 Event(839 100.kbps,840 BandwidthAllocation(841 setOf(842 SingleAllocation(A, targetLayer = ld7_5),843 SingleAllocation(B, targetLayer = ld7_5),844 SingleAllocation(C, targetLayer = noVideo),845 SingleAllocation(D, targetLayer = noVideo)846 )847 )848 ),849 Event(850 150.kbps,851 BandwidthAllocation(852 setOf(853 SingleAllocation(A, targetLayer = ld7_5),854 SingleAllocation(B, targetLayer = ld7_5),855 SingleAllocation(C, targetLayer = ld7_5),856 SingleAllocation(D, targetLayer = noVideo)857 )858 )859 ),860 Event(861 200.kbps,862 BandwidthAllocation(863 setOf(864 SingleAllocation(A, targetLayer = ld7_5),865 SingleAllocation(B, targetLayer = ld7_5),866 SingleAllocation(C, targetLayer = ld7_5),867 SingleAllocation(D, targetLayer = ld7_5)868 )869 )870 ),871 Event(872 250.kbps,873 BandwidthAllocation(874 setOf(875 SingleAllocation(A, targetLayer = ld15),876 SingleAllocation(B, targetLayer = ld7_5),877 SingleAllocation(C, targetLayer = ld7_5),878 SingleAllocation(D, targetLayer = ld7_5)879 )880 )881 ),882 Event(883 300.kbps,884 BandwidthAllocation(885 setOf(886 SingleAllocation(A, targetLayer = ld15),887 SingleAllocation(B, targetLayer = ld15),888 SingleAllocation(C, targetLayer = ld7_5),889 SingleAllocation(D, targetLayer = ld7_5)890 )891 )892 ),893 Event(894 350.kbps,895 BandwidthAllocation(896 setOf(897 SingleAllocation(A, targetLayer = ld15),898 SingleAllocation(B, targetLayer = ld15),899 SingleAllocation(C, targetLayer = ld15),900 SingleAllocation(D, targetLayer = ld7_5)901 )902 )903 ),904 Event(905 400.kbps,906 BandwidthAllocation(907 setOf(908 SingleAllocation(A, targetLayer = ld15),909 SingleAllocation(B, targetLayer = ld15),910 SingleAllocation(C, targetLayer = ld15),911 SingleAllocation(D, targetLayer = ld15)912 )913 )914 ),915 Event(916 450.kbps,917 BandwidthAllocation(918 setOf(919 SingleAllocation(A, targetLayer = ld30),920 SingleAllocation(B, targetLayer = ld15),921 SingleAllocation(C, targetLayer = ld15),922 SingleAllocation(D, targetLayer = ld15)923 )924 )925 ),926 Event(927 500.kbps,928 BandwidthAllocation(929 setOf(930 SingleAllocation(A, targetLayer = ld30),931 SingleAllocation(B, targetLayer = ld30),932 SingleAllocation(C, targetLayer = ld15),933 SingleAllocation(D, targetLayer = ld15)934 )935 )936 ),937 Event(938 550.kbps,939 BandwidthAllocation(940 setOf(941 SingleAllocation(A, targetLayer = ld30),942 SingleAllocation(B, targetLayer = ld30),943 SingleAllocation(C, targetLayer = ld30),944 SingleAllocation(D, targetLayer = ld15)945 )946 )947 ),948 Event(949 610.kbps,950 BandwidthAllocation(951 setOf(952 SingleAllocation(A, targetLayer = ld30),953 SingleAllocation(B, targetLayer = ld30),954 SingleAllocation(C, targetLayer = ld30),955 SingleAllocation(D, targetLayer = ld30)956 )957 )958 )959 )960 }961 private fun verifyTileView360p() {962 // At this stage the purpose of this is just to document current behavior.963 // TODO: The results with bwe==-1 are wrong.964 bc.forwardedSourcesHistory.removeIf { it.bwe < 0.bps }965 bc.forwardedSourcesHistory.map { it.event }.shouldContainInOrder(966 setOf("A-v0"),967 setOf("A-v0", "B-v0"),968 setOf("A-v0", "B-v0", "C-v0"),969 setOf("A-v0", "B-v0", "C-v0", "D-v0")970 )971 bc.allocationHistory.shouldMatchInOrder(972 Event(973 (-1).bps,974 BandwidthAllocation(975 setOf(976 SingleAllocation(A, targetLayer = noVideo),977 SingleAllocation(B, targetLayer = noVideo),978 SingleAllocation(C, targetLayer = noVideo),979 SingleAllocation(D, targetLayer = noVideo)980 )981 )982 ),983 Event(984 50.kbps,985 BandwidthAllocation(986 setOf(987 SingleAllocation(A, targetLayer = ld7_5),988 SingleAllocation(B, targetLayer = noVideo),989 SingleAllocation(C, targetLayer = noVideo),990 SingleAllocation(D, targetLayer = noVideo)991 ),992 oversending = false993 )994 ),995 Event(996 100.kbps,997 BandwidthAllocation(998 setOf(999 SingleAllocation(A, targetLayer = ld7_5),1000 SingleAllocation(B, targetLayer = ld7_5),1001 SingleAllocation(C, targetLayer = noVideo),1002 SingleAllocation(D, targetLayer = noVideo)1003 )1004 )1005 ),1006 Event(1007 150.kbps,1008 BandwidthAllocation(1009 setOf(1010 SingleAllocation(A, targetLayer = ld7_5),1011 SingleAllocation(B, targetLayer = ld7_5),1012 SingleAllocation(C, targetLayer = ld7_5),1013 SingleAllocation(D, targetLayer = noVideo)1014 )1015 )1016 ),1017 Event(1018 200.kbps,1019 BandwidthAllocation(1020 setOf(1021 SingleAllocation(A, targetLayer = ld7_5),1022 SingleAllocation(B, targetLayer = ld7_5),1023 SingleAllocation(C, targetLayer = ld7_5),1024 SingleAllocation(D, targetLayer = ld7_5)1025 )1026 )1027 ),1028 Event(1029 250.kbps,1030 BandwidthAllocation(1031 setOf(1032 SingleAllocation(A, targetLayer = ld15),1033 SingleAllocation(B, targetLayer = ld7_5),1034 SingleAllocation(C, targetLayer = ld7_5),1035 SingleAllocation(D, targetLayer = ld7_5)1036 )1037 )1038 ),1039 Event(1040 300.kbps,1041 BandwidthAllocation(1042 setOf(1043 SingleAllocation(A, targetLayer = ld15),1044 SingleAllocation(B, targetLayer = ld15),1045 SingleAllocation(C, targetLayer = ld7_5),1046 SingleAllocation(D, targetLayer = ld7_5)1047 )1048 )1049 ),1050 Event(1051 350.kbps,1052 BandwidthAllocation(1053 setOf(1054 SingleAllocation(A, targetLayer = ld15),1055 SingleAllocation(B, targetLayer = ld15),1056 SingleAllocation(C, targetLayer = ld15),1057 SingleAllocation(D, targetLayer = ld7_5)1058 )1059 )1060 ),1061 Event(1062 400.kbps,1063 BandwidthAllocation(1064 setOf(1065 SingleAllocation(A, targetLayer = ld15),1066 SingleAllocation(B, targetLayer = ld15),1067 SingleAllocation(C, targetLayer = ld15),1068 SingleAllocation(D, targetLayer = ld15)1069 )1070 )1071 ),1072 Event(1073 450.kbps,1074 BandwidthAllocation(1075 setOf(1076 SingleAllocation(A, targetLayer = ld30),1077 SingleAllocation(B, targetLayer = ld15),1078 SingleAllocation(C, targetLayer = ld15),1079 SingleAllocation(D, targetLayer = ld15)1080 )1081 )1082 ),1083 Event(1084 500.kbps,1085 BandwidthAllocation(1086 setOf(1087 SingleAllocation(A, targetLayer = ld30),1088 SingleAllocation(B, targetLayer = ld30),1089 SingleAllocation(C, targetLayer = ld15),1090 SingleAllocation(D, targetLayer = ld15)1091 )1092 )1093 ),1094 Event(1095 550.kbps,1096 BandwidthAllocation(1097 setOf(1098 SingleAllocation(A, targetLayer = ld30),1099 SingleAllocation(B, targetLayer = ld30),1100 SingleAllocation(C, targetLayer = ld30),1101 SingleAllocation(D, targetLayer = ld15)1102 )1103 )1104 ),1105 Event(1106 610.kbps,1107 BandwidthAllocation(1108 setOf(1109 SingleAllocation(A, targetLayer = ld30),1110 SingleAllocation(B, targetLayer = ld30),1111 SingleAllocation(C, targetLayer = ld30),1112 SingleAllocation(D, targetLayer = ld30)1113 )1114 )1115 ),1116 Event(1117 960.kbps,1118 BandwidthAllocation(1119 setOf(1120 SingleAllocation(A, targetLayer = sd30),1121 SingleAllocation(B, targetLayer = ld30),1122 SingleAllocation(C, targetLayer = ld30),1123 SingleAllocation(D, targetLayer = ld30)1124 )1125 )1126 ),1127 Event(1128 1310.kbps,1129 BandwidthAllocation(1130 setOf(1131 SingleAllocation(A, targetLayer = sd30),1132 SingleAllocation(B, targetLayer = sd30),1133 SingleAllocation(C, targetLayer = ld30),1134 SingleAllocation(D, targetLayer = ld30)1135 )1136 )1137 ),1138 Event(1139 1660.kbps,1140 BandwidthAllocation(1141 setOf(1142 SingleAllocation(A, targetLayer = sd30),1143 SingleAllocation(B, targetLayer = sd30),1144 SingleAllocation(C, targetLayer = sd30),1145 SingleAllocation(D, targetLayer = ld30)1146 )1147 )1148 ),1149 Event(1150 2010.kbps,1151 BandwidthAllocation(1152 setOf(1153 SingleAllocation(A, targetLayer = sd30),1154 SingleAllocation(B, targetLayer = sd30),1155 SingleAllocation(C, targetLayer = sd30),1156 SingleAllocation(D, targetLayer = sd30)1157 )1158 )1159 )1160 )1161 }1162 private fun verifyTileViewLastN1(maxFrameHeight: Int = 180) {1163 // At this stage the purpose of this is just to document current behavior.1164 // TODO: The results with bwe==-1 are wrong.1165 bc.forwardedSourcesHistory.removeIf { it.bwe < 0.bps }1166 bc.forwardedSourcesHistory.map { it.event }.shouldContainInOrder(1167 setOf("A-v0")1168 )1169 bc.effectiveConstraintsHistory.last().event shouldBe mapOf(1170 "A-v0" to VideoConstraints(maxFrameHeight),1171 "B-v0" to VideoConstraints(0),1172 "C-v0" to VideoConstraints(0),1173 "D-v0" to VideoConstraints(0)1174 )1175 val expectedAllocationHistory = mutableListOf(1176 // TODO: do we want to oversend in tile view?1177 Event(1178 (-1).bps,1179 BandwidthAllocation(1180 setOf(1181 SingleAllocation(A, targetLayer = noVideo),1182 SingleAllocation(B, targetLayer = noVideo),1183 SingleAllocation(C, targetLayer = noVideo),1184 SingleAllocation(D, targetLayer = noVideo)1185 ),1186 oversending = true1187 )1188 ),1189 Event(1190 50.kbps,1191 BandwidthAllocation(1192 setOf(1193 SingleAllocation(A, targetLayer = ld7_5),1194 SingleAllocation(B, targetLayer = noVideo),1195 SingleAllocation(C, targetLayer = noVideo),1196 SingleAllocation(D, targetLayer = noVideo)1197 )1198 )1199 ),1200 Event(1201 100.kbps,1202 BandwidthAllocation(1203 setOf(1204 SingleAllocation(A, targetLayer = ld15),1205 SingleAllocation(B, targetLayer = noVideo),1206 SingleAllocation(C, targetLayer = noVideo),1207 SingleAllocation(D, targetLayer = noVideo)1208 )1209 )1210 ),1211 Event(1212 160.kbps, // TODO: why 160 instead of 150? weird.1213 BandwidthAllocation(1214 setOf(1215 SingleAllocation(A, targetLayer = ld30),1216 SingleAllocation(B, targetLayer = noVideo),1217 SingleAllocation(C, targetLayer = noVideo),1218 SingleAllocation(D, targetLayer = noVideo)1219 )1220 )1221 )1222 )1223 if (maxFrameHeight > 180) {1224 expectedAllocationHistory.addAll(1225 listOf(1226 Event(1227 510.kbps,1228 BandwidthAllocation(1229 setOf(1230 SingleAllocation(A, targetLayer = sd30),1231 SingleAllocation(B, targetLayer = noVideo),1232 SingleAllocation(C, targetLayer = noVideo),1233 SingleAllocation(D, targetLayer = noVideo)1234 )1235 )1236 )1237 )1238 )1239 }1240 bc.allocationHistory.shouldMatchInOrder(*expectedAllocationHistory.toTypedArray())1241 }1242}1243class BitrateControllerWrapper2(initialEndpoints: List<MediaSourceContainer>, val clock: FakeClock = FakeClock()) {1244 var endpoints: List<MediaSourceContainer> = initialEndpoints1245 val logger = createLogger()1246 var bwe = (-1).bps1247 set(value) {1248 logger.debug("Setting bwe=$value")1249 field = value1250 bc.bandwidthChanged(value.bps.toLong())1251 }1252 // Save the output.1253 val effectiveConstraintsHistory: History<Map<String, VideoConstraints>> = mutableListOf()1254 val forwardedSourcesHistory: History<Set<String>> = mutableListOf()1255 val allocationHistory: History<BandwidthAllocation> = mutableListOf()1256 val bc = BitrateController(1257 object : BitrateController.EventHandler {1258 override fun forwardedEndpointsChanged(forwardedEndpoints: Set<String>) { }1259 override fun forwardedSourcesChanged(forwardedSources: Set<String>) {1260 Event(bwe, forwardedSources, clock.instant()).apply {1261 logger.info("Forwarded sources changed: $this")1262 forwardedSourcesHistory.add(this)1263 }1264 }1265 override fun effectiveVideoConstraintsChanged(1266 oldEffectiveConstraints: Map<String, VideoConstraints>,1267 newEffectiveConstraints: Map<String, VideoConstraints>1268 ) {1269 Event(bwe, newEffectiveConstraints, clock.instant()).apply {1270 logger.info("Effective constraints changed: $this")1271 effectiveConstraintsHistory.add(this)1272 }1273 }1274 override fun keyframeNeeded(endpointId: String?, ssrc: Long) {}1275 override fun allocationChanged(allocation: BandwidthAllocation) {1276 Event(1277 bwe,1278 allocation,1279 clock.instant()1280 ).apply {1281 logger.info("Allocation changed: $this")1282 allocationHistory.add(this)1283 }1284 }1285 },1286 Supplier { endpoints },1287 DiagnosticContext(),1288 logger,1289 true, // TODO merge BitrateControllerNewTest with old and use this flag1290 clock1291 )1292 fun setEndpointOrdering(vararg endpoints: TestEndpoint2) {1293 logger.info("Set endpoints ${endpoints.map{ it.id }.joinToString(",")}")1294 this.endpoints = endpoints.toList()1295 bc.endpointOrderingChanged()1296 }1297 fun setStageView(onStageSource: String, lastN: Int? = null) {1298 bc.setBandwidthAllocationSettings(1299 ReceiverVideoConstraintsMessage(1300 lastN = lastN,1301 onStageSources = listOf(onStageSource),1302 constraints = mapOf(onStageSource to VideoConstraints(720))1303 )1304 )1305 }1306 fun setTileView(1307 vararg selectedSources: String,1308 maxFrameHeight: Int = 180,1309 lastN: Int? = null1310 ) {1311 bc.setBandwidthAllocationSettings(1312 ReceiverVideoConstraintsMessage(1313 lastN = lastN,1314 selectedSources = listOf(*selectedSources),1315 constraints = selectedSources.map { it to VideoConstraints(maxFrameHeight) }.toMap()1316 )1317 )1318 }1319 init {1320 // The BC only starts working 10 seconds after it first received media, so fake that.1321 bc.transformRtp(PacketInfo(VideoRtpPacket(ByteArray(100), 0, 100)))1322 clock.elapse(15.secs)1323 // Adaptivity is disabled when RTX support is not signalled.1324 bc.addPayloadType(RtxPayloadType(123, mapOf("apt" to "124")))1325 }1326}1327class TestEndpoint2(1328 override val id: String,1329 override val mediaSources: Array<MediaSourceDesc> = emptyArray(),1330 override val videoType: VideoType = VideoType.CAMERA,1331 override val mediaSource: MediaSourceDesc? = null,1332) : MediaSourceContainer1333fun createEndpoints2(vararg ids: String): MutableList<TestEndpoint2> {1334 return MutableList(ids.size) { i ->1335 TestEndpoint2(1336 ids[i],1337 arrayOf(1338 createSourceDesc(1339 3 * i + 1,1340 3 * i + 2,1341 3 * i + 3,1342 ids[i] + "-v0",1343 ids[i]1344 )1345 )1346 )1347 }1348}1349fun createSources(vararg ids: String): MutableList<MediaSourceDesc> {1350 return MutableList(ids.size) { i ->1351 createSourceDesc(1352 3 * i + 1,1353 3 * i + 2,1354 3 * i + 3,1355 ids[i],1356 null1357 )1358 }1359}1360fun createSourceDesc(1361 ssrc1: Int,1362 ssrc2: Int,1363 ssrc3: Int,1364 sourceName: String,1365 owner: String?1366): MediaSourceDesc = MediaSourceDesc(1367 arrayOf(1368 RtpEncodingDesc(ssrc1.toLong(), arrayOf(ld7_5, ld15, ld30)),1369 RtpEncodingDesc(ssrc2.toLong(), arrayOf(sd7_5, sd15, sd30)),1370 RtpEncodingDesc(ssrc3.toLong(), arrayOf(hd7_5, hd15, hd30))1371 ),1372 sourceName = sourceName,1373 owner = owner1374)...

Full Screen

Full Screen

CollectionMatchersTest.kt

Source:CollectionMatchersTest.kt Github

copy

Full Screen

1package com.sksamuel.kotest.matchers.collections2import io.kotest.assertions.shouldFail3import io.kotest.assertions.throwables.shouldNotThrow4import io.kotest.assertions.throwables.shouldThrow5import io.kotest.assertions.withClue6import io.kotest.core.spec.style.WordSpec7import io.kotest.equals.Equality8import io.kotest.equals.types.byObjectEquality9import io.kotest.matchers.collections.atLeastSize10import io.kotest.matchers.collections.atMostSize11import io.kotest.matchers.collections.beLargerThan12import io.kotest.matchers.collections.beSameSizeAs13import io.kotest.matchers.collections.beSmallerThan14import io.kotest.matchers.collections.contain15import io.kotest.matchers.collections.containDuplicates16import io.kotest.matchers.collections.containNoNulls17import io.kotest.matchers.collections.containNull18import io.kotest.matchers.collections.containOnlyNulls19import io.kotest.matchers.collections.matchInOrder20import io.kotest.matchers.collections.existInOrder21import io.kotest.matchers.collections.haveElementAt22import io.kotest.matchers.collections.haveSize23import io.kotest.matchers.collections.matchEach24import io.kotest.matchers.collections.matchInOrderSubset25import io.kotest.matchers.collections.monotonicallyDecreasing26import io.kotest.matchers.collections.monotonicallyDecreasingWith27import io.kotest.matchers.collections.monotonicallyIncreasing28import io.kotest.matchers.collections.monotonicallyIncreasingWith29import io.kotest.matchers.collections.shouldBeIn30import io.kotest.matchers.collections.shouldBeLargerThan31import io.kotest.matchers.collections.shouldBeMonotonicallyDecreasing32import io.kotest.matchers.collections.shouldBeMonotonicallyDecreasingWith33import io.kotest.matchers.collections.shouldBeMonotonicallyIncreasing34import io.kotest.matchers.collections.shouldBeMonotonicallyIncreasingWith35import io.kotest.matchers.collections.shouldBeSameSizeAs36import io.kotest.matchers.collections.shouldBeSingleton37import io.kotest.matchers.collections.shouldBeSmallerThan38import io.kotest.matchers.collections.shouldBeSorted39import io.kotest.matchers.collections.shouldBeSortedBy40import io.kotest.matchers.collections.shouldBeSortedWith41import io.kotest.matchers.collections.shouldBeStrictlyDecreasing42import io.kotest.matchers.collections.shouldBeStrictlyDecreasingWith43import io.kotest.matchers.collections.shouldBeStrictlyIncreasing44import io.kotest.matchers.collections.shouldBeStrictlyIncreasingWith45import io.kotest.matchers.collections.shouldContainAnyOf46import io.kotest.matchers.collections.shouldContainDuplicates47import io.kotest.matchers.collections.shouldContainNoNulls48import io.kotest.matchers.collections.shouldContainNull49import io.kotest.matchers.collections.shouldContainOnlyNulls50import io.kotest.matchers.collections.shouldExist51import io.kotest.matchers.collections.shouldHaveAtLeastSize52import io.kotest.matchers.collections.shouldHaveAtMostSize53import io.kotest.matchers.collections.shouldHaveElementAt54import io.kotest.matchers.collections.shouldHaveSingleElement55import io.kotest.matchers.collections.shouldHaveSize56import io.kotest.matchers.collections.shouldMatchInOrder57import io.kotest.matchers.collections.shouldMatchInOrderSubset58import io.kotest.matchers.collections.shouldNotBeIn59import io.kotest.matchers.collections.shouldNotBeMonotonicallyDecreasing60import io.kotest.matchers.collections.shouldNotBeMonotonicallyDecreasingWith61import io.kotest.matchers.collections.shouldNotBeMonotonicallyIncreasing62import io.kotest.matchers.collections.shouldNotBeMonotonicallyIncreasingWith63import io.kotest.matchers.collections.shouldNotBeSingleton64import io.kotest.matchers.collections.shouldNotBeSorted65import io.kotest.matchers.collections.shouldNotBeSortedBy66import io.kotest.matchers.collections.shouldNotBeSortedWith67import io.kotest.matchers.collections.shouldNotBeStrictlyDecreasing68import io.kotest.matchers.collections.shouldNotBeStrictlyDecreasingWith69import io.kotest.matchers.collections.shouldNotBeStrictlyIncreasing70import io.kotest.matchers.collections.shouldNotBeStrictlyIncreasingWith71import io.kotest.matchers.collections.shouldNotContainAnyOf72import io.kotest.matchers.collections.shouldNotContainDuplicates73import io.kotest.matchers.collections.shouldNotContainNoNulls74import io.kotest.matchers.collections.shouldNotContainNull75import io.kotest.matchers.collections.shouldNotContainOnlyNulls76import io.kotest.matchers.collections.shouldNotHaveElementAt77import io.kotest.matchers.collections.shouldNotHaveSize78import io.kotest.matchers.collections.shouldNotMatchEach79import io.kotest.matchers.collections.shouldNotMatchInOrder80import io.kotest.matchers.collections.shouldNotMatchInOrderSubset81import io.kotest.matchers.collections.singleElement82import io.kotest.matchers.collections.sorted83import io.kotest.matchers.collections.strictlyDecreasing84import io.kotest.matchers.collections.strictlyDecreasingWith85import io.kotest.matchers.collections.strictlyIncreasing86import io.kotest.matchers.collections.strictlyIncreasingWith87import io.kotest.matchers.ints.shouldBeGreaterThan88import io.kotest.matchers.ints.shouldBeInRange89import io.kotest.matchers.should90import io.kotest.matchers.shouldBe91import io.kotest.matchers.shouldHave92import io.kotest.matchers.shouldNot93import io.kotest.matchers.shouldNotBe94import io.kotest.matchers.shouldNotHave95import io.kotest.matchers.throwable.shouldHaveMessage96class CollectionMatchersTest : WordSpec() {97 private val countdown = (10 downTo 0).toList()98 private val asc = { a: Int, b: Int -> a - b }99 private val desc = { a: Int, b: Int -> b - a }100 init {101 "a descending non-empty list" should {102 "fail to ascend" {103 shouldFail {104 countdown.shouldBeSortedWith(asc)105 }106 }107 "descend" {108 countdown.shouldBeSortedWith(desc)109 }110 "not ascend" {111 countdown.shouldNotBeSortedWith(asc)112 }113 "fail not to descend" {114 shouldFail {115 countdown.shouldNotBeSortedWith(desc)116 }117 }118 }119 "sortedWith" should {120 val items = listOf(121 1 to "I",122 2 to "II",123 4 to "IV",124 5 to "V",125 6 to "VI",126 9 to "IX",127 10 to "X"128 )129 "work on non-Comparable given a Comparator" {130 items.shouldBeSortedWith(Comparator { a, b -> asc(a.first, b.first) })131 }132 "work on non-Comparable given a compare function" {133 items.shouldBeSortedWith { a, b -> asc(a.first, b.first) }134 }135 }136 "haveElementAt" should {137 "test that a collection contains the specified element at the given index" {138 listOf("a", "b", "c") should haveElementAt(1, "b")139 listOf("a", "b", "c") shouldNot haveElementAt(1, "c")140 listOf("a", "b", null) should haveElementAt(2, null)141 listOf("a", "b", null) shouldNot haveElementAt(3, null)142 listOf("a", "b", "c").shouldHaveElementAt(1, "b")143 listOf("a", "b", "c").shouldNotHaveElementAt(1, "c")144 listOf("a", "b", null).shouldHaveElementAt(2, null)145 }146 "support type inference for subtypes of collection" {147 val tests = listOf(148 TestSealed.Test1("test1"),149 TestSealed.Test2(2)150 )151 tests should haveElementAt(0, TestSealed.Test1("test1"))152 tests.shouldHaveElementAt(1, TestSealed.Test2(2))153 }154 }155 "containNull()" should {156 "test that a collection contains at least one null" {157 listOf(1, 2, null) should containNull()158 listOf(null) should containNull()159 listOf(1, 2) shouldNot containNull()160 listOf(1, 2, null).shouldContainNull()161 listOf(null).shouldContainNull()162 listOf(1, 2).shouldNotContainNull()163 }164 }165 "sorted" should {166 "test that a collection is sorted" {167 emptyList<Int>() shouldBe sorted<Int>()168 listOf(1) shouldBe sorted<Int>()169 listOf(1, 2, 3, 4) shouldBe sorted<Int>()170 shouldThrow<AssertionError> {171 listOf(2, 1) shouldBe sorted<Int>()172 }.shouldHaveMessage("List [2, 1] should be sorted. Element 2 at index 0 was greater than element 1")173 listOf(1, 2, 6, 9).shouldBeSorted()174 shouldThrow<AssertionError> {175 listOf(2, 1).shouldBeSorted()176 }.shouldHaveMessage("List [2, 1] should be sorted. Element 2 at index 0 was greater than element 1")177 shouldThrow<AssertionError> {178 listOf(1, 2, 3).shouldNotBeSorted()179 }.shouldHaveMessage("List [1, 2, 3] should not be sorted")180 }181 "restrict items at the error message" {182 val longList = (1..1000).toList()183 shouldThrow<AssertionError> {184 longList.shouldNotBeSorted()185 }.shouldHaveMessage("List [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...and 980 more (set the 'kotest.assertions.collection.print.size' JVM property to see more / less items)] should not be sorted")186 }187 }188 "sortedBy" should {189 val items = listOf(190 1 to "I",191 2 to "II",192 4 to "IV",193 5 to "V",194 6 to "VI",195 9 to "IX",196 10 to "X"197 )198 "compare by the tranformed value" {199 items.shouldBeSortedBy { it.first }200 items.shouldNotBeSortedBy { it.second }201 }202 }203 "shouldBeIncreasing" should {204 "test that a collection is monotonically increasing" {205 listOf(1, 2, 2, 3) shouldBe monotonicallyIncreasing<Int>()206 listOf(6, 5) shouldNotBe monotonicallyIncreasing<Int>()207 listOf(1, 2, 2, 3).shouldBeMonotonicallyIncreasing()208 listOf(6, 5).shouldNotBeMonotonicallyIncreasing()209 }210 "test that a collection is monotonically increasing according to comparator" {211 val comparator = Comparator(desc)212 listOf(3, 2, 2, 1) shouldBe monotonicallyIncreasingWith(comparator)213 listOf(5, 6) shouldNotBe monotonicallyIncreasingWith(comparator)214 listOf(3, 2, 2, 1).shouldBeMonotonicallyIncreasingWith(comparator)215 listOf(5, 6).shouldNotBeMonotonicallyIncreasingWith(comparator)216 }217 "test that a collection is strictly increasing" {218 listOf(1, 2, 3) shouldBe strictlyIncreasing<Int>()219 listOf(1, 2, 2, 3) shouldNotBe strictlyIncreasing<Int>()220 listOf(6, 5) shouldNotBe strictlyIncreasing<Int>()221 listOf(1, 2, 3).shouldBeStrictlyIncreasing()222 listOf(1, 2, 2, 3).shouldNotBeStrictlyIncreasing()223 listOf(6, 5).shouldNotBeStrictlyIncreasing()224 }225 "test that a collection is strictly increasing according to comparator" {226 val comparator = Comparator(desc)227 listOf(3, 2, 1) shouldBe strictlyIncreasingWith(comparator)228 listOf(3, 2, 2, 1) shouldNotBe strictlyIncreasingWith(comparator)229 listOf(5, 6) shouldNotBe strictlyIncreasingWith(comparator)230 listOf(3, 2, 1).shouldBeStrictlyIncreasingWith(comparator)231 listOf(3, 2, 2, 1).shouldNotBeStrictlyIncreasingWith(comparator)232 listOf(5, 6).shouldNotBeStrictlyIncreasingWith(comparator)233 }234 }235 "shouldBeDecreasing" should {236 "test that a collection is monotonically decreasing" {237 listOf(3, 2, 2, -4) shouldBe monotonicallyDecreasing<Int>()238 listOf(5, 6) shouldNotBe monotonicallyDecreasing<Int>()239 listOf(3, 2, 2, -4).shouldBeMonotonicallyDecreasing()240 listOf(5, 6).shouldNotBeMonotonicallyDecreasing()241 }242 "test that a collection is monotonically decreasing according to comparator" {243 val comparator = Comparator(desc)244 listOf(-4, 2, 2, 3) shouldBe monotonicallyDecreasingWith(comparator)245 listOf(6, 5) shouldNotBe monotonicallyDecreasingWith(comparator)246 listOf(-4, 2, 2, 3).shouldBeMonotonicallyDecreasingWith(comparator)247 listOf(6, 5).shouldNotBeMonotonicallyDecreasingWith(comparator)248 }249 "test that a collection is strictly decreasing" {250 listOf(3, 2, -4) shouldBe strictlyDecreasing<Int>()251 listOf(3, 2, 2, -4) shouldNotBe strictlyDecreasing<Int>()252 listOf(5, 6) shouldNotBe strictlyDecreasing<Int>()253 listOf(3, 2, -4).shouldBeStrictlyDecreasing()254 listOf(3, 2, 2, -4).shouldNotBeStrictlyDecreasing()255 listOf(5, 6).shouldNotBeStrictlyDecreasing()256 }257 "test that a collection is strictly decreasing according to comparator" {258 val comparator = Comparator(desc)259 listOf(-4, 2, 3) shouldBe strictlyDecreasingWith(comparator)260 listOf(-4, 2, 2, 3) shouldNotBe strictlyDecreasingWith(comparator)261 listOf(6, 5) shouldNotBe strictlyDecreasingWith(comparator)262 listOf(-4, 2, 3).shouldBeStrictlyDecreasingWith(comparator)263 listOf(-4, 2, 2, 3).shouldNotBeStrictlyDecreasingWith(comparator)264 listOf(6, 5).shouldNotBeStrictlyDecreasingWith(comparator)265 }266 }267 "haveDuplicates" should {268 "test that a collection is unique" {269 listOf(1, 2, 3, 3) should containDuplicates()270 listOf(1, 2, 3, 4) shouldNot containDuplicates()271 listOf(1, 2, 3, 3).shouldContainDuplicates()272 listOf(1, 2, 3, 4).shouldNotContainDuplicates()273 }274 }275 "singleElement" should {276 "test that a collection contains a single given element" {277 listOf(1) shouldBe singleElement(1)278 listOf(1).shouldHaveSingleElement(1)279 shouldThrow<AssertionError> {280 listOf(1) shouldBe singleElement(2)281 }.shouldHaveMessage("Collection should be a single element of 2 but has 1 elements: [1]")282 shouldThrow<AssertionError> {283 listOf(1, 2) shouldBe singleElement(2)284 }.shouldHaveMessage("Collection should be a single element of 2 but has 2 elements: [1, 2]")285 }286 }287 "singleElement with predicate" should {288 "test that a collection contains a single element by given predicate" {289 listOf(1) shouldHave singleElement { e -> e == 1 }290 listOf(1).shouldHaveSingleElement { e -> e == 1 }291 shouldThrow<AssertionError> {292 listOf(1) shouldHave singleElement { e -> e == 2 }293 }.shouldHaveMessage("Collection should have a single element by a given predicate but has 0 elements: [1]")294 shouldThrow<AssertionError> {295 listOf(2, 2) shouldHave singleElement { e -> e == 2 }296 }.shouldHaveMessage("Collection should have a single element by a given predicate but has 2 elements: [2, 2]")297 }298 }299 "should contain element" should {300 "test that a collection contains an element" {301 val col = listOf(1, 2, 3)302 col should contain(2)303 col should contain(2.0) // uses strict num equality = false304 shouldThrow<AssertionError> {305 col should contain(4)306 }.shouldHaveMessage("Collection should contain element 4 based on object equality; but the collection is [1, 2, 3]")307 }308 }309 "should contain element based on a custom equality object" should {310 "test that a collection contains an element" {311 val col = listOf(1, 2, 3.0)312 val verifier = Equality.byObjectEquality<Number>(strictNumberEquality = true)313 col should contain(2, verifier)314 col should contain(3.0, verifier)315 shouldThrow<AssertionError> {316 col should contain(3, verifier)317 }.shouldHaveMessage("Collection should contain element 3 based on object equality; but the collection is [1, 2, 3.0]")318 }319 }320 "shouldBeLargerThan" should {321 "test that a collection is larger than another collection" {322 val col1 = listOf(1, 2, 3)323 val col2 = setOf(1, 2, 3, 4)324 col2.shouldBeLargerThan(col1)325 col2 should beLargerThan(col1)326 col1 shouldNot beLargerThan(col2)327 shouldThrow<AssertionError> {328 col1.shouldBeLargerThan(col2)329 }.shouldHaveMessage("Collection of size 3 should be larger than collection of size 4")330 }331 }332 "shouldBeSmallerThan" should {333 "test that a collection is smaller than another collection" {334 val col1 = listOf(1, 2, 3)335 val col2 = setOf(1, 2, 3, 4)336 col1.shouldBeSmallerThan(col2)337 col1 should beSmallerThan(col2)338 col2 shouldNot beSmallerThan(col1)339 shouldThrow<AssertionError> {340 col2.shouldBeSmallerThan(col1)341 }.shouldHaveMessage("Collection of size 4 should be smaller than collection of size 3")342 }343 }344 "shouldBeSameSizeAs" should {345 "test that a collection is the same size as another collection" {346 val col1 = listOf(1, 2, 3)347 val col2 = setOf(1, 2, 3)348 val col3 = listOf(1, 2, 3, 4)349 col1.shouldBeSameSizeAs(col2)350 col1 should beSameSizeAs(col2)351 col1 shouldNot beSameSizeAs(col3)352 shouldThrow<AssertionError> {353 col1.shouldBeSameSizeAs(col3)354 }.shouldHaveMessage("Collection of size 3 should be the same size as collection of size 4")355 }356 }357 "haveSize" should {358 "test that a collection has a certain size" {359 val col1 = listOf(1, 2, 3)360 col1 should haveSize(3)361 col1.shouldHaveSize(3)362 shouldThrow<AssertionError> {363 col1 should haveSize(2)364 }365 val col2 = emptyList<String>()366 col2 should haveSize(0)367 shouldThrow<AssertionError> {368 col2 should haveSize(1)369 }370 listOf(1, 2, 3).shouldNotHaveSize(1)371 listOf(1, 2, 3).shouldNotHaveSize(4)372 shouldThrow<AssertionError> {373 listOf(1, 2, 3).shouldNotHaveSize(3)374 }.shouldHaveMessage("Collection should not have size 3. Values: [1, 2, 3]")375 }376 }377 "should be singleton" should {378 "pass for collection with a single element" {379 listOf(1).shouldBeSingleton()380 }381 "fail for collection with 0 elements" {382 shouldThrow<AssertionError> {383 listOf<Int>().shouldBeSingleton()384 }.shouldHaveMessage("Collection should have size 1 but has size 0. Values: []")385 }386 "fail for collection with 2+ elements" {387 shouldThrow<AssertionError> {388 listOf(1, 2).shouldBeSingleton()389 }.shouldHaveMessage("Collection should have size 1 but has size 2. Values: [1, 2]")390 shouldThrow<AssertionError> {391 listOf(1, 2, 3, 4).shouldBeSingleton()392 }.shouldHaveMessage("Collection should have size 1 but has size 4. Values: [1, 2, 3, 4]")393 }394 }395 "should be singleton with block" should {396 "pass for collection with a single element" {397 listOf(1).shouldBeSingleton { it shouldBe 1 }398 }399 "fail for collection with 0 elements" {400 shouldThrow<AssertionError> {401 listOf<Int>().shouldBeSingleton { it shouldBe 1 }402 }.shouldHaveMessage("Collection should have size 1 but has size 0. Values: []")403 }404 "fail for collection with a single incorrect elements" {405 shouldThrow<AssertionError> {406 listOf(2).shouldBeSingleton { it shouldBe 1 }407 }.shouldHaveMessage("expected:<1> but was:<2>")408 }409 "fail for collection with 2+ elements" {410 shouldThrow<AssertionError> {411 listOf(1, 2).shouldBeSingleton { it shouldBe 1 }412 }.shouldHaveMessage("Collection should have size 1 but has size 2. Values: [1, 2]")413 shouldThrow<AssertionError> {414 listOf(1, 2, 3, 4).shouldBeSingleton { it shouldBe 1 }415 }.shouldHaveMessage("Collection should have size 1 but has size 4. Values: [1, 2, 3, 4]")416 }417 }418 "should not be singleton" should {419 "pass for collection with 0 elements" {420 listOf<Int>().shouldNotBeSingleton()421 }422 "pass for collection with 2+ elements" {423 listOf(1, 2).shouldNotBeSingleton()424 listOf(1, 2, 3, 4).shouldNotBeSingleton()425 }426 "fail for collection with a single element" {427 shouldThrow<AssertionError> {428 listOf(1).shouldNotBeSingleton()429 }.shouldHaveMessage("Collection should not have size 1. Values: [1]")430 }431 }432 "shouldExist" should {433 "test that a collection contains at least one element that matches a predicate" {434 val list = listOf(1, 2, 3)435 list.shouldExist { it == 2 }436 }437 }438 "shouldHaveAtLeastSize" should {439 "test that a collection has at least a certain number of elements" {440 val list = listOf(1, 2, 3)441 list.shouldHaveAtLeastSize(2)442 list shouldHave atLeastSize(2)443 val set = setOf(1, 2, 3)444 set.shouldHaveAtLeastSize(3)445 set shouldHave atLeastSize(3)446 shouldThrow<AssertionError> {447 list.shouldHaveAtLeastSize(4)448 }.shouldHaveMessage("Collection [1, 2, 3] should contain at least 4 elements")449 shouldThrow<AssertionError> {450 list shouldHave atLeastSize(4)451 }.shouldHaveMessage("Collection [1, 2, 3] should contain at least 4 elements")452 shouldThrow<AssertionError> {453 list shouldNotHave atLeastSize(2)454 }.shouldHaveMessage("Collection [1, 2, 3] should contain less than 2 elements")455 }456 }457 "shouldHaveAtMostSize" should {458 "test that a collection has at least a certain number of elements" {459 val list = listOf(1, 2, 3)460 list.shouldHaveAtMostSize(3)461 list shouldHave atMostSize(3)462 list.shouldHaveAtMostSize(4)463 list shouldHave atMostSize(4)464 val set = setOf(1, 2, 3)465 set.shouldHaveAtMostSize(3)466 set shouldHave atMostSize(3)467 set.shouldHaveAtMostSize(4)468 set shouldHave atMostSize(4)469 shouldThrow<AssertionError> {470 list.shouldHaveAtMostSize(2)471 }.shouldHaveMessage("Collection [1, 2, 3] should contain at most 2 elements")472 shouldThrow<AssertionError> {473 list shouldHave atMostSize(2)474 }.shouldHaveMessage("Collection [1, 2, 3] should contain at most 2 elements")475 shouldThrow<AssertionError> {476 list shouldNotHave atMostSize(4)477 }.shouldHaveMessage("Collection [1, 2, 3] should contain more than 4 elements")478 }479 }480 "containNoNulls" should {481 "test that a collection contains zero nulls" {482 emptyList<String>() should containNoNulls()483 listOf(1, 2, 3) should containNoNulls()484 listOf(null, null, null) shouldNot containNoNulls()485 listOf(1, null, null) shouldNot containNoNulls()486 emptyList<String>().shouldContainNoNulls()487 listOf(1, 2, 3).shouldContainNoNulls()488 listOf(null, null, null).shouldNotContainNoNulls()489 listOf(1, null, null).shouldNotContainNoNulls()490 shouldThrow<AssertionError> {491 listOf(null, null, null).shouldContainNoNulls()492 }.shouldHaveMessage("Collection should not contain nulls")493 shouldThrow<AssertionError> {494 listOf(1, 2, 3).shouldNotContainNoNulls()495 }.shouldHaveMessage("Collection should have at least one null")496 }497 "support type inference for subtypes of collection" {498 val tests = listOf(499 TestSealed.Test1("test1"),500 TestSealed.Test2(2)501 )502 tests should containNoNulls()503 tests.shouldContainNoNulls()504 }505 }506 "containOnlyNulls" should {507 "test that a collection contains only nulls" {508 emptyList<String>() should containOnlyNulls()509 listOf(null, null, null) should containOnlyNulls()510 listOf(1, null, null) shouldNot containOnlyNulls()511 listOf(1, 2, 3) shouldNot containOnlyNulls()512 listOf(null, 1, 2, 3).shouldNotContainOnlyNulls()513 listOf(1, 2, 3).shouldNotContainOnlyNulls()514 listOf(null, null, null).shouldContainOnlyNulls()515 }516 }517 "matchInOrder" should {518 "test that a collection matches the assertions in the given order, duplicates permitted" {519 withClue("Gaps not allowed") {520 shouldFail {521 listOf(1, 2, 2, 3) should matchInOrder(522 { it shouldBe 1 },523 { it shouldBe 2 },524 { it shouldBe 3 }525 )526 }527 }528 arrayOf(2, 2, 3).shouldMatchInOrder(529 { it shouldBe 2 },530 { it shouldBe 2 },531 { it shouldBe 3 },532 )533 }534 "failure shows best result" {535 shouldFail {536 listOf(1, 2, 3, 1, 2, 1, 2).shouldMatchInOrder(537 { it shouldBe 1 },538 { it shouldBe 2 },539 { it shouldBe 1 },540 { it shouldBe 3 },541 )542 }.message shouldBe """543 Expected a sequence of elements to pass the assertions, but failed to match all assertions544 Best result when comparing from index [3], where 3 elements passed, but the following elements failed:545 6 => expected:<3> but was:<2>546 """.trimIndent()547 }548 "Non existing element causes error" {549 shouldThrow<AssertionError> {550 listOf(1, 2, 3).shouldMatchInOrder(551 { it shouldBe 1 },552 { it shouldBe 2 },553 { it shouldBe 6 }554 )555 }556 }557 "out-of-order elements cause error" {558 shouldThrow<AssertionError> {559 listOf(1, 2, 3) should matchInOrder(560 { it shouldBe 2 },561 { it shouldBe 1 },562 { it shouldBe 3 }563 )564 }565 }566 "work with unsorted collections" {567 val actual = listOf(5, 3, 1, 2, 4, 2)568 withClue("should match 4th, 5th and 6th elements ([.., 2, 4, 2])") {569 actual should matchInOrder(570 { it shouldBe 2 },571 { it shouldBeGreaterThan 3 },572 { it shouldBeInRange 2..2 }573 )574 }575 }576 "negation should work" {577 shouldFail {578 listOf(1, 2, 3, 4).shouldNotMatchInOrder(579 { it shouldBe 2 },580 { it shouldBe 3 },581 )582 }.message shouldBe """583 Expected some assertion to fail but all passed584 """.trimIndent()585 listOf(1, 2, 3, 4).shouldNotMatchInOrder(586 { it shouldBe 2 },587 { it shouldBe 4 }588 )589 }590 }591 "matchInOrderSubset" should {592 "test that a collection matches the assertions in the given order without gaps" {593 listOf(1, 1, 2, 2, 3, 3) should matchInOrderSubset(594 { it shouldBe 1 },595 { it shouldBe 2 },596 { it shouldBe 2 },597 { it shouldBe 3 }598 )599 arrayOf(1, 1, 1).shouldMatchInOrderSubset(600 { it shouldBe 1 }601 )602 }603 "Negation should work" {604 shouldFail {605 listOf(1, 2, 3, 4).shouldNotMatchInOrderSubset(606 { it shouldBe 2 },607 { it shouldBe 4 },608 )609 }.message shouldBe """610 Expected some assertion to fail but all passed611 """.trimIndent()612 arrayOf(1, 2, 3, 4).shouldNotMatchInOrder(613 { it shouldBe 4 },614 { it shouldBe 1 }615 )616 }617 "Non existing element causes error" {618 shouldThrow<AssertionError> {619 listOf(1, 1, 2, 2, 3, 3) should matchInOrderSubset(620 { it shouldBe 1 },621 { it shouldBe 2 },622 { it shouldBe 6 }623 )624 }.message shouldBe """625 Expected a sequence of elements to pass the assertions, possibly with gaps between but failed to match all assertions626 Best result when comparing from index [0], where 2 elements passed, but the following elements failed:627 3 => expected:<6> but was:<2>628 4 => expected:<6> but was:<3>629 5 => expected:<6> but was:<3>630 """.trimIndent()631 }632 "out-of-order elements cause error" {633 shouldThrow<AssertionError> {634 listOf(1, 2, 3) should matchInOrderSubset(635 { it shouldBe 2 },636 { it shouldBe 1 },637 { it shouldBe 3 }638 )639 }640 }641 "gaps should be ok" {642 listOf(1, 1, 2, 2, 3, 3) should matchInOrderSubset(643 { it shouldBe 1 },644 { it shouldBe 2 },645 { it shouldBe 3 }646 )647 }648 "work with unsorted collections" {649 val actual = listOf(5, 3, 1, 2, 4, 2)650 withClue("should match 4th, 5th and 6th elements ([.., 2, 4, 2])") {651 actual should matchInOrderSubset(652 { it shouldBe 2 },653 { it shouldBeGreaterThan 3 },654 { it shouldBeInRange 2..2 }655 )656 }657 }658 }659 "matchEach" should {660 "test that a collection matches the assertions in the given order without gaps" {661 listOf(1, 3, 7) should matchEach(662 { it shouldBe 1 },663 { it shouldBeInRange 2..4 },664 { it shouldBeGreaterThan 2 }665 )666 }667 "Negation should work" {668 shouldFail{669 listOf(1, 2).shouldNotMatchEach(670 { it shouldBe 1 },671 { it shouldBe 2 },672 )673 }.message shouldBe """674 Expected some element to fail its assertion, but all passed.675 """.trimIndent()676 arrayOf(1, 2).shouldNotMatchEach(677 { it shouldBe 2 },678 { it shouldBe 1 }679 )680 }681 "No assertion exists for each element" {682 shouldFail {683 listOf(1, -1, 999) should matchEach(684 { it shouldBe 1 }685 )686 }.message shouldBe """687 Expected each element to pass its assertion, but found issues at indexes: [1, 2]688 1 => Element has no corresponding assertion. Only 1 assertions provided689 2 => Element has no corresponding assertion. Only 1 assertions provided690 """.trimIndent()691 }692 "Too many assertions cause error" {693 shouldFail {694 listOf(1, 3, 7) should matchEach(695 { it shouldBe 1 },696 { it shouldBe 3 },697 { it shouldBe 7 },698 { it shouldBe 7 },699 { it shouldBe 7 },700 )701 }.message shouldBe """702 Expected each element to pass its assertion, but found issues at indexes: [3, 4]703 3 => No actual element for assertion at index 3704 4 => No actual element for assertion at index 4705 """.trimIndent()706 }707 "Non matching element causes error" {708 shouldFail {709 listOf(1, 3, 7) should matchEach(710 { it shouldBe 1 },711 { it shouldBeInRange 2..4 },712 { it shouldBeGreaterThan 7 }713 )714 }.message shouldBe """715 Expected each element to pass its assertion, but found issues at indexes: [2]716 2 => 7 should be > 7717 """.trimIndent()718 }719 "out-of-order elements cause error" {720 shouldThrow<AssertionError> {721 setOf(2, 3, 1) should matchEach(722 { it shouldBe 2 },723 { it shouldBe 1 },724 { it shouldBe 3 }725 )726 }.message shouldBe """727 Expected each element to pass its assertion, but found issues at indexes: [1, 2]728 1 => expected:<1> but was:<3>729 2 => expected:<3> but was:<1>730 """.trimIndent()731 }732 "gaps cause errors" {733 shouldThrow<AssertionError> {734 listOf(1, 1, 2, 2, 3, 3) should matchEach(735 { it shouldBe 1 },736 { it shouldBe 2 },737 { it shouldBe 3 }738 )739 }.message shouldBe """740 Expected each element to pass its assertion, but found issues at indexes: [1, 2, 3, 4, 5]741 1 => expected:<2> but was:<1>742 2 => expected:<3> but was:<2>743 3 => Element has no corresponding assertion. Only 3 assertions provided744 4 => Element has no corresponding assertion. Only 3 assertions provided745 5 => Element has no corresponding assertion. Only 3 assertions provided746 """.trimIndent()747 }748 }749 "existInOrder" should {750 "test that a collection matches the predicates in the given order, duplicates permitted" {751 val col = listOf(1, 1, 2, 2, 3, 3)752 col should existInOrder(753 { it == 1 },754 { it == 2 },755 { it == 3 }756 )757 col should existInOrder({ it == 1 })758 shouldThrow<AssertionError> {759 col should existInOrder(760 { it == 1 },761 { it == 2 },762 { it == 6 }763 )764 }765 shouldThrow<AssertionError> {766 col should existInOrder({ it == 4 })767 }768 shouldThrow<AssertionError> {769 col should existInOrder(770 { it == 2 },771 { it == 1 },772 { it == 3 }773 )774 }775 }776 "work with unsorted collections" {777 val actual = listOf(5, 3, 1, 2, 4, 2)778 actual should existInOrder(779 { it == 3 },780 { it == 2 },781 { it == 2 }782 )783 }784 }785 "Contain any" should {786 "Fail when the list is empty" {787 shouldThrow<AssertionError> {788 listOf(1, 2, 3).shouldContainAnyOf(emptyList())789 }.shouldHaveMessage("Asserting content on empty collection. Use Collection.shouldBeEmpty() instead.")790 }791 "Pass when one element is in the list" {792 listOf(1, 2, 3).shouldContainAnyOf(1)793 }794 "Pass when all elements are in the list" {795 listOf(1, 2, 3).shouldContainAnyOf(1, 2, 3)796 }797 "Fail when no element is in the list" {798 shouldThrow<AssertionError> {799 listOf(1, 2, 3).shouldContainAnyOf(4)800 }.shouldHaveMessage("Collection [1, 2, 3] should contain any of [4]")801 }802 }803 "Contain any (negative)" should {804 "Fail when the list is empty" {805 shouldThrow<AssertionError> {806 listOf(1, 2, 3).shouldNotContainAnyOf(emptyList())807 }.shouldHaveMessage("Asserting content on empty collection. Use Collection.shouldBeEmpty() instead.")808 }809 "Pass when no element is present in the list" {810 listOf(1, 2, 3).shouldNotContainAnyOf(4)811 }812 "Fail when one element is in the list" {813 shouldThrow<AssertionError> {814 listOf(1, 2, 3).shouldNotContainAnyOf(1)815 }.shouldHaveMessage("Collection [1, 2, 3] should not contain any of [1]")816 }817 "Fail when all elements are in the list" {818 shouldThrow<AssertionError> {819 listOf(1, 2, 3).shouldNotContainAnyOf(1, 2, 3)820 }.shouldHaveMessage("Collection [1, 2, 3] should not contain any of [1, 2, 3]")821 }822 }823 "Be in" should {824 "Pass when the element is in the list" {825 val foo = Foo("Bar")826 val list = listOf(foo)827 foo shouldBeIn list828 }829 "Fail when the element is not in the list" {830 val foo1 = Foo("Bar")831 val foo2 = Foo("Booz")832 val list = listOf(foo1)833 shouldThrow<AssertionError> {834 foo2.shouldBeIn(list)835 }.shouldHaveMessage("Collection should contain Foo(bar=Booz), but doesn't. Possible values: [Foo(bar=Bar)]")836 }837 "Pass when there's an equal element, but not the same instance in the list" {838 val foo1 = Foo("Bar")839 val foo2 = Foo("Bar")840 val list = listOf(foo1)841 shouldNotThrow<AssertionError> { foo2 shouldBeIn list }842 }843 "Pass when there's an equal element, but not the same instance in the array" {844 val foo1 = Foo("Bar")845 val foo2 = Foo("Bar")846 val list = arrayOf(foo1)847 shouldNotThrow<AssertionError> { foo2 shouldBeIn list }848 }849 "Fail when the list is empty" {850 val foo = Foo("Bar")851 val list = emptyList<Foo>()852 shouldThrow<AssertionError> {853 foo shouldBeIn list854 }.shouldHaveMessage("Asserting content on empty collection. Use Collection.shouldBeEmpty() instead.")855 }856 }857 "Be in (negative)" should {858 "Fail when the element is in the list" {859 val foo = Foo("Bar")860 val list = listOf(foo)861 shouldThrow<AssertionError> {862 foo shouldNotBeIn list863 }.shouldHaveMessage("Collection should not contain Foo(bar=Bar), but does. Forbidden values: [Foo(bar=Bar)]")864 }865 "Pass when the element is not in the list" {866 val foo1 = Foo("Bar")867 val foo2 = Foo("Booz")868 val list = listOf(foo1)869 shouldNotThrow<AssertionError> {870 foo2.shouldNotBeIn(list)871 }872 }873 "Fail when there's an equal element, but not the same instance in the list" {874 val foo1 = Foo("Bar")875 val foo2 = Foo("Bar")876 val list = listOf(foo1)877 shouldThrow<AssertionError> {878 foo2 shouldNotBeIn list879 }.shouldHaveMessage("Collection should not contain Foo(bar=Bar), but does. Forbidden values: [Foo(bar=Bar)]")880 }881 "Fail when the list is empty" {882 val foo = Foo("Bar")883 val list = emptyList<Foo>()884 shouldThrow<AssertionError> {885 foo shouldNotBeIn list886 }.shouldHaveMessage("Asserting content on empty collection. Use Collection.shouldBeEmpty() instead.")887 }888 }889 }890}891private data class Foo(val bar: String)892sealed class TestSealed {893 data class Test1(val value: String) : TestSealed()894 data class Test2(val value: Int) : TestSealed()895}...

Full Screen

Full Screen

BitrateControllerTest.kt

Source:BitrateControllerTest.kt Github

copy

Full Screen

1/*2 * Copyright @ 2018 - present 8x8, Inc.3 *4 * Licensed under the Apache License, Version 2.0 (the "License");5 * you may not use this file except in compliance with the License.6 * You may obtain a copy of the License at7 *8 * http://www.apache.org/licenses/LICENSE-2.09 *10 * Unless required by applicable law or agreed to in writing, software11 * distributed under the License is distributed on an "AS IS" BASIS,12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.13 * See the License for the specific language governing permissions and14 * limitations under the License.15 */16package org.jitsi.videobridge.cc.allocation17import com.google.common.collect.ImmutableMap18import io.kotest.core.spec.IsolationMode19import io.kotest.core.spec.style.ShouldSpec20import io.kotest.matchers.collections.shouldContainExactly21import io.kotest.matchers.maps.shouldContainExactly22import io.kotest.matchers.shouldBe23import io.mockk.every24import io.mockk.mockk25import org.jitsi.nlj.MediaSourceDesc26import org.jitsi.nlj.PacketInfo27import org.jitsi.nlj.RtpEncodingDesc28import org.jitsi.nlj.RtpLayerDesc29import org.jitsi.nlj.format.RtxPayloadType30import org.jitsi.nlj.rtp.VideoRtpPacket31import org.jitsi.nlj.util.Bandwidth32import org.jitsi.nlj.util.bps33import org.jitsi.nlj.util.kbps34import org.jitsi.nlj.util.mbps35import org.jitsi.test.time.FakeClock36import org.jitsi.utils.logging.DiagnosticContext37import org.jitsi.utils.logging2.createLogger38import org.jitsi.utils.ms39import org.jitsi.utils.secs40import org.jitsi.videobridge.VideoConstraints41import org.jitsi.videobridge.cc.VideoConstraintsCompatibility42import java.time.Instant43import java.util.function.Supplier44class BitrateControllerTest : ShouldSpec() {45 override fun isolationMode(): IsolationMode? = IsolationMode.InstancePerLeaf46 private val logger = createLogger()47 private val clock = FakeClock()48 private val bc = BitrateControllerWrapper("A", "B", "C", "D", clock = clock)49 init {50 context("Effective constraints") {51 val conferenceEndpoints = List(5) { i -> Endpoint("endpoint-${i + 1}") }52 context("When nothing is specified (expect 180p)") {53 val lastN = -154 val videoConstraints = mapOf("endpoint-1" to VideoConstraints(720))55 EndpointMultiRank.makeEndpointMultiRankList(56 conferenceEndpoints,57 videoConstraints,58 lastN59 ).map {60 it.endpoint.id to it.effectiveVideoConstraints61 }.toMap().shouldContainExactly(62 mapOf(63 "endpoint-1" to VideoConstraints(720),64 "endpoint-2" to VideoConstraints.thumbnailVideoConstraints,65 "endpoint-3" to VideoConstraints.thumbnailVideoConstraints,66 "endpoint-4" to VideoConstraints.thumbnailVideoConstraints,67 "endpoint-5" to VideoConstraints.thumbnailVideoConstraints68 )69 )70 }71 context("With LastN") {72 val lastN = 373 val videoConstraints = mapOf<String, VideoConstraints>()74 EndpointMultiRank.makeEndpointMultiRankList(75 conferenceEndpoints,76 videoConstraints,77 lastN78 ).map {79 it.endpoint.id to it.effectiveVideoConstraints80 }.toMap().shouldContainExactly(81 mapOf(82 "endpoint-1" to VideoConstraints.thumbnailVideoConstraints,83 "endpoint-2" to VideoConstraints.thumbnailVideoConstraints,84 "endpoint-3" to VideoConstraints.thumbnailVideoConstraints,85 "endpoint-4" to VideoConstraints.disabledVideoConstraints,86 "endpoint-5" to VideoConstraints.disabledVideoConstraints87 )88 )89 }90 context("With explicitly selected ep outside LastN") {91 // This replicates what the client's low-bandwidth mode does when there is a screenshare -92 // it explicitly selects only the share, ignoring the last-N list.93 val lastN = 194 val videoConstraints = mapOf("endpoint-2" to VideoConstraints(1080))95 EndpointMultiRank.makeEndpointMultiRankList(96 conferenceEndpoints,97 videoConstraints,98 lastN99 ).map {100 it.endpoint.id to it.effectiveVideoConstraints101 }.toMap().shouldContainExactly(102 mapOf(103 "endpoint-1" to VideoConstraints.disabledVideoConstraints,104 "endpoint-2" to VideoConstraints(1080),105 "endpoint-3" to VideoConstraints.disabledVideoConstraints,106 "endpoint-4" to VideoConstraints.disabledVideoConstraints,107 "endpoint-5" to VideoConstraints.disabledVideoConstraints108 )109 )110 }111 }112 context("Allocation") {113 context("Stage view") {114 context("When LastN is not set") {115 context("and the dominant speaker is on stage") {116 bc.setEndpointOrdering("A", "B", "C", "D")117 bc.setStageView("A")118 runBweLoop()119 verifyStageView()120 }121 context("and a non-dominant speaker is on stage") {122 bc.setEndpointOrdering("B", "A", "C", "D")123 bc.setStageView("A")124 runBweLoop()125 verifyStageView()126 }127 }128 context("When LastN=0") {129 // LastN=0 is used when the client goes in "audio-only" mode.130 bc.setEndpointOrdering("A", "B", "C", "D")131 bc.setStageView("A")132 bc.setLastN(0)133 runBweLoop()134 verifyLastN0()135 }136 context("When LastN=1") {137 // LastN=1 is used when the client goes in "audio-only" mode, but someone starts a screenshare.138 context("and the dominant speaker is on-stage") {139 bc.setEndpointOrdering("A", "B", "C", "D")140 bc.setStageView("A")141 bc.setLastN(1)142 runBweLoop()143 verifyStageViewLastN1()144 }145 context("and a non-dominant speaker is on stage") {146 bc.setEndpointOrdering("B", "A", "C", "D")147 bc.setStageView("A")148 bc.setLastN(1)149 runBweLoop()150 verifyStageViewLastN1()151 }152 }153 }154 context("Tile view") {155 bc.setEndpointOrdering("A", "B", "C", "D")156 bc.setTileView("A", "B", "C", "D")157 context("When LastN is not set") {158 runBweLoop()159 verifyTileView()160 }161 context("When LastN=0") {162 bc.setLastN(0)163 runBweLoop()164 verifyLastN0()165 }166 context("When LastN=1") {167 bc.setLastN(1)168 runBweLoop()169 verifyTileViewLastN1()170 }171 }172 context("Selected endpoints should override the dominant speaker") {173 // A is dominant speaker, A and B are selected. With LastN=2 we should always forward the selected174 // endpoints regardless of who is speaking.175 // The exact flow of this scenario was taken from a (non-jitsi-meet) client.176 bc.setEndpointOrdering("A", "B", "C", "D")177 bc.setSelectedEndpoints("A", "B", maxFrameHeight = 720)178 bc.setLastN(2)179 clock.elapse(20.secs)180 bc.bwe = 10.mbps181 bc.forwardedEndpointsHistory.last().event.shouldBe(setOf("A", "B"))182 clock.elapse(2.secs)183 // B becomes dominant speaker.184 bc.setEndpointOrdering("B", "A", "C", "D")185 bc.forwardedEndpointsHistory.last().event.shouldBe(setOf("A", "B"))186 clock.elapse(2.secs)187 bc.setMaxFrameHeight(360)188 clock.elapse(2.secs)189 // This should change nothing, the selection didn't change.190 bc.setSelectedEndpoints("A", "B")191 bc.forwardedEndpointsHistory.last().event.shouldBe(setOf("A", "B"))192 clock.elapse(2.secs)193 bc.setLastN(-1)194 bc.forwardedEndpointsHistory.last().event.shouldBe(setOf("A", "B", "C", "D"))195 clock.elapse(2.secs)196 bc.setMaxFrameHeight(360)197 clock.elapse(2.secs)198 bc.forwardedEndpointsHistory.last().event.shouldBe(setOf("A", "B", "C", "D"))199 bc.setLastN(2)200 clock.elapse(2.secs)201 bc.forwardedEndpointsHistory.last().event.shouldBe(setOf("A", "B"))202 clock.elapse(2.secs)203 // D is now dominant speaker, but it should not override the selected endpoints.204 bc.setEndpointOrdering("D", "B", "A", "C")205 bc.forwardedEndpointsHistory.last().event.shouldBe(setOf("A", "B"))206 bc.bwe = 10.mbps207 bc.forwardedEndpointsHistory.last().event.shouldBe(setOf("A", "B"))208 clock.elapse(2.secs)209 bc.bwe = 0.mbps210 clock.elapse(2.secs)211 bc.bwe = 10.mbps212 bc.forwardedEndpointsHistory.last().event.shouldBe(setOf("A", "B"))213 clock.elapse(2.secs)214 // C is now dominant speaker, but it should not override the selected endpoints.215 bc.setEndpointOrdering("C", "D", "A", "B")216 bc.forwardedEndpointsHistory.last().event.shouldBe(setOf("A", "B"))217 }218 }219 }220 private fun runBweLoop() {221 for (bwe in 0..5_000_000 step 10_000) {222 bc.bwe = bwe.bps223 clock.elapse(100.ms)224 }225 logger.info("Forwarded endpoints history: ${bc.forwardedEndpointsHistory}")226 logger.info("Effective constraints history: ${bc.effectiveConstraintsHistory}")227 logger.info("Allocation history: ${bc.allocationHistory}")228 }229 private fun verifyStageView() {230 // At this stage the purpose of this is just to document current behavior.231 // TODO: The results with bwe==-1 are wrong.232 bc.forwardedEndpointsHistory.removeIf { it.bwe < 0.bps }233 bc.forwardedEndpointsHistory.map { it.event }.shouldContainInOrder(234 listOf("A"),235 listOf("A", "B"),236 listOf("A", "B", "C"),237 listOf("A", "B", "C", "D")238 )239 // At this stage the purpose of this is just to document current behavior.240 // TODO: the allocations for bwe=-1 are wrong.241 bc.allocationHistory.removeIf { it.bwe < 0.bps }242 bc.allocationHistory.shouldMatchInOrder(243 Event(244 0.kbps,245 listOf(246 AllocationInfo("A", ld7_5, oversending = true),247 AllocationInfo("B", noVideo),248 AllocationInfo("C", noVideo),249 AllocationInfo("D", noVideo)250 )251 ),252 Event(253 100.kbps,254 listOf(255 AllocationInfo("A", ld15),256 AllocationInfo("B", noVideo),257 AllocationInfo("C", noVideo),258 AllocationInfo("D", noVideo)259 )260 ),261 Event(262 150.kbps,263 listOf(264 AllocationInfo("A", ld30),265 AllocationInfo("B", noVideo),266 AllocationInfo("C", noVideo),267 AllocationInfo("D", noVideo)268 )269 ),270 Event(271 500.kbps,272 listOf(273 AllocationInfo("A", sd30),274 AllocationInfo("B", noVideo),275 AllocationInfo("C", noVideo),276 AllocationInfo("D", noVideo)277 )278 ),279 Event(280 550.kbps,281 listOf(282 AllocationInfo("A", sd30),283 AllocationInfo("B", ld7_5),284 AllocationInfo("C", noVideo),285 AllocationInfo("D", noVideo)286 )287 ),288 Event(289 600.kbps,290 listOf(291 AllocationInfo("A", sd30),292 AllocationInfo("B", ld7_5),293 AllocationInfo("C", ld7_5),294 AllocationInfo("D", noVideo)295 )296 ),297 Event(298 650.kbps,299 listOf(300 AllocationInfo("A", sd30),301 AllocationInfo("B", ld7_5),302 AllocationInfo("C", ld7_5),303 AllocationInfo("D", ld7_5)304 )305 ),306 Event(307 700.kbps,308 listOf(309 AllocationInfo("A", sd30),310 AllocationInfo("B", ld15),311 AllocationInfo("C", ld7_5),312 AllocationInfo("D", ld7_5)313 )314 ),315 Event(316 750.kbps,317 listOf(318 AllocationInfo("A", sd30),319 AllocationInfo("B", ld15),320 AllocationInfo("C", ld15),321 AllocationInfo("D", ld7_5)322 )323 ),324 Event(325 800.kbps,326 listOf(327 AllocationInfo("A", sd30),328 AllocationInfo("B", ld15),329 AllocationInfo("C", ld15),330 AllocationInfo("D", ld15)331 )332 ),333 Event(334 850.kbps,335 listOf(336 AllocationInfo("A", sd30),337 AllocationInfo("B", ld30),338 AllocationInfo("C", ld15),339 AllocationInfo("D", ld15)340 )341 ),342 Event(343 900.kbps,344 listOf(345 AllocationInfo("A", sd30),346 AllocationInfo("B", ld30),347 AllocationInfo("C", ld30),348 AllocationInfo("D", ld15)349 )350 ),351 Event(352 960.kbps,353 listOf(354 AllocationInfo("A", sd30),355 AllocationInfo("B", ld30),356 AllocationInfo("C", ld30),357 AllocationInfo("D", ld30)358 )359 ),360 Event(361 2150.kbps,362 listOf(363 AllocationInfo("A", hd30),364 AllocationInfo("B", ld7_5),365 AllocationInfo("C", ld7_5),366 AllocationInfo("D", ld7_5)367 )368 ),369 Event(370 2200.kbps,371 listOf(372 AllocationInfo("A", hd30),373 AllocationInfo("B", ld15),374 AllocationInfo("C", ld7_5),375 AllocationInfo("D", ld7_5)376 )377 ),378 Event(379 2250.kbps,380 listOf(381 AllocationInfo("A", hd30),382 AllocationInfo("B", ld15),383 AllocationInfo("C", ld15),384 AllocationInfo("D", ld7_5)385 )386 ),387 Event(388 2300.kbps,389 listOf(390 AllocationInfo("A", hd30),391 AllocationInfo("B", ld15),392 AllocationInfo("C", ld15),393 AllocationInfo("D", ld15)394 )395 ),396 Event(397 2350.kbps,398 listOf(399 AllocationInfo("A", hd30),400 AllocationInfo("B", ld30),401 AllocationInfo("C", ld15),402 AllocationInfo("D", ld15)403 )404 ),405 Event(406 2400.kbps,407 listOf(408 AllocationInfo("A", hd30),409 AllocationInfo("B", ld30),410 AllocationInfo("C", ld30),411 AllocationInfo("D", ld15)412 )413 ),414 Event(415 2460.kbps,416 listOf(417 AllocationInfo("A", hd30),418 AllocationInfo("B", ld30),419 AllocationInfo("C", ld30),420 AllocationInfo("D", ld30)421 )422 )423 )424 }425 private fun verifyLastN0() {426 // No video forwarded even with high BWE.427 bc.forwardedEndpointsHistory.size shouldBe 0428 // TODO: The history contains 3 identical elements, which is probably a bug.429 bc.allocationHistory.last().event shouldContainExactly listOf(430 AllocationInfo("A", noVideo),431 AllocationInfo("B", noVideo),432 AllocationInfo("C", noVideo),433 AllocationInfo("D", noVideo)434 )435 }436 private fun verifyStageViewLastN1() {437 // At this stage the purpose of this is just to document current behavior.438 // TODO: The results with bwe==-1 are wrong.439 bc.forwardedEndpointsHistory.removeIf { it.bwe < 0.bps }440 bc.forwardedEndpointsHistory.map { it.event }.shouldContainInOrder(441 listOf("A")442 )443 // At this stage the purpose of this is just to document current behavior.444 // TODO: the allocations for bwe=-1 are wrong.445 bc.allocationHistory.removeIf { it.bwe < 0.bps }446 bc.allocationHistory.shouldMatchInOrder(447 Event(448 0.kbps,449 listOf(450 AllocationInfo("A", ld7_5, oversending = true),451 AllocationInfo("B", noVideo),452 AllocationInfo("C", noVideo),453 AllocationInfo("D", noVideo)454 )455 ),456 Event(457 100.kbps,458 listOf(459 AllocationInfo("A", ld15),460 AllocationInfo("B", noVideo),461 AllocationInfo("C", noVideo),462 AllocationInfo("D", noVideo)463 )464 ),465 Event(466 150.kbps,467 listOf(468 AllocationInfo("A", ld30),469 AllocationInfo("B", noVideo),470 AllocationInfo("C", noVideo),471 AllocationInfo("D", noVideo)472 )473 ),474 Event(475 500.kbps,476 listOf(477 AllocationInfo("A", sd30),478 AllocationInfo("B", noVideo),479 AllocationInfo("C", noVideo),480 AllocationInfo("D", noVideo)481 )482 ),483 Event(484 2010.kbps,485 listOf(486 AllocationInfo("A", hd30),487 AllocationInfo("B", noVideo),488 AllocationInfo("C", noVideo),489 AllocationInfo("D", noVideo)490 )491 )492 )493 }494 private fun verifyTileView() {495 // At this stage the purpose of this is just to document current behavior.496 // TODO: The results with bwe==-1 are wrong.497 bc.forwardedEndpointsHistory.removeIf { it.bwe < 0.bps }498 bc.forwardedEndpointsHistory.map { it.event }.shouldContainInOrder(499 listOf("A"),500 listOf("A", "B"),501 listOf("A", "B", "C"),502 listOf("A", "B", "C", "D")503 )504 // At this stage the purpose of this is just to document current behavior.505 // TODO: the allocations for bwe=-1 are wrong.506 bc.allocationHistory.removeIf { it.bwe < 0.bps }507 bc.allocationHistory.shouldMatchInOrder(508 Event(509 0.kbps,510 listOf(511 // TODO: do we want to oversend in tile view?512 AllocationInfo("A", ld7_5, oversending = true),513 AllocationInfo("B", noVideo),514 AllocationInfo("C", noVideo),515 AllocationInfo("D", noVideo)516 )517 ),518 Event(519 100.kbps,520 listOf(521 AllocationInfo("A", ld7_5),522 AllocationInfo("B", ld7_5),523 AllocationInfo("C", noVideo),524 AllocationInfo("D", noVideo)525 )526 ),527 Event(528 150.kbps,529 listOf(530 AllocationInfo("A", ld7_5),531 AllocationInfo("B", ld7_5),532 AllocationInfo("C", ld7_5),533 AllocationInfo("D", noVideo)534 )535 ),536 Event(537 200.kbps,538 listOf(539 AllocationInfo("A", ld7_5),540 AllocationInfo("B", ld7_5),541 AllocationInfo("C", ld7_5),542 AllocationInfo("D", ld7_5)543 )544 ),545 Event(546 250.kbps,547 listOf(548 AllocationInfo("A", ld15),549 AllocationInfo("B", ld7_5),550 AllocationInfo("C", ld7_5),551 AllocationInfo("D", ld7_5)552 )553 ),554 Event(555 300.kbps,556 listOf(557 AllocationInfo("A", ld15),558 AllocationInfo("B", ld15),559 AllocationInfo("C", ld7_5),560 AllocationInfo("D", ld7_5)561 )562 ),563 Event(564 350.kbps,565 listOf(566 AllocationInfo("A", ld15),567 AllocationInfo("B", ld15),568 AllocationInfo("C", ld15),569 AllocationInfo("D", ld7_5)570 )571 ),572 Event(573 400.kbps,574 listOf(575 AllocationInfo("A", ld15),576 AllocationInfo("B", ld15),577 AllocationInfo("C", ld15),578 AllocationInfo("D", ld15)579 )580 ),581 Event(582 450.kbps,583 listOf(584 AllocationInfo("A", ld30),585 AllocationInfo("B", ld15),586 AllocationInfo("C", ld15),587 AllocationInfo("D", ld15)588 )589 ),590 Event(591 500.kbps,592 listOf(593 AllocationInfo("A", ld30),594 AllocationInfo("B", ld30),595 AllocationInfo("C", ld15),596 AllocationInfo("D", ld15)597 )598 ),599 Event(600 550.kbps,601 listOf(602 AllocationInfo("A", ld30),603 AllocationInfo("B", ld30),604 AllocationInfo("C", ld30),605 AllocationInfo("D", ld15)606 )607 ),608 Event(609 610.kbps,610 listOf(611 AllocationInfo("A", ld30),612 AllocationInfo("B", ld30),613 AllocationInfo("C", ld30),614 AllocationInfo("D", ld30)615 )616 )617 )618 }619 private fun verifyTileViewLastN1() {620 // At this stage the purpose of this is just to document current behavior.621 // TODO: The results with bwe==-1 are wrong.622 bc.forwardedEndpointsHistory.removeIf { it.bwe < 0.bps }623 bc.forwardedEndpointsHistory.map { it.event }.shouldContainInOrder(624 listOf("A")625 )626 // At this stage the purpose of this is just to document current behavior.627 // TODO: the allocations for bwe=-1 are wrong.628 bc.allocationHistory.removeIf { it.bwe < 0.bps }629 bc.allocationHistory.shouldMatchInOrder(630 Event(631 0.kbps,632 listOf(633 // TODO: do we want to oversend in tile view?634 AllocationInfo("A", ld7_5, oversending = true),635 AllocationInfo("B", noVideo),636 AllocationInfo("C", noVideo),637 AllocationInfo("D", noVideo)638 )639 ),640 Event(641 100.kbps,642 listOf(643 AllocationInfo("A", ld15),644 AllocationInfo("B", noVideo),645 AllocationInfo("C", noVideo),646 AllocationInfo("D", noVideo)647 )648 ),649 Event(650 160.kbps, // TODO: why 160 instead of 150? weird.651 listOf(652 AllocationInfo("A", ld30),653 AllocationInfo("B", noVideo),654 AllocationInfo("C", noVideo),655 AllocationInfo("D", noVideo)656 )657 )658 )659 }660}661fun List<Event<List<AllocationInfo>>>.shouldMatchInOrder(vararg events: Event<List<AllocationInfo>>) {662 events.size shouldBe size663 events.forEachIndexed { i, it ->664 this[i].bwe shouldBe it.bwe665 this[i].event.shouldContainExactly(it.event)666 // Ignore this.time667 }668}669private class BitrateControllerWrapper(vararg endpointIds: String, val clock: FakeClock = FakeClock()) {670 val endpoints: List<Endpoint> = createEndpoints(*endpointIds)671 val logger = createLogger()672 val vcc = VideoConstraintsCompatibility()673 var bwe = (-1).bps674 set(value) {675 logger.debug("Setting bwe=$value")676 field = value677 bc.bandwidthChanged(value.bps.toLong())678 }679 // Save the output.680 val effectiveConstraintsHistory: History<ImmutableMap<String, VideoConstraints>> = mutableListOf()681 val forwardedEndpointsHistory: History<Collection<String>> = mutableListOf()682 val allocationHistory: History<List<AllocationInfo>> = mutableListOf()683 val bc = BitrateController(684 "destinationEndpoint",685 object : BitrateController.EventHandler {686 override fun forwardedEndpointsChanged(forwardedEndpoints: Collection<String>) {687 Event(bwe, forwardedEndpoints, clock.instant()).apply {688 logger.info("Forwarded endpoints changed: $this")689 forwardedEndpointsHistory.add(this)690 }691 }692 override fun effectiveVideoConstraintsChanged(693 oldVideoConstraints: ImmutableMap<String, VideoConstraints>,694 newVideoConstraints: ImmutableMap<String, VideoConstraints>695 ) {696 Event(bwe, newVideoConstraints, clock.instant()).apply {697 logger.info("Effective constraints changed: $this")698 effectiveConstraintsHistory.add(this)699 }700 }701 override fun keyframeNeeded(endpointId: String?, ssrc: Long) { }702 override fun allocationChanged(allocation: List<SingleSourceAllocation>) {703 Event(bwe, allocation.map { it.toEndpointAllocationInfo() }, clock.instant()).apply {704 logger.info("Allocation changed: $this")705 allocationHistory.add(this)706 }707 }708 },709 Supplier { endpoints },710 DiagnosticContext(),711 logger,712 clock713 )714 fun setEndpointOrdering(vararg endpoints: String) {715 logger.info("Set endpoints ${endpoints.joinToString(",")}")716 bc.endpointOrderingChanged(mutableListOf(*endpoints))717 }718 fun setStageView(onStageEndpoint: String, maxFrameHeight: Int = 720) {719 vcc.setMaxFrameHeight(maxFrameHeight)720 vcc.setSelectedEndpoints(setOf(onStageEndpoint))721 setVideoConstraints(ImmutableMap.copyOf(vcc.computeVideoConstraints()))722 }723 fun setSelectedEndpoints(vararg selectedEndpoints: String, maxFrameHeight: Int? = null) {724 maxFrameHeight?.let { vcc.setMaxFrameHeight(it) }725 vcc.setSelectedEndpoints(setOf(*selectedEndpoints))726 setVideoConstraints(ImmutableMap.copyOf(vcc.computeVideoConstraints()))727 }728 fun setTileView(vararg selectedEndpoints: String) {729 setSelectedEndpoints(*selectedEndpoints, maxFrameHeight = 180)730 }731 fun setMaxFrameHeight(maxFrameHeight: Int) {732 vcc.setMaxFrameHeight(maxFrameHeight)733 setVideoConstraints(ImmutableMap.copyOf(vcc.computeVideoConstraints()))734 }735 fun setVideoConstraints(videoConstraints: ImmutableMap<String, VideoConstraints>) {736 logger.info("Set video constraints $videoConstraints")737 bc.setVideoConstraints(videoConstraints)738 }739 fun setLastN(n: Int) {740 logger.info("Set LastN $n")741 bc.lastN = n742 }743 init {744 // The BC only starts working 10 seconds after it first received media, so fake that.745 bc.transformRtp(PacketInfo(VideoRtpPacket(ByteArray(100), 0, 100)))746 clock.elapse(15.secs)747 // Adaptivity is disabled when RTX support is not signalled.748 bc.addPayloadType(RtxPayloadType(123, mapOf("apt" to "124")))749 }750}751typealias History<T> = MutableList<Event<T>>752data class Event<T>(753 val bwe: Bandwidth,754 val event: T,755 val time: Instant = Instant.MIN756) {757 override fun toString(): String = "\n[time=${time.toEpochMilli()} bwe=$bwe] $event"758}759/**760 * Describe the layer that is currently forwarded to an endpoint in a human-readable way.761 */762data class AllocationInfo(763 val id: String,764 val height: Int,765 val fps: Double,766 val bitrate: Bandwidth,767 val oversending: Boolean = false768) {769 constructor(id: String, layer: RtpLayerDesc, oversending: Boolean = false) :770 this(id, layer.height, layer.frameRate, layer.getBitrate(0), oversending)771 override fun toString(): String =772 "\n\t[id=$id, height=$height, fps=$fps, bitrate=$bitrate, oversending=$oversending]"773}774fun SingleSourceAllocation.toEndpointAllocationInfo() =775 AllocationInfo(776 endpointID,777 targetLayer?.height ?: 0,778 targetLayer?.frameRate ?: 0.0,779 targetLayer?.getBitrate(0) ?: 0.bps, // 0 is fine with our Mck RtpLayerDesc780 oversending781 )782/**783 * Like the normal List<T>.shouldContainInOrder, but compare elements' contents.784 */785fun <T> List<Collection<T>>.shouldContainInOrder(vararg ts: Collection<T>) {786 this.size shouldBe ts.size787 ts.forEachIndexed { i, it -> this[i].shouldContainExactly(it) }788}789class Endpoint(790 override val id: String,791 mediaSource: MediaSourceDesc? = null792) : MediaSourceContainer {793 override val mediaSources = mediaSource?.let { arrayOf(mediaSource) } ?: emptyArray()794}795fun createEndpoints(vararg ids: String): List<Endpoint> {796 return List(ids.size) { i ->797 Endpoint(798 ids[i],799 createSource(800 3 * i + 1,801 3 * i + 2,802 3 * i + 3803 )804 )805 }806}807fun createSource(ssrc1: Int, ssrc2: Int, ssrc3: Int): MediaSourceDesc = MediaSourceDesc(808 arrayOf(809 RtpEncodingDesc(ssrc1.toLong(), arrayOf(ld7_5, ld15, ld30)),810 RtpEncodingDesc(ssrc2.toLong(), arrayOf(sd7_5, sd15, sd30)),811 RtpEncodingDesc(ssrc3.toLong(), arrayOf(hd7_5, hd15, hd30))812 )813)814val bitrateLd = 150.kbps815val bitrateSd = 500.kbps816val bitrateHd = 2000.kbps817val ld7_5818 get() = createLayer(tid = 0, eid = 0, height = 180, frameRate = 7.5, bitrate = bitrateLd * 0.33)819val ld15820 get() = createLayer(tid = 1, eid = 0, height = 180, frameRate = 15.0, bitrate = bitrateLd * 0.66)821val ld30822 get() = createLayer(tid = 2, eid = 0, height = 180, frameRate = 30.0, bitrate = bitrateLd)823val sd7_5824 get() = createLayer(tid = 0, eid = 1, height = 360, frameRate = 7.5, bitrate = bitrateSd * 0.33)825val sd15826 get() = createLayer(tid = 1, eid = 1, height = 360, frameRate = 15.0, bitrate = bitrateSd * 0.66)827val sd30828 get() = createLayer(tid = 2, eid = 1, height = 360, frameRate = 30.0, bitrate = bitrateSd)829val hd7_5830 get() = createLayer(tid = 0, eid = 2, height = 720, frameRate = 7.5, bitrate = bitrateHd * 0.33)831val hd15832 get() = createLayer(tid = 1, eid = 2, height = 720, frameRate = 15.0, bitrate = bitrateHd * 0.66)833val hd30834 get() = createLayer(tid = 2, eid = 2, height = 720, frameRate = 30.0, bitrate = bitrateHd)835val noVideo836 get() = createLayer(tid = -1, eid = -1, height = 0, frameRate = 0.0, bitrate = 0.bps)837fun createLayer(838 tid: Int,839 eid: Int,840 height: Int,841 frameRate: Double,842 /**843 * Note: this mock impl does not model the dependency layers, so the cumulative bitrate should be provided.844 */845 bitrate: Bandwidth846): RtpLayerDesc {847 val sid = -1848 val rtpLayerDesc = mockk<RtpLayerDesc>()849 every { rtpLayerDesc.eid } returns eid850 every { rtpLayerDesc.tid } returns tid851 every { rtpLayerDesc.sid } returns sid852 every { rtpLayerDesc.height } returns height853 every { rtpLayerDesc.frameRate } returns frameRate854 every { rtpLayerDesc.getBitrate(any()) } returns bitrate855 // This is copied from the real implementation.856 every { rtpLayerDesc.layerId } returns RtpLayerDesc.getIndex(0, sid, tid)857 every { rtpLayerDesc.index } returns RtpLayerDesc.getIndex(eid, sid, tid)858 return rtpLayerDesc859}...

Full Screen

Full Screen

matchers.kt

Source:matchers.kt Github

copy

Full Screen

1package io.kotest.matchers.collections2import io.kotest.assertions.print.print3import io.kotest.matchers.*4fun <T> Iterable<T>.shouldHaveElementAt(index: Int, element: T) = toList().shouldHaveElementAt(index, element)5fun <T> Array<T>.shouldHaveElementAt(index: Int, element: T) = asList().shouldHaveElementAt(index, element)6fun <T> List<T>.shouldHaveElementAt(index: Int, element: T) = this should haveElementAt(index, element)7fun <T> Iterable<T>.shouldNotHaveElementAt(index: Int, element: T) = toList().shouldNotHaveElementAt(index, element)8fun <T> Array<T>.shouldNotHaveElementAt(index: Int, element: T) = asList().shouldNotHaveElementAt(index, element)9fun <T> List<T>.shouldNotHaveElementAt(index: Int, element: T) = this shouldNot haveElementAt(index, element)10fun <T, L : List<T>> haveElementAt(index: Int, element: T) = object : Matcher<L> {11 override fun test(value: L) =12 MatcherResult(13 index < value.size && value[index] == element,14 { "Collection ${value.print().value} should contain ${element.print().value} at index $index" },15 { "Collection ${value.print().value} should not contain ${element.print().value} at index $index" }16 )17}18infix fun <T> Iterable<T>.shouldHaveSingleElement(t: T): Iterable<T> {19 toList().shouldHaveSingleElement(t)20 return this21}22infix fun <T> Array<T>.shouldHaveSingleElement(t: T): Array<T> {23 asList().shouldHaveSingleElement(t)24 return this25}26infix fun <T> Iterable<T>.shouldHaveSingleElement(p: (T) -> Boolean): Iterable<T> {27 toList().shouldHaveSingleElement(p)28 return this29}30infix fun <T> Array<T>.shouldHaveSingleElement(p: (T) -> Boolean) = asList().shouldHaveSingleElement(p)31infix fun <T> Collection<T>.shouldHaveSingleElement(t: T) = this should singleElement(t)32infix fun <T> Collection<T>.shouldHaveSingleElement(p: (T) -> Boolean) = this should singleElement(p)33infix fun <T> Iterable<T>.shouldNotHaveSingleElement(t: T) = toList().shouldNotHaveSingleElement(t)34infix fun <T> Array<T>.shouldNotHaveSingleElement(t: T) = asList().shouldNotHaveSingleElement(t)35infix fun <T> Collection<T>.shouldNotHaveSingleElement(t: T) = this shouldNot singleElement(t)36infix fun <T> Iterable<T>.shouldExist(p: (T) -> Boolean) = toList().shouldExist(p)37infix fun <T> Array<T>.shouldExist(p: (T) -> Boolean) = asList().shouldExist(p)38infix fun <T> Collection<T>.shouldExist(p: (T) -> Boolean) = this should exist(p)39fun <T> exist(p: (T) -> Boolean) = object : Matcher<Collection<T>> {40 override fun test(value: Collection<T>) = MatcherResult(41 value.any { p(it) },42 { "Collection ${value.print().value} should contain an element that matches the predicate $p" },43 {44 "Collection ${value.print().value} should not contain an element that matches the predicate $p"45 })46}47fun <T> Iterable<T>.shouldMatchInOrder(vararg assertions: (T) -> Unit) = toList().shouldMatchInOrder(assertions.toList())48fun <T> Array<T>.shouldMatchInOrder(vararg assertions: (T) -> Unit) = asList().shouldMatchInOrder(assertions.toList())49fun <T> List<T>.shouldMatchInOrder(vararg assertions: (T) -> Unit) = this.shouldMatchInOrder(assertions.toList())50infix fun <T> Iterable<T>.shouldMatchInOrder(assertions: List<(T) -> Unit>) = toList().shouldMatchInOrder(assertions)51infix fun <T> Array<T>.shouldMatchInOrder(assertions: List<(T) -> Unit>) = asList().shouldMatchInOrder(assertions)52infix fun <T> List<T>.shouldMatchInOrder(assertions: List<(T) -> Unit>) = this should matchInOrder(assertions.toList(), allowGaps = false)53fun <T> Iterable<T>.shouldNotMatchInOrder(vararg assertions: (T) -> Unit) = toList().shouldNotMatchInOrder(assertions.toList())54fun <T> Array<T>.shouldNotMatchInOrder(vararg assertions: (T) -> Unit) = asList().shouldNotMatchInOrder(assertions.toList())55fun <T> List<T>.shouldNotMatchInOrder(vararg assertions: (T) -> Unit) = this.shouldNotMatchInOrder(assertions.toList())56infix fun <T> Iterable<T>.shouldNotMatchInOrder(assertions: List<(T) -> Unit>) = toList().shouldNotMatchInOrder(assertions)57infix fun <T> Array<T>.shouldNotMatchInOrder(assertions: List<(T) -> Unit>) = asList().shouldNotMatchInOrder(assertions)58infix fun <T> List<T>.shouldNotMatchInOrder(assertions: List<(T) -> Unit>) = this shouldNot matchInOrder(assertions.toList(), allowGaps = false)59fun <T> Iterable<T>.shouldMatchInOrderSubset(vararg assertions: (T) -> Unit) = toList().shouldMatchInOrderSubset(assertions.toList())60fun <T> Array<T>.shouldMatchInOrderSubset(vararg assertions: (T) -> Unit) = asList().shouldMatchInOrderSubset(assertions.toList())61fun <T> List<T>.shouldMatchInOrderSubset(vararg assertions: (T) -> Unit) = this.shouldMatchInOrderSubset(assertions.toList())62infix fun <T> Iterable<T>.shouldMatchInOrderSubset(assertions: List<(T) -> Unit>) = toList().shouldMatchInOrderSubset(assertions)63infix fun <T> Array<T>.shouldMatchInOrderSubset(assertions: List<(T) -> Unit>) = asList().shouldMatchInOrderSubset(assertions)64infix fun <T> List<T>.shouldMatchInOrderSubset(assertions: List<(T) -> Unit>) = this should matchInOrder(assertions.toList(), allowGaps = true)65fun <T> Iterable<T>.shouldNotMatchInOrderSubset(vararg assertions: (T) -> Unit) = toList().shouldNotMatchInOrderSubset(assertions.toList())66fun <T> Array<T>.shouldNotMatchInOrderSubset(vararg assertions: (T) -> Unit) = asList().shouldNotMatchInOrderSubset(assertions.toList())67fun <T> List<T>.shouldNotMatchInOrderSubset(vararg assertions: (T) -> Unit) = this.shouldNotMatchInOrderSubset(assertions.toList())68infix fun <T> Iterable<T>.shouldNotMatchInOrderSubset(assertions: List<(T) -> Unit>) = toList().shouldNotMatchInOrderSubset(assertions)69infix fun <T> Array<T>.shouldNotMatchInOrderSubset(assertions: List<(T) -> Unit>) = asList().shouldNotMatchInOrderSubset(assertions)70infix fun <T> List<T>.shouldNotMatchInOrderSubset(assertions: List<(T) -> Unit>) = this shouldNot matchInOrder(assertions.toList(), allowGaps = true)71fun <T> Iterable<T>.shouldMatchEach(vararg assertions: (T) -> Unit) = toList().shouldMatchEach(assertions.toList())72fun <T> Array<T>.shouldMatchEach(vararg assertions: (T) -> Unit) = asList().shouldMatchEach(assertions.toList())73fun <T> List<T>.shouldMatchEach(vararg assertions: (T) -> Unit) = this.shouldMatchEach(assertions.toList())74infix fun <T> Iterable<T>.shouldMatchEach(assertions: List<(T) -> Unit>) = toList().shouldMatchEach(assertions)75infix fun <T> Array<T>.shouldMatchEach(assertions: List<(T) -> Unit>) = asList().shouldMatchEach(assertions)76infix fun <T> List<T>.shouldMatchEach(assertions: List<(T) -> Unit>) = this should matchEach(assertions.toList())77fun <T> Iterable<T>.shouldNotMatchEach(vararg assertions: (T) -> Unit) = toList().shouldNotMatchEach(assertions.toList())78fun <T> Array<T>.shouldNotMatchEach(vararg assertions: (T) -> Unit) = asList().shouldNotMatchEach(assertions.toList())79fun <T> List<T>.shouldNotMatchEach(vararg assertions: (T) -> Unit) = this.shouldNotMatchEach(assertions.toList())80infix fun <T> Iterable<T>.shouldNotMatchEach(assertions: List<(T) -> Unit>) = toList().shouldNotMatchEach(assertions)81infix fun <T> Array<T>.shouldNotMatchEach(assertions: List<(T) -> Unit>) = asList().shouldNotMatchEach(assertions)82infix fun <T> List<T>.shouldNotMatchEach(assertions: List<(T) -> Unit>) = this shouldNot matchEach(assertions.toList())83fun <T> Iterable<T>.shouldExistInOrder(vararg ps: (T) -> Boolean) = toList().shouldExistInOrder(ps.toList())84fun <T> Array<T>.shouldExistInOrder(vararg ps: (T) -> Boolean) = asList().shouldExistInOrder(ps.toList())85fun <T> List<T>.shouldExistInOrder(vararg ps: (T) -> Boolean) = this.shouldExistInOrder(ps.toList())86infix fun <T> Iterable<T>.shouldExistInOrder(expected: List<(T) -> Boolean>) = toList().shouldExistInOrder(expected)87infix fun <T> Array<T>.shouldExistInOrder(expected: List<(T) -> Boolean>) = asList().shouldExistInOrder(expected)88infix fun <T> List<T>.shouldExistInOrder(expected: List<(T) -> Boolean>) = this should existInOrder(expected)89infix fun <T> Iterable<T>.shouldNotExistInOrder(expected: Iterable<(T) -> Boolean>) =90 toList().shouldNotExistInOrder(expected.toList())91infix fun <T> Array<T>.shouldNotExistInOrder(expected: Array<(T) -> Boolean>) =92 asList().shouldNotExistInOrder(expected.asList())93infix fun <T> Iterable<T>.shouldNotExistInOrder(expected: List<(T) -> Boolean>) =94 toList().shouldNotExistInOrder(expected)95infix fun <T> Array<T>.shouldNotExistInOrder(expected: List<(T) -> Boolean>) = asList().shouldNotExistInOrder(expected)96infix fun <T> List<T>.shouldNotExistInOrder(expected: List<(T) -> Boolean>) = this shouldNot existInOrder(expected)97fun <T> Iterable<T>.shouldContainAnyOf(vararg ts: T) = toList().shouldContainAnyOf(ts)98fun <T> Array<T>.shouldContainAnyOf(vararg ts: T) = asList().shouldContainAnyOf(ts)99fun <T> Collection<T>.shouldContainAnyOf(vararg ts: T) = this should containAnyOf(ts.asList())100fun <T> Iterable<T>.shouldNotContainAnyOf(vararg ts: T) = toList().shouldNotContainAnyOf(ts)101fun <T> Array<T>.shouldNotContainAnyOf(vararg ts: T) = asList().shouldNotContainAnyOf(ts)102fun <T> Collection<T>.shouldNotContainAnyOf(vararg ts: T) = this shouldNot containAnyOf(ts.asList())103infix fun <T> Iterable<T>.shouldContainAnyOf(ts: Collection<T>) = toList().shouldContainAnyOf(ts)104infix fun <T> Array<T>.shouldContainAnyOf(ts: Collection<T>) = asList().shouldContainAnyOf(ts)105infix fun <T> Collection<T>.shouldContainAnyOf(ts: Collection<T>) = this should containAnyOf(ts)106infix fun <T> Iterable<T>.shouldNotContainAnyOf(ts: Collection<T>) = toList().shouldNotContainAnyOf(ts)107infix fun <T> Array<T>.shouldNotContainAnyOf(ts: Collection<T>) = asList().shouldNotContainAnyOf(ts)108infix fun <T> Collection<T>.shouldNotContainAnyOf(ts: Collection<T>) = this shouldNot containAnyOf(ts)109fun <T> containAnyOf(ts: Collection<T>) = object : Matcher<Collection<T>> {110 override fun test(value: Collection<T>): MatcherResult {111 if (ts.isEmpty()) throwEmptyCollectionError()112 return MatcherResult(113 ts.any { it in value },114 { "Collection ${value.print().value} should contain any of ${ts.print().value}" },115 { "Collection ${value.print().value} should not contain any of ${ts.print().value}" }116 )117 }118}119internal fun throwEmptyCollectionError(): Nothing {120 throw AssertionError("Asserting content on empty collection. Use Collection.shouldBeEmpty() instead.")121}...

Full Screen

Full Screen

List.shouldMatchInOrder

Using AI Code Generation

copy

Full Screen

1val list = listOf(1, 2, 3)2list.shouldMatchInOrder(listOf(1, 2, 3))3val list = listOf(1, 2, 3)4list.shouldNotMatchInOrder(listOf(1, 2, 3))5val list = listOf(1, 2, 3)6list.shouldBeEmpty()7val list = listOf(1, 2, 3)8list.shouldBeNotEmpty()9val list = listOf(1, 2, 3)10list.shouldHaveSize(3)11val list = listOf(1, 2, 3)12list.shouldHaveSameSizeAs(listOf(1, 2, 3))13val list = listOf(1, 2, 3)14list.shouldBeSorted()15val list = listOf(1, 2, 3)16list.shouldBeSortedWith(naturalOrder())17val list = listOf(1, 2, 3)18list.shouldBeSortedBy { it }19val list = listOf(1, 2, 3)20list.shouldBeSortedDescending()21val list = listOf(1, 2, 3)22list.shouldBeSortedByDescending { it }23val list = listOf(1, 2,

Full Screen

Full Screen

List.shouldMatchInOrder

Using AI Code Generation

copy

Full Screen

1val list = listOf(1, 2, 3)2list.shouldMatchInOrder(listOf(1, 2, 3))3val list = listOf(1, 2, 3)4list.shouldContainInOrder(listOf(1, 2))5val list = listOf(1, 2, 3)6list.shouldContainAll(listOf(1, 2))7val list = listOf(1, 2, 3)8list.shouldContainNone(listOf(4, 5))9val list = listOf(1, 2, 3)10list.shouldContainNoneInOrder(listOf(4, 5))11val list = listOf(1, 2, 3)12list.shouldContainNoneInOrder(listOf(4, 5))13val list = listOf(1, 2, 2, 3)14list.shouldContainDuplicates()15val list = listOf(1, 2, 3)16list.shouldNotContainDuplicates()17val list = listOf(1, 2, 2, 3)18list.shouldHaveDuplicates()19val list = listOf(1, 2, 3)20list.shouldNotHaveDuplicates()21val list = listOf(1, 2, 3)22list.shouldHaveSize(3)

Full Screen

Full Screen

List.shouldMatchInOrder

Using AI Code Generation

copy

Full Screen

1val list = listOf ( 1 , 2 , 3 , 4 , 5 )2list.shouldMatchInOrder ( listOf ( 1 , 2 , 3 , 4 , 5 ))3val list = listOf ( 1 , 2 , 3 , 4 , 5 )4list.shouldNotMatchInOrder ( listOf ( 1 , 2 , 3 , 4 , 5 ))5val list = listOf ()6list.shouldBeEmpty ()7val list = listOf ( 1 , 2 , 3 , 4 , 5 )8list.shouldBeSorted ()9val list = listOf ( 1 , 2 , 3 , 4 , 5 )10list.shouldBeSortedWith ( Comparator { a , b -> b - a })11val list = listOf ( 1 , 2 , 3 , 4 , 5 )12list.shouldBeSortedBy { it }13val list = listOf ( 1 , 2 , 3 , 4 , 5 )14list.shouldBeSortedDescending ()15val list = listOf ( 1 , 2 , 3 , 4 , 5 )16list.shouldContainDuplicates ()17val list = listOf ( 1 , 2 , 3 , 4 , 5 )18list.shouldContainDuplicatesBy { it }19val list = listOf ( 1 , 2 , 3 , 4 , 5 )20list.shouldContain ( 1 )

Full Screen

Full Screen

List.shouldMatchInOrder

Using AI Code Generation

copy

Full Screen

1val actual = listOf("a", "b", "c")2actual.shouldMatchInOrder(listOf("a", "b", "c"))3val actual = listOf("a", "b", "c")4actual.shouldMatchInAnyOrder(listOf("b", "c", "a"))5val actual = listOf("a", "b", "c")6actual.shouldHaveSize(3)7val actual = listOf("a")8actual.shouldHaveSingleElement()9val actual = listOf("a", "b", "c")10actual.shouldContainAll(listOf("b", "c"))11val actual = listOf("a", "b", "c")12actual.shouldContain("b")13val actual = listOf("a", "b", "c")14actual.shouldContainNone(listOf("d", "e"))15val actual = listOf("a", "b", "c")16actual.shouldContainExactly(listOf("c", "b", "a"))17val actual = listOf("a", "b", "c")18actual.shouldContainExactlyInAnyOrder(listOf("c", "b", "a"))19val actual = listOf("a", "b", "c")20actual.shouldContainInOrder(listOf("a", "b"))21val actual = listOf("a", "b", "c")22actual.shouldContainInstanceOf<String>()

Full Screen

Full Screen

List.shouldMatchInOrder

Using AI Code Generation

copy

Full Screen

1List.shouldMatchInOrder ( 1 , 2 , 3 )2List.shouldMatchInOrder ( 1 , 2 , 3 ) shouldThrow AssertionError :: class3List.shouldMatchInOrder ( 1 , 2 , 3 , 4 ) shouldThrow AssertionError :: class4List.shouldMatchInOrder ( 1 , 2 , 4 ) shouldThrow AssertionError :: class5List.shouldMatchInOrder ( 1 , 2 , 3 ) shouldNotThrow AssertionError :: class6List.shouldMatchInOrder ( 1 , 2 , 3 , 4 ) shouldNotThrow AssertionError :: class7List.shouldMatchInOrder ( 1 , 2 , 4 ) shouldNotThrow AssertionError :: 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.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful