From b3cc7201f7c9d270dc65ef572a646e6003c0ba3c Mon Sep 17 00:00:00 2001 From: =?utf8?q?C=C3=A9sar=20Sagaert?= Date: Wed, 19 Mar 2025 17:13:48 +0100 Subject: [PATCH] feat: add test runner selection via `--id` (#1909) * feat: add test runner selection via `--id` * docs: document `id` field for tests --- doc/catalog-format-spec.md | 7 +++- src/alire/alire-properties-tests.adb | 15 +++++++ src/alire/alire-properties-tests.ads | 29 +++++++++----- src/alire/alire-toml_keys.ads | 1 + src/alr/alr-commands-test.adb | 42 ++++++++++++++++--- src/alr/alr-commands-test.ads | 1 + testsuite/tests/test/select_id/test.py | 51 ++++++++++++++++++++++++ testsuite/tests/test/select_id/test.yaml | 3 ++ 8 files changed, 133 insertions(+), 16 deletions(-) create mode 100644 testsuite/tests/test/select_id/test.py create mode 100644 testsuite/tests/test/select_id/test.yaml diff --git a/doc/catalog-format-spec.md b/doc/catalog-format-spec.md index bd901eb4..96731a01 100644 --- a/doc/catalog-format-spec.md +++ b/doc/catalog-format-spec.md @@ -449,6 +449,8 @@ static, i.e. they cannot depend on the context. # OR command = ["", "", ...] + # optional keys + id = directory = jobs = ``` @@ -465,7 +467,10 @@ static, i.e. they cannot depend on the context. The `[test]` section also accepts an array of test runners (with `[[test]]`), although you lose the ability to pass extra arguments to the - test command with `alr test`. + test command with `alr test`. You can assign a unique `id` to a test runner + and then select it with `alr test --id=`, which allows you to pass + command line arguments to this runner only. The `` must be a unique, + non-empty string. - `auto-gpr-with`: optional Boolean value that specifies if the project (gpr) files of a crate can be automatically depended upon ('withed') directly by the root diff --git a/src/alire/alire-properties-tests.adb b/src/alire/alire-properties-tests.adb index b3d377fa..a415b597 100644 --- a/src/alire/alire-properties-tests.adb +++ b/src/alire/alire-properties-tests.adb @@ -40,6 +40,8 @@ package body Alire.Properties.Tests is use TOML; Raw : TOML_Value; + Id_Set : AAA.Strings.Set; + -- keep track of encountered ids to forbid duplicates begin if From.Unwrap.Kind /= TOML_Table then From.Checked_Error @@ -53,6 +55,8 @@ package body Alire.Properties.Tests is end if; + Id_Set.Insert (""); -- so that the empty string is rejected as an id + return Props : Conditional.Properties do declare Local : constant TOML_Adapters.Key_Queue := @@ -127,6 +131,17 @@ package body Alire.Properties.Tests is end if; Res.Jobs := Natural (Val.As_Integer); end if; + + if Local.Pop (TOML_Keys.Test_Id, Val) then + if Val.Kind /= TOML_String + or else Id_Set.Contains (Val.As_String) + then + Local.Checked_Error ("id must be a non-empty unique string"); + end if; + Id_Set.Insert (Val.As_String); + Res.Id := Val.As_Unbounded_String; + end if; + Local.Report_Extra_Keys; Props := Props and Res; diff --git a/src/alire/alire-properties-tests.ads b/src/alire/alire-properties-tests.ads index 04a9992a..0b7462dc 100644 --- a/src/alire/alire-properties-tests.ads +++ b/src/alire/alire-properties-tests.ads @@ -39,10 +39,12 @@ is function Runner (S : Settings) return Runner_Type; - function Directory (S : Settings) return Unbounded_Relative_Path; + function Directory (S : Settings) return Relative_Path; function Jobs (S : Settings) return Natural; + function Id (S : Settings) return String; + function Default return Settings; private @@ -51,16 +53,19 @@ private Runner : Runner_Type; Directory : Unbounded_Relative_Path; Jobs : Natural; + Id : UString; end record; overriding function Image (S : Settings) return String - is (" test runner: " + is (" test runner" + & (if Id (S) = "" then "" else ("'" & Id (S) & "'")) + & ": " & (case S.Runner.Kind is when Alire_Runner => "alire", - when External => S.Runner.Command.Flatten) + when External => "`" & S.Runner.Command.Flatten & "`") & ", directory: " - & UStrings.To_String (S.Directory) + & Directory (S) & (if S.Runner.Kind = Alire_Runner then (", jobs:" & S.Jobs'Image) else "")); @@ -73,22 +78,28 @@ private when External => S.Runner.Command.Flatten) & New_Line & "directory: " - & Alire.Utils.YAML.YAML_Stringify (UStrings.To_String (S.Directory)) + & Alire.Utils.YAML.YAML_Stringify (Directory (S)) & New_Line & "jobs:" - & S.Jobs'Image); + & S.Jobs'Image + & New_Line + & "id: " + & Alire.Utils.YAML.YAML_Stringify (Id (S))); function Runner (S : Settings) return Runner_Type is (S.Runner); - function Directory (S : Settings) return Unbounded_Relative_Path - is (S.Directory); + function Directory (S : Settings) return Relative_Path + is (+S.Directory); function Jobs (S : Settings) return Natural is (S.Jobs); + function Id (S : Settings) return String + is (+S.Id); + function Default return Settings is (Properties.Property - with (Kind => Alire_Runner), +Alire.Paths.Default_Tests_Folder, 0); + with (Kind => Alire_Runner), +Alire.Paths.Default_Tests_Folder, 0, +""); end Alire.Properties.Tests; diff --git a/src/alire/alire-toml_keys.ads b/src/alire/alire-toml_keys.ads index 89b06080..21feaeec 100644 --- a/src/alire/alire-toml_keys.ads +++ b/src/alire/alire-toml_keys.ads @@ -49,6 +49,7 @@ package Alire.TOML_Keys with Preelaborate is Test_Command : constant String := "command"; Test_Folder : constant String := "directory"; Test_Jobs : constant String := "jobs"; + Test_Id : constant String := "id"; Toolchain : constant String := "toolchain"; Version : constant String := "version"; Version_Cmd : constant String := "version-command"; diff --git a/src/alr/alr-commands-test.adb b/src/alr/alr-commands-test.adb index 4e4ab976..d7776b73 100644 --- a/src/alr/alr-commands-test.adb +++ b/src/alr/alr-commands-test.adb @@ -1,5 +1,4 @@ with Ada.Containers; -with Ada.Strings.Unbounded; with Alire.Directories; with Alire.OS_Lib; @@ -55,6 +54,7 @@ package body Alr.Commands.Test is overriding procedure Execute (Cmd : in out Command; Args : AAA.Strings.Vector) is + use type GNAT.Strings.String_Access; use type Ada.Containers.Count_Type; use Alire.Properties.Tests; @@ -72,6 +72,30 @@ package body Alr.Commands.Test is Execute_Legacy (Cmd.Root); end if; + -- id selection logic + if Cmd.By_Id /= null and then Cmd.By_Id.all /= "" then + declare + Found : Natural := 0; + begin + for I in All_Settings.First_Index .. All_Settings.Last_Index loop + if Settings (All_Settings.Element (I)).Id = Cmd.By_Id.all then + Found := I; + end if; + end loop; + + if Found = 0 then + Reportaise_Command_Failed + ("Could not find test runner with id '" + & Cmd.By_Id.all + & "'"); + else + -- swap to first position and remove the rest + All_Settings.Swap (All_Settings.First_Index, Found); + All_Settings.Set_Length (1); + end if; + end; + end if; + if not Args.Is_Empty and then (Cmd.Jobs >= 0 or else All_Settings.Length > 1) then @@ -91,11 +115,10 @@ package body Alr.Commands.Test is end if; for Test_Setting of All_Settings loop - if Alire.Directories.Is_Directory (+Settings (Test_Setting).Directory) + if Alire.Directories.Is_Directory (Settings (Test_Setting).Directory) then declare use Alire.Directories; - use all type Ada.Strings.Unbounded.Unbounded_String; function Get_Args return AAA.Strings.Vector is (if All_Settings.Length = 1 then Args @@ -104,8 +127,7 @@ package body Alr.Commands.Test is S : constant Settings := Settings (Test_Setting); - Dir : constant Alire.Relative_Path := - To_String (S.Directory); + Dir : constant Alire.Relative_Path := S.Directory; Failures : Integer; Guard : Alire.Directories.Guard (Enter (Dir)) @@ -146,7 +168,7 @@ package body Alr.Commands.Test is Trace.Error ("while running" & (Settings (Test_Setting).Image)); Reportaise_Command_Failed ("directory '" - & (+Settings (Test_Setting).Directory) + & (Settings (Test_Setting).Directory) & "' does not exist."); end if; end loop; @@ -194,6 +216,14 @@ package body Alr.Commands.Test is & " if 0", Default => -1, Argument => "N"); + + Define_Switch + (Config, + Cmd.By_Id'Access, + "", + "--id=", + "Select a specific test runner by id", + Argument => ""); end Setup_Switches; end Alr.Commands.Test; diff --git a/src/alr/alr-commands-test.ads b/src/alr/alr-commands-test.ads index 819590ac..ca636d04 100644 --- a/src/alr/alr-commands-test.ads +++ b/src/alr/alr-commands-test.ads @@ -36,6 +36,7 @@ private type Command is new Commands.Command with record Jobs : aliased Integer := 0; + By_Id : aliased GNAT.Strings.String_Access; end record; end Alr.Commands.Test; diff --git a/testsuite/tests/test/select_id/test.py b/testsuite/tests/test/select_id/test.py new file mode 100644 index 00000000..12cf8aea --- /dev/null +++ b/testsuite/tests/test/select_id/test.py @@ -0,0 +1,51 @@ +""" +Select a specific test runner by its id +""" + +import os.path + +from drivers.alr import init_local_crate, run_alr +from drivers.asserts import assert_not_substring, assert_substring + +init_local_crate("xxx") + +with open("alire.toml", "+a") as f: + f.writelines([ + "\n", + "[[test]]\n", + "id = 'a'\n", + "command = ['echo', 'MAGIC_TEST_A']\n", + "directory = '.'\n", + "\n", + "[[test]]\n", + "id = 'b'\n", + "command = ['echo', 'MAGIC_TEST_B']\n", + "directory = '.'\n", + ]) + +# check that both test runners run without argyments +p = run_alr("test") +assert_substring("MAGIC_TEST_A", p.out) +assert_substring("MAGIC_TEST_B", p.out) + +# check that arguments are not forwarded +p = run_alr("test", "EXTRA_MAGIC") +assert_substring("MAGIC_TEST_A", p.out) +assert_substring("MAGIC_TEST_B", p.out) +assert_not_substring("EXTRA_MAGIC", p.out) + +# check that only one test runner is selected with "--id" +p = run_alr("test", "--id", "a") +assert_substring ("MAGIC_TEST_A", p.out) +assert_not_substring("MAGIC_TEST_B", p.out) + +# check that arguments are forwarded with "--id" +p = run_alr("test", "--id", "b", "EXTRA_MAGIC") +assert_substring ("MAGIC_TEST_B", p.out) +assert_not_substring("MAGIC_TEST_A", p.out) +assert_substring ("EXTRA_MAGIC", p.out) + +# check for failure when using an invalid id +p = run_alr("test", "--id", "c", complain_on_error = False) + +print('SUCCESS') diff --git a/testsuite/tests/test/select_id/test.yaml b/testsuite/tests/test/select_id/test.yaml new file mode 100644 index 00000000..fa855459 --- /dev/null +++ b/testsuite/tests/test/select_id/test.yaml @@ -0,0 +1,3 @@ +driver: python-script +indexes: + compiler_only_index: {} -- 2.39.5