| #!/usr/bin/env python |
| # |
| # Copyright 2017 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. |
| """Tests for java_deobfuscate.""" |
| |
| import argparse |
| import os |
| import subprocess |
| import sys |
| import tempfile |
| import unittest |
| |
| # Set by command-line argument. |
| _JAVA_DEOBFUSCATE_PATH = None |
| |
| LINE_PREFIXES = [ |
| '', |
| # logcat -v threadtime |
| '09-08 14:38:35.535 18029 18084 E qcom_sensors_hal: ', |
| # logcat |
| 'W/GCM (15158): ', |
| 'W/GCM ( 158): ', |
| ] |
| |
| TEST_MAP = """\ |
| this.was.Deobfuscated -> FOO: |
| int[] FontFamily -> a |
| 1:3:void someMethod(int,android.os.Bundle):65:65 -> bar |
| """ |
| |
| TEST_DATA = """\ |
| Here is a FOO |
| Here is a FOO baz |
| Here is a "FOO" baz |
| Here is a "FOO.bar" baz |
| Here it is: FOO |
| Here it is: FOO.bar |
| SomeError: SomeFrameworkClass in isTestClass for FOO |
| Here is a FOO.bar |
| Here is a FOO.bar baz |
| END FOO#bar |
| new-instance 3810 (LSome/Framework/Class;) in LFOO; |
| FOO: Error message |
| \tat FOO.bar(PG:1) |
| """.splitlines(True) |
| |
| EXPECTED_OUTPUT = """\ |
| Here is a this.was.Deobfuscated |
| Here is a FOO baz |
| Here is a "this.was.Deobfuscated" baz |
| Here is a "this.was.Deobfuscated.someMethod" baz |
| Here it is: this.was.Deobfuscated |
| Here it is: this.was.Deobfuscated.someMethod |
| SomeError: SomeFrameworkClass in isTestClass for this.was.Deobfuscated |
| Here is a this.was.Deobfuscated.someMethod |
| Here is a FOO.bar baz |
| END this.was.Deobfuscated#someMethod |
| new-instance 3810 (LSome/Framework/Class;) in Lthis/was/Deobfuscated; |
| this.was.Deobfuscated: Error message |
| \tat this.was.Deobfuscated.someMethod(Deobfuscated.java:65) |
| """.splitlines(True) |
| |
| |
| class JavaDeobfuscateTest(unittest.TestCase): |
| |
| def __init__(self, *args, **kwargs): |
| super(JavaDeobfuscateTest, self).__init__(*args, **kwargs) |
| self._map_file = None |
| |
| def setUp(self): |
| self._map_file = tempfile.NamedTemporaryFile() |
| self._map_file.write(TEST_MAP) |
| self._map_file.flush() |
| |
| def tearDown(self): |
| if self._map_file: |
| self._map_file.close() |
| |
| def _testImpl(self, input_lines=None, expected_output_lines=None, |
| prefix=''): |
| self.assertTrue(bool(input_lines) == bool(expected_output_lines)) |
| |
| if not input_lines: |
| input_lines = [prefix + x for x in TEST_DATA] |
| if not expected_output_lines: |
| expected_output_lines = [prefix + x for x in EXPECTED_OUTPUT] |
| |
| cmd = [_JAVA_DEOBFUSCATE_PATH, self._map_file.name] |
| proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) |
| proc_output, _ = proc.communicate(''.join(input_lines)) |
| actual_output_lines = proc_output.splitlines(True) |
| for actual, expected in zip(actual_output_lines, expected_output_lines): |
| self.assertTrue( |
| actual == expected or actual.replace('bar', 'someMethod') == expected, |
| msg=''.join([ |
| 'Deobfuscation failed.\n', |
| ' actual: %s' % actual, |
| ' expected: %s' % expected])) |
| |
| def testNoPrefix(self): |
| self._testImpl(prefix='') |
| |
| def testThreadtimePrefix(self): |
| self._testImpl(prefix='09-08 14:38:35.535 18029 18084 E qcom_sensors_hal: ') |
| |
| def testStandardPrefix(self): |
| self._testImpl(prefix='W/GCM (15158): ') |
| |
| def testStandardPrefixWithPadding(self): |
| self._testImpl(prefix='W/GCM ( 158): ') |
| |
| @unittest.skip('causes java_deobfuscate to hang, see crbug.com/876539') |
| def testIndefiniteHang(self): |
| # Test for crbug.com/876539. |
| self._testImpl( |
| input_lines=[ |
| 'VFY: unable to resolve virtual method 2: LFOO;' |
| + '.onDescendantInvalidated ' |
| + '(Landroid/view/View;Landroid/view/View;)V', |
| ], |
| expected_output_lines=[ |
| 'VFY: unable to resolve virtual method 2: Lthis.was.Deobfuscated;' |
| + '.onDescendantInvalidated ' |
| + '(Landroid/view/View;Landroid/view/View;)V', |
| ]) |
| |
| |
| if __name__ == '__main__': |
| parser = argparse.ArgumentParser() |
| parser.add_argument('--java-deobfuscate-path', type=os.path.realpath, |
| required=True) |
| known_args, unittest_args = parser.parse_known_args() |
| _JAVA_DEOBFUSCATE_PATH = known_args.java_deobfuscate_path |
| unittest_args = [sys.argv[0]] + unittest_args |
| unittest.main(argv=unittest_args) |