menu

Unit Tests

Unit test Guide Find out how to run Junit tests and how to add new tests.

Unit Test Guide

The Unit Test Guide explains the test infrastructure associated with Aparapi, including instructions for executing existing tests adding new test cases. OpenCL™ code generation tests

The initial open source tree includes the codegen subdirectory (test/codegen), which used to validate the Aparapi bytecode to OpenCL™ conversion.


/src/test/java/
   com/aparapi/
      codegen/
         test/
   pom.xml

The code generation tests to not require OpenCL™ , AMD APP SDK or a GPU devices to be configured; these tests only validate the creation of valid OpenCL™ code by comparing against predefined expected output.

Running the OpenCL™ code generation JUnit tests

Before executing the code generation tests, build the com.aparapi sub-project and ensure that you have JUnit 4 installed.

Edit the junit.jar property in test/codegen/build.xml to point to your install directory.


<property name="junit.jar" value="C:\JUnit4.9\junit-4.9.jar"/>

Initiate the code generation tests using ant.


C:\> cd tests/codegen
C:\> ant
<failures will be reported here>
C:>

View the HTML version of the JUnit report at junit/html/index.html. On Microsoft Windows® platforms use


C:\> start junit\html\index.html

On Linux® platforms just invoke your browser (Firefox in this case).


firefox junit\html\index.html

Adding a new OpenCL™ code generation test

The test cases for OpenCL™ code generation are not strictly JUnit tests. Instead the codegen Java tree contains a tool (CreateJUnitTests) to create JUnit test cases from specially formatted test source files.

The package com.aparapi.test (codegen/src/java/com/aparapi/test) contains all of the existing code generation tests.

Here is an example that tests the code generation resulting from a call to Kernel.getPassId(), this is taken from com.aparapi.test.CallGetPassId


package com.aparapi.test;

import com.aparapi.Kernel;

public class CallGetPassId extends Kernel{
   public void run() {
      int thePassId = getPassId();
   }

}
/**{OpenCL{

typedef struct This_s{
   int passid;
}This;
int get_pass_id(This *this){
   return this->passid;
}
__kernel void run(
   int passid
){
   This thisStruct;
   This* this=&thisStruct;
   this->passid = passid;
   {
      int thePassId = get_pass_id(this);
      return;
   }
}

}OpenCL}**/

The test source takes the form of a simple class that extends the kernel and a block of OpenCL code between the /{OpenCL{ and }OpenCL}/ markers. The code between these markers is the OpenCL code that we expect Aparapi to produce as a result of converting the run() method to OpenCL.

The code-generating ant build.xml file performs the following steps to generate its report:

To create a new test case, just add your test case to the codegen/src/java/com/aparapi/test package (including the expected OpenCL).

Sometimes different javac implementations (such as Oracle and Eclipse) will generate different bytecode for the same source. When Aparapi converts this bytecode it may yield different (but equally acceptable) OpenCL forms. One example of this is the BooleanToggle test:


public class BooleanToggle{
   public void run() {
      boolean pass = false;

      pass = !pass;

   }
}

The BooleanToggle test code creates two (slightly different) versions of OpenCL™ (sadly one line different) depending on the javac compiler.

This example shows the ‘toggle’ OpenCL™ created from the bytecode generated by Oracle.


pass = pass==1?0:1;

This example shows the bytecode from Eclipse javac:


pass = pass==0?1:0;

Logically either of the above are correct. However, to accommodate the alternate acceptable forms we need to add two complete /**{OpenCL{ and }OpenCL}**/ sections to the file. If either matches, the test will pass.

Here is the complete BooleanToggle code.


package com.aparapi.test;

public class BooleanToggle{
   public void run() {
      boolean pass = false;

      pass = !pass;

   }
}
/**{OpenCL{
typedef struct This_s{
   int passid;
}This;
int get_pass_id(This *this){
   return this->passid;
}
__kernel void run(
   int passid
){
   This thisStruct;
   This* this=&thisStruct;
   this->passid = passid;
   {
      char pass = 0;
      pass = (pass==0)?1:0;
      return;
   }
}
}OpenCL}**/
/**{OpenCL{
typedef struct This_s{
   int passid;
}This;
int get_pass_id(This *this){
   return this->passid;
}
__kernel void run(
   int passid
){
   This thisStruct;
   This* this=&thisStruct;
   this->passid = passid;
   {
      char pass = 0;
      pass = (pass!=0)?0:1;
      return;
   }
}
}OpenCL}**/