blob: fc228562260a653b86b7fb5c4ba45c8ec80aa9c6 [file]
# Copyright 2016 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.
from collections import namedtuple
from analysis import crash_util
from analysis.analysis_testcase import AnalysisTestCase
from analysis.crash_match import CrashMatch
from analysis.crash_match import FrameInfo
from analysis.stacktrace import CallStack
from analysis.stacktrace import ProfilerStackFrame
from analysis.stacktrace import StackFrame
from analysis.stacktrace import Stacktrace
from analysis.suspect import Suspect
from analysis.type_enums import RenameType
from libs.deps.dependency import Dependency
from libs.gitiles.change_log import ChangeLog
_CHANGELOG = ChangeLog.FromDict({
'author': {
'name': 'r@chromium.org',
'email': 'r@chromium.org',
'time': 'Thu Mar 31 21:24:43 2016',
},
'committer': {
'name': 'example@chromium.org',
'email': 'r@chromium.org',
'time': 'Thu Mar 31 21:28:39 2016',
},
'message': 'dummy',
'commit_position': 175900,
'touched_files': [
{
'change_type': 'modify',
'new_path': 'src/a.cc',
'old_path': 'src/a.cc',
},
],
'commit_url':
'https://repo.test/+/1',
'code_review_url': 'https://codereview.chromium.org/3281',
'revision': '1',
'reverted_revision': None
})
def Factory(frame):
return MockCrashedGroup(frame.raw_file_path) if frame.raw_file_path else None
def Match(crashed, touched_file):
return touched_file.new_path == crashed.value
class MockCrashedGroup(namedtuple('MockCrashedGroup', ['value'])):
__slots__ = ()
class CrashUtilTest(AnalysisTestCase):
def testIsSameFilePath(self):
path_1 = 'third_party/a/b/c/file.cc'
path_2 = 'third_party/a/file.cc'
self.assertTrue(crash_util.IsSameFilePath(path_1, path_2))
path_1 = 'a/b/c/file.cc'
path_2 = 'a/b/c/file2.cc'
self.assertFalse(crash_util.IsSameFilePath(path_1, path_2))
path_1 = 'a/b/c/d/e/file.cc'
path_2 = 'f/g/file.cc'
self.assertTrue(crash_util.IsSameFilePath(None, None))
self.assertFalse(crash_util.IsSameFilePath(path_1, path_2))
self.assertFalse(crash_util.IsSameFilePath(None, path_2))
self.assertFalse(crash_util.IsSameFilePath(path_1, None))
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 testDoNotIndexFramesWithNoneCrashedGroup(self):
"""Tests ``IndexFramesWithCrashedGroup`` function."""
frame = StackFrame(0, 'src/', 'func', '', '', [2], 'h://repo')
stack = CallStack(0, frame_list=[frame])
stack_trace = Stacktrace([stack], stack)
deps = {'src/': Dependency('src/', 'h://repo', 'rev3')}
indexed_frame_infos = crash_util.IndexFramesWithCrashedGroup(
stack_trace, Factory, deps)
self.assertEqual(indexed_frame_infos, {})
def testIndexFramesWithCrashedGroupWhenFrameHasNoDepPath(self):
"""Tests a bug with ``IndexFramesWithCrashedGroup``.
This function would crash when passed a frame with a ``None`` dep path.
Instead it should ignore this frame.
"""
frame = ProfilerStackFrame(0, 0.1, 0.5, True, dep_path=None)
stack = CallStack(0, frame_list=[frame])
stack_trace = Stacktrace([stack], stack)
deps = {'src': Dependency('src', 'h://repo', 'rev3')}
indexed_frame_infos = crash_util.IndexFramesWithCrashedGroup(
stack_trace, Factory, deps)
self.assertDictEqual(indexed_frame_infos, {})
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 testFilterStackFrameFunction(self):
"""Tests ``FilterStackFrameFunction`` strips part correctly."""
a = 'function::(anonymous namespace)::abc'
self.assertEqual(crash_util.FilterStackFrameFunction(a), 'function::abc')
b = 'abc(dcew(wqn{ew}io)eqs)::penc(senc)'
self.assertEqual(crash_util.FilterStackFrameFunction(b), 'abc')
c = 'no_parenthese'
self.assertEqual(crash_util.FilterStackFrameFunction(c), c)
def testRenameFileName(self):
"""Tests ``RenameFileName`` function."""
self.assertEqual (
crash_util.RenameFileName('UpperFileName.cpp',
RenameType.CAPITAL_TO_UNDERSCORE),
'upper_file_name.cpp')
self.assertEqual (
crash_util.RenameFileName('AbcAbcAbc.cpp',
RenameType.CAPITAL_TO_UNDERSCORE),
'abc_abc_abc.cpp')
self.assertEqual (
crash_util.RenameFileName('underscore_file_name.cpp',
RenameType.UNDERSCORE_TO_CAPITAL),
'UnderscoreFileName.cpp')
self.assertEqual (
crash_util.RenameFileName('UpperFileName.cpp', None),
'UpperFileName.cpp')
def testMapPath(self):
self.assertEqual(crash_util.MapPath('', []), '')
self.assertEqual(crash_util.MapPath(None, []), None)
change_naming_convention = crash_util.ChangeNamingConvention({'a/old_dir':
'capital_to_underscore'})
replace_path = crash_util.ReplacePath({'a/old_dir': 'b/new_dir'})
self.assertEqual(
crash_util.MapPath('a/old_dir/ClassName.cpp',
[change_naming_convention, replace_path]),
'b/new_dir/class_name.cpp'
)
class ChangeNamingConventionTest(AnalysisTestCase):
def testCall(self):
change_naming_convention = crash_util.ChangeNamingConvention(
{'a/b': 'capital_to_underscore'})
self.assertEqual(change_naming_convention('a/b/ClassBlaBla.cpp'),
'a/b/class_bla_bla.cpp')
self.assertEqual(change_naming_convention('a/ClassBlaBla.cpp'),
'a/ClassBlaBla.cpp')
class ReplacePathTest(AnalysisTestCase):
def testCall(self):
replace_path = crash_util.ReplacePath({'a/old_dir': 'b/new_dir'})
self.assertEqual(replace_path('a/old_dir/ClassBlaBla.cpp'),
'b/new_dir/ClassBlaBla.cpp')
self.assertEqual(replace_path('a/ClassBlaBla.cpp'), 'a/ClassBlaBla.cpp')
class ChangeFileExtension(AnalysisTestCase):
def testCall(self):
change_file_extension = crash_util.ChangeFileExtension(
{'a/b': {'cpp': 'cc'}})
self.assertEqual(change_file_extension('a/b/ClassBlaBla.cpp'),
'a/b/ClassBlaBla.cc')
self.assertEqual(change_file_extension('a/ClassBlaBla.cpp'),
'a/ClassBlaBla.cpp')
self.assertEqual(change_file_extension('a/b/ClassBlaBla'),
'a/b/ClassBlaBla')