aboutsummaryrefslogtreecommitdiff
path: root/rh/hooks_unittest.py
diff options
context:
space:
mode:
Diffstat (limited to 'rh/hooks_unittest.py')
-rwxr-xr-xrh/hooks_unittest.py254
1 files changed, 235 insertions, 19 deletions
diff --git a/rh/hooks_unittest.py b/rh/hooks_unittest.py
index 9b48119..8466319 100755
--- a/rh/hooks_unittest.py
+++ b/rh/hooks_unittest.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding:utf-8 -*-
# Copyright 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +15,10 @@
"""Unittests for the hooks module."""
-from __future__ import print_function
-
import os
import sys
import unittest
+from unittest import mock
_path = os.path.realpath(__file__ + '/../..')
if sys.path[0] != _path:
@@ -33,8 +31,6 @@ del _path
import rh
import rh.config
import rh.hooks
-from rh.sixish import mock
-from rh.sixish import string_types
class HooksDocsTests(unittest.TestCase):
@@ -97,7 +93,9 @@ class PlaceholderTests(unittest.TestCase):
'PREUPLOAD_COMMIT_MESSAGE': 'commit message',
'PREUPLOAD_COMMIT': '5c4c293174bb61f0f39035a71acd9084abfa743d',
})
- self.replacer = rh.hooks.Placeholders()
+ self.replacer = rh.hooks.Placeholders(
+ [rh.git.RawDiffEntry(file=x)
+ for x in ['path1/file1', 'path2/file2']])
def tearDown(self):
os.environ.clear()
@@ -117,9 +115,13 @@ class PlaceholderTests(unittest.TestCase):
# We also make sure that things in ${REPO_ROOT} are not double
# expanded (which is why the return includes ${BUILD_OS}).
'${REPO_ROOT}/some/prog/REPO_ROOT/ok',
- # Verify lists are merged rather than inserted. In this case, the
- # list is empty, but we'd hit an error still if we saw [] in args.
+ # Verify lists are merged rather than inserted.
'${PREUPLOAD_FILES}',
+ # Verify each file is preceded with '--file=' prefix.
+ '--file=${PREUPLOAD_FILES_PREFIXED}',
+ # Verify each file is preceded with '--file' argument.
+ '--file',
+ '${PREUPLOAD_FILES_PREFIXED}',
# Verify values with whitespace don't expand into multiple args.
'${PREUPLOAD_COMMIT_MESSAGE}',
# Verify multiple values get replaced.
@@ -130,6 +132,14 @@ class PlaceholderTests(unittest.TestCase):
output_args = self.replacer.expand_vars(input_args)
exp_args = [
'/ ${BUILD_OS}/some/prog/REPO_ROOT/ok',
+ 'path1/file1',
+ 'path2/file2',
+ '--file=path1/file1',
+ '--file=path2/file2',
+ '--file',
+ 'path1/file1',
+ '--file',
+ 'path2/file2',
'commit message',
'5c4c293174bb61f0f39035a71acd9084abfa743d^commit message',
'${THIS_VAR_IS_GOOD}',
@@ -154,7 +164,8 @@ class PlaceholderTests(unittest.TestCase):
def testPREUPLOAD_FILES(self):
"""Verify handling of PREUPLOAD_FILES."""
- self.assertEqual(self.replacer.get('PREUPLOAD_FILES'), [])
+ self.assertEqual(self.replacer.get('PREUPLOAD_FILES'),
+ ['path1/file1', 'path2/file2'])
@mock.patch.object(rh.git, 'find_repo_root', return_value='/repo!')
def testREPO_ROOT(self, m):
@@ -167,6 +178,28 @@ class PlaceholderTests(unittest.TestCase):
self.assertEqual(self.replacer.get('BUILD_OS'), m.return_value)
+class ExclusionScopeTests(unittest.TestCase):
+ """Verify behavior of ExclusionScope class."""
+
+ def testEmpty(self):
+ """Verify the in operator for an empty scope."""
+ scope = rh.hooks.ExclusionScope([])
+ self.assertNotIn('external/*', scope)
+
+ def testGlob(self):
+ """Verify the in operator for a scope using wildcards."""
+ scope = rh.hooks.ExclusionScope(['vendor/*', 'external/*'])
+ self.assertIn('external/tools', scope)
+
+ def testRegex(self):
+ """Verify the in operator for a scope using regular expressions."""
+ scope = rh.hooks.ExclusionScope(['^vendor/(?!google)',
+ 'external/*'])
+ self.assertIn('vendor/', scope)
+ self.assertNotIn('vendor/google/', scope)
+ self.assertIn('vendor/other/', scope)
+
+
class HookOptionsTests(unittest.TestCase):
"""Verify behavior of HookOptions object."""
@@ -224,14 +257,14 @@ class UtilsTests(unittest.TestCase):
# Just verify it returns something and doesn't crash.
# pylint: disable=protected-access
ret = rh.hooks._get_build_os_name()
- self.assertTrue(isinstance(ret, string_types))
+ self.assertTrue(isinstance(ret, str))
self.assertNotEqual(ret, '')
def testGetHelperPath(self):
"""Check get_helper_path behavior."""
# Just verify it doesn't crash. It's a dirt simple func.
ret = rh.hooks.get_helper_path('booga')
- self.assertTrue(isinstance(ret, string_types))
+ self.assertTrue(isinstance(ret, str))
self.assertNotEqual(ret, '')
@@ -278,7 +311,7 @@ class BuiltinHooksTests(unittest.TestCase):
"""
# First call should do nothing as there are no files to check.
ret = func(self.project, 'commit', 'desc', (), options=self.options)
- self.assertEqual(ret, None)
+ self.assertIsNone(ret)
self.assertFalse(mock_check.called)
# Second call should include some checks.
@@ -489,12 +522,13 @@ class BuiltinHooksTests(unittest.TestCase):
True,
(
'subj',
- 'subj\n\nTest: i did done dood it\n',
- 'subj\n\nMore content\n\nTest: i did done dood it\n',
- 'subj\n\nRelnote: This is a release note\n',
- 'subj\n\nRelnote:This is a release note\n',
+ 'subj\n\nTest: i did done dood it\nBug: 1234',
+ 'subj\n\nMore content\n\nTest: i did done dood it\nBug: 1234',
+ 'subj\n\nRelnote: This is a release note\nBug: 1234',
+ 'subj\n\nRelnote:This is a release note\nBug: 1234',
'subj\n\nRelnote: This is a release note.\nBug: 1234',
'subj\n\nRelnote: "This is a release note."\nBug: 1234',
+ 'subj\n\nRelnote: "This is a \\"release note\\"."\n\nBug: 1234',
'subj\n\nRelnote: This is a release note.\nChange-Id: 1234',
'subj\n\nRelnote: This is a release note.\n\nChange-Id: 1234',
('subj\n\nRelnote: "This is a release note."\n\n'
@@ -510,6 +544,10 @@ class BuiltinHooksTests(unittest.TestCase):
'It contains a correct second line.\n'
'And even a third line."\n'
'Bug: 1234'),
+ ('subj\n\nRelnote: "This is a release note.\n'
+ 'It contains a correct second line.\n'
+ '\\"Quotes\\" are even used on the third line."\n'
+ 'Bug: 1234'),
('subj\n\nRelnote: This is release note 1.\n'
'Relnote: This is release note 2.\n'
'Bug: 1234'),
@@ -522,6 +560,37 @@ class BuiltinHooksTests(unittest.TestCase):
'Relnote: "This is release note 2, and it\n'
'contains a correctly formatted second line."\n'
'Bug: 1234'),
+ ('subj\n\nRelnote: "This is a release note with\n'
+ 'a correctly formatted second line."\n\n'
+ 'Bug: 1234'
+ 'Here is some extra "quoted" content.'),
+ ('subj\n\nRelnote: """This is a release note.\n\n'
+ 'This relnote contains an empty line.\n'
+ 'Then a non-empty line.\n\n'
+ 'And another empty line."""\n\n'
+ 'Bug: 1234'),
+ ('subj\n\nRelnote: """This is a release note.\n\n'
+ 'This relnote contains an empty line.\n'
+ 'Then an acceptable "quoted" line.\n\n'
+ 'And another empty line."""\n\n'
+ 'Bug: 1234'),
+ ('subj\n\nRelnote: """This is a release note."""\n\n'
+ 'Bug: 1234'),
+ ('subj\n\nRelnote: """This is a release note.\n'
+ 'It has a second line."""\n\n'
+ 'Bug: 1234'),
+ ('subj\n\nRelnote: """This is a release note.\n'
+ 'It has a second line, but does not end here.\n'
+ '"""\n\n'
+ 'Bug: 1234'),
+ ('subj\n\nRelnote: """This is a release note.\n'
+ '"It" has a second line, but does not end here.\n'
+ '"""\n\n'
+ 'Bug: 1234'),
+ ('subj\n\nRelnote: "This is a release note.\n'
+ 'It has a second line, but does not end here.\n'
+ '"\n\n'
+ 'Bug: 1234'),
))
# Check some bad messages.
@@ -534,6 +603,8 @@ class BuiltinHooksTests(unittest.TestCase):
'subj\n\nRel-note: This is a release note.\n',
'subj\n\nrelnoTes: This is a release note.\n',
'subj\n\nrel-Note: This is a release note.\n',
+ 'subj\n\nRelnote: "This is a "release note"."\nBug: 1234',
+ 'subj\n\nRelnote: This is a "release note".\nBug: 1234',
('subj\n\nRelnote: This is a release note.\n'
'It contains an incorrect second line.'),
('subj\n\nRelnote: "This is a release note.\n'
@@ -556,8 +627,126 @@ class BuiltinHooksTests(unittest.TestCase):
'Relnote: This is release note 2, and it\n'
'contains an incorrectly formatted second line.\n'
'Bug: 1234'),
+ ('subj\n\nRelnote: "This is a release note.\n'
+ 'It contains a correct second line.\n'
+ 'But incorrect "quotes" on the third line."\n'
+ 'Bug: 1234'),
+ ('subj\n\nRelnote: """This is a release note.\n'
+ 'It has a second line, but no closing triple quote.\n\n'
+ 'Bug: 1234'),
+ ('subj\n\nRelnote: "This is a release note.\n'
+ '"It" has a second line, but does not end here.\n'
+ '"\n\n'
+ 'Bug: 1234'),
))
+ def test_commit_msg_relnote_for_current_txt(self, _mock_check, _mock_run):
+ """Verify the commit_msg_relnote_for_current_txt builtin hook."""
+ diff_without_current_txt = ['bar/foo.txt',
+ 'foo.cpp',
+ 'foo.java',
+ 'foo_current.java',
+ 'foo_current.txt',
+ 'baz/current.java',
+ 'baz/foo_current.txt']
+ diff_with_current_txt = diff_without_current_txt + ['current.txt']
+ diff_with_subdir_current_txt = \
+ diff_without_current_txt + ['foo/current.txt']
+ diff_with_experimental_current_txt = \
+ diff_without_current_txt + ['public_plus_experimental_current.txt']
+ # Check some good messages.
+ self._test_commit_messages(
+ rh.hooks.check_commit_msg_relnote_for_current_txt,
+ True,
+ (
+ 'subj\n\nRelnote: This is a release note\n',
+ 'subj\n\nRelnote: This is a release note.\n\nChange-Id: 1234',
+ ('subj\n\nRelnote: This is release note 1 with\n'
+ 'an incorrectly formatted second line.\n\n'
+ 'Relnote: "This is release note 2, and it\n'
+ 'contains a correctly formatted second line."\n'
+ 'Bug: 1234'),
+ ),
+ files=diff_with_current_txt,
+ )
+ # Check some good messages.
+ self._test_commit_messages(
+ rh.hooks.check_commit_msg_relnote_for_current_txt,
+ True,
+ (
+ 'subj\n\nRelnote: This is a release note\n',
+ 'subj\n\nRelnote: This is a release note.\n\nChange-Id: 1234',
+ ('subj\n\nRelnote: This is release note 1 with\n'
+ 'an incorrectly formatted second line.\n\n'
+ 'Relnote: "This is release note 2, and it\n'
+ 'contains a correctly formatted second line."\n'
+ 'Bug: 1234'),
+ ),
+ files=diff_with_experimental_current_txt,
+ )
+ # Check some good messages.
+ self._test_commit_messages(
+ rh.hooks.check_commit_msg_relnote_for_current_txt,
+ True,
+ (
+ 'subj\n\nRelnote: This is a release note\n',
+ 'subj\n\nRelnote: This is a release note.\n\nChange-Id: 1234',
+ ('subj\n\nRelnote: This is release note 1 with\n'
+ 'an incorrectly formatted second line.\n\n'
+ 'Relnote: "This is release note 2, and it\n'
+ 'contains a correctly formatted second line."\n'
+ 'Bug: 1234'),
+ ),
+ files=diff_with_subdir_current_txt,
+ )
+ # Check some good messages.
+ self._test_commit_messages(
+ rh.hooks.check_commit_msg_relnote_for_current_txt,
+ True,
+ (
+ 'subj',
+ 'subj\nBug: 12345\nChange-Id: 1234',
+ 'subj\n\nRelnote: This is a release note\n',
+ 'subj\n\nRelnote: This is a release note.\n\nChange-Id: 1234',
+ ('subj\n\nRelnote: This is release note 1 with\n'
+ 'an incorrectly formatted second line.\n\n'
+ 'Relnote: "This is release note 2, and it\n'
+ 'contains a correctly formatted second line."\n'
+ 'Bug: 1234'),
+ ),
+ files=diff_without_current_txt,
+ )
+ # Check some bad messages.
+ self._test_commit_messages(
+ rh.hooks.check_commit_msg_relnote_for_current_txt,
+ False,
+ (
+ 'subj'
+ 'subj\nBug: 12345\nChange-Id: 1234',
+ ),
+ files=diff_with_current_txt,
+ )
+ # Check some bad messages.
+ self._test_commit_messages(
+ rh.hooks.check_commit_msg_relnote_for_current_txt,
+ False,
+ (
+ 'subj'
+ 'subj\nBug: 12345\nChange-Id: 1234',
+ ),
+ files=diff_with_experimental_current_txt,
+ )
+ # Check some bad messages.
+ self._test_commit_messages(
+ rh.hooks.check_commit_msg_relnote_for_current_txt,
+ False,
+ (
+ 'subj'
+ 'subj\nBug: 12345\nChange-Id: 1234',
+ ),
+ files=diff_with_subdir_current_txt,
+ )
+
def test_cpplint(self, mock_check, _mock_run):
"""Verify the cpplint builtin hook."""
self._test_file_filter(mock_check, rh.hooks.check_cpplint,
@@ -568,21 +757,21 @@ class BuiltinHooksTests(unittest.TestCase):
# First call should do nothing as there are no files to check.
ret = rh.hooks.check_gofmt(
self.project, 'commit', 'desc', (), options=self.options)
- self.assertEqual(ret, None)
+ self.assertIsNone(ret)
self.assertFalse(mock_check.called)
# Second call will have some results.
diff = [rh.git.RawDiffEntry(file='foo.go')]
ret = rh.hooks.check_gofmt(
self.project, 'commit', 'desc', diff, options=self.options)
- self.assertNotEqual(ret, None)
+ self.assertIsNotNone(ret)
def test_jsonlint(self, mock_check, _mock_run):
"""Verify the jsonlint builtin hook."""
# First call should do nothing as there are no files to check.
ret = rh.hooks.check_json(
self.project, 'commit', 'desc', (), options=self.options)
- self.assertEqual(ret, None)
+ self.assertIsNone(ret)
self.assertFalse(mock_check.called)
# TODO: Actually pass some valid/invalid json data down.
@@ -602,6 +791,19 @@ class BuiltinHooksTests(unittest.TestCase):
self._test_file_filter(mock_check, rh.hooks.check_pylint3,
('foo.py',))
+ def test_rustfmt(self, mock_check, _mock_run):
+ # First call should do nothing as there are no files to check.
+ ret = rh.hooks.check_rustfmt(
+ self.project, 'commit', 'desc', (), options=self.options)
+ self.assertEqual(ret, None)
+ self.assertFalse(mock_check.called)
+
+ # Second call will have some results.
+ diff = [rh.git.RawDiffEntry(file='lib.rs')]
+ ret = rh.hooks.check_rustfmt(
+ self.project, 'commit', 'desc', diff, options=self.options)
+ self.assertNotEqual(ret, None)
+
def test_xmllint(self, mock_check, _mock_run):
"""Verify the xmllint builtin hook."""
self._test_file_filter(mock_check, rh.hooks.check_xmllint,
@@ -621,6 +823,20 @@ class BuiltinHooksTests(unittest.TestCase):
self.project, 'commit', 'desc', diff, options=self.options)
self.assertIsNotNone(ret)
+ def test_aidl_format(self, mock_check, _mock_run):
+ """Verify the aidl_format builtin hook."""
+ # First call should do nothing as there are no files to check.
+ ret = rh.hooks.check_aidl_format(
+ self.project, 'commit', 'desc', (), options=self.options)
+ self.assertIsNone(ret)
+ self.assertFalse(mock_check.called)
+
+ # Second call will have some results.
+ diff = [rh.git.RawDiffEntry(file='IFoo.go')]
+ ret = rh.hooks.check_gofmt(
+ self.project, 'commit', 'desc', diff, options=self.options)
+ self.assertIsNotNone(ret)
+
if __name__ == '__main__':
unittest.main()