public void CodeAnalysisResultManager_VerifyFileWithArtifactHash_HasNoEmbeddedFile()
        {
            // Arrange.
            const string PathInLogFile    = @"C:\Code\sarif-sdk\src\Sarif\Notes.cs";
            const string ResolvedPath     = @"D:\Users\John\source\sarif-sdk\src\Sarif\Notes.cs";
            const string EmbeddedFilePath = null;
            const int    RunId            = 1;

            var target = new CodeAnalysisResultManager(
                null,                               // This test never touches the file system.
                this.FakePromptForResolvedPath,
                this.FakePromptForEmbeddedFile);
            var dataCache = new RunDataCache();

            target.RunIndexToRunDataCache.Add(RunId, dataCache);
            this.embeddedFileDialogResult = ResolveEmbeddedFileDialogResult.None;

            var sarifErrorListItem = new SarifErrorListItem {
                LogFilePath = @"C:\Code\sarif-sdk\src\.sarif\Result.sarif"
            };

            // Act.
            bool result = target.VerifyFileWithArtifactHash(sarifErrorListItem, PathInLogFile, dataCache, ResolvedPath, EmbeddedFilePath, out string actualResolvedPath);

            // Assert.
            result.Should().BeTrue();
            actualResolvedPath.Should().Be(ResolvedPath);
            // no dialog pop up
            this.numEmbeddedFilePrompts.Should().Be(0);
        }
        // return false means cannot resolve local file and will use embedded file.
        internal bool VerifyFileWithArtifactHash(SarifErrorListItem sarifErrorListItem, string pathFromLogFile, RunDataCache dataCache, string resolvedPath, string embeddedTempFilePath, out string newResolvedPath)
        {
            newResolvedPath = null;

            if (string.IsNullOrEmpty(resolvedPath))
            {
                // cannot find corresponding file in local, then use embedded file
                newResolvedPath = embeddedTempFilePath;
                return(true);
            }

            if (!dataCache.FileDetails.TryGetValue(pathFromLogFile, out ArtifactDetailsModel fileData))
            {
                // has no embedded file, return the path resolved till now
                newResolvedPath = resolvedPath;
                return(true);
            }

            string fileHash = this.GetFileHash(this._fileSystem, resolvedPath);

            if (fileHash.Equals(fileData.Sha256Hash, StringComparison.OrdinalIgnoreCase))
            {
                // found a file in file system which has same hashcode as embeded content.
                newResolvedPath = resolvedPath;
                return(true);
            }

            bool hasEmbeddedContent = !string.IsNullOrEmpty(embeddedTempFilePath);
            ResolveEmbeddedFileDialogResult dialogResult = this._promptForEmbeddedFileDelegate(sarifErrorListItem.LogFilePath, hasEmbeddedContent, this.userDialogPreference);

            switch (dialogResult)
            {
            case ResolveEmbeddedFileDialogResult.None:
                // dialog is cancelled.
                newResolvedPath = null;
                return(false);

            case ResolveEmbeddedFileDialogResult.OpenEmbeddedFileContent:
                newResolvedPath = embeddedTempFilePath;
                return(true);

            case ResolveEmbeddedFileDialogResult.OpenLocalFileFromSolution:
                newResolvedPath = resolvedPath;
                return(true);

            case ResolveEmbeddedFileDialogResult.BrowseAlternateLocation:
                // if returns null means user cancelled the open file dialog.
                newResolvedPath = this._promptForResolvedPathDelegate(sarifErrorListItem, pathFromLogFile);
                return(!string.IsNullOrEmpty(newResolvedPath));

            default:
                return(false);
            }
        }
        public void CodeAnalysisResultManager_VerifyFileWithArtifactHash_LocalFileDoesNotExists()
        {
            // Arrange.
            const string PathInLogFile       = @"C:\Code\sarif-sdk\src\Sarif\Notes.cpp";
            const string ResolvedPath        = null;
            const string EmbeddedFilePath    = @"D:\Users\John\AppData\Local\Temp\SarifViewer\e1bb39f712fbb56ee0ae3782c68d1278a6ab494b7e2daf214400af283b75307c\Notes.cpp";
            const string EmbeddedFileContent = "UUID uuid;\nUuidCreate(&uuid);";
            const int    RunId = 1;

            var target = new CodeAnalysisResultManager(
                null,                               // This test never touches the file system.
                this.FakePromptForResolvedPath,
                this.FakePromptForEmbeddedFile);
            var dataCache = new RunDataCache();

            target.RunIndexToRunDataCache.Add(RunId, dataCache);
            var artifact = new Artifact
            {
                Hashes = new Dictionary <string, string> {
                    ["sha-256"] = "e1bb39f712fbb56ee0ae3782c68d1278a6ab494b7e2daf214400af283b75307c"
                },
                Contents = new ArtifactContent {
                    Text = EmbeddedFileContent
                },
            };

            dataCache.FileDetails.Add(PathInLogFile, new Models.ArtifactDetailsModel(artifact));
            this.embeddedFileDialogResult = ResolveEmbeddedFileDialogResult.None;

            var sarifErrorListItem = new SarifErrorListItem {
                LogFilePath = @"C:\Code\sarif-sdk\src\.sarif\Result.sarif"
            };

            // Act.
            bool result = target.VerifyFileWithArtifactHash(sarifErrorListItem, PathInLogFile, dataCache, ResolvedPath, EmbeddedFilePath, out string actualResolvedPath);

            // Assert.
            result.Should().BeTrue();
            actualResolvedPath.Should().Be(EmbeddedFilePath);
            // no dialog pop up
            this.numEmbeddedFilePrompts.Should().Be(0);
        }
        public void CodeAnalysisResultManager_VerifyFileWithArtifactHash_HashDoesNotMatches()
        {
            // Arrange.
            const string PathInLogFile       = @"C:\Code\sarif-sdk\src\Sarif\Notes.cpp";
            const string ResolvedPath        = @"D:\Users\John\source\sarif-sdk\src\Sarif\Notes.cs";
            const string EmbeddedFilePath    = @"D:\Users\John\AppData\Local\Temp\SarifViewer\e1bb39f712fbb56ee0ae3782c68d1278a6ab494b7e2daf214400af283b75307c\Notes.cpp";
            const string EmbeddedFileContent = "UUID uuid;\nUuidCreate(&uuid);";
            const int    RunId = 1;

            this.existingFiles.Add(ResolvedPath);
            this.mockFileSystem
            .Setup(fs => fs.FileOpenRead(ResolvedPath))
            .Returns(new MemoryStream(Encoding.UTF8.GetBytes(EmbeddedFileContent + "\n")));

            var target = new CodeAnalysisResultManager(
                this.mockFileSystem.Object,
                this.FakePromptForResolvedPath,
                this.FakePromptForEmbeddedFile);
            var dataCache = new RunDataCache();

            target.RunIndexToRunDataCache.Add(RunId, dataCache);
            var artifact = new Artifact
            {
                Hashes = new Dictionary <string, string> {
                    ["sha-256"] = "e1bb39f712fbb56ee0ae3782c68d1278a6ab494b7e2daf214400af283b75307c"
                },
                Contents = new ArtifactContent {
                    Text = EmbeddedFileContent
                },
            };

            dataCache.FileDetails.Add(PathInLogFile, new Models.ArtifactDetailsModel(artifact));

            // simulate user cancelled dialog without selecting any option
            this.embeddedFileDialogResult = ResolveEmbeddedFileDialogResult.None;

            var sarifErrorListItem = new SarifErrorListItem {
                LogFilePath = @"C:\Code\sarif-sdk\src\.sarif\Result.sarif"
            };

            // Act.
            bool result = target.VerifyFileWithArtifactHash(sarifErrorListItem, PathInLogFile, dataCache, ResolvedPath, EmbeddedFilePath, out string actualResolvedPath);

            // Assert.
            result.Should().BeFalse();
            actualResolvedPath.Should().BeNull();
            // dialog pop up
            this.numEmbeddedFilePrompts.Should().Be(1);

            // simulate user selected open embedded file
            this.embeddedFileDialogResult = ResolveEmbeddedFileDialogResult.OpenEmbeddedFileContent;
            this.mockFileSystem
            .Setup(fs => fs.FileOpenRead(ResolvedPath))
            .Returns(new MemoryStream(Encoding.UTF8.GetBytes(EmbeddedFileContent + "\n")));
            // Act.
            result = target.VerifyFileWithArtifactHash(sarifErrorListItem, PathInLogFile, dataCache, ResolvedPath, EmbeddedFilePath, out actualResolvedPath);

            // Assert.
            result.Should().BeTrue();
            actualResolvedPath.Should().Be(EmbeddedFilePath);
            // dialog pop up
            this.numEmbeddedFilePrompts.Should().Be(2);

            // simulate user selected open local file
            this.embeddedFileDialogResult = ResolveEmbeddedFileDialogResult.OpenLocalFileFromSolution;
            this.mockFileSystem
            .Setup(fs => fs.FileOpenRead(ResolvedPath))
            .Returns(new MemoryStream(Encoding.UTF8.GetBytes(EmbeddedFileContent + "\n")));
            // Act.
            result = target.VerifyFileWithArtifactHash(sarifErrorListItem, PathInLogFile, dataCache, ResolvedPath, EmbeddedFilePath, out actualResolvedPath);

            // Assert.
            result.Should().BeTrue();
            actualResolvedPath.Should().Be(ResolvedPath);
            // dialog pop up
            this.numEmbeddedFilePrompts.Should().Be(3);

            // simulate user selected to browser alternate file
            this.embeddedFileDialogResult = ResolveEmbeddedFileDialogResult.BrowseAlternateLocation;
            this.mockFileSystem
            .Setup(fs => fs.FileOpenRead(ResolvedPath))
            .Returns(new MemoryStream(Encoding.UTF8.GetBytes(EmbeddedFileContent + "\n")));
            this.pathFromPrompt = ResolvedPath;
            // Act.
            result = target.VerifyFileWithArtifactHash(sarifErrorListItem, PathInLogFile, dataCache, ResolvedPath, EmbeddedFilePath, out actualResolvedPath);

            // Assert.
            result.Should().BeTrue();
            actualResolvedPath.Should().Be(ResolvedPath);
            // dialog pop up
            this.numEmbeddedFilePrompts.Should().Be(4);
            this.numPrompts.Should().Be(1);
        }
        public void CodeAnalysisResultManager_VerifyFileWithArtifactHash_HashMatches()
        {
            // Arrange.
            const string PathInLogFile       = @"C:\Code\sarif-sdk\src\Sarif\Notes.cpp";
            const string ResolvedPath        = @"D:\Users\John\source\sarif-sdk\src\Sarif\Notes.cs";
            const string EmbeddedFilePath    = @"D:\Users\John\AppData\Local\Temp\SarifViewer\e1bb39f712fbb56ee0ae3782c68d1278a6ab494b7e2daf214400af283b75307c\Notes.cpp";
            const string EmbeddedFileContent = "UUID uuid;\nUuidCreate(&uuid);";
            const int    RunId = 1;

            this.existingFiles.Add(ResolvedPath);
            this.mockFileSystem
            .Setup(fs => fs.FileOpenRead(ResolvedPath))
            .Returns(new MemoryStream(Encoding.UTF8.GetBytes(EmbeddedFileContent)));

            var target = new CodeAnalysisResultManager(
                this.mockFileSystem.Object,
                this.FakePromptForResolvedPath,
                this.FakePromptForEmbeddedFile);
            var dataCache = new RunDataCache();

            target.RunIndexToRunDataCache.Add(RunId, dataCache);
            var artifact = new Artifact
            {
                Hashes = new Dictionary <string, string> {
                    ["sha-256"] = "e1bb39f712fbb56ee0ae3782c68d1278a6ab494b7e2daf214400af283b75307c"
                },
                Contents = new ArtifactContent {
                    Text = EmbeddedFileContent
                },
            };

            dataCache.FileDetails.Add(PathInLogFile, new Models.ArtifactDetailsModel(artifact));
            this.embeddedFileDialogResult = ResolveEmbeddedFileDialogResult.None;

            var sarifErrorListItem = new SarifErrorListItem {
                LogFilePath = @"C:\Code\sarif-sdk\src\.sarif\Result.sarif"
            };

            // Act.
            bool result = target.VerifyFileWithArtifactHash(sarifErrorListItem, PathInLogFile, dataCache, ResolvedPath, EmbeddedFilePath, out string actualResolvedPath);

            // Assert.
            result.Should().BeTrue();
            actualResolvedPath.Should().Be(ResolvedPath);
            // no dialog pop up
            this.numEmbeddedFilePrompts.Should().Be(0);

            // change hash to upper case and verify again
            this.mockFileSystem
            .Setup(fs => fs.FileOpenRead(ResolvedPath))
            .Returns(new MemoryStream(Encoding.UTF8.GetBytes(EmbeddedFileContent)));
            artifact = new Artifact
            {
                Hashes = new Dictionary <string, string> {
                    ["sha-256"] = "e1bb39f712fbb56ee0ae3782c68d1278a6ab494b7e2daf214400af283b75307c".ToUpper()
                },
                Contents = new ArtifactContent {
                    Text = EmbeddedFileContent
                },
            };
            dataCache.FileDetails[PathInLogFile] = new Models.ArtifactDetailsModel(artifact);
            this.embeddedFileDialogResult        = ResolveEmbeddedFileDialogResult.None;

            // Act.
            result = target.VerifyFileWithArtifactHash(sarifErrorListItem, PathInLogFile, dataCache, ResolvedPath, EmbeddedFilePath, out actualResolvedPath);

            // Assert.
            result.Should().BeTrue();
            actualResolvedPath.Should().Be(ResolvedPath);
            // no dialog pop up
            this.numEmbeddedFilePrompts.Should().Be(0);
        }
 private void BrowseFileButton_Click(object sender, System.Windows.RoutedEventArgs e)
 {
     this.Result       = ResolveEmbeddedFileDialogResult.BrowseAlternateLocation;
     this.DialogResult = true;
     this.Close();
 }
 private void OpenLocalFileButton_Click(object sender, System.Windows.RoutedEventArgs e)
 {
     this.Result       = ResolveEmbeddedFileDialogResult.OpenLocalFileFromSolution;
     this.DialogResult = true;
     this.Close();
 }