// 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.query2.engine;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.Argument;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.ArgumentType;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryFunction;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.QueryTaskFuture;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.Setting;
import com.google.devtools.build.lib.query2.engine.QueryEnvironment.TargetAccessor;
import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
import com.google.devtools.build.lib.server.FailureDetails.Query;
import com.google.devtools.build.lib.server.FailureDetails.Query.Code;
import com.google.devtools.build.lib.util.DetailedExitCode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * A tests(x) filter expression, which returns all the tests in set x, expanding test_suite rules
 * into their constituents.
 *
 * <p>Unfortunately this class reproduces a substantial amount of logic from {@code
 * TestSuiteConfiguredTarget}, albeit in a somewhat simplified form. This is basically inevitable
 * since the expansion of test_suites cannot be done during the loading phase, because it involves
 * inter-package references. We make no attempt to validate the input, or report errors or warnings
 * other than missing target.
 *
 * <pre>expr ::= TESTS '(' expr ')'</pre>
 */
public class TestsFunction implements QueryFunction {
  @VisibleForTesting
  public TestsFunction() {}

  @Override
  public String getName() {
    return "tests";
  }

  @Override
  public int getMandatoryArguments() {
    return 1;
  }

  @Override
  public List<ArgumentType> getArgumentTypes() {
    return ImmutableList.of(ArgumentType.EXPRESSION);
  }

  @Override
  public <T> QueryTaskFuture<Void> eval(
      QueryEnvironment<T> env,
      QueryExpressionContext<T> context,
      QueryExpression expression,
      List<Argument> args,
      Callback<T> callback) {
    Closure<T> closure = new Closure<>(expression, callback, env);

    // A callback that appropriately feeds top-level test and test_suite targets to 'closure'.
    Callback<T> visitAllTestSuitesCallback =
        partialResult -> {
          PartitionResult<T> partitionResult = closure.partition(partialResult);
          closure
              .getUniqueTestSuites(partitionResult.testSuiteTargets)
              .forEach(closure::visitUniqueTestsInUniqueSuite);
          callback.process(closure.getUniqueTests(partitionResult.testTargets));
        };

    // Get a future that represents full evaluation of the argument expression.
    QueryTaskFuture<Void> testSuiteVisitationStartedFuture =
        env.eval(args.get(0).getExpression(), context, visitAllTestSuitesCallback);

    return env.transformAsync(
        // When this future is done, all top-level test_suite targets have already been fed to the
        // 'closure', meaning that ...
        testSuiteVisitationStartedFuture,
        // ... 'closure.getTopLevelRecursiveVisitationFutures()' represents the full visitation of
        // all these test_suite targets.
        dummyVal -> env.whenAllSucceed(closure.getTopLevelRecursiveVisitationFutures()));
  }

  private static class PartitionResult<T> {
    final ImmutableList<T> testTargets;
    final ImmutableList<T> testSuiteTargets;
    final ImmutableList<T> otherTargets;

    private PartitionResult(
        ImmutableList<T> testTargets,
        ImmutableList<T> testSuiteTargets,
        ImmutableList<T> otherTargets) {
      this.testTargets = testTargets;
      this.testSuiteTargets = testSuiteTargets;
      this.otherTargets = otherTargets;
    }
  }

  /** A closure over the state needed to do asynchronous test_suite visitation and expansion. */
  @ThreadSafe
  private static final class Closure<T> {
    private final QueryExpression expression;
    private final Callback<T> callback;
    /** The environment in which this query is being evaluated. */
    private final QueryEnvironment<T> env;

    private final TargetAccessor<T> accessor;
    private final boolean strict;
    private final Uniquifier<T> testUniquifier;
    private final Uniquifier<T> testSuiteUniquifier;
    private final List<QueryTaskFuture<Void>> topLevelRecursiveVisitationFutures =
        Collections.synchronizedList(new ArrayList<>());

    private Closure(QueryExpression expression, Callback<T> callback, QueryEnvironment<T> env) {
      this.expression = expression;
      this.callback = callback;
      this.env = env;
      this.accessor = env.getAccessor();
      this.strict = env.isSettingEnabled(Setting.TESTS_EXPRESSION_STRICT);
      this.testUniquifier = env.createUniquifier();
      this.testSuiteUniquifier = env.createUniquifier();
    }

    private Iterable<T> getUniqueTests(Iterable<T> tests) throws QueryException {
      return testUniquifier.unique(tests);
    }

    private Iterable<T> getUniqueTestSuites(Iterable<T> testSuites) throws QueryException {
      return testSuiteUniquifier.unique(testSuites);
    }

    private void visitUniqueTestsInUniqueSuite(T testSuite) {
      topLevelRecursiveVisitationFutures.add(
          env.executeAsync(() -> recursivelyVisitUniqueTestsInUniqueSuite(testSuite)));
    }

    /**
     * Returns all the futures representing the work items entailed by all the previous calls to
     * {@link #visitUniqueTestsInUniqueSuite}.
     */
    private ImmutableList<QueryTaskFuture<Void>> getTopLevelRecursiveVisitationFutures() {
      return ImmutableList.copyOf(topLevelRecursiveVisitationFutures);
    }

    private QueryTaskFuture<Void> recursivelyVisitUniqueTestsInUniqueSuite(T testSuite) {
      List<String> tagsAttribute = accessor.getStringListAttr(testSuite, "tags");
      // Split the tags list into positive and negative tags
      Set<String> requiredTags = new HashSet<>();
      Set<String> excludedTags = new HashSet<>();
      sortTagsBySense(tagsAttribute, requiredTags, excludedTags);

      List<T> testsToProcess = new ArrayList<>();
      List<T> testSuites;

      try {
        PartitionResult<T> partitionResult = partition(getPrerequisites(testSuite, "tests"));

        for (T testTarget : partitionResult.testTargets) {
          if (includeTest(requiredTags, excludedTags, testTarget)
              && testUniquifier.unique(testTarget)) {
            testsToProcess.add(testTarget);
          }
        }

        testSuites = testSuiteUniquifier.unique(partitionResult.testSuiteTargets);

        // If strict mode is enabled, then give an error for any non-test, non-test-suite target.
        if (strict) {
          for (T otherTarget : partitionResult.otherTargets) {
            String message =
                String.format(
                    "The label '%s' in the test_suite '%s' does not refer to a test or test_suite"
                        + " rule!",
                    accessor.getLabel(otherTarget), accessor.getLabel(testSuite));
            env.handleError(
                expression,
                message,
                DetailedExitCode.of(
                    FailureDetail.newBuilder()
                        .setMessage(message)
                        .setQuery(Query.newBuilder().setCode(Code.INVALID_LABEL_IN_TEST_SUITE))
                        .build()));
          }
        }

        // Add implicit dependencies on tests in same package, if any.
        for (T target : getPrerequisites(testSuite, "$implicit_tests")) {
          // The Package construction of $implicit_tests ensures that this check never fails, but we
          // add it here anyway for compatibility with future code.
          if (accessor.isTestRule(target)
              && includeTest(requiredTags, excludedTags, target)
              && testUniquifier.unique(target)) {
            testsToProcess.add(target);
          }
        }
      } catch (InterruptedException e) {
        return env.immediateCancelledFuture();
      } catch (QueryException e) {
        return env.immediateFailedFuture(e);
      }

      // Process all tests, asynchronously.
      QueryTaskFuture<Void> allTestsProcessedFuture =
          env.execute(
              () -> {
                callback.process(testsToProcess);
                return null;
              });

      // Visit all suites recursively, asynchronously.
      QueryTaskFuture<Void> allTestSuitsVisitedFuture =
          env.whenAllSucceed(
              Iterables.transform(testSuites, this::recursivelyVisitUniqueTestsInUniqueSuite));

      return env.whenAllSucceed(
          ImmutableList.of(allTestsProcessedFuture, allTestSuitsVisitedFuture));
    }

    private PartitionResult<T> partition(Iterable<T> targets) {
      ImmutableList.Builder<T> testTargetsBuilder = ImmutableList.builder();
      ImmutableList.Builder<T> testSuiteTargetsBuilder = ImmutableList.builder();
      ImmutableList.Builder<T> otherTargetsBuilder = ImmutableList.builder();

      for (T target : targets) {
        if (accessor.isTestRule(target)) {
          testTargetsBuilder.add(target);
        } else if (accessor.isTestSuite(target)) {
          testSuiteTargetsBuilder.add(target);
        } else {
          otherTargetsBuilder.add(target);
        }
      }

      return new PartitionResult<>(
          testTargetsBuilder.build(), testSuiteTargetsBuilder.build(), otherTargetsBuilder.build());
    }

    /**
     * Returns the set of rules named by the attribute 'attrName' of test_suite rule 'testSuite'.
     * The attribute must be a list of labels. If a target cannot be resolved, then an error is
     * reported to the environment (which may throw an exception if {@code keep_going} is disabled).
     *
     * @precondition env.getAccessor().isTestSuite(testSuite)
     */
    private Iterable<T> getPrerequisites(T testSuite, String attrName)
        throws QueryException, InterruptedException {
      return accessor.getPrerequisites(
          expression,
          testSuite,
          attrName,
          "couldn't expand '"
              + attrName
              + "' attribute of test_suite "
              + accessor.getLabel(testSuite)
              + ": ");
    }

    /**
     * Filters 'tests' (by mutation) according to the 'tags' attribute, specifically those that
     * match ALL of the tags in tagsAttribute.
     *
     * @precondition {@code env.getAccessor().isTestSuite(testSuite)}
     * @precondition {@code env.getAccessor().isTestRule(test)}
     */
    private boolean includeTest(Set<String> requiredTags, Set<String> excludedTags, T test) {
      List<String> testTags = new ArrayList<>(accessor.getStringListAttr(test, "tags"));
      testTags.add(accessor.getStringAttr(test, "size"));
      return TestsFunction.includeTest(testTags, requiredTags, excludedTags);
    }
  }

  // TODO(ulfjack): This must match the code in TestTargetUtils. However, we don't currently want
  // to depend on the packages library. Extract to a neutral place?
  /**
   * Decides whether to include a test in a test_suite or not.
   *
   * @param testTags Collection of all tags exhibited by a given test.
   * @param positiveTags Tags declared by the suite. A test must match ALL of these.
   * @param negativeTags Tags declared by the suite. A test must match NONE of these.
   * @return false is the test is to be removed.
   */
  private static boolean includeTest(
      Collection<String> testTags,
      Collection<String> positiveTags,
      Collection<String> negativeTags) {
    // Add this test if it matches ALL of the positive tags and NONE of the
    // negative tags in the tags attribute.
    for (String tag : negativeTags) {
      if (testTags.contains(tag)) {
        return false;
      }
    }
    for (String tag : positiveTags) {
      if (!testTags.contains(tag)) {
        return false;
      }
    }
    return true;
  }

  /**
   * Separates a list of text "tags" into a Pair of Collections, where
   * the first element are the required or positive tags and the second element
   * are the excluded or negative tags.
   * This should work on tag list provided from the command line
   * --test_tags_filters flag or on tag filters explicitly declared in the
   * suite.
   *
   * Keep this function in sync with the version in
   *  java.com.google.devtools.build.lib.view.packages.TestTargetUtils.sortTagsBySense
   *
   * @param tagList A collection of text tags to separate.
   */
  private static void sortTagsBySense(
      Collection<String> tagList, Set<String> requiredTags, Set<String> excludedTags) {
    for (String tag : tagList) {
      if (tag.startsWith("-")) {
        excludedTags.add(tag.substring(1));
      } else if (tag.startsWith("+")) {
        requiredTags.add(tag.substring(1));
      } else if (tag.equals("manual")) {
        // Ignore manual attribute because it is an exception: it is not a filter
        // but a property of test_suite
        continue;
      } else {
        requiredTags.add(tag);
      }
    }
  }
}
