Exemple #1
0
        public void FlagReturnsOffVariationAndEventIfPrerequisiteIsOff()
        {
            var f0 = new FeatureFlagBuilder("feature0")
                     .On(true)
                     .Prerequisites(new Prerequisite("feature1", 1))
                     .OffVariation(1)
                     .FallthroughVariation(0)
                     .Variations(fallthroughValue, offValue, onValue)
                     .Version(1)
                     .Build();
            var f1 = new FeatureFlagBuilder("feature1")
                     .On(false)
                     .OffVariation(1)
                     // note that even though it returns the desired variation, it is still off and therefore not a match
                     .Variations(LdValue.Of("nogo"), LdValue.Of("go"))
                     .Version(2)
                     .Build();
            var evaluator = BasicEvaluator.WithStoredFlags(f1);

            var result = evaluator.Evaluate(f0, baseUser, EventFactory.Default);

            var expected = new EvaluationDetail <LdValue>(offValue, 1,
                                                          EvaluationReason.PrerequisiteFailedReason("feature1"));

            Assert.Equal(expected, result.Result);

            Assert.Equal(1, result.PrerequisiteEvents.Count);
            EvaluationEvent e = result.PrerequisiteEvents[0];

            Assert.Equal(f1.Key, e.FlagKey);
            Assert.Equal(LdValue.Of("go"), e.Value);
            Assert.Equal(f1.Version, e.FlagVersion);
            Assert.Equal(f0.Key, e.PrerequisiteOf);
        }
        private static void AssertVariationIndexFromRollout(
            int expectedVariation,
            Rollout rollout,
            User user,
            string flagKey,
            string salt
            )
        {
            var flag1 = new FeatureFlagBuilder(flagKey)
                        .On(true)
                        .GeneratedVariations(3)
                        .FallthroughRollout(rollout)
                        .Salt(salt)
                        .Build();
            var result1 = BasicEvaluator.Evaluate(flag1, user, EventFactory.Default);

            Assert.Equal(EvaluationReason.FallthroughReason, result1.Result.Reason);
            Assert.Equal(expectedVariation, result1.Result.VariationIndex);

            // Make sure we consistently apply the rollout regardless of whether it's in a rule or a fallthrough
            var flag2 = new FeatureFlagBuilder(flagKey)
                        .On(true)
                        .GeneratedVariations(3)
                        .Rules(new RuleBuilder().Id("id")
                               .Rollout(rollout)
                               .Clauses(new ClauseBuilder().Attribute(UserAttribute.Key).Op(Operator.In).Values(LdValue.Of(user.Key)).Build())
                               .Build())
                        .Salt(salt)
                        .Build();
            var result2 = BasicEvaluator.Evaluate(flag2, user, EventFactory.Default);

            Assert.Equal(EvaluationReason.RuleMatchReason(0, "id"), result2.Result.Reason);
            Assert.Equal(expectedVariation, result2.Result.VariationIndex);
        }
Exemple #3
0
        public void FlagReturnsFallthroughVariationAndEventIfPrerequisiteIsMetAndThereAreNoRules()
        {
            var f0 = new FeatureFlagBuilder("feature0")
                     .On(true)
                     .Prerequisites(new Prerequisite("feature1", 1))
                     .OffVariation(1)
                     .FallthroughVariation(0)
                     .Variations(fallthroughValue, offValue, onValue)
                     .Version(1)
                     .Build();
            var f1 = new FeatureFlagBuilder("feature1")
                     .On(true)
                     .FallthroughVariation(1) // this is what makes the prerequisite pass
                     .Variations(LdValue.Of("nogo"), LdValue.Of("go"))
                     .Version(2)
                     .Build();
            var evaluator = BasicEvaluator.WithStoredFlags(f1);

            var result = evaluator.Evaluate(f0, baseUser, EventFactory.Default);

            var expected = new EvaluationDetail <LdValue>(fallthroughValue, 0, EvaluationReason.FallthroughReason);

            Assert.Equal(expected, result.Result);

            Assert.Equal(1, result.PrerequisiteEvents.Count);
            EvaluationEvent e = result.PrerequisiteEvents[0];

            Assert.Equal(f1.Key, e.FlagKey);
            Assert.Equal(LdValue.Of("go"), e.Value);
            Assert.Equal(f1.Version, e.FlagVersion);
            Assert.Equal(f0.Key, e.PrerequisiteOf);
        }
        public void BigSegmentStateIsQueriedOnlyOncePerUserEvenIfFlagReferencesMultipleSegments()
        {
            var segment1    = new SegmentBuilder("segmentkey1").Unbounded(true).Generation(2).Build();
            var segment2    = new SegmentBuilder("segmentkey2").Unbounded(true).Generation(3).Build();
            var bigSegments = new MockBigSegmentProvider();
            var membership  = MockMembership.New().Include(segment2);

            bigSegments.Membership[baseUser.Key] = membership;
            var flag = new FeatureFlagBuilder("key").On(true)
                       .Variations(LdValue.Of(false), LdValue.Of(true))
                       .FallthroughVariation(0)
                       .Rules(
                new RuleBuilder().Variation(1).Clauses(ClauseBuilder.ShouldMatchSegment(segment1.Key)).Build(),
                new RuleBuilder().Variation(1).Clauses(ClauseBuilder.ShouldMatchSegment(segment2.Key)).Build()
                )
                       .Build();
            var evaluator = BasicEvaluator.WithStoredSegments(segment1, segment2).WithBigSegments(bigSegments);

            var result = evaluator.Evaluate(flag, baseUser, EventFactory.Default);

            Assert.Equal(LdValue.Of(true), result.Result.Value);
            Assert.Equal(BigSegmentsStatus.Healthy, result.Result.Reason.BigSegmentsStatus);

            Assert.Equal(1, bigSegments.MembershipQueryCount);
            Assert.Equal(new List <string> {
                MakeBigSegmentRef(segment1), MakeBigSegmentRef(segment2)
            },
                         membership.Queries);
        }
        static void Main(string[] args)
        {
            Console.WriteLine("******");
            Console.WriteLine("Please put expression consisting of non-negative integers and the [+ - / *] operators only, then press enter:");
            Console.WriteLine("******");

            Console.WriteLine();
            Console.Write("Expression: ");
            string expression = Console.ReadLine();

            try
            {
                BasicEvaluator basicEvaluator = new BasicEvaluator();
                decimal        result         = basicEvaluator.Evaluate(expression);

                Console.WriteLine();
                Console.WriteLine($"Result: {result}");
                Console.WriteLine();
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.DarkRed;
                Console.WriteLine($"Error: {ex.Message}");
                Console.ResetColor();
            }

            Console.WriteLine();
            Console.Write("Press any key...");
            Console.ReadKey();
        }
Exemple #6
0
        public void ClauseWithUnknownOperatorDoesNotMatch()
        {
            var clause = new ClauseBuilder().Attribute("name").Op("invalidOp").Values(LdValue.Of("Bob")).Build();
            var f      = new FeatureFlagBuilder("key").BooleanWithClauses(clause).Build();
            var user   = User.Builder("key").Name("Bob").Build();

            Assert.Equal(LdValue.Of(false), BasicEvaluator.Evaluate(f, user, EventFactory.Default).Result.Value);
        }
Exemple #7
0
        public void SegmentMatchClauseFallsThroughIfSegmentNotFound()
        {
            var f         = new FeatureFlagBuilder("key").BooleanMatchingSegment("segkey").Build();
            var user      = User.WithKey("foo");
            var evaluator = BasicEvaluator.WithNonexistentSegment("segkey");

            Assert.Equal(LdValue.Of(false), evaluator.Evaluate(f, user, EventFactory.Default).Result.Value);
        }
Exemple #8
0
        public void ClauseReturnsFalseForMissingAttribute()
        {
            var clause = new ClauseBuilder().Attribute("legs").Op("in").Values(LdValue.Of(4)).Build();
            var f      = new FeatureFlagBuilder("key").BooleanWithClauses(clause).Build();
            var user   = User.Builder("key").Name("bob").Build();

            Assert.Equal(LdValue.Of(false), BasicEvaluator.Evaluate(f, user, EventFactory.Default).Result.Value);
        }
        private bool SegmentMatchesUser(Segment segment, User user)
        {
            var flag      = new FeatureFlagBuilder("key").BooleanMatchingSegment(segment.Key).Build();
            var evaluator = BasicEvaluator.WithStoredSegments(segment);
            var result    = evaluator.Evaluate(flag, user, EventFactory.Default);

            return(result.Result.Value.AsBool);
        }
Exemple #10
0
        public void ClauseCanMatchCustomAttribute()
        {
            var clause = new ClauseBuilder().Attribute("legs").Op("in").Values(LdValue.Of(4)).Build();
            var f      = new FeatureFlagBuilder("key").BooleanWithClauses(clause).Build();
            var user   = User.Builder("key").Custom("legs", 4).Build();

            Assert.Equal(LdValue.Of(true), BasicEvaluator.Evaluate(f, user, EventFactory.Default).Result.Value);
        }
Exemple #11
0
        public void ClauseCanBeNegated()
        {
            var clause = new ClauseBuilder().Attribute("name").Op("in").Values(LdValue.Of("Bob"))
                         .Negate(true).Build();
            var f    = new FeatureFlagBuilder("key").BooleanWithClauses(clause).Build();
            var user = User.Builder("key").Name("Bob").Build();

            Assert.Equal(LdValue.Of(false), BasicEvaluator.Evaluate(f, user, EventFactory.Default).Result.Value);
        }
Exemple #12
0
        public void SegmentMatchClauseRetrievesSegmentFromStore()
        {
            var segment   = new SegmentBuilder("segkey").Version(1).Included("foo").Build();
            var evaluator = BasicEvaluator.WithStoredSegments(segment);

            var f    = new FeatureFlagBuilder("key").BooleanMatchingSegment("segkey").Build();
            var user = User.WithKey("foo");

            Assert.Equal(LdValue.Of(true), evaluator.Evaluate(f, user, EventFactory.Default).Result.Value);
        }
Exemple #13
0
        public static T Evaluate <T>(RPNExpression expression)
        {
            try
            {
                var context = new RPNContext(expression);
                while (context.CanMove)
                {
                    context.MoveNext();

                    if (DefaultEvaluator.Evaluate(context))
                    {
                        continue;
                    }
                    if (BasicEvaluator.Evaluate(context))
                    {
                        continue;
                    }
                    if (MathEvaluator.Evaluate(context))
                    {
                        continue;
                    }
                    if (LogicEvaluator.Evaluate(context))
                    {
                        continue;
                    }
                    if (StringEvaluator.Evaluate(context))
                    {
                        continue;
                    }
                    if (RegexEvaluator.Evaluate(context))
                    {
                        continue;
                    }
                    if (DateTimeEvaluator.Evaluate(context))
                    {
                        continue;
                    }
                    if (ControlEvaluator.Evaluate <T>(context))
                    {
                        continue;
                    }

                    context.Stack.Push(context.Current);
                }
                return(context.GetResult <T>());
            }
            catch (RPNException)
            {
                throw;
            }
            catch
            {
                throw new ParsingException(expression.Expression);
            }
        }
Exemple #14
0
        public void throws_error_when_dividing_by_zero(string expression)
        {
            // Arrange
            BasicEvaluator stringEvaluator = new BasicEvaluator();

            // Act
            void evaluateDelegate() => stringEvaluator.Evaluate(expression);

            // Assert
            Exception ex = Assert.Throws <DivideByZeroException>(() => evaluateDelegate());
        }
Exemple #15
0
        public void standarize_string_expression(string expression, string standarizedExpression)
        {
            // Arrange
            BasicEvaluator stringEvaluator = new BasicEvaluator();

            // Act
            stringEvaluator.ValidateAndStandarize(ref expression);

            // Assert
            Assert.AreEqual(expression, standarizedExpression);
        }
Exemple #16
0
        public void get_result_from_string_expression(string expression, decimal expectedResult)
        {
            // Arrange
            BasicEvaluator stringEvaluator = new BasicEvaluator();

            // Act
            decimal result = stringEvaluator.Evaluate(expression);

            // Assert
            Assert.That(expectedResult, Is.EqualTo(result).Within(0.00000001));
        }
        public void FlagReturnsInExperimentForRuleMatchWhenInExperimentVariationButNonExperimentRollout()
        {
            var user    = User.WithKey("userkey");
            var rollout = BuildRollout(RolloutKind.Rollout, false);
            var rule    = new RuleBuilder().Id("id").Rollout(rollout).Clauses(ClauseBuilder.ShouldMatchUser(user)).Build();
            var f       = FeatureFlagWithRules(rule);
            var result  = BasicEvaluator.Evaluate(f, baseUser, EventFactory.Default);

            Assert.Equal(EvaluationReasonKind.RuleMatch, result.Result.Reason.Kind);
            Assert.False(result.Result.Reason.InExperiment);
        }
Exemple #18
0
        public void throws_error_when_number_is_too_big(string expression)
        {
            // Arrange
            BasicEvaluator stringEvaluator = new BasicEvaluator();

            // Act
            void evaluateDelegate() => stringEvaluator.Evaluate(expression);

            // Assert
            Exception ex = Assert.Throws <OverflowException>(() => evaluateDelegate());
        }
Exemple #19
0
        public void get_list_of_factors(string expression, string[] exprectedListOfFactors)
        {
            // Arrange
            BasicEvaluator stringEvaluator = new BasicEvaluator();

            // Act
            ICollection <string> expressionFactors = stringEvaluator.GetSplitExpression(expression);

            // Assert
            Assert.AreEqual(exprectedListOfFactors.Length, expressionFactors.Count);
            Assert.AreEqual(exprectedListOfFactors.ToList(), expressionFactors.ToList());
        }
        public void BigSegmentWithNoProviderIsNotMatched()
        {
            var segment = new SegmentBuilder("segmentkey").Unbounded(true).Generation(1)
                          .Included(baseUser.Key) // Included should be ignored for a Big Segment
                          .Build();
            var flag      = new FeatureFlagBuilder("key").BooleanMatchingSegment(segment.Key).Build();
            var evaluator = BasicEvaluator.WithStoredSegments(segment);

            var result = evaluator.Evaluate(flag, baseUser, EventFactory.Default);

            Assert.Equal(LdValue.Of(false), result.Result.Value);
            Assert.Equal(BigSegmentsStatus.NotConfigured, result.Result.Reason.BigSegmentsStatus);
        }
Exemple #21
0
        public void throws_error_if_string_expression_is_not_valid(string expression)
        {
            // Arrange
            BasicEvaluator stringEvaluator = new BasicEvaluator();

            // Act
            void evaluateDelegate() => stringEvaluator.Evaluate(expression);

            // Assert
            Exception ex = Assert.Throws <ArgumentException>(() => evaluateDelegate());

            Assert.That(ex.Message, Is.EqualTo("Expression is not valid"));
        }
Exemple #22
0
        public void FlagReturnsInExperimentForFallthroughWhenInExperimentVariationButNonExperimentRollout()
        {
            var rollout = BuildRollout(RolloutKind.Rollout, false);
            var f       = new FeatureFlagBuilder("feature")
                          .On(true)
                          .FallthroughRollout(rollout)
                          .Variations(fallthroughValue, offValue, onValue)
                          .Build();
            var result = BasicEvaluator.Evaluate(f, baseUser, EventFactory.Default);

            Assert.Equal(EvaluationReasonKind.Fallthrough, result.Result.Reason.Kind);
            Assert.False(result.Result.Reason.InExperiment);
        }
Exemple #23
0
        public void throws_error_if_string_expression_is_empty()
        {
            // Arrange
            BasicEvaluator stringEvaluator = new BasicEvaluator();

            // Act
            void evaluateDelegate() => stringEvaluator.Evaluate(string.Empty);

            // Assert
            Exception ex = Assert.Throws <ArgumentException>(() => evaluateDelegate());

            Assert.That(ex.Message, Is.EqualTo("Expression cannot be null or empty"));
        }
Exemple #24
0
        public void FlagReturnsNullIfFlagIsOffAndOffVariationIsUnspecified()
        {
            var f = new FeatureFlagBuilder("feature")
                    .On(false)
                    .FallthroughVariation(0)
                    .Variations(fallthroughValue, offValue, onValue)
                    .Build();
            var result = BasicEvaluator.Evaluate(f, baseUser, EventFactory.Default);

            var expected = new EvaluationDetail <LdValue>(LdValue.Null, null, EvaluationReason.OffReason);

            Assert.Equal(expected, result.Result);
            Assert.Equal(0, result.PrerequisiteEvents.Count);
        }
        public void MatchedWithInclude()
        {
            var segment     = new SegmentBuilder("segmentkey").Unbounded(true).Generation(2).Build();
            var bigSegments = new MockBigSegmentProvider();

            bigSegments.Membership[baseUser.Key] = MockMembership.New().Include(segment);
            var flag      = new FeatureFlagBuilder("key").BooleanMatchingSegment(segment.Key).Build();
            var evaluator = BasicEvaluator.WithStoredSegments(segment).WithBigSegments(bigSegments);

            var result = evaluator.Evaluate(flag, baseUser, EventFactory.Default);

            Assert.Equal(LdValue.Of(true), result.Result.Value);
            Assert.Equal(BigSegmentsStatus.Healthy, result.Result.Reason.BigSegmentsStatus);
        }
Exemple #26
0
        public void FlagReturnsFallthroughIfFlagIsOnAndThereAreNoRules()
        {
            var f = new FeatureFlagBuilder("feature")
                    .On(true)
                    .OffVariation(1)
                    .FallthroughVariation(0)
                    .Variations(fallthroughValue, offValue, onValue)
                    .Build();
            var result = BasicEvaluator.Evaluate(f, baseUser, EventFactory.Default);

            var expected = new EvaluationDetail <LdValue>(fallthroughValue, 0, EvaluationReason.FallthroughReason);

            Assert.Equal(expected, result.Result);
            Assert.Equal(0, result.PrerequisiteEvents.Count);
        }
        public void RuleWithNoVariationOrRolloutReturnsMalformedFlagError()
        {
            var user   = User.WithKey("userkey");
            var clause = ClauseBuilder.ShouldMatchUser(user);
            var rule   = new RuleBuilder().Id("ruleid").Clauses(clause).Build();
            var f      = FeatureFlagWithRules(rule);

            var result = BasicEvaluator.Evaluate(f, user, EventFactory.Default);

            var expected = new EvaluationDetail <LdValue>(LdValue.Null, null,
                                                          EvaluationReason.ErrorReason(EvaluationErrorKind.MalformedFlag));

            Assert.Equal(expected, result.Result);
            Assert.Equal(0, result.PrerequisiteEvents.Count);
        }
Exemple #28
0
        public void FlagReturnsErrorIfFallthroughHasEmptyRolloutVariationList()
        {
            var f = new FeatureFlagBuilder("feature")
                    .On(true)
                    .OffVariation(1)
                    .FallthroughRollout(new Rollout(RolloutKind.Rollout, null, new List <WeightedVariation>(), null))
                    .Variations(fallthroughValue, offValue, onValue)
                    .Build();
            var result = BasicEvaluator.Evaluate(f, baseUser, EventFactory.Default);

            var expected = new EvaluationDetail <LdValue>(LdValue.Null, null,
                                                          EvaluationReason.ErrorReason(EvaluationErrorKind.MalformedFlag));

            Assert.Equal(expected, result.Result);
            Assert.Equal(0, result.PrerequisiteEvents.Count);
        }
Exemple #29
0
        public void MultipleLevelsOfPrerequisitesProduceMultipleEvents()
        {
            var f0 = new FeatureFlagBuilder("feature0")
                     .On(true)
                     .Prerequisites(new Prerequisite("feature1", 1))
                     .OffVariation(1)
                     .FallthroughVariation(0)
                     .Variations(fallthroughValue, offValue, onValue)
                     .Version(1)
                     .Build();
            var f1 = new FeatureFlagBuilder("feature1")
                     .On(true)
                     .Prerequisites(new Prerequisite("feature2", 1))
                     .FallthroughVariation(1)
                     .Variations(LdValue.Of("nogo"), LdValue.Of("go"))
                     .Version(2)
                     .Build();
            var f2 = new FeatureFlagBuilder("feature2")
                     .On(true)
                     .FallthroughVariation(1)
                     .Variations(LdValue.Of("nogo"), LdValue.Of("go"))
                     .Version(3)
                     .Build();
            var evaluator = BasicEvaluator.WithStoredFlags(f1, f2);

            var result = evaluator.Evaluate(f0, baseUser, EventFactory.Default);

            var expected = new EvaluationDetail <LdValue>(fallthroughValue, 0, EvaluationReason.FallthroughReason);

            Assert.Equal(expected, result.Result);

            Assert.Equal(2, result.PrerequisiteEvents.Count);

            EvaluationEvent e0 = result.PrerequisiteEvents[0];

            Assert.Equal(f2.Key, e0.FlagKey);
            Assert.Equal(LdValue.Of("go"), e0.Value);
            Assert.Equal(f2.Version, e0.FlagVersion);
            Assert.Equal(f1.Key, e0.PrerequisiteOf);

            EvaluationEvent e1 = result.PrerequisiteEvents[1];

            Assert.Equal(f1.Key, e1.FlagKey);
            Assert.Equal(LdValue.Of("go"), e1.Value);
            Assert.Equal(f1.Version, e1.FlagVersion);
            Assert.Equal(f0.Key, e1.PrerequisiteOf);
        }
Exemple #30
0
        public void FlagReturnsOffVariationIfPrerequisiteIsNotFound()
        {
            var f0 = new FeatureFlagBuilder("feature0")
                     .On(true)
                     .Prerequisites(new Prerequisite("feature1", 1))
                     .OffVariation(1)
                     .FallthroughVariation(0)
                     .Variations(fallthroughValue, offValue, onValue)
                     .Build();
            var evaluator = BasicEvaluator.WithNonexistentFlag("feature1");
            var result    = evaluator.Evaluate(f0, baseUser, EventFactory.Default);

            var expected = new EvaluationDetail <LdValue>(offValue, 1,
                                                          EvaluationReason.PrerequisiteFailedReason("feature1"));

            Assert.Equal(expected, result.Result);
            Assert.Equal(0, result.PrerequisiteEvents.Count);
        }