From 4d58bbd0b767a224ff8165c6ed4512aed86625b1 Mon Sep 17 00:00:00 2001 From: Adam Simon Date: Fri, 30 Jun 2023 22:00:47 +0200 Subject: [PATCH] Add matrix tests --- .../ConfigEvaluatorTestsBase.cs | 111 +--- .../ConfigV6MatrixTests.cs | 83 +++ .../MatrixTestRunner.cs | 131 +++++ .../data/sample_and_or_v6.json | 270 +++++++++ .../data/sample_comparators_v6.json | 368 +++++++++++++ .../data/sample_flagdependency_v6.json | 520 ++++++++++++++++++ .../data/sample_segments_v6.json | 180 ++++++ .../data/testmatrix_and_or.csv | 15 + .../data/testmatrix_comparators_v6.csv | 16 + .../data/testmatrix_dependent_flag.csv | 5 + .../data/testmatrix_segments.csv | 6 + 11 files changed, 1598 insertions(+), 107 deletions(-) create mode 100644 src/ConfigCat.Client.Tests/ConfigV6MatrixTests.cs create mode 100644 src/ConfigCat.Client.Tests/MatrixTestRunner.cs create mode 100644 src/ConfigCat.Client.Tests/data/sample_and_or_v6.json create mode 100644 src/ConfigCat.Client.Tests/data/sample_comparators_v6.json create mode 100644 src/ConfigCat.Client.Tests/data/sample_flagdependency_v6.json create mode 100644 src/ConfigCat.Client.Tests/data/sample_segments_v6.json create mode 100644 src/ConfigCat.Client.Tests/data/testmatrix_and_or.csv create mode 100644 src/ConfigCat.Client.Tests/data/testmatrix_comparators_v6.csv create mode 100644 src/ConfigCat.Client.Tests/data/testmatrix_dependent_flag.csv create mode 100644 src/ConfigCat.Client.Tests/data/testmatrix_segments.csv diff --git a/src/ConfigCat.Client.Tests/ConfigEvaluatorTestsBase.cs b/src/ConfigCat.Client.Tests/ConfigEvaluatorTestsBase.cs index f767b14a..2009619e 100644 --- a/src/ConfigCat.Client.Tests/ConfigEvaluatorTestsBase.cs +++ b/src/ConfigCat.Client.Tests/ConfigEvaluatorTestsBase.cs @@ -1,118 +1,25 @@ -using System; using System.Collections.Generic; -using System.Globalization; -using System.IO; using ConfigCat.Client.Evaluation; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace ConfigCat.Client.Tests; -public interface IMatrixTestDescriptor -{ - public string SampleJsonFileName { get; } - public string MatrixResultFileName { get; } -} - -public abstract class ConfigEvaluatorTestsBase where TDescriptor : IMatrixTestDescriptor, new() +public abstract class ConfigEvaluatorTestsBase : MatrixTestRunner + where TDescriptor : IMatrixTestDescriptor, new() { #pragma warning disable IDE1006 // Naming Styles private protected readonly LoggerWrapper Logger; #pragma warning restore IDE1006 // Naming Styles - private protected readonly Dictionary config; - internal readonly IRolloutEvaluator configEvaluator; public ConfigEvaluatorTestsBase() { - var descriptor = new TDescriptor(); - this.config = GetSampleJson(descriptor.SampleJsonFileName).Deserialize()!.Settings; - this.Logger = new ConsoleLogger(LogLevel.Debug).AsWrapper(); this.configEvaluator = new RolloutEvaluator(this.Logger); } - protected virtual void AssertValue(string jsonFileName, string keyName, string expected, User? user) - { - var k = keyName.ToLowerInvariant(); - - if (k.StartsWith("bool")) - { - var actual = this.configEvaluator.Evaluate(this.config, keyName, false, user, null, this.Logger).Value; - - Assert.AreEqual(bool.Parse(expected), actual, $"jsonFileName: {jsonFileName} | keyName: {keyName} | userId: {user?.Identifier}"); - } - else if (k.StartsWith("double")) - { - var actual = this.configEvaluator.Evaluate(this.config, keyName, double.NaN, user, null, this.Logger).Value; - - Assert.AreEqual(double.Parse(expected, CultureInfo.InvariantCulture), actual, $"jsonFileName: {jsonFileName} | keyName: {keyName} | userId: {user?.Identifier}"); - } - else if (k.StartsWith("integer")) - { - var actual = this.configEvaluator.Evaluate(this.config, keyName, int.MinValue, user, null, this.Logger).Value; - - Assert.AreEqual(int.Parse(expected), actual, $"jsonFileName: {jsonFileName} | keyName: {keyName} | userId: {user?.Identifier}"); - } - else - { - var actual = this.configEvaluator.Evaluate(this.config, keyName, string.Empty, user, null, this.Logger).Value; - - Assert.AreEqual(expected, actual, $"jsonFileName: {jsonFileName} | keyName: {keyName} | userId: {user?.Identifier}"); - } - } - - protected string GetSampleJson(string fileName) - { - using Stream stream = File.OpenRead(Path.Combine("data", fileName)); - using StreamReader reader = new(stream); - return reader.ReadToEnd(); - } - - public static IEnumerable GetMatrixTests() - { - var descriptor = new TDescriptor(); - - var resultFilePath = Path.Combine("data", descriptor.MatrixResultFileName); - using var reader = new StreamReader(resultFilePath); - var header = reader.ReadLine()!; - - var columns = header.Split(new[] { ';' }); - - while (!reader.EndOfStream) - { - var rawline = reader.ReadLine(); - - if (string.IsNullOrEmpty(rawline)) - { - continue; - } - - var row = rawline.Split(new[] { ';' }); - - string? userId = null, userEmail = null, userCountry = null, userCustomAttributeName = null, userCustomAttributeValue = null; - if (row[0] != "##null##") - { - userId = row[0]; - userEmail = row[1] == "##null##" ? null : row[1]; - userCountry = row[2] == "##null##" ? null : row[2]; - if (row[3] != "##null##") - { - userCustomAttributeName = columns[3]; - userCustomAttributeValue = row[3]; - } - } - - for (var i = 4; i < columns.Length; i++) - { - yield return new[] - { - descriptor.SampleJsonFileName, columns[i], row[i], - userId, userEmail, userCountry, userCustomAttributeName, userCustomAttributeValue - }; - } - } - } + public static IEnumerable GetMatrixTests() => GetTests(); [TestCategory("MatrixTests")] [DataTestMethod] @@ -120,16 +27,6 @@ protected string GetSampleJson(string fileName) public void Run_MatrixTests(string jsonFileName, string settingKey, string expectedReturnValue, string? userId, string? userEmail, string? userCountry, string? userCustomAttributeName, string? userCustomAttributeValue) { - User? user = null; - if (userId is not null) - { - user = new User(userId) { Email = userEmail, Country = userCountry }; - if (userCustomAttributeValue is not null) - { - user.Custom[userCustomAttributeName!] = userCustomAttributeValue; - } - } - - AssertValue(jsonFileName, settingKey, expectedReturnValue, user); + RunTest(this.configEvaluator, this.Logger, settingKey, expectedReturnValue, userId, userEmail, userCountry, userCustomAttributeName, userCustomAttributeValue); } } diff --git a/src/ConfigCat.Client.Tests/ConfigV6MatrixTests.cs b/src/ConfigCat.Client.Tests/ConfigV6MatrixTests.cs new file mode 100644 index 00000000..4324f2e6 --- /dev/null +++ b/src/ConfigCat.Client.Tests/ConfigV6MatrixTests.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using ConfigCat.Client.Evaluation; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ConfigCat.Client.Tests; + +[TestCategory("MatrixTests")] +[TestClass] +public class ConfigV6MatrixTests +{ + public class AndOrTestsDescriptor : IMatrixTestDescriptor + { + public string SampleJsonFileName => "sample_and_or_v6.json"; + public string MatrixResultFileName => "testmatrix_and_or.csv"; + public static IEnumerable GetTests() => MatrixTestRunner.GetTests(); + } + + public class ComparatorTestsDescriptor : IMatrixTestDescriptor + { + public string SampleJsonFileName => "sample_comparators_v6.json"; + public string MatrixResultFileName => "testmatrix_comparators_v6.csv"; + public static IEnumerable GetTests() => MatrixTestRunner.GetTests(); + } + + public class FlagDependencyTestsDescriptor : IMatrixTestDescriptor + { + public string SampleJsonFileName => "sample_flagdependency_v6.json"; + public string MatrixResultFileName => "testmatrix_dependent_flag.csv"; + public static IEnumerable GetTests() => MatrixTestRunner.GetTests(); + } + + public class SegmentTestsDescriptor : IMatrixTestDescriptor + { + public string SampleJsonFileName => "sample_segments_v6.json"; + public string MatrixResultFileName => "testmatrix_segments.csv"; + public static IEnumerable GetTests() => MatrixTestRunner.GetTests(); + } + + private readonly LoggerWrapper logger; + private readonly IRolloutEvaluator configEvaluator; + + public ConfigV6MatrixTests() + { + this.logger = new ConsoleLogger(LogLevel.Debug).AsWrapper(); + this.configEvaluator = new RolloutEvaluator(this.logger); + } + + [DataTestMethod] + [DynamicData(nameof(AndOrTestsDescriptor.GetTests), typeof(AndOrTestsDescriptor), DynamicDataSourceType.Method)] + public void AndOrTests(string jsonFileName, string settingKey, string expectedReturnValue, + string? userId, string? userEmail, string? userCountry, string? userCustomAttributeName, string? userCustomAttributeValue) + { + MatrixTestRunner.Default.RunTest(this.configEvaluator, this.logger, settingKey, expectedReturnValue, + userId, userEmail, userCountry, userCustomAttributeName, userCustomAttributeValue); + } + + [DataTestMethod] + [DynamicData(nameof(ComparatorTestsDescriptor.GetTests), typeof(ComparatorTestsDescriptor), DynamicDataSourceType.Method)] + public void ComparatorTests(string jsonFileName, string settingKey, string expectedReturnValue, + string? userId, string? userEmail, string? userCountry, string? userCustomAttributeName, string? userCustomAttributeValue) + { + MatrixTestRunner.Default.RunTest(this.configEvaluator, this.logger, settingKey, expectedReturnValue, + userId, userEmail, userCountry, userCustomAttributeName, userCustomAttributeValue); + } + + [DataTestMethod] + [DynamicData(nameof(FlagDependencyTestsDescriptor.GetTests), typeof(FlagDependencyTestsDescriptor), DynamicDataSourceType.Method)] + public void FlagDependencyTests(string jsonFileName, string settingKey, string expectedReturnValue, + string? userId, string? userEmail, string? userCountry, string? userCustomAttributeName, string? userCustomAttributeValue) + { + MatrixTestRunner.Default.RunTest(this.configEvaluator, this.logger, settingKey, expectedReturnValue, + userId, userEmail, userCountry, userCustomAttributeName, userCustomAttributeValue); + } + + [DataTestMethod] + [DynamicData(nameof(SegmentTestsDescriptor.GetTests), typeof(SegmentTestsDescriptor), DynamicDataSourceType.Method)] + public void SegmentTests(string jsonFileName, string settingKey, string expectedReturnValue, + string? userId, string? userEmail, string? userCountry, string? userCustomAttributeName, string? userCustomAttributeValue) + { + MatrixTestRunner.Default.RunTest(this.configEvaluator, this.logger, settingKey, expectedReturnValue, + userId, userEmail, userCountry, userCustomAttributeName, userCustomAttributeValue); + } +} diff --git a/src/ConfigCat.Client.Tests/MatrixTestRunner.cs b/src/ConfigCat.Client.Tests/MatrixTestRunner.cs new file mode 100644 index 00000000..06da40db --- /dev/null +++ b/src/ConfigCat.Client.Tests/MatrixTestRunner.cs @@ -0,0 +1,131 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using ConfigCat.Client.Evaluation; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ConfigCat.Client.Tests; + +public interface IMatrixTestDescriptor +{ + public string SampleJsonFileName { get; } + public string MatrixResultFileName { get; } +} + +public class MatrixTestRunner where TDescriptor : IMatrixTestDescriptor, new() +{ + private static readonly Lazy> DefaultLazy = new(() => new MatrixTestRunner(), isThreadSafe: true); + public static MatrixTestRunner Default => DefaultLazy.Value; + + public static readonly TDescriptor DescriptorInstance = new(); + + private protected readonly Dictionary config; + + public MatrixTestRunner() + { + this.config = GetSampleJson(DescriptorInstance.SampleJsonFileName).Deserialize()!.Settings; + } + + public static string GetSampleJson(string fileName) + { + using Stream stream = File.OpenRead(Path.Combine("data", fileName)); + using StreamReader reader = new(stream); + return reader.ReadToEnd(); + } + + public static IEnumerable GetTests() + { + var resultFilePath = Path.Combine("data", DescriptorInstance.MatrixResultFileName); + using var reader = new StreamReader(resultFilePath); + var header = reader.ReadLine()!; + + var columns = header.Split(new[] { ';' }); + + while (!reader.EndOfStream) + { + var rawline = reader.ReadLine(); + + if (string.IsNullOrEmpty(rawline)) + continue; + + var row = rawline.Split(new[] { ';' }); + + string? userId = null, userEmail = null, userCountry = null, userCustomAttributeName = null, userCustomAttributeValue = null; + if (row[0] != "##null##") + { + userId = row[0]; + userEmail = row[1] is "" or "##null##" ? null : row[1]; + userCountry = row[2] is "" or "##null##" ? null : row[2]; + if (row[3] is not ("" or "##null##")) + { + userCustomAttributeName = columns[3]; + userCustomAttributeValue = row[3]; + } + } + + for (var i = 4; i < columns.Length; i++) + { + yield return new[] + { + DescriptorInstance.SampleJsonFileName, columns[i], row[i], + userId, userEmail, userCountry, userCustomAttributeName, userCustomAttributeValue + }; + } + } + } + + protected virtual bool AssertValue(string expected, Func parse, T actual, string keyName, string? userId) + { + Assert.AreEqual(parse(expected), actual, $"jsonFileName: {DescriptorInstance.SampleJsonFileName} | keyName: {keyName} | userId: {userId}"); + return true; + } + + internal bool RunTest(IRolloutEvaluator evaluator, LoggerWrapper logger, string settingKey, string expectedReturnValue, User? user = null) + { + if (settingKey.StartsWith("bool", StringComparison.OrdinalIgnoreCase)) + { + var actual = evaluator.Evaluate(this.config, settingKey, false, user, null, logger).Value; + + return AssertValue(expectedReturnValue, static e => bool.Parse(e), actual, settingKey, user?.Identifier); + } + else if (settingKey.StartsWith("double", StringComparison.OrdinalIgnoreCase)) + { + var actual = evaluator.Evaluate(this.config, settingKey, double.NaN, user, null, logger).Value; + + return AssertValue(expectedReturnValue, static e => double.Parse(e, CultureInfo.InvariantCulture), actual, settingKey, user?.Identifier); + } + else if (settingKey.StartsWith("integer", StringComparison.OrdinalIgnoreCase)) + { + var actual = evaluator.Evaluate(this.config, settingKey, int.MinValue, user, null, logger).Value; + + return AssertValue(expectedReturnValue, static e => int.Parse(e, CultureInfo.InvariantCulture), actual, settingKey, user?.Identifier); + } + else if (settingKey.StartsWith("string", StringComparison.OrdinalIgnoreCase)) + { + var actual = evaluator.Evaluate(this.config, settingKey, string.Empty, user, null, logger).Value; + + return AssertValue(expectedReturnValue, static e => e, actual, settingKey, user?.Identifier); + } + else + { + var actual = evaluator.Evaluate(this.config, settingKey, (object?)null, user, null, logger).Value; + + return AssertValue(expectedReturnValue, static e => e, Convert.ToString(actual, CultureInfo.InvariantCulture), settingKey, user?.Identifier); + } + } + + internal bool RunTest(IRolloutEvaluator evaluator, LoggerWrapper logger, string settingKey, string expectedReturnValue, + string? userId, string? userEmail, string? userCountry, string? userCustomAttributeName, string? userCustomAttributeValue) + { + User? user = null; + if (userId is not null) + { + user = new User(userId) { Email = userEmail, Country = userCountry }; + if (userCustomAttributeValue is not null) + user.Custom[userCustomAttributeName!] = userCustomAttributeValue; + } + + return RunTest(evaluator, logger, settingKey, expectedReturnValue, user); + } +} diff --git a/src/ConfigCat.Client.Tests/data/sample_and_or_v6.json b/src/ConfigCat.Client.Tests/data/sample_and_or_v6.json new file mode 100644 index 00000000..f177292f --- /dev/null +++ b/src/ConfigCat.Client.Tests/data/sample_and_or_v6.json @@ -0,0 +1,270 @@ +{ + "p": { + "u": "https://test-cdn-eu.configcat.com", + "r": 0, + "s": "az3pBWME9aWMPoIfIaANgCOGm9W38ZLOV68W/cznnak=" + }, + "s": [ + { + "n": "Beta", + "r": [ + { + "a": "Email", + "c": 16, + "l": [ + "8ce91ec158f90ee775dd27d325df1808ac5524264d75b71503ec9e8f5a2995e5", + "45086cef4138010300e1ec6cd0c634164928be5b4922dd48c80b9442279efbd0" + ] + } + ] + }, + { + "n": "Deve", + "r": [ + { + "a": "Email", + "c": 16, + "l": [ + "4c87c42ca527c67c915b97ee05710875f4e63b0a9ebe2883afd235ea9326edc0", + "5f7e0f5f0f7187d0a2cb0c028800571967059c15682d89d1ad0582478d517115" + ] + } + ] + } + ], + "f": { + "dependentFeature": { + "t": 1, + "r": [ + { + "c": [ + { + "d": { + "f": "mainFeature", + "c": 0, + "v": { + "s": "target" + } + } + } + ], + "p": [ + { + "p": 25, + "v": { + "s": "Cat" + }, + "i": "993d7ee0" + }, + { + "p": 25, + "v": { + "s": "Dog" + }, + "i": "08b8348e" + }, + { + "p": 25, + "v": { + "s": "Falcon" + }, + "i": "a6fb7a01" + }, + { + "p": 25, + "v": { + "s": "Horse" + }, + "i": "699fb4bf" + } + ] + } + ], + "v": { + "s": "Chicken" + }, + "i": "e6198f92" + }, + "emailAnd": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 22, + "l": [ + "4_82d1be6769aae4915132c810246f0e4e55604abc6d0745c9200a48ccb4932219" + ] + } + }, + { + "t": { + "a": "Email", + "c": 2, + "l": [ + "@" + ] + } + }, + { + "t": { + "a": "Email", + "c": 23, + "l": [ + "20_1d54924b2d446a23bb8655ee23c55f77990f952b189443afea73c77ff9332d89" + ] + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "a1393561" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "bdabd589" + }, + "emailOr": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 22, + "l": [ + "5_4856f7f73845a5078d604543fc803e027fa4167c97dfc21f3f8e36089cc21dca" + ] + } + } + ], + "s": { + "v": { + "s": "Jane" + }, + "i": "01383bbf" + } + }, + { + "c": [ + { + "t": { + "a": "Email", + "c": 22, + "l": [ + "5_ddc6f2a92390569bd3f0d67d894eeaf986fc2c47d4162f2e415d16273d468d85" + ] + } + } + ], + "s": { + "v": { + "s": "John" + }, + "i": "a069dc24" + } + }, + { + "c": [ + { + "t": { + "a": "Email", + "c": 22, + "l": [ + "5_ea327c01fe032017d1d44abda3f5687bf3222d71696718f7f19ef3eb2ed7b0c7" + ] + } + } + ], + "s": { + "v": { + "s": "Mark" + }, + "i": "d7b02cc0" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "ab0b46ad" + }, + "mainFeature": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 23, + "l": [ + "21_ff4f72a95f9c721f6cc70ffac896bb42fd3613e3248f5f09e672bbe52168004c" + ] + } + }, + { + "t": { + "a": "Country", + "c": 16, + "l": [ + "98ab46322c5af478279c6f22be442e193e0f399634e8e27221c1504ff061cc2b", + "fe3cfb77aa05445db8cc314e6dd1a156980756819d88a68e5188fd0ebdd4c1a1" + ] + } + } + ], + "s": { + "v": { + "s": "private" + }, + "i": "64f8e1a6" + } + }, + { + "c": [ + { + "t": { + "a": "Country", + "c": 16, + "l": [ + "391ea48edd104a06f3350666c52e82ee6bff33bce63f153cdbfa3ed5e8621e5e" + ] + } + }, + { + "s": { + "s": 0, + "c": 1 + } + }, + { + "s": { + "s": 1, + "c": 1 + } + } + ], + "s": { + "v": { + "s": "target" + }, + "i": "f570ef26" + } + } + ], + "v": { + "s": "public" + }, + "i": "f16ac582" + } + } +} diff --git a/src/ConfigCat.Client.Tests/data/sample_comparators_v6.json b/src/ConfigCat.Client.Tests/data/sample_comparators_v6.json new file mode 100644 index 00000000..98e6e137 --- /dev/null +++ b/src/ConfigCat.Client.Tests/data/sample_comparators_v6.json @@ -0,0 +1,368 @@ +{ + "p": { + "u": "https://test-cdn-eu.configcat.com", + "r": 0, + "s": "OMMRn/iOWHRK3uyhEIh2vF/h7BmRZEAeCMiX0YTnW04=" + }, + "f": { + "arrayContainsCaseCheckDogDefaultCat": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Custom1", + "c": 24, + "s": "4deba9a545c066fa278baedd9c8e26244678c9055f6d5233b11fb6b5473958e7" + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "5d80eff1" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "ce055a38" + }, + "arrayContainsDogDefaultCat": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Custom1", + "c": 24, + "s": "14c1936a4d2a752529cdaf9cacb8448ace0624a288ddf0cfb4b95c38632d5563" + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "147fdd01" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "5f573f9c" + }, + "arrayDoesNotContainCaseCheckDogDefaultCat": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Custom1", + "c": 25, + "s": "4e1ce609402cc2fcd2b445c060f1bc965cb421a5b5eef633d0e1f5bf0b75e225" + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "d4ad5730" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "df4915fd" + }, + "arrayDoesNotContainDogDefaultCat": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Custom1", + "c": 25, + "s": "3d9512db57ce9ae86c995246f6d175ef67e84569b0efb8e8c89187624aa610d7" + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "c2161ac9" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "41910880" + }, + "boolTrueIn202304": { + "t": 0, + "r": [ + { + "c": [ + { + "t": { + "a": "Custom1", + "c": 19, + "d": 1680307200 + } + }, + { + "t": { + "a": "Custom1", + "c": 18, + "d": 1682899200 + } + } + ], + "s": { + "v": { + "b": true + }, + "i": "6948d7cd" + } + } + ], + "v": { + "b": false + }, + "i": "ae2a09bd" + }, + "countryPercentageAttribute": { + "t": 1, + "p": "Country", + "r": [ + { + "p": [ + { + "p": 50, + "v": { + "s": "Falcon" + }, + "i": "2b05fd81" + }, + { + "p": 50, + "v": { + "s": "Horse" + }, + "i": "e28b6a82" + } + ] + } + ], + "v": { + "s": "Chicken" + }, + "i": "29bb6bbb" + }, + "customPercentageAttribute": { + "t": 1, + "p": "Custom1", + "r": [ + { + "p": [ + { + "p": 50, + "v": { + "s": "Falcon" + }, + "i": "3715712d" + }, + { + "p": 50, + "v": { + "s": "Horse" + }, + "i": "7b3542d5" + } + ] + } + ], + "v": { + "s": "Chicken" + }, + "i": "50466fb6" + }, + "missingPercentageAttribute": { + "t": 1, + "p": "NotFound", + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 23, + "l": [ + "14_65c03652573a0269ea92a552b8fbefbc77a8c802246751d1297727f94d2c274b" + ] + } + } + ], + "p": [ + { + "p": 50, + "v": { + "s": "Falcon" + }, + "i": "4b7d88ba" + }, + { + "p": 50, + "v": { + "s": "Horse" + }, + "i": "a1c2c9a9" + } + ] + }, + { + "c": [ + { + "t": { + "a": "Email", + "c": 23, + "l": [ + "14_65c03652573a0269ea92a552b8fbefbc77a8c802246751d1297727f94d2c274b" + ] + } + } + ], + "s": { + "v": { + "s": "NotFound" + }, + "i": "8aa042fe" + } + } + ], + "v": { + "s": "Chicken" + }, + "i": "e5107172" + }, + "stringDoseNotEqualDogDefaultCat": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 21, + "s": "0457803ad75fa1a5afbee1da1d514d8f33da384e73cada4ad690ac37d849eaf4" + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "8e423808" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "1835a09a" + }, + "stringEndsWithDogDefaultCat": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 23, + "l": [ + "14_3b5bc40493ea5245fb31fe3499f2566181840cbe4b97156474bce37d71795be4" + ] + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "d7a00741" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "45b7d922" + }, + "stringEqualsDogDefaultCat": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 20, + "s": "71ae1b93ac5e880186f38ce6f5e2102e60d1e3e9e670a5fce3704378e9610b73" + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "703c31ed" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "adc0b01c" + }, + "stringStartsWithDogDefaultCat": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 22, + "l": [ + "1_fc6315e1e0fceb01fdd841361415dfe1952a8375c0d57f2dd2239846828b4bf4" + ] + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "3b409872" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "3659b0fe" + } + } +} diff --git a/src/ConfigCat.Client.Tests/data/sample_flagdependency_v6.json b/src/ConfigCat.Client.Tests/data/sample_flagdependency_v6.json new file mode 100644 index 00000000..5c0c12d5 --- /dev/null +++ b/src/ConfigCat.Client.Tests/data/sample_flagdependency_v6.json @@ -0,0 +1,520 @@ +{ + "p": { + "u": "https://test-cdn-eu.configcat.com", + "r": 0, + "s": "aSJB3ZAYcuG\u002BpPutxgM9z/ShekLfhUjQHpKUI4j4sOU=" + }, + "f": { + "boolDependsOnBool": { + "t": 0, + "r": [ + { + "c": [ + { + "d": { + "f": "mainBoolFlag", + "c": 0, + "v": { + "b": true + } + } + } + ], + "s": { + "v": { + "b": true + }, + "i": "8dc94c1d" + } + } + ], + "v": { + "b": false + }, + "i": "d6194760" + }, + "boolDependsOnBoolDependsOnBool": { + "t": 0, + "r": [ + { + "c": [ + { + "d": { + "f": "boolDependsOnBool", + "c": 0, + "v": { + "b": true + } + } + } + ], + "s": { + "v": { + "b": false + }, + "i": "d6870486" + } + } + ], + "v": { + "b": true + }, + "i": "cd4c95e7" + }, + "boolDependsOnBoolInverse": { + "t": 0, + "r": [ + { + "c": [ + { + "d": { + "f": "mainBoolFlagInverse", + "c": 1, + "v": { + "b": true + } + } + } + ], + "s": { + "v": { + "b": true + }, + "i": "3c09bff0" + } + } + ], + "v": { + "b": false + }, + "i": "cecbc501" + }, + "doubleDependsOnBool": { + "t": 3, + "r": [ + { + "c": [ + { + "d": { + "f": "mainBoolFlag", + "c": 0, + "v": { + "b": true + } + } + } + ], + "s": { + "v": { + "d": 1.1 + }, + "i": "271fd003" + } + } + ], + "v": { + "d": 3.14 + }, + "i": "718aae2b" + }, + "intDependsOnBool": { + "t": 2, + "r": [ + { + "c": [ + { + "d": { + "f": "mainBoolFlag", + "c": 0, + "v": { + "b": true + } + } + } + ], + "s": { + "v": { + "i": 1 + }, + "i": "d2dda649" + } + } + ], + "v": { + "i": 42 + }, + "i": "43ec49a8" + }, + "mainBoolFlag": { + "t": 0, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 23, + "l": [ + "21_a6945ecaa58a2b8a1b297768511bb72acc3b77fa86a408812c47172af3db0774" + ] + } + } + ], + "s": { + "v": { + "b": false + }, + "i": "e842ea6f" + } + } + ], + "v": { + "b": true + }, + "i": "8a68b064" + }, + "mainBoolFlagEmpty": { + "t": 0, + "v": { + "b": true + }, + "i": "f3295d43" + }, + "mainBoolFlagInverse": { + "t": 0, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 23, + "l": [ + "21_cda0e9a4455d858822ed0c0fac751ee57c79feab4612433b3afc58505698ea32" + ] + } + } + ], + "s": { + "v": { + "b": true + }, + "i": "28c65f1f" + } + } + ], + "v": { + "b": false + }, + "i": "d70e47a7" + }, + "mainDoubleFlag": { + "t": 3, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 23, + "l": [ + "21_8d951d1b58f70bee3396b29537fa07f8ba6e32513451d3b1c101eb4eacb841be" + ] + } + } + ], + "s": { + "v": { + "d": 0.1 + }, + "i": "a67947ed" + } + } + ], + "v": { + "d": 3.14 + }, + "i": "beb3acc7" + }, + "mainIntFlag": { + "t": 2, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 23, + "l": [ + "21_0e9b9f9406df4f5a7daca1c0b357f4d8c74827914a56ce9d217cb8f2def7fb8c" + ] + } + } + ], + "s": { + "v": { + "i": 2 + }, + "i": "67e14078" + } + } + ], + "v": { + "i": 42 + }, + "i": "a7490aca" + }, + "mainStringFlag": { + "t": 1, + "r": [ + { + "c": [ + { + "t": { + "a": "Email", + "c": 23, + "l": [ + "21_a7af91b860fd02dad64d2c46be08260d45eaf83014585bebf14092bad05a24e3" + ] + } + } + ], + "s": { + "v": { + "s": "private" + }, + "i": "51b57fb0" + } + } + ], + "v": { + "s": "public" + }, + "i": "24c96275" + }, + "stringDependsOnBool": { + "t": 1, + "r": [ + { + "c": [ + { + "d": { + "f": "mainBoolFlag", + "c": 0, + "v": { + "b": true + } + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "fc8daf80" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "d53a2b42" + }, + "stringDependsOnDouble": { + "t": 1, + "r": [ + { + "c": [ + { + "d": { + "f": "mainDoubleFlag", + "c": 0, + "v": { + "d": 0.1 + } + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "84fc7ed9" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "9cc8fd8f" + }, + "stringDependsOnDoubleIntValue": { + "t": 1, + "r": [ + { + "c": [ + { + "d": { + "f": "mainDoubleFlag", + "c": 0, + "v": { + "d": 0 + } + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "842c1d75" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "db7f56c8" + }, + "stringDependsOnEmptyBool": { + "t": 1, + "r": [ + { + "c": [ + { + "d": { + "f": "mainBoolFlagEmpty", + "c": 0, + "v": { + "b": true + } + } + } + ], + "s": { + "v": { + "s": "EmptyOn" + }, + "i": "d5508c78" + } + } + ], + "v": { + "s": "EmptyOff" + }, + "i": "8e0dbe88" + }, + "stringDependsOnInt": { + "t": 1, + "r": [ + { + "c": [ + { + "d": { + "f": "mainIntFlag", + "c": 0, + "v": { + "i": 2 + } + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "12531eec" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "e227d926" + }, + "stringDependsOnString": { + "t": 1, + "r": [ + { + "c": [ + { + "d": { + "f": "mainStringFlag", + "c": 0, + "v": { + "s": "private" + } + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "426b6d4d" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "d36000e1" + }, + "stringDependsOnStringCaseCheck": { + "t": 1, + "r": [ + { + "c": [ + { + "d": { + "f": "mainStringFlag", + "c": 0, + "v": { + "s": "Private" + } + } + } + ], + "s": { + "v": { + "s": "Dog" + }, + "i": "87d24aed" + } + } + ], + "v": { + "s": "Cat" + }, + "i": "ad94f385" + }, + "stringInverseDependsOnEmptyBool": { + "t": 1, + "r": [ + { + "c": [ + { + "d": { + "f": "mainBoolFlagEmpty", + "c": 1, + "v": { + "b": true + } + } + } + ], + "s": { + "v": { + "s": "EmptyOff" + }, + "i": "b7c3efae" + } + } + ], + "v": { + "s": "EmptyOn" + }, + "i": "f6b4b8a2" + } + } +} diff --git a/src/ConfigCat.Client.Tests/data/sample_segments_v6.json b/src/ConfigCat.Client.Tests/data/sample_segments_v6.json new file mode 100644 index 00000000..1293bef6 --- /dev/null +++ b/src/ConfigCat.Client.Tests/data/sample_segments_v6.json @@ -0,0 +1,180 @@ +{ + "p": { + "u": "https://test-cdn-eu.configcat.com", + "r": 0, + "s": "xsZfkjIELRJhElvdQJJWcys0cn836z8DcClMiR1Vd/s=" + }, + "s": [ + { + "n": "Beta", + "r": [ + { + "a": "Email", + "c": 16, + "l": [ + "42be0307afe6d38e8a0ba7f5ab9230104bed054149c50b6903e2514b77c5f8f4", + "82847209de6d4bfa4ba9e0902c9caf7b36ce3b52e54f019686d5dc9b9cc175d9" + ] + } + ] + }, + { + "n": "Deve", + "r": [ + { + "a": "Email", + "c": 16, + "l": [ + "ea05dc0e0eec2f4921c3f87aba58a0bb245887399507bac129f8401443264b96", + "b399eca1657a3ba9ae5fdf20c287ec341ef06db42779cecd238c37ebafd552b4" + ] + } + ] + }, + { + "n": "Not ", + "r": [ + { + "a": "Email", + "c": 17, + "l": [ + "27ea22674ccea76dd6fbdab96f36a20b22897e88f2821f93f0ac75d76df3219d", + "334423d07640c751beb2ac0c2e247d7af6cffcc729d619ec005ae1782bf0551a" + ] + } + ] + }, + { + "n": "Not ", + "r": [ + { + "a": "Email", + "c": 17, + "l": [ + "18fef9b334075fb1e8f61edd22d88fc7ffd0dbf56bba9ab6a82c7d2f183cf6bc", + "334423d07640c751beb2ac0c2e247d7af6cffcc729d619ec005ae1782bf0551a" + ] + } + ] + }, + { + "n": "Unit", + "r": [ + { + "a": "Country", + "c": 2, + "l": [ + "United" + ] + } + ] + }, + { + "n": "Not ", + "r": [ + { + "a": "Country", + "c": 3, + "l": [ + "States" + ] + } + ] + } + ], + "f": { + "countrySegment": { + "t": 1, + "r": [ + { + "c": [ + { + "s": { + "s": 4, + "c": 0 + } + }, + { + "s": { + "s": 5, + "c": 0 + } + } + ], + "s": { + "v": { + "s": "A" + }, + "i": "9b7e6414" + } + } + ], + "v": { + "s": "Z" + }, + "i": "f71b6d96" + }, + "developerAndBetaUserSegment": { + "t": 0, + "r": [ + { + "c": [ + { + "s": { + "s": 1, + "c": 0 + } + }, + { + "s": { + "s": 0, + "c": 1 + } + } + ], + "s": { + "v": { + "b": true + }, + "i": "ddc50638" + } + } + ], + "v": { + "b": false + }, + "i": "6427f4b8" + }, + "notDeveloperAndNotBetaUserSegment": { + "t": 0, + "r": [ + { + "c": [ + { + "s": { + "s": 2, + "c": 0 + } + }, + { + "s": { + "s": 3, + "c": 1 + } + } + ], + "s": { + "v": { + "b": true + }, + "i": "77081d42" + } + } + ], + "v": { + "b": false + }, + "i": "a14eaf13" + } + } +} diff --git a/src/ConfigCat.Client.Tests/data/testmatrix_and_or.csv b/src/ConfigCat.Client.Tests/data/testmatrix_and_or.csv new file mode 100644 index 00000000..5a149f4a --- /dev/null +++ b/src/ConfigCat.Client.Tests/data/testmatrix_and_or.csv @@ -0,0 +1,15 @@ +Identifier;Email;Country;Custom1;mainFeature;dependentFeature;emailAnd;emailOr +##null##;;;;public;Chicken;Cat;Cat +;;;;public;Chicken;Cat;Cat +jane@example.com;jane@example.com;##null##;##null##;public;Chicken;Cat;Jane +john@example.com;john@example.com;##null##;##null##;public;Chicken;Cat;John +a@example.com;a@example.com;USA;##null##;target;Cat;Cat;Cat +mark@example.com;mark@example.com;USA;##null##;target;Dog;Cat;Mark +nora@example.com;nora@example.com;USA;##null##;target;Falcon;Cat;Cat +stern@msn.com;stern@msn.com;USA;##null##;target;Horse;Cat;Cat +jane@sensitivecompany.com;jane@sensitivecompany.com;England;##null##;private;Chicken;Dog;Jane +anna@sensitivecompany.com;anna@sensitivecompany.com;France;##null##;private;Chicken;Cat;Cat +jane@sensitivecompany.com;jane@sensitivecompany.com;england;##null##;public;Chicken;Dog;Jane +jane;jane;##null##;##null##;public;Chicken;Cat;Cat +@sensitivecompany.com;@sensitivecompany.com;##null##;##null##;public;Chicken;Cat;Cat +jane.sensitivecompany.com;jane.sensitivecompany.com;##null##;##null##;public;Chicken;Cat;Cat diff --git a/src/ConfigCat.Client.Tests/data/testmatrix_comparators_v6.csv b/src/ConfigCat.Client.Tests/data/testmatrix_comparators_v6.csv new file mode 100644 index 00000000..4e79d7df --- /dev/null +++ b/src/ConfigCat.Client.Tests/data/testmatrix_comparators_v6.csv @@ -0,0 +1,16 @@ +Identifier;Email;Country;Custom1;boolTrueIn202304;stringEqualsDogDefaultCat;stringDoseNotEqualDogDefaultCat;stringStartsWithDogDefaultCat;stringEndsWithDogDefaultCat;arrayContainsDogDefaultCat;arrayDoesNotContainDogDefaultCat;arrayContainsCaseCheckDogDefaultCat;arrayDoesNotContainCaseCheckDogDefaultCat;customPercentageAttribute;missingPercentageAttribute;countryPercentageAttribute +##null##;;;;False;Cat;Cat;Cat;Cat;Cat;Cat;Cat;Cat;Chicken;Chicken;Chicken +;;;;False;Cat;Cat;Cat;Cat;Cat;Cat;Cat;Cat;Chicken;Chicken;Chicken +a@configcat.com;a@configcat.com;##null##;##null##;False;Dog;Dog;Dog;Dog;Cat;Cat;Cat;Cat;Chicken;NotFound;Chicken +b@configcat.com;b@configcat.com;Hungary;0;False;Cat;Cat;Cat;Dog;Cat;Dog;Cat;Dog;Horse;NotFound;Falcon +c@configcat.com;c@configcat.com;United Kingdom;1680307199.9;False;Cat;Dog;Cat;Dog;Cat;Dog;Cat;Dog;Falcon;NotFound;Falcon +anna@configcat.com;anna@configcat.com;Hungary;1681118000.56;True;Cat;Dog;Dog;Dog;Cat;Dog;Cat;Dog;Falcon;NotFound;Falcon +bogjobber@verizon.net;bogjobber@verizon.net;##null##;1682899200.1;False;Cat;Dog;Cat;Cat;Cat;Dog;Cat;Dog;Horse;Chicken;Chicken +cliffordj@aol.com;cliffordj@aol.com;Austria;1682999200;False;Cat;Dog;Cat;Cat;Cat;Dog;Cat;Dog;Falcon;Chicken;Falcon +reader@configcat.com;reader@configcat.com;Bahamas;read,execute;False;Cat;Dog;Cat;Dog;Dog;Dog;Cat;Dog;Falcon;NotFound;Falcon +writer@configcat.com;writer@configcat.com;Belgium;write, execute;False;Cat;Dog;Cat;Dog;Cat;Cat;Cat;Dog;Horse;NotFound;Horse +reader@configcat.com;reader@configcat.com;Canada;execute, Read;False;Cat;Dog;Cat;Dog;Cat;Dog;Dog;Dog;Horse;NotFound;Horse +writer@configcat.com;writer@configcat.com;China;Write;False;Cat;Dog;Cat;Dog;Cat;Dog;Cat;Cat;Falcon;NotFound;Horse +admin@configcat.com;admin@configcat.com;France;read, write,execute;False;Cat;Dog;Dog;Dog;Dog;Cat;Cat;Dog;Falcon;NotFound;Horse +user@configcat.com;user@configcat.com;Greece;,execute;False;Cat;Dog;Cat;Dog;Cat;Dog;Cat;Dog;Falcon;NotFound;Horse +user@configcat.com;user@configcat.com;Monaco;,null, ,,nil, None;False;Cat;Dog;Cat;Dog;Cat;Dog;Cat;Dog;Falcon;NotFound;Horse diff --git a/src/ConfigCat.Client.Tests/data/testmatrix_dependent_flag.csv b/src/ConfigCat.Client.Tests/data/testmatrix_dependent_flag.csv new file mode 100644 index 00000000..dcf68f4d --- /dev/null +++ b/src/ConfigCat.Client.Tests/data/testmatrix_dependent_flag.csv @@ -0,0 +1,5 @@ +Identifier;Email;Country;Custom1;mainBoolFlag;mainStringFlag;mainIntFlag;mainDoubleFlag;stringDependsOnBool;stringDependsOnString;stringDependsOnStringCaseCheck;stringDependsOnInt;stringDependsOnDouble;stringDependsOnDoubleIntValue;boolDependsOnBool;intDependsOnBool;doubleDependsOnBool;boolDependsOnBoolDependsOnBool;mainBoolFlagEmpty;stringDependsOnEmptyBool;stringInverseDependsOnEmptyBool;mainBoolFlagInverse;boolDependsOnBoolInverse +##null##;;;;True;public;42;3.14;Dog;Cat;Cat;Cat;Cat;Cat;True;1;1.1;False;True;EmptyOn;EmptyOn;False;True +;;;;True;public;42;3.14;Dog;Cat;Cat;Cat;Cat;Cat;True;1;1.1;False;True;EmptyOn;EmptyOn;False;True +john@sensitivecompany.com;john@sensitivecompany.com;##null##;##null##;False;private;2;0.1;Cat;Dog;Cat;Dog;Dog;Cat;False;42;3.14;True;True;EmptyOn;EmptyOn;True;False +jane@example.com;jane@example.com;##null##;##null##;True;public;42;3.14;Dog;Cat;Cat;Cat;Cat;Cat;True;1;1.1;False;True;EmptyOn;EmptyOn;False;True diff --git a/src/ConfigCat.Client.Tests/data/testmatrix_segments.csv b/src/ConfigCat.Client.Tests/data/testmatrix_segments.csv new file mode 100644 index 00000000..47de1ab6 --- /dev/null +++ b/src/ConfigCat.Client.Tests/data/testmatrix_segments.csv @@ -0,0 +1,6 @@ +Identifier;Email;Country;Custom1;developerAndBetaUserSegment +##null##;;;;False +;;;;False +john@example.com;john@example.com;##null##;##null##;False +jane@example.com;jane@example.com;##null##;##null##;False +kate@example.com;kate@example.com;##null##;##null##;True