using LabViewHelper; using NationalInstruments.LabVIEW.Interop; using OpenTap; using OpenTap.Addin.Annotation; using OpenTap.Addin.Util; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reflection; using System.Xml.Serialization; using UtilLib; using ViHelper; namespace AddInPlugin.Super { public enum JudgeType { Number = 0, String = 1, Bool = 2 } [Display("Adapter")] public enum AdapterType { None = 0, [Display(".Net")] CShape = 1, LabView = 2, Lvlibp = 3, } [Display("ComparisonType")] public enum ComparisonType { [Display("x == Low")] EQ = 0, [Display("x != Low")] NE = 1, [Display("x > Low")] GT = 2, [Display("x < Low")] LT = 3, [Display("x >= Low")] GE = 4, [Display("x <= Low")] LE = 5, [Display("Low < x < High")] GTLT = 6, [Display("Low <= x <= High")] GELE = 7, [Display("Low <= x < High")] GELT = 8, [Display("Low < x <= High")] GTLE = 9, [Display("x < Low OR x > High")] LTGT = 10, [Display("x <= Low OR x >= High")] LEGE = 11, [Display("x <= Low OR x > High")] LEGT = 12, [Display("x < Low OR x >= High")] LTGE = 13, } public class JudgeTest : VariableTestStep { private Exception loadException; [XmlIgnore] public Exception LoadException { get => loadException; set { Set(ref loadException, value); } } private AdapterType adapter = AdapterType.None; [Display("适配器")] public AdapterType Adapter { get => adapter; set { Set(ref adapter, value); } } public JudgeTest() : base() { DllLocation = new LocationString(); LvlibpLocation = new LocationString(); } protected override void OnRootChanged(TestPlan old, TestPlan plan) { if (old == plan) return; try { if (Adapter == AdapterType.CShape) { if (!string.IsNullOrEmpty(DllPath)) { DllLocation.AbsoluteLocation = DllPath; DllPath = null; } DllLocation.Refresh(Root.Path); LoadDll(true); } else if (Adapter == AdapterType.Lvlibp) { if (!string.IsNullOrEmpty(LvlibpPath)) { LvlibpLocation.AbsoluteLocation = LvlibpPath; LvlibpPath = null; } LvlibpLocation.Refresh(Root.Path); LoadLvlibp(true); } } catch (Exception ex) { Log.Error($"{Name}: JudgeTest load dll error. {0}", ex); } } private void Location_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { if (sender == DllLocation) { LoadDll(false); } else if (sender == LvlibpLocation) { LoadLvlibp(false); } } private void ConcatVariable(MethodVariable mv, MethodVariable[] source) { MethodVariables.Add(mv); var preview = source?.FirstOrDefault(v => v.Name == mv.Name && !string.IsNullOrEmpty(v.ValueStr)); if (preview != null) { mv.ValueStr = preview.ValueStr; } } #region .Net相关 private Assembly assembly; private Type targetType; private Dictionary methodCache = new Dictionary(); [XmlIgnore] private object instance; private string dllPath; [Obsolete] public string DllPath { get => dllPath; set { Set(ref dllPath, value); } } private LocationString dllLocation; [Display("DLL路径", Order: 0.0, Description: "Dll绝对路径.")] [DependOn("Adapter", AdapterType.CShape)] [FilePath(FilePathAttribute.BehaviorChoice.Open, fileExtension: "Dll|*.dll")] public LocationString DllLocation { get => dllLocation; set { if (value != dllLocation) { value.PropertyChanged += Location_PropertyChanged; } Set(ref dllLocation, value); } } private ObservableCollection types; [XmlIgnore] public ObservableCollection Types { get => types; set { types = value; OnPropertyChanged(nameof(Types)); } } private ObservableCollection methods; [XmlIgnore] public ObservableCollection Methods { get => methods; set { methods = value; OnPropertyChanged(nameof(Methods)); } } private string className; [DependOn("Adapter", AdapterType.CShape)] [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 string methodName; [DependOn("Adapter", AdapterType.CShape)] [Display("方法", Order: 0.0, Description: "方法名.")] [DynamicSelect("Methods")] public string MethodName { get => methodName; set { if (methodName != value) { methodName = value; OnPropertyChanged(nameof(MethodName)); if (!string.IsNullOrEmpty(value)) { RefreshVariables(); } } } } private void LoadDll(bool loadAll) { try { if (!DllLocation.GetLocation(Root.Path, out string path)) { throw new Exception("Dll Exception"); } assembly = DllLoader.Instance.LoadAssembly(path, out var types); Types = types; if (loadAll) { LoadTypes(); RefreshVariables(); } LoadException = null; } catch (Exception ex) { LoadException = ex; Log.Error($"{Name}: JudgeTest 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(methodCache.Keys.ToArray()); } catch (Exception ex) { Log.Error("DotNetStep LoadTypes error. {0}", ex); } } public void RefreshVariables() { if (MethodVariables == null) { MethodVariables = new ObservableCollection(); } var last = MethodVariables.ToArray(); MethodVariables.Clear(); try { if (!methodCache.ContainsKey(MethodName)) { return; } var method = methodCache[MethodName]; var ps = method.GetParameters(); var IsStatic = method.IsStatic; var IsConstructorMethod = method.IsConstructor; if (IsConstructorMethod) { var newOne = new MethodVariable { Name = "(return)", Type = targetType, TypeName = targetType?.ToString(), Direction = VariableDirection.Out, }; ConcatVariable(newOne, last); } else if (!IsStatic) { var mi = (MethodInfo)method; var newOne = new MethodVariable { Name = "(instance)", Type = targetType, TypeName = targetType?.ToString(), Direction = VariableDirection.In, }; ConcatVariable(newOne, last); newOne = new MethodVariable { Name = "(return)", Type = mi.ReturnType, TypeName = mi.ReturnType?.ToString(), Direction = VariableDirection.Out, }; ConcatVariable(newOne, last); } else { var mi = (MethodInfo)method; var newOne = new MethodVariable { Name = "(return)", Type = mi.ReturnType, TypeName = mi.ReturnType?.ToString(), Direction = VariableDirection.Out, }; ConcatVariable(newOne, last); } foreach (var p in ps) { var newOne = new MethodVariable { Name = p.Name, Type = p.ParameterType, TypeName = p.ParameterType.ToString(), Direction = p.IsOut ? VariableDirection.Out : VariableDirection.In, }; ConcatVariable(newOne, last); } } catch (Exception ex) { Log.Error("DotNetStep LoadVariables error. {0}", ex); } } /// /// 转换参数 /// private void ResolveDotNetVariables() { var method = methodCache[methodName]; var IsStatic = method.IsStatic; var IsConstructorMethod = method.IsConstructor; if (IsConstructorMethod) { 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); } } } else if (IsStatic) { 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); } } } else { 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); } } } } #endregion #region LabView相关 private string viPath; [Display("VI路径", Order: 0.0, Description: "Dll绝对路径.")] [DependOn(nameof(Adapter), AdapterType.LabView)] [FilePath(FilePathAttribute.BehaviorChoice.Open)] public string ViPath { get => viPath; set { if (viPath != value) { viPath = value; OnPropertyChanged(nameof(viPath)); LoadVi(); } } } private void LoadVi() { try { if (string.IsNullOrEmpty(ViPath)) { return; } LabViHelper.GetIOType(ViPath, out var inVariables, out var outVariables); var last = MethodVariables?.ToArray(); MethodVariables.Clear(); foreach (var inv in inVariables) { var newOne = new MethodVariable { Name = inv.Name, Type = inv.Type, TypeName = inv.Type.ToString(), Direction = VariableDirection.In, ValueStr = inv.Data.ToString() }; ConcatVariable(newOne, last); } foreach (var onv in outVariables) { var newOne = new MethodVariable { Name = onv.Name, Type = onv.Type, TypeName = onv.Type.ToString(), Direction = VariableDirection.Out }; ConcatVariable(newOne, last); } } catch (Exception ex) { Log.Error("ViStep load vi error. {0}", ex); } } /// /// 转换参数 /// private void ResolveLabViewVariables() { foreach (var m in MethodVariables) { m.Value = PlanRun.Resolve(this, m.ValueStr); } } #endregion #region lvlibp相关 private string lvlibpPath; [Obsolete] public string LvlibpPath { get => lvlibpPath; set { Set(ref lvlibpPath, value); } } private LocationString lvlibpLocation; [Display("路径", Order: 0.0, Description: "lvlibp绝对路径.")] [DependOn(nameof(Adapter), AdapterType.Lvlibp)] [FilePath(FilePathAttribute.BehaviorChoice.Open, fileExtension: "Labview|*.lvlibp")] public LocationString LvlibpLocation { get => lvlibpLocation; set { if (value != lvlibpLocation) { value.PropertyChanged += Location_PropertyChanged; } Set(ref lvlibpLocation, value); } } private ObservableCollection nameDatasource; [XmlIgnore] public ObservableCollection NameDatasource { get => nameDatasource; set { Set(ref nameDatasource, value); } } private string viName; [Display("VI", Order: 0.0, Description: "VI名称.")] [DependOn(nameof(Adapter), AdapterType.Lvlibp)] [DynamicSelect(nameof(NameDatasource))] public string ViName { get => viName; set { Set(ref viName, value); LoadViByName(); } } private bool showWindow; [Display("显示窗口", Order: 0.0)] [DependOn(nameof(Adapter), AdapterType.Lvlibp)] public bool ShowWindow { get => showWindow; set { Set(ref showWindow, value); } } private void LoadLvlibp(bool loadAll) { try { if (!LvlibpLocation.GetLocation(Root.Path, out string path)) { return; } LabViewRunner.GetLibpNames(new LVPath(path), out string[] names, out var outVariables); NameDatasource = new ObservableCollection(names); if (loadAll) { LoadVi(); } LoadException = null; } catch (Exception ex) { LoadException = ex; //Log.Error("ViStep load vi error. {0}", ex); } } private void LoadViByName() { try { if (!LvlibpLocation.GetLocation(Root?.Path, out string path)) { return; } LabViHelper.GetIOTypeByLvlibp(path, ViName, out var inVariables, out var outVariables); var last = MethodVariables.ToArray(); MethodVariables.Clear(); foreach (var inv in inVariables) { var newOne = new MethodVariable { Name = inv.Name, Type = inv.Type, TypeName = inv.Type.ToString(), Direction = VariableDirection.In, ValueStr = inv.Type == typeof(string) ? $"\"{inv.Data?.ToString()}\"" : inv.Data?.ToString() }; ConcatVariable(newOne, last); } foreach (var onv in outVariables) { var newOne = new MethodVariable { Name = onv.Name, Type = onv.Type, TypeName = onv.Type.ToString(), Direction = VariableDirection.Out }; ConcatVariable(newOne, last); } LoadException = null; } catch (Exception ex) { LoadException = ex; } } #endregion [Display("参数", Order: 0.0, Description: "运行参数.")] [BindingList(nameof(MethodVariables))] [DependOn(nameof(Adapter), new object[] { AdapterType.Lvlibp, AdapterType.LabView, AdapterType.CShape }, GroupCheck.OR)] public override ObservableCollection MethodVariables { get => methodVariables; set { methodVariables = value; foreach (var mv in value) { mv.Type = System.Type.GetType(mv.TypeName); } OnPropertyChanged(nameof(MethodVariables)); OnMethodVariablesChanged(value); } } protected JudgeType type = JudgeType.Number; // [Display("校验类型")] public virtual JudgeType Type { get => type; set { Set(ref type, value); } } private string compareSource; [Display("数据源")] public string CompareSource { get => compareSource; set { Set(ref compareSource, value); } } private ComparisonType comparsion = ComparisonType.EQ; [Display("比较方法")] [DependOn("Type", JudgeType.Number)] public ComparisonType Comparison { get => comparsion; set { Set(ref comparsion, value); } } private string limitDown; [Display("下限 (Low)")] [DependOn("Type", JudgeType.Number)] public string LimitDown { get => limitDown; set { Set(ref limitDown, value); OnPropertyChanged(nameof(TargetValue)); } } private string limitUp; [Display("上限 (High)")] [DependOn("Type", JudgeType.Number)] public string LimitUp { get => limitUp; set { Set(ref limitUp, value); } } [Display("目标值")] [DependOn("Type", JudgeType.String)] public string TargetValue { get => limitDown; set { Set(ref limitDown, value); OnPropertyChanged(nameof(LimitDown)); } } private bool ignoreCase = false; [Display("忽略大小写")] [DependOn("Type", JudgeType.String)] public bool IgnoreCase { get => ignoreCase; set { Set(ref ignoreCase, value); } } private string output = ConstNames.StepResultPassFail; [Display("输出结果")] public string Output { get => output; set { Set(ref output, value); } } /// /// 运行函数 /// private void RunDotNetMethod() { ResolveDotNetVariables(); var method = methodCache[methodName]; var IsStatic = method.IsStatic; var IsConstructorMethod = method.IsConstructor; if (IsConstructorMethod) { var constructor = (ConstructorInfo)method; 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 = constructor.Invoke(methodParams); MethodVariables[0].Value = instance; } else if (IsStatic) { 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 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]; } } } /// /// 运行函数 /// private void RunLabViewMethod() { ResolveLabViewVariables(); var ins = MethodVariables.Where(m => m.Direction == VariableDirection.In) .Select(m => new Cluster { name = m.Name, variant__32Data = new LVVariant(m.Value) }).ToArray(); LabViewRunner.ViRunner(new LVPath(this.ViPath), 0, ins, out var outs); foreach (var ov in outs) { foreach (var m in MethodVariables) { if (ov.name == m.Name) { m.Value = ov.variant__32Data.value; break; } } } } private void RunLvlibpMethod() { if (!LvlibpLocation.GetLocation(Root?.Path, out string path)) { return; } ResolveLabViewVariables(); var ins = MethodVariables.Where(m => m.Direction == VariableDirection.In && m.Value != null) .Select(m => new Cluster { name = m.Name, variant__32Data = new LVVariant(m.Value) }).ToArray(); LabViewRunner.RunLibpByName2(new LVPath(path), ViName, 0, ShowWindow, ins, out var outs, out ErrorCluster err); if (err.status) { Verdict = Verdict.Error; return; } foreach (var ov in outs) { foreach (var m in MethodVariables) { if (ov.name == m.Name) { m.Value = ov.variant__32Data.value; break; } } } } protected override void RunDetail() { try { if (Adapter == AdapterType.CShape) { RunDotNetMethod(); UpdateVariableToRuntime(); } else if (Adapter == AdapterType.LabView) { RunLabViewMethod(); UpdateVariableToRuntime(); } else if (Adapter == AdapterType.Lvlibp) { RunLvlibpMethod(); UpdateVariableToRuntime(); } bool res = false; if (Type == JudgeType.Number) { res = DoCompareNumber(); Log.Debug($"DoCompareNumber: {res}"); } else if (Type == JudgeType.String) { res = DoCompareString(); Log.Debug($"DoCompareString: {res}"); } else if (Type == JudgeType.Bool) { res = DoCompareBool(); Log.Debug($"DoCompareBool: {res}"); } UploadResult(res); } catch (Exception ex) { UploadResult(false); Log.Error("JudgeTest Run error. {0}", ex); this.Verdict = Verdict.Error; } } private void UploadResult(bool data) { this.Verdict = data ? Verdict.Pass : Verdict.Fail; PlanRun.Update(this, ConstNames.StepResultPassFail, data); PlanRun.Update(this, Output, data); } private bool DoCompareNumber() { string express = $"{CompareSource} == {LimitDown}"; switch (Comparison) { case ComparisonType.NE: express = $"{CompareSource} != {LimitDown}"; break; case ComparisonType.GT: express = $"{CompareSource} > {LimitDown}"; break; case ComparisonType.LT: express = $"{CompareSource} < {LimitDown}"; break; case ComparisonType.GE: express = $"{CompareSource} >= {LimitDown}"; break; case ComparisonType.LE: express = $"{CompareSource} <= {LimitDown}"; break; case ComparisonType.GTLT: express = $"{CompareSource} > {LimitDown} && {CompareSource} < {LimitUp}"; break; case ComparisonType.GELE: express = $"{CompareSource} >= {LimitDown} && {CompareSource} <= {LimitUp}"; break; case ComparisonType.GELT: express = $"{CompareSource} >= {LimitDown} && {CompareSource} < {LimitUp}"; break; case ComparisonType.GTLE: express = $"{CompareSource} > {LimitDown} && {CompareSource} <= {LimitUp}"; break; case ComparisonType.LTGT: express = $"{CompareSource} > {LimitUp} || {CompareSource} < {LimitDown}"; break; case ComparisonType.LEGE: express = $"{CompareSource} >= {LimitUp} || {CompareSource} <= {LimitDown}"; break; case ComparisonType.LEGT: express = $"{CompareSource} > {LimitUp} || {CompareSource} <= {LimitDown}"; break; case ComparisonType.LTGE: express = $"{CompareSource} >= {LimitUp} || {CompareSource} < {LimitDown}"; break; default: break; } return PlanRun.Resolve(this, express); } private bool DoCompareString() { string express = $"CompareString({CompareSource},{TargetValue},{IgnoreCase})"; return PlanRun.Resolve(this, express); } private bool DoCompareBool() { if (string.IsNullOrEmpty(CompareSource)) { return false; } return PlanRun.Resolve(this, CompareSource); } } }