1
Vote

Exception thrown for multiple failed parsings in MSTest ordered test

description

I have a series of unit tests using CommandLine 1.9.71.2 that pass when run 'simultaneously', but not in an ordered test (run in Visual Studio 2013 using MSTest).

This exception is always thrown for the second method that tries to write to the command line, even if you switch the order:
System.ObjectDisposedException: Cannot write to a closed TextWriter.
Result1 StackTrace:
at System.IO.__Error.WriterClosed()
at System.IO.StringWriter.Write(String value)
at Microsoft.VisualStudio.TestTools.TestTypes.Unit.ThreadSafeStringWriter.Write(String value)
at System.IO.TextWriter.SyncTextWriter.Write(String value)
at CommandLine.Parser.InvokeAutoBuildIfNeeded(Object options)
at CommandLine.Parser.ParseArgumentsStrict(String[] args, Object options, Action onFail)
at TestDataStorageReduction.CommandLineOptions.ParseArgs(String[] args) in <file.cs>
at TdsrTest.Main.CommandLineTest.OneDashCmdLineOptions() in <file.cs>
Relevant code looks like this:
    public class CommandLineOptions
    {
        public const string OVERRIDE_AGE = "override-age-requirement";
        public const string TEST_MODE = "test";

        [Option(TEST_MODE, DefaultValue = false, Required = false,
            HelpText = "Run application in sandbox")]
        public bool TestMode { get; set; }

        [OptionArray(OVERRIDE_AGE, DefaultValue = new string[] { },
            Required = false,
            HelpText = "some help text")]
        public string[] OverrideAgeProcesses { get; set; }

        // Call default parser, do nothing if fails
        public bool ParseArgs(string[] args)
        { return CommandLine.Parser.Default.ParseArgumentsStrict(args, this, () => { }); }
    }

    [TestClass]
    public class CommandLineTest
    {
        private CommandLineOptions GetCmdLineOpt()
        { return new CommandLineOptions(); }

        // This test fails strict parsing because of missing hypen
        [TestMethod]
        public void OneDashCmdLineOptions()
        {
            CommandLineOptions clo = GetCmdLineOpt();
            string[] args = new string[] { "-test" };

            Assert.IsFalse(clo.ParseArgs(args));
        }

        // This test fails strict parsing because of no arguments
        [TestMethod]
        public void EmptyOverrideAgeCmdLineOption()
        {
            CommandLineOptions clo = GetCmdLineOpt();
            string[] args = new string[] 
            { "--" + CommandLineOptions.OVERRIDE_AGE };

            Assert.IsFalse(clo.ParseArgs(args));
        }
    }

comments

jdsleppy wrote Jul 2, 2015 at 3:46 PM

Since the code used the default, singleton parser, I assume the problem is either in the singleton or in how MSTest's ordered test (a very complicated beast, I'm sure) interacts with the singleton.

For now, I am using a non-default parser that has null ParserSettings.HelpWriter in the unit tests.
    public class CommandLineOptions
    {
        public CommandLineOptions(bool writeToConsole)
        { 
            parser = new Parser((settings) => 
            {
                settings.CaseSensitive = true;
                settings.IgnoreUnknownArguments = false;
                settings.MutuallyExclusive = false;
                settings.HelpWriter = (writeToConsole) ? Console.Error : null;
            });        
        }
        public bool ParseArgs(string[] args)
        {
            return parser.ParseArgumentsStrict(args, this, () => { });
        }
}

jdsleppy wrote Jul 2, 2015 at 3:53 PM

Actually, I don't even need the constructor parameter: all you have to do is "recreate" the default parser as a regular Parser instance and it works.
    public class CommandLineOptions
    {
        public CommandLineOptions()
        { 
            parser = new Parser((settings) => 
            {
                settings.CaseSensitive = true;
                settings.IgnoreUnknownArguments = false;
                settings.MutuallyExclusive = false;
                settings.HelpWriter = Console.Error;
            });        
        }
        ...
    }

wrote Jul 2, 2015 at 3:55 PM