|
1 | 1 | import json |
| 2 | +import os |
| 3 | +import platform |
2 | 4 | import re |
3 | 5 | import textwrap |
4 | 6 | import unittest |
|
8 | 10 | from conan.cli.exit_codes import ERROR_INVALID_CONFIGURATION, ERROR_GENERAL |
9 | 11 | from conans.client.graph.graph import BINARY_INVALID |
10 | 12 | from conan.test.assets.genconanfile import GenConanfile |
11 | | -from conans.util.files import save |
| 13 | +from conans.util.files import save, load |
12 | 14 | from conan.test.utils.tools import TestClient, NO_SETTINGS_PACKAGE_ID |
13 | 15 |
|
14 | 16 |
|
@@ -698,6 +700,65 @@ def compatibility(self): |
698 | 700 | assert "compiler.cppstd=14" in client.out |
699 | 701 | assert "compiler.cppstd=17" not in client.out |
700 | 702 |
|
| 703 | + @pytest.mark.skipif(platform.system() == "Windows", reason="Needs at least 3 cppstd values available, msvc 191 does not") |
| 704 | + def test_extension_properties_cppstd_compat_non_transitiveness(self): |
| 705 | + """ |
| 706 | + The cppstd_compat is not transitive, so if a recipe has cppstd_compat=False, |
| 707 | + its dependencies will still be checked for compatibility |
| 708 | + """ |
| 709 | + tc = TestClient() |
| 710 | + tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0").with_setting("compiler"), |
| 711 | + "lib/conanfile.py": GenConanfile("lib", "1.0") |
| 712 | + .with_setting("compiler") |
| 713 | + .with_class_attribute('extension_properties = {"compatibility_cppstd": False}') |
| 714 | + .with_requirement("dep/1.0"), |
| 715 | + "app/conanfile.py": GenConanfile("app", "1.0") |
| 716 | + .with_setting("compiler") |
| 717 | + .with_requirement("lib/1.0")}) |
| 718 | + tc.run("create dep -s=compiler.cppstd=20") |
| 719 | + tc.run("create lib -s=compiler.cppstd=17") |
| 720 | + tc.run("create app -s=compiler.cppstd=14", assert_error=True) |
| 721 | + |
| 722 | + tc.run("install --requires=app/1.0 -s=compiler.cppstd=11", assert_error=True) |
| 723 | + assert "dep/1.0: Found compatible package" in tc.out |
| 724 | + assert "ERROR: Missing binary: app/1.0" in tc.out |
| 725 | + |
| 726 | + def test_extension_properties_make_transitive(self): |
| 727 | + """ |
| 728 | + The cppstd_compat is not transitive, so if a recipe has cppstd_compat=False, |
| 729 | + its dependencies will still be checked for compatibility |
| 730 | + """ |
| 731 | + tc = TestClient() |
| 732 | + tc.save({"lib/conanfile.py": GenConanfile("lib", "1.0").with_setting("compiler"), |
| 733 | + "dep/conanfile.py": GenConanfile("dep", "1.0") |
| 734 | + .with_setting("compiler") |
| 735 | + .with_class_attribute('extension_properties = {"compatibility_cppstd": False}') |
| 736 | + .with_requirement("lib/1.0"), |
| 737 | + "conanfile.py": GenConanfile("app", "1.0") |
| 738 | + .with_setting("compiler") |
| 739 | + .with_requirement("dep/1.0")}) |
| 740 | + tc.run("create lib -s=compiler.cppstd=17") |
| 741 | + tc.run("create dep -s=compiler.cppstd=14") |
| 742 | + tc.run("create . -s=compiler.cppstd=14") |
| 743 | + |
| 744 | + compat_path = os.path.join(tc.cache_folder, "extensions/plugins/compatibility/compatibility.py") |
| 745 | + compat_contents = load(compat_path) |
| 746 | + |
| 747 | + transitive_expansions = textwrap.indent(textwrap.dedent(""" |
| 748 | + extension_properties = getattr(conanfile, "extension_properties", {}).copy() |
| 749 | + for dep in conanfile.dependencies.values(): |
| 750 | + if not dep.extension_properties.get("compatibility_cppstd", True): |
| 751 | + extension_properties["compatibility_cppstd"] = False |
| 752 | + """), " ") |
| 753 | + |
| 754 | + compat_contents = compat_contents.replace('extension_properties = getattr(conanfile, "extension_properties", {})', transitive_expansions) |
| 755 | + save(compat_path, compat_contents) |
| 756 | + |
| 757 | + tc.run("install --requires=app/1.0 -s=compiler.cppstd=17", assert_error=True) |
| 758 | + |
| 759 | + assert "Missing prebuilt package for 'app/1.0', 'dep/1.0'" in tc.out |
| 760 | + |
| 761 | + |
701 | 762 |
|
702 | 763 | class TestCompatibleSettingsTarget(unittest.TestCase): |
703 | 764 | """ aims to be a very close to real use case of tool being used across different settings_target |
|
0 commit comments