1+ #if ! NETCOREAPP1_1
2+
3+ using System ;
4+ using System . Text ;
5+ using FluentAssertions ;
6+ using Microsoft . Extensions . Caching . Memory ;
7+ using Microsoft . Extensions . Caching . Distributed ;
8+ using Microsoft . Extensions . Options ;
9+ using Newtonsoft . Json ;
10+ using Polly . Caching ;
11+ using Polly . Caching . Distributed ;
12+ using Polly . Caching . Serialization . Json ;
13+ using Xunit ;
14+
15+ namespace Polly . Specs . Caching . DistributedNew
16+ {
17+ public class NetStandardIDistributedCacheProvider_CacheRoundTripSpecs_String : NetStandardIDistributedCacheProvider_CacheRoundTripSpecs < string > { }
18+
19+ public class NetStandardIDistributedCacheProvider_CacheRoundTripSpecs_ByteArray : NetStandardIDistributedCacheProvider_CacheRoundTripSpecs < byte [ ] > { }
20+
21+ public abstract class NetStandardIDistributedCacheProvider_CacheRoundTripSpecs < TCache >
22+ {
23+
24+ const string OperationKey = "SomeOperationKey" ;
25+
26+ #region Round-trip
27+
28+ private class ByteArraySerializer : ICacheItemSerializer < string , byte [ ] >
29+ {
30+ public string Deserialize ( byte [ ] objectToDeserialize )
31+ {
32+ return objectToDeserialize == null ? null : Encoding . UTF8 . GetString ( objectToDeserialize ) ;
33+ }
34+
35+ public byte [ ] Serialize ( string objectToSerialize )
36+ {
37+ return objectToSerialize == null ? null : Encoding . UTF8 . GetBytes ( objectToSerialize ) ;
38+ }
39+ }
40+
41+ private ( ISyncCacheProvider < TResult > , ISyncPolicy < TResult > ) GetFreshCachePolicy < TResult > ( )
42+ {
43+ var memoryIDistributedCache = new MemoryDistributedCache ( Options . Create ( new MemoryDistributedCacheOptions ( ) ) ) ;
44+ ISyncCacheProvider < TResult > memoryIDistributedCacheProvider ;
45+ if ( typeof ( TCache ) == typeof ( string ) )
46+ {
47+ memoryIDistributedCacheProvider = memoryIDistributedCache . AsSyncCacheProvider < string > ( ) . WithSerializer < TResult , string > ( new JsonSerializer < TResult > ( new JsonSerializerSettings ( ) ) ) ;
48+ }
49+ else if ( typeof ( TCache ) == typeof ( byte [ ] ) )
50+ {
51+ memoryIDistributedCacheProvider = memoryIDistributedCache . AsSyncCacheProvider < byte [ ] > ( ) . WithSerializer ( new ByteArraySerializer ( ) ) . WithSerializer < TResult , string > ( new JsonSerializer < TResult > ( new JsonSerializerSettings ( ) ) ) ;
52+ }
53+ else
54+ {
55+ throw new ArgumentException ( $ "{ nameof ( TCache ) } must be either { typeof ( string ) . Name } or { typeof ( byte ) . Name } []", nameof ( TCache ) ) ;
56+ }
57+
58+ var policy = Policy . Cache < TResult > ( memoryIDistributedCacheProvider , TimeSpan . FromHours ( 1 ) ) ;
59+ return ( memoryIDistributedCacheProvider , policy ) ;
60+ }
61+
62+ private void Should_roundtrip_this_variant_of < TResult > ( TResult testValue )
63+ {
64+ // Arrange
65+ var ( memoryIDistributedCacheProvider , cache ) = GetFreshCachePolicy < TResult > ( ) ;
66+
67+ // Assert - should not be in cache
68+ /* v7.0 (bool cacheHit1, object fromCache1) = memoryIDistributedCacheProvider.TryGet(OperationKey);
69+ cacheHit1.Should().BeFalse();*/
70+ TResult fromCache1 = memoryIDistributedCacheProvider . Get ( OperationKey ) ;
71+ fromCache1 . Should ( ) . Be ( default ( TResult ) ) ;
72+
73+ // Act - should execute underlying delegate and place in cache
74+ int underlyingDelegateExecuteCount = 0 ;
75+ cache . Execute ( ctx =>
76+ {
77+ underlyingDelegateExecuteCount ++ ;
78+ return testValue ;
79+ } , new Context ( OperationKey ) )
80+ . ShouldBeEquivalentTo ( testValue ) ;
81+
82+ // Assert - should have executed underlying delegate
83+ underlyingDelegateExecuteCount . Should ( ) . Be ( 1 ) ;
84+
85+ // Assert - should be in cache
86+ /* v7.0 (bool cacheHit2, object fromCache2) = memoryIDistributedCacheProvider.TryGet(OperationKey);
87+ cacheHit2.Should().BeTrue();*/
88+ TResult fromCache2 = memoryIDistributedCacheProvider . Get ( OperationKey ) ;
89+ fromCache2 . ShouldBeEquivalentTo ( testValue ) ;
90+
91+ // Act - should execute underlying delegate and place in cache
92+ cache . Execute ( ctx =>
93+ {
94+ underlyingDelegateExecuteCount ++ ;
95+ throw new Exception ( "Cache should be used so this should not get invoked." ) ;
96+ } , new Context ( OperationKey ) )
97+ . ShouldBeEquivalentTo ( testValue ) ;
98+ underlyingDelegateExecuteCount . Should ( ) . Be ( 1 ) ;
99+ }
100+
101+ [ Theory ]
102+ [ MemberData ( nameof ( SampleClassData ) ) ]
103+ public void Should_roundtrip_all_variants_of_reference_type ( SampleClass testValue )
104+ {
105+ Should_roundtrip_this_variant_of < SampleClass > ( testValue ) ;
106+ }
107+
108+ public static TheoryData < SampleClass > SampleClassData =>
109+ new TheoryData < SampleClass >
110+ {
111+ new SampleClass ( ) ,
112+ new SampleClass ( )
113+ {
114+ StringProperty = "<html></html>" ,
115+ IntProperty = 1
116+ } ,
117+ ( SampleClass ) null ,
118+ default ( SampleClass )
119+ } ;
120+
121+ public class SampleClass
122+ {
123+ public string StringProperty { get ; set ; }
124+ public int IntProperty { get ; set ; }
125+ }
126+
127+ [ Theory ]
128+ [ MemberData ( nameof ( SampleStringData ) ) ]
129+ public void Should_roundtrip_all_variants_of_string ( String testValue )
130+ {
131+ Should_roundtrip_this_variant_of < String > ( testValue ) ;
132+ }
133+
134+ public static TheoryData < String > SampleStringData =>
135+ new TheoryData < String >
136+ {
137+ "some string" ,
138+ "" ,
139+ null ,
140+ default ( string ) ,
141+ "null"
142+ } ;
143+
144+ [ Theory ]
145+ [ MemberData ( nameof ( SampleNumericData ) ) ]
146+ public void Should_roundtrip_all_variants_of_numeric ( int testValue )
147+ {
148+ Should_roundtrip_this_variant_of < int > ( testValue ) ;
149+ }
150+
151+
152+ public static TheoryData < int > SampleNumericData =>
153+ new TheoryData < int >
154+ {
155+ - 1 ,
156+ 0 ,
157+ 1 ,
158+ default ( int )
159+ } ;
160+
161+ [ Theory ]
162+ [ MemberData ( nameof ( SampleEnumData ) ) ]
163+ public void Should_roundtrip_all_variants_of_enum ( SampleEnum testValue )
164+ {
165+ Should_roundtrip_this_variant_of < SampleEnum > ( testValue ) ;
166+ }
167+
168+
169+ public static TheoryData < SampleEnum > SampleEnumData =>
170+ new TheoryData < SampleEnum >
171+ {
172+ SampleEnum . FirstValue ,
173+ SampleEnum . SecondValue ,
174+ default ( SampleEnum ) ,
175+ } ;
176+
177+ public enum SampleEnum
178+ {
179+ FirstValue ,
180+ SecondValue ,
181+ }
182+
183+ [ Theory ]
184+ [ MemberData ( nameof ( SampleBoolData ) ) ]
185+ public void Should_roundtrip_all_variants_of_bool ( bool testValue )
186+ {
187+ Should_roundtrip_this_variant_of < bool > ( testValue ) ;
188+ }
189+
190+ public static TheoryData < bool > SampleBoolData =>
191+ new TheoryData < bool >
192+ {
193+ true ,
194+ false ,
195+ default ( bool ) ,
196+ } ;
197+
198+ [ Theory ]
199+ [ MemberData ( nameof ( SampleNullableBoolData ) ) ]
200+ public void Should_roundtrip_all_variants_of_nullable_bool ( bool ? testValue )
201+ {
202+ Should_roundtrip_this_variant_of < bool ? > ( testValue ) ;
203+ }
204+
205+ public static TheoryData < bool ? > SampleNullableBoolData =>
206+ new TheoryData < bool ? >
207+ {
208+ true ,
209+ false ,
210+ null ,
211+ default ( bool ? ) ,
212+ } ;
213+
214+ #endregion
215+ }
216+ }
217+
218+ #endif
0 commit comments