public async Task SuccessfulRunTestAsync() { TestHelper.InitializePackageTaskFactory(); /* Create a test project */ var projectMock = new Mock <IProject>(); var options = new ProjectOptions(); options.SetProfiles(new Dictionary <string, ProfileOptions> { { "Default", new ProfileOptions() } }, activeProfile: "Default"); projectMock.Setup((p) => p.Options).Returns(options); projectMock.Setup(p => p.RunWhenLoaded(It.IsAny <Action <ProjectOptions> >())).Callback((Action <ProjectOptions> a) => a(options)); var breakLineTagger = new Mock <BreakLineGlyphTaggerProvider>(); projectMock.Setup((p) => p.GetExportByMetadataAndType(It.IsAny <Predicate <IAppliesToMetadataView> >(), It.IsAny <Predicate <IViewTaggerProvider> >())) .Returns(breakLineTagger.Object); var project = projectMock.Object; project.Options.Profile.MenuCommands.DebugAction = "Debug"; project.Options.Profile.General.LocalWorkDir = "local/dir"; project.Options.Profile.General.RemoteWorkDir = "/periphery/votw"; project.Options.Profile.Actions.Add(new ActionProfileOptions { Name = "Debug" }); project.Options.DebuggerOptions.Watches.Add(new Watch("a", VariableType.Hex, false)); project.Options.DebuggerOptions.Watches.Add(new Watch("c", VariableType.Hex, false)); project.Options.DebuggerOptions.Watches.Add(new Watch("tide", VariableType.Hex, false)); var readDebugDataStep = new ReadDebugDataStep { BinaryOutput = false, OutputOffset = 1 }; readDebugDataStep.OutputFile.CheckTimestamp = true; readDebugDataStep.OutputFile.Path = "output-path"; project.Options.Profile.Actions[0].Steps.Add(new ExecuteStep { Executable = "ohmu", Arguments = "-break-line $(RadBreakLine) -source $(RadActiveSourceFile) -source-line $(RadActiveSourceFileLine) -watch $(RadWatches)" }); project.Options.Profile.Actions[0].Steps.Add(readDebugDataStep); var codeEditor = new Mock <IActiveCodeEditor>(); codeEditor.Setup(e => e.GetCurrentLine()).Returns(13); var breakpointTracker = new Mock <IBreakpointTracker>(); breakpointTracker.Setup(t => t.MoveToNextBreakTarget(false)).Returns((@"C:\MEHVE\JATO.s", new[] { 666u })); var serviceProvider = new Mock <SVsServiceProvider>(); serviceProvider.Setup(p => p.GetService(typeof(SVsStatusbar))).Returns(new Mock <IVsStatusbar>().Object); var channel = new MockCommunicationChannel(DebugServer.IPC.ServerPlatform.Linux); var sourceManager = new Mock <IProjectSourceManager>(); var actionLauncher = new ActionLauncher(project, new Mock <IActionLogger>().Object, channel, sourceManager.Object, codeEditor.Object, breakpointTracker.Object, serviceProvider.Object); var debuggerIntegration = new DebuggerIntegration(project, actionLauncher, codeEditor.Object, breakpointTracker.Object); /* Set up server responses */ channel.ThenRespond(new MetadataFetched { Status = FetchStatus.FileNotFound }, (FetchMetadata timestampFetch) => Assert.Equal(new[] { "/periphery/votw/output-path" }, timestampFetch.FilePath)); channel.ThenRespond(new ExecutionCompleted { Status = ExecutionStatus.Completed, ExitCode = 0 }, (Execute execute) => { Assert.Equal("ohmu", execute.Executable); Assert.Equal(@"-break-line 666 -source JATO.s -source-line 13 -watch a:c:tide", execute.Arguments); }); channel.ThenRespond(new MetadataFetched { Status = FetchStatus.Successful, Timestamp = DateTime.Now }); /* Start debugging */ var tcs = new TaskCompletionSource <ExecutionCompletedEventArgs>(); BreakState breakState = null; debuggerIntegration.ExecutionCompleted += (s, e) => tcs.SetResult(e); debuggerIntegration.BreakEntered += (s, e) => breakState = e; var engine = debuggerIntegration.RegisterEngine(); engine.Execute(false); var execCompletedEvent = await tcs.Task; Assert.NotNull(execCompletedEvent); Assert.Equal(@"C:\MEHVE\JATO.s", execCompletedEvent.File); Assert.Equal(666u, execCompletedEvent.Lines[0]); sourceManager.Verify(s => s.SaveProjectState(), Times.Once); Assert.NotNull(breakState); Assert.Equal(3, breakState.Data.Watches.Count); Assert.Equal("a", breakState.Data.Watches[0]); Assert.Equal("c", breakState.Data.Watches[1]); Assert.Equal("tide", breakState.Data.Watches[2]); breakLineTagger.Verify(t => t.OnExecutionCompleted(execCompletedEvent)); }
private async Task <(StepResult, BreakState)> DoReadDebugDataAsync(ReadDebugDataStep step) { var watches = _debugWatches; BreakStateDispatchParameters dispatchParams = null; if (!string.IsNullOrEmpty(step.WatchesFile.Path)) { var result = await ReadDebugDataFileAsync("Valid watches", step.WatchesFile.Path, step.WatchesFile.IsRemote(), step.WatchesFile.CheckTimestamp); if (!result.TryGetResult(out var data, out var error)) { return(new StepResult(false, error.Message, ""), null); } var watchString = Encoding.UTF8.GetString(data); var watchArray = watchString.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); watches = Array.AsReadOnly(watchArray); } if (!string.IsNullOrEmpty(step.DispatchParamsFile.Path)) { var result = await ReadDebugDataFileAsync("Dispatch parameters", step.DispatchParamsFile.Path, step.DispatchParamsFile.IsRemote(), step.DispatchParamsFile.CheckTimestamp); if (!result.TryGetResult(out var data, out var error)) { return(new StepResult(false, error.Message, ""), null); } var paramsString = Encoding.UTF8.GetString(data); var dispatchParamsResult = BreakStateDispatchParameters.Parse(paramsString); if (!dispatchParamsResult.TryGetResult(out dispatchParams, out error)) { return(new StepResult(false, error.Message, ""), null); } } { var outputPath = step.OutputFile.Path; var initOutputTimestamp = GetInitialFileTimestamp(outputPath); int GetDispatchDwordCount(int fileDwordCount, out string warning) { warning = ""; if (dispatchParams == null) { return(fileDwordCount); } var laneDataSize = 1 /* system watch */ + watches.Count; var totalLaneCount = dispatchParams.GridSizeX * dispatchParams.GridSizeY * dispatchParams.GridSizeZ; var dispatchDwordCount = (int)totalLaneCount * laneDataSize; if (fileDwordCount < dispatchDwordCount) { warning = $"Output file ({outputPath}) is smaller than expected.\r\n\r\n" + $"Grid size as specified in the dispatch parameters file is ({dispatchParams.GridSizeX}, {dispatchParams.GridSizeY}, {dispatchParams.GridSizeZ}), " + $"which corresponds to {totalLaneCount} lanes. With {laneDataSize} DWORDs per lane, the output file is expected to contain at least " + $"{dispatchDwordCount} DWORDs, but it only contains {fileDwordCount} DWORDs."; } return(Math.Min(dispatchDwordCount, fileDwordCount)); } BreakStateOutputFile outputFile; uint[] localOutputData = null; string stepWarning; if (step.OutputFile.IsRemote()) { var response = await _channel.SendWithReplyAsync <MetadataFetched>( new FetchMetadata { FilePath = new[] { outputPath }, BinaryOutput = step.BinaryOutput }, _controller.CancellationToken); if (response.Status == FetchStatus.FileNotFound) { return(new StepResult(false, $"Output file ({outputPath}) could not be found.", ""), null); } if (step.OutputFile.CheckTimestamp && response.Timestamp == initOutputTimestamp) { return(new StepResult(false, $"Output file ({outputPath}) was not modified. Data may be stale.", ""), null); } var offset = step.BinaryOutput ? step.OutputOffset : step.OutputOffset * 4; var fileByteCount = Math.Max(0, response.ByteCount - offset); var dispatchDwordCount = GetDispatchDwordCount(fileDwordCount: fileByteCount / 4, out stepWarning); outputFile = new BreakStateOutputFile(outputPath, step.BinaryOutput, step.OutputOffset, response.Timestamp, dispatchDwordCount); } else { var timestamp = GetLocalFileLastWriteTimeUtc(outputPath); if (step.OutputFile.CheckTimestamp && timestamp == initOutputTimestamp) { return(new StepResult(false, $"Output file ({outputPath}) was not modified. Data may be stale.", ""), null); } int dispatchDwordCount; if (step.BinaryOutput) { if (!ReadLocalFile(outputPath, out var outputBytes, out var readError)) { return(new StepResult(false, "Output file could not be opened. " + readError, ""), null); } var fileByteCount = Math.Max(0, outputBytes.Length - step.OutputOffset); dispatchDwordCount = GetDispatchDwordCount(fileDwordCount: fileByteCount / 4, out stepWarning); localOutputData = new uint[dispatchDwordCount]; Buffer.BlockCopy(outputBytes, step.OutputOffset, localOutputData, 0, dispatchDwordCount * 4); } else { var outputDwords = TextDebuggerOutputParser.ReadTextOutput(outputPath, step.OutputOffset); dispatchDwordCount = GetDispatchDwordCount(fileDwordCount: outputDwords.Count, out stepWarning); if (outputDwords.Count > dispatchDwordCount) { outputDwords.RemoveRange(dispatchDwordCount, outputDwords.Count - dispatchDwordCount); } localOutputData = outputDwords.ToArray(); } outputFile = new BreakStateOutputFile(outputPath, step.BinaryOutput, offset: 0, timestamp, dispatchDwordCount); } var data = new BreakStateData(watches, outputFile, localOutputData); return(new StepResult(true, stepWarning, ""), new BreakState(data, dispatchParams)); } }