Skip to content

Commit

Permalink
add basic and intermediate coverage exercises
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexandreDubray committed Nov 5, 2020
1 parent 80cd8bc commit bdd00ae
Show file tree
Hide file tree
Showing 16 changed files with 534 additions and 0 deletions.
6 changes: 6 additions & 0 deletions CoverageBasic/feedback_settings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
has_feedback: true
quorum: 0.9
feedback_kind: JaCoCo
coverage_stats:
- INSTRUCTION
- BRANCH
20 changes: 20 additions & 0 deletions CoverageBasic/flavour/Maximum.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package flavour;

public class Maximum {

/**
* Find the maximum in an array
*
* @param array A non-null and non empty array of integers
* @return The maximum value in the array
*/
public static int maximum(int [] array) {
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
}
}
22 changes: 22 additions & 0 deletions CoverageBasic/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/python3
import importlib.util
import sys


# Dynamically load modules we need
# Credits to https://stackoverflow.com/a/67692/6149867
# And for the explanation : http://www.blog.pythonlibrary.org/2016/05/27/python-201-an-intro-to-importlib/
def dynamically_load_module(module, path):
spec = importlib.util.spec_from_file_location(module, path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod


#####################################
# Our import for common run file #
#####################################
sys.path.append("/course/common")

runfile = dynamically_load_module("runfile", "/course/common/runfile.py")
runfile.main()
17 changes: 17 additions & 0 deletions CoverageBasic/src/ExerciseFlavour.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package src;

public interface ExerciseFlavour {

/*
* An exercise flavour is an exercise where you want to run a single test suite
* on different implementations of the same algorithm / problem. Each flavour
* MUST implement the method "correctness" stating whether the flavour is correct
* or not. You may want to willingly implement wrong algorithm(s) if (for example) you
* want to assess the quality of a test suite provided by students.
*/


// Return if the flavour is correct or not.
public boolean correctness();

}
88 changes: 88 additions & 0 deletions CoverageBasic/src/JailRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package src;

import com.github.guillaumederval.javagrading.GradeClass;
import com.github.guillaumederval.javagrading.TestSecurityManager;
import org.junit.internal.runners.statements.FailOnTimeout;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import java.security.*;
import java.security.cert.Certificate;
import java.util.concurrent.TimeUnit;


/**
* Custom runner that jails everything
*/
public class JailRunner extends BlockJUnit4ClassRunner {

public JailRunner(Class<?> klass) throws InitializationError {
super(klass);
}


@Override
protected Statement withPotentialTimeout(FrameworkMethod method, Object test, Statement next) {

GradeClass annoGradeClass = method.getDeclaringClass().getAnnotation(GradeClass.class);

long timeout = 0;

if(annoGradeClass != null && timeout == 0 && annoGradeClass.defaultCpuTimeout() > 0)
timeout = annoGradeClass.defaultCpuTimeout() * 3;

if (timeout <= 0) {
return next;
}
return FailOnTimeout.builder()
.withTimeout(timeout, TimeUnit.MILLISECONDS)
.build(next);
}


@Override
protected Statement methodInvoker(FrameworkMethod method, Object test) {
Statement base = super.methodInvoker(method, test);

checkSecurity();

PermissionCollection coll = new Permissions();

ProtectionDomain pd = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), coll);

return new Statement() {
@Override
public void evaluate() throws Throwable {

Throwable ex = AccessController.doPrivileged(new PrivilegedExceptionAction<Throwable>() {
@Override
public Throwable run() throws Exception {
Throwable ex = null;
try {
base.evaluate();
} catch (Throwable throwable) {
ex = throwable;
}
return ex;
}
}, new AccessControlContext(new ProtectionDomain[]{pd}));

if(ex != null)
throw ex;
}
};
}


private static void checkSecurity() {
if(!(System.getSecurityManager() instanceof TestSecurityManager)) {
try {
System.setSecurityManager(new TestSecurityManager());
}
catch (SecurityException e) {
System.out.println("/!\\ WARNING: Cannot set a TestSecurityManager as the security manager. Tests may not be jailed properly.");
}
}
}
}
13 changes: 13 additions & 0 deletions CoverageBasic/src/StudentTestRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package src;

import org.junit.runner.JUnitCore;
import org.junit.runner.Result;

public class StudentTestRunner {

public static void main(String[] args) {
JUnitCore runner = new JUnitCore();
Result result = runner.run(StudentTests.class);
}

}
67 changes: 67 additions & 0 deletions CoverageBasic/task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
accessible: true
author: Alexandre Dubray
categories:
- module4
contact_url: ''
context: |
In this task, you should provide a test suite for coverage check of the following class:
.. code-block:: java
public class Maximum {
/**
* Find the maximum in an array
*
* @param array A non-null and non empty array of integers
* @return The maximum value in the array
*/
public static int maximum(int [] array) {
int max = array[0];
for (int i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
}
}
Here is a small example to show you how to call the method:
.. code-block:: java
@Test
public void test() {
int [] a = new int[]{}; // your test array
int max = Maximum.maximum(a); // find the maximum
// some asserts
}
// some other tests in order to have edge and node coverage
environment: java8scala
evaluate: best
file: ''
groups: false
input_random: '0'
limits:
memory: '100'
output: '2'
time: '30'
name: '[Module 4] Coverage Testing: the basics'
network_grading: false
order: 37
problems:
student_code:
type: code
header: 'Insert the **BODY** (i.e., your test functions) of your test suite here:'
language: java
name: ''
default: ''
run_cmd: ''
stored_submissions: 0
submission_limit:
amount: -1
period: -1
weight: 1.0
18 changes: 18 additions & 0 deletions CoverageBasic/templates/StudentTests.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package src;

import com.github.guillaumederval.javagrading.GradeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import flavour.*;

import static org.junit.Assert.*;

@RunWith(JailRunner.class)
@GradeClass(totalValue = 1, defaultCpuTimeout = 2000)
public class StudentTests {

// STUDENT CODE WILL BE INSERTED HERE
@ @student_code@@
// END OF STUDENT CODE

}
6 changes: 6 additions & 0 deletions CoverageIntermediate/feedback_settings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
has_feedback: true
quorum: 0.9
feedback_kind: JaCoCo
coverage_stats:
- INSTRUCTION
- BRANCH
36 changes: 36 additions & 0 deletions CoverageIntermediate/flavour/BinarySearch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package flavour;

public class BinarySearch{

/**
* Find a value in an integer array
*
* @param array A non-null array of distinct integer
* values sorted in increasing order
* @param value The value to look for in the array
* @return The index of the value in the array of -1
* if the value is not in the array
*/
public static int binarySearch(int [] array, int value) {
int lo = 0;
int hi = array.length - 1;

while (lo <= hi) {
if (array[lo] == value)
return lo;
if (array[hi] == value)
return hi;

int mid = lo + (hi - lo)/2;

if (array[mid] == value)
return mid;

if (mid > value)
hi = mid - 1;
else
lo = mid + 1;
}
return -1;
}
}
22 changes: 22 additions & 0 deletions CoverageIntermediate/run
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/python3
import importlib.util
import sys


# Dynamically load modules we need
# Credits to https://stackoverflow.com/a/67692/6149867
# And for the explanation : http://www.blog.pythonlibrary.org/2016/05/27/python-201-an-intro-to-importlib/
def dynamically_load_module(module, path):
spec = importlib.util.spec_from_file_location(module, path)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod


#####################################
# Our import for common run file #
#####################################
sys.path.append("/course/common")

runfile = dynamically_load_module("runfile", "/course/common/runfile.py")
runfile.main()
17 changes: 17 additions & 0 deletions CoverageIntermediate/src/ExerciseFlavour.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package src;

public interface ExerciseFlavour {

/*
* An exercise flavour is an exercise where you want to run a single test suite
* on different implementations of the same algorithm / problem. Each flavour
* MUST implement the method "correctness" stating whether the flavour is correct
* or not. You may want to willingly implement wrong algorithm(s) if (for example) you
* want to assess the quality of a test suite provided by students.
*/


// Return if the flavour is correct or not.
public boolean correctness();

}
Loading

0 comments on commit bdd00ae

Please sign in to comment.