xref: /aosp_15_r20/tools/repohooks/rh/hooks_unittest.py (revision d68f33bc6fb0cc2476107c2af0573a2f5a63dfc1)
1*d68f33bcSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*d68f33bcSAndroid Build Coastguard Worker# Copyright 2016 The Android Open Source Project
3*d68f33bcSAndroid Build Coastguard Worker#
4*d68f33bcSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*d68f33bcSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*d68f33bcSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*d68f33bcSAndroid Build Coastguard Worker#
8*d68f33bcSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*d68f33bcSAndroid Build Coastguard Worker#
10*d68f33bcSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*d68f33bcSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*d68f33bcSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d68f33bcSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*d68f33bcSAndroid Build Coastguard Worker# limitations under the License.
15*d68f33bcSAndroid Build Coastguard Worker
16*d68f33bcSAndroid Build Coastguard Worker"""Unittests for the hooks module."""
17*d68f33bcSAndroid Build Coastguard Worker
18*d68f33bcSAndroid Build Coastguard Workerimport os
19*d68f33bcSAndroid Build Coastguard Workerimport sys
20*d68f33bcSAndroid Build Coastguard Workerimport unittest
21*d68f33bcSAndroid Build Coastguard Workerfrom unittest import mock
22*d68f33bcSAndroid Build Coastguard Worker
23*d68f33bcSAndroid Build Coastguard Worker_path = os.path.realpath(__file__ + '/../..')
24*d68f33bcSAndroid Build Coastguard Workerif sys.path[0] != _path:
25*d68f33bcSAndroid Build Coastguard Worker    sys.path.insert(0, _path)
26*d68f33bcSAndroid Build Coastguard Workerdel _path
27*d68f33bcSAndroid Build Coastguard Worker
28*d68f33bcSAndroid Build Coastguard Worker# We have to import our local modules after the sys.path tweak.  We can't use
29*d68f33bcSAndroid Build Coastguard Worker# relative imports because this is an executable program, not a module.
30*d68f33bcSAndroid Build Coastguard Worker# pylint: disable=wrong-import-position
31*d68f33bcSAndroid Build Coastguard Workerimport rh
32*d68f33bcSAndroid Build Coastguard Workerimport rh.config
33*d68f33bcSAndroid Build Coastguard Workerimport rh.hooks
34*d68f33bcSAndroid Build Coastguard Worker
35*d68f33bcSAndroid Build Coastguard Worker
36*d68f33bcSAndroid Build Coastguard Worker# pylint: disable=unused-argument
37*d68f33bcSAndroid Build Coastguard Workerdef mock_find_repo_root(path=None, outer=False):
38*d68f33bcSAndroid Build Coastguard Worker    return '/ ${BUILD_OS}' if outer else '/ ${BUILD_OS}/sub'
39*d68f33bcSAndroid Build Coastguard Worker
40*d68f33bcSAndroid Build Coastguard Worker
41*d68f33bcSAndroid Build Coastguard Workerclass HooksDocsTests(unittest.TestCase):
42*d68f33bcSAndroid Build Coastguard Worker    """Make sure all hook features are documented.
43*d68f33bcSAndroid Build Coastguard Worker
44*d68f33bcSAndroid Build Coastguard Worker    Note: These tests are a bit hokey in that they parse README.md.  But they
45*d68f33bcSAndroid Build Coastguard Worker    get the job done, so that's all that matters right?
46*d68f33bcSAndroid Build Coastguard Worker    """
47*d68f33bcSAndroid Build Coastguard Worker
48*d68f33bcSAndroid Build Coastguard Worker    def setUp(self):
49*d68f33bcSAndroid Build Coastguard Worker        self.readme = os.path.join(os.path.dirname(os.path.dirname(
50*d68f33bcSAndroid Build Coastguard Worker            os.path.realpath(__file__))), 'README.md')
51*d68f33bcSAndroid Build Coastguard Worker
52*d68f33bcSAndroid Build Coastguard Worker    def _grab_section(self, section):
53*d68f33bcSAndroid Build Coastguard Worker        """Extract the |section| text out of the readme."""
54*d68f33bcSAndroid Build Coastguard Worker        ret = []
55*d68f33bcSAndroid Build Coastguard Worker        in_section = False
56*d68f33bcSAndroid Build Coastguard Worker        with open(self.readme, encoding='utf-8') as fp:
57*d68f33bcSAndroid Build Coastguard Worker            for line in fp:
58*d68f33bcSAndroid Build Coastguard Worker                if not in_section:
59*d68f33bcSAndroid Build Coastguard Worker                    # Look for the section like "## [Tool Paths]".
60*d68f33bcSAndroid Build Coastguard Worker                    if (line.startswith('#') and
61*d68f33bcSAndroid Build Coastguard Worker                            line.lstrip('#').strip() == section):
62*d68f33bcSAndroid Build Coastguard Worker                        in_section = True
63*d68f33bcSAndroid Build Coastguard Worker                else:
64*d68f33bcSAndroid Build Coastguard Worker                    # Once we hit the next section (higher or lower), break.
65*d68f33bcSAndroid Build Coastguard Worker                    if line[0] == '#':
66*d68f33bcSAndroid Build Coastguard Worker                        break
67*d68f33bcSAndroid Build Coastguard Worker                    ret.append(line)
68*d68f33bcSAndroid Build Coastguard Worker        return ''.join(ret)
69*d68f33bcSAndroid Build Coastguard Worker
70*d68f33bcSAndroid Build Coastguard Worker    def testBuiltinHooks(self):
71*d68f33bcSAndroid Build Coastguard Worker        """Verify builtin hooks are documented."""
72*d68f33bcSAndroid Build Coastguard Worker        data = self._grab_section('[Builtin Hooks]')
73*d68f33bcSAndroid Build Coastguard Worker        for hook in rh.hooks.BUILTIN_HOOKS:
74*d68f33bcSAndroid Build Coastguard Worker            self.assertIn(f'* `{hook}`:', data,
75*d68f33bcSAndroid Build Coastguard Worker                          msg=f'README.md missing docs for hook "{hook}"')
76*d68f33bcSAndroid Build Coastguard Worker
77*d68f33bcSAndroid Build Coastguard Worker    def testToolPaths(self):
78*d68f33bcSAndroid Build Coastguard Worker        """Verify tools are documented."""
79*d68f33bcSAndroid Build Coastguard Worker        data = self._grab_section('[Tool Paths]')
80*d68f33bcSAndroid Build Coastguard Worker        for tool in rh.hooks.TOOL_PATHS:
81*d68f33bcSAndroid Build Coastguard Worker            self.assertIn(f'* `{tool}`:', data,
82*d68f33bcSAndroid Build Coastguard Worker                          msg=f'README.md missing docs for tool "{tool}"')
83*d68f33bcSAndroid Build Coastguard Worker
84*d68f33bcSAndroid Build Coastguard Worker    def testPlaceholders(self):
85*d68f33bcSAndroid Build Coastguard Worker        """Verify placeholder replacement vars are documented."""
86*d68f33bcSAndroid Build Coastguard Worker        data = self._grab_section('Placeholders')
87*d68f33bcSAndroid Build Coastguard Worker        for var in rh.hooks.Placeholders.vars():
88*d68f33bcSAndroid Build Coastguard Worker            self.assertIn('* `${' + var + '}`:', data,
89*d68f33bcSAndroid Build Coastguard Worker                          msg=f'README.md missing docs for var "{var}"')
90*d68f33bcSAndroid Build Coastguard Worker
91*d68f33bcSAndroid Build Coastguard Worker
92*d68f33bcSAndroid Build Coastguard Workerclass PlaceholderTests(unittest.TestCase):
93*d68f33bcSAndroid Build Coastguard Worker    """Verify behavior of replacement variables."""
94*d68f33bcSAndroid Build Coastguard Worker
95*d68f33bcSAndroid Build Coastguard Worker    def setUp(self):
96*d68f33bcSAndroid Build Coastguard Worker        self._saved_environ = os.environ.copy()
97*d68f33bcSAndroid Build Coastguard Worker        os.environ.update({
98*d68f33bcSAndroid Build Coastguard Worker            'PREUPLOAD_COMMIT_MESSAGE': 'commit message',
99*d68f33bcSAndroid Build Coastguard Worker            'PREUPLOAD_COMMIT': '5c4c293174bb61f0f39035a71acd9084abfa743d',
100*d68f33bcSAndroid Build Coastguard Worker        })
101*d68f33bcSAndroid Build Coastguard Worker        self.replacer = rh.hooks.Placeholders(
102*d68f33bcSAndroid Build Coastguard Worker            [rh.git.RawDiffEntry(file=x)
103*d68f33bcSAndroid Build Coastguard Worker             for x in ['path1/file1', 'path2/file2']])
104*d68f33bcSAndroid Build Coastguard Worker
105*d68f33bcSAndroid Build Coastguard Worker    def tearDown(self):
106*d68f33bcSAndroid Build Coastguard Worker        os.environ.clear()
107*d68f33bcSAndroid Build Coastguard Worker        os.environ.update(self._saved_environ)
108*d68f33bcSAndroid Build Coastguard Worker
109*d68f33bcSAndroid Build Coastguard Worker    def testVars(self):
110*d68f33bcSAndroid Build Coastguard Worker        """Light test for the vars inspection generator."""
111*d68f33bcSAndroid Build Coastguard Worker        ret = list(self.replacer.vars())
112*d68f33bcSAndroid Build Coastguard Worker        self.assertGreater(len(ret), 4)
113*d68f33bcSAndroid Build Coastguard Worker        self.assertIn('PREUPLOAD_COMMIT', ret)
114*d68f33bcSAndroid Build Coastguard Worker
115*d68f33bcSAndroid Build Coastguard Worker    @mock.patch.object(rh.git, 'find_repo_root',
116*d68f33bcSAndroid Build Coastguard Worker                       side_effect=mock_find_repo_root)
117*d68f33bcSAndroid Build Coastguard Worker    def testExpandVars(self, _m):
118*d68f33bcSAndroid Build Coastguard Worker        """Verify the replacement actually works."""
119*d68f33bcSAndroid Build Coastguard Worker        input_args = [
120*d68f33bcSAndroid Build Coastguard Worker            # Verify ${REPO_ROOT} is updated, but not REPO_ROOT.
121*d68f33bcSAndroid Build Coastguard Worker            # We also make sure that things in ${REPO_ROOT} are not double
122*d68f33bcSAndroid Build Coastguard Worker            # expanded (which is why the return includes ${BUILD_OS}).
123*d68f33bcSAndroid Build Coastguard Worker            '${REPO_ROOT}/some/prog/REPO_ROOT/ok',
124*d68f33bcSAndroid Build Coastguard Worker            # Verify that ${REPO_OUTER_ROOT} is expanded.
125*d68f33bcSAndroid Build Coastguard Worker            '${REPO_OUTER_ROOT}/some/prog/REPO_OUTER_ROOT/ok',
126*d68f33bcSAndroid Build Coastguard Worker            # Verify lists are merged rather than inserted.
127*d68f33bcSAndroid Build Coastguard Worker            '${PREUPLOAD_FILES}',
128*d68f33bcSAndroid Build Coastguard Worker            # Verify each file is preceded with '--file=' prefix.
129*d68f33bcSAndroid Build Coastguard Worker            '--file=${PREUPLOAD_FILES_PREFIXED}',
130*d68f33bcSAndroid Build Coastguard Worker            # Verify each file is preceded with '--file' argument.
131*d68f33bcSAndroid Build Coastguard Worker            '--file',
132*d68f33bcSAndroid Build Coastguard Worker            '${PREUPLOAD_FILES_PREFIXED}',
133*d68f33bcSAndroid Build Coastguard Worker            # Verify values with whitespace don't expand into multiple args.
134*d68f33bcSAndroid Build Coastguard Worker            '${PREUPLOAD_COMMIT_MESSAGE}',
135*d68f33bcSAndroid Build Coastguard Worker            # Verify multiple values get replaced.
136*d68f33bcSAndroid Build Coastguard Worker            '${PREUPLOAD_COMMIT}^${PREUPLOAD_COMMIT_MESSAGE}',
137*d68f33bcSAndroid Build Coastguard Worker            # Unknown vars should be left alone.
138*d68f33bcSAndroid Build Coastguard Worker            '${THIS_VAR_IS_GOOD}',
139*d68f33bcSAndroid Build Coastguard Worker        ]
140*d68f33bcSAndroid Build Coastguard Worker        output_args = self.replacer.expand_vars(input_args)
141*d68f33bcSAndroid Build Coastguard Worker        exp_args = [
142*d68f33bcSAndroid Build Coastguard Worker            '/ ${BUILD_OS}/sub/some/prog/REPO_ROOT/ok',
143*d68f33bcSAndroid Build Coastguard Worker            '/ ${BUILD_OS}/some/prog/REPO_OUTER_ROOT/ok',
144*d68f33bcSAndroid Build Coastguard Worker            'path1/file1',
145*d68f33bcSAndroid Build Coastguard Worker            'path2/file2',
146*d68f33bcSAndroid Build Coastguard Worker            '--file=path1/file1',
147*d68f33bcSAndroid Build Coastguard Worker            '--file=path2/file2',
148*d68f33bcSAndroid Build Coastguard Worker            '--file',
149*d68f33bcSAndroid Build Coastguard Worker            'path1/file1',
150*d68f33bcSAndroid Build Coastguard Worker            '--file',
151*d68f33bcSAndroid Build Coastguard Worker            'path2/file2',
152*d68f33bcSAndroid Build Coastguard Worker            'commit message',
153*d68f33bcSAndroid Build Coastguard Worker            '5c4c293174bb61f0f39035a71acd9084abfa743d^commit message',
154*d68f33bcSAndroid Build Coastguard Worker            '${THIS_VAR_IS_GOOD}',
155*d68f33bcSAndroid Build Coastguard Worker        ]
156*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(output_args, exp_args)
157*d68f33bcSAndroid Build Coastguard Worker
158*d68f33bcSAndroid Build Coastguard Worker    def testTheTester(self):
159*d68f33bcSAndroid Build Coastguard Worker        """Make sure we have a test for every variable."""
160*d68f33bcSAndroid Build Coastguard Worker        for var in self.replacer.vars():
161*d68f33bcSAndroid Build Coastguard Worker            self.assertIn(f'test{var}', dir(self),
162*d68f33bcSAndroid Build Coastguard Worker                          msg=f'Missing unittest for variable {var}')
163*d68f33bcSAndroid Build Coastguard Worker
164*d68f33bcSAndroid Build Coastguard Worker    def testPREUPLOAD_COMMIT_MESSAGE(self):
165*d68f33bcSAndroid Build Coastguard Worker        """Verify handling of PREUPLOAD_COMMIT_MESSAGE."""
166*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(self.replacer.get('PREUPLOAD_COMMIT_MESSAGE'),
167*d68f33bcSAndroid Build Coastguard Worker                         'commit message')
168*d68f33bcSAndroid Build Coastguard Worker
169*d68f33bcSAndroid Build Coastguard Worker    def testPREUPLOAD_COMMIT(self):
170*d68f33bcSAndroid Build Coastguard Worker        """Verify handling of PREUPLOAD_COMMIT."""
171*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(self.replacer.get('PREUPLOAD_COMMIT'),
172*d68f33bcSAndroid Build Coastguard Worker                         '5c4c293174bb61f0f39035a71acd9084abfa743d')
173*d68f33bcSAndroid Build Coastguard Worker
174*d68f33bcSAndroid Build Coastguard Worker    def testPREUPLOAD_FILES(self):
175*d68f33bcSAndroid Build Coastguard Worker        """Verify handling of PREUPLOAD_FILES."""
176*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(self.replacer.get('PREUPLOAD_FILES'),
177*d68f33bcSAndroid Build Coastguard Worker                         ['path1/file1', 'path2/file2'])
178*d68f33bcSAndroid Build Coastguard Worker
179*d68f33bcSAndroid Build Coastguard Worker    @mock.patch.object(rh.git, 'find_repo_root')
180*d68f33bcSAndroid Build Coastguard Worker    def testREPO_OUTER_ROOT(self, m):
181*d68f33bcSAndroid Build Coastguard Worker        """Verify handling of REPO_OUTER_ROOT."""
182*d68f33bcSAndroid Build Coastguard Worker        m.side_effect = mock_find_repo_root
183*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(self.replacer.get('REPO_OUTER_ROOT'),
184*d68f33bcSAndroid Build Coastguard Worker                         mock_find_repo_root(path=None, outer=True))
185*d68f33bcSAndroid Build Coastguard Worker
186*d68f33bcSAndroid Build Coastguard Worker    @mock.patch.object(rh.git, 'find_repo_root')
187*d68f33bcSAndroid Build Coastguard Worker    def testREPO_ROOT(self, m):
188*d68f33bcSAndroid Build Coastguard Worker        """Verify handling of REPO_ROOT."""
189*d68f33bcSAndroid Build Coastguard Worker        m.side_effect = mock_find_repo_root
190*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(self.replacer.get('REPO_ROOT'),
191*d68f33bcSAndroid Build Coastguard Worker                         mock_find_repo_root(path=None, outer=False))
192*d68f33bcSAndroid Build Coastguard Worker
193*d68f33bcSAndroid Build Coastguard Worker    def testREPO_PATH(self):
194*d68f33bcSAndroid Build Coastguard Worker        """Verify handling of REPO_PATH."""
195*d68f33bcSAndroid Build Coastguard Worker        os.environ['REPO_PATH'] = ''
196*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(self.replacer.get('REPO_PATH'), '')
197*d68f33bcSAndroid Build Coastguard Worker        os.environ['REPO_PATH'] = 'foo/bar'
198*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(self.replacer.get('REPO_PATH'), 'foo/bar')
199*d68f33bcSAndroid Build Coastguard Worker
200*d68f33bcSAndroid Build Coastguard Worker    def testREPO_PROJECT(self):
201*d68f33bcSAndroid Build Coastguard Worker        """Verify handling of REPO_PROJECT."""
202*d68f33bcSAndroid Build Coastguard Worker        os.environ['REPO_PROJECT'] = ''
203*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(self.replacer.get('REPO_PROJECT'), '')
204*d68f33bcSAndroid Build Coastguard Worker        os.environ['REPO_PROJECT'] = 'platform/foo/bar'
205*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(self.replacer.get('REPO_PROJECT'), 'platform/foo/bar')
206*d68f33bcSAndroid Build Coastguard Worker
207*d68f33bcSAndroid Build Coastguard Worker    @mock.patch.object(rh.hooks, '_get_build_os_name', return_value='vapier os')
208*d68f33bcSAndroid Build Coastguard Worker    def testBUILD_OS(self, m):
209*d68f33bcSAndroid Build Coastguard Worker        """Verify handling of BUILD_OS."""
210*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(self.replacer.get('BUILD_OS'), m.return_value)
211*d68f33bcSAndroid Build Coastguard Worker
212*d68f33bcSAndroid Build Coastguard Worker
213*d68f33bcSAndroid Build Coastguard Workerclass ExclusionScopeTests(unittest.TestCase):
214*d68f33bcSAndroid Build Coastguard Worker    """Verify behavior of ExclusionScope class."""
215*d68f33bcSAndroid Build Coastguard Worker
216*d68f33bcSAndroid Build Coastguard Worker    def testEmpty(self):
217*d68f33bcSAndroid Build Coastguard Worker        """Verify the in operator for an empty scope."""
218*d68f33bcSAndroid Build Coastguard Worker        scope = rh.hooks.ExclusionScope([])
219*d68f33bcSAndroid Build Coastguard Worker        self.assertNotIn('external/*', scope)
220*d68f33bcSAndroid Build Coastguard Worker
221*d68f33bcSAndroid Build Coastguard Worker    def testGlob(self):
222*d68f33bcSAndroid Build Coastguard Worker        """Verify the in operator for a scope using wildcards."""
223*d68f33bcSAndroid Build Coastguard Worker        scope = rh.hooks.ExclusionScope(['vendor/*', 'external/*'])
224*d68f33bcSAndroid Build Coastguard Worker        self.assertIn('external/tools', scope)
225*d68f33bcSAndroid Build Coastguard Worker
226*d68f33bcSAndroid Build Coastguard Worker    def testRegex(self):
227*d68f33bcSAndroid Build Coastguard Worker        """Verify the in operator for a scope using regular expressions."""
228*d68f33bcSAndroid Build Coastguard Worker        scope = rh.hooks.ExclusionScope(['^vendor/(?!google)',
229*d68f33bcSAndroid Build Coastguard Worker                                         'external/*'])
230*d68f33bcSAndroid Build Coastguard Worker        self.assertIn('vendor/', scope)
231*d68f33bcSAndroid Build Coastguard Worker        self.assertNotIn('vendor/google/', scope)
232*d68f33bcSAndroid Build Coastguard Worker        self.assertIn('vendor/other/', scope)
233*d68f33bcSAndroid Build Coastguard Worker
234*d68f33bcSAndroid Build Coastguard Worker
235*d68f33bcSAndroid Build Coastguard Workerclass HookOptionsTests(unittest.TestCase):
236*d68f33bcSAndroid Build Coastguard Worker    """Verify behavior of HookOptions object."""
237*d68f33bcSAndroid Build Coastguard Worker
238*d68f33bcSAndroid Build Coastguard Worker    @mock.patch.object(rh.hooks, '_get_build_os_name', return_value='vapier os')
239*d68f33bcSAndroid Build Coastguard Worker    def testExpandVars(self, m):
240*d68f33bcSAndroid Build Coastguard Worker        """Verify expand_vars behavior."""
241*d68f33bcSAndroid Build Coastguard Worker        # Simple pass through.
242*d68f33bcSAndroid Build Coastguard Worker        args = ['who', 'goes', 'there ?']
243*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(args, rh.hooks.HookOptions.expand_vars(args))
244*d68f33bcSAndroid Build Coastguard Worker
245*d68f33bcSAndroid Build Coastguard Worker        # At least one replacement.  Most real testing is in PlaceholderTests.
246*d68f33bcSAndroid Build Coastguard Worker        args = ['who', 'goes', 'there ?', '${BUILD_OS} is great']
247*d68f33bcSAndroid Build Coastguard Worker        exp_args = ['who', 'goes', 'there ?', f'{m.return_value} is great']
248*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(exp_args, rh.hooks.HookOptions.expand_vars(args))
249*d68f33bcSAndroid Build Coastguard Worker
250*d68f33bcSAndroid Build Coastguard Worker    def testArgs(self):
251*d68f33bcSAndroid Build Coastguard Worker        """Verify args behavior."""
252*d68f33bcSAndroid Build Coastguard Worker        # Verify initial args to __init__ has higher precedent.
253*d68f33bcSAndroid Build Coastguard Worker        args = ['start', 'args']
254*d68f33bcSAndroid Build Coastguard Worker        options = rh.hooks.HookOptions('hook name', args, {})
255*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(options.args(), args)
256*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(options.args(default_args=['moo']), args)
257*d68f33bcSAndroid Build Coastguard Worker
258*d68f33bcSAndroid Build Coastguard Worker        # Verify we fall back to default_args.
259*d68f33bcSAndroid Build Coastguard Worker        args = ['default', 'args']
260*d68f33bcSAndroid Build Coastguard Worker        options = rh.hooks.HookOptions('hook name', [], {})
261*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(options.args(), [])
262*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(options.args(default_args=args), args)
263*d68f33bcSAndroid Build Coastguard Worker
264*d68f33bcSAndroid Build Coastguard Worker    def testToolPath(self):
265*d68f33bcSAndroid Build Coastguard Worker        """Verify tool_path behavior."""
266*d68f33bcSAndroid Build Coastguard Worker        options = rh.hooks.HookOptions('hook name', [], {
267*d68f33bcSAndroid Build Coastguard Worker            'cpplint': 'my cpplint',
268*d68f33bcSAndroid Build Coastguard Worker        })
269*d68f33bcSAndroid Build Coastguard Worker        # Check a builtin (and not overridden) tool.
270*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(options.tool_path('pylint'), 'pylint')
271*d68f33bcSAndroid Build Coastguard Worker        # Check an overridden tool.
272*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(options.tool_path('cpplint'), 'my cpplint')
273*d68f33bcSAndroid Build Coastguard Worker        # Check an unknown tool fails.
274*d68f33bcSAndroid Build Coastguard Worker        self.assertRaises(AssertionError, options.tool_path, 'extra_tool')
275*d68f33bcSAndroid Build Coastguard Worker
276*d68f33bcSAndroid Build Coastguard Worker
277*d68f33bcSAndroid Build Coastguard Workerclass UtilsTests(unittest.TestCase):
278*d68f33bcSAndroid Build Coastguard Worker    """Verify misc utility functions."""
279*d68f33bcSAndroid Build Coastguard Worker
280*d68f33bcSAndroid Build Coastguard Worker    def testRunCommand(self):
281*d68f33bcSAndroid Build Coastguard Worker        """Check _run behavior."""
282*d68f33bcSAndroid Build Coastguard Worker        # Most testing is done against the utils.RunCommand already.
283*d68f33bcSAndroid Build Coastguard Worker        # pylint: disable=protected-access
284*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks._run(['true'])
285*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(ret.returncode, 0)
286*d68f33bcSAndroid Build Coastguard Worker
287*d68f33bcSAndroid Build Coastguard Worker    def testBuildOs(self):
288*d68f33bcSAndroid Build Coastguard Worker        """Check _get_build_os_name behavior."""
289*d68f33bcSAndroid Build Coastguard Worker        # Just verify it returns something and doesn't crash.
290*d68f33bcSAndroid Build Coastguard Worker        # pylint: disable=protected-access
291*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks._get_build_os_name()
292*d68f33bcSAndroid Build Coastguard Worker        self.assertTrue(isinstance(ret, str))
293*d68f33bcSAndroid Build Coastguard Worker        self.assertNotEqual(ret, '')
294*d68f33bcSAndroid Build Coastguard Worker
295*d68f33bcSAndroid Build Coastguard Worker    def testGetHelperPath(self):
296*d68f33bcSAndroid Build Coastguard Worker        """Check get_helper_path behavior."""
297*d68f33bcSAndroid Build Coastguard Worker        # Just verify it doesn't crash.  It's a dirt simple func.
298*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.get_helper_path('booga')
299*d68f33bcSAndroid Build Coastguard Worker        self.assertTrue(isinstance(ret, str))
300*d68f33bcSAndroid Build Coastguard Worker        self.assertNotEqual(ret, '')
301*d68f33bcSAndroid Build Coastguard Worker
302*d68f33bcSAndroid Build Coastguard Worker    def testSortedToolPaths(self):
303*d68f33bcSAndroid Build Coastguard Worker        """Check TOOL_PATHS is sorted."""
304*d68f33bcSAndroid Build Coastguard Worker        # This assumes dictionary key ordering matches insertion/definition
305*d68f33bcSAndroid Build Coastguard Worker        # order which Python 3.7+ has codified.
306*d68f33bcSAndroid Build Coastguard Worker        # https://docs.python.org/3.7/library/stdtypes.html#dict
307*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(list(rh.hooks.TOOL_PATHS), sorted(rh.hooks.TOOL_PATHS))
308*d68f33bcSAndroid Build Coastguard Worker
309*d68f33bcSAndroid Build Coastguard Worker    def testSortedBuiltinHooks(self):
310*d68f33bcSAndroid Build Coastguard Worker        """Check BUILTIN_HOOKS is sorted."""
311*d68f33bcSAndroid Build Coastguard Worker        # This assumes dictionary key ordering matches insertion/definition
312*d68f33bcSAndroid Build Coastguard Worker        # order which Python 3.7+ has codified.
313*d68f33bcSAndroid Build Coastguard Worker        # https://docs.python.org/3.7/library/stdtypes.html#dict
314*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(
315*d68f33bcSAndroid Build Coastguard Worker            list(rh.hooks.BUILTIN_HOOKS), sorted(rh.hooks.BUILTIN_HOOKS))
316*d68f33bcSAndroid Build Coastguard Worker
317*d68f33bcSAndroid Build Coastguard Worker
318*d68f33bcSAndroid Build Coastguard Worker@mock.patch.object(rh.utils, 'run')
319*d68f33bcSAndroid Build Coastguard Worker@mock.patch.object(rh.hooks, '_check_cmd', return_value=['check_cmd'])
320*d68f33bcSAndroid Build Coastguard Workerclass BuiltinHooksTests(unittest.TestCase):
321*d68f33bcSAndroid Build Coastguard Worker    """Verify the builtin hooks."""
322*d68f33bcSAndroid Build Coastguard Worker
323*d68f33bcSAndroid Build Coastguard Worker    def setUp(self):
324*d68f33bcSAndroid Build Coastguard Worker        self.project = rh.Project(name='project-name', dir='/.../repo/dir')
325*d68f33bcSAndroid Build Coastguard Worker        self.options = rh.hooks.HookOptions('hook name', [], {})
326*d68f33bcSAndroid Build Coastguard Worker
327*d68f33bcSAndroid Build Coastguard Worker    def _test_commit_messages(self, func, accept, msgs, files=None):
328*d68f33bcSAndroid Build Coastguard Worker        """Helper for testing commit message hooks.
329*d68f33bcSAndroid Build Coastguard Worker
330*d68f33bcSAndroid Build Coastguard Worker        Args:
331*d68f33bcSAndroid Build Coastguard Worker          func: The hook function to test.
332*d68f33bcSAndroid Build Coastguard Worker          accept: Whether all the |msgs| should be accepted.
333*d68f33bcSAndroid Build Coastguard Worker          msgs: List of messages to test.
334*d68f33bcSAndroid Build Coastguard Worker          files: List of files to pass to the hook.
335*d68f33bcSAndroid Build Coastguard Worker        """
336*d68f33bcSAndroid Build Coastguard Worker        if files:
337*d68f33bcSAndroid Build Coastguard Worker            diff = [rh.git.RawDiffEntry(file=x) for x in files]
338*d68f33bcSAndroid Build Coastguard Worker        else:
339*d68f33bcSAndroid Build Coastguard Worker            diff = []
340*d68f33bcSAndroid Build Coastguard Worker        for desc in msgs:
341*d68f33bcSAndroid Build Coastguard Worker            ret = func(self.project, 'commit', desc, diff, options=self.options)
342*d68f33bcSAndroid Build Coastguard Worker            if accept:
343*d68f33bcSAndroid Build Coastguard Worker                self.assertFalse(
344*d68f33bcSAndroid Build Coastguard Worker                    bool(ret), msg='Should have accepted: {{{' + desc + '}}}')
345*d68f33bcSAndroid Build Coastguard Worker            else:
346*d68f33bcSAndroid Build Coastguard Worker                self.assertTrue(
347*d68f33bcSAndroid Build Coastguard Worker                    bool(ret), msg='Should have rejected: {{{' + desc + '}}}')
348*d68f33bcSAndroid Build Coastguard Worker
349*d68f33bcSAndroid Build Coastguard Worker    def _test_file_filter(self, mock_check, func, files):
350*d68f33bcSAndroid Build Coastguard Worker        """Helper for testing hooks that filter by files and run external tools.
351*d68f33bcSAndroid Build Coastguard Worker
352*d68f33bcSAndroid Build Coastguard Worker        Args:
353*d68f33bcSAndroid Build Coastguard Worker          mock_check: The mock of _check_cmd.
354*d68f33bcSAndroid Build Coastguard Worker          func: The hook function to test.
355*d68f33bcSAndroid Build Coastguard Worker          files: A list of files that we'd check.
356*d68f33bcSAndroid Build Coastguard Worker        """
357*d68f33bcSAndroid Build Coastguard Worker        # First call should do nothing as there are no files to check.
358*d68f33bcSAndroid Build Coastguard Worker        ret = func(self.project, 'commit', 'desc', (), options=self.options)
359*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNone(ret)
360*d68f33bcSAndroid Build Coastguard Worker        self.assertFalse(mock_check.called)
361*d68f33bcSAndroid Build Coastguard Worker
362*d68f33bcSAndroid Build Coastguard Worker        # Second call should include some checks.
363*d68f33bcSAndroid Build Coastguard Worker        diff = [rh.git.RawDiffEntry(file=x) for x in files]
364*d68f33bcSAndroid Build Coastguard Worker        ret = func(self.project, 'commit', 'desc', diff, options=self.options)
365*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(ret, mock_check.return_value)
366*d68f33bcSAndroid Build Coastguard Worker
367*d68f33bcSAndroid Build Coastguard Worker    def testTheTester(self, _mock_check, _mock_run):
368*d68f33bcSAndroid Build Coastguard Worker        """Make sure we have a test for every hook."""
369*d68f33bcSAndroid Build Coastguard Worker        for hook in rh.hooks.BUILTIN_HOOKS:
370*d68f33bcSAndroid Build Coastguard Worker            self.assertIn(f'test_{hook}', dir(self),
371*d68f33bcSAndroid Build Coastguard Worker                          msg=f'Missing unittest for builtin hook {hook}')
372*d68f33bcSAndroid Build Coastguard Worker
373*d68f33bcSAndroid Build Coastguard Worker    def test_aosp_license(self, mock_check, _mock_run):
374*d68f33bcSAndroid Build Coastguard Worker        """Verify the aosp_license builtin hook."""
375*d68f33bcSAndroid Build Coastguard Worker        # First call should do nothing as there are no files to check.
376*d68f33bcSAndroid Build Coastguard Worker        diff = [
377*d68f33bcSAndroid Build Coastguard Worker            rh.git.RawDiffEntry(file='d.bp', status='D'),
378*d68f33bcSAndroid Build Coastguard Worker            rh.git.RawDiffEntry(file='m.bp', status='M'),
379*d68f33bcSAndroid Build Coastguard Worker            rh.git.RawDiffEntry(file='non-interested', status='A'),
380*d68f33bcSAndroid Build Coastguard Worker        ]
381*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_aosp_license(
382*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff, options=self.options)
383*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNone(ret)
384*d68f33bcSAndroid Build Coastguard Worker        self.assertFalse(mock_check.called)
385*d68f33bcSAndroid Build Coastguard Worker
386*d68f33bcSAndroid Build Coastguard Worker        # Second call will have some results.
387*d68f33bcSAndroid Build Coastguard Worker        diff = [
388*d68f33bcSAndroid Build Coastguard Worker            rh.git.RawDiffEntry(file='a.bp', status='A'),
389*d68f33bcSAndroid Build Coastguard Worker        ]
390*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_aosp_license(
391*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff, options=self.options)
392*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNotNone(ret)
393*d68f33bcSAndroid Build Coastguard Worker
394*d68f33bcSAndroid Build Coastguard Worker        # No result since all paths are excluded.
395*d68f33bcSAndroid Build Coastguard Worker        diff = [
396*d68f33bcSAndroid Build Coastguard Worker            rh.git.RawDiffEntry(file='a/a.bp', status='A'),
397*d68f33bcSAndroid Build Coastguard Worker            rh.git.RawDiffEntry(file='b/a.bp', status='A'),
398*d68f33bcSAndroid Build Coastguard Worker            rh.git.RawDiffEntry(file='c/d/a.bp', status='A'),
399*d68f33bcSAndroid Build Coastguard Worker        ]
400*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_aosp_license(
401*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff,
402*d68f33bcSAndroid Build Coastguard Worker            options=rh.hooks.HookOptions('hook name',
403*d68f33bcSAndroid Build Coastguard Worker                ['--exclude-dirs=a,b', '--exclude-dirs=c/d'], {})
404*d68f33bcSAndroid Build Coastguard Worker        )
405*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNone(ret)
406*d68f33bcSAndroid Build Coastguard Worker
407*d68f33bcSAndroid Build Coastguard Worker        # Make sure that `--exclude-dir` doesn't match the path in the middle.
408*d68f33bcSAndroid Build Coastguard Worker        diff = [
409*d68f33bcSAndroid Build Coastguard Worker            rh.git.RawDiffEntry(file='a/b/c.bp', status='A'),
410*d68f33bcSAndroid Build Coastguard Worker        ]
411*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_aosp_license(
412*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff,
413*d68f33bcSAndroid Build Coastguard Worker            options=rh.hooks.HookOptions('hook name', ['--exclude-dirs=b'], {})
414*d68f33bcSAndroid Build Coastguard Worker        )
415*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNotNone(ret)
416*d68f33bcSAndroid Build Coastguard Worker
417*d68f33bcSAndroid Build Coastguard Worker
418*d68f33bcSAndroid Build Coastguard Worker    def test_bpfmt(self, mock_check, _mock_run):
419*d68f33bcSAndroid Build Coastguard Worker        """Verify the bpfmt builtin hook."""
420*d68f33bcSAndroid Build Coastguard Worker        # First call should do nothing as there are no files to check.
421*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_bpfmt(
422*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', (), options=self.options)
423*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNone(ret)
424*d68f33bcSAndroid Build Coastguard Worker        self.assertFalse(mock_check.called)
425*d68f33bcSAndroid Build Coastguard Worker
426*d68f33bcSAndroid Build Coastguard Worker        # Second call will have some results.
427*d68f33bcSAndroid Build Coastguard Worker        diff = [rh.git.RawDiffEntry(file='Android.bp')]
428*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_bpfmt(
429*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff, options=self.options)
430*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNotNone(ret)
431*d68f33bcSAndroid Build Coastguard Worker        for result in ret:
432*d68f33bcSAndroid Build Coastguard Worker            self.assertIsNotNone(result.fixup_cmd)
433*d68f33bcSAndroid Build Coastguard Worker
434*d68f33bcSAndroid Build Coastguard Worker    def test_checkpatch(self, mock_check, _mock_run):
435*d68f33bcSAndroid Build Coastguard Worker        """Verify the checkpatch builtin hook."""
436*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_checkpatch(
437*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', (), options=self.options)
438*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(ret, mock_check.return_value)
439*d68f33bcSAndroid Build Coastguard Worker
440*d68f33bcSAndroid Build Coastguard Worker    def test_clang_format(self, mock_check, _mock_run):
441*d68f33bcSAndroid Build Coastguard Worker        """Verify the clang_format builtin hook."""
442*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_clang_format(
443*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', (), options=self.options)
444*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(ret, mock_check.return_value)
445*d68f33bcSAndroid Build Coastguard Worker
446*d68f33bcSAndroid Build Coastguard Worker    def test_google_java_format(self, mock_check, _mock_run):
447*d68f33bcSAndroid Build Coastguard Worker        """Verify the google_java_format builtin hook."""
448*d68f33bcSAndroid Build Coastguard Worker        # First call should do nothing as there are no files to check.
449*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_google_java_format(
450*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', (), options=self.options)
451*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNone(ret)
452*d68f33bcSAndroid Build Coastguard Worker        self.assertFalse(mock_check.called)
453*d68f33bcSAndroid Build Coastguard Worker        # Check that .java files are included by default.
454*d68f33bcSAndroid Build Coastguard Worker        diff = [rh.git.RawDiffEntry(file='foo.java'),
455*d68f33bcSAndroid Build Coastguard Worker                rh.git.RawDiffEntry(file='bar.kt'),
456*d68f33bcSAndroid Build Coastguard Worker                rh.git.RawDiffEntry(file='baz/blah.java')]
457*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_google_java_format(
458*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff, options=self.options)
459*d68f33bcSAndroid Build Coastguard Worker        self.assertListEqual(ret[0].files, ['foo.java', 'baz/blah.java'])
460*d68f33bcSAndroid Build Coastguard Worker        diff = [rh.git.RawDiffEntry(file='foo/f1.java'),
461*d68f33bcSAndroid Build Coastguard Worker                rh.git.RawDiffEntry(file='bar/f2.java'),
462*d68f33bcSAndroid Build Coastguard Worker                rh.git.RawDiffEntry(file='baz/f2.java')]
463*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_google_java_format(
464*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff,
465*d68f33bcSAndroid Build Coastguard Worker            options=rh.hooks.HookOptions('hook name',
466*d68f33bcSAndroid Build Coastguard Worker            ['--include-dirs=foo,baz'], {}))
467*d68f33bcSAndroid Build Coastguard Worker        self.assertListEqual(ret[0].files, ['foo/f1.java', 'baz/f2.java'])
468*d68f33bcSAndroid Build Coastguard Worker
469*d68f33bcSAndroid Build Coastguard Worker    def test_commit_msg_bug_field(self, _mock_check, _mock_run):
470*d68f33bcSAndroid Build Coastguard Worker        """Verify the commit_msg_bug_field builtin hook."""
471*d68f33bcSAndroid Build Coastguard Worker        # Check some good messages.
472*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
473*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_bug_field, True, (
474*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nBug: 1234\n',
475*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nBug: 1234\nChange-Id: blah\n',
476*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nFix: 1234\n',
477*d68f33bcSAndroid Build Coastguard Worker            ))
478*d68f33bcSAndroid Build Coastguard Worker
479*d68f33bcSAndroid Build Coastguard Worker        # Check some bad messages.
480*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
481*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_bug_field, False, (
482*d68f33bcSAndroid Build Coastguard Worker                'subj',
483*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nBUG=1234\n',
484*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nBUG: 1234\n',
485*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nBug: N/A\n',
486*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nBug:\n',
487*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nFIX=1234\n',
488*d68f33bcSAndroid Build Coastguard Worker            ))
489*d68f33bcSAndroid Build Coastguard Worker
490*d68f33bcSAndroid Build Coastguard Worker    def test_commit_msg_changeid_field(self, _mock_check, _mock_run):
491*d68f33bcSAndroid Build Coastguard Worker        """Verify the commit_msg_changeid_field builtin hook."""
492*d68f33bcSAndroid Build Coastguard Worker        # Check some good messages.
493*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
494*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_changeid_field, True, (
495*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nChange-Id: I1234\n',
496*d68f33bcSAndroid Build Coastguard Worker            ))
497*d68f33bcSAndroid Build Coastguard Worker
498*d68f33bcSAndroid Build Coastguard Worker        # Check some bad messages.
499*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
500*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_changeid_field, False, (
501*d68f33bcSAndroid Build Coastguard Worker                'subj',
502*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nChange-Id: 1234\n',
503*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nChange-ID: I1234\n',
504*d68f33bcSAndroid Build Coastguard Worker            ))
505*d68f33bcSAndroid Build Coastguard Worker
506*d68f33bcSAndroid Build Coastguard Worker    def test_commit_msg_prebuilt_apk_fields(self, _mock_check, _mock_run):
507*d68f33bcSAndroid Build Coastguard Worker        """Verify the check_commit_msg_prebuilt_apk_fields builtin hook."""
508*d68f33bcSAndroid Build Coastguard Worker        # Commits without APKs should pass.
509*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
510*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_prebuilt_apk_fields,
511*d68f33bcSAndroid Build Coastguard Worker            True,
512*d68f33bcSAndroid Build Coastguard Worker            (
513*d68f33bcSAndroid Build Coastguard Worker                'subj\nTest: test case\nBug: bug id\n',
514*d68f33bcSAndroid Build Coastguard Worker            ),
515*d68f33bcSAndroid Build Coastguard Worker            ['foo.cpp', 'bar.py',]
516*d68f33bcSAndroid Build Coastguard Worker        )
517*d68f33bcSAndroid Build Coastguard Worker
518*d68f33bcSAndroid Build Coastguard Worker        # Commits with APKs and all the required messages should pass.
519*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
520*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_prebuilt_apk_fields,
521*d68f33bcSAndroid Build Coastguard Worker            True,
522*d68f33bcSAndroid Build Coastguard Worker            (
523*d68f33bcSAndroid Build Coastguard Worker                ('Test App\n\nbar.apk\npackage: name=\'com.foo.bar\'\n'
524*d68f33bcSAndroid Build Coastguard Worker                 'versionCode=\'1001\'\nversionName=\'1.0.1001-A\'\n'
525*d68f33bcSAndroid Build Coastguard Worker                 'platformBuildVersionName=\'\'\ncompileSdkVersion=\'28\'\n'
526*d68f33bcSAndroid Build Coastguard Worker                 'compileSdkVersionCodename=\'9\'\nsdkVersion:\'16\'\n'
527*d68f33bcSAndroid Build Coastguard Worker                 'targetSdkVersion:\'28\'\n\nBuilt here:\n'
528*d68f33bcSAndroid Build Coastguard Worker                 'http://foo.bar.com/builder\n\n'
529*d68f33bcSAndroid Build Coastguard Worker                 'This build IS suitable for public release.\n\n'
530*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 123\nTest: test\nChange-Id: XXXXXXX\n'),
531*d68f33bcSAndroid Build Coastguard Worker                ('Test App\n\nBuilt here:\nhttp://foo.bar.com/builder\n\n'
532*d68f33bcSAndroid Build Coastguard Worker                 'This build IS NOT suitable for public release.\n\n'
533*d68f33bcSAndroid Build Coastguard Worker                 'bar.apk\npackage: name=\'com.foo.bar\'\n'
534*d68f33bcSAndroid Build Coastguard Worker                 'versionCode=\'1001\'\nversionName=\'1.0.1001-A\'\n'
535*d68f33bcSAndroid Build Coastguard Worker                 'platformBuildVersionName=\'\'\ncompileSdkVersion=\'28\'\n'
536*d68f33bcSAndroid Build Coastguard Worker                 'compileSdkVersionCodename=\'9\'\nsdkVersion:\'16\'\n'
537*d68f33bcSAndroid Build Coastguard Worker                 'targetSdkVersion:\'28\'\n\nBug: 123\nTest: test\n'
538*d68f33bcSAndroid Build Coastguard Worker                 'Change-Id: XXXXXXX\n'),
539*d68f33bcSAndroid Build Coastguard Worker                ('Test App\n\nbar.apk\npackage: name=\'com.foo.bar\'\n'
540*d68f33bcSAndroid Build Coastguard Worker                 'versionCode=\'1001\'\nversionName=\'1.0.1001-A\'\n'
541*d68f33bcSAndroid Build Coastguard Worker                 'platformBuildVersionName=\'\'\ncompileSdkVersion=\'28\'\n'
542*d68f33bcSAndroid Build Coastguard Worker                 'compileSdkVersionCodename=\'9\'\nsdkVersion:\'16\'\n'
543*d68f33bcSAndroid Build Coastguard Worker                 'targetSdkVersion:\'28\'\n\nBuilt here:\n'
544*d68f33bcSAndroid Build Coastguard Worker                 'http://foo.bar.com/builder\n\n'
545*d68f33bcSAndroid Build Coastguard Worker                 'This build IS suitable for preview release but IS NOT '
546*d68f33bcSAndroid Build Coastguard Worker                 'suitable for public release.\n\n'
547*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 123\nTest: test\nChange-Id: XXXXXXX\n'),
548*d68f33bcSAndroid Build Coastguard Worker                ('Test App\n\nbar.apk\npackage: name=\'com.foo.bar\'\n'
549*d68f33bcSAndroid Build Coastguard Worker                 'versionCode=\'1001\'\nversionName=\'1.0.1001-A\'\n'
550*d68f33bcSAndroid Build Coastguard Worker                 'platformBuildVersionName=\'\'\ncompileSdkVersion=\'28\'\n'
551*d68f33bcSAndroid Build Coastguard Worker                 'compileSdkVersionCodename=\'9\'\nsdkVersion:\'16\'\n'
552*d68f33bcSAndroid Build Coastguard Worker                 'targetSdkVersion:\'28\'\n\nBuilt here:\n'
553*d68f33bcSAndroid Build Coastguard Worker                 'http://foo.bar.com/builder\n\n'
554*d68f33bcSAndroid Build Coastguard Worker                 'This build IS NOT suitable for preview or public release.\n\n'
555*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 123\nTest: test\nChange-Id: XXXXXXX\n'),
556*d68f33bcSAndroid Build Coastguard Worker            ),
557*d68f33bcSAndroid Build Coastguard Worker            ['foo.apk', 'bar.py',]
558*d68f33bcSAndroid Build Coastguard Worker        )
559*d68f33bcSAndroid Build Coastguard Worker
560*d68f33bcSAndroid Build Coastguard Worker        # Commits with APKs and without all the required messages should fail.
561*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
562*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_prebuilt_apk_fields,
563*d68f33bcSAndroid Build Coastguard Worker            False,
564*d68f33bcSAndroid Build Coastguard Worker            (
565*d68f33bcSAndroid Build Coastguard Worker                'subj\nTest: test case\nBug: bug id\n',
566*d68f33bcSAndroid Build Coastguard Worker                # Missing 'package'.
567*d68f33bcSAndroid Build Coastguard Worker                ('Test App\n\nbar.apk\n'
568*d68f33bcSAndroid Build Coastguard Worker                 'versionCode=\'1001\'\nversionName=\'1.0.1001-A\'\n'
569*d68f33bcSAndroid Build Coastguard Worker                 'platformBuildVersionName=\'\'\ncompileSdkVersion=\'28\'\n'
570*d68f33bcSAndroid Build Coastguard Worker                 'compileSdkVersionCodename=\'9\'\nsdkVersion:\'16\'\n'
571*d68f33bcSAndroid Build Coastguard Worker                 'targetSdkVersion:\'28\'\n\nBuilt here:\n'
572*d68f33bcSAndroid Build Coastguard Worker                 'http://foo.bar.com/builder\n\n'
573*d68f33bcSAndroid Build Coastguard Worker                 'This build IS suitable for public release.\n\n'
574*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 123\nTest: test\nChange-Id: XXXXXXX\n'),
575*d68f33bcSAndroid Build Coastguard Worker                # Missing 'sdkVersion'.
576*d68f33bcSAndroid Build Coastguard Worker                ('Test App\n\nbar.apk\npackage: name=\'com.foo.bar\'\n'
577*d68f33bcSAndroid Build Coastguard Worker                 'versionCode=\'1001\'\nversionName=\'1.0.1001-A\'\n'
578*d68f33bcSAndroid Build Coastguard Worker                 'platformBuildVersionName=\'\'\ncompileSdkVersion=\'28\'\n'
579*d68f33bcSAndroid Build Coastguard Worker                 'compileSdkVersionCodename=\'9\'\n'
580*d68f33bcSAndroid Build Coastguard Worker                 'targetSdkVersion:\'28\'\n\nBuilt here:\n'
581*d68f33bcSAndroid Build Coastguard Worker                 'http://foo.bar.com/builder\n\n'
582*d68f33bcSAndroid Build Coastguard Worker                 'This build IS suitable for public release.\n\n'
583*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 123\nTest: test\nChange-Id: XXXXXXX\n'),
584*d68f33bcSAndroid Build Coastguard Worker                # Missing 'targetSdkVersion'.
585*d68f33bcSAndroid Build Coastguard Worker                ('Test App\n\nbar.apk\npackage: name=\'com.foo.bar\'\n'
586*d68f33bcSAndroid Build Coastguard Worker                 'versionCode=\'1001\'\nversionName=\'1.0.1001-A\'\n'
587*d68f33bcSAndroid Build Coastguard Worker                 'platformBuildVersionName=\'\'\ncompileSdkVersion=\'28\'\n'
588*d68f33bcSAndroid Build Coastguard Worker                 'compileSdkVersionCodename=\'9\'\nsdkVersion:\'16\'\n'
589*d68f33bcSAndroid Build Coastguard Worker                 'Built here:\nhttp://foo.bar.com/builder\n\n'
590*d68f33bcSAndroid Build Coastguard Worker                 'This build IS suitable for public release.\n\n'
591*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 123\nTest: test\nChange-Id: XXXXXXX\n'),
592*d68f33bcSAndroid Build Coastguard Worker                # Missing build location.
593*d68f33bcSAndroid Build Coastguard Worker                ('Test App\n\nbar.apk\npackage: name=\'com.foo.bar\'\n'
594*d68f33bcSAndroid Build Coastguard Worker                 'versionCode=\'1001\'\nversionName=\'1.0.1001-A\'\n'
595*d68f33bcSAndroid Build Coastguard Worker                 'platformBuildVersionName=\'\'\ncompileSdkVersion=\'28\'\n'
596*d68f33bcSAndroid Build Coastguard Worker                 'compileSdkVersionCodename=\'9\'\nsdkVersion:\'16\'\n'
597*d68f33bcSAndroid Build Coastguard Worker                 'targetSdkVersion:\'28\'\n\n'
598*d68f33bcSAndroid Build Coastguard Worker                 'This build IS suitable for public release.\n\n'
599*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 123\nTest: test\nChange-Id: XXXXXXX\n'),
600*d68f33bcSAndroid Build Coastguard Worker                # Missing public release indication.
601*d68f33bcSAndroid Build Coastguard Worker                ('Test App\n\nbar.apk\npackage: name=\'com.foo.bar\'\n'
602*d68f33bcSAndroid Build Coastguard Worker                 'versionCode=\'1001\'\nversionName=\'1.0.1001-A\'\n'
603*d68f33bcSAndroid Build Coastguard Worker                 'platformBuildVersionName=\'\'\ncompileSdkVersion=\'28\'\n'
604*d68f33bcSAndroid Build Coastguard Worker                 'compileSdkVersionCodename=\'9\'\nsdkVersion:\'16\'\n'
605*d68f33bcSAndroid Build Coastguard Worker                 'targetSdkVersion:\'28\'\n\nBuilt here:\n'
606*d68f33bcSAndroid Build Coastguard Worker                 'http://foo.bar.com/builder\n\n'
607*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 123\nTest: test\nChange-Id: XXXXXXX\n'),
608*d68f33bcSAndroid Build Coastguard Worker            ),
609*d68f33bcSAndroid Build Coastguard Worker            ['foo.apk', 'bar.py',]
610*d68f33bcSAndroid Build Coastguard Worker        )
611*d68f33bcSAndroid Build Coastguard Worker
612*d68f33bcSAndroid Build Coastguard Worker    def test_commit_msg_test_field(self, _mock_check, _mock_run):
613*d68f33bcSAndroid Build Coastguard Worker        """Verify the commit_msg_test_field builtin hook."""
614*d68f33bcSAndroid Build Coastguard Worker        # Check some good messages.
615*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
616*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_test_field, True, (
617*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nTest: i did done dood it\n',
618*d68f33bcSAndroid Build Coastguard Worker            ))
619*d68f33bcSAndroid Build Coastguard Worker
620*d68f33bcSAndroid Build Coastguard Worker        # Check some bad messages.
621*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
622*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_test_field, False, (
623*d68f33bcSAndroid Build Coastguard Worker                'subj',
624*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nTEST=1234\n',
625*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nTEST: I1234\n',
626*d68f33bcSAndroid Build Coastguard Worker            ))
627*d68f33bcSAndroid Build Coastguard Worker
628*d68f33bcSAndroid Build Coastguard Worker    def test_commit_msg_relnote_field_format(self, _mock_check, _mock_run):
629*d68f33bcSAndroid Build Coastguard Worker        """Verify the commit_msg_relnote_field_format builtin hook."""
630*d68f33bcSAndroid Build Coastguard Worker        # Check some good messages.
631*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
632*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_relnote_field_format,
633*d68f33bcSAndroid Build Coastguard Worker            True,
634*d68f33bcSAndroid Build Coastguard Worker            (
635*d68f33bcSAndroid Build Coastguard Worker                'subj',
636*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nTest: i did done dood it\nBug: 1234',
637*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nMore content\n\nTest: i did done dood it\nBug: 1234',
638*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note\nBug: 1234',
639*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote:This is a release note\nBug: 1234',
640*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note.\nBug: 1234',
641*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: "This is a release note."\nBug: 1234',
642*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: "This is a \\"release note\\"."\n\nBug: 1234',
643*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note.\nChange-Id: 1234',
644*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note.\n\nChange-Id: 1234',
645*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is a release note."\n\n'
646*d68f33bcSAndroid Build Coastguard Worker                 'Change-Id: 1234'),
647*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: This is a release note.\n\n'
648*d68f33bcSAndroid Build Coastguard Worker                 'It has more info, but it is not part of the release note'
649*d68f33bcSAndroid Build Coastguard Worker                 '\nChange-Id: 1234'),
650*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is a release note.\n'
651*d68f33bcSAndroid Build Coastguard Worker                 'It contains a correct second line."'),
652*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote:"This is a release note.\n'
653*d68f33bcSAndroid Build Coastguard Worker                 'It contains a correct second line."'),
654*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is a release note.\n'
655*d68f33bcSAndroid Build Coastguard Worker                 'It contains a correct second line.\n'
656*d68f33bcSAndroid Build Coastguard Worker                 'And even a third line."\n'
657*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
658*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is a release note.\n'
659*d68f33bcSAndroid Build Coastguard Worker                 'It contains a correct second line.\n'
660*d68f33bcSAndroid Build Coastguard Worker                 '\\"Quotes\\" are even used on the third line."\n'
661*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
662*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: This is release note 1.\n'
663*d68f33bcSAndroid Build Coastguard Worker                 'Relnote: This is release note 2.\n'
664*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
665*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: This is release note 1.\n'
666*d68f33bcSAndroid Build Coastguard Worker                 'Relnote: "This is release note 2, and it\n'
667*d68f33bcSAndroid Build Coastguard Worker                 'contains a correctly formatted third line."\n'
668*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
669*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is release note 1 with\n'
670*d68f33bcSAndroid Build Coastguard Worker                 'a correctly formatted second line."\n\n'
671*d68f33bcSAndroid Build Coastguard Worker                 'Relnote: "This is release note 2, and it\n'
672*d68f33bcSAndroid Build Coastguard Worker                 'contains a correctly formatted second line."\n'
673*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
674*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is a release note with\n'
675*d68f33bcSAndroid Build Coastguard Worker                 'a correctly formatted second line."\n\n'
676*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'
677*d68f33bcSAndroid Build Coastguard Worker                 'Here is some extra "quoted" content.'),
678*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: """This is a release note.\n\n'
679*d68f33bcSAndroid Build Coastguard Worker                 'This relnote contains an empty line.\n'
680*d68f33bcSAndroid Build Coastguard Worker                 'Then a non-empty line.\n\n'
681*d68f33bcSAndroid Build Coastguard Worker                 'And another empty line."""\n\n'
682*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
683*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: """This is a release note.\n\n'
684*d68f33bcSAndroid Build Coastguard Worker                 'This relnote contains an empty line.\n'
685*d68f33bcSAndroid Build Coastguard Worker                 'Then an acceptable "quoted" line.\n\n'
686*d68f33bcSAndroid Build Coastguard Worker                 'And another empty line."""\n\n'
687*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
688*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: """This is a release note."""\n\n'
689*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
690*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: """This is a release note.\n'
691*d68f33bcSAndroid Build Coastguard Worker                 'It has a second line."""\n\n'
692*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
693*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: """This is a release note.\n'
694*d68f33bcSAndroid Build Coastguard Worker                 'It has a second line, but does not end here.\n'
695*d68f33bcSAndroid Build Coastguard Worker                 '"""\n\n'
696*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
697*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: """This is a release note.\n'
698*d68f33bcSAndroid Build Coastguard Worker                 '"It" has a second line, but does not end here.\n'
699*d68f33bcSAndroid Build Coastguard Worker                 '"""\n\n'
700*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
701*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is a release note.\n'
702*d68f33bcSAndroid Build Coastguard Worker                 'It has a second line, but does not end here.\n'
703*d68f33bcSAndroid Build Coastguard Worker                 '"\n\n'
704*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
705*d68f33bcSAndroid Build Coastguard Worker            ))
706*d68f33bcSAndroid Build Coastguard Worker
707*d68f33bcSAndroid Build Coastguard Worker        # Check some bad messages.
708*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
709*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_relnote_field_format,
710*d68f33bcSAndroid Build Coastguard Worker            False,
711*d68f33bcSAndroid Build Coastguard Worker            (
712*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nReleaseNote: This is a release note.\n',
713*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnotes: This is a release note.\n',
714*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRel-note: This is a release note.\n',
715*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nrelnoTes: This is a release note.\n',
716*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nrel-Note: This is a release note.\n',
717*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: "This is a "release note"."\nBug: 1234',
718*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a "release note".\nBug: 1234',
719*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: This is a release note.\n'
720*d68f33bcSAndroid Build Coastguard Worker                 'It contains an incorrect second line.'),
721*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is a release note.\n'
722*d68f33bcSAndroid Build Coastguard Worker                 'It contains multiple lines.\n'
723*d68f33bcSAndroid Build Coastguard Worker                 'But it does not provide an ending quote.\n'),
724*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is a release note.\n'
725*d68f33bcSAndroid Build Coastguard Worker                 'It contains multiple lines but no closing quote.\n'
726*d68f33bcSAndroid Build Coastguard Worker                 'Test: my test "hello world"\n'),
727*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: This is release note 1.\n'
728*d68f33bcSAndroid Build Coastguard Worker                 'Relnote: "This is release note 2, and it\n'
729*d68f33bcSAndroid Build Coastguard Worker                 'contains an incorrectly formatted third line.\n'
730*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
731*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: This is release note 1 with\n'
732*d68f33bcSAndroid Build Coastguard Worker                 'an incorrectly formatted second line.\n\n'
733*d68f33bcSAndroid Build Coastguard Worker                 'Relnote: "This is release note 2, and it\n'
734*d68f33bcSAndroid Build Coastguard Worker                 'contains a correctly formatted second line."\n'
735*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
736*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is release note 1 with\n'
737*d68f33bcSAndroid Build Coastguard Worker                 'a correctly formatted second line."\n\n'
738*d68f33bcSAndroid Build Coastguard Worker                 'Relnote: This is release note 2, and it\n'
739*d68f33bcSAndroid Build Coastguard Worker                 'contains an incorrectly formatted second line.\n'
740*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
741*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is a release note.\n'
742*d68f33bcSAndroid Build Coastguard Worker                 'It contains a correct second line.\n'
743*d68f33bcSAndroid Build Coastguard Worker                 'But incorrect "quotes" on the third line."\n'
744*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
745*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: """This is a release note.\n'
746*d68f33bcSAndroid Build Coastguard Worker                 'It has a second line, but no closing triple quote.\n\n'
747*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
748*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: "This is a release note.\n'
749*d68f33bcSAndroid Build Coastguard Worker                 '"It" has a second line, but does not end here.\n'
750*d68f33bcSAndroid Build Coastguard Worker                 '"\n\n'
751*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
752*d68f33bcSAndroid Build Coastguard Worker            ))
753*d68f33bcSAndroid Build Coastguard Worker
754*d68f33bcSAndroid Build Coastguard Worker    def test_commit_msg_relnote_for_current_txt(self, _mock_check, _mock_run):
755*d68f33bcSAndroid Build Coastguard Worker        """Verify the commit_msg_relnote_for_current_txt builtin hook."""
756*d68f33bcSAndroid Build Coastguard Worker        diff_without_current_txt = ['bar/foo.txt',
757*d68f33bcSAndroid Build Coastguard Worker                                    'foo.cpp',
758*d68f33bcSAndroid Build Coastguard Worker                                    'foo.java',
759*d68f33bcSAndroid Build Coastguard Worker                                    'foo_current.java',
760*d68f33bcSAndroid Build Coastguard Worker                                    'foo_current.txt',
761*d68f33bcSAndroid Build Coastguard Worker                                    'baz/current.java',
762*d68f33bcSAndroid Build Coastguard Worker                                    'baz/foo_current.txt']
763*d68f33bcSAndroid Build Coastguard Worker        diff_with_current_txt = diff_without_current_txt + ['current.txt']
764*d68f33bcSAndroid Build Coastguard Worker        diff_with_subdir_current_txt = \
765*d68f33bcSAndroid Build Coastguard Worker            diff_without_current_txt + ['foo/current.txt']
766*d68f33bcSAndroid Build Coastguard Worker        diff_with_experimental_current_txt = \
767*d68f33bcSAndroid Build Coastguard Worker            diff_without_current_txt + ['public_plus_experimental_current.txt']
768*d68f33bcSAndroid Build Coastguard Worker        # Check some good messages.
769*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
770*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_relnote_for_current_txt,
771*d68f33bcSAndroid Build Coastguard Worker            True,
772*d68f33bcSAndroid Build Coastguard Worker            (
773*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note\n',
774*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note.\n\nChange-Id: 1234',
775*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: This is release note 1 with\n'
776*d68f33bcSAndroid Build Coastguard Worker                 'an incorrectly formatted second line.\n\n'
777*d68f33bcSAndroid Build Coastguard Worker                 'Relnote: "This is release note 2, and it\n'
778*d68f33bcSAndroid Build Coastguard Worker                 'contains a correctly formatted second line."\n'
779*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
780*d68f33bcSAndroid Build Coastguard Worker            ),
781*d68f33bcSAndroid Build Coastguard Worker            files=diff_with_current_txt,
782*d68f33bcSAndroid Build Coastguard Worker        )
783*d68f33bcSAndroid Build Coastguard Worker        # Check some good messages.
784*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
785*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_relnote_for_current_txt,
786*d68f33bcSAndroid Build Coastguard Worker            True,
787*d68f33bcSAndroid Build Coastguard Worker            (
788*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note\n',
789*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note.\n\nChange-Id: 1234',
790*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: This is release note 1 with\n'
791*d68f33bcSAndroid Build Coastguard Worker                 'an incorrectly formatted second line.\n\n'
792*d68f33bcSAndroid Build Coastguard Worker                 'Relnote: "This is release note 2, and it\n'
793*d68f33bcSAndroid Build Coastguard Worker                 'contains a correctly formatted second line."\n'
794*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
795*d68f33bcSAndroid Build Coastguard Worker            ),
796*d68f33bcSAndroid Build Coastguard Worker            files=diff_with_experimental_current_txt,
797*d68f33bcSAndroid Build Coastguard Worker        )
798*d68f33bcSAndroid Build Coastguard Worker        # Check some good messages.
799*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
800*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_relnote_for_current_txt,
801*d68f33bcSAndroid Build Coastguard Worker            True,
802*d68f33bcSAndroid Build Coastguard Worker            (
803*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note\n',
804*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note.\n\nChange-Id: 1234',
805*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: This is release note 1 with\n'
806*d68f33bcSAndroid Build Coastguard Worker                 'an incorrectly formatted second line.\n\n'
807*d68f33bcSAndroid Build Coastguard Worker                 'Relnote: "This is release note 2, and it\n'
808*d68f33bcSAndroid Build Coastguard Worker                 'contains a correctly formatted second line."\n'
809*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
810*d68f33bcSAndroid Build Coastguard Worker            ),
811*d68f33bcSAndroid Build Coastguard Worker            files=diff_with_subdir_current_txt,
812*d68f33bcSAndroid Build Coastguard Worker        )
813*d68f33bcSAndroid Build Coastguard Worker        # Check some good messages.
814*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
815*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_relnote_for_current_txt,
816*d68f33bcSAndroid Build Coastguard Worker            True,
817*d68f33bcSAndroid Build Coastguard Worker            (
818*d68f33bcSAndroid Build Coastguard Worker                'subj',
819*d68f33bcSAndroid Build Coastguard Worker                'subj\nBug: 12345\nChange-Id: 1234',
820*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note\n',
821*d68f33bcSAndroid Build Coastguard Worker                'subj\n\nRelnote: This is a release note.\n\nChange-Id: 1234',
822*d68f33bcSAndroid Build Coastguard Worker                ('subj\n\nRelnote: This is release note 1 with\n'
823*d68f33bcSAndroid Build Coastguard Worker                 'an incorrectly formatted second line.\n\n'
824*d68f33bcSAndroid Build Coastguard Worker                 'Relnote: "This is release note 2, and it\n'
825*d68f33bcSAndroid Build Coastguard Worker                 'contains a correctly formatted second line."\n'
826*d68f33bcSAndroid Build Coastguard Worker                 'Bug: 1234'),
827*d68f33bcSAndroid Build Coastguard Worker            ),
828*d68f33bcSAndroid Build Coastguard Worker            files=diff_without_current_txt,
829*d68f33bcSAndroid Build Coastguard Worker        )
830*d68f33bcSAndroid Build Coastguard Worker        # Check some bad messages.
831*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
832*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_relnote_for_current_txt,
833*d68f33bcSAndroid Build Coastguard Worker            False,
834*d68f33bcSAndroid Build Coastguard Worker            (
835*d68f33bcSAndroid Build Coastguard Worker                'subj'
836*d68f33bcSAndroid Build Coastguard Worker                'subj\nBug: 12345\nChange-Id: 1234',
837*d68f33bcSAndroid Build Coastguard Worker            ),
838*d68f33bcSAndroid Build Coastguard Worker            files=diff_with_current_txt,
839*d68f33bcSAndroid Build Coastguard Worker        )
840*d68f33bcSAndroid Build Coastguard Worker        # Check some bad messages.
841*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
842*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_relnote_for_current_txt,
843*d68f33bcSAndroid Build Coastguard Worker            False,
844*d68f33bcSAndroid Build Coastguard Worker            (
845*d68f33bcSAndroid Build Coastguard Worker                'subj'
846*d68f33bcSAndroid Build Coastguard Worker                'subj\nBug: 12345\nChange-Id: 1234',
847*d68f33bcSAndroid Build Coastguard Worker            ),
848*d68f33bcSAndroid Build Coastguard Worker            files=diff_with_experimental_current_txt,
849*d68f33bcSAndroid Build Coastguard Worker        )
850*d68f33bcSAndroid Build Coastguard Worker        # Check some bad messages.
851*d68f33bcSAndroid Build Coastguard Worker        self._test_commit_messages(
852*d68f33bcSAndroid Build Coastguard Worker            rh.hooks.check_commit_msg_relnote_for_current_txt,
853*d68f33bcSAndroid Build Coastguard Worker            False,
854*d68f33bcSAndroid Build Coastguard Worker            (
855*d68f33bcSAndroid Build Coastguard Worker                'subj'
856*d68f33bcSAndroid Build Coastguard Worker                'subj\nBug: 12345\nChange-Id: 1234',
857*d68f33bcSAndroid Build Coastguard Worker            ),
858*d68f33bcSAndroid Build Coastguard Worker            files=diff_with_subdir_current_txt,
859*d68f33bcSAndroid Build Coastguard Worker        )
860*d68f33bcSAndroid Build Coastguard Worker
861*d68f33bcSAndroid Build Coastguard Worker    def test_cpplint(self, mock_check, _mock_run):
862*d68f33bcSAndroid Build Coastguard Worker        """Verify the cpplint builtin hook."""
863*d68f33bcSAndroid Build Coastguard Worker        self._test_file_filter(mock_check, rh.hooks.check_cpplint,
864*d68f33bcSAndroid Build Coastguard Worker                               ('foo.cpp', 'foo.cxx'))
865*d68f33bcSAndroid Build Coastguard Worker
866*d68f33bcSAndroid Build Coastguard Worker    def test_gofmt(self, mock_check, _mock_run):
867*d68f33bcSAndroid Build Coastguard Worker        """Verify the gofmt builtin hook."""
868*d68f33bcSAndroid Build Coastguard Worker        # First call should do nothing as there are no files to check.
869*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_gofmt(
870*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', (), options=self.options)
871*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNone(ret)
872*d68f33bcSAndroid Build Coastguard Worker        self.assertFalse(mock_check.called)
873*d68f33bcSAndroid Build Coastguard Worker
874*d68f33bcSAndroid Build Coastguard Worker        # Second call will have some results.
875*d68f33bcSAndroid Build Coastguard Worker        diff = [rh.git.RawDiffEntry(file='foo.go')]
876*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_gofmt(
877*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff, options=self.options)
878*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNotNone(ret)
879*d68f33bcSAndroid Build Coastguard Worker
880*d68f33bcSAndroid Build Coastguard Worker    def test_jsonlint(self, mock_check, _mock_run):
881*d68f33bcSAndroid Build Coastguard Worker        """Verify the jsonlint builtin hook."""
882*d68f33bcSAndroid Build Coastguard Worker        # First call should do nothing as there are no files to check.
883*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_json(
884*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', (), options=self.options)
885*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNone(ret)
886*d68f33bcSAndroid Build Coastguard Worker        self.assertFalse(mock_check.called)
887*d68f33bcSAndroid Build Coastguard Worker
888*d68f33bcSAndroid Build Coastguard Worker        # TODO: Actually pass some valid/invalid json data down.
889*d68f33bcSAndroid Build Coastguard Worker
890*d68f33bcSAndroid Build Coastguard Worker    def test_ktfmt(self, mock_check, _mock_run):
891*d68f33bcSAndroid Build Coastguard Worker        """Verify the ktfmt builtin hook."""
892*d68f33bcSAndroid Build Coastguard Worker        # First call should do nothing as there are no files to check.
893*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_ktfmt(
894*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', (), options=self.options)
895*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNone(ret)
896*d68f33bcSAndroid Build Coastguard Worker        self.assertFalse(mock_check.called)
897*d68f33bcSAndroid Build Coastguard Worker        # Check that .kt files are included by default.
898*d68f33bcSAndroid Build Coastguard Worker        diff = [rh.git.RawDiffEntry(file='foo.kt'),
899*d68f33bcSAndroid Build Coastguard Worker                rh.git.RawDiffEntry(file='bar.java'),
900*d68f33bcSAndroid Build Coastguard Worker                rh.git.RawDiffEntry(file='baz/blah.kt')]
901*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_ktfmt(
902*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff, options=self.options)
903*d68f33bcSAndroid Build Coastguard Worker        self.assertListEqual(ret[0].files, ['foo.kt', 'baz/blah.kt'])
904*d68f33bcSAndroid Build Coastguard Worker        diff = [rh.git.RawDiffEntry(file='foo/f1.kt'),
905*d68f33bcSAndroid Build Coastguard Worker                rh.git.RawDiffEntry(file='bar/f2.kt'),
906*d68f33bcSAndroid Build Coastguard Worker                rh.git.RawDiffEntry(file='baz/f2.kt')]
907*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_ktfmt(self.project, 'commit', 'desc', diff,
908*d68f33bcSAndroid Build Coastguard Worker                                   options=rh.hooks.HookOptions('hook name', [
909*d68f33bcSAndroid Build Coastguard Worker                                       '--include-dirs=foo,baz'], {}))
910*d68f33bcSAndroid Build Coastguard Worker        self.assertListEqual(ret[0].files, ['foo/f1.kt', 'baz/f2.kt'])
911*d68f33bcSAndroid Build Coastguard Worker
912*d68f33bcSAndroid Build Coastguard Worker    def test_pylint(self, mock_check, _mock_run):
913*d68f33bcSAndroid Build Coastguard Worker        """Verify the pylint builtin hook."""
914*d68f33bcSAndroid Build Coastguard Worker        self._test_file_filter(mock_check, rh.hooks.check_pylint2,
915*d68f33bcSAndroid Build Coastguard Worker                               ('foo.py',))
916*d68f33bcSAndroid Build Coastguard Worker
917*d68f33bcSAndroid Build Coastguard Worker    def test_pylint2(self, mock_check, _mock_run):
918*d68f33bcSAndroid Build Coastguard Worker        """Verify the pylint2 builtin hook."""
919*d68f33bcSAndroid Build Coastguard Worker        self._test_file_filter(mock_check, rh.hooks.check_pylint2,
920*d68f33bcSAndroid Build Coastguard Worker                               ('foo.py',))
921*d68f33bcSAndroid Build Coastguard Worker
922*d68f33bcSAndroid Build Coastguard Worker    def test_pylint3(self, mock_check, _mock_run):
923*d68f33bcSAndroid Build Coastguard Worker        """Verify the pylint3 builtin hook."""
924*d68f33bcSAndroid Build Coastguard Worker        self._test_file_filter(mock_check, rh.hooks.check_pylint3,
925*d68f33bcSAndroid Build Coastguard Worker                               ('foo.py',))
926*d68f33bcSAndroid Build Coastguard Worker
927*d68f33bcSAndroid Build Coastguard Worker    def test_rustfmt(self, mock_check, _mock_run):
928*d68f33bcSAndroid Build Coastguard Worker        # First call should do nothing as there are no files to check.
929*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_rustfmt(
930*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', (), options=self.options)
931*d68f33bcSAndroid Build Coastguard Worker        self.assertEqual(ret, None)
932*d68f33bcSAndroid Build Coastguard Worker        self.assertFalse(mock_check.called)
933*d68f33bcSAndroid Build Coastguard Worker
934*d68f33bcSAndroid Build Coastguard Worker        # Second call will have some results.
935*d68f33bcSAndroid Build Coastguard Worker        diff = [rh.git.RawDiffEntry(file='lib.rs')]
936*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_rustfmt(
937*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff, options=self.options)
938*d68f33bcSAndroid Build Coastguard Worker        self.assertNotEqual(ret, None)
939*d68f33bcSAndroid Build Coastguard Worker
940*d68f33bcSAndroid Build Coastguard Worker    def test_xmllint(self, mock_check, _mock_run):
941*d68f33bcSAndroid Build Coastguard Worker        """Verify the xmllint builtin hook."""
942*d68f33bcSAndroid Build Coastguard Worker        self._test_file_filter(mock_check, rh.hooks.check_xmllint,
943*d68f33bcSAndroid Build Coastguard Worker                               ('foo.xml',))
944*d68f33bcSAndroid Build Coastguard Worker
945*d68f33bcSAndroid Build Coastguard Worker    def test_android_test_mapping_format(self, mock_check, _mock_run):
946*d68f33bcSAndroid Build Coastguard Worker        """Verify the android_test_mapping_format builtin hook."""
947*d68f33bcSAndroid Build Coastguard Worker        # First call should do nothing as there are no files to check.
948*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_android_test_mapping(
949*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', (), options=self.options)
950*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNone(ret)
951*d68f33bcSAndroid Build Coastguard Worker        self.assertFalse(mock_check.called)
952*d68f33bcSAndroid Build Coastguard Worker
953*d68f33bcSAndroid Build Coastguard Worker        # Second call will have some results.
954*d68f33bcSAndroid Build Coastguard Worker        diff = [rh.git.RawDiffEntry(file='TEST_MAPPING')]
955*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_android_test_mapping(
956*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff, options=self.options)
957*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNotNone(ret)
958*d68f33bcSAndroid Build Coastguard Worker
959*d68f33bcSAndroid Build Coastguard Worker    def test_aidl_format(self, mock_check, _mock_run):
960*d68f33bcSAndroid Build Coastguard Worker        """Verify the aidl_format builtin hook."""
961*d68f33bcSAndroid Build Coastguard Worker        # First call should do nothing as there are no files to check.
962*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_aidl_format(
963*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', (), options=self.options)
964*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNone(ret)
965*d68f33bcSAndroid Build Coastguard Worker        self.assertFalse(mock_check.called)
966*d68f33bcSAndroid Build Coastguard Worker
967*d68f33bcSAndroid Build Coastguard Worker        # Second call will have some results.
968*d68f33bcSAndroid Build Coastguard Worker        diff = [rh.git.RawDiffEntry(file='IFoo.go')]
969*d68f33bcSAndroid Build Coastguard Worker        ret = rh.hooks.check_gofmt(
970*d68f33bcSAndroid Build Coastguard Worker            self.project, 'commit', 'desc', diff, options=self.options)
971*d68f33bcSAndroid Build Coastguard Worker        self.assertIsNotNone(ret)
972*d68f33bcSAndroid Build Coastguard Worker
973*d68f33bcSAndroid Build Coastguard Worker
974*d68f33bcSAndroid Build Coastguard Workerif __name__ == '__main__':
975*d68f33bcSAndroid Build Coastguard Worker    unittest.main()
976