The templates used to generate output files are little more than just “documents with holes” in the most simple case. They contain parts (“string chunks”) that will be placed verbatim to the output file and special named placeholders that may refer to other templates or parameters.
The file generator uses special template engine (MiST Engine - “Minimal String Template Engine”) to process the templates and create the output files. The engine is statically linked into the generator, so there is no need to build and install it separately, if you have installed T2C. MiST Engine is also available as a separate package from the Template2Code project page at SourceForge.net.
Here is an example of a simple template:
Good morning, <$Title$> <$Name$>! It is good to see you.
Let “GoodMorning” be the name of the template. This template has two placeholders:
<$Name$>. If parameter “Name” has value “Freeman” and “Title” has value “Dr.”, the above template will evaluate to the following:
Good morning, Dr. Freeman! It is good to see you.
As you can see from the example, newline characters in string chunks are also placed verbatim to the resulting text.
$> are the markers to denote the beginning and the end of a placeholder. If necessary, user-defined values can be used as the markers instead of the default ones. The new values can be specified in the configuration file of the appropriate template group and will affect the whole group (template groups are described in detail in Section 5.2, “Template groups and subtemplates”).
Whitespace characters (spaces, tabs and newlines) are ignored after the opening marker and before the closing marker of a placeholder. The following template is equivalent to “GoodMorning” template above:
Good morning, <$ Title $> <$ Name $>! It is good to see you.
A template may refer to other templates (from the group it belongs to) in the same way it refers to the parameters. That is, assume “Name” is not a parameter but there is rather a template with name “Name” and the following contents:
If “Title” is “Dr.” as above, “first_name” is “Gordon” and “last_name” is “Freeman”, “GoodMorning” template will evaluate to the following:
Good morning, Dr. Gordon Freeman! It is good to see you.
The placeholders referring to subtemplates and parameters have the same syntax (a parameter can actually be viewed as a special case of a subtemplate). How a placeholder is interpreted depends only on the presense of a template with the appropriate name in the corresponding template group. For example,
<$Title$> is a reference to the template with name “Title” if there is such template in the group, but a reference to a parameter otherwise.
The value of each parameter is a string. There are no types of values here, like integer, float, etc. The file generator operates on strings only.
If a parameter has no value, its value is assumed to be an empty string.
A parameter may have more than one value (multi-valued parameter). Consider the following “GoodMorning” template similar to the one from the examples above:
Good morning, <$Title$> <$Name$>!
Now let “Name” and “Title” parameters have 3 values each, “Freeman”, “Vance”, “Grigory” and “Mr.”, “Dr.”, “Mr.”, respectively. The order of values of each particular parameter is important. Note that it is possible for a parameter to have two or more identical values, like “Mr.” in case of “Title” parameter.
“GoodMorning” template will have 3 values as a result:
Good morning, Mr. Freeman!
Good morning, Dr. Vance!
Good morning, Mr. Grigory!
As you can see, the first values of “Name” and “Title” are used to create the first resulting value, the second values of these parameters are used for the second one, etc.
Note that it is exactly 3 values that the template will have as a result rather than a single string with these values concatenated. To concatenate these values into a single string, you need to use
join() construct described below.
If the main (top-level) template in a group is multi-valued as a result, T2C file generator will report this as an error. Other templates can be multi-valued - as long as the top-level template has only one value.
The number of resulting values is the maximum number of values associated with the placeholders in the template. If there are less values associated with a particular placeholder than the number of the resulting values, the last value associated with this placeholder is used when creating the remaining resulting strings.
For example, assume that “Name” parameter has the 3 values described above but “Title” has only two: “Doctor” and “Mr.”, in this order. “GoodMorning” template will have the following 3 values in this case:
Good morning, Doctor Freeman!
Good morning, Mr. Vance!
Good morning, Mr. Grigory!
Even if “Title” parameter had only a single value, “Mr.”, the template would have 3 values as a result:
Good morning, Mr. Freeman!
Good morning, Mr. Vance!
Good morning, Mr. Grigory!
That is, the only value of “Title” parameter is used in conjunction with each of the three values of “Name” parameter to produce three resulting strings.
Now assume we have two templates: “GoodMorning” and “Person”.
“GoodMorning” (note that it refers to “Person” subtemplate, see Section 5.2.2, “References in the templates” for details):
Good morning, <$Person$>!
If “Title” or “Name” parameter is multi-valued, “Person” and “GoodMorning” templates will also have more than one value.
Sometimes it is necessary to join the values of a multi-valued template or parameter.
join() construct in the placeholder can be used to do this. Suppose we rewrite “GoodMorning” template as follows:
Good morning, <$Person : join(, )$>!
Let “Name” and “Title” parameters have 3 values each, “Freeman”, “Vance”, “Grigory” and “Dr.”, “Mr.”, “F.” respectively. “GoodMorning” template will have a single value in this case:
Good morning, Dr. Freeman, Mr. Vance, F. Grigory!
The values of “Person” subtemplate are joined here into a single string with “, ” inbetween as a separator. This separator sequence was specified in the parentheses in
join(). So, a construct like this allows to create various list-like structures in the resulting files.
The syntax of a placeholder with
join() construct is as follows:
<name>: join (
Space, tab and newline characters are optional before and after the colon, before the opening parenthesis and after the closing parenthesis. These whitespace characters are ignored.
The whitespace characters are not ignored between the parentheses. That is, the sequence between the first '(' character after
join and the last ')' character of the placeholder is taken as a whole as the separator string. This also allows to use '(' and ')' characters in the separator string without escaping.
If there is nothing between the parentheses in a
join() construct, an empty string will be used as a separator as you could expect.
If the subtemplate or parameter referred to in a placeholder with
join() has only one value, the
join() construct is ignored. As a result, the placeholder will have the same value as if there were no
The following character sequences have special meaning when used in the separator string in
join(). They are interpreted in the similar way as in the strings in C programming language.
\\ - '\' character.
\n - LF character.
\r - CR character.
\t - TAB character.
These escaped sequences are supported to provide a convenient way to specify tabs and newline characters in the separator strings. Nevertheless, a newline can still be specified in the separator literally, for example:
Good morning, <$Person : join(, )$>!
The following variant is often more convenient to use here instead:
Good morning, <$Person : join(,\n)$>!
If is sometimes needed to include one or another part in a template depending on whether some particlular parameter is defined or not. Conditional constructs in the templates allow to do this. There are two forms of conditional constructs (with and without “else” branch):
<$if … $>,
<$endif$> are placeholders of a special sort.
cond is a conditional expression which will be checked to select appropriate branch. It can be a name of a parameter or a subtemplate or it can be a concat-expression (see below).
else-branch can be arbitrary sequences of string chunks and placeholders. These branches may also contain conditional constructs (nested conditionals).
join() constructs are not allowed in the conditional expression (
cond). If you need to use a joined value as the condition, you should prepare a subtemplate, join the appropriate values there and use the name of the subtemplate as the conditional expression instead.
If you need the branches to be chosen depending on whether a parameter or a template has at least one non-empty value, you can also use a concat-expression as a conditional expression.
The most simple case is when the template or the parameter referred to by
cond has the only value (if it is not defined at all, it is considered the same as if it was defined and had only one value, an empty string).
Consider the following extract from a template of a makefile for the group of tests:
TEST_EXT = <$if TEST_SOURCE_EXT$>.<$TEST_SOURCE_EXT$><$else$>.cpp<$endif$>
In this example, “TEST_SOURCE_EXT” is a parameter than may be specified in the configuration file for the test suite or for the group of tests. It defines the extension of the file names used for the sources of the tests. If “TEST_SOURCE_EXT” is defined and is not empty, its value will be assigned to
TEST_EXT variable in the makefile with a dot prepended. For example, if “TEST_SOURCE_EXT” has value “dxx”, the value of the conditional construct will be “.dxx”. If “TEST_SOURCE_EXT” is empty or is not defined, the value of the conditional construct will be “.cpp”.
cond is multi-valued, things get more complicated. The template engine processes such conditional constructs as follows.
First, for each value of
cond, the template engine determines which branch should be evaluated and evaluates it (if it has not done that yet).
Second, the number of values the conditional construct will have (
nvals) is determined. It is the maximum among the numbers of values of
cond and of the branches that are actually taken. That is, if
cond has such values that one branch is never chosen, this branch is not evaluated and the number of its values is not taken into account as well.
Finally, each of
nvals resulting values of the conditional construct is prepared. To obtain the value #i, the value #i of
cond and the value #i of the corresponding branch are taken. If the branch does not have value #i, its last value is used instead, same for
To make it clearer, consider the following example. Suppose we have a template:
Suppose the parameters
PC have the following values:
PA: “A1”, “A2”, “A3” (3 values)
PB: “B1”, “B2”, “B3”, “B4” (4 values)
PC: “C”, “”, “C”, “”, “”, “C” (6 values, 3 of which are empty)
The template will have 6 values as a result: “[A1]”, “-B2-”, “[A3]”, “-B4-”, “-B4-”, “[A3]”.
PC had only one value, “C”, the template would have 3 values as a result: “[A1]”, “[A2]”, “[A3]”.
PC had 6 values, each of which was empty, the template would have 6 values as a result: “-B1-”, “-B2-”, “-B3-”, “-B4-”, “-B4-”, “-B4-”.
It can be helpful to be able to choose a branch depending on whether a parameter or a subtemplate has at least one non-empty value. This is equivalent to checking whether a string created by concatenating (“gluing”) the values of that parameter or subtemplate is non-empty. This can be achieved by using a subtemplate where
join() is applied to these values but it is often more convenient to use a concat-expression instead.
A concat-expression has the following form:
name is the name of the corresponding parameter or a subtemplate. The expression can only be used within
<$if ...$> placeholder. The conditional construct is interpreted the same way in this case as if the conditional expression was a parameter having only one value which was non-empty if and only if
name had at least one non-empty value.
Consider a modified version of the template from the example above:
PB have the same values as above and
PC has 6 values: “C”, “”, “C”, “”, “”, “C”. The template will have 3 values as a result: “[A1]”, “[A2]”, “[A3]”.
PC has some non-empty values, so only then-branch is used.
PC had only one value, “C”, the result would be the same.
PC had 6 values, each of which was empty, the template would have 4 values as a result: “-B1-”, “-B2-”, “-B3-”, “-B4-”. Note the difference from the example without a concat-expression. This is because
concat(PC) is an expression having only one value even though
PC has 6 values.
The templates are often organized in groups (template groups). It is a template group rather than a single template that the template engine (and hence the file generator) usually operates on. Each group corresponds to a single file to be generated.
Each group has a main (“top-level”) template. This template usually defines the structure of the file to be generated from this group. Name of the group is the name of its main template.
A template group is represented in the file system by a directory with the same name as the group. This directory should contain at least two files:
The file containing the main template of the group. This file has .tpl extension and the same name as the template (and the group).
The configuration file for the group. This file has .cfg extension and the same name as the group. The contents of this file are described below.
Each template from a group is stored in a file with .tpl extension and the same name as the template in the directory of the group.
For example, the templates considered in Section 5.1.3, “Joining values” could be organized as “GoodMorning” template group as follows in the file system:
GoodMorning // directory for "GoodMorning" template group | +- GoodMorning.cfg // configuration file for the group +- GoodMorning.tpl // main template ("GoodMorning") +- Person.tpl // "Person" template
Only the configuration file of a template group and .tpl files contained in the directory of this group are loaded by the template engine. All other files are ignored.
The configuration file for a template group has the same format as the configuration files defining the values of parameters referred to by the templates. The format is described in Section 5.3, “Parameters and configuration files”.
The following parameters are recognized by the template engine in the configuration file for a template group (all other parameters are ignored):
(optional) A character sequence that marks the beginning of each placeholder in the templates from the template group as well as in the template defined in
FILE_PATH_TEMPLATE parameter (see below).
(optional) A character sequence that marks the end of each placeholder in the templates from the template group as well as in the template defined in
FILE_PATH_TEMPLATE parameter (see below).
(required) Template of the path to the file to be generated. This template must not refer to subtemplates, but it may refer to the parameters of the tests (default parameters, parameters defined for the test suite or for a particular group of tests).
For example, here is a sample template of the path to the test source file:
FILE_PATH_TEMPLATE = <$SUITE_ROOT_DIR$>/tests/<$T2C_FILE_NAME$>.cpp
When the file generator is about to create the resulting file for a template group, it evaluates the template from
FILE_PATH_TEMPLATE parameter to obtain the path to that file. If some directories in the path do not exist at the moment, the file generator will attempt to create them.
Sometimes (for example, for debugging purposes) it can be useful to define this parameter without any placeholders, like this:
FILE_PATH_TEMPLATE = output.txt
This instructs the file generator to place the result to
output.txt file in the current working directory.
FILE_PATH_TEMPLATE parameter must be defined in the configuration file for test_case template group too, even though it is not used there. You may specify any value for
FILE_PATH_TEMPLATE in this case.
If a custom begin or end marker has been specified in the configuration file for the template group, it will affect not only the templates from this group but also the template in
# Custom begin and end markers of placeholders in the templates. PH_BEGIN_MARKER = $$ PH_END_MARKER = $$ # The template of the path to the file to be generated. # Note the use of the custom markers ('$$') here. FILE_PATH_TEMPLATE = some_dir/$$OUT_DIR$$/Good Morning.txt
A template may refer to other templates (subtemplates) from the same group. These templates may in turn refer to subtemplates of their own and so on. A template may refer to any number of subtemplates and any number of templates may refer to the same template. This allows to use the templates as the building blocks to factor out common parts of the generated file, etc. From this point of view, the templates are a bit similar to macros (preprocessor definitions, #define constructs) used in C source code, macro definitions processed by m4 tool, etc.
Currently, there is no way for a template to refer to a subtemplate from another group.
Avoid creating recursion in the template references. Here are two common examples of recursion:
Template “A” has a placeholder that refers to template “A”.
Template “A” has a placeholder that refers to template “B”, template “B” (or some other template “B” refers to, etc.) has a placeholder that refers to template “A”.
Currently, the template engine does not detect the recursion in the template references. If there is a recursion, the following is guaranteed though:
The template engine will neither hang nor crash, the evaluation of the group will complete (but it is undefined what the result will look like).
When the group is evaluated, each template will be evaluated no more than once.
Each template in a group must have a unique name. It is the name that is used to refer to this template from other templates in the group. The names are case sensitive.
The name of a template is a string of single-byte characters. It must not begin with a dot or a space and must consist only of characters listed below:
latin letters: 'A'..'Z', 'a'..'z' (character codes 0x41-0x5A, 0x61-0x7A)
digits: '0'..'9' (character codes 0x30-0x39)
space: ' ' (character code 0x20)
hyphen: '-' (character code 0x2D)
dot: '.' (character code 0x2E)
underscore: '_' (character code 0x5F)
If a template group is to be loaded from the file system, this may impose additional system-specific restrictions on the names of the templates. This is because the name of a template is the name of the corresponding file (without .tpl extension) in this case. In addition, the name of the main template of the group is the name of the directory where the group is located. For example, this may impose a restriction on the length of the name.
The following keywords have special meaning and must not be used as the names of templates or parameters:
When the group is evaluated, the template engine starts with the main template. It looks for the templates it refers to, processes these templates and their subtemplates recursively in a similar way and so on. If the template engine encounters a template that does not refer to any other templates (it may refer to parameters, though), the values of the template are prepared, that is, evaluation of the template is complete. The template engine continues until all the necessary templates are evaluated and finally, the main template is evaluated.
This process can be viewed as traversing a tree (a hierarchy) of the templates. The main template is the root node, the parameters and subtemplates it directly refers to are its child nodes. A child node may have children of its own, etc. The nodes representing the parameters are the leaf nodes of this tree. The template engine goes deep to these leaf nodes first and then back to the root evaluating the nodes in its path.
With this approach, only the templates needed to evaluate the main template are actually evaluated. Nevertheless, all the templates from the group are loaded when the group is loaded by the template engine including the ones that will not actually be used. In particular, syntax checking will be performed for each template in the group.
The values of parameters that can be referred to by the templates are often specified in “configuration files” (“value files”). Format of such files is described below. Note that the term “whitespace characters” refers only to spaces and tab characters in this section.
A configuration file has the following format. The file may contain blank lines (1), comments (2), and parameter definitions (3, 4).
(1) Blank lines, that is, the lines containing only whitespace charaters, are ignored.
(2) A comment is a line, the first non-whitespace character in which is '#'. Comments are also ignored.
Parameter definitions can be “single-line” and “multiline”.
(3) A definition of a “single-line” parameter has the following form:
<Name> = <Value>
Whitespace characters surrounding
<Value> are ignored.
<Name> must not contain whitespace characters.
<Value> can be empty. It may also contain '=' characters. Example:
CFLAGS = -std=c99 -O2
Here, the name of the parameter is “CFLAGS” and its value is
A backslash character ('\') can be used to split long
<Value> strings into several logical lines (“logical” because all of them will be combined into a single line when the configuration file is loaded). Leading and trailing whitespace characters will be removed from each logical line. Single space characters will be inserted between the lines when combining.
For example, the above definition of “CFLAGS” can be written equivalently as follows:
CFLAGS = \ -std=c99 -O2
or as follows:
CFLAGS = -std=c99 \ -O2
A backslash must not occur between
<Name> and '='. The following example is not allowed:
CFLAGS \ = -std=c99 -O2
Note that the “logical” lines that begin with '#' or contain only whitespace characters are considered to be the part of
<Value> and hence are not ignored. Consider the following definition:
CFLAGS = -std=c99 \ \ # foo
It is is interpreted as follows:
CFLAGS = -std=c99 # foo
The value of “CFLAGS” parameter is
“-std=c99 # foo” in this case.
(4) A definition of a “multiline” parameter has the following form:
<Name> =>> <line1> <line2> ... <lineN> <<
The value of this parameter is the part of the file between
“<<” (excluding the newline characters before
<line1> and after
These lines are taken “as is”: no trimming of whitespace characters, no comment and blank line recognition, no special meaning of the trailing backslash characters like in (3) above, etc.
The resulting value will contain newline characters between
<lineN>, so the value of the parameter can be multiline indeed.
Non-whitespace characters are not allowed after
“=>>” marker at the same line.
If and only if a line contains just
“<<” and, optionally, whitespace characters, it is considered an end marker for the value of this parameter. That is, it is allowed to specify multiline parameters like this:
CFLAGS =>> -O2 -D"_FOO=<<" -g <<
“-D"_FOO=<<"” is not considered an end marker for this value because apart from
“<<”, there are non-whitespace characters on the line.
An example of a configuration file is shown below:
############################################################################ # mysuite.cfg ############################################################################ # Name of the test suite TEST_SUITE_NAME = mysuite-t2c # Version of the test suite TEST_SUITE_VERSION = 0.1.0_alpha2 # Bug report address of the test suite (typically, email or web address) TEST_SUITE_BUGREPORT = http://bugtracker.somesite.org/sample-tests/ # Copyright holder COPYRIGHT_HOLDER = Some Company Ltd # Extra options for the compiler and linker common for all the tests in the # suite. COMMON_COMPILER_FLAGS = -DCHECK_EXT_REQS \ `pkg-config --cflags MySuperLibrary-3.1 \ gtk+-2.0` COMMON_LINKER_FLAGS = COMMON_LIBS = `pkg-config --libs MySuperLibrary-3.1 gtk+-2.0` # A boilerplate notice. NOTICE =>> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. <<
If there are several
records with the same
Name in the file, all the values defined this way will be associated with the corresponding parameter. The parameter will be multi-valued as a result. The order of its values will be the same as the order of the respective records in the file.
Note that when T2C file generator processes the configuration files for the test suites and test groups, it will report an error if it encounters a multiple definition of a parameter. This makes sense in T2C because usually the very meaning of a configuration parameter requires that it has only one value. There are some multi-valued parameters used there too (
TEST_MODULE, for example) but they always have special meaning and hence are specified in a special way. Custom multi-valued parameters are not allowed by T2C file generator.
On the other hand, MiST Engine allows to define multi-valued parameters in the configuration files (“value files”) as described above. Unlike T2C, MiST Engine does not make any assumptions about the meaning of parameters (except the parameters of template groups like
FILE_PATH_TEMPLATE, etc.). So you can use parameters with MiST Engine if you want to.
Parameters used by T2C file generator to create resulting files can be specified at three levels:
Several special parameters are set by the file generator (see Section 5.7.2, “Special parameters defined by the file generator”). The values of these parameters cannot be overridden at suite-specific or test-specific level (it usually makes no sense to try to do so, anyway).
These parameters are specified in the configuration file of the test suite. Among these are often custom compiler and linker options to be used when building the tests from the generated files, parameters controlling execution of the tests (for example, time limits), etc. Even a copyright notice that should appear at the top of the generated source files can often be made a parameter.
A configuration file should always be provided for the test suite. This file should be located in the main (root) directory of the suite. It has .cfg extension and the same name as that directory (without “–t2c” suffix if it was present). For example, if the main directory of the suite is
foo, the file generator will look for
foo.cfg in that directory. For
baz-t2c directory, the configuration file should be named
It is allowed to specify user-defined parameters at this level. The file generator makes no assumptions about the meaning of suite-specific parameters (except two special parameters described below) and just substitutes them to appropriate places in the templates.
Two special parameters can be specified at this level, both of which are optional:
TARGET - instruct t2c to use the value of this parameter as the name of file generation target if target is not specified in the command line options (see Section 3, “T2C Command Line Tool” for details).
This parameter cannot be overridden at the test-specific level.
TEMPLATE_DIR - path to the directory containing suite-specific templates (see Section 5.5, “Default, suite-specific and test-specific templates” for details).
This parameter cannot be overridden at the test-specific level. If some value is still specified for it there, this “test-specific” value is ignored.
You can optionally specify parameters that will affect only the group of tests generated from a particular .t2c file. If a parameter is defined both at suite-specific and test-specific levels, its value from the test-specific level is used. Special parameters (see above) cannot be overridden this way.
It is also allowed to define the parameters at this level that are not specified at two other levels.
Using test-specific parameters can be helpful, for instance, in the following (if the file generation target supports appropriate features):
Set a different time limit on the execution of the tests for the group of tests than for the remaining groups.
Specify a particular copyright notice for the group of tests if it should be different than for the rest of the suite.
Specify custom compiler and linker options to be used for this group of tests.
Specify additional source files and other files necessary to build the tests from this group. This could also be achieved by overriding the appropriate templates at test-specific level (see Section 5.5, “Default, suite-specific and test-specific templates”) but using the parameters for that could sometimes be more convenient.
Specify a custom extension to use in the name of the generated source file for the group if it differs from the one used in this test suite by default.
The parameters defined at this level are set in a test-specific configuration file. This file should be located in the same directory as the corresponding .t2c file. The configuration file should have the same name as the .t2c file but its extension should be .cfg, for example,
test.cfg for the group of tests defined in
bar.foo.t2c, etc. If the T2C source file defining the group or tests does not have .t2c extension, .cfg extension is appended to get the name of the configuration file:
Similar to parameters, there are default, suite-specific and test-specific templates (more exactly, template groups) used by the file generator.
New template groups can be added at suite-specific and test-specific levels which will result in creation of the corresponding output files by the file generator. For example, if you need an additional file to be created for each group of tests in the suite, you should provide appropriate template group for that file at the suite-specific level. The file generator will do the rest.
Some or even all of the template groups can be overridden (replaced by the groups with the same names but probably different contents) at the suite-specific or test-specific level. The file generator decides which templates to use individually for each template group. First, it creates a list of the groups provided by default for the file generation target currently used. Then, if there are suite-specific template groups for this target, the file generator updates the list, adding these groups to it. Each template group in the list that has the same name as a suite-specific group is replaced by the latter. Finally, the process is repeated for test-specific templates for the target: new template groups are added and the default and suite-specific ones are overridden by the test-specific ones. The resulting list may contain the template groups from one, two or even from all three levels. These groups are then evaluated by the file generator to create the required files.
When looking for appropriate templates, the file generator processes each template group as a whole. So, it is not possible to add or override only a part of a group and leave the remaining templates from the group unchanged. Only a template group as a whole can be added or overridden.
Currently, there is no way to instruct the file generator to create less files at, say, suite-specific level than required by the template groups at the default level. That is, template groups cannot be “turned off” at suite-specific and test-specific levels, they can only be added or overridden.
It is not required to use suite-specific or test-specific templates.
Here is a description of how the template groups are defined at each level (see also Section 5.6, “Directory structure of the templates for a T2C target”).
Default templates are loaded from
subdirectory of the main template directory (
<target_name> is the name of the file generation target to be used). Main template directory is
templates subdirectory of what is returned by t2c --print-data-dir unless t2c is executed with
-d command line option (see Section 3, “T2C Command Line Tool” for details).
If there is
TEMPLATE_DIR parameter defined in the configuration file of the test suite, its value specifies the path to the suite-specific template directory. This directory must contain a subdirectory with appropriate name for each file generation target the suite-specific templates are provided for. The value of
TEMPLATE_DIR parameter is interpreted as the path relative to the root directory of the suite.
For example, suppose “makefile_am”, “test_group” and “test_case” template groups are defined by default for test mode (see Section 3, “T2C Command Line Tool”) for a target named “c_sample”. The directory structure of the main template directory may look as follows:
<main_template_directory> | c_sample // name of the target | +- common // template groups used by t2c in "common mode" | | | ... | +- test // template groups used by t2c in "test mode" | +- makefile_am +- test_case +- test_group
Assume we want to add “some_data” template group and replace “test_group” with a suite-specific one in the test mode. To do so, we should create
custom_templates subdirectory in the main directory of the suite. The subdirectory should contain the following:
custom_templates | c_sample // name of the target | +- test // template groups used by t2c in "test mode" | +- some_data // another template group to be processed +- test_group // these templates override the default ones
Note that as we do not change anything in common mode, we do not need to provide
Now we need to define
TEMPLATE_DIR parameter in the configuration file of the suite as follows:
TEMPLATE_DIR = custom_templates
After that, if we execute t2c in test mode, it will use default template groups “makefile_am” and “test_case” and suite-specific template groups “test_group” and “some_data”.
These templates affect only the group of tests created from a particular .t2c file. Main directory of the templates should be located in the same directory as the corresponding .t2c file. The name of this template directory should be the same as the full name of that file with “.templates” suffix appended. If the T2C source file ends with .t2c extension, this extension is omitted. For example, test-specific templates for the group of tests defined in
test.t2c should be stored in
test.templates directory, for
bar.foo.t2c - in
bar.bz - in
The directory structure for test-specific templates is similar to that of the suite-specific ones.
Let us extend the example above. Suppose we also want to replace the templates from “makefile_am” and “some_data” groups with test-specific ones for the group of tests to be created from
buzz.t2c. To do this, we should create
buzz.templates subdirectory in the directory where
buzz.t2c is located. The subdirectory should contain the following:
buzz.templates | c_sample // name of the target | +- test // template groups used by t2c in "test mode" | +- makefile_am // overrides the default templates +- some_data // overrides the suite-specific templates
If we now execute t2c in test mode, it will use the default template group “test_case”, suite-specific template group “test_group” and test-specific template groups “some_data” and “makefile_am”.
If you use test-specific templates, it does not mean that you should use suite-specific templates as well.
Main template directory for a T2C file generation target should have the same name as the target. It may contain two subdirectories:
common - this directory contains templates for the files specific to the test suite. t2c will use these templates when called in common mode (see Section 3, “T2C Command Line Tool”). If there are no such files to be generated, the directory could be absent.
test - this directory contains templates for the files specific to the group of tests defined in a particular .t2c file. t2c will use these templates when called in per-test mode (see Section 3, “T2C Command Line Tool”). This directory can also be absent but it usually makes little sense not to use it.
For each file to be generated in common or per-test mode, a template group should be prepared (see Section 5.2, “Template groups and subtemplates” for details). The templates from this group should be located in a subdirectory of
test directory, respectively, that has the same name as the group.
Name of a template group does not need to be the same as the name of the file to be created from it. The name (the path) of the resulting file should be specified in
FILE_PATH_TEMPLATE parameter in the configuration file of the group. The configuration file of the group has .cfg extension and the same name as the group. This file is located in the directory containing the templates from this group.
There is one notable exception to “One template group - one generated file” rule. The file with source code of a group of tests is created using two template groups that must always be present in per-test mode: test_case and test_group. The former allows to create an individual test, the latter defines the structure of the source file where these individual tests will be placed. The path to the source file is specified in
FILE_PATH_TEMPLATE parameter in the configuration file of test_group group. How these template groups are processed is described in Section 5.7, “Generating output files for the test suites”.
Consider, for example, directory structure of the templates for c_gtest_nested target:
c_gtest_nested | +- common | | | +- configure_file // templates for top-level configure.ac file | | | | | +- configure_file.cfg // configuration file | | +- configure_file.tpl // main template | | +- makefile_item.tpl // subtemplate | | | +- makefile_am_file // templates for top-level Makefile.am file | | | +- makefile_am_file.cfg // configuration file | +- makefile_am_file.tpl // main template | +- test_subdir.tpl // subtemplate | +- test | +- makefile // template for per-test makefiles | | | +- makefile.cfg // configuration file | +- makefile.tpl // main template | +- test_case // templates for an individual test | | | +- test_case.cfg // configuration file | +- test_case.tpl // main template | +- define.tpl // subtemplate | +- undef.tpl // subtemplate | +- test_group // templates for a test source file | +- test_group.cfg // configuration file +- test_group.tpl // main template +- test_func_item.tpl // subtemplate +- test_name_item.tpl // subtemplate
Apart from the sources of the tests, the output files (Makefiles, etc.) are generated simply by evaluating appropriate template groups. The process of generating the source files is more complicated, test_group and test_case template groups are handled in a special way by the file generator. The process is described below.
Each individual test is generated from a <BLOCK> section for the corresponding set of parameter values defined in the <VALUES> (or <PURPOSE>) subsection of the <BLOCK>. The file generator uses test_case template group to do this. It is the only template group from which no file is created. It is rather used to prepare the parts of the test source file. After test_case template group is evaluated to obtain the source of an individual test, the resulting string is appended to the list of values of
test_case parameter used by test_group template group. From the latter group, the file with the source code of the tests is created.
Technically, a file containing the source code of the tests is created by the file generator in three steps:
An intermediate template of the source code of the tests from a <BLOCK> section is prepared by evaluating test_case template group with respect to <$…$>-parameters and subtemplates. That is, the templates from test_case group, the contents of <CODE> and <FINALLY> sections are assembled into a single template that may refer only to <%…%>-parameters.
The intermediate template prepared at the previous step is now evaluated for each set of values of test parameters (<%…%>-parameters) to produce the source code of the corresponding individual tests. In particular, this is the step when the values from <VALUES> (<PURPOSE>) sections replace
<%2%>, etc., in the source code of the tests.
The resulting strings containing the source code of the individual tests created from the <BLOCK> section are appended to the list of values of
test_case parameter that will be used by test_group template group.
The previous two steps should now have been performed for each <BLOCK> section in the .t2c file. Finally, the test_group template group is evaluated to produce the file containing the source code of all the tests generated from the .t2c file.
The main template of test_group template group often contains a construct like the following one to place the sources of the individual tests in the resulting test source file:
<$test_case : join(\n)$>
Here, the generated sources of the individual tests will be placed in the resulting source file separated by newline characters ('\n').
Because the file generator operates this way when creating source files, there are some restrictions on using template parameters in .t2c files.
For example, the parameters defined in the configuration file(s) for the tests as well as the special parameters defined by the file generator are substituted only when test_group template group is evaluated (as well as the template groups, from which other files are generated). This means, it is no good using these parameters in the sections of a .t2c file: they will be taken literally by the file generator. If you want these parameters to be used in the source files of the tests, you should appropriately change the templates from test_group group rather than refer to these parameters in the .t2c file.
Begin and end markers of the placeholders in the templates (
“$>” by default) can be changed for all template groups except
“%>” in test_case group.
User-defined markers can be specified in
PH_END_MARKER parameters, respectively, in the configuration file of the template group of interest.
T2C file generator defines several special parameters that can be referred to by the templates. The parameters are listed below.
The actual path to the data directory of T2C file generator.
This parameter should not be confused with
T2C_DATADIR environment variable (see Section 3, “T2C Command Line Tool”).
T2C_DATADIR parameter is rather what t2c --print-data-dir returns. It is always non-empty while
T2C_DATADIR environment variable may or may not be defined.
The absolute path to the root directory of the test suite.
The name of the test suite. It is the name of the main directory of the suite (without “–t2c” suffix if it was present).
The name of the .t2c file being processed (without “.t2c” extension if it was present).
Current year in YYYY format (mostly for copyright notices).
Name of the T2C target this file has been generated for (like c_minimal, c_standalone, etc.)
If t2c is called with
--list-file) option, the values of this parameter are entries read from the file specified in this option. The entries may have any meaning but usually they somehow identify the groups of tests. For example, each entry can be the name of the .t2c file in the suite.
TEST_MODULE is commonly used when generating top-level files for a test suite:
Makefile.am or the like. This parameter is often multi-valued, its values being the names of groups of tests involved. This allows to create the lists of files or directories depending on these names. Consider the following example from the template of
configure.ac file (c_gtest_nested target):
AC_CONFIG_FILES([ <$if concat(TEST_MODULE)$><$makefile_item: join(\n)$><$endif$> t2c_api/<$TARGET$>/Makefile testdata/Makefile Makefile ])
<$if concat(TEST_MODULE)$> is used to check if
TEST_MODULE is defined. The values of
TEST_MODULE are always non-empty strings, so if we created a concatenated string from these values, it would be non-empty if and only if
TEST_MODULE had at least one value.
makefile_item subtemplate is defined in
makefile_item.tpl as follows:
Assume t2c is called with
--list-file= option and
modules.list file contains the following:
glib_arrays glib_date_and_time glib_file_utilities glib_i18n glib_string_utility
Then, the corresponding part of generated
configure.ac file may look like this:
AC_CONFIG_FILES([ tests/glib_arrays/Makefile tests/glib_date_and_time/Makefile tests/glib_file_utilities/Makefile tests/glib_i18n/Makefile tests/glib_string_utility/Makefile t2c_api/c_gtest_nested/Makefile testdata/Makefile Makefile ])
All these parameters except
T2C_FILE_NAME are available when the file generator is used in “test mode” or in “common mode”.
T2C_FILE_NAME is available only when the file generator is used in “test mode” (because no .t2c file is processed in “common mode” anyway). See Section 3, “T2C Command Line Tool” for details on how the file generator operates in these modes.