├── src
├── Testee
│ ├── paket.references
│ ├── App.config
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Program.cs
│ └── Testee.csproj
├── DocoptNet.Tests
│ ├── paket.references
│ ├── app.config
│ ├── DocoptNet.Tests.csproj.DotSettings
│ ├── OptionNameTests.cs
│ ├── Assumptions.cs
│ ├── StringPartitionTests.cs
│ ├── PatternFlatTests.cs
│ ├── DocoptNet.Tests.csproj
│ ├── ParseDefaultsTests.cs
│ ├── PatternFixIdentitiesTests.cs
│ ├── ShortOptionsErrorHandlingTests.cs
│ ├── AnyOptionsParameterTests.cs
│ ├── PatternFixRepeatingArgumentsTests.cs
│ ├── GenerateCodeHelperTest.cs
│ ├── DefaultValueForPositionalArgumentsTests.cs
│ ├── OptionsFirstTests.cs
│ ├── RequiredMatchTests.cs
│ ├── ArgumentMatchTests.cs
│ ├── CommandMatchTests.cs
│ ├── UsageTests.cs
│ ├── LongOptionsErrorHandlingTests.cs
│ ├── ListArgumentMatchTests.cs
│ ├── BasicPatternMatchingTests.cs
│ ├── OptionMatchTests.cs
│ ├── LanguageAgnosticTests.cs
│ ├── EitherMatchTests.cs
│ ├── OptionParseTests.cs
│ ├── PatterEitherTests.cs
│ ├── GenerateCodeTests.cs
│ ├── CommandsTests.cs
│ ├── SyntaxTests.cs
│ ├── CountMultipleFlagsTests.cs
│ ├── OptionalMatchTests.cs
│ ├── ParseArgvTests.cs
│ ├── GetNodesTests.cs
│ ├── OneOrMoreMatchTests.cs
│ ├── ParsePatternTests.cs
│ ├── DocoptTests.cs
│ └── ValueObjectTests.cs
├── DocoptNet
│ ├── DocoptNet.snk
│ ├── DocoptNet.publickey
│ ├── OptionsShortcut.cs
│ ├── GenerateCodeHelper.cs
│ ├── Optional.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Required.cs
│ ├── Either.cs
│ ├── DocoptExitException.cs
│ ├── DocoptLanguageErrorException.cs
│ ├── DocoptInputErrorException.cs
│ ├── Command.cs
│ ├── DocoptBaseException.cs
│ ├── BranchPattern.cs
│ ├── OneOrMore.cs
│ ├── StringPartition.cs
│ ├── MatchResult.cs
│ ├── Argument.cs
│ ├── Tokens.cs
│ ├── Node.cs
│ ├── LeafPattern.cs
│ ├── Option.cs
│ ├── DocoptNet.csproj
│ ├── ValueObject.cs
│ └── Pattern.cs
├── Examples
│ └── NavalFate
│ │ ├── App.config
│ │ ├── Program.cs
│ │ ├── Properties
│ │ └── AssemblyInfo.cs
│ │ └── NavalFate.csproj
├── T4DocoptNetHostApp
│ ├── Another.usage.txt
│ ├── App.config
│ ├── Program.cs
│ ├── Main.usage.txt
│ ├── T4DocoptNet.tt.hooks.t4
│ ├── T4DocoptNet.tt.settings.xml
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── T4DocoptNet.cs
│ ├── T4DocoptNet.tt
│ └── T4DocoptNetHostApp.csproj
├── LanguageAgnosticTests
│ ├── README.md
│ ├── generate_tests.py
│ ├── language_agnostic_tester.py
│ └── testcases.docopt
├── NuGet
│ ├── Main.usage.txt
│ └── install.ps1
└── DocoptNet.sln
├── .paket
├── paket.bootstrapper.exe
└── paket.targets
├── paket.dependencies
├── appveyor.yml
├── .gitignore
├── paket.lock
├── .gitattributes
└── LICENSE-MIT
/src/Testee/paket.references:
--------------------------------------------------------------------------------
1 | Newtonsoft.Json
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/paket.references:
--------------------------------------------------------------------------------
1 | Newtonsoft.Json
2 | NSubstitute
3 | NUnit
--------------------------------------------------------------------------------
/src/DocoptNet/DocoptNet.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/docopt.net/master/src/DocoptNet/DocoptNet.snk
--------------------------------------------------------------------------------
/.paket/paket.bootstrapper.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/docopt.net/master/.paket/paket.bootstrapper.exe
--------------------------------------------------------------------------------
/src/DocoptNet/DocoptNet.publickey:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baruchiro/docopt.net/master/src/DocoptNet/DocoptNet.publickey
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/Testee/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/Examples/NavalFate/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/T4DocoptNetHostApp/Another.usage.txt:
--------------------------------------------------------------------------------
1 | Test host app for T4 Docopt.NET
2 |
3 | Usage:
4 | other command1 ARG [-o --long=ARG --switch -v]
5 | other command2
6 |
7 | Options:
8 | -o A string with some double "quotes".
9 |
--------------------------------------------------------------------------------
/src/T4DocoptNetHostApp/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/paket.dependencies:
--------------------------------------------------------------------------------
1 | source https://www.nuget.org/api/v2/
2 |
3 | nuget NuGet.CommandLine
4 | nuget Newtonsoft.Json
5 | nuget NSubstitute
6 | nuget NUnit
7 |
8 | group Build
9 | source https://www.nuget.org/api/v2/
10 | nuget NUnit.Runners
11 | nuget MSBuildTasks
--------------------------------------------------------------------------------
/src/DocoptNet/OptionsShortcut.cs:
--------------------------------------------------------------------------------
1 | namespace DocoptNet
2 | {
3 | ///
4 | /// Marker/placeholder for [options] shortcut.
5 | ///
6 | internal class OptionsShortcut : Optional
7 | {
8 | public OptionsShortcut() : base(new Pattern[0])
9 | {
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/T4DocoptNetHostApp/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace T4DocoptNetHostApp
4 | {
5 | class Program
6 | {
7 | static void Main(string[] args)
8 | {
9 | var mainArgs = new MainArgs(args);
10 | if (mainArgs.CmdCommand)
11 | Console.WriteLine("First command");
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.1.{build}
2 | image: Visual Studio 2017 Preview
3 | configuration: Release
4 | build_script:
5 | - cmd: dotnet build src\DocoptNet.sln --configuration Release
6 | - cmd: IF NOT EXIST dist MKDIR dist
7 | - cmd: dotnet pack --configuration Release src\DocoptNet
8 | test_script:
9 | - cmd: dotnet test src\DocoptNet.Tests
10 | artifacts:
11 | - path: '**\docopt.net*.nupkg'
12 | name: Nuget
13 |
--------------------------------------------------------------------------------
/src/T4DocoptNetHostApp/Main.usage.txt:
--------------------------------------------------------------------------------
1 | Test host app for T4 Docopt.NET
2 |
3 | Usage:
4 | prog command ARG [OPTIONALARG] [-o -s= --long=ARG --switch]
5 | prog files FILE...
6 |
7 | Options:
8 | -o Short switch.
9 | -s= Short option with arg.
10 | --long=ARG Long option with arg.
11 | --switch Long switch.
12 |
13 | Explanation:
14 | This is a test usage file.
15 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Thumbs.db
2 | *.obj
3 | *.exe
4 | *.pdb
5 | *.user
6 | *.aps
7 | *.pch
8 | *.vspscc
9 | *_i.c
10 | *_p.c
11 | *.ncb
12 | *.suo
13 | *.sln.docstates
14 | *.tlb
15 | *.tlh
16 | *.bak
17 | *.cache
18 | *.ilk
19 | *.log
20 | [Bb]in
21 | [Dd]ebug*/
22 | *.lib
23 | *.sbr
24 | obj/
25 | [Rr]elease*/
26 | _ReSharper*/
27 | [Tt]est[Rr]esult*
28 | packages/
29 | *.nupkg
30 | /_build
31 | .vs/
32 | .paket/Paket.Restore.targets
33 |
--------------------------------------------------------------------------------
/paket.lock:
--------------------------------------------------------------------------------
1 | NUGET
2 | remote: https://www.nuget.org/api/v2
3 | specs:
4 | FSharp.TypeProviders.StarterPack (1.1.3.56) - framework: >= net35
5 | Newtonsoft.Json (5.0.5)
6 | NSubstitute (1.6.1) - framework: >= net40
7 | NuGet.CommandLine (3.3)
8 | NUnit (2.6.2) - framework: >= net40
9 |
10 | GROUP Build
11 | NUGET
12 | remote: https://www.nuget.org/api/v2
13 | specs:
14 | MSBuildTasks (1.4.0.61)
15 | NUnit.Runners (2.6.2)
16 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/DocoptNet.Tests.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | CSharp40
--------------------------------------------------------------------------------
/src/T4DocoptNetHostApp/T4DocoptNet.tt.hooks.t4:
--------------------------------------------------------------------------------
1 | <#+
2 | /*
3 |
4 | This file contains hooks and extra code used by T4DocoptNet.tt. The main goal is to avoid the need for users
5 | to fork the 'official' template in order to achieve what they want.
6 |
7 | */
8 |
9 | void RenderAdditionalCode() {
10 | #>
11 | [GeneratedCode("T4DocoptNet", "2.0"), DebuggerNonUserCode]
12 | internal static class T4DocoptNetHelpers {
13 | // TODO
14 | }
15 |
16 | <#+
17 | }
18 | #>
19 |
--------------------------------------------------------------------------------
/src/T4DocoptNetHostApp/T4DocoptNet.tt.settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | T4DocoptNet
5 |
6 | Args
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/LanguageAgnosticTests/README.md:
--------------------------------------------------------------------------------
1 | Language Agnostic Tests
2 | =======================
3 |
4 | Method 1: testee app
5 | --------------------
6 | 1. Compile the Testee project
7 | 2. Run the following commands
8 | cd src\LanguageAgnosticTests
9 | python language_agnostic_tester.py ..\Testee\bin\Debug\Testee.exe
10 |
11 | Method 2: generated unit tests
12 | ------------------------------
13 |
14 | 1. Generate the tests
15 | cd src\LanguageAgnosticTests
16 | generate_tests >..\DocoptNet.Tests\LanguageAgnosticTests.generated.cs
17 | 2. Run all the unit tests
18 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/OptionNameTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class OptionNameTests
7 | {
8 | [Test]
9 | public void Short_only()
10 | {
11 | Assert.AreEqual("-h", new Option("-h", null).Name);
12 | }
13 |
14 | [Test]
15 | public void Short_and_long()
16 | {
17 | Assert.AreEqual("--help", new Option("-h", "--help").Name);
18 | }
19 |
20 | [Test]
21 | public void Long_only()
22 | {
23 | Assert.AreEqual("--help", new Option(null, "--help").Name);
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/src/DocoptNet/GenerateCodeHelper.cs:
--------------------------------------------------------------------------------
1 | namespace DocoptNet
2 | {
3 | public static class GenerateCodeHelper
4 | {
5 | public static string ConvertDashesToCamelCase(string s)
6 | {
7 | // Start with uppercase char
8 | var makeUpperCase = true;
9 | var result = "";
10 | for (int i = 0; i < s.Length; i++)
11 | {
12 | if(s[i] == '-')
13 | {
14 | makeUpperCase = true;
15 | continue;
16 | }
17 |
18 | result += makeUpperCase ? char.ToUpperInvariant(s[i]) : s[i];
19 | makeUpperCase = false;
20 | }
21 |
22 | return result;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/Assumptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using NUnit.Framework;
3 |
4 | namespace DocoptNet.Tests
5 | {
6 | ///
7 | /// Set of tests to validate assumptions about the BCL or other APIs.
8 | ///
9 | [TestFixture]
10 | public class Assumptions
11 | {
12 | [Test]
13 | public void String_Split_with_no_args_should_split_on_white_space()
14 | {
15 | const string TEST_STRING = "first second\tthird\nfourth \n\t\ffifth";
16 | var s1 = TEST_STRING.Split();
17 | Assert.AreEqual(8, s1.Length);
18 | var s2 = TEST_STRING.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
19 | Assert.AreEqual(5, s2.Length);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/src/DocoptNet/Optional.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace DocoptNet
4 | {
5 | internal class Optional : BranchPattern
6 | {
7 | public Optional(params Pattern[] patterns) : base(patterns)
8 | {
9 |
10 | }
11 |
12 | public override MatchResult Match(IList left, IEnumerable collected = null)
13 | {
14 | var c = collected ?? new List();
15 | var l = left;
16 | foreach (var pattern in Children)
17 | {
18 | var res = pattern.Match(l, c);
19 | l = res.Left;
20 | c = res.Collected;
21 | }
22 | return new MatchResult(true, l, c);
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/StringPartitionTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class StringPartitionTests
7 | {
8 | [Test]
9 | public void Should_partition_string()
10 | {
11 | var p = new StringPartition("left=right", "=");
12 | Assert.AreEqual("left", p.LeftString);
13 | Assert.AreEqual("=", p.Separator);
14 | Assert.AreEqual("right", p.RightString);
15 | }
16 |
17 | [Test]
18 | public void Should_partition_string_no_sep_match()
19 | {
20 | var p = new StringPartition("left", "=");
21 | Assert.AreEqual("left", p.LeftString);
22 | Assert.AreEqual("", p.Separator);
23 | Assert.AreEqual("", p.RightString);
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/PatternFlatTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class PatternFlatTests
7 | {
8 | [Test]
9 | public void Should_flatten_all_types()
10 | {
11 | Assert.AreEqual(
12 | new Pattern[] {new Argument("N"), new Option("-a"), new Argument("M")},
13 | new Required(new OneOrMore(new Argument("N")),
14 | new Option("-a"), new Argument("M")).Flat());
15 | }
16 |
17 | [Test]
18 | public void Should_flatten_specific_type()
19 | {
20 | Assert.AreEqual(
21 | new Pattern[] {new OptionsShortcut()},
22 | new Required(new Optional(new OptionsShortcut()),
23 | new Optional(new Option("-a"))).Flat());
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/src/DocoptNet/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // Setting ComVisible to false makes the types in this assembly not visible
6 | // to COM components. If you need to access a type in this assembly from
7 | // COM, set the ComVisible attribute to true on that type.
8 | [assembly: ComVisible(false)]
9 |
10 | // The following GUID is for the ID of the typelib if this project is exposed to COM
11 | [assembly: Guid("fba1ac90-b7b0-483a-b881-a8e8b6566765")]
12 |
13 | [assembly: InternalsVisibleTo("DocoptNet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100915abcad70deeb2af0f6424bf23227473e27c84df5e57319274e9c8f5dba27363c2a6d93fa4883dbbc0a3bf18cdba7b677b9d02fa8ab885ca01adc30be2eec9d00e0655e7e1da16c307e2f3dfd95ad84e85b28765de915f2da1dc8d5f9f359614f2ee7838823a4a0cca9fd3d9425b231dabae00f46fbebcf5b5d6a0f5126efb5")]
14 |
--------------------------------------------------------------------------------
/src/DocoptNet/Required.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace DocoptNet
4 | {
5 | internal class Required : BranchPattern
6 | {
7 | public Required(params Pattern[] patterns)
8 | : base(patterns)
9 | {
10 | }
11 |
12 | public override MatchResult Match(IList left,
13 | IEnumerable collected = null)
14 | {
15 | var coll = collected ?? new List();
16 | var l = left;
17 | var c = coll;
18 | foreach (var pattern in Children)
19 | {
20 | var res = pattern.Match(l, c);
21 | l = res.Left;
22 | c = res.Collected;
23 | if (!res.Matched)
24 | return new MatchResult(false, left, coll);
25 | }
26 | return new MatchResult(true, l, c);
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/src/DocoptNet/Either.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace DocoptNet
5 | {
6 | internal class Either : BranchPattern
7 | {
8 | public Either(params Pattern[] patterns) : base(patterns)
9 | {
10 | }
11 |
12 | public override MatchResult Match(IList left, IEnumerable collected = null)
13 | {
14 | var coll = collected ?? new List();
15 | var outcomes =
16 | Children.Select(pattern => pattern.Match(left, coll))
17 | .Where(outcome => outcome.Matched)
18 | .ToList();
19 | if (outcomes.Count != 0)
20 | {
21 | var minCount = outcomes.Min(x => x.Left.Count);
22 | return outcomes.First(x => x.Left.Count == minCount);
23 | }
24 | return new MatchResult(false, left, coll);
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/DocoptNet.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp1.1;netcoreapp2.1;net47
5 | ..\DocoptNet\DocoptNet.snk
6 | true
7 | true
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/ParseDefaultsTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class ParseDefaultsTests
7 | {
8 | [Test]
9 | public void Test_parse_defaults()
10 | {
11 | const string DOC = @"usage: prog
12 | Options:
13 | -h, --help Print help message.
14 | -o FILE Output file.
15 | --verbose Verbose mode.
16 | ";
17 |
18 | var expected = new Option[]
19 | {new Option("-h", "--help"), new Option("-o", null, 1), new Option(null, "--verbose")};
20 | Assert.AreEqual(expected, Docopt.ParseDefaults(DOC));
21 | }
22 |
23 | [Test]
24 | public void Test_issue_126_defaults_not_parsed_correctly_when_tabs()
25 | {
26 | const string section = "Options:\n\t--foo= [default: bar]";
27 | var expected = new Option[] { new Option(null, "--foo", 1, "bar")};
28 | Assert.AreEqual(expected, Docopt.ParseDefaults(section));
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/PatternFixIdentitiesTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class PatternFixIdentitiesTests
7 | {
8 | [Test]
9 | public void Should_fix_all_args()
10 | {
11 | var pattern = new Required(new Argument("N"), new Argument("N"));
12 | Assert.AreEqual(pattern.Children[0], pattern.Children[1]);
13 | Assert.AreNotSame(pattern.Children[0], pattern.Children[1]);
14 | pattern.FixIdentities();
15 | Assert.AreSame(pattern.Children[0], pattern.Children[1]);
16 | }
17 |
18 | [Test]
19 | public void Should_fix_some_args()
20 | {
21 | var pattern = new Required(new Optional(new Argument("X"), new Argument("N")), new Argument("N"));
22 | Assert.AreEqual(pattern.Children[0].Children[1], pattern.Children[1]);
23 | Assert.AreNotSame(pattern.Children[0].Children[1], pattern.Children[1]);
24 | pattern.FixIdentities();
25 | Assert.AreSame(pattern.Children[0].Children[1], pattern.Children[1]);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/ShortOptionsErrorHandlingTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class ShortOptionsErrorHandlingTests
7 | {
8 | [Test]
9 | public void Duplicate()
10 | {
11 | Assert.Throws(
12 | () => new Docopt().Apply("Usage: prog -x\nOptions: -x this\n -x that"));
13 | }
14 |
15 | [Test]
16 | public void Non_existent()
17 | {
18 | Assert.Throws(
19 | () => new Docopt().Apply("Usage: prog", "-x"));
20 | }
21 |
22 | [Test]
23 | public void Wrong_opt_with_arg_spec()
24 | {
25 | Assert.Throws(
26 | () => new Docopt().Apply("Usage: prog -o\nOptions: -o ARG"));
27 | }
28 |
29 | [Test]
30 | public void Wrong_missing_arg()
31 | {
32 | Assert.Throws(
33 | () => new Docopt().Apply("Usage: prog -o ARG\nOptions: -o ARG", "-o"));
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/src/DocoptNet/DocoptExitException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #if NET40
3 | using System.Runtime.Serialization;
4 | #endif
5 |
6 | namespace DocoptNet
7 | {
8 | #if NET40
9 | [Serializable]
10 | #endif
11 | public class DocoptExitException : DocoptBaseException
12 | {
13 | //
14 | // For guidelines regarding the creation of new exception types, see
15 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
16 | // and
17 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp
18 | //
19 |
20 | public DocoptExitException()
21 | {
22 | }
23 | public DocoptExitException(string message) : base(message)
24 | {
25 | }
26 | public DocoptExitException(string message, Exception inner) : base(message, inner)
27 | {
28 | }
29 | #if NET40
30 | protected DocoptExitException(
31 | SerializationInfo info,
32 | StreamingContext context) : base(info, context)
33 | {
34 | }
35 | #endif
36 | }
37 | }
--------------------------------------------------------------------------------
/src/NuGet/Main.usage.txt:
--------------------------------------------------------------------------------
1 | Example usage for T4 Docopt.NET
2 |
3 | Usage:
4 | prog command ARG [OPTIONALARG] [-o -s= --long=ARG --switch]
5 | prog files FILE...
6 |
7 | Options:
8 | -o Short switch.
9 | -s= Short option with arg.
10 | --long=ARG Long option with arg.
11 | --switch Long switch.
12 |
13 | Explanation:
14 | This is an example usage file that needs to be customized.
15 | Every time you change this file, run the Custom Tool command
16 | on T4DocoptNet.tt to re-generate the MainArgs class
17 | (defined in T4DocoptNet.cs).
18 | You can then use the MainArgs classed as follows:
19 |
20 | class Program
21 | {
22 |
23 | static void DoStuff(string arg, bool flagO, string longValue)
24 | {
25 | // ...
26 | }
27 |
28 | static void Main(string[] argv)
29 | {
30 | // Automatically exit(1) if invalid arguments
31 | var args = new MainArgs(argv, exit: true);
32 | if (args.CmdCommand)
33 | {
34 | Console.WriteLine("First command");
35 | DoStuff(args.ArgArg, args.OptO, args.OptLong);
36 | }
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/src/DocoptNet/DocoptLanguageErrorException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #if NET40
3 | using System.Runtime.Serialization;
4 | #endif
5 |
6 | namespace DocoptNet
7 | {
8 | #if NET40
9 | [Serializable]
10 | #endif
11 | public class DocoptLanguageErrorException : DocoptBaseException
12 | {
13 | //
14 | // For guidelines regarding the creation of new exception types, see
15 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
16 | // and
17 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp
18 | //
19 |
20 | public DocoptLanguageErrorException()
21 | {
22 | }
23 | public DocoptLanguageErrorException(string message) : base(message)
24 | {
25 | }
26 | public DocoptLanguageErrorException(string message, Exception inner) : base(message, inner)
27 | {
28 | }
29 | #if NET40
30 | protected DocoptLanguageErrorException(
31 | SerializationInfo info,
32 | StreamingContext context) : base(info, context)
33 | {
34 | }
35 | #endif
36 | }
37 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/AnyOptionsParameterTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class AnyOptionsParameterTests
7 | {
8 | [Test]
9 | public void Error_long_with_arg()
10 | {
11 | Assert.Throws(
12 | () => new Docopt().Apply("usage: prog [options]", "-foo --bar --spam=eggs"));
13 |
14 | }
15 |
16 | [Test]
17 | public void Error_all_long()
18 | {
19 | Assert.Throws(
20 | () => new Docopt().Apply("usage: prog [options]", "--foo --bar --bar"));
21 |
22 | }
23 |
24 | [Test]
25 | public void Error_short_acc()
26 | {
27 | Assert.Throws(
28 | () => new Docopt().Apply("usage: prog [options]", "--bar --bar --bar -ffff"));
29 |
30 | }
31 |
32 | [Test]
33 | public void Error_all_long_with_arg()
34 | {
35 | Assert.Throws(
36 | () => new Docopt().Apply("usage: prog [options]", "--long=arg --long=another"));
37 |
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 Vladimir Keleshev,
2 | Dinh Doan Van Bien,
3 |
4 | Permission is hereby granted, free of charge, to any person
5 | obtaining a copy of this software and associated
6 | documentation files (the "Software"), to deal in the Software
7 | without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense,
9 | and/or sell copies of the Software, and to permit persons to
10 | whom the Software is furnished to do so, subject to the
11 | following conditions:
12 |
13 | The above copyright notice and this permission notice shall
14 | be included in all copies or substantial portions of the
15 | Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
18 | KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
19 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
20 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
21 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 |
--------------------------------------------------------------------------------
/src/DocoptNet/DocoptInputErrorException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #if NET40
3 | using System.Runtime.Serialization;
4 | #endif
5 |
6 | namespace DocoptNet
7 | {
8 | #if NET40
9 | [Serializable]
10 | #endif
11 | public class DocoptInputErrorException : DocoptBaseException
12 | {
13 | //
14 | // For guidelines regarding the creation of new exception types, see
15 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
16 | // and
17 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp
18 | //
19 |
20 | public DocoptInputErrorException()
21 | {
22 | }
23 | public DocoptInputErrorException(string message)
24 | : base(message)
25 | {
26 | }
27 | public DocoptInputErrorException(string message, Exception inner)
28 | : base(message, inner)
29 | {
30 | }
31 | #if NET40
32 | protected DocoptInputErrorException(
33 | SerializationInfo info,
34 | StreamingContext context)
35 | : base(info, context)
36 | {
37 | }
38 | #endif
39 | }
40 | }
--------------------------------------------------------------------------------
/src/DocoptNet/Command.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace DocoptNet
4 | {
5 | internal class Command : Argument
6 | {
7 | public Command(string name, ValueObject value = null) : base(name, value ?? new ValueObject(false))
8 | {
9 | }
10 |
11 | public override SingleMatchResult SingleMatch(IList left)
12 | {
13 | for (var i = 0; i < left.Count; i++)
14 | {
15 | var pattern = left[i];
16 | if (pattern is Argument)
17 | {
18 | if (pattern.Value.ToString() == Name)
19 | return new SingleMatchResult(i, new Command(Name, new ValueObject(true)));
20 | break;
21 | }
22 | }
23 | return new SingleMatchResult();
24 | }
25 |
26 | public override Node ToNode() { return new CommandNode(this.Name); }
27 |
28 | public override string GenerateCode()
29 | {
30 | var s = Name.ToLowerInvariant();
31 | s = "Cmd" + GenerateCodeHelper.ConvertDashesToCamelCase(s);
32 | return string.Format("public bool {0} {{ get {{ return _args[\"{1}\"].IsTrue; }} }}", s, Name);
33 | }
34 |
35 | }
36 | }
--------------------------------------------------------------------------------
/src/DocoptNet/DocoptBaseException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | #if NET40
3 | using System.Runtime.Serialization;
4 | #endif
5 |
6 | namespace DocoptNet
7 | {
8 | #if NET40
9 | [Serializable]
10 | #endif
11 | public class DocoptBaseException : Exception
12 | {
13 | //
14 | // For guidelines regarding the creation of new exception types, see
15 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
16 | // and
17 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp
18 | //
19 |
20 | public DocoptBaseException()
21 | {
22 | }
23 |
24 | public DocoptBaseException(string message)
25 | : base(message)
26 | {
27 | }
28 |
29 | public DocoptBaseException(string message, Exception inner)
30 | : base(message, inner)
31 | {
32 | }
33 |
34 | #if NET40
35 | protected DocoptBaseException(
36 | SerializationInfo info,
37 | StreamingContext context)
38 | : base(info, context)
39 | {
40 | }
41 | #endif
42 |
43 | public int ErrorCode
44 | {
45 | get { return 1; }
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/src/Examples/NavalFate/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DocoptNet;
3 |
4 | namespace NavalFate
5 | {
6 | internal class Program
7 | {
8 | private const string usage = @"Naval Fate.
9 |
10 | Usage:
11 | naval_fate.exe ship new ...
12 | naval_fate.exe ship move [--speed=]
13 | naval_fate.exe ship shoot
14 | naval_fate.exe mine (set|remove) [--moored | --drifting]
15 | naval_fate.exe (-h | --help)
16 | naval_fate.exe --version
17 |
18 | Options:
19 | -h --help Show this screen.
20 | --version Show version.
21 | --speed= Speed in knots [default: 10].
22 | --moored Moored (anchored) mine.
23 | --drifting Drifting mine.
24 |
25 | ";
26 |
27 | private static void Main(string[] args)
28 | {
29 | try
30 | {
31 | var arguments = new Docopt().Apply(usage, args, version: "Naval Fate 2.0", exit: true);
32 | foreach (var argument in arguments)
33 | {
34 | Console.WriteLine("{0} = {1}", argument.Key, argument.Value);
35 | }
36 | }
37 | catch (Exception e)
38 | {
39 | Console.WriteLine(e.Message);
40 | }
41 | }
42 |
43 | }
44 | }
--------------------------------------------------------------------------------
/src/DocoptNet/BranchPattern.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 |
6 | namespace DocoptNet
7 | {
8 | ///
9 | /// Branch/inner node of a pattern tree.
10 | ///
11 | internal class BranchPattern : Pattern
12 | {
13 |
14 | public BranchPattern(params Pattern[] children)
15 | {
16 | if (children == null) throw new ArgumentNullException("children");
17 | Children = children;
18 | }
19 |
20 | public override bool HasChildren { get { return true; } }
21 |
22 | public IEnumerable Flat() where T: Pattern
23 | {
24 | return Flat(typeof (T));
25 | }
26 |
27 | public override ICollection Flat(params Type[] types)
28 | {
29 | if (types == null) throw new ArgumentNullException("types");
30 | if (types.Contains(this.GetType()))
31 | {
32 | return new Pattern[] { this };
33 | }
34 | return Children.SelectMany(child => child.Flat(types)).ToList();
35 | }
36 |
37 | public override string ToString()
38 | {
39 | return string.Format("{0}({1})", GetType().Name, String.Join(", ", Children.Select(c => c == null ? "None" : c.ToString())));
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/DocoptNet/OneOrMore.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics;
3 |
4 | namespace DocoptNet
5 | {
6 | internal class OneOrMore : BranchPattern
7 | {
8 | public OneOrMore(params Pattern[] patterns)
9 | : base(patterns)
10 | {
11 | }
12 |
13 | public override MatchResult Match(IList left, IEnumerable collected = null)
14 | {
15 | Debug.Assert(Children.Count == 1);
16 | var coll = collected ?? new List();
17 | var l = left;
18 | var c = coll;
19 | IList l_ = null;
20 | var matched = true;
21 | var times = 0;
22 | while (matched)
23 | {
24 | // could it be that something didn't match but changed l or c?
25 | var res = Children[0].Match(l, c);
26 | matched = res.Matched;
27 | l = res.Left;
28 | c = res.Collected;
29 | times += matched ? 1 : 0;
30 | if (l_ != null && l_.Equals(l))
31 | break;
32 | l_ = l;
33 | }
34 | if (times >= 1)
35 | {
36 | return new MatchResult(true, l, c);
37 | }
38 | return new MatchResult(false, left, coll);
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/src/DocoptNet/StringPartition.cs:
--------------------------------------------------------------------------------
1 | namespace DocoptNet
2 | {
3 | public struct StringPartition
4 | {
5 | public string LeftString;
6 | public string Separator;
7 | public string RightString;
8 |
9 | ///
10 | /// Split the at the first occurrence of , and stores the part before the separator,
11 | /// the separator itself, and the part after the separator. If the separator is not found, stores the string itself, and
12 | /// two empty strings.
13 | ///
14 | ///
15 | ///
16 | public StringPartition(string stringToPartition, string separator)
17 | {
18 | LeftString = stringToPartition;
19 | Separator = "";
20 | RightString = "";
21 |
22 | var i = stringToPartition.IndexOf(separator, System.StringComparison.Ordinal);
23 | if (i > 0)
24 | {
25 | LeftString = stringToPartition.Substring(0, i);
26 | Separator = separator;
27 | RightString = stringToPartition.Substring(i + separator.Length);
28 | }
29 | }
30 |
31 | public bool NoSeparatorFound
32 | {
33 | get { return Separator=="" && RightString == ""; }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/PatternFixRepeatingArgumentsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using NUnit.Framework;
3 |
4 | namespace DocoptNet.Tests
5 | {
6 | [TestFixture]
7 | public class PatternFixRepeatingArgumentsTests
8 | {
9 | [Test]
10 | public void Should_fix_option()
11 | {
12 | Assert.AreEqual(
13 | new Option("-a"),
14 | new Option("-a").FixRepeatingArguments()
15 | );
16 | }
17 |
18 | [Test]
19 | public void Should_fix_arg()
20 | {
21 | Assert.AreEqual(
22 | new Argument("A"),
23 | new Argument("A").FixRepeatingArguments()
24 | );
25 | }
26 |
27 | [Test]
28 | public void Should_fix_required_args()
29 | {
30 | Assert.AreEqual(
31 | new Required(new Argument("N", new ArrayList()), new Argument("N", new ArrayList())),
32 | new Required(new Argument("N"), new Argument("N")).FixRepeatingArguments()
33 | );
34 | }
35 |
36 | [Test]
37 | public void Should_fix_either_args()
38 | {
39 | Assert.AreEqual(
40 | new Either(new Argument("N", new ArrayList()),
41 | new OneOrMore(new Argument("N", new ArrayList()))),
42 | new Either(new Argument("N"), new OneOrMore(new Argument("N"))).Fix()
43 | );
44 | }
45 | }
46 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/GenerateCodeHelperTest.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class GenerateCodeHelperTest
7 | {
8 | [Test]
9 | public void ConvertDashesToCamelCase_single_dashes()
10 | {
11 | var actual = GenerateCodeHelper.ConvertDashesToCamelCase("string-with-dashes");
12 | Assert.AreEqual("StringWithDashes", actual);
13 | }
14 |
15 | [Test]
16 | public void ConvertDashesToCamelCase_consecutive_dashes()
17 | {
18 | var input = "string--with----dashes";
19 | var expected = "StringWithDashes";
20 | var actual = GenerateCodeHelper.ConvertDashesToCamelCase(input);
21 | Assert.AreEqual(expected, actual);
22 | }
23 |
24 | [Test]
25 | public void ConvertDashesToCamelCase_existing_uppercase_letters()
26 | {
27 | var input = "string-With-Dashes";
28 | var expected = "StringWithDashes";
29 | var actual = GenerateCodeHelper.ConvertDashesToCamelCase(input);
30 | Assert.AreEqual(expected, actual);
31 | }
32 |
33 | [Test]
34 | public void ConvertDashesToCamelCase_all_uppercase_letters()
35 | {
36 | var input = "STRING-WITH-DASHES";
37 | var expected = "STRINGWITHDASHES";
38 | var actual = GenerateCodeHelper.ConvertDashesToCamelCase(input);
39 | Assert.AreEqual(expected, actual);
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/Testee/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Testee")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("Testee")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2013")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("c47d4981-d4ac-4f8d-b130-ba1625434bb0")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/Examples/NavalFate/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("NavalFate")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("NavalFate")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2013")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("e681ff82-f89d-4c62-97a5-e7d3c609333f")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/T4DocoptNetHostApp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("T4DocoptNetHostApp")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("T4DocoptNetHostApp")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2013")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("98f7dff8-2d92-454c-8a76-e8ecd7061923")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/DefaultValueForPositionalArgumentsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using NUnit.Framework;
3 |
4 | namespace DocoptNet.Tests
5 | {
6 | [TestFixture]
7 | public class DefaultValueForPositionalArgumentsTests
8 | {
9 | [Test]
10 | public void Expect_default_value()
11 | {
12 | var expected = new Dictionary
13 | {
14 | {"--data", new ValueObject(new[] {"x"})}
15 | };
16 | var actual = new Docopt().Apply("Usage: prog [--data=...]\n\nOptions:\n\t-d --data= Input data [default: x]", "");
17 | Assert.AreEqual(expected, actual);
18 | }
19 |
20 | [Test]
21 | public void Expect_default_collection()
22 | {
23 | var expected = new Dictionary
24 | {
25 | {"--data", new ValueObject(new string[] {"x", "y"})}
26 | };
27 | var actual = new Docopt().Apply("Usage: prog [--data=...]\n\n Options:\n\t-d --data= Input data [default: x y]", "");
28 | Assert.AreEqual(expected, actual);
29 | }
30 |
31 | [Test]
32 | public void Expect_one_arg()
33 | {
34 | var expected = new Dictionary
35 | {
36 | {"--data", new ValueObject(new[] {"this"})}
37 | };
38 | var actual = new Docopt().Apply("Usage: prog [--data=...]\n\n Options:\n\t-d --data= Input data [default: x y]", "--data=this");
39 | Assert.AreEqual(expected, actual);
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/OptionsFirstTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using NUnit.Framework;
3 |
4 | namespace DocoptNet.Tests
5 | {
6 | [TestFixture]
7 | public class OptionsFirstTests
8 | {
9 | [Test]
10 | public void Match_opt_first()
11 | {
12 | var expected = new Dictionary
13 | {
14 | {"--opt", new ValueObject(true)},
15 | {"", new ValueObject(new[]{"this", "that"})}
16 | };
17 | var actual = new Docopt().Apply("usage: prog [--opt] [...]", "--opt this that");
18 | Assert.AreEqual(expected, actual);
19 | }
20 |
21 | [Test]
22 | public void Match_args_first()
23 | {
24 | var expected = new Dictionary
25 | {
26 | {"--opt", new ValueObject(true)},
27 | {"", new ValueObject(new[]{"this", "that"})}
28 | };
29 | var actual = new Docopt().Apply("usage: prog [--opt] [...]", "this that --opt");
30 | Assert.AreEqual(expected, actual);
31 | }
32 |
33 | [Test]
34 | public void Check_options_first()
35 | {
36 | var expected = new Dictionary
37 | {
38 | {"--opt", new ValueObject(false)},
39 | {"", new ValueObject(new[]{"this", "that", "--opt"})}
40 | };
41 | var actual = new Docopt().Apply("usage: prog [--opt] [...]", "this that --opt", optionsFirst: true);
42 | Assert.AreEqual(expected, actual);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/src/LanguageAgnosticTests/generate_tests.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 |
3 | #
4 | # Quick and dirty script to generate a C# test suite
5 | # out of testcases.docopt
6 | #
7 | # e.g. generate_tests >LanguageAgnosticTests.generated.cs
8 | #
9 |
10 | import sys, json, re, os
11 |
12 | fixtures = open(os.path.join(os.path.dirname(__file__), 'testcases.docopt'), 'r').read()
13 |
14 | # remove comments
15 | fixtures = re.sub('#.*$', '', fixtures, flags=re.M)
16 |
17 | ids = [int(x) for x in sys.argv[1:]] if len(sys.argv) > 1 else None
18 |
19 | fmt = """
20 | [Test]
21 | public void Test_%d()
22 | {
23 | var doc = @"%s";
24 | var actual = Docopt(doc, @"%s");
25 | var expected = @"%s";
26 | CheckResult(expected, actual);
27 | }
28 | """
29 |
30 | print ("""using System.Collections.Generic;
31 | using NUnit.Framework;
32 |
33 | namespace DocoptNet.Tests
34 | {
35 | [TestFixture]
36 | public partial class LanguageAgnosticTests
37 | {
38 | #region Language agnostic tests generated code
39 | """)
40 |
41 | index = 0
42 | for fixture in fixtures.split('r"""'):
43 | doc, _, body = fixture.partition('"""')
44 | for case in body.split('$')[1:]:
45 | index += 1
46 | if ids is not None and index not in ids:
47 | continue
48 | argv, _, expect = case.strip().partition('\n')
49 | prog, _, argv = argv.strip().partition(' ')
50 | assert prog == 'prog', repr(prog)
51 | doc = doc.replace('"', '""')
52 | expect = expect.replace('"', '""')
53 | argv = argv.replace('"', '"""')
54 | print (fmt % (index,doc,argv,expect))
55 |
56 | print ("""
57 | #endregion
58 | }
59 | }""")
60 |
--------------------------------------------------------------------------------
/src/DocoptNet/MatchResult.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace DocoptNet
6 | {
7 | internal class MatchResult
8 | {
9 | public bool Matched;
10 | public IList Left;
11 | public IEnumerable Collected;
12 |
13 | public MatchResult() { }
14 |
15 | public MatchResult(bool matched, IList left, IEnumerable collected)
16 | {
17 | Matched = matched;
18 | Left = left;
19 | Collected = collected;
20 | }
21 |
22 | public bool LeftIsEmpty { get { return Left.Count == 0; } }
23 |
24 | public override bool Equals(object obj)
25 | {
26 | //
27 | // See the full list of guidelines at
28 | // http://go.microsoft.com/fwlink/?LinkID=85237
29 | // and also the guidance for operator== at
30 | // http://go.microsoft.com/fwlink/?LinkId=85238
31 | //
32 |
33 | if (obj == null || GetType() != obj.GetType())
34 | {
35 | return false;
36 | }
37 |
38 | return ToString().Equals(obj.ToString());
39 | }
40 |
41 | public override int GetHashCode()
42 | {
43 | return ToString().GetHashCode();
44 | }
45 |
46 | public override string ToString()
47 | {
48 | return string.Format("matched={0} left=[{1}], collected=[{2}]",
49 | Matched,
50 | Left == null ? "" : string.Join(", ", Left.Select(p => p.ToString())),
51 | Collected == null ? "" : string.Join(", ", Collected.Select(p => p.ToString()))
52 | );
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/RequiredMatchTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class RequiredMatchTests
7 | {
8 | [Test]
9 | public void Should_match_option()
10 | {
11 | Assert.AreEqual(
12 | new MatchResult(true,
13 | new Pattern[0],
14 | new Pattern[] {new Option("-a")}),
15 | new Required(new Option("-a")).Match(new Pattern[] {new Option("-a")})
16 | );
17 | }
18 |
19 | [Test]
20 | public void Should_not_match_empty()
21 | {
22 | Assert.AreEqual(
23 | new MatchResult(false,
24 | new Pattern[0],
25 | new Pattern[0]),
26 | new Required(new Option("-a")).Match(new Pattern[0])
27 | );
28 | }
29 |
30 | [Test]
31 | public void Should_not_match_other_option()
32 | {
33 | Assert.AreEqual(
34 | new MatchResult(false,
35 | new Pattern[] {new Option("-x")},
36 | new Pattern[0]
37 | ),
38 | new Required(new Option("-a")).Match(new Pattern[] {new Option("-x")})
39 | );
40 | }
41 |
42 | [Test]
43 | public void Should_not_match_2_required()
44 | {
45 | Assert.AreEqual(
46 | new MatchResult(false,
47 | new Pattern[] { new Option("-a") },
48 | new Pattern[0]
49 | ),
50 | new Required(new Option("-a"), new Option("-b")).Match(new Pattern[] { new Option("-a") })
51 | );
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/src/LanguageAgnosticTests/language_agnostic_tester.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python
2 | import sys, json, re, os
3 | from subprocess import Popen, PIPE, STDOUT
4 |
5 | fixtures = open(os.path.join(os.path.dirname(__file__), 'testcases.docopt'), 'r').read()
6 |
7 | # remove comments
8 | fixtures = re.sub('#.*$', '', fixtures, flags=re.M)
9 |
10 | testee = (sys.argv[1] if len(sys.argv) >= 2 else
11 | exit('Usage: language_agnostic_tester.py ./path/to/executable/testee [ID ...]'))
12 | ids = [int(x) for x in sys.argv[2:]] if len(sys.argv) > 2 else None
13 | summary = ''
14 |
15 | index = 0
16 | for fixture in fixtures.split('r"""'):
17 | doc, _, body = fixture.partition('"""')
18 | for case in body.split('$')[1:]:
19 | index += 1
20 | if ids is not None and index not in ids:
21 | continue
22 | argv, _, expect = case.strip().partition('\n')
23 | prog, _, argv = argv.strip().partition(' ')
24 | assert prog == 'prog', repr(prog)
25 | p = Popen(testee + ' ' + argv,
26 | stdout=PIPE, stdin=PIPE, stderr=STDOUT, shell=True)
27 | result = p.communicate(input=doc)[0]
28 | try:
29 | py_result = json.loads(result)
30 | py_expect = json.loads(expect)
31 | except:
32 | summary += 'J'
33 | print (' %d: BAD JSON ' % index).center(79, '=')
34 | print 'result>', result
35 | print 'expect>', expect
36 | continue
37 | if py_result == py_expect:
38 | summary += '.'
39 | else:
40 | print (' %d: FAILED ' % index).center(79, '=')
41 | print 'r"""%s"""' % doc
42 | print '$ prog %s\n' % argv
43 | print 'result>', result
44 | print 'expect>', expect
45 | summary += 'F'
46 |
47 | print (' %d / %d ' % (summary.count('.'), len(summary))).center(79, '=')
48 | print summary
49 |
--------------------------------------------------------------------------------
/src/DocoptNet/Argument.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 |
4 | namespace DocoptNet
5 | {
6 | internal class Argument: LeafPattern
7 | {
8 | public Argument(string name, ValueObject value = null) : base(name, value)
9 | {
10 | }
11 |
12 | public Argument(string name, string value)
13 | : base(name, new ValueObject(value))
14 | {
15 | }
16 |
17 | public Argument(string name, ICollection coll)
18 | : base(name, new ValueObject(coll))
19 | {
20 | }
21 |
22 | public Argument(string name, int value)
23 | : base(name, new ValueObject(value))
24 | {
25 | }
26 |
27 | public override SingleMatchResult SingleMatch(IList left)
28 | {
29 | for (var i = 0; i < left.Count; i++)
30 | {
31 | if (left[i] is Argument)
32 | return new SingleMatchResult(i, new Argument(Name, left[i].Value));
33 | }
34 | return new SingleMatchResult();
35 | }
36 |
37 | public override Node ToNode()
38 | {
39 | return new ArgumentNode(this.Name, (this.Value != null && this.Value.IsList) ? ValueType.List : ValueType.String);
40 | }
41 |
42 | public override string GenerateCode()
43 | {
44 | var s = Name.Replace("<", "").Replace(">", " ").ToLowerInvariant();
45 | s = "Arg" + GenerateCodeHelper.ConvertDashesToCamelCase(s);
46 |
47 | if (Value != null && Value.IsList)
48 | {
49 | return string.Format("public ArrayList {0} {{ get {{ return _args[\"{1}\"].AsList; }} }}", s, Name);
50 | }
51 | return string.Format("public string {0} {{ get {{ return null == _args[\"{1}\"] ? null : _args[\"{1}\"].ToString(); }} }}", s, Name);
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/ArgumentMatchTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class ArgumentMatchTests
7 | {
8 | [Test]
9 | public void Should_match_arg()
10 | {
11 | Assert.AreEqual(
12 | new MatchResult(true, new Pattern[0], new Pattern[] {new Argument("N", new ValueObject(9))}),
13 | new Argument("N").Match(new Pattern[] {new Argument(null, new ValueObject(9))})
14 | );
15 | }
16 |
17 | [Test]
18 | public void Should_not_match_arg()
19 | {
20 | Assert.AreEqual(
21 | new MatchResult(false, new Pattern[] {new Option("-x")}, new Pattern[0]),
22 | new Argument("N").Match(new Pattern[] {new Option("-x")})
23 | );
24 | }
25 |
26 | [Test]
27 | public void Should_match_arg_after_opts()
28 | {
29 | Assert.AreEqual(
30 | new MatchResult(true, new Pattern[] {new Option("-x"), new Option("-a")},
31 | new Pattern[] {new Argument("N", new ValueObject(5))}),
32 | new Argument("N").Match(new Pattern[]
33 | {
34 | new Option("-x"),
35 | new Option("-a"),
36 | new Argument(null, new ValueObject(5))
37 | })
38 | );
39 | }
40 |
41 | [Test]
42 | public void Should_match_first_arg_only()
43 | {
44 | Assert.AreEqual(
45 | new MatchResult(true,
46 | new Pattern[] {new Argument(null, new ValueObject(0))},
47 | new Pattern[] {new Argument("N", new ValueObject(9))}),
48 | new Argument("N").Match(new Pattern[]
49 | {new Argument(null, new ValueObject(9)), new Argument(null, new ValueObject(0))})
50 | );
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/CommandMatchTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class CommandMatchTests
7 | {
8 | [Test]
9 | public void Should_match_command()
10 | {
11 | Assert.AreEqual(
12 | new MatchResult(true,
13 | new Pattern[0],
14 | new Pattern[] {new Command("c", new ValueObject(true))}),
15 | new Command("c").Match(new Pattern[] {new Argument(null, new ValueObject("c"))})
16 | );
17 | }
18 |
19 | [Test]
20 | public void Should_not_match_command()
21 | {
22 | Assert.AreEqual(
23 | new MatchResult(false,
24 | new Pattern[] {new Option("-x")},
25 | new Pattern[0]),
26 | new Command("c").Match(new Pattern[] {new Option("-x")})
27 | );
28 | }
29 |
30 | [Test]
31 | public void Should_match_command_after_options()
32 | {
33 | Assert.AreEqual(
34 | new MatchResult(true,
35 | new Pattern[] { new Option("-x"), new Option("-a") },
36 | new Pattern[] { new Command("c", new ValueObject(true)) }),
37 | new Command("c").Match(new Pattern[] { new Option("-x"), new Option("-a"), new Argument(null, new ValueObject("c")) })
38 | );
39 | }
40 |
41 | [Test]
42 | public void Should_match_either_command()
43 | {
44 | Assert.AreEqual(
45 | new MatchResult(true,
46 | new Pattern[0],
47 | new Pattern[] { new Command("rm", new ValueObject(true)) }),
48 | new Either(new Command("add"), new Command("rm")).Match(new Pattern[] { new Argument(null, new ValueObject("rm")) })
49 | );
50 | }
51 |
52 | }
53 | }
--------------------------------------------------------------------------------
/src/NuGet/install.ps1:
--------------------------------------------------------------------------------
1 | param($installPath, $toolsPath, $package, $project)
2 | # Set the build action type to None
3 | $project.ProjectItems.Item("T4DocoptNet.tt").Properties.Item("BuildAction").Value = 0 #prjBuildActionNone
4 | $project.ProjectItems.Item("T4DocoptNet.tt.hooks.t4").Properties.Item("BuildAction").Value = 0
5 | $project.ProjectItems.Item("T4DocoptNet.tt.settings.xml").Properties.Item("BuildAction").Value = 0
6 |
7 | # Edit the project's T4DocoptNet.tt file to point to the right DocoptNet assembly path.
8 | function Set-DocoptNetAssemblyPath($AssemblyPath, $ProjectDirectoryPath)
9 | {
10 | # Get the path to the T4DocoptNet.tt file.
11 | Write-Debug "Project directory is '$ProjectDirectoryPath'."
12 | $t4FilePath = Join-Path $ProjectDirectoryPath "T4DocoptNet.tt"
13 |
14 | # If we found the T4 file, try and update it.
15 | if (Test-Path -Path $t4FilePath)
16 | {
17 | Write-Debug "Found T4 file at '$t4FilePath'."
18 |
19 | # Load the packages.config xml document and grab all of the elements.
20 | $wholeFile = [System.IO.File]::ReadAllText($t4FilePath)
21 | $searchString = '\$\(ProjectDir\)\$\(OutDir\)DocoptNet.dll'
22 | if (!($wholeFile -match $searchString))
23 | {
24 | Write-Debug "Could not find search string in '$t4FilePath'."
25 | return
26 | }
27 |
28 | Write-Debug "Setting assembly path '$AssemblyPath' in '$t4FilePath'."
29 | $wholeFile = $wholeFile -replace $searchString, $AssemblyPath
30 |
31 | # Save the T4 file back now that we've changed it.
32 | [System.IO.File]::WriteAllText($t4FilePath, $wholeFile)
33 | }
34 | # Else we coudn't find the T4 file for some reason, so error out.
35 | else
36 | {
37 | Write-Debug "Could not find T4 file at '$t4FilePath'."
38 | }
39 | }
40 |
41 | $p = (gci -Path $installPath -Filter net40 -recurse | select -First 1).FullName | Join-Path -ChildPath "DocoptNet.dll"
42 | Set-DocoptNetAssemblyPath -AssemblyPath $p -ProjectDirectoryPath ([System.IO.Directory]::GetParent($project.FullName))
43 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/UsageTests.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using NUnit.Framework;
3 |
4 | namespace DocoptNet.Tests
5 | {
6 | [TestFixture]
7 | public class UsageTests
8 | {
9 | [Test]
10 | public void Test_formal_usage()
11 | {
12 | const string DOC =
13 | "Usage: prog [-hv] ARG\r\n" +
14 | " prog N M\r\n" +
15 | "\r\n" +
16 | " prog is a program.";
17 | var usage = Docopt.ParseSection("usage:", DOC).First();
18 | Assert.AreEqual("Usage: prog [-hv] ARG\r\n prog N M", usage);
19 | Assert.AreEqual("( [-hv] ARG ) | ( N M )", Docopt.FormalUsage(usage));
20 | }
21 | [Test]
22 | public void Should_parse_usage_section_correctly()
23 | {
24 | const string USAGE = @"usage: this
25 |
26 | usage:hai
27 | usage: this that
28 |
29 | usage: foo
30 | bar
31 |
32 | PROGRAM USAGE:
33 | foo
34 | bar
35 | " +
36 | "usage:\r\n\ttoo\r\n" +
37 | "\ttar\r\n" +
38 | @"Usage: eggs spam
39 | BAZZ
40 | usage: pit stop
41 | ";
42 |
43 |
44 | Assert.AreEqual(new string[] {}, Docopt.ParseSection("usage:", "foo bar fizz buzz"), "No usage");
45 |
46 | Assert.AreEqual(new[] {"usage: prog"}, Docopt.ParseSection("usage:", "usage: prog"), "One line usage");
47 |
48 | Assert.AreEqual(new[] {@"usage: -args\r\n -y"}, Docopt.ParseSection("usage:", @"usage: -args\r\n -y"),
49 | "Multi line usage");
50 |
51 | Assert.AreEqual(new[]
52 | {
53 | "usage: this",
54 | "usage:hai",
55 | "usage: this that",
56 | @"usage: foo
57 | bar",
58 | @"PROGRAM USAGE:
59 | foo
60 | bar",
61 | "usage:\r\n\ttoo\r\n\ttar",
62 | "Usage: eggs spam",
63 | "usage: pit stop"
64 | }, Docopt.ParseSection("usage:", USAGE), "Variations on casing, spaces and tabs");
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/LongOptionsErrorHandlingTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class LongOptionsErrorHandlingTests
7 | {
8 | [Test]
9 | public void Non_existent()
10 | {
11 | Assert.Throws(() =>
12 | new Docopt().Apply("Usage: prog", "--non-existent")
13 | );
14 | }
15 |
16 | [Test]
17 | public void Wrong_long_opt()
18 | {
19 | Assert.Throws(
20 | () => new Docopt().Apply(
21 | "Usage: prog [--version --verbose]\n" +
22 | "Options: --version\n" +
23 | " --verbose", "--ver")
24 | );
25 | }
26 |
27 | [Test]
28 | public void Missing_long_opt_arg_spec()
29 | {
30 | Assert.Throws(
31 | () => new Docopt().Apply(
32 | "Usage: prog --long\n" +
33 | "Options: --long ARG\n", "")
34 | );
35 | }
36 |
37 | [Test]
38 | public void Missing_long_opt_arg()
39 | {
40 | Assert.Throws(
41 | () => new Docopt().Apply(
42 | "Usage: prog --long ARG\n" +
43 | "Options: --long ARG\n", "--long")
44 | );
45 | }
46 |
47 | [Test]
48 | public void Missing_long_opt_arg_spec2()
49 | {
50 | Assert.Throws(
51 | () => new Docopt().Apply(
52 | "Usage: prog --long=ARG\n" +
53 | "Options: --long\n", "")
54 | );
55 | }
56 |
57 | [Test]
58 | public void Unexpected_arg()
59 | {
60 | Assert.Throws(
61 | () => new Docopt().Apply(
62 | "Usage: prog --long\n" +
63 | "Options: --long\n", "--long=ARG")
64 | );
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/Testee/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 | using DocoptNet;
7 | using Newtonsoft.Json;
8 |
9 | namespace Testee
10 | {
11 | internal class Program
12 | {
13 | public static string Docopt(string doc, string[] cmdLine)
14 | {
15 | try
16 | {
17 | var arguments = new Docopt().Apply(doc, cmdLine);
18 | var dict = new Dictionary();
19 | foreach (var argument in arguments)
20 | {
21 | if (argument.Value == null)
22 | dict[argument.Key] = null;
23 | else if (argument.Value.IsList)
24 | {
25 | var l = new ArrayList();
26 | foreach (var v in argument.Value.AsList)
27 | {
28 | if (v is ValueObject)
29 | l.Add(((v) as ValueObject).Value);
30 | else
31 | l.Add(v);
32 | }
33 | dict[argument.Key] = l;
34 | }
35 | else
36 | dict[argument.Key] = argument.Value.Value;
37 | }
38 | return JsonConvert.SerializeObject(dict);
39 | }
40 | catch (Exception)
41 | {
42 | return "\"user-error\"";
43 | }
44 | }
45 |
46 | private static void Main(string[] args)
47 | {
48 | Stream inputStream = Console.OpenStandardInput();
49 | var bytes = new byte[100];
50 | var sb = new StringBuilder();
51 | int outputLength = inputStream.Read(bytes, 0, 100);
52 | while (outputLength > 0)
53 | {
54 | char[] chars = Encoding.UTF8.GetChars(bytes, 0, outputLength);
55 | sb.Append(chars);
56 | outputLength = inputStream.Read(bytes, 0, 100);
57 | }
58 | var doc = sb.ToString();
59 | var s = Docopt(doc, args);
60 | Console.WriteLine(s);
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/ListArgumentMatchTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class ListArgumentMatchTests
7 | {
8 | [Test]
9 | public void Should_match_required_two_args_into_a_list()
10 | {
11 | Assert.AreEqual(
12 | new MatchResult(true,
13 | new Pattern[0],
14 | new Pattern[] { new Argument("N", new [] { "1", "2"}) }),
15 | new Required(new Argument("N"), new Argument("N")).Fix().Match(new Pattern[] { new Argument(null, "1"), new Argument(null, "2") })
16 | );
17 | }
18 |
19 | [Test]
20 | public void Should_match_oneormore_arg_into_a_list()
21 | {
22 | Assert.AreEqual(
23 | new MatchResult(true,
24 | new Pattern[0],
25 | new Pattern[] { new Argument("N", new[] { "1", "2", "3" }) }),
26 | new OneOrMore(new Argument("N")).Fix().Match(new Pattern[] { new Argument(null, "1"), new Argument(null, "2"), new Argument(null, "3") })
27 | );
28 | }
29 |
30 | [Test]
31 | public void Should_match_required_and_oneormore_arg_into_a_list()
32 | {
33 | Assert.AreEqual(
34 | new MatchResult(true,
35 | new Pattern[0],
36 | new Pattern[] { new Argument("N", new[] { "1", "2", "3" }) }),
37 | new Required(new Argument("N"), new OneOrMore(new Argument("N"))).Fix().Match(new Pattern[] { new Argument(null, "1"), new Argument(null, "2"), new Argument(null, "3") })
38 | );
39 | }
40 |
41 | [Test]
42 | public void Should_match_doubly_required_arg_into_a_list()
43 | {
44 | Assert.AreEqual(
45 | new MatchResult(true,
46 | new Pattern[0],
47 | new Pattern[] { new Argument("N", new[] { "1", "2" }) }),
48 | new Required(new Argument("N"), new Required(new Argument("N"))).Fix().Match(new Pattern[] { new Argument(null, "1"), new Argument(null, "2")})
49 | );
50 | }
51 | }
52 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/BasicPatternMatchingTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class BasicPatternMatchingTests
7 | {
8 | // ( -a N [ -x Z ] )
9 | private readonly Pattern _pattern = new Required(new Option("-a"), new Argument("N"),
10 | new Optional(new Option("-x"), new Argument("Z")));
11 |
12 | [Test]
13 | public void Should_match_required()
14 | {
15 | // -a N
16 | Assert.AreEqual(
17 | new MatchResult(true,
18 | new Pattern[0],
19 | new Pattern[] {new Option("-a"), new Argument("N", "9")}),
20 | _pattern.Match(new Pattern[] {new Option("-a"), new Argument(null, "9")})
21 | );
22 | }
23 |
24 | [Test]
25 | public void Should_match_required_and_optional()
26 | {
27 | // -a -x N Z
28 | Assert.AreEqual(
29 | new MatchResult(true,
30 | new Pattern[0],
31 | new Pattern[]
32 | {
33 | new Option("-a"), new Argument("N", "9"),
34 | new Option("-x"), new Argument("Z", "5")
35 | }),
36 | _pattern.Match(new Pattern[]
37 | {new Option("-a"), new Option("-x"), new Argument(null, "9"), new Argument(null, "5")})
38 | );
39 | }
40 |
41 | [Test]
42 | public void Should_not_match_spurious_arg()
43 | {
44 | // -x N Z
45 | Assert.AreEqual(
46 | new MatchResult(false,
47 | new Pattern[]
48 | {
49 | new Option("-x"), new Argument(null, "9"), new Argument(null, "5")
50 | },
51 | new Pattern[0]
52 | ),
53 | _pattern.Match(new Pattern[] {new Option("-x"), new Argument(null, "9"), new Argument(null, "5")})
54 | );
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/OptionMatchTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class OptionMatchTests
7 | {
8 | [Test]
9 | public void Test_option_match_opt_matched()
10 | {
11 | var expected = new MatchResult(true, new Pattern[0], new[] {new Option("-a", value: new ValueObject(true))});
12 | var actual = new Option("-a").Match(new[] {new Option("-a", value: new ValueObject(true))});
13 | Assert.AreEqual(expected, actual);
14 | }
15 |
16 | [Test]
17 | public void Test_option_match_opt_no_match()
18 | {
19 | var expected = new MatchResult(false, new[] {new Option("-x")}, new Pattern[0]);
20 | var actual = new Option("-a").Match(new[] {new Option("-x")});
21 | Assert.AreEqual(expected, actual);
22 | }
23 |
24 | [Test]
25 | public void Test_option_match_opt_no_match_with_arg()
26 | {
27 | var expected = new MatchResult(false, new[] {new Argument("N"),}, new Pattern[0]);
28 | var actual = new Option("-a").Match(new[] {new Argument("N")});
29 | Assert.AreEqual(expected, actual);
30 | }
31 |
32 | [Test]
33 | public void Test_option_match_one_opt_out_of_two()
34 | {
35 | var expected = new MatchResult(true,
36 | new Pattern[] {new Option("-x"), new Argument("N")},
37 | new[] {new Option("-a")}
38 | );
39 | var actual = new Option("-a").Match(new Pattern[] {new Option("-x"), new Option("-a"), new Argument("N")});
40 | Assert.AreEqual(expected, actual);
41 | }
42 |
43 | [Test]
44 | public void Test_option_match_same_opt_one_with_value()
45 | {
46 | var expected = new MatchResult(true,
47 | new Pattern[] {new Option("-a")},
48 | new Pattern[] {new Option("-a", value: new ValueObject(true))}
49 | );
50 | var actual =
51 | new Option("-a").Match(new Pattern[] { new Option("-a", value: new ValueObject(true)), new Option("-a") });
52 | Assert.AreEqual(expected, actual);
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/LanguageAgnosticTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using NUnit.Framework;
5 | using Newtonsoft.Json;
6 |
7 | namespace DocoptNet.Tests
8 | {
9 | [TestFixture]
10 | public partial class LanguageAgnosticTests
11 | {
12 | public string Docopt(string doc, string cmdLine)
13 | {
14 | try
15 | {
16 | var arguments = new Docopt().Apply(doc, cmdLine);
17 | var dict = new Dictionary();
18 | foreach (var argument in arguments)
19 | {
20 | if (argument.Value == null)
21 | dict[argument.Key] = null;
22 | else if (argument.Value.IsList)
23 | {
24 | var l = new ArrayList();
25 | foreach (var v in argument.Value.AsList)
26 | {
27 | if (v is ValueObject)
28 | l.Add(((v) as ValueObject).Value);
29 | else
30 | l.Add(v);
31 | }
32 | dict[argument.Key] = l;
33 | }
34 | else
35 | dict[argument.Key] = argument.Value.Value;
36 | }
37 | return JsonConvert.SerializeObject(dict);
38 | }
39 | catch (Exception)
40 | {
41 | return "\"user-error\"";
42 | }
43 | }
44 |
45 | public void CheckResult(string expectedJson, string resultJson)
46 | {
47 | if (expectedJson.StartsWith("{"))
48 | {
49 | var expectedDict = JsonConvert.DeserializeObject>(expectedJson);
50 | var actualDict = JsonConvert.DeserializeObject>(resultJson);
51 | Assert.AreEqual(expectedDict, actualDict);
52 | }
53 | else
54 | {
55 | var expected = JsonConvert.DeserializeObject(expectedJson).ToString();
56 | var actual = JsonConvert.DeserializeObject(resultJson).ToString();
57 | Assert.AreEqual(expected, actual);
58 | }
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/EitherMatchTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class EitherMatchTests
7 | {
8 | [Test]
9 | public void Should_match_option()
10 | {
11 | Assert.AreEqual(
12 | new MatchResult(true,
13 | new Pattern[0],
14 | new Pattern[] { new Option("-a") }),
15 | new Either(new Option("-a"), new Option("-b")).Match(new Pattern[] { new Option("-a") })
16 | );
17 | }
18 |
19 | [Test]
20 | public void Should_match_first_option()
21 | {
22 | Assert.AreEqual(
23 | new MatchResult(true,
24 | new Pattern[] { new Option("-b") },
25 | new Pattern[] { new Option("-a") }),
26 | new Either(new Option("-a"), new Option("-b")).Match(new Pattern[] { new Option("-a"), new Option("-b"), })
27 | );
28 | }
29 |
30 | [Test]
31 | public void Should_not_match_other_option()
32 | {
33 | Assert.AreEqual(
34 | new MatchResult(false,
35 | new Pattern[] { new Option("-x") },
36 | new Pattern[0]),
37 | new Either(new Option("-a"), new Option("-b")).Match(new Pattern[] { new Option("-x") })
38 | );
39 | }
40 |
41 | [Test]
42 | public void Should_match_one_option_out_of_three()
43 | {
44 | Assert.AreEqual(
45 | new MatchResult(true,
46 | new Pattern[] { new Option("-x") },
47 | new Pattern[] { new Option("-b") }),
48 | new Either(new Option("-a"), new Option("-b"), new Option("-c")).Match(new Pattern[] { new Option("-x"), new Option("-b") })
49 | );
50 | }
51 |
52 | [Test]
53 | public void Should_match_required_args()
54 | {
55 | Assert.AreEqual(
56 | new MatchResult(true,
57 | new Pattern[0],
58 | new Pattern[] { new Argument("N", 1), new Argument("M", 2) }),
59 | new Either(new Argument("M"), new Required(new Argument("N"), new Argument("M"))).Match(new Pattern[] { new Argument(null, 1), new Argument(null, 2) })
60 | );
61 | }
62 |
63 | }
64 | }
--------------------------------------------------------------------------------
/src/DocoptNet/Tokens.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text.RegularExpressions;
6 |
7 | namespace DocoptNet
8 | {
9 | public class Tokens: IEnumerable
10 | {
11 | private readonly Type _errorType;
12 | private readonly List _tokens = new List();
13 |
14 | public Tokens(IEnumerable source, Type errorType)
15 | {
16 | _errorType = errorType ?? typeof(DocoptInputErrorException);
17 | _tokens.AddRange(source);
18 | }
19 |
20 | public Tokens(string source, Type errorType)
21 | {
22 | _errorType = errorType ?? typeof(DocoptInputErrorException);
23 | _tokens.AddRange(source.Split(new char[0], StringSplitOptions.RemoveEmptyEntries));
24 | }
25 |
26 | public Type ErrorType
27 | {
28 | get { return _errorType; }
29 | }
30 |
31 | public bool ThrowsInputError
32 | {
33 | get { return ErrorType == typeof (DocoptInputErrorException); }
34 | }
35 |
36 |
37 | public static Tokens FromPattern(string pattern)
38 | {
39 | var spacedOut = Regex.Replace(pattern, @"([\[\]\(\)\|]|\.\.\.)", @" $1 ");
40 | var source = Regex.Split(spacedOut, @"\s+|(\S*<.*?>)").Where(x => !string.IsNullOrEmpty(x));
41 | return new Tokens(source, typeof(DocoptLanguageErrorException));
42 | }
43 |
44 | public IEnumerator GetEnumerator()
45 | {
46 | return _tokens.GetEnumerator();
47 | }
48 |
49 | IEnumerator IEnumerable.GetEnumerator()
50 | {
51 | return GetEnumerator();
52 | }
53 |
54 | public string Move()
55 | {
56 | string s = null;
57 | if (_tokens.Count > 0)
58 | {
59 | s = _tokens[0];
60 | _tokens.RemoveAt(0);
61 | }
62 | return s;
63 | }
64 |
65 | public string Current()
66 | {
67 | return (_tokens.Count > 0) ? _tokens[0] : null;
68 | }
69 |
70 | public Exception CreateException(string message)
71 | {
72 | return Activator.CreateInstance(_errorType, new object[] {message}) as Exception;
73 | }
74 |
75 | public override string ToString()
76 | {
77 | return string.Format("current={0},count={1}", Current(), _tokens.Count);
78 | }
79 | }
80 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/OptionParseTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class OptionParseTests
7 | {
8 | [Test]
9 | public void Short_and_long()
10 | {
11 | Assert.AreEqual(new Option("-h", null), Option.Parse("-h"));
12 | Assert.AreEqual(new Option(null, "--help"), Option.Parse("--help"));
13 | Assert.AreEqual(new Option("-h", "--help"), Option.Parse("-h --help"));
14 | Assert.AreEqual(new Option("-h", "--help"), Option.Parse("-h, --help"));
15 | }
16 |
17 | [Test]
18 | public void With_args()
19 | {
20 | Assert.AreEqual(new Option("-h", null, 1), Option.Parse("-h TOPIC"));
21 | Assert.AreEqual(new Option(null, "--help", 1), Option.Parse("--help TOPIC"));
22 | Assert.AreEqual(new Option("-h", "--help", 1), Option.Parse("-h TOPIC --help TOPIC"));
23 | Assert.AreEqual(new Option("-h", "--help", 1), Option.Parse("-h TOPIC, --help TOPIC"));
24 | Assert.AreEqual(new Option("-h", "--help", 1), Option.Parse("-h TOPIC, --help=TOPIC"));
25 |
26 | }
27 |
28 | [Test]
29 | public void With_description()
30 | {
31 | Assert.AreEqual(new Option("-h", null), Option.Parse("-h Description..."));
32 | Assert.AreEqual(new Option("-h", "--help"), Option.Parse("-h --help Description..."));
33 | Assert.AreEqual(new Option("-h", null, 1), Option.Parse("-h TOPIC Description..."));
34 | }
35 |
36 | [Test]
37 | public void Leading_spaces()
38 | {
39 |
40 | Assert.AreEqual(new Option("-h", null), Option.Parse(" -h"));
41 | }
42 |
43 | [Test]
44 | public void With_defaults()
45 | {
46 |
47 | Assert.AreEqual(new Option("-h", null, 1, "2"), Option.Parse("-h TOPIC Description... [default: 2]"));
48 | Assert.AreEqual(new Option("-h", null, 1, "2"), Option.Parse("-h TOPIC Description... [dEfAuLt: 2]"));
49 | }
50 |
51 | [Test]
52 | public void With_args_and_defaults()
53 | {
54 |
55 | Assert.AreEqual(new Option("-h", null, 1, "topic-1"),
56 | Option.Parse("-h TOPIC Description... [default: topic-1]"));
57 | Assert.AreEqual(new Option(null, "--help", 1, "3.14"), Option.Parse("--help=TOPIC ... [default: 3.14]"));
58 | Assert.AreEqual(new Option("-h", "--help", 1, "./"), Option.Parse("-h, --help=DIR ... [default: ./]"));
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/PatterEitherTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class PatterEitherTests
7 | {
8 | [Test]
9 | public void Should_transform_option()
10 | {
11 | Assert.AreEqual(
12 | new Either(new Required(new Option("-a"))),
13 | Pattern.Transform(new Option("-a"))
14 | );
15 | }
16 |
17 | [Test]
18 | public void Should_transform_arg()
19 | {
20 | Assert.AreEqual(
21 | new Either(new Required(new Argument("A"))),
22 | Pattern.Transform(new Argument("A"))
23 | );
24 | }
25 |
26 | [Test]
27 | public void Should_distribute_opt()
28 | {
29 | Assert.AreEqual(
30 | new Either(
31 | new Required(new Option("-a"), new Option("-c")),
32 | new Required(new Option("-b"), new Option("-c"))),
33 | Pattern.Transform(new Required(
34 | new Either(new Option("-a"), new Option("-b")), new Option("-c")))
35 | );
36 | }
37 |
38 | [Test]
39 | public void Should_distribute_optional()
40 | {
41 | Assert.AreEqual(
42 | new Either(
43 | new Required(new Option("-b"), new Option("-a")),
44 | new Required(new Option("-c"), new Option("-a"))),
45 | Pattern.Transform(new Optional(
46 | new Option("-a"), new Either(new Option("-b"), new Option("-c"))))
47 | );
48 | }
49 |
50 | [Test]
51 | public void Should_split_either()
52 | {
53 | Assert.AreEqual(
54 | new Either(
55 | new Required(new Option("-x")),
56 | new Required(new Option("-y")),
57 | new Required(new Option("-z"))
58 | ),
59 | Pattern.Transform(new Either(new Option("-x"),
60 | new Either(new Option("-y"), new Option("-z"))))
61 | );
62 | }
63 |
64 | [Test]
65 | public void Should_transform_oneormore_args()
66 | {
67 | Assert.AreEqual(
68 | new Either(new Required(new Argument("N"), new Argument("M"),
69 | new Argument("N"), new Argument("M"))),
70 | Pattern.Transform(new OneOrMore(new Argument("N"), new Argument("M")))
71 | );
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/GenerateCodeTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text.RegularExpressions;
3 | using NUnit.Framework;
4 |
5 | namespace DocoptNet.Tests
6 | {
7 | [TestFixture]
8 | public class GenerateCodeTests
9 | {
10 | [Test]
11 | public void Should_generate_code()
12 | {
13 | // TODO: not a very useful test, more of a sanity check
14 |
15 | const string USAGE = @"Test host app for T4 Docopt.NET
16 |
17 | Usage:
18 | prog command ARG [OPTIONALARG] [-o -s= --long=ARG --switch-dash]
19 | prog command2 ARG
20 | prog files FILE...
21 |
22 | Options:
23 | -o Short switch.
24 | -s= Short option with arg. [default: 128]
25 | --long=ARG Long option with arg.
26 | --switch-dash Long switch.
27 |
28 | Explanation:
29 | This is a test usage file.
30 | ";
31 | const string expected = @"
32 | public bool CmdCommand { get { return _args[""command""].IsTrue; } }
33 | public string ArgArg { get { return null == _args[""ARG""] ? null : _args[""ARG""].ToString(); } }
34 | public string ArgMyarg { get { return null == _args[""""] ? null : _args[""""].ToString(); } }
35 | public string ArgOptionalarg { get { return null == _args[""OPTIONALARG""] ? null : _args[""OPTIONALARG""].ToString(); } }
36 | public bool OptO { get { return _args[""-o""].IsTrue; } }
37 | public string OptS { get { return null == _args[""-s""] ? ""128"" : _args[""-s""].ToString(); } }
38 | public string OptLong { get { return null == _args[""--long""] ? null : _args[""--long""].ToString(); } }
39 | public bool OptSwitchDash { get { return _args[""--switch-dash""].IsTrue; } }
40 | public bool CmdCommand2 { get { return _args[""command2""].IsTrue; } }
41 | public bool CmdFiles { get { return _args[""files""].IsTrue; } }
42 | public ArrayList ArgFile { get { return _args[""FILE""].AsList; } }
43 | ";
44 | var s = new Docopt().GenerateCode(USAGE);
45 | Assert.AreEqual(NormalizeNewLines(expected), NormalizeNewLines(s));
46 | }
47 |
48 | private static string NormalizeNewLines(string s)
49 | {
50 | return string.Join(Environment.NewLine, s.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries));
51 | }
52 |
53 | [Test]
54 | public void Short_and_long_option_lead_to_only_one_property()
55 | {
56 | const string usage = @"Usage:
57 | naval_fate -h | --help
58 |
59 | Options:
60 | -h --help Show this screen.";
61 |
62 | var generatedCode = new Docopt().GenerateCode(usage);
63 |
64 | Assert.AreEqual(1, Regex.Matches(generatedCode, "OptHelp").Count);
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/DocoptNet/Node.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace DocoptNet
7 | {
8 | public enum ValueType { Bool, List, String, }
9 |
10 | public class ArgumentNode : Node
11 | {
12 | public ArgumentNode(string name, ValueType valueType) : base(name, valueType) { }
13 | }
14 |
15 | public class OptionNode : Node
16 | {
17 | public OptionNode(string name, ValueType valueType) : base(name, valueType) { }
18 | }
19 |
20 | public class CommandNode : Node
21 | {
22 | public CommandNode(string name) : base(name, ValueType.Bool) { }
23 | }
24 |
25 | public abstract class Node : IEquatable
26 | {
27 | private class EmptyNode : Node
28 | {
29 | public EmptyNode() : base("", (ValueType)0) { }
30 | }
31 |
32 | ///
33 | /// Indicates an empty or non-existant node.
34 | ///
35 | public static readonly Node Empty = new EmptyNode();
36 |
37 | protected Node(string name, ValueType valueType)
38 | {
39 | if (name == null) throw new ArgumentNullException("name");
40 |
41 | this.Name = name;
42 | this.ValueType = valueType;
43 | }
44 |
45 | public ValueType ValueType { get; private set; }
46 | public string Name { get; private set; }
47 |
48 | public override string ToString()
49 | {
50 | return string.Format("{0} {1} {2}", GetType().Name, Name, ValueType);
51 | }
52 |
53 | public override int GetHashCode()
54 | {
55 | return this.Name.GetHashCode() ^ this.ValueType.GetHashCode();
56 | }
57 |
58 | public bool Equals(Node other)
59 | {
60 | if (object.ReferenceEquals(null, other))
61 | {
62 | return false;
63 | }
64 |
65 | if (object.ReferenceEquals(this, other))
66 | {
67 | return true;
68 | }
69 |
70 | return other.Name == this.Name
71 | && other.ValueType == this.ValueType;
72 | }
73 |
74 | public override bool Equals(object obj)
75 | {
76 | if (object.ReferenceEquals(null, obj))
77 | {
78 | return false;
79 | }
80 |
81 | if (object.ReferenceEquals(this, obj))
82 | {
83 | return true;
84 | }
85 |
86 | if (obj.GetType() != this.GetType())
87 | {
88 | return false;
89 | }
90 |
91 | return this.Equals((Node)obj);
92 | }
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/CommandsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using NUnit.Framework;
3 |
4 | namespace DocoptNet.Tests
5 | {
6 | [TestFixture]
7 | public class CommandsTests
8 | {
9 | [Test]
10 | public void Required()
11 | {
12 | var expected = new Dictionary
13 | {
14 | {"add", new ValueObject(true)}
15 | };
16 | var actual = new Docopt().Apply("Usage: prog add", "add");
17 | Assert.AreEqual(expected, actual);
18 | }
19 |
20 | [Test]
21 | public void Optional_no_args()
22 | {
23 | var expected = new Dictionary
24 | {
25 | {"add", new ValueObject(false)}
26 | };
27 | var actual = new Docopt().Apply("Usage: prog [add]", "");
28 | Assert.AreEqual(expected, actual);
29 | }
30 |
31 | [Test]
32 | public void Optional_one_arg()
33 | {
34 | var expected = new Dictionary
35 | {
36 | {"add", new ValueObject(true)}
37 | };
38 | var actual = new Docopt().Apply("Usage: prog [add]", "add");
39 | Assert.AreEqual(expected, actual);
40 | }
41 |
42 | [Test]
43 | public void Optional_either_first_specified()
44 | {
45 | var expected = new Dictionary
46 | {
47 | {"add", new ValueObject(true)},
48 | {"rm", new ValueObject(false)}
49 | };
50 | var actual = new Docopt().Apply("Usage: prog (add|rm)", "add");
51 | Assert.AreEqual(expected, actual);
52 | }
53 |
54 | [Test]
55 | public void Optional_either_second_specified()
56 | {
57 | var expected = new Dictionary
58 | {
59 | {"add", new ValueObject(false)},
60 | {"rm", new ValueObject(true)}
61 | };
62 | var actual = new Docopt().Apply("Usage: prog (add|rm)", "rm");
63 | Assert.AreEqual(expected, actual);
64 | }
65 |
66 | [Test]
67 | public void Required_both_specified()
68 | {
69 | var expected = new Dictionary
70 | {
71 | {"a", new ValueObject(true)},
72 | {"b", new ValueObject(true)}
73 | };
74 | var actual = new Docopt().Apply("Usage: prog a b", "a b");
75 | Assert.AreEqual(expected, actual);
76 | }
77 |
78 | [Test]
79 | public void Required_wrong_order()
80 | {
81 | Assert.Throws(() => new Docopt().Apply("Usage: prog a b", "b a"));
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/src/Examples/NavalFate/NavalFate.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {2B454F8B-D702-4281-80DF-367142007B0C}
8 | Exe
9 | Properties
10 | NavalFate
11 | NavalFate
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 | {d87f19b8-a15f-4bc2-8e1c-47cc6038a0df}
53 | DocoptNet
54 |
55 |
56 |
57 |
64 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/SyntaxTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using NUnit.Framework;
3 |
4 | namespace DocoptNet.Tests
5 | {
6 | [TestFixture]
7 | public class SyntaxTests
8 | {
9 | [Test]
10 | public void Missing_closing_square_bracket()
11 | {
12 | Assert.Throws(
13 | () => new Docopt().Apply("Usage: prog [a [b]"));
14 |
15 | }
16 |
17 | [Test]
18 | public void Missing_opening_paren()
19 | {
20 | Assert.Throws(
21 | () => new Docopt().Apply("Usage: prog [a [b] ] c )"));
22 |
23 | }
24 |
25 | [Test]
26 | public void Detect_double_dash()
27 | {
28 | var expected = new Dictionary
29 | {
30 | {"-o", new ValueObject(false)},
31 | {"", new ValueObject("-o")},
32 | {"--", new ValueObject(true)}
33 | };
34 | var actual = new Docopt().Apply("usage: prog [-o] [--] \nOptions: -o", "-- -o");
35 | Assert.AreEqual(expected, actual);
36 | }
37 |
38 | [Test]
39 | public void No_double_dash()
40 | {
41 | var expected = new Dictionary
42 | {
43 | {"-o", new ValueObject(true)},
44 | {"", new ValueObject("1")},
45 | {"--", new ValueObject(false)}
46 | };
47 | var actual = new Docopt().Apply("usage: prog [-o] [--] \nOptions: -o", "-o 1");
48 | Assert.AreEqual(expected, actual);
49 | }
50 |
51 | [Test]
52 | public void Double_dash_not_allowed() // FIXME?
53 | {
54 | Assert.Throws(
55 | () => new Docopt().Apply("usage: prog [-o] \noptions:-o", "-- -o"));
56 |
57 | }
58 |
59 | [Test]
60 | public void No_usage()
61 | {
62 | Assert.Throws(
63 | () => new Docopt().Apply("no usage with colon here"));
64 |
65 | }
66 |
67 | [Test]
68 | public void Duplicate_usage()
69 | {
70 | Assert.Throws(
71 | () => new Docopt().Apply("usage: here \n\n and again usage: here"));
72 |
73 | }
74 |
75 | [Test]
76 | public void Test_issue_71_double_dash_is_not_a_valid_option_argument()
77 | {
78 | Assert.Throws(
79 | () => new Docopt().Apply("usage: prog [--log=LEVEL] [--] ...", "--log -- 1 2"));
80 |
81 | Assert.Throws(
82 | () => new Docopt().Apply("usage: prog [-l LEVEL] [--] ...\r\n" +
83 | "options: -l LEVEL", "-l -- 1 2"));
84 | }
85 |
86 | }
87 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/CountMultipleFlagsTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using NUnit.Framework;
3 |
4 | namespace DocoptNet.Tests
5 | {
6 | [TestFixture]
7 | public class CountMultipleFlagsTests
8 | {
9 | [Test]
10 | public void Simple_flag()
11 | {
12 | var expected = new Dictionary
13 | {
14 | {"-v", new ValueObject(true)}
15 | };
16 | var actual = new Docopt().Apply("Usage: prog [-v]", "-v");
17 | Assert.AreEqual(expected, actual);
18 | }
19 |
20 | [Test]
21 | public void Flag_0()
22 | {
23 | var expected = new Dictionary
24 | {
25 | {"-v", new ValueObject(0)}
26 | };
27 | var actual = new Docopt().Apply("Usage: prog [-vv]", "");
28 | Assert.AreEqual(expected, actual);
29 | }
30 |
31 | [Test]
32 | public void Flag_1()
33 | {
34 | var expected = new Dictionary
35 | {
36 | {"-v", new ValueObject(1)}
37 | };
38 | var actual = new Docopt().Apply("Usage: prog [-vv]", "-v");
39 | Assert.AreEqual(expected, actual);
40 | }
41 |
42 | [Test]
43 | public void Flag_2()
44 | {
45 | var expected = new Dictionary
46 | {
47 | {"-v", new ValueObject(2)}
48 | };
49 | var actual = new Docopt().Apply("Usage: prog [-vv]", "-vv");
50 | Assert.AreEqual(expected, actual);
51 | }
52 |
53 | [Test]
54 | public void Flag_too_many()
55 | {
56 | Assert.Throws(() => new Docopt().Apply("Usage: prog [-vv]", "-vvv"));
57 | }
58 |
59 | [Test]
60 | public void Flag_3()
61 | {
62 | var expected = new Dictionary
63 | {
64 | {"-v", new ValueObject(3)}
65 | };
66 | var actual = new Docopt().Apply("Usage: prog [-v | -vv | -vvv]", "-vvv");
67 | Assert.AreEqual(expected, actual);
68 | }
69 |
70 | [Test]
71 | public void Flag_one_or_more()
72 | {
73 | var expected = new Dictionary
74 | {
75 | {"-v", new ValueObject(6)}
76 | };
77 | var actual = new Docopt().Apply("Usage: prog -v...", "-vvvvvv");
78 | Assert.AreEqual(expected, actual);
79 | }
80 |
81 | [Test]
82 | public void Flag_long_2()
83 | {
84 | var expected = new Dictionary
85 | {
86 | {"--ver", new ValueObject(2)}
87 | };
88 | var actual = new Docopt().Apply("Usage: prog [--ver --ver]", "--ver --ver");
89 | Assert.AreEqual(expected, actual);
90 | }
91 |
92 | }
93 | }
--------------------------------------------------------------------------------
/src/T4DocoptNetHostApp/T4DocoptNet.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using DocoptNet;
5 |
6 | namespace T4DocoptNetHostApp
7 | {
8 | // Generated class for Another.usage.txt
9 | public class AnotherArgs
10 | {
11 | public const string USAGE = @"Test host app for T4 Docopt.NET
12 |
13 | Usage:
14 | other command1 ARG [-o --long=ARG --switch -v]
15 | other command2
16 |
17 | Options:
18 | -o A string with some double ""quotes"".
19 | ";
20 | private readonly IDictionary _args;
21 | public AnotherArgs(ICollection argv, bool help = true,
22 | object version = null, bool optionsFirst = false, bool exit = false)
23 | {
24 | _args = new Docopt().Apply(USAGE, argv, help, version, optionsFirst, exit);
25 | }
26 |
27 | public IDictionary Args
28 | {
29 | get { return _args; }
30 | }
31 |
32 | public bool CmdCommand1 { get { return _args["command1"].IsTrue; } }
33 | public string ArgArg { get { return _args["ARG"].ToString(); } }
34 | public bool OptO { get { return _args["-o"].IsTrue; } }
35 | public string OptLong { get { return _args["--long"].ToString(); } }
36 | public bool OptSwitch { get { return _args["--switch"].IsTrue; } }
37 | public bool OptV { get { return _args["-v"].IsTrue; } }
38 | public bool CmdCommand2 { get { return _args["command2"].IsTrue; } }
39 |
40 | }
41 |
42 | // Generated class for Main.usage.txt
43 | public class MainArgs
44 | {
45 | public const string USAGE = @"Test host app for T4 Docopt.NET
46 |
47 | Usage:
48 | prog command ARG [OPTIONALARG] [-o -s= --long=ARG --switch]
49 | prog files FILE...
50 |
51 | Options:
52 | -o Short switch.
53 | -s= Short option with arg.
54 | --long=ARG Long option with arg.
55 | --switch Long switch.
56 |
57 | Explanation:
58 | This is a test usage file.
59 | ";
60 | private readonly IDictionary _args;
61 | public MainArgs(ICollection argv, bool help = true,
62 | object version = null, bool optionsFirst = false, bool exit = false)
63 | {
64 | _args = new Docopt().Apply(USAGE, argv, help, version, optionsFirst, exit);
65 | }
66 |
67 | public IDictionary Args
68 | {
69 | get { return _args; }
70 | }
71 |
72 | public bool CmdCommand { get { return _args["command"].IsTrue; } }
73 | public string ArgArg { get { return _args["ARG"].ToString(); } }
74 | public string ArgMyarg { get { return _args[""].ToString(); } }
75 | public string ArgOptionalarg { get { return _args["OPTIONALARG"].ToString(); } }
76 | public bool OptO { get { return _args["-o"].IsTrue; } }
77 | public string OptS { get { return _args["-s"].ToString(); } }
78 | public string OptLong { get { return _args["--long"].ToString(); } }
79 | public bool OptSwitch { get { return _args["--switch"].IsTrue; } }
80 | public bool CmdFiles { get { return _args["files"].IsTrue; } }
81 | public ArrayList ArgFile { get { return _args["FILE"].AsList; } }
82 |
83 | }
84 |
85 |
86 | }
87 |
88 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/OptionalMatchTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class OptionalMatchTests
7 | {
8 | [Test]
9 | public void Should_match_option()
10 | {
11 | Assert.AreEqual(
12 | new MatchResult(true,
13 | new Pattern[0],
14 | new Pattern[] {new Option("-a")}),
15 | new Optional(new Option("-a")).Match(new Pattern[] {new Option("-a")})
16 | );
17 | }
18 |
19 | [Test]
20 | public void Should_match_empty()
21 | {
22 | Assert.AreEqual(
23 | new MatchResult(true,
24 | new Pattern[0],
25 | new Pattern[0]),
26 | new Optional(new Option("-a")).Match(new Pattern[0])
27 | );
28 | }
29 |
30 | [Test]
31 | public void Should_not_collect_other_opt()
32 | {
33 | Assert.AreEqual(
34 | new MatchResult(true,
35 | new Pattern[] {new Option("-x")},
36 | new Pattern[0]
37 | ),
38 | new Optional(new Option("-a")).Match(new Pattern[] {new Option("-x")})
39 | );
40 | }
41 |
42 | [Test]
43 | public void Should_match_first_option()
44 | {
45 | Assert.AreEqual(
46 | new MatchResult(true,
47 | new Pattern[0],
48 | new Pattern[] {new Option("-a")}),
49 | new Optional(new Option("-a"), new Option("-b")).Match(new Pattern[] {new Option("-a")})
50 | );
51 | }
52 |
53 | [Test]
54 | public void Should_not_collect_other_option_2()
55 | {
56 | Assert.AreEqual(
57 | new MatchResult(true,
58 | new Pattern[] {new Option("-x")},
59 | new Pattern[0]),
60 | new Optional(new Option("-a"), new Option("-b")).Match(new Pattern[] {new Option("-x")})
61 | );
62 | }
63 |
64 | [Test]
65 | public void Should_match_optional_arg()
66 | {
67 | Assert.AreEqual(
68 | new MatchResult(true,
69 | new Pattern[0],
70 | new Pattern[] { new Argument("N", new ValueObject(9)) }),
71 | new Optional(new Argument("N")).Match(new Pattern[] { new Argument(null, new ValueObject(9)) })
72 | );
73 | }
74 |
75 | [Test]
76 | public void Should_collect_all_except_other()
77 | {
78 | Assert.AreEqual(
79 | new MatchResult(true,
80 | new Pattern[] { new Option("-x") },
81 | new Pattern[] { new Option("-a"), new Option("-b") }),
82 | new Optional(new Option("-a"), new Option("-b")).Match(
83 | new Pattern[] { new Option("-b"), new Option("-x"), new Option("-a") })
84 | );
85 | }
86 | }
87 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/ParseArgvTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class ParseArgvTests
7 | {
8 | private readonly Option[] _options = new[]
9 | {new Option("-h"), new Option("-v", "--verbose"), new Option("-f", "--file", 1)};
10 |
11 | private Tokens TS(string s)
12 | {
13 | return new Tokens(s, typeof(DocoptInputErrorException));
14 | }
15 |
16 | [Test]
17 | public void Test_parse_argv_empty()
18 | {
19 | Assert.IsEmpty(Docopt.ParseArgv(TS(""), _options));
20 | }
21 |
22 | [Test]
23 | public void Test_parse_argv_one_opt()
24 | {
25 | Assert.AreEqual(new[] {new Option("-h", null, 0, new ValueObject(true))},
26 | Docopt.ParseArgv(TS("-h"), _options));
27 | }
28 |
29 | [Test]
30 | public void Test_parse_argv_short_and_long()
31 | {
32 | Assert.AreEqual(new[]
33 | {
34 | new Option("-h", null, 0, new ValueObject(true)),
35 | new Option("-v", "--verbose", 0, new ValueObject(true))
36 | },
37 | Docopt.ParseArgv(TS("-h --verbose"), _options));
38 | }
39 |
40 | [Test]
41 | public void Test_parse_argv_opt_with_arg()
42 | {
43 | Assert.AreEqual(new[]
44 | {
45 | new Option("-h", null, 0, new ValueObject(true)),
46 | new Option("-f", "--file", 1, "f.txt")
47 | },
48 | Docopt.ParseArgv(TS("-h --file f.txt"), _options));
49 | }
50 |
51 | [Test]
52 | public void Test_parse_argv_with_arg()
53 | {
54 | Assert.AreEqual(
55 | new Pattern[]
56 | {
57 | new Option("-h", null, 0, new ValueObject(true)),
58 | new Option("-f", "--file", 1, "f.txt"),
59 | new Argument(null, "arg")
60 | },
61 | Docopt.ParseArgv(TS("-h --file f.txt arg"), _options));
62 | }
63 |
64 | [Test]
65 | public void Test_parse_argv_two_args()
66 | {
67 | Assert.AreEqual(
68 | new Pattern[]
69 | {
70 | new Option("-h", null, 0, new ValueObject(true)),
71 | new Option("-f", "--file", 1, "f.txt"),
72 | new Argument(null, "arg"),
73 | new Argument(null, "arg2")
74 | },
75 | Docopt.ParseArgv(TS("-h --file f.txt arg arg2"), _options));
76 | }
77 |
78 | [Test]
79 | public void Test_parse_argv_with_double_dash()
80 | {
81 | Assert.AreEqual(
82 | new Pattern[]
83 | {
84 | new Option("-h", null, 0, new ValueObject(true)),
85 | new Argument(null, "arg"),
86 | new Argument(null, "--"),
87 | new Argument(null, "-v")
88 | },
89 | Docopt.ParseArgv(TS("-h arg -- -v"), _options));
90 | }
91 | }
92 | }
--------------------------------------------------------------------------------
/.paket/paket.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | true
6 |
7 | true
8 | $(MSBuildThisFileDirectory)
9 | $(MSBuildThisFileDirectory)..\
10 | /Library/Frameworks/Mono.framework/Commands/mono
11 | mono
12 |
13 |
14 |
15 | $(PaketToolsPath)paket.exe
16 | $(PaketToolsPath)paket.bootstrapper.exe
17 | "$(PaketExePath)"
18 | $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"
19 | "$(PaketBootStrapperExePath)" $(PaketBootStrapperCommandArgs)
20 | $(MonoPath) --runtime=v4.0.30319 $(PaketBootStrapperExePath) $(PaketBootStrapperCommandArgs)
21 |
22 | $(MSBuildProjectDirectory)\paket.references
23 | $(MSBuildStartupDirectory)\paket.references
24 | $(MSBuildProjectFullPath).paket.references
25 | $(PaketCommand) restore --references-files "$(PaketReferences)"
26 | $(PaketBootStrapperCommand)
27 |
28 | RestorePackages; $(BuildDependsOn);
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/src/DocoptNet/LeafPattern.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace DocoptNet
6 | {
7 | ///
8 | /// Leaf/terminal node of a pattern tree.
9 | ///
10 | internal class LeafPattern: Pattern
11 | {
12 | private readonly string _name;
13 |
14 | protected LeafPattern(string name, ValueObject value=null)
15 | {
16 | _name = name;
17 | Value = value;
18 | }
19 |
20 | protected LeafPattern()
21 | {
22 | }
23 |
24 | public override string Name
25 | {
26 | get { return _name; }
27 | }
28 |
29 | public override ICollection Flat(params Type[] types)
30 | {
31 | if (types == null) throw new ArgumentNullException("types");
32 | if (types.Length == 0 || types.Contains(this.GetType()))
33 | {
34 | return new Pattern[] { this };
35 | }
36 | return new Pattern[] {};
37 | }
38 |
39 | public virtual SingleMatchResult SingleMatch(IList patterns)
40 | {
41 | return new SingleMatchResult();
42 | }
43 |
44 | public override MatchResult Match(IList left, IEnumerable collected = null)
45 | {
46 | var coll = collected ?? new List();
47 | var sresult = SingleMatch(left);
48 | var match = sresult.Match;
49 | if (match == null)
50 | {
51 | return new MatchResult(false, left, coll);
52 | }
53 | var left_ = new List();
54 | left_.AddRange(left.Take(sresult.Position));
55 | left_.AddRange(left.Skip(sresult.Position + 1));
56 | var sameName = coll.Where(a => a.Name == Name).ToList();
57 | if (Value != null && (Value.IsList || Value.IsOfTypeInt))
58 | {
59 | var increment = new ValueObject(1);
60 | if (!Value.IsOfTypeInt)
61 | {
62 | increment = match.Value.IsString ? new ValueObject(new [] {match.Value}) : match.Value;
63 | }
64 | if (sameName.Count == 0)
65 | {
66 | match.Value = increment;
67 | var res = new List(coll) {match};
68 | return new MatchResult(true, left_, res);
69 | }
70 | sameName[0].Value.Add(increment);
71 | return new MatchResult(true, left_, coll);
72 | }
73 | var resColl = new List();
74 | resColl.AddRange(coll);
75 | resColl.Add(match);
76 | return new MatchResult(true, left_, resColl);
77 | }
78 |
79 | public override string ToString()
80 | {
81 | return string.Format("{0}({1}, {2})", GetType().Name, Name, Value);
82 | }
83 | }
84 |
85 | internal class SingleMatchResult
86 | {
87 | public SingleMatchResult(int index, Pattern match)
88 | {
89 | Position = index;
90 | Match = match;
91 | }
92 |
93 | public SingleMatchResult()
94 | {
95 | }
96 |
97 | public int Position { get; set; }
98 | public Pattern Match { get; set; }
99 | }
100 | }
--------------------------------------------------------------------------------
/src/T4DocoptNetHostApp/T4DocoptNet.tt:
--------------------------------------------------------------------------------
1 | <#
2 | /*
3 | T4DocopNet Version 0.1.0
4 | */
5 | #>
6 | <#@ template language="C#" debug="true" hostspecific="true" #>
7 | <#@ assembly name="System.Core" #>
8 | <#@ assembly name="Microsoft.VisualStudio.Shell.Interop" #>
9 | <#@ assembly name="EnvDTE" #>
10 | <#@ assembly name="EnvDTE80" #>
11 | <#@ assembly name="VSLangProj" #>
12 | <#@ assembly name="System.Xml" #>
13 | <#@ assembly name="System.Xml.Linq" #>
14 | <#
15 | // This directive will be updated at package install time
16 | // by install.ps1. It can also be set manually to point
17 | // to the right path.
18 | #>
19 | <#@ assembly name="$(ProjectDir)$(OutDir)DocoptNet.dll" #>
20 | <#@ import namespace="System.Collections.Generic" #>
21 | <#@ import namespace="System.IO" #>
22 | <#@ import namespace="System.Linq" #>
23 | <#@ import namespace="DocoptNet" #>
24 | <#@ import namespace="System.Text" #>
25 | <#@ import namespace="System.Text.RegularExpressions" #>
26 | <#@ import namespace="Microsoft.VisualStudio.Shell.Interop" #>
27 | <#@ import namespace="EnvDTE" #>
28 | <#@ import namespace="EnvDTE80" #>
29 | <#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
30 |
31 | using System.Collections;
32 | using System.Collections.Generic;
33 | using DocoptNet;
34 |
35 | namespace <#= System.Runtime.Remoting.Messaging.CallContext.LogicalGetData("NamespaceHint") #>
36 | {
37 | <#
38 | var templateDir = Path.GetDirectoryName(Host.TemplateFile);
39 | var files = Directory.EnumerateFiles(templateDir).Where(f => f.EndsWith(".usage.txt"));
40 | foreach (var file in files)
41 | {
42 | var entry = new UsageFileEntry(file);
43 | #>
44 | // Generated class for <#= Path.GetFileName(entry.FileName) #>
45 | public class <#= entry.Name #>Args
46 | {
47 | public const string USAGE = @"<#= entry.Usage #>";
48 | private readonly IDictionary _args;
49 | public <#= entry.Name #>Args(ICollection argv, bool help = true,
50 | object version = null, bool optionsFirst = false, bool exit = false)
51 | {
52 | _args = new Docopt().Apply(USAGE, argv, help, version, optionsFirst, exit);
53 | }
54 |
55 | public IDictionary Args
56 | {
57 | get { return _args; }
58 | }
59 |
60 | <#
61 | var s = new Docopt().GenerateCode(entry.Usage);
62 | PushIndent(" ");
63 | Write(s);
64 | ClearIndent();
65 | #>
66 | }
67 |
68 | <#
69 | }
70 |
71 | #>
72 | }
73 |
74 | <#+
75 | class UsageFileEntry
76 | {
77 | public string FileName;
78 | public string Name;
79 | public string Usage;
80 | public UsageFileEntry(string fileName)
81 | {
82 | FileName = fileName;
83 | Name = ExtractName(fileName);
84 | Usage = File.ReadAllText(fileName).Replace("\"", "\"\"");
85 | }
86 |
87 | private static string ExtractName(string fileName)
88 | {
89 |
90 | var s = Path.GetFileName(fileName).Replace(".usage.txt", "");
91 | var res = "";
92 | var first = true;
93 | foreach (char c in s)
94 | {
95 | if (char.IsLetterOrDigit(c))
96 | {
97 | res += first ? char.ToUpperInvariant(c) : char.ToLowerInvariant(c);
98 | first = false;
99 | }
100 | else
101 | {
102 | res += "_";
103 | }
104 | }
105 | return res;
106 | }
107 | }
108 |
109 | /* IMPORTANT: Do not add blanks after this last tag as it would break the T4 generation
110 | * See http://stackoverflow.com/questions/11379471/error-a-template-containing-a-class-feature-must-end-with-a-class-feature
111 | */
112 | #>
--------------------------------------------------------------------------------
/src/T4DocoptNetHostApp/T4DocoptNetHostApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {5A641DFB-CB1A-4044-AF52-554CC8904449}
8 | Exe
9 | Properties
10 | T4DocoptNetHostApp
11 | T4DocoptNetHostApp
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | True
48 | True
49 | T4DocoptNet.tt
50 |
51 |
52 |
53 |
54 |
55 | TextTemplatingFileGenerator
56 | T4DocoptNet.cs
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | Designer
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | {d87f19b8-a15f-4bc2-8e1c-47cc6038a0df}
73 | DocoptNet
74 |
75 |
76 |
77 |
84 |
--------------------------------------------------------------------------------
/src/DocoptNet/Option.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Text.RegularExpressions;
5 |
6 | namespace DocoptNet
7 | {
8 | internal class Option : LeafPattern
9 | {
10 | public string ShortName { get; private set; }
11 | public string LongName { get; private set; }
12 | public int ArgCount { get; private set; }
13 |
14 | public Option(string shortName = null, string longName = null, int argCount = 0, ValueObject value = null)
15 | : base()
16 | {
17 | ShortName = shortName;
18 | LongName = longName;
19 | ArgCount = argCount;
20 | var v = value ?? new ValueObject(false);
21 | Value = (v.IsFalse && argCount > 0) ? null : v;
22 | }
23 |
24 | public Option(string shortName, string longName, int argCount, string value)
25 | : this(shortName, longName, argCount, new ValueObject(value))
26 | {
27 | }
28 |
29 | public override string Name
30 | {
31 | get { return LongName ?? ShortName; }
32 | }
33 |
34 | public override Node ToNode()
35 | {
36 | return new OptionNode(this.Name.TrimStart('-'), this.ArgCount == 0 ? ValueType.Bool : ValueType.String);
37 | }
38 |
39 | public override string GenerateCode()
40 | {
41 | var s = Name.ToLowerInvariant();
42 | s = "Opt" + GenerateCodeHelper.ConvertDashesToCamelCase(s);
43 |
44 | if (ArgCount == 0)
45 | {
46 | return string.Format("public bool {0} {{ get {{ return _args[\"{1}\"].IsTrue; }} }}", s, Name);
47 | }
48 | var defaultValue = Value == null ? "null" : string.Format("\"{0}\"", Value);
49 | return string.Format("public string {0} {{ get {{ return null == _args[\"{1}\"] ? {2} : _args[\"{1}\"].ToString(); }} }}", s, Name, defaultValue);
50 | }
51 |
52 | public override SingleMatchResult SingleMatch(IList left)
53 | {
54 | for (var i = 0; i < left.Count; i++)
55 | {
56 | if (left[i].Name == Name)
57 | return new SingleMatchResult(i, left[i]);
58 | }
59 | return new SingleMatchResult();
60 | }
61 |
62 | public override string ToString()
63 | {
64 | return string.Format("Option({0},{1},{2},{3})", ShortName, LongName, ArgCount, Value);
65 | }
66 |
67 | private const string DESC_SEPARATOR = " ";
68 |
69 | public static Option Parse(string optionDescription)
70 | {
71 | if (optionDescription == null) throw new ArgumentNullException("optionDescription");
72 |
73 | string shortName = null;
74 | string longName = null;
75 | var argCount = 0;
76 | var value = new ValueObject(false);
77 | var p = new StringPartition(optionDescription, DESC_SEPARATOR);
78 | var options = p.LeftString;
79 | var description = p.RightString;
80 | foreach (var s in options.Split(" \t,=".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
81 | {
82 | if (s.StartsWith("--"))
83 | longName = s;
84 | else if (s.StartsWith("-"))
85 | {
86 | shortName = s;
87 | }
88 | else
89 | {
90 | argCount = 1;
91 | }
92 | }
93 | if (argCount > 0)
94 | {
95 | var r = new Regex(@"\[default: (.*)\]", RegexOptions.IgnoreCase);
96 | var m = r.Match(description);
97 | value = m.Success ? new ValueObject(m.Groups[1].Value) : null;
98 | }
99 | return new Option(shortName, longName, argCount, value);
100 | }
101 | }
102 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/GetNodesTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text.RegularExpressions;
3 | using NUnit.Framework;
4 |
5 | namespace DocoptNet.Tests
6 | {
7 | [TestFixture]
8 | public class GetNodesTests
9 | {
10 | [Test]
11 | public void Should_get_nodes()
12 | {
13 | const string USAGE = @"Test host app for T4 Docopt.NET
14 |
15 | Usage:
16 | prog command ARG [OPTIONALARG] [-o -s= --long=ARG --switch]
17 | prog files FILE...
18 |
19 | Options:
20 | -o --opt Short switch with a longer name. The longer name is the ""main"" one.
21 | -s= Short option with arg.
22 | --long=ARG Long option with arg.
23 | --switch Long switch. [default: false]
24 |
25 | Explanation:
26 | This is a test ""usage"".
27 | ";
28 |
29 | var actual = new Docopt().GetNodes(USAGE);
30 |
31 | CollectionAssert.AreEqual(
32 | new Node[]
33 | {
34 | new CommandNode ("command"),
35 | new ArgumentNode("ARG", ValueType.String),
36 | new ArgumentNode("", ValueType.String),
37 | new ArgumentNode("OPTIONALARG", ValueType.String),
38 | new OptionNode ("opt", ValueType.Bool),
39 | new OptionNode ("s", ValueType.String),
40 | new OptionNode ("long", ValueType.String),
41 | new OptionNode ("switch", ValueType.Bool),
42 | new CommandNode ("files"),
43 | new ArgumentNode("FILE", ValueType.List),
44 | },
45 | actual);
46 | }
47 |
48 | [Test]
49 | public void Should_return_duplicates_so_caller_knows_which_args_are_after_each_command()
50 | {
51 | const string USAGE = @"Test for duplicate commands and arguments.
52 | Usage:
53 | prog command ARG [OPTIONALARG] [-o -s= --long=ARG --switch]
54 | prog command ARG [OPTIONALARG] [-o -s= --long=ARG --switch] FILE...
55 | prog diff-command [OPTIONALARG] ARG
56 |
57 | Options:
58 | -o --option Short & long option flag, the long will be used as it's more descriptive.
59 | -s= Short option with arg.
60 | --long=ARG Long option with arg.
61 | --switch Long switch.
62 | ";
63 |
64 | var actual = new Docopt().GetNodes(USAGE);
65 |
66 | CollectionAssert.AreEqual(
67 | new Node[]
68 | {
69 | new CommandNode ("command"),
70 | new ArgumentNode("ARG", ValueType.String),
71 | new ArgumentNode("", ValueType.String),
72 | new ArgumentNode("OPTIONALARG", ValueType.String),
73 | new OptionNode ("option", ValueType.Bool),
74 | new OptionNode ("s", ValueType.String),
75 | new OptionNode ("long", ValueType.String),
76 | new OptionNode ("switch", ValueType.Bool),
77 | new CommandNode ("command"),
78 | new ArgumentNode("ARG", ValueType.String),
79 | new ArgumentNode("", ValueType.String),
80 | new ArgumentNode("OPTIONALARG", ValueType.String),
81 | new OptionNode ("option", ValueType.Bool),
82 | new OptionNode ("s", ValueType.String),
83 | new OptionNode ("long", ValueType.String),
84 | new OptionNode ("switch", ValueType.Bool),
85 | new ArgumentNode("FILE", ValueType.List),
86 | new CommandNode ("diff-command"),
87 | new ArgumentNode("", ValueType.String),
88 | new ArgumentNode("OPTIONALARG", ValueType.String),
89 | new ArgumentNode("ARG", ValueType.String),
90 | },
91 | actual);
92 | }
93 | }
94 | }
--------------------------------------------------------------------------------
/src/DocoptNet/DocoptNet.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net40;netstandard1.5;netstandard2.0
5 | DocoptNet
6 | 0.6.1.10
7 | DocoptNet.snk
8 | true
9 | true
10 | DocoptNet
11 | Copyright (c) 2013 Dinh Doan Van Bien, dinh@doanvanbien.com
12 | 1.6.0
13 | 1.6.0
14 | false
15 | false
16 | docopt.net
17 | https://github.com/docopt/docopt.net/blob/master/LICENSE-MIT
18 | https://github.com/docopt/docopt.net
19 | https://secure.gravatar.com/avatar/e82bc289285e348387313a00cfd84979?s=400&d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-user-420.png
20 | docopt.net, a beautiful command-line parser
21 | Dinh Doan Van Bien;Vladimir Keleshev
22 | docopt.net is the .net version of the docopt python beautiful command line parser. docopt.net helps you define an interface for your command-line app, and automatically generate a parser for it. docopt.net is based on conventions that have been used for decades in help messages and man pages for program interface description. Interface description in docopt.net is such a help message, but formalized. Check out http://docopt.org for a more detailed explanation.
23 | Quick example:
24 | var arguments = new Docopt().Apply("Usage: prog [-a] [-b] FILE", args);
25 | if (arguments["-a"].IsTrue) {{ ... }}
26 |
27 |
28 | - T4DocoptNet.tt assembly path fix.
29 | - Added support for .net core RC2
30 |
31 | Copyright (c) 2012-2014 Vladimir Keleshev, Dinh Doan Van Bien
32 | parser;command line argument;option library;syntax;shell;beautiful;posix;python;console;command-line;docopt
33 | 1.6.0
34 | 1.6.0
35 |
36 |
37 |
38 |
39 | content\Main.usage.txt
40 | true
41 |
42 |
43 | content\T4DocoptNet.tt
44 | true
45 |
46 |
47 | content\T4DocoptNet.tt.hooks.t4
48 | true
49 |
50 |
51 | content\T4DocoptNet.tt.settings.xml
52 | true
53 |
54 |
55 | tools\install.ps1
56 | true
57 |
58 |
59 |
60 |
61 |
62 | 4.3.0
63 |
64 |
65 |
66 |
67 |
68 | 4.3.0
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/src/DocoptNet/ValueObject.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Linq;
4 |
5 | namespace DocoptNet
6 | {
7 | public class ValueObject
8 | {
9 | public object Value { get; private set; }
10 |
11 | internal ValueObject(object obj)
12 | {
13 | if (obj is ArrayList)
14 | {
15 | Value = new ArrayList(obj as ArrayList);
16 | return;
17 | }
18 | if (obj is ICollection)
19 | {
20 | Value = new ArrayList(obj as ICollection);
21 | return;
22 | }
23 | Value = obj;
24 | }
25 |
26 | internal ValueObject()
27 | {
28 | Value = null;
29 | }
30 |
31 | public bool IsNullOrEmpty
32 | {
33 | get { return Value == null || Value.ToString() == ""; }
34 | }
35 |
36 | public bool IsFalse
37 | {
38 | get { return (Value as bool?) == false; }
39 | }
40 |
41 | public bool IsTrue
42 | {
43 | get { return (Value as bool?) == true; }
44 | }
45 |
46 | public bool IsList
47 | {
48 | get { return Value is ArrayList; }
49 | }
50 |
51 | internal bool IsOfTypeInt
52 | {
53 | get { return Value is int?; }
54 | }
55 |
56 | public bool IsInt
57 | {
58 | get
59 | {
60 | int value;
61 | return Value != null && (Value is int || Int32.TryParse(Value.ToString(), out value));
62 | }
63 | }
64 |
65 | public int AsInt
66 | {
67 | get { return IsList ? 0 : Convert.ToInt32(Value); }
68 | }
69 |
70 | public bool IsString
71 | {
72 | get { return Value is string; }
73 | }
74 |
75 | public override bool Equals(object obj)
76 | {
77 | //
78 | // See the full list of guidelines at
79 | // http://go.microsoft.com/fwlink/?LinkID=85237
80 | // and also the guidance for operator== at
81 | // http://go.microsoft.com/fwlink/?LinkId=85238
82 | //
83 |
84 | if (obj == null || GetType() != obj.GetType())
85 | {
86 | return false;
87 | }
88 |
89 | var v = (obj as ValueObject).Value;
90 | if (Value == null && v == null) return true;
91 | if (Value == null || v == null) return false;
92 | if (IsList || (obj as ValueObject).IsList)
93 | return Value.ToString().Equals(v.ToString());
94 | return Value.Equals(v);
95 | }
96 |
97 | public override int GetHashCode()
98 | {
99 | return ToString().GetHashCode();
100 | }
101 |
102 | public override string ToString()
103 | {
104 | if (IsList)
105 | {
106 | var l = (from object v in AsList select v.ToString()).ToList();
107 | return string.Format("[{0}]", String.Join(", ", l));
108 | }
109 | return (Value ?? "").ToString();
110 | }
111 |
112 | internal void Add(ValueObject increment)
113 | {
114 | if (increment == null) throw new ArgumentNullException("increment");
115 |
116 | if (increment.Value == null) throw new InvalidOperationException("increment.Value is null");
117 |
118 | if (Value == null) throw new InvalidOperationException("Value is null");
119 |
120 | if (increment.IsOfTypeInt)
121 | {
122 | if (IsList)
123 | (Value as ArrayList).Add(increment.AsInt);
124 | else
125 | Value = increment.AsInt + AsInt;
126 | }
127 | else
128 | {
129 | var l = new ArrayList();
130 | if (IsList)
131 | {
132 | l.AddRange(AsList);
133 | }
134 | else
135 | {
136 | l.Add(Value);
137 | }
138 | if (increment.IsList)
139 | {
140 | l.AddRange(increment.AsList);
141 | }
142 | else
143 | {
144 | l.Add(increment);
145 | }
146 | Value = l;
147 | }
148 | }
149 |
150 | public ArrayList AsList
151 | {
152 | get { return IsList ? (Value as ArrayList) : (new ArrayList(new[] {Value})); }
153 | }
154 | }
155 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/OneOrMoreMatchTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class OneOrMoreMatchTests
7 | {
8 | [Test]
9 | public void Should_match_arg()
10 | {
11 | Assert.AreEqual(
12 | new MatchResult(true,
13 | new Pattern[0],
14 | new Pattern[] {new Argument("N", new ValueObject(9))}),
15 | new OneOrMore(new Argument("N")).Match(new Pattern[] {new Argument(null, new ValueObject(9))})
16 | );
17 | }
18 |
19 | [Test]
20 | public void Should_not_match_empty()
21 | {
22 | Assert.AreEqual(
23 | new MatchResult(false,
24 | new Pattern[0],
25 | new Pattern[0]),
26 | new OneOrMore(new Argument("N")).Match(new Pattern[0])
27 | );
28 | }
29 |
30 | [Test]
31 | public void Should_not_match_option()
32 | {
33 | Assert.AreEqual(
34 | new MatchResult(false,
35 | new Pattern[] {new Option("-x")},
36 | new Pattern[0]
37 | ),
38 | new OneOrMore(new Argument("N")).Match(new Pattern[] {new Option("-x")})
39 | );
40 | }
41 |
42 | [Test]
43 | public void Should_match_all_args()
44 | {
45 | Assert.AreEqual(
46 | new MatchResult(true,
47 | new Pattern[0],
48 | new Pattern[]
49 | {new Argument("N", new ValueObject(9)), new Argument("N", new ValueObject(8))}),
50 | new OneOrMore(new Argument("N")).Match(new Pattern[]
51 | {new Argument(null, new ValueObject(9)), new Argument(null, new ValueObject(8))})
52 | );
53 | }
54 |
55 | [Test]
56 | public void Should_not_match_unknown_opt()
57 | {
58 | Assert.AreEqual(
59 | new MatchResult(true,
60 | new Pattern[] {new Option("-x")},
61 | new Pattern[]
62 | {new Argument("N", new ValueObject(9)), new Argument("N", new ValueObject(8))}),
63 | new OneOrMore(new Argument("N")).Match(new Pattern[]
64 | {new Argument(null, new ValueObject(9)), new Option("-x"), new Argument(null, new ValueObject(8))})
65 | );
66 | }
67 |
68 | [Test]
69 | public void Should_not_match_unknown_arg()
70 | {
71 | Assert.AreEqual(
72 | new MatchResult(true,
73 | new Pattern[] {new Argument(null, new ValueObject(8))},
74 | new Pattern[] {new Option("-a"), new Option("-a")}
75 | ),
76 | new OneOrMore(new Option("-a")).Match(new Pattern[]
77 | {new Option("-a"), new Argument(null, new ValueObject(8)), new Option("-a")})
78 | );
79 | }
80 |
81 | [Test]
82 | public void Should_not_match_unknown_opt_and_arg()
83 | {
84 | Assert.AreEqual(
85 | new MatchResult(false,
86 | new Pattern[] {new Argument(null, new ValueObject(98)), new Option("-x")},
87 | new Pattern[0]),
88 | new OneOrMore(new Option("-a")).Match(new Pattern[]
89 | {new Argument(null, new ValueObject(98)), new Option("-x")})
90 | );
91 | }
92 |
93 | [Test]
94 | public void Should_match_all_opt_and_args()
95 | {
96 | Assert.AreEqual(
97 | new MatchResult(true,
98 | new Pattern[] {new Option("-x")},
99 | new Pattern[]
100 | {
101 | new Option("-a"), new Argument("N", new ValueObject(1)),
102 | new Option("-a"), new Argument("N", new ValueObject(2))
103 | }
104 | ),
105 | new OneOrMore(new Required(new Option("-a"), new Argument("N"))).Match(new Pattern[]
106 | {
107 | new Option("-a"), new Argument(null, new ValueObject(1)),
108 | new Option("-x"),
109 | new Option("-a"), new Argument(null, new ValueObject(2))
110 | })
111 | );
112 | }
113 |
114 | [Test]
115 | public void Should_match_optional_arg()
116 | {
117 | Assert.AreEqual(
118 | new MatchResult(true,
119 | new Pattern[0],
120 | new Pattern[] {new Argument("N", new ValueObject(9))}
121 | ),
122 | new OneOrMore(new Optional(new Argument("N"))).Match(new Pattern[]
123 | {new Argument(null, new ValueObject(9))})
124 | );
125 | }
126 | }
127 | }
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/ParsePatternTests.cs:
--------------------------------------------------------------------------------
1 | using NUnit.Framework;
2 |
3 | namespace DocoptNet.Tests
4 | {
5 | [TestFixture]
6 | public class ParsePatternTests
7 | {
8 | private readonly Option[] _options = new[] {new Option("-h"), new Option("-v", "--verbose"), new Option("-f", "--file", 1)};
9 |
10 | [Test]
11 | public void Test_parse_pattern_one_optional_option()
12 | {
13 | Assert.AreEqual(new Required(new Optional(new Option("-h"))), Docopt.ParsePattern("[ -h ]", _options));
14 | }
15 |
16 | [Test]
17 | public void Test_parse_pattern_optional_oneormore_arg()
18 | {
19 | Assert.AreEqual(new Required(new Optional(new OneOrMore(new Argument("ARG")))),
20 | Docopt.ParsePattern("[ ARG ... ]", _options));
21 | }
22 |
23 | [Test]
24 | public void Test_parse_pattern_either_options()
25 | {
26 | Assert.AreEqual(new Required(new Optional(new Either(new Option("-h"), new Option("-v", "--verbose")))),
27 | Docopt.ParsePattern("[ -h | -v ]", _options));
28 | }
29 |
30 | [Test]
31 | public void Test_parse_pattern_either_options_and_optional_arg_opt()
32 | {
33 | Assert.AreEqual(new Required(new Required(
34 | new Either(new Option("-h"),
35 | new Required(new Option("-v", "--verbose"),
36 | new Optional(new Option("-f", "--file", 1))
37 | )
38 | )
39 | )
40 | ),
41 | Docopt.ParsePattern("( -h | -v [ --file ] )", _options));
42 | }
43 |
44 | [Test]
45 | public void Test_parse_pattern_optional_and_oneormore_arg()
46 | {
47 | Assert.AreEqual(new Required(new Required(
48 | new Either(new Option("-h"),
49 | new Required(new Option("-v", "--verbose"),
50 | new Optional(new Option("-f", "--file", 1)),
51 | new OneOrMore(new Argument("N"))
52 | )
53 | )
54 | )
55 | ),
56 | Docopt.ParsePattern("(-h|-v[--file=]N...)", _options));
57 | }
58 |
59 | [Test]
60 | public void Test_parse_pattern_mix_of_either()
61 | {
62 | Assert.AreEqual(new Required(new Required(new Either(
63 | new Required(new Argument("N"),
64 | new Optional(new Either(new Argument("M"),
65 | new Required(
66 | new Either(
67 | new Argument("K"),
68 | new Argument("L")))
69 | )
70 | )
71 | )
72 | , new Required(new Argument("O"), new Argument("P"))))
73 | ),
74 | Docopt.ParsePattern("(N [M | (K | L)] | O P)", _options));
75 | }
76 |
77 | [Test]
78 | public void Test_parse_pattern_option_with_optional_arg()
79 | {
80 | Assert.AreEqual(new Required(new Optional(new Option("-h")), new Optional(new Argument("N"))),
81 | Docopt.ParsePattern("[ -h ] [N]", _options));
82 | }
83 |
84 | [Test]
85 | public void Test_parse_pattern_options_shortcut()
86 | {
87 | Assert.AreEqual(new Required(new Optional(new OptionsShortcut())),
88 | Docopt.ParsePattern("[options]", _options));
89 | }
90 |
91 | [Test]
92 | public void Test_parse_pattern_options_shortcut_with_arg()
93 | {
94 | Assert.AreEqual(new Required(new Optional(new OptionsShortcut()), new Argument("A")),
95 | Docopt.ParsePattern("[options] A", _options));
96 | }
97 |
98 | [Test]
99 | public void Test_parse_pattern_options_shortcut_with_long()
100 | {
101 | Assert.AreEqual(new Required(new Option("-v", "--verbose"), new Optional(new OptionsShortcut())),
102 | Docopt.ParsePattern("-v [options]", _options));
103 | }
104 |
105 | [Test]
106 | public void Test_parse_pattern_arg_upper_case()
107 | {
108 | Assert.AreEqual(new Required(new Argument("ADD")),
109 | Docopt.ParsePattern("ADD", _options));
110 | }
111 |
112 | [Test]
113 | public void Test_parse_pattern_arg_between_pointy_brackets()
114 | {
115 | Assert.AreEqual(new Required(new Argument("")),
116 | Docopt.ParsePattern("", _options));
117 | }
118 |
119 | [Test]
120 | public void Test_parse_pattern_command()
121 | {
122 | Assert.AreEqual(new Required(new Command("add")),
123 | Docopt.ParsePattern("add", _options));
124 | }
125 |
126 | }
127 | }
--------------------------------------------------------------------------------
/src/DocoptNet/Pattern.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Linq;
6 |
7 | namespace DocoptNet
8 | {
9 | internal abstract class Pattern
10 | {
11 | public ValueObject Value { get; set; }
12 |
13 | public virtual string Name
14 | {
15 | get { return ToString(); }
16 | }
17 |
18 | public virtual string GenerateCode()
19 | {
20 | return "// No code for " + Name;
21 | }
22 |
23 | public virtual Node ToNode()
24 | {
25 | return null;
26 | }
27 |
28 | // override object.Equals
29 | public override bool Equals(object obj)
30 | {
31 | //
32 | // See the full list of guidelines at
33 | // http://go.microsoft.com/fwlink/?LinkID=85237
34 | // and also the guidance for operator== at
35 | // http://go.microsoft.com/fwlink/?LinkId=85238
36 | //
37 |
38 | if (obj == null || GetType() != obj.GetType())
39 | {
40 | return false;
41 | }
42 |
43 | return ToString() == obj.ToString();
44 | }
45 |
46 | // override object.GetHashCode
47 | public override int GetHashCode()
48 | {
49 | return ToString().GetHashCode();
50 | }
51 |
52 | public virtual bool HasChildren
53 | {
54 | get { return false; }
55 | }
56 |
57 | public IList Children { get; set; }
58 |
59 | public Pattern Fix()
60 | {
61 | FixIdentities();
62 | FixRepeatingArguments();
63 | return this;
64 | }
65 |
66 | ///
67 | /// Make pattern-tree tips point to same object if they are equal.
68 | ///
69 | ///
70 | public void FixIdentities(ICollection uniq = null)
71 | {
72 | var listUniq = uniq ?? Flat().Distinct().ToList();
73 | for (int i = 0; i < Children.Count; i++)
74 | {
75 | var child = Children[i];
76 | if (!child.HasChildren)
77 | {
78 | Debug.Assert(listUniq.Contains(child));
79 | Children[i] = listUniq.First(p => p.Equals(child));
80 | }
81 | else
82 | {
83 | child.FixIdentities(listUniq);
84 | }
85 | }
86 | }
87 |
88 |
89 | public Pattern FixRepeatingArguments()
90 | {
91 | var transform = Transform(this);
92 | var either = transform.Children.Select(c => c.Children);
93 | foreach (var aCase in either)
94 | {
95 | var cx = aCase.ToList();
96 | var l = aCase.Where(e => cx.Count(c2 => c2.Equals(e)) > 1).ToList();
97 |
98 | foreach (var e in l)
99 | {
100 | if (e is Argument || (e is Option && (e as Option).ArgCount > 0))
101 | {
102 | if (e.Value == null)
103 | {
104 | e.Value = new ValueObject(new ArrayList());
105 | }
106 | else if (!e.Value.IsList)
107 | {
108 | e.Value =
109 | new ValueObject(e.Value.ToString()
110 | .Split(new char[0], StringSplitOptions.RemoveEmptyEntries));
111 | }
112 | }
113 | if (e is Command || (e is Option && (e as Option).ArgCount == 0))
114 | {
115 | e.Value = new ValueObject(0);
116 | }
117 | }
118 | }
119 | return this;
120 | }
121 |
122 | ///
123 | /// Expand pattern into an (almost) equivalent one, but with single Either.
124 | /// Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
125 | /// Quirks: [-a] => (-a), (-a...) => (-a -a)
126 | ///
127 | ///
128 | ///
129 | public static Either Transform(Pattern pattern)
130 | {
131 | var result = new List>();
132 | var groups = new List> {new List {pattern}};
133 | while (groups.Count > 0)
134 | {
135 | var children = groups[0];
136 | groups.RemoveAt(0);
137 | var parents = new[]
138 | {
139 | typeof (Required), typeof (Optional), typeof (OptionsShortcut), typeof (Either), typeof (OneOrMore)
140 | };
141 | if (parents.Any(t => children.Any(c => c.GetType() == t)))
142 | {
143 | var child = children.First(c => parents.Contains(c.GetType()));
144 | children.Remove(child);
145 | if (child is Either)
146 | {
147 | foreach (var c in (child as Either).Children)
148 | {
149 | var l = new List {c};
150 | l.AddRange(children);
151 | groups.Add(l);
152 | }
153 | }
154 | else if (child is OneOrMore)
155 | {
156 | var l = new List();
157 | l.AddRange((child as OneOrMore).Children);
158 | l.AddRange((child as OneOrMore).Children); // add twice
159 | l.AddRange(children);
160 | groups.Add(l);
161 | }
162 | else
163 | {
164 | var l = new List();
165 | if (child.HasChildren)
166 | l.AddRange(child.Children);
167 | l.AddRange(children);
168 | groups.Add(l);
169 | }
170 | }
171 | else
172 | {
173 | result.Add(children);
174 | }
175 | }
176 | return new Either(result.Select(r => new Required(r.ToArray()) as Pattern).ToArray());
177 | }
178 |
179 | public virtual MatchResult Match(IList left, IEnumerable collected = null)
180 | {
181 | return new MatchResult();
182 | }
183 |
184 | public abstract ICollection Flat(params Type[] types);
185 |
186 | ///
187 | /// Flattens the current patterns to the leaves only
188 | ///
189 | ///
190 | public IEnumerable Flat()
191 | {
192 | return Flat(new Type[0]);
193 | }
194 | }
195 | }
--------------------------------------------------------------------------------
/src/DocoptNet.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28010.2026
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".paket", ".paket", "{78331D52-9B59-4779-933C-EFE1C19D0D2B}"
7 | ProjectSection(SolutionItems) = preProject
8 | ..\paket.dependencies = ..\paket.dependencies
9 | EndProjectSection
10 | EndProject
11 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{AE631D61-6BE6-438F-A535-955BB9A0218F}"
12 | EndProject
13 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{DC286C58-6D9D-4B8B-9C0D-F6E8CDB0D28E}"
14 | ProjectSection(SolutionItems) = preProject
15 | ..\build\Bootstrap.proj = ..\build\Bootstrap.proj
16 | ..\build\Build.bat = ..\build\Build.bat
17 | ..\build\Main.proj = ..\build\Main.proj
18 | EndProjectSection
19 | EndProject
20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{B5A8AA26-1434-40D0-87BB-C1B8ED01F8D1}"
21 | ProjectSection(SolutionItems) = preProject
22 | NuGet\docopt.net.nuspec = NuGet\docopt.net.nuspec
23 | NuGet\install.ps1 = NuGet\install.ps1
24 | NuGet\Main.usage.txt = NuGet\Main.usage.txt
25 | EndProjectSection
26 | EndProject
27 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DocoptNet", "DocoptNet\DocoptNet.csproj", "{D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}"
28 | EndProject
29 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DocoptNet.Tests", "DocoptNet.Tests\DocoptNet.Tests.csproj", "{80A9BB30-873C-47E9-8314-5E53AC66E8B7}"
30 | EndProject
31 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NavalFate", "Examples\NavalFate\NavalFate.csproj", "{2B454F8B-D702-4281-80DF-367142007B0C}"
32 | EndProject
33 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testee", "Testee\Testee.csproj", "{C3490CAE-5A69-4852-BD61-50179D587D0D}"
34 | EndProject
35 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "T4DocoptNetHostApp", "T4DocoptNetHostApp\T4DocoptNetHostApp.csproj", "{5A641DFB-CB1A-4044-AF52-554CC8904449}"
36 | EndProject
37 | Global
38 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
39 | Debug|Any CPU = Debug|Any CPU
40 | Debug|Mixed Platforms = Debug|Mixed Platforms
41 | Debug|x86 = Debug|x86
42 | Release|Any CPU = Release|Any CPU
43 | Release|Mixed Platforms = Release|Mixed Platforms
44 | Release|x86 = Release|x86
45 | EndGlobalSection
46 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
47 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
49 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
50 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
51 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Debug|x86.ActiveCfg = Debug|Any CPU
52 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Debug|x86.Build.0 = Debug|Any CPU
53 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
54 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Release|Any CPU.Build.0 = Release|Any CPU
55 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
56 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Release|Mixed Platforms.Build.0 = Release|Any CPU
57 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Release|x86.ActiveCfg = Release|Any CPU
58 | {D87F19B8-A15F-4BC2-8E1C-47CC6038A0DF}.Release|x86.Build.0 = Release|Any CPU
59 | {80A9BB30-873C-47E9-8314-5E53AC66E8B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
60 | {80A9BB30-873C-47E9-8314-5E53AC66E8B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
61 | {80A9BB30-873C-47E9-8314-5E53AC66E8B7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
62 | {80A9BB30-873C-47E9-8314-5E53AC66E8B7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
63 | {80A9BB30-873C-47E9-8314-5E53AC66E8B7}.Debug|x86.ActiveCfg = Debug|Any CPU
64 | {80A9BB30-873C-47E9-8314-5E53AC66E8B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
65 | {80A9BB30-873C-47E9-8314-5E53AC66E8B7}.Release|Any CPU.Build.0 = Release|Any CPU
66 | {80A9BB30-873C-47E9-8314-5E53AC66E8B7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
67 | {80A9BB30-873C-47E9-8314-5E53AC66E8B7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
68 | {80A9BB30-873C-47E9-8314-5E53AC66E8B7}.Release|x86.ActiveCfg = Release|Any CPU
69 | {2B454F8B-D702-4281-80DF-367142007B0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
70 | {2B454F8B-D702-4281-80DF-367142007B0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
71 | {2B454F8B-D702-4281-80DF-367142007B0C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
72 | {2B454F8B-D702-4281-80DF-367142007B0C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
73 | {2B454F8B-D702-4281-80DF-367142007B0C}.Debug|x86.ActiveCfg = Debug|Any CPU
74 | {2B454F8B-D702-4281-80DF-367142007B0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
75 | {2B454F8B-D702-4281-80DF-367142007B0C}.Release|Any CPU.Build.0 = Release|Any CPU
76 | {2B454F8B-D702-4281-80DF-367142007B0C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
77 | {2B454F8B-D702-4281-80DF-367142007B0C}.Release|Mixed Platforms.Build.0 = Release|Any CPU
78 | {2B454F8B-D702-4281-80DF-367142007B0C}.Release|x86.ActiveCfg = Release|Any CPU
79 | {C3490CAE-5A69-4852-BD61-50179D587D0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
80 | {C3490CAE-5A69-4852-BD61-50179D587D0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
81 | {C3490CAE-5A69-4852-BD61-50179D587D0D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
82 | {C3490CAE-5A69-4852-BD61-50179D587D0D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
83 | {C3490CAE-5A69-4852-BD61-50179D587D0D}.Debug|x86.ActiveCfg = Debug|Any CPU
84 | {C3490CAE-5A69-4852-BD61-50179D587D0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
85 | {C3490CAE-5A69-4852-BD61-50179D587D0D}.Release|Any CPU.Build.0 = Release|Any CPU
86 | {C3490CAE-5A69-4852-BD61-50179D587D0D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
87 | {C3490CAE-5A69-4852-BD61-50179D587D0D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
88 | {C3490CAE-5A69-4852-BD61-50179D587D0D}.Release|x86.ActiveCfg = Release|Any CPU
89 | {5A641DFB-CB1A-4044-AF52-554CC8904449}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
90 | {5A641DFB-CB1A-4044-AF52-554CC8904449}.Debug|Any CPU.Build.0 = Debug|Any CPU
91 | {5A641DFB-CB1A-4044-AF52-554CC8904449}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
92 | {5A641DFB-CB1A-4044-AF52-554CC8904449}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
93 | {5A641DFB-CB1A-4044-AF52-554CC8904449}.Debug|x86.ActiveCfg = Debug|Any CPU
94 | {5A641DFB-CB1A-4044-AF52-554CC8904449}.Release|Any CPU.ActiveCfg = Release|Any CPU
95 | {5A641DFB-CB1A-4044-AF52-554CC8904449}.Release|Any CPU.Build.0 = Release|Any CPU
96 | {5A641DFB-CB1A-4044-AF52-554CC8904449}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
97 | {5A641DFB-CB1A-4044-AF52-554CC8904449}.Release|Mixed Platforms.Build.0 = Release|Any CPU
98 | {5A641DFB-CB1A-4044-AF52-554CC8904449}.Release|x86.ActiveCfg = Release|Any CPU
99 | EndGlobalSection
100 | GlobalSection(SolutionProperties) = preSolution
101 | HideSolutionNode = FALSE
102 | EndGlobalSection
103 | GlobalSection(NestedProjects) = preSolution
104 | {2B454F8B-D702-4281-80DF-367142007B0C} = {AE631D61-6BE6-438F-A535-955BB9A0218F}
105 | EndGlobalSection
106 | GlobalSection(ExtensibilityGlobals) = postSolution
107 | SolutionGuid = {3DEED27A-6D3F-4F2E-A5D5-1F71648F2413}
108 | EndGlobalSection
109 | EndGlobal
110 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/DocoptTests.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using NUnit.Framework;
4 |
5 | namespace DocoptNet.Tests
6 | {
7 | [TestFixture]
8 | public class DocoptTests
9 | {
10 | [Test]
11 | public void Test_tokens_from_pattern()
12 | {
13 | var tokens = Tokens.FromPattern("[ -h ]");
14 | Assert.AreEqual(3, tokens.Count());
15 | Assert.AreEqual("[", tokens.Current());
16 | Assert.AreEqual("[", tokens.Move());
17 | Assert.AreEqual("-h", tokens.Move());
18 | Assert.AreEqual("]", tokens.Move());
19 | }
20 |
21 | [Test]
22 | public void Test_set()
23 | {
24 | Assert.AreEqual(new Argument("N"), new Argument("N"));
25 | var l = new List {new Argument("N"), new Argument("N")};
26 | var s = new HashSet(l);
27 | Assert.AreEqual(new Pattern[] {new Argument("N"),}, s.ToList());
28 | }
29 |
30 | [Test]
31 | public void Test_issue_40_help()
32 | {
33 | var message = "";
34 | var d = new Docopt();
35 | d.PrintExit += (s, e) => message = e.Message;
36 | d.Apply("usage: prog --help-commands | --help", "--help");
37 | StringAssert.StartsWith("usage", message);
38 | }
39 |
40 | [Test]
41 | public void Test_issue_106_exit()
42 | {
43 | Assert.Throws(
44 | () => new Docopt().Apply("usage: prog --help-commands | --help", "--help", exit: false));
45 | }
46 |
47 | [Test]
48 | public void Test_issue_40_same_prefix()
49 | {
50 | var expected = new Dictionary
51 | {
52 | {"--aabb", new ValueObject(false)},
53 | {"--aa", new ValueObject(true)}
54 | };
55 | var actual = new Docopt().Apply("usage: prog --aabb | --aa", "--aa");
56 | Assert.AreEqual(expected, actual);
57 | }
58 |
59 | [Test]
60 | public void Match_arg_only()
61 | {
62 | var expected = new Dictionary
63 | {
64 | {"-v", new ValueObject(false)},
65 | {"A", new ValueObject("arg")}
66 | };
67 | var actual = new Docopt().Apply(@"Usage: prog [-v] A
68 |
69 | Options: -v Be verbose.", "arg");
70 | Assert.AreEqual(expected, actual);
71 | }
72 |
73 | [Test]
74 | public void Match_opt_and_arg()
75 | {
76 | var expected = new Dictionary
77 | {
78 | {"-v", new ValueObject(true)},
79 | {"A", new ValueObject("arg")}
80 | };
81 | var actual = new Docopt().Apply(@"Usage: prog [-v] A
82 |
83 | Options: -v Be verbose.", "-v arg");
84 | Assert.AreEqual(expected, actual);
85 | }
86 |
87 | private const string DOC = @"Usage: prog [-vqr] [FILE]
88 | prog INPUT OUTPUT
89 | prog --help
90 |
91 | Options:
92 | -v print status messages
93 | -q report only file names
94 | -r show all occurrences of the same error
95 | --help
96 | ";
97 |
98 | [Test]
99 | public void Match_one_opt_with_arg()
100 | {
101 | var expected = new Dictionary
102 | {
103 | {"-v", new ValueObject(true)},
104 | {"-q", new ValueObject(false)},
105 | {"-r", new ValueObject(false)},
106 | {"--help", new ValueObject(false)},
107 | {"FILE", new ValueObject("file.py")},
108 | {"INPUT", null},
109 | {"OUTPUT", null}
110 | };
111 | var actual = new Docopt().Apply(DOC, "-v file.py");
112 | Assert.AreEqual(expected, actual);
113 | }
114 |
115 | [Test]
116 | public void Match_one_opt_only()
117 | {
118 | var expected = new Dictionary
119 | {
120 | {"-v", new ValueObject(true)},
121 | {"-q", new ValueObject(false)},
122 | {"-r", new ValueObject(false)},
123 | {"--help", new ValueObject(false)},
124 | {"FILE", null},
125 | {"INPUT", null},
126 | {"OUTPUT", null}
127 | };
128 | var actual = new Docopt().Apply(DOC, "-v");
129 | Assert.AreEqual(expected, actual);
130 | }
131 |
132 | [Test]
133 | public void No_match()
134 | {
135 | Assert.Throws(() => new Docopt().Apply(DOC, "-v input.py output.py"));
136 | }
137 |
138 | [Test]
139 | public void Non_existent_long()
140 | {
141 | Assert.Throws(() => new Docopt().Apply(DOC, "--fake"));
142 | }
143 |
144 | [Test]
145 | public void Should_exit_error_code_1()
146 | {
147 | var message = "";
148 | var errorCode = 0;
149 | var d = new Docopt();
150 | d.PrintExit += (s, e) =>
151 | {
152 | message = e.Message;
153 | errorCode = e.ErrorCode;
154 | };
155 | d.Apply(DOC, "--fake", exit:true);
156 | StringAssert.StartsWith("Usage", message);
157 | Assert.AreEqual(1, errorCode, "Should exit with error code 1 when exit=true and invalid args provided");
158 | }
159 |
160 | [Test]
161 | public void Display_help()
162 | {
163 | var message = "";
164 | var errorCode = 0;
165 | var d = new Docopt();
166 | d.PrintExit += (s, e) =>
167 | {
168 | message = e.Message;
169 | errorCode = e.ErrorCode;
170 | };
171 | d.Apply(DOC, "--help");
172 | StringAssert.StartsWith("Usage", message);
173 | Assert.AreEqual(0, errorCode);
174 | }
175 |
176 | [Test]
177 | public void Test_issue_59_assign_empty_string_to_long()
178 | {
179 | var expected = new Dictionary
180 | {
181 | {"--long", new ValueObject("")}
182 | };
183 | var actual = new Docopt().Apply("usage: prog --long=", "--long=");
184 | Assert.AreEqual(expected, actual);
185 | }
186 |
187 | [Test]
188 | public void Test_issue_59_assign_empty_string_to_short()
189 | {
190 | var expected = new Dictionary
191 | {
192 | {"-l", new ValueObject("")}
193 | };
194 | var actual = new Docopt().Apply("usage: prog -l \noptions: -l ", new[] {"-l", ""});
195 | Assert.AreEqual(expected, actual);
196 | }
197 |
198 | [Test]
199 | public void Test_issue_68_options_shortcut_does_not_include_options_in_usage_pattern()
200 | {
201 | var args = new Docopt().Apply("usage: prog [-ab] [options]\noptions: -x\n -y", "-ax");
202 | Assert.True(args["-a"].IsTrue);
203 | Assert.True(args["-b"].IsFalse);
204 | Assert.True(args["-x"].IsTrue);
205 | Assert.True(args["-y"].IsFalse);
206 | }
207 | }
208 | }
--------------------------------------------------------------------------------
/src/Testee/Testee.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {C3490CAE-5A69-4852-BD61-50179D587D0D}
8 | Exe
9 | Properties
10 | Testee
11 | Testee
12 | v4.5
13 | 512
14 | ..\
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 | $(BuildOutDir)\$(MSBuildProjectName)
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | {d87f19b8-a15f-4bc2-8e1c-47cc6038a0df}
58 | DocoptNet
59 |
60 |
61 |
62 |
69 |
70 |
71 |
72 |
73 |
74 | ..\..\packages\Newtonsoft.Json\lib\netcore45\Newtonsoft.Json.dll
75 | True
76 | True
77 |
78 |
79 |
80 |
81 |
82 |
83 | ..\..\packages\Newtonsoft.Json\lib\net35\Newtonsoft.Json.dll
84 | True
85 | True
86 |
87 |
88 |
89 |
90 |
91 |
92 | ..\..\packages\Newtonsoft.Json\lib\net20\Newtonsoft.Json.dll
93 | True
94 | True
95 |
96 |
97 |
98 |
99 |
100 |
101 | ..\..\packages\Newtonsoft.Json\lib\net40\Newtonsoft.Json.dll
102 | True
103 | True
104 |
105 |
106 |
107 |
108 |
109 |
110 | ..\..\packages\Newtonsoft.Json\lib\net45\Newtonsoft.Json.dll
111 | True
112 | True
113 |
114 |
115 |
116 |
117 |
118 |
119 | ..\..\packages\Newtonsoft.Json\lib\portable-net40+sl4+wp7+win8\Newtonsoft.Json.dll
120 | True
121 | True
122 |
123 |
124 |
125 |
126 |
127 |
128 | ..\..\packages\Newtonsoft.Json\lib\portable-net45+wp80+win8\Newtonsoft.Json.dll
129 | True
130 | True
131 |
132 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/src/DocoptNet.Tests/ValueObjectTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using NUnit.Framework;
7 |
8 | namespace DocoptNet.Tests
9 | {
10 | [TestFixture]
11 | public class ValueObjectTests
12 | {
13 | [Test]
14 | public void IsNullOrEmpty_null_object_evaluates_true()
15 | {
16 | var systemUnderTest = new ValueObject(null);
17 | Assert.IsTrue(systemUnderTest.IsNullOrEmpty, "IsNullOrEmpty should evaluate to true when ValueObject wraps null.");
18 | }
19 |
20 | [Test]
21 | public void IsNullOrEmpty_empty_string_evaluates_true()
22 | {
23 | var systemUnderTest = new ValueObject(string.Empty);
24 | Assert.IsTrue(systemUnderTest.IsNullOrEmpty, "IsNullOrEmpty should evaluate to true when ValueObject wraps the empty string.");
25 | }
26 |
27 | [Test]
28 | public void IsNullOrEmpty_nonempty_string_evaluates_false()
29 | {
30 | var systemUnderTest = new ValueObject("a");
31 | Assert.IsFalse(systemUnderTest.IsNullOrEmpty, "IsNullOrEmpty should evaluate to false when ValueObject wraps a non-empty string.");
32 | }
33 |
34 | [Test]
35 | public void IsNullOrEmpty_number_evaluates_false()
36 | {
37 | var systemUnderTest = new ValueObject(1);
38 | Assert.IsFalse(systemUnderTest.IsNullOrEmpty, "IsNullOrEmpty should evaluate to false when ValueObject wraps an integer.");
39 | }
40 |
41 | [Test]
42 | public void IsNullOrEmpty_bool_evaluates_false()
43 | {
44 | var systemUnderTest = new ValueObject(true);
45 | Assert.IsFalse(systemUnderTest.IsNullOrEmpty, "IsNullOrEmpty should evaluate to false when ValueObject wraps a bool.");
46 | systemUnderTest = new ValueObject(false);
47 | Assert.IsFalse(systemUnderTest.IsNullOrEmpty, "IsNullOrEmpty should evaluate to false when ValueObject wraps a bool.");
48 | }
49 |
50 | [Test]
51 | public void IsNullOrEmpty_list_evaluates_false()
52 | {
53 | var systemUnderTest = new ValueObject(new ArrayList());
54 | Assert.IsFalse(systemUnderTest.IsNullOrEmpty, "IsNullOrEmpty should evaluate to false when ValueObject wraps a list.");
55 | }
56 |
57 | [Test]
58 | public void IsFalse_false_evaluates_true()
59 | {
60 | var systemUnderTest = new ValueObject(false);
61 | Assert.IsTrue(systemUnderTest.IsFalse, "IsFalse should evaluate to true when ValueObject wraps false.");
62 | }
63 |
64 | [Test]
65 | public void IsFalse_true_evaluates_false()
66 | {
67 | var systemUnderTest = new ValueObject(new ArrayList());
68 | Assert.IsFalse(systemUnderTest.IsFalse, "IsFalse should evaluate to false when ValueObject wraps true.");
69 | }
70 |
71 | [Test]
72 | public void IsFalse_null_evaluates_false()
73 | {
74 | var systemUnderTest = new ValueObject(null);
75 | Assert.IsFalse(systemUnderTest.IsFalse, "IsFalse should evaluate to false when ValueObject wraps null.");
76 | }
77 |
78 | [Test]
79 | public void IsFalse_string_evaluates_false()
80 | {
81 | var systemUnderTest = new ValueObject("false");
82 | Assert.IsFalse(systemUnderTest.IsFalse, "IsFalse should evaluate to false when ValueObject wraps a string.");
83 | }
84 |
85 | [Test]
86 | public void IsFalse_number_evaluates_false()
87 | {
88 | var systemUnderTest = new ValueObject(0);
89 | Assert.IsFalse(systemUnderTest.IsFalse, "IsFalse should evaluate to false when ValueObject wraps an integer.");
90 | }
91 |
92 | [Test]
93 | public void IsTrue_true_evaluates_true()
94 | {
95 | var systemUnderTest = new ValueObject(true);
96 | Assert.IsTrue(systemUnderTest.IsTrue, "IsTrue should evaluate to true when ValueObject wraps true.");
97 | }
98 |
99 | [Test]
100 | public void IsTrue_false_evaluates_false()
101 | {
102 | var systemUnderTest = new ValueObject(new ArrayList());
103 | Assert.IsFalse(systemUnderTest.IsTrue, "IsTrue should evaluate to false when ValueObject wraps false.");
104 | }
105 |
106 | [Test]
107 | public void IsTrue_null_evaluates_false()
108 | {
109 | var systemUnderTest = new ValueObject(null);
110 | Assert.IsFalse(systemUnderTest.IsTrue, "IsTrue should evaluate to false when ValueObject wraps null.");
111 | }
112 |
113 | [Test]
114 | public void IsTrue_string_evaluates_false()
115 | {
116 | var systemUnderTest = new ValueObject("true");
117 | Assert.IsFalse(systemUnderTest.IsTrue, "IsTrue should evaluate to false when ValueObject wraps a string.");
118 | }
119 |
120 | [Test]
121 | public void IsTrue_number_evaluates_false()
122 | {
123 | var systemUnderTest = new ValueObject(1);
124 | Assert.IsFalse(systemUnderTest.IsTrue, "IsTrue should evaluate to false when ValueObject wraps an integer.");
125 | }
126 |
127 | [Test]
128 | public void IsList_arraylist_evaluates_true()
129 | {
130 | var systemUnderTest = new ValueObject(new ArrayList());
131 | Assert.IsTrue(systemUnderTest.IsList, "IsList should evaluate to true when ValueObject wraps an ArrayList.");
132 | }
133 |
134 | [Test]
135 | public void IsList_genericlist_evaluates_true()
136 | {
137 | var systemUnderTest = new ValueObject(new List