diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b9bcca..8c186e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 3.1.1 - 16/01/2024 + +- Return the correct flag value from value() method when null is given as default value or when the value for flag is null + # 3.1.0 - 08/11/2023 - Troubleshooting mode : If you are experiencing issues while using the SDK, we are now able to gather logs and information to help you. diff --git a/example/lib/widgets/Modifications.dart b/example/lib/widgets/Modifications.dart index 154d611..c060899 100644 --- a/example/lib/widgets/Modifications.dart +++ b/example/lib/widgets/Modifications.dart @@ -57,10 +57,7 @@ class _ModificationsState extends State { myFlag = currentVisitor?.getFlag(keyFlagController.text, defaultValue); - var ret = myFlag?.value(visitorExposed: false); - - // var ret = - // currentVisitor?.getModification(keyFlagController.text, defaultValue); + var ret = myFlag?.value(); setState(() { valueForFlag = ret.toString(); diff --git a/lib/flagship_version.dart b/lib/flagship_version.dart index 227304e..b04712c 100644 --- a/lib/flagship_version.dart +++ b/lib/flagship_version.dart @@ -1,2 +1,2 @@ /// This file is automatically updated -const FlagshipVersion = "3.1.0"; +const FlagshipVersion = "3.1.1"; diff --git a/lib/model/flag.dart b/lib/model/flag.dart index 4994613..fce75c1 100644 --- a/lib/model/flag.dart +++ b/lib/model/flag.dart @@ -17,20 +17,34 @@ class Flag implements IFlag { // Get value for flag // // visitorExposed is true by default - T value({bool visitorExposed = true}) { + dynamic value({bool visitorExposed = true}) { + dynamic retValue = _defaultValue; Modification? modif = this._visitorDelegate.getFlagModification(this._key); if (modif != null) { - if (_isSameType(modif.value)) { - // Activate if necessary - if (visitorExposed) { - this.visitorExposed(); + try { + { + if (modif.value == null) { + // Activate if necessary + if (visitorExposed) { + this.visitorExposed(); + } + } else if (_isSameTypeOrDefaultValueNull(modif.value)) { + /// Get the flag value + retValue = modif.value; + // Activate if necessary + if (visitorExposed) { + this.visitorExposed(); + } + } else { + DataUsageTracking.sharedInstance().proceesTroubleShootingFlag( + CriticalPoints.GET_FLAG_VALUE_TYPE_WARNING.name, + this, + this._visitorDelegate.visitor); + } } - return modif.value as T; - } else { - DataUsageTracking.sharedInstance().proceesTroubleShootingFlag( - CriticalPoints.GET_FLAG_VALUE_TYPE_WARNING.name, - this, - this._visitorDelegate.visitor); + } catch (exp) { + Flagship.logger(Level.INFO, + "an exception raised $exp , will return a default value "); } } else { DataUsageTracking.sharedInstance().proceesTroubleShootingFlag( @@ -38,7 +52,7 @@ class Flag implements IFlag { this, this._visitorDelegate.visitor); } - return _defaultValue; + return retValue; } // Expose Flag @@ -53,7 +67,8 @@ class Flag implements IFlag { Modification? modification = this._visitorDelegate.getFlagModification(this._key); if (modification != null) { - if (modification.value == null || _isSameType(modification.value)) { + if (modification.value == null || + _isSameTypeOrDefaultValueNull(modification.value)) { Flagship.logger( Level.DEBUG, "Send exposure flag (activate) for : " + _key); @@ -81,7 +96,8 @@ class Flag implements IFlag { FlagMetadata metadata() { // Before expose whe should check the Type Modification? modif = this._visitorDelegate.getFlagModification(this._key); - if (modif != null && (modif.value == null || _isSameType(modif.value))) { + if (modif != null && + (modif.value == null || _isSameTypeOrDefaultValueNull(modif.value))) { // when the flag value is null we provide the metadata return FlagMetadata.withMap( this._visitorDelegate.getModificationInfo(this._key)); @@ -90,8 +106,12 @@ class Flag implements IFlag { } } - // Check the type of flag's value with the default value - bool _isSameType(dynamic value) { + // Check the type of flag's value with the default value and return true if the same + // If the default value is null will return true + bool _isSameTypeOrDefaultValueNull(dynamic value) { + if (this._defaultValue.runtimeType == Null) { + return true; + } return (value is T); } diff --git a/pubspec.yaml b/pubspec.yaml index 71356e1..b405450 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flagship description: Flutter SDK for Flagship Feature management & Experiment platform for modern engineering and product teams -version: 3.1.0 +version: 3.1.1 homepage: https://flagship.io environment: diff --git a/test/flag_test.dart b/test/flag_test.dart index 14b22eb..9f54a0f 100644 --- a/test/flag_test.dart +++ b/test/flag_test.dart @@ -212,6 +212,10 @@ void main() async { v2.fetchFlags().whenComplete(() { Flag myFlag = v2.getFlag("key_A", 3.14); expect(myFlag.value(), 3.14); + + Flag myFlagBis = v2.getFlag("key_A", false); + expect(myFlagBis.value(), false); + expect(myFlag.exists(), true); FlagMetadata metadata = myFlag.metadata(); expect(metadata.campaignId, ""); @@ -224,12 +228,23 @@ void main() async { }); test("Flag with null as value", () { - // PathProviderPlatform.instance = FakePathProviderPlatform(); var v3 = Flagship.newVisitor("flagVisitor").build(); v3.fetchFlags().whenComplete(() { + // String as default value Flag myFlag = v3.getFlag("keyNull", "nullValue"); expect(myFlag.value(), "nullValue"); + // bool as default value + Flag myFlagBool = v3.getFlag("keyNull", false); + expect(myFlagBool.value(), false); + // Double as default value + Flag myFlagDouble = v3.getFlag("keyNull", 12.0); + expect(myFlagDouble.value(), 12.0); + // Int as default value + Flag myFlagInt = v3.getFlag("keyNull", 2); + expect(myFlagInt.value(), 2); + // is existing expect(myFlag.exists(), true); + // Get metadata FlagMetadata metadata = myFlag.metadata(); expect(metadata.campaignId, "bsffhle242b2l3igq4dg"); expect(metadata.variationGroupId, "bsffhle242b2l3igq4egaa"); @@ -257,6 +272,23 @@ void main() async { }); }); + test("Flag with default value = null", () { + //PathProviderPlatform.instance = FakePathProviderPlatform(); + var v4 = Flagship.newVisitor("flagVisitor").build(); + v4.fetchFlags().whenComplete(() { + Flag myFlag = v4.getFlag("key_A", null); + expect(myFlag.value(), "val_A"); + expect(myFlag.exists(), true); + FlagMetadata metadata = myFlag.metadata(); + expect(metadata.campaignId, "bsffhle242b2l3igq4dg"); + expect(metadata.variationGroupId, "bsffhle242b2l3igq4egaa"); + expect(metadata.variationId, "bsffhle242b2l3igq4f0"); + expect(metadata.isReference, true); + expect(metadata.slug, "flutter"); + expect(metadata.campaignType, "ab"); + }); + }); + test("Failed Activate Flag", () { when(fakeService.sendHttpRequest(RequestType.Post, 'https://decision.flagship.io/v2/activate', any, any,