// Path: mug/src/test/java/com/google/mu/util/concurrent/FutureAssertions.java
// public static ThrowableSubject assertCauseOf(
//     Class<? extends Throwable> exceptionType, CompletionStage<?> stage) {
//   CompletableFuture<?> future = stage.toCompletableFuture();
//   Throwable thrown = Assertions.assertThrows(exceptionType, future::get);
//   assertThat(future.isDone()).isTrue();
//   assertThat(future.isCompletedExceptionally()).isTrue();
//   return assertThat(thrown.getCause());
// }


import org.junit.Test;
import org.mockito.Mockito;
import com.google.common.testing.NullPointerTester;
import static com.google.common.truth.Truth.assertThat;
import static com.google.mu.util.concurrent.FutureAssertions.assertCauseOf;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicReference;
  }

  @Test public void testPropagateCancellation_innerAlreadyCompleted() throws Exception {
    CompletableFuture<String> outer = new CompletableFuture<>();
    CompletableFuture<String> inner = new CompletableFuture<>();
    assertThat(Utils.propagateCancellation(outer, inner)).isSameAs(outer);
    inner.complete("inner");
    outer.cancel(false);
    assertThat(outer.isCancelled()).isTrue();
    assertThat(inner.isCancelled()).isFalse();
    assertThat(outer.isCompletedExceptionally()).isTrue();
    assertThat(inner.isCompletedExceptionally()).isFalse();
    assertThat(outer.isDone()).isTrue();
    assertThat(inner.isDone()).isTrue();
    assertThat(inner.get()).isEqualTo("inner");
  }

  @Test public void testPropagateCancellation_innerAlreadyFailed() {
    CompletableFuture<String> outer = new CompletableFuture<>();
    CompletableFuture<String> inner = new CompletableFuture<>();
    assertThat(Utils.propagateCancellation(outer, inner)).isSameAs(outer);
    IOException exception = new IOException();
    inner.completeExceptionally(exception);
    outer.cancel(false);
    assertThat(outer.isCancelled()).isTrue();
    assertThat(inner.isCancelled()).isFalse();
    assertThat(outer.isCompletedExceptionally()).isTrue();
    assertThat(inner.isCompletedExceptionally()).isTrue();
    assertThat(outer.isDone()).isTrue();
    assertThat(inner.isDone()).isTrue();
// Path: mug/src/test/java/com/google/mu/util/concurrent/FutureAssertions.java
// public static ThrowableSubject assertCauseOf(
//     Class<? extends Throwable> exceptionType, CompletionStage<?> stage) {
//   CompletableFuture<?> future = stage.toCompletableFuture();
//   Throwable thrown = Assertions.assertThrows(exceptionType, future::get);
//   assertThat(future.isDone()).isTrue();
//   assertThat(future.isCompletedExceptionally()).isTrue();
//   return assertThat(thrown.getCause());
// }


// Path: mug/src/test/java/com/google/mu/util/concurrent/UtilsTest.java
import org.junit.Test;
import org.mockito.Mockito;
import com.google.common.testing.NullPointerTester;
import static com.google.common.truth.Truth.assertThat;
import static com.google.mu.util.concurrent.FutureAssertions.assertCauseOf;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Optional;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicReference;

  }

  @Test public void testPropagateCancellation_innerAlreadyCompleted() throws Exception {
    CompletableFuture<String> outer = new CompletableFuture<>();
    CompletableFuture<String> inner = new CompletableFuture<>();
    assertThat(Utils.propagateCancellation(outer, inner)).isSameAs(outer);
    inner.complete("inner");
    outer.cancel(false);
    assertThat(outer.isCancelled()).isTrue();
    assertThat(inner.isCancelled()).isFalse();
    assertThat(outer.isCompletedExceptionally()).isTrue();
    assertThat(inner.isCompletedExceptionally()).isFalse();
    assertThat(outer.isDone()).isTrue();
    assertThat(inner.isDone()).isTrue();
    assertThat(inner.get()).isEqualTo("inner");
  }

  @Test public void testPropagateCancellation_innerAlreadyFailed() {
    CompletableFuture<String> outer = new CompletableFuture<>();
    CompletableFuture<String> inner = new CompletableFuture<>();
    assertThat(Utils.propagateCancellation(outer, inner)).isSameAs(outer);
    IOException exception = new IOException();
    inner.completeExceptionally(exception);
    outer.cancel(false);
    assertThat(outer.isCancelled()).isTrue();
    assertThat(inner.isCancelled()).isFalse();
    assertThat(outer.isCompletedExceptionally()).isTrue();
    assertThat(inner.isCompletedExceptionally()).isTrue();
    assertThat(outer.isDone()).isTrue();
    assertThat(inner.isDone()).isTrue();
    assertCauseOf(ExecutionException.class, inner).isSameAs(exception);