static object WalkObjectTree(List<ChainStep> chain, ref string path, Result result, IList<INamedPredicate> predicates) { var remainingChain = chain; while (remainingChain.Count > 1) { var step = remainingChain.First(); remainingChain = remainingChain.Skip(1).ToList(); var pathHere = path + "." + step.Name; object next; try { next = result.Target.Get(step.Name); } catch (FastFailureException) { result.FailBecause(pathHere + " is not a valid path"); return null; } if (next == null) { result.FailBecause(pathHere + " is null or not accessible"); return null; } if (next is IEnumerable) { string stepMsg; var container = FilterWithNamedPredicate((IEnumerable)next, step, out stepMsg); pathHere += stepMsg; switch (step.ListAssertionType) { case ListAssertion.Single: case ListAssertion.Simple: if ( ! StepSingle(result, pathHere, container, out next)) return null; break; case ListAssertion.Index: if ( ! StepIndex(result, step, container, out next, ref pathHere)) return null; break; case ListAssertion.All: CheckAllSubpaths(result, predicates, pathHere, remainingChain, container); return null; case ListAssertion.Any: CheckAnySubpaths(result, predicates, remainingChain, pathHere, container); return null; default: throw new Exception("Unexpected list assertion type"); } } result.Target = next; path = pathHere; } return ApplyPredicatesToEndOfChain(ref path, result, predicates, remainingChain); }
static bool StepSingle(Result result, string pathHere, object[] container, out object resultTarget) { resultTarget = null; if (container.Length > 1) { result.FailBecause(pathHere + " has length of " + container.Length + ", expected 1"); return false; } if (container.Length < 1) { result.FailBecause(pathHere + " has no items"); return false; } resultTarget = container[0]; return true; }
static void ApplyPredicatesToSimpleTerminal(string path, Result result, IEnumerable<INamedPredicate> predicates) { foreach (var predicate in predicates) { string message; if (!predicate.Matches(result.Target, out message)) result.FailBecause(path + " " + message); } }
static bool StepIndex(Result result, ChainStep step, object[] container, out object next, ref string pathHere) { next = null; if (step.SingleIndex < 0 || step.SingleIndex >= container.Length) { result.FailBecause(pathHere + " has length of " + container.Length + ", tried to access index " + step.SingleIndex); return false; } pathHere += "[" + step.SingleIndex + "]"; next = container[step.SingleIndex]; return true; }
static object ApplyPredicatesToEndOfChain(ref string path, Result result, IList<INamedPredicate> predicates, List<ChainStep> remainingChain) { ChainStep step; if (remainingChain.Count == 1) { step = remainingChain[0]; try { result.Target = result.Target.Get(step.Name); path += "." + step.Name; } catch (FastFailureException) { result.FailBecause(path + "." + step.Name + " is not a valid path"); return null; } } else { step = ChainStep.SimpleStep("?"); } if (result.Target is IEnumerable) { ApplyPredicatesToTerminalEnumerable(path, result, predicates, step); } else { ApplyPredicatesToSimpleTerminal(path, result, predicates); } return result.Target; }