@NonNull
public static <T> Result<T> failure(@NonNull final Throwable failure) {
  return failure == ABSENT_THROWABLE
      ? Result.<T>absent() : new Result<T>(null, checkNotNull(failure));
} @NonNull
public static <T> Result<T> present(@NonNull final T value) {
  return success(value);
} @NonNull
public static <T> Result<T> success(@NonNull final T value) {
  return new Result<>(checkNotNull(value), null);
} @SuppressWarnings({"unchecked", "UnusedParameters"})
@NonNull
public static <T> RPLayout<T, RPMain<T>> repositoryPresenterOf(@Nullable final Class<T> type) {
  return new RepositoryPresenterCompiler();
} @NonNull
public static ListUpdateCallback verifyingWrapper(
    @NonNull final ListUpdateCallback mockCallback) {
  // 'verify()' turns only the next method call on that mock to a verification call, so using
  // this wrapper to insert 'verify()' for each call when verifying the diff results.
  return new ListUpdateCallback() {
    @Override
    public void onInserted(final int position, final int count) {
      verify(mockCallback).onInserted(position, count);
    }

    @Override
    public void onRemoved(final int position, final int count) {
      verify(mockCallback).onRemoved(position, count);
    }

    @Override
    public void onMoved(final int fromPosition, final int toPosition) {
      verify(mockCallback).onMoved(fromPosition, toPosition);
    }

    @Override
    public void onChanged(final int position, final int count, final Object payload) {
      verify(mockCallback).onChanged(position, count, payload);
    }
  };
} public interface Binder<TFirst, TSecond> {

  /**
   * Accepts the given values {@code first} and {@code second}.
   */
  void bind(@NonNull TFirst first, @NonNull TSecond second);
} public final class Binders {

  /**
   * Returns a {@link Binder} that does nothing.
   */
  @SuppressWarnings("unchecked")
  @NonNull
  public static <TFirst, TSecond> Binder<TFirst, TSecond> nullBinder() {
    return NULL_OPERATOR;
  }

  private Binders() {}
} public final class Functions {
  @NonNull
  private static final ResultAsListFunction<Object> RESULT_AS_LIST_FUNCTION =
      new ResultAsListFunction<>();
  @NonNull
  private static final ItemAsListFunction<Object> ITEM_AS_LIST_FUNCTION =
      new ItemAsListFunction<>();
  @NonNull
  private static final ResultListAsListFunction<Object> RESULT_LIST_AS_LIST_FUNCTION =
      new ResultListAsListFunction<>();

  /**
   * Returns a {@link Function} that returns {@code object} as the result of each
   * {@link Function#apply} function call.
   */
  @NonNull
  public static <F, T> Function<F, T> staticFunction(@NonNull final T object) {
    return new StaticProducer<>(object);
  }

  /**
   * Returns a {@link Function} that returns the result of {@code supplier} as the result of each
   * {@link Function#apply} function call.
   */
  @NonNull
  public static <F, T> Function<F, T> supplierAsFunction(
      @NonNull final Supplier<? extends T> supplier) {
    return new SupplierAsFunction<>(supplier);
  }

  /**
   * Returns a {@link Function} that passes on the {@link Function} input as output.
   */
  @NonNull
  public static <T> Function<T, T> identityFunction() {
    @SuppressWarnings("unchecked")
    final Function<T, T> identityFunction = (Function<T, T>) NULL_OPERATOR;
    return identityFunction;
  }

  /**
   * Starts describing {@link Function} that starts with a single item.
   *
   * @return the next {@link FunctionCompilerStates} state
   */
  @NonNull
  @SuppressWarnings({"unchecked", "UnusedParameters"})
  public static <F> FItem<F, F> functionFrom(@Nullable Class<F> from) {
    return functionCompiler();
  }

  /**
   * Starts describing a {@link Function} that starts with a {@link List} of items.
   *
   * @return the next {@link FunctionCompilerStates} state
   */
  @NonNull
  @SuppressWarnings({"unchecked", "UnusedParameters"})
  public static <F> FList<F, List<F>, List<F>> functionFromListOf(
      @Nullable final Class<F> from) {
    return functionCompiler();
  }

  /**
   * Returns a {@link Function} that wraps a {@link Throwable} in a
   * {@link Result#failure(Throwable)}).
   */
  @SuppressWarnings("unchecked")
  @NonNull
  public static <T> Function<Throwable, Result<T>> failedResult() {
    return (Function<Throwable, Result<T>>) FAILED_RESULT;
  }

  /**
   * Returns a {@link Function} that wraps a {@link Throwable} in a
   * {@link Result#failure(Throwable)}).
   */
  @SuppressWarnings("unchecked")
  @NonNull
  public static <T> Function<Result<T>, List<T>> resultAsList() {
    return (Function) RESULT_AS_LIST_FUNCTION;
  }

  /**
   * Returns a {@link Function} that wraps a {@link Throwable} in a
   * {@link Result#failure(Throwable)}).
   */
  @SuppressWarnings("unchecked")
  @NonNull
  public static <T> Function<T, List<T>> itemAsList() {
    return (Function) ITEM_AS_LIST_FUNCTION;
  }

  /**
   * Returns a {@link Function} that wraps a {@link Throwable} in a
   * {@link Result#failure(Throwable)}).
   */
  @SuppressWarnings("unchecked")
  @NonNull
  public static <T> Function<Result<List<T>>, List<T>> resultListAsList() {
    return (Function) RESULT_LIST_AS_LIST_FUNCTION;
  }

  private static final class SupplierAsFunction<F, T> implements Function<F, T> {
    @NonNull
    private final Supplier<? extends T> supplier;

    SupplierAsFunction(@NonNull final Supplier<? extends T> supplier) {
      this.supplier = checkNotNull(supplier);
    }

    @NonNull
    @Override
    public T apply(@NonNull F from) {
      return supplier.get();
    }
  }

  private static final class ItemAsListFunction<T> implements Function<T, List<T>> {

    @NonNull
    @Override
    public List<T> apply(@NonNull final T input) {
      return singletonList(input);
    }
  }

  private static final class ResultAsListFunction<T> implements Function<Result<T>, List<T>> {

    @NonNull
    @Override
    public List<T> apply(@NonNull final Result<T> input) {
      return input.asList();
    }
  }

  private static final class ResultListAsListFunction<T>
      implements Function<Result<List<T>>, List<T>> {

    @NonNull
    @Override
    public List<T> apply(@NonNull final Result<List<T>> input) {
      return input.isPresent() ? input.get() : Collections.<T>emptyList();
    }
  }

  private Functions() {}
} public final class Result<T> {
  @NonNull
  private static final Result<Object> ABSENT;
  @NonNull
  private static final Result<Object> FAILURE;
  @NonNull
  private static final Throwable ABSENT_THROWABLE;

  static {
    final Throwable failureThrowable = new Throwable("Attempt failed");
    failureThrowable.setStackTrace(new StackTraceElement[0]);
    FAILURE = new Result<>(null, failureThrowable);
    ABSENT_THROWABLE = new NullPointerException("Value is absent");
    ABSENT_THROWABLE.setStackTrace(new StackTraceElement[0]);
    ABSENT = new Result<>(null, ABSENT_THROWABLE);
  }

  @Nullable
  private final T value;
  @Nullable
  private transient volatile List<T> list;
  @Nullable
  private final Throwable failure;

  Result(@Nullable final T value, @Nullable final Throwable failure) {
    checkArgument(value != null ^ failure != null, "Illegal Result arguments");
    this.value = value;
    this.failure = failure;
    this.list = value != null ? null : Collections.<T>emptyList();
  }

  /**
   * Creates a {@link Result} of a successful attempt that produced the given {@code value}.
   */
  @NonNull
  public static <T> Result<T> success(@NonNull final T value) {
    return new Result<>(checkNotNull(value), null);
  }

  /**
   * Creates a {@link Result} of a failed attempt that encountered the given {@code failure}.
   */
  @NonNull
  public static <T> Result<T> failure(@NonNull final Throwable failure) {
    return failure == ABSENT_THROWABLE
        ? Result.<T>absent() : new Result<T>(null, checkNotNull(failure));
  }

  /**
   * Returns the singleton {@link Result} denoting a failed attempt that has a generic failure.
   */
  @SuppressWarnings("unchecked")
  @NonNull
  public static <T> Result<T> failure() {
    return (Result<T>) FAILURE;
  }

  /**
   * Creates a {@link Result} denoting a non-null value. This is an alias of {@link #success}.
   */
  @NonNull
  public static <T> Result<T> present(@NonNull final T value) {
    return success(value);
  }

  /**
   * Returns the singleton {@link Result} denoting an absent value, with a failure of
   * {@link NullPointerException}.
   */
  @SuppressWarnings("unchecked")
  @NonNull
  public static <T> Result<T> absent() {
    return (Result<T>) ABSENT;
  }

  /**
   * Creates a {@code Result} denoting the {@code value} if it is non-null, or returns the singleton
   * {@link #absent} result.
   */
  @NonNull
  public static <T> Result<T> absentIfNull(@Nullable final T value) {
    return value == null ? Result.<T>absent() : present(value);
  }

  /**
   * Returns whether this is the result of a successful attempt.
   */
  public boolean succeeded() {
    return value != null;
  }

  /**
   * Returns whether this is the result of a failed attempt.
   */
  public boolean failed() {
    return value == null;
  }

  /**
   * Returns whether the output value is present. This is an alias of {@link #succeeded()}.
   */
  public boolean isPresent() {
    return succeeded();
  }

  /**
   * Returns whether this is a result denoting an absent value. This is <i>not</i> an alias of
   * {@link #failed()}; this checks whether this instance is obtained from {@link #absent()}.
   */
  public boolean isAbsent() {
    return this == ABSENT;
  }

  /**
   * Returns the output value of the successful attempt that produced this result.
   *
   * @throws FailedResultException If this is the result of a {@link #failed} attempt. The failure
   *     is available from {@link FailedResultException#getCause()}. This is an unchecked exception
   *     because it is easily avoidable by first checking whether the attempt has {@link #succeeded}
   *     or {@link #failed}, or by using other fluent style methods to achieve the same purpose.
   */
  @NonNull
  public T get() throws FailedResultException {
    if (value != null) {
      return value;
    }
    throw new FailedResultException(failure);
  }


  /**
   * Returns a list containing the value if it is present, or an empty list.
   */
  @NonNull
  public List<T> asList() {
    List<T> list = this.list;
    if (list == null) {
      synchronized (this) {
        list = this.list;
        if (list == null) {
          this.list = list = singletonList(value);
        }
      }
    }
    return list;
  }

  /**
   * Returns the failure encountered in the attempt that produced this result.
   *
   * @throws IllegalStateException If this is the result of a {@link #succeeded} attempt.
   */
  @NonNull
  public Throwable getFailure() {
    checkState(failure != null, "Not a failure");
    return failure;
  }

  /**
   * Returns the output value of the successful attempt, or null if the attempt has {@link #failed}.
   */
  @Nullable
  public T orNull() {
    return value;
  }

  /**
   * Returns the failure encountered in the attempt that produced this result, or null if the
   * attempt has {@link #succeeded}.
   */
  @Nullable
  public Throwable failureOrNull() {
    return failure;
  }

  /**
   * Passes the output value to the {@code receiver} if the attempt has succeeded; otherwise does
   * nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public Result<T> ifSucceededSendTo(@NonNull final Receiver<? super T> receiver) {
    if (value != null) {
      receiver.accept(value);
    }
    return this;
  }

  /**
   * Passes the encountered failure to the {@code receiver} if the attempt has failed; otherwise
   * does nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public Result<T> ifFailedSendTo(@NonNull final Receiver<? super Throwable> receiver) {
    if (failure != null) {
      receiver.accept(failure);
    }
    return this;
  }


  /**
   * Passes the encountered failure to the {@code receiver} if the failure is absent; otherwise
   * does nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public Result<T> ifAbsentFailureSendTo(@NonNull final Receiver<? super Throwable> receiver) {
    if (failure == ABSENT_THROWABLE) {
      receiver.accept(failure);
    }
    return this;
  }

  /**
   * Passes the encountered failure to the {@code receiver} if the attempt has failed, except for
   * the failure absent; otherwise does nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public Result<T> ifNonAbsentFailureSendTo(@NonNull final Receiver<? super Throwable> receiver) {
    if (failure != null && failure != ABSENT_THROWABLE) {
      receiver.accept(failure);
    }
    return this;
  }

  /**
   * Binds the output value with {@code bindValue} using {@code binder} if the attempt has
   * succeeded; otherwise does nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public <U> Result<T> ifSucceededBind(@NonNull final U bindValue,
      @NonNull final Binder<? super T, ? super U> binder) {
    if (value != null) {
      binder.bind(value, bindValue);
    }
    return this;
  }

  /**
   * Binds the output value with {@code bindValue} using {@code binder} if the attempt has failed;
   * otherwise does nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public <U> Result<T> ifFailedBind(@NonNull final U bindValue,
      @NonNull final Binder<Throwable, ? super U> binder) {
    if (failure != null) {
      binder.bind(failure, bindValue);
    }
    return this;
  }

  /**
   * Binds the output value with {@code bindValue} using {@code binder} if the failure is absent;
   * otherwise does nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public <U> Result<T> ifAbsentFailureBind(@NonNull final U bindValue,
      @NonNull final Binder<Throwable, ? super U> binder) {
    if (failure == ABSENT_THROWABLE) {
      binder.bind(failure, bindValue);
    }
    return this;
  }

  /**
   * Binds the output value with {@code bindValue} using {@code binder} if the attempt has failed,
   * except for the failure absent; otherwise does nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public <U> Result<T> ifNonAbsentFailureBind(@NonNull final U bindValue,
      @NonNull final Binder<Throwable, ? super U> binder) {
    if (failure != null && failure != ABSENT_THROWABLE) {
      binder.bind(failure, bindValue);
    }
    return this;
  }

  /**
   * Binds the output value with the value from the {@code supplier} using {@code binder} if the
   * attempt has succeeded; otherwise does nothing, not calling either the binder or the supplier.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public <U> Result<T> ifSucceededBindFrom(@NonNull final Supplier<U> supplier,
      @NonNull final Binder<? super T, ? super U> binder) {
    if (value != null) {
      binder.bind(value, supplier.get());
    }
    return this;
  }

  /**
   * Binds the output value with the value from the {@code supplier} using {@code binder} if the
   * attempt has failed; otherwise does nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public <U> Result<T> ifFailedBindFrom(@NonNull final Supplier<U> supplier,
      @NonNull final Binder<Throwable, ? super U> binder) {
    if (failure != null) {
      binder.bind(failure, supplier.get());
    }
    return this;
  }

  /**
   * Binds the output value with the value from the {@code supplier} using {@code binder} if the
   * failure is absent; otherwise does nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public <U> Result<T> ifAbsentFailureBindFrom(@NonNull final Supplier<U> supplier,
      @NonNull final Binder<Throwable, ? super U> binder) {
    if (failure == ABSENT_THROWABLE) {
      binder.bind(failure, supplier.get());
    }
    return this;
  }

  /**
   * Binds the output value with the value from the {@code supplier} using {@code binder} if the
   * attempt has failed, except for the failure absent; otherwise does nothing.
   *
   * @return This instance, for chaining.
   */
  @NonNull
  public <U> Result<T> ifNonAbsentFailureBindFrom(@NonNull final Supplier<U> supplier,
      @NonNull final Binder<Throwable, ? super U> binder) {
    if (failure != null && failure != ABSENT_THROWABLE) {
      binder.bind(failure, supplier.get());
    }
    return this;
  }

  /**
   * Returns a result denoting a failed attempt to obtain a value of a different type, with the same
   * failure.
   *
   * @throws IllegalStateException If this is the result of a {@link #succeeded} attempt.
   */
  @SuppressWarnings("unchecked")
  @NonNull
  public <U> Result<U> sameFailure() {
    checkState(failed(), "Not a failure");
    return (Result<U>) this;
  }

  /**
   * Returns a {@link Result} wrapping the result of applying the given {@code function} to the
   * output value encapsulated in this result, or if this is the result of a {@link #failed}
   * attempt, returns the {@link #sameFailure}.
   */
  @NonNull
  public <U> Result<U> ifSucceededMap(@NonNull final Function<? super T, U> function) {
    if (value != null) {
      return success(function.apply(value));
    }
    return sameFailure();
  }

  /**
   * Returns the result of a follow-up attempt to apply the given {@code attemptFunction} to the
   * output value encapsulated in this result, or if this is the result of a {@link #failed}
   * attempt, returns the {@link #sameFailure}.
   */
  @NonNull
  public <U> Result<U> ifSucceededAttemptMap(
      @NonNull final Function<? super T, Result<U>> attemptFunction) {
    if (value != null) {
      return attemptFunction.apply(value);
    }
    return sameFailure();
  }

  /**
   * Returns a {@link Result} wrapping the result of merging the output value encapsulated in this
   * result with the given {@code mergeValue} using the {@code merger}, or if this is the result of
   * a {@link #failed} attempt, returns the {@link #sameFailure}.
   */
  @NonNull
  public <U, V> Result<V> ifSucceededMerge(@NonNull final U mergeValue,
      @NonNull final Merger<? super T, ? super U, V> merger) {
    if (value != null) {
      return success(merger.merge(value, mergeValue));
    }
    return sameFailure();
  }

  /**
   * Returns the result of a follow-up attempt to merge the output value encapsulated in this
   * result with the given {@code mergeValue} using the {@code attemptMerger}, or if this is the
   * result of a {@link #failed} attempt, returns the {@link #sameFailure}.
   */
  @NonNull
  public <U, V> Result<V> ifSucceededAttemptMerge(@NonNull final U mergeValue,
      @NonNull final Merger<? super T, ? super U, Result<V>> attemptMerger) {
    if (value != null) {
      return attemptMerger.merge(value, mergeValue);
    }
    return sameFailure();
  }

  /**
   * Returns a {@link Result} wrapping the result of merging the output value encapsulated in this
   * result with the value from the given {@code mergeValueSupplier} using the {@code merger}, or if
   * this is the result of a {@link #failed} attempt, returns the {@link #sameFailure}.
   */
  @NonNull
  public <U, V> Result<V> ifSucceededMergeFrom(@NonNull final Supplier<U> mergeValueSupplier,
      @NonNull final Merger<? super T, ? super U, V> merger) {
    if (value != null) {
      return success(merger.merge(value, mergeValueSupplier.get()));
    }
    return sameFailure();
  }

  /**
   * Returns the result of a follow-up attempt to merge the output value encapsulated in this
   * result with the value from the given {@code mergeValueSupplier} using the
   * {@code attemptMerger}, or if this is the result of a {@link #failed} attempt, returns the
   * {@link #sameFailure}.
   *
   * <p>This method is agnostic of the value type of the {@code mergeValueSupplier}. If it is also
   * fallible, the {@code attemptMerger} has the responsibility to interpret the result should the
   * supplier fail. The merger may choose to, for example, return the {@code sameFailure()} if this
   * happens.
   */
  @NonNull
  public <U, V> Result<V> ifSucceededAttemptMergeFrom(
      @NonNull final Supplier<U> mergeValueSupplier,
      @NonNull final Merger<? super T, ? super U, Result<V>> attemptMerger) {
    if (value != null) {
      return attemptMerger.merge(value, mergeValueSupplier.get());
    }
    return sameFailure();
  }

  /**
   * Returns the output value if the attempt has succeeded, or the given {@code other} value
   * otherwise.
   */
  @NonNull
  public T orElse(@NonNull final T other) {
    return value != null ? value : checkNotNull(other);
  }

  /**
   * Returns the output value if the attempt has succeeded, or the value from the given
   * {@code supplier} otherwise.
   */
  @NonNull
  public T orGetFrom(@NonNull final Supplier<? extends T> supplier) {
    return value != null ? value : Preconditions.<T>checkNotNull(supplier.get());
  }

  /**
   * Returns the same result if the attempt has succeeded, or the result of the attempt to get from
   * the given {@code attemptSupplier} otherwise.
   */
  @SuppressWarnings("unchecked")
  @NonNull
  public Result<T> orAttemptGetFrom(
      @NonNull final Supplier<? extends Result<? extends T>> supplier) {
    return value != null ? this : (Result<T>) checkNotNull(supplier.get());
  }

  /**
   * Returns the output value if the attempt has succeeded, or the resulting value of applying the
   * given {@code recoverFunction} to the failure of the attempt.
   */
  @SuppressWarnings("ConstantConditions")
  @NonNull
  public T recover(@NonNull final Function<? super Throwable, ? extends T> recoverFunction) {
    if (value != null) {
      return value;
    }
    return recoverFunction.apply(failure);
  }

  /**
   * Returns the same result if the attempt has succeeded, or the result of the attempt to apply the
   * given {@code attemptRecoverFunction} to the failure of the attempt.
   */
  @SuppressWarnings({"ConstantConditions", "unchecked"})
  @NonNull
  public Result<T> attemptRecover(
      @NonNull final Function<? super Throwable, ? extends Result<? extends T>>
          attemptRecoverFunction) {
    if (value != null) {
      return this;
    }
    return (Result<T>) attemptRecoverFunction.apply(failure);
  }

  public boolean contains(@NonNull final T value) {
    return this.value != null && this.value.equals(value);
  }

  @Override
  public boolean equals(final Object o) {
    if (this == o) { return true; }
    if (o == null || getClass() != o.getClass()) { return false; }

    final Result<?> result = (Result<?>) o;

    if (value != null ? !value.equals(result.value) : result.value != null) { return false; }
    if (failure != null ? !failure.equals(result.failure) : result.failure != null) {
      return false;
    }

    return true;
  }

  @Override
  public int hashCode() {
    int result = value != null ? value.hashCode() : 0;
    result = 31 * result + (failure != null ? failure.hashCode() : 0);
    return result;
  }

  @Override
  public String toString() {
    if (this == ABSENT) {
      return "Result{Absent}";
    }
    if (this == FAILURE) {
      return "Result{Failure}";
    }
    if (value != null) {
      return "Result{Success; value=" + value + "}";
    }
    return "Result{Failure; failure=" + failure + "}";
  }
} public final class DiffingLogic extends DiffUtil.Callback
    implements Function<String, String> {
  @NonNull
  private final List<String> oldData;
  @NonNull
  private final List<String> newData;

  public DiffingLogic(@NonNull final List<String> oldData, @NonNull final List<String> newData) {
    this.oldData = oldData;
    this.newData = newData;
  }

  @NonNull
  @Override
  public String apply(@NonNull final String input) {
    // Function as key extractor
    return input.substring(0, 2);
  }

  @Override
  public int getOldListSize() {
    return oldData.size();
  }

  @Override
  public int getNewListSize() {
    return newData.size();
  }

  @Override
  public boolean areItemsTheSame(final int oldItemPosition, final int newItemPosition) {
    final String oldItem = oldData.get(oldItemPosition);
    final String newItem = newData.get(newItemPosition);
    return apply(oldItem).equals(apply(newItem));
  }

  @Override
  public boolean areContentsTheSame(final int oldItemPosition, final int newItemPosition) {
    final String oldItem = oldData.get(oldItemPosition);
    final String newItem = newData.get(newItemPosition);
    return oldItem.equals(newItem);
  }
}
import static com.google.android.agera.Result.failure;
import static com.google.android.agera.Result.present;
import static com.google.android.agera.Result.success;
import static com.google.android.agera.rvadapter.RepositoryPresenters.repositoryPresenterOf;
import static com.google.android.agera.rvadapter.test.VerifyingWrappers.verifyingWrapper;
import static com.google.android.agera.rvadapter.test.matchers.HasPrivateConstructor.hasPrivateConstructor;
import static java.lang.String.valueOf;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import android.support.annotation.NonNull;
import android.support.v7.util.DiffUtil;
import android.support.v7.util.ListUpdateCallback;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import com.google.android.agera.Binder;
import com.google.android.agera.Binders;
import com.google.android.agera.Function;
import com.google.android.agera.Functions;
import com.google.android.agera.Receiver;
import com.google.android.agera.Result;
import com.google.android.agera.rvadapter.test.DiffingLogic;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
    final RepositoryPresenter<Result<String>> resultRepositoryPresenter =
        repositoryPresenterOf(String.class)
            .layout(LAYOUT_ID)
            .stableId(STABLE_ID)
            .forResult();
    assertThat(resultRepositoryPresenter.getItemId(STRING_RESULT, 0), is(STABLE_ID));
  }

  @Test
  public void shouldReturnStaticStableIdForRepositoryPresenterOfItem() {
    final RepositoryPresenter<String> resultRepositoryPresenter =
        repositoryPresenterOf(String.class)
            .layout(LAYOUT_ID)
            .stableId(STABLE_ID)
            .forItem();
    assertThat(resultRepositoryPresenter.getItemId(STRING, 0), is(STABLE_ID));
  }

  @Test
  public void shouldReturnStableIdForRepositoryPresenterOfResultList() {
    final RepositoryPresenter<Result<List<String>>> resultListRepositoryPresenter =
        repositoryPresenterOf(String.class)
            .layout(LAYOUT_ID)
            .stableIdForItem(Functions.<String, Long>staticFunction(STABLE_ID))
            .forResultList();
    assertThat(resultListRepositoryPresenter.getItemId(STRING_LIST_RESULT, 1), is(STABLE_ID));
  }

  @Test
  public void shouldReturnStableIdForRepositoryPresenterOfList() {
    final RepositoryPresenter<List<String>> listRepositoryPresenter =
        repositoryPresenterOf(String.class)
            .layout(LAYOUT_ID)
            .stableIdForItem(Functions.<String, Long>staticFunction(STABLE_ID))
            .forList();
    assertThat(listRepositoryPresenter.getItemId(STRING_LIST, 1), is(STABLE_ID));
  }

  @Test
  public void shouldReturnStableIdForRepositoryPresenterOfListWithBinder() {
    final RepositoryPresenter<List<String>> resultRepositoryPresenter =
        repositoryPresenterOf(String.class)
            .layout(LAYOUT_ID)
            .stableIdForItem(Functions.<String, Long>staticFunction(STABLE_ID))
            .bindWith(binder)
            .forList();
    assertThat(resultRepositoryPresenter.getItemId(STRING_LIST, 1), is(STABLE_ID));
  }

  @Test
  public void shouldAllowStableIdMethodForAnySuperType() {
    repositoryPresenterOf(String.class)
        .layout(LAYOUT_ID)
        .stableIdForItem(Functions.<CharSequence, Long>staticFunction(STABLE_ID))
        .forResult();
  }

  @Test
  public void shouldHandleRebindWithNewData() {
    final RepositoryPresenter<String> resultRepositoryPresenter =
        repositoryPresenterOf(String.class)
            .layout(LAYOUT_ID)
            .bindWith(binder)
            .forItem();

    resultRepositoryPresenter.bind(STRING, 0, viewHolder);

    verify(binder).bind(STRING, view);
    reset(binder);

    resultRepositoryPresenter.bind(SECOND_STRING, 0, viewHolder);

    verify(binder).bind(SECOND_STRING, view);
  }

  @Test
  public void shouldHandleRebindWithSameData() {
    final RepositoryPresenter<String> resultRepositoryPresenter =
        repositoryPresenterOf(String.class)
            .layout(LAYOUT_ID)
            .bindWith(binder)
            .forItem();

    resultRepositoryPresenter.bind(STRING, 0, viewHolder);

    verify(binder).bind(STRING, view);
    reset(binder);

    resultRepositoryPresenter.bind(STRING, 0, viewHolder);

    verify(binder).bind(STRING, view);
  }

  @Test
  public void shouldRefuseFineGrainedEventsWithoutDiffWith() {
    final RepositoryPresenter<String> presenter =
        repositoryPresenterOf(String.class)
            .layout(LAYOUT_ID)
            .forItem();

    final boolean fineGrained = presenter.getUpdates("String1", "String2", listUpdateCallback);

    assertThat(fineGrained, is(false));
  }

  @Test
  public void shouldNotifyFineGrainedEventsWithDiffWith() {
    final List<String> oldData = asList("A:1", "B:2", "C:3");
    final List<String> newData = asList("B:2", "A:4", "C:5");
    final DiffingLogic diffingLogic = new DiffingLogic(oldData, newData);
    final RepositoryPresenter<List<String>> diffingPresenter =
        repositoryPresenterOf(String.class)
            .layout(LAYOUT_ID)
            .diffWith(diffingLogic, false)
            .forList();

    final boolean fineGrained = diffingPresenter.getUpdates(oldData, newData, listUpdateCallback);

    assertThat(fineGrained, is(true));
    DiffUtil.calculateDiff(diffingLogic, false).dispatchUpdatesTo(
        verifyingWrapper(listUpdateCallback));