using AddInPlugin;
using AddInPlugin.Setting;
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.Win32;
using OpenTap;
using OpenTap.Addin;
using OpenTap.Addin.Listener;
using OpenTap.Addin.Util;
using OpenTap.Plugins.BasicSteps;
using SeqEditor.Util;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace OpenTapEditor;
///
/// Interaction logic for SequencePanel.xaml
///
[ObservableObject]
public partial class ExecutionPanel : UserControl, ITabItem, IStepRunStatus
{
private TestPlan Plan;
private TestPlanRun PlanRun;
private TapThread testPlanThread;
private string startedSeqName;
[ObservableProperty]
private ITestStep selectedTestStep;
[ObservableProperty]
private bool isRunning = false;
[ObservableProperty]
private bool hasChanged = false;
public string TabName
{
get
{
return $"Execution-{Plan?.Name}";
}
set
{
}
}
[ObservableProperty]
private RuningMode runingMode = RuningMode.Stop;
private ManualResetEvent SingleStepHandle = new ManualResetEvent(true);
public event EventHandler RunningFinished;
public ExecutionPanel(TestPlan plan, string seqName)
{
this.Plan = plan;
this.startedSeqName = seqName;
InitializeComponent();
treeView.Plan = plan;
}
private void VariableControl_SequenceChanged(object? sender, EventArgs e)
{
HasChanged = true;
}
private void ChildTestSteps_ChildStepsChanged(TestStepList senderList, TestStepList.ChildStepsChangedAction Action, ITestStep Object, int Index)
{
HasChanged = true;
}
private void ChildTestSteps_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
HasChanged = true;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var btn = (Button)sender;
switch (btn.Tag)
{
case "运行":
RunBtn();
break;
case "调试":
RunTestPlan(RuningMode.RunningInDebugMode);
break;
case "单步运行":
StepRuning();
break;
case "停止":
StopRunTestPlan();
break;
default:
break;
}
}
private void RunBtn()
{
if (IsRunning)
{
if (RuningMode == RuningMode.RunningInStepMode)
{
RuningMode = RuningMode.Running;
SingleStepHandle.Set();
return;
}
if (RuningMode == RuningMode.RunningInDebugModeButStep)
{
RuningMode = RuningMode.RunningInDebugMode;
SingleStepHandle.Set();
return;
}
if (RuningMode == RuningMode.RunningInDebugMode)
{
SingleStepHandle.Set();
return;
}
}
else
{
RunTestPlan(RuningMode.Running);
}
}
public void RunTestPlan(RuningMode mode)
{
try
{
/// 保存一下StationGlobals变量
try
{
StationGlobalsManager.WriteToLocal(UIStationGlobalsManager.Instance.Datasource);
}
catch (Exception ex)
{
}
IsRunning = true;
RuningMode = mode;
treeView.ComplatedIds.Clear();
treeView.UpdateStepStatus();
RunVars = null;
RunVarContext = null;
handledPlan.Clear();
handledPlan.Add(Plan);
Plan.BreakOffered += Plan_BreakOffered;
settingView.CanEdit = false;
runVariableControl.Visibility = Visibility.Visible;
var uiListener = new UIListener(SeqEditorUI.Instance.logControl, this);
testPlanThread = TapThread.Start(() =>
{
try
{
var s = ResultSettings.Current;
ResultSettings.Current.Add(uiListener);
if (StationSettings.Current.ReportType == ReportType.TXT)
{
ResultSettings.Current.Add(new TxtReportListener("Report"));
}
else
{
ResultSettings.Current.Add(new HtmlReportListener("Report"));
}
var res = ResultSettings.Current;
var run = Plan.Execute(startedSeqName, res, null, null, null);
}
catch (Exception ex)
{
SeqEditorUI.Log.Error("Start TestPlan Error. {0}", ex);
}
finally
{
ResultSettings.Current.Remove(uiListener);
RunVarContext?.Release();
Dispatcher.BeginInvoke(() =>
{
RunningFinished?.Invoke(this, new EventArgs());
RuningMode = RuningMode.Stop;
Plan.BreakOffered -= Plan_BreakOffered;
treeView.DebugStepId = Guid.Empty;
treeView.RunningStepId = Guid.Empty;
settingView.CanEdit = true;
IsRunning = false;
foreach (var handled in handledPlan)
{
handled.BreakOffered -= Plan_BreakOffered;
}
handledPlan.Clear();
});
}
}, "UI_Start");
}
catch (Exception ex)
{
SeqEditorUI.Log.Error("Run TestPlan Error. {0}", ex);
}
}
[ObservableProperty]
private RunningVarContext runVarContext;
[ObservableProperty]
private ObservableCollection runVars;
private readonly List handledPlan = new List();
private string currentSeqId = null;
private void Plan_BreakOffered(object? sender, BreakOfferedEventArgs e)
{
try
{
var stepRun = e.TestStepRun;
var planRun = stepRun.testPlanRun;
var step = stepRun.CurrentStep;
var plan = step.Root;
var seqId = $"{plan.VisualPath}_{planRun.RunningSeqName}";
TestStepList list = plan.GetStepsByName(planRun.RunningSeqName);
Dispatcher.BeginInvoke(() =>
{
treeView.DebugStepId = e.TestStepRun.TestStepId;
if (RunVarContext == null)
{
RunVarContext = new RunningVarContext()
{
PlanRun = planRun
};
RunVarContext.Children = RunningVar.FromTest(RunVarContext, null, false, new ObservableCollection() {
new TestVariable(){
Name = "Locals",
Type = TestVariableType.Container,
Children = list.Variables
},
new TestVariable(){
Name = "Parameters",
Type = TestVariableType.Container,
Children = list.Parameters
},
new TestVariable(){
Name = "FileGlobals",
Type = TestVariableType.Container,
Children = plan.Variables
},
new TestVariable(){
Name = "StationGlobals",
Type = TestVariableType.Container,
Children = UIStationGlobalsManager.Instance.Datasource,
}});
RunVars = RunVarContext.Children;
}
RunVarContext.Children[0].ContextName = list.SequenceName;
RunVarContext.Children[1].ContextName = list.SequenceName;
RunVarContext.Children[2].ContextName = plan.VisualPath;
if (currentSeqId != seqId)
{
RunVarContext.RefreshPlan(planRun, plan, list);
treeView.Datasource = list;
currentSeqId = seqId;
}
}).Wait();
if (step is SequenceCallStep scs)
{
//if (lastChildPlan != null)
//{
// lastChildPlan.BreakOffered -= Plan_BreakOffered;
//}
if (!handledPlan.Contains(scs.runningPlan))
{
scs.runningPlan.BreakOffered += Plan_BreakOffered;
handledPlan.Add(scs.runningPlan);
}
}
if (RuningMode == RuningMode.RunningInStepMode || RuningMode == RuningMode.RunningInDebugModeButStep)
{
SingleStepHandle.Reset();
WaitHandle.WaitAny(new[] { SingleStepHandle, testPlanThread.AbortToken.WaitHandle });
}
else if (RuningMode == RuningMode.RunningInDebugMode)
{
if (treeView.NeedBreak(e.TestStepRun.TestStepId))
{
SingleStepHandle.Reset();
WaitHandle.WaitAny(new[] { SingleStepHandle, testPlanThread.AbortToken.WaitHandle });
}
}
}
catch (Exception ex)
{
SeqEditorUI.Log.Error($"Plan_BreakOffered Error: {ex}");
}
}
private void StepRuning()
{
if (IsRunning && RuningMode != RuningMode.Running)
{
if (RuningMode == RuningMode.RunningInDebugMode)
{
RuningMode = RuningMode.RunningInDebugModeButStep;
}
SingleStepHandle.Set();
}
else
{
RunTestPlan(RuningMode.RunningInStepMode);
}
}
public void StopRunTestPlan()
{
testPlanThread?.Abort();
}
public bool TrySaveTestStep(Func check)
{
if (!string.IsNullOrEmpty(Plan.Path))
{
Plan.Save(Plan.Path);
HasChanged = false;
OnPropertyChanged(nameof(TabName));
return true;
}
return TrySaveAs(check);
}
public bool TrySaveAs(Func check)
{
SaveFileDialog sfd = new SaveFileDialog()
{
Filter = "Test Plan|*.TapPlan",
DefaultExt = ".TapPlan"
};
if (sfd.ShowDialog() == true)
{
if (check.Invoke(sfd.FileName))
{
Plan.Save(sfd.FileName);
HasChanged = false;
OnPropertyChanged(nameof(TabName));
return true;
}
}
return false;
}
private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs