C# validation question template

C# validation question template

by A R -
Number of replies: 1

Hello All,

I would like to get the programs with validation working in C# with Coderunner:

Enter shape to draw: Sqare
Invalid input. Try again.
Enter shape to draw: Square
Filled or unfilled? Filed
Invalid input. Try again.
Filled or unfilled? Filled
Size: 200
Invalid input. Try again.
Size: -1
Invalid input. Try again.
Size: 1

I know that in the examples provided, for Python the template additions below work.
__saved_input__ = input
def input(prompt=""):
    result = __saved_input__(prompt)
    print(result)
    return result

{{STUDENT_ANSWER}}

{{TEST.testcode}}

I am not entirely sure how the above works for Python.  I would appreciate help with how Console.ReadLine(); in C# could be re-written.
The template I am using for C# is listed below.
Thank you

""" 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 = """{{ STUDENT_ANSWER | e('py') }}"""

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)

In reply to A R

Re: C# validation question template

by Richard Lobb -

I have very little C# experience, but as no-one else is attempting an answer, here's my best guess.

The Python snippet you mention replaces the built-in input function with a custom one that echos to stdout the characters read by the function from stdin. This mimics the behaviour observed by students typing on a keyboard. With most other languages, replacing the input function isn't so easy.

I can think of three possibilities:

  1. Explain to the students what "keyboard echo" is all about and why it doesn't work in CodeRunner, where stdin is redirected to a file. This is the approach I take in a second year systems course in C and in the past I've used it with Python in a first year course. Yes, it causes some confusion, but the students get over it, in time. Probably not the preferred option, but easy for you (if you ignore the time spent explaining the problem over and over to students).
  2. Find a way of replacing the C# console class with a custom version that you insert at the start of the program that you run. I'm not sure how do-able this is in C# but this link might help.
  3. As a hacky variant on (2), write your own console class, say CodeRunnerConsole, which just delegates to Console except that the ReadLine() method passes what it gets by calling Console.ReadLine() to Console.WriteLine(), just like the Python example. Insert it at the start of the program that you send to Jobe, and do a global replace of the word 'Console' (and equivalents like System.Console perhaps) in the student answer with CodeRunnerConsole. More sophisticated variants of this approach use a parser to ensure that only "appropriate" Console tokens are replaced.

Step 3 would involve tweaking the template to include code like the following, just before writing the student_answer variable to a file:

console_code = """ ... C# code to define class CodeRunnerConsole """
student_answer = console_code + student_answer.replace('Console', 'CodeRunnerConsole')

A downside of both (2) and (3) is that the line numbers in error messages from the compiler or run-time won't match those in the student's code. Solving that problem is harder - you have to edit the captured output from the compiler and run time, identifying the error message lines and tweaking them.