How to use Array.shouldNotContain method of io.kotest.matchers.collections.contain class

Best Kotest code snippet using io.kotest.matchers.collections.contain.Array.shouldNotContain

TestLineTrace.kt

Source:TestLineTrace.kt Github

copy

Full Screen

1package edu.illinois.cs.cs125.jeed.core2import io.kotest.core.spec.style.StringSpec3import io.kotest.matchers.collections.beEmpty4import io.kotest.matchers.collections.shouldContain5import io.kotest.matchers.collections.shouldHaveAtLeastSize6import io.kotest.matchers.collections.shouldHaveAtMostSize7import io.kotest.matchers.collections.shouldHaveSize8import io.kotest.matchers.collections.shouldNotContain9import io.kotest.matchers.ints.beGreaterThan10import io.kotest.matchers.ints.shouldBeGreaterThan11import io.kotest.matchers.ints.shouldBeGreaterThanOrEqual12import io.kotest.matchers.ints.shouldBeLessThanOrEqual13import io.kotest.matchers.longs.shouldBeGreaterThan14import io.kotest.matchers.longs.shouldBeLessThanOrEqual15import io.kotest.matchers.should16import io.kotest.matchers.shouldBe17import io.kotest.matchers.shouldNot18import io.kotest.matchers.shouldNotBe19import io.kotest.matchers.string.endWith20import io.kotest.matchers.string.shouldStartWith21import io.kotest.matchers.types.beInstanceOf22import org.junit.jupiter.api.assertThrows23import java.lang.reflect.InvocationTargetException24class TestLineTrace : StringSpec({25 "should trace a main method" {26 val result = Source.fromJava(27 """28public class Main {29 public static void main() {30 int i = 4;31 i += 1;32 System.out.println(i);33 }34}""".trim()35 ).compile().execute(SourceExecutionArguments().addPlugin(LineTrace))36 result should haveCompleted()37 result should haveOutput("5")38 val trace = result.pluginResult(LineTrace)39 trace.steps shouldHaveAtLeastSize 340 trace.steps[0] shouldBe LineTraceResult.LineStep("Main.java", 3, 0)41 }42 "should trace an if statement" {43 val result = Source.fromJava(44 """45public class Main {46 public static void main() {47 int i = 4;48 if (i > 1) {49 System.out.println("yes");50 }51 }52}""".trim()53 ).compile().execute(SourceExecutionArguments().addPlugin(LineTrace))54 result should haveCompleted()55 result should haveOutput("yes")56 val trace = result.pluginResult(LineTrace)57 trace.steps shouldHaveAtLeastSize 358 trace.steps.map { it.line } shouldContain 559 }60 "should show that an if statement wasn't entered" {61 val result = Source.fromJava(62 """63public class Main {64 public static void main() {65 int i = 4;66 if (i > 9) {67 System.out.println("yes");68 System.out.println("the universe has fractured");69 System.out.println("all is possible");70 }71 }72}""".trim()73 ).compile().execute(SourceExecutionArguments().addPlugin(LineTrace))74 result should haveCompleted()75 result should haveOutput("")76 val trace = result.pluginResult(LineTrace)77 trace.steps shouldHaveAtMostSize 378 trace.steps.map { it.line } shouldNotContain 579 }80 "should trace an if-else statement" {81 val result = Source.fromJava(82 """83public class Main {84 public static void main() {85 int i = 0;86 if (i > 1) {87 System.out.println("yes");88 } else {89 System.out.println("no");90 }91 }92}""".trim()93 ).compile().execute(SourceExecutionArguments().addPlugin(LineTrace))94 result should haveCompleted()95 result should haveOutput("no")96 val trace = result.pluginResult(LineTrace)97 trace.steps.map { it.line } shouldNotContain 598 trace.steps.map { it.line } shouldContain 799 }100 "should trace a for loop" {101 val result = Source.fromJava(102 """103public class Main {104 public static void main() {105 for (int i = 0; i < 3; i++) {106 System.out.println(i);107 }108 }109}""".trim()110 ).compile().execute(SourceExecutionArguments().addPlugin(LineTrace))111 result should haveCompleted()112 result should haveOutput("0\n1\n2")113 val trace = result.pluginResult(LineTrace)114 trace.steps.filter { it.line == 4 }.size shouldBe 3115 trace.steps.filter { it.line == 3 }.size shouldBe 4116 }117 "should trace a while loop" {118 val result = Source.fromJava(119 """120public class Main {121 public static void main() {122 int i = 20;123 while (i > 0) {124 System.out.println(i);125 i /= 2;126 if (i % 2 != 0) {127 i -= 1;128 }129 }130 }131}""".trim()132 ).compile().execute(SourceExecutionArguments().addPlugin(LineTrace))133 result should haveCompleted()134 result should haveOutput("20\n10\n4\n2")135 val trace = result.pluginResult(LineTrace)136 trace.steps.filter { it.line == 5 }.size shouldBe 4137 trace.steps.filter { it.line == 8 }.size shouldBe 2138 }139 "should trace a try-catch-finally block" {140 val result = Source.fromJava(141 """142public class Main {143 public static void main() {144 try {145 System.out.println("Try");146 String s = null;147 s.toString();148 System.out.println("Hmm");149 } catch (Exception e) {150 System.out.println("Catch");151 } finally {152 System.out.println("Finally");153 }154 }155}""".trim()156 ).compile().execute(SourceExecutionArguments().addPlugin(LineTrace))157 result should haveCompleted()158 result should haveOutput("Try\nCatch\nFinally")159 val trace = result.pluginResult(LineTrace)160 trace.steps.filter { it.line == 4 }.size shouldBe 1161 trace.steps.filter { it.line == 7 }.size shouldBe 0162 trace.steps.filter { it.line == 9 }.size shouldBe 1163 trace.steps.filter { it.line == 11 }.size shouldBe 1164 }165 "should trace multiple functions" {166 val result = Source.fromJava(167 """168public class Main {169 public static void main() {170 for (int i = 0; i < 10; i++) {171 showIfOdd(i);172 }173 System.out.println("Done");174 }175 private static void showIfOdd(int i) {176 if (i % 2 != 0) {177 System.out.println(i);178 }179 }180}""".trim()181 ).compile().execute(SourceExecutionArguments().addPlugin(LineTrace))182 result should haveCompleted()183 result should haveOutput("1\n3\n5\n7\n9\nDone")184 val trace = result.pluginResult(LineTrace)185 trace.steps.filter { it.line == 4 }.size shouldBe 10186 trace.steps.filter { it.line == 6 }.size shouldBe 1187 trace.steps.filter { it.line == 9 }.size shouldBe 10188 trace.steps.filter { it.line == 10 }.size shouldBe 5189 }190 "should trace multiple classes" {191 val result = Source.fromJava(192 """193public class Main {194 public static void main() {195 for (int i = 0; i < 10; i++) {196 ShowIfOdd.showIfOdd(i);197 }198 System.out.println("Done");199 }200}201public class ShowIfOdd {202 public static void showIfOdd(int i) {203 if (i % 2 != 0) {204 System.out.println(i);205 }206 }207}""".trim()208 ).compile().execute(SourceExecutionArguments().addPlugin(LineTrace))209 result should haveCompleted()210 result should haveOutput("1\n3\n5\n7\n9\nDone")211 val trace = result.pluginResult(LineTrace)212 trace.steps.filter { it.line == 4 }.size shouldBe 10213 trace.steps.filter { it.line == 6 }.size shouldBe 1214 trace.steps.filter { it.line == 11 }.size shouldBe 10215 trace.steps.filter { it.line == 12 }.size shouldBe 5216 trace.linesRun shouldBe trace.steps.size217 }218 "should trace multiple files" {219 val result = Source(220 mapOf(221 "Main.java" to """222public class Main {223 public static void main() {224 for (int i = 0; i < 10; i++) {225 ShowIfOdd.showIfOdd(i);226 }227 System.out.println("Done");228 }229}""".trim(),230 "ShowIfOdd.java" to """231public class ShowIfOdd {232 public static void showIfOdd(int i) {233 if (i % 2 != 0) {234 System.out.println(i);235 }236 }237}""".trim()238 )239 ).compile().execute(SourceExecutionArguments().addPlugin(LineTrace))240 result should haveCompleted()241 result should haveOutput("1\n3\n5\n7\n9\nDone")242 val trace = result.pluginResult(LineTrace)243 trace.steps.filter { it.source == "Main.java" && it.line == 4 }.size shouldBe 10244 trace.steps.filter { it.source == "Main.java" && it.line == 6 }.size shouldBe 1245 trace.steps.filter { it.source == "ShowIfOdd.java" && it.line == 3 }.size shouldBe 10246 trace.steps.filter { it.source == "ShowIfOdd.java" && it.line == 4 }.size shouldBe 5247 }248 "should trace a simple snippet" {249 val source = Source.fromSnippet(250 """System.out.println("Hello");""".trim()251 )252 val result = source.compile().execute(SourceExecutionArguments().addPlugin(LineTrace))253 result should haveCompleted()254 result should haveOutput("Hello")255 val trace = result.pluginResult(LineTrace).remap(source)256 trace.steps shouldHaveSize 1257 trace.steps[0].line shouldBe 1258 }259 "should trace a snippet" {260 val source = Source.fromSnippet(261 """262 printWithObject();263 264 void printWithObject() {265 new Printer().print();266 }267 268 class Printer {269 void print() {270 System.out.println("Hello");271 }272 void unused() {273 System.out.println("Unused");274 }275 }276 """.trimIndent().trim()277 )278 val result = source.compile().execute(SourceExecutionArguments().addPlugin(LineTrace))279 result should haveCompleted()280 result should haveOutput("Hello")281 val trace = result.pluginResult(LineTrace).remap(source)282 trace.steps shouldHaveAtLeastSize 3283 trace.steps[0].line shouldBe 1284 trace.steps.filter { it.line == 4 }.size shouldBe 1285 trace.steps.filter { it.line == 9 }.size shouldBe 1286 trace.steps.filter { it.line == 12 }.size shouldBe 0287 }288 "should report multiple calls during external iteration" {289 val source = Source.fromSnippet(290 """291 import java.util.ArrayList;292 var list = new ArrayList<String>();293 list.add("a");294 list.add("b");295 list.add("c");296 list.forEach(s -> {297 System.out.println(s); }); // Crazy bracing to ensure only this line is called298 """.trimIndent()299 )300 val result = source.compile().execute(SourceExecutionArguments().addPlugin(LineTrace))301 result should haveCompleted()302 result should haveOutput("a\nb\nc")303 val trace = result.pluginResult(LineTrace).remap(source)304 trace.steps.filter { it.line == 6 }.size shouldBe 1305 trace.steps.filter { it.line == 7 }.size shouldBe 3306 }307 "should stop logging lines after reaching the recording limit" {308 val source = Source.fromSnippet(309 """310 long i = 0;311 while (true) {312 i += 2;313 i -= 1;314 }315 """.trimIndent()316 )317 val lineTraceArguments = LineTraceArguments(recordedLineLimit = 5000L) // Reduced because slow under debugger318 val result = source.compile().execute(SourceExecutionArguments().addPlugin(LineTrace, lineTraceArguments))319 result should haveTimedOut()320 val rawTrace = result.pluginResult(LineTrace)321 val trace = rawTrace.remap(source)322 trace.steps.filter { it.line == 3 }.size shouldBeGreaterThan 100323 rawTrace.steps.size shouldBe lineTraceArguments.recordedLineLimit324 }325 "should keep counting after reaching the recording limit" {326 val source = Source.fromSnippet(327 """328 long i = 0;329 while (true) {330 i += 2;331 i -= 1;332 }333 """.trimIndent()334 )335 val lineTraceArguments = LineTraceArguments(recordedLineLimit = 5000L)336 val result = source.compile().execute(SourceExecutionArguments().addPlugin(LineTrace, lineTraceArguments))337 result should haveTimedOut()338 val trace = result.pluginResult(LineTrace).remap(source)339 trace.linesRun.toInt() should beGreaterThan(trace.arguments.recordedLineLimit.toInt())340 }341 "should trace a Kotlin method" {342 val result = Source.fromKotlin(343 """344 fun main() {345 println("Hello")346 }347 """.trimIndent()348 ).kompile().execute(SourceExecutionArguments().addPlugin(LineTrace))349 result should haveCompleted()350 result should haveOutput("Hello")351 val trace = result.pluginResult(LineTrace)352 trace.steps shouldHaveAtMostSize 2353 trace.steps[0].line shouldBe 2354 }355 "should trace a Kotlin forEach loop" {356 val source = Source.fromKotlin(357 """358 fun main() {359 (1..3).forEach {360 println(it * it)361 }362 }363 """.trimIndent()364 )365 val result = source.kompile().execute(SourceExecutionArguments().addPlugin(LineTrace))366 result should haveCompleted()367 result should haveOutput("1\n4\n9")368 val trace = result.pluginResult(LineTrace).remap(source)369 trace.steps shouldHaveAtLeastSize 4370 trace.steps[0].line shouldBe 2371 trace.steps.filter { it.line == 3 }.size shouldBe 3372 trace.steps.filter { it.line == 5 }.size shouldBe 1373 trace.steps.filter { it.line > 5 }.size shouldBe 0374 }375 "should trace across Kotlin files" {376 val source = Source(377 mapOf(378 "Main.kt" to """379fun main() {380 println(test())381}382 """.trim(),383 "Test.kt" to """384fun test(): List<String> {385 return listOf("test", "me")386}387 """.trim()388 )389 )390 val result = source.kompile().execute(SourceExecutionArguments().addPlugin(LineTrace))391 result should haveCompleted()392 result should haveOutput("[test, me]")393 val trace = result.pluginResult(LineTrace).remap(source)394 trace.steps shouldHaveAtLeastSize 2395 trace.steps[0] shouldBe LineTraceResult.LineStep("Main.kt", 2, 0)396 trace.steps[1] shouldBe LineTraceResult.LineStep("Test.kt", 2, 0)397 }398 "should trace a simple Kotlin snippet" {399 val source = Source.fromSnippet(400 """println("Hi")""", SnippetArguments(fileType = Source.FileType.KOTLIN)401 )402 val result = source.kompile().execute(SourceExecutionArguments().addPlugin(LineTrace))403 result should haveCompleted()404 result should haveOutput("Hi")405 val trace = result.pluginResult(LineTrace).remap(source)406 trace.steps shouldHaveSize 1407 trace.steps[0].line shouldBe 1408 }409 "should trace a Kotlin snippet with a loop" {410 val source = Source.fromSnippet(411 """412 val fruits = listOf("apple", "banana")413 fruits.forEach {414 println(it + ".")415 }416 """.trimIndent(),417 SnippetArguments(fileType = Source.FileType.KOTLIN)418 )419 val result = source.kompile().execute(SourceExecutionArguments().addPlugin(LineTrace))420 result should haveCompleted()421 result should haveOutput("apple.\nbanana.")422 val trace = result.pluginResult(LineTrace).remap(source)423 trace.steps shouldHaveAtLeastSize 5424 trace.steps[0].line shouldBe 1425 trace.steps.filter { it.line == 3 }.size shouldBe 2426 }427 "should trace a Kotlin snippet with an if expression" {428 val source = Source.fromSnippet(429 """430 val i = System.currentTimeMillis() // Avoid compile-time evaluation431 val verdict = if (i > 0) {432 "Positive"433 } else {434 "Non-positive"435 }436 println(verdict)437 """.trimIndent(),438 SnippetArguments(fileType = Source.FileType.KOTLIN)439 )440 val result = source.kompile().execute(SourceExecutionArguments().addPlugin(LineTrace))441 result should haveCompleted()442 result should haveOutput("Positive")443 val trace = result.pluginResult(LineTrace).remap(source)444 trace.steps shouldHaveAtLeastSize 4 // NOTE: Storing the if expression's result visits line 2 again445 trace.steps[0].line shouldBe 1446 trace.steps[1].line shouldBe 2447 trace.steps[2].line shouldBe 3448 trace.steps.last().line shouldBe 7449 trace.steps.filter { it.line == 5 }.size shouldBe 0450 }451 "should trace a Kotlin snippet with a loop and inlined method" {452 val source = Source.fromSnippet(453 """454 val fruits = listOf("apple", "banana")455 fruits.forEach {456 println(it.uppercase())457 }458 """.trimIndent(),459 SnippetArguments(fileType = Source.FileType.KOTLIN)460 )461 val result = source.kompile().execute(SourceExecutionArguments().addPlugin(LineTrace))462 result should haveCompleted()463 result should haveOutput("APPLE\nBANANA")464 val trace = result.pluginResult(LineTrace).remap(source)465 trace.steps shouldHaveAtLeastSize 3466 trace.steps[0].line shouldBe 1467 trace.steps.filter { it.line == 3 }.size shouldBe 2468 }469 "should skip Kotlin inline/loop duplicates" {470 val source = Source.fromSnippet(471 """472 val fruits = listOf("apple", "banana")473 fruits.forEach { println(it.uppercase()) }474 """.trimIndent(),475 SnippetArguments(fileType = Source.FileType.KOTLIN)476 )477 val result = source.kompile().execute(SourceExecutionArguments().addPlugin(LineTrace))478 result should haveCompleted()479 result should haveOutput("APPLE\nBANANA")480 val trace = result.pluginResult(LineTrace).remap(source)481 trace.steps.filter { it.line == 2 }.size shouldBeLessThanOrEqual 3482 }483 "should allow recording duplicates" {484 val source = Source.fromSnippet(485 """486 val fruits = listOf("apple", "banana")487 fruits.forEach { println(it.uppercase()) }488 """.trimIndent(),489 SnippetArguments(fileType = Source.FileType.KOTLIN)490 )491 val result = source.kompile().execute(492 SourceExecutionArguments().addPlugin(LineTrace, LineTraceArguments(coalesceDuplicates = false))493 )494 result should haveCompleted()495 result should haveOutput("APPLE\nBANANA")496 val trace = result.pluginResult(LineTrace).remap(source)497 trace.steps.filter { it.line == 2 }.size shouldBeGreaterThan 3498 }499 "should trace a Kotlin snippet with a method" {500 val source = Source.fromSnippet(501 """502 fun printLoud(text: String) {503 println(text.uppercase())504 }505 506 val fruits = listOf("apple", "banana")507 fruits.forEach(::printLoud)508 """.trimIndent(),509 SnippetArguments(fileType = Source.FileType.KOTLIN)510 )511 val result = source.kompile().execute(SourceExecutionArguments().addPlugin(LineTrace))512 result should haveCompleted()513 result should haveOutput("APPLE\nBANANA")514 val trace = result.pluginResult(LineTrace).remap(source)515 trace.steps shouldHaveAtLeastSize 4516 trace.steps[0].line shouldBe 5517 trace.steps.filter { it.line == 2 }.size shouldBeGreaterThanOrEqual 2518 trace.steps.filter { it.line == 3 }.size shouldBe 2519 trace.steps.filter { it.line == 4 }.size shouldBe 0520 }521 "should trace multiple threads" {522 val source = Source.fromSnippet(523 """524public class Example implements Runnable {525 public void run() {526 System.out.println("Ended");527 }528}529Thread thread = new Thread(new Example());530thread.start();531System.out.println("Started");532try {533 thread.join();534} catch (Exception e) {535 throw new RuntimeException(e);536}537 """.trim()538 )539 val result = source.compile().execute(SourceExecutionArguments(maxExtraThreads = 1).addPlugin(LineTrace))540 result should haveCompleted()541 result should haveOutput("Started\nEnded")542 val rawTrace = result.pluginResult(LineTrace)543 rawTrace.linesRun shouldBe rawTrace.steps.size544 val trace = rawTrace.remap(source)545 val mainLines = trace.steps.filter { it.threadIndex == 0 }.map { it.line }546 mainLines shouldContain 6547 mainLines shouldContain 10548 mainLines shouldNotContain 3549 val extraLines = trace.steps.filter { it.threadIndex == 1 }.map { it.line }550 extraLines shouldContain 3551 extraLines shouldNotContain 6552 trace.steps.filter { it.threadIndex >= 2 }.size shouldBe 0553 }554 "should trace multiple threads using coroutines" {555 val source = Source.fromKotlin(556 """557 import kotlinx.coroutines.*558 fun main() {559 GlobalScope.launch {560 delay(100)561 println("Finished")562 }563 println("Started")564 }565 """.trimIndent()566 )567 val executionArgs = SourceExecutionArguments(waitForShutdown = true, timeout = 2000).addPlugin(LineTrace)568 val result = source.kompile().execute(executionArgs)569 result should haveCompleted()570 result should haveOutput("Started\nFinished")571 val rawTrace = result.pluginResult(LineTrace)572 rawTrace.linesRun shouldBe rawTrace.steps.size573 val trace = rawTrace.remap(source)574 val mainLines = trace.steps.filter { it.threadIndex == 0 }.map { it.line }575 mainLines shouldContain 3576 mainLines shouldContain 7577 mainLines shouldNotContain 5578 val extraLines = trace.steps.filter { it.threadIndex == 1 }.map { it.line }579 extraLines shouldContain 5580 extraLines shouldNotContain 7581 trace.steps.filter { it.threadIndex >= 2 }.size shouldBe 0582 trace.steps.filter { it.source != "Main.kt" }.size shouldBe 0583 }584 "should limit executed lines by killing the sandbox" {585 val source = Source.fromSnippet(586 """587 long i = 0;588 while (true) {589 i += 2;590 i -= 1;591 }592 """.trimIndent()593 )594 val result = source.compile().execute(595 SourceExecutionArguments().addPlugin(596 LineTrace, LineTraceArguments(recordedLineLimit = 0, runLineLimit = 100)597 )598 )599 result should haveBeenKilled()600 result.killReason shouldBe LineTrace.KILL_REASON601 result shouldNot haveCompleted()602 result shouldNot haveTimedOut()603 val trace = result.pluginResult(LineTrace)604 trace.linesRun shouldBe 100605 trace.steps should beEmpty()606 }607 "should limit executed lines by throwing an error" {608 val source = Source.fromSnippet(609 """610 try {611 long i = 0;612 while (true) {613 i += 2;614 i -= 1;615 }616 } catch (Throwable t) {}617 """.trimIndent()618 )619 val lineTraceArgs = LineTraceArguments(620 recordedLineLimit = 0,621 runLineLimit = 100,622 runLineLimitExceededAction = LineTraceArguments.RunLineLimitAction.THROW_ERROR623 )624 val result = source.compile().execute(SourceExecutionArguments().addPlugin(LineTrace, lineTraceArgs))625 result shouldNot haveBeenKilled()626 result shouldNot haveCompleted()627 result shouldNot haveTimedOut()628 result.threw should beInstanceOf<LineLimitExceeded>()629 val trace = result.pluginResult(LineTrace)630 trace.linesRun shouldBe 100631 }632 "should limit total lines from multiple threads" {633 val source = Source.fromSnippet(634 """635public class Example implements Runnable {636 public void run() {637 long e = 0;638 while (true) {639 e += 1;640 }641 }642}643Thread thread = new Thread(new Example());644thread.start();645long i = 0;646while (true) {647 i += 1;648}649 """.trim()650 )651 val lineTraceArgs = LineTraceArguments(runLineLimit = 10000)652 val result =653 source.compile().execute(SourceExecutionArguments(maxExtraThreads = 1).addPlugin(LineTrace, lineTraceArgs))654 result should haveBeenKilled()655 val rawTrace = result.pluginResult(LineTrace)656 rawTrace.linesRun.toInt() shouldBeGreaterThan rawTrace.steps.size - 3 // May be killed before incrementing657 rawTrace.linesRun.toInt() shouldBeLessThanOrEqual rawTrace.steps.size658 val trace = rawTrace.remap(source)659 val mainLines = trace.steps.filter { it.threadIndex == 0 }.map { it.line }660 mainLines shouldContain 10661 mainLines shouldNotContain 5662 val extraLines = trace.steps.filter { it.threadIndex == 1 }.map { it.line }663 extraLines shouldContain 5664 extraLines shouldNotContain 10665 trace.linesRun shouldBeLessThanOrEqual lineTraceArgs.runLineLimit!! + lineTraceArgs.maxUnsynchronizedLines666 }667 "should closely limit total lines if required" {668 val source = Source.fromSnippet(669 """670public class Example implements Runnable {671 public void run() {672 long e = 0;673 while (true) {674 e += 1;675 }676 }677}678Thread thread = new Thread(new Example());679thread.start();680long i = 0;681while (true) {682 i += 1;683}684 """.trim()685 )686 val lineTraceArgs = LineTraceArguments(687 runLineLimit = 10000, recordedLineLimit = 0, maxUnsynchronizedLines = 0688 )689 val compiledSource = source.compile()690 repeat(10) {691 val result = compiledSource.execute(692 SourceExecutionArguments(maxExtraThreads = 1).addPlugin(693 LineTrace, lineTraceArgs694 )695 )696 result should haveBeenKilled()697 val rawTrace = result.pluginResult(LineTrace)698 rawTrace.linesRun shouldBeLessThanOrEqual lineTraceArgs.runLineLimit!! + 1699 }700 }701 "should not allow untrusted code to reset the line counter" {702 val source = Source.fromSnippet(703 """edu.illinois.cs.cs125.jeed.core.LineTrace.resetLineCounts()""",704 SnippetArguments(fileType = Source.FileType.KOTLIN)705 )706 val result = source.kompile().execute(SourceExecutionArguments().addPlugin(LineTrace))707 result shouldNot haveCompleted()708 result.permissionDenied shouldBe true709 }710 "should allow trusted code to reset the line counter" {711 val compiledSource = Source.fromJava(712 """713public class Main {714 public static void print(String text, int times) {715 for (int i = 0; i < times; i++) {716 System.out.print(text);717 } // At least 2, probably 3 lines per iteration718 System.out.println("");719 }720}""".trim()721 ).compile()722 val lineTraceArgs = LineTraceArguments(723 recordedLineLimit = 0, runLineLimit = 25724 )725 val plugins = listOf(ConfiguredSandboxPlugin(LineTrace, lineTraceArgs))726 val subtaskLinesRun = mutableListOf<Long>()727 val result = Sandbox.execute(compiledSource.classLoader, configuredPlugins = plugins) { (loader, _) ->728 val method = loader.loadClass("Main").getMethod("print", String::class.java, Int::class.java)729 method(null, "A", 3)730 subtaskLinesRun.add(LineTrace.getCurrentReport().linesRun)731 LineTrace.resetLineCounts()732 method(null, "B", 4)733 subtaskLinesRun.add(LineTrace.getCurrentReport().linesRun)734 LineTrace.resetLineCounts()735 method(null, "C", 5)736 subtaskLinesRun.add(LineTrace.getCurrentReport().linesRun)737 }738 result should haveCompleted()739 @Suppress("SpellCheckingInspection")740 result should haveOutput("AAA\nBBBB\nCCCCC")741 subtaskLinesRun.size shouldBe 3742 subtaskLinesRun[0] shouldBeGreaterThan 7743 subtaskLinesRun[1] shouldBeGreaterThan 9744 subtaskLinesRun[2] shouldBeGreaterThan 11 // At least 27 lines run in total745 }746 "should allow trusted code to handle the limit exception" {747 val compiledSource = Source.fromJava(748 """749public class Main {750 public static void print(String text, int times) {751 try {752 for (int i = 0; i < times; i++) {753 System.out.print(text);754 }755 System.out.println("");756 } catch (Throwable t) {}757 }758}""".trim()759 ).compile()760 val lineTraceArgs = LineTraceArguments(761 recordedLineLimit = 0,762 runLineLimit = 15,763 runLineLimitExceededAction = LineTraceArguments.RunLineLimitAction.THROW_ERROR764 )765 val plugins = listOf(ConfiguredSandboxPlugin(LineTrace, lineTraceArgs))766 var hitLimit = false767 val result = Sandbox.execute(compiledSource.classLoader, configuredPlugins = plugins) { (loader, _) ->768 val method = loader.loadClass("Main").getMethod("print", String::class.java, Int::class.java)769 try {770 method(null, "A", 15)771 } catch (e: InvocationTargetException) {772 hitLimit = e.cause is LineLimitExceeded773 }774 LineTrace.resetLineCounts()775 method(null, "B", 2)776 }777 result should haveCompleted()778 result.output should endWith("BB")779 hitLimit shouldBe true780 }781 "should be compatible with Jacoco" {782 val result = Source.fromJava(783 """784public class Test {785 private int value;786 public Test() {787 value = 10;788 }789 public Test(int setValue) {790 value = setValue;791 }792}793public class Main {794 public static void main() {795 Test test = new Test(10);796 System.out.println("Done");797 }798}""".trim()799 ).compile().execute(SourceExecutionArguments().addPlugin(Jacoco).addPlugin(LineTrace))800 result.completed shouldBe true801 result.permissionDenied shouldNotBe true802 result should haveOutput("Done")803 val coverage = result.pluginResult(Jacoco)804 val testCoverage = coverage.classes.find { it.name == "Test" }!!805 testCoverage.lineCounter.missedCount shouldBeGreaterThanOrEqual 1806 testCoverage.lineCounter.coveredCount shouldBe 3807 val trace = result.pluginResult(LineTrace)808 trace.steps[0].line shouldBe 12809 trace.steps.map { it.line } shouldContain 7810 trace.steps.map { it.line } shouldNotContain 4811 }812 "should not be installable as a duplicate" {813 val source = Source.fromJava(814 """815public class Main {816 public static void main() {817 System.out.println("Done");818 }819}""".trim()820 )821 assertThrows<IllegalStateException> {822 source.compile().execute(SourceExecutionArguments().addPlugin(LineTrace).addPlugin(LineTrace))823 }.message shouldStartWith "Duplicate plugin: edu.illinois.cs.cs125.jeed.core.LineTrace"824 }825})...

Full Screen

Full Screen

ClassContainerJarTest.kt

Source:ClassContainerJarTest.kt Github

copy

Full Screen

1package com.anatawa12.relocator.internal2import com.anatawa12.relocator.file.SingleFile3import com.anatawa12.relocator.internal.ClassContainer.Jar.Companion.META_INF_VERSIONS4import io.kotest.core.spec.style.DescribeSpec5import io.kotest.matchers.*6import io.kotest.matchers.collections.shouldBeEmpty7import io.kotest.matchers.collections.shouldContain8import io.kotest.matchers.collections.shouldNotContain9import kotlinx.coroutines.Dispatchers10import kotlinx.coroutines.withContext11import java.io.OutputStream12import java.nio.file.Files13import java.util.jar.JarFile14import java.util.zip.ZipEntry15import java.util.zip.ZipOutputStream16class ClassContainerJarTest : DescribeSpec() {17 private fun makeJar(out: OutputStream, withManifest: Boolean) {18 ZipOutputStream(out).use { zipOut ->19 val writer = zipOut.writer()20 // root entries21 zipOut.putNextEntry(ZipEntry("root-only.txt"))22 writer.apply { write("root") }.flush()23 zipOut.putNextEntry(ZipEntry("9-root.txt"))24 writer.apply { write("root") }.flush()25 zipOut.putNextEntry(ZipEntry("9-10-root.txt"))26 writer.apply { write("root") }.flush()27 zipOut.putNextEntry(ZipEntry("8-root.txt"))28 writer.apply { write("root") }.flush()29 // release 9 entries for basic30 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/9/9-only.txt"))31 writer.apply { write("9") }.flush()32 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/9/9-root.txt"))33 writer.apply { write("9") }.flush()34 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/9/9-10-root.txt"))35 writer.apply { write("9") }.flush()36 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/9/9-10-only.txt"))37 writer.apply { write("9") }.flush()38 // release 10 entries for multiple release39 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/10/10-only.txt"))40 writer.apply { write("10") }.flush()41 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/10/9-10-root.txt"))42 writer.apply { write("10") }.flush()43 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/10/9-10-only.txt"))44 writer.apply { write("10") }.flush()45 // invalid version/release: 846 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/8/8-only.txt"))47 writer.apply { write("8") }.flush()48 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/8/8-root.txt"))49 writer.apply { write("8") }.flush()50 // files on META-INF/versions51 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/9"))52 writer.apply { write("$META_INF_VERSIONS/9") }.flush()53 zipOut.putNextEntry(ZipEntry("$META_INF_VERSIONS/test.txt"))54 writer.apply { write("$META_INF_VERSIONS/test.txt") }.flush()55 // enable multi release if withManifest is true56 if (withManifest) {57 zipOut.putNextEntry(ZipEntry(JarFile.MANIFEST_NAME))58 writer.apply {59 write("""60 Manifest-Version: 1.061 Multi-Release: true62 """.trimIndent())63 }.flush()64 }65 }66 }67 init {68 describe("multi release support") {69 val temp = withContext(Dispatchers.IO) {70 val temp = Files.createTempFile("multi-release", ".jar")71 makeJar(Files.newOutputStream(temp), true)72 temp73 }74 val jar = ClassContainer.Jar(temp.toFile())75 it("version list") {76 jar.releases.toSet() shouldBe setOf(9, 10)77 }78 it("check path list") {79 // check multi-release resources80 jar.files shouldContain "root-only.txt"81 jar.files shouldContain "9-only.txt"82 jar.files shouldContain "10-only.txt"83 jar.files shouldContain "9-10-only.txt"84 jar.files shouldContain "9-root.txt"85 jar.files shouldContain "9-10-root.txt"86 jar.files shouldContain "8-root.txt"87 // check files in versions/8 are exists88 jar.files shouldContain "$META_INF_VERSIONS/8/8-only.txt"89 jar.files shouldContain "$META_INF_VERSIONS/8/8-root.txt"90 // check files on META-INF/versions91 jar.files shouldContain "$META_INF_VERSIONS/9"92 jar.files shouldContain "$META_INF_VERSIONS/test.txt"93 // check files in versions/(9|10) are not exists94 jar.files shouldNotContain "$META_INF_VERSIONS/9/9-only.txt"95 jar.files shouldNotContain "$META_INF_VERSIONS/9/9-root.txt"96 jar.files shouldNotContain "$META_INF_VERSIONS/9/9-10-root.txt"97 jar.files shouldNotContain "$META_INF_VERSIONS/9/9-10-only.txt"98 jar.files shouldNotContain "$META_INF_VERSIONS/10/10-only.txt"99 jar.files shouldNotContain "$META_INF_VERSIONS/10/9-10-root.txt"100 jar.files shouldNotContain "$META_INF_VERSIONS/10/9-10-only.txt"101 }102 it("check resolve") {103 // root entries104 jar.loadFiles("root-only.txt") should haveFile("root", 0)105 jar.loadFiles("9-root.txt") should haveFile("root", 0)106 jar.loadFiles("9-10-root.txt") should haveFile("root", 0)107 jar.loadFiles("8-root.txt") should haveFile("root", 0)108 // release 9 entries for basic109 jar.loadFiles("$META_INF_VERSIONS/9/9-only.txt") should haveFile("9", 0)110 jar.loadFiles("$META_INF_VERSIONS/9/9-root.txt") should haveFile("9", 0)111 jar.loadFiles("$META_INF_VERSIONS/9/9-10-root.txt") should haveFile("9", 0)112 jar.loadFiles("$META_INF_VERSIONS/9/9-10-only.txt") should haveFile("9", 0)113 jar.loadFiles("$META_INF_VERSIONS/9/9-only.txt").size shouldBe 1114 jar.loadFiles("$META_INF_VERSIONS/9/9-root.txt").size shouldBe 1115 jar.loadFiles("$META_INF_VERSIONS/9/9-10-root.txt").size shouldBe 1116 jar.loadFiles("$META_INF_VERSIONS/9/9-10-only.txt").size shouldBe 1117 jar.loadFiles("9-only.txt") should haveFile("9", 9)118 jar.loadFiles("9-root.txt") should haveFile("9", 9)119 jar.loadFiles("9-10-root.txt") should haveFile("9", 9)120 jar.loadFiles("9-10-only.txt") should haveFile("9", 9)121 // release 10 entries for multiple release122 jar.loadFiles("$META_INF_VERSIONS/10/10-only.txt") should haveFile("10", 0)123 jar.loadFiles("$META_INF_VERSIONS/10/9-10-root.txt") should haveFile("10", 0)124 jar.loadFiles("$META_INF_VERSIONS/10/9-10-only.txt") should haveFile("10", 0)125 jar.loadFiles("$META_INF_VERSIONS/10/10-only.txt").size shouldBe 1126 jar.loadFiles("$META_INF_VERSIONS/10/9-10-root.txt").size shouldBe 1127 jar.loadFiles("$META_INF_VERSIONS/10/9-10-only.txt").size shouldBe 1128 jar.loadFiles("10-only.txt") should haveFile("10", 10)129 jar.loadFiles("9-10-root.txt") should haveFile("10", 10)130 jar.loadFiles("9-10-only.txt") should haveFile("10", 10)131 // invalid version/release: 8132 jar.loadFiles("$META_INF_VERSIONS/8/8-only.txt") should haveFile("8", 0)133 jar.loadFiles("$META_INF_VERSIONS/8/8-root.txt") should haveFile("8", 0)134 jar.loadFiles("8-only.txt").shouldBeEmpty()135 jar.loadFiles("8-root.txt") shouldNot haveRelease(8)136 // files on META-INF/versions137 jar.loadFiles("$META_INF_VERSIONS/9") should haveFile("$META_INF_VERSIONS/9", 0)138 jar.loadFiles("$META_INF_VERSIONS/test.txt") should haveFile("$META_INF_VERSIONS/test.txt", 0)139 }140 finalizeSpec { withContext(Dispatchers.IO) { Files.delete(temp) } }141 }142 describe("non multi release support") {143 val temp = withContext(Dispatchers.IO) {144 val temp = Files.createTempFile("multi-release", ".jar")145 makeJar(Files.newOutputStream(temp), false)146 temp147 }148 val jar = ClassContainer.Jar(temp.toFile())149 it("version list") {150 jar.releases.toSet().shouldBeEmpty()151 }152 it("check path list") {153 // check multi-release resources154 jar.files shouldContain "root-only.txt"155 jar.files shouldNotContain "9-only.txt"156 jar.files shouldNotContain "10-only.txt"157 jar.files shouldNotContain "9-10-only.txt"158 jar.files shouldContain "9-root.txt"159 jar.files shouldContain "9-10-root.txt"160 jar.files shouldContain "8-root.txt"161 // check files in versions/8 are exists162 jar.files shouldContain "$META_INF_VERSIONS/8/8-only.txt"163 jar.files shouldContain "$META_INF_VERSIONS/8/8-root.txt"164 // check files on META-INF/versions165 jar.files shouldContain "$META_INF_VERSIONS/9"166 jar.files shouldContain "$META_INF_VERSIONS/test.txt"167 // check files in versions/(9|10) are not exists168 jar.files shouldContain "$META_INF_VERSIONS/9/9-only.txt"169 jar.files shouldContain "$META_INF_VERSIONS/9/9-root.txt"170 jar.files shouldContain "$META_INF_VERSIONS/9/9-10-root.txt"171 jar.files shouldContain "$META_INF_VERSIONS/9/9-10-only.txt"172 jar.files shouldContain "$META_INF_VERSIONS/10/10-only.txt"173 jar.files shouldContain "$META_INF_VERSIONS/10/9-10-root.txt"174 jar.files shouldContain "$META_INF_VERSIONS/10/9-10-only.txt"175 }176 it("check resolve") {177 // root entries178 jar.loadFiles("root-only.txt") should haveFile("root", 0)179 jar.loadFiles("9-root.txt") should haveFile("root", 0)180 jar.loadFiles("9-10-root.txt") should haveFile("root", 0)181 jar.loadFiles("8-root.txt") should haveFile("root", 0)182 // release 9 entries for basic183 jar.loadFiles("$META_INF_VERSIONS/9/9-only.txt") should haveFile("9", 0)184 jar.loadFiles("$META_INF_VERSIONS/9/9-root.txt") should haveFile("9", 0)185 jar.loadFiles("$META_INF_VERSIONS/9/9-10-root.txt") should haveFile("9", 0)186 jar.loadFiles("$META_INF_VERSIONS/9/9-10-only.txt") should haveFile("9", 0)187 jar.loadFiles("$META_INF_VERSIONS/9/9-only.txt").size shouldBe 1188 jar.loadFiles("$META_INF_VERSIONS/9/9-root.txt").size shouldBe 1189 jar.loadFiles("$META_INF_VERSIONS/9/9-10-root.txt").size shouldBe 1190 jar.loadFiles("$META_INF_VERSIONS/9/9-10-only.txt").size shouldBe 1191 jar.loadFiles("9-only.txt").shouldBeEmpty()192 jar.loadFiles("9-root.txt").size shouldBe 1193 jar.loadFiles("9-10-root.txt").size shouldBe 1194 jar.loadFiles("9-10-only.txt").shouldBeEmpty()195 // release 10 entries for multiple release196 jar.loadFiles("$META_INF_VERSIONS/10/10-only.txt") should haveFile("10", 0)197 jar.loadFiles("$META_INF_VERSIONS/10/9-10-root.txt") should haveFile("10", 0)198 jar.loadFiles("$META_INF_VERSIONS/10/9-10-only.txt") should haveFile("10", 0)199 jar.loadFiles("$META_INF_VERSIONS/10/10-only.txt").size shouldBe 1200 jar.loadFiles("$META_INF_VERSIONS/10/9-10-root.txt").size shouldBe 1201 jar.loadFiles("$META_INF_VERSIONS/10/9-10-only.txt").size shouldBe 1202 jar.loadFiles("10-only.txt").shouldBeEmpty()203 jar.loadFiles("9-10-root.txt").size shouldBe 1204 jar.loadFiles("9-10-only.txt").shouldBeEmpty()205 // invalid version/release: 8206 jar.loadFiles("$META_INF_VERSIONS/8/8-only.txt") should haveFile("8", 0)207 jar.loadFiles("$META_INF_VERSIONS/8/8-root.txt") should haveFile("8", 0)208 jar.loadFiles("8-only.txt").shouldBeEmpty()209 jar.loadFiles("8-root.txt") shouldNot haveRelease(8)210 // files on META-INF/versions211 jar.loadFiles("$META_INF_VERSIONS/9") should haveFile("$META_INF_VERSIONS/9", 0)212 jar.loadFiles("$META_INF_VERSIONS/test.txt") should haveFile("$META_INF_VERSIONS/test.txt", 0)213 }214 finalizeSpec { withContext(Dispatchers.IO) { Files.delete(temp) } }215 }216 }217 private fun haveFile(body: String, release: Int) = object : Matcher<Collection<SingleFile>> {218 override fun test(value: Collection<SingleFile>): MatcherResult =219 if (value.any { it.data.contentEquals(body.toByteArray()) && it.release == release }) {220 MatcherResult(true, { error("") },221 { "Collection that have SingleFile for release $release with body '$body'is not expected." }222 )223 } else {224 val contentEq = value.firstOrNull { it.data.contentEquals(body.toByteArray()) }225 if (contentEq != null) {226 MatcherResult(227 false,228 {229 "Expected collection that have SingleFile for release $release with body '$body'" +230 " but not found for $release"231 },232 { error("") }233 )234 } else {235 MatcherResult(236 false,237 { "Expected collection that have SingleFile for release $release with body '$body'." },238 { error("") }239 )240 }241 }242 }243 private fun haveRelease(@Suppress("SameParameterValue") release: Int) = object : Matcher<Collection<SingleFile>> {244 override fun test(value: Collection<SingleFile>) = MatcherResult(245 value.any { it.release == release },246 { "Expected collection that have SingleFile for release $release." },247 { "Collection that have SingleFile for release $release is not expected." }248 )249 }250}...

Full Screen

Full Screen

DogControllerIntegrationTest.kt

Source:DogControllerIntegrationTest.kt Github

copy

Full Screen

1package pl.poznan.put.dogloverservice.modules.dog2import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule3import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper4import com.fasterxml.jackson.module.kotlin.readValue5import io.kotest.core.spec.style.AnnotationSpec6import io.kotest.matchers.collections.shouldContain7import io.kotest.matchers.collections.shouldNotContain8import io.kotest.matchers.equality.shouldBeEqualToIgnoringFields9import io.kotest.matchers.should10import io.kotest.matchers.shouldBe11import io.kotest.matchers.shouldNotBe12import io.kotest.spring.SpringListener13import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc14import org.springframework.boot.test.context.SpringBootTest15import org.springframework.http.MediaType16import org.springframework.security.test.context.support.WithMockUser17import org.springframework.test.context.ActiveProfiles18import org.springframework.test.web.servlet.MockMvc19import org.springframework.test.web.servlet.get20import org.springframework.test.web.servlet.multipart21import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*22import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status23import pl.poznan.put.dogloverservice.infrastructure.exceptions.InvalidAvatarImageException24import pl.poznan.put.dogloverservice.modules.dog.dto.DogDTO25import pl.poznan.put.dogloverservice.modules.dog.dto.UpdateDogDTO26import javax.transaction.Transactional27@Transactional28@ActiveProfiles("integration")29@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)30@WithMockUser(authorities = ["SCOPE_dog-lover"], value = "9c04f2d5-0f58-4f1b-9f1a-0a2a3a25fad5")31@AutoConfigureMockMvc32class DogControllerIntegrationTest(33 val mockMvc: MockMvc34) : AnnotationSpec() {35 override fun listeners() = listOf(SpringListener)36 @Test37 fun `Should add dog`() {38 //given39 val updateDogDTO = UpdateDogDTO(DogData.burek)40 val expectedDogDTO = DogDTO(DogData.burek)41 //when42 val response = mockMvc.perform(post("/dogs")43 .content(jacksonObjectMapper().registerModule(JavaTimeModule()).writeValueAsString(updateDogDTO))44 .contentType(MediaType.APPLICATION_JSON))45 .andExpect(status().isCreated)46 .andReturn()47 .response48 .contentAsString49 val returnedDogDTO = jacksonObjectMapper().registerModule(JavaTimeModule()).readValue<DogDTO>(response)50 //then51 returnedDogDTO.should {52 it.name shouldBe expectedDogDTO.name53 it.breed shouldBe expectedDogDTO.breed54 it.color shouldBe expectedDogDTO.color55 it.description shouldBe expectedDogDTO.description56 it.lastVaccinationDate shouldBe expectedDogDTO.lastVaccinationDate57 it.avatarChecksum shouldBe null58 }59 }60 @Test61 fun `Should throw while adding existing dog`() {62 //given63 val dogLoverId = "9c04f2d5-0f58-4f1b-9f1a-0a2a3a25fad5"64 val updateDogDTO = UpdateDogDTO(DogData.yogi)65 //when66 mockMvc.perform(post("/dogs")67 .content(jacksonObjectMapper().registerModule(JavaTimeModule()).writeValueAsString(updateDogDTO))68 .contentType(MediaType.APPLICATION_JSON))69 //then70 .andExpect(status().isConflict)71 .andExpect(status().reason("Dog with name: ${updateDogDTO.name} already exists for user with id: $dogLoverId."))72 }73 @Test74 fun `Should update dog with avatar`() {75 //given76 val updateDogDTO = UpdateDogDTO(DogData.yogi)77 val expectedDogDTO = DogDTO(DogData.yogi)78 val dogId = expectedDogDTO.id79 val avatarMultipartFile = DogAvatarImageData.avatarMultipartFile80 mockMvc.multipart("/dogs/$dogId/avatar") {81 file(avatarMultipartFile)82 with {83 it.apply { method = "PUT" }84 }85 }86 //then87 .andExpect {88 status { isOk }89 }90 //when91 val response = mockMvc.perform(put("/dogs")92 .content(jacksonObjectMapper().registerModule(JavaTimeModule()).writeValueAsString(updateDogDTO))93 .contentType(MediaType.APPLICATION_JSON))94 .andExpect(status().isOk)95 .andReturn()96 .response97 .contentAsString98 val returnedDogDTO = jacksonObjectMapper().registerModule(JavaTimeModule()).readValue<DogDTO>(response)99 //then100 returnedDogDTO.shouldBeEqualToIgnoringFields(expectedDogDTO, DogDTO::avatarChecksum)101 returnedDogDTO.avatarChecksum shouldNotBe null102 }103 @Test104 fun `Should get dog lover dogs`() {105 //given106 val dogName = "yogi"107 //when108 val response = mockMvc.perform(get("/dogs")109 .contentType(MediaType.APPLICATION_JSON))110 .andExpect(status().isOk)111 .andReturn()112 .response113 .contentAsString114 val returnedDogs = jacksonObjectMapper().registerModule(JavaTimeModule()).readValue<List<DogDTO>>(response)115 //then116 returnedDogs.size shouldBe 2117 returnedDogs.map { it.name } shouldContain dogName118 }119 @Test120 fun `Should remove dog`() {121 //given122 val dogId = DogData.yogi.id123 //when124 mockMvc.perform(delete("/dogs/$dogId")125 .contentType(MediaType.APPLICATION_JSON))126 //then127 .andExpect(status().isNoContent)128 //when129 val response = mockMvc.perform(get("/dogs")130 .contentType(MediaType.APPLICATION_JSON))131 //then132 .andExpect(status().isOk)133 .andReturn()134 .response135 .contentAsString136 val returnedDogs = jacksonObjectMapper().registerModule(JavaTimeModule()).readValue<List<DogDTO>>(response)137 returnedDogs.size shouldBe 1138 returnedDogs.map { it.id } shouldNotContain dogId139 }140 @Test141 fun `Should save and get dog avatar image`() {142 //given143 val dog = DogData.yogi144 val dogId = dog.id145 val avatarMultipartFile = DogAvatarImageData.avatarMultipartFile146 //when147 mockMvc.multipart("/dogs/$dogId/avatar") {148 file(avatarMultipartFile)149 with {150 it.apply { method = "PUT" }151 }152 }153 //then154 .andExpect {155 status { isOk }156 }157 //when158 val response = mockMvc.get("/dogs/$dogId/avatar")159 //then160 .andExpect {161 status { isOk }162 }163 .andReturn()164 .response165 .contentAsByteArray166 response contentEquals DogAvatarImageData.avatarBytes shouldBe true167 }168 @Test169 fun `Should throw when adding invalid dog avatar image`() {170 //given171 val dog = DogData.yogi172 val dogId = dog.id173 val invalidAvatarMultipartFile = DogAvatarImageData.invalidAvatarMultipartFile174 //when175 mockMvc.multipart("/dogs/$dogId/avatar") {176 file(invalidAvatarMultipartFile)177 with {178 it.apply { method = "PUT" }179 }180 }181 //then182 .andExpect {183 status {184 isBadRequest185 reason(InvalidAvatarImageException().message)186 }187 }188 }189}...

Full Screen

Full Screen

RiotServiceTests.kt

Source:RiotServiceTests.kt Github

copy

Full Screen

1package me.l3n.bot.discord.lod.service.http2import io.kotest.assertions.fail3import io.kotest.core.spec.style.ShouldSpec4import io.kotest.matchers.collections.*5import io.kotest.matchers.shouldBe6import io.kotest.matchers.string.shouldNotContain7import io.mockk.coEvery8import io.mockk.mockk9import me.l3n.bot.discord.lod.model.RiotConfig10import me.l3n.bot.discord.lod.model.Role11import me.l3n.bot.discord.lod.models.Champs12import me.l3n.bot.discord.lod.models.Champs.currentRotationIds13import me.l3n.bot.discord.lod.toJson14import kotlin.time.ExperimentalTime15private const val LATEST_VERSION = "1.3.3.7"16private val VERSIONS = listOf(LATEST_VERSION, "1.0", "0.1")17@ExperimentalTime18class RiotServiceTests : ShouldSpec({19 val httpResponseMock = mockk<MockableHttpHandler> {20 coEvery { responseFor("$LEAGUE_DATA_URL/$VERSIONS_ENDPOINT", any()) } returns VERSIONS.toJson()21 coEvery {22 responseFor(23 "$LEAGUE_DATA_URL/$CDN_ENDPOINT/$LATEST_VERSION/$GET_ALL_CHAMPIONS_ENDPOINT",24 any(),25 )26 } returns ChampionListResponse(Champs.noIconsList).toJson()27 coEvery {28 responseFor(29 "$LEAGUE_URL/$GET_CURRENT_ROTATION_ENDPOINT",30 any(),31 )32 } returns ChampionRotationResponse(currentRotationIds, currentRotationIds).toJson()33 Champs.withIconsList.values.forEach { champ ->34 val icon = champ.icon ?: fail("Icon of `${champ.id}` should not be null")35 coEvery {36 responseFor(37 "$LEAGUE_DATA_URL/cdn/$LATEST_VERSION/$GET_CHAMPION_ICON/${champ.id}.png",38 any()39 )40 } returns icon.toByteArray()41 }42 }43 val httpClient = MockableHttpHandler.createClient(httpResponseMock)44 context("internal API") {45 val target = RiotServiceImpl(RiotConfig("dummy"), httpClient)46 should("remove spaces from champion names") {47 target.trimChampionsName(Champs.noIconsList).values.forEach { champ ->48 champ.name shouldNotContain " "49 }50 }51 should("filter champions from the rotation list") {52 val filtered =53 target.filterChampionsOnRotation(Champs.noIconsList, Champs.currentRotationIds)54 filtered shouldBe Champs.currentRotation55 }56 should("give all roles with champions") {57 val actual = target.getRoleChampions(Champs.allRolesFilled, Champs.noIconsList)58 actual.keys shouldContain Role.Unknown59 actual.keys shouldContainInOrder listOf(60 Role.Top,61 Role.Jungle,62 Role.Mid,63 Role.Bot,64 Role.Support,65 Role.Unknown66 )67 actual shouldBe mapOf(68 Role.Top to listOf(Champs.NoIcon.lulu),69 Role.Jungle to listOf(Champs.NoIcon.nunu),70 Role.Mid to listOf(Champs.NoIcon.syndra),71 Role.Bot to listOf(Champs.NoIcon.draven),72 Role.Support to listOf(Champs.NoIcon.nami),73 Role.Unknown to listOf(Champs.NoIcon.knox),74 )75 }76 should("give roles with champions, without `Unknown` because there's none") {77 val actual = target.getRoleChampions(Champs.rolesFilledWithoutUnknown, Champs.noIconsList)78 actual.keys shouldNotContain Role.Unknown79 actual.keys shouldContainInOrder listOf(Role.Top, Role.Jungle, Role.Mid, Role.Bot, Role.Support)80 actual shouldBe mapOf(81 Role.Top to listOf(Champs.NoIcon.lulu),82 Role.Jungle to listOf(Champs.NoIcon.nunu),83 Role.Mid to listOf(Champs.NoIcon.syndra),84 Role.Bot to listOf(Champs.NoIcon.draven),85 Role.Support to listOf(Champs.NoIcon.nami, Champs.NoIcon.knox),86 )87 }88 should("give some roles with champions, including `Unknown`") {89 val actual = target.getRoleChampions(Champs.someRolesFilled, Champs.noIconsList)90 actual.keys shouldContain Role.Unknown91 actual.keys shouldContainInOrder listOf(Role.Mid, Role.Bot, Role.Support, Role.Unknown)92 actual shouldBe mapOf(93 Role.Top to listOf(),94 Role.Jungle to listOf(),95 Role.Mid to listOf(Champs.NoIcon.syndra),96 Role.Bot to listOf(Champs.NoIcon.draven, Champs.NoIcon.lulu),97 Role.Support to listOf(Champs.NoIcon.nami, Champs.NoIcon.nunu),98 Role.Unknown to listOf(Champs.NoIcon.knox),99 )100 }101 should("give some roles with champions, without `Unknown` because there's none") {102 val actual =103 target.getRoleChampions(Champs.someRolesFilledWithoutUnknown, Champs.noIconsList)104 actual.keys shouldNotContain Role.Unknown105 actual.keys shouldContainInOrder listOf(Role.Mid, Role.Bot, Role.Support)106 actual shouldBe mapOf(107 Role.Top to listOf(),108 Role.Jungle to listOf(),109 Role.Mid to listOf(Champs.NoIcon.syndra, Champs.NoIcon.knox),110 Role.Bot to listOf(Champs.NoIcon.draven, Champs.NoIcon.lulu),111 Role.Support to listOf(Champs.NoIcon.nami, Champs.NoIcon.nunu),112 )113 }114 context("using HTTP services") {115 should("fetch the latest version in initialization") {116 target.getLatestVersion() shouldBe LATEST_VERSION117 }118 should("get all champions") {119 target.getAllChampions() shouldBe Champs.noIconsList120 }121 should("get champion icon") {122 val case = Champs.WithIcon.draven123 val icon = case.icon ?: fail("`case.icon` must not be null")124 val actual = target.getChampionIcon(case.id)125 actual.shouldContainAll(*icon.toTypedArray())126 }127 should("get champions with icons") {128 val actual = target.addIconsToChampions(Champs.noIconsList)129 actual.keys shouldBe Champs.withIconsList.keys130 actual.values shouldBe Champs.withIconsList.values131 }132 }133 }134 context("public API") {135 should("return rotation champions with their icons") {136 val target = RiotServiceImpl(RiotConfig("dummy"), httpClient)137 val currentRotation = target.getCurrentRotation(Champs.allRolesFilled)138 val champs = currentRotation.roledChampions139 champs.keys.size shouldBe 5140 champs.filterValues { it.isEmpty() }.keys shouldContainExactly listOf(Role.Jungle, Role.Mid, Role.Support)141 champs[Role.Bot]?.shouldHaveSingleElement(Champs.WithIcon.draven)142 champs[Role.Top]?.shouldHaveSingleElement(Champs.WithIcon.lulu)143 }144 }145})...

Full Screen

Full Screen

TestOutputCapture.kt

Source:TestOutputCapture.kt Github

copy

Full Screen

1package edu.illinois.cs.cs125.jeed.core.sandbox2import edu.illinois.cs.cs125.jeed.core.Sandbox3import edu.illinois.cs.cs125.jeed.core.Source4import edu.illinois.cs.cs125.jeed.core.SourceExecutionArguments5import edu.illinois.cs.cs125.jeed.core.compile6import edu.illinois.cs.cs125.jeed.core.execute7import edu.illinois.cs.cs125.jeed.core.findClassMethod8import edu.illinois.cs.cs125.jeed.core.fromSnippet9import edu.illinois.cs.cs125.jeed.core.haveCompleted10import edu.illinois.cs.cs125.jeed.core.haveOutput11import edu.illinois.cs.cs125.jeed.core.haveStderr12import edu.illinois.cs.cs125.jeed.core.haveStdout13import edu.illinois.cs.cs125.jeed.core.haveTimedOut14import io.kotest.core.spec.style.StringSpec15import io.kotest.matchers.collections.shouldNotContain16import io.kotest.matchers.should17import io.kotest.matchers.shouldBe18import io.kotest.matchers.shouldNot19import kotlinx.coroutines.async20import kotlinx.coroutines.delay21import java.io.ByteArrayOutputStream22import java.io.PrintStream23class TestOutputCapture : StringSpec({24 "should capture stdout" {25 val executionResult = Source.fromSnippet(26 """27System.out.println("Here");28 """.trim()29 ).compile().execute()30 executionResult should haveCompleted()31 executionResult shouldNot haveTimedOut()32 executionResult should haveStdout("Here")33 executionResult should haveStderr("")34 }35 "should capture stderr" {36 val executionResult = Source.fromSnippet(37 """38System.err.println("Here");39 """.trim()40 ).compile().execute()41 executionResult should haveCompleted()42 executionResult shouldNot haveTimedOut()43 executionResult should haveStdout("")44 executionResult should haveStderr("Here")45 }46 "should capture stderr and stdout" {47 val executionResult = Source.fromSnippet(48 """49System.out.println("Here");50System.err.println("There");51 """.trim()52 ).compile().execute()53 executionResult should haveCompleted()54 executionResult shouldNot haveTimedOut()55 executionResult should haveStdout("Here")56 executionResult should haveStderr("There")57 executionResult should haveOutput("Here\nThere")58 }59 "should capture incomplete stderr and stdout lines" {60 val executionResult = Source.fromSnippet(61 """62System.out.print("Here");63System.err.print("There");64 """.trim()65 ).compile().execute()66 executionResult should haveCompleted()67 executionResult shouldNot haveTimedOut()68 executionResult should haveStdout("Here")69 executionResult should haveStderr("There")70 executionResult should haveOutput("Here\nThere")71 }72 "should not intermingle unrelated thread output" {73 val combinedOutputStream = ByteArrayOutputStream()74 val combinedPrintStream = PrintStream(combinedOutputStream)75 val originalStdout = System.out76 val originalStderr = System.err77 System.setOut(combinedPrintStream)78 System.setErr(combinedPrintStream)79 (0..8).toList().map {80 if (it % 2 == 0) {81 async {82 Source.fromSnippet(83 """84for (int i = 0; i < 32; i++) {85 for (long j = 0; j < 1024 * 1024 * 1024; j++);86}87 """.trim()88 ).compile().execute(SourceExecutionArguments(timeout = 1000L))89 }90 } else {91 async {92 repeat(512) {93 println("Bad")94 System.err.println("Bad")95 delay(1L)96 }97 }98 }99 }.map { it.await() }.filterIsInstance<Sandbox.TaskResults<out Any?>>().forEach { executionResult ->100 executionResult should haveTimedOut()101 executionResult.outputLines.map { it.line } shouldNotContain "Bad"102 executionResult.stderrLines.map { it.line } shouldNotContain "Bad"103 }104 System.setOut(originalStdout)105 System.setErr(originalStderr)106 val unrelatedOutput = combinedOutputStream.toString()107 unrelatedOutput.lines().filter { it == "Bad" }.size shouldBe (4 * 2 * 512)108 }109 "should redirect output to trusted task properly" {110 val compiledSource = Source.fromSnippet(111 """112System.out.println("Here");113System.out.println("There");114System.err.println("There");115 """.trim()116 ).compile()117 val executionResult = Sandbox.execute(compiledSource.classLoader) { (classLoader, redirectOutput) ->118 redirectOutput {119 classLoader.findClassMethod().invoke(null)120 }.also {121 assert(it.stdout == "Here\nThere\n")122 assert(it.stderr == "There\n")123 }124 }125 executionResult should haveCompleted()126 executionResult shouldNot haveTimedOut()127 executionResult should haveStdout("Here\nThere")128 executionResult should haveStderr("There")129 }130 "should redirect output to trusted task properly with print" {131 val compiledSource = Source.fromSnippet(132 """133System.out.println("Here");134System.out.print("There");135System.err.print("There");136 """.trim()137 ).compile()138 val executionResult = Sandbox.execute(compiledSource.classLoader) { (classLoader, redirectOutput) ->139 redirectOutput {140 classLoader.findClassMethod().invoke(null)141 }.also {142 assert(it.stdout == "Here\nThere")143 assert(it.stderr == "There")144 }145 redirectOutput {146 classLoader.findClassMethod().invoke(null)147 }.also {148 assert(it.stdout == "Here\nThere")149 assert(it.stderr == "There")150 }151 }152 executionResult should haveCompleted()153 executionResult shouldNot haveTimedOut()154 executionResult should haveStdout("Here\nThereHere\nThere")155 executionResult should haveStderr("ThereThere")156 }157 "should handle null print arguments" {158 val executionResult = Source.fromSnippet(159 """160int[] output = null;161System.out.println(output);162 """.trim()163 ).compile().execute()164 executionResult should haveCompleted()165 executionResult shouldNot haveTimedOut()166 executionResult should haveStdout("null")167 executionResult should haveStderr("")168 }169 "should handle print without newline" {170 val executionResult = Source.fromSnippet(171 """172System.out.print("Hello");173 """.trim()174 ).compile().execute()175 executionResult should haveCompleted()176 executionResult shouldNot haveTimedOut()177 executionResult should haveStdout("Hello")178 }179})...

Full Screen

Full Screen

FileSystemServiceImplTest.kt

Source:FileSystemServiceImplTest.kt Github

copy

Full Screen

1package org.factcast.schema.registry.cli.fs2import com.fasterxml.jackson.databind.JsonNode3import io.kotest.core.spec.style.StringSpec4import io.kotest.core.test.TestCase5import io.kotest.core.test.TestResult6import io.kotest.matchers.collections.shouldContain7import io.kotest.matchers.collections.shouldHaveSize8import io.kotest.matchers.shouldBe9import io.kotest.matchers.string.shouldContain10import io.kotest.matchers.string.shouldNotContain11import io.kotest.matchers.types.shouldBeInstanceOf12import org.factcast.schema.registry.cli.fixture13import java.nio.file.Files14import java.nio.file.Paths15class FileSystemServiceImplTest : StringSpec() {16 var tmp = Files.createTempDirectory("fc-test")17 val uut = FileSystemServiceImpl()18 override fun afterTest(testCase: TestCase, result: TestResult) {19 try {20 Files.delete(tmp)21 } catch (e: Exception) {22 } finally {23 tmp = Files.createTempDirectory("fx-test")24 }25 }26 init {27 "exists" {28 uut.exists(fixture("schema.json")) shouldBe true29 uut.exists(fixture("nope.json")) shouldBe false30 }31 "listDirectories" {32 uut.listDirectories(fixture("")) shouldContain fixture("sample-folder")33 uut.listDirectories(fixture("sample-folder")) shouldHaveSize 034 }35 "listFiles" {36 val files = uut.listFiles(fixture(""))37 files shouldHaveSize 138 files shouldContain fixture("schema.json")39 }40 "ensureDirectories" {41 val outputPath = Paths.get(tmp.toString(), "foo")42 uut.ensureDirectories(outputPath)43 uut.exists(outputPath) shouldBe true44 }45 "writeToFile" {46 val outputPath = Paths.get(tmp.toString(), "test.txt")47 uut.writeToFile(outputPath.toFile(), "bar")48 uut.exists(outputPath) shouldBe true49 }50 "readToString" {51 uut.readToString(fixture("schema.json").toFile()) shouldContain "firstName"52 }53 "readToStrings" {54 val output = uut.readToStrings(fixture("schema.json").toFile())55 output[1] shouldContain "additionalProperties"56 output[8] shouldContain "required"57 }58 "copyFile" {59 val outputPath = Paths.get(tmp.toString(), "schema.json")60 uut.copyFile(fixture("schema.json").toFile(), outputPath.toFile())61 uut.exists(outputPath)62 }63 "readToJsonNode" {64 uut.readToJsonNode(fixture("schema.json")).shouldBeInstanceOf<JsonNode>()65 uut.readToJsonNode(fixture("nope.json")) shouldBe null66 }67 "deleteDirectory" {68 uut.exists(tmp) shouldBe true69 uut.deleteDirectory(tmp)70 uut.exists(tmp) shouldBe false71 }72 "readToBytes" {73 val exampleFile = fixture("schema.json")74 uut.readToBytes(exampleFile) shouldBe uut.readToString(exampleFile.toFile()).toByteArray()75 }76 "copyDirectory" {77 val outputPath = Paths.get(tmp.toString(), "foo")78 uut.exists(outputPath) shouldBe false79 uut.copyDirectory(fixture(""), outputPath)80 uut.exists(outputPath) shouldBe true81 }82 "copyFilteredJson" {83 val outputPath = Paths.get(tmp.toString(), "test.txt")84 uut.copyFilteredJson(85 fixture("schema.json").toFile(),86 outputPath.toFile(),87 setOf("title")88 )89 uut.exists(outputPath) shouldBe true90 uut.readToString(outputPath.toFile()) shouldNotContain "title"91 }92 }93}...

Full Screen

Full Screen

contain.kt

Source:contain.kt Github

copy

Full Screen

1package io.kotest.matchers.collections2import io.kotest.assertions.print.print3import io.kotest.equals.Equality4import io.kotest.matchers.Matcher5import io.kotest.matchers.MatcherResult6import io.kotest.matchers.should7import io.kotest.matchers.shouldNot8// Infix9infix fun <T> Iterable<T>.shouldNotContain(t: T): Iterable<T> = shouldNotContain(t, Equality.default())10infix fun <T> Array<T>.shouldNotContain(t: T): Array<T> = shouldNotContain(t, Equality.default())11infix fun <T> Iterable<T>.shouldContain(t: T): Iterable<T> = shouldContain(t, Equality.default())12infix fun <T> Array<T>.shouldContain(t: T): Array<T> = shouldContain(t, Equality.default())13// Should not14fun <T> Iterable<T>.shouldNotContain(t: T, comparator: Equality<T>): Iterable<T> = apply {15 toList() shouldNot contain(t, comparator)16}17fun <T> Array<T>.shouldNotContain(t: T, comparator: Equality<T>): Array<T> = apply {18 asList().shouldNotContain(t, comparator)19}20// Should21fun <T> Iterable<T>.shouldContain(t: T, comparator: Equality<T>): Iterable<T> = apply {22 toList() should contain(t, comparator)23}24fun <T> Array<T>.shouldContain(t: T, comparator: Equality<T>): Array<T> = apply {25 asList().shouldContain(t, comparator)26}27// Matcher28fun <T, C : Collection<T>> contain(t: T, verifier: Equality<T> = Equality.default()) = object : Matcher<C> {29 override fun test(value: C) = MatcherResult(30 value.any { verifier.verify(it, t).areEqual() },31 {32 "Collection should contain element ${t.print().value} based on ${verifier.name()}; " +33 "but the collection is ${value.print().value}"34 },35 { "Collection should not contain element ${t.print().value} based on ${verifier.name()}" }36 )37}...

Full Screen

Full Screen

_001_FindMultInArrayTest.kt

Source:_001_FindMultInArrayTest.kt Github

copy

Full Screen

...18 it shouldBeLessThan array.size19 it shouldBeGreaterThanOrEqual 020 }21 val resultArray = _001_FindMultInArray.findMult(array)22 resultArray shouldNotContain 123 resultArray shouldContain 224 resultArray shouldHaveSize 325 val testList: List<Int> = listOf(2, 3, 5)26 resultArray shouldContainAll testList27 }28 @Test29 fun findMultTestContainNull() {30 val array = listOf(0, 1, 2, 3, 4, 5, 6, 7, 8).toIntArray()31 array.forEach {32 it shouldBeLessThan array.size33 it shouldBeGreaterThanOrEqual 034 }35 _001_FindMultInArray.findMult(array) shouldHaveSize 036 }...

Full Screen

Full Screen

Array.shouldNotContain

Using AI Code Generation

copy

Full Screen

1val list = listOf ( "A" , "B" , "C" , "D" ) list . shouldNotContain ( "E" )2val list = listOf ( "A" , "B" , "C" , "D" ) list . shouldNotContain ( "A" , "B" )3val list = listOf ( "A" , "B" , "C" , "D" ) list . shouldNotContain ( "A" , "B" , "C" , "D" )4val list = listOf ( "A" , "B" , "C" , "D" ) list . shouldNotContain ( "A" , "B" , "C" , "D" , "E" )5val list = listOf ( "A" , "B" , "C" , "D" ) list . shouldNotContain ( "E" , "F" , "G" , "H" )6val list = listOf ( "A" , "B" , "C" , "D" ) list . shouldNotContain ( "E" , "F" , "G" , "H" , "I" )7val list = listOf ( "A" , "B" , "C" , "D" ) list . shouldNotContain ( "E" , "F" , "G" , "H" , "I" , "J" )8val list = listOf ( "A" , "B" , "C" , "D" ) list . shouldNotContain ( "E" , "F" , "G" , "H" , "I" , "J" , "K"

Full Screen

Full Screen

Array.shouldNotContain

Using AI Code Generation

copy

Full Screen

1val list = listOf("Kotlin", "Java", "C++", "C", "C#")2list.shouldNotContain("C++")3val list = listOf("Kotlin", "Java", "C++", "C", "C#")4list.shouldContainAll("C++", "Java")5val list = listOf("Kotlin", "Java", "C++", "C", "C#")6list.shouldNotContainAll("C++", "Java")7val list = listOf("Kotlin", "Java", "C++", "C", "C#")8list.shouldContainAny("C++", "Java")9val list = listOf("Kotlin", "Java", "C++", "C", "C#")10list.shouldNotContainAny("C++", "Java")11val list = listOf("Kotlin", "Java", "C++", "C", "C#")12list.shouldContainNone("C++", "Java")13val list = listOf("Kotlin", "Java", "C++", "C", "C#")14list.shouldNotContainNone("C++", "Java")15val list = listOf("Kotlin", "Java", "C++", "C", "C#")16list.shouldContainExactly("C++", "Java")17val list = listOf("Kotlin", "Java", "C++", "C", "C#")18list.shouldNotContainExactly("C++", "Java")19val list = listOf("Kotlin", "Java",

Full Screen

Full Screen

Automation Testing Tutorials

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

LambdaTest Learning Hubs:

YouTube

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

Run Kotest automation tests on LambdaTest cloud grid

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

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful