brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.8 KiB · b8ee2ca Raw
630 lines · python
1# ===----------------------------------------------------------------------===##2#3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4# See https://llvm.org/LICENSE.txt for license information.5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6#7# ===----------------------------------------------------------------------===##8 9# With picolibc, test_program_stderr_is_not_conflated_with_stdout fails10# because stdout & stderr are treated as the same.11# XFAIL: LIBCXX-PICOLIBC-FIXME12 13# Note: We prepend arguments with 'x' to avoid thinking there are too few14#       arguments in case an argument is an empty string.15# RUN: %{python} %s x%S x%{temp} x%{substitutions}16 17import base6418import copy19import os20import pickle21import platform22import subprocess23import sys24import unittest25from os.path import dirname26 27# Allow importing 'lit' and the 'libcxx' module. Make sure we put the lit28# path first so we don't find any system-installed version.29monorepoRoot = dirname(dirname(dirname(dirname(dirname(__file__)))))30sys.path = [31    os.path.join(monorepoRoot, "libcxx", "utils"),32    os.path.join(monorepoRoot, "llvm", "utils", "lit"),33] + sys.path34import libcxx.test.dsl as dsl35import lit.LitConfig36import lit.util37 38# Steal some parameters from the config running this test so that we can39# bootstrap our own TestingConfig.40args = list(map(lambda s: s[1:], sys.argv[1:8]))  # Remove the leading 'x'41SOURCE_ROOT, EXEC_PATH, SUBSTITUTIONS = args42sys.argv[1:8] = []43 44# Decode the substitutions.45SUBSTITUTIONS = pickle.loads(base64.b64decode(SUBSTITUTIONS))46for s, sub in SUBSTITUTIONS:47    print("Substitution '{}' is '{}'".format(s, sub))48 49 50class SetupConfigs(unittest.TestCase):51    """52    Base class for the tests below -- it creates a fake TestingConfig.53    """54 55    def setUp(self):56        """57        Create a fake TestingConfig that can be populated however we wish for58        the purpose of running unit tests below. We pre-populate it with the59        minimum required substitutions.60        """61        self.litConfig = lit.LitConfig.LitConfig(62            progname="lit",63            path=[],64            diagnostic_level="note",65            useValgrind=False,66            valgrindLeakCheck=False,67            valgrindArgs=[],68            noExecute=False,69            debug=False,70            isWindows=platform.system() == "Windows",71            order="smart",72            params={},73        )74 75        self.config = lit.TestingConfig.TestingConfig.fromdefaults(self.litConfig)76        self.config.environment = dict(os.environ)77        self.config.test_source_root = SOURCE_ROOT78        self.config.test_exec_root = EXEC_PATH79        self.config.recursiveExpansionLimit = 1080        self.config.substitutions = copy.deepcopy(SUBSTITUTIONS)81 82    def getSubstitution(self, substitution):83        """84        Return a given substitution from the TestingConfig. It is an error if85        there is no such substitution.86        """87        found = [x for (s, x) in self.config.substitutions if s == substitution]88        assert len(found) == 189        return found[0]90 91 92def findIndex(list, pred):93    """Finds the index of the first element satisfying 'pred' in a list, or94    'len(list)' if there is no such element."""95    index = 096    for x in list:97        if pred(x):98            break99        else:100            index += 1101    return index102 103 104class TestHasCompileFlag(SetupConfigs):105    """106    Tests for libcxx.test.dsl.hasCompileFlag107    """108 109    def test_no_flag_should_work(self):110        self.assertTrue(dsl.hasCompileFlag(self.config, ""))111 112    def test_flag_exists(self):113        self.assertTrue(dsl.hasCompileFlag(self.config, "-O1"))114 115    def test_nonexistent_flag(self):116        self.assertFalse(117            dsl.hasCompileFlag(self.config, "-this_is_not_a_flag_any_compiler_has")118        )119 120    def test_multiple_flags(self):121        self.assertTrue(dsl.hasCompileFlag(self.config, "-O1 -Dhello"))122 123 124class TestSourceBuilds(SetupConfigs):125    """126    Tests for libcxx.test.dsl.sourceBuilds127    """128 129    def test_valid_program_builds(self):130        source = """int main(int, char**) { return 0; }"""131        self.assertTrue(dsl.sourceBuilds(self.config, source))132 133    def test_compilation_error_fails(self):134        source = """int main(int, char**) { this does not compile }"""135        self.assertFalse(dsl.sourceBuilds(self.config, source))136 137    def test_link_error_fails(self):138        source = """extern void this_isnt_defined_anywhere();139                    int main(int, char**) { this_isnt_defined_anywhere(); return 0; }"""140        self.assertFalse(dsl.sourceBuilds(self.config, source))141 142 143class TestProgramOutput(SetupConfigs):144    """145    Tests for libcxx.test.dsl.programOutput146    """147 148    def test_valid_program_returns_output(self):149        source = """150        #include <cstdio>151        int main(int, char**) { std::printf("FOOBAR"); return 0; }152        """153        self.assertEqual(dsl.programOutput(self.config, source), "FOOBAR")154 155    def test_valid_program_returns_output_newline_handling(self):156        source = """157        #include <cstdio>158        int main(int, char**) { std::printf("FOOBAR\\n"); return 0; }159        """160        self.assertEqual(dsl.programOutput(self.config, source), "FOOBAR\n")161 162    def test_valid_program_returns_no_output(self):163        source = """164        int main(int, char**) { return 0; }165        """166        self.assertEqual(dsl.programOutput(self.config, source), "")167 168    def test_program_that_fails_to_run_raises_runtime_error(self):169        # The program compiles, but exits with an error170        source = """171        int main(int, char**) { return 1; }172        """173        self.assertRaises(174            dsl.ConfigurationRuntimeError,175            lambda: dsl.programOutput(self.config, source),176        )177 178    def test_program_that_fails_to_compile_raises_compilation_error(self):179        # The program doesn't compile180        source = """181        int main(int, char**) { this doesnt compile }182        """183        self.assertRaises(184            dsl.ConfigurationCompilationError,185            lambda: dsl.programOutput(self.config, source),186        )187 188    def test_pass_arguments_to_program(self):189        source = """190        #include <cassert>191        #include <string>192        int main(int argc, char** argv) {193            assert(argc == 3);194            assert(argv[1] == std::string("first-argument"));195            assert(argv[2] == std::string("second-argument"));196            return 0;197        }198        """199        args = ["first-argument", "second-argument"]200        self.assertEqual(dsl.programOutput(self.config, source, args=args), "")201 202    def test_caching_is_not_too_aggressive(self):203        # Run a program, then change the substitutions and run it again.204        # Make sure the program is run the second time and the right result205        # is given, to ensure we're not incorrectly caching the result of the206        # first program run.207        source = """208        #include <cstdio>209        int main(int, char**) {210            std::printf("MACRO=%u\\n", MACRO);211            return 0;212        }213        """214        compileFlagsIndex = findIndex(215            self.config.substitutions, lambda x: x[0] == "%{compile_flags}"216        )217        compileFlags = self.config.substitutions[compileFlagsIndex][1]218 219        self.config.substitutions[compileFlagsIndex] = (220            "%{compile_flags}",221            compileFlags + " -DMACRO=1",222        )223        output1 = dsl.programOutput(self.config, source)224        self.assertEqual(output1, "MACRO=1\n")225 226        self.config.substitutions[compileFlagsIndex] = (227            "%{compile_flags}",228            compileFlags + " -DMACRO=2",229        )230        output2 = dsl.programOutput(self.config, source)231        self.assertEqual(output2, "MACRO=2\n")232 233    def test_program_stderr_is_not_conflated_with_stdout(self):234        # Run a program that produces stdout output and stderr output too, making235        # sure the stderr output does not pollute the stdout output.236        source = """237        #include <cstdio>238        int main(int, char**) {239            std::fprintf(stdout, "STDOUT-OUTPUT");240            std::fprintf(stderr, "STDERR-OUTPUT");241            return 0;242        }243        """244        self.assertEqual(dsl.programOutput(self.config, source), "STDOUT-OUTPUT")245 246 247class TestProgramSucceeds(SetupConfigs):248    """249    Tests for libcxx.test.dsl.programSucceeds250    """251 252    def test_success(self):253        source = """254        int main(int, char**) { return 0; }255        """256        self.assertTrue(dsl.programSucceeds(self.config, source))257 258    def test_failure(self):259        source = """260        int main(int, char**) { return 1; }261        """262        self.assertFalse(dsl.programSucceeds(self.config, source))263 264    def test_compile_failure(self):265        source = """266        this does not compile267        """268        self.assertRaises(269            dsl.ConfigurationCompilationError,270            lambda: dsl.programSucceeds(self.config, source),271        )272 273 274class TestHasLocale(SetupConfigs):275    """276    Tests for libcxx.test.dsl.hasLocale277    """278 279    def test_doesnt_explode(self):280        # It's really hard to test that a system has a given locale, so at least281        # make sure we don't explode when we try to check it.282        try:283            dsl.hasAnyLocale(self.config, ["en_US.UTF-8"])284        except subprocess.CalledProcessError:285            self.fail("checking for hasLocale should not explode")286 287    def test_nonexistent_locale(self):288        self.assertFalse(289            dsl.hasAnyLocale(self.config, ["forsurethisisnotanexistinglocale"])290        )291 292    def test_localization_program_doesnt_compile(self):293        compilerIndex = findIndex(self.config.substitutions, lambda x: x[0] == "%{cxx}")294        self.config.substitutions[compilerIndex] = (295            "%{cxx}",296            "this-is-certainly-not-a-valid-compiler!!",297        )298        self.assertRaises(299            dsl.ConfigurationCompilationError,300            lambda: dsl.hasAnyLocale(self.config, ["en_US.UTF-8"]),301        )302 303 304class TestCompilerMacros(SetupConfigs):305    """306    Tests for libcxx.test.dsl.compilerMacros307    """308 309    def test_basic(self):310        macros = dsl.compilerMacros(self.config)311        self.assertIsInstance(macros, dict)312        self.assertGreater(len(macros), 0)313        for (k, v) in macros.items():314            self.assertIsInstance(k, str)315            self.assertIsInstance(v, str)316 317    def test_no_flag(self):318        macros = dsl.compilerMacros(self.config)319        self.assertIn("__cplusplus", macros.keys())320 321    def test_empty_flag(self):322        macros = dsl.compilerMacros(self.config, "")323        self.assertIn("__cplusplus", macros.keys())324 325    def test_with_flag(self):326        macros = dsl.compilerMacros(self.config, "-DFOO=3")327        self.assertIn("__cplusplus", macros.keys())328        self.assertEqual(macros["FOO"], "3")329 330    def test_with_flags(self):331        macros = dsl.compilerMacros(self.config, "-DFOO=3 -DBAR=hello")332        self.assertIn("__cplusplus", macros.keys())333        self.assertEqual(macros["FOO"], "3")334        self.assertEqual(macros["BAR"], "hello")335 336 337class TestFeatureTestMacros(SetupConfigs):338    """339    Tests for libcxx.test.dsl.featureTestMacros340    """341 342    def test_basic(self):343        macros = dsl.featureTestMacros(self.config)344        self.assertIsInstance(macros, dict)345        self.assertGreater(len(macros), 0)346        for (k, v) in macros.items():347            self.assertIsInstance(k, str)348            self.assertIsInstance(v, int)349 350 351class TestFeature(SetupConfigs):352    """353    Tests for libcxx.test.dsl.Feature354    """355 356    def test_trivial(self):357        feature = dsl.Feature(name="name")358        origSubstitutions = copy.deepcopy(self.config.substitutions)359        actions = feature.getActions(self.config)360        self.assertTrue(len(actions) == 1)361        for a in actions:362            a.applyTo(self.config)363        self.assertEqual(origSubstitutions, self.config.substitutions)364        self.assertIn("name", self.config.available_features)365 366    def test_name_can_be_a_callable(self):367        feature = dsl.Feature(name=lambda cfg: "name")368        for a in feature.getActions(self.config):369            a.applyTo(self.config)370        self.assertIn("name", self.config.available_features)371 372    def test_name_is_not_a_string_1(self):373        feature = dsl.Feature(name=None)374        self.assertRaises(ValueError, lambda: feature.getActions(self.config))375        self.assertRaises(ValueError, lambda: feature.pretty(self.config))376 377    def test_name_is_not_a_string_2(self):378        feature = dsl.Feature(name=lambda cfg: None)379        self.assertRaises(ValueError, lambda: feature.getActions(self.config))380        self.assertRaises(ValueError, lambda: feature.pretty(self.config))381 382    def test_adding_action(self):383        feature = dsl.Feature(name="name", actions=[dsl.AddCompileFlag("-std=c++03")])384        origLinkFlags = copy.deepcopy(self.getSubstitution("%{link_flags}"))385        for a in feature.getActions(self.config):386            a.applyTo(self.config)387        self.assertIn("name", self.config.available_features)388        self.assertIn("-std=c++03", self.getSubstitution("%{compile_flags}"))389        self.assertEqual(origLinkFlags, self.getSubstitution("%{link_flags}"))390 391    def test_actions_can_be_a_callable(self):392        feature = dsl.Feature(393            name="name",394            actions=lambda cfg: (395                self.assertIs(self.config, cfg),396                [dsl.AddCompileFlag("-std=c++03")],397            )[1],398        )399        for a in feature.getActions(self.config):400            a.applyTo(self.config)401        self.assertIn("-std=c++03", self.getSubstitution("%{compile_flags}"))402 403    def test_unsupported_feature(self):404        feature = dsl.Feature(name="name", when=lambda _: False)405        self.assertEqual(feature.getActions(self.config), [])406 407    def test_is_supported_gets_passed_the_config(self):408        feature = dsl.Feature(409            name="name", when=lambda cfg: (self.assertIs(self.config, cfg), True)[1]410        )411        self.assertEqual(len(feature.getActions(self.config)), 1)412 413 414def _throw():415    raise ValueError()416 417 418class TestParameter(SetupConfigs):419    """420    Tests for libcxx.test.dsl.Parameter421    """422 423    def test_empty_name_should_blow_up(self):424        self.assertRaises(425            ValueError,426            lambda: dsl.Parameter(427                name="", choices=["c++03"], type=str, help="", actions=lambda _: []428            ),429        )430 431    def test_empty_choices_should_blow_up(self):432        self.assertRaises(433            ValueError,434            lambda: dsl.Parameter(435                name="std", choices=[], type=str, help="", actions=lambda _: []436            ),437        )438 439    def test_no_choices_is_ok(self):440        param = dsl.Parameter(name="triple", type=str, help="", actions=lambda _: [])441        self.assertEqual(param.name, "triple")442 443    def test_name_is_set_correctly(self):444        param = dsl.Parameter(445            name="std", choices=["c++03"], type=str, help="", actions=lambda _: []446        )447        self.assertEqual(param.name, "std")448 449    def test_no_value_provided_and_no_default_value(self):450        param = dsl.Parameter(451            name="std", choices=["c++03"], type=str, help="", actions=lambda _: []452        )453        self.assertRaises(454            ValueError, lambda: param.getActions(self.config, self.litConfig.params)455        )456 457    def test_no_value_provided_and_default_value(self):458        param = dsl.Parameter(459            name="std",460            choices=["c++03"],461            type=str,462            help="",463            default="c++03",464            actions=lambda std: [dsl.AddFeature(std)],465        )466        for a in param.getActions(self.config, self.litConfig.params):467            a.applyTo(self.config)468        self.assertIn("c++03", self.config.available_features)469 470    def test_value_provided_on_command_line_and_no_default_value(self):471        self.litConfig.params["std"] = "c++03"472        param = dsl.Parameter(473            name="std",474            choices=["c++03"],475            type=str,476            help="",477            actions=lambda std: [dsl.AddFeature(std)],478        )479        for a in param.getActions(self.config, self.litConfig.params):480            a.applyTo(self.config)481        self.assertIn("c++03", self.config.available_features)482 483    def test_value_provided_on_command_line_and_default_value(self):484        """The value provided on the command line should override the default value"""485        self.litConfig.params["std"] = "c++11"486        param = dsl.Parameter(487            name="std",488            choices=["c++03", "c++11"],489            type=str,490            default="c++03",491            help="",492            actions=lambda std: [dsl.AddFeature(std)],493        )494        for a in param.getActions(self.config, self.litConfig.params):495            a.applyTo(self.config)496        self.assertIn("c++11", self.config.available_features)497        self.assertNotIn("c++03", self.config.available_features)498 499    def test_value_provided_in_config_and_default_value(self):500        """The value provided in the config should override the default value"""501        self.config.std = "c++11"502        param = dsl.Parameter(503            name="std",504            choices=["c++03", "c++11"],505            type=str,506            default="c++03",507            help="",508            actions=lambda std: [dsl.AddFeature(std)],509        )510        for a in param.getActions(self.config, self.litConfig.params):511            a.applyTo(self.config)512        self.assertIn("c++11", self.config.available_features)513        self.assertNotIn("c++03", self.config.available_features)514 515    def test_value_provided_in_config_and_on_command_line(self):516        """The value on the command line should override the one in the config"""517        self.config.std = "c++11"518        self.litConfig.params["std"] = "c++03"519        param = dsl.Parameter(520            name="std",521            choices=["c++03", "c++11"],522            type=str,523            help="",524            actions=lambda std: [dsl.AddFeature(std)],525        )526        for a in param.getActions(self.config, self.litConfig.params):527            a.applyTo(self.config)528        self.assertIn("c++03", self.config.available_features)529        self.assertNotIn("c++11", self.config.available_features)530 531    def test_no_actions(self):532        self.litConfig.params["std"] = "c++03"533        param = dsl.Parameter(534            name="std", choices=["c++03"], type=str, help="", actions=lambda _: []535        )536        actions = param.getActions(self.config, self.litConfig.params)537        self.assertEqual(actions, [])538 539    def test_boolean_value_parsed_from_trueish_string_parameter(self):540        self.litConfig.params["enable_exceptions"] = "True"541        param = dsl.Parameter(542            name="enable_exceptions",543            choices=[True, False],544            type=bool,545            help="",546            actions=lambda exceptions: [] if exceptions else _throw(),547        )548        self.assertEqual(param.getActions(self.config, self.litConfig.params), [])549 550    def test_boolean_value_from_true_boolean_parameter(self):551        self.litConfig.params["enable_exceptions"] = True552        param = dsl.Parameter(553            name="enable_exceptions",554            choices=[True, False],555            type=bool,556            help="",557            actions=lambda exceptions: [] if exceptions else _throw(),558        )559        self.assertEqual(param.getActions(self.config, self.litConfig.params), [])560 561    def test_boolean_value_parsed_from_falseish_string_parameter(self):562        self.litConfig.params["enable_exceptions"] = "False"563        param = dsl.Parameter(564            name="enable_exceptions",565            choices=[True, False],566            type=bool,567            help="",568            actions=lambda exceptions: []569            if exceptions570            else [dsl.AddFeature("-fno-exceptions")],571        )572        for a in param.getActions(self.config, self.litConfig.params):573            a.applyTo(self.config)574        self.assertIn("-fno-exceptions", self.config.available_features)575 576    def test_boolean_value_from_false_boolean_parameter(self):577        self.litConfig.params["enable_exceptions"] = False578        param = dsl.Parameter(579            name="enable_exceptions",580            choices=[True, False],581            type=bool,582            help="",583            actions=lambda exceptions: []584            if exceptions585            else [dsl.AddFeature("-fno-exceptions")],586        )587        for a in param.getActions(self.config, self.litConfig.params):588            a.applyTo(self.config)589        self.assertIn("-fno-exceptions", self.config.available_features)590 591    def test_list_parsed_from_comma_delimited_string_empty(self):592        self.litConfig.params["additional_features"] = ""593        param = dsl.Parameter(594            name="additional_features", type=list, help="", actions=lambda f: f595        )596        self.assertEqual(param.getActions(self.config, self.litConfig.params), [])597 598    def test_list_parsed_from_comma_delimited_string_1(self):599        self.litConfig.params["additional_features"] = "feature1"600        param = dsl.Parameter(601            name="additional_features", type=list, help="", actions=lambda f: f602        )603        self.assertEqual(604            param.getActions(self.config, self.litConfig.params), ["feature1"]605        )606 607    def test_list_parsed_from_comma_delimited_string_2(self):608        self.litConfig.params["additional_features"] = "feature1,feature2"609        param = dsl.Parameter(610            name="additional_features", type=list, help="", actions=lambda f: f611        )612        self.assertEqual(613            param.getActions(self.config, self.litConfig.params),614            ["feature1", "feature2"],615        )616 617    def test_list_parsed_from_comma_delimited_string_3(self):618        self.litConfig.params["additional_features"] = "feature1,feature2, feature3"619        param = dsl.Parameter(620            name="additional_features", type=list, help="", actions=lambda f: f621        )622        self.assertEqual(623            param.getActions(self.config, self.litConfig.params),624            ["feature1", "feature2", "feature3"],625        )626 627 628if __name__ == "__main__":629    unittest.main(verbosity=2)630