# ==--- opt_bug_reducer_test.py ------------------------------------------===# # # This source file is part of the Swift.org open source project # # Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors # Licensed under Apache License v2.0 with Runtime Library Exception # # See https://swift.org/LICENSE.txt for license information # See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors # # ==----------------------------------------------------------------------===# import json import os import platform import random import re import shutil import subprocess import unittest import bug_reducer.swift_tools as swift_tools @unittest.skipUnless(platform.system() == 'Darwin', 'opt_bug_reducer is only available on Darwin for now') class OptBugReducerTestCase(unittest.TestCase): def setUp(self): self.file_dir = os.path.dirname(os.path.abspath(__file__)) self.reducer = os.path.join(os.path.dirname(self.file_dir), 'bug_reducer', 'bug_reducer.py') self.build_dir = os.path.abspath( os.environ['BUGREDUCE_TEST_SWIFT_OBJ_ROOT']) (root, _) = os.path.splitext(os.path.abspath(__file__)) self.root_basename = ''.join(os.path.basename(root).split('_')) self.tmp_dir = os.path.join(os.path.abspath( os.environ['BUGREDUCE_TEST_TMP_DIR']), self.root_basename) subprocess.call(['mkdir', '-p', self.tmp_dir]) self.module_cache = os.path.join(self.tmp_dir, 'module_cache') self.sdk = subprocess.check_output(['xcrun', '--sdk', 'macosx', '--toolchain', 'Default', '--show-sdk-path']).strip("\n") self.tools = swift_tools.SwiftTools(self.build_dir) json_data = json.loads(subprocess.check_output( [self.tools.sil_passpipeline_dumper, '-Performance'])) self.passes = [] for y in (x[2:] for x in json_data): for z in y: self.passes.append('--pass=-' + z[1]) random.seed(0xf487c07f) random.shuffle(self.passes) self.passes.insert(random.randint(0, len(self.passes)), '--pass=-bug-reducer-tester') if os.access(self.tmp_dir, os.F_OK): shutil.rmtree(self.tmp_dir) os.makedirs(self.tmp_dir) os.makedirs(self.module_cache) def _get_test_file_path(self, module_name): return os.path.join(self.file_dir, '{}_{}.swift'.format( self.root_basename, module_name)) def _get_sib_file_path(self, filename): (root, ext) = os.path.splitext(filename) return os.path.join(self.tmp_dir, os.path.basename(root) + '.sib') def run_swiftc_command(self, name): input_file_path = self._get_test_file_path(name) args = [self.tools.swiftc, '-module-cache-path', self.module_cache, '-sdk', self.sdk, '-Onone', '-parse-as-library', '-module-name', name, '-emit-sib', '-resource-dir', os.path.join(self.build_dir, 'lib', 'swift'), '-o', self._get_sib_file_path(input_file_path), input_file_path] subprocess.check_call(args) def test_basic(self): name = 'testbasic' self.run_swiftc_command(name) args = [ self.reducer, 'opt', self.build_dir, self._get_sib_file_path(self._get_test_file_path(name)), '--sdk=%s' % self.sdk, '--module-cache=%s' % self.module_cache, '--module-name=%s' % name, '--work-dir=%s' % self.tmp_dir, '--extra-arg=-bug-reducer-tester-target-func=test_target', '--extra-arg=-bug-reducer-tester-failure-kind=opt-crasher' ] args.extend(self.passes) output = subprocess.check_output(args).split("\n") self.assertTrue('*** Found miscompiling passes!' in output) self.assertTrue('*** Final Passes: --bug-reducer-tester' in output) re_end = 'testoptbugreducer_testbasic_initial' output_file_re = re.compile(r'\*\*\* Final File: .*' + re_end) output_matches = [ 1 for o in output if output_file_re.match(o) is not None] self.assertEqual(sum(output_matches), 1) # Make sure our final output command does not have -emit-sib in # the output. We want users to get sil output when they type in # the relevant command. self.assertEqual([], [o for o in output if '-emit-sib' in o]) def test_suffix_in_need_of_prefix(self): name = 'testsuffixinneedofprefix' self.run_swiftc_command(name) args = [ self.reducer, 'opt', self.build_dir, self._get_sib_file_path(self._get_test_file_path(name)), '--sdk=%s' % self.sdk, '--module-cache=%s' % self.module_cache, '--module-name=%s' % name, '--work-dir=%s' % self.tmp_dir, '--extra-arg=-bug-reducer-tester-target-func=closure_test_target', '--extra-arg=-bug-reducer-tester-failure-kind=opt-crasher' ] args.extend(self.passes) output = subprocess.check_output(args).split("\n") self.assertTrue('*** Found miscompiling passes!' in output) self.assertTrue('*** Final Passes: --bug-reducer-tester' in output) re_end = 'testoptbugreducer_testsuffixinneedofprefix_initial' output_file_re = re.compile(r'\*\*\* Final File: .*' + re_end) output_matches = [ 1 for o in output if output_file_re.match(o) is not None] self.assertEqual(sum(output_matches), 1) # Make sure our final output command does not have -emit-sib in the # output. We want users to get sil output when they type in the # relevant command. self.assertEqual([], [o for o in output if '-emit-sib' in o]) def test_reduce_function(self): name = 'testreducefunction' self.run_swiftc_command(name) args = [ self.reducer, 'opt', self.build_dir, self._get_sib_file_path(self._get_test_file_path(name)), '--sdk=%s' % self.sdk, '--module-cache=%s' % self.module_cache, '--module-name=%s' % name, '--work-dir=%s' % self.tmp_dir, '--extra-arg=-bug-reducer-tester-target-func=__TF_test_target', '--extra-arg=-bug-reducer-tester-failure-kind=opt-crasher', '--reduce-sil' ] args.extend(self.passes) output = subprocess.check_output(args).split("\n") self.assertTrue('*** Found miscompiling passes!' in output) self.assertTrue( '*** Final Functions: $s18testreducefunction6foo413yyF' in output) self.assertTrue('*** Final Passes: --bug-reducer-tester' in output) re_end = 'testoptbugreducer_testreducefunction_initial_' re_end += '30775a3d942671a403702a9846afa7a4.sib' output_file_re = re.compile(r'\*\*\* Final File: .*' + re_end) output_matches = [ 1 for o in output if output_file_re.match(o) is not None] self.assertEqual(sum(output_matches), 1) # Make sure our final output command does not have -emit-sib in the # output. We want users to get sil output when they type in the # relevant command. self.assertEqual([], [o for o in output if '-emit-sib' in o]) if __name__ == '__main__': unittest.main()