Exemple #1
0
        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));
        }
Exemple #2
0
        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));
            }
        }