README: make sure all hooks are documented

Add a unittest to require all hooks are documented, and backfill all
the missing ones.

BUG=b:266165002
TEST=`./pre-upload_unittest.py` passes

Change-Id: I43902847dea335a270ac641db340d5d7861bd949
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/repohooks/+/4186049
Reviewed-by: Guenter Roeck <groeck@chromium.org>
Tested-by: Mike Frysinger <vapier@chromium.org>
Auto-Submit: Mike Frysinger <vapier@chromium.org>
Commit-Queue: Guenter Roeck <groeck@chromium.org>
diff --git a/README.md b/README.md
index f554463..20824a1 100644
--- a/README.md
+++ b/README.md
@@ -98,22 +98,36 @@
 may be controlled by the config file here, but we run many more checks.
 
 *   `aosp_license_check`: Require source files have an Android (Apache) license.
+*   `black_check`: Require Python files be formated by Black.
+*   `blank_line_check`: Check for trailing blank lines.
 *   `branch_check`: Require all commit messages have a `BRANCH=` line.
 *   `bug_field_check`: Require all commit messages have a `BUG=` line.
+*   `cargo_clippy_check`: Run Rust code through `cargo clippy`.
+*   `check_change_no_include_board_phase`: Reject commit messages that refer to
+    hardware board development phases (e.g. PVT).
+*   `check_rustfmt`: Run Rust code through `rustfmt`.
 *   `checkpatch_check`: Run commits through Linux's `checkpatch.pl` tool.
 *   `clang_format_check`: Run source code through `clang-format`.
 *   `contribution_check`: Check source files for invalid "not a contribution".
 *   `cros_license_check`: Require source files have a Chromium (BSD) license.
+*   `exec_files_check`: Check common file types do not have +x permission bits.
 *   `filepath_chartype_check`: Check source files for FilePath::CharType use.
+*   `gofmt_check`: Run Go code through `gofmt`.
+*   `handle_eintr_close_check`: Check C++ code does not use unsafe
+    `HANDLE_EINTR(close(...))` idioms.
 *   `json_check`: Check all `.json` files are valid JSON.
+*   `kernel_splitconfig_check`: Require CrOS kernel config changes are separate
+    commits from kernel code changes.
 *   `kerneldoc_check`: Run commits through Linux's `kernel-doc` tool.
+*   `keyword_check`: Check text files & commit messages for
+    [blocked terms](#blocked_terms).
 *   `long_line_check`: Do not allow lines longer than 80 cols.
 *   `manifest_check`: Check all ebuild `Manifest` files.
 *   `project_prefix_check`: Require all commit message have a subdir prefix.
 *   `signoff_check`: Require all commit messages have a `Signed-off-by` tag.
 *   `stray_whitespace_check`: Check source files for stray whitespace.
-*   `tabbed_indent_required_check`: Require tabs for indentation.
 *   `tab_check`: Do not allow tabs for indentation in source files.
+*   `tabbed_indent_required_check`: Require tabs for indentation.
 *   `test_field_check`: Require all commit messages have a `TEST=` line.
 
 ## [Hook Overrides Options]
@@ -126,7 +140,7 @@
 cros_license_check: --exclude_regex=\b(checkpatch\.pl|kernel-doc)$
 ```
 
-## Blocked and Unblocked Word List
+## Blocked and Unblocked Word List {#blocked_terms}
 
 `blocked_terms.txt` contains a default list of words which are blocked by
 keyword_check. `unblocked_terms.txt` is a default list of words which are
diff --git a/pre-upload_unittest.py b/pre-upload_unittest.py
index 87822c9..7f35b92 100755
--- a/pre-upload_unittest.py
+++ b/pre-upload_unittest.py
@@ -3325,5 +3325,48 @@
         self.assertTrue(options["ignore_merged_commits"])
 
 
+class ReadmeTests(cros_test_lib.TestCase):
+    """Tests to check README.md content."""
+
+    def setUp(self):
+        self.readme = (DIR / "README.md").read_text(encoding="utf-8")
+
+    def testHookOverridesDocs(self):
+        """Make sure [Hook Overrides] is kept up-to-date."""
+        # Extract documented sections from the readme.
+        start = end = None
+        lines = self.readme.splitlines()
+        for i, line in enumerate(lines):
+            if start is None:
+                if line == "## [Hook Overrides]":
+                    start = i
+            elif line.startswith("## "):
+                end = i - 1
+                break
+
+        # See which hooks we support.
+        doc_sections = [
+            x.split("`")[1]
+            for x in lines[start : start + end]
+            if x.startswith("*")
+        ]
+        all_sections = sorted(pre_upload._HOOK_FLAGS.keys())
+        sorted_docs = sorted(doc_sections)
+
+        # Hook docs must be sorted.
+        self.assertEqual(
+            doc_sections,
+            sorted_docs,
+            msg="Keep README.md:[Hook Overrides] sorted",
+        )
+
+        # All hooks must be documented.
+        self.assertEqual(
+            sorted_docs,
+            all_sections,
+            msg="All configurable hooks must be documented in README.md:[Hook Overrides]",
+        )
+
+
 if __name__ == "__main__":
     cros_test_lib.main(module=__name__)