public void ShouldGiveRandomScienceFact()
        {
            var skill = new ScienceFactsSkill();

            intent.Name = "GiveScienceFact";

            var result = skill.FunctionHandler(basicRequest, null);
            var output = result.Response.OutputSpeech;

            CollectionAssert.Contains(Facts.GetFacts(), (output as PlainTextOutputSpeech).Text);
            Assert.AreEqual(result.Response.ShouldEndSession, true);
        }
Esempio n. 2
0
        /// <summary>
        /// Runs the set of rules against the supplied facts.
        /// The supplied facts can trigger rules which may add more facts and trigger more rules.
        /// </summary>
        /// <param name="suppliedFacts">The facts that are already known.</param>
        /// <returns></returns>
        public Results Run(Facts suppliedFacts)
        {
            if (suppliedFacts == null)
            {
                throw new RulesException("Initial facts must be supplied");
            }

            // A runner performs a single run through the rules. If there are enough
            // facts defined to evaluate all conditions of a rule then that rule is
            // triggered. When a rule is triggered and evaluates to true it adds
            // facts and/or actions.
            //
            // If facts get added during a run-through then further run-throughs are
            // required. If no facts get added, the rules have been fully evaluated.

            // Once a rule has been triggered it cannot be triggered again. If all
            // rules have been triggered then the rules have been fully evaluated.

            // Special case: Final rules are only evaluated if a run-through adds
            // no new facts.

            // Setup initial states
            var rules   = _rules;
            var facts   = suppliedFacts.GetFacts();
            var actions = new Dictionary <string, RuleAction>();

            // Keep evaluating the rules until no more run-throughs are required.
            bool finalRun = false;

            while (true)
            {
                var results = Runner.EvaluateRules(facts, rules, finalRun);

                // Facts cannot be modified so ignore any identical facts but throw
                // an error if the value has changed.
                foreach (var fact in results.Facts)
                {
                    try
                    {
                        facts.Add(fact.Id, fact);
                    }
                    catch (ArgumentException)
                    {
                        var value = facts.GetValueOrDefault(fact.Id).Value;

                        if (!value.CompareValue(Condition.Oper.Equal, fact.Value))
                        {
                            throw new RulesException($"Established fact '{fact.Id} = {value}' cannot be modified to '{fact.Id} = {fact.Value}'");
                        }
                    }
                }

                // Ignore duplicate actions
                foreach (var action in results.Actions)
                {
                    var key = action.Type + " " + action.Id;
                    actions.TryAdd(key, action);
                }

                // If all the rules have been triggered we have finished
                if (results.RemainingRules.Count == 0)
                {
                    break;
                }

                /// Note that 'final' rules should not really add new facts but,
                /// if they do, the order of rules becomes significant and there
                /// will be further runs after this final run!
                if (finalRun && results.Facts.Count == 0)
                {
                    break;
                }

                // If no facts were added we need to perform a final run
                finalRun = (results.Facts.Count == 0);

                // Rules are only triggered once
                rules = results.RemainingRules;
            }

            // Populate results
            var finalFacts = new Facts();

            finalFacts.SetFacts(facts);

            return(new Results()
            {
                Facts = finalFacts,
                Actions = actions.Values.OrderBy(o => o.Type).ThenBy(o => o.Id).ToList()
            });
        }