1#!/usr/bin/env python3 2# 3# Copyright (C) 2016 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17"""Tests for bisection-search module.""" 18 19import unittest 20 21from unittest.mock import Mock 22 23from bisection_search import BugSearch 24from bisection_search import Dex2OatWrapperTestable 25from bisection_search import FatalError 26from bisection_search import MANDATORY_PASSES 27 28 29class BisectionTestCase(unittest.TestCase): 30 """BugSearch method test case. 31 32 Integer constants were chosen arbitrarily. They should be large enough and 33 random enough to ensure binary search does nontrivial work. 34 35 Attributes: 36 _METHODS: list of strings, methods compiled by testable 37 _PASSES: list of strings, passes run by testable 38 _FAILING_METHOD: string, name of method which fails in some tests 39 _FAILING_PASS: string, name of pass which fails in some tests 40 _MANDATORY_PASS: string, name of a mandatory pass 41 """ 42 _METHODS_COUNT = 1293 43 _PASSES_COUNT = 573 44 _FAILING_METHOD_IDX = 237 45 _FAILING_PASS_IDX = 444 46 _METHODS = ['method_{0}'.format(i) for i in range(_METHODS_COUNT)] 47 _PASSES = ['pass_{0}'.format(i) for i in range(_PASSES_COUNT)] 48 _FAILING_METHOD = _METHODS[_FAILING_METHOD_IDX] 49 _FAILING_PASS = _PASSES[_FAILING_PASS_IDX] 50 _MANDATORY_PASS = MANDATORY_PASSES[0] 51 52 def setUp(self): 53 self.testable_mock = Mock(spec=Dex2OatWrapperTestable) 54 self.testable_mock.GetAllMethods.return_value = self._METHODS 55 self.testable_mock.GetAllPassesForMethod.return_value = self._PASSES 56 57 def MethodFailsForAllPasses(self, compiled_methods, run_passes=None): 58 return self._FAILING_METHOD not in compiled_methods 59 60 def MethodFailsForAPass(self, compiled_methods, run_passes=None): 61 return (self._FAILING_METHOD not in compiled_methods or 62 (run_passes is not None and self._FAILING_PASS not in run_passes)) 63 64 def testNeverFails(self): 65 self.testable_mock.Test.return_value = True 66 res = BugSearch(self.testable_mock) 67 self.assertEqual(res, (None, None)) 68 69 def testAlwaysFails(self): 70 self.testable_mock.Test.return_value = False 71 with self.assertRaises(FatalError): 72 BugSearch(self.testable_mock) 73 74 def testAMethodFailsForAllPasses(self): 75 self.testable_mock.Test.side_effect = self.MethodFailsForAllPasses 76 res = BugSearch(self.testable_mock) 77 self.assertEqual(res, (self._FAILING_METHOD, None)) 78 79 def testAMethodFailsForAPass(self): 80 self.testable_mock.Test.side_effect = self.MethodFailsForAPass 81 res = BugSearch(self.testable_mock) 82 self.assertEqual(res, (self._FAILING_METHOD, self._FAILING_PASS)) 83 84 def testMandatoryPassPresent(self): 85 self.testable_mock.GetAllPassesForMethod.return_value += ( 86 [self._MANDATORY_PASS]) 87 self.testable_mock.Test.side_effect = self.MethodFailsForAPass 88 BugSearch(self.testable_mock) 89 for (ordered_args, keyword_args) in self.testable_mock.Test.call_args_list: 90 passes = None 91 if 'run_passes' in keyword_args: 92 passes = keyword_args['run_passes'] 93 if len(ordered_args) > 1: # run_passes passed as ordered argument 94 passes = ordered_args[1] 95 if passes is not None: 96 self.assertIn(self._MANDATORY_PASS, passes) 97 98if __name__ == '__main__': 99 unittest.main() 100