diff --git a/openfeature/BUILD b/openfeature/BUILD index 162621d..fd06df3 100644 --- a/openfeature/BUILD +++ b/openfeature/BUILD @@ -120,7 +120,8 @@ cc_library( include_prefix = "openfeature", deps = [ ":evaluation_context", - ":value" + ":evaluation_options", + ":value", ], ) diff --git a/openfeature/client_api.cpp b/openfeature/client_api.cpp index 73d6260..3747953 100644 --- a/openfeature/client_api.cpp +++ b/openfeature/client_api.cpp @@ -30,62 +30,141 @@ ProviderStatus ClientAPI::GetProviderStatus() { } bool ClientAPI::GetBooleanValue(std::string_view flag_key, bool default_value) { - return EvaluateBooleanFlag(flag_key, default_value, std::nullopt)->GetValue(); + return EvaluateBooleanFlag(flag_key, default_value, std::nullopt, + std::nullopt) + ->GetValue(); } bool ClientAPI::GetBooleanValue(std::string_view flag_key, bool default_value, const EvaluationContext& ctx) { - return EvaluateBooleanFlag(flag_key, default_value, ctx)->GetValue(); + return EvaluateBooleanFlag(flag_key, default_value, ctx, std::nullopt) + ->GetValue(); +} + +bool ClientAPI::GetBooleanValue(std::string_view flag_key, bool default_value, + const EvaluationOptions& options) { + return EvaluateBooleanFlag(flag_key, default_value, std::nullopt, options) + ->GetValue(); +} + +bool ClientAPI::GetBooleanValue(std::string_view flag_key, bool default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) { + return EvaluateBooleanFlag(flag_key, default_value, ctx, options)->GetValue(); } std::string ClientAPI::GetStringValue(std::string_view flag_key, std::string_view default_value) { - return EvaluateStringFlag(flag_key, default_value, std::nullopt)->GetValue(); + return EvaluateStringFlag(flag_key, default_value, std::nullopt, std::nullopt) + ->GetValue(); } std::string ClientAPI::GetStringValue(std::string_view flag_key, std::string_view default_value, const EvaluationContext& ctx) { - return EvaluateStringFlag(flag_key, default_value, ctx)->GetValue(); + return EvaluateStringFlag(flag_key, default_value, ctx, std::nullopt) + ->GetValue(); +} + +std::string ClientAPI::GetStringValue(std::string_view flag_key, + std::string_view default_value, + const EvaluationOptions& options) { + return EvaluateStringFlag(flag_key, default_value, std::nullopt, options) + ->GetValue(); +} + +std::string ClientAPI::GetStringValue(std::string_view flag_key, + std::string_view default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) { + return EvaluateStringFlag(flag_key, default_value, ctx, options)->GetValue(); } int64_t ClientAPI::GetIntegerValue(std::string_view flag_key, int64_t default_value) { - return EvaluateIntegerFlag(flag_key, default_value, std::nullopt)->GetValue(); + return EvaluateIntegerFlag(flag_key, default_value, std::nullopt, + std::nullopt) + ->GetValue(); } int64_t ClientAPI::GetIntegerValue(std::string_view flag_key, int64_t default_value, const EvaluationContext& ctx) { - return EvaluateIntegerFlag(flag_key, default_value, ctx)->GetValue(); + return EvaluateIntegerFlag(flag_key, default_value, ctx, std::nullopt) + ->GetValue(); +} + +int64_t ClientAPI::GetIntegerValue(std::string_view flag_key, + int64_t default_value, + const EvaluationOptions& options) { + return EvaluateIntegerFlag(flag_key, default_value, std::nullopt, options) + ->GetValue(); +} + +int64_t ClientAPI::GetIntegerValue(std::string_view flag_key, + int64_t default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) { + return EvaluateIntegerFlag(flag_key, default_value, ctx, options)->GetValue(); } double ClientAPI::GetDoubleValue(std::string_view flag_key, double default_value) { - return EvaluateDoubleFlag(flag_key, default_value, std::nullopt)->GetValue(); + return EvaluateDoubleFlag(flag_key, default_value, std::nullopt, std::nullopt) + ->GetValue(); } double ClientAPI::GetDoubleValue(std::string_view flag_key, double default_value, const EvaluationContext& ctx) { - return EvaluateDoubleFlag(flag_key, default_value, ctx)->GetValue(); + return EvaluateDoubleFlag(flag_key, default_value, ctx, std::nullopt) + ->GetValue(); +} + +double ClientAPI::GetDoubleValue(std::string_view flag_key, + double default_value, + const EvaluationOptions& options) { + return EvaluateDoubleFlag(flag_key, default_value, std::nullopt, options) + ->GetValue(); +} + +double ClientAPI::GetDoubleValue(std::string_view flag_key, + double default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) { + return EvaluateDoubleFlag(flag_key, default_value, ctx, options)->GetValue(); } Value ClientAPI::GetObjectValue(std::string_view flag_key, Value default_value) { - return EvaluateObjectFlag(flag_key, default_value, std::nullopt)->GetValue(); + return EvaluateObjectFlag(flag_key, default_value, std::nullopt, std::nullopt) + ->GetValue(); } Value ClientAPI::GetObjectValue(std::string_view flag_key, Value default_value, const EvaluationContext& ctx) { - return EvaluateObjectFlag(flag_key, default_value, ctx)->GetValue(); + return EvaluateObjectFlag(flag_key, default_value, ctx, std::nullopt) + ->GetValue(); +} + +Value ClientAPI::GetObjectValue(std::string_view flag_key, Value default_value, + const EvaluationOptions& options) { + return EvaluateObjectFlag(flag_key, default_value, std::nullopt, options) + ->GetValue(); +} + +Value ClientAPI::GetObjectValue(std::string_view flag_key, Value default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) { + return EvaluateObjectFlag(flag_key, default_value, ctx, options)->GetValue(); } std::unique_ptr ClientAPI::EvaluateBooleanFlag( std::string_view flag_key, bool default_value, - const std::optional& ctx) { + const std::optional& ctx, + const std::optional& options) { return this->EvaluateFlag( - default_value, ctx, + default_value, ctx, options, [&](const std::shared_ptr& provider, const EvaluationContext& merged_ctx) { return provider->GetBooleanEvaluation(flag_key, default_value, @@ -95,10 +174,11 @@ std::unique_ptr ClientAPI::EvaluateBooleanFlag( std::unique_ptr ClientAPI::EvaluateStringFlag( std::string_view flag_key, std::string_view default_value, - const std::optional& ctx) { + const std::optional& ctx, + const std::optional& options) { std::string default_str(default_value); return this->EvaluateFlag( - default_str, ctx, + default_str, ctx, options, [&](const std::shared_ptr& provider, const EvaluationContext& merged_ctx) { return provider->GetStringEvaluation(flag_key, default_value, @@ -108,9 +188,10 @@ std::unique_ptr ClientAPI::EvaluateStringFlag( std::unique_ptr ClientAPI::EvaluateIntegerFlag( std::string_view flag_key, int64_t default_value, - const std::optional& ctx) { + const std::optional& ctx, + const std::optional& options) { return this->EvaluateFlag( - default_value, ctx, + default_value, ctx, options, [&](const std::shared_ptr& provider, const EvaluationContext& merged_ctx) { return provider->GetIntegerEvaluation(flag_key, default_value, @@ -120,9 +201,10 @@ std::unique_ptr ClientAPI::EvaluateIntegerFlag( std::unique_ptr ClientAPI::EvaluateDoubleFlag( std::string_view flag_key, double default_value, - const std::optional& ctx) { + const std::optional& ctx, + const std::optional& options) { return this->EvaluateFlag( - default_value, ctx, + default_value, ctx, options, [&](const std::shared_ptr& provider, const EvaluationContext& merged_ctx) { return provider->GetDoubleEvaluation(flag_key, default_value, @@ -132,9 +214,10 @@ std::unique_ptr ClientAPI::EvaluateDoubleFlag( std::unique_ptr ClientAPI::EvaluateObjectFlag( std::string_view flag_key, Value default_value, - const std::optional& ctx) { + const std::optional& ctx, + const std::optional& options) { return this->EvaluateFlag( - default_value, ctx, + default_value, ctx, options, [&](const std::shared_ptr& provider, const EvaluationContext& merged_ctx) { return provider->GetObjectEvaluation(flag_key, default_value, diff --git a/openfeature/client_api.h b/openfeature/client_api.h index 8ea62da..8ae85ba 100644 --- a/openfeature/client_api.h +++ b/openfeature/client_api.h @@ -47,6 +47,11 @@ class ClientAPI : public Client { bool GetBooleanValue(std::string_view flag_key, bool default_value) override; bool GetBooleanValue(std::string_view flag_key, bool default_value, const EvaluationContext& ctx) override; + bool GetBooleanValue(std::string_view flag_key, bool default_value, + const EvaluationOptions& options) override; + bool GetBooleanValue(std::string_view flag_key, bool default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) override; // Evaluate a string flag. std::string GetStringValue(std::string_view flag_key, @@ -54,21 +59,54 @@ class ClientAPI : public Client { std::string GetStringValue(std::string_view flag_key, std::string_view default_value, const EvaluationContext& ctx) override; + std::string GetStringValue(std::string_view flag_key, + std::string_view default_value, + const EvaluationOptions& options) override; + std::string GetStringValue(std::string_view flag_key, + std::string_view default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) override; // Evaluate an integer flag. int64_t GetIntegerValue(std::string_view flag_key, int64_t default_value) override; int64_t GetIntegerValue(std::string_view flag_key, int64_t default_value, const EvaluationContext& ctx) override; + int64_t GetIntegerValue(std::string_view flag_key, int64_t default_value, + const EvaluationOptions& options) override; + int64_t GetIntegerValue(std::string_view flag_key, int64_t default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) override; + // Evaluate a double flag. double GetDoubleValue(std::string_view flag_key, double default_value) override; double GetDoubleValue(std::string_view flag_key, double default_value, const EvaluationContext& ctx) override; + double GetDoubleValue(std::string_view flag_key, double default_value, + const EvaluationOptions& options) override; + double GetDoubleValue(std::string_view flag_key, double default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) override; + // Evaluate an object flag. Value GetObjectValue(std::string_view flag_key, Value default_value) override; Value GetObjectValue(std::string_view flag_key, Value default_value, const EvaluationContext& ctx) override; + Value GetObjectValue(std::string_view flag_key, Value default_value, + const EvaluationOptions& options) override; + Value GetObjectValue(std::string_view flag_key, Value default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) override; + + // Adds one or more hooks to the client-level hook repository. + void AddHooks(std::vector> hooks) override; + + // Adds a single hook to the client-level hook repository. + void AddHook(std::shared_ptr hook) override; + + // Retrieves all configured client-level hooks. + std::vector> GetHooks() const override; // Adds one or more hooks to the client-level hook repository. void AddHooks(std::vector> hooks) override; @@ -80,34 +118,39 @@ class ClientAPI : public Client { std::vector> GetHooks() const override; // TODO: Add methods for detailed flag evaluation. - // TODO: Overload method "GetBooleanValue" to accept "Evaluation Options". private: template std::unique_ptr EvaluateFlag( ValueType default_value, const std::optional& ctx, + const std::optional& options, ProviderCallable provider_call); std::unique_ptr EvaluateBooleanFlag( std::string_view flag_key, bool default_value, - const std::optional& ctx); + const std::optional& ctx, + const std::optional& options = std::nullopt); std::unique_ptr EvaluateStringFlag( std::string_view flag_key, std::string_view default_value, - const std::optional& ctx); + const std::optional& ctx, + const std::optional& options = std::nullopt); std::unique_ptr EvaluateIntegerFlag( std::string_view flag_key, int64_t default_value, - const std::optional& ctx); + const std::optional& ctx, + const std::optional& options = std::nullopt); std::unique_ptr EvaluateDoubleFlag( std::string_view flag_key, double default_value, - const std::optional& ctx); + const std::optional& ctx, + const std::optional& options = std::nullopt); std::unique_ptr EvaluateObjectFlag( std::string_view flag_key, Value default_value, - const std::optional& ctx); + const std::optional& ctx, + const std::optional& options = std::nullopt); EvaluationContext MergeContexts( const std::optional& invocation_ctx); @@ -124,6 +167,7 @@ template std::unique_ptr ClientAPI::EvaluateFlag( ValueType default_value, const std::optional& ctx, + const std::optional& options, ProviderCallable provider_call) { std::shared_ptr manager = provider_repository_.GetFeatureProviderStatusManager(domain_); diff --git a/openfeature/features.h b/openfeature/features.h index 83897eb..7b51084 100644 --- a/openfeature/features.h +++ b/openfeature/features.h @@ -4,6 +4,7 @@ #include #include "openfeature/evaluation_context.h" +#include "openfeature/evaluation_options.h" #include "openfeature/value.h" namespace openfeature { @@ -16,28 +17,57 @@ class Features { bool default_value) = 0; virtual bool GetBooleanValue(std::string_view flag_key, bool default_value, const EvaluationContext& ctx) = 0; + virtual bool GetBooleanValue(std::string_view flag_key, bool default_value, + const EvaluationOptions& options) = 0; + virtual bool GetBooleanValue(std::string_view flag_key, bool default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) = 0; virtual std::string GetStringValue(std::string_view flag_key, std::string_view default_value) = 0; virtual std::string GetStringValue(std::string_view flag_key, std::string_view default_value, const EvaluationContext& ctx) = 0; + virtual std::string GetStringValue(std::string_view flag_key, + std::string_view default_value, + const EvaluationOptions& options) = 0; + virtual std::string GetStringValue(std::string_view flag_key, + std::string_view default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) = 0; virtual int64_t GetIntegerValue(std::string_view flag_key, int64_t default_value) = 0; virtual int64_t GetIntegerValue(std::string_view flag_key, int64_t default_value, const EvaluationContext& ctx) = 0; + virtual int64_t GetIntegerValue(std::string_view flag_key, + int64_t default_value, + const EvaluationOptions& options) = 0; + virtual int64_t GetIntegerValue(std::string_view flag_key, + int64_t default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) = 0; virtual double GetDoubleValue(std::string_view flag_key, double default_value) = 0; virtual double GetDoubleValue(std::string_view flag_key, double default_value, const EvaluationContext& ctx) = 0; + virtual double GetDoubleValue(std::string_view flag_key, double default_value, + const EvaluationOptions& options) = 0; + virtual double GetDoubleValue(std::string_view flag_key, double default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) = 0; virtual Value GetObjectValue(std::string_view flag_key, Value default_value) = 0; virtual Value GetObjectValue(std::string_view flag_key, Value default_value, const EvaluationContext& ctx) = 0; + virtual Value GetObjectValue(std::string_view flag_key, Value default_value, + const EvaluationOptions& options) = 0; + virtual Value GetObjectValue(std::string_view flag_key, Value default_value, + const EvaluationContext& ctx, + const EvaluationOptions& options) = 0; // TODO: Add detailed evaluation methods }; diff --git a/test/client_api_test.cpp b/test/client_api_test.cpp index d3eb534..8214211 100644 --- a/test/client_api_test.cpp +++ b/test/client_api_test.cpp @@ -13,6 +13,7 @@ #include "absl/status/status.h" #include "mocks/mock_feature_provider.h" #include "openfeature/evaluation_context.h" +#include "openfeature/evaluation_options.h" #include "openfeature/global_context_manager.h" #include "openfeature/hook.h" #include "openfeature/provider_status.h" @@ -21,6 +22,7 @@ using ::openfeature::BoolResolutionDetails; using ::openfeature::ClientAPI; using ::openfeature::ErrorCode; using ::openfeature::EvaluationContext; +using ::openfeature::EvaluationOptions; using ::openfeature::FlagMetadata; using ::openfeature::GlobalContextManager; using ::openfeature::Metadata; @@ -158,6 +160,69 @@ TEST_F(ClientAPITest, GetObjectValueWithContextReturnsDefault) { EXPECT_EQ(client.GetObjectValue(flag_key, Value(1), ctx), Value(1)); } +// Test GetBooleanValue with EvaluationOptions. +TEST_F(ClientAPITest, GetBooleanValueWithOptionsReturnsDefault) { + ClientAPI client(repo_, "test-domain"); + EvaluationOptions options; + std::string flag_key = "my-boolean-flag"; + + EXPECT_TRUE(client.GetBooleanValue(flag_key, true, options)); + EXPECT_FALSE(client.GetBooleanValue(flag_key, false, options)); + + EvaluationContext ctx = EvaluationContext::Builder().build(); + EXPECT_TRUE(client.GetBooleanValue(flag_key, true, ctx, options)); + EXPECT_FALSE(client.GetBooleanValue(flag_key, false, ctx, options)); +} + +// Test GetStringValue with EvaluationOptions. +TEST_F(ClientAPITest, GetStringValueWithOptionsReturnsDefault) { + ClientAPI client(repo_, "test-domain"); + EvaluationOptions options; + std::string flag_key = "my-string-flag"; + + EXPECT_EQ(client.GetStringValue(flag_key, "default", options), "default"); + + EvaluationContext ctx = EvaluationContext::Builder().build(); + EXPECT_EQ(client.GetStringValue(flag_key, "default", ctx, options), + "default"); +} + +// Test GetIntegerValue with EvaluationOptions. +TEST_F(ClientAPITest, GetIntegerValueWithOptionsReturnsDefault) { + ClientAPI client(repo_, "test-domain"); + EvaluationOptions options; + std::string flag_key = "my-integer-flag"; + + EXPECT_EQ(client.GetIntegerValue(flag_key, 42, options), 42); + + EvaluationContext ctx = EvaluationContext::Builder().build(); + EXPECT_EQ(client.GetIntegerValue(flag_key, 42, ctx, options), 42); +} + +// Test GetDoubleValue with EvaluationOptions. +TEST_F(ClientAPITest, GetDoubleValueWithOptionsReturnsDefault) { + ClientAPI client(repo_, "test-domain"); + EvaluationOptions options; + std::string flag_key = "my-double-flag"; + + EXPECT_DOUBLE_EQ(client.GetDoubleValue(flag_key, 3.14, options), 3.14); + + EvaluationContext ctx = EvaluationContext::Builder().build(); + EXPECT_DOUBLE_EQ(client.GetDoubleValue(flag_key, 3.14, ctx, options), 3.14); +} + +// Test GetObjectValue with EvaluationOptions. +TEST_F(ClientAPITest, GetObjectValueWithOptionsReturnsDefault) { + ClientAPI client(repo_, "test-domain"); + EvaluationOptions options; + std::string flag_key = "my-object-flag"; + + EXPECT_EQ(client.GetObjectValue(flag_key, Value(1), options), Value(1)); + + EvaluationContext ctx = EvaluationContext::Builder().build(); + EXPECT_EQ(client.GetObjectValue(flag_key, Value(1), ctx, options), Value(1)); +} + // Test context merging logic indirectly. TEST_F(ClientAPITest, ContextMergingPrecedence) { GlobalContextManager::GetInstance().SetGlobalEvaluationContext(