| # Copyright 2026 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. |
| |
| import os |
| import unittest |
| from scripts.docs import clr_converter |
| |
| |
| def _read_data_file(basename): |
| path = os.path.join( |
| os.getenv("TEST_SRCDIR"), |
| os.getenv("TEST_WORKSPACE"), |
| "scripts/docs/testdata", |
| basename, |
| ) |
| with open(path, "rt", encoding="utf-8") as f: |
| return f.read() |
| |
| |
| class ConvertTest(unittest.TestCase): |
| |
| def test_full_conversion(self): |
| html_content = _read_data_file("clr_input.html") |
| expected = _read_data_file("clr_expected.mdx") |
| actual = clr_converter.convert(html_content) |
| self.assertEqual(actual, expected) |
| |
| def test_boolean_option(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h2>Options</h2> |
| <dl>Category: |
| <dt id="opts-flag--batch"><code><a href="#opts-flag--batch">--[no]batch</a></code> default: "false"</dt> |
| <dd><p>Run in batch mode.</p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertIn('path="--[no]batch"', result) |
| self.assertIn('type="boolean"', result) |
| self.assertIn('default="false"', result) |
| |
| def test_typed_option(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h2>Options</h2> |
| <dl>Category: |
| <dt id="opts-flag--jobs"><code><a href="#opts-flag--jobs">--jobs</a>=<an integer></code> default: "auto"</dt> |
| <dd><p>Number of jobs.</p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertIn('path="--jobs"', result) |
| self.assertIn('type="an integer"', result) |
| self.assertIn('default="auto"', result) |
| |
| def test_void_expansion_option(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h2>Options</h2> |
| <dl>Category: |
| <dt id="opts-flag--debug"><code><a href="#opts-flag--debug">--debug</a></code></dt> |
| <dd> |
| <p>Enable debug mode.</p> |
| <p>Expands to: |
| <br/> <code><a href="#flag--verbose">--verbose</a></code> |
| </p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertIn('type="void"', result) |
| self.assertIn("Expands to:", result) |
| self.assertIn("`--verbose`", result) |
| self.assertNotIn("default=", result) |
| |
| def test_allow_multiple_option(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h2>Options</h2> |
| <dl>Category: |
| <dt id="opts-flag--rc"><code><a href="#opts-flag--rc">--rc</a>=<path></code> multiple uses are accumulated</dt> |
| <dd><p>RC file location.</p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertIn("May be used multiple times", result) |
| self.assertNotIn("default=", result) |
| |
| def test_deprecated_option(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h2>Options</h2> |
| <dl>Category: |
| <dt id="opts-flag--old"><code><a href="#opts-flag--old">--[no]old</a></code> default: "false"</dt> |
| <dd><p>Old flag.</p> |
| <p>Tags: |
| <a href="#metadata_tag_DEPRECATED"><code>deprecated</code></a> |
| </p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertIn("deprecated", result) |
| |
| def test_abbreviation(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h2>Options</h2> |
| <dl>Category: |
| <dt id="opts-flag--jobs"><code><a href="#opts-flag--jobs">--jobs</a>=<an integer></code> [<code>-j</code>] default: "8"</dt> |
| <dd><p>Number of jobs.</p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertIn("Short form: `-j`", result) |
| |
| def test_inherits_from(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h2><a name="build">Build Options</a></h2> |
| <p>Inherits all options from <a href="#common">common</a> and <a href="#test">test</a>.</p> |
| <dl>Cat: |
| <dt id="build-flag--f"><code><a href="#build-flag--f">--[no]f</a></code> default: "true"</dt> |
| <dd><p>A flag.</p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertIn( |
| "Inherits all options from [common](#common) and [test](#test)", result |
| ) |
| self.assertIn("{#build}", result) |
| |
| def test_enum_type_escaping(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h2>Options</h2> |
| <dl>Category: |
| <dt id="opts-flag--level"><code><a href="#opts-flag--level">--level</a>={0,1,2}</code> default: "0"</dt> |
| <dd><p>Set level.</p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertIn("{0,1,2}", result) |
| |
| def test_quotes_in_type_description(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h2>Options</h2> |
| <dl>Category: |
| <dt id="opts-flag--jobs"><code><a href="#opts-flag--jobs">--jobs</a>=<an integer, or a keyword ("auto", "HOST_CPUS")></code> default: "auto"</dt> |
| <dd><p>Number of jobs.</p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertNotIn('("auto"', result) |
| self.assertIn(""auto"", result) |
| |
| def test_angle_brackets_in_type_description(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h2>Options</h2> |
| <dl>Category: |
| <dt id="opts-flag--mem"><code><a href="#opts-flag--mem">--mem</a>=<an integer or "HOST_RAM", followed by [-|*]<float>></code> default: "0"</dt> |
| <dd><p>Memory limit.</p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| for line in result.split("\n"): |
| if "<ParamField" in line: |
| self.assertNotIn("*]<float", line) |
| self.assertIn("<float>", line) |
| break |
| |
| def test_commands_table(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table> |
| <tr> |
| <td><a href="#build"><code>build</code></a></td> |
| <td>Build targets.</td> |
| </tr> |
| </table> |
| <h2>Options</h2> |
| <dl>Cat: |
| <dt id="f"><code><a href="#f">--[no]f</a></code> default: "true"</dt> |
| <dd><p>Flag.</p></dd> |
| </dl> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertIn("## Commands", result) |
| self.assertIn("[`build`](#build)", result) |
| self.assertIn("Build targets.", result) |
| |
| def test_tag_tables(self): |
| html_input = """ |
| <h2>Commands</h2> |
| <table></table> |
| <h3>Option Effect Tags</h3> |
| <table> |
| <tr> |
| <td id="effect_tag_FOO"><code>foo</code></td> |
| <td>Foo description.</td> |
| </tr> |
| </table> |
| """ |
| result = clr_converter.convert(html_input) |
| self.assertIn("### Option Effect Tags", result) |
| self.assertIn('<span id="effect_tag_FOO">`foo`</span>', result) |
| self.assertIn("Foo description.", result) |
| |
| |
| if __name__ == "__main__": |
| unittest.main() |