diff --git a/CHANGELOG.md b/CHANGELOG.md index c9dc8efd..1ca561e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ -## XX.XX.XX +## 24.1.1 +* Fixed a bug where same, null, and empty keys were permitted in the Segmentation. * Fixed an issue where some requests are not url encoded. ## 24.1.0 diff --git a/countlyCommon/TestingRelated/EventTests.cs b/countlyCommon/TestingRelated/EventTests.cs index 06eac5ad..30a00914 100644 --- a/countlyCommon/TestingRelated/EventTests.cs +++ b/countlyCommon/TestingRelated/EventTests.cs @@ -75,6 +75,38 @@ public async void TestEventLimits() Countly.Instance.SessionEnd().Wait(); } + [Fact] + /// + /// It validates that segmentation cannot have same keys + /// + public async void TestEventSameSegmentationKey() + { + CountlyConfig cc = TestHelper.CreateConfig(); + + Countly.Instance.Init(cc).Wait(); + Countly.Instance.SessionBegin().Wait(); + + Countly.Instance.deferUpload = true; + + Segmentation segm = new Segmentation(); + segm.Add("key1", "value1"); + segm.Add("key2", "value2"); + segm.Add("key2", "value3"); + + Assert.Equal("key1", segm.segmentation[0].Key); + Assert.Equal("value1", segm.segmentation[0].Value); + Assert.Equal("key2", segm.segmentation[1].Key); + Assert.Equal("value3", segm.segmentation[1].Value); + + Assert.True(segm.segmentation.Count == 2); // not 3 becasue key 2 overridden and segmentation does not permit same keys + bool res = await Countly.RecordEvent("test_event", 1, 23, 5.0, Segmentation: segm); + Assert.True(res); + + CountlyEvent countlyEvent = Countly.Instance.Events[0]; + validateEventData(countlyEvent, "test_event", 1, 23, 5, segm); + Countly.Instance.SessionEnd().Wait(); + } + /// /// It validates the cancellation of timed events on changing device id without merge. /// diff --git a/countlyCommon/TestingRelated/SegmentationTests.cs b/countlyCommon/TestingRelated/SegmentationTests.cs new file mode 100644 index 00000000..a9aec94e --- /dev/null +++ b/countlyCommon/TestingRelated/SegmentationTests.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using CountlySDK; +using CountlySDK.Entities; +using Xunit; +using static CountlySDK.CountlyCommon.CountlyBase; + +namespace TestProject_common +{ + public class SegmentationTests : IDisposable + { + /// + /// Test setup + /// + public SegmentationTests() + { + CountlyImpl.SetPCLStorageIfNeeded(); + Countly.Halt(); + TestHelper.CleanDataFiles(); + Countly.Instance.deferUpload = true; + } + + /// + /// Test cleanup + /// + public void Dispose() + { + Countly.Instance.HaltInternal().Wait(); + } + + [Fact] + /// + /// It validates the invalid key values + /// All values are accepted + /// Only validated invalid keys + /// + public void InvalidKeyValues() + { + Segmentation segmentation = new Segmentation(); + + segmentation.Add(null, null); + Assert.Empty(segmentation.segmentation); + + segmentation.Add("", null); + Assert.Empty(segmentation.segmentation); + + segmentation.Add(" ", null); + Assert.Equal(" ", segmentation.segmentation[0].Key); + Assert.Null(segmentation.segmentation[0].Value); + } + + [Fact] + /// + /// It validates valid values + /// + public void ValidKeyValues() + { + Segmentation segmentation = new Segmentation(); + + segmentation.Add("1", "2"); + Assert.Equal("1", segmentation.segmentation[0].Key); + Assert.Equal("2", segmentation.segmentation[0].Value); + + segmentation.Add("3", "4"); + Assert.Equal("3", segmentation.segmentation[1].Key); + Assert.Equal("4", segmentation.segmentation[1].Value); + Assert.Equal(2, segmentation.segmentation.Count); + + } + + [Fact] + /// + /// It validates valid values with same keys, + /// this test shows no same keys accepted + /// + public void ValidKeyValues_SameKeys() + { + Segmentation segmentation = new Segmentation(); + + segmentation.Add("1", "2"); + Assert.Equal("1", segmentation.segmentation[0].Key); + Assert.Equal("2", segmentation.segmentation[0].Value); + + segmentation.Add("1", "4"); + Assert.Equal("1", segmentation.segmentation[0].Key); + Assert.Equal("4", segmentation.segmentation[0].Value); + Assert.Single(segmentation.segmentation); + + } + + } +} diff --git a/countlyCommon/countlyCommon/Entities/Segmentation.cs b/countlyCommon/countlyCommon/Entities/Segmentation.cs index cf626a3f..12afe536 100644 --- a/countlyCommon/countlyCommon/Entities/Segmentation.cs +++ b/countlyCommon/countlyCommon/Entities/Segmentation.cs @@ -47,13 +47,25 @@ public Segmentation() } /// - /// Add new segmentation value + /// Add new segmentation value, omits the null keys + /// overrides the same keys /// /// Segmenation key /// Segmenation value public void Add(string Key, string Value) { - segmentation.Add(new SegmentationItem(Key, Value)); + if (string.IsNullOrEmpty(Key)) { + return; + } + // Check if a segmentation item with the same key already exists + SegmentationItem existingItem = segmentation.Find(item => item.Key == Key); + if (existingItem != null) { + // Update the value if the key exists + existingItem.Value = Value; + } else { + // Add a new item if the key doesn't exist + segmentation.Add(new SegmentationItem(Key, Value)); + } } public int CompareTo(Segmentation other) diff --git a/net35/CountlyTest_35/CountlyTest_35.csproj b/net35/CountlyTest_35/CountlyTest_35.csproj index d2c982f9..96291580 100644 --- a/net35/CountlyTest_35/CountlyTest_35.csproj +++ b/net35/CountlyTest_35/CountlyTest_35.csproj @@ -86,6 +86,9 @@ RequestTestCases.cs + + SegmentationTests.cs + SessionTests.cs diff --git a/net45/CountlyTest_45/CountlyTest_45.csproj b/net45/CountlyTest_45/CountlyTest_45.csproj index d366c9ff..86af235b 100644 --- a/net45/CountlyTest_45/CountlyTest_45.csproj +++ b/net45/CountlyTest_45/CountlyTest_45.csproj @@ -85,6 +85,9 @@ RequestTestCases.cs + + SegmentationTests.cs + SessionTests.cs diff --git a/netstd/CountlyTest_461/CountlyTest_461.csproj b/netstd/CountlyTest_461/CountlyTest_461.csproj index 8de5b8fb..7165d95f 100644 --- a/netstd/CountlyTest_461/CountlyTest_461.csproj +++ b/netstd/CountlyTest_461/CountlyTest_461.csproj @@ -96,6 +96,9 @@ RequestTestCases.cs + + SegmentationTests.cs + SessionTests.cs