diff options
Diffstat (limited to 'llvm_tools/patch_utils_unittest.py')
-rwxr-xr-x | llvm_tools/patch_utils_unittest.py | 368 |
1 files changed, 190 insertions, 178 deletions
diff --git a/llvm_tools/patch_utils_unittest.py b/llvm_tools/patch_utils_unittest.py index 04541ae0..54c38763 100755 --- a/llvm_tools/patch_utils_unittest.py +++ b/llvm_tools/patch_utils_unittest.py @@ -16,87 +16,90 @@ import patch_utils as pu class TestPatchUtils(unittest.TestCase): - """Test the patch_utils.""" - - def test_atomic_write(self): - """Test that atomic write safely writes.""" - prior_contents = 'This is a test written by patch_utils_unittest.py\n' - new_contents = 'I am a test written by patch_utils_unittest.py\n' - with tempfile.TemporaryDirectory(prefix='patch_utils_unittest') as dirname: - dirpath = Path(dirname) - filepath = dirpath / 'test_atomic_write.txt' - with filepath.open('w', encoding='utf-8') as f: - f.write(prior_contents) - - def _t(): - with pu.atomic_write(filepath, encoding='utf-8') as f: - f.write(new_contents) - raise Exception('Expected failure') - - self.assertRaises(Exception, _t) - with filepath.open(encoding='utf-8') as f: - lines = f.readlines() - self.assertEqual(lines[0], prior_contents) - with pu.atomic_write(filepath, encoding='utf-8') as f: - f.write(new_contents) - with filepath.open(encoding='utf-8') as f: - lines = f.readlines() - self.assertEqual(lines[0], new_contents) - - def test_from_to_dict(self): - """Test to and from dict conversion.""" - d = TestPatchUtils._default_json_dict() - d['metadata'] = { - 'title': 'hello world', - 'info': [], - 'other_extra_info': { - 'extra_flags': [], + """Test the patch_utils.""" + + def test_atomic_write(self): + """Test that atomic write safely writes.""" + prior_contents = "This is a test written by patch_utils_unittest.py\n" + new_contents = "I am a test written by patch_utils_unittest.py\n" + with tempfile.TemporaryDirectory( + prefix="patch_utils_unittest" + ) as dirname: + dirpath = Path(dirname) + filepath = dirpath / "test_atomic_write.txt" + with filepath.open("w", encoding="utf-8") as f: + f.write(prior_contents) + + def _t(): + with pu.atomic_write(filepath, encoding="utf-8") as f: + f.write(new_contents) + raise Exception("Expected failure") + + self.assertRaises(Exception, _t) + with filepath.open(encoding="utf-8") as f: + lines = f.readlines() + self.assertEqual(lines[0], prior_contents) + with pu.atomic_write(filepath, encoding="utf-8") as f: + f.write(new_contents) + with filepath.open(encoding="utf-8") as f: + lines = f.readlines() + self.assertEqual(lines[0], new_contents) + + def test_from_to_dict(self): + """Test to and from dict conversion.""" + d = TestPatchUtils._default_json_dict() + d["metadata"] = { + "title": "hello world", + "info": [], + "other_extra_info": { + "extra_flags": [], + }, } - } - e = pu.PatchEntry.from_dict(TestPatchUtils._mock_dir(), d) - self.assertEqual(d, e.to_dict()) - - def test_patch_path(self): - """Test that we can get the full path from a PatchEntry.""" - d = TestPatchUtils._default_json_dict() - with mock.patch.object(Path, 'is_dir', return_value=True): - entry = pu.PatchEntry.from_dict(Path('/home/dir'), d) - self.assertEqual(entry.patch_path(), - Path('/home/dir') / d['rel_patch_path']) - - def test_can_patch_version(self): - """Test that patch application based on version is correct.""" - base_dict = TestPatchUtils._default_json_dict() - workdir = TestPatchUtils._mock_dir() - e1 = pu.PatchEntry.from_dict(workdir, base_dict) - self.assertFalse(e1.can_patch_version(3)) - self.assertTrue(e1.can_patch_version(4)) - self.assertTrue(e1.can_patch_version(5)) - self.assertFalse(e1.can_patch_version(9)) - base_dict['version_range'] = {'until': 9} - e2 = pu.PatchEntry.from_dict(workdir, base_dict) - self.assertTrue(e2.can_patch_version(0)) - self.assertTrue(e2.can_patch_version(5)) - self.assertFalse(e2.can_patch_version(9)) - base_dict['version_range'] = {'from': 4} - e3 = pu.PatchEntry.from_dict(workdir, base_dict) - self.assertFalse(e3.can_patch_version(3)) - self.assertTrue(e3.can_patch_version(5)) - self.assertTrue(e3.can_patch_version(1 << 31)) - base_dict['version_range'] = {'from': 4, 'until': None} - e4 = pu.PatchEntry.from_dict(workdir, base_dict) - self.assertFalse(e4.can_patch_version(3)) - self.assertTrue(e4.can_patch_version(5)) - self.assertTrue(e4.can_patch_version(1 << 31)) - base_dict['version_range'] = {'from': None, 'until': 9} - e5 = pu.PatchEntry.from_dict(workdir, base_dict) - self.assertTrue(e5.can_patch_version(0)) - self.assertTrue(e5.can_patch_version(5)) - self.assertFalse(e5.can_patch_version(9)) - - def test_can_parse_from_json(self): - """Test that patches be loaded from json.""" - json = """ + e = pu.PatchEntry.from_dict(TestPatchUtils._mock_dir(), d) + self.assertEqual(d, e.to_dict()) + + def test_patch_path(self): + """Test that we can get the full path from a PatchEntry.""" + d = TestPatchUtils._default_json_dict() + with mock.patch.object(Path, "is_dir", return_value=True): + entry = pu.PatchEntry.from_dict(Path("/home/dir"), d) + self.assertEqual( + entry.patch_path(), Path("/home/dir") / d["rel_patch_path"] + ) + + def test_can_patch_version(self): + """Test that patch application based on version is correct.""" + base_dict = TestPatchUtils._default_json_dict() + workdir = TestPatchUtils._mock_dir() + e1 = pu.PatchEntry.from_dict(workdir, base_dict) + self.assertFalse(e1.can_patch_version(3)) + self.assertTrue(e1.can_patch_version(4)) + self.assertTrue(e1.can_patch_version(5)) + self.assertFalse(e1.can_patch_version(9)) + base_dict["version_range"] = {"until": 9} + e2 = pu.PatchEntry.from_dict(workdir, base_dict) + self.assertTrue(e2.can_patch_version(0)) + self.assertTrue(e2.can_patch_version(5)) + self.assertFalse(e2.can_patch_version(9)) + base_dict["version_range"] = {"from": 4} + e3 = pu.PatchEntry.from_dict(workdir, base_dict) + self.assertFalse(e3.can_patch_version(3)) + self.assertTrue(e3.can_patch_version(5)) + self.assertTrue(e3.can_patch_version(1 << 31)) + base_dict["version_range"] = {"from": 4, "until": None} + e4 = pu.PatchEntry.from_dict(workdir, base_dict) + self.assertFalse(e4.can_patch_version(3)) + self.assertTrue(e4.can_patch_version(5)) + self.assertTrue(e4.can_patch_version(1 << 31)) + base_dict["version_range"] = {"from": None, "until": 9} + e5 = pu.PatchEntry.from_dict(workdir, base_dict) + self.assertTrue(e5.can_patch_version(0)) + self.assertTrue(e5.can_patch_version(5)) + self.assertFalse(e5.can_patch_version(9)) + + def test_can_parse_from_json(self): + """Test that patches be loaded from json.""" + json = """ [ { "metadata": {}, @@ -118,51 +121,56 @@ class TestPatchUtils(unittest.TestCase): } ] """ - result = pu.json_to_patch_entries(Path(), io.StringIO(json)) - self.assertEqual(len(result), 4) - - def test_parsed_hunks(self): - """Test that we can parse patch file hunks.""" - m = mock.mock_open(read_data=_EXAMPLE_PATCH) - - def mocked_open(self, *args, **kwargs): - return m(self, *args, **kwargs) - - with mock.patch.object(Path, 'open', mocked_open): - e = pu.PatchEntry.from_dict(TestPatchUtils._mock_dir(), - TestPatchUtils._default_json_dict()) - hunk_dict = e.parsed_hunks() - - m.assert_called() - filename1 = 'clang/lib/Driver/ToolChains/Clang.cpp' - filename2 = 'llvm/lib/Passes/PassBuilder.cpp' - self.assertEqual(set(hunk_dict.keys()), {filename1, filename2}) - hunk_list1 = hunk_dict[filename1] - hunk_list2 = hunk_dict[filename2] - self.assertEqual(len(hunk_list1), 1) - self.assertEqual(len(hunk_list2), 2) - - def test_apply_when_patch_nonexistent(self): - """Test that we error out when we try to apply a non-existent patch.""" - src_dir = TestPatchUtils._mock_dir('somewhere/llvm-project') - patch_dir = TestPatchUtils._mock_dir() - e = pu.PatchEntry.from_dict(patch_dir, TestPatchUtils._default_json_dict()) - with mock.patch('subprocess.run', mock.MagicMock()): - self.assertRaises(RuntimeError, lambda: e.apply(src_dir)) - - def test_apply_success(self): - """Test that we can call apply.""" - src_dir = TestPatchUtils._mock_dir('somewhere/llvm-project') - patch_dir = TestPatchUtils._mock_dir() - e = pu.PatchEntry.from_dict(patch_dir, TestPatchUtils._default_json_dict()) - with mock.patch('pathlib.Path.is_file', return_value=True): - with mock.patch('subprocess.run', mock.MagicMock()): - result = e.apply(src_dir) - self.assertTrue(result.succeeded) - - def test_parse_failed_patch_output(self): - """Test that we can call parse `patch` output.""" - fixture = """ + result = pu.json_to_patch_entries(Path(), io.StringIO(json)) + self.assertEqual(len(result), 4) + + def test_parsed_hunks(self): + """Test that we can parse patch file hunks.""" + m = mock.mock_open(read_data=_EXAMPLE_PATCH) + + def mocked_open(self, *args, **kwargs): + return m(self, *args, **kwargs) + + with mock.patch.object(Path, "open", mocked_open): + e = pu.PatchEntry.from_dict( + TestPatchUtils._mock_dir(), TestPatchUtils._default_json_dict() + ) + hunk_dict = e.parsed_hunks() + + m.assert_called() + filename1 = "clang/lib/Driver/ToolChains/Clang.cpp" + filename2 = "llvm/lib/Passes/PassBuilder.cpp" + self.assertEqual(set(hunk_dict.keys()), {filename1, filename2}) + hunk_list1 = hunk_dict[filename1] + hunk_list2 = hunk_dict[filename2] + self.assertEqual(len(hunk_list1), 1) + self.assertEqual(len(hunk_list2), 2) + + def test_apply_when_patch_nonexistent(self): + """Test that we error out when we try to apply a non-existent patch.""" + src_dir = TestPatchUtils._mock_dir("somewhere/llvm-project") + patch_dir = TestPatchUtils._mock_dir() + e = pu.PatchEntry.from_dict( + patch_dir, TestPatchUtils._default_json_dict() + ) + with mock.patch("subprocess.run", mock.MagicMock()): + self.assertRaises(RuntimeError, lambda: e.apply(src_dir)) + + def test_apply_success(self): + """Test that we can call apply.""" + src_dir = TestPatchUtils._mock_dir("somewhere/llvm-project") + patch_dir = TestPatchUtils._mock_dir() + e = pu.PatchEntry.from_dict( + patch_dir, TestPatchUtils._default_json_dict() + ) + with mock.patch("pathlib.Path.is_file", return_value=True): + with mock.patch("subprocess.run", mock.MagicMock()): + result = e.apply(src_dir) + self.assertTrue(result.succeeded) + + def test_parse_failed_patch_output(self): + """Test that we can call parse `patch` output.""" + fixture = """ checking file a/b/c.cpp Hunk #1 SUCCEEDED at 96 with fuzz 1. Hunk #12 FAILED at 77. @@ -172,59 +180,63 @@ Hunk #4 FAILED at 30. checking file works.cpp Hunk #1 SUCCEEDED at 96 with fuzz 1. """ - result = pu.parse_failed_patch_output(fixture) - self.assertEqual(result['a/b/c.cpp'], [12, 42]) - self.assertEqual(result['x/y/z.h'], [4]) - self.assertNotIn('works.cpp', result) - - def test_is_git_dirty(self): - """Test if a git directory has uncommitted changes.""" - with tempfile.TemporaryDirectory(prefix='patch_utils_unittest') as dirname: - dirpath = Path(dirname) - - def _run_h(cmd): - subprocess.run(cmd, - cwd=dirpath, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL, - check=True) - - _run_h(['git', 'init']) - self.assertFalse(pu.is_git_dirty(dirpath)) - test_file = dirpath / 'test_file' - test_file.touch() - self.assertTrue(pu.is_git_dirty(dirpath)) - _run_h(['git', 'add', '.']) - _run_h(['git', 'commit', '-m', 'test']) - self.assertFalse(pu.is_git_dirty(dirpath)) - test_file.touch() - self.assertFalse(pu.is_git_dirty(dirpath)) - with test_file.open('w', encoding='utf-8'): - test_file.write_text('abc') - self.assertTrue(pu.is_git_dirty(dirpath)) - - @staticmethod - def _default_json_dict(): - return { - 'metadata': { - 'title': 'hello world', - }, - 'platforms': ['a'], - 'rel_patch_path': 'x/y/z', - 'version_range': { - 'from': 4, - 'until': 9, + result = pu.parse_failed_patch_output(fixture) + self.assertEqual(result["a/b/c.cpp"], [12, 42]) + self.assertEqual(result["x/y/z.h"], [4]) + self.assertNotIn("works.cpp", result) + + def test_is_git_dirty(self): + """Test if a git directory has uncommitted changes.""" + with tempfile.TemporaryDirectory( + prefix="patch_utils_unittest" + ) as dirname: + dirpath = Path(dirname) + + def _run_h(cmd): + subprocess.run( + cmd, + cwd=dirpath, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + check=True, + ) + + _run_h(["git", "init"]) + self.assertFalse(pu.is_git_dirty(dirpath)) + test_file = dirpath / "test_file" + test_file.touch() + self.assertTrue(pu.is_git_dirty(dirpath)) + _run_h(["git", "add", "."]) + _run_h(["git", "commit", "-m", "test"]) + self.assertFalse(pu.is_git_dirty(dirpath)) + test_file.touch() + self.assertFalse(pu.is_git_dirty(dirpath)) + with test_file.open("w", encoding="utf-8"): + test_file.write_text("abc") + self.assertTrue(pu.is_git_dirty(dirpath)) + + @staticmethod + def _default_json_dict(): + return { + "metadata": { + "title": "hello world", + }, + "platforms": ["a"], + "rel_patch_path": "x/y/z", + "version_range": { + "from": 4, + "until": 9, + }, } - } - @staticmethod - def _mock_dir(path: str = 'a/b/c'): - workdir = Path(path) - workdir = mock.MagicMock(workdir) - workdir.is_dir = lambda: True - workdir.joinpath = lambda x: Path(path).joinpath(x) - workdir.__truediv__ = lambda self, x: self.joinpath(x) - return workdir + @staticmethod + def _mock_dir(path: str = "a/b/c"): + workdir = Path(path) + workdir = mock.MagicMock(workdir) + workdir.is_dir = lambda: True + workdir.joinpath = lambda x: Path(path).joinpath(x) + workdir.__truediv__ = lambda self, x: self.joinpath(x) + return workdir _EXAMPLE_PATCH = """ @@ -272,5 +284,5 @@ index c5fd68299eb..4c6e15eeeb9 100644 // FIXME: It would seem like these should come first in the optimization """ -if __name__ == '__main__': - unittest.main() +if __name__ == "__main__": + unittest.main() |