void IUserInputInterface.RequestUserInput(object dataObject, TimeSpan Timeout, bool modal) { if (readerThread == null) { lock (readerLock) { if (readerThread == null) { readerThread = TapThread.Start(() => { while (true) { lines.Add(Console.ReadLine()); } }, "Console Reader"); } } } DateTime TimeoutTime; if (Timeout == TimeSpan.MaxValue) { TimeoutTime = DateTime.MaxValue; } else { TimeoutTime = DateTime.Now + Timeout; } if (Timeout >= new TimeSpan(0, 0, 0, 0, int.MaxValue)) { Timeout = new TimeSpan(0, 0, 0, 0, -1); } do { if (platforDialogMutex.WaitOne(Timeout)) { break; } if (DateTime.Now >= TimeoutTime) { throw new TimeoutException("Request User Input timed out"); } } while (true); try { Log.Flush(); var a = AnnotationCollection.Annotate(dataObject); var mems = a.Get <IMembersAnnotation>()?.Members; if (mems == null) { return; } mems = mems.Concat(a.Get <IForwardedAnnotations>()?.Forwarded ?? Array.Empty <AnnotationCollection>()); var title = TypeData.GetTypeData(dataObject)?.GetMember("Name")?.GetValue(dataObject) as string; if (string.IsNullOrWhiteSpace(title) == false) { Console.WriteLine(title); } bool isBrowsable(IMemberData m) { var browsable = m.GetAttribute <System.ComponentModel.BrowsableAttribute>(); // Browsable overrides everything if (browsable != null) { return(browsable.Browsable); } if (m is IMemberData mem) { if (m.HasAttribute <OutputAttribute>()) { return(true); } if (!mem.Writable || !mem.Readable) { return(false); } return(true); } return(false); } foreach (var _message in mems) { var mem = _message.Get <IMemberAnnotation>()?.Member; if (mem != null) { if (!isBrowsable(mem)) { continue; } } log.Flush(); var str = _message.Get <IStringValueAnnotation>(); if (str == null) { continue; } var name = _message.Get <DisplayAttribute>()?.Name; start: var isVisible = _message.Get <IAccessAnnotation>()?.IsVisible ?? true; if (!isVisible) { continue; } var isReadOnly = _message.Get <IAccessAnnotation>()?.IsReadOnly ?? false; if (isReadOnly) { Console.WriteLine($"{str.Value}"); continue; } var proxy = _message.Get <IAvailableValuesAnnotationProxy>(); List <string> options = null; bool pleaseEnter = true; if (proxy != null) { pleaseEnter = false; options = new List <string>(); int index = 0; var current_value = proxy.SelectedValue; foreach (var value in proxy.AvailableValues) { var v = value.Get <IStringValueAnnotation>(); if (v != null) { Console.Write("{1}: '{0}'", v.Value, index); if (value == current_value) { Console.WriteLine(" (default)"); } else { Console.WriteLine(); } } options.Add(v?.Value); index++; } Console.Write("Please enter a number or name "); } var layout = _message.Get <IMemberAnnotation>()?.Member.GetAttribute <LayoutAttribute>(); bool showName = layout?.Mode.HasFlag(LayoutMode.FullRow) == true ? false : true; if (pleaseEnter) { Console.Write("Please enter "); } if (showName) { Console.Write($"{name} ({str.Value}): "); } else { Console.Write($"({str.Value}): "); } var read = (awaitReadLine(TimeoutTime) ?? "").Trim(); if (read == "") { // accept the default value. continue; } try { if (options != null && int.TryParse(read, out int result)) { if (result < options.Count) { read = options[result]; } else { goto start; } } str.Value = read; var err = a.Get <IErrorAnnotation>(); IEnumerable <string> errors = err?.Errors; _message.Write(); if (errors?.Any() == true) { Console.WriteLine("Unable to parse value {0}", read); goto start; } } catch (Exception) { Console.WriteLine("Unable to parse '{0}'", read); goto start; } } a.Write(); } finally { platforDialogMutex.ReleaseMutex(); } }
/// <summary> /// Calls the PromptForDutMetadata delegate for all referenced DUTs. /// </summary> internal void StartResourcePromptAsync(TestPlanRun planRun, IEnumerable <IResource> _resources) { var resources = _resources.Where(x => x != null).ToArray(); List <Type> componentSettingsWithMetaData = new List <Type>(); var componentSettings = PluginManager.GetPlugins <ComponentSettings>(); bool AnyMetaData = false; planRun.PromptWaitHandle.Reset(); try { foreach (var setting in componentSettings) { foreach (var member in setting.GetMembers()) { var attr = member.GetAttribute <MetaDataAttribute>(); if (attr != null && attr.PromptUser) { AnyMetaData = true; componentSettingsWithMetaData.Add(setting); } } } foreach (var resource in resources) { var type = TypeData.GetTypeData(resource); foreach (var __prop in type.GetMembers()) { IMemberData prop = __prop; var attr = prop.GetAttribute <MetaDataAttribute>(); if (attr != null && attr.PromptUser) { AnyMetaData = true; } } } } catch { // this is just a defensive catch to make sure that the waithandle is not left unset (and we risk waiting for it indefinitely) planRun.PromptWaitHandle.Set(); throw; } if (AnyMetaData && EngineSettings.Current.PromptForMetaData) { TapThread.Start(() => { try { List <object> objects = new List <object>(); objects.AddRange(componentSettingsWithMetaData.Select(ComponentSettings.GetCurrent)); objects.AddRange(resources); planRun.PromptedResources = resources; var obj = new MetadataPromptObject { Resources = objects }; UserInput.Request(obj, false); if (obj.Response == MetadataPromptObject.PromptResponse.Abort) { planRun.MainThread.Abort(); } } catch (Exception e) { Log.Debug(e); planRun.MainThread.Abort("Error occured while executing platform requests. Metadata prompt can be disabled from the Engine settings menu."); } finally { planRun.PromptWaitHandle.Set(); } }, name: "Request Metadata"); } else { planRun.PromptWaitHandle.Set(); } }
/// <summary> Get all known types that derive from a given type.</summary> /// <typeparam name="BaseType">Base type that all returned types descends to.</typeparam> /// <returns>All known types that descends to the given base type.</returns> public static IEnumerable <ITypeData> GetDerivedTypes <BaseType>() { return(GetDerivedTypes(TypeData.FromType(typeof(BaseType)))); }
/// <summary> Get all known types that derive from a given type.</summary> /// <param name="baseType">Base type that all returned types descends to.</param> /// <returns>All known types that descends to the given base type.</returns> public static IEnumerable <ITypeData> GetDerivedTypes(ITypeData baseType) { checkCacheValidity(); var searcherTypes = TypeData.FromType(typeof(ITypeDataSearcher)).DerivedTypes.Where(x => x.CanCreateInstance); bool invalidated = searchers.Any(s => s?.Types == null); if (derivedTypesCache.ContainsKey(baseType) && searchers.Count == searcherTypes.Count() && !invalidated) { return(derivedTypesCache[baseType]); } lock (lockSearchers) { var searchTasks = new List <Task>(); if (invalidated) { foreach (var s in searchers) { if (s != null && s.Types == null) { searchTasks.Add(Task.Run(() => s.Search())); } } } if (searchers.Count() != searcherTypes.Count()) { foreach (var st in searcherTypes) { if (!searchers.Any(s => TypeData.GetTypeData(s) == st)) { var searcher = (ITypeDataSearcher)st.CreateInstance(Array.Empty <object>()); searchTasks.Add(Task.Run(() => searcher.Search())); searchers.Add(searcher); } } } try { Task.WaitAll(searchTasks.ToArray()); } catch (Exception ex) { Log.CreateSource("TypeData").Debug(ex); } } var derivedTypes = new List <ITypeData>(); foreach (ITypeDataSearcher searcher in searchers) { if (searcher is DotNetTypeDataSearcher && baseType is TypeData td) { // This is a performance shortcut. derivedTypes.AddRange(td.DerivedTypes); continue; } if (searcher?.Types != null) { foreach (ITypeData type in searcher.Types) { if (type.DescendsTo(baseType)) { derivedTypes.Add(type); } } } } var result = derivedTypes.ToArray(); derivedTypesCache[baseType] = result; return(result); }
static List <object> GetProviders() { var providerTypes = TypeData.FromType(typeof(IStackedTypeDataProvider)).DerivedTypes; providerTypes = providerTypes.Concat(TypeData.FromType(typeof(ITypeDataProvider)).DerivedTypes).Distinct(); if (providersCache.Count + badProviders.Count == providerTypes.Count()) { return(providersCache); } Dictionary <object, double> priorities = new Dictionary <object, double>(); foreach (var providerType in providerTypes) { if (providerType.CanCreateInstance == false) { continue; } try { var provider = providerType.CreateInstance(); double priority; if (provider is IStackedTypeDataProvider p) { priority = p.Priority; } else if (provider is ITypeDataProvider p2) { priority = p2.Priority; } else { lock (badProviders) { if (badProviders.Contains(providerType)) { continue; // error was printed first time, so just continue. } } throw new InvalidOperationException("Unreachable code path executed."); } priorities.Add(provider, priority); } catch (Exception e) { bool isNewError = false; lock (badProviders) isNewError = badProviders.Add(providerType); if (isNewError) { var log = Log.CreateSource("TypeDataProvider"); log.Error("Unable to use TypeDataProvider of type '{0}' due to errors.", providerType.Name); log.Debug("The error was '{0}'", e.Message); log.Debug(e); } } } providersCache = priorities.Keys.OrderByDescending(x => priorities[x]).ToList(); return(providersCache); }