def check_equivalent(dep="", path="", url="", commit="", branch=""): """ Run manual and auto and compare outputs """ manual = [False, True] p = [None, None] for i in [0, 1]: init_local_crate() # run command alr_with(dep=dep, path=path, url=url, commit=commit, branch=branch, force=True, manual=manual[i]) # get output of solution p[i] = run_alr("with", "--solve").out if i == 1: assert_eq(p[0], p[1]) # Cleanup os.chdir("..") shutil.rmtree("xxx")
import subprocess import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # This test relies on three crates in the toolchain_index: # crate_conflict=1.2.3 conflicts with crate_lone* and crate_virtual* # crate_lone is a regular crate # crate_virtual has no releases, but is provided by crate_conflict_1 # Crate conflict cannot appear with any of the others in a solution, because of # its [forbids] table. init_local_crate("conflict_lone") alr_with("crate_conflict") alr_with("crate_lone") match_solution("crate_(conflict|lone)=.* \(origin:.*\)") # has origin: solved match_solution("crate_(conflict|lone)\* \(direct,missed\)") # Because of load/solving details, we do not know which of the two crates is # going to be missed/accepted in the solution, so we check there is one of each init_local_crate("conflict_virtual") alr_with("crate_conflict") alr_with("crate_virtual") match_solution("crate_(conflict|virtual)=.* \(origin:.*\)") match_solution("crate_(conflict|virtual)\* \(direct,missed\)") print('SUCCESS')
Test solver using the "provides" field for regular crates """ import subprocess import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # This test relies on two crates in the index: crate_lone=1.0 is unavailable. # crate_equiv=2.0 also provides crate_lone=1.0 and crate_virtual=1.0. # Finally there is crate_lone=2.0 that is available and nobody else provides. init_local_crate("xxx") alr_with("crate_lone^1") # Since crate_lone is unavailable, in the solution we should find crate_equiv: match_solution("crate_lone=2.0.0 (crate_equiv)", escape=True) # Likewise, a dependency on crate_virtual will be fulfilled by the same crate alr_with("crate_virtual") match_solution("crate_virtual=2.0.0 (crate_equiv)", escape=True) # Whereas a dependency on crate_equiv will show plainly without equivalence alr_with("crate_equiv") match_solution( "Dependencies (solution):\n" " crate_equiv=2.0.0 (origin: filesystem)\n" " crate_lone=2.0.0 (crate_equiv) (origin: filesystem)\n" " crate_virtual=2.0.0 (crate_equiv) (origin: filesystem)\n",
alr_publish("mychild", "0.0.0", index_path=index_dir) # Publish also its parent for later test os.chdir("..") alr_publish("myparent", "0.0.0", index_path=index_dir) # Verify that the crate can be got and compiled, and expected location os.chdir(start_dir) run_alr("get", "--build", "mychild") assert os.path.isdir(os.path.join(f"monoproject_{commit[:8]}", "myparent", "mychild")), \ "Expected directory does not exist" # Verify that the crate is usable as a dependency, and expected location init_local_crate("top") alr_with("mychild") run_alr("build") assert os.path.isdir(os.path.join("alire", "cache", "dependencies", f"monoproject_{commit[:8]}", "myparent", "mychild")), \ "Expected directory does not exist" # Verify that "with"ing the parent does not result in a new checkout alr_with("myparent", update=False) p = run_alr("-v", "update", quiet=False) assert "Skipping checkout of already available myparent=0.0.0" in p.out, \ "Expected output not found: " + p.out # Verify the build is successful. As the dependencies were created with --bin, # they will be built even if not "with"ed in the Ada code to make their binary # available to the root crate during the build process.
assert_match( ".*\n" # Headers "gnat_external.*Available.*Detected.*\n", p.out) # Capture version version = re.search("gnat_external ([0-9.]+)", p.out, re.MULTILINE).group(1) # When no compiler is selected, only the gnat_external one should be used # unless a targeted compiler dependency is used # Create a crate for our experiments init_local_crate("xxx") # Check that a generic dependency results in the external being used alr_with("gnat") match_solution(f"gnat={version} (gnat_external) (installed)", escape=True) # Check that adding a second dependency on native packaged compiler is honored. # Both dependencies should appear in the solution. alr_with("gnat_native") match_solution("gnat=8888.0.0 (gnat_native) (installed)", escape=True) match_solution("gnat_native=8888.0.0 (installed)", escape=True) # The previous dependency also should have caused the installation of the # native compiler as an available compiler, which we will check: p = run_alr("toolchain") assert_match(".*gnat_native.*8888.0.0.*Available.*", p.out) # Move to a new crate init_local_crate("yyy")
print(f"erroneous path was: {paths[0]}") raise # First we test manual installation run_alr("toolchain", "--install", "gnat_native") check_content("gnat_native") # Uninstall the compiler and verify absence run_alr("toolchain", "--uninstall", "gnat_native", quiet=False) paths = contents(cache_dir, "gnat_native") assert len(paths) == 0, "Unexpected contents: " + str(paths) # Require the external compiler and verify no trace appears in install folder # nor in local folder init_local_crate("xxx") alr_with("gnat_external") match_solution("gnat_external=.* \(installed\)") paths = contents(cache_dir, "gnat_external") assert len(paths) == 0, "Unexpected contents: " + str(paths) paths = contents(".", "gnat_external") assert len(paths) == 0, "Unexpected contents: " + str(paths) # Require a cross compiler and verify it is automatically installed alr_with("gnat_external", delete=True, manual=False) alr_with("gnat_cross_1") match_solution("gnat_cross_1=.* \(installed\)") check_content("gnat_cross_1") print('SUCCESS')
""" Test pinning to a version """ from drivers.alr import run_alr, alr_pin, alr_with, init_local_crate from drivers.asserts import assert_eq, assert_match init_local_crate() alr_with("hello") # Test pinning to the version currently in the solution alr_pin("hello", manual=False) p = run_alr("pin") assert_eq("hello 1.0.1\n", p.out) # Test pinning to a different explicit version alr_pin("hello", version="1.0", manual=False, force=True) p = run_alr("pin") assert_eq("hello 1.0.0\n", p.out) # Test that trying to use a non-equal restriction fails p = run_alr("pin", "hello^1.0", complain_on_error=False) assert_eq( "ERROR: Plain crate name or crate=version argument expected" " for pinning, but got: hello^1.0\n", p.out) # Test that pinning to a non-existent version is doable but solution is missing p = run_alr("pin", "hello=7.7.7", force=True) p = run_alr("pin") assert_eq("hello 7.7.7\n", p.out) p = run_alr("with", "--solve")
# Verify only external compiler available p = run_alr("toolchain") assert_match( ".*\n" # Headers "gnat_external.*Available.*Detected.*\n", p.out) # Capture version version = re.search("gnat_external ([0-9.]+)", p.out, re.MULTILINE).group(1) # Prepare a couple of dependencies, one depending on gnat, and another one # depending on gnat_native. init_local_crate("dep_generic") alr_with("gnat") os.chdir("..") init_local_crate("dep_targeted") alr_with("gnat_native") # This step also installs the native compiler os.chdir("..") # First we check that a root generic dependency mixes well with either of the # two dependencies init_local_crate("xxx_generic_generic") run_alr("with", "--use=../dep_generic") alr_with("gnat") # gnat x gnat results in the external available compiler being used, preferred # over the native also available compiler (but not selected)
from drivers.alr import run_alr, alr_with, init_local_crate from drivers.asserts import assert_eq, assert_match from drivers.helpers import init_git_repo import os import subprocess # Create a new "remote" repository with a tag that we'll use as reference init_local_crate("remote") init_git_repo(".") subprocess.run(["git", "tag", "v1"]).check_returncode() # Verify that pinning to a valid reference succeeds os.chdir("..") init_local_crate() alr_with(path="../remote", commit="v1", manual=False) p = run_alr("pin") assert_match("remote file:alire/cache/pins/remote_.{,8} ../remote#.{,8}", p.out) # Remove dependency for next test alr_with("remote", delete=True, manual=False) p = run_alr("pin") assert_eq("There are no pins\n", p.out) # Verify that pinning to an invalid reference fails p = run_alr("with", "--use", "../remote", "--commit", "v2",
""" import subprocess import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # Select the default preferred compiler, which is the native packaged one run_alr("toolchain", "--select") # Init a crate depending on gnat init_local_crate("xxx") alr_with("gnat*") # Will appear in the solution as generic fulfilled by the preferred compiler match_solution("gnat=8888.0.0 (gnat_native) (installed)", escape=True) # Selecting another default will cause a corresponding change in the solution run_alr("config", "--set", "toolchain.use.gnat", "gnat_cross_2=1") run_alr("update") match_solution("gnat=1.0.0 (gnat_cross_2) (installed)", escape=True) # Adding another incompatible compiler dependency should result in overriding # the configured one alr_with("gnat_cross_1") # Both dependencies will appear in the solution, matching the same crate match_solution("gnat=9999.0.0 \(gnat_cross_1\) \(installed\).*"
# We are now at monoproject/mycrate. os.chdir("mycrate") run_alr("show") # Verify the crate is detected properly # This call creates the manifest and puts it in place in the index alr_publish("mycrate", "0.0.0", index_path=os.path.join(start_dir, "my_index")) # Verify that the crate can be got and compiled, and expected location os.chdir(start_dir) run_alr("get", "--build", "mycrate") assert os.path.isdir(os.path.join(f"monoproject_{commit[:8]}", "mycrate")), \ "Expected directory does not exist" # Verify that the crate is usable as a dependency, and expected binary location init_local_crate("top") alr_with("mycrate") run_alr("build") assert os.path.isfile(os.path.join( "alire", "cache", "dependencies", f"monoproject_{commit[:8]}", "mycrate", "bin", f"mycrate{'.exe' if on_windows() else ''}")), \ "Expected binary does not exist" # Also that the info file is there assert os.path.isfile(os.path.join( "alire", "cache", "dependencies", f"mycrate_0.0.0_in_monoproject_{commit[:8]}")), \ "Expected info file does not exist" print('SUCCESS')
# pre/post-build expected for successful build check(flag_post_fetch, False) check(flag_pre_build, True) check(flag_post_build, True) return # updating dependencies causes the post-fetch action to run: run_alr('update') check(flag_post_fetch, True) check(flag_pre_build, True) check(flag_post_build, True) # Initialize a crate and add as dependency the crate that contains the triggers init_local_crate("root", binary=False) # Lib so all contents are compiled alr_with("hello_world") # Test all triggers do_checks(glob("./alire/cache/dependencies/hello*")[0].replace('\\', '/')) # Repeat tests, for a crate that has been added as a linked dependency os.chdir("..") rmtree("root") run_alr("get", "hello_world") hello = glob("hello*")[0].replace('\\', '/') init_local_crate("root", binary=False) os.rename(f"../{hello}", f"./{hello}") alr_with(path=f"{hello}", manual=False) do_checks(f"./{hello}") print('SUCCESS')
""" import subprocess import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # This test relies on two crates in the toolchain_index: # crate_subst both provides and forbids crate_real # crate_real is a regular crate only provided by itself and crate_subst # The following has only one possible solution, which is for crate_subst # providing both dependencies. init_local_crate("test") alr_with("crate_real") # Check that this is initially solved with the regular crate. This is currently # guaranteed by the solver attempting crates in alphabetical order. We will # need eventually a way to disable equivalences (via pins, or solver config). match_solution("crate_real=1.0.0 (origin: filesystem)", escape=True) # Let's add the drop-in equivalent crate that provides+forbids crate_lone alr_with("crate_subst") match_solution("crate_real=1.0.0 (crate_subst) (origin: filesystem)", escape=True) # This is the substituted release match_solution("crate_subst=1.0.0 (origin: filesystem)", escape=True) print('SUCCESS')
Test that a tool built by a dependency is available to a dependent crate """ from drivers.alr import run_alr, init_local_crate, alr_with, alr_manifest from drivers.alr import add_action from os import chdir from os.path import join from shutil import rmtree, which # We test with a locally pinned dependency, which should make no difference as # it is a regular release in the eyes of the build process init_local_crate("root") init_local_crate("depended", binary=True, enter=False) alr_with("depended", path="depended") # Add a pre-build action to the root crate that attempts to run bin/depended add_action("pre-build", ["depended/bin/depended"]) run_alr("build") # Now, add the executable to the path in the depended crate, and an action that # uses only the executable name # First, ensure that a same-name executable isn't in the environment by some # bizarre chance assert which("depended") is None, "Unexpected 'depended' command in PATH" chdir("depended") with open(alr_manifest(), "a") as manifest:
comes first alphabetically), and verify the environment contains the compiler. """ import os import re import subprocess from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match from drivers.helpers import dir_separator # Install a binary compiler for later use run_alr("toolchain", "--select", "gnat_native") init_local_crate("another_crate") # This enters the crate alr_with("gnat") # Make it depend on gnat (in the original bug, the dependency # was also indirect, although it would have been a problem with a direct # dependency as well). os.chdir("..") # Back to root folder init_local_crate() alr_with(path="../another_crate", manual=False) # Autodetect the linked crate p = run_alr("printenv") s = re.escape(dir_separator()) # Ensure the compiler-set flag is in there: assert_match( ".*export TEST_PATH=.*" f"printenv__compiler-indirect{s}alr-config{s}cache{s}"
p = run_alr("pin", complain_on_error=False) s = re.escape(dir_separator()) assert_match( ".*" "ERROR: Pin circularity detected when adding pin zzz --> xxx:\n" f"ERROR: Last manifest in the cycle is .*{s}zzz{s}alire.toml\n", p.out) # Verify that the buggy case that was reported does not happen again # In this case, we have # dep1 -> dep2 -> dep3 -> dep4; dep1 -> dep3; dep1 -> dep4; dep2 -> dep4 init_local_crate("dep4", enter=False) init_local_crate("dep3") alr_with("dep4", path="../dep4") os.chdir("..") init_local_crate("dep2") alr_with("dep3", path="../dep3") alr_with("dep4", path="../dep4") os.chdir("..") init_local_crate("dep1") alr_with("dep2", path="../dep2") alr_with("dep3", path="../dep3") alr_with("dep4", path="../dep4") p = run_alr("with", "--solve") assert_eq("""\ Dependencies (direct):
from glob import glob expected_output = "POST-FETCH MAIN\n" # Test trigger action in a root crate run_alr("get", "main") os.chdir(glob("main*")[0]) p = run_alr("action", "post-fetch") assert_eq(expected_output, p.out) # Test trigger of undefined action p = run_alr("action", "post-build") assert_eq("No actions to run.\n", p.out) # Test trigger of non-existent action p = run_alr("action", "made-up", complain_on_error=False) assert_eq("ERROR: Invalid action: made-up\n", p.out) # Test that action in dependency is not triggered by default os.chdir("..") init_local_crate() alr_with("main") p = run_alr("action", "post-fetch") assert_eq("No actions to run.\n", p.out) # Third test, check that action in dependency is listed with --recursive, -r p = run_alr("action", "post-fetch", "--recursive") assert_eq(expected_output, p.out) print('SUCCESS')
# We create a second crate at another commit os.chdir(os.path.join(start_dir, "monoproject.upstream")) init_local_crate("crate2", enter=False) os.chdir(start_dir) commit2 = commit_all("monoproject.upstream") # Check out changes and publish crate2 os.chdir("monoproject") run(["git", "pull"]).check_returncode() os.chdir("crate2") alr_publish("crate2", "0.0.0", index_path=os.path.join(start_dir, "my_index")) # Verify that the crates are usable as a dependency, and expected binary # locations init_local_crate("top") alr_with("crate1") alr_with("crate2") run_alr("build") assert os.path.isfile(os.path.join( "alire", "cache", "dependencies", f"monoproject_{commit1[:8]}", "crate1", "bin", f"crate1{'.exe' if on_windows() else ''}")), \ "Expected binary does not exist" assert os.path.isfile(os.path.join( "alire", "cache", "dependencies", f"monoproject_{commit2[:8]}", "crate2", "bin", f"crate2{'.exe' if on_windows() else ''}")), \ "Expected binary does not exist" # Also that the info files are there
""" Test that two crates providing the same third crate are compatible """ import subprocess import os from drivers.alr import run_alr, init_local_crate, alr_with from drivers.asserts import assert_eq, assert_match, match_solution from re import escape as e # This test relies on two crates in the index: # crate_virt_1=2.0 also provides crate_virtual=1.0 # crate_virt_2=1.0 also provides crate_virtual=1.0 # Verify that these crates provide the same virtual release p = run_alr("show", "crate_virt_1") assert_match(".*Provides: crate_virtual=1.0.0.*", p.out) p = run_alr("show", "crate_virt_2") assert_match(".*Provides: crate_virtual=1.0.0.*", p.out) init_local_crate("xxx") alr_with("crate_virt_1") alr_with("crate_virt_2") # Both crates must appear in the solution match_solution("crate_virt_1=2.0.0 (origin: filesystem)", escape=True) match_solution("crate_virt_2=1.0.0 (origin: filesystem)", escape=True) print('SUCCESS')
# pre/post-build expected for successful build check_not_expected('./test_post_fetch') check_expected('./test_pre_build') check_expected('./test_post_build') # updating dependencies causes the post-fetch action on the root crate to run: run_alr('update') check_expected('./test_post_fetch') check_expected('./test_pre_build') check_expected('./test_post_build') # Add a linked dependency. Since these are never "fetched", in order to # complete their action cycle, post-fetch is also run on updates init_local_crate("depended", binary=False, enter=True) # Add a similar action if on_windows(): add_action("post-fetch", ["cmd", "/C", "copy NUL test_post_fetch_dep"]) else: add_action("post-fetch", ["touch", "test_post_fetch_dep"]) check_not_expected('./test_post_fetch_dep') os.chdir("..") # Back to parent crate alr_with("depended", path="depended", update=False) run_alr("update") check_not_expected('./test_post_fetch_dep') check_expected('./depended/test_post_fetch_dep') print('SUCCESS')
""" import os from drivers.alr import run_alr, init_local_crate, alr_lockfile, alr_with # from drivers.asserts import assert_eq, assert_match from drivers.helpers import content_of from os.path import isfile old_lockfile = "alire.lock" init_local_crate() # Add a dependency so the lockfile is not the same as the default one default_content = content_of(alr_lockfile()) alr_with("libhello") proper_content = content_of(alr_lockfile()) assert default_content != proper_content, \ "error setting up the test (contents should differ)" def verify(): """ Check that the lockfile is only in the new location, with proper contents """ assert isfile(alr_lockfile()) and not isfile(old_lockfile), \ "Unexpected lockfile placement" assert content_of(alr_lockfile()) == proper_content, "bad contents" # Case 1: lockfile is only in the old location, and it is moved to new location
check_config(bin_config, 'development') # Check that the project builds run_alr('build') # Build in validation mode run_alr('build', '--validation') check_config_changed() check_config(bin_config, 'validation') # Build in validation mode run_alr('build', '--development') check_config_changed() check_config(bin_config, 'development') # Build in release mode run_alr('build', '--release') check_config_changed() check_config(bin_config, 'release') # Alr with will re-generate the crate config and default to DEVELOPMENT alr_with('lib_1', path='../lib_1') check_config_changed() check_config(bin_config, 'development') # Build with default profile, the config should not change run_alr('build') check_config_not_changed() print('SUCCESS')
".*\n" # Headers "gnat_external.*Available.*Detected.*\n", p.out) # Capture version version = re.search("gnat_external ([0-9.]+)", p.out, re.MULTILINE).group(1) print(version) # When no compiler is selected, since the external one is available, it should # be used before offering to download a new compiler. # Create a crate for our experiments init_local_crate("xxx") # Check that a generic dependency results in the external being used alr_with("gnat") match_solution(f"gnat={version} (gnat_external) (installed)", escape=True) # Check that requesting a version different to the one externally available # results in missing compiler, as Alire won't try to install one. alr_with("gnat", delete=True, manual=False) alr_with(f"gnat/={version}") match_solution(f"gnat/={version} (direct,hinted)", escape=True) # Hinted because we know the crate exists as external # Now, if the user installs a cross compiler, it will be used run_alr("toolchain", "--install", "gnat_cross_2") run_alr("update") match_solution("gnat=1.0.0 (gnat_cross_2) (installed)", escape=True)