1# Copyright 2023 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import io
16import re
17
18from absl.testing import absltest
19from google.protobuf import text_format
20from stardoc.proto import stardoc_output_pb2
21
22from sphinxdocs.private import proto_to_markdown
23
24_EVERYTHING_MODULE = """\
25module_docstring: "MODULE_DOC_STRING"
26file: "@repo//pkg:foo.bzl"
27
28rule_info: {
29  rule_name: "rule_1"
30  doc_string: "RULE_1_DOC_STRING"
31  attribute: {
32    name: "rule_1_attr_1",
33    doc_string: "RULE_1_ATTR_1_DOC_STRING"
34    type: STRING
35    default_value: "RULE_1_ATTR_1_DEFAULT_VALUE"
36  }
37}
38provider_info: {
39  provider_name: "ProviderAlpha"
40  doc_string: "PROVIDER_ALPHA_DOC_STRING"
41  field_info: {
42    name: "ProviderAlpha_field_a"
43    doc_string: "PROVIDER_ALPHA_FIELD_A_DOC_STRING"
44  }
45}
46func_info: {
47  function_name: "function_1"
48  doc_string: "FUNCTION_1_DOC_STRING"
49  parameter: {
50    name: "function_1_param_a"
51    doc_string: "FUNCTION_1_PARAM_A_DOC_STRING"
52    default_value: "FUNCTION_1_PARAM_A_DEFAULT_VALUE"
53  }
54  return: {
55    doc_string: "FUNCTION_1_RETURN_DOC_STRING"
56  }
57  deprecated: {
58    doc_string: "FUNCTION_1_DEPRECATED_DOC_STRING"
59  }
60}
61aspect_info: {
62  aspect_name: "aspect_1"
63  doc_string: "ASPECT_1_DOC_STRING"
64  aspect_attribute: "aspect_1_aspect_attribute_a"
65  attribute: {
66    name: "aspect_1_attribute_a",
67    doc_string: "ASPECT_1_ATTRIBUTE_A_DOC_STRING"
68    type: INT
69    default_value: "694638"
70  }
71}
72module_extension_info: {
73  extension_name: "bzlmod_ext"
74  doc_string: "BZLMOD_EXT_DOC_STRING"
75  tag_class: {
76    tag_name: "bzlmod_ext_tag_a"
77    doc_string: "BZLMOD_EXT_TAG_A_DOC_STRING"
78    attribute: {
79      name: "bzlmod_ext_tag_a_attribute_1",
80      doc_string: "BZLMOD_EXT_TAG_A_ATTRIBUTE_1_DOC_STRING"
81      type: STRING_LIST
82      default_value: "[BZLMOD_EXT_TAG_A_ATTRIBUTE_1_DEFAULT_VALUE]"
83    }
84  }
85}
86repository_rule_info: {
87  rule_name: "repository_rule",
88  doc_string: "REPOSITORY_RULE_DOC_STRING"
89  attribute: {
90    name: "repository_rule_attribute_a",
91    doc_string: "REPOSITORY_RULE_ATTRIBUTE_A_DOC_STRING"
92    type: BOOLEAN
93    default_value: "True"
94  }
95  environ: "ENV_VAR_A"
96}
97"""
98
99
100class ProtoToMarkdownTest(absltest.TestCase):
101    def setUp(self):
102        super().setUp()
103        self.stream = io.StringIO()
104
105    def _render(self, module_text):
106        renderer = proto_to_markdown._MySTRenderer(
107            module=text_format.Parse(module_text, stardoc_output_pb2.ModuleInfo()),
108            out_stream=self.stream,
109            public_load_path="",
110        )
111        renderer.render()
112        return self.stream.getvalue()
113
114    def test_basic_rendering_everything(self):
115        actual = self._render(_EVERYTHING_MODULE)
116
117        self.assertIn("{bzl:currentfile} //pkg:foo.bzl", actual)
118        self.assertRegex(actual, "# //pkg:foo.bzl")
119        self.assertRegex(actual, "MODULE_DOC_STRING")
120
121        self.assertRegex(actual, "{bzl:rule} rule_1.*")
122        self.assertRegex(actual, "RULE_1_DOC_STRING")
123        self.assertRegex(actual, "rule_1_attr_1")
124        self.assertRegex(actual, "RULE_1_ATTR_1_DOC_STRING")
125        self.assertRegex(actual, "RULE_1_ATTR_1_DEFAULT_VALUE")
126
127        self.assertRegex(actual, "{bzl:provider} ProviderAlpha")
128        self.assertRegex(actual, "PROVIDER_ALPHA_DOC_STRING")
129        self.assertRegex(actual, "ProviderAlpha_field_a")
130        self.assertRegex(actual, "PROVIDER_ALPHA_FIELD_A_DOC_STRING")
131
132        self.assertRegex(actual, "{bzl:function} function_1")
133        self.assertRegex(actual, "FUNCTION_1_DOC_STRING")
134        self.assertRegex(actual, "function_1_param_a")
135        self.assertRegex(actual, "FUNCTION_1_PARAM_A_DOC_STRING")
136        self.assertRegex(actual, "FUNCTION_1_PARAM_A_DEFAULT_VALUE")
137        self.assertRegex(actual, "FUNCTION_1_RETURN_DOC_STRING")
138        self.assertRegex(actual, "FUNCTION_1_DEPRECATED_DOC_STRING")
139
140        self.assertRegex(actual, "{bzl:aspect} aspect_1")
141        self.assertRegex(actual, "ASPECT_1_DOC_STRING")
142        self.assertRegex(actual, "aspect_1_aspect_attribute_a")
143        self.assertRegex(actual, "aspect_1_attribute_a")
144        self.assertRegex(actual, "ASPECT_1_ATTRIBUTE_A_DOC_STRING")
145        self.assertRegex(actual, "694638")
146
147        self.assertRegex(actual, "{bzl:module-extension} bzlmod_ext")
148        self.assertRegex(actual, "BZLMOD_EXT_DOC_STRING")
149        self.assertRegex(actual, "{bzl:tag-class} bzlmod_ext_tag_a")
150        self.assertRegex(actual, "BZLMOD_EXT_TAG_A_DOC_STRING")
151        self.assertRegex(actual, "bzlmod_ext_tag_a_attribute_1")
152        self.assertRegex(actual, "BZLMOD_EXT_TAG_A_ATTRIBUTE_1_DOC_STRING")
153        self.assertRegex(actual, "BZLMOD_EXT_TAG_A_ATTRIBUTE_1_DEFAULT_VALUE")
154
155        self.assertRegex(actual, "{bzl:repo-rule} repository_rule")
156        self.assertRegex(actual, "REPOSITORY_RULE_DOC_STRING")
157        self.assertRegex(actual, "repository_rule_attribute_a")
158        self.assertRegex(actual, "REPOSITORY_RULE_ATTRIBUTE_A_DOC_STRING")
159        self.assertRegex(actual, "repository_rule_attribute_a.*=.*True")
160        self.assertRegex(actual, "ENV_VAR_A")
161
162    def test_render_signature(self):
163        actual = self._render(
164            """\
165file: "@repo//pkg:foo.bzl"
166func_info: {
167  function_name: "func"
168  parameter: {
169    name: "param_with_default"
170    default_value: "DEFAULT"
171  }
172  parameter: {
173    name: "param_without_default"
174  }
175  parameter: {
176    name: "param_with_function_default",
177    default_value: "<function foo from //bar:baz.bzl>"
178  }
179  parameter: {
180    name: "param_with_label_default",
181    default_value: 'Label(*, "@repo//pkg:file.bzl")'
182  }
183  parameter: {
184    name: "last_param"
185  }
186}
187        """
188        )
189        self.assertIn("param_with_default=DEFAULT,", actual)
190        self.assertIn("{default-value}`DEFAULT`", actual)
191        self.assertIn(":arg param_with_default:", actual)
192        self.assertIn("param_without_default,", actual)
193        self.assertIn('{default-value}`"@repo//pkg:file.bzl"`', actual)
194        self.assertIn("{default-value}`'<function foo from //bar:baz.bzl>'", actual)
195
196
197if __name__ == "__main__":
198    absltest.main()
199