commandline: Version 2.4.x System.ArgumentNullException parsing options in unit-test

Hello,

i tried all 2.4.x versions (2.4.0, 2.4.1, 2.4.2, 2.4.3) and all have the same exception. In my unit-test i call my program only with “–help” after that, i receive the following stacktrace:

// Stacktrace
System.ArgumentNullException
Value cannot be null.
Parameter name: element
   at System.Attribute.GetCustomAttributes(Assembly element, Type attributeType, Boolean inherit)
   at System.Reflection.CustomAttributeExtensions.GetCustomAttributes[T](Assembly element)
   at CommandLine.Infrastructure.ReflectionHelper.GetAttribute[TAttribute]()
   at CommandLine.Text.HelpText.AutoBuild[T](ParserResult`1 parserResult, Func`2 onError, Func`2 onExample, Boolean verbsIndex, Int32 maxDisplayWidth)
   at CommandLine.Text.HelpText.AutoBuild[T](ParserResult`1 parserResult, Int32 maxDisplayWidth)
   at CommandLine.Parser.<>c__DisplayClass17_0`1.<DisplayHelp>b__1(IEnumerable`1 _, TextWriter writer)
   at CSharpx.MaybeExtensions.Do[T1,T2](Maybe`1 maybe, Action`2 action)
   at CommandLine.ParserResultExtensions.WithNotParsed[T](ParserResult`1 result, Action`1 action)
   at CommandLine.Parser.DisplayHelp[T](ParserResult`1 parserResult, TextWriter helpWriter, Int32 maxDisplayWidth)
   at Program.<Main>d__5.MoveNext() in C:\..\..\Program.cs:line 33

My code snippets are the following ones:

// Test method (xUnit) which fails
[Fact]
public async Task CallMain_GiveHelpArgument_ExpectSuccess() {
    var result = await Program.Main(new[] { "--help" });

    Assert.Equal(ERROR_SUCCESS, result);
}
// main program
internal class Program {

  private const int ERROR_SUCCESS = 0;

  internal static async Task<int> Main(string[] args) {
      bool hasError = false;
      bool helpOrVersionRequested = false;

      ParserResult<Options> parsedOptions = Parser.Default.ParseArguments<Options>(args).WithNotParsed(errors => {
          helpOrVersionRequested = errors.Any(x => x.Tag == ErrorType.HelpRequestedError || x.Tag == ErrorType.VersionRequestedError);
          hasError = true;
      });

      if (helpOrVersionRequested) {
          return ERROR_SUCCESS;
      }

    // Execute as a normal call
    // ...
  }
  
}
// Options
internal class Options {

  [Option('c', "connectionString", Required = true, HelpText = Texts.ExplainConnection)]
  public string ConnectionString { get; set; }

  [Option('j', "jobId", Required = true, HelpText = Texts.ExplainJob)]
  public int JobId { get; set; }

  [Usage(ApplicationAlias = "Importer.exe")]
  public static IEnumerable<Example> Examples {
      get => new[] {
          new Example(Texts.ExplainExampleExecution, new Options() {
              ConnectionString="Server=MyServer;Database=MyDatabase",
              JobId = 5
          }),
      };
  }

}

I did a downgrade to version 2.3.0 without any issues. Calling the compiled Program.exe by a command line seems to be working as well. I created that test to ensure my application stops when the version or help is requested only without any additional information.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 19 (4 by maintainers)

Most upvoted comments

TL;DR,

I could reproduce the same error in a test project of target framework net472 , but sucess in netcoreapp2.1 using commaline v2.4.3.

This problem is due to the behavior of testhost in Full framework net46.x / net4.7.x and netcore2.x in reading AssemblyAttributes.

This a long story and I have previously posted an issue to vstest project to correct that behavior.

Commandlineparser consider AseemplyAttributes copyright and company shouldn’t be null and raise exception (I think it should be relaxed), which may be null in hosttest and cause troubles with commandlineparser.

To workaround the problem in net472 (compliant with netstandard2) let test classes inherit the following class:

    public class BaseTest
   {
       public BaseTest()  
      {  
	//in case multi target project,use #if because no appdomain in netcore
	#if NET472
        /* Preparing test start */  
        Assembly assembly = Assembly.GetCallingAssembly();  

        AppDomainManager manager = new AppDomainManager();  
        FieldInfo entryAssemblyfield = manager.GetType().GetField("m_entryAssembly", BindingFlags.Instance | BindingFlags.NonPublic);  
        entryAssemblyfield.SetValue(manager, assembly);  

        AppDomain domain = AppDomain.CurrentDomain;  
        FieldInfo domainManagerField = domain.GetType().GetField("_domainManager", BindingFlags.Instance | BindingFlags.NonPublic);  
        domainManagerField.SetValue(domain, manager);  
        /* Preparing test end */  
	#endif
    } 
  }

   //your test class inherit BaseTest
    public class TestProgram: BaseTest
	{
		// Test method (xUnit) which fails and really fail when inheriting the BaseTet class
		[Fact]
		public async Task CallMain_GiveHelpArgument_ExpectSuccess() {
		var result = await Program.Main(new[] { "--help" });
                    int ERROR_SUCCESS = 0;
		Assert.Equal(ERROR_SUCCESS, result);
	  }
	}	

I tested your code in multi-target project in Xunit for net472 and netcoreapp2.1 and both are sucess and NO exception is raised. Run:

   dotnet test

The output in the multi-target test project is:

Test run for F:\github_issues\CommandParser432\CommandParser432\bin\Debug\net472\CommandParser432.dll(.NETFramework,Version=v4.7.2) Microsoft ® Test Execution Command Line Tool Version 15.9.0 Copyright © Microsoft Corporation. All rights reserved.

Starting test execution, please wait…

Total tests: 1. Passed: 1. Failed: 0. Skipped: 0. Test Run Successful. Test execution time: 7.9740 Seconds Test run for F:\github_issues\CommandParser432\CommandParser432\bin\Debug\netcoreapp2.1\CommandParser432.dll(.NETCoreApp,Version=v2.1) Microsoft ® Test Execution Command Line Tool Version 15.9.0 Copyright © Microsoft Corporation. All rights reserved.

Starting test execution, please wait…

Total tests: 1. Passed: 1. Failed: 0. Skipped: 0. Test Run Successful. Test execution time: 5.0017 Seconds

Conclusion:

The xunit test project is working fine when you inherit the TestBase class in net472.

I test your demo and it fail with the error message

Error Message: System.ArgumentNullException : Value cannot be null. Parameter name: element

As a workaround solution, I modified your project by inheriting the class `BaseTest’ that i described in my comment and it pass successfully.

Total tests: 1. Passed: 1. Failed: 0. Skipped: 0. Test Run Successful.

The root error is that the Assemplyattribute copyright and company are null in the hosttest of vstest which is used by NUnit and Xunit, so Commandlineparser raise an exception when execute Assembly.GetEntryAssembly() .

This bug is in net4x only. In netcoreapp2.x test pass successfully. So it’s best to test project in netcoreapp2.x which use the same packages (work only in SDK style project )

IssueDemo-sucess.zip