11using System ;
22using System . Collections . Generic ;
33using System . Collections . Immutable ;
4+ using System . Threading ;
45using OpenFeature . Constant ;
56using OpenFeature . Error ;
67using OpenFeature . Model ;
910
1011namespace OpenFeature . Tests
1112{
12- // most of the in-memory tests are handled in the e2e suite
1313 public class InMemoryProviderTests
1414 {
15+ private FeatureProvider commonProvider ;
16+
17+ public InMemoryProviderTests ( )
18+ {
19+ var provider = new InMemoryProvider ( new Dictionary < string , Flag > ( ) {
20+ {
21+ "boolean-flag" , new Flag < bool > (
22+ variants : new Dictionary < string , bool > ( ) {
23+ { "on" , true } ,
24+ { "off" , false }
25+ } ,
26+ defaultVariant : "on"
27+ )
28+ } ,
29+ {
30+ "string-flag" , new Flag < string > (
31+ variants : new Dictionary < string , string > ( ) {
32+ { "greeting" , "hi" } ,
33+ { "parting" , "bye" }
34+ } ,
35+ defaultVariant : "greeting"
36+ )
37+ } ,
38+ {
39+ "integer-flag" , new Flag < int > (
40+ variants : new Dictionary < string , int > ( ) {
41+ { "one" , 1 } ,
42+ { "ten" , 10 }
43+ } ,
44+ defaultVariant : "ten"
45+ )
46+ } ,
47+ {
48+ "float-flag" , new Flag < double > (
49+ variants : new Dictionary < string , double > ( ) {
50+ { "tenth" , 0.1 } ,
51+ { "half" , 0.5 }
52+ } ,
53+ defaultVariant : "half"
54+ )
55+ } ,
56+ {
57+ "object-flag" , new Flag < Value > (
58+ variants : new Dictionary < string , Value > ( ) {
59+ { "empty" , new Value ( ) } ,
60+ { "template" , new Value ( Structure . Builder ( )
61+ . Set ( "showImages" , true )
62+ . Set ( "title" , "Check out these pics!" )
63+ . Set ( "imagesPerPage" , 100 ) . Build ( )
64+ )
65+ }
66+ } ,
67+ defaultVariant : "template"
68+ )
69+ }
70+ } ) ;
71+
72+ this . commonProvider = provider ;
73+ }
74+
75+ [ Fact ]
76+ public async void GetBoolean_ShouldEvaluate ( )
77+ {
78+ ResolutionDetails < bool > details = await this . commonProvider . ResolveBooleanValue ( "boolean-flag" , false , EvaluationContext . Empty ) . ConfigureAwait ( false ) ;
79+ Assert . True ( details . Value ) ;
80+ Assert . Equal ( Reason . Static , details . Reason ) ;
81+ Assert . Equal ( "on" , details . Variant ) ;
82+ }
83+
84+ [ Fact ]
85+ public async void GetString_ShouldEvaluate ( )
86+ {
87+ ResolutionDetails < string > details = await this . commonProvider . ResolveStringValue ( "string-flag" , "nope" , EvaluationContext . Empty ) . ConfigureAwait ( false ) ;
88+ Assert . Equal ( "hi" , details . Value ) ;
89+ Assert . Equal ( Reason . Static , details . Reason ) ;
90+ Assert . Equal ( "greeting" , details . Variant ) ;
91+ }
92+
93+ [ Fact ]
94+ public async void GetInt_ShouldEvaluate ( )
95+ {
96+ ResolutionDetails < int > details = await this . commonProvider . ResolveIntegerValue ( "integer-flag" , 13 , EvaluationContext . Empty ) . ConfigureAwait ( false ) ;
97+ Assert . Equal ( 10 , details . Value ) ;
98+ Assert . Equal ( Reason . Static , details . Reason ) ;
99+ Assert . Equal ( "ten" , details . Variant ) ;
100+ }
101+
102+ [ Fact ]
103+ public async void GetDouble_ShouldEvaluate ( )
104+ {
105+ ResolutionDetails < double > details = await this . commonProvider . ResolveDoubleValue ( "float-flag" , 13 , EvaluationContext . Empty ) . ConfigureAwait ( false ) ;
106+ Assert . Equal ( 0.5 , details . Value ) ;
107+ Assert . Equal ( Reason . Static , details . Reason ) ;
108+ Assert . Equal ( "half" , details . Variant ) ;
109+ }
110+
111+ [ Fact ]
112+ public async void GetStruct_ShouldEvaluate ( )
113+ {
114+ ResolutionDetails < Value > details = await this . commonProvider . ResolveStructureValue ( "object-flag" , new Value ( ) , EvaluationContext . Empty ) . ConfigureAwait ( false ) ;
115+ Assert . Equal ( true , details . Value . AsStructure [ "showImages" ] . AsBoolean ) ;
116+ Assert . Equal ( "Check out these pics!" , details . Value . AsStructure [ "title" ] . AsString ) ;
117+ Assert . Equal ( 100 , details . Value . AsStructure [ "imagesPerPage" ] . AsInteger ) ;
118+ Assert . Equal ( Reason . Static , details . Reason ) ;
119+ Assert . Equal ( "template" , details . Variant ) ;
120+ }
121+
122+ [ Fact ]
123+ public async void MissingFlag_ShouldThrow ( )
124+ {
125+ await Assert . ThrowsAsync < FlagNotFoundException > ( ( ) => commonProvider . ResolveBooleanValue ( "missing-flag" , false , EvaluationContext . Empty ) ) . ConfigureAwait ( false ) ;
126+ }
127+
128+ [ Fact ]
129+ public async void MismatchedFlag_ShouldThrow ( )
130+ {
131+ await Assert . ThrowsAsync < TypeMismatchException > ( ( ) => commonProvider . ResolveStringValue ( "boolean-flag" , "nope" , EvaluationContext . Empty ) ) . ConfigureAwait ( false ) ;
132+ }
133+
15134 [ Fact ]
16135 public async void PutConfiguration_shouldUpdateConfigAndRunHandlers ( )
17136 {
18- var handlerRuns = 0 ;
19137 var provider = new InMemoryProvider ( new Dictionary < string , Flag > ( ) {
20138 {
21- "boolean -flag" , new Flag < bool > (
139+ "old -flag" , new Flag < bool > (
22140 variants : new Dictionary < string , bool > ( ) {
23141 { "on" , true } ,
24142 { "off" , false }
@@ -27,19 +145,13 @@ public async void PutConfiguration_shouldUpdateConfigAndRunHandlers()
27145 )
28146 } } ) ;
29147
30- // setup client and handler and run initial eval
31- await Api . Instance . SetProviderAsync ( "mem-test" , provider ) . ConfigureAwait ( false ) ;
32- var client = Api . Instance . GetClient ( "mem-test" ) ;
33- client . AddHandler ( ProviderEventTypes . ProviderConfigurationChanged , ( details ) =>
34- {
35- handlerRuns ++ ;
36- } ) ;
37- Assert . True ( await client . GetBooleanValue ( "boolean-flag" , false ) . ConfigureAwait ( false ) ) ;
148+ ResolutionDetails < bool > details = await provider . ResolveBooleanValue ( "old-flag" , false , EvaluationContext . Empty ) . ConfigureAwait ( false ) ;
149+ Assert . True ( details . Value ) ;
38150
39151 // update flags
40152 await provider . UpdateFlags ( new Dictionary < string , Flag > ( ) {
41153 {
42- "string -flag" , new Flag < string > (
154+ "new -flag" , new Flag < string > (
43155 variants : new Dictionary < string , string > ( ) {
44156 { "greeting" , "hi" } ,
45157 { "parting" , "bye" }
@@ -48,10 +160,15 @@ await provider.UpdateFlags(new Dictionary<string, Flag>(){
48160 )
49161 } } ) . ConfigureAwait ( false ) ;
50162
163+ var res = await provider . GetEventChannel ( ) . Reader . ReadAsync ( ) . ConfigureAwait ( false ) as ProviderEventPayload ;
164+ Assert . Equal ( ProviderEventTypes . ProviderConfigurationChanged , res . Type ) ;
165+
166+ await Assert . ThrowsAsync < FlagNotFoundException > ( ( ) => provider . ResolveBooleanValue ( "old-flag" , false , EvaluationContext . Empty ) ) . ConfigureAwait ( false ) ;
167+
51168 // new flag should be present, old gone (defaults), handler run.
52- Assert . Equal ( "hi" , await client . GetStringValue ( "string -flag", "nope" ) . ConfigureAwait ( false ) ) ;
53- Assert . False ( await client . GetBooleanValue ( "boolean-flag" , false ) . ConfigureAwait ( false ) ) ;
54- Assert . Equal ( 1 , handlerRuns ) ;
169+ ResolutionDetails < string > detailsAfter = await provider . ResolveStringValue ( "new -flag", "nope" , EvaluationContext . Empty ) . ConfigureAwait ( false ) ;
170+ Assert . True ( details . Value ) ;
171+ Assert . Equal ( "hi" , detailsAfter . Value ) ;
55172 }
56173 }
57174}
0 commit comments