Skip to content

Commit 22cab23

Browse files
Merge branch 'main' into e2e
2 parents f17b6b0 + 3b805aa commit 22cab23

4 files changed

Lines changed: 128 additions & 24 deletions

File tree

openfeature/memory_provider/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ cc_library(
2929
"//openfeature:provider_status",
3030
"//openfeature:reason",
3131
"//openfeature:resolution_details",
32+
"//openfeature:value",
3233
"@abseil-cpp//absl/status",
3334
"@abseil-cpp//absl/status:statusor",
3435
],

openfeature/memory_provider/in_memory_provider.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,27 @@ std::unique_ptr<BoolResolutionDetails> InMemoryProvider::GetBooleanEvaluation(
5555
return Evaluate<bool>(key, default_value, ctx);
5656
}
5757

58+
std::unique_ptr<StringResolutionDetails> InMemoryProvider::GetStringEvaluation(
59+
std::string_view key, std::string_view default_value,
60+
const EvaluationContext& ctx) {
61+
return Evaluate<std::string>(key, std::string(default_value), ctx);
62+
}
63+
64+
std::unique_ptr<IntResolutionDetails> InMemoryProvider::GetIntegerEvaluation(
65+
std::string_view key, int64_t default_value, const EvaluationContext& ctx) {
66+
return Evaluate<int64_t>(key, default_value, ctx);
67+
}
68+
69+
std::unique_ptr<DoubleResolutionDetails> InMemoryProvider::GetDoubleEvaluation(
70+
std::string_view key, double default_value, const EvaluationContext& ctx) {
71+
return Evaluate<double>(key, default_value, ctx);
72+
}
73+
74+
std::unique_ptr<ObjectResolutionDetails> InMemoryProvider::GetObjectEvaluation(
75+
std::string_view key, Value default_value, const EvaluationContext& ctx) {
76+
return Evaluate<Value>(key, default_value, ctx);
77+
}
78+
5879
template <typename T>
5980
std::unique_ptr<ResolutionDetails<T>> InMemoryProvider::Evaluate(
6081
std::string_view key, T default_value, const EvaluationContext& ctx) {

openfeature/memory_provider/in_memory_provider.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "openfeature/provider.h"
1515
#include "openfeature/provider_status.h"
1616
#include "openfeature/resolution_details.h"
17+
#include "openfeature/value.h"
1718

1819
namespace openfeature {
1920

@@ -45,6 +46,22 @@ class InMemoryProvider : public FeatureProvider {
4546
std::string_view key, bool default_value,
4647
const EvaluationContext& ctx) override;
4748

49+
std::unique_ptr<StringResolutionDetails> GetStringEvaluation(
50+
std::string_view key, std::string_view default_value,
51+
const EvaluationContext& ctx) override;
52+
53+
std::unique_ptr<IntResolutionDetails> GetIntegerEvaluation(
54+
std::string_view key, int64_t default_value,
55+
const EvaluationContext& ctx) override;
56+
57+
std::unique_ptr<DoubleResolutionDetails> GetDoubleEvaluation(
58+
std::string_view key, double default_value,
59+
const EvaluationContext& ctx) override;
60+
61+
std::unique_ptr<ObjectResolutionDetails> GetObjectEvaluation(
62+
std::string_view key, Value default_value,
63+
const EvaluationContext& ctx) override;
64+
4865
private:
4966
template <typename T>
5067
std::unique_ptr<ResolutionDetails<T>> Evaluate(std::string_view key,

test/memory_provider/in_memory_provider_test.cpp

Lines changed: 89 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "openfeature/memory_provider/flag.h"
1616
#include "openfeature/reason.h"
1717
#include "openfeature/resolution_details.h"
18+
#include "openfeature/value.h"
1819

1920
namespace openfeature {
2021

@@ -25,13 +26,14 @@ class InMemoryProviderTest : public ::testing::Test {
2526
protected:
2627
EvaluationContext empty_ctx_ = EvaluationContext::Builder().build();
2728

28-
// Helper method to create a basic boolean flag for testing.
29-
Flag<bool> CreateBoolFlag(std::unordered_map<std::string, bool> variants,
30-
std::optional<std::string> default_variant_opt,
31-
Flag<bool>::ContextEvaluator evaluator = nullptr,
32-
bool disabled = false) {
33-
return Flag<bool>(std::move(variants), std::move(default_variant_opt),
34-
std::move(evaluator), FlagMetadata{}, disabled);
29+
// Helper method to create a generic flag for testing.
30+
template <typename T>
31+
Flag<T> CreateFlag(std::unordered_map<std::string, T> variants,
32+
std::optional<std::string> default_variant_opt,
33+
typename Flag<T>::ContextEvaluator evaluator = nullptr,
34+
bool disabled = false) {
35+
return Flag<T>(std::move(variants), std::move(default_variant_opt),
36+
std::move(evaluator), FlagMetadata{}, disabled);
3537
}
3638
};
3739

@@ -101,7 +103,7 @@ TEST_F(InMemoryProviderTest, FlagTypeMismatch) {
101103
TEST_F(InMemoryProviderTest, DisabledFlagReturnsDisabledReason) {
102104
InMemoryProvider provider({});
103105
provider.UpdateFlag("disabled_flag",
104-
CreateBoolFlag({{"on", true}}, "on", nullptr, true));
106+
CreateFlag<bool>({{"on", true}}, "on", nullptr, true));
105107
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
106108

107109
std::unique_ptr<BoolResolutionDetails> res =
@@ -115,7 +117,7 @@ TEST_F(InMemoryProviderTest, DisabledFlagReturnsDisabledReason) {
115117
TEST_F(InMemoryProviderTest, StaticEvaluationSuccess) {
116118
InMemoryProvider provider({});
117119
provider.UpdateFlag("static_flag",
118-
CreateBoolFlag({{"on", true}, {"off", false}}, "on"));
120+
CreateFlag<bool>({{"on", true}, {"off", false}}, "on"));
119121
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
120122

121123
std::unique_ptr<BoolResolutionDetails> res =
@@ -133,8 +135,9 @@ TEST_F(InMemoryProviderTest, ContextEvaluatorSuccess) {
133135
};
134136

135137
InMemoryProvider provider({});
136-
provider.UpdateFlag("dyn_flag", CreateBoolFlag({{"on", true}, {"off", false}},
137-
"on", evaluator));
138+
provider.UpdateFlag(
139+
"dyn_flag",
140+
CreateFlag<bool>({{"on", true}, {"off", false}}, "on", evaluator));
138141
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
139142

140143
std::unique_ptr<BoolResolutionDetails> res =
@@ -151,8 +154,9 @@ TEST_F(InMemoryProviderTest, ContextEvaluatorFailureFallsBackToDefaultVariant) {
151154
};
152155

153156
InMemoryProvider provider({});
154-
provider.UpdateFlag("dyn_flag", CreateBoolFlag({{"on", true}, {"off", false}},
155-
"off", evaluator));
157+
provider.UpdateFlag(
158+
"dyn_flag",
159+
CreateFlag<bool>({{"on", true}, {"off", false}}, "off", evaluator));
156160
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
157161

158162
std::unique_ptr<BoolResolutionDetails> res =
@@ -201,23 +205,23 @@ TEST_F(InMemoryProviderTest, UpdateFlagReplacesAndAddsNew) {
201205
InMemoryProvider provider({});
202206
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
203207

204-
provider.UpdateFlag("flag1", CreateBoolFlag({{"on", true}}, "on"));
208+
provider.UpdateFlag("flag1", CreateFlag<bool>({{"on", true}}, "on"));
205209
EXPECT_TRUE(
206210
provider.GetBooleanEvaluation("flag1", false, empty_ctx_)->GetValue());
207211

208-
provider.UpdateFlag("flag1", CreateBoolFlag({{"off", false}}, "off"));
212+
provider.UpdateFlag("flag1", CreateFlag<bool>({{"off", false}}, "off"));
209213
EXPECT_FALSE(
210214
provider.GetBooleanEvaluation("flag1", true, empty_ctx_)->GetValue());
211215

212-
provider.UpdateFlag("new_flag", CreateBoolFlag({{"added", true}}, "added"));
216+
provider.UpdateFlag("new_flag", CreateFlag<bool>({{"added", true}}, "added"));
213217
EXPECT_TRUE(
214218
provider.GetBooleanEvaluation("new_flag", false, empty_ctx_)->GetValue());
215219
}
216220

217221
TEST_F(InMemoryProviderTest, UpdateFlagsAddsAndOverwritesExisting) {
218222
std::unordered_map<std::string, std::any> initial;
219-
initial["flag1"] = CreateBoolFlag({{"on", true}}, "on");
220-
initial["common_flag"] = CreateBoolFlag({{"initial", false}}, "initial");
223+
initial["flag1"] = CreateFlag<bool>({{"on", true}}, "on");
224+
initial["common_flag"] = CreateFlag<bool>({{"initial", false}}, "initial");
221225

222226
InMemoryProvider provider(std::move(initial));
223227
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
@@ -227,8 +231,8 @@ TEST_F(InMemoryProviderTest, UpdateFlagsAddsAndOverwritesExisting) {
227231
->GetValue());
228232

229233
std::unordered_map<std::string, std::any> updated;
230-
updated["flag2"] = CreateBoolFlag({{"off", false}}, "off");
231-
updated["common_flag"] = CreateBoolFlag({{"updated", true}}, "updated");
234+
updated["flag2"] = CreateFlag<bool>({{"off", false}}, "off");
235+
updated["common_flag"] = CreateFlag<bool>({{"updated", true}}, "updated");
232236

233237
provider.UpdateFlags(std::move(updated));
234238

@@ -258,7 +262,7 @@ TEST_F(InMemoryProviderTest, UpdateFlagsAddsAndOverwritesExisting) {
258262
TEST_F(InMemoryProviderTest, NoDefaultVariantAndEvaluatorFailsOrMissing) {
259263
InMemoryProvider provider1({});
260264
provider1.UpdateFlag("no_default_no_evaluator",
261-
CreateBoolFlag({{"v1", true}}, std::nullopt, nullptr));
265+
CreateFlag<bool>({{"v1", true}}, std::nullopt, nullptr));
262266
EXPECT_TRUE(provider1.Init(empty_ctx_).ok());
263267
std::unique_ptr<BoolResolutionDetails> res1 = provider1.GetBooleanEvaluation(
264268
"no_default_no_evaluator", true, empty_ctx_);
@@ -273,7 +277,7 @@ TEST_F(InMemoryProviderTest, NoDefaultVariantAndEvaluatorFailsOrMissing) {
273277
InMemoryProvider provider2({});
274278
provider2.UpdateFlag(
275279
"no_default_failing_evaluator",
276-
CreateBoolFlag({{"v1", true}}, std::nullopt, failing_evaluator));
280+
CreateFlag<bool>({{"v1", true}}, std::nullopt, failing_evaluator));
277281
EXPECT_TRUE(provider2.Init(empty_ctx_).ok());
278282
std::unique_ptr<BoolResolutionDetails> res2 = provider2.GetBooleanEvaluation(
279283
"no_default_failing_evaluator", false, empty_ctx_);
@@ -300,8 +304,8 @@ TEST_F(InMemoryProviderTest, ContextEvaluatorUsesContext) {
300304

301305
InMemoryProvider provider({});
302306
provider.UpdateFlag("admin_flag",
303-
CreateBoolFlag({{"on", true}, {"off", false}}, "off",
304-
context_aware_evaluator));
307+
CreateFlag<bool>({{"on", true}, {"off", false}}, "off",
308+
context_aware_evaluator));
305309
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
306310

307311
EvaluationContext admin_ctx =
@@ -342,4 +346,65 @@ TEST_F(InMemoryProviderTest, ContextEvaluatorUsesContext) {
342346
EXPECT_THAT(res_wrong_type->GetVariant(), Optional(std::string("off")));
343347
EXPECT_FALSE(res_wrong_type->GetErrorCode().has_value());
344348
}
349+
350+
TEST_F(InMemoryProviderTest, StringEvaluationSuccess) {
351+
InMemoryProvider provider({});
352+
provider.UpdateFlag(
353+
"string_flag",
354+
CreateFlag<std::string>({{"v1", "hello"}, {"v2", "world"}}, "v2"));
355+
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
356+
357+
std::unique_ptr<StringResolutionDetails> res =
358+
provider.GetStringEvaluation("string_flag", "default", empty_ctx_);
359+
360+
ASSERT_NE(res, nullptr);
361+
EXPECT_EQ(res->GetValue(), "world");
362+
EXPECT_EQ(res->GetReason(), Reason::kStatic);
363+
EXPECT_THAT(res->GetVariant(), Optional(std::string("v2")));
364+
}
365+
366+
TEST_F(InMemoryProviderTest, IntegerEvaluationSuccess) {
367+
InMemoryProvider provider({});
368+
provider.UpdateFlag("int_flag",
369+
CreateFlag<int64_t>({{"v1", 100}, {"v2", 200}}, "v1"));
370+
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
371+
372+
std::unique_ptr<IntResolutionDetails> res =
373+
provider.GetIntegerEvaluation("int_flag", 0, empty_ctx_);
374+
375+
ASSERT_NE(res, nullptr);
376+
EXPECT_EQ(res->GetValue(), 100);
377+
EXPECT_EQ(res->GetReason(), Reason::kStatic);
378+
EXPECT_THAT(res->GetVariant(), Optional(std::string("v1")));
379+
}
380+
381+
TEST_F(InMemoryProviderTest, DoubleEvaluationSuccess) {
382+
InMemoryProvider provider({});
383+
provider.UpdateFlag("double_flag",
384+
CreateFlag<double>({{"v1", 3.14}, {"v2", 2.71}}, "v2"));
385+
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
386+
387+
std::unique_ptr<DoubleResolutionDetails> res =
388+
provider.GetDoubleEvaluation("double_flag", 0.0, empty_ctx_);
389+
390+
ASSERT_NE(res, nullptr);
391+
EXPECT_DOUBLE_EQ(res->GetValue(), 2.71);
392+
EXPECT_EQ(res->GetReason(), Reason::kStatic);
393+
EXPECT_THAT(res->GetVariant(), Optional(std::string("v2")));
394+
}
395+
396+
TEST_F(InMemoryProviderTest, ObjectEvaluationSuccess) {
397+
InMemoryProvider provider({});
398+
provider.UpdateFlag("object_flag",
399+
CreateFlag<Value>({{"v1", Value()}}, "v1"));
400+
EXPECT_TRUE(provider.Init(empty_ctx_).ok());
401+
402+
std::unique_ptr<ObjectResolutionDetails> res =
403+
provider.GetObjectEvaluation("object_flag", Value(), empty_ctx_);
404+
405+
ASSERT_NE(res, nullptr);
406+
EXPECT_EQ(res->GetReason(), Reason::kStatic);
407+
EXPECT_THAT(res->GetVariant(), Optional(std::string("v1")));
408+
}
409+
345410
} // namespace openfeature

0 commit comments

Comments
 (0)