// 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.skyframe;

import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.Interner;
import com.google.devtools.build.lib.concurrent.BlazeInterners;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

/** Test for {@code ReverseDepsUtility}. */
@RunWith(Parameterized.class)
public class ReverseDepsUtilityTest {
  private final int numElements;

  @Parameters(name = "numElements-{0}")
  public static List<Object[]> parameters() {
    List<Object[]> params = new ArrayList<>();
    for (int i = 0; i < 20; i++) {
      params.add(new Object[] {i});
    }
    return params;
  }

  public ReverseDepsUtilityTest(int numElements) {
    this.numElements = numElements;
  }

  @Test
  public void testAddAndRemove() {
    for (int numRemovals = 0; numRemovals <= numElements; numRemovals++) {
      InMemoryNodeEntry example = new InMemoryNodeEntry();
      for (int j = 0; j < numElements; j++) {
        ReverseDepsUtility.addReverseDeps(example, Collections.singleton(Key.create(j)));
      }
      // Not a big test but at least check that it does not blow up.
      assertThat(ReverseDepsUtility.toString(example)).isNotEmpty();
      assertThat(ReverseDepsUtility.getReverseDeps(example)).hasSize(numElements);
      for (int i = 0; i < numRemovals; i++) {
        ReverseDepsUtility.removeReverseDep(example, Key.create(i));
      }
      assertThat(ReverseDepsUtility.getReverseDeps(example)).hasSize(numElements - numRemovals);
      assertThat(example.getReverseDepsDataToConsolidateForReverseDepsUtil()).isNull();
    }
  }

  // Same as testAdditionAndRemoval but we add all the reverse deps in one call.
  @Test
  public void testAddAllAndRemove() {
    for (int numRemovals = 0; numRemovals <= numElements; numRemovals++) {
      InMemoryNodeEntry example = new InMemoryNodeEntry();
      List<SkyKey> toAdd = new ArrayList<>();
      for (int j = 0; j < numElements; j++) {
        toAdd.add(Key.create(j));
      }
      ReverseDepsUtility.addReverseDeps(example, toAdd);
      assertThat(ReverseDepsUtility.getReverseDeps(example)).hasSize(numElements);
      for (int i = 0; i < numRemovals; i++) {
        ReverseDepsUtility.removeReverseDep(example, Key.create(i));
      }
      assertThat(ReverseDepsUtility.getReverseDeps(example)).hasSize(numElements - numRemovals);
      assertThat(example.getReverseDepsDataToConsolidateForReverseDepsUtil()).isNull();
    }
  }

  @Test
  public void testDuplicateCheckOnGetReverseDeps() {
    InMemoryNodeEntry example = new InMemoryNodeEntry();
    for (int i = 0; i < numElements; i++) {
      ReverseDepsUtility.addReverseDeps(example, Collections.singleton(Key.create(i)));
    }
    // Should only fail when we call getReverseDeps().
    ReverseDepsUtility.addReverseDeps(example, Collections.singleton(Key.create(0)));
    if (numElements == 0) {
      // Will not throw.
      ReverseDepsUtility.getReverseDeps(example);
    } else {
      assertThrows(Exception.class, () -> ReverseDepsUtility.getReverseDeps(example));
    }
  }

  @Test
  public void doubleAddThenRemove() {
    InMemoryNodeEntry example = new InMemoryNodeEntry();
    SkyKey key = Key.create(0);
    ReverseDepsUtility.addReverseDeps(example, Collections.singleton(key));
    // Should only fail when we call getReverseDeps().
    ReverseDepsUtility.addReverseDeps(example, Collections.singleton(key));
    ReverseDepsUtility.removeReverseDep(example, key);
    assertThrows(IllegalStateException.class, () -> ReverseDepsUtility.getReverseDeps(example));
  }

  @Test
  public void doubleAddThenRemoveCheckedOnSize() {
    InMemoryNodeEntry example = new InMemoryNodeEntry();
    SkyKey fixedKey = Key.create(0);
    SkyKey key = Key.create(1);
    ReverseDepsUtility.addReverseDeps(example, ImmutableList.of(fixedKey, key));
    // Should only fail when we reach the limit.
    ReverseDepsUtility.addReverseDeps(example, Collections.singleton(key));
    ReverseDepsUtility.removeReverseDep(example, key);
    ReverseDepsUtility.checkReverseDep(example, fixedKey);
    assertThrows(
        IllegalStateException.class, () -> ReverseDepsUtility.checkReverseDep(example, fixedKey));
  }

  @Test
  public void addRemoveAdd() {
    InMemoryNodeEntry example = new InMemoryNodeEntry();
    SkyKey fixedKey = Key.create(0);
    SkyKey key = Key.create(1);
    ReverseDepsUtility.addReverseDeps(example, ImmutableList.of(fixedKey, key));
    ReverseDepsUtility.removeReverseDep(example, key);
    ReverseDepsUtility.addReverseDeps(example, Collections.singleton(key));
    assertThat(ReverseDepsUtility.getReverseDeps(example)).containsExactly(fixedKey, key);
  }

  @Test
  public void testMaybeCheck() {
    InMemoryNodeEntry example = new InMemoryNodeEntry();
    for (int i = 0; i < numElements; i++) {
      ReverseDepsUtility.addReverseDeps(example, Collections.singleton(Key.create(i)));
      // This should always succeed, since the next element is still not present.
      ReverseDepsUtility.maybeCheckReverseDepNotPresent(example, Key.create(i + 1));
    }
    if (numElements == 0 || numElements >= ReverseDepsUtility.MAYBE_CHECK_THRESHOLD) {
      // This will not throw, because the numElements is 0 or above the threshold.
      ReverseDepsUtility.maybeCheckReverseDepNotPresent(example, Key.create(0));
    } else {
      assertThrows(
          IllegalStateException.class,
          () -> ReverseDepsUtility.maybeCheckReverseDepNotPresent(example, Key.create(0)));
    }
  }

  private static class Key extends AbstractSkyKey<Integer> {
    private static final Interner<Key> interner = BlazeInterners.newWeakInterner();

    private Key(Integer arg) {
      super(arg);
    }

    private static Key create(Integer arg) {
      return interner.intern(new Key(arg));
    }

    @Override
    public SkyFunctionName functionName() {
      return SkyFunctionName.FOR_TESTING;
    }
  }
}
