ISIS Documentation
ISIS Application and Category Test How-toGuide to writing an application and category tests | Home |
Isis Application Test files are used to ensure that an application is working correctly. Isis Category Test files are used to ensure that a category is working correctly. These tests are especially important when porting to a new operating system, or changing compilers. They are also important when changes are made to the entire system (such as refactoring) or to other files that directly affect the application. If something is changed that affects the outcome of the application, the test will fail, making the programmer aware that something has changed and needs to be examined. This guide focuses on the specific task of adding tests to an existing application or category.
You need to be familiar with what the application or category does in order to test it properly. Also a basic knowledge of make would be helpful but not required.
Make is a programming tool used to automate the build process. Make is used used to build C/C++ projects.
Make is a text file that is broken down into what is known as targets. Targets represent a series of actions as a single word. Targets are distinguished by the colon ( : ) after the target name
clean:
actions
An action is a single command that is terminated by a semicolon ( ;
). If a command must be on multiple lines, each line must end with
a backslash ( \ ).
clean:
ratio num=isisTruth.cub+1 \
den=isisTruth.cub+2 \
to=temp.cub;
If there is any character, after the backslash (even a space), the
command will end at that line. Make will not show an error but the
command will not run as intended.
Each line in a target must be preceded with a tab character. Make will show an error if there is not a tab at the front of each line in a target.
Make allows for variables to be used to store values. These variables can be set at the command line by using the syntax VARIABLE=value. For example, setting the variable clean would be CLEAN=yes. Variables are usually in all capital letters. Variables are accessed using the $( ) syntax. For example, using the clean variable would be $(CLEAN).
A test is composed of input, output, truth and make files. All of the files the test needs as input are placed in the input directory. Everything the test generates goes into the output directory. When the test is working correctly the output files representing the base truth files of the test are placed in the truth directory. The make file contains the commands to run the test.
Tests are to ensure that the programs are running correctly. This is done by comparing the output files generated by the test with the files designated as the truth for the test. If the files have the same contents the test shows an OK status. If the files are different in some way the test shows a FAILED status.
APPNAME =
include $(ISISROOT)/make/isismake.tsts
commands:
> /dev/null;
Tests deal with files. Variables for the tests are strings attached to the end of file names. For example
if the file is test.txt then the variable IGNORELINES would be test.txt.IGNORELINES. The file portion must match spelling and
capitalization of the file it is assoiciated with. The variable portion (.IGNORELINES) needs to be in all capital letters.
For each file in the test if the variable is not set than a default value is used.
Possible variables for file types are:
In order to perserve the data that is used by the test, type make checkin . This copies the contents of the input and truth directories to the testdata area. Since the output files can be generated by using the output command, these files do not need to be saved. Once the files are stored in the testdata area you can do make release to remove all of the files exept the makefile. Then the makefile can be checked into cvs. To restore these files back into the test, type make checkout . This copies the files into the proper directories. Once the files for the test are in the test data area, the test will still run even if the test files are not in the same directory as the test.
Category tests work the same way as application tests do. The difference is that category tests don't test a single program but a sequence of programs. Therefore the APPNAME variable should not be used. Instead use variables such as APP1NAME, APP2NAME, etc. In addition, all ISIS application names need to be followed by $(TSTARGS) to guarantee proper testing parameters. Currently, this ensures that they use the default preference file. All of the variables for testing an application also work for category tests. A brief example is shown below.
APP1NAME = clem2isis
APP2NAME = spiceinit
APP3NAME = campt
APP4NAME = getsn
include $(ISISROOT)/make/isismake.tsts
commands:
$(APP1NAME) $(TSTARGS) from= $(INPUT)/lna3819k.045 \
to= $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub > /dev/null
$(APP2NAME) $(TSTARGS) from= $(OUTPUT)/lna3819k.045--clem2isis-spiceinit.cub \
> /dev/nul
In order to assure the most accurate testing possible, pvl (parameter value language) files are compared by parsing through the groups, objects and keywords in the file. Any file with a .pvl extension is considered a pvl file. Because pvl files contain text, the text file test variables will work on the pvl files; it is not recommended to use these test variables, however, and the result must still be a valid pvl file. The order of the keywords, objects and groups matter and may not be different in any case. In order to set tolerances and ignore keywords, a pvl tolerance file with .DIFF attached to the end will be used. For example, if if file is test.pvl then the tolerance file must be named test.pvl.DIFF. These files must only exist in the input data directory. Inside the pvl tolerance file you can specify numerical tolerances and keywords to ignore. Inside the pvl tolerance file, there should be one or two groups, Tolerances and IgnoreKeys, in the root of the file. So, a basic pvl tolerance file looks like this:
Group = Tolerances
End_Group
Group = IgnoreKeys
End_Group
Group = IgnoreFilePaths
End_Group
End
To set a tolerance on a number, inside the Tolerances group there
must be a keyword in this format:
KeywordName = MaximumDifference
If the output and truth data values exceed the maximum difference
(tolerance), then the files are not considered the same. In order to
ignore a non-numerical value, such as a file name, inside the
IgnoreKeys group there must be a keyword in this format:
KeywordName = true
Note: The value of this keyword does not matter.
To ignore a file's path up until the name, Put a corresponding
keyword set to true inside the IgnoreFilePaths group.
KeywordName = true
Group = Tolerances
StandardDeviation = 0.0000000001
End_Group
Group = IgnoreKeys
FileName = true
End_Group
Group = IgnoreFilePaths
FilePath = true
End_Group
End
To debug these files, or see why two pvl files compare as different,
you can use pvldiff. The FROM parameter will be the output file
(which will be created with the command make output), the
FROM2 parameter will be the truth file and the DIFF parameter will
be the DIFF file inside of the input folder (the same as the FROM2
parameter with .DIFF added on to the end). When pvldiff is run, it
will output the first difference it finds that exceeds the
tolerances.
Object = IsisCube
Object = Core
SomeFile = /foo/bar/fakefile.cub
StartByte = 65537
Format = Tile
TileSamples = 128
TileLines = 128
Group = Dimensions
Samples = 1024
Lines = 1024
Bands = 7
End_Group
Group = Pixels
Type = Real
ByteOrder = LSB
Base = 0.0
Multiplier = 1.0
End_Group
End_Object
End_Object
Object = SomeObject
SomeCalculaion = 5536.4363463414
End_Object
End
The SomeCalculation keyword may vary by 0.000000001 and the
ByteOrder could be MSB or LSB. SomeFile could have a different path if
the tester is not using the default data area. To compensate for
this, you would add a file named cubelabels.pvl.DIFF in the input
folder with the following:
Group = Tolerances
SomeCalculation = 0.000000001
End_Group
Group = IgnoreKeys
ByteOrder = true
End_Group
Group = IgnoreFilePaths
SomeFile = true
End_Group
End
This would ignore the value of ByteOrder always, the path of SomeFile,
and the value of SomeCalculation if it were within the tolerance.
Finally, you can create unique tolerances and ignore keys for each element of an array contained within a keyword, like so:
Group = Tolerances
SomeArray = (0.000000001, 0.0, 0.025)
AnotherArray = 0.000000001
End_Group
Group = IgnoreKeys
SomeArray =(false, true, false)
End_Group
Group = IgnoreFilePaths
SomeArray = (false, false, true)
End_Group
End
In the above case, the keyword SomeArray would have a tolerance of
0.000000001 applied to the first element, a tolerance of 0.025
applied to the third element, and the second element would be
ignored entirely.
Just make sure when working with arrays that you have exactly the same number of tolerances/ignore keys for the keyword as there are elements in the array. Alternatively, you can list only one tolerance or ignore key for the keyword, and it will be applied to every element in the array. In the above case, the keyword AnotherArray could have 50 elements, but each element would have a tolerance of 0.000000001 applied to it. Having multiple tolerances and ignore keys without matching the number of array elements, however, will result in an error.
A similar tool exists for comparing two comma-separated value (CSV) files as those for PVL files and cubes. When writing application tests, any file output with a ".csv" extension will automatically be compared against the truth CSV using the CSV-Diff script. The benefit of using this script over a one-to-one textual comparison comes into play when the CSV files being compared contain numerical data.
By specifying tolerance values in a DIFF file contained within the test's input directory, one can consider two CSV files "the same" within some margin of error. The DIFF fle uses a similar naming convention as that for PVL diffing: csvfile.csv.DIFF. The tolerance file must contain one tolerance per line of the form:
COLUMN=VALUE
where COLUMN is the name of the tolerance value for every cell in that column,
and VALUE is the actual tolerance that will be compared against the difference
between the values in the two files.
The script can also be used by itself, independent of any application test. This is most useful when a test fails, and the user wishes to run the CSV diff directly in order to see the reason why. Running the script directly can be accomplished with the following usage:
$ISISROOT/scripts/csvdiff.py CSV1 CSV2 [TOLERANCES]
Output will be a message stating either SUCCESS or FAILURE followed by an
explanation of why. Difference failures will also include a reference to the
exact line and column where the offending difference occurred. The program
will terminate with an error signal when a failure occurs during processing.
Before any cells are compared the program will first ensure that the two CSV files to be compared have the same number of columns and rows, additionally checking that their headers match.
Future versions will support an option for submitting files without headers.
If the application test looks like this:
<test>
<commandLine>
num=\$ISISDATA/base/examples/isisTruth.cub+1
den=\$ISISDATA/base/examples/isisTruth.cub+2
to=<temp>temp1.cub</temp>
</commandLine>
<cubes>
<compareCube>
<truth>ratioTruth1.cub</truth>
<against>temp1.cub</against>
</compareCube>
</cubes>
</test>
Then the test would look like:
APPNAME =
include $(ISISROOT)/make/isismake.tsts
commands:
num=\$ISISDATA/base/examples/isisTruth.cub+1
den=\$ISISDATA/base/examples/isisTruth.cub+2
to=<temp>temp1.cub</temp> > /dev/null;
The test now looks like:
APPNAME =
include $(ISISROOT)/make/isismake.tsts
commands:
num=\$ISISDATA/base/examples/isisTruth.cub+1 \
den=\$ISISDATA/base/examples/isisTruth.cub+2 \
to=<temp>temp1.cub</temp> > /dev/null;
The test now looks like:
APPNAME =
include $(ISISROOT)/make/isismake.tsts
commands:
num=\$ISISDATA/base/examples/isisTruth.cub+1 \
den=\$ISISDATA/base/examples/isisTruth.cub+2 \
to=<temp>temp1.cub</temp> > /dev/null;
The test now looks like:
APPNAME = ratio
include $(ISISROOT)/make/isismake.tsts
commands:
$(APPNAME) num=\$ISISDATA/base/examples/isisTruth.cub+1 \
den=\$ISISDATA/base/examples/isisTruth.cub+2 \
to=<temp>temp1.cub</temp> > /dev/null;
The test now looks like:
APPNAME = ratio
include $(ISISROOT)/make/isismake.tsts
commands:
$(APPNAME) num=$(INPUT)/isisTruth.cub+1 \
den=$(INPUT)/isisTruth.cub+2 \
to=<temp>temp1.cub</temp> > /dev/null;
The test now looks like:
APPNAME = ratio
include $(ISISROOT)/make/isismake.tsts
commands:
$(APPNAME) num=$(INPUT)/isisTruth.cub+1 \
den=$(INPUT)/isisTruth.cub+2 \
to=ratioTruth1.cub > /dev/null;
The test now looks like:
APPNAME = ratio
include $(ISISROOT)/make/isismake.tsts
commands:
$(APPNAME) num=$(INPUT)/isisTruth.cub+1 \
den=$(INPUT)/isisTruth.cub+2 \
to=$(OUTPUT)/ratioTruth1.cub > /dev/null;
Robert Wallace | 2006-09-08 | Created |
Robert Wallace | 2006-10-06 | Updated with recent changes to testing system and added examples |
Travis Addair | 2011-05-13 | Added section for Comparing Files, moved PVL diff discussion into this section and added new discussion for CSV file diffing. |
Jesse Mapel | 2016-04-05 | Updated section on category tests. Fixes #3884. |