/*
 * Copyright 2013-present Facebook, Inc.
 *
 * 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.facebook.buck.cli;

import com.facebook.buck.test.selectors.TestSelectorList;
import com.facebook.buck.test.selectors.TestSelectorParseException;
import com.facebook.buck.util.HumanReadableException;
import com.facebook.buck.util.MoreSuppliers;
import com.facebook.infer.annotation.SuppressFieldNotInitialized;
import java.util.function.Supplier;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.OptionDef;
import org.kohsuke.args4j.spi.OptionHandler;
import org.kohsuke.args4j.spi.Parameters;
import org.kohsuke.args4j.spi.Setter;

public class TestSelectorOptions {

  @Option(
    name = "--test-selectors",
    aliases = {"--filter", "-f"},
    usage =
        "Select tests to run using <class>, #<method> or <class>#<method>.  "
            + "Selectors are interpreted as java.util.regex regular expressions.  "
            + "If selectors are given, test result caching is disabled.  "
            + "If the class (or method) part is omitted, all classes (or methods) will match.  "
            + "If both the class and method is omitted (the string '#') then all tests will match.  "
            + "Prefix a selector with '!' to exclude a class or method.  "
            + "If multiple selectors are given, the first matching selector is used "
            + "to include (or exclude) a test.  "
            + "By default, all tests are excluded unless a selector includes them.  "
            + "However, if all selectors are exclusive then the default is to include.  "
            + "Use the format ':/path/to/file' to load selectors, one per line, from a file.  "
            + "Examples: 'com.example.MyTest' to run all tests in MyTest; "
            + "'com.example.MyTest#testFoo' or 'MyTest#Foo' to just run the testFoo test; "
            + "'!MyTest#Foo' to run everything except the testFoo test; "
            + "'#Important !TestA !TestC #' to only run the important tests in TestA and TestC "
            + "and run everything else.)",
    handler = TestSelectorsOptionHandler.class
  )
  @SuppressFieldNotInitialized
  public Supplier<TestSelectorList> testSelectorListSupplier;

  @Option(
    name = "--explain-test-selectors",
    usage = "Buck will say how it interpreted your test selectors before running tests."
  )
  private boolean shouldExplain = false;

  public TestSelectorList getTestSelectorList() {
    return testSelectorListSupplier.get();
  }

  public boolean shouldExplain() {
    return shouldExplain;
  }

  public static class TestSelectorsOptionHandler extends OptionHandler<Supplier<TestSelectorList>> {

    private final TestSelectorList.Builder builder = TestSelectorList.builder();

    public TestSelectorsOptionHandler(
        CmdLineParser parser, OptionDef option, Setter<Supplier<TestSelectorList>> setter)
        throws CmdLineException {
      super(parser, option, setter);
      setter.addValue(MoreSuppliers.memoize(builder::build));
    }

    @Override
    public int parseArguments(Parameters parameters) throws CmdLineException {
      String rawTestSelector = parameters.getParameter(0);
      try {
        builder.addRawSelectors(rawTestSelector);
      } catch (TestSelectorParseException e) {
        String message = "Unable to parse test selectors: " + e.getMessage();
        throw new HumanReadableException(e, message);
      }
      return 1;
    }

    @Override
    public String getDefaultMetaVariable() {
      return "TEST-SELECTOR ";
    }
  }
}

@@ -1546,65 +1546,217 @@
  + %22
-If selectors are given, test result caching is disabl
+Not every language supports these selectors. Notably, C++ and python do %22%0A            + %22not respect these filters. Note also that if an external test runner is used, %22%0A            + %22this filter also ignor
 ed.
- 
  %22%0A 

Clarify when test-selectors works