xref: /aosp_15_r20/external/pigweed/pw_presubmit/py/gitmodules_test.py (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*61c4878aSAndroid Build Coastguard Worker# Copyright 2022 The Pigweed Authors
3*61c4878aSAndroid Build Coastguard Worker#
4*61c4878aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); you may not
5*61c4878aSAndroid Build Coastguard Worker# use this file except in compliance with the License. You may obtain a copy of
6*61c4878aSAndroid Build Coastguard Worker# the License at
7*61c4878aSAndroid Build Coastguard Worker#
8*61c4878aSAndroid Build Coastguard Worker#     https://www.apache.org/licenses/LICENSE-2.0
9*61c4878aSAndroid Build Coastguard Worker#
10*61c4878aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*61c4878aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12*61c4878aSAndroid Build Coastguard Worker# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13*61c4878aSAndroid Build Coastguard Worker# License for the specific language governing permissions and limitations under
14*61c4878aSAndroid Build Coastguard Worker# the License.
15*61c4878aSAndroid Build Coastguard Worker"""Tests for gitmodules."""
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Workerfrom pathlib import Path
18*61c4878aSAndroid Build Coastguard Workerimport tempfile
19*61c4878aSAndroid Build Coastguard Workerimport unittest
20*61c4878aSAndroid Build Coastguard Workerfrom unittest.mock import MagicMock
21*61c4878aSAndroid Build Coastguard Worker
22*61c4878aSAndroid Build Coastguard Workerfrom pw_presubmit import gitmodules, PresubmitFailure
23*61c4878aSAndroid Build Coastguard Worker
24*61c4878aSAndroid Build Coastguard Worker
25*61c4878aSAndroid Build Coastguard Workerdef dotgitmodules(
26*61c4878aSAndroid Build Coastguard Worker    name: str = 'foo',
27*61c4878aSAndroid Build Coastguard Worker    url: str | None = None,
28*61c4878aSAndroid Build Coastguard Worker    host: str | None = None,
29*61c4878aSAndroid Build Coastguard Worker    branch: str | None = 'main',
30*61c4878aSAndroid Build Coastguard Worker):
31*61c4878aSAndroid Build Coastguard Worker    cfg = f'[submodule "{name}"]\n'
32*61c4878aSAndroid Build Coastguard Worker    cfg += f'path = {name}\n'
33*61c4878aSAndroid Build Coastguard Worker    if url is None and host is None:
34*61c4878aSAndroid Build Coastguard Worker        host = 'host'
35*61c4878aSAndroid Build Coastguard Worker    if host:
36*61c4878aSAndroid Build Coastguard Worker        cfg += f'url = https://{host}.googlesource.com/{name}\n'
37*61c4878aSAndroid Build Coastguard Worker    else:
38*61c4878aSAndroid Build Coastguard Worker        assert url
39*61c4878aSAndroid Build Coastguard Worker        cfg += f'url = {url}\n'
40*61c4878aSAndroid Build Coastguard Worker    if branch:
41*61c4878aSAndroid Build Coastguard Worker        cfg += f'branch = {branch}\n'
42*61c4878aSAndroid Build Coastguard Worker    return cfg
43*61c4878aSAndroid Build Coastguard Worker
44*61c4878aSAndroid Build Coastguard Worker
45*61c4878aSAndroid Build Coastguard Workerclass TestGitmodules(unittest.TestCase):
46*61c4878aSAndroid Build Coastguard Worker    """Test gitmodules check."""
47*61c4878aSAndroid Build Coastguard Worker
48*61c4878aSAndroid Build Coastguard Worker    def setUp(self):
49*61c4878aSAndroid Build Coastguard Worker        self.ctx: MagicMock = None
50*61c4878aSAndroid Build Coastguard Worker
51*61c4878aSAndroid Build Coastguard Worker    def _run(self, config: gitmodules.Config, contents: str) -> None:
52*61c4878aSAndroid Build Coastguard Worker        self.ctx = MagicMock()
53*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail = MagicMock()
54*61c4878aSAndroid Build Coastguard Worker
55*61c4878aSAndroid Build Coastguard Worker        with tempfile.TemporaryDirectory() as tempdir:
56*61c4878aSAndroid Build Coastguard Worker            path = Path(tempdir) / '.gitmodules'
57*61c4878aSAndroid Build Coastguard Worker            with path.open('w') as outs:
58*61c4878aSAndroid Build Coastguard Worker                outs.write(contents)
59*61c4878aSAndroid Build Coastguard Worker
60*61c4878aSAndroid Build Coastguard Worker            gitmodules.process_gitmodules(self.ctx, config, path)
61*61c4878aSAndroid Build Coastguard Worker
62*61c4878aSAndroid Build Coastguard Worker    def test_ok_no_submodules(self) -> None:
63*61c4878aSAndroid Build Coastguard Worker        self._run(gitmodules.Config(), '')
64*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_not_called()
65*61c4878aSAndroid Build Coastguard Worker
66*61c4878aSAndroid Build Coastguard Worker    def test_no_submodules_allowed(self) -> None:
67*61c4878aSAndroid Build Coastguard Worker        self._run(
68*61c4878aSAndroid Build Coastguard Worker            gitmodules.Config(allow_submodules=False),
69*61c4878aSAndroid Build Coastguard Worker            dotgitmodules(url='../foo'),
70*61c4878aSAndroid Build Coastguard Worker        )
71*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_called()
72*61c4878aSAndroid Build Coastguard Worker
73*61c4878aSAndroid Build Coastguard Worker    def test_ok_default(self) -> None:
74*61c4878aSAndroid Build Coastguard Worker        self._run(gitmodules.Config(), dotgitmodules(url='../foo'))
75*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_not_called()
76*61c4878aSAndroid Build Coastguard Worker
77*61c4878aSAndroid Build Coastguard Worker    def test_ok_restrictive(self) -> None:
78*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(
79*61c4878aSAndroid Build Coastguard Worker            allow_non_googlesource_hosts=False,
80*61c4878aSAndroid Build Coastguard Worker            allowed_googlesource_hosts=('host',),
81*61c4878aSAndroid Build Coastguard Worker            require_relative_urls=True,
82*61c4878aSAndroid Build Coastguard Worker            allow_sso=False,
83*61c4878aSAndroid Build Coastguard Worker            allow_git_corp_google_com=False,
84*61c4878aSAndroid Build Coastguard Worker            require_branch=True,
85*61c4878aSAndroid Build Coastguard Worker        )
86*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(url='../foo'))
87*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_not_called()
88*61c4878aSAndroid Build Coastguard Worker
89*61c4878aSAndroid Build Coastguard Worker    def test_validate_ok(self) -> None:
90*61c4878aSAndroid Build Coastguard Worker        def validator(ctx, path, name, props) -> None:
91*61c4878aSAndroid Build Coastguard Worker            _ = name
92*61c4878aSAndroid Build Coastguard Worker            if 'bad' in props['url']:
93*61c4878aSAndroid Build Coastguard Worker                ctx.fail('bad', path)
94*61c4878aSAndroid Build Coastguard Worker
95*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(validator=validator)
96*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(host='host'))
97*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_not_called()
98*61c4878aSAndroid Build Coastguard Worker
99*61c4878aSAndroid Build Coastguard Worker    def test_validate_fail(self) -> None:
100*61c4878aSAndroid Build Coastguard Worker        def validator(ctx, path, name, props) -> None:
101*61c4878aSAndroid Build Coastguard Worker            _ = name
102*61c4878aSAndroid Build Coastguard Worker            if 'bad' in props['url']:
103*61c4878aSAndroid Build Coastguard Worker                ctx.fail('bad', path)
104*61c4878aSAndroid Build Coastguard Worker
105*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(validator=validator)
106*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(host='badhost'))
107*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_called()
108*61c4878aSAndroid Build Coastguard Worker
109*61c4878aSAndroid Build Coastguard Worker    def test_non_google_ok(self) -> None:
110*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(
111*61c4878aSAndroid Build Coastguard Worker            allow_non_googlesource_hosts=True
112*61c4878aSAndroid Build Coastguard Worker        )
113*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(url='https://github.com/foo/bar'))
114*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_not_called()
115*61c4878aSAndroid Build Coastguard Worker
116*61c4878aSAndroid Build Coastguard Worker    def test_non_google_fail(self) -> None:
117*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(
118*61c4878aSAndroid Build Coastguard Worker            allow_non_googlesource_hosts=False
119*61c4878aSAndroid Build Coastguard Worker        )
120*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(url='https://github.com/foo/bar'))
121*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_called()
122*61c4878aSAndroid Build Coastguard Worker
123*61c4878aSAndroid Build Coastguard Worker    def test_bad_allowed_googlesource_hosts(self) -> None:
124*61c4878aSAndroid Build Coastguard Worker        with self.assertRaises(PresubmitFailure):
125*61c4878aSAndroid Build Coastguard Worker            cfg: gitmodules.Config = gitmodules.Config(
126*61c4878aSAndroid Build Coastguard Worker                allowed_googlesource_hosts=('pigweed-review',)
127*61c4878aSAndroid Build Coastguard Worker            )
128*61c4878aSAndroid Build Coastguard Worker            self._run(cfg, dotgitmodules())
129*61c4878aSAndroid Build Coastguard Worker
130*61c4878aSAndroid Build Coastguard Worker    def test_bad_type_allowed_googlesource_hosts(self) -> None:
131*61c4878aSAndroid Build Coastguard Worker        with self.assertRaises(AssertionError):
132*61c4878aSAndroid Build Coastguard Worker            cfg: gitmodules.Config = gitmodules.Config(
133*61c4878aSAndroid Build Coastguard Worker                allowed_googlesource_hosts=('pigweed')
134*61c4878aSAndroid Build Coastguard Worker            )
135*61c4878aSAndroid Build Coastguard Worker            self._run(cfg, dotgitmodules())
136*61c4878aSAndroid Build Coastguard Worker
137*61c4878aSAndroid Build Coastguard Worker    def test_allowed_googlesource_hosts_ok(self) -> None:
138*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(
139*61c4878aSAndroid Build Coastguard Worker            allowed_googlesource_hosts=(
140*61c4878aSAndroid Build Coastguard Worker                'pigweed',
141*61c4878aSAndroid Build Coastguard Worker                'pigweed-internal',
142*61c4878aSAndroid Build Coastguard Worker            )
143*61c4878aSAndroid Build Coastguard Worker        )
144*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(host='pigweed-internal'))
145*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_not_called()
146*61c4878aSAndroid Build Coastguard Worker
147*61c4878aSAndroid Build Coastguard Worker    def test_allowed_googlesource_hosts_fail(self) -> None:
148*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(
149*61c4878aSAndroid Build Coastguard Worker            allowed_googlesource_hosts=('pigweed-internal',)
150*61c4878aSAndroid Build Coastguard Worker        )
151*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(host='pigweed'))
152*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_called()
153*61c4878aSAndroid Build Coastguard Worker
154*61c4878aSAndroid Build Coastguard Worker    def test_require_relative_urls_ok(self) -> None:
155*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(require_relative_urls=False)
156*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(host='foo'))
157*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_not_called()
158*61c4878aSAndroid Build Coastguard Worker
159*61c4878aSAndroid Build Coastguard Worker    def test_require_relative_urls_fail(self) -> None:
160*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(require_relative_urls=True)
161*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(host='foo'))
162*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_called()
163*61c4878aSAndroid Build Coastguard Worker
164*61c4878aSAndroid Build Coastguard Worker    def test_allow_sso_ok(self) -> None:
165*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(allow_sso=True)
166*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(url='sso://host/foo'))
167*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_not_called()
168*61c4878aSAndroid Build Coastguard Worker
169*61c4878aSAndroid Build Coastguard Worker    def test_allow_sso_fail(self) -> None:
170*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(allow_sso=False)
171*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(url='sso://host/foo'))
172*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_called()
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker    def test_allow_git_corp_google_com_ok(self) -> None:
175*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(
176*61c4878aSAndroid Build Coastguard Worker            allow_git_corp_google_com=True
177*61c4878aSAndroid Build Coastguard Worker        )
178*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(url='https://foo.git.corp.google.com/bar'))
179*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_not_called()
180*61c4878aSAndroid Build Coastguard Worker
181*61c4878aSAndroid Build Coastguard Worker    def test_allow_git_corp_google_com_fail(self) -> None:
182*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(
183*61c4878aSAndroid Build Coastguard Worker            allow_git_corp_google_com=False
184*61c4878aSAndroid Build Coastguard Worker        )
185*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(url='https://foo.git.corp.google.com/bar'))
186*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_called()
187*61c4878aSAndroid Build Coastguard Worker
188*61c4878aSAndroid Build Coastguard Worker    def test_require_branch_ok(self) -> None:
189*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(require_branch=False)
190*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(branch=None))
191*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_not_called()
192*61c4878aSAndroid Build Coastguard Worker
193*61c4878aSAndroid Build Coastguard Worker    def test_require_branch_fail(self) -> None:
194*61c4878aSAndroid Build Coastguard Worker        cfg: gitmodules.Config = gitmodules.Config(require_branch=True)
195*61c4878aSAndroid Build Coastguard Worker        self._run(cfg, dotgitmodules(branch=None))
196*61c4878aSAndroid Build Coastguard Worker        self.ctx.fail.assert_called()
197*61c4878aSAndroid Build Coastguard Worker
198*61c4878aSAndroid Build Coastguard Worker
199*61c4878aSAndroid Build Coastguard Workerif __name__ == '__main__':
200*61c4878aSAndroid Build Coastguard Worker    unittest.main()
201