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); }
/// <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() }); }