#!/usr/bin/env python3 # # Copyright (C) 2016 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Tests for bisection-search module.""" import unittest from unittest.mock import Mock from bisection_search import BugSearch from bisection_search import Dex2OatWrapperTestable from bisection_search import FatalError from bisection_search import MANDATORY_PASSES class BisectionTestCase(unittest.TestCase): """BugSearch method test case. Integer constants were chosen arbitrarily. They should be large enough and random enough to ensure binary search does nontrivial work. Attributes: _METHODS: list of strings, methods compiled by testable _PASSES: list of strings, passes run by testable _FAILING_METHOD: string, name of method which fails in some tests _FAILING_PASS: string, name of pass which fails in some tests _MANDATORY_PASS: string, name of a mandatory pass """ _METHODS_COUNT = 1293 _PASSES_COUNT = 573 _FAILING_METHOD_IDX = 237 _FAILING_PASS_IDX = 444 _METHODS = ['method_{0}'.format(i) for i in range(_METHODS_COUNT)] _PASSES = ['pass_{0}'.format(i) for i in range(_PASSES_COUNT)] _FAILING_METHOD = _METHODS[_FAILING_METHOD_IDX] _FAILING_PASS = _PASSES[_FAILING_PASS_IDX] _MANDATORY_PASS = MANDATORY_PASSES[0] def setUp(self): self.testable_mock = Mock(spec=Dex2OatWrapperTestable) self.testable_mock.GetAllMethods.return_value = self._METHODS self.testable_mock.GetAllPassesForMethod.return_value = self._PASSES def MethodFailsForAllPasses(self, compiled_methods, run_passes=None): return self._FAILING_METHOD not in compiled_methods def MethodFailsForAPass(self, compiled_methods, run_passes=None): return (self._FAILING_METHOD not in compiled_methods or (run_passes is not None and self._FAILING_PASS not in run_passes)) def testNeverFails(self): self.testable_mock.Test.return_value = True res = BugSearch(self.testable_mock) self.assertEqual(res, (None, None)) def testAlwaysFails(self): self.testable_mock.Test.return_value = False with self.assertRaises(FatalError): BugSearch(self.testable_mock) def testAMethodFailsForAllPasses(self): self.testable_mock.Test.side_effect = self.MethodFailsForAllPasses res = BugSearch(self.testable_mock) self.assertEqual(res, (self._FAILING_METHOD, None)) def testAMethodFailsForAPass(self): self.testable_mock.Test.side_effect = self.MethodFailsForAPass res = BugSearch(self.testable_mock) self.assertEqual(res, (self._FAILING_METHOD, self._FAILING_PASS)) def testMandatoryPassPresent(self): self.testable_mock.GetAllPassesForMethod.return_value += ( [self._MANDATORY_PASS]) self.testable_mock.Test.side_effect = self.MethodFailsForAPass BugSearch(self.testable_mock) for (ordered_args, keyword_args) in self.testable_mock.Test.call_args_list: passes = None if 'run_passes' in keyword_args: passes = keyword_args['run_passes'] if len(ordered_args) > 1: # run_passes passed as ordered argument passes = ordered_args[1] if passes is not None: self.assertIn(self._MANDATORY_PASS, passes) if __name__ == '__main__': unittest.main()