@@ -40,8 +40,37 @@ public Attr2(string resolvedProp2, string constantProp)
40
40
41
41
public string ConstantProp { get ; private set ; }
42
42
43
- [ AutoResolve ( AllowTokens = false ) ]
43
+ [ AppSetting ]
44
44
public string ResolvedSetting { get ; set ; }
45
+
46
+ [ AppSetting ( Default = "default" ) ]
47
+ public string DefaultSetting { get ; set ; }
48
+ }
49
+
50
+ public class Attr3 : Attribute
51
+ {
52
+ [ AppSetting ]
53
+ public string Required { get ; set ; }
54
+
55
+ [ AppSetting ( Default = "default" ) ]
56
+ public string Default { get ; set ; }
57
+ }
58
+
59
+ public class Attr4 : Attribute
60
+ {
61
+ [ AppSetting ]
62
+ public string AppSetting { get ; set ; }
63
+
64
+ [ AutoResolve ]
65
+ public string AutoResolve { get ; set ; }
66
+ }
67
+
68
+ public class InvalidAnnotation : Attribute
69
+ {
70
+ // only one of appsetting/autoresolve allowed
71
+ [ AppSetting ]
72
+ [ AutoResolve ]
73
+ public string Required { get ; set ; }
45
74
}
46
75
47
76
public class AttributeWithResolutionPolicy : Attribute
@@ -159,7 +188,9 @@ public async Task InvokeStringBlobAttribute()
159
188
[ Fact ]
160
189
public async Task InvokeStringMultipleResolvedProperties ( )
161
190
{
162
- Attr2 attr = new Attr2 ( "{p2}" , "constant" ) { ResolvedProp1 = "{p1}" } ;
191
+ Attr2 attr = new Attr2 ( "{p2}" , "constant" ) {
192
+ ResolvedProp1 = "{p1}"
193
+ } ;
163
194
164
195
var cloner = new AttributeCloner < Attr2 > ( attr , GetBindingContract ( "p1" , "p2" ) ) ;
165
196
@@ -232,12 +263,52 @@ public void Setting()
232
263
}
233
264
234
265
[ Fact ]
235
- public void Setting_WithNoValueInResolver_Throws ( )
266
+ public void Setting_WithNoValueInResolver_ThrowsIfNoDefault ( )
236
267
{
237
268
Attr2 a2 = new Attr2 ( string . Empty , string . Empty ) { ResolvedSetting = "appsetting" } ;
238
269
Assert . Throws < InvalidOperationException > ( ( ) => new AttributeCloner < Attr2 > ( a2 , EmptyContract , null ) ) ;
239
270
}
240
271
272
+ [ Fact ]
273
+ public void Setting_WithNoValueInResolver_UsesDefault ( )
274
+ {
275
+ Attr2 a2 = new Attr2 ( string . Empty , string . Empty ) { ResolvedSetting = "appsetting" } ;
276
+ var nameResolver = new FakeNameResolver ( ) . Add ( "appsetting" , "ABC" ) . Add ( "default" , "default" ) ;
277
+ var cloner = new AttributeCloner < Attr2 > ( a2 , EmptyContract , nameResolver ) ;
278
+
279
+ var a2Cloned = cloner . GetNameResolvedAttribute ( ) ;
280
+ Assert . Equal ( "default" , a2Cloned . DefaultSetting ) ;
281
+ }
282
+
283
+ [ Fact ]
284
+ public void AppSettingAttribute_Resolves_IfDefaultSet ( )
285
+ {
286
+ Attr3 a3 = new Attr3 ( ) { Required = "req" , Default = "env" } ;
287
+ var nameResolver = new FakeNameResolver ( ) . Add ( "env" , "envval" ) . Add ( "req" , "reqval" ) ;
288
+ var cloner = new AttributeCloner < Attr3 > ( a3 , EmptyContract , nameResolver ) ;
289
+ var cloned = cloner . GetNameResolvedAttribute ( ) ;
290
+ Assert . Equal ( "reqval" , cloned . Required ) ;
291
+ Assert . Equal ( "envval" , cloned . Default ) ;
292
+ }
293
+
294
+ [ Fact ]
295
+ public void AppSettingAttribute_Resolves_IfDefaultMatched ( )
296
+ {
297
+ Attr3 a3 = new Attr3 ( ) { Required = "req" } ;
298
+ var nameResolver = new FakeNameResolver ( ) . Add ( "default" , "defaultval" ) . Add ( "req" , "reqval" ) ;
299
+ var cloner = new AttributeCloner < Attr3 > ( a3 , EmptyContract , nameResolver ) ;
300
+ var cloned = cloner . GetNameResolvedAttribute ( ) ;
301
+ Assert . Equal ( "reqval" , cloned . Required ) ;
302
+ Assert . Equal ( "defaultval" , cloned . Default ) ;
303
+ }
304
+
305
+ [ Fact ]
306
+ public void AppSettingAttribute_Throws_IfDefaultUnmatched ( )
307
+ {
308
+ Attr3 a3 = new Attr3 ( ) { Required = "req" } ;
309
+ Assert . Throws < InvalidOperationException > ( ( ) => new AttributeCloner < Attr3 > ( a3 , EmptyContract , null ) ) ;
310
+ }
311
+
241
312
[ Fact ]
242
313
public async Task Setting_Null ( )
243
314
{
@@ -250,6 +321,32 @@ public async Task Setting_Null()
250
321
Assert . Null ( a2Clone . ResolvedSetting ) ;
251
322
}
252
323
324
+ [ Fact ]
325
+ public void AppSettingAttribute_ResolvesWholeValueAsSetting ( )
326
+ {
327
+ Attr4 a4 = new Attr4 ( ) ;
328
+ var name = "test{x}and%y%" ;
329
+ a4 . AppSetting = a4 . AutoResolve = name ;
330
+
331
+ var nameResolver = new FakeNameResolver ( )
332
+ . Add ( "y" , "Setting" )
333
+ . Add ( name , "AppSetting" ) ;
334
+ var cloner = new AttributeCloner < Attr4 > ( a4 , GetBindingContract ( "x" ) , nameResolver ) ;
335
+ var cloned = cloner . GetNameResolvedAttribute ( ) ;
336
+ // autoresolve resolves tokens
337
+ Assert . Equal ( "test{x}andSetting" , cloned . AutoResolve ) ;
338
+ // appsetting treats entire string as app setting name
339
+ Assert . Equal ( "AppSetting" , cloned . AppSetting ) ;
340
+ }
341
+
342
+ [ Fact ]
343
+ public void AttributeCloner_Throws_IfAppSettingAndAutoResolve ( )
344
+ {
345
+ InvalidAnnotation a = new InvalidAnnotation ( ) ;
346
+ var exc = Assert . Throws < InvalidOperationException > ( ( ) => new AttributeCloner < InvalidAnnotation > ( a , EmptyContract , null ) ) ;
347
+ Assert . Equal ( "Property 'Required' cannot be annotated with both AppSetting and AutoResolve." , exc . Message ) ;
348
+ }
349
+
253
350
[ Fact ]
254
351
public async Task CloneNoDefaultCtor ( )
255
352
{
@@ -326,18 +423,19 @@ public void TryAutoResolveValue_UnresolvedValue_ThrowsExpectedException()
326
423
ResolvedSetting = "MySetting"
327
424
} ;
328
425
var prop = attribute . GetType ( ) . GetProperty ( "ResolvedSetting" ) ;
329
- string resolvedValue = null ;
426
+ var attr = prop . GetCustomAttribute < AppSettingAttribute > ( ) ;
427
+ string resolvedValue = "MySetting" ;
330
428
331
- var ex = Assert . Throws < InvalidOperationException > ( ( ) => AttributeCloner < Attr2 > . TryAutoResolveValue ( attribute , prop , resolver , out resolvedValue ) ) ;
429
+ var ex = Assert . Throws < InvalidOperationException > ( ( ) => AttributeCloner < Attr2 > . GetAppSettingResolver ( resolvedValue , attr , resolver , prop ) ) ;
332
430
Assert . Equal ( "Unable to resolve value for property 'Attr2.ResolvedSetting'." , ex . Message ) ;
333
431
}
334
432
335
433
[ Fact ]
336
434
public void GetPolicy_ReturnsDefault_WhenNoSpecifiedPolicy ( )
337
435
{
338
436
PropertyInfo propInfo = typeof ( AttributeWithResolutionPolicy ) . GetProperty ( nameof ( AttributeWithResolutionPolicy . PropWithoutPolicy ) ) ;
339
-
340
- IResolutionPolicy policy = AttributeCloner < AttributeWithResolutionPolicy > . GetPolicy ( propInfo ) ;
437
+ AutoResolveAttribute attr = propInfo . GetCustomAttribute < AutoResolveAttribute > ( ) ;
438
+ IResolutionPolicy policy = AttributeCloner < AttributeWithResolutionPolicy > . GetPolicy ( attr . ResolutionPolicyType , propInfo ) ;
341
439
342
440
Assert . IsType < DefaultResolutionPolicy > ( policy ) ;
343
441
}
@@ -347,7 +445,8 @@ public void GetPolicy_Returns_SpecifiedPolicy()
347
445
{
348
446
PropertyInfo propInfo = typeof ( AttributeWithResolutionPolicy ) . GetProperty ( nameof ( AttributeWithResolutionPolicy . PropWithPolicy ) ) ;
349
447
350
- IResolutionPolicy policy = AttributeCloner < AttributeWithResolutionPolicy > . GetPolicy ( propInfo ) ;
448
+ AutoResolveAttribute attr = propInfo . GetCustomAttribute < AutoResolveAttribute > ( ) ;
449
+ IResolutionPolicy policy = AttributeCloner < AttributeWithResolutionPolicy > . GetPolicy ( attr . ResolutionPolicyType , propInfo ) ;
351
450
352
451
Assert . IsType < TestResolutionPolicy > ( policy ) ;
353
452
}
@@ -359,7 +458,8 @@ public void GetPolicy_ReturnsODataFilterPolicy_ForMarkerType()
359
458
// because BindingTemplate doesn't exist in the core assembly.
360
459
PropertyInfo propInfo = typeof ( AttributeWithResolutionPolicy ) . GetProperty ( nameof ( AttributeWithResolutionPolicy . PropWithMarkerPolicy ) ) ;
361
460
362
- IResolutionPolicy policy = AttributeCloner < AttributeWithResolutionPolicy > . GetPolicy ( propInfo ) ;
461
+ AutoResolveAttribute attr = propInfo . GetCustomAttribute < AutoResolveAttribute > ( ) ;
462
+ IResolutionPolicy policy = AttributeCloner < AttributeWithResolutionPolicy > . GetPolicy ( attr . ResolutionPolicyType , propInfo ) ;
363
463
364
464
Assert . IsType < Host . Bindings . ODataFilterResolutionPolicy > ( policy ) ;
365
465
}
@@ -368,8 +468,8 @@ public void GetPolicy_ReturnsODataFilterPolicy_ForMarkerType()
368
468
public void GetPolicy_Throws_IfPolicyDoesNotImplementInterface ( )
369
469
{
370
470
PropertyInfo propInfo = typeof ( AttributeWithResolutionPolicy ) . GetProperty ( nameof ( AttributeWithResolutionPolicy . PropWithInvalidPolicy ) ) ;
371
-
372
- InvalidOperationException ex = Assert . Throws < InvalidOperationException > ( ( ) => AttributeCloner < AttributeWithResolutionPolicy > . GetPolicy ( propInfo ) ) ;
471
+ AutoResolveAttribute attr = propInfo . GetCustomAttribute < AutoResolveAttribute > ( ) ;
472
+ InvalidOperationException ex = Assert . Throws < InvalidOperationException > ( ( ) => AttributeCloner < AttributeWithResolutionPolicy > . GetPolicy ( attr . ResolutionPolicyType , propInfo ) ) ;
373
473
374
474
Assert . Equal ( $ "The { nameof ( AutoResolveAttribute . ResolutionPolicyType ) } on { nameof ( AttributeWithResolutionPolicy . PropWithInvalidPolicy ) } must derive from { typeof ( IResolutionPolicy ) . Name } .", ex . Message ) ;
375
475
}
@@ -378,8 +478,8 @@ public void GetPolicy_Throws_IfPolicyDoesNotImplementInterface()
378
478
public void GetPolicy_Throws_IfPolicyHasNoDefaultConstructor ( )
379
479
{
380
480
PropertyInfo propInfo = typeof ( AttributeWithResolutionPolicy ) . GetProperty ( nameof ( AttributeWithResolutionPolicy . PropWithConstructorlessPolicy ) ) ;
381
-
382
- InvalidOperationException ex = Assert . Throws < InvalidOperationException > ( ( ) => AttributeCloner < AttributeWithResolutionPolicy > . GetPolicy ( propInfo ) ) ;
481
+ AutoResolveAttribute attr = propInfo . GetCustomAttribute < AutoResolveAttribute > ( ) ;
482
+ InvalidOperationException ex = Assert . Throws < InvalidOperationException > ( ( ) => AttributeCloner < AttributeWithResolutionPolicy > . GetPolicy ( attr . ResolutionPolicyType , propInfo ) ) ;
383
483
384
484
Assert . Equal ( $ "The { nameof ( AutoResolveAttribute . ResolutionPolicyType ) } on { nameof ( AttributeWithResolutionPolicy . PropWithConstructorlessPolicy ) } must derive from { typeof ( IResolutionPolicy ) . Name } and have a default constructor.", ex . Message ) ;
385
485
}
0 commit comments