// Path: src/main/java/com/spotify/trickle/Trickle.java
// public static <R> ConfigurableGraph<R> call(Func0<R> func) {
//   return new GraphBuilder<R>(func);
// }
// 
// Path: src/test/java/com/spotify/trickle/Util.java
// static Matcher<Throwable> hasAncestor(final Throwable expected) {
//   return new TypeSafeMatcher<Throwable>() {
//     @Override
//     protected boolean matchesSafely(Throwable item) {
//       for (Throwable cause = item ; cause != null ; cause = cause.getCause()) {
//         if (cause.equals(expected)) {
//           return true;
//         }
//       }
// 
//       return false;
//     }
// 
//     @Override
//     public void describeTo(Description description) {
//       description.appendText("with parent cause " + expected);
//     }
//   };
// }


import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import javax.annotation.Nullable;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
import static com.google.common.util.concurrent.Futures.immediateFuture;
import static com.spotify.trickle.Trickle.call;
import static com.spotify.trickle.Util.hasAncestor;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
    RuntimeException expected = new RuntimeException("expected");
    Graph<String> g = call(failingFunction(expected)).with(setupDebugInfoGraph()).named("failure")
        .bind(debugInfoInput, "fail me").debug(true);

    verifyCallInfos(g, expectedCallInfos(g, debugInfoReport));
  }

  @Test
  public void shouldUseDebugFlagOfInvokedGraph() throws Exception {
    RuntimeException expected = new RuntimeException("expected");
    Graph<String> succeedingGraph = setupDebugInfoGraph().debug(false);

    Graph<String> g = call(failingFunction(expected)).with(succeedingGraph).named("failure")
        .bind(debugInfoInput, "fail me").debug(true);

    verifyCallInfos(g, expectedCallInfos(g, succeedingGraph));
  }

  @Test
  public void shouldNotIncludeDebugInfoTwice() throws Exception {
    Throwable expected = new RuntimeException("expected");
    Graph<String> g = call(failingFunction(expected)).with(setupDebugInfoGraph()).named("failure")
        .bind(debugInfoInput, "fail me").debug(true);
    Graph<Integer> g1 = call(new Func1<String, Integer>() {
      @Override
      public ListenableFuture<Integer> run(@Nullable String arg) {
        return immediateFuture(arg == null ? 0 : arg.length());
      }
    }).with(g);

// Path: src/main/java/com/spotify/trickle/Trickle.java
// public static <R> ConfigurableGraph<R> call(Func0<R> func) {
//   return new GraphBuilder<R>(func);
// }
// 
// Path: src/test/java/com/spotify/trickle/Util.java
// static Matcher<Throwable> hasAncestor(final Throwable expected) {
//   return new TypeSafeMatcher<Throwable>() {
//     @Override
//     protected boolean matchesSafely(Throwable item) {
//       for (Throwable cause = item ; cause != null ; cause = cause.getCause()) {
//         if (cause.equals(expected)) {
//           return true;
//         }
//       }
// 
//       return false;
//     }
// 
//     @Override
//     public void describeTo(Description description) {
//       description.appendText("with parent cause " + expected);
//     }
//   };
// }


// Path: src/test/java/com/spotify/trickle/TrickleErrorHandlingTest.java
import com.google.common.base.Function;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import javax.annotation.Nullable;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
import static com.google.common.util.concurrent.Futures.immediateFuture;
import static com.spotify.trickle.Trickle.call;
import static com.spotify.trickle.Util.hasAncestor;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;

    RuntimeException expected = new RuntimeException("expected");
    Graph<String> g = call(failingFunction(expected)).with(setupDebugInfoGraph()).named("failure")
        .bind(debugInfoInput, "fail me").debug(true);

    verifyCallInfos(g, expectedCallInfos(g, debugInfoReport));
  }

  @Test
  public void shouldUseDebugFlagOfInvokedGraph() throws Exception {
    RuntimeException expected = new RuntimeException("expected");
    Graph<String> succeedingGraph = setupDebugInfoGraph().debug(false);

    Graph<String> g = call(failingFunction(expected)).with(succeedingGraph).named("failure")
        .bind(debugInfoInput, "fail me").debug(true);

    verifyCallInfos(g, expectedCallInfos(g, succeedingGraph));
  }

  @Test
  public void shouldNotIncludeDebugInfoTwice() throws Exception {
    Throwable expected = new RuntimeException("expected");
    Graph<String> g = call(failingFunction(expected)).with(setupDebugInfoGraph()).named("failure")
        .bind(debugInfoInput, "fail me").debug(true);
    Graph<Integer> g1 = call(new Func1<String, Integer>() {
      @Override
      public ListenableFuture<Integer> run(@Nullable String arg) {
        return immediateFuture(arg == null ? 0 : arg.length());
      }
    }).with(g);

    try {