diff --git a/src/OpenFeature/Model/FlagEvaluationDetails.cs b/src/OpenFeature/Model/FlagEvaluationDetails.cs index 9af2f4bf..28c83e55 100644 --- a/src/OpenFeature/Model/FlagEvaluationDetails.cs +++ b/src/OpenFeature/Model/FlagEvaluationDetails.cs @@ -2,74 +2,74 @@ namespace OpenFeature.Model { - /// - /// The contract returned to the caller that describes the result of the flag evaluation process. - /// - /// Flag value type - /// - public sealed class FlagEvaluationDetails - { /// - /// Feature flag evaluated value + /// The contract returned to the caller that describes the result of the flag evaluation process. /// - public T Value { get; } + /// Flag value type + /// + public sealed class FlagEvaluationDetails + { + /// + /// Feature flag evaluated value + /// + public T Value { get; } - /// - /// Feature flag key - /// - public string FlagKey { get; } + /// + /// Feature flag key + /// + public string FlagKey { get; } - /// - /// Error that occurred during evaluation - /// - public ErrorType ErrorType { get; } + /// + /// Error that occurred during evaluation + /// + public ErrorType ErrorType { get; } - /// - /// Message containing additional details about an error. - /// - /// Will be if there is no error or if the provider didn't provide any additional error - /// details. - /// - /// - public string? ErrorMessage { get; } + /// + /// Message containing additional details about an error. + /// + /// Will be if there is no error or if the provider didn't provide any additional error + /// details. + /// + /// + public string? ErrorMessage { get; } - /// - /// Describes the reason for the outcome of the evaluation process - /// - public string? Reason { get; } + /// + /// Describes the reason for the outcome of the evaluation process + /// + public string? Reason { get; } - /// - /// A variant is a semantic identifier for a value. This allows for referral to particular values without - /// necessarily including the value itself, which may be quite prohibitively large or otherwise unsuitable - /// in some cases. - /// - public string? Variant { get; } + /// + /// A variant is a semantic identifier for a value. This allows for referral to particular values without + /// necessarily including the value itself, which may be quite prohibitively large or otherwise unsuitable + /// in some cases. + /// + public string? Variant { get; } - /// - /// A structure which supports definition of arbitrary properties, with keys of type string, and values of type boolean, string, or number. - /// - public FlagMetadata? FlagMetadata { get; } + /// + /// A structure which supports definition of arbitrary properties, with keys of type string, and values of type boolean, string, or number. + /// + public ImmutableMetadata? FlagMetadata { get; } - /// - /// Initializes a new instance of the class. - /// - /// Feature flag key - /// Evaluated value - /// Error - /// Reason - /// Variant - /// Error message - /// Flag metadata - public FlagEvaluationDetails(string flagKey, T value, ErrorType errorType, string? reason, string? variant, - string? errorMessage = null, FlagMetadata? flagMetadata = null) - { - this.Value = value; - this.FlagKey = flagKey; - this.ErrorType = errorType; - this.Reason = reason; - this.Variant = variant; - this.ErrorMessage = errorMessage; - this.FlagMetadata = flagMetadata; + /// + /// Initializes a new instance of the class. + /// + /// Feature flag key + /// Evaluated value + /// Error + /// Reason + /// Variant + /// Error message + /// Flag metadata + public FlagEvaluationDetails(string flagKey, T value, ErrorType errorType, string? reason, string? variant, + string? errorMessage = null, ImmutableMetadata? flagMetadata = null) + { + this.Value = value; + this.FlagKey = flagKey; + this.ErrorType = errorType; + this.Reason = reason; + this.Variant = variant; + this.ErrorMessage = errorMessage; + this.FlagMetadata = flagMetadata; + } } - } } diff --git a/src/OpenFeature/Model/FlagMetadata.cs b/src/OpenFeature/Model/FlagMetadata.cs deleted file mode 100644 index 0fddbdd3..00000000 --- a/src/OpenFeature/Model/FlagMetadata.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections.Generic; - -namespace OpenFeature.Model; - -/// -/// Represents the metadata associated with a feature flag. -/// -/// -public sealed class FlagMetadata : BaseMetadata -{ - /// - /// Constructor for the class. - /// - public FlagMetadata() : this([]) - { - } - - /// - /// Constructor for the class. - /// - /// The dictionary containing the metadata. - public FlagMetadata(Dictionary metadata) : base(metadata) - { - } -} diff --git a/src/OpenFeature/Model/BaseMetadata.cs b/src/OpenFeature/Model/ImmutableMetadata.cs similarity index 67% rename from src/OpenFeature/Model/BaseMetadata.cs rename to src/OpenFeature/Model/ImmutableMetadata.cs index 876247df..40d452d0 100644 --- a/src/OpenFeature/Model/BaseMetadata.cs +++ b/src/OpenFeature/Model/ImmutableMetadata.cs @@ -1,16 +1,31 @@ using System.Collections.Generic; using System.Collections.Immutable; +#nullable enable namespace OpenFeature.Model; /// -/// Represents the base class for metadata objects. +/// Represents immutable metadata associated with feature flags and events. /// -public abstract class BaseMetadata +/// +/// +public sealed class ImmutableMetadata { private readonly ImmutableDictionary _metadata; - internal BaseMetadata(Dictionary metadata) + /// + /// Constructor for the class. + /// + public ImmutableMetadata() + { + this._metadata = ImmutableDictionary.Empty; + } + + /// + /// Constructor for the class. + /// + /// The dictionary containing the metadata. + public ImmutableMetadata(Dictionary metadata) { this._metadata = metadata.ToImmutableDictionary(); } @@ -20,7 +35,7 @@ internal BaseMetadata(Dictionary metadata) /// /// The key of the value to retrieve. /// The boolean value associated with the key, or null if the key is not found. - public virtual bool? GetBool(string key) + public bool? GetBool(string key) { return this.GetValue(key); } @@ -30,7 +45,7 @@ internal BaseMetadata(Dictionary metadata) /// /// The key of the value to retrieve. /// The integer value associated with the key, or null if the key is not found. - public virtual int? GetInt(string key) + public int? GetInt(string key) { return this.GetValue(key); } @@ -40,7 +55,7 @@ internal BaseMetadata(Dictionary metadata) /// /// The key of the value to retrieve. /// The double value associated with the key, or null if the key is not found. - public virtual double? GetDouble(string key) + public double? GetDouble(string key) { return this.GetValue(key); } @@ -50,7 +65,7 @@ internal BaseMetadata(Dictionary metadata) /// /// The key of the value to retrieve. /// The string value associated with the key, or null if the key is not found. - public virtual string? GetString(string key) + public string? GetString(string key) { var hasValue = this._metadata.TryGetValue(key, out var value); if (!hasValue) diff --git a/src/OpenFeature/Model/ProviderEvents.cs b/src/OpenFeature/Model/ProviderEvents.cs index 6feccfb0..fa22f7cd 100644 --- a/src/OpenFeature/Model/ProviderEvents.cs +++ b/src/OpenFeature/Model/ProviderEvents.cs @@ -3,40 +3,39 @@ namespace OpenFeature.Model { - /// - /// The EventHandlerDelegate is an implementation of an Event Handler - /// - public delegate void EventHandlerDelegate(ProviderEventPayload? eventDetails); - - /// - /// Contains the payload of an OpenFeature Event. - /// - public class ProviderEventPayload - { /// - /// Name of the provider. + /// The EventHandlerDelegate is an implementation of an Event Handler /// - public string? ProviderName { get; set; } + public delegate void EventHandlerDelegate(ProviderEventPayload? eventDetails); /// - /// Type of the event + /// Contains the payload of an OpenFeature Event. /// - public ProviderEventTypes Type { get; set; } + public class ProviderEventPayload + { + /// + /// Name of the provider. + /// + public string? ProviderName { get; set; } - /// - /// A message providing more information about the event. - /// - public string? Message { get; set; } + /// + /// Type of the event + /// + public ProviderEventTypes Type { get; set; } - /// - /// A List of flags that have been changed. - /// - public List? FlagsChanged { get; set; } + /// + /// A message providing more information about the event. + /// + public string? Message { get; set; } - /// - /// Metadata information for the event. - /// - // TODO: This needs to be changed to a EventMetadata object - public Dictionary? EventMetadata { get; set; } - } + /// + /// A List of flags that have been changed. + /// + public List? FlagsChanged { get; set; } + + /// + /// Metadata information for the event. + /// + public ImmutableMetadata? EventMetadata { get; set; } + } } diff --git a/src/OpenFeature/Model/ResolutionDetails.cs b/src/OpenFeature/Model/ResolutionDetails.cs index 5f686d47..4dda0e21 100644 --- a/src/OpenFeature/Model/ResolutionDetails.cs +++ b/src/OpenFeature/Model/ResolutionDetails.cs @@ -2,73 +2,73 @@ namespace OpenFeature.Model { - /// - /// Defines the contract that the is required to return - /// Describes the details of the feature flag being evaluated - /// - /// Flag value type - /// - public sealed class ResolutionDetails - { /// - /// Feature flag evaluated value + /// Defines the contract that the is required to return + /// Describes the details of the feature flag being evaluated /// - public T Value { get; } + /// Flag value type + /// + public sealed class ResolutionDetails + { + /// + /// Feature flag evaluated value + /// + public T Value { get; } - /// - /// Feature flag key - /// - public string FlagKey { get; } + /// + /// Feature flag key + /// + public string FlagKey { get; } - /// - /// Error that occurred during evaluation - /// - /// - public ErrorType ErrorType { get; } + /// + /// Error that occurred during evaluation + /// + /// + public ErrorType ErrorType { get; } - /// - /// Message containing additional details about an error. - /// - public string? ErrorMessage { get; } + /// + /// Message containing additional details about an error. + /// + public string? ErrorMessage { get; } - /// - /// Describes the reason for the outcome of the evaluation process - /// - /// - public string? Reason { get; } + /// + /// Describes the reason for the outcome of the evaluation process + /// + /// + public string? Reason { get; } - /// - /// A variant is a semantic identifier for a value. This allows for referral to particular values without - /// necessarily including the value itself, which may be quite prohibitively large or otherwise unsuitable - /// in some cases. - /// - public string? Variant { get; } + /// + /// A variant is a semantic identifier for a value. This allows for referral to particular values without + /// necessarily including the value itself, which may be quite prohibitively large or otherwise unsuitable + /// in some cases. + /// + public string? Variant { get; } - /// - /// A structure which supports definition of arbitrary properties, with keys of type string, and values of type boolean, string, or number. - /// - public FlagMetadata? FlagMetadata { get; } + /// + /// A structure which supports definition of arbitrary properties, with keys of type string, and values of type boolean, string, or number. + /// + public ImmutableMetadata? FlagMetadata { get; } - /// - /// Initializes a new instance of the class. - /// - /// Feature flag key - /// Evaluated value - /// Error - /// Reason - /// Variant - /// Error message - /// Flag metadata - public ResolutionDetails(string flagKey, T value, ErrorType errorType = ErrorType.None, string? reason = null, - string? variant = null, string? errorMessage = null, FlagMetadata? flagMetadata = null) - { - this.Value = value; - this.FlagKey = flagKey; - this.ErrorType = errorType; - this.Reason = reason; - this.Variant = variant; - this.ErrorMessage = errorMessage; - this.FlagMetadata = flagMetadata; + /// + /// Initializes a new instance of the class. + /// + /// Feature flag key + /// Evaluated value + /// Error + /// Reason + /// Variant + /// Error message + /// Flag metadata + public ResolutionDetails(string flagKey, T value, ErrorType errorType = ErrorType.None, string? reason = null, + string? variant = null, string? errorMessage = null, ImmutableMetadata? flagMetadata = null) + { + this.Value = value; + this.FlagKey = flagKey; + this.ErrorType = errorType; + this.Reason = reason; + this.Variant = variant; + this.ErrorMessage = errorMessage; + this.FlagMetadata = flagMetadata; + } } - } } diff --git a/test/OpenFeature.Tests/FlagMetadataTest.cs b/test/OpenFeature.Tests/ImmutableMetadataTest.cs similarity index 91% rename from test/OpenFeature.Tests/FlagMetadataTest.cs rename to test/OpenFeature.Tests/ImmutableMetadataTest.cs index d716d91e..344392b0 100644 --- a/test/OpenFeature.Tests/FlagMetadataTest.cs +++ b/test/OpenFeature.Tests/ImmutableMetadataTest.cs @@ -5,7 +5,7 @@ namespace OpenFeature.Tests; -public class FlagMetadataTest +public class ImmutableMetadataTest { [Fact] [Specification("1.4.14", @@ -13,7 +13,7 @@ public class FlagMetadataTest public void GetBool_Should_Return_Null_If_Key_Not_Found() { // Arrange - var flagMetadata = new FlagMetadata(); + var flagMetadata = new ImmutableMetadata(); // Act var result = flagMetadata.GetBool("nonexistentKey"); @@ -35,7 +35,7 @@ public void GetBool_Should_Return_Value_If_Key_Found() "boolKey", true } }; - var flagMetadata = new FlagMetadata(metadata); + var flagMetadata = new ImmutableMetadata(metadata); // Act var result = flagMetadata.GetBool("boolKey"); @@ -56,7 +56,7 @@ public void GetBool_Should_Throw_Value_Is_Invalid() "wrongKey", "11a" } }; - var flagMetadata = new FlagMetadata(metadata); + var flagMetadata = new ImmutableMetadata(metadata); // Act var result = flagMetadata.GetBool("wrongKey"); @@ -71,7 +71,7 @@ public void GetBool_Should_Throw_Value_Is_Invalid() public void GetInt_Should_Return_Null_If_Key_Not_Found() { // Arrange - var flagMetadata = new FlagMetadata(); + var flagMetadata = new ImmutableMetadata(); // Act var result = flagMetadata.GetInt("nonexistentKey"); @@ -93,7 +93,7 @@ public void GetInt_Should_Return_Value_If_Key_Found() "intKey", 1 } }; - var flagMetadata = new FlagMetadata(metadata); + var flagMetadata = new ImmutableMetadata(metadata); // Act var result = flagMetadata.GetInt("intKey"); @@ -115,7 +115,7 @@ public void GetInt_Should_Throw_Value_Is_Invalid() "wrongKey", "11a" } }; - var flagMetadata = new FlagMetadata(metadata); + var flagMetadata = new ImmutableMetadata(metadata); // Act var result = flagMetadata.GetInt("wrongKey"); @@ -130,7 +130,7 @@ public void GetInt_Should_Throw_Value_Is_Invalid() public void GetDouble_Should_Return_Null_If_Key_Not_Found() { // Arrange - var flagMetadata = new FlagMetadata(); + var flagMetadata = new ImmutableMetadata(); // Act var result = flagMetadata.GetDouble("nonexistentKey"); @@ -152,7 +152,7 @@ public void GetDouble_Should_Return_Value_If_Key_Found() "doubleKey", 1.2 } }; - var flagMetadata = new FlagMetadata(metadata); + var flagMetadata = new ImmutableMetadata(metadata); // Act var result = flagMetadata.GetDouble("doubleKey"); @@ -174,7 +174,7 @@ public void GetDouble_Should_Throw_Value_Is_Invalid() "wrongKey", "11a" } }; - var flagMetadata = new FlagMetadata(metadata); + var flagMetadata = new ImmutableMetadata(metadata); // Act var result = flagMetadata.GetDouble("wrongKey"); @@ -189,7 +189,7 @@ public void GetDouble_Should_Throw_Value_Is_Invalid() public void GetString_Should_Return_Null_If_Key_Not_Found() { // Arrange - var flagMetadata = new FlagMetadata(); + var flagMetadata = new ImmutableMetadata(); // Act var result = flagMetadata.GetString("nonexistentKey"); @@ -211,7 +211,7 @@ public void GetString_Should_Return_Value_If_Key_Found() "stringKey", "11" } }; - var flagMetadata = new FlagMetadata(metadata); + var flagMetadata = new ImmutableMetadata(metadata); // Act var result = flagMetadata.GetString("stringKey"); @@ -233,7 +233,7 @@ public void GetString_Should_Throw_Value_Is_Invalid() "wrongKey", new object() } }; - var flagMetadata = new FlagMetadata(metadata); + var flagMetadata = new ImmutableMetadata(metadata); // Act var result = flagMetadata.GetString("wrongKey"); diff --git a/test/OpenFeature.Tests/OpenFeatureEventTests.cs b/test/OpenFeature.Tests/OpenFeatureEventTests.cs index 599cea30..3a373c98 100644 --- a/test/OpenFeature.Tests/OpenFeatureEventTests.cs +++ b/test/OpenFeature.Tests/OpenFeatureEventTests.cs @@ -25,12 +25,7 @@ public async Task Event_Executor_Should_Propagate_Events_ToGlobal_Handler() eventExecutor.AddApiLevelHandler(ProviderEventTypes.ProviderConfigurationChanged, eventHandler); - var eventMetadata = new Dictionary - { - { - "foo", "bar" - } - }; + var eventMetadata = new ImmutableMetadata(new Dictionary { { "foo", "bar" } }); var myEvent = new Event { EventPayload = new ProviderEventPayload