Open source BazelDocumentationTest (and fix documentation).

--
MOS_MIGRATED_REVID=108145081
diff --git a/site/BUILD b/site/BUILD
new file mode 100644
index 0000000..58365fe
--- /dev/null
+++ b/site/BUILD
@@ -0,0 +1,3 @@
+exports_files(
+    ["docs/bazel-user-manual.html"],
+)
diff --git a/site/docs/bazel-user-manual.html b/site/docs/bazel-user-manual.html
index 9eb7d00..2510cee 100644
--- a/site/docs/bazel-user-manual.html
+++ b/site/docs/bazel-user-manual.html
@@ -669,7 +669,8 @@
   </li>
   <li>
     Use the value of <code class="flag">--host_cpu</code> for
-    <code class='flag'>--cpu</code> and <code class='flag'>--java_cpu</code>
+    <code class='flag'>--cpu</code>
+
     (default: <code>k8</code>).
   </li>
   <li>Use the same values of these options as specified in the request
@@ -1491,8 +1492,6 @@
 </p>
 <p>
 
-  This option does not apply to Java binaries or to any C/C++ code linked into them; there are
-  <code class='flag'>--java_cpu</code> flag is used to specify that.
 </p>
 
 <p>
@@ -1507,14 +1506,6 @@
   used to build host tools.
 </p>
 
-<h4 id='flag--java_cpu'><code class='flag'>--java_cpu <var>cpu</var></code></h4>
-<p>
-  This option specifies the name of the CPU architecture (piii, k8, etc) that
-  should be used to build libraries dynamically loaded by the JVM.
-  By default it is set to k8, ensuring that all such libraries will be 64-bit
-  x86 code.
-</p>
-
 <h4 id='flag--experimental_skip_static_outputs'><code class='flag'>--experimental_skip_static_outputs</code></h4>
 <p>
   The <code class='flag'>--experimental_skip_static_outputs</code> option causes all
@@ -1685,14 +1676,6 @@
   the CROSSTOOL file and the following options where appropriate:
   <ul>
     <li><a href="#flag--cpu"><code class='flag'>--cpu</code></a></li>
-    <li><a href="#flag--java_cpu"><code class='flag'>--java_cpu</code></a></li>
-
-  </ul>
-</p>
-<p>
-  Note that only certain combinations of crosstool version, compiler version,
-  glibc version, and target CPU are allowed.
-</p>
 
 <h4 id='flag--javabuilder_top'><code class='flag'>--javabuilder_top <var>label</var></code></h4>
 <p>
@@ -1993,20 +1976,6 @@
   breakages in the <code>foo</code> tree.
 </p>
 
-<h4 id="flag--compile_only"><code class='flag'>--[no]compile_only</code></h4>
-<p>
-  This option forces Bazel to execute only "lightweight" compilation steps
-  related to the specified targets. At this time such steps only include
-  compilation of sources for <code>cc_*</code> and <code>java_*</code> rules
-  without building dependencies or performing linking.
-</p>
-<p>
-  This option can be useful to quickly validate a given C++ or Java target for
-  compilation errors. In particular, it might be especially useful when
-  specified together with the <a href="#flag--compile_one_dependency">
-  <code class='flag'>--compile_one_dependency</code></a> option.
-</p>
-
 <h4 id="flag--compilation_prerequisites_only"><code class='flag'>--[no]compilation_prerequisites_only</code></h4>
 <p>
   Given this option, Bazel will only build files that are prerequisites for
@@ -2075,13 +2044,6 @@
   setting is high enough.
 </p>
 
-<h4 id='flag--source_jars'><code class='flag'>--[no]source_jars</code></h4>
-<p>
-  By default, this option is disabled. If enabled, Bazel will also build all
-  source jars in the transitive closure of the targets specified on the command
-  line.
-</p>
-
 <h4 id='flag--test_size_filters'><code class='flag'>--test_size_filters <var>size[,size]*</var></code></h4>
 <p>
   If specified, Bazel will test (or build if <code class='flag'>--build_tests_only</code>
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index 370614e..3f776a9 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -490,8 +490,10 @@
     deps = [
         ":foundations_testutil",
         ":testutil",
+        "//src/main/java/com/google/devtools/build/docgen",
         "//src/main/java/com/google/devtools/build/lib:analysis-exec-rules-skyframe",
         "//src/main/java/com/google/devtools/build/lib:bazel-core",
+        "//src/main/java/com/google/devtools/build/lib:buildtool-runtime",
         "//src/main/java/com/google/devtools/build/lib:clock",
         "//src/main/java/com/google/devtools/build/lib:events",
         "//src/main/java/com/google/devtools/build/lib:io",
@@ -512,9 +514,14 @@
 
 java_test(
     name = "packages_test",
-    srcs = glob([
-        "packages/*.java",
-    ]),
+    srcs = glob(
+        [
+            "packages/*.java",
+        ],
+        exclude = [
+            "packages/BazelDocumentationTest.java",
+        ],
+    ),
     args = ["com.google.devtools.build.lib.AllTests"],
     deps = [
         ":actions_testutil",
@@ -666,6 +673,26 @@
     ],
 )
 
+java_test(
+    name = "BazelDocumentationTests",
+    size = "medium",
+    srcs = ["packages/BazelDocumentationTest.java"],
+    data = [
+        "//site:docs/bazel-user-manual.html",
+    ],
+    deps = [
+        ":foundations_testutil",
+        ":packages_testutil",
+        "//src/main/java/com/google/devtools/build/lib:bazel-core",
+        "//src/main/java/com/google/devtools/build/lib:packages",
+        "//third_party:guava",
+        "//third_party:guava-testlib",
+        "//third_party:jsr305",
+        "//third_party:junit4",
+        "//third_party:truth",
+    ],
+)
+
 java_library(
     name = "syntax_testutil",
     srcs = glob([
diff --git a/src/test/java/com/google/devtools/build/lib/packages/BazelDocumentationTest.java b/src/test/java/com/google/devtools/build/lib/packages/BazelDocumentationTest.java
new file mode 100644
index 0000000..3717893
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/packages/BazelDocumentationTest.java
@@ -0,0 +1,49 @@
+// Copyright 2015 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.packages;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import com.google.common.io.Files;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+
+import com.google.devtools.build.lib.bazel.BazelMain;
+import com.google.devtools.build.lib.bazel.rules.BazelRuleClassProvider;
+import com.google.devtools.build.lib.packages.util.DocumentationTestUtil;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.File;
+
+/**
+ * Test for Bazel documentation.
+ */
+@RunWith(JUnit4.class)
+public class BazelDocumentationTest {
+  /**
+   * Checks that the blaze-user-manual is in sync with the
+   * {@link BuildConfiguration}.
+   */
+  @Test
+  public void testBazelUserManual() throws Exception {
+    final File documentationFile = new File("site/docs/bazel-user-manual.html");
+    DocumentationTestUtil.validateUserManual(
+        BazelMain.BAZEL_MODULES,
+        BazelRuleClassProvider.create(),
+        Files.asCharSource(documentationFile, UTF_8).read());
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/packages/util/DocumentationTestUtil.java b/src/test/java/com/google/devtools/build/lib/packages/util/DocumentationTestUtil.java
new file mode 100644
index 0000000..0836b5f
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/packages/util/DocumentationTestUtil.java
@@ -0,0 +1,105 @@
+// Copyright 2015 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.packages.util;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import com.google.common.collect.Iterables;
+import com.google.devtools.build.docgen.DocCheckerUtils;
+import com.google.devtools.build.lib.analysis.ConfiguredRuleClassProvider;
+import com.google.devtools.build.lib.runtime.BlazeCommand;
+import com.google.devtools.build.lib.runtime.BlazeCommandUtils;
+import com.google.devtools.build.lib.runtime.BlazeModule;
+import com.google.devtools.build.lib.runtime.BlazeRuntime;
+import com.google.devtools.common.options.Options;
+import com.google.devtools.common.options.OptionsBase;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Utility functions for validating correctness of Bazel documentation.
+ */
+public abstract class DocumentationTestUtil {
+
+  private DocumentationTestUtil() {}
+
+  private static final Pattern CODE_FLAG_PATTERN =
+      Pattern.compile(
+          "<code class\\s*=\\s*[\"']flag[\"']\\s*>--([a-z_\\[\\]]*)<\\/code>",
+          Pattern.CASE_INSENSITIVE);
+
+  /**
+   * Validates that a user manual {@code documentationSource} contains only
+   * the flags actually provided by a given set of modules.
+   */
+  public static void validateUserManual(
+      List<Class<? extends BlazeModule>> modules,
+      ConfiguredRuleClassProvider ruleClassProvider, String documentationSource)
+      throws IOException {
+    // if there is a class missing, one can find it using
+    //   find . -name "*.java" -exec grep -Hn "@Option(name = " {} \; | grep "xxx"
+    // where 'xxx' is a flag name.
+    List<BlazeModule> blazeModules = BlazeRuntime.createModules(modules);
+
+    Map<String, Object> optionsMap = new HashMap<>();
+
+    // collect all startup options
+    for (Class<? extends OptionsBase> optionsClass :
+        BlazeCommandUtils.getStartupOptions(blazeModules)) {
+      optionsMap.putAll(Options.getDefaults(optionsClass).asMap());
+    }
+
+    // collect all command options
+    List<BlazeCommand> blazeCommands = new ArrayList<>();
+    blazeCommands.addAll(BlazeRuntime.getBuiltinCommandList());
+    for (BlazeModule module : blazeModules) {
+      Iterables.addAll(blazeCommands, module.getCommands());
+    }
+
+    for (BlazeCommand command : blazeCommands) {
+      for (Class<? extends OptionsBase> optionClass :
+          BlazeCommandUtils.getOptions(command.getClass(), blazeModules, ruleClassProvider)) {
+        optionsMap.putAll(Options.getDefaults(optionClass).asMap());
+      }
+    }
+
+    // check validity of option flags in manual
+    Matcher anchorMatcher = CODE_FLAG_PATTERN.matcher(documentationSource);
+    String flag;
+    boolean found;
+
+    while (anchorMatcher.find()) {
+      flag = anchorMatcher.group(1);
+      found = optionsMap.containsKey(flag);
+      if (!found && flag.startsWith("no")) {
+        found = optionsMap.containsKey(flag.substring(2));
+      }
+      if (!found && flag.startsWith("[no]")) {
+        found = optionsMap.containsKey(flag.substring(4));
+      }
+
+      assertWithMessage("flag '" + flag + "' is not a blaze option (anymore)").that(found).isTrue();
+    }
+
+    String unclosedTag = DocCheckerUtils.getFirstUnclosedTagAndPrintHelp(documentationSource);
+    assertWithMessage("Unclosed tag found: " + unclosedTag).that(unclosedTag).isNull();
+  }
+}