Package au.edu.mq.comp.junitGrading.grader

Source Code of au.edu.mq.comp.junitGrading.grader.JavaGrader

package au.edu.mq.comp.junitGrading.grader;


import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import au.edu.mq.comp.common.*;
import au.edu.mq.comp.junitGrading.Assignment;
import au.edu.mq.comp.junitGrading.GlobalSetting;
import au.edu.mq.comp.junitGrading.GraderWorker;
import au.edu.mq.comp.junitGrading.TestResult;


/**
*
* @author psksvp@gmail.com
* a GraderWorker for a java assignment
*/
public class JavaGrader extends GraderWorker
{  
    private String GradingRunListenerDotjava = "";
    private String GradedDotJava = "";
    private String ResourceDotJava = "";
   
   
    //////////////////////////////////////////////
    private String unitTestClassName;
    private java.util.HashMap<String, String> junitTestSourceMapCollection = new java.util.HashMap<String, String>();
    private java.util.ArrayList<String> junitTestSourceFullPathCollection = new java.util.ArrayList<String>();
    private String junitTestSourceZipFilePath = null;
    private java.util.ArrayList<String> libraryCollection = new java.util.ArrayList<String>();
    private java.util.ArrayList<String> testDataZipCollection = new java.util.ArrayList<String>();
    //////////////////////////////////////////////
   
    public JavaGrader clone()
    {
      try
      {
        JavaGrader twin = new JavaGrader(this.unitTestClassName);
       
        if(null != this.junitTestSourceZipFilePath)
          twin.addJUnitTestSource(this.junitTestSourceZipFilePath);
       
        for(String path : this.junitTestSourceFullPathCollection)
          twin.addJUnitTestSource(path);

            for(String path : this.libraryCollection)
              twin.addLibrary(path);

            for(String path : this.testDataZipCollection)
              twin.addTestDataZipFile(path);
           
        return twin;
      }
      catch(Exception ex)
      {
        Log.error("Exception thown at JavaGrader.clone() with message ->" +  ex.toString());
        return null;
      }
    }
   
    /**
     * constructor
     * @param unitTestClassName - <p>must be a fully qualified class name. This class(with junit @Test) is usually provided by instructor to test target class which is written by a student</p>
     * @throws IOException - if CodeTemplate is not found.
     */
    public JavaGrader(String unitTestClassName) throws IOException
    {
        this.unitTestClassName = new String(unitTestClassName);
       
        // all path name in JAR and out size of JAR is case sensitive
        this.GradingRunListenerDotjava = SimpleFileIO.readTextFromSelfJarBundleFile(this, GlobalSetting.programResourcePath() + "/CodeTemplate/GradingRunListenerDotJava");
        this.GradedDotJava = SimpleFileIO.readTextFromSelfJarBundleFile(this, GlobalSetting.programResourcePath() + "/CodeTemplate/GradedDotJava");
        this.ResourceDotJava = SimpleFileIO.readTextFromSelfJarBundleFile(this, GlobalSetting.programResourcePath() + "/CodeTemplate/ResourceDotJava");
       
        if(0 == this.GradingRunListenerDotjava.length() ||
           0 == this.GradedDotJava.length() ||
           0 == this.ResourceDotJava.length())
        {
          Log.error("at class JavaGrader, Fail to read code template from /Resources/CodeTemplate/");
          throw new IOException("at class JavaGrader, Fail to read code template from /Resources/CodeTemplate/");
        }                  
    }
   
    /**
     *
     * @param path - to just unit test source <p>If the test has no package name(default package), the junit test class source file does not need
     *                                           to be in a zip archive and can be specified like the example below. If the test needs more java files,
     *                                           it can be specified using the same key name.  Or all the files can be in one zip file, but the zip
     *                                           file must not have directory structure.
     *                                           if the test has package name, all junit test class source files must be in a zip file with correct
     *                                           directory structure according to the package name. </p>
     * @throws IOException
     */
    public void addJUnitTestSource(String path) throws IOException
    {
        String extension = SimpleFileIO.extensionOfFileName(path);
        if(true == extension.equalsIgnoreCase("java"))
        {
            String sourceContent = SimpleFileIO.readTextFromFile(path);
            this.junitTestSourceMapCollection.put((new java.io.File(path)).getName(), sourceContent);
            this.junitTestSourceFullPathCollection.add(path);
        }
        else if(true == extension.equalsIgnoreCase("zip"))
        {
            this.junitTestSourceZipFilePath = new String(path);
        }
        else
        {
            Log.message("edu.macquarie.computing.junitGrading.grader.Automark::addJUnitTestSource is ignoring file -->" + path);
        }
    }
   
    /**
     *
     * @param pathToJAR - path to external library JAR file needed by this test
     */
    public void addLibrary(String pathToJAR)
    {
        this.libraryCollection.add(pathToJAR);
    }
   
    /**
     *
     * @param pathToZipOfData - path to data zip file if this test needed external data. It must be in a zip file
     */
    public void addTestDataZipFile(String pathToZipOfData)
    {
        this.testDataZipCollection.add(pathToZipOfData);   
    }
   
   
    /**
     * compile java source in the Assignment being graded
     * @param assignment
     * @param runResult
     * @return
     * @throws Exception
     */
    private boolean compile(Assignment assignment, TestResult runResult) throws Exception
    {
      JavaCodeCompiler compiler = new  JavaCodeCompiler();
        this.copyJUnitTestSource(assignment.containerDirectory().getAbsolutePath());
       
        compiler.appendLibraryClassPath(assignment.containerDirectory().getAbsolutePath());
        compiler.appendLibraryClassPath(OS.pathToRunningJAR());
        for(String libraryPath : this.libraryCollection)
        {
            compiler.appendLibraryClassPath(libraryPath);
        }
       
        this.copyJUnitDriverSource(assignment.containerDirectory().getAbsolutePath());
       
        java.util.List<java.io.File> listOfJavaFiles = SimpleFileIO.traverseDirectoryForFiles(assignment.containerDirectory(), "java");
       
        if(0 != compiler.compileJavaFilesInList(listOfJavaFiles))
        {
          runResult.appendResult("RunResult", "CompileFail");
            runResult.setErrorMessage("compiler process returned with error " + compiler.errorString());
          return false;
        }
        else
        {
          return true;
        }
    }
   
    /**
     * run the test
     * @param assignment
     * @param runResult
     * @throws Exception
     */
    private void run(Assignment assignment, TestResult runResult) throws Exception
    {
      JavaClassRunner jcr = new JavaClassRunner(assignment.containerDirectory().getAbsolutePath());
      jcr.appendLibraryClassPath(OS.pathToRunningJAR());
        for(String libraryPath : this.libraryCollection)
        {
            jcr.appendLibraryClassPath(libraryPath);
        }
       
        for(String pathToZip : this.testDataZipCollection)
        {
            SimpleFileIO.unzipFile(new java.io.File(pathToZip),
                                   new java.io.File(assignment.containerDirectory().getAbsolutePath() +
                                                    File.separator + "Resources"));
        }
       
        String packageName = this.packageNameOfUnitTestClass().length() > 0 ? this.packageNameOfUnitTestClass() + "." : "";
        String classNameToRun = packageName + "GradingRunListener";
        int exitCode = jcr.runAndWait(classNameToRun, TimeUnit.SECONDS.toMillis(GlobalSetting.processWaitTimeout()));
        if(0 == exitCode)
        {
            int startIndex = jcr.outputString().indexOf("<dataStart>");
            int endIndex = jcr.outputString().indexOf("<dataEnd>");
            if(startIndex >= 0 && endIndex >= 0)
            {
                String data =  jcr.outputString().substring(startIndex + "<dataStart>".length(), endIndex);
                runResult.appendResult("RunResult", "success");
                runResult.appendResultFromMapInString(data);
            }
            else
            {
                runResult.appendResult("RunResult", "DataError");
                runResult.setErrorMessage("there is no <dataStart> or <dataEnd> marker in the output from GradingRunListener.java");
            }
        }
        else if(JavaClassRunner.kWaitForProcessTimeout == exitCode)
        {
            runResult.appendResult("RunResult", "RunTimeout");
            runResult.setErrorMessage("junittest process returned with error: possible runnaway process");
        }
        else
        {
            runResult.appendResult("RunResult", "RunFail");
            runResult.setErrorMessage("junittest process returned with error" + jcr.errorString());
        }
    }
   
   
    @Override
    public TestResult gradeAnAssignment(Assignment assignment)
    {
      TestResult runResult = new TestResult(assignment.ownerIdentification());
        try
        {
          if(true == this.compile(assignment, runResult))
            this.run(assignment, runResult);           
        }
        catch(Exception e)
        {           
            runResult.appendResult("RunResult", "ExceptionThrown");
            runResult.setErrorMessage("exception raised -->" + e.toString());
           
            Log.error(runResult.errorMessage());
            e.printStackTrace();
        }
        try
        {
          SimpleFileIO.writeStringToTextFile(runResult.toString(), assignment.containerDirectory().getAbsolutePath() + File.separator + "runResult.txt");
        }
        catch(Exception e)
        {
          Log.error("Fail to write run result to " + assignment.containerDirectory().getAbsolutePath());
        }
        return runResult;
    }
   
    /**
     *
     * @param destinationPath
     * @throws IOException
     */
    private void copyJUnitTestSource(String destinationPath) throws IOException
    {
        for(String sourceName : junitTestSourceMapCollection.keySet())
        {
            String pathToWriteUnitTestJavaSourceFile = destinationPath + File.separator + sourceName;
            SimpleFileIO.writeStringToTextFile(this.junitTestSourceMapCollection.get(sourceName), pathToWriteUnitTestJavaSourceFile);
        }
       
        if(null != this.junitTestSourceZipFilePath)
            SimpleFileIO.unzipFile(new java.io.File(this.junitTestSourceZipFilePath), new java.io.File(destinationPath));
    }
   
    /**
     *
     * @param destinationPath
     * @throws IOException
     */
    private void copyJUnitDriverSource(String destinationPath) throws IOException
    {
      String packageName = this.makePackageNameOfUnitTestClass();
     
      //--------------------------
      //GradingRunListener.java
        String source = this.GradingRunListenerDotjava.replace(GlobalSetting.codeTemplatePackageName(), packageName);
        source = source.replace("/*%%%(junitTest.class)%%%*/", "core.run(" + this.unitTestClassName + ".class);");                       
       
        String packagePath = this.classNameWithPackageToPath(this.unitTestClassName);
        String finalPath = destinationPath + File.separator + packagePath + "GradingRunListener.java";
        SimpleFileIO.writeStringToTextFile(source, finalPath);
       
        //--------------------------
        //Graded.java
        source = this.GradedDotJava.replace(GlobalSetting.codeTemplatePackageName(), packageName);
       
        finalPath = destinationPath + File.separator + packagePath + "Graded.java";
        SimpleFileIO.writeStringToTextFile(source, finalPath);
       
        //--------------------------
        //Resource.java
        source = this.ResourceDotJava.replace(GlobalSetting.codeTemplatePackageName(), packageName);
       
        if(true == OS.isAnyWindows())
            source = source.replace("$(path)$", (destinationPath + File.separator + "Resources").replace("\\", "\\\\"));
        else
            source = source.replace("$(path)$", destinationPath + File.separator + "Resources");
                   
        finalPath = destinationPath + File.separator + packagePath + "Resource.java";
        SimpleFileIO.writeStringToTextFile(source, finalPath);
    }
   
    /**
     *
     * @return
     */
    private String makePackageNameOfUnitTestClass()
    {
        int index = this.unitTestClassName.lastIndexOf('.');
        if(index <= 0)
            return "";
        else
        {
            String packageName = this.unitTestClassName.substring(0, index);
            return "package " + packageName + ";";
        }
    }
   
    /**
     *
     * @return
     */
    private String packageNameOfUnitTestClass()
    {
        int index = this.unitTestClassName.lastIndexOf('.');
        if(index <= 0)
            return "";
        else
            return this.unitTestClassName.substring(0, index);
    }
   
    /**
     *
     * @param packageName
     * @return
     */
    private String classNameWithPackageToPath(String packageName)
    {
        int index = packageName.lastIndexOf('.');
        if(index <= 0)
            return File.separator;
        else
            return packageName.substring(0, index).replace('.', OS.fileSeparator().charAt(0)) + OS.fileSeparator();      
    }
}



////////////////////////
/*
String pathToUnitTestJavaClassFile = assignment.containerDirectory() + "/" + this.unitTestClassName + ".class";
FileClassLoader classLoader = new FileClassLoader();
Class<?> junitTestClass = classLoader.createClass(new java.io.File(pathToUnitTestJavaClassFile));
Result result = JUnitCore.runClasses(junitTestClass.newInstance().getClass());
int failures = 0;
StringBuffer output = new StringBuffer();
for (Failure failure : result.getFailures())
{
output.append(failure.toString());
output.append(",\t");
failures++;
}
output.append("There are "+failures+" failures.");
int mark = (4-failures)*25;
output.append("Your mark is "+mark+" out of 100");

return assignment.ownerIdentification() + ",\t" + output.toString();  */



/*
* @Override
    public RunResult gradeAnAssignment(Assignment assignment)
    {
      RunResult runResult = new RunResult();
        runResult.appendResult("identification", assignment.ownerIdentification());
        try
        {
         
            JavaCodeCompiler compiler = new  JavaCodeCompiler();
            this.copyJUnitTestSource(assignment.containerDirectory().getAbsolutePath());
           
            compiler.appendLibraryClassPath(assignment.containerDirectory().getAbsolutePath());
            for(String libraryPath : this.libraryCollection)
            {
                compiler.appendLibraryClassPath(libraryPath);
            }
           
            this.copyJUnitDriverSource(assignment.containerDirectory().getAbsolutePath());
           
            java.util.List<java.io.File> listOfJavaFiles = SimpleFileIO.traverseDirectoryForFiles(assignment.containerDirectory(), "java");
           
            if(0 == compiler.compileJavaFilesInList(listOfJavaFiles))
            {
                JavaClassRunner jcr = new JavaClassRunner(assignment.containerDirectory().getAbsolutePath());
                for(String libraryPath : this.libraryCollection)
                {
                    jcr.appendLibraryClassPath(libraryPath);
                }
               
                for(String pathToZip : this.testDataZipCollection)
                {
                    SimpleFileIO.unzipFile(new java.io.File(pathToZip),
                                           new java.io.File(assignment.containerDirectory().getAbsolutePath() +
                                                            OS.fileSeparator() + "Resources"));
                }
               
                String packageName = this.packageNameOfUnitTestClass().length() > 0 ? this.packageNameOfUnitTestClass() + "." : "";
                String classNameToRun = packageName + "GradingRunListener";
                int exitCode = jcr.runAndWait(classNameToRun, TimeUnit.SECONDS.toMillis(GlobalSetting.processTimeout()));
                if(0 == exitCode)
                {
                    int startIndex = jcr.outputString().indexOf("<dataStart>");
                    int endIndex = jcr.outputString().indexOf("<dataEnd>");
                    if(startIndex >= 0 && endIndex >= 0)
                    {
                        String data =  jcr.outputString().substring(startIndex + "<dataStart>".length(), endIndex);
                        runResult.appendResult("RunResult", "success");
                        runResult.appendResultFromMapInString(data);
                    }
                    else
                    {
                        runResult.appendResult("RunResult", "DataError");
                        runResult.setErrorMessage("there is no <dataStart> or <dataEnd> marker in the output from GradingRunListener.java");
                    }
                }
                else if(JavaClassRunner.kWaitForProcessTimeout == exitCode)
                {
                    runResult.appendResult("RunResult", "RunTimeout");
                    runResult.setErrorMessage("junittest process returned with error: possible runnaway process");
                }
                else
                {
                    runResult.appendResult("RunResult", "RunFail");
                    runResult.setErrorMessage("junittest process returned with error" + jcr.errorString());
                }
             
            }
            else
            {
                runResult.appendResult("RunResult", "CompileFail");
                runResult.setErrorMessage("compiler process returned with error " + compiler.errorString());
            }
           
        }
        catch(Exception e)
        {           
            runResult.appendResult("RunResult", "ExceptionThrown");
            runResult.setErrorMessage("exception raised -->" + e.toString());
           
            Log.error(runResult.errorMessage());
            e.printStackTrace();
        }
       
        return runResult;
    }
   
    */ 
TOP

Related Classes of au.edu.mq.comp.junitGrading.grader.JavaGrader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.