xref: /aosp_15_r20/external/pigweed/pw_build/py/gn_writer_test.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1# Copyright 2023 The Pigweed Authors
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may not
4# use this file except in compliance with the License. You may obtain a copy of
5# the License at
6#
7#     https://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, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations under
13# the License.
14"""Tests for the pw_build.gn_writer module."""
15
16import os
17import unittest
18
19from io import StringIO
20from pathlib import PurePath
21from tempfile import TemporaryDirectory
22
23from pw_build.gn_writer import (
24    COPYRIGHT_HEADER,
25    GnFile,
26    GnWriter,
27)
28from pw_build.gn_target import GnTarget
29
30
31class TestGnWriter(unittest.TestCase):
32    """Tests for gn_writer.GnWriter."""
33
34    def setUp(self):
35        """Creates a GnWriter that writes to a StringIO."""
36        self.output = StringIO()
37        self.writer = GnWriter(self.output)
38
39    def test_write_comment(self):
40        """Writes a GN comment."""
41        self.writer.write_comment('hello, world!')
42        self.assertEqual(
43            self.output.getvalue(),
44            '# hello, world!\n',
45        )
46
47    def test_write_comment_wrap(self):
48        """Writes a GN comment that is exactly 80 characters."""
49        extra_long = (
50            "This line is a " + ("really, " * 5) + "REALLY extra long comment"
51        )
52        self.writer.write_comment(extra_long)
53        self.assertEqual(
54            self.output.getvalue(),
55            '# This line is a really, really, really, really, really, REALLY '
56            'extra long\n# comment\n',
57        )
58
59    def test_write_comment_nowrap(self):
60        """Writes a long GN comment without whitespace to wrap on."""
61        no_breaks = 'A' + ('a' * 76) + 'h!'
62        self.writer.write_comment(no_breaks)
63        self.assertEqual(
64            self.output.getvalue(),
65            '# Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
66            'aaaaaaaaaaaaah!\n',
67        )
68
69    def test_write_target(self):
70        """Tests writing the target using a GnWriter."""
71        target = GnTarget('custom_type', 'my-target')
72        target.attrs = {
73            'public': ['$src/foo/my-header.h'],
74            'sources': ['$src/foo/my-source.cc'],
75            'inputs': ['$src/bar/my.data'],
76            'cflags': ['-frobinator'],
77            'public_deps': [
78                ':foo',
79                '$dir_pw_third_party/repo/bar',
80            ],
81            'deps': [
82                '$dir_pw_third_party/repo:top-level',
83                '../another-pkg/baz',
84            ],
85        }
86        target.origin = '//my-package:my-target'
87        self.writer.write_target(target)
88
89        self.assertEqual(
90            self.output.getvalue(),
91            '''
92# Generated from //my-package:my-target
93custom_type("my-target") {
94  public = [
95    "$src/foo/my-header.h",
96  ]
97  sources = [
98    "$src/foo/my-source.cc",
99  ]
100  inputs = [
101    "$src/bar/my.data",
102  ]
103  cflags = [
104    "-frobinator",
105  ]
106  public_deps = [
107    "$dir_pw_third_party/repo/bar",
108    ":foo",
109  ]
110  deps = [
111    "$dir_pw_third_party/repo:top-level",
112    "../another-pkg/baz",
113  ]
114}
115'''.lstrip(),
116        )
117
118    def test_write_list(self):
119        """Writes a GN list assigned to a variable."""
120        self.writer.write_list('empty', [])
121        self.writer.write_list('items', ['foo', 'bar', 'baz'])
122        lines = [
123            'items = [',
124            '  "bar",',
125            '  "baz",',
126            '  "foo",',
127            ']',
128        ]
129        self.assertEqual('\n'.join(lines), self.output.getvalue().strip())
130
131    def test_write_file(self):
132        """Writes a BUILD.gn file."""
133        imports = {
134            '$dir_pw_third_party/foo/foo.gni',
135            '$dir_pw_third_party/bar/bar.gni',
136        }
137        gn_targets = [
138            GnTarget('foo_source_set', 'foo'),
139            GnTarget('bar_source_set', 'bar'),
140        ]
141        gn_targets[0].attrs = {
142            'public': ['$dir_pw_third_party_foo/foo.h'],
143            'sources': ['$dir_pw_third_party_foo/foo.cc'],
144            'deps': [':bar'],
145        }
146        gn_targets[1].attrs = {
147            'public': ['$dir_pw_third_party_bar/bar.h'],
148        }
149        self.writer.write_file(imports, gn_targets)
150        lines = [
151            'import("//build_overrides/pigweed.gni")',
152            '',
153            'import("$dir_pw_third_party/bar/bar.gni")',
154            'import("$dir_pw_third_party/foo/foo.gni")',
155            '',
156            'bar_source_set("bar") {',
157            '  public = [',
158            '    "$dir_pw_third_party_bar/bar.h",',
159            '  ]',
160            '}',
161            '',
162            'foo_source_set("foo") {',
163            '  public = [',
164            '    "$dir_pw_third_party_foo/foo.h",',
165            '  ]',
166            '  sources = [',
167            '    "$dir_pw_third_party_foo/foo.cc",',
168            '  ]',
169            '  deps = [',
170            '    ":bar",',
171            '  ]',
172            '}',
173        ]
174        self.assertEqual('\n'.join(lines), self.output.getvalue().strip())
175
176
177class TestGnFile(unittest.TestCase):
178    """Tests for gn_writer.GnFile."""
179
180    def test_format_on_close(self):
181        """Verifies the GN file is formatted when the file is closed."""
182        with TemporaryDirectory() as tmpdirname:
183            with GnFile(PurePath(tmpdirname, 'BUILD.gn')) as build_gn:
184                build_gn.write('  correct = "indent"')
185                build_gn.write_comment('comment')
186                build_gn.write_list('single_item', ['is.inlined'])
187
188            filename = PurePath('pw_build', 'gn_writer.py')
189            expected = (
190                COPYRIGHT_HEADER
191                + f'''
192# This file was automatically generated by {filename}
193
194correct = "indent"
195
196# comment
197single_item = [ "is.inlined" ]
198'''
199            )
200            with open(os.path.join(tmpdirname, 'BUILD.gn'), 'r') as build_gn:
201                self.assertEqual(expected.strip(), build_gn.read().strip())
202
203
204if __name__ == '__main__':
205    unittest.main()
206