383 lines
16 KiB
C#
383 lines
16 KiB
C#
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
|
|
|
namespace CmdLine.Tests
|
|
{
|
|
extern alias migrate;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using Xunit;
|
|
|
|
public class CommandLineTest
|
|
{
|
|
[Fact]
|
|
public void CommandLineTokenizesQuestionMarkSwitches()
|
|
{
|
|
var args = new[] { "/?" };
|
|
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment(args);
|
|
|
|
var tokens = migrate::CmdLine.CommandLine.Tokenize();
|
|
|
|
Assert.Equal(1, migrate::CmdLine.CommandLine.Args.Length);
|
|
Assert.Equal(1, migrate::CmdLine.CommandLine.GetSwitches(tokens).Count);
|
|
Assert.Equal(0, migrate::CmdLine.CommandLine.GetParameters(tokens).Count);
|
|
Assert.True(tokens[0].IsCommand());
|
|
Assert.Equal("?", tokens[0].Command);
|
|
}
|
|
|
|
[Fact]
|
|
public void CommandLineTokenizesSwitchesAndParameters()
|
|
{
|
|
var args = new[]
|
|
{
|
|
"C:\\Foo And Bar\\Some Long File.txt", "/1:Test", "-2:Some Quoted Arg", "/3=Arg with in it", "/Y-",
|
|
"And another",
|
|
"Another", "One", "Word", "Args"
|
|
};
|
|
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment(args);
|
|
|
|
var tokens = migrate::CmdLine.CommandLine.Tokenize();
|
|
|
|
Assert.Equal(10, migrate::CmdLine.CommandLine.Args.Length);
|
|
Assert.Equal(4, migrate::CmdLine.CommandLine.GetSwitches(tokens).Count);
|
|
Assert.Equal(6, migrate::CmdLine.CommandLine.GetParameters(tokens).Count);
|
|
Assert.True(tokens[0].IsParameter());
|
|
Assert.True(tokens[1].IsCommand());
|
|
Assert.True(tokens[2].IsCommand());
|
|
Assert.True(tokens[3].IsCommand());
|
|
Assert.True(tokens[4].IsCommand());
|
|
Assert.True(tokens[5].IsParameter());
|
|
Assert.True(tokens[6].IsParameter());
|
|
Assert.True(tokens[7].IsParameter());
|
|
Assert.True(tokens[8].IsParameter());
|
|
Assert.True(tokens[9].IsParameter());
|
|
|
|
for (var i = 0; i < args.Length; i++)
|
|
{
|
|
Assert.Equal(args[i], tokens[i].Token);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ParseDoesNotThrowWhenNullCommandLine()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment();
|
|
migrate::CmdLine.CommandLine.Parse<object>();
|
|
}
|
|
|
|
[Fact]
|
|
public void MissingRequiredSwitchArgShouldThrow()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment();
|
|
Assert.Equal(
|
|
new migrate::CmdLine.CommandLineRequiredArgumentMissingException(typeof(string), "N", -1).Message,
|
|
Assert.Throws<migrate::CmdLine.CommandLineRequiredArgumentMissingException>(
|
|
() => migrate::CmdLine.CommandLine.Parse<TestArgs>()).Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void AttributeWithNoCommandNameShouldUsePropertyName()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment("/b1-");
|
|
var actual = migrate::CmdLine.CommandLine.Parse<PropWithNoCommandName>();
|
|
Assert.False(actual.b1);
|
|
}
|
|
|
|
[Fact]
|
|
public void MissingRequiredPositionArgShouldThrow()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment();
|
|
Assert.Equal(
|
|
new migrate::CmdLine.CommandLineRequiredArgumentMissingException(typeof(string), "String 1", 1).Message,
|
|
Assert.Throws<migrate::CmdLine.CommandLineRequiredArgumentMissingException>(
|
|
() => migrate::CmdLine.CommandLine.Parse<ThreeRequiredPositionArgs>()).Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void DuplicateArgsShouldThrow()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment("/N:123 /N:345");
|
|
|
|
var commandArg = new migrate::CmdLine.CommandArgument("/N:345", 7);
|
|
commandArg.Command = "N";
|
|
Assert.Equal(
|
|
new migrate::CmdLine.CommandLineArgumentInvalidException(typeof(string), commandArg).Message,
|
|
Assert.Throws<migrate::CmdLine.CommandLineArgumentInvalidException>(() => migrate::CmdLine.CommandLine.Parse<TestArgs>()).
|
|
Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void DuplicateArgsWithListShouldNotThrow()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment("/N:123 /N:345");
|
|
var actual = migrate::CmdLine.CommandLine.Parse<TestArgsWithList>();
|
|
Assert.Equal(2, actual.NList.Count);
|
|
Assert.Equal("123", actual.NList[0]);
|
|
Assert.Equal("345", actual.NList[1]);
|
|
}
|
|
|
|
[Fact]
|
|
public void DefaultArgsAreApplied()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment("/n:123");
|
|
var target = migrate::CmdLine.CommandLine.Parse<TestArgs>();
|
|
|
|
Assert.True(target.BoolT);
|
|
Assert.False(target.BoolY);
|
|
Assert.Equal(TestArgs.StringArgDefault, target.StringArg);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that you can use alternate seperators
|
|
/// </summary>
|
|
[Fact]
|
|
public void CommandLineTokenizesWithAlternateSwitchChars()
|
|
{
|
|
var args = new[]
|
|
{
|
|
"C:\\Foo And Bar\\Some Long File.txt", "~1|Test", "~2|Some Quoted Arg", "~3|Arg with in it", "_Y-",
|
|
"And another",
|
|
"Another", "One", "Word", "Args"
|
|
};
|
|
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment(args);
|
|
|
|
// Save the seperators since they are static members
|
|
var oldSep = migrate::CmdLine.CommandLine.CommandSeparators;
|
|
var oldValueSep = migrate::CmdLine.CommandLine.ValueSeparators;
|
|
|
|
migrate::CmdLine.CommandLine.CommandSeparators = new List<string>
|
|
{
|
|
"~",
|
|
"_"
|
|
};
|
|
migrate::CmdLine.CommandLine.ValueSeparators = new List<string>
|
|
{
|
|
"|"
|
|
};
|
|
|
|
var tokens = migrate::CmdLine.CommandLine.Tokenize();
|
|
|
|
// Restore the seperators
|
|
migrate::CmdLine.CommandLine.CommandSeparators = oldSep;
|
|
migrate::CmdLine.CommandLine.ValueSeparators = oldValueSep;
|
|
|
|
Assert.Equal(10, migrate::CmdLine.CommandLine.Args.Length);
|
|
Assert.Equal(4, migrate::CmdLine.CommandLine.GetSwitches(tokens).Count);
|
|
Assert.Equal(6, migrate::CmdLine.CommandLine.GetParameters(tokens).Count);
|
|
Assert.True(tokens[0].IsParameter());
|
|
Assert.True(tokens[1].IsCommand());
|
|
Assert.True(tokens[2].IsCommand());
|
|
Assert.True(tokens[3].IsCommand());
|
|
Assert.True(tokens[4].IsCommand());
|
|
Assert.True(tokens[5].IsParameter());
|
|
Assert.True(tokens[6].IsParameter());
|
|
Assert.True(tokens[7].IsParameter());
|
|
Assert.True(tokens[8].IsParameter());
|
|
Assert.True(tokens[9].IsParameter());
|
|
|
|
for (var i = 0; i < args.Length; i++)
|
|
{
|
|
Assert.Equal(args[i], tokens[i].Token);
|
|
}
|
|
}
|
|
|
|
///<summary>
|
|
/// Verifies positional args work
|
|
///</summary>
|
|
[Fact]
|
|
public void PositionalArgsAreApplied()
|
|
{
|
|
var args = new[]
|
|
{
|
|
@"D:\Documents and Settings\MY.USERNAME\My Documents\*", @"E:\MYBACKUP\My Documents\", "/A",
|
|
@"/EXCLUDE:SomeQuoted String"
|
|
, "/I", "/D:7-8-2011"
|
|
};
|
|
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment(args);
|
|
var xcopyCommand = migrate::CmdLine.CommandLine.Parse<XCopyCommandArgs>();
|
|
|
|
Assert.NotNull(xcopyCommand);
|
|
Assert.Equal(args[0], xcopyCommand.Source);
|
|
Assert.Equal(args[1], xcopyCommand.Destination);
|
|
Assert.Equal("SomeQuoted String", xcopyCommand.ExcludeFiles);
|
|
Assert.True(xcopyCommand.ArchivedBit);
|
|
Assert.True(xcopyCommand.InferDirectory);
|
|
Assert.Equal(DateTime.Parse("7-8-2011"), xcopyCommand.ChangedAfterDate);
|
|
}
|
|
|
|
[Fact]
|
|
public void EmbeddedSeparatorsDoNotCountAsSwitch()
|
|
{
|
|
var args = new[] { "/S:Value/With:Separators", "/Y-", "/t", "/N:123" };
|
|
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment(args);
|
|
|
|
var actual = migrate::CmdLine.CommandLine.Parse<TestArgs>();
|
|
|
|
Assert.Equal("Value/With:Separators", actual.StringArg);
|
|
Assert.True(actual.BoolT);
|
|
Assert.False(actual.BoolY);
|
|
}
|
|
|
|
[Fact]
|
|
public void CaseSensitiveAllowsUpperAndLowerWithSameSwitch()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment("/t:lower /T:UPPER /y /Y-");
|
|
var oldValue = migrate::CmdLine.CommandLine.CaseSensitive;
|
|
migrate::CmdLine.CommandLine.CaseSensitive = true;
|
|
|
|
var actual = migrate::CmdLine.CommandLine.Parse<TypeWithUpperAndLower>();
|
|
|
|
migrate::CmdLine.CommandLine.CaseSensitive = oldValue;
|
|
|
|
Assert.Equal("lower", actual.Lower);
|
|
Assert.Equal("UPPER", actual.Upper);
|
|
Assert.True(actual.YLower);
|
|
Assert.False(actual.YUpper);
|
|
}
|
|
|
|
[Fact]
|
|
public void NoMatchingPropertyShouldThrow()
|
|
{
|
|
var args = new[] { "/?" };
|
|
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment(args);
|
|
|
|
try
|
|
{
|
|
migrate::CmdLine.CommandLine.Parse<TestArgs>();
|
|
Assert.True(false, "Parse did not throw an exception");
|
|
}
|
|
catch (migrate::CmdLine.CommandLineArgumentInvalidException exception)
|
|
{
|
|
Assert.NotNull(exception.ArgumentHelp);
|
|
Assert.Equal(4, exception.ArgumentHelp.ValidArguments.Count());
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void NoMatchingPropertyWithInferredShouldThrow()
|
|
{
|
|
var args = new[] { "/NoMatch" };
|
|
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment(args);
|
|
|
|
var commandArg = new migrate::CmdLine.CommandArgument("/NoMatch", 0);
|
|
commandArg.Command = "NoMatch";
|
|
Assert.Equal(
|
|
new migrate::CmdLine.CommandLineArgumentInvalidException(typeof(string), commandArg).Message,
|
|
Assert.Throws<migrate::CmdLine.CommandLineArgumentInvalidException>(
|
|
() => migrate::CmdLine.CommandLine.Parse<InferredTestArgs>()).Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void TwoPropsWithSameSwitchShouldThrow()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment();
|
|
Assert.Equal(
|
|
new migrate::CmdLine.CommandLineException("Duplicate Command \"B\"").Message,
|
|
Assert.Throws<migrate::CmdLine.CommandLineException>(() => migrate::CmdLine.CommandLine.Parse<TwoPropsWithSameSwitch>()).
|
|
Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void WhenNoAttributesParseWillUsePropertyNames()
|
|
{
|
|
var args = new[] { "/StringArg:Value/With:Separators", "/BoolY-", "/BoolT", "/Date:12-1-2011", "/Number:23" };
|
|
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment(args);
|
|
|
|
var actual = migrate::CmdLine.CommandLine.Parse<InferredTestArgs>();
|
|
|
|
Assert.Equal("Value/With:Separators", actual.StringArg);
|
|
Assert.True(actual.BoolT);
|
|
Assert.False(actual.BoolY);
|
|
Assert.Equal(DateTime.Parse("12-1-2011"), actual.Date);
|
|
Assert.Equal(23, actual.Number);
|
|
}
|
|
|
|
[Fact]
|
|
public void WhenNoPositionOneShouldThrow()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment();
|
|
Assert.Equal(
|
|
new migrate::CmdLine.CommandLineException(
|
|
"Out of order parameter \"source\" should have be at parameter index 1 but was found at 2").Message,
|
|
Assert.Throws<migrate::CmdLine.CommandLineException>(() => migrate::CmdLine.CommandLine.Parse<BadPositionArgNoOne>()).
|
|
Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void WhenNoPositionTwoShouldThrow()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment();
|
|
Assert.Equal(
|
|
new migrate::CmdLine.CommandLineException(
|
|
"Out of order parameter \"destination\" should have be at parameter index 2 but was found at 3").
|
|
Message,
|
|
Assert.Throws<migrate::CmdLine.CommandLineException>(() => migrate::CmdLine.CommandLine.Parse<BadPositionArgMissingTwo>()).
|
|
Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void WhenDuplicatePositionShouldThrow()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment();
|
|
Assert.Equal(
|
|
new migrate::CmdLine.CommandLineException("Duplicate Parameter Index [1] on Property \"S2\"").Message,
|
|
Assert.Throws<migrate::CmdLine.CommandLineException>(
|
|
() => migrate::CmdLine.CommandLine.Parse<TypeWithDuplicateParamIndex>()).Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void WhenBadParameterIndexShouldThrow()
|
|
{
|
|
migrate::CmdLine.CommandLine.CommandEnvironment = new TestCommandEnvironment();
|
|
Assert.Equal(
|
|
new CustomAttributeFormatException("'ParameterIndex' property specified was not found.").Message,
|
|
Assert.Throws<CustomAttributeFormatException>(() => migrate::CmdLine.CommandLine.Parse<TypeWithBadParamIndex>()).Message);
|
|
}
|
|
}
|
|
|
|
public class TestArgsWithList
|
|
{
|
|
[migrate::CmdLine.CommandLineParameterAttribute(Command = "N")]
|
|
public List<string> NList { get; set; }
|
|
}
|
|
|
|
public class TypeWithUpperAndLower
|
|
{
|
|
[migrate::CmdLine.CommandLineParameterAttribute("t")]
|
|
public string Lower { get; set; }
|
|
|
|
[migrate::CmdLine.CommandLineParameterAttribute("T")]
|
|
public string Upper { get; set; }
|
|
|
|
[migrate::CmdLine.CommandLineParameterAttribute("y")]
|
|
public bool YLower { get; set; }
|
|
|
|
[migrate::CmdLine.CommandLineParameterAttribute("Y")]
|
|
public bool YUpper { get; set; }
|
|
}
|
|
|
|
public class TypeWithBadParamIndex
|
|
{
|
|
[migrate::CmdLine.CommandLineParameterAttribute(ParameterIndex = -1)]
|
|
public string S1 { get; set; }
|
|
}
|
|
|
|
public class TypeWithDuplicateParamIndex
|
|
{
|
|
[migrate::CmdLine.CommandLineParameterAttribute(ParameterIndex = 1)]
|
|
public string S1 { get; set; }
|
|
|
|
[migrate::CmdLine.CommandLineParameterAttribute(ParameterIndex = 1)]
|
|
public string S2 { get; set; }
|
|
}
|
|
}
|