diff --git a/pom.xml b/pom.xml index 94e454fa..e16c3773 100644 --- a/pom.xml +++ b/pom.xml @@ -601,6 +601,8 @@ Spotbugs support @SuppressWarnings https://github.com/spotbugs/spotbugs/issues/737#issuecomment-416118033 + Is it possible for spotbugs to skip kotlin files from pure maven configuration? + https://stackoverflow.com/questions/55060459 --> com.github.spotbugs spotbugs-maven-plugin @@ -612,6 +614,9 @@ + + ${project.basedir}/src/spotbugs-exclude-filter-file.xml + diff --git a/src/main/java/io/foldright/cffu/CffuFactory.java b/src/main/java/io/foldright/cffu/CffuFactory.java index 9d642bf7..03f2f73d 100644 --- a/src/main/java/io/foldright/cffu/CffuFactory.java +++ b/src/main/java/io/foldright/cffu/CffuFactory.java @@ -298,7 +298,7 @@ public Cffu asCffu(CompletionStage stage) { /** * A convenient util method for wrap input {@link CompletableFuture}/{@link CompletionStage} array element - * using {@link #asCffu(CompletionStage)}. + * by {@link #asCffu(CompletionStage)}. * * @see #asCffu(CompletionStage) */ @@ -318,7 +318,7 @@ public final Cffu[] asCffuArray(CompletionStage... stages) { //////////////////////////////////////////////////////////////////////////////// /** - * Returns a new Cffu that is completed when all of the given Cffus complete. + * Returns a new Cffu that is completed when all the given Cffus complete. * If any of the given Cffu complete exceptionally, then the returned * Cffu also does so, with a CompletionException holding this exception as its cause.
* Otherwise, the results, if any, of the given Cffus are not reflected in @@ -337,7 +337,7 @@ public final Cffu[] asCffuArray(CompletionStage... stages) { * as in: {@code CffuFactory.allOf(c1, c2, c3).join();}. * * @param cfs the Cffus - * @return a new Cffu that is completed when all of the given Cffus complete + * @return a new Cffu that is completed when all the given Cffus complete * @throws NullPointerException if the array or any of its elements are {@code null} * @see #cffuAllOf(Cffu[]) * @see #cffuCombine(Cffu, Cffu) @@ -364,7 +364,7 @@ public Cffu allOf(Cffu... cfs) { * * * @param cfs the CompletableFutures - * @return a new Cffu that is completed when all of the given CompletableFutures complete + * @return a new Cffu that is completed when all the given CompletableFutures complete * @throws NullPointerException if the array or any of its elements are {@code null} * @see #allOf(Cffu[]) * @see #cffuAllOf(CompletableFuture[]) @@ -401,8 +401,8 @@ public Cffu allOf() { * because {@link #cffuAnyOf(Cffu[])} return type {@code T} instead of {@code Object}, more type safe. * * @param cfs the Cffus - * @return a new Cffu that is completed with the result or exception of - * any of the given Cffus when one completes + * @return a new Cffu that is completed with the result + * or exception of any of the given Cffus when one completes * @throws NullPointerException if the array or any of its elements are {@code null} * @see #cffuAnyOf(Cffu[]) * @see CompletableFuture#anyOf(CompletableFuture[]) @@ -421,8 +421,8 @@ public Cffu anyOf(Cffu... cfs) { * because {@link #cffuAnyOf(CompletableFuture[])} return type {@code T} instead of {@code Object}, more type safe. * * @param cfs the CompletableFutures - * @return a new Cffu that is completed with the result or exception of - * any of the given CompletableFutures when one completes + * @return a new Cffu that is completed with the result + * or exception of any of the given CompletableFutures when one completes * @throws NullPointerException if the array or any of its elements are {@code null} * @see #cffuAnyOf(CompletableFuture[]) * @see #anyOf(Cffu[]) @@ -497,10 +497,13 @@ public Executor delayedExecutor(long delay, TimeUnit unit, Executor executor) { //////////////////////////////////////////////////////////////////////////////// /** - * Same to {@link #allOf(Cffu[])}, but return the results of input {@link Cffu}. + * Returns a new Cffu with the result of all the given Cffus, + * the new Cffu is completed when all the given Cffus complete. + *

+ * Same to {@link #allOf(Cffu[])}, but return the results of input Cffus. * * @param cfs the Cffus - * @return a new Cffu that is completed when all of the given Cffus complete + * @return a new Cffu that is completed when all the given Cffus complete * @throws NullPointerException if the array or any of its elements are {@code null} * @see #allOf(Cffu[]) */ @@ -511,10 +514,13 @@ public final Cffu> cffuAllOf(Cffu... cfs) { } /** + * Returns a new Cffu with the result of all the given CompletableFutures, + * the new Cffu is completed when all the given CompletableFutures complete. + *

* Same as {@link #cffuAllOf(Cffu[])} with overloaded argument type {@link CompletableFuture}. * * @param cfs the CompletableFutures - * @return a new Cffu that is completed when all of the given CompletableFutures complete + * @return a new Cffu that is completed when all the given CompletableFutures complete * @throws NullPointerException if the array or any of its elements are {@code null} * @see #cffuAllOf(Cffu[]) */ @@ -556,11 +562,13 @@ public Cffu> cffuAllOf() { } /** + * Returns a new Cffu that is completed when any of the given Cffus complete, with the same result. + *

* Same as {@link #anyOf(Cffu[])}, but return result type is specified type instead of {@code Object}. * * @param cfs the Cffus - * @return a new Cffu that is completed with the result or exception of - * any of the given Cffus when one completes + * @return a new Cffu that is completed with the result + * or exception of any of the given Cffus when one completes * @throws NullPointerException if the array or any of its elements are {@code null} * @see #anyOf(Cffu[]) */ @@ -571,11 +579,13 @@ public final Cffu cffuAnyOf(Cffu... cfs) { } /** + * Returns a new Cffu that is completed when any of the given CompletableFutures complete, with the same result. + *

* Same as {@link #cffuAllOf(Cffu[])} with overloaded argument type {@link CompletableFuture}. * * @param cfs the CompletableFutures - * @return a new Cffu that is completed with the result or exception of - * any of the given CompletableFutures when one completes + * @return a new Cffu that is completed with the result + * or exception of any of the given CompletableFutures when one completes * @throws NullPointerException if the array or any of its elements are {@code null} * @see #cffuAnyOf(Cffu[]) */ @@ -839,7 +849,7 @@ public static CompletableFuture[] toCompletableFutureArray(CompletionStag } /** - * A convenient util method for unwrap input {@link Cffu} array elements using {@link Cffu#cffuUnwrap()}. + * A convenient util method for unwrap input {@link Cffu} array elements by {@link Cffu#cffuUnwrap()}. * * @param cfs the Cffus * @see Cffu#cffuUnwrap() diff --git a/src/main/java/io/foldright/cffu/kotlin/CffuExtensions.kt b/src/main/java/io/foldright/cffu/kotlin/CffuExtensions.kt index ba8acd3b..52487028 100644 --- a/src/main/java/io/foldright/cffu/kotlin/CffuExtensions.kt +++ b/src/main/java/io/foldright/cffu/kotlin/CffuExtensions.kt @@ -2,14 +2,210 @@ package io.foldright.cffu.kotlin import io.foldright.cffu.Cffu import io.foldright.cffu.CffuFactory +import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletionStage + +/** + * Returns a new CompletableFuture that is completed when all the given CompletableFutures complete. + * + * Same as [CompletableFuture.allOf], providing this method is convenient for method chaining. + * + * @see CompletableFuture.allOf + * @see CffuFactory.allOf + */ +fun Collection>.allCompletableFuture(): CompletableFuture = + CompletableFuture.allOf(*this.toTypedArray()) + +/** + * Returns a new CompletableFuture that is completed when all the given CompletableFutures complete. + * + * Same as [CompletableFuture.allOf], providing this method is convenient for method chaining. + * + * @see CompletableFuture.allOf + * @see CffuFactory.allOf + */ +fun Array>.allCompletableFuture(): CompletableFuture = + CompletableFuture.allOf(*this) + +/** + * Returns a new CompletableFuture that is completed + * when any of the given CompletableFutures complete, with the same result. + * + * Same as [CompletableFuture.anyOf], providing this method is convenient for method chaining. + * + * @see CompletableFuture.anyOf + * @see CffuFactory.anyOf + */ +fun Collection>.anyCompletableFuture(): CompletableFuture = + CompletableFuture.anyOf(*this.toTypedArray()) + +/** + * Returns a new CompletableFuture that is completed + * when any of the given CompletableFutures complete, with the same result. + * + * Same as [CompletableFuture.anyOf], providing this method is convenient for method chaining. + * + * @see CompletableFuture.anyOf + * @see CffuFactory.anyOf + */ +fun Array>.anyCompletableFuture(): CompletableFuture = + CompletableFuture.anyOf(*this) + /** - * Wrap this [CompletionStage] to [Cffu]. + * Wrap an existed [CompletableFuture]/[CompletionStage] to [Cffu]. * - * reimplement [CffuFactory.asCffu] method as extension of [CompletionStage], - * providing this method convenient for method chaining. + * Same as [CffuFactory.asCffu], providing this method is convenient for method chaining. * * @see CffuFactory.asCffu */ -fun CompletionStage.asCffu(cffuFactory: CffuFactory): Cffu = cffuFactory.asCffu(this) +fun CompletionStage.asCffu(cffuFactory: CffuFactory): Cffu = + cffuFactory.asCffu(this) + +/** + * Wrap input [CompletableFuture]/[CompletionStage] collection element to [Cffu] by [CffuFactory.asCffu]. + * + * Same as [CffuFactory.asCffu], providing this method is convenient for method chaining. + * + * @see CffuFactory.asCffu + */ +fun Collection>.asCffu(cffuFactory: CffuFactory): List> = + map { it.asCffu(cffuFactory) } + +/** + * Wrap input [CompletableFuture]/[CompletionStage] array element to [Cffu] by [CffuFactory.asCffu]. + * + * Same as [CffuFactory.asCffu], providing this method is convenient for method chaining. + * + * @see CffuFactory.asCffu + * @see CffuFactory.asCffuArray + */ +fun > Array.asCffu(cffuFactory: CffuFactory): Array> = + cffuFactory.asCffuArray(*this) + +/** + * Returns a new Cffu with the result of all the given Cffus, + * the new Cffu is completed when all the given Cffus complete. + * + * Same as [CffuFactory.cffuAllOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.cffuAllOf + */ +fun Collection>.allCffu(cffuFactory: CffuFactory): Cffu> = + cffuFactory.cffuAllOf(*this.toTypedArray()) + +/** + * Returns a new Cffu with the result of all the given Cffus, + * the new Cffu is completed when all the given Cffus complete. + * + * Same as [CffuFactory.cffuAllOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.cffuAllOf + */ + +fun Array>.allCffu(cffuFactory: CffuFactory): Cffu> = + cffuFactory.cffuAllOf(*this) + +/** + * Returns a new Cffu with the result of all the given CompletableFutures, + * the new Cffu is completed when all the given CompletableFutures complete. + * + * Same as [CffuFactory.cffuAllOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.cffuAllOf + */ +@JvmName("cffuAllOfCf") +fun Collection>.allCffu(cffuFactory: CffuFactory): Cffu> = + cffuFactory.cffuAllOf(*this.toTypedArray()) + +/** + * Returns a new Cffu with the result of all the given CompletableFutures, + * the new Cffu is completed when all the given CompletableFutures complete. + * + * Same as [CffuFactory.cffuAllOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.cffuAllOf + */ +fun Array>.allCffu(cffuFactory: CffuFactory): Cffu> = + cffuFactory.cffuAllOf(*this) + +/** + * Returns a new Cffu that is completed when any of the given Cffus complete, with the same result. + * + * Same as [CffuFactory.cffuAnyOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.cffuAnyOf + */ +fun Collection>.anyCffu(cffuFactory: CffuFactory): Cffu = + cffuFactory.cffuAnyOf(*this.toTypedArray()) + +/** + * Returns a new Cffu that is completed when any of the given Cffus complete, with the same result. + * + * Same as [CffuFactory.cffuAnyOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.cffuAnyOf + */ +fun Array>.anyCffu(cffuFactory: CffuFactory): Cffu = + cffuFactory.cffuAnyOf(*this) + +/** + * Returns a new Cffu that is completed when any of the given CompletableFutures complete, with the same result. + * + * Same as [CffuFactory.cffuAnyOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.cffuAnyOf + */ +@JvmName("cffuAnyOfCf") +fun Collection>.anyCffu(cffuFactory: CffuFactory): Cffu = + cffuFactory.cffuAnyOf(*this.toTypedArray()) + +/** + * Returns a new Cffu that is completed when any of the given CompletableFutures complete, with the same result. + * + * Same as [CffuFactory.cffuAnyOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.cffuAnyOf + */ +fun Array>.anyCffu(cffuFactory: CffuFactory): Cffu = + cffuFactory.cffuAnyOf(*this) + +/** + * Convert [Cffu] collection elements to [CompletableFuture] by [Cffu.toCompletableFuture]. + * + * Same as [CffuFactory.cffuAnyOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.toCompletableFutureArray + */ +fun Collection>.toCompletableFuture(): List> = + map { it.toCompletableFuture() } + +/** + * Convert [Cffu] array elements to [CompletableFuture] by [Cffu.toCompletableFuture]. + * + * Same as [CffuFactory.cffuAnyOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.toCompletableFutureArray + */ +fun > Array.toCompletableFuture(): Array> = + CffuFactory.toCompletableFutureArray(*this) + +/** + * Unwrap input [Cffu] collection elements by [Cffu.cffuUnwrap]. + * + * Same as [CffuFactory.cffuAnyOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.cffuArrayUnwrap + */ +fun Collection>.cffuUnwrap(): List> = + map { it.cffuUnwrap() } + +/** + * Unwrap input [Cffu] array elements by [Cffu.cffuUnwrap]. + * + * Same as [CffuFactory.cffuAnyOf], providing this method is convenient for method chaining. + * + * @see CffuFactory.cffuArrayUnwrap + */ +fun Array>.cffuUnwrap(): Array> = + CffuFactory.cffuArrayUnwrap(*this) diff --git a/src/spotbugs-exclude-filter-file.xml b/src/spotbugs-exclude-filter-file.xml new file mode 100644 index 00000000..8eb216f1 --- /dev/null +++ b/src/spotbugs-exclude-filter-file.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/src/test/java/io/foldright/cffu/CffuFactoryTest.java b/src/test/java/io/foldright/cffu/CffuFactoryTest.java index 24af6093..944822ae 100644 --- a/src/test/java/io/foldright/cffu/CffuFactoryTest.java +++ b/src/test/java/io/foldright/cffu/CffuFactoryTest.java @@ -15,6 +15,7 @@ import java.util.concurrent.*; import java.util.function.Function; +import static io.foldright.cffu.CffuFactoryBuilder.newCffuFactoryBuilder; import static io.foldright.test_utils.TestUtils.*; import static org.junit.jupiter.api.Assertions.*; @@ -132,7 +133,7 @@ void test_asCffu() throws Exception { assertEquals(n, cf.get()); shouldNotBeMinimalStage(cf); - CffuFactory fac = CffuFactoryBuilder.newCffuFactoryBuilder(anotherExecutorService).forbidObtrudeMethods(true).build(); + CffuFactory fac = newCffuFactoryBuilder(anotherExecutorService).forbidObtrudeMethods(true).build(); Cffu cffu = fac.asCffu(cffuFactory.completedFuture(42)); assertSame(anotherExecutorService, cffu.defaultExecutor()); assertSame(fac, cffu.cffuFactory()); @@ -511,7 +512,7 @@ void test_getter() { assertSame(executorService, cffuFactory.defaultExecutor()); assertFalse(cffuFactory.forbidObtrudeMethods()); - CffuFactory fac = CffuFactoryBuilder.newCffuFactoryBuilder(anotherExecutorService).forbidObtrudeMethods(true).build(); + CffuFactory fac = newCffuFactoryBuilder(anotherExecutorService).forbidObtrudeMethods(true).build(); assertSame(anotherExecutorService, fac.defaultExecutor()); assertTrue(fac.forbidObtrudeMethods()); } @@ -529,7 +530,7 @@ static void beforeAll() { executorService = TestThreadPoolManager.createThreadPool("CffuFactoryTest"); anotherExecutorService = TestThreadPoolManager.createThreadPool("CffuFactoryTest-Another", true); - cffuFactory = CffuFactoryBuilder.newCffuFactoryBuilder(executorService).build(); + cffuFactory = newCffuFactoryBuilder(executorService).build(); } @AfterAll diff --git a/src/test/java/io/foldright/cffu/CffuTest.java b/src/test/java/io/foldright/cffu/CffuTest.java index 2ad461bc..903f07a9 100644 --- a/src/test/java/io/foldright/cffu/CffuTest.java +++ b/src/test/java/io/foldright/cffu/CffuTest.java @@ -9,6 +9,7 @@ import java.util.concurrent.*; +import static io.foldright.cffu.CffuFactoryBuilder.newCffuFactoryBuilder; import static io.foldright.cffu.CffuFactoryTest.n; import static io.foldright.cffu.CffuFactoryTest.rte; import static org.junit.jupiter.api.Assertions.*; @@ -168,8 +169,8 @@ void test_toString() { static void beforeAll() { executorService = TestThreadPoolManager.createThreadPool("CffuTest"); - cffuFactory = CffuFactoryBuilder.newCffuFactoryBuilder(executorService).build(); - forbidObtrudeMethodsCffuFactory = CffuFactoryBuilder.newCffuFactoryBuilder(executorService) + cffuFactory = newCffuFactoryBuilder(executorService).build(); + forbidObtrudeMethodsCffuFactory = newCffuFactoryBuilder(executorService) .forbidObtrudeMethods(true).build(); } diff --git a/src/test/java/io/foldright/cffu/kotlin/CffuExtensionsTest.kt b/src/test/java/io/foldright/cffu/kotlin/CffuExtensionsTest.kt index 0afb0369..7635eada 100644 --- a/src/test/java/io/foldright/cffu/kotlin/CffuExtensionsTest.kt +++ b/src/test/java/io/foldright/cffu/kotlin/CffuExtensionsTest.kt @@ -1,30 +1,229 @@ package io.foldright.cffu.kotlin +import io.foldright.cffu.Cffu import io.foldright.cffu.CffuFactoryBuilder.newCffuFactoryBuilder +import io.foldright.test_utils.testCffuFactory import io.foldright.test_utils.testForkJoinPoolExecutor import io.foldright.test_utils.testThreadPoolExecutor import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe import io.kotest.matchers.types.shouldBeSameInstanceAs +import io.kotest.matchers.types.shouldBeTypeOf +import io.kotest.matchers.types.shouldNotBeSameInstanceAs +import io.kotest.matchers.types.shouldNotBeTypeOf import kotlinx.coroutines.future.await import java.util.concurrent.CompletableFuture +import java.util.concurrent.CompletionStage class CffuExtensionsTest : FunSpec({ val n = 42 - test("asCffu") { - val factory = newCffuFactoryBuilder(testThreadPoolExecutor).build() - CompletableFuture.completedFuture(n).asCffu(factory).await() shouldBe n + test("allOf/anyOf - collection") { + listOf( + CompletableFuture.completedFuture(42), + CompletableFuture.completedFuture("42"), + CompletableFuture.completedFuture(42.0), + ).allCompletableFuture().await() + + setOf( + CompletableFuture.completedFuture(42), + CompletableFuture.completedFuture("42"), + CompletableFuture.completedFuture(42.0), + ).allCompletableFuture().await() + + listOf( + CompletableFuture(), + CompletableFuture(), + CompletableFuture.completedFuture(42), + ).anyCompletableFuture().await() shouldBe 42 + + setOf( + CompletableFuture(), + CompletableFuture(), + CompletableFuture.completedFuture(42), + ).anyCompletableFuture().await() shouldBe 42 + } + + test("allOf/anyOf - array") { + arrayOf>( + CompletableFuture.completedFuture(42), + CompletableFuture.completedFuture("42"), + CompletableFuture.completedFuture(42.0), + ).allCompletableFuture().await() + + arrayOf>( + CompletableFuture(), + CompletableFuture(), + CompletableFuture.completedFuture(42), + ).anyCompletableFuture().await() shouldBe 42 + } + + suspend fun checkAsCffu(cffu: Cffu, n: Int) { + cffu.await() shouldBe n + + cffu.defaultExecutor() shouldBeSameInstanceAs testThreadPoolExecutor + cffu.cffuFactory() shouldBeSameInstanceAs testCffuFactory - CompletableFuture.completedFuture(n).asCffu(factory).let { - it.defaultExecutor() shouldBeSameInstanceAs testThreadPoolExecutor - it.cffuFactory() shouldBeSameInstanceAs factory - } val fac2 = newCffuFactoryBuilder(testForkJoinPoolExecutor).build() - CompletableFuture.completedFuture(n).asCffu(factory) - .resetCffuFactory(fac2).let { - it.defaultExecutor() shouldBeSameInstanceAs testForkJoinPoolExecutor - it.cffuFactory() shouldBeSameInstanceAs fac2 - } + cffu.resetCffuFactory(fac2).let { + it.defaultExecutor() shouldBeSameInstanceAs testForkJoinPoolExecutor + it.cffuFactory() shouldBeSameInstanceAs fac2 + } + } + + test("asCffu for CompletableFuture") { + val cf = CompletableFuture.completedFuture(n) + checkAsCffu(cf.asCffu(testCffuFactory), n) + } + + test("asCffu for CompletableFuture collection") { + val range = 0 until 10 + val cfs: List> = range.map { + CompletableFuture.completedFuture(it) + } + + cfs.asCffu(testCffuFactory).forEachIndexed { index, cffu -> + checkAsCffu(cffu, index) + } + cfs.toSet().asCffu(testCffuFactory).forEachIndexed { index, cffu -> + checkAsCffu(cffu, index) + } + } + + test("asCffu for CompletableFuture array") { + val cfArray: Array> = Array(10) { CompletableFuture.completedFuture(it) } + cfArray.asCffu(testCffuFactory).forEachIndexed { index, cffu -> + checkAsCffu(cffu, index) + } + + val csArray: Array> = Array(10) { CompletableFuture.completedFuture(it) } + csArray.asCffu(testCffuFactory).forEachIndexed { index, cffu -> + checkAsCffu(cffu, index) + } + } + + test("cffuAllOf/cffuAnyOf for collection") { + listOf( + testCffuFactory.completedFuture(42), + testCffuFactory.completedFuture(43), + testCffuFactory.completedFuture(44), + ).allCffu(testCffuFactory).await() shouldBe listOf(42, 43, 44) + + setOf( + testCffuFactory.completedFuture(42), + testCffuFactory.completedFuture(43), + testCffuFactory.completedFuture(44), + ).allCffu(testCffuFactory).await() shouldBe listOf(42, 43, 44) + + listOf( + CompletableFuture.completedFuture(42), + CompletableFuture.completedFuture(43), + CompletableFuture.completedFuture(44), + ).allCffu(testCffuFactory).await() shouldBe listOf(42, 43, 44) + + setOf( + CompletableFuture.completedFuture(42), + CompletableFuture.completedFuture(43), + CompletableFuture.completedFuture(44), + ).allCffu(testCffuFactory).await() shouldBe listOf(42, 43, 44) + + listOf( + testCffuFactory.newIncompleteCffu(), + testCffuFactory.newIncompleteCffu(), + testCffuFactory.completedFuture(42), + ).anyCffu(testCffuFactory).await() shouldBe 42 + + setOf( + testCffuFactory.newIncompleteCffu(), + testCffuFactory.completedFuture(42), + testCffuFactory.newIncompleteCffu(), + ).anyCffu(testCffuFactory).await() shouldBe 42 + + listOf( + CompletableFuture(), + CompletableFuture(), + CompletableFuture.completedFuture(42), + ).anyCffu(testCffuFactory).await() shouldBe 42 + + setOf( + CompletableFuture(), + CompletableFuture.completedFuture(42), + CompletableFuture(), + ).anyCffu(testCffuFactory).await() shouldBe 42 + } + + test("cffuAllOf/cffuAnyOf for array") { + arrayOf( + testCffuFactory.completedFuture(42), + testCffuFactory.completedFuture(43), + testCffuFactory.completedFuture(44), + ).allCffu(testCffuFactory).await() shouldBe listOf(42, 43, 44) + + arrayOf( + CompletableFuture.completedFuture(42), + CompletableFuture.completedFuture(43), + CompletableFuture.completedFuture(44), + ).allCffu(testCffuFactory).await() shouldBe listOf(42, 43, 44) + + arrayOf( + testCffuFactory.newIncompleteCffu(), + testCffuFactory.newIncompleteCffu(), + testCffuFactory.completedFuture(42), + ).anyCffu(testCffuFactory).await() shouldBe 42 + + arrayOf( + CompletableFuture(), + CompletableFuture(), + CompletableFuture.completedFuture(42), + ).anyCffu(testCffuFactory).await() shouldBe 42 + } + + test("toCompletableFuture for Cffu collection/array") { + val range = 0 until 10 + val cfs: List> = range.map { + CompletableFuture.completedFuture(it) + } + val cfArray = cfs.toTypedArray() + val csArray: Array> = Array(cfArray.size) { cfArray[it] } + cfArray.javaClass shouldNotBe csArray.javaClass + cfArray::class shouldNotBe csArray::class + cfArray shouldBe csArray // shouldBe ignore the array type! + + val cffus: List> = cfs.asCffu(testCffuFactory) + cffus.toCompletableFuture() shouldBe cfs + cffus.toSet().toCompletableFuture() shouldBe cfs + + val cffuArray: Array> = cffus.toTypedArray() + cffuArray.toCompletableFuture().let { + it shouldBe cfArray + it shouldNotBeSameInstanceAs cfArray + + it.shouldBeTypeOf>>() + it.shouldNotBeTypeOf>>() + } + + csArray.toCompletableFuture().let { + it shouldBe cfArray + it shouldNotBeSameInstanceAs cfArray + + it.shouldBeTypeOf>>() + it.shouldNotBeTypeOf>>() + } + } + + test("cffuUnwrap for Cffu collection/array") { + val range = 0 until 10 + val cfs: List> = range.map { + CompletableFuture.completedFuture(it) + } + val cfArray = cfs.toTypedArray() + + val cffus: List> = cfs.asCffu(testCffuFactory) + cffus.cffuUnwrap() shouldBe cfs + cffus.toSet().cffuUnwrap() shouldBe cfs + + val cffuArray: Array> = cffus.toTypedArray() + cffuArray.cffuUnwrap() shouldBe cfArray } }) diff --git a/src/test/java/io/foldright/test_utils/TestThreadPoolManager.kt b/src/test/java/io/foldright/test_utils/TestThreadPoolManager.kt index f9bc5951..e382dd49 100644 --- a/src/test/java/io/foldright/test_utils/TestThreadPoolManager.kt +++ b/src/test/java/io/foldright/test_utils/TestThreadPoolManager.kt @@ -2,6 +2,7 @@ package io.foldright.test_utils +import io.foldright.cffu.CffuFactoryBuilder.newCffuFactoryBuilder import io.kotest.core.annotation.AutoScan import io.kotest.core.listeners.AfterProjectListener import io.kotest.core.listeners.BeforeProjectListener @@ -93,6 +94,8 @@ fun shutdownExecutorService(vararg executors: ExecutorService) { val testThreadPoolExecutor: ExecutorService = createThreadPool("CompletableFutureUseTest_ThreadPool") +val testCffuFactory = newCffuFactoryBuilder(testThreadPoolExecutor).build(); + val testForkJoinPoolExecutor: ExecutorService = createThreadPool("CompletableFutureUseTest_ForkJoinPool", true)