Let us identify and markup the requirements for the behaviour of the functions from “GLib Arrays” group.
Open doc/glib-Arrays.html
in KompoZer. Switch to Normal view if it is not already active.
For now, you need not worry about how the requirements for the functions are going to be checked in the tests. Just mark them up as described below.
Only those parts of the text that contain the requirements for the behaviour of the functions are marked up. That is why the following fragments should NOT be marked up in this case:
general description of the functions dealing with GLib arrays (“Description”): there are no particular requirements for the functions in it, the requirements are stated below in the descriptions of these functions;
the example “Example3”.
The results of identifying and marking up the requirements for the functions from “GLib Arrays” group can be found here:
doc/glib-Arrays_with_reqs.html
.
Let us begin with g_array_new().
Select a continuous text block containing the requirement: “Creates a new GArray.”
Press Ctrl+R, Alt+R or select “Assign REQ” in the context menu, on the toolbar or in “Insert” menu.
Specify an identifier for the requirement. Each requirement we mark up should have a unique identifier. It will be used in the catalogue of requirements, it will be output to the test execution log (journal) in case of failure, etc. Most of the time, the IDs of requirements have the following syntax:
<function_name>.NN
, where NN is a number (index) containing at least two digits, e.g.: g_array_new.01
The numbers (indices) should start from 01 although it is not mandatory.
More complex cases will be explained later as we encounter them.
So the requirement contained in the selected fragment now has an ID: g_array_new.01
“Original text” field shows the text we have just selected. If the complete text of the requirement differs from it, we can specify the complete text manually in the “Requirement text” field. This can be useful, for example, when a requirement is formulated in several fragments of the documentation rather than in one contiguous block and the text needs to be “assembled” or when some part of the requirement comes from the very structure of the documentation or from description of other functions, etc. We use this functionality to make the requirement's text complete and clear if necessary because this textual representation of the requirement will be output to the test execution log in case of a failure.
When we specify the text of a requirement manually, it is important to preserve the meaning of the requirement. The goal is only to make the textual representation of the requirement easier to read and understand (assembling the text from several parts of the documentation if necessary).
If we do not specify the text of the requirement explicitly, the original text is used as the requirement's textual representation.
Press “Add”. Now the text block we selected represents a requirement with ID g_array_new.01.
The text blocks we have marked up are highlighted in yellow. To toggle the highlighting, press “Highlight REQ” on the toolbar.
There is another requirement for g_array_new() in the description of zero_terminated
parameter: “TRUE if the array should have an extra element at the end which is set to 0”. The requirement can be reformulated this way:
“If zero_terminated
is TRUE, the array shall have an extra element at the end which is filled with 0s.”
Like g_array_new.01, select the appropriate text block in the documentation, press Ctrl+R, then edit the ID (you may leave the ID suggested by ReqMarkup: g_array_new.02).
The “+” button increments by 1 the last index in the ID. For example, “foo.02” becomes “foo.03”, “bar.05.03.01” becomes “bar.05.03.02”, etc. The situation where there is more than one index in the ID of a requirement is described below concerning the requirements for g_array_free().
Remember that ID of a requirement should be unique. Within a single HTML file, this is enforced by ReqMarkup. The prefixes (“app”, “ext”, etc.) described below are not taken into account when ReqMarkup checks the IDs for collision (uniqueness violation). For example, the IDs “g_array_new.06” and “ext.g_array_new.06” should not exist in a document at the same time while “g_array_new.05” and “g_array_sized_new.05” do not conflict with each other.
The indices in the ID may not go in order, i.e. it is allowed that there are “foo.03”, “foo.05” and “foo.99”, but there is no “foo.04”, etc.
Press “Add” when the ID is specified.
We added the requirement but forgot to explicitly specify its textual representation (“If zero_terminated
is TRUE, the array shall have an extra element at the end which is filled with 0s.”). We need to do this because it differs from the text we selected. Now we can do the following:
Do not select any text, just press Ctrl+R. “REQ Properties” dialog appears again.
Select g_array_new.02 in the list of existing IDs. Note that “Add” button turned into “Overwrite”. Enter the text of the requirement.
Press “Overwrite”.
Note that you cannot change the ID of the requirement this way with the current ReqMarkup version. To change the ID without modifying the HTML source directly, you can do the following in KompoZer:
Position the cursor on the marked up text block of the requirement. The KompoZer's status bar will show something like this:
<span id="g_array_new.03" class="req">
Right-click this region of the status bar and select “Advanced Properties” from the context menu.
Edit the value of the “id” attribute in the dialog, then press “OK”.
The description of the clear_
parameter (“TRUE if GArray elements should be automatically cleared to 0 when they are allocated.”) should be marked up in a similar way as above. The requirement can be reformulated as follows:
“If clear_
is TRUE, the GArray elements shall be automatically cleared to 0 when they are allocated.”
g_array_new.03 will be the ID of this requirement.
If you have accidentally added a requirement, you can always remove it using the “REQ Properties” dialog:
Press Ctrl+R to open the dialog.
Select the requirement you would like to delete in the list of exising requirements (using a filter can help to quickly find the requirement).
Press “Delete” button.
Or, as usual, you can just press Ctrl+Z to undo the last operation.
You can also remove all requirements marked up in a document by pressing “Remove Markup” button on the toolbar. Beware: this operation cannot be undone.
There seems to be no requirements in the description of the element_size
parameter. Leave this description as it is.
There is a requirement in the description of the return value but we have marked up the same requirement before as “g_array_new.01”. Still we should mark up this text fragment too but give it a special ID: “&g_array_new.01”. The '&' symbol prepended to the ID means that the requirement from this text block has already been marked up somewhere in this or some other HTML file and it has been given ID “g_array_new.01”.
In fact, this newly marked up text block refers to some other text block containing the requirement (if you have experience with C++, you can recall C++ references and how '&' is used to denote them - hence the similar notation for the markup here).
The referenced requirement may be located before or after its “reference” in the document, it does not matter. References to the requirements from the different documents are allowed.
There can be unlimited number of references to a requirement. References to references are not allowed.
From the common sense and from what the documentation says about g_array_sized_new() (“the size of the array is still 0”), we can assume that the size of the newly created array is 0. That is, len
field of this GArray contains a meaningful value and this value is 0. The documentation says nothing about this, its authors probably considered it obvious. Well, let us assume it is not so obvious for us and specify it explicitly as a requirement.
If we suppose this requirement holds for g_array_new(), we can insert new text right into the HTML document and mark it up. The ID is assigned as usual except it gets the “ext” prefix: ext.g_array_new.06.
“ext” means “extension” in this case. Such requirements with ext-prefixed IDs (ext-requirements, for brevity) extend the documentation, add something to it that was not there before.
There is a crucial difference between adding an ext-requirement and manually specifying the text of the requirement. When we specify the text of the requirement, we must not change the meaning of the requirement. So we must not add any meaning to the requirement that was not there before. More often than not, we just try to make the text of the requirement clearer or “assemble” it from several parts. If we are rather going to add something new to the documentation, we should use an ext-requirement for that to distinguish it from the ordinary requirements. In practice, the line between these cases can be blurred sometimes, especially if the documentation is ambiguous.
Checking of ext-requirements can be turned on via the parameters of the tests. To enable checking of such requirements, you should specify -DCHECK_EXT_REQS
in the COMPILER_FLAGS
parameter in the .cfg file of the test suite.
We have finished marking up the requirements for g_array_new(). Please do not forget to save the HTML file we have been editing.
There are some tools provided with ReqMarkup that can be useful when the HTML file with the requirement markup is viewed in a web browser. These tools are implemented in ReqTools javascript (the example in this case study uses a copy: util/reqtools.js
). If you open the HTML files provided with this case study in a text editor, you may notice the line
<script language="javascript" src="../util/reqtools.js"></script>
just after the opening <body> tag. It is all about that.
Now if you open the HTML in a browser (currently works with Firefox and Opera, may not work in Konqueror though), you will see a “Show Requirements” link at the top. If you click this link and there are requirements marked up in the document, other links will appear (“Table >>”, etc.) which will be discussed later.
The identifiers assigned to the requirements will now be shown (in curly brackets) before the text of the corresponding requirements marked up in this file. This can help to determine if some fragment has been marked up wrong.
Click “Hide Requirements” to return to the original view of the document.
If you click on the link (“>>”) near the word “Table”, a table of all requirements marked up in the document will open. The table shows the identifier and the textual representation of each requirement. You can click the ID to go to the corresponding location in the document.
The requirements for g_array_sized_new() function can be marked up in the similar way as above. There are some things you should consider when performing the markup.
There are two requirements for g_array_sized_new() in the first sentence of its description rather than one as for g_array_new(). The first one is that the function creates a new array while the second one is that the created array has reserved_size elements preallocated. That is, the principle “one sentence – one requirement” does not always hold.
There are no requirements for the behaviour of g_array_sized_new() in the sentence “This avoids frequent reallocation, if you are going to add many elements to the array.”
Now we can markup the requirements for g_array_append_vals(), g_array_prepend_vals() and so on up to g_array_remove_range() inclusive. This should not be a problem.
When there are many requirements marked up in an HTML document, it can be difficult to find the one you need in the list in the “REQ Properties” dialog. The possibility to specify which requirements to show in the list (i.e. to filter them) can prove handy in this case.
A filter is a regular expression and it can be set in the “Filter” field of the “REQ Properties” dialog. Only those IDs that match the filter will be shown in the list. The empty filter matches any ID.
Often a substring is specified as a filter that should be in the IDs we are interested in (for example, “&g_array_new”). In fact, any regular expression can be used here provided its syntax is acceptable by JavaScript (the syntax is described here, for instance).
Now let us markup the requirements for the functions g_array_sort() and g_array_sort_with_data().
First, note that the description of g_array_sort_with_data() refers to the description of g_array_sort(): “Like g_array_sort(), but <…>”. That is, the requirements for both g_array_sort() and g_array_sort_with_data() are specified here at the same time.
In the situations like this, several IDs separated by semicolons are specified for the fragment of the documentation rather than one. For example, “g_array_sort.01; g_array_sort_with_data.01”
By the way, the text of this requirement should probably be reformulated to explicitly indicate that sorting is done in ascending order. This is almost obvious, of course, but still.
Second, consider the following fragment: “which should be a qsort()-style comparison function (returns -1 for first arg is less than second arg, 0 for equal, 1 if first arg is greater than second arg).”
There is a requirement here too but not for the g_array_sort() function but rather for any application that uses this function. The application may only pass such a comparison function to g_array_sort() that meets this requirement. Otherwise nothing is guaranteed.
Requirements like this (requirements for applications, app-requirements) are often found, for example, in the description of input parameters of the functions under test. We need to mark up them too. The rules for assigning IDs are the same as above except they get the “app” prefix. Examples:
If an ID has more than one prefix, their order does not matter. I.e. “app.ext.my_func.63” and “ext.app.my_func.63” is actually the same ID.
It is not mandatory to check app-requirements in the tests but it is allowed to do so. Often app-requirements are checked in a test scenario before calling the function under test. If an app-requirement is violated, it may indicate an error in the test itself or some unhandled error in the system under test. Ideally, app-requirements should be satisfied by the way the tests are organized so it would be not necessary to check them explicitly.
REQ()
and REQva()
macros can be used to check app-requirements as well as the requirements for the system under test (see Section 4.1.5, “REQ( ) and REQva( )”).
There is another requirement in the description of g_array_sort_with_data() in the following fragment: “the comparison function receives a user data argument.”
This fragment means that g_array_sort_with_data() is implemented so that when the comparison function is called during sorting, its last argument contains the value of user_data
. So it is also a requirement and needs to be marked up.
At this stage, marking up the requirements for g_array_set_size() should pose no problem.
When marking up the requirements for g_array_free(), consider the last sentence:
“Returns : the element data if free_segment is FALSE, otherwise NULL”
Two possible ways for the function to behave are described here. It is in fact a compound requirement specifying what value the function must return. This requirement is not atomic, it contains two separate requirements (one for the case when free_segment
is FALSE and one for the case it is not FALSE). The requirements like these are marked up in the following way.
A so called parent requirement is associated with a common part of the text of these requirements (“Returns:” in this case). Let us set “g_array_free.03” as its ID.
Then two child requirements are associated with the following text fragements: “the element data if free_segment is FALSE” and “otherwise NULL”. These requirements get the identifiers “g_array_free.03.01” and “g_array_free.03.02”, respectively. That is, we simply append one more index to the ID of the parent requirement.
The child requirements can be formulated as follows:
g_array_free.03.01: “The function returns the element data if free_segment is FALSE.”
g_array_free.03.02: “The function returns NULL if free_segment is TRUE.”
The parent requirement (“g_array_free.03”) is considered checked if and only if all its children have been checked (g_array_free.03.01 and g_array_free.03.02).
Child requirements may have child requirements of their own. The IDs are assigned the same way: for instance, the children of “g_array_free.03.02” would be “g_array_free.03.02.01”, “g_array_free.03.02.02”, etc.
Before we finish marking up the requirements, let us take a closer look at the description of GArray structure at the beginning of the document. There are two public fields in this structure, data
and len
.
The description of these fields imposes additional restrictions on the behaviour of the functions from “GLib Arrays” group.
First, consider len
field:
“guint len; the number of elements in the GArray.”
This means that if a function changes the length of the array, len
should change accordingly. That is, say, if we use g_array_append_vals() to add 3 elements to an array, len
should increase by 3 after that.
On the other hand, if a function does not change the number of elements in an array (like g_array_sort()), len
should remain the same.
Second, let us look at the description of data
field: “gchar *data; a pointer to the element data.”
This means that whatever happens to the array, data
must point to the location where the elements of this array are stored. The format used to store the elements is not specified exactly but at least data
must not be NULL.
The implicit requirements like these usually affect all or the most of the functions in the particular group. So we should mark them up specifying the lists of ids like the following: “g_array_new.07; g_array_sized_new.07; g_array_set_size.07; …”
For the next requirement of this kind we would use “g_array_new.08; g_array_sized_new.08; g_array_set_size.08; …”
Using long lists of ids that differ only in the indexes can be tedious and error-prone. There is a more convenient way to handle this: define–blocks.
To create a “define-block”, press “Defines” button on the toolbar. A dialog will appear displaying all “define-blocks” found in the document. Press “Add” button and enter name (“@g_array_funcs”) and value for a new “define-block” in the “Define Editor” dialog, then press “Add” button there.
In this case, the value is as follows:
“g_array_new; g_array_sized_new; g_array_set_size; g_array_free; g_array_append_vals; g_array_insert_vals; g_array_prepend_vals; g_array_remove_index; g_array_remove_index_fast; g_array_remove_range; g_array_sort; g_array_sort_with_data”
The “Defines” dialog will now show us the newly added “define”-block:
To edit an existing define-block, select it in “Defines” dialog and press “Edit”. Then you will be able to edit the name and the contents of the define-block in “Define Editor” dialog.
It is recommended (but not mandatory) for the names of define-blocks to begin with '@'. This makes it easier to distinguish such names from the ordinary function names, etc.
Now we can use “@g_array_funcs” instead of this list of function names: the description of data
field will have the id “@g_array_funcs.07”, while the description of len
– “@g_array_funcs.08”.
In order to keep this example relatively simple, some of these requirements are not checked in the sample tests provided with this manual.
ReqTools script can also show the define blocks present in the HTML file. Click on “>>” to the right of the word “defines” at the beginning of the document to see them. If there are no define blocks in the HTML, this link will not be shown.
Markup of requirements in the documentation for “Glib Arrays” group is now complete.