Skip to content

Instantly share code, notes, and snippets.

@krishnadey30
Last active June 17, 2019 23:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krishnadey30/9be9d17fb373023af0a568b2ae38f11e to your computer and use it in GitHub Desktop.
Save krishnadey30/9be9d17fb373023af0a568b2ae38f11e to your computer and use it in GitHub Desktop.
This Gist holds the initial draft of Test Launcher of Unit Test Framework(Chapel) which be used with mason
/*
  This launcher will be used to run the test files and catch the halts.
  You can specify a different directory name using the `--dir` 
  You can set whether or not to descend recursively into 
  subdirectories (defaults to true) using `--subdir`
*/
use FileSystem;
use Spawn;
use Path;
use TestResult;
config const dir: string = ".";
config const subdir: string = "true";

proc Runtests(executable,fileName, ref result,skipId = 0) {
  var separator1 = "="* 70,
      separator2 = "-"* 70;
  var testName: string,
      flavour: string;
  var curIndex = 0;
  var sep1Found = false,
      haltOccured = false;
  var exec = spawn(["./"+executable,"--skipId",skipId:string], stdout = PIPE, stderr = PIPE); //Executing the file
  var line: string,
      tempString: string;
    //std output pipe
  while exec.stdout.readline(line) {
    // write(line);
    if line.strip() == separator1 then sep1Found = true;
    else if line.strip() == separator2 && sep1Found {
      if flavour == "ERROR" then result.addError(testName, tempString);
      else if flavour == "FAIL" then result.addFailure(testName, tempString);
      else if flavour == "SKIPPED" then result.addSkip(testName,tempString);
      // writeln(tempString, flavour, testName);
      tempString = "";
      sep1Found = false;
    }
    else if sep1Found then tempString+=line;
    else {
      var temp = line.strip().split(":");
      // writeln(temp);
      if temp[1].strip().endsWith(")") {
        var strSplit = temp[1].strip().split(")");
        // writeln(strSplit[1]);
        var testNameIndex = strSplit[1].split("(");
        testName = fileName+": "+testNameIndex[1];
        curIndex = testNameIndex[2]: int;
        result.startTest();
        if temp.size > 1 {
          flavour = temp[2].strip();
          if flavour == "OK" then result.addSuccess(testName);
        }
        tempString = "";
      }  
    }
  }
  //this is to check the error
  if exec.stderr.readline(line) { 
    tempString = line;
    // write("Error ",line);
    while exec.stderr.readline(line) do tempString+=line;
    if testName!="" {
      result.addError(testName,tempString);
      haltOccured =  true;
    }
  }
  exec.wait();//wait till the subprocess is complete
  if haltOccured then Runtests(executable, fileName, result, curIndex);
}

var result =  new TestResult();
if isDir(dir) {
  var totalTestCount = 0;
  for file in findfiles(startdir = dir, recursive = subdir:bool) {
    var fileName = basename(file);
    if fileName.endsWith(".chpl") && fileName.startsWith("test") {
      // writeln("[",fileName,"]");
      var tempName = fileName.split(".chpl");
      var executable = tempName[1];
      var sub = spawn(["chpl",file,"-o",executable,"-M."]); //Compiling the file
      sub.wait();
      Runtests(executable,fileName,result);
    }
  }
  result.printErrors();
  writeln(result.separator2);
  result.PrintResult();
}
else {
  writeln(dir+" is not a Directory");
}
@ben-albrecht
Copy link

Hey Krishna, this looks like a good start. Nice work putting this together quickly!

fileName.startsWith("test") {

I don't think we want this to be a requirement. Users should be able to write unit tests into their library code if they want.

var sub = spawn(["chpl",files,"-o","temp","-M."]); //Compiling the file

We'll want to loop over files and compile each file individually. Compiling multiple files on the same chpl call ends up creating a single binary with 1 entry point (main module). If there isn't a clear main module, chapel will report an error.

Also, I wouldn't expect -M. to be necessary here. Can you confirm this?

writeln(dir+" is not a Directory");

We should also support being able to specify a file directly. Examples:

./launcher test1.chpl
./launcher test1.chpl test2.chpl test3.chpl
./launcher tests/*.chpl
      //this is to check the error
      if exec.stderr.readline(line) { 
        writeln("Error",line);
        while exec.stderr.readline(line) do writeln(line);
      }

I know this is just a starting point, but I expect we'll be adding a lot more complexity to here later. We'll be storing a results object in the launcher itself (it can even be the same test result object defined in UnitTest. I'm not 100% sure what the hierarchy should look like right now. Maybe organized by file and then test-per-file? Here's some cases to consider when we're parsing the output here:

  • detect if skip error was emitted, and log that test as skipped
  • detect if test failure error was emitted, and log that test as failed
  • index all tests in a given file, and have UnitTest emit the index for each test before it is run, so that the launcher can track which test it's running.
  • detect if halt occurred, and rerun the program with a UnitTest-defined flag to specify the index in which we want to continue from. e.g. if we failed on test 2/5, rerun on test 3.

@krishnadey30
Copy link
Author

krishnadey30 commented Jun 14, 2019

 var sub = spawn(["chpl",files,"-o","temp","-M."]); //Compiling the file

It's a mistake by me to take variable name wrong. files is a single file. I have updated the code. I am running a single file per loop.

@krishnadey30
Copy link
Author

krishnadey30 commented Jun 14, 2019

fileName.startsWith("test")
This is for a temporary purpose and I will remove it.

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