// Copyright 2014 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.lib.collect.nestedset;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.util.concurrent.Futures.immediateCancelledFuture;
import static com.google.common.util.concurrent.Futures.immediateFailedFuture;
import static com.google.common.util.concurrent.Futures.immediateFuture;
import static org.junit.Assert.assertThrows;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.testing.EqualsTester;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.google.devtools.build.lib.collect.nestedset.NestedSetStore.MissingNestedSetException;
import com.google.devtools.build.lib.testutil.TestThread;
import com.google.devtools.build.lib.testutil.TestUtils;
import com.google.protobuf.ByteString;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeoutException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/** Tests for {@link NestedSet}. */
@RunWith(JUnit4.class)
public final class NestedSetTest {

  private static NestedSetBuilder<String> nestedSetBuilder(String... directMembers) {
    NestedSetBuilder<String> builder = NestedSetBuilder.stableOrder();
    builder.addAll(Lists.newArrayList(directMembers));
    return builder;
  }

  @Test
  public void simple() {
    NestedSet<String> set = nestedSetBuilder("a").build();

    assertThat(set.toList()).containsExactly("a");
    assertThat(set.isEmpty()).isFalse();
  }

  @Test
  public void flatToString() {
    assertThat(nestedSetBuilder().build().toString()).isEqualTo("[]");
    assertThat(nestedSetBuilder("a").build().toString()).isEqualTo("[a]");
    assertThat(nestedSetBuilder("a", "b").build().toString()).isEqualTo("[a, b]");
  }

  @Test
  public void nestedToString() {
    NestedSet<String> b = nestedSetBuilder("b1", "b2").build();
    NestedSet<String> c = nestedSetBuilder("c1", "c2").build();

    assertThat(nestedSetBuilder("a").addTransitive(b).build().toString()).isEqualTo("[b1, b2, a]");
    assertThat(nestedSetBuilder("a").addTransitive(b).addTransitive(c).build().toString())
        .isEqualTo("[b1, b2, c1, c2, a]");
    NestedSet<String> linkOrderSet =
        NestedSetBuilder.<String>linkOrder().add("a").addTransitive(b).addTransitive(c).build();
    assertThat(linkOrderSet.toString()).isEqualTo("[a, b2, b1, c2, c1]");

    assertThat(nestedSetBuilder().addTransitive(b).build().toString()).isEqualTo("[b1, b2]");
  }

  @Test
  public void tooLongToString() {
    NestedSetBuilder<Integer> builder = NestedSetBuilder.stableOrder();
    for (int i = 0; i < NestedSet.MAX_ELEMENTS_TO_STRING + 3; i++) {
      builder.add(i);
    }
    String stringRep = builder.build().toString();
    assertThat(stringRep).contains("[0, 1, 2, 3");
    assertThat(stringRep)
        .containsMatch(
            "\\[0, 1, 2, 3, .*"
                + (NestedSet.MAX_ELEMENTS_TO_STRING - 2)
                + ", "
                + (NestedSet.MAX_ELEMENTS_TO_STRING - 1)
                + "] \\(truncated, full size "
                + (NestedSet.MAX_ELEMENTS_TO_STRING + 3)
                + "\\)");
  }

  @Test
  public void isEmpty() {
    NestedSet<String> triviallyEmpty = nestedSetBuilder().build();
    assertThat(triviallyEmpty.isEmpty()).isTrue();

    NestedSet<String> emptyLevel1 = nestedSetBuilder().addTransitive(triviallyEmpty).build();
    assertThat(emptyLevel1.isEmpty()).isTrue();

    NestedSet<String> emptyLevel2 = nestedSetBuilder().addTransitive(emptyLevel1).build();
    assertThat(emptyLevel2.isEmpty()).isTrue();

    NestedSet<String> triviallyNonEmpty = nestedSetBuilder("mango").build();
    assertThat(triviallyNonEmpty.isEmpty()).isFalse();

    NestedSet<String> nonEmptyLevel1 = nestedSetBuilder().addTransitive(triviallyNonEmpty).build();
    assertThat(nonEmptyLevel1.isEmpty()).isFalse();

    NestedSet<String> nonEmptyLevel2 = nestedSetBuilder().addTransitive(nonEmptyLevel1).build();
    assertThat(nonEmptyLevel2.isEmpty()).isFalse();
  }

  @Test
  public void canIncludeAnyOrderInStableOrderAndViceVersa() {
    NestedSetBuilder.stableOrder()
        .addTransitive(
            NestedSetBuilder.compileOrder()
                .addTransitive(NestedSetBuilder.stableOrder().build())
                .build())
        .addTransitive(
            NestedSetBuilder.linkOrder()
                .addTransitive(NestedSetBuilder.stableOrder().build())
                .build())
        .addTransitive(
            NestedSetBuilder.naiveLinkOrder()
                .addTransitive(NestedSetBuilder.stableOrder().build())
                .build())
        .build();
    assertThrows(
        "Shouldn't be able to include a non-stable order inside a different non-stable order!",
        IllegalArgumentException.class,
        () ->
            NestedSetBuilder.compileOrder()
                .addTransitive(NestedSetBuilder.linkOrder().build())
                .build());
  }

  @Test
  public void reusesSingleTransitiveSet_noDirectMembers() {
    NestedSet<String> set = NestedSetBuilder.create(Order.STABLE_ORDER, "a", "b", "c");
    NestedSet<String> built = NestedSetBuilder.<String>stableOrder().addTransitive(set).build();
    assertThat(built).isSameInstanceAs(set);
  }

  @Test
  public void reusesSingleTransitiveSet_singletonEqualsDirects() {
    NestedSet<String> set = NestedSetBuilder.create(Order.STABLE_ORDER, "a");
    NestedSet<String> built =
        NestedSetBuilder.<String>stableOrder().add("a").addTransitive(set).build();
    assertThat(built).isSameInstanceAs(set);
  }

  @Test
  public void noReuseOfSingleTransitiveSet_orderWouldDiffer() {
    NestedSet<String> set = NestedSetBuilder.create(Order.NAIVE_LINK_ORDER, "b", "a");
    NestedSet<String> built =
        NestedSetBuilder.<String>naiveLinkOrder().add("a").add("b").addTransitive(set).build();
    assertThat(built).isNotSameInstanceAs(set);
    assertThat(set.toList()).containsExactly("b", "a").inOrder();
    assertThat(built.toList()).containsExactly("a", "b").inOrder();
  }

  /**
   * A handy wrapper that allows us to use EqualsTester to test shallowEquals and shallowHashCode.
   */
  private static final class SetWrapper<E> {
    NestedSet<E> set;

    SetWrapper(NestedSet<E> wrapped) {
      set = wrapped;
    }

    @Override
    public int hashCode() {
      return set.shallowHashCode();
    }

    @Override
    public boolean equals(Object o) {
      if (this == o) {
        return true;
      }
      if (!(o instanceof SetWrapper)) {
        return false;
      }
      try {
        @SuppressWarnings("unchecked")
        SetWrapper<E> other = (SetWrapper<E>) o;
        return set.shallowEquals(other.set);
      } catch (ClassCastException e) {
        return false;
      }
    }
  }

  @SafeVarargs
  private static <E> SetWrapper<E> flat(E... directMembers) {
    NestedSetBuilder<E> builder = NestedSetBuilder.stableOrder();
    builder.addAll(Lists.newArrayList(directMembers));
    return new SetWrapper<>(builder.build());
  }

  @SafeVarargs
  private static <E> SetWrapper<E> nest(SetWrapper<E>... nested) {
    NestedSetBuilder<E> builder = NestedSetBuilder.stableOrder();
    for (SetWrapper<E> wrap : nested) {
      builder.addTransitive(wrap.set);
    }
    return new SetWrapper<>(builder.build());
  }

  @SafeVarargs
  // Restricted to <Integer> to avoid ambiguity with the other nest() function.
  private static SetWrapper<Integer> nest(Integer elem, SetWrapper<Integer>... nested) {
    NestedSetBuilder<Integer> builder = NestedSetBuilder.stableOrder();
    builder.add(elem);
    for (SetWrapper<Integer> wrap : nested) {
      builder.addTransitive(wrap.set);
    }
    return new SetWrapper<>(builder.build());
  }

  private static final int UNKNOWN_DEPTH = 7;

  @Test
  public void shallowEquality() {
    // Used below to check that inner nested sets can be compared by reference equality.
    SetWrapper<Integer> myRef = nest(nest(flat(7, 8)), flat(9));
    // Used to check equality for deserializing nested sets
    ListenableFuture<Object[]> contents = immediateFuture(new Object[] {"a", "b"});
    NestedSet<String> referenceNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, contents);
    NestedSet<String> otherReferenceNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, contents);

    // Each "equality group" contains elements that are equal to one another
    // (according to equals() and hashCode()), yet distinct from all elements
    // of all other equality groups.
    new EqualsTester()
        .addEqualityGroup(flat(), flat(), nest(flat())) // Empty set elision.
        .addEqualityGroup(NestedSetBuilder.<Integer>linkOrder().build())
        .addEqualityGroup(flat(3), flat(3), flat(3, 3)) // Element de-duplication.
        .addEqualityGroup(flat(4), nest(flat(4))) // Automatic elision of one-element nested sets.
        .addEqualityGroup(NestedSetBuilder.<Integer>linkOrder().add(4).build())
        .addEqualityGroup(nestedSetBuilder("4").build()) // Like flat("4").
        .addEqualityGroup(flat(3, 4), flat(3, 4))
        // Make a couple sets deep enough that shallowEquals() fails.
        // If this test case fails because you improve the representation, just delete it.
        .addEqualityGroup(nest(nest(flat(3, 4), flat(5)), nest(flat(6, 7), flat(8))))
        .addEqualityGroup(nest(nest(flat(3, 4), flat(5)), nest(flat(6, 7), flat(8))))
        .addEqualityGroup(nest(myRef), nest(myRef), nest(myRef, myRef)) // Set de-duplication.
        .addEqualityGroup(nest(3, myRef))
        .addEqualityGroup(nest(4, myRef))
        .addEqualityGroup(
            new SetWrapper<>(referenceNestedSet), new SetWrapper<>(otherReferenceNestedSet))
        .testEquals();

    // Some things that are not tested by the above:
    //  - ordering among direct members
    //  - ordering among transitive sets
  }

  @Test
  public void shallowInequality() {
    assertThat(nestedSetBuilder("a").build().shallowEquals(null)).isFalse();
    Object[] contents = {"a", "b"};
    assertThat(
            NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, immediateFuture(contents))
                .shallowEquals(null))
        .isFalse();

    // shallowEquals() should require reference equality for underlying futures
    assertThat(
            NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, immediateFuture(contents))
                .shallowEquals(
                    NestedSet.withFuture(
                        Order.STABLE_ORDER, UNKNOWN_DEPTH, immediateFuture(contents))))
        .isFalse();
  }

  /** Checks that the builder always return a nested set with the correct order. */
  @Test
  public void correctOrder() {
    for (Order order : Order.values()) {
      for (int numDirects = 0; numDirects < 3; numDirects++) {
        for (int numTransitives = 0; numTransitives < 3; numTransitives++) {
          assertThat(createNestedSet(order, numDirects, numTransitives, order).getOrder())
              .isEqualTo(order);
          // We allow mixing orders if one of them is stable. This tests that the top level order is
          // the correct one.
          assertThat(
                  createNestedSet(order, numDirects, numTransitives, Order.STABLE_ORDER).getOrder())
              .isEqualTo(order);
        }
      }
    }
  }

  private static NestedSet<Integer> createNestedSet(
      Order order, int numDirects, int numTransitives, Order transitiveOrder) {
    NestedSetBuilder<Integer> builder = new NestedSetBuilder<>(order);

    for (int direct = 0; direct < numDirects; direct++) {
      builder.add(direct);
    }
    for (int transitive = 0; transitive < numTransitives; transitive++) {
      builder.addTransitive(new NestedSetBuilder<Integer>(transitiveOrder).add(transitive).build());
    }
    return builder.build();
  }

  @Test
  public void memoizedFlattenAndGetSize() {
    NestedSet<String> empty = NestedSetBuilder.<String>stableOrder().build();
    checkSize(empty, 0); // {}

    NestedSet<String> singleton = NestedSetBuilder.<String>stableOrder().add("a").build();
    checkSize(singleton, 1); // {a}

    NestedSet<String> deuce = NestedSetBuilder.<String>stableOrder().add("a").add("b").build();
    checkSize(deuce, 2); // {a, b}

    checkSize(
        NestedSetBuilder.<String>stableOrder()
            .add("a")
            .addTransitive(deuce)
            .addTransitive(singleton)
            .addTransitive(empty)
            .build(),
        2); // {a, b}
    checkSize(
        NestedSetBuilder.<String>stableOrder()
            .add("c")
            .addTransitive(deuce)
            .addTransitive(singleton)
            .addTransitive(empty)
            .build(),
        3); // {a, b, c}

    // 25000 has a 3-digit base128 encoding.
    NestedSetBuilder<Integer> largeShallow = NestedSetBuilder.stableOrder();
    for (int i = 0; i < 25000; ++i) {
      largeShallow.add(i);
    }
    checkSize(largeShallow.build(), 25000); // {0, 1, ..., 24999}

    // a deep and narrow graph
    NestedSet<String> deep = deuce;
    for (int i = 0; i < 200; ++i) {
      deep = NestedSetBuilder.<String>stableOrder().addTransitive(deep).add("c").build();
    }
    checkSize(deep, 3); // {a, b, c}
  }

  private static void checkSize(NestedSet<?> set, int size) {
    assertThat(set.memoizedFlattenAndGetSize()).isEqualTo(size); // first call: flattens
    assertThat(set.memoizedFlattenAndGetSize()).isEqualTo(size); // second call: memoized
  }

  @Test
  public void concurrentMemoizedFlattenAndGetSize() throws Exception {
    NestedSet<String> deep = NestedSetBuilder.<String>stableOrder().add("a").add("b").build();
    for (int i = 0; i < 200; ++i) {
      deep = NestedSetBuilder.<String>stableOrder().addTransitive(deep).add("c").build();
    }
    NestedSet<String> underTest = deep;
    List<TestThread> threads = new ArrayList<>(20);
    for (int i = 0; i < 20; i++) {
      threads.add(new TestThread(underTest::memoizedFlattenAndGetSize));
    }
    for (TestThread thread : threads) {
      thread.start();
    }
    for (TestThread thread : threads) {
      thread.joinAndAssertState(TestUtils.WAIT_TIMEOUT_MILLISECONDS);
    }
  }

  @Test
  public void hoistingKeepsSetSmall() {
    NestedSet<String> first = NestedSetBuilder.<String>stableOrder().add("a").build();
    NestedSet<String> second = NestedSetBuilder.<String>stableOrder().add("a").build();
    NestedSet<String> singleton =
        NestedSetBuilder.<String>stableOrder().addTransitive(first).addTransitive(second).build();
    assertThat(singleton.toList()).containsExactly("a");
    assertThat(singleton.isSingleton()).isTrue();
  }

  @Test
  public void buildInterruptibly_propagatesInterrupt() {
    NestedSet<String> deserializingNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, SettableFuture.create());
    NestedSetBuilder<String> builder =
        NestedSetBuilder.<String>stableOrder().addTransitive(deserializingNestedSet).add("a");
    Thread.currentThread().interrupt();
    assertThrows(InterruptedException.class, builder::buildInterruptibly);
  }

  @Test
  public void getChildrenInterruptibly_propagatesInterrupt() {
    NestedSet<String> deserializingNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, SettableFuture.create());
    Thread.currentThread().interrupt();
    assertThrows(InterruptedException.class, deserializingNestedSet::getChildrenInterruptibly);
  }

  @Test
  public void toListInterruptibly_propagatesInterrupt() {
    NestedSet<String> deserializingNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, SettableFuture.create());
    Thread.currentThread().interrupt();
    assertThrows(InterruptedException.class, deserializingNestedSet::toListInterruptibly);
  }

  @Test
  public void toListInterruptibly_propagatesMissingNestedSetException() {
    NestedSet<String> deserializingNestedSet =
        NestedSet.withFuture(
            Order.STABLE_ORDER,
            UNKNOWN_DEPTH,
            immediateFailedFuture(
                new MissingNestedSetException(ByteString.copyFromUtf8("fingerprint"))));
    assertThrows(MissingNestedSetException.class, deserializingNestedSet::toListInterruptibly);
  }

  @Test
  public void toListWithTimeout_propagatesInterrupt() {
    NestedSet<String> deserializingNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, SettableFuture.create());
    Thread.currentThread().interrupt();
    assertThrows(
        InterruptedException.class,
        () -> deserializingNestedSet.toListWithTimeout(Duration.ofDays(1)));
  }

  @Test
  public void toListWithTimeout_propagatesMissingNestedSetException() {
    NestedSet<String> deserializingNestedSet =
        NestedSet.withFuture(
            Order.STABLE_ORDER,
            UNKNOWN_DEPTH,
            immediateFailedFuture(
                new MissingNestedSetException(ByteString.copyFromUtf8("fingerprint"))));
    assertThrows(
        MissingNestedSetException.class,
        () -> deserializingNestedSet.toListWithTimeout(Duration.ofNanos(1)));
  }

  @Test
  public void toListWithTimeout_timesOut() {
    NestedSet<String> deserializingNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, SettableFuture.create());
    assertThrows(
        TimeoutException.class,
        () -> deserializingNestedSet.toListWithTimeout(Duration.ofNanos(1)));
  }

  @Test
  public void toListWithTimeout_waits() throws Exception {
    SettableFuture<Object[]> future = SettableFuture.create();
    NestedSet<String> deserializingNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, future);
    Future<ImmutableList<String>> result =
        Executors.newSingleThreadExecutor()
            .submit(() -> deserializingNestedSet.toListWithTimeout(Duration.ofMinutes(1)));
    Thread.sleep(100);
    assertThat(result.isDone()).isFalse();
    future.set(new Object[] {"a", "b"});
    assertThat(result.get()).containsExactly("a", "b");
  }

  @Test
  public void isFromStorage_true() {
    NestedSet<?> deserializingNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, SettableFuture.create());
    assertThat(deserializingNestedSet.isFromStorage()).isTrue();
  }

  @Test
  public void isFromStorage_false() {
    NestedSet<?> inMemoryNestedSet = NestedSetBuilder.create(Order.STABLE_ORDER, "a", "b");
    assertThat(inMemoryNestedSet.isFromStorage()).isFalse();
  }

  @Test
  public void isReady_inMemory() {
    NestedSet<?> inMemoryNestedSet = NestedSetBuilder.create(Order.STABLE_ORDER, "a", "b");
    assertThat(inMemoryNestedSet.isReady()).isTrue();
  }

  @Test
  public void isReady_fromStorage() {
    SettableFuture<Object[]> future = SettableFuture.create();
    NestedSet<?> deserializingNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, future);
    assertThat(deserializingNestedSet.isReady()).isFalse();
    future.set(new Object[] {"a", "b"});
    assertThat(deserializingNestedSet.isReady()).isTrue();
  }

  @Test
  public void isReady_fromStorage_cancelled() {
    NestedSet<?> deserializingNestedSet =
        NestedSet.withFuture(Order.STABLE_ORDER, UNKNOWN_DEPTH, immediateCancelledFuture());
    assertThat(deserializingNestedSet.isReady()).isFalse();
  }

  @Test
  public void isReady_fromStorage_failed() {
    NestedSet<?> deserializingNestedSet =
        NestedSet.withFuture(
            Order.STABLE_ORDER,
            UNKNOWN_DEPTH,
            immediateFailedFuture(
                new MissingNestedSetException(ByteString.copyFromUtf8("fingerprint"))));
    assertThat(deserializingNestedSet.isReady()).isFalse();
  }

  @Test
  public void getApproxDepth() {
    NestedSet<String> empty = nestedSetBuilder().build();
    NestedSet<String> justA = nestedSetBuilder("a").build();
    NestedSet<String> justB = nestedSetBuilder("b").build();
    NestedSet<String> ab = nestedSetBuilder().addTransitive(justA).addTransitive(justB).build();

    assertThat(empty.getApproxDepth()).isEqualTo(0);
    assertThat(
            nestedSetBuilder().addTransitive(empty).addTransitive(empty).build().getApproxDepth())
        .isEqualTo(0);
    assertThat(justA.getApproxDepth()).isEqualTo(1);
    assertThat(justB.getApproxDepth()).isEqualTo(1);
    assertThat(
            nestedSetBuilder().addTransitive(empty).addTransitive(empty).build().getApproxDepth())
        .isEqualTo(0);
    assertThat(
            nestedSetBuilder().addTransitive(empty).addTransitive(justA).build().getApproxDepth())
        .isEqualTo(1);
    assertThat(
            nestedSetBuilder().addTransitive(justA).addTransitive(empty).build().getApproxDepth())
        .isEqualTo(1);
    assertThat(
            nestedSetBuilder().addTransitive(justA).addTransitive(justA).build().getApproxDepth())
        .isEqualTo(1);
    assertThat(
            nestedSetBuilder().addTransitive(justA).addTransitive(justB).build().getApproxDepth())
        .isEqualTo(2);
    assertThat(
            nestedSetBuilder("a", "b", "c")
                .addTransitive(justA)
                .addTransitive(justB)
                .addTransitive(ab)
                .build()
                .getApproxDepth())
        .isEqualTo(3);
  }
}
