Question Authors' Forum

Running C# in CodeRunner

 
Picture of Martin Zwerschke
Re: Running C# in CodeRunner
by Martin Zwerschke - Saturday, 20 January 2018, 6:18 AM
 

I did it this way (Prototype for question to create a c#-function):

""" The template for a question type that compiles and runs a student-submitted
    mono C# program. 
"""

import subprocess, sys

# Write the student code to a file prog.cs
student_answer = """using System;using System.IO;using System.Text;namespace myProg {    class program {"""
student_answer += """ {{ STUDENT_ANSWER | e('py') }} """
student_answer += """ public static void Main(string[] args) { """
student_answer += """ {{TEST.testcode | e('py') }}"""
student_answer += """ } } } """

with open("prog.cs", "w") as src:
    print(student_answer, file=src)

# Compile
return_code = subprocess.call(['mcs', 'prog.cs'])
if return_code != 0:
    print("** Compilation failed. Testing aborted **", file=sys.stderr)

# If compile succeeded, run the code. Since this is a per-test template,
# stdin is already set up for the stdin text specified in the test case,
# so we can run the compiled program directly.
if return_code == 0:
    try:
        output = subprocess.check_output(["mono", "./prog.exe"], universal_newlines=True)
        print(output)
    except subprocess.CalledProcessError as e:
        if e.returncode > 0:
            # Ignore non-zero positive return codes
            if e.output:
                print(e.output)
        else:
            # But negative return codes are signals - abort
            if e.output:
                print(e.output, file=sys.stderr)
            if e.returncode < 0:
                print("Task failed with signal", -e.returncode, file=sys.stderr)
            print("** Further testing aborted **", file=sys.stderr)

For example you ask your students to write a function that calculates the average of three values.

The Question for the students is:


Please write a C#-Function  (private static oder public static does not matter),

that calculates the average value of 3 Numbers (type int) and returns it as a float value.

Please only put this function into the answer box (and nothing else) !

Moodle calls your function and tests the result.


And they just have to fill this function into the answer-box.

The correct answer could be like this:

public static float Average(int a, int b, int c)
{
            int sum = a + b + c;

            return sum / 3.0f; 
}

Then use test cases like:

Console.Write(Average(3,4,2));

with expexted output of 3

or

Console.Write(Average(5,8,12));

with expected output of 8.333333


This workes for me, though I not really know, why the 

| e('py') 

is necessary. I just copied it from Robb's sample above.


Hope that will help you.


Picture of Richard Lobb
Re: Running C# in CodeRunner
by Richard Lobb - Sunday, 21 January 2018, 9:11 PM
 

Hi Martin

Thanks for posting. Just to answer your question about why the | e('py') is necessary....

When wrapping a raw string from the author form or student answer in quotes to make a literal string within the template code, you generally need to escape various special characters that might result in invalid string literals. As a trivial example, if a student's answer was "Hi" (including the double quotes) and you wrote, in JavaScript.

s = "{{STUDENT_ANSWER}}";

you'd get

s = ""Hi"";

which is broken. Hence Twig provides a range of escapers, so that for a JavaScript template you can write

s = "{{STUDENT_ANSWER | e('js')}}"

which would give you the valid

s = "\"Hi\"";

I've added to the Twig base set of escapers, e('py'), e('java') and e('matlab'). The Java escaper can be used for C and C++ too. 

The Python escaper is intended for use only within triple-quoted string literals. It escapes only double quotes (in case the raw string itself has triple quotes in it) and backslashes. Backslashes need to be escaped so that, for example, a 2-character \n in the student's code doesn't get converted to a single newline character in the triple-quoted literal.

Richard