mirror of https://github.com/briot/gnatbdd
Add support for @setup_driver and @setup_feature annotations
This commit is contained in:
parent
31973ca3df
commit
b1f55e8e5a
|
@ -158,6 +158,13 @@ The comments should start with one of '@given', '@then' or '@when'.
|
|||
There is no semantic difference, they only act as a way to help
|
||||
introduce the regexp.
|
||||
|
||||
It is recommended that regular expressions always be surrounded with '^' and
|
||||
'$', to indicate they should match the whole step definition, and not just part
|
||||
of it.
|
||||
|
||||
Parameter types
|
||||
===============
|
||||
|
||||
The regular expressions are matched with the step as found in the
|
||||
:file:`*.feature` file. The parenthesis groups found in the regexp will be
|
||||
passed as parameters to the procedure. By default, all parameters are passed as
|
||||
|
@ -165,9 +172,22 @@ strings. If you use another scalar type for the parameter, GNATbdd will use a
|
|||
`Type'Value (...)` before passing the parameter, and raise an error if
|
||||
the type is incorrect.
|
||||
|
||||
It is recommended that regular expressions always be surrounded with '^' and
|
||||
'$', to indicate they should match the whole step definition, and not just part
|
||||
of it.
|
||||
GNATbdd provides specific handling for a few parameter types. Note that the
|
||||
type must be written exactly as in the table below (case-insensitive), since
|
||||
GNATbdd does not contain a semantic analyzer to resolve names.
|
||||
|
||||
+-------------------+-----------------------------------------------------+
|
||||
| Type | Conversion from regexp match |
|
||||
+===================+=====================================================+
|
||||
| String | The parenthesis group as matched by the regexp |
|
||||
+-------------------+-----------------------------------------------------+
|
||||
| Ada.Calendar.Time | Converts a date with GNATCOLL.Utils.Time_Value. |
|
||||
| | This supports a number of date and time formats, for|
|
||||
| | instance '2015-06-15T12:00:00Z' or '2015-06-15' or |
|
||||
| | '15 jun 2015' or 'jun 15, 2015'. |
|
||||
+-------------------+-----------------------------------------------------+
|
||||
| others | Use others'Value to convert from string |
|
||||
+-------------------+-----------------------------------------------------+
|
||||
|
||||
.. _using_tables_in_step_definitions:
|
||||
|
||||
|
@ -274,7 +294,6 @@ percent sign, as in::
|
|||
The predefined regexps are automatically included in a parenthesis group,
|
||||
so you should not add parenthesis yourself.
|
||||
|
||||
|
||||
Here is the full list of predefined regular expressions:
|
||||
|
||||
+---------+----------------------------+-----------------------------+
|
||||
|
@ -289,6 +308,11 @@ Here is the full list of predefined regular expressions:
|
|||
| date | Feb 04, 2014; 2014-02-04 | String or Ada.Calendar.Time |
|
||||
+---------+----------------------------+-----------------------------+
|
||||
|
||||
You can use the percent symbol twice ("%%") when you need to ignore a
|
||||
string matching one of the predefined regular expressions. For instance,
|
||||
"%%integer" would match the string "%integer" in the feature file. When
|
||||
you only when to insert a percent sign before any other string, you do not
|
||||
need to duplicate it though (so "%test" can be written exactly as is).
|
||||
|
||||
Predefined steps
|
||||
================
|
||||
|
@ -343,6 +367,36 @@ As usual, any python file found in the :file:`features/step_definitions`
|
|||
directory or the one set through :option:`--steps` will be analyzed,
|
||||
and those that use the `@step_regexp` decorator.
|
||||
|
||||
Set up
|
||||
------
|
||||
|
||||
Often, the code for the step definitions will need some initialization
|
||||
(connecting to a database, opening a web browser,...). It is possible
|
||||
to declare any number of such initialization subprograms.
|
||||
|
||||
Some of them will be run once per execution of the driver, others will
|
||||
be executed one per feature file.
|
||||
|
||||
These subprograms are also declared in the step definitions files, as
|
||||
in::
|
||||
|
||||
package My_Steps is
|
||||
|
||||
@setup_driver
|
||||
procedure Init_Driver;
|
||||
|
||||
@setup_feature
|
||||
procedure Init_Feature;
|
||||
|
||||
end My_Steps;
|
||||
|
||||
The subprograms never take any parameter. Since they might be called
|
||||
multiple times, they also need to clean up any initialization they might
|
||||
have done before.
|
||||
|
||||
Most of the time, it is better for these procedures to be written directly
|
||||
as specific steps in the tests, so `@setup_feature` should in general be
|
||||
replaced with a `Background` section in the feature file.
|
||||
|
||||
Asynchronous tests
|
||||
==================
|
||||
|
|
|
@ -34,7 +34,8 @@ package body BDD.Main is
|
|||
-- Main --
|
||||
----------
|
||||
|
||||
procedure Main (Self : in out BDD.Runner.Feature_Runner) is
|
||||
procedure Main (Self : in out BDD.Runner.Feature_Runner'Class)
|
||||
is
|
||||
Parser : BDD.Parser.Feature_Parser;
|
||||
Format : access BDD.Formatters.Formatter'Class;
|
||||
Media : Media_Writer_Access;
|
||||
|
|
|
@ -27,8 +27,8 @@ with BDD.Runner;
|
|||
|
||||
package BDD.Main is
|
||||
|
||||
procedure Main (Self : in out BDD.Runner.Feature_Runner);
|
||||
procedure Main (Self : in out BDD.Runner.Feature_Runner'Class);
|
||||
-- The main loop, which discovers and then runs all the tests
|
||||
-- Self should have been initialized with Add_Step_Runner first
|
||||
-- Self should have been initialized with Add_Step_Runner first.
|
||||
|
||||
end BDD.Main;
|
||||
|
|
|
@ -60,7 +60,7 @@ package BDD.Parser is
|
|||
Feature : BDD.Features.Feature) is null;
|
||||
-- Called when the last line of a feature has been seen.
|
||||
|
||||
type Feature_Parser is tagged private;
|
||||
type Feature_Parser is tagged null record;
|
||||
|
||||
procedure Parse
|
||||
(Self : in out Feature_Parser;
|
||||
|
@ -72,7 +72,4 @@ package BDD.Parser is
|
|||
--
|
||||
-- Raises Syntax_Error when the file does not contain valid syntax.
|
||||
|
||||
private
|
||||
type Feature_Parser is tagged null record;
|
||||
|
||||
end BDD.Parser;
|
||||
|
|
|
@ -78,14 +78,14 @@ package body BDD.Runner is
|
|||
is
|
||||
begin
|
||||
if Self.Files /= null then
|
||||
Self.Run_Start;
|
||||
Feature_Runner'Class (Self).Run_Start;
|
||||
Self.Format := Format;
|
||||
Sort (Self.Files.all);
|
||||
for F in Self.Files'Range loop
|
||||
Parser.Parse (Self.Files (F), Self);
|
||||
end loop;
|
||||
|
||||
Self.Run_End;
|
||||
Feature_Runner'Class (Self).Run_End;
|
||||
Self.Format := null;
|
||||
|
||||
Set_Exit_Status
|
||||
|
|
|
@ -52,9 +52,9 @@ package BDD.Runner is
|
|||
-- Register one or more features file explicitly.
|
||||
|
||||
procedure Run
|
||||
(Self : in out Feature_Runner;
|
||||
Format : not null access BDD.Formatters.Formatter'Class;
|
||||
Parser : in out BDD.Parser.Feature_Parser'Class);
|
||||
(Self : in out Feature_Runner;
|
||||
Format : not null access BDD.Formatters.Formatter'Class;
|
||||
Parser : in out BDD.Parser.Feature_Parser'Class);
|
||||
-- Run all features and their scenarios.
|
||||
--
|
||||
-- Each of the features file is parsed through Parser. This allows you to
|
||||
|
|
|
@ -47,8 +47,14 @@ package body Gnatbdd.Codegen is
|
|||
Case_Insensitive or Single_Line);
|
||||
Cst_Package_Re : constant Pattern_Matcher :=
|
||||
Compile ("^package ([_\.\w]+)", Case_Insensitive or Multiple_Lines);
|
||||
|
||||
Cst_Comment_Re : constant Pattern_Matcher :=
|
||||
Compile ("--\s*@(given|then|when)\s+");
|
||||
-- Matches the special comments before step definitions
|
||||
|
||||
Cst_Setup_Re : constant Pattern_Matcher :=
|
||||
Compile ("--\s*@setup_(driver|feature)\s*$", Multiple_Lines);
|
||||
-- Matches the special comments before initialization procedures
|
||||
|
||||
Predefined_Regexps : constant Substitution_Array :=
|
||||
(1 => (new String'("integer"),
|
||||
|
@ -59,7 +65,7 @@ package body Gnatbdd.Codegen is
|
|||
new String'("(\+?\d+)")),
|
||||
4 => (new String'("date"),
|
||||
new String'(
|
||||
"((?:" -- date part
|
||||
"((?:" -- date part
|
||||
& "\d{4}/\d{2}/\d{2}" -- 2014/01/02
|
||||
& "|"
|
||||
& "\d{2}/\d{2}/\d{4}" -- 01/02/2014
|
||||
|
@ -70,7 +76,8 @@ package body Gnatbdd.Codegen is
|
|||
& "\d{2}:\d{2}:\d{2}" -- hh:mm:ss
|
||||
& "(?:\s*[+-]\d{2})" -- optional time zone within time
|
||||
& "))"
|
||||
))
|
||||
)),
|
||||
5 => (new String'("%"), new String'("%"))
|
||||
);
|
||||
|
||||
type Generated_Data is record
|
||||
|
@ -78,6 +85,9 @@ package body Gnatbdd.Codegen is
|
|||
-- Code extract that, for a given step, checks all known step definition
|
||||
-- and execute the corresponding subprogram if needed.
|
||||
|
||||
Setup_Driver, Setup_Feature : Unbounded_String;
|
||||
-- Code extract that calls all the initializers defined by the user.
|
||||
|
||||
Regexps : Unbounded_String;
|
||||
-- Code extract that declares all the regexps used by the step
|
||||
-- definitions.
|
||||
|
@ -124,6 +134,18 @@ package body Gnatbdd.Codegen is
|
|||
-- Found is set to True if at least one step definition was found, and left
|
||||
-- unchanged otherwise
|
||||
|
||||
procedure Parse_Setup_Subprogram_Def
|
||||
(Contents : String;
|
||||
Package_Name : String;
|
||||
Setup_Type : String;
|
||||
Found : in out Boolean;
|
||||
Pos : in out Integer;
|
||||
Data : in out Generated_Data);
|
||||
-- Parse the definition of an initialization subprogram.
|
||||
-- Pos is left after the declaration (if the latter could
|
||||
-- be parsed).
|
||||
-- Found is set to True if an initialization subprogram was found.
|
||||
|
||||
type Param_Description is record
|
||||
Name : GNAT.Strings.String_Access;
|
||||
Of_Type : GNAT.Strings.String_Access;
|
||||
|
@ -470,6 +492,68 @@ package body Gnatbdd.Codegen is
|
|||
Free (List);
|
||||
end Parse_Subprogram_Def;
|
||||
|
||||
--------------------------------
|
||||
-- Parse_Setup_Subprogram_Def --
|
||||
--------------------------------
|
||||
|
||||
procedure Parse_Setup_Subprogram_Def
|
||||
(Contents : String;
|
||||
Package_Name : String;
|
||||
Setup_Type : String;
|
||||
Found : in out Boolean;
|
||||
Pos : in out Integer;
|
||||
Data : in out Generated_Data)
|
||||
is
|
||||
Name : constant String := "@setup_" & Setup_Type;
|
||||
Matches : Match_Array (0 .. 3);
|
||||
Subprogram : GNAT.Strings.String_Access;
|
||||
begin
|
||||
Skip_Blanks (Contents, Pos);
|
||||
if Pos > Contents'Last
|
||||
or else not Starts_With
|
||||
(Contents (Pos .. Contents'Last), Cst_Procedure)
|
||||
then
|
||||
Put_Line
|
||||
(Standard_Error,
|
||||
"Error: The step definition for '" & Name & "' must be"
|
||||
& " followed immediately by its subprogram");
|
||||
Ada.Command_Line.Set_Exit_Status (Failure);
|
||||
return;
|
||||
end if;
|
||||
|
||||
Match (Cst_Procedure_Re, Contents, Matches, Data_First => Pos);
|
||||
if Matches (1) = No_Match then
|
||||
Put_Line
|
||||
(Standard_Error,
|
||||
"Could not find name of subprogram for '" & Name & "'");
|
||||
Ada.Command_Line.Set_Exit_Status (Failure);
|
||||
return;
|
||||
end if;
|
||||
|
||||
Pos := Matches (0).Last;
|
||||
|
||||
Subprogram := new String'
|
||||
(Package_Name & '.'
|
||||
& Contents (Matches (1).First .. Matches (1).Last));
|
||||
|
||||
if Matches (3) /= No_Match then
|
||||
Put_Line
|
||||
(Standard_Error,
|
||||
"Subprogram for " & Name & " should take no parameter");
|
||||
Ada.Command_Line.Set_Exit_Status (Failure);
|
||||
return;
|
||||
end if;
|
||||
|
||||
if Setup_Type = "driver" then
|
||||
Append (Data.Setup_Driver, " " & Subprogram.all & ";");
|
||||
elsif Setup_Type = "feature" then
|
||||
Append (Data.Setup_Feature, " " & Subprogram.all & ";");
|
||||
end if;
|
||||
|
||||
Found := True;
|
||||
Free (Subprogram);
|
||||
end Parse_Setup_Subprogram_Def;
|
||||
|
||||
-----------------
|
||||
-- Check_Steps --
|
||||
-----------------
|
||||
|
@ -524,6 +608,27 @@ package body Gnatbdd.Codegen is
|
|||
Pos => Pos);
|
||||
end loop;
|
||||
|
||||
-- Parse the initialization functions
|
||||
Pos := Contents'First;
|
||||
while Pos <= Contents'Last loop
|
||||
Match (Cst_Setup_Re, Contents.all, Matches, Data_First => Pos);
|
||||
exit when Matches (0) = No_Match;
|
||||
|
||||
Pos := Matches (0).Last;
|
||||
Skip_Blanks (Contents.all, Pos);
|
||||
Last := EOL (Contents (Pos .. Contents'Last));
|
||||
|
||||
Start := Pos;
|
||||
Pos := Last + 1; -- After ASCII.LF
|
||||
Parse_Setup_Subprogram_Def
|
||||
(Contents.all,
|
||||
Package_Name => Contents (Pack_Start .. Pack_End),
|
||||
Setup_Type => Contents (Matches (1).First .. Matches (1).Last),
|
||||
Found => Found,
|
||||
Data => Data,
|
||||
Pos => Pos);
|
||||
end loop;
|
||||
|
||||
if Found then
|
||||
Append (Data.Withs,
|
||||
"with " & Contents (Pack_Start .. Pack_End)
|
||||
|
@ -637,7 +742,46 @@ package body Gnatbdd.Codegen is
|
|||
|
||||
Put_Line (F, " end Run_Steps;");
|
||||
New_Line (F);
|
||||
Put_Line (F, " Runner : Feature_Runner;");
|
||||
|
||||
-- Feature_Runner
|
||||
|
||||
Put_Line (F, " type Auto_Feature_Runner is new Feature_Runner");
|
||||
Put_Line (F, " with null record;");
|
||||
|
||||
if Data.Setup_Driver /= "" then
|
||||
Put_Line (F, " overriding procedure Run_Start");
|
||||
Put_Line (F, " (Self : in out Auto_Feature_Runner);");
|
||||
end if;
|
||||
if Data.Setup_Feature /= "" then
|
||||
Put_Line (F, " overriding procedure Feature_Start");
|
||||
Put_Line (F, " (Self : in out Auto_Feature_Runner;");
|
||||
Put_Line (F, " Feature : BDD.Features.Feature);");
|
||||
end if;
|
||||
|
||||
New_Line (F);
|
||||
|
||||
if Data.Setup_Driver /= "" then
|
||||
Put_Line (F, " overriding procedure Run_Start");
|
||||
Put_Line (F, " (Self : in out Auto_Feature_Runner) is");
|
||||
Put_Line (F, " begin");
|
||||
Put_Line (F, To_String (Data.Setup_Driver));
|
||||
Put_Line (F, " Run_Start (Feature_Runner (Self)); -- inherited");
|
||||
Put_Line (F, " end Run_Start;");
|
||||
New_Line (F);
|
||||
end if;
|
||||
|
||||
if Data.Setup_Feature /= "" then
|
||||
Put_Line (F, " overriding procedure Feature_Start");
|
||||
Put_Line (F, " (Self : in out Auto_Feature_Runner;");
|
||||
Put_Line (F, " Feature : BDD.Features.Feature) is");
|
||||
Put_Line (F, " begin");
|
||||
Put_Line (F, To_String (Data.Setup_Feature));
|
||||
Put_Line (F, " Feature_Start (Feature_Runner (Self), Feature);");
|
||||
Put_Line (F, " end Feature_Start;");
|
||||
New_Line (F);
|
||||
end if;
|
||||
|
||||
Put_Line (F, " Runner : Auto_Feature_Runner;");
|
||||
Put_Line (F, "begin");
|
||||
Put_Line
|
||||
(F, " Runner.Add_Step_Runner (Run_Steps'Unrestricted_Access);");
|
||||
|
|
Loading…
Reference in New Issue