using System; using System.Collections.Generic; using System.Linq; namespace Ariadne.UnitTests { /// /// Saves an arc as plain objects, for testing arcs without a save library. /// public class ArcRecord : IArcWriter, IArcReader { public readonly Dictionary Fields = new Dictionary(StringComparer.Ordinal); /// /// This field holds the locals written at this level, which leave out those of the calls it holds. /// public readonly Dictionary Locals = new Dictionary(StringComparer.Ordinal); /// /// This field holds what each call written at this level saved, by the name the call was given. /// public readonly Dictionary Scopes = new Dictionary(StringComparer.Ordinal); /// /// This field holds the type each field and local was written as, by key. /// public readonly Dictionary Types = new Dictionary(StringComparer.Ordinal); /// /// This field holds each arc handed to Publish, in order. /// public readonly List Published = new List(); // The record of the whole arc, which is this one unless this holds the locals of a call. private readonly ArcRecord root; public ArcRecord() { root = this; } private ArcRecord(ArcRecord root) { this.root = root; } public List Cursor { get; } = new List(); IReadOnlyList IArcReader.Cursor { get { return root.Cursor; } } public bool Finished { get; set; } bool IArcReader.Finished { get { return root.Finished; } } public IEnumerable LocalKeys { get { return Locals.Keys; } } public IEnumerable ScopeNames { get { return Scopes.Keys; } } /// /// Returns every local written, by the path of calls it was written under and its key, eg: /// Run.first/Step.gate. /// public Dictionary AllLocals() { var returnMe = new Dictionary(StringComparer.Ordinal); var pending = new Stack>(); pending.Push(new KeyValuePair("", this)); while (pending.Count > 0) { KeyValuePair level = pending.Pop(); foreach (KeyValuePair local in level.Value.Locals) { returnMe.Add(level.Key + local.Key, local.Value); } foreach (KeyValuePair scope in level.Value.Scopes) { pending.Push(new KeyValuePair(level.Key + scope.Key, scope.Value)); } } return returnMe; } public static ArcRecord Of(Arc arc) { var returnMe = new ArcRecord(); arc.Save(returnMe); return returnMe; } void IArcWriter.Cursor(IReadOnlyList cursor) { root.Cursor.Clear(); root.Cursor.AddRange(cursor); } void IArcWriter.Finished(bool finished) { root.Finished = finished; } /// The arc already wrote a field with this key. public void Field(string key, T value) { root.Fields.Add(key, value); root.Types.Add(key, typeof(T)); } /// The arc already wrote a local with this key. public void Local(string key, T value) { Locals.Add(key, value); Types.Add(key, typeof(T)); } /// The arc already wrote a call with this name. public IArcWriter Scope(string name) { var returnMe = new ArcRecord(root); Scopes.Add(name, returnMe); return returnMe; } private static bool TryGet(Dictionary values, string key, out T value) { object found; if (!values.TryGetValue(key, out found)) { value = default(T); return false; } value = (T)found; return true; } /// /// This field holds the type arguments written at this level, or null if none were. /// public Type[] SavedTypeArguments; public void TypeArguments(params Type[] types) { SavedTypeArguments = types; } public bool TryTypeArguments(out Type[] types) { types = SavedTypeArguments; return types != null; } public bool TryField(string key, out T value) { return TryGet(root.Fields, key, out value); } public bool HasField(string key) { return root.Fields.ContainsKey(key); } public bool TryLocal(string key, out T value) { return TryGet(Locals, key, out value); } public bool TryScope(string name, out IArcReader scope) { ArcRecord found; bool returnMe = Scopes.TryGetValue(name, out found); scope = found; return returnMe; } public void Publish(object built) { root.Published.Add(built); } } }