Tutorial: Moodle VPL -- Count Number of Passed Tests for Student Java Program

From dftwiki
Jump to: navigation, search

--D. Thiebaut (talk) 13:37, 3 November 2014 (EST)


MoodleVPLLogo.png



Moodle VPL Tutorials



This VPL activity tests a Java class submitted by the student and energized all its methods. Then compares behavior of methods against what is expected. Outputs OK or FAIL messages depending on how the methods behave. The vpl_evaluate.sh script simply counts the number of OK strings to compute the grade.


vpl_run.sh


#! /bin/bash
# D. Thiebaut

cat > vpl_execution <<EEOOFF
#! /bin/bash
 
prog1=Heap
 
javac \${prog1}.java 2>&1 >/dev/null | grep -v Note > grepLines.out
javac HeapTest.java  2>&1 >/dev/null 
javac HeapEmptyException.java  2>&1 >/dev/null 

if [ -s grepLines.out ] ; then 
     echo "Some compiler ERRORS reported"
     cat grepLines.out
     exit
fi

echo "--------------------"
echo "Your program output:"
java HeapTest | cat -v
echo "--------------------"


EEOOFF
 
chmod +x vpl_execution


vpl_evaluate.sh


#! /bin/bash
# D. Thiebaut
# Smith College
# vpl_evaluate.sh script looping through several tests, each test with
# its own input file and its own expected output file.  The output of the
# student program is tested against the expected output file.
#
#set -x

cat > vpl_execution <<EEOOFF
#! /bin/bash

# ----------------------------------------------------------------------
# User program and test program
prog=Heap
testProg=HeapTest
exception=HeapEmptyException

logKey=Zorro      # if found in user program, generates a log
log=false

if grep --quiet -i \$logKey \${prog}.java ; then
  set -x
  log=true
fi

# ----------------------------------------------------------------------
# Grade information
gradeCompileError=10 
gradeCompileGood=30
gradeIncrement=6    # (100-30)/ # test (70/12 = 6)

# ----------------------------------------------------------------------
# compile function
compile() {

   if [ "\$log" = "true" ]; then
       echo "--- compile() ---"
       javac \${prog}.java  | grep -v Note > grepLines.out
       javac \${testProg}.java 
       javac \${exception}.java
   fi


   javac \${prog}.java 2>&1 >/dev/null | grep -v Note > grepLines.out
   javac \${testProg}.java 2>&1 >/dev/null 
   javac \${exception}.java 2>&1 > /dev/null
   
   if [ -s grepLines.out ] ; then 
     echo "Comment :=>> Compilation ERRORS reported"
     echo "<|--"
     cat grepLines.out
     echo "--|>"
     echo "Grade :=>> \$gradeCompileError"
     exit
   fi
}

# ----------------------------------------------------------------------
# getUserOutput: get the output from the user program
getUserOutput() {

    if [ "\$log" = "true" ]; then
       echo "--- getUserOutput() ---"
    fi


    java  \${testProg} 1 > user1.out
    java  \${testProg} 1 | grep "OK" | wc -l  > user2.out

    if [ "\$log" = "true" ]; then
        echo "--- user1.out ---"
        cat -v user1.out
        echo "--- user2.out ---"
        cat -v user2.out
    fi
}

# ----------------------------------------------------------------------
# generateExpectedOutput: generate files containg what is expected to
# be output.
generateExpectedOutput() {

    if [ "\$log" = "true" ]; then
       echo "--- generateExpectedOutput() ---"
    fi

    cat > expected1.out <<EOF
Test #1: Empty-Heap Test -- OK
Test #2: Empty-Size Test -- OK
Test #3: Heap-Size Test -- OK
Test #4: Heap-GetTop Test -- OK
Test #5: Heap-GetTop Test -- OK
Test #6: Heap-Size Test -- OK
Test #7: Heap-GetTop Test -- OK
Test #8: Heap-GetTop Test -- OK
Test #9: Heap-Empty One-At-A-Time Test -- OK
Test #10: Heap-Pop Throw Execption Test -- OK
Test #12: Heap-Pop Throw Execption Test -- OK
Test #13: Heap-Pop Throw Execption Test -- OK
EOF

    cat > expected2.out <<EOF
12
EOF

    if [ "\$log" = "true" ]; then
        echo "--- expected1.out ---"
        cat expected1.out
        echo "--- expected2.out ---"
        cat expected2.out
    fi
}

# ----------------------------------------------------------------------
# EvaluateUserOutput: evaluates what the program outputs
EvaluateUserOutput() {
   user=\$1
   expected=\$2

   if [ "\$log" = "true" ]; then
       echo "--- EvaluateUserOutput() ---"
       echo "user = \$user"
       echo "expected = \$expected"
   fi

   diff -y -w --ignore-all-space \$user \$expected > diff.out

   if ((\$? > 0)); then
      if [ "\!$bool" = "true" ]; then
          echo "---diff.out---"
          cat diff.out
      fi 


      echo "Comment :=>>- Your output is incorrect."

      echo "Comment :=>> ---------------"
      echo "Comment :=>>- Your output:"
      echo "Comment :=>> ---------------"
      echo "<|--"
      cat \$user
      echo "--|>"
      echo ""
      #echo "Comment :=>> ---------------"
      #echo "Comment :=>>- Expected output "
      #echo "Comment :=>> ---------------"
      #echo "<|--"
      #cat \$expected
      #echo "--|>"
   else
      echo "Comment :=>> Correct output."
      grade=\$((grade+gradeIncrement))
   fi
}

cleanup() {
   rm *.out?
}

#============================================================
#                           M  A  I  N 
#============================================================

compile

#--- if we're here, there's no compilation errors ---

grade=\$gradeCompileGood

#---  generate the user output ---

getUserOutput

#--- generate output from solution program ---

generateExpectedOutput

#--- compare user output to computer output ---

echo "Comment :=>> Test 1"
EvaluateUserOutput user1.out expected1.out


noTestsPassed=\`cat user2.out\`
echo "Comment :=>> Your program passed \$noTestsPassed tests out of 12"
grade=\$((grade+gradeIncrement*noTestsPassed))
if (( grade > 100 )); then
    grade=100
fi

echo "Grade :=>> \$grade"
EEOOFF

chmod +x vpl_execution


HeapTest.asm (the Test Program)


public class HeapTest {

	private static void test( boolean ok, int n, String msg ) {
		System.out.print( "Test #" + n + ": " + msg );
		if ( ok ) System.out.println( " -- OK" );
		else System.out.println( " -- FAIL" );
	}

	public static void main( String[] args ) {
		if ( args.length != 0 ) 
			test1();
		else
			test0();
	}
	public static void test0() {
		Heap heap = new Heap();
		int[] keys = new int[] { 3, 100, 10 };
		
		System.out.println( "Heap empty status: " + heap.isEmpty() );
		
		for ( int i=0; i<keys.length; i++ ) {
			heap.insert( keys[i] );
			System.out.println( "After inserting "+ keys[i] + ": " 
					+ heap + " -- size = " + heap.size()  );
		}

		while ( ! heap.isEmpty() ) {
			int root = heap.getTop();
			System.out.println( "heap after deleting " + root + ": " 
					+ heap +" -- size = " + heap.size() );
		}	
	}
	
	public static void test1( ) {
		Heap heap = new Heap();
				
		test(  heap.isEmpty(), 1, "Empty-Heap Test" ); 
		test(  heap.size()==0, 2, "Empty-Size Test" ); 
				
		for ( int i=0; i<100; i++ ) 
			heap.insert( 0 );
		
		test( heap.size()==100, 3, "Heap-Size Test" );
		int x = heap.getTop();
		test( x==0, 4, "Heap-GetTop Test" );

		heap.insert( 1 );;
		test( heap.getTop()==1, 5, "Heap-GetTop Test" );
		
		heap.clear();
		
		
		for ( int i=0; i<100; i++ ) 
			heap.insert( i );
		
		test( heap.size()==100, 6, "Heap-Size Test" );
		x = heap.getTop();
		test( x==99, 7, "Heap-GetTop Test" );

		heap.insert( 100 );
		x = heap.getTop();
		test( x==100, 8, "Heap-GetTop Test" );

		// empty the heap
		int count = 0;
		int size = heap.size();
		while( ! heap.isEmpty() ) {
			heap.getTop();
			count++;
		}
		
		test( count==size, 9, "Heap-Empty One-At-A-Time Test" );
		
		// test Exception
		heap.clear();
		heap.insert( 1 );
		try {
			int x1 = heap.pop();
			test( x1==1, 10, "Heap-Pop Throw Execption Test" );
			x1 = heap.pop();
			test( false, 11, "Heap-Pop Throw Execption Test" );
		}
		catch ( HeapEmptyException e ) {
			test( true, 12, "Heap-Pop Throw Execption Test" );
		}
		test( true, 13, "Heap-Pop Throw Execption Test" );
		
	}
}


HeapEmptyException


public class HeapEmptyException extends Exception{
    //Parameterless Constructor
    public HeapEmptyException() {}

    //Constructor that accepts a message
    public HeapEmptyException(String message){
       super(message);
    }
}


<onlydft>

Heap.java (The Student's Program)


/**
 * An implementation of a heap of ints with ArrayLists
 * @author D. Thiebaut
 */
import java.util.ArrayList;

/**
 * The Heap class
 * @author D. Thiebaut
 *
 */
public class Heap {
	private ArrayList<Integer> heap;
	private int size;
	
	/**
	 * constructor.  Creates an empty list
	 */
	public Heap() {
		size = 0;
		heap = new ArrayList<Integer>();
		heap.add( 0 ); // item at 0 does not exist
	}

	/**
	 * returns status of heap
	 * @return true if heap is empty, false otherwise
	 */
	public boolean isEmpty() {
		return ( size == 0 );
	}
	
	/**
	 * return the size of the heap.  0 if empty.
	 * @return
	 */
	public int size() {
		return size;
	}
	
	/**
	 * clears the heap completely and bring its size down to 0.
	 */
	public void clear() {
		size = 0;
		heap.clear();
		heap.add( 0 );
	}
	
	/**
	 * returns a string that is the representation of the contents of the heap.  
	 * <br /><b>Example</b> (heap of 8 items): [12, 5, 10, 5, 5, 5, 2, 3] 
	 * <br /><b>Example</b> (empty heap): []  
	 */
	public String toString() {
		String s ="[";
		for ( int i=1; i<=size; i++ ) {
			s += heap.get( i );
			if ( i!=size ) s += ", ";
		}
		return s+"]";
	}
	
	/**
	 * inserts a new key in the heap and heapifies it.
	 * @param key
	 */
	public void insert( int key ) {
		if ( heap.size() < size+2 ) 
			heap.add( 0 );
		heap.set( ++size, key );
		heapifyUp( size );
	}
	
	/**
	 * heapifyUP: given the index of a node in the heap, moves node up
	 * if necessary to establish heap property back.
	 * @param index: the index of the node currently processed.
	 */
	protected void heapifyUp( int index ) {
		while ( ( index > 1 ) && ( heap.get(index) > heap.get(index/2) ) ) {
			swap( index, index/2 );
			index = index / 2;
		}
	}

	/**
	 * function swapping nodes at indexes i and j
	 * @param i
	 * @param j
	 */
	protected void swap(int i, int j) {
		int temp = heap.get( i );
		heap.set( i, heap.get( j ) );
		heap.set( j, temp );
	}

	/**
	 * pop attempts to return the int at the top of the heap, and removes it
	 * from the heap.  An exception is raised if the heap is empty.
	 * @return the top of the heap, if successful
	 * @throws HeapEmptyException if the heap is empty before the deletion
	 */
	public int pop() throws HeapEmptyException {
		if ( isEmpty() )
			throw new HeapEmptyException( "Popping out of an empty heap" );
		return getTop();	
	}
	
	/**
	 * returns the top of the heap, and removes it from the heap.
	 * @return the top of the heap, or null if the heap is empty.
	 */
	public Integer getTop( ) {
		if ( isEmpty() )
			return null;
		
		int temp = heap.get( 1 );
		
		heap.set( 1, heap.get( size-- ) );
		heap.set( size+1, 0 );
		heapifyDown( 1 );
		return temp;
	}

	/**
	 * heapifyDown: given the index of a node in the heap (implemented by an arrayList)
	 * swap the node with the child with the largest key if necessary, in order to maintain
	 * the heap property.  Recurses on the child just swapped.
	 * @param index is the index of the node being considered.
	 */
	protected void heapifyDown(int index ) {
		// stop if we're out of the array
		if ( index > size  )
			return;
		
		int left = index * 2;
		int right = index * 2 + 1;
		
		if ( left > size )
			return;
		
		int swapIndex = -1;
		
		if ( heap.get( index ) < heap.get( left ) ) 
			swapIndex = left;
		if ( right <= size && heap.get(index ) < heap.get( right ) && heap.get( left )< heap.get(right ) )
			swapIndex = right;

		if ( swapIndex != -1 ) {
			swap( swapIndex, index );
			heapifyDown( swapIndex );
		}
	}

	/**
	 * main: main entry point of the program.
	 * @param args
	 */
	public static void main(String[] args) {
		Heap heap = new Heap();
		int[] keys = new int[] { 3, 100, 10, 5, 5, 5, 20, 5, 12, 40, 2, 100 };
		
		System.out.println( "Heap empty status: " + heap.isEmpty() );
		
		for ( int i=0; i<keys.length; i++ ) {
			heap.insert( keys[i] );
			System.out.println( "After inserting "+ keys[i] + ": " 
					+ heap + " -- size = " + heap.size()  );
		}
		//heap.swap( 1,  3 );
		//System.out.println( "After swapping "+ keys[1] + " and " + keys[3] + ": " + heap );

		while ( ! heap.isEmpty() ) {
			int root = heap.getTop();
			System.out.println( "heap after deleting " + root + ": " 
					+ heap +" -- size = " + heap.size() );
		}	
	}
	
}