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