4

I have a problem with testing "Console in" and "Console out" in a C# console application.

If I use Console.WriteLine and Console.ReadLine I can use NUnit framework to test the application, but if I use a helper class for in and output to console I cannot get it to work.

The helper class is https://open.kattis.com/download/Kattio.cs and uses a BufferedStream to write to the Console, but I cannot get my test to read it...

It uses A StreamReader for "Console in" but I get a "NoMoreTokenException" which I guess that it don't get any input...

I would like to use the helper class but I cannot test with it...

Ex: Testcase:

    [Test]
    public void test_hello_world ()
    {
        using (var sw = new StringWriter ()) {              
            Console.SetOut (sw);
            using (var sr = new StringReader ("Start")) {
                Console.SetIn (sr);
                MainClass.Main(new string[]{});
                string expected = "Hello World!\n";
                Assert.AreEqual (sw.ToString (), expected);
            }
        }
    }

Ex: Code that work:

    string line = "";
    if (Console.ReadLine().Equals("Start"))
        line = "Hello World!";
    else
        line = "No such luck!";
    Console.WriteLine (line);

Ex: Code that don't work:

        string line = "";
        Scanner sc = new Scanner ();
        if (sc.Next ().Equals ("Start"))
            line = "Hello World!";
        else
            line = "No such luck!";
        BufferedStdoutWriter outWritter = new BufferedStdoutWriter ();
        outWritter.WriteLine (line);
        outWritter.Flush ();

Anyone having any insight on how to solve this?

hub
  • 165
  • 3
  • 13
  • If you look at [documentation](https://msdn.microsoft.com/en-us/library/tx55zca2(v=vs.110).aspx) for `Console.OpenStandardInput`, it says _This method can be used to reacquire the standard input stream after it has been changed by the SetIn method._ I take that to mean that it's undoing the `Console.SetIn` and so it's actually reading from the console instead of your `StringReader`. – juharr Jul 29 '15 at 18:18
  • You might be able to pull this off by starting up your program in a separate process and passing the input and getting the output from it. – juharr Jul 29 '15 at 18:43
  • Related (duplicate?): http://stackoverflow.com/q/2139274/126014 – Mark Seemann Jul 29 '15 at 21:10

1 Answers1

6

As @juharr mentioned in the comment that calling Console.OpenStandardInput will reset the input stream. So you need to make the helper class testable for console streams. (Only If you are allowed to change the implementation).

First the Tokenizer class can be updated to use the console Reader as default TextReader:

public class Tokenizer
{
    string[] tokens = new string[0];
    private int pos;

    // StreamReader reader; Changed to TextReader
    TextReader reader;

    public Tokenizer(Stream inStream)
    {
        var bs = new BufferedStream(inStream);
        reader = new StreamReader(bs);
    }

    public Tokenizer()
    {
        // Add a default initializer as Console Input stream reader.
        reader = Console.In;
    }

    // ...... Rest of the code goe here...............
    // .....................
}

Also change the Buffer output writer to following:

Updated - Constructor will accept other streams as well.

public class BufferedStdoutWriter
{
    public TextWriter Writer;

    public BufferedStdoutWriter() 
    {
        // Use default writer as console output writer
        this.Writer = Console.Out;
    }

    public BufferedStdoutWriter(Stream stream)
    {
        Writer = new StreamWriter(new BufferedStream(stream));
    }
    public void Flush()
    {
        Writer.Flush();
    }

    public void Write<T>(T value)
    {
        Writer.Write(value);
    }

    public void WriteLine<T>(T value)
    {
        Writer.WriteLine(value);
    }
}

similarly can implementation of more functions if required.

Now your test will successfully pass for EX: Code that don't work snippet.

vendettamit
  • 14,315
  • 2
  • 32
  • 54