def testDistanceBetweenTouchedFileAndFrameInfos(self): """Tests ``DistanceBetweenTouchedFileAndFrameInfos`` method.""" feature = min_distance.MinDistanceFeature(self._get_repository, _MAXIMUM) frame1 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [7], repo_url='https://repo_url') frame2 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [17], repo_url='https://repo_url') touched_file = FileChangeInfo(ChangeType.MODIFY, 'file', 'file') blame = Blame('rev', 'src/') blame.AddRegions([Region(0, 10, 'rev', 'a1', 'e1', 't1'), Region(11, 20, 'dummy_rev', 'a2', 'e2', 't2')]) url_to_blame = {'rev/file': blame} def _MockGetBlame(path, revision): revision_path = '%s/%s' % (revision, path) return url_to_blame.get(revision_path) with mock.patch('libs.gitiles.gitiles_repository.GitilesRepository.' 'GetBlame') as mock_get_blame: mock_get_blame.side_effect = _MockGetBlame distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos( 'rev', touched_file, [FrameInfo(frame1, 0), FrameInfo(frame2, 0)], Dependency('src/', 'https://repo', 'rev')) self.assertEqual(distance_info, min_distance.Distance(0, frame1)) distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos( 'wrong_rev', touched_file, [FrameInfo(frame1, 0), FrameInfo(frame2, 0)], Dependency('src/', 'https://repo', 'wrong_rev')) self.assertIsNone(distance_info)
def testMinDistanceFeatureIsOverMax(self): """Test that we return log(0) when the min_distance is too large.""" report = self._GetDummyReport( deps={'src/': Dependency('src/', 'https://repo', '6')}, dep_rolls={ 'src/': DependencyRoll('src/', 'https://repo', '0', '4') }) distance = _MAXIMUM + 1 frame = _MOCK_FRAME._replace(file_path='file') crashed = CrashedFile('file') matches = { crashed: CrashMatch(crashed, [FileChangeInfo(ChangeType.MODIFY, 'file', 'file')], [FrameInfo(frame, 0)]) } with mock.patch( 'analysis.linear.changelist_features.' 'min_distance.MinDistanceFeature.' 'DistanceBetweenTouchedFileAndFrameInfos') as mock_distance: mock_distance.return_value = min_distance.Distance(distance, None) self.assertEqual( 0.0, min_distance.MinDistanceFeature( self._get_repository, _MAXIMUM)(report)(self._GetMockSuspect(), matches).value)
def testMinDistanceFeatureMiddling(self): """Test that the feature returns middling scores for middling distances.""" report = self._GetDummyReport( deps={'src/': Dependency('src/', 'https://repo', '6')}, dep_rolls={ 'src/': DependencyRoll('src/', 'https://repo', '0', '4') }) frame = StackFrame(0, 'src/', 'func', 'f.cc', 'f.cc', [232], 'https://repo') distance = 42. crashed = CrashedFile('file') matches = { crashed: CrashMatch(crashed, [FileChangeInfo(ChangeType.MODIFY, 'file', 'file')], [FrameInfo(frame, 0)]) } with mock.patch( 'analysis.linear.changelist_features.' 'min_distance.MinDistanceFeature.' 'DistanceBetweenTouchedFileAndFrameInfos') as mock_distance: mock_distance.return_value = min_distance.Distance(distance, frame) self.assertEqual((_MAXIMUM - distance) / _MAXIMUM, min_distance.MinDistanceFeature( self._get_repository, _MAXIMUM)(report)(self._GetMockSuspect(), matches).value)
def testMinDistanceChangedFiles(self): """Tests ``ChangedFile`` method.""" report = self._GetDummyReport( deps={'src/': Dependency('src/', 'https://repo', '6')}, dep_rolls={'src/': DependencyRoll('src/', 'https://repo', '0', '4')}) distance = 42 crashed = CrashedFile(_MOCK_FRAME) matches = { crashed: CrashMatch(crashed, [FileChangeInfo(ChangeType.MODIFY, 'file', 'file')], [FrameInfo(_MOCK_FRAME, 0)]) } frame = StackFrame(0, 'src/', 'func', 'f.cc', 'f.cc', [7], 'https://repo') with mock.patch('analysis.linear.changelist_features.min_distance.' 'MinDistanceFeature.' 'DistanceBetweenTouchedFileAndFrameInfos') as mock_distance: mock_distance.return_value = min_distance.Distance(distance, frame) self.assertEqual( min_distance.MinDistanceFeature( self._get_repository, _MAXIMUM)(report)( self._GetMockSuspect(), matches).changed_files, [ChangedFile(name='file', blame_url=('%s/+blame/%s/f.cc#%d' % (frame.repo_url, report.crashed_version, frame.crashed_line_numbers[0])), reasons=['Distance between touched lines and crashed' ' lines is %d, in frame #%d' % ( distance, frame.index)])])
def testMinDistanceFeatureInfinityDistance(self): """Test that we return log(0) when the min_distance is infinity. The infinity distance means the touched file get overwritten by other cls, and the change didn't show in the final blame file. """ report = self._GetDummyReport( deps={'src/': Dependency('src/', 'https://repo', '6')}, dep_rolls={'src/': DependencyRoll('src/', 'https://repo', '0', '4')}) suspect = self._GetMockSuspect() crashed = CrashedFile(_MOCK_FRAME) matches = { crashed: CrashMatch(crashed, [FileChangeInfo(ChangeType.MODIFY, 'file', 'file')], [FrameInfo(_MOCK_FRAME, 0)]) } with mock.patch('analysis.linear.changelist_features.min_distance.' 'MinDistanceFeature.' 'DistanceBetweenTouchedFileAndFrameInfos') as mock_distance: mock_distance.return_value = None self.assertEqual( 0.0, min_distance.MinDistanceFeature( self._get_repository, _MAXIMUM)(report)(suspect, matches).value) with mock.patch('analysis.linear.changelist_features.min_distance.' 'MinDistanceFeature.' 'DistanceBetweenTouchedFileAndFrameInfos') as mock_distance: mock_distance.return_value = min_distance.Distance(float('inf'), None) self.assertEqual( 0.0, min_distance.MinDistanceFeature(self._get_repository, 100)(report)( suspect, matches).value)
def testMatchSuspectWithFrameInfos(self): """Tests ``MatchSuspectWithFrameInfos`` function.""" frame1 = StackFrame(0, 'src/', 'func', 'f.cc', 'src/f.cc', [2, 3], 'h://repo') frame2 = StackFrame(1, 'src/', 'func', 'a.cc', 'src/a.cc', [31, 32], 'h://repo') grouped_frame_infos = { MockCrashedGroup('src/f.cc'): [FrameInfo(frame1, 0)], MockCrashedGroup('src/a.cc'): [FrameInfo(frame2, 0)] } suspect = Suspect(_CHANGELOG, 'src/') matches = crash_util.MatchSuspectWithFrameInfos( suspect, grouped_frame_infos, Match) crashed = MockCrashedGroup('src/a.cc') expected_matches = { crashed: CrashMatch(crashed, _CHANGELOG.touched_files, [FrameInfo(frame2, 0)]) } self.assertDictEqual(matches, expected_matches)
def testFilePathIdfFeatureCallForMatches(self): """Tests ``__call__`` of ``FilePathIdfFeature`` for non-empty matches.""" report = CrashReport(None, None, None, None, None, None, None) frame1 = StackFrame(0, '', 'func', 'keyword1', 'src/keyword1', [2], 'http://repo') frame2 = StackFrame(0, '', 'func', 'keyword2', 'src/keyword2', [9], 'http://repo') matches = { CrashedFile('keyword1'): CrashMatch(CrashedFile('keyword1'), ['keyword1'], [FrameInfo(frame1, 0)]), CrashedFile('keyword2'): CrashMatch(CrashedFile('keyword2'), ['keyword2'], [FrameInfo(frame2, 0)]) } feature_value = self.feature(report)(None, matches) self.assertEqual( feature_value.value, file_path_idf.LogRegressNomalize(math.log(9 / float(1 + 3))))
def testDistanceBetweenTouchedFileAndFrameInfosWithDeletedFile(self): """Tests that this method returns None when the touched_file is deleted.""" feature = min_distance.MinDistanceFeature(self._get_repository, _MAXIMUM) touched_file = FileChangeInfo(ChangeType.DELETE, 'file', None) distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos( 'rev', touched_file, [FrameInfo(_MOCK_FRAME, 0)], Dependency('src/', 'https://repo', 'rev')) self.assertIsNone(distance_info)
def testIndexFramesWithCrashedGroup(self): """Tests ``IndexFramesWithCrashedGroup`` function.""" frame1 = StackFrame(0, 'src/', 'func', 'f.cc', 'src/f.cc', [2, 3], 'h://repo') frame2 = StackFrame(1, 'src/', 'func', 'a.cc', 'src/a.cc', [31, 32], 'h://repo') frame3 = StackFrame(1, 'src/dummy', 'func', 'a.cc', 'src/dummy/a.cc', [131, 132], 'h://repo') stack = CallStack(0, frame_list=[frame1, frame2, frame3]) stack_trace = Stacktrace([stack], stack) deps = {'src/': Dependency('src/', 'h://repo', 'rev3')} indexed_frame_infos = crash_util.IndexFramesWithCrashedGroup( stack_trace, Factory, deps) expected_frame_infos = { 'src/': { MockCrashedGroup('src/f.cc'): [FrameInfo(frame1, 0)], MockCrashedGroup('src/a.cc'): [FrameInfo(frame2, 0)] } } self.assertEqual(indexed_frame_infos, expected_frame_infos)
def testOnlyOneTouchedFilePerMatchedCrashedFile(self): """Test that ``CrashMatch`` can only have 1 touched file.""" report = self._GetDummyReport( deps={'src/': Dependency('src/', 'https://repo', '6')}, dep_rolls={'src/': DependencyRoll('src/', 'https://repo', '0', '4')}) frame = _MOCK_FRAME._replace(file_path='file') crashed = CrashedFile('file') matches = { crashed: CrashMatch(crashed, [FileChangeInfo(ChangeType.MODIFY, 'file', 'file'), FileChangeInfo(ChangeType.MODIFY, 'dummy', 'dummy')], [FrameInfo(frame, 0)]) } self.assertEqual( 0.0, min_distance.MinDistanceFeature(self._get_repository, _MAXIMUM)(report)( self._GetMockSuspect(), matches).value)
def IndexFramesWithCrashedGroup(stacktrace, crashed_group_factory, dependencies): """Index frames in stacktrace by dep_path and crashed_groups. Args: stacktrace (Stacktrace): The stacktrace to parse. crashed_group_factory (callable): A callable to factory crashed_group. N.B. So as to be used a key in a dict, the ``crashed_group`` should be able to be hashed. dependencies (dict of Dependency): Dict mapping dep path to ``Dependency``s. The ``dependencies`` is used to filter those frames whose dep path are not in ``dependencies``. Returns: A dict mapping dep_path to crashed_group to list of ``FrameInfo``s. For example: { 'src/': { 'a.cc': [ FrameInfo(StackFrame(0, 'src/', '', 'func', 'a.cc', [1]), 0), FrameInfo(StackFrame(2, 'src/', '', 'func', 'a.cc', [33]), 0), ] } } """ frame_infos = defaultdict(lambda: defaultdict(list)) for stack in stacktrace.stacks: for frame in stack.frames: if frame.dep_path is None: continue if frame.dep_path not in dependencies: continue crashed_group = crashed_group_factory(frame) if crashed_group: frame_infos[frame.dep_path][crashed_group].append( FrameInfo(frame, stack.priority)) return frame_infos
def testIsLogOneWhenThereIsMatchedFiles(self): """Test that the feature returns log(1) when there is matched file.""" report = self._GetDummyReport() suspect = self._GetMockSuspect() frame = StackFrame(index=0, dep_path=suspect.dep_path, function='func', file_path='a.cc', raw_file_path='a.cc', crashed_line_numbers=[7]) crashed = CrashedFile(frame) matches = { crashed: CrashMatch(crashed, [FileChangeInfo(ChangeType.MODIFY, 'a.cc', 'a.cc')], [FrameInfo(frame=frame, priority=0)]) } self.assertEqual( 1.0, TouchCrashedFileFeature()(report)(suspect, matches).value)
def testTopFrameIndexValueForBottonFrame(self): """Test that feature returns 0 when the frame index is larger than max.""" report = self._GetDummyReport() suspect = self._GetMockSuspect() frame = StackFrame(index=_MAXIMUM + 1, dep_path=suspect.dep_path, function='func', file_path='a.cc', raw_file_path='a.cc', crashed_line_numbers=[7]) crashed = CrashedFile(frame) matches = { crashed: CrashMatch(crashed, [FileChangeInfo(ChangeType.MODIFY, 'a.cc', 'a.cc')], [FrameInfo(frame=frame, priority=0)]) } self.assertEqual( 0.0, top_frame_index.TopFrameIndexFeature(_MAXIMUM)(report)( suspect, matches).value)
def testDistanceBetweenTouchedFileAndFrameInfos(self): """Tests ``DistanceBetweenTouchedFileAndFrameInfos`` method.""" feature = min_distance.MinDistanceFeature(self._get_repository, _MAXIMUM) frame1 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [7], repo_url='https://repo_url') frame2 = StackFrame(0, 'src/', 'func', 'a.cc', 'src/a.cc', [17], repo_url='https://repo_url') profiler_frame = ProfilerStackFrame(0, -0.1, -5.3, True, function_start_line=13) profiler_frame_without_line_number = ProfilerStackFrame( 0, -0.1, -5.3, True, function_start_line=None) touched_file = FileChangeInfo(ChangeType.MODIFY, 'file', 'file') blame = Blame('rev', 'src/') blame.AddRegions([ Region(0, 10, 'rev', 'a1', 'e1', 't1'), Region(11, 20, 'dummy_rev', 'a2', 'e2', 't2') ]) url_to_blame = {'rev/file': blame} def _MockGetBlame(path, revision): revision_path = '%s/%s' % (revision, path) return url_to_blame.get(revision_path) with mock.patch('libs.gitiles.gitiles_repository.GitilesRepository.' 'GetBlame') as mock_get_blame: mock_get_blame.side_effect = _MockGetBlame distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos( 'rev', touched_file, [FrameInfo(frame1, 0), FrameInfo(frame2, 0)], Dependency('src/', 'https://repo', 'rev')) self.assertEqual(distance_info, min_distance.Distance(0, frame1)) distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos( 'wrong_rev', touched_file, [FrameInfo(frame1, 0), FrameInfo(frame2, 0)], Dependency('src/', 'https://repo', 'wrong_rev')) self.assertIsNone(distance_info) # Test with a ProfilerStackFrame distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos( 'rev', touched_file, [ FrameInfo(profiler_frame, 0), FrameInfo(profiler_frame_without_line_number, 0) ], Dependency('src/', 'https://repo', 'rev')) self.assertEqual(distance_info, min_distance.Distance(4, profiler_frame)) # Test that the distance remains at ``inf`` if the ProfilerStackFrames # passed in do not have line numbers. distance_info = feature.DistanceBetweenTouchedFileAndFrameInfos( 'rev', touched_file, [FrameInfo(profiler_frame_without_line_number, 0)], Dependency('src/', 'https://repo', 'rev')) self.assertEqual(distance_info, min_distance.Distance(float('inf'), None))