Skip to content

Instantly share code, notes, and snippets.

@krishnadey30
Last active June 17, 2019 23:11
Show Gist options
  • Save krishnadey30/45dfc521b02f7b6012aa20be9eea33ce to your computer and use it in GitHub Desktop.
Save krishnadey30/45dfc521b02f7b6012aa20be9eea33ce to your computer and use it in GitHub Desktop.
This gist contains the initial draft of the UnitTest Framework - Chapel
module UnitTest {
  use Reflection;
  use TestError;

  config const skipId: int = 0;
  // This is a dummy test so that we get capture the function signature
  private
  proc testSignature(test: Test) throws { }
  var tempFcf = testSignature;
  type argType = tempFcf.type;  //Type of First Class Test Functions

  /*A test result class that can print formatted text results to a stream.*/
  class TextTestResult {
    var separator1 = "="* 70,
        separator2 = "-"* 70;
    
    proc startTest(test, indx) throws {
      stdout.write(test: string,"(",indx: string,"): ");
    }

    proc addError(test, errMsg) throws {
      stdout.writeln("ERROR");
      PrintError(errMsg);
    }

    proc addFailure(test, errMsg) throws {
      stdout.writeln("FAIL");
      PrintError(errMsg);
    }

    proc addSuccess(test) throws {
      stdout.writeln("OK");
    }

    proc addSkip(test, reason) throws {
      stdout.writeln("SKIPPED");
      PrintError(reason);
    }

    proc PrintError(err) throws {
      stdout.writeln(this.separator1);
      stdout.writeln(err);
      stdout.writeln(this.separator2);
    }
    
  }

  /*Runs the tests*/
  proc runTest(tests: argType ...?n) throws {

    // Assuming 1 global test suite for now
    // Per-module or per-class is possible too
    var testSuite = new TestSuite();
    testSuite.addTests(tests);
    var testResult = new TextTestResult();
    // if skipId == 0 then
    //   stdout.writeln("Found "+testSuite.testCount+" "+printTest(testSuite.testCount));
    for indx in (skipId+1)..testSuite.testCount {
      var test = testSuite[indx];
      try {
        // Create a test object per test
        var testObject = new Test();
        //test is a FCF:
        testResult.startTest(test: string, indx);
        test(testObject);
        testResult.addSuccess(test: string);
      }
      // A variety of catch statements will handle errors thrown
      catch e: AssertionError {
        testResult.addFailure(test:string, e:string);
        // print info of the assertion error
      }
      catch e: TestSkipped {
        testResult.addSkip(test:string, e:string);
        // Print info on test skipped
      }
      catch e: TestDependencyNotMet {
        // Pop test out of array and append to end
      }
      catch e { 
        testResult.addError(test:string, e:string);
      }
    }
    // testResult.printErrors();
    // stdout.writeln(testResult.separator2);
    // testResult.PrintResult();
  }

  class TestSuite {
    var testCount = 0;
    var _tests: [1..0] argType;
    
    proc addTest(test) lifetime this < test {
      // var tempTest = new Test();
      // param test_name = test: string;
      // if !canResolve(test_name,tempTest) then
      //   compilerError(test + " is not callable");
      this._tests.push_back(test);
      this.testCount += 1;
    }

    proc addTests(tests) lifetime this < tests {
      /*if isString(tests) then
        compilerError("tests must be an iterable, not a string");*/
      for test in tests do
        this.addTest(test);
    }

    proc this(i : int) ref: argType {
      return this._tests[i];
    }

    iter these() {
      for i in this._tests do
        yield i;
    }
  }
  
}

Example

use UnitTest;

proc test1(test: Test) throws {
  test.assertTrue(false);
}

proc test2(test: Test) throws {
  test.assertTrue(false);
}

proc test3(test: Test) throws {
  test.skip("Skipping Test 3");
}
UnitTest.runTest(test1,test2,test3);

Current Output

Run 3 test
FAILED
failures= 2
skipped= 1
@krishnadey30
Copy link
Author

I used ref as same was mentioned in the docs.

@ben-albrecht
Copy link

I used ref as same was mentioned in the docs.

Gotcha. The ref allows you to modify the elements yielded by the iterator by reference. For example, the array these() method has a ref intent:

var array: [1..3] int;
for a in array {
  a += 1; // modifies array element by reference
}
writeln(array); // [1, 1, 1]

If it didn't have the ref, the a element would be a local copy, and array would remain unchanged:

// If array.these() didn't have a ref intent
var array: [1..3] int;
for a in array {
  a += 1; // modifies local copy of element. array remains unchanged
}
writeln(array); // [0, 0, 0]

I don't think we need to modify FCFs by reference, so I think it's safe to drop.

@krishnadey30
Copy link
Author

Okay, Thanks. I will do that.

@ben-albrecht
Copy link

I think we can remove use LinkedLists; now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment