11using System ;
22using System . Collections ;
33using System . Collections . Generic ;
4+ using System . Linq ;
45using System . Text ;
56using System . Text . RegularExpressions ;
67using System . Web ;
@@ -272,7 +273,7 @@ public void Should_Throw_When_Comma_List_Limit_Exceeded()
272273
273274 action
274275 . Should ( )
275- . Throw < IndexOutOfRangeException > ( )
276+ . Throw < InvalidOperationException > ( )
276277 . WithMessage ( "List limit exceeded. Only 3 elements allowed in a list." ) ;
277278 }
278279
@@ -2277,7 +2278,7 @@ public void Decode_StrictDepth_ThrowsExceptionForMultipleNestedObjectsWithStrict
22772278 var options = new DecodeOptions { Depth = 1 , StrictDepth = true } ;
22782279
22792280 Action act = ( ) => Qs . Decode ( "a[b][c][d][e][f][g][h][i]=j" , options ) ;
2280- act . Should ( ) . Throw < IndexOutOfRangeException > ( ) ;
2281+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
22812282 }
22822283
22832284 [ Fact ]
@@ -2286,7 +2287,7 @@ public void Decode_StrictDepth_ThrowsExceptionForMultipleNestedListsWithStrictDe
22862287 var options = new DecodeOptions { Depth = 3 , StrictDepth = true } ;
22872288
22882289 Action act = ( ) => Qs . Decode ( "a[0][1][2][3][4]=b" , options ) ;
2289- act . Should ( ) . Throw < IndexOutOfRangeException > ( ) ;
2290+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
22902291 }
22912292
22922293 [ Fact ]
@@ -2295,7 +2296,7 @@ public void Decode_StrictDepth_ThrowsExceptionForNestedMapsAndListsWithStrictDep
22952296 var options = new DecodeOptions { Depth = 3 , StrictDepth = true } ;
22962297
22972298 Action act = ( ) => Qs . Decode ( "a[b][c][0][d][e]=f" , options ) ;
2298- act . Should ( ) . Throw < IndexOutOfRangeException > ( ) ;
2299+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
22992300 }
23002301
23012302 [ Fact ]
@@ -2304,7 +2305,7 @@ public void Decode_StrictDepth_ThrowsExceptionForDifferentTypesOfValuesWithStric
23042305 var options = new DecodeOptions { Depth = 3 , StrictDepth = true } ;
23052306
23062307 Action act = ( ) => Qs . Decode ( "a[b][c][d][e]=true&a[b][c][d][f]=42" , options ) ;
2307- act . Should ( ) . Throw < IndexOutOfRangeException > ( ) ;
2308+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
23082309 }
23092310
23102311 [ Fact ]
@@ -2405,7 +2406,7 @@ public void Decode_ParameterLimit_ThrowsErrorWhenParameterLimitExceeded()
24052406 var options = new DecodeOptions { ParameterLimit = 3 , ThrowOnLimitExceeded = true } ;
24062407
24072408 Action act = ( ) => Qs . Decode ( "a=1&b=2&c=3&d=4&e=5&f=6" , options ) ;
2408- act . Should ( ) . Throw < IndexOutOfRangeException > ( ) ;
2409+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
24092410 }
24102411
24112412 [ Fact ]
@@ -2483,7 +2484,7 @@ public void Decode_ListLimit_ThrowsErrorWhenListLimitExceeded()
24832484 var options = new DecodeOptions { ListLimit = 3 , ThrowOnLimitExceeded = true } ;
24842485
24852486 Action act = ( ) => Qs . Decode ( "a[]=1&a[]=2&a[]=3&a[]=4" , options ) ;
2486- act . Should ( ) . Throw < IndexOutOfRangeException > ( ) ;
2487+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
24872488 }
24882489
24892490 [ Fact ]
@@ -2530,7 +2531,7 @@ public void Decode_ListLimit_HandlesNegativeListLimitCorrectly()
25302531 var options = new DecodeOptions { ListLimit = - 1 , ThrowOnLimitExceeded = true } ;
25312532
25322533 Action act = ( ) => Qs . Decode ( "a[]=1&a[]=2" , options ) ;
2533- act . Should ( ) . Throw < IndexOutOfRangeException > ( ) ;
2534+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
25342535 }
25352536
25362537 [ Fact ]
@@ -2539,7 +2540,7 @@ public void Decode_ListLimit_AppliesListLimitToNestedLists()
25392540 var options = new DecodeOptions { ListLimit = 3 , ThrowOnLimitExceeded = true } ;
25402541
25412542 Action act = ( ) => Qs . Decode ( "a[0][]=1&a[0][]=2&a[0][]=3&a[0][]=4" , options ) ;
2542- act . Should ( ) . Throw < IndexOutOfRangeException > ( ) ;
2543+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
25432544 }
25442545
25452546 [ Fact ]
@@ -4127,10 +4128,50 @@ public void Decode_NonGeneric_Hashtable_Is_Normalised()
41274128 decoded . Should ( ) . Equal ( new Dictionary < string , object ? > { [ "x" ] = 1 , [ "2" ] = "y" } ) ;
41284129 }
41294130
4131+ [ Fact ]
4132+ public void Decode_CommaSplit_NoTruncationWhenSumExceedsLimit_AndThrowOff ( )
4133+ {
4134+ var opts = new DecodeOptions
4135+ {
4136+ Comma = true ,
4137+ ListLimit = 3 ,
4138+ ThrowOnLimitExceeded = false ,
4139+ ParseLists = true ,
4140+ Duplicates = Duplicates . Combine
4141+ } ;
4142+
4143+ var result = Qs . Decode ( "a=1,2&a=3,4,5" , opts ) ;
4144+
4145+ var dict = Assert . IsType < Dictionary < string , object ? > > ( result ) ;
4146+ var list = Assert . IsType < List < object ? > > ( dict [ "a" ] ) ;
4147+ // With ThrowOnLimitExceeded = false, no truncation occurs; full concatenation is allowed
4148+ list . Select ( x => x ? . ToString ( ) ) . Should ( ) . Equal ( "1" , "2" , "3" , "4" , "5" ) ;
4149+ }
4150+
4151+ [ Fact ]
4152+ public void Decode_BracketSingle_CommaSplit_YieldsNestedList ( )
4153+ {
4154+ var opts = new DecodeOptions { Comma = true } ;
4155+
4156+ // Control: unbracketed key
4157+ var res = Qs . Decode ( "a=1,2,3" , opts ) ;
4158+ var dict1 = Assert . IsType < Dictionary < string , object ? > > ( res ) ;
4159+ var list1 = Assert . IsType < List < object ? > > ( dict1 [ "a" ] ) ;
4160+ list1 . Select ( x => x ? . ToString ( ) ) . Should ( ) . Equal ( "1" , "2" , "3" ) ;
4161+
4162+ // Bracketed single occurrence yields a nested list: [["1","2","3"]]
4163+ var res2 = Qs . Decode ( "a[]=1,2,3" , opts ) ;
4164+ var dict2 = Assert . IsType < Dictionary < string , object ? > > ( res2 ) ;
4165+ var outer = Assert . IsType < List < object ? > > ( dict2 [ "a" ] ) ;
4166+ outer . Should ( ) . HaveCount ( 1 ) ;
4167+ var inner = Assert . IsType < List < object ? > > ( outer [ 0 ] ) ;
4168+ inner . Select ( x => x ? . ToString ( ) ) . Should ( ) . Equal ( "1" , "2" , "3" ) ;
4169+ }
4170+
41304171 #region Encoded dot behavior in keys (%2E / %2e)
41314172
41324173 [ Fact ]
4133- public void EncodedDot_TopLevel_AllowDotsTrue_DecodeDotInKeysTrue_PlainDotSplits_EncodedDotDoesNotSplit ( )
4174+ public void EncodedDot_TopLevel_AllowDotsTrue_DecodeDotInKeysTrue_PlainAndEncodedDotSplit ( )
41344175 {
41354176 var opt = new DecodeOptions { AllowDots = true , DecodeDotInKeys = true } ;
41364177
@@ -4157,7 +4198,7 @@ public void EncodedDot_TopLevel_AllowDotsTrue_DecodeDotInKeysTrue_PlainDotSplits
41574198 }
41584199
41594200 [ Fact ]
4160- public void EncodedDot_TopLevel_AllowDotsTrue_DecodeDotInKeysFalse_EncodedDotRemainsPercentSequence ( )
4201+ public void EncodedDot_TopLevel_AllowDotsTrue_DecodeDotInKeysFalse_EncodedDotAlsoSplits ( )
41614202 {
41624203 var opt = new DecodeOptions { AllowDots = true , DecodeDotInKeys = false } ;
41634204
@@ -4181,7 +4222,7 @@ public void EncodedDot_AllowDotsFalse_DecodeDotInKeysTrue_IsInvalid()
41814222 {
41824223 var opt = new DecodeOptions { AllowDots = false , DecodeDotInKeys = true } ;
41834224 Action act = ( ) => Qs . Decode ( "a%2Eb=c" , opt ) ;
4184- act . Should ( ) . Throw < ArgumentException > ( ) ;
4225+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
41854226 }
41864227
41874228 [ Fact ]
@@ -4205,7 +4246,7 @@ public void EncodedDot_BracketSegment_MapsToDot_WhenDecodeDotInKeysTrue()
42054246 }
42064247
42074248 [ Fact ]
4208- public void EncodedDot_BracketSegment_RemainsPercentSequence_WhenDecodeDotInKeysFalse ( )
4249+ public void EncodedDot_BracketSegment_DecodesToDot_WhenDecodeDotInKeysFalse ( )
42094250 {
42104251 var opt = new DecodeOptions { AllowDots = true , DecodeDotInKeys = false } ;
42114252
@@ -4349,8 +4390,9 @@ public void MixedCase_EncodedBrackets_EncodedDot_AllowDotsFalse_DecodeDotInKeysT
43494390 {
43504391 var opt = new DecodeOptions { AllowDots = false , DecodeDotInKeys = true } ;
43514392 Action act = ( ) => Qs . Decode ( "a%5Bb%5D%5Bc%5D%2Ed=x" , opt ) ;
4352- act . Should ( ) . Throw < ArgumentException > ( )
4353- . WithMessage ( "*decodeDotInKeys*allowDots*" ) ;
4393+ act . Should ( ) . Throw < InvalidOperationException > ( )
4394+ . WithMessage ( "*DecodeDotInKeys*AllowDots*" )
4395+ . WithMessage ( "*DecodeDotInKeys=true*AllowDots=true*" ) ;
43544396 }
43554397
43564398 [ Fact ]
@@ -4646,7 +4688,7 @@ public void StrictDepthOverflow_RaisesForWellFormed()
46464688 {
46474689 var act = ( ) =>
46484690 InternalDecoder . SplitKeyIntoSegments ( "a[b][c][d]" , false , 1 , true ) ;
4649- act . Should ( ) . Throw < IndexOutOfRangeException > ( ) ;
4691+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
46504692 }
46514693
46524694 [ Fact ]
@@ -4681,4 +4723,46 @@ public void LeadingDot_EncodedBracket_AllowDotsTrue_DecodeDotInKeysTrue()
46814723 }
46824724
46834725 #endregion
4726+
4727+ #region Decode comma limit
4728+
4729+ [ Fact ]
4730+ public void Decode_CommaSplit_AllowedWhenSumEqualsLimit ( )
4731+ {
4732+ var opts = new DecodeOptions
4733+ {
4734+ Comma = true ,
4735+ ListLimit = 5 ,
4736+ ThrowOnLimitExceeded = true ,
4737+ ParseLists = true ,
4738+ Duplicates = Duplicates . Combine
4739+ } ;
4740+
4741+ // Existing N=2 from first part, incoming M=3; N+M = 5 == limit → allowed
4742+ var result = Assert . IsType < Dictionary < string , object ? > > ( Qs . Decode ( "a=1,2&a=3,4,5" , opts ) ) ;
4743+ result . Should ( ) . ContainKey ( "a" ) ;
4744+
4745+ var list = Assert . IsType < List < object ? > > ( result [ "a" ] ) ;
4746+ list . Should ( ) . HaveCount ( 5 ) ;
4747+ list . Select ( x => x ? . ToString ( ) ) . Should ( ) . Equal ( "1" , "2" , "3" , "4" , "5" ) ;
4748+ }
4749+
4750+ [ Fact ]
4751+ public void Decode_CommaSplit_ThrowsWhenSumExceedsLimitAndThrowOn ( )
4752+ {
4753+ var opts = new DecodeOptions
4754+ {
4755+ Comma = true ,
4756+ ListLimit = 5 ,
4757+ ThrowOnLimitExceeded = true ,
4758+ ParseLists = true ,
4759+ Duplicates = Duplicates . Combine
4760+ } ;
4761+
4762+ // Existing N=2, incoming M=4; N+M = 6 > limit and ThrowOnLimitExceeded = true → throws
4763+ Action act = ( ) => Qs . Decode ( "a=1,2&a=3,4,5,6" , opts ) ;
4764+ act . Should ( ) . Throw < InvalidOperationException > ( ) ;
4765+ }
4766+
4767+ #endregion
46844768}
0 commit comments