/// <summary> /// Converts the given arguments to vstest parsable arguments /// </summary> /// <param name="args">original arguments</param> /// <param name="ignoredArgs">arguments ignored by the converter</param> /// <returns>list of args which can be passsed to vstest</returns> public List <string> Convert(string[] args, out List <string> ignoredArgs) { var newArgList = new List <string>(); ignoredArgs = new List <string>(); string activeArgument = null; BlameArgs blame = new BlameArgs(); foreach (var arg in args) { if (arg == "--") { throw new ArgumentException("Inline settings should not be passed to Convert."); } if (arg.StartsWith("-")) { if (!string.IsNullOrEmpty(activeArgument)) { if (IgnoredArguments.Contains(activeArgument)) { ignoredArgs.Add(activeArgument); } else if (blame.IsBlameArg(activeArgument, null)) { // do nothing, we process remaining arguments ourselves } else { newArgList.Add(activeArgument); } activeArgument = null; } // Check if the arg contains the value separated by colon if (arg.Contains(":")) { var argValues = arg.Split(':'); if (IgnoredArguments.Contains(argValues[0])) { ignoredArgs.Add(arg); continue; } if (this.IsVerbosityArg(argValues[0])) { UpdateVerbosity(argValues[1], newArgList); continue; } if (blame.IsBlameArg(argValues[0], argValues[1])) { blame.UpdateBlame(argValues[0], argValues[1]); continue; } // Check if the argument is shortname if (ArgumentMapping.TryGetValue(argValues[0].ToLower(), out var longName)) { argValues[0] = longName; } newArgList.Add(string.Join(":", argValues)); } else { if (blame.IsBlameSwitch(arg)) { blame.UpdateBlame(arg, null); activeArgument = arg; } else { activeArgument = arg.ToLower(); if (ArgumentMapping.TryGetValue(activeArgument, out var value)) { activeArgument = value; } } } } else if (!string.IsNullOrEmpty(activeArgument)) { if (IsVerbosityArg(activeArgument)) { UpdateVerbosity(arg, newArgList); } else if (IgnoredArguments.Contains(activeArgument)) { ignoredArgs.Add(activeArgument); ignoredArgs.Add(arg); } else if (blame.IsBlameArg(activeArgument, arg)) { blame.UpdateBlame(activeArgument, arg); } else { newArgList.Add(string.Concat(activeArgument, ":", arg)); } activeArgument = null; } else { if (blame.IsBlameArg(arg, null)) { blame.UpdateBlame(arg, null); } else { newArgList.Add(arg); } } } if (!string.IsNullOrEmpty(activeArgument)) { if (IgnoredArguments.Contains(activeArgument)) { ignoredArgs.Add(activeArgument); } else if (blame.IsBlameArg(activeArgument, null)) { // do nothing, we process remaining arguments ourselves } else { newArgList.Add(activeArgument); } } if (blame.Blame) { blame.AddCombinedBlameArgs(newArgList); } return(newArgList); }
/// <summary> /// Converts the given arguments to vstest parsable arguments /// </summary> /// <param name="args">original arguments</param> /// <param name="ignoredArgs">arguments ignored by the converter</param> /// <returns>list of args which can be passsed to vstest</returns> public List <string> Convert(string[] args, out List <string> ignoredArgs) { var newArgList = new List <string>(); ignoredArgs = new List <string>(); string activeArgument = null; BlameArgs blame = new(); foreach (string arg in args) { if (arg == "--") { throw new ArgumentException("Inline settings should not be passed to Convert."); } if (arg.StartsWith('-')) { if (!string.IsNullOrEmpty(activeArgument)) { if (s_ignoredArguments.Contains(activeArgument)) { ignoredArgs.Add(activeArgument); } else if (BlameArgs.IsBlameArg(activeArgument)) { // do nothing, we process remaining arguments ourselves } else { newArgList.Add(activeArgument); } activeArgument = null; } // Check if the arg contains the value separated by colon if (arg.Contains(':')) { string[] argValues = arg.Split(':'); if (s_ignoredArguments.Contains(argValues[0])) { ignoredArgs.Add(arg); continue; } if (IsVerbosityArg(argValues[0])) { UpdateVerbosity(argValues[1], newArgList); continue; } if (BlameArgs.IsBlameArg(argValues[0])) { blame.UpdateBlame(argValues[0], argValues[1]); continue; } // Check if the argument is shortname if (s_argumentMapping.TryGetValue(argValues[0].ToLower(), out string longName)) { argValues[0] = longName; } newArgList.Add(string.Join(':', argValues)); } else { if (BlameArgs.IsBlameSwitch(arg)) { blame.UpdateBlame(arg, null); activeArgument = arg; } else { activeArgument = arg.ToLower(); if (s_argumentMapping.TryGetValue(activeArgument, out string value)) { activeArgument = value; } } } } else if (!string.IsNullOrEmpty(activeArgument)) { if (IsVerbosityArg(activeArgument)) { UpdateVerbosity(arg, newArgList); } // It's possible to have activeArgument that is both ignored and considered as // a switch. Order of the two contains clauses is important because the current // implementation wants to check first if activeArgument is a switch first so // that we don't consume the arg, and the inner if will take care of deciding // if active argument should be ignored or handled. else if (s_switchArguments.Contains(activeArgument)) { if (s_ignoredArguments.Contains(activeArgument)) { ignoredArgs.Add(activeArgument); } else { newArgList.Add(activeArgument); } // The only real case where we would end-up here is when the item under // test (.dll or .exe) is passed as last argument so we could potentially // check the extension and for invalid ones, either add it to the ignored // args or have a specific failure. newArgList.Add(arg); } // When reaching this point, we are sure that activeArgument is not a switch // so we can add it and the arg to the list of ignored arguments. else if (s_ignoredArguments.Contains(activeArgument)) { ignoredArgs.Add(activeArgument); ignoredArgs.Add(arg); } // When entering this condition, we know that the activeArgument is either a // blame switch or a blame argument. Blame args have to be handled differently // because they are cumulative and so need to be combined. The inner logic will // decide how to handle it. else if (BlameArgs.IsBlameArg(activeArgument)) { // We know that activeArgument is a blame kind, we now want to see if arg // is linked to the blame or not. If activeArgument is a not blame switch // (e.g., --blame-crash-dump-type full) or if it is the legacy blame syntax // (e.g., --blame CollectDump;DumpType=full) then we do want to update the // blame combination based both on activeArgument and arg. Otherwise, we // have a simple blame switch (e.g., --blame some.dll) so we can add it to // the args list. if (!BlameArgs.IsBlameSwitch(activeArgument) || BlameArgs.IsLegacyBlame(activeArgument, arg)) { blame.UpdateBlame(activeArgument, arg); } else { newArgList.Add(arg); } } else { newArgList.Add(string.Concat(activeArgument, ":", arg)); } activeArgument = null; } else { if (BlameArgs.IsBlameArg(arg)) { blame.UpdateBlame(arg, null); } else { newArgList.Add(arg); } } } if (!string.IsNullOrEmpty(activeArgument)) { if (s_ignoredArguments.Contains(activeArgument)) { ignoredArgs.Add(activeArgument); } else if (BlameArgs.IsBlameArg(activeArgument)) { // do nothing, we process remaining arguments ourselves } else { newArgList.Add(activeArgument); } } if (blame.Blame) { blame.AddCombinedBlameArgs(newArgList); } return(newArgList); }