You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
depot_tools/tests/presubmit_support_test.py

329 lines
10 KiB
Python

#!/usr/bin/env python3
# Copyright 2024 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os.path
import sys
import unittest
from unittest import mock
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, ROOT_DIR)
import gclient_utils
import presubmit_support
import subprocess2
from testing_support import fake_repos
class PresubmitSupportTest(unittest.TestCase):
def test_environ(self):
self.assertIsNone(os.environ.get('PRESUBMIT_FOO_ENV', None))
kv = {'PRESUBMIT_FOO_ENV': 'FOOBAR'}
with presubmit_support.setup_environ(kv):
self.assertEqual(os.environ.get('PRESUBMIT_FOO_ENV', None),
'FOOBAR')
self.assertIsNone(os.environ.get('PRESUBMIT_FOO_ENV', None))
class ProvidedDiffChangeFakeRepo(fake_repos.FakeReposBase):
NB_GIT_REPOS = 1
def populateGit(self):
self._commit_git(
'repo_1', {
'to_be_modified': 'please change me\n',
'to_be_deleted': 'delete\nme\n',
'somewhere/else': 'not a top level file!\n',
})
self._commit_git(
'repo_1', {
'to_be_modified': 'changed me!\n',
'to_be_deleted': None,
'somewhere/else': 'still not a top level file!\n',
'added': 'a new file\n',
})
class ProvidedDiffChangeTest(fake_repos.FakeReposTestBase):
FAKE_REPOS_CLASS = ProvidedDiffChangeFakeRepo
def setUp(self):
super(ProvidedDiffChangeTest, self).setUp()
self.enabled = self.FAKE_REPOS.set_up_git()
if not self.enabled:
self.skipTest('git fake repos not available')
self.repo = os.path.join(self.FAKE_REPOS.git_base, 'repo_1')
diff = subprocess2.check_output(['git', 'show'],
cwd=self.repo).decode('utf-8')
self.change = self._create_change(diff)
def _create_change(self, diff):
with gclient_utils.temporary_file() as tmp:
gclient_utils.FileWrite(tmp, diff)
options = mock.Mock(root=self.repo,
all_files=False,
generate_diff=False,
description='description',
files=None,
diff_file=tmp)
change = presubmit_support._parse_change(None, options)
assert isinstance(change, presubmit_support.ProvidedDiffChange)
return change
def _get_affected_file_from_name(self, change, name):
for file in change._affected_files:
if file.LocalPath() == os.path.normpath(name):
return file
self.fail(f'No file named {name}')
def _test(self, name, old, new):
affected_file = self._get_affected_file_from_name(self.change, name)
self.assertEqual(affected_file.OldContents(), old)
self.assertEqual(affected_file.NewContents(), new)
def test_old_contents_of_added_file_returns_empty(self):
self._test('added', [], ['a new file'])
def test_old_contents_of_deleted_file_returns_whole_file(self):
self._test('to_be_deleted', ['delete', 'me'], [])
def test_old_contents_of_modified_file(self):
self._test('to_be_modified', ['please change me'], ['changed me!'])
def test_old_contents_of_file_with_nested_dirs(self):
self._test('somewhere/else', ['not a top level file!'],
['still not a top level file!'])
def test_unix_local_paths(self):
if sys.platform == 'win32':
self.assertIn(r'somewhere\else', self.change.LocalPaths())
else:
self.assertIn('somewhere/else', self.change.LocalPaths())
self.assertIn('somewhere/else', self.change.UnixLocalPaths())
class TestGenerateDiff(fake_repos.FakeReposTestBase):
""" Tests for --generate_diff.
The option is used to generate diffs of given files against the upstream
server as base.
"""
FAKE_REPOS_CLASS = ProvidedDiffChangeFakeRepo
def setUp(self):
super().setUp()
self.repo = os.path.join(self.FAKE_REPOS.git_base, 'repo_1')
self.parser = mock.Mock()
self.parser.error.side_effect = SystemExit
def test_with_diff_file(self):
"""Tests that only either --generate_diff or --diff_file is allowed."""
options = mock.Mock(root=self.repo,
all_files=False,
generate_diff=True,
description='description',
files=None,
diff_file="patch.diff")
with self.assertRaises(SystemExit):
presubmit_support._parse_change(self.parser, options)
self.parser.error.assert_called_once_with(
'<diff_file> cannot be specified when <generate_diff> is set.', )
@mock.patch('presubmit_diff.create_diffs')
def test_with_all_files(self, create_diffs):
"""Ensures --generate_diff is noop if --all_files is specified."""
options = mock.Mock(root=self.repo,
all_files=True,
generate_diff=True,
description='description',
files=None,
source_controlled_only=False,
diff_file=None)
changes = presubmit_support._parse_change(self.parser, options)
self.assertEqual(changes.AllFiles(),
['added', 'somewhere/else', 'to_be_modified'])
create_diffs.assert_not_called()
@mock.patch('presubmit_diff.fetch_content')
def test_with_files(self, fetch_content):
"""Tests --generate_diff with files, which should call create_diffs()."""
# fetch_content would return the old content of a given file.
# In this test case, the mocked file is a newly added file.
# hence, empty content.
fetch_content.side_effect = ['']
options = mock.Mock(root=self.repo,
all_files=False,
gerrit_url='https://chromium.googlesource.com',
generate_diff=True,
description='description',
files=['added'],
source_controlled_only=False,
diff_file=None)
change = presubmit_support._parse_change(self.parser, options)
affected_files = change.AffectedFiles()
self.assertEqual(len(affected_files), 1)
self.assertEqual(affected_files[0].LocalPath(), 'added')
class TestParseDiff(unittest.TestCase):
"""A suite of tests related to diff parsing and processing."""
def _test_diff_to_change_files(self, diff, expected):
with gclient_utils.temporary_file() as tmp:
gclient_utils.FileWrite(tmp, diff, mode='w+')
content, change_files = presubmit_support._process_diff_file(tmp)
self.assertCountEqual(content, diff)
self.assertCountEqual(change_files, expected)
def test_diff_to_change_files_raises_on_empty_diff_header(self):
diff = """
diff --git a/foo b/foo
"""
with self.assertRaises(presubmit_support.PresubmitFailure):
self._test_diff_to_change_files(diff=diff, expected=[])
def test_diff_to_change_files_simple_add(self):
diff = """
diff --git a/foo b/foo
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/foo
@@ -0,0 +1 @@
+add
"""
self._test_diff_to_change_files(diff=diff, expected=[('A', 'foo')])
def test_diff_to_change_files_simple_delete(self):
diff = """
diff --git a/foo b/foo
deleted file mode 100644
index f675c2a..0000000
--- a/foo
+++ /dev/null
@@ -1,1 +0,0 @@
-delete
"""
self._test_diff_to_change_files(diff=diff, expected=[('D', 'foo')])
def test_diff_to_change_files_simple_modification(self):
diff = """
diff --git a/foo b/foo
index d7ba659f..b7957f3 100644
--- a/foo
+++ b/foo
@@ -29,7 +29,7 @@
other
random
text
- foo1
+ foo2
other
random
text
"""
self._test_diff_to_change_files(diff=diff, expected=[('M', 'foo')])
def test_diff_to_change_files_multiple_changes(self):
diff = """
diff --git a/foo b/foo
index d7ba659f..b7957f3 100644
--- a/foo
+++ b/foo
@@ -29,7 +29,7 @@
other
random
text
- foo1
+ foo2
other
random
text
diff --git a/bar b/bar
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/bar
@@ -0,0 +1 @@
+add
diff --git a/baz b/baz
deleted file mode 100644
index f675c2a..0000000
--- a/baz
+++ /dev/null
@@ -1,1 +0,0 @@
-delete
"""
self._test_diff_to_change_files(diff=diff,
expected=[('M', 'foo'), ('A', 'bar'),
('D', 'baz')])
def test_parse_unified_diff_with_valid_diff(self):
diff = """
diff --git a/foo b/foo
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/foo
@@ -0,0 +1 @@
+add
"""
res = presubmit_support._parse_unified_diff(diff)
self.assertCountEqual(
res, {
'foo':
"""
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ b/foo
@@ -0,0 +1 @@
+add
"""
})
def test_parse_unified_diff_with_valid_diff_noprefix(self):
diff = """
diff --git foo foo
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ foo
@@ -0,0 +1 @@
+add
"""
res = presubmit_support._parse_unified_diff(diff)
self.assertCountEqual(
res, {
'foo':
"""
new file mode 100644
index 0000000..9daeafb
--- /dev/null
+++ foo
@@ -0,0 +1 @@
+add
"""
})
def test_parse_unified_diff_with_invalid_diff(self):
diff = """
diff --git a/ffoo b/foo
"""
with self.assertRaises(presubmit_support.PresubmitFailure):
presubmit_support._parse_unified_diff(diff)
def test_diffs_to_change_files_with_empty_diff(self):
res = presubmit_support._diffs_to_change_files({'file': ''})
self.assertEqual(res, [('M', 'file')])
if __name__ == "__main__":
unittest.main()