1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# ===----------------------------------------------------------------------===## 4# 5# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 6# See https://llvm.org/LICENSE.txt for license information. 7# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 8# 9# ===----------------------------------------------------------------------===## 10"""Tests for revert_checker. 11 12Note that these tests require having LLVM's git history available, since our 13repository has a few interesting instances of edge-cases. 14""" 15 16import os 17import logging 18import unittest 19from typing import List 20 21import revert_checker 22 23# pylint: disable=protected-access 24 25 26def get_llvm_project_path() -> str: 27 """Returns the path to llvm-project's root.""" 28 my_dir = os.path.dirname(__file__) 29 return os.path.realpath(os.path.join(my_dir, "..", "..")) 30 31 32class _SilencingFilter(logging.Filter): 33 """Silences all log messages. 34 35 Also collects info about log messages that would've been emitted. 36 """ 37 38 def __init__(self) -> None: 39 self.messages: List[str] = [] 40 41 def filter(self, record: logging.LogRecord) -> bool: 42 self.messages.append(record.getMessage()) 43 return False 44 45 46class Test(unittest.TestCase): 47 """Tests for revert_checker.""" 48 49 def silence_logging(self) -> _SilencingFilter: 50 root = logging.getLogger() 51 filt = _SilencingFilter() 52 root.addFilter(filt) 53 self.addCleanup(root.removeFilter, filt) 54 return filt 55 56 def test_log_stream_with_known_sha_range(self) -> None: 57 start_sha = "e241573d5972d34a323fa5c64774c4207340beb3" 58 end_sha = "a7a37517751ffb0f5529011b4ba96e67fcb27510" 59 commits = [ 60 revert_checker._LogEntry( 61 "e241573d5972d34a323fa5c64774c4207340beb3", 62 "\n".join( 63 ( 64 "[mlir] NFC: remove IntegerValueSet / MutableIntegerSet", 65 "", 66 "Summary:", 67 "- these are unused and really not needed now given flat " 68 "affine", 69 " constraints", 70 "", 71 "Differential Revision: https://reviews.llvm.org/D75792", 72 ) 73 ), 74 ), 75 revert_checker._LogEntry( 76 "97572fa6e9daecd648873496fd11f7d1e25a55f0", 77 "[NFC] use hasAnyOperatorName and hasAnyOverloadedOperatorName " 78 "functions in clang-tidy matchers", 79 ), 80 ] 81 82 logs = list( 83 revert_checker._log_stream( 84 get_llvm_project_path(), 85 root_sha=start_sha, 86 end_at_sha=end_sha, 87 ) 88 ) 89 self.assertEqual(commits, logs) 90 91 def test_reverted_noncommit_object_is_a_nop(self) -> None: 92 log_filter = self.silence_logging() 93 # c9944df916e41b1014dff5f6f75d52297b48ecdc mentions reverting a non-commit 94 # object. It sits between the given base_ref and root. 95 reverts = revert_checker.find_reverts( 96 git_dir=get_llvm_project_path(), 97 across_ref="c9944df916e41b1014dff5f6f75d52297b48ecdc~", 98 root="c9944df916e41b1014dff5f6f75d52297b48ecdc", 99 max_pr_lookback=50, 100 ) 101 self.assertEqual(reverts, []) 102 103 complaint = ( 104 "Failed to resolve reverted object " 105 "edd18355be574122aaa9abf58c15d8c50fb085a1" 106 ) 107 self.assertTrue( 108 any(x.startswith(complaint) for x in log_filter.messages), 109 log_filter.messages, 110 ) 111 112 def test_known_reverts_across_arbitrary_llvm_rev(self) -> None: 113 reverts = revert_checker.find_reverts( 114 git_dir=get_llvm_project_path(), 115 across_ref="c47f971694be0159ffddfee8a75ae515eba91439", 116 root="9f981e9adf9c8d29bb80306daf08d2770263ade6", 117 max_pr_lookback=50, 118 ) 119 self.assertEqual( 120 reverts, 121 [ 122 revert_checker.Revert( 123 sha="4e0fe038f438ae1679eae9e156e1f248595b2373", 124 reverted_sha="65b21282c710afe9c275778820c6e3c1cf46734b", 125 ), 126 revert_checker.Revert( 127 sha="9f981e9adf9c8d29bb80306daf08d2770263ade6", 128 reverted_sha="4060016fce3e6a0b926ee9fc59e440a612d3a2ec", 129 ), 130 ], 131 ) 132 133 def test_pr_based_revert_works(self) -> None: 134 reverts = revert_checker.find_reverts( 135 git_dir=get_llvm_project_path(), 136 # This SHA is a direct child of the reverted SHA expected below. 137 across_ref="2d5f3b0a61fb171617012a2c3ba05fd31fb3bb1d", 138 # This SHA is a direct child of the revert SHA listed below. 139 root="2c01b278580212914ec037bb5dd9b73702dfe7f1", 140 max_pr_lookback=50, 141 ) 142 self.assertEqual( 143 reverts, 144 [ 145 revert_checker.Revert( 146 # This SHA is a `Reverts ${PR}` for #111004. 147 sha="50866e84d1da8462aeb96607bf6d9e5bbd5869c5", 148 # ...And this was the commit for #111004. 149 reverted_sha="67160c5ab5f5b7fd5fa7851abcfde367c8a9f91b", 150 ), 151 ], 152 ) 153 154 155if __name__ == "__main__": 156 unittest.main() 157