/// <summary> Deserialization implementation. </summary> public override bool Deserialize(XElement elem, ITypeData t, Action <object> setter) { if (t.DescendsTo(typeof(IDynamicStep)) == false) { return(false); } try { IDynamicStep step = (IDynamicStep)t.CreateInstance(Array.Empty <object>()); Serializer.Register(step); TryDeserializeObject(elem, TypeData.GetTypeData(step), setter, step, logWarnings: false); ITestStep genStep = step.GetStep(); bool res = true; if (elem.IsEmpty == false) { res = TryDeserializeObject(elem, TypeData.GetTypeData(genStep), setter, genStep, logWarnings: false); } else { setter(genStep); } Serializer.GetSerializer <TestStepSerializer>().FixupStep(genStep, true); return(res); } catch (Exception e) { Log.Error("Unable to deserialize step of type {0}. Error was: {1}", t, e.Message); Log.Debug(e); return(true); } }
/// <summary> /// Constructs a new instance of the object represented by the expression. /// </summary> /// <param name="expression">json object expression</param> /// <param name="deserializer">deserializer for deserializing constructor arguments if any</param> /// <returns>constructed, but unpopulated object</returns> protected virtual object ConstructObject(ObjectExpression expression, IDeserializerHandler deserializer) { ITypeData handler = Settings.Types[expression.ResultType]; // set the default type if none set if (expression.ConstructorArguments.Count > 0) { // old way expects parameters in the constructor list ResolveConstructorTypes(Settings, expression); } else { foreach (IPropertyData parameter in handler.ConstructorParameters) { int propLocation = expression.IndexOf(parameter.Alias); if (propLocation >= 0) { Expression arg = expression.Properties[propLocation].ValueExpression; arg.ResultType = parameter.PropertyType; expression.ConstructorArguments.Add(arg); expression.Properties.RemoveAt(propLocation); } else { expression.ConstructorArguments.Add(new NullExpression()); } } } object[] args = new object[expression.ConstructorArguments.Count]; for (int i = 0; i < args.Length; i++) { Expression carg = expression.ConstructorArguments[i]; if (i < handler.ConstructorParameters.Count && handler.ConstructorParameters[i].HasConverter) { TypeConverterExpressionHandler converterHandler = (TypeConverterExpressionHandler)Settings.ExpressionHandlers.Find(typeof(TypeConverterExpressionHandler)); args[i] = converterHandler.Evaluate(carg, deserializer, handler.ConstructorParameters[i].TypeConverter); } else { args[i] = deserializer.Evaluate(carg); } } object result = handler.CreateInstance(args); expression.OnObjectConstructed(result); return(result); }
public object CreateInstance(object[] arguments) { return(innerType.CreateInstance(arguments)); }
public static int Execute(params string[] args) { // Trigger plugin manager before anything else. if (ExecutorClient.IsRunningIsolated) { // TODO: This is not needed right now, but might be again when we fix the TODO in tap.exe //PluginManager.DirectoriesToSearch.Clear(); //PluginManager.DirectoriesToSearch.Add(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)); using (var tpmClient = new ExecutorClient()) { tpmClient.MessageServer("delete " + Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)); } } // Set TapMutex to ensure any installers know about running OpenTAP processes. ReflectionHelper.SetTapMutex(); try { // Turn off the default system behavior when CTRL+C is pressed. // When Console.TreatControlCAsInput is false, CTRL+C is treated as an interrupt instead of as input. Console.TreatControlCAsInput = false; } catch { } try { var execThread = TapThread.Current; Console.CancelKeyPress += (s, e) => { e.Cancel = true; execThread.Abort(); }; } catch { } CultureInfo.CurrentCulture = CultureInfo.InvariantCulture; CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; // Find the called action if (!TypeData.GetDerivedTypes <ICliAction>().Any()) { Console.WriteLine("No commands found. Please try reinstalling OpenTAP."); return(1); } try { // setup logging to be relative to the executing assembly. // at this point SessionLogs.Initialize has already been called (PluginManager.Load). // so the log is already being saved at a different location. var logpath = EngineSettings.Current.SessionLogPath.Expand(date: Process.GetCurrentProcess().StartTime); bool isPathRooted = Path.IsPathRooted(logpath); if (isPathRooted == false) { var dir = Path.GetDirectoryName(typeof(SessionLogs).Assembly.Location); if (ExecutorClient.IsRunningIsolated) { // redirect the isolated log path to the non-isolated path. dir = ExecutorClient.ExeDir; } logpath = Path.Combine(dir, logpath); } SessionLogs.Rename(logpath); } catch (Exception e) { log.Error("Path defined in Engine settings contains invalid characters: {0}", EngineSettings.Current.SessionLogPath); log.Debug(e); } ITypeData selectedCommand = null; // Find selected command var actionTree = new CliActionTree(); var selectedcmd = actionTree.GetSubCommand(args); if (selectedcmd?.Type != null && selectedcmd?.SubCommands.Any() != true) { selectedCommand = selectedcmd.Type; } void print_command(CliActionTree cmd, int level, int descriptionStart) { if (cmd.IsBrowsable) { int relativePadding = descriptionStart - (level * LevelPadding); // Calculate amount of characters to pad right before description start to ensure description alignments. Console.Write($"{"".PadRight(level * LevelPadding)}{cmd.Name.PadRight(relativePadding)}"); if (cmd.Type?.IsBrowsable() ?? false) { Console.WriteLine($"{cmd.Type.GetDisplayAttribute().Description}"); } else { Console.WriteLine(); } if (cmd.IsGroup) { foreach (var subCmd in cmd.SubCommands) { print_command(subCmd, level + 1, descriptionStart); } } } } // Print default info if (selectedCommand == null) { Console.WriteLine("OpenTAP Command Line Interface ({0})", Assembly.GetExecutingAssembly().GetSemanticVersion().ToString(4)); Console.WriteLine("Usage: tap <command> [<subcommand(s)>] [<args>]\n"); if (selectedcmd == null) { Console.WriteLine("Valid commands are:"); foreach (var cmd in actionTree.SubCommands) { print_command(cmd, 0, actionTree.GetMaxCommandTreeLength(LevelPadding) + LevelPadding); } } else { Console.Write("Valid subcommands of "); print_command(selectedcmd, 0, actionTree.GetMaxCommandTreeLength(LevelPadding) + LevelPadding); } Console.WriteLine($"\nRun \"{(OperatingSystem.Current == OperatingSystem.Windows ? "tap.exe" : "tap")} " + "<command> [<subcommand>] -h\" to get additional help for a specific command.\n"); if (args.Length == 0 || args.Any(s => s.ToLower() == "--help" || s.ToLower() == "-h")) { return(0); } else { return(-1); } } if (selectedCommand != TypeData.FromType(typeof(RunCliAction)) && UserInput.Interface == null) // RunCliAction has --non-interactive flag and custom platform interaction handling. { CliUserInputInterface.Load(); } ICliAction packageAction = null; try{ packageAction = (ICliAction)selectedCommand.CreateInstance(); }catch (TargetInvocationException e1) when(e1.InnerException is System.ComponentModel.LicenseException e) { Console.Error.WriteLine("Unable to load CLI Action '{0}'", selectedCommand.GetDisplayAttribute().GetFullName()); Console.Error.WriteLine(e.Message); return(-4); } if (packageAction == null) { Console.WriteLine("Error instantiating command {0}", selectedCommand.Name); return(-3); } try { int skip = selectedCommand.GetDisplayAttribute().Group.Length + 1; // If the selected command has a group, it takes two arguments to use the command. E.g. "package create". If not, it only takes 1 argument, E.g. "restapi". return(packageAction.Execute(args.Skip(skip).ToArray())); } catch (ExitCodeException ec) { log.Error(ec.Message); return(ec.ExitCode); } catch (ArgumentException ae) { // ArgumentException usually contains several lines. // Only print the first line as an error message. // Example message: // "Directory is not a git repository. // Parameter name: repositoryDir" var lines = ae.Message.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); log.Error(lines.First()); for (int i = 1; i < lines.Length; i++) { log.Debug(lines[i]); } return(-1); } catch (OperationCanceledException ex) { log.Error(ex.Message); return(1); } catch (Exception ex) { log.Error(ex.Message); log.Debug(ex); return(-1); } finally { Log.Flush(); } }
/// <summary> /// Tries to deserialize an object from an XElement. /// </summary> /// <param name="element"></param> /// <param name="t"></param> /// <param name="setter"></param> /// <param name="newobj"></param> /// <param name="logWarnings">Whether warning messages should be emitted in case of missing properties.</param> /// <returns>True on success.</returns> public virtual bool TryDeserializeObject(XElement element, ITypeData t, Action <object> setter, object newobj = null, bool logWarnings = true) { if (element.IsEmpty && !element.HasAttributes) { setter(null); return(true); } if (newobj == null) { try { newobj = t.CreateInstance(Array.Empty <object>()); t = TypeData.GetTypeData(newobj); } catch (TargetInvocationException ex) { if (ex.InnerException is System.ComponentModel.LicenseException) { throw new Exception(string.Format("Could not create an instance of '{0}': {1}", t.GetAttribute <DisplayAttribute>().Name, ex.InnerException.Message)); } else { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } } var prevobj = Object; Object = newobj; var t2 = t; if (newobj == null) { throw new ArgumentNullException(nameof(newobj)); } var properties = t2.GetMembers() .Where(x => x.HasAttribute <XmlIgnoreAttribute>() == false) .ToArray(); try { foreach (var prop in properties) { var attr = prop.GetAttribute <XmlAttributeAttribute>(); if (attr == null) { continue; } var name = string.IsNullOrWhiteSpace(attr.AttributeName) ? prop.Name : attr.AttributeName; var attr_value = element.Attribute(XmlConvert.EncodeLocalName(name)); var p = prop as MemberData; if (p != null && attr_value != null && p.Member is PropertyInfo csprop) { try { readContentInternal(csprop.PropertyType, false, () => attr_value.Value, element, out object value); p.SetValue(newobj, value); } catch (Exception e) { if (logWarnings) { Log.Warning(element, "Attribute value '{0}' was not read correctly as a {1}", attr_value.Value, p); Log.Debug(e); } } } } if (properties.FirstOrDefault(x => x.HasAttribute <XmlTextAttribute>()) is IMemberData mem2) { object value; if (mem2.TypeDescriptor is TypeData td && readContentInternal(td.Load(), false, () => element.Value, element, out object _value)) { value = _value; } else { value = StringConvertProvider.FromString(element.Value, mem2.TypeDescriptor, null); } mem2.SetValue(newobj, value); } else { var props = properties.ToLookup(x => x.GetAttributes <XmlElementAttribute>().FirstOrDefault()?.ElementName ?? x.Name); var elements = element.Elements().ToArray(); bool[] visited = new bool[elements.Length]; double order = 0; int foundWithCurrentType = 0; while (true) { double nextOrder = 1000; // since the object might be dynamically adding properties as other props are added. // we need to iterate a bit. Example: Test Plan Reference. int found = visited.Count(x => x); for (int i = 0; i < elements.Length; i++) { var element2 = elements[i]; if (visited[i]) { continue; } if (element2.Attribute(IgnoreMemberXName) is XAttribute attr && attr.Value == "true") { visited[i] = true; continue; } IMemberData property = null; var name = XmlConvert.DecodeName(element2.Name.LocalName); var propertyMatches = props[name]; int hits = 0; foreach (var p in propertyMatches) { if (p.Writable || p.HasAttribute <XmlIgnoreAttribute>()) { property = p; hits++; } } if (0 == hits) { try { if (property == null) { property = t2.GetMember(name); } if (property == null) { property = t2.GetMembers().FirstOrDefault(x => x.Name == name); } } catch { } if (property == null || property.Writable == false) { continue; } hits = 1; } if (hits > 1) { Log.Warning(element2, "Multiple properties named '{0}' are available to the serializer in '{1}' this might give issues in serialization.", element2.Name.LocalName, t.GetAttribute <DisplayAttribute>().Name); } if (property.GetAttribute <DeserializeOrderAttribute>() is DeserializeOrderAttribute orderAttr) { if (order < orderAttr.Order) { if (orderAttr.Order < nextOrder) { nextOrder = orderAttr.Order; } continue; } } else { nextOrder = order; } visited[i] = true; var prev = CurrentMember; CurrentMember = property; try { if (CurrentMember.HasAttribute <XmlIgnoreAttribute>()) // This property shouldn't have been in the file in the first place, but in case it is (because of a change or a bug), we shouldn't try to set it. (E.g. SweepLoopRange.SweepStep) { if (!CurrentMember.HasAttribute <BrowsableAttribute>()) // In the special case we assume that this is some compatibility property that still needs to be set if present in the XML. (E.g. TestPlanReference.DynamicDataContents) { continue; } } if (property is MemberData mem && mem.Member is PropertyInfo Property && Property.PropertyType.HasInterface <IList>() && Property.PropertyType.IsGenericType && Property.HasAttribute <XmlElementAttribute>()) { // Special case to mimic old .NET XmlSerializer behavior var list = (IList)Property.GetValue(newobj); Action <object> setValue = x => list.Add(x); Serializer.Deserialize(element2, setValue, Property.PropertyType.GetGenericArguments().First()); } else { Action <object> setValue = x => { var current = property.GetValue(newobj); property.SetValue(newobj, x); if (false == Equals(current, x)) { // for some value-like type, it may be needed // to set the parent object when a property is changed // example: complex test plan parameters. setter(newobj); } }; Serializer.Deserialize(element2, setValue, property.TypeDescriptor); } }
public object CreateInstance(object[] arguments) { return(InnerDescriptor.CreateInstance(arguments)); }
/// <summary> /// Creates an instance of this type using the default constructor. /// </summary> public static object CreateInstance(this ITypeData type) { return(type.CreateInstance(Array.Empty <object>())); }