using AddInPlugin.Util;
|
using OpenTap;
|
using OpenTap.Addin.Annotation;
|
using System;
|
using System.Collections.Generic;
|
using System.Collections.ObjectModel;
|
using System.Linq;
|
using System.Reflection;
|
using System.Xml.Serialization;
|
using UtilLib;
|
|
namespace AddInPlugin
|
{
|
public enum VariableDirection
|
{
|
In = 0,
|
Out = 1
|
}
|
|
public class MethodVariable
|
{
|
[DataGridCol("Ãû³Æ", "*", true)]
|
public string Name { get; set; }
|
|
[XmlIgnore]
|
public Type Type { get; set; }
|
|
[XmlIgnore]
|
public object Value { get; set; }
|
|
[DataGridCol("·½Ïò", "*", true)]
|
public VariableDirection Direction { get; set; }
|
|
[DataGridCol("ÀàÐÍ", "*", true)]
|
public string TypeName { get; set; }
|
|
[DataGridCol("Öµ", "*", false)]
|
public string ValueStr { get; set; }
|
|
public override bool Equals(object obj)
|
{
|
if (obj is MethodVariable ev)
|
{
|
return ev.Name == Name && ev.ValueStr == ValueStr;
|
}
|
return base.Equals(obj);
|
}
|
|
public override int GetHashCode()
|
{
|
var h1 = Name?.GetHashCode() ?? 0;
|
var h2 = ValueStr?.GetHashCode() ?? 0;
|
return (((h1 + 742759321) * 1593213024) + h2) * 1079741372;
|
}
|
}
|
|
[Prototype]
|
[Display("DotNetStep", Description: "ÔËÐÐ.Net")]
|
|
public class DotNetStep : VariableTestStep
|
{
|
#region Settings
|
// ToDo: Add property here for each parameter the end user should be able to change
|
//[Display("Instrument", Order: 0.0, Description: "The instrument that the query is sent to.")]
|
//public DllAction Instrument { get; set; }
|
|
//// ToDo: Add property here for each parameter the end user should be able to change
|
//[Display("Dut", Order: 0.0, Description: "The instrument that the query is sent to.")]
|
//public MyDUT Dut { get; set; }
|
|
private string dllPath;
|
|
[Display("·¾¶", Order: 0.0, Description: "Dll¾ø¶Ô·¾¶.")]
|
[FilePath(FilePathAttribute.BehaviorChoice.Open)]
|
public string DllPath
|
{
|
get => dllPath;
|
set
|
{
|
if (dllPath != value)
|
{
|
dllPath = value;
|
OnPropertyChanged(nameof(DllPath));
|
LoadDll();
|
}
|
}
|
}
|
|
private Assembly assembly;
|
|
private Type targetType;
|
|
private ObservableCollection<string> types;
|
[XmlIgnore]
|
public ObservableCollection<string> Types
|
{
|
get => types;
|
set
|
{
|
types = value;
|
OnPropertyChanged(nameof(Types));
|
}
|
}
|
|
private string className;
|
[Display("ˈ̞", Order: 0.0, Description: "ˈ̞.")]
|
[DynamicSelect("Types")]
|
public string ClassName
|
{
|
get => className;
|
set
|
{
|
if (className != value)
|
{
|
className = value;
|
if (!string.IsNullOrEmpty(value))
|
{
|
LoadTypes();
|
}
|
OnPropertyChanged(nameof(ClassName));
|
}
|
}
|
}
|
|
private ObservableCollection<string> methods;
|
[XmlIgnore]
|
public ObservableCollection<string> Methods
|
{
|
get => methods;
|
set
|
{
|
methods = value;
|
OnPropertyChanged(nameof(Methods));
|
}
|
}
|
|
private string methodName;
|
[Display("·½·¨", Order: 0.0, Description: "·½·¨Ãû.")]
|
//[DynamicSelect(nameof(MethodName), "ClassName", "RefreshMethodName")]
|
[DynamicSelect("Methods")]
|
public string MethodName
|
{
|
get => methodName;
|
set
|
{
|
if (methodName != value)
|
{
|
methodName = value;
|
OnPropertyChanged(nameof(MethodName));
|
if (!string.IsNullOrEmpty(value))
|
{
|
RefreshVariables();
|
}
|
}
|
}
|
}
|
|
private Dictionary<string, MethodBase> methodCache = new Dictionary<string, MethodBase>();
|
|
[XmlIgnore]
|
private bool IsConstructorMethod = false;
|
|
[XmlIgnore]
|
private bool IsStatic = false;
|
|
[XmlIgnore]
|
private object instance;
|
|
#endregion
|
public DotNetStep()
|
{
|
// ToDo: Set default values for properties / settings.
|
Rules.Add(() => !string.IsNullOrWhiteSpace(DllPath), "·¾¶²»ÄÜΪ¿Õ", DllPath);
|
Rules.Add(() => !string.IsNullOrWhiteSpace(ClassName), "ÀàÃû²»ÄÜΪ¿Õ", ClassName);
|
}
|
|
private void LoadDll()
|
{
|
try
|
{
|
if (string.IsNullOrEmpty(DllPath))
|
{
|
return;
|
}
|
assembly = Assembly.LoadFrom(DllPath);
|
Types = new ObservableCollection<string>(assembly.GetTypes().Select(e => e.ToString()).ToArray());
|
}
|
catch (Exception ex)
|
{
|
Log.Error("DotNetStep load dll error. {0}", ex);
|
}
|
}
|
|
public void LoadTypes()
|
{
|
methodCache.Clear();
|
try
|
{
|
targetType = assembly?.GetType(ClassName);
|
if (targetType != null)
|
{
|
var creators = targetType?.GetConstructors();
|
if (creators != null)
|
{
|
for (int i = 0; i < creators.Length; i++)
|
{
|
var creator = creators[i];
|
var ps = creator.GetParameters();
|
var displayName = $"{targetType.Name} ({string.Join(", ", ps.Select(p => $"{p.ParameterType.ToString()} {p.Name}").ToArray())})";
|
methodCache[displayName] = creator;
|
}
|
}
|
|
var methods = MethodInfoHelper.GetPublicMethodNames(targetType);
|
if (methods != null)
|
{
|
for (int i = 0; i < methods.Count; i++)
|
{
|
var method = methods[i];
|
var ps = method.GetParameters();
|
var displayName = $"{method.Name} ({string.Join(", ", ps.Select(p => $"{p.ParameterType.ToString()} {p.Name}").ToArray())})";
|
methodCache[displayName] = method;
|
}
|
}
|
}
|
Methods = new ObservableCollection<string>(methodCache.Keys.ToArray());
|
}
|
catch (Exception ex)
|
{
|
Log.Error("DotNetStep LoadTypes error. {0}", ex);
|
}
|
}
|
|
public void RefreshVariables()
|
{
|
if (MethodVariables == null)
|
{
|
MethodVariables = new ObservableCollection<MethodVariable>();
|
}
|
MethodVariables.Clear();
|
try
|
{
|
if (!methodCache.ContainsKey(MethodName))
|
{
|
return;
|
}
|
var method = methodCache[MethodName];
|
var ps = method.GetParameters();
|
IsStatic = method.IsStatic;
|
IsConstructorMethod = method.IsConstructor;
|
|
if (IsConstructorMethod)
|
{
|
MethodVariables.Add(new MethodVariable
|
{
|
Name = "(return)",
|
Type = targetType,
|
TypeName = targetType?.ToString(),
|
Direction = VariableDirection.Out,
|
});
|
|
}
|
else if (!IsStatic)
|
{
|
var mi = (MethodInfo)method;
|
MethodVariables.Add(new MethodVariable
|
{
|
Name = "(instance)",
|
Type = targetType,
|
TypeName = targetType?.ToString(),
|
Direction = VariableDirection.In,
|
});
|
MethodVariables.Add(new MethodVariable
|
{
|
Name = "(return)",
|
Type = mi.ReturnType,
|
TypeName = mi.ReturnType?.ToString(),
|
Direction = VariableDirection.Out,
|
});
|
}
|
else
|
{
|
var mi = (MethodInfo)method;
|
MethodVariables.Add(new MethodVariable
|
{
|
Name = "(return)",
|
Type = mi.ReturnType,
|
TypeName = mi.ReturnType?.ToString(),
|
Direction = VariableDirection.Out,
|
});
|
}
|
|
foreach (var p in ps)
|
{
|
MethodVariables.Add(new MethodVariable
|
{
|
Name = p.Name,
|
Type = p.ParameterType,
|
TypeName = p.ParameterType.ToString(),
|
Direction = p.IsOut ? VariableDirection.Out : VariableDirection.In,
|
});
|
}
|
}
|
catch (Exception ex)
|
{
|
Log.Error("DotNetStep LoadVariables error. {0}", ex);
|
}
|
}
|
|
public override void PrePlanRun()
|
{
|
// ToDo: Optionally add any setup code this step needs to run before the testplan starts
|
base.PrePlanRun();
|
}
|
|
/// <summary>
|
/// ת»»²ÎÊý
|
/// </summary>
|
private void ResolveVariables()
|
{
|
var method = methodCache[methodName];
|
if (IsConstructorMethod)
|
{
|
//methodParams = new object[MethodVariables.Count - 1];
|
for (int i = 1; i < MethodVariables.Count; i++)
|
{
|
MethodVariable mv = MethodVariables[i];
|
if (mv.Direction == VariableDirection.In)
|
{
|
mv.Value = PlanRun.Resolve(this, mv.ValueStr, mv.Type); // mv.GetValue(PlanRun);
|
}
|
//methodParams[i-1] = mv.GetValue(PlanRun);
|
}
|
}
|
else if (IsStatic)
|
{
|
//methodParams = new object[MethodVariables.Count - 2];
|
for (int i = 1; i < MethodVariables.Count; i++)
|
{
|
MethodVariable mv = MethodVariables[i];
|
if (mv.Direction == VariableDirection.In)
|
{
|
mv.Value = PlanRun.Resolve(this, mv.ValueStr, mv.Type); //mv.GetValue(PlanRun);
|
}
|
//methodParams[i] = mv.GetValue(PlanRun);
|
}
|
}
|
else
|
{
|
//methodParams = new object[MethodVariables.Count - 1];
|
for (int i = 1; i < MethodVariables.Count; i++)
|
{
|
var mv = MethodVariables[i];
|
if (mv.Direction == VariableDirection.In)
|
{
|
mv.Value = PlanRun.Resolve(this, mv.ValueStr, mv.Type); //mv.GetValue(PlanRun);
|
}
|
//methodParams[i] = mv.GetValue(PlanRun);
|
}
|
}
|
}
|
|
/// <summary>
|
/// ÔËÐк¯Êý
|
/// </summary>
|
private void RunMethod()
|
{
|
ResolveVariables();
|
|
if (IsConstructorMethod)
|
{
|
var method = (ConstructorInfo)methodCache[methodName];
|
var methodParams = new object[MethodVariables.Count - 1];
|
for (int i = 1; i < MethodVariables.Count; i++)
|
{
|
var mv = MethodVariables[i];
|
methodParams[i - 1] = mv.Value;
|
}
|
instance = method.Invoke(methodParams);
|
MethodVariables[0].Value = instance;
|
}
|
else if (IsStatic)
|
{
|
var method = methodCache[methodName];
|
var methodParams = new object[MethodVariables.Count - 1];
|
for (int i = 1; i < MethodVariables.Count; i++)
|
{
|
var mv = MethodVariables[i];
|
methodParams[i - 1] = mv.Value;
|
}
|
|
MethodVariables[0].Value = method.Invoke(null, methodParams);
|
for (int i = 0; i < methodParams.Length; i++)
|
{
|
MethodVariables[i + 1].Value = methodParams[i];
|
}
|
}
|
else
|
{
|
var method = methodCache[methodName];
|
var methodParams = new object[MethodVariables.Count - 2];
|
for (int i = 2; i < MethodVariables.Count; i++)
|
{
|
var mv = MethodVariables[i];
|
methodParams[i - 2] = mv.Value;
|
}
|
instance = PlanRun.Resolve(this, MethodVariables[0].ValueStr);
|
MethodVariables[1].Value = method.Invoke(instance, methodParams);
|
for (int i = 0; i < methodParams.Length; i++)
|
{
|
MethodVariables[i + 2].Value = methodParams[i];
|
}
|
}
|
}
|
|
public override void Run()
|
{
|
try
|
{
|
// ToDo: Add test case code here
|
//RunChildSteps(); //If step has child steps.
|
RunMethod();
|
|
UpdateVariableToRuntime();
|
this.Verdict = Verdict.Pass;
|
}
|
catch (Exception ex)
|
{
|
Log.Error("DotNetStep Run error. {0}", ex);
|
this.Verdict = Verdict.Error;
|
}
|
}
|
|
private void UpdateVariableToRuntime()
|
{
|
//if (IsConstructorMethod)
|
//{
|
// var methodVariable = MethodVariables[0];
|
// PlanRun.UpdateRuntimeVariable(methodVariable.ValueStr, instance);
|
//}
|
foreach (var mv in MethodVariables)
|
{
|
if (mv.Direction == VariableDirection.Out)
|
{
|
PlanRun.Update(this, mv.ValueStr, mv.Value);
|
}
|
}
|
}
|
|
public override void PostPlanRun()
|
{
|
// ToDo: Optionally add any cleanup code this step needs to run after the entire testplan has finished
|
base.PostPlanRun();
|
}
|
}
|
}
|