UnitTest

Usage

use UnitTest;

or

import UnitTest;

Support for automated testing in Chapel.

The UnitTest module is intended to be used with the mason test command, which automates execution of any test function.

A unit test function is defined as any function with the following signature:

proc funcName(test: borrowed Test) throws {}

These functions must accept an argument of type borrowed Test, and have a throws.

A program containing tests must execute the UnitTest main() function to run the tests.

Assert Functions

Here are the assert functions available in the UnitTest module:

Test Metadata Functions

UnitTest module also provides multiple methods for specifying test Metadata:

Examples

All examples are run using the mason test command, which acts as a test runner for the UnitTest module. See Testing your Package for more info.

Note

These examples can also be run standalone, but that output is not shown here.

Basic Usage

Here is a minimal example demonstrating how to use the UnitTest module:

use UnitTest;

proc celsius2fahrenheit(x) {
  // we should be returning "(x: real * 9 / 5) + 32"
  return (x * 9 / 5) + 32;
}

proc test_temperature(test: borrowed Test) throws {
  // we were expecting 98.6 but since we missed typecasting
  // the above function returned 98.
  test.assertFalse(celsius2fahrenheit(37) == 98);
}

UnitTest.main();

Output:

======================================================================
FAIL BasicUsage.chpl: test_temperature()
----------------------------------------------------------------------
AssertionError: in BasicUsage.chpl:17 - assertFalse failed. Given expression is True

----------------------------------------------------------------------

FAILED (failures = 1 )

Skipping Tests

You can skip tests unconditionally with skip and conditionally with skipIf:

use UnitTest;

/* calculates factorial */
proc factorial(x: int): int {
  return if x == 0 then 1 else x * factorial(x - 1);
}

/*Conditional skip*/
proc test1(test: borrowed Test) throws {
  test.skipIf(factorial(0) != 1, "Base condition is wrong in factorial");
  test.assertTrue(factorial(5) == 120);
}

/*Unconditional skip*/
proc test2(test: borrowed Test) throws {
  test.skip("Skipping the test directly");
}

UnitTest.main();

Output:

======================================================================
SKIPPED Skip.chpl: test2()
----------------------------------------------------------------------
TestSkipped: in Skip.chpl:22 - Skipping the test directly

----------------------------------------------------------------------

OK (passed = 1 skipped = 1 )

Specifying locales

You can control the number of locales a test should use with these methods:

addNumLocales maxLocales minLocales

Here is an example demonstrating how to use addNumLocales

proc test_square(test: borrowed Test) throws {
  test.addNumLocales(5);
  var A: [Locales.domain] int;
  coforall i in 0..<numLocales with (ref A) {
    on Locales(i) {
      A[i] = (i+1) * (i+1);
    }
  }
  test.assertTrue(A[4] == 25);
}

Output:

----------------------------------------------------------------------

OK (passed = 1 )

You can also specify multiple locales on which your code can run.

proc test3(test: borrowed Test) throws {
  test.addNumLocales(5, 3);
}

You can specify the range of locales using maxLocales and minLocales

proc test4(test: borrowed Test) throws {
  test.maxLocales(4);
  test.minLocales(2);
}

Specifying Dependencies

You can specify the order in which tests should run using dependsOn:

use UnitTest;
use List;

var factorials: list(int);

// calculates factorial
proc factorial(x: int): int {
  return if x == 0 then 1 else x * factorial(x - 1);
}

proc testFillFact(test: borrowed Test) throws {
  test.skipIf(factorial(0) != 1, "Base condition is wrong in factorial");
  for i in 1..10 do
    factorials.pushBack(factorial(i));
}

proc testSumFact(test: borrowed Test) throws {
  test.dependsOn(testFillFact);
  var s = 0;
  for i in factorials.indices do
    s += factorials[i];
  test.assertGreaterThan(s, 0);
}

UnitTest.main();

Output:

----------------------------------------------------------------------

OK (passed = 2 )

Filtering Tests

When running tests, you can run a subset of the tests in a given file by using specifying a filter. This is done by specifying --filter followed by a regular expression matching the names of the tests to run.

Note

If you are using a build of Chapel without regex support (i.e. CHPL_RE2=none), you can compile your test case with -snoRegex to disable regex support in the test runner. --filter will then perform simple substring matching instead of regex matching.

class Test
proc skip(reason: string = "") throws

Unconditionally skip a test.

Arguments:

reason – the reason for skipping

Throws:

TestSkipped – Always

proc skipIf(condition: bool, reason: string = "") throws

Skip a test if the condition is true.

Arguments:
  • condition – the boolean condition

  • reason – the reason for skipping

Throws:

TestSkipped – If the condition is true.

proc assertTrue(test: bool) throws

Assert that test is true.

Arguments:

test – the boolean condition

Throws:

AssertionError – If the assertion is false.

proc assertFalse(test: bool) throws

Assert that test is false.

Arguments:

test – the boolean condition

Throws:

AssertionError – If the assertion is true.

proc assertEqual(first, second) throws

Assert that first == second.

Arguments:
  • first – The first object to compare.

  • second – The second object to compare.

Throws:

AssertionError – If both the arguments are not equal.

proc assertRegexMatch(x: ?t, pattern: t) throws

Assert that x matches the regular expression pattern.

Warning

This method requires Chapel to be built with CHPL_RE2=bundled.

Arguments:
  • x – The first string or bytes to match.

  • pattern – The regular expression pattern.

Throws:

AssertionError – If x doesn’t match the regex

proc assertRegexMatch(x: ?t, re: regex(t)) throws

Assert that x matches the pre-compiled regular expression object.

Warning

This method requires Chapel to be built with CHPL_RE2=bundled.

Arguments:
  • x – The first string or bytes to match.

  • pattern – The pre-compiled regular expression object.

Throws:

AssertionError – If x doesn’t match the regex

proc assertNotEqual(first, second) throws

Assert that first != second.

Arguments:
  • first – The first object to compare.

  • second – The second object to compare.

Throws:

AssertionError – If both the arguments are equal.

proc assertGreaterThan(first, second) throws

Assert that first > second.

Arguments:
  • first – The first object to compare.

  • second – The second object to compare.

Throws:

AssertionError – If the first argument is not greater than second argument.

proc assertLessThan(first, second) throws

Assert that first < second.

Arguments:
  • first – The first object to compare.

  • second – The second object to compare.

Throws:

AssertionError – If the first argument is not less than the second argument.

proc maxLocales(value: int) throws

Specify maximum number of locales this test can run on.

Arguments:

value – Maximum number of locales with which the test can be run.

Throws:

UnexpectedLocales – If value is less than 1 or minNumLocales

proc minLocales(value: int) throws

Specify minimum number of locales required to run the test.

Arguments:

value – Minimum number of locales with which the test can be run.

Throws:

UnexpectedLocales – If value is more than maxNumLocales

proc addNumLocales(locales: int ...?n) throws

Indicate how many locales to run the test on.

If a test can run on multiple different locale counts, they can be specified using multiple arguments. Only one of the locale counts specified will be run in testing.

Note

To run a single test with multiple locale counts, create multiple tests where each test requires a specific locale count.

Arguments:

locales – locale counts

Throws:

UnexpectedLocales – If locales are already added.

proc dependsOn(tests: argType ...?n) throws

Adds the tests which must run before this test.

Arguments:

tests – First class functions

Throws:

DependencyFound – If called for the first time in a function.

proc main() throws

Runs the tests

Call this as

UnitTest.main();