Why is CSharpOptParse UsageBuilder failing due to an XPathException only when used in an NUnit test?

做~自己de王妃 提交于 2019-12-25 00:09:50

问题


What is the root cause of this issue? CSharpOptParse, XslTransform.Transform(...), or NUnit? What other equivalent library could I use instead, if this problem is unfixable, that is being actively supported?

I'm using version 1.0.1 of CSharpOptParse which was last modified in Feb 2005.

I've have the following class (simplified for this example of course) to use along with CSharpOptParse:

public enum CommandType
{
   Usage
}

public class Options
{
   [OptDef(OptValType.Flag)]
   [LongOptionName("help")]
   [Description("Displays this help")]
   public bool Help { get; set; }

   public CommandType CommandType
   {
      get { return CommandType.Usage; }
   }
}

Here is a bit of unit test code that replicates the issue:

TextWriter output = Console.Out;

Options options = new Options { Help = true };
Parser p = ParserFactory.BuildParser(options);
p.Parse();

output.WriteLine("Usage: Console [--a]");
UsageBuilder builder = new UsageBuilder();
builder.BeginSection("Arguments:"); 
builder.AddOptions(p.GetOptionDefinitions()); //could the issue be created here?
builder.EndSection();
builder.ToText(output, OptStyle.Unix, true); //The problem occurs here

Is it possible that I'm causing the problem by not setting up the UsageBuilder with the correct sections? Possibly this might be causing problems in the xslt file???

When I run that code I get the following exception:

    System.Xml.XPath.XPathException : Function 'ext:FormatText()' has failed.
    ----> System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
      ----> System.ArgumentOutOfRangeException : Index was out of range. Must be non-negative and less than the size of the collection.
    Parameter name: startIndex
       at MS.Internal.Xml.XPath.FunctionQuery.Evaluate(XPathNodeIterator nodeIterator)
       at System.Xml.Xsl.XsltOld.Processor.ValueOf(ActionFrame context, Int32 key)
       at System.Xml.Xsl.XsltOld.ValueOfAction.Execute(Processor processor, ActionFrame frame)
       at System.Xml.Xsl.XsltOld.ActionFrame.Execute(Processor processor)
       at System.Xml.Xsl.XsltOld.Processor.Execute()
       at System.Xml.Xsl.XsltOld.Processor.Execute(TextWriter writer)
       at System.Xml.Xsl.XslTransform.Transform(XPathNavigator input, XsltArgumentList args, TextWriter output, XmlResolver resolver)
       at System.Xml.Xsl.XslTransform.Transform(IXPathNavigable input, XsltArgumentList args, TextWriter output, XmlResolver resolver)
       at CommandLine.OptParse.UsageBuilder.ToText(TextWriter writer, OptStyle optStyle, Boolean includeDefaultValues, Int32 maxColumns)
--TargetInvocationException
    at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
    at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
    at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
    at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
    at System.Xml.Xsl.XsltOld.XsltCompileContext.FuncExtension.Invoke(XsltContext xsltContext, Object[] args, XPathNavigator docContext)
    at MS.Internal.Xml.XPath.FunctionQuery.Evaluate(XPathNodeIterator nodeIterator)
    --ArgumentOutOfRangeException
    at System.String.LastIndexOfAny(Char[] anyOf, Int32 startIndex, Int32 count)

I have no idea what is causing this problem....and the weirdest part is that is only occurs within my NUnit test. When this code is called via "Console.exe --help" it runs fine with no exceptions. I can't see anything wrong with CSharpOptParse so could this be a problem in .NET's XslTransform class or in NUnit?

Has anyone else experienced this issue? Does anyone have any advice on how to track down the issue or switch to a better library?


回答1:


I know this is an old question. But..

The exception is caused because the ToText() method tries to determine the width of the console and it fails when you're writing to anything that is not a real console.

The fix is simple: Set a fixed width.

Change the call to ToText to:

try
{
    usage.ToText(Console.Out, OptStyle.Unix, true);
}
catch
{
    usage.ToText(Console.Out, OptStyle.Unix, true, 90);
}

Now if the normal call fails, it will try a fail-safe one.




回答2:


Why don't you attach a debugger to NUnit, turn on First-Chance exceptions, and find out what's going on?




回答3:


I ran into the same issue and have seemed to have fixed it (not sure of the issues it would cause doing this but everything seems to work okay).

Find:

public TextTransformHelper(int maxColumns)
        {
            _maxColumns = maxColumns;

            if (_maxColumns == -1)
            {
                // try to determine console width
                string os = Environment.GetEnvironmentVariable("OS");

                if (os != null && os.StartsWith("Win"))
                {
                    ConsoleUtils.ConsoleHelper ch = new ConsoleUtils.ConsoleHelper();
                    _maxColumns = ch.GetScreenInfo().Size.X;
                }
            }
        }

and then modify it to the following:

public TextTransformHelper(int maxColumns)
    {
        _maxColumns = maxColumns;

        if (_maxColumns == -1)
        {
            // try to determine console width
            string os = Environment.GetEnvironmentVariable("OS");

            if (os != null && os.StartsWith("Win"))
            {
                ConsoleUtils.ConsoleHelper ch = new ConsoleUtils.ConsoleHelper();
                _maxColumns = ch.GetScreenInfo().Size.X;
                if(_maxColumns == 0) //added
                    _maxColumns = -1; //added
            }
        }
    }

The reason it was blowing up was because in the FormatText function it has the following if statement which was supposed to be hit if a columnwidth was not defined or was -1. The function for me would always return 0 which would cause the below if statement to not get hit and then cause an "ArgumentOutOfRange" exception. This was on Windows Server 2008:

if (_maxColumns == -1)
                {
                    output.Append((first) ? indentStr : handingIndentStr);
                    output.Append(line);
                    output.Append(Environment.NewLine);
                    first = false;
                    continue;
                }

I was able to debug it by seeing the "ext:FormatText" failed error and then setting breakpoints on all FormatText functions (the xslt was calling the C# function) and then looking at the exception and debugging in further.

I hope this helps.

John Rennemeyer



来源:https://stackoverflow.com/questions/486119/why-is-csharpoptparse-usagebuilder-failing-due-to-an-xpathexception-only-when-us

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!