File tree Expand file tree Collapse file tree 3 files changed +78
-0
lines changed
test/CommandLineUtils.Tests Expand file tree Collapse file tree 3 files changed +78
-0
lines changed Original file line number Diff line number Diff line change 1
1
// Copyright (c) Nate McMaster.
2
2
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
4
+ using McMaster . Extensions . CommandLineUtils . Abstractions ;
5
+ using McMaster . Extensions . CommandLineUtils . Errors ;
4
6
using System ;
5
7
using System . Linq ;
6
8
using System . Reflection ;
@@ -28,6 +30,8 @@ public virtual void Apply(ConventionContext context)
28
30
var contextArgs = new object [ ] { context , attribute } ;
29
31
foreach ( var type in attribute . Types )
30
32
{
33
+ AssertSubcommandIsNotCycled ( type , context . Application ) ;
34
+
31
35
var impl = s_addSubcommandMethod . MakeGenericMethod ( type ) ;
32
36
try
33
37
{
@@ -42,6 +46,19 @@ public virtual void Apply(ConventionContext context)
42
46
}
43
47
}
44
48
49
+ private void AssertSubcommandIsNotCycled ( Type modelType , CommandLineApplication parentCommand )
50
+ {
51
+ while ( parentCommand != null )
52
+ {
53
+ if ( parentCommand is IModelAccessor parentCommandAccessor
54
+ && parentCommandAccessor . GetModelType ( ) == modelType )
55
+ {
56
+ throw new SubcommandCycleException ( modelType ) ;
57
+ }
58
+ parentCommand = parentCommand . Parent ;
59
+ }
60
+ }
61
+
45
62
private static readonly MethodInfo s_addSubcommandMethod
46
63
= typeof ( SubcommandAttributeConvention ) . GetRuntimeMethods ( )
47
64
. Single ( m => m . Name == nameof ( AddSubcommandImpl ) ) ;
Original file line number Diff line number Diff line change
1
+ // Copyright (c) Nate McMaster.
2
+ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
+
4
+ using System ;
5
+
6
+ namespace McMaster . Extensions . CommandLineUtils . Errors
7
+ {
8
+ /// <summary>
9
+ /// The exception that is thrown when a subcommand cycle is detected
10
+ /// </summary>
11
+ public class SubcommandCycleException : Exception
12
+ {
13
+ /// <summary>
14
+ /// Initializes an instance of <see cref="SubcommandCycleException"/>.
15
+ /// </summary>
16
+ /// <param name="modelType">The type of the cycled command model</param>
17
+ public SubcommandCycleException ( Type modelType )
18
+ : base ( $ "Subcommand cycle detected: trying to add command of model { modelType } as its own direct or indirect subcommand")
19
+ {
20
+ ModelType = modelType ;
21
+ }
22
+
23
+ /// <summary>
24
+ /// The type of the cycled command model
25
+ /// </summary>
26
+ public Type ModelType { get ; }
27
+ }
28
+ }
Original file line number Diff line number Diff line change 1
1
// Copyright (c) Nate McMaster.
2
2
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3
3
4
+ using McMaster . Extensions . CommandLineUtils . Errors ;
4
5
using System ;
5
6
using System . IO ;
6
7
using System . Linq ;
@@ -198,5 +199,37 @@ public void CommandNamesCannotDifferByCaseOnly()
198
199
( ) => CommandLineApplication . Execute < DuplicateSubCommands > ( new TestConsole ( _output ) ) ) ;
199
200
Assert . Equal ( Strings . DuplicateSubcommandName ( "level1" ) , ex . Message ) ;
200
201
}
202
+
203
+ [ Command , Subcommand ( typeof ( CycledCommand2 ) ) ]
204
+ private class CycledCommand1
205
+ {
206
+ }
207
+
208
+ [ Command , Subcommand ( typeof ( CycledCommand1 ) ) ]
209
+ private class CycledCommand2
210
+ {
211
+ }
212
+
213
+ [ Fact ]
214
+ public void ThrowsForCycledSubCommand ( )
215
+ {
216
+ var ex = Assert . Throws < SubcommandCycleException > (
217
+ ( ) => CommandLineApplication . Execute < CycledCommand1 > ( new TestConsole ( _output ) ) ) ;
218
+ Assert . Equal ( typeof ( CycledCommand1 ) , ex . ModelType ) ;
219
+ }
220
+
221
+ [ Command , Subcommand ( typeof ( SelfCycledCommand ) ) ]
222
+ private class SelfCycledCommand
223
+ {
224
+
225
+ }
226
+
227
+ [ Fact ]
228
+ public void ThrowsForSelfCycledCommand ( )
229
+ {
230
+ var ex = Assert . Throws < SubcommandCycleException > (
231
+ ( ) => CommandLineApplication . Execute < SelfCycledCommand > ( new TestConsole ( _output ) ) ) ;
232
+ Assert . Equal ( typeof ( SelfCycledCommand ) , ex . ModelType ) ;
233
+ }
201
234
}
202
235
}
You can’t perform that action at this time.
0 commit comments