| #!/usr/bin/env python3 |
| # Copyright 2018 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import unittest |
| |
| import apkanalyzer |
| |
| |
| class ApkAnalyzerTest(unittest.TestCase): |
| def assertEqualLists(self, list1, list2): |
| self.assertEqual(set(list1), set(list2)) |
| |
| def testUndoHierarchicalSizing_Empty(self): |
| data = [] |
| nodes = apkanalyzer.UndoHierarchicalSizing(data) |
| self.assertEqual(0, len(nodes)) |
| |
| def testUndoHierarchicalSizing_TotalSingleRootNode(self): |
| data = [ |
| ('P', '<TOTAL>', 5), |
| ] |
| nodes = apkanalyzer.UndoHierarchicalSizing(data) |
| # No changes expected since there are no child nodes. |
| self.assertEqualLists(data, nodes) |
| |
| def testUndoHierarchicalSizing_TotalSizeMinusChildNode(self): |
| data = [ |
| ('P', '<TOTAL>', 10), |
| ('C', 'child1', 7), |
| ] |
| nodes = apkanalyzer.UndoHierarchicalSizing(data) |
| self.assertEqualLists([ |
| ('P', '<TOTAL>', 3), |
| ('C', 'child1', 7), |
| ], nodes) |
| |
| def testUndoHierarchicalSizing_SiblingAnonymousClass(self): |
| data = [ |
| ('C', 'class1', 10), |
| ('C', 'class1$inner', 8), |
| ] |
| nodes = apkanalyzer.UndoHierarchicalSizing(data) |
| # No change in size expected since these should be siblings. |
| self.assertEqualLists(data, nodes) |
| |
| def testUndoHierarchicalSizing_MethodsShouldBeChildNodes(self): |
| data = [ |
| ('C', 'class1', 10), |
| ('M', 'class1 method', 8), |
| ] |
| nodes = apkanalyzer.UndoHierarchicalSizing(data) |
| self.assertEqualLists([ |
| ('C', 'class1', 2), |
| ('M', 'class1 method', 8), |
| ], nodes) |
| |
| def testUndoHierarchicalSizing_ClassIsChildNodeOfPackage(self): |
| data = [ |
| ('P', 'package1', 10), |
| ('C', 'package1.class1', 10), |
| ] |
| nodes = apkanalyzer.UndoHierarchicalSizing(data) |
| self.assertEqualLists([ |
| ('C', 'package1.class1', 10), |
| ], nodes) |
| |
| def testUndoHierarchicalSizing_TotalIncludesAllPackages(self): |
| data = [ |
| ('P', '<TOTAL>', 10), |
| ('C', 'class1', 3), |
| ('C', 'class2', 4), |
| ('C', 'class3', 2), |
| ] |
| nodes = apkanalyzer.UndoHierarchicalSizing(data) |
| self.assertEqualLists([ |
| ('P', '<TOTAL>', 1), |
| ('C', 'class1', 3), |
| ('C', 'class2', 4), |
| ('C', 'class3', 2), |
| ], nodes) |
| |
| def testUndoHierarchicalSizing_PackageAndClassSameName(self): |
| data = [ |
| ('P', 'name', 4), |
| ('C', 'name.Class', 4), |
| ('C', 'name', 2), |
| ] |
| nodes = apkanalyzer.UndoHierarchicalSizing(data) |
| self.assertEqualLists([ |
| ('C', 'name.Class', 4), |
| ('C', 'name', 2), |
| ], nodes) |
| |
| def assertNormalizedTo(self, class_path, expected_outer_class, expected_name): |
| actual_outer_class, actual_name = apkanalyzer.NormalizeLine( |
| class_path, class_path) |
| self.assertEqual(expected_outer_class, actual_outer_class) |
| self.assertEqual(expected_name, actual_name) |
| |
| def testNoramlize_internalSyntheticLambda(self): |
| self.assertNormalizedTo( |
| class_path='pkg.Cls$$InternalSyntheticLambda$3$81073ff626$0', |
| expected_outer_class='pkg.Cls', |
| expected_name='pkg.Cls$$InternalSyntheticLambda$3') |
| |
| def testNoramlize_externalSyntheticLambda(self): |
| self.assertNormalizedTo( |
| class_path='pkg.AnimatedProgressBar$$ExternalSyntheticLambda0', |
| expected_outer_class='pkg.AnimatedProgressBar', |
| expected_name=('pkg.AnimatedProgressBar$$ExternalSyntheticLambda0')) |
| |
| # Google3 still uses this format. |
| def testNoramlize_DesugarLambda(self): |
| self.assertNormalizedTo(class_path='pkg.Cls$$Lambda$1', |
| expected_outer_class='pkg.Cls', |
| expected_name='pkg.Cls$$Lambda$1') |
| |
| def testNoramlize_apiModelOutline(self): |
| self.assertNormalizedTo( |
| class_path='pkg.Cls$$ExternalSyntheticApiModelOutline0', |
| expected_outer_class='pkg.Cls', |
| expected_name='pkg.Cls$$ExternalSyntheticApiModelOutline0') |
| |
| def testNoramlize_r8Outline(self): |
| self.assertNormalizedTo(class_path='pkg.Cls$$ExternalSyntheticOutline0', |
| expected_outer_class=None, |
| expected_name='pkg.Cls$$ExternalSyntheticOutline0') |
| |
| def testNoramlize_externalSyntheticCodegen(self): |
| self.assertNormalizedTo( |
| class_path='pkg.Cls$$ExternalSyntheticThrowCCEIfNotNull0', |
| expected_outer_class=None, |
| expected_name=('pkg.Cls$$ExternalSyntheticThrowCCEIfNotNull0')) |
| |
| self.assertNormalizedTo( |
| class_path='pkg.Cls$$ExternalSyntheticBackportWithForwarding0', |
| expected_outer_class=None, |
| expected_name=('pkg.Cls$$ExternalSyntheticBackportWithForwarding0')) |
| |
| def testNoramlize_externalSyntheticOther(self): |
| self.assertNormalizedTo( |
| class_path='pkg.Cls$$ExternalSyntheticServiceLoad0', |
| expected_outer_class='pkg.Cls', |
| expected_name='pkg.Cls$$ExternalSyntheticServiceLoad0', |
| ) |
| |
| def testNoramlize_multiSameLine(self): |
| name = ('pkg1.Cls$$InternalSyntheticLambda$3$81073ff626$0 ' |
| 'pkg2.Cls$$InternalSyntheticLambda$0$81073ff626$0 bar') |
| outer_class = name.split(' ')[0] |
| expected_name = ('pkg1.Cls$$InternalSyntheticLambda$3 ' |
| 'pkg2.Cls$$InternalSyntheticLambda$0$81073ff626$0 bar') |
| self.assertEqual(('pkg1.Cls', expected_name), |
| apkanalyzer.NormalizeLine(outer_class, name)) |
| name = expected_name |
| outer_class = name.split(' ')[1] |
| expected_name = ('pkg1.Cls$$InternalSyntheticLambda$3 ' |
| 'pkg2.Cls$$InternalSyntheticLambda$0 bar') |
| self.assertEqual(('pkg2.Cls', expected_name), |
| apkanalyzer.NormalizeLine(outer_class, name)) |
| |
| def testCreateDexSymbol_normal(self): |
| name = ('org.StackAnimation org.ChromeAnimation ' |
| 'createReachTopAnimatorSet(org.StackTab[],float)') |
| size = 1 |
| source_map = {} |
| symbol = apkanalyzer.CreateDexSymbol(name, size, source_map) |
| self.assertEqual('$APK/org/StackAnimation', symbol.object_path) |
| |
| def testCreateDexSymbol_classMerged_noSource(self): |
| name = ('org.NewClass org.ChromeAnimation ' |
| 'org.OldClass.createReachTopAnimatorSet(org.StackTab[],float)') |
| size = 1 |
| source_map = {} |
| symbol = apkanalyzer.CreateDexSymbol(name, size, source_map) |
| self.assertEqual('$APK/org/OldClass', symbol.object_path) |
| |
| def testCreateDexSymbol_classMerged_withSource(self): |
| name = ('org.NewClass org.ChromeAnimation ' |
| 'org.OldClass.createReachTopAnimatorSet(org.StackTab[],float)') |
| size = 1 |
| source_map = {'org.OldClass': 'old_path.java'} |
| symbol = apkanalyzer.CreateDexSymbol(name, size, source_map) |
| self.assertEqual('$APK/org/OldClass', symbol.object_path) |
| self.assertEqual('old_path.java', symbol.source_path) |
| |
| def testCreateDexSymbol_classMerged_field(self): |
| name = 'org.NewClass int org.OldClass.createReachTopAnimatorSet' |
| size = 1 |
| source_map = {} |
| symbol = apkanalyzer.CreateDexSymbol(name, size, source_map) |
| self.assertEqual('$APK/org/OldClass', symbol.object_path) |
| |
| def testCreateDexSymbol_total(self): |
| name = '<TOTAL>' |
| size = 1 |
| source_map = {} |
| symbol = apkanalyzer.CreateDexSymbol(name, size, source_map) |
| self.assertIsNone(symbol) |
| |
| |
| if __name__ == '__main__': |
| unittest.main() |