| OLD | NEW |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 from crash.stacktrace import StackFrame | 5 from crash.stacktrace import StackFrame |
| 6 from crash.suspect import AnalysisInfo | |
| 7 from crash.suspect import StackInfo | |
| 8 from crash.suspect import Suspect | 6 from crash.suspect import Suspect |
| 9 from crash.suspect import SuspectMap | |
| 10 from crash.test.crash_test_suite import CrashTestSuite | 7 from crash.test.crash_test_suite import CrashTestSuite |
| 11 from libs.gitiles.blame import Blame | |
| 12 from libs.gitiles.blame import Region | |
| 13 from libs.gitiles.change_log import ChangeLog | 8 from libs.gitiles.change_log import ChangeLog |
| 14 | 9 |
| 15 DUMMY_CHANGELOG1 = ChangeLog.FromDict({ | 10 DUMMY_CHANGELOG1 = ChangeLog.FromDict({ |
| 16 'author': { | 11 'author': { |
| 17 'name': 'r@chromium.org', | 12 'name': 'r@chromium.org', |
| 18 'email': 'r@chromium.org', | 13 'email': 'r@chromium.org', |
| 19 'time': 'Thu Mar 31 21:24:43 2016', | 14 'time': 'Thu Mar 31 21:24:43 2016', |
| 20 }, | 15 }, |
| 21 'committer': { | 16 'committer': { |
| 22 'email': 'r', | 17 'email': 'r', |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 'old_path': 'a.cc', | 59 'old_path': 'a.cc', |
| 65 }, | 60 }, |
| 66 ], | 61 ], |
| 67 'commit_url': | 62 'commit_url': |
| 68 'https://repo.test/+/2', | 63 'https://repo.test/+/2', |
| 69 'code_review_url': 'https://codereview.chromium.org/3290', | 64 'code_review_url': 'https://codereview.chromium.org/3290', |
| 70 'revision': '2', | 65 'revision': '2', |
| 71 'reverted_revision': None | 66 'reverted_revision': None |
| 72 }) | 67 }) |
| 73 | 68 |
| 74 DUMMY_BLAME = Blame('4', 'a.cc') | |
| 75 DUMMY_BLAME.AddRegions([ | |
| 76 Region(1, 5, '2', 'r', 'r@chromium.org', 'Thu Mar 25 21:24:43 2016'), | |
| 77 Region(6, 3, '1', 'e', 'e@chromium.org', 'Thu Mar 31 21:24:43 2016'), | |
| 78 Region(9, 2, '3', 'k', 'k@chromium.org', 'Thu Apr 1 21:24:43 2016')]) | |
| 79 | |
| 80 DUMMY_BLAME2 = Blame('4', 'b.cc') | |
| 81 DUMMY_BLAME2.AddRegions([ | |
| 82 Region(1, 5, '2', 'r', 'r@chromium.org', 'Thu Mar 25 21:24:43 2016'), | |
| 83 Region(6, 3, '1', 'e', 'e@chromium.org', 'Thu Mar 31 21:24:43 2016')]) | |
| 84 | |
| 85 | 69 |
| 86 class SuspectTest(CrashTestSuite): | 70 class SuspectTest(CrashTestSuite): |
| 87 | 71 |
| 88 def testSuspectToDict(self): | 72 def testSuspectToDict(self): |
| 89 | |
| 90 suspect = Suspect(DUMMY_CHANGELOG1, 'src/', | 73 suspect = Suspect(DUMMY_CHANGELOG1, 'src/', |
| 91 confidence=1, reasons=['MinDistance', 0.5, 'some reason'], | 74 confidence=1, reasons=['MinDistance', 0.5, 'some reason'], |
| 92 changed_files={'file': 'f', 'blame_url': 'http://b', | 75 changed_files={'file': 'f', 'blame_url': 'http://b', |
| 93 'info': 'min distance (LOC) 5'}) | 76 'info': 'min distance (LOC) 5'}) |
| 94 | 77 |
| 95 expected_suspect_json = { | 78 expected_suspect_json = { |
| 96 'url': DUMMY_CHANGELOG1.commit_url, | 79 'url': DUMMY_CHANGELOG1.commit_url, |
| 97 'review_url': DUMMY_CHANGELOG1.code_review_url, | 80 'review_url': DUMMY_CHANGELOG1.code_review_url, |
| 98 'revision': DUMMY_CHANGELOG1.revision, | 81 'revision': DUMMY_CHANGELOG1.revision, |
| 99 'project_path': 'src/', | 82 'project_path': 'src/', |
| 100 'author': DUMMY_CHANGELOG1.author.email, | 83 'author': DUMMY_CHANGELOG1.author.email, |
| 101 'time': str(DUMMY_CHANGELOG1.author.time), | 84 'time': str(DUMMY_CHANGELOG1.author.time), |
| 102 'reasons': ['MinDistance', 0.5, 'some reason'], | 85 'reasons': ['MinDistance', 0.5, 'some reason'], |
| 103 'changed_files': {'file': 'f', 'blame_url': 'http://b', | 86 'changed_files': {'file': 'f', 'blame_url': 'http://b', |
| 104 'info': 'min distance (LOC) 5'}, | 87 'info': 'min distance (LOC) 5'}, |
| 105 'confidence': 1, | 88 'confidence': 1, |
| 106 } | 89 } |
| 107 | 90 |
| 108 self.assertEqual(suspect.ToDict(), expected_suspect_json) | 91 self.assertDictEqual(suspect.ToDict(), expected_suspect_json) |
| 109 | 92 |
| 110 def testSuspectToString(self): | 93 def testSuspectToString(self): |
| 111 | |
| 112 suspect = Suspect(DUMMY_CHANGELOG1, 'src/', confidence=1) | 94 suspect = Suspect(DUMMY_CHANGELOG1, 'src/', confidence=1) |
| 113 | 95 self.assertEqual(suspect.ToString(), str(suspect.ToDict())) |
| 114 expected_str = '' | 96 self.assertEqual(str(suspect), str(suspect.ToDict())) |
| 115 self.assertEqual(suspect.ToString(), expected_str) | |
| 116 | |
| 117 suspect.file_to_stack_infos = { | |
| 118 'a.cc': [StackInfo( | |
| 119 frame = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', []), | |
| 120 priority = 0)] | |
| 121 } | |
| 122 expected_str = 'Changed file a.cc crashed in frame #0' | |
| 123 | |
| 124 self.assertEqual(str(suspect), expected_str) | |
| 125 | |
| 126 def testSuspectUpdate(self): | |
| 127 # Touched lines have intersection with crashed lines. | |
| 128 suspect = Suspect(DUMMY_CHANGELOG1, 'src/', confidence=1) | |
| 129 stack_infos = [StackInfo( | |
| 130 frame = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [7]), | |
| 131 priority = 0)] | |
| 132 | |
| 133 suspect._UpdateSuspect('a.cc', stack_infos, DUMMY_BLAME) | |
| 134 self.assertEqual(suspect.file_to_analysis_info['a.cc'].min_distance, 0) | |
| 135 | |
| 136 # Touched lines are before crashed lines. | |
| 137 suspect = Suspect(DUMMY_CHANGELOG1, 'src/', confidence=1) | |
| 138 | |
| 139 stack_infos = [StackInfo( | |
| 140 frame = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [3]), | |
| 141 priority = 0)] | |
| 142 | |
| 143 suspect._UpdateSuspect('a.cc', stack_infos, DUMMY_BLAME) | |
| 144 self.assertEqual(suspect.file_to_analysis_info['a.cc'].min_distance, 3) | |
| 145 | |
| 146 # Touched lines are after crashed lines. | |
| 147 suspect = Suspect(DUMMY_CHANGELOG1, 'src/', confidence=1) | |
| 148 | |
| 149 stack_infos = [StackInfo( | |
| 150 frame = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [10]), | |
| 151 priority = 0)] | |
| 152 | |
| 153 suspect._UpdateSuspect('a.cc', stack_infos, DUMMY_BLAME) | |
| 154 self.assertEqual(suspect.file_to_analysis_info['a.cc'].min_distance, 2) | |
| 155 | |
| 156 def testSuspectUpdateWithEmptyBlame(self): | |
| 157 suspect = Suspect(DUMMY_CHANGELOG1, 'src/', confidence=1) | |
| 158 stack_infos = [StackInfo( | |
| 159 frame = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [7]), | |
| 160 priority = 0)] | |
| 161 | |
| 162 suspect._UpdateSuspect('a.cc', stack_infos, None) | |
| 163 self.assertEqual(suspect.file_to_stack_infos['a.cc'], stack_infos) | |
| 164 self.assertEqual(suspect.file_to_analysis_info, {}) | |
| 165 | |
| 166 def testSuspectUpdateMinimumDistance(self): | |
| 167 suspect = Suspect(DUMMY_CHANGELOG1, 'src/', confidence=1) | |
| 168 frame1 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [7]) | |
| 169 frame2 = StackFrame(2, 'src/', 'func', 'a.cc', 'src/a.cc', [20]) | |
| 170 stack_infos = [StackInfo(frame1, 0), StackInfo(frame2, 0)] | |
| 171 | |
| 172 suspect._UpdateSuspect('a.cc', stack_infos, DUMMY_BLAME) | |
| 173 self.assertEqual(suspect.file_to_stack_infos['a.cc'], stack_infos) | |
| 174 self.assertEqual(suspect.file_to_analysis_info, | |
| 175 {'a.cc': AnalysisInfo(min_distance = 0, min_distance_frame = frame1)}) | |
| 176 | |
| 177 def testSuspectsGenerateSuspects(self): | |
| 178 suspects = SuspectMap(ignore_cls=set(['2'])) | |
| 179 frame1 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [7]) | |
| 180 frame2 = StackFrame(1, 'src/', 'func', 'b.cc', 'src/b.cc', [11]) | |
| 181 stack_infos1 = [StackInfo(frame1, 0)] | |
| 182 stack_infos2 = [StackInfo(frame2, 0)] | |
| 183 suspects.GenerateSuspects('a.cc', 'src/', stack_infos1, | |
| 184 [DUMMY_CHANGELOG1, DUMMY_CHANGELOG2], | |
| 185 DUMMY_BLAME) | |
| 186 | |
| 187 suspects.GenerateSuspects('b.cc', 'src/', stack_infos2, | |
| 188 [DUMMY_CHANGELOG1, DUMMY_CHANGELOG2], | |
| 189 DUMMY_BLAME2) | |
| 190 | |
| 191 expected_suspect = Suspect(DUMMY_CHANGELOG1, 'src/') | |
| 192 expected_suspect.file_to_stack_infos = { | |
| 193 'a.cc': stack_infos1, | |
| 194 'b.cc': stack_infos2, | |
| 195 } | |
| 196 expected_suspect.file_to_analysis_info = { | |
| 197 'a.cc': AnalysisInfo(min_distance = 0, min_distance_frame = frame1), | |
| 198 'b.cc': AnalysisInfo(min_distance = 3, min_distance_frame = frame2), | |
| 199 } | |
| 200 | |
| 201 expected_suspects = SuspectMap(ignore_cls=set(['2'])) | |
| 202 expected_suspects['1'] = expected_suspect | |
| 203 | |
| 204 self._VerifyTwoSuspectMapEqual(suspects, expected_suspects) | |
| OLD | NEW |