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. |