| # This source file is part of the Swift.org open source project |
| # |
| # Copyright (c) 2014 - 2020 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 |
| |
| |
| from __future__ import unicode_literals |
| |
| import os |
| import unittest |
| |
| from build_swift import constants |
| from build_swift import presets |
| from build_swift.presets import Preset, PresetParser |
| |
| import six |
| from six.moves import configparser |
| |
| from .. import utils |
| |
| |
| # ----------------------------------------------------------------------------- |
| # Constants |
| |
| PRESET_FILES = [ |
| os.path.join(constants.UTILS_PATH, 'build-presets.ini'), |
| ] |
| |
| PRESET_DEFAULTS = { |
| 'darwin_toolchain_alias': 'Alias', |
| 'darwin_toolchain_bundle_identifier': 'BundleIdentifier', |
| 'darwin_toolchain_display_name': 'DisplayName', |
| 'darwin_toolchain_display_name_short': 'DispalyNameShort', |
| 'darwin_toolchain_version': '1.0', |
| 'darwin_toolchain_xctoolchain_name': 'default', |
| # SWIFT_ENABLE_TENSORFLOW |
| 'darwin_toolchain_installer_package': '/tmp/install/swift-installer.pkg', |
| # SWIFT_ENABLE_TENSORFLOW |
| 'darwin_toolchain_application_cert': 'cert_name', |
| 'extra_swift_args': '', |
| 'install_destdir': '/tmp/install', |
| 'install_symroot': '/tmp/install/symroot', |
| 'install_all': False, |
| 'install_toolchain_dir': '/tmp/install/toolchain', |
| 'install_prefix': '/usr', |
| 'installable_package': '/tmp/install/pkg', |
| 'swift_install_destdir': '/tmp/install/swift', |
| 'symbols_package': '/path/to/symbols/package', |
| 'ndk_path': '/path/to/ndk', |
| 'arm_dir': '/path/to/arm', |
| 'toolchain_path': '/tmp/toolchain', |
| } |
| |
| SAMPLE_PRESET = """ |
| [preset: sample] |
| |
| # This is a comment |
| |
| ios |
| tvos |
| watchos |
| test |
| validation-test |
| lit-args=-v |
| compiler-vendor=apple |
| |
| # The '--' argument is now unnecessary |
| dash-dash |
| |
| verbose-build |
| build-ninja |
| |
| # Default interpolation |
| install-symroot=%(install_symroot)s |
| """ |
| |
| IGNORED_SECTION = """ |
| [section_name] |
| |
| random-options=1 |
| """ |
| |
| MIXIN_ORDER_PRESETS = """ |
| [preset: test_mixin] |
| first-opt=0 |
| second-opt=1 |
| |
| |
| [preset: test] |
| first-opt=1 |
| mixin-preset=test_mixin |
| second-opt=2 |
| """ |
| |
| INTERPOLATED_PRESET = """ |
| [preset: test] |
| |
| install-symroot=%(install_symroot)s |
| """ |
| |
| DUPLICATE_PRESET_NAMES = """ |
| [preset: test] |
| ios |
| |
| |
| [preset: test] |
| tvos |
| """ |
| |
| DUPLICATE_PRESET_OPTIONS = """ |
| [preset: test] |
| |
| ios |
| ios |
| """ |
| |
| |
| # ----------------------------------------------------------------------------- |
| |
| class TestPreset(unittest.TestCase): |
| |
| def test_args(self): |
| preset = Preset('sample', [('ios', None), ('test', '1')]) |
| |
| self.assertEqual(preset.args, ['--ios', '--test=1']) |
| |
| |
| # ----------------------------------------------------------------------------- |
| |
| class TestPresetParserMeta(type): |
| """Metaclass used to dynamically generate test methods to validate all of |
| the available presets. |
| """ |
| |
| def __new__(cls, name, bases, attrs): |
| preset_parser = PresetParser() |
| preset_parser.read_files(PRESET_FILES) |
| |
| # Generate tests for each preset |
| for preset_name in preset_parser.preset_names: |
| test_name = 'test_get_preset_' + preset_name |
| attrs[test_name] = cls.generate_get_preset_test( |
| preset_parser, preset_name) |
| |
| return super(TestPresetParserMeta, cls).__new__( |
| cls, name, bases, attrs) |
| |
| @classmethod |
| def generate_get_preset_test(cls, preset_parser, preset_name): |
| def test(self): |
| preset_parser.get_preset(preset_name, vars=PRESET_DEFAULTS) |
| |
| return test |
| |
| |
| @six.add_metaclass(TestPresetParserMeta) |
| class TestPresetParser(unittest.TestCase): |
| |
| def test_read_files(self): |
| parser = PresetParser() |
| parser.read_files(PRESET_FILES) |
| |
| def test_read_invalid_files(self): |
| parser = PresetParser() |
| |
| with self.assertRaises(presets.UnparsedFilesError) as cm: |
| parser.read_files(['nonsense-presets.ini']) |
| |
| e = cm.exception |
| unparsed = e.unparsed_files |
| self.assertEqual(len(unparsed), 1) |
| self.assertEqual(unparsed[0].filename, 'nonsense-presets.ini') |
| self.assertIsInstance(unparsed[0].reason, IOError) |
| |
| def test_read_file(self): |
| parser = PresetParser() |
| parser.read_file(PRESET_FILES[0]) |
| |
| def test_read_string(self): |
| parser = PresetParser() |
| parser.read_string(SAMPLE_PRESET) |
| |
| preset = parser.get_preset('sample', vars={'install_symroot': '/tmp'}) |
| self.assertIsNotNone(preset) |
| self.assertEqual(preset.name, 'sample') |
| self.assertListEqual(preset.options, [ |
| ('ios', None), |
| ('tvos', None), |
| ('watchos', None), |
| ('test', None), |
| ('validation-test', None), |
| ('lit-args', '-v'), |
| ('compiler-vendor', 'apple'), |
| ('verbose-build', None), |
| ('build-ninja', None), |
| ('install-symroot', '/tmp') |
| ]) |
| |
| def test_parser_ignores_non_preset_sections(self): |
| parser = PresetParser() |
| |
| parser.read_string(IGNORED_SECTION) |
| self.assertEqual(len(parser._presets), 0) |
| |
| def test_mixin_expansion_preserves_argument_order(self): |
| """Mixins should be expanded in-place. |
| """ |
| |
| parser = PresetParser() |
| |
| parser.read_string(MIXIN_ORDER_PRESETS) |
| |
| preset = parser.get_preset('test') |
| self.assertListEqual(preset.args, [ |
| '--first-opt=1', |
| |
| # Mixin arguments |
| '--first-opt=0', |
| '--second-opt=1', |
| |
| '--second-opt=2', |
| ]) |
| |
| def test_interpolation_error(self): |
| parser = PresetParser() |
| parser.read_string(INTERPOLATED_PRESET) |
| |
| with self.assertRaises(presets.InterpolationError) as cm: |
| parser.get_preset('test') |
| |
| e = cm.exception |
| self.assertEqual(e.preset_name, 'test') |
| self.assertEqual(e.option, 'install-symroot') |
| self.assertEqual(e.rawval, '%(install_symroot)s') |
| self.assertEqual(e.reference, 'install_symroot') |
| |
| @utils.requires_attr(configparser, 'DuplicateOptionError') |
| def test_duplicate_option_error(self): |
| parser = PresetParser() |
| |
| with self.assertRaises(presets.DuplicateOptionError) as cm: |
| parser.read_string(DUPLICATE_PRESET_OPTIONS) |
| |
| e = cm.exception |
| self.assertEqual(e.preset_name, 'test') |
| self.assertEqual(e.option, 'ios') |
| |
| @utils.requires_attr(configparser, 'DuplicateOptionError') |
| def test_duplicate_preset_error(self): |
| parser = PresetParser() |
| |
| with self.assertRaises(presets.DuplicatePresetError) as cm: |
| parser.read_string(DUPLICATE_PRESET_NAMES) |
| |
| e = cm.exception |
| self.assertEqual(e.preset_name, 'test') |
| |
| def test_get_preset_raw(self): |
| parser = PresetParser() |
| parser.read_string(INTERPOLATED_PRESET) |
| |
| preset = parser.get_preset('test', raw=True) |
| self.assertEqual(preset.options, [ |
| ('install-symroot', '%(install_symroot)s') |
| ]) |
| |
| def test_get_missing_preset(self): |
| parser = PresetParser() |
| |
| with self.assertRaises(presets.PresetNotFoundError) as cm: |
| parser.get_preset('test') |
| |
| e = cm.exception |
| self.assertEqual(e.preset_name, 'test') |
| |
| def test_preset_names(self): |
| parser = PresetParser() |
| |
| parser.read_string('[preset: foo]') |
| parser.read_string('[preset: bar]') |
| parser.read_string('[preset: baz]') |
| |
| self.assertEqual(set(parser.preset_names), |
| set(['foo', 'bar', 'baz'])) |